Skip to content
This repository has been archived by the owner on May 3, 2022. It is now read-only.

Commit

Permalink
ref(cmd/duffle): export using bundle ref or file
Browse files Browse the repository at this point in the history
duffle export takes one arg, the bundle. By default, the
bundle reference passed in is used to find the bundle file
from local storage. One can use the --source-is-file flag
to override this and pass in a filepath for the bundlefile
as the arg instead.

resolves #582
  • Loading branch information
Michelle Noorali committed Feb 12, 2019
1 parent eaa7595 commit 8251f0f
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 53 deletions.
90 changes: 53 additions & 37 deletions cmd/duffle/export.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"errors"
"fmt"
"io"

Expand All @@ -13,29 +12,34 @@ import (
)

const exportDesc = `
Packages a bundle, invocation images, and all referenced images within a single
gzipped tarfile.
All images specified in the bundle metadata are saved as tar files in the artifacts/
directory along with an artifacts.json file which describes the contents of artifacts/.
By default, this command will use the name and version information of the bundle to create
a compressed archive file called <name>-<version>.tgz in the current directory. This
destination can be updated by specifying a file path to save the compressed bundle to using
Packages a bundle, invocation images, and all referenced images within
a single gzipped tarfile. All images specified in the bundle metadata
are saved as tar files in the artifacts/ directory along with an
artifacts.json file which describes the contents of artifacts/ directory.
By default, this command will use the name and version information of
the bundle to create a compressed archive file called
<name>-<version>.tgz in the current directory. This destination can be
updated by specifying a file path to save the compressed bundle to using
the --output-file flag.
If you want to export only the bundle manifest without the invocation images and referenced
images, use the --thin flag.
Use the --thin flag to export the bundle manifest without the invocation
images and referenced images.
Pass in a path to a bundle file instead of a bundle in local storage by
using the --source-is-file flag like below:
$ duffle export [PATH] --source-is-file
`

type exportCmd struct {
bundleRef string
dest string
home home.Home
out io.Writer
thin bool
verbose bool
insecure bool
bundle string
dest string
home home.Home
out io.Writer
thin bool
verbose bool
insecure bool
sourceIsFile bool
}

func newExportCmd(w io.Writer) *cobra.Command {
Expand All @@ -45,19 +49,18 @@ func newExportCmd(w io.Writer) *cobra.Command {
Use: "export [BUNDLE]",
Short: "package CNAB bundle in gzipped tar file",
Long: exportDesc,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("this command requires an argument: a bundle")
}
export.home = home.Home(homePath())
export.bundleRef = args[0]
export.bundle = args[0]

return export.run()
},
}

f := cmd.Flags()
f.StringVarP(&export.dest, "output-file", "o", "", "Save exported bundle to file path")
f.BoolVarP(&export.sourceIsFile, "source-is-file", "s", false, "Indicates that the bundle source is a file path")
f.BoolVarP(&export.thin, "thin", "t", false, "Export only the bundle manifest")
f.BoolVarP(&export.verbose, "verbose", "v", false, "Verbose output")
f.BoolVarP(&export.insecure, "insecure", "k", false, "Do not verify the bundle (INSECURE)")
Expand All @@ -66,19 +69,33 @@ func newExportCmd(w io.Writer) *cobra.Command {
}

