Example #1
0
func (c *Compilator) compilePackage(pkg *model.Package) (err error) {
	// Prepare input dir (package plus deps)
	if err := c.createCompilationDirStructure(pkg); err != nil {
		return err
	}

	if err := c.copyDependencies(pkg); err != nil {
		return err
	}

	// Generate a compilation script
	targetScriptName := "compile.sh"
	hostScriptPath := filepath.Join(pkg.GetTargetPackageSourcesDir(c.hostWorkDir), targetScriptName)
	containerScriptPath := filepath.Join(docker.ContainerInPath, targetScriptName)
	if err := compilation.SaveScript(c.baseType, compilation.CompilationScript, hostScriptPath); err != nil {
		return err
	}

	// Extract package
	extractDir := c.getSourcePackageDir(pkg)
	if _, err := pkg.Extract(extractDir); err != nil {
		return err
	}

	// Run compilation in container
	containerName := c.getPackageContainerName(pkg)

	// in-memory buffer of the log
	log := new(bytes.Buffer)

	stdoutWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-%s > %s", color.MagentaString("%s", pkg.Name), color.WhiteString("%s", line))
		},
	)
	stderrWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-%s > %s", color.MagentaString("%s", pkg.Name), color.RedString("%s", line))
		},
	)
	sourceMountName := fmt.Sprintf("source_mount-%s", uuid.New())
	mounts := map[string]string{
		pkg.GetTargetPackageSourcesDir(c.hostWorkDir): docker.ContainerInPath,
		pkg.GetPackageCompiledTempDir(c.hostWorkDir):  docker.ContainerOutPath,
		// Add the volume mount to work around AUFS issues.  We will clean
		// the volume up (as long as we're not trying to keep the container
		// around for debugging).  We don't give it an actual directory to mount
		// from, so it will be in some docker-maintained storage.
		sourceMountName: ContainerSourceDir,
	}
	exitCode, container, err := c.dockerManager.RunInContainer(docker.RunInContainerOpts{
		ContainerName: containerName,
		ImageName:     c.BaseImageName(),
		Cmd:           []string{"bash", containerScriptPath, pkg.Name, pkg.Version},
		Mounts:        mounts,
		Volumes:       map[string]map[string]string{sourceMountName: nil},
		KeepContainer: c.keepContainer,
		StdoutWriter:  stdoutWriter,
		StderrWriter:  stderrWriter,
	})

	if container != nil && (!c.keepContainer || err == nil || exitCode == 0) {
		// Attention. While the assignments to 'err' in the
		// deferal below take effect after the 'return'
		// statements coming later they are visible to the
		// caller, i.e.  override the 'return'ed value,
		// because 'err' is a __named__ return parameter.
		defer func() {
			// Remove container - dockerManager.RemoveContainer does a force-rm

			if removeErr := c.dockerManager.RemoveContainer(container.ID); removeErr != nil {
				if err == nil {
					err = removeErr
				} else {
					err = fmt.Errorf("Error compiling package: %s. Error removing package: %s", err.Error(), removeErr.Error())
				}
			}

			if removeErr := c.dockerManager.RemoveVolumes(container); removeErr != nil {
				if err == nil {
					err = removeErr
				} else {
					err = fmt.Errorf("%s: Error removing volumes for package %s: %s", err, pkg.Name, removeErr)
				}
			}
		}()
	}

	if err != nil {
		log.WriteTo(c.ui)
		return fmt.Errorf("Error compiling package %s: %s", pkg.Name, err.Error())
	}

	if exitCode != 0 {
		log.WriteTo(c.ui)
		return fmt.Errorf("Error - compilation for package %s exited with code %d", pkg.Name, exitCode)
	}

	return os.Rename(
		pkg.GetPackageCompiledTempDir(c.hostWorkDir),
		pkg.GetPackageCompiledDir(c.hostWorkDir))
}
Example #2
0
// CreateCompilationBase will create the compiler container
func (c *Compilator) CreateCompilationBase(baseImageName string) (image *dockerClient.Image, err error) {
	imageTag := c.baseCompilationImageTag()
	imageName := c.BaseImageName()
	c.ui.Println(color.GreenString("Using %s as a compilation image name", color.YellowString(imageName)))

	containerName := c.baseCompilationContainerName()
	c.ui.Println(color.GreenString("Using %s as a compilation container name", color.YellowString(containerName)))

	image, err = c.dockerManager.FindImage(imageName)
	if err != nil {
		c.ui.Println("Image doesn't exist, it will be created ...")
	} else {
		c.ui.Println(color.GreenString(
			"Compilation image %s with ID %s already exists. Doing nothing.",
			color.YellowString(imageName),
			color.YellowString(image.ID),
		))
		return image, nil
	}

	tempScriptDir, err := util.TempDir("", "fissile-compilation")
	if err != nil {
		return nil, fmt.Errorf("Could not create temp dir %s: %s", tempScriptDir, err.Error())
	}
	defer os.RemoveAll(tempScriptDir)

	targetScriptName := "compilation-prerequisites.sh"
	containerScriptPath := filepath.Join(docker.ContainerInPath, targetScriptName)
	hostScriptPath := filepath.Join(tempScriptDir, targetScriptName)
	if err = compilation.SaveScript(c.baseType, compilation.PrerequisitesScript, hostScriptPath); err != nil {
		return nil, fmt.Errorf("Error saving script asset: %s", err.Error())
	}

	// in-memory buffer of the log
	log := new(bytes.Buffer)

	stdoutWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-container > %s", color.WhiteString("%s", line))
		},
	)
	stderrWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-container > %s", color.RedString("%s", line))
		},
	)
	exitCode, container, err := c.dockerManager.RunInContainer(docker.RunInContainerOpts{
		ContainerName: containerName,
		ImageName:     baseImageName,
		Cmd:           []string{"bash", "-c", containerScriptPath},
		Mounts:        map[string]string{tempScriptDir: docker.ContainerInPath},
		KeepContainer: false, // There is never a need to keep this container on failure
		StdoutWriter:  stdoutWriter,
		StderrWriter:  stderrWriter,
	})
	if container != nil {
		defer func() {
			removeErr := c.dockerManager.RemoveContainer(container.ID)
			if removeErr != nil {
				if err == nil {
					err = removeErr
				} else {
					err = fmt.Errorf(
						"Image creation error: %s. Image removal error: %s",
						err,
						removeErr,
					)
				}
			}
		}()
	}

	if err != nil {
		log.WriteTo(c.ui)
		return nil, fmt.Errorf("Error running script: %s", err.Error())
	}

	if exitCode != 0 {
		log.WriteTo(c.ui)
		return nil, fmt.Errorf("Error - script script exited with code %d", exitCode)
	}

	image, err = c.dockerManager.CreateImage(
		container.ID,
		c.baseCompilationImageRepository(),
		imageTag,
		"",
		[]string{},
	)

	if err != nil {
		return nil, fmt.Errorf("Error creating image %s", err.Error())
	}

	c.ui.Println(color.GreenString(
		"Image %s with ID %s created successfully.",
		color.YellowString(c.BaseImageName()),
		color.YellowString(image.ID)))

	return image, nil
}