Example #1
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 b.prevExportContainerID == "" {
		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.
	if b.currentExportContainerName == "" {
		return s, fmt.Errorf("You have to EXPORT something first to do IMPORT")
	}

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

	log.Infof("| Import from %s (%.12s)", b.currentExportContainerName, 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)
	}

	s.Commit("IMPORT %q : %q %s", b.prevExportContainerID, 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
}
Example #2
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

	s.Commit("EXPORT %q to %s, prev_export_container_salt: %s", src, dest, b.prevExportContainerID)

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

	s, hit, err := b.probeCacheAndPreserveCommits(s)
	if err != nil {
		return s, err
	}
	if hit {
		b.prevExportContainerID = s.ExportsID
		b.currentExportContainerName = exportsContainerName(s.ParentID, s.GetCommits())
		log.Infof("| Export container: %s", b.currentExportContainerName)
		log.Debugf("===EXPORT CONTAINER NAME: %s ('%s', '%s')", b.currentExportContainerName, s.ParentID, s.GetCommits())
		s.CleanCommits()
		return s, nil
	}

	prevExportContainerName := b.currentExportContainerName
	b.currentExportContainerName = exportsContainerName(s.ImageID, s.GetCommits())

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

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

	defer func() {
		s = origState
		s.ExportsID = exportsID
		b.prevExportContainerID = 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
}