Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 6d16347

Browse files
Merge pull request #391 from mnottale/split-merge-fix
split/merge: Fix loading from image/URL with an empty target.
2 parents 0ec4226 + fe3ee65 commit 6d16347

4 files changed

Lines changed: 59 additions & 20 deletions

File tree

cmd/docker-app/merge.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/docker/app/internal"
1111
"github.com/docker/app/internal/packager"
12+
"github.com/docker/app/types"
1213
"github.com/docker/cli/cli"
1314
"github.com/docker/cli/cli/command"
1415
"github.com/pkg/errors"
@@ -39,6 +40,25 @@ func extraFiles(appname string) ([]string, error) {
3940
return res, nil
4041
}
4142

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+
4262
func mergeCmd(dockerCli command.Cli) *cobra.Command {
4363
cmd := &cobra.Command{
4464
Use: "merge [<app-name>] [-o output_file]",
@@ -50,7 +70,10 @@ func mergeCmd(dockerCli command.Cli) *cobra.Command {
5070
return err
5171
}
5272
defer extractedApp.Cleanup()
53-
inPlace := mergeOutputFile == ""
73+
inPlace := false
74+
if mergeOutputFile == "" {
75+
mergeOutputFile, inPlace = handleInPlace(extractedApp)
76+
}
5477
if inPlace {
5578
extra, err := extraFiles(extractedApp.Path)
5679
if err != nil {
@@ -59,7 +82,6 @@ func mergeCmd(dockerCli command.Cli) *cobra.Command {
5982
if len(extra) != 0 {
6083
return fmt.Errorf("refusing to overwrite %s: extra files would be deleted: %s", extractedApp.Path, strings.Join(extra, ","))
6184
}
62-
mergeOutputFile = extractedApp.Path + ".tmp"
6385
}
6486
var target io.Writer
6587
if mergeOutputFile == "-" {
@@ -78,12 +100,7 @@ func mergeCmd(dockerCli command.Cli) *cobra.Command {
78100
target.(io.WriteCloser).Close()
79101
}
80102
if inPlace {
81-
if err := os.RemoveAll(extractedApp.Path); err != nil {
82-
return errors.Wrap(err, "failed to erase previous application")
83-
}
84-
if err := os.Rename(mergeOutputFile, extractedApp.Path); err != nil {
85-
return errors.Wrap(err, "failed to rename new application")
86-
}
103+
return removeAndRename(mergeOutputFile, extractedApp.Path)
87104
}
88105
return nil
89106
},

cmd/docker-app/split.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
package main
22

33
import (
4-
"os"
5-
64
"github.com/docker/app/internal/packager"
75
"github.com/docker/cli/cli"
8-
"github.com/pkg/errors"
96
"github.com/spf13/cobra"
107
)
118

@@ -22,20 +19,15 @@ func splitCmd() *cobra.Command {
2219
return err
2320
}
2421
defer extractedApp.Cleanup()
25-
inPlace := splitOutputDir == ""
26-
if inPlace {
27-
splitOutputDir = extractedApp.Path + ".tmp"
22+
inPlace := false
23+
if splitOutputDir == "" {
24+
splitOutputDir, inPlace = handleInPlace(extractedApp)
2825
}
2926
if err := packager.Split(extractedApp, splitOutputDir); err != nil {
3027
return err
3128
}
3229
if inPlace {
33-
if err := os.RemoveAll(extractedApp.Path); err != nil {
34-
return errors.Wrap(err, "failed to erase previous application directory")
35-
}
36-
if err := os.Rename(splitOutputDir, extractedApp.Path); err != nil {
37-
return errors.Wrap(err, "failed to rename new application directory")
38-
}
30+
return removeAndRename(splitOutputDir, extractedApp.Path)
3931
}
4032
return nil
4133
},

internal/packager/extract.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,18 @@ func Extract(name string, ops ...func(*types.App) error) (*types.App, error) {
113113
// URL or docker image
114114
u, err := url.Parse(name)
115115
if err == nil && (u.Scheme == "http" || u.Scheme == "https") {
116+
ops = append(ops, types.WithSource(types.AppSourceURL))
116117
return loader.LoadFromURL(name, ops...)
117118
}
118119
// look for a docker image
120+
ops = append(ops, types.WithSource(types.AppSourceImage))
119121
return extractImage(name, ops...)
120122
}
121123
if s.IsDir() {
122124
// directory: already decompressed
123125
appOpts := append(ops,
124126
types.WithPath(appname),
127+
types.WithSource(types.AppSourceSplit),
125128
)
126129
return loader.LoadFromDirectory(appname, appOpts...)
127130
}
@@ -133,7 +136,9 @@ func Extract(name string, ops ...func(*types.App) error) (*types.App, error) {
133136
return nil, err
134137
}
135138
defer f.Close()
139+
ops = append(ops, types.WithSource(types.AppSourceMerged))
136140
return loader.LoadFromSingleFile(appname, f, ops...)
137141
}
142+
app.Source = types.AppSourceArchive
138143
return app, nil
139144
}

types/types.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,28 @@ import (
1616
// SingleFileSeparator is the separator used in single-file app
1717
const SingleFileSeparator = "\n---\n"
1818

19+
// AppSourceKind represents what format the app was in when read
20+
type AppSourceKind int
21+
22+
const (
23+
// AppSourceSplit represents an Application in multiple file format
24+
AppSourceSplit AppSourceKind = iota
25+
// AppSourceMerged represents an Application in single file format
26+
AppSourceMerged
27+
// AppSourceImage represents an Application pulled from an image
28+
AppSourceImage
29+
// AppSourceURL represents an Application fetched from an URL
30+
AppSourceURL
31+
// AppSourceArchive represents an Application in an archive format
32+
AppSourceArchive
33+
)
34+
1935
// App represents an app
2036
type App struct {
2137
Name string
2238
Path string
2339
Cleanup func()
40+
Source AppSourceKind
2441

2542
composesContent [][]byte
2643
settingsContent [][]byte
@@ -149,6 +166,14 @@ func WithCleanup(f func()) func(*App) error {
149166
}
150167
}
151168

169+
// WithSource sets the source of the app
170+
func WithSource(source AppSourceKind) func(*App) error {
171+
return func(app *App) error {
172+
app.Source = source
173+
return nil
174+
}
175+
}
176+
152177
// WithSettingsFiles adds the specified settings files to the app
153178
func WithSettingsFiles(files ...string) func(*App) error {
154179
return settingsLoader(func() ([][]byte, error) { return readFiles(files...) })

0 commit comments

Comments
 (0)