Skip to content

Commit ee59ba3

Browse files
committed
add global flag to define download directory for remote configuration (oci & git)
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
1 parent 4db5fcd commit ee59ba3

File tree

5 files changed

+92
-22
lines changed

5 files changed

+92
-22
lines changed

cmd/compose/compose.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ type ProjectOptions struct {
150150
Progress string
151151
Offline bool
152152
All bool
153+
DownloadDir string
153154
}
154155

155156
// ProjectFunc does stuff within a types.Project
@@ -226,7 +227,9 @@ func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
226227
f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
227228
f.StringVar(&o.Progress, "progress", string(buildkit.AutoMode), fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
228229
f.BoolVar(&o.All, "all-resources", false, "Include all resources, even those not used by services")
230+
f.StringVar(&o.DownloadDir, "download-dir", "", "Directory to store OCI or GIT Compose configurations")
229231
_ = f.MarkHidden("workdir")
232+
_ = f.MarkHidden("download-dir")
230233
}
231234

232235
// get default value for a command line flag that is set by a coma-separated value in environment variable
@@ -372,8 +375,8 @@ func (o *ProjectOptions) remoteLoaders(dockerCli command.Cli) []loader.ResourceL
372375
if o.Offline {
373376
return nil
374377
}
375-
git := remote.NewGitRemoteLoader(o.Offline)
376-
oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline)
378+
git := remote.NewGitRemoteLoader(o.Offline, o.DownloadDir)
379+
oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline, o.DownloadDir)
377380
return []loader.ResourceLoader{git, oci}
378381
}
379382

@@ -537,6 +540,22 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
537540
}
538541
}
539542

