4
4
"context"
5
5
"fmt"
6
6
"github.com/compose-spec/compose-go/cli"
7
+ "github.com/compose-spec/compose-go/loader"
7
8
"github.com/compose-spec/compose-go/types"
8
9
"github.com/docker/cli/cli/command"
9
10
"github.com/docker/cli/cli/flags"
@@ -14,6 +15,7 @@ import (
14
15
"os"
15
16
"os/signal"
16
17
"path/filepath"
18
+ "regexp"
17
19
"sort"
18
20
"strings"
19
21
"syscall"
@@ -34,7 +36,7 @@ var options = []string{
34
36
func main () {
35
37
normalizeEnvironment ()
36
38
37
- dockerizedOptions , commandName , commandArgs := parseArguments ()
39
+ dockerizedOptions , commandName , commandVersion , commandArgs := parseArguments ()
38
40
39
41
var optionHelp = contains (dockerizedOptions , "--help" ) || contains (dockerizedOptions , "-h" )
40
42
var optionVerbose = contains (dockerizedOptions , "--verbose" ) || contains (dockerizedOptions , "-v" )
@@ -76,7 +78,55 @@ func main() {
76
78
panic (err )
77
79
}
78
80
79
- project , err := getProject (dockerizedDockerComposeFilePath )
81
+ if commandVersion != "" {
82
+ rawProject , err := getRawProject (dockerizedDockerComposeFilePath )
83
+ if err != nil {
84
+ panic (err )
85
+ }
86
+
87
+ rawService , err := rawProject .GetService (commandName )
88
+
89
+ var versionVariableExpected = strings .ReplaceAll (strings .ToUpper (commandName ), "-" , "_" ) + "_VERSION"
90
+ var versionVariablesUsed []string
91
+ for _ , variable := range ExtractVariables (rawService ) {
92
+ if strings .HasSuffix (variable , "_VERSION" ) {
93
+ versionVariablesUsed = append (versionVariablesUsed , variable )
94
+ }
95
+ }
96
+
97
+ if len (versionVariablesUsed ) == 0 {
98
+ fmt .Printf ("Error: Version selection for %s is currently not supported.\n " , commandName )
99
+ os .Exit (1 )
100
+ }
101
+
102
+ versionKey := versionVariableExpected
103
+
104
+ if ! contains (versionVariablesUsed , versionVariableExpected ) {
105
+ if len (versionVariablesUsed ) == 1 {
106
+ fmt .Printf ("Error: To specify the version of %s, please set %s.\n " ,
107
+ commandName ,
108
+ versionVariablesUsed [0 ],
109
+ )
110
+ os .Exit (1 )
111
+ } else if len (versionVariablesUsed ) > 1 {
112
+ fmt .Println ("Multiple version variables found:" )
113
+ for _ , variable := range versionVariablesUsed {
114
+ fmt .Println (" " + variable )
115
+ }
116
+ os .Exit (1 )
117
+ }
118
+ }
119
+
120
+ if optionVerbose {
121
+ fmt .Printf ("Setting %s to %s...\n " , versionKey , commandVersion )
122
+ }
123
+ err = os .Setenv (versionKey , commandVersion )
124
+ if err != nil {
125
+ panic (err )
126
+ }
127
+ }
128
+
129
+ project , err := getProject (dockerizedDockerComposeFilePath , true )
80
130
if err != nil {
81
131
panic (err )
82
132
}
@@ -302,7 +352,26 @@ func newSigContext() (context.Context, func()) {
302
352
return ctx , cancel
303
353
}
304
354
305
- func getProject (dockerComposeFilePath string ) (* types.Project , error ) {
355
+ func getRawProject (dockerComposeFilePath string ) (* types.Project , error ) {
356
+ options , err := cli .NewProjectOptions ([]string {
357
+ dockerComposeFilePath ,
358
+ },
359
+ cli .WithInterpolation (false ),
360
+ cli .WithLoadOptions (func (l * loader.Options ) {
361
+ l .SkipValidation = true
362
+ l .SkipConsistencyCheck = true
363
+ l .SkipNormalization = true
364
+ }),
365
+ )
366
+
367
+ if err != nil {
368
+ return nil , nil
369
+ }
370
+
371
+ return cli .ProjectFromOptions (options )
372
+ }
373
+
374
+ func getProject (dockerComposeFilePath string , interpolation bool ) (* types.Project , error ) {
306
375
options , err := cli .NewProjectOptions ([]string {
307
376
dockerComposeFilePath ,
308
377
},
@@ -363,7 +432,7 @@ func getBackend() (*api.ServiceProxy, error) {
363
432
}
364
433
365
434
func dockerComposeBuild (dockerComposeFilePath string , buildOptions api.BuildOptions ) error {
366
- project , err := getProject (dockerComposeFilePath )
435
+ project , err := getProject (dockerComposeFilePath , true )
367
436
if err != nil {
368
437
return err
369
438
}
@@ -422,12 +491,17 @@ func dockerComposeRun(project *types.Project, runOptions api.RunOptions, volumes
422
491
}
423
492
424
493
func help (dockerComposeFilePath string ) error {
425
- project , err := getProject (dockerComposeFilePath )
494
+ project , err := getProject (dockerComposeFilePath , false )
426
495
if err != nil {
427
496
return err
428
497
}
429
498
430
- fmt .Println ("Usage: dockerized [options] <command> [arguments]" )
499
+ fmt .Println ("Usage: dockerized [options] <command>[:version] [arguments]" )
500
+ fmt .Println ("" )
501
+ fmt .Println ("Examples:" )
502
+ fmt .Println (" dockerized go" )
503
+ fmt .Println (" dockerized go:1.8 build" )
504
+ fmt .Println (" dockerized --shell go" )
431
505
fmt .Println ("" )
432
506
fmt .Println ("Commands:" )
433
507
@@ -455,10 +529,11 @@ func help(dockerComposeFilePath string) error {
455
529
return nil
456
530
}
457
531
458
- func parseArguments () ([]string , string , []string ) {
532
+ func parseArguments () ([]string , string , string , []string ) {
459
533
commandName := ""
460
534
var commandArgs []string
461
535
var dockerizedOptions []string
536
+ var commandVersion string
462
537
for _ , arg := range os .Args [1 :] {
463
538
if arg [0 ] == '-' && commandName == "" {
464
539
if contains (options , arg ) {
@@ -475,5 +550,44 @@ func parseArguments() ([]string, string, []string) {
475
550
}
476
551
}
477
552
}
478
- return dockerizedOptions , commandName , commandArgs
553
+ if strings .ContainsRune (commandName , ':' ) {
554
+ commandSplit := strings .Split (commandName , ":" )
555
+ commandName = commandSplit [0 ]
556
+ commandVersion = commandSplit [1 ]
557
+ }
558
+ return dockerizedOptions , commandName , commandVersion , commandArgs
559
+ }
560
+
561
+ func unique (s []string ) []string {
562
+ keys := make (map [string ]bool )
563
+ var list []string
564
+ for _ , entry := range s {
565
+ if _ , value := keys [entry ]; ! value {
566
+ keys [entry ] = true
567
+ list = append (list , entry )
568
+ }
569
+ }
570
+ return list
571
+ }
572
+
573
+ func ExtractVariables (rawService types.ServiceConfig ) []string {
574
+ var usedVariables []string
575
+ for envKey := range rawService .Environment {
576
+ usedVariables = append (usedVariables , envKey )
577
+ }
578
+ if rawService .Build != nil {
579
+ for argKey := range rawService .Build .Args {
580
+ usedVariables = append (usedVariables , argKey )
581
+ }
582
+ }
583
+
584
+ pattern := regexp .MustCompile (`\$\{([^}]+)\}` )
585
+ for _ , match := range pattern .FindAllStringSubmatch (rawService .Image , - 1 ) {
586
+ usedVariables = append (usedVariables , match [1 ])
587
+ }
588
+
589
+ usedVariables = unique (usedVariables )
590
+ sort .Strings (usedVariables )
591
+
592
+ return usedVariables
479
593
}
0 commit comments