Skip to content

Commit 2c20f19

Browse files
committed
fix: env loading
issue: #64
1 parent 233707c commit 2c20f19

File tree

2 files changed

+112
-16
lines changed

2 files changed

+112
-16
lines changed

core/internal/docker/compose.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ package docker
33
import (
44
"context"
55
"fmt"
6+
"io"
7+
"maps"
8+
"path/filepath"
9+
"reflect"
10+
"slices"
11+
"strings"
12+
13+
"github.com/RA341/dockman/pkg/fileutil"
614
"github.com/compose-spec/compose-go/v2/cli"
715
"github.com/compose-spec/compose-go/v2/types"
816
"github.com/docker/cli/cli/command"
@@ -12,12 +20,6 @@ import (
1220
"github.com/docker/docker/api/types/container"
1321
"github.com/docker/docker/api/types/filters"
1422
"github.com/rs/zerolog/log"
15-
"io"
16-
"maps"
17-
"path/filepath"
18-
"reflect"
19-
"slices"
20-
"strings"
2123
)
2224

2325
// reference: https://github.com/portainer/portainer/blob/develop/pkg/libstack/compose/composeplugin.go
@@ -217,17 +219,28 @@ func (s *ComposeService) LoadProject(ctx context.Context, shortName string) (*ty
217219
// will be the parent dir of the compose file else equal to compose root
218220
workingDir := filepath.Dir(fullPath)
219221

222+
sampleFile := []string{
223+
// Global .env
224+
filepath.Join(s.composeRoot, ".env"),
225+
// Subdirectory .env (will override global)
226+
filepath.Join(workingDir, ".env"),
227+
}
228+
slices.DeleteFunc(sampleFile, func(s string) bool {
229+
return !fileutil.FileExists(s)
230+
})
231+
220232
options, err := cli.NewProjectOptions(
221233
[]string{fullPath},
222234
// important maintain this order to load .env properly
223-
// working-dir -> env -> os -> dot env -> sub dir .envs
224-
cli.WithWorkingDirectory(s.composeRoot),
235+
// highest lowest
236+
// working-dir .env <- compose root .env <- os envs
225237
cli.WithEnvFiles(),
226-
cli.WithOsEnv,
227238
cli.WithDotEnv,
228-
cli.WithDefaultProfiles(),
239+
cli.WithOsEnv,
240+
// compose operations will take place in working dir
229241
cli.WithWorkingDirectory(workingDir),
230-
cli.WithDotEnv,
242+
// other shit
243+
cli.WithDefaultProfiles(),
231244
cli.WithResolvedPaths(true),
232245
)
233246
if err != nil {

readme.md

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [Why](#why-dockman)
1616
- [Common Errors](#common-errors)
1717
- [File Layout](#file-layout)
18+
- [Env loading](#env-loading)
1819
- [Multihost support](#multihost-support)
1920
- [Feedback](#feedback)
2021
- [Security Considerations](#security-considerations)
@@ -288,7 +289,8 @@ Dockman will only see top level directories but Git will attempt to load all fil
288289
* **Keep stack root clean:** Only include Docker Compose files and relevant configuration files in your stack
289290
directory.
290291
* **Avoid .gitignore as a workaround**: While you can use .gitignore to exclude files, this is not recommended for
291-
Dockman. The better cleaner practice is to keep only relevant configuration files in your compose root and separate your
292+
Dockman. The better cleaner practice is to keep only relevant configuration files in your compose root and
293+
separate your
292294
stack definitions from your data directories entirely.
293295
* **See also:** [Recommended file layout](#file-layout) for best practices.
294296

@@ -331,12 +333,93 @@ stacks/
331333
332334
Think this is too limiting? Open an [issue](https://github.com/RA341/dockman/issues) and we can argue about it.
333335
334-
## Multihost Support
336+
## Env Loading
335337
336-
> [!IMPORTANT]
338+
Dockman can automatically discover and load environment files when running your compose setup.
339+
340+
> [!NOTE]
341+
> **Only files named `.env` are supported.**
342+
343+
If the same variable is defined in multiple places, the value from the **higher-precedence** source will overwrite the
344+
lower one. This makes it easy to override global defaults with project-specific settings.
345+
346+
Precedence (highest → lowest):
347+
348+
1. **Subfolder `.env`** - scoped to a specific compose folder
349+
2. **Root `.env`** - global defaults for everything under the compose root
350+
3. **OS env vars** - values already defined in your shell/OS environment
351+
352+
```text
353+
compose-root/
354+
├─ .env (global)
355+
└─ subfolder/
356+
└─ .env (overrides global)
357+
```
358+
359+
> [!Note]
360+
> These `.env` files are **only for Docker Compose interpolation**.
337361
>
338-
> From [v2+](https://github.com/RA341/dockman/releases/tag/v2.0.0) onwards, hosts.yaml method is removed,
339-
> in favour of a easier UI method
362+
> They are not automatically transferred into the container.
363+
>
364+
> Only variables referenced with `${VAR}` in the compose file are substituted.
365+
366+
Example (interpolation only):
367+
368+
```yaml
369+
services:
370+
database:
371+
image: postgres:15
372+
environment:
373+
POSTGRES_DB: myapp
374+
POSTGRES_USER: user
375+
POSTGRES_PASSWORD: password
376+
volumes:
377+
- ${TEST}:/var/somepath
378+
- ${ENVIRONMENT}:/anotherpath/
379+
- db_data:/var/lib/postgresql/data
380+
ports:
381+
- "5432:5432"
382+
383+
volumes:
384+
db_data:
385+
```
386+
387+
In this example, `${TEST}` and `${ENVIRONMENT}` are resolved from `.env`
388+
but are not injected into the container environment automatically.
389+
390+
### Adding Environment Variables to the Container
391+
392+
To actually pass environment variables into the container, you can:
393+
394+
**1. Pass them via `environment`:**
395+
396+
```yaml
397+
services:
398+
app:
399+
image: myapp:latest
400+
environment:
401+
APP_ENV: ${ENVIRONMENT} # <- docker compose will replace these before parsing the compose file
402+
DEBUG: ${DEBUG}
403+
```
404+
405+
**2. Or use the `env_file`:**
406+
407+
```yaml
408+
services:
409+
app:
410+
image: myapp:latest
411+
env_file:
412+
- ./.env # load sub dir env file
413+
```
414+
415+
Where `.env` might look like:
416+
417+
```dotenv
418+
ENVIRONMENT=production
419+
DEBUG=false
420+
```
421+
422+
## Multihost Support
340423

341424
Dockman's multihost feature lets you manage remote Docker hosts from one centralized interface.
342425
Jump between servers, keep your configurations perfectly organized, and deploy across your entire infrastructure

0 commit comments

Comments
 (0)