543+
if opts.DownloadDir != "" {
544+
if len(opts.ConfigPaths) == 0 {
545+
return fmt.Errorf("cannot use --download-dir without --file using oci:// or git:// prefix")
546+
}
547+
remoteResources := false
548+
for _, file := range opts.ConfigPaths {
549+
if strings.HasPrefix(file, "oci://") || strings.HasPrefix(file, "git://") {
550+
remoteResources = true
551+
break
552+
}
553+
}
554+
if !remoteResources {
555+
return fmt.Errorf("cannot use --download-dir without --file using oci:// or git:// prefix")
556+
}
557+
}
558+
540559
composeCmd := cmd
541560
for {
542561
if composeCmd.Name() == PluginName {

docs/reference/docker_compose.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ options:
102102
experimentalcli: false
103103
kubernetes: false
104104
swarm: false
105+
- option: download-dir
106+
value_type: string
107+
description: Directory to store OCI or GIT Compose configurations
108+
deprecated: false
109+
hidden: true
110+
experimental: false
111+
experimentalcli: false
112+
kubernetes: false
113+
swarm: false
105114
- option: dry-run
106115
value_type: bool
107116
default_value: "false"

internal/paths/paths.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,23 @@ func EncompassingPaths(paths []string) []string {
118118
}
119119
return result
120120
}
121+
122+
func GetAbsPath(path string) (string, error) {
123+
if filepath.IsAbs(path) {
124+
return path, nil
125+
}
126+
127+
if strings.HasPrefix(path, "~") {
128+
home, err := os.UserHomeDir()
129+
if err != nil {
130+
return "", err
131+
}
132+
return filepath.Join(home, path[1:]), nil
133+
}
134+
135+
wd, err := os.Getwd()
136+
if err != nil {
137+
return "", err
138+
}
139+
return filepath.Join(wd, path), nil
140+
}

pkg/remote/git.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"regexp"
2626
"strconv"
2727

28+
"github.com/docker/compose/v2/internal/paths"
29+
2830
"github.com/compose-spec/compose-go/v2/cli"
2931
"github.com/compose-spec/compose-go/v2/loader"
3032
"github.com/compose-spec/compose-go/v2/types"
@@ -45,16 +47,18 @@ func gitRemoteLoaderEnabled() (bool, error) {
4547
return false, nil
4648
}
4749

48-
func NewGitRemoteLoader(offline bool) loader.ResourceLoader {
50+
func NewGitRemoteLoader(offline bool, downloadDirectory string) loader.ResourceLoader {
4951
return gitRemoteLoader{
50-
offline: offline,
51-
known: map[string]string{},
52+
offline: offline,
53+
known: map[string]string{},
54+
downloadDirectory: downloadDirectory,
5255
}
5356
}
5457

5558
type gitRemoteLoader struct {
56-
offline bool
57-
known map[string]string
59+
offline bool
60+
known map[string]string
61+
downloadDirectory string
5862
}
5963

6064
func (g gitRemoteLoader) Accept(path string) bool {
@@ -89,12 +93,20 @@ func (g gitRemoteLoader) Load(ctx context.Context, path string) (string, error)
8993
return "", err
9094
}
9195

92-
cache, err := cacheDir()
93-
if err != nil {
94-
return "", fmt.Errorf("initializing remote resource cache: %w", err)
96+
if local == "" {
97+
cache, err := cacheDir()
98+
if err != nil {
99+
return "", fmt.Errorf("initializing remote resource cache: %w", err)
100+
}
101+
local = cache
102+
} else {
103+
local, err = paths.GetAbsPath(g.downloadDirectory)
104+
if err != nil {
105+
return "", err
106+
}
95107
}
96108

97-
local = filepath.Join(cache, ref.Commit)
109+
local = filepath.Join(local, ref.Commit)
98110
if _, err := os.Stat(local); os.IsNotExist(err) {
99111
if g.offline {
100112
return "", nil

pkg/remote/oci.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/docker/buildx/util/imagetools"
3232
"github.com/docker/cli/cli/command"
3333
"github.com/docker/compose/v2/internal/ocipush"
34+
"github.com/docker/compose/v2/internal/paths"
3435
v1 "github.com/opencontainers/image-spec/specs-go/v1"
3536
)
3637

@@ -47,18 +48,20 @@ func ociRemoteLoaderEnabled() (bool, error) {
4748
return false, nil
4849
}
4950

50-
func NewOCIRemoteLoader(dockerCli command.Cli, offline bool) loader.ResourceLoader {
51+
func NewOCIRemoteLoader(dockerCli command.Cli, offline bool, downloadDirectory string) loader.ResourceLoader {
5152
return ociRemoteLoader{
52-
dockerCli: dockerCli,
53-
offline: offline,
54-
known: map[string]string{},
53+
dockerCli: dockerCli,
54+
offline: offline,
55+
downloadDirectory: downloadDirectory,
56+
known: map[string]string{},
5557
}
5658
}
5759

5860
type ociRemoteLoader struct {
59-
dockerCli command.Cli
60-
offline bool
61-
known map[string]string
61+
dockerCli command.Cli
62+
offline bool
63+
known map[string]string
64+
downloadDirectory string
6265
}
6366

6467
const prefix = "oci://"
@@ -98,12 +101,19 @@ func (g ociRemoteLoader) Load(ctx context.Context, path string) (string, error)
98101
return "", err
99102
}
100103

101-
cache, err := cacheDir()
102-
if err != nil {
103-
return "", fmt.Errorf("initializing remote resource cache: %w", err)
104+
if local == "" {
105+
cache, err := cacheDir()
106+
if err != nil {
107+
return "", fmt.Errorf("initializing remote resource cache: %w", err)
108+
}
109+
local = filepath.Join(cache, descriptor.Digest.Hex())
110+
} else {
111+
local, err = paths.GetAbsPath(g.downloadDirectory)
112+
if err != nil {
113+
return "", err
114+
}
104115
}
105116

106-
local = filepath.Join(cache, descriptor.Digest.Hex())
107117
composeFile := filepath.Join(local, "compose.yaml")
108118
if _, err = os.Stat(local); os.IsNotExist(err) {
109119
var manifest v1.Manifest

0 commit comments

Comments
 (0)