66 "encoding/json"
77 "errors"
88 "fmt"
9+ "io/ioutil"
910 "os"
11+ "path/filepath"
1012 "strconv"
1113 "strings"
1214
@@ -34,14 +36,15 @@ type buildOptions struct {
3436 progress string
3537 pull bool
3638 tag string
39+ folder string
3740}
3841
3942func Cmd (dockerCli command.Cli ) * cobra.Command {
4043 var opts buildOptions
4144 cmd := & cobra.Command {
42- Use : "build [APP_NAME ] [OPTIONS ]" ,
45+ Use : "build [OPTIONS ] [CONTEXT_PATH ]" ,
4346 Short : "Build service images for the application" ,
44- Example : `$ docker app build myapp.dockerapp --tag my/app:1.0.0` ,
47+ Example : `$ docker app build --tag my/app:1.0.0 . ` ,
4548 Args : cli .ExactArgs (1 ),
4649 RunE : func (cmd * cobra.Command , args []string ) error {
4750 ref , err := runBuild (dockerCli , args [0 ], opts )
@@ -56,12 +59,13 @@ func Cmd(dockerCli command.Cli) *cobra.Command {
5659 flags .BoolVar (& opts .noCache , "no-cache" , false , "Do not use cache when building the image" )
5760 flags .StringVar (& opts .progress , "progress" , "auto" , "Set type of progress output (auto, plain, tty). Use plain to show container output" )
5861 flags .StringVarP (& opts .tag , "tag" , "t" , "" , "Application image and optionally a tag in the 'image:tag' format" )
62+ flags .StringVarP (& opts .folder , "folder" , "f" , "" , "Docker app folder containing application definition" )
5963 flags .BoolVar (& opts .pull , "pull" , false , "Always attempt to pull a newer version of the image" )
6064
6165 return cmd
6266}
6367
64- func runBuild (dockerCli command.Cli , application string , opt buildOptions ) (reference.Reference , error ) {
68+ func runBuild (dockerCli command.Cli , contextPath string , opt buildOptions ) (reference.Reference , error ) {
6569 err := checkMinimalEngineVersion (dockerCli )
6670 if err != nil {
6771 return nil , err
@@ -73,13 +77,18 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
7377 return nil , err
7478 }
7579
80+ application , err := getAppFolder (opt , contextPath )
81+ if err != nil {
82+ return nil , err
83+ }
84+
7685 app , err := packager .Extract (application )
7786 if err != nil {
7887 return nil , err
7988 }
8089 defer app .Cleanup ()
8190
82- buildopts , err := parseCompose (app , opt )
91+ buildopts , err := parseCompose (app , contextPath , opt )
8392 if err != nil {
8493 return nil , err
8594 }
@@ -126,6 +135,28 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
126135 return packager .PersistInBundleStore (ref , bundle )
127136}
128137
138+ func getAppFolder (opt buildOptions , contextPath string ) (string , error ) {
139+ application := opt .folder
140+ if application == "" {
141+ files , err := ioutil .ReadDir (contextPath )
142+ if err != nil {
143+ return "" , err
144+ }
145+ for _ , f := range files {
146+ if strings .HasSuffix (f .Name (), ".dockerapp" ) {
147+ if application != "" {
148+ return "" , fmt .Errorf ("%s contains multiple *.dockerapp folders, use -f option to select the one to build" , contextPath )
149+ }
150+ application = filepath .Join (contextPath , f .Name ())
151+ if ! f .IsDir () {
152+ return "" , fmt .Errorf ("%s isn't a directory" , f .Name ())
153+ }
154+ }
155+ }
156+ }
157+ return application , nil
158+ }
159+
129160func checkMinimalEngineVersion (dockerCli command.Cli ) error {
130161 info , err := dockerCli .Client ().Info (appcontext .Context ())
131162 if err != nil {
0 commit comments