func (ex *exportCmd) run() error {
source, l, err := ex.setup()
bundlefile, l, err := ex.setup()
if err != nil {
return err
}
if ex.Export(source, l); err != nil {
if err := ex.Export(bundlefile, l); err != nil {
return err
}

return nil
}

func (ex *exportCmd) Export(bundlefile string, l loader.Loader) error {
exp, err := packager.NewExporter(bundlefile, ex.dest, ex.home.Logs(), l, ex.thin, ex.insecure)
if err != nil {
return fmt.Errorf("Unable to set up exporter: %s", err)
}
if err := exp.Export(); err != nil {
return err
}
if ex.verbose {
fmt.Fprintf(ex.out, "Export logs: %s\n", exp.Logs)
}
return nil
}

func (ex *exportCmd) setup() (string, loader.Loader, error) {
source, err := getBundleFilepath(ex.bundleRef, ex.home.String(), ex.insecure)
bundlefile, err := resolveBundleFilePath(ex.bundle, ex.home.String(), ex.sourceIsFile, ex.insecure)
if err != nil {
return "", nil, err
}
Expand All @@ -88,19 +105,18 @@ func (ex *exportCmd) setup() (string, loader.Loader, error) {
return "", nil, err
}

return source, l, nil
return bundlefile, l, nil
}

func (ex *exportCmd) Export(source string, l loader.Loader) error {
exp, err := packager.NewExporter(source, ex.dest, ex.home.Logs(), l, ex.thin, ex.insecure)
if err != nil {
return fmt.Errorf("Unable to set up exporter: %s", err)
}
if err := exp.Export(); err != nil {
return err
func resolveBundleFilePath(bun, homePath string, sourceIsFile, insecure bool) (string, error) {

if sourceIsFile {
return bun, nil
}
if ex.verbose {
fmt.Fprintf(ex.out, "Export logs: %s\n", exp.Logs)

bundlefile, err := getBundleFilepath(bun, homePath, insecure)
if err != nil {
return "", err
}
return nil
return bundlefile, err
}
34 changes: 25 additions & 9 deletions cmd/duffle/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ func TestExportSetup(t *testing.T) {

duffleHome := home.Home(tempDuffleHome)
exp := &exportCmd{
bundleRef: "foo:1.0.0",
dest: tempDir,
home: duffleHome,
out: out,
bundle: "foo:1.0.0",
dest: tempDir,
home: duffleHome,
out: out,
}

source, _, err := exp.setup()
if err != nil {
t.Fatal(err)
t.Errorf("Did not expect error but got %s", err)
}

expectedSource := filepath.Join(tempDuffleHome, "bundles", "foo-1.0.0.cnab")
Expand All @@ -70,16 +70,32 @@ func TestExportSetup(t *testing.T) {
}

expFail := &exportCmd{
bundleRef: "bar:1.0.0",
dest: tempDir,
home: duffleHome,
out: out,
bundle: "bar:1.0.0",
dest: tempDir,
home: duffleHome,
out: out,
}
_, _, err = expFail.setup()
if err == nil {
t.Error("Expected error, got none")
}

bundlepath := filepath.Join("..", "..", "tests", "testdata", "bundles", "foo.json")
expFile := &exportCmd{
bundle: bundlepath,
dest: tempDir,
home: duffleHome,
out: out,
sourceIsFile: true,
}
source, _, err = expFile.setup()
if err != nil {
t.Errorf("Did not expect error but got %s", err)
}

if source != bundlepath {
t.Errorf("Expected bundle file path to be %s, got %s", bundlepath, source)
}
}

func copyFile(src, dst string) (err error) {
Expand Down
9 changes: 2 additions & 7 deletions pkg/packager/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package packager

import (
"context"
"errors"
"fmt"
"io"
"os"
Expand All @@ -18,10 +17,6 @@ import (
"github.com/deislabs/duffle/pkg/loader"
)

var (
ErrDestinationNotDirectory = errors.New("Destination not directory")
)

type Exporter struct {
Source string
Destination string
Expand Down Expand Up @@ -77,8 +72,8 @@ func (ex *Exporter) Export() error {
defer logsf.Close()

fi, err := os.Stat(ex.Source)
if err != nil && os.IsNotExist(err) {
return fmt.Errorf("Bundle manifest not found at %s", ex.Source)
if os.IsNotExist(err) {
return err
}
if fi.IsDir() {
return fmt.Errorf("Bundle manifest %s is a directory, should be a file", ex.Source)
Expand Down

0 comments on commit 8251f0f

Please sign in to comment.