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  }