# Sand 🏝
[](https://github.com/gkpln3/Sand/actions/workflows/ci.yml)
Sand is a Dockerfile generator.
It allows you to write cleaner, shorter and more configurable Dockerfiles.
## Developers ❤️ Sand
Sand is built by developers, for developers. It's built to be as simple as possible, while still being super useful.
## Installation
You can install Sand using pip.
```bash
pip3 install docker-sand
```
## Features
✅ Simple, easy to learn syntax based on Python.
✅ Configurable Dockerfiles.
✅ Share code between Dockerfiles.
✅ Perfect for monorepos composed of multiple microservices.
✅ Supports multi-stage builds.
#### Planned Features:
🔘 Optimize builds by finding common layers between Dockerfiles, and merging them into a base image.
🔘 Minimizing the number of layers by combining multiple RUN commands into one.
# Example
Write your Dockerfile in a Python-like syntax.
```python
# Sandfile
from sand import *
From("ubuntu", Tag="20.04")
Run([
"apt-get update",
"apt-get install ffmpeg python3"
])
# Install python debugger on debug images.
if config.DEBUG:
Run("pip3 install pdb")
Copy("app", "/app")
Entrypoint("python3 /app/app.py")
```
⬇️
```dockerfile
# Auto-generated by Sand, do not edit!
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install ffmpeg python3
COPY app /app
ENTRYPOINT python3 /app/app.py
```
### Share Code
Because `Sandfile`s are just Python files, and are being evaluated in an hierarchical manner by using the `Sand` directive, so you can easily share code between them.
Given the following directory structure:
```
my-monorepo/
│
├── tweet-service/
| ├── src/
| ├── ...
│ └── Sandfile
│
├── home-timeline/
| ├── src/
| ├── ...
│ └── Sandfile
│
└── Sandfile
```
You can write your `Sandfile`s like this:
```python
# ./my-monorepo/Sandfile
from sand import *
def MyService(name):
From("ubuntu", "20.04")
Run("apt-get install python3")
Copy(Src="src", Dst="/app")
Entrypoint(f"python3 /app/{name}.py")
Sand("tweet-service")
Sand("home-timeline")
```
```python
# ./my-monorepo/tweet-service/Sandfile
from sand import *
MyService("tweet-service") # Defined in ../Sandfile
```
```python
# ./my-monorepo/home-timeline/Sandfile
from sand import *
MyService("home-timeline") # Defined in ../Sandfile
```
This allows you to share code between your Dockerfiles, and keep them [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself).
This is similar to the way `add_subdirectory` works in [CMake](https://cmake.org/)
## Usage
Running Sand is as simple as running `sand` in your terminal.
This will generate Dockerfiles for all Sandfiles in the current directory.
```
$ sand config
Saving Dockerfile to backend/service1/Dockerfile
Saving Dockerfile to backend/service2/Dockerfile
Built successfully!
```
You can also watch for changes and automatically rebuild your Dockerfiles.
```
$ sand config -w
Watching for changes...
```
### Configuration
You can pass configuration values to Sand using the `-D` or `--set` flag.
```
$ sand config -DDEBUG=True
```
Or use a YAML file.
```yaml
# sand.yaml
DEBUG: True
```
```
$ sand config --values sand.yaml
```