diff --git a/util/buildflags/output.go b/util/buildflags/output.go index 0382d8f1..fa1adfaa 100644 --- a/util/buildflags/output.go +++ b/util/buildflags/output.go @@ -4,6 +4,7 @@ import ( "encoding/csv" "io" "os" + "strconv" "strings" "github.com/containerd/console" @@ -62,25 +63,52 @@ func ParseOutputs(inp []string) ([]client.ExportEntry, error) { return nil, errors.Errorf("type is required for output") } - // handle client side + supportFile := false + supportDir := false switch out.Type { case client.ExporterLocal: - dest, ok := out.Attrs["dest"] + supportDir = true + case client.ExporterTar: + supportFile = true + case client.ExporterOCI, client.ExporterDocker: + tar, err := strconv.ParseBool(out.Attrs["tar"]) + if err != nil { + tar = true + } + supportFile = tar + supportDir = !tar + case "registry": + out.Type = client.ExporterImage + if _, ok := out.Attrs["push"]; !ok { + out.Attrs["push"] = "true" + } + } + + dest, ok := out.Attrs["dest"] + if supportDir { if !ok { - return nil, errors.Errorf("dest is required for local output") + return nil, errors.Errorf("dest is required for %s exporter", out.Type) + } + if dest == "-" { + return nil, errors.Errorf("dest cannot be stdout for %s exporter", out.Type) + } + + fi, err := os.Stat(dest) + if err != nil && !os.IsNotExist(err) { + return nil, errors.Wrapf(err, "invalid destination directory: %s", dest) + } + if err == nil && !fi.IsDir() { + return nil, errors.Errorf("destination directory %s is a file", dest) } out.OutputDir = dest - delete(out.Attrs, "dest") - case client.ExporterOCI, client.ExporterDocker, client.ExporterTar: - dest, ok := out.Attrs["dest"] - if !ok { - if out.Type != client.ExporterDocker { - dest = "-" - } + } + if supportFile { + if !ok && out.Type != client.ExporterDocker { + dest = "-" } if dest == "-" { if _, err := console.ConsoleFromFile(os.Stdout); err == nil { - return nil, errors.Errorf("output file is required for %s exporter. refusing to write to console", out.Type) + return nil, errors.Errorf("dest file is required for %s exporter. refusing to write to console", out.Type) } out.Output = wrapWriteCloser(os.Stdout) } else if dest != "" { @@ -97,12 +125,9 @@ func ParseOutputs(inp []string) ([]client.ExportEntry, error) { } out.Output = wrapWriteCloser(f) } + } + if supportFile || supportDir { delete(out.Attrs, "dest") - case "registry": - out.Type = client.ExporterImage - if _, ok := out.Attrs["push"]; !ok { - out.Attrs["push"] = "true" - } } outs = append(outs, out)