github.com/simonferquel/app@v0.6.1-0.20181012141724-68b7cccf26ac/cmd/docker-app/merge.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "os" 8 "strings" 9 10 "github.com/docker/app/internal" 11 "github.com/docker/app/internal/packager" 12 "github.com/docker/app/types" 13 "github.com/docker/cli/cli" 14 "github.com/docker/cli/cli/command" 15 "github.com/pkg/errors" 16 "github.com/spf13/cobra" 17 ) 18 19 var mergeOutputFile string 20 21 // Check appname directory for extra files and return them 22 func extraFiles(appname string) ([]string, error) { 23 files, err := ioutil.ReadDir(appname) 24 if err != nil { 25 return nil, err 26 } 27 var res []string 28 for _, f := range files { 29 hit := false 30 for _, afn := range internal.FileNames { 31 if afn == f.Name() { 32 hit = true 33 break 34 } 35 } 36 if !hit { 37 res = append(res, f.Name()) 38 } 39 } 40 return res, nil 41 } 42 43 //handleInPlace returns the operation target path and if it's in-place 44 func handleInPlace(app *types.App) (string, bool) { 45 if app.Source == types.AppSourceURL || app.Source == types.AppSourceImage { 46 return internal.DirNameFromAppName(app.Name), false 47 } 48 return app.Path + ".tmp", true 49 } 50 51 // removeAndRename removes target and rename source into target 52 func removeAndRename(source, target string) error { 53 if err := os.RemoveAll(target); err != nil { 54 return errors.Wrap(err, "failed to erase previous application") 55 } 56 if err := os.Rename(source, target); err != nil { 57 return errors.Wrap(err, "failed to rename new application") 58 } 59 return nil 60 } 61 62 func mergeCmd(dockerCli command.Cli) *cobra.Command { 63 cmd := &cobra.Command{ 64 Use: "merge [<app-name>] [-o output_file]", 65 Short: "Merge a multi-file application into a single file", 66 Args: cli.RequiresMaxArgs(1), 67 RunE: func(cmd *cobra.Command, args []string) error { 68 extractedApp, err := packager.Extract(firstOrEmpty(args)) 69 if err != nil { 70 return err 71 } 72 defer extractedApp.Cleanup() 73 inPlace := false 74 if mergeOutputFile == "" { 75 mergeOutputFile, inPlace = handleInPlace(extractedApp) 76 } 77 if inPlace { 78 extra, err := extraFiles(extractedApp.Path) 79 if err != nil { 80 return errors.Wrap(err, "error scanning application directory") 81 } 82 if len(extra) != 0 { 83 return fmt.Errorf("refusing to overwrite %s: extra files would be deleted: %s", extractedApp.Path, strings.Join(extra, ",")) 84 } 85 } 86 var target io.Writer 87 if mergeOutputFile == "-" { 88 target = dockerCli.Out() 89 } else { 90 target, err = os.Create(mergeOutputFile) 91 if err != nil { 92 return err 93 } 94 } 95 if err := packager.Merge(extractedApp, target); err != nil { 96 return err 97 } 98 if mergeOutputFile != "-" { 99 // Need to close for the Rename to work on windows. 100 target.(io.WriteCloser).Close() 101 } 102 if inPlace { 103 return removeAndRename(mergeOutputFile, extractedApp.Path) 104 } 105 return nil 106 }, 107 } 108 cmd.Flags().StringVarP(&mergeOutputFile, "output", "o", "", "Output file (default: in-place)") 109 return cmd 110 }