Beispiel #1
0
// cmdImport implements IMPORT command
// TODO: document behavior of cmdImport
func (builder *Builder) cmdImport(args []string, attributes map[string]bool, flags map[string]string, original string) (err error) {
	if len(args) == 0 {
		return fmt.Errorf("Command is missing value: %s", original)
	}
	if builder.lastExportImageID == "" {
		return fmt.Errorf("You have to EXPORT something first in order to: %s", original)
	}
	if builder.exportsContainerID == "" {
		return fmt.Errorf("Something went wrong, missing exports container: %s", original)
	}
	// If only one argument was given to IMPORT, use the same path for destination
	// IMPORT /my/dir/file.tar --> ADD ./EXPORT_VOLUME/my/dir/file.tar /my/dir/file.tar
	if len(args) < 2 {
		args = []string{args[0], "/"}
	}
	dest := args[len(args)-1] // last one is always the dest

	// prepare builder mount
	builder.addMount(builderMount{
		dest:        exportsVolume,
		containerID: builder.exportsContainerID,
	})
	defer builder.removeLastMount()

	// TODO: rsync doesn't work as expected if ENTRYPOINT is inherited by parent image
	//       STILL RELEVANT?

	cmd := []string{"/opt/rsync/bin/rsync", "-a"}
	for _, arg := range args[0 : len(args)-1] {
		argResolved, err := util.ResolvePath(exportsVolume, arg)
		if err != nil {
			return fmt.Errorf("Invalid IMPORT source: %s", arg)
		}
		cmd = append(cmd, argResolved)
	}
	cmd = append(cmd, dest)

	// For caching
	builder.addLabels(map[string]string{
		"rocker-lastExportImageId": builder.lastExportImageID,
	})

	// Configure container temporarily, only for this execution
	resetFunc := builder.temporaryConfig(func() {
		builder.Config.Entrypoint = []string{}
	})
	defer resetFunc()

	fmt.Fprintf(builder.OutStream, "[Rocker]  run: %s\n", strings.Join(cmd, " "))

	return builder.runAndCommit(cmd, "import")
}
Beispiel #2
0
// Execute runs the command
func (c *CommandImport) Execute(b *Build) (s State, err error) {
	s = b.state
	args := c.cfg.args

	if len(args) == 0 {
		return s, fmt.Errorf("IMPORT requires at least one argument")
	}
	if len(b.exports) == 0 {
		return s, fmt.Errorf("You have to EXPORT something first in order to IMPORT")
	}

	// TODO: EXPORT and IMPORT cache is not invalidated properly in between
	// 			 different tracks of the same build. The EXPORT may be cached
	// 			 because it was built earlier with the same prerequisites, but the actual
	// 			 data in the exports container may be from the latest EXPORT of different
	// 			 build. So we need to prefix ~/.rocker_exports dir with some id somehow.

	exportsContainer, err := b.getExportsContainer()
	if err != nil {
		return s, err
	}

	log.Infof("| Import from %s (%.12s)", b.exportsContainerName(), exportsContainer.ID)

	// If only one argument was given to IMPORT, use the same path for destination
	// IMPORT /my/dir/file.tar --> ADD ./EXPORT_VOLUME/my/dir/file.tar /my/dir/file.tar
	if len(args) < 2 {
		args = []string{args[0], "/"}
	}
	dest := args[len(args)-1] // last one is always the dest
	src := []string{}

	for _, arg := range args[0 : len(args)-1] {
		argResolved, err := util.ResolvePath(ExportsPath, arg)
		if err != nil {
			return s, fmt.Errorf("Invalid IMPORT source: %s", arg)
		}
		src = append(src, argResolved)
	}

	sort.Strings(b.exports)
	s.Commit("IMPORT %q : %q %s", b.exports, src, dest)

	// Check cache
	s, hit, err := b.probeCache(s)
	if err != nil {
		return s, err
	}
	if hit {
		return s, nil
	}

	// Remember original stuff so we can restore it when we finished
	origState := s

	var importID string

	defer func() {
		s = origState
		s.NoCache.ContainerID = importID
	}()

	cmd := []string{"/opt/rsync/bin/rsync", "-a"}

	if b.cfg.Verbose {
		cmd = append(cmd, "--verbose")
	}

	cmd = append(cmd, src...)
	cmd = append(cmd, dest)

	s.Config.Cmd = cmd
	s.Config.Entrypoint = []string{}

	// Append exports container as a volume
	s.NoCache.HostConfig.Binds = append(s.NoCache.HostConfig.Binds,
		mountsToBinds(exportsContainer.Mounts)...)

	if importID, err = b.client.CreateContainer(s); err != nil {
		return s, err
	}

	log.Infof("| Running in %.12s: %s", importID, strings.Join(cmd, " "))

	if err = b.client.RunContainer(importID, false); err != nil {
		return s, err
	}

	// TODO: if b.exportsCacheBusted and IMPORT cache was invalidated,
	// 			 CommitCommand then caches it anyway.

	return s, nil
}
Beispiel #3
0
// cmdExport implements EXPORT command
// TODO: document behavior of cmdExport
func (builder *Builder) cmdExport(args []string, attributes map[string]bool, flags map[string]string, original string) error {
	if len(args) == 0 {
		return fmt.Errorf("Command is missing value: %s", original)
	}
	// If only one argument was given to EXPORT, use basename of a file
	// EXPORT /my/dir/file.tar --> /EXPORT_VOLUME/file.tar
	if len(args) < 2 {
		args = []string{args[0], "/"}
	}

	dest := args[len(args)-1] // last one is always the dest

	// EXPORT /my/dir my_dir --> /EXPORT_VOLUME/my_dir
	// EXPORT /my/dir /my_dir --> /EXPORT_VOLUME/my_dir
	// EXPORT /my/dir stuff/ --> /EXPORT_VOLUME/stuff/my_dir
	// EXPORT /my/dir /stuff/ --> /EXPORT_VOLUME/stuff/my_dir
	// EXPORT /my/dir/* / --> /EXPORT_VOLUME/stuff/my_dir

	exportsContainerID, err := builder.makeExportsContainer()
	if err != nil {
		return err
	}

	// prepare builder mount
	builder.addMount(builderMount{
		dest:        exportsVolume,
		containerID: exportsContainerID,
	})
	defer builder.removeLastMount()

	cmdDestPath, err := util.ResolvePath(exportsVolume, dest)
	if err != nil {
		return fmt.Errorf("Invalid EXPORT destination: %s", dest)
	}

	// TODO: rsync doesn't work as expected if ENTRYPOINT is inherited by parent image
	//       STILL RELEVANT?

	// build the command
	cmd := []string{"/opt/rsync/bin/rsync", "-a", "--delete-during"}
	cmd = append(cmd, args[0:len(args)-1]...)
	cmd = append(cmd, cmdDestPath)

	// For caching
	builder.addLabels(map[string]string{
		"rocker-exportsContainerId": exportsContainerID,
	})

	// Configure container temporarily, only for this execution
	resetFunc := builder.temporaryConfig(func() {
		builder.Config.Entrypoint = []string{}
	})
	defer resetFunc()

	fmt.Fprintf(builder.OutStream, "[Rocker]  run: %s\n", strings.Join(cmd, " "))

	if err := builder.runAndCommit(cmd, "import"); err != nil {
		return err
	}

	builder.lastExportImageID = builder.imageID

	return nil
}
Beispiel #4
0
// Execute runs the command
func (c *CommandExport) Execute(b *Build) (s State, err error) {

	s = b.state
	args := c.cfg.args

	if len(args) == 0 {
		return s, fmt.Errorf("EXPORT requires at least one argument")
	}

	// If only one argument was given to EXPORT, use basename of a file
	// EXPORT /my/dir/file.tar --> /EXPORT_VOLUME/file.tar
	if len(args) < 2 {
		args = []string{args[0], "/"}
	}

	src := args[0 : len(args)-1]
	dest := args[len(args)-1] // last one is always the dest

	// EXPORT /my/dir my_dir --> /EXPORT_VOLUME/my_dir
	// EXPORT /my/dir /my_dir --> /EXPORT_VOLUME/my_dir
	// EXPORT /my/dir stuff/ --> /EXPORT_VOLUME/stuff/my_dir
	// EXPORT /my/dir /stuff/ --> /EXPORT_VOLUME/stuff/my_dir
	// EXPORT /my/dir/* / --> /EXPORT_VOLUME/stuff/my_dir

	exportsContainer, err := b.getExportsContainer()
	if err != nil {
		return s, err
	}

	// build the command
	cmdDestPath, err := util.ResolvePath(ExportsPath, dest)
	if err != nil {
		return s, fmt.Errorf("Invalid EXPORT destination: %s", dest)
	}

	s.Commit("EXPORT %q to %.12s:%s", src, exportsContainer.ID, dest)

	s, hit, err := b.probeCache(s)
	if err != nil {
		return s, err
	}
	if hit {
		b.exports = append(b.exports, s.ExportsID)
		return s, nil
	}

	// Remember original stuff so we can restore it when we finished
	var exportsID string
	origState := s

	defer func() {
		s = origState
		s.ExportsID = exportsID
		b.exports = append(b.exports, exportsID)
	}()

	// Append exports container as a volume
	s.NoCache.HostConfig.Binds = append(s.NoCache.HostConfig.Binds,
		mountsToBinds(exportsContainer.Mounts)...)

	cmd := []string{"/opt/rsync/bin/rsync", "-a", "--delete-during"}

	if b.cfg.Verbose {
		cmd = append(cmd, "--verbose")
	}

	cmd = append(cmd, src...)
	cmd = append(cmd, cmdDestPath)

	s.Config.Cmd = cmd
	s.Config.Entrypoint = []string{}

	if exportsID, err = b.client.CreateContainer(s); err != nil {
		return s, err
	}
	defer b.client.RemoveContainer(exportsID)

	log.Infof("| Running in %.12s: %s", exportsID, strings.Join(cmd, " "))

	if err = b.client.RunContainer(exportsID, false); err != nil {
		return s, err
	}

	return s, nil
}