Example #1
0
func (C *CMD) execute() (code int, err error) {
	c := exec.Command(C.Name, C.Args...)
	c.Stdout = C.Stdout
	c.Stderr = C.Stderr
	c.Env = os.Environ()
	if C.EchoStdout {
		c.Stdout = io.MultiWriter(os.Stdout, c.Stdout)
	}
	if C.EchoStderr {
		c.Stderr = io.MultiWriter(os.Stderr, c.Stderr)
	}
	if C.WriteStdout != nil {
		c.Stdout = io.MultiWriter(C.WriteStdout, c.Stdout)
	}
	if C.WriteStderr != nil {
		c.Stderr = io.MultiWriter(C.WriteStderr, c.Stderr)
	}
	if C.EchoStdout || C.EchoStderr {
		cli.Logf("shell> %s", C)
	}
	if err := c.Start(); err != nil {
		cli.Fatalf("Unable to begin command execution; %s", err)
	}
	err = c.Wait()
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return status.ExitStatus(), err
			}
		}
		cli.Fatalf("Command failed, unable to get exit code: %s", C)
	}
	return 0, nil
}
Example #2
0
func (s *Sous) AssembleTargetContext(targetName string) (Target, *Context) {
	packs := s.Packs
	p := DetectProjectType(packs)
	if p == nil {
		cli.Fatalf("no buildable project detected")
	}
	pack := CompiledPack{Pack: p}
	target, ok := pack.GetTarget(targetName)
	if !ok {
		cli.Fatalf("The %s build pack does not support %s", pack, targetName)
	}
	if fatal := CheckForProblems(pack.Pack); fatal {
		cli.Fatal()
	}
	context := GetContext(targetName)
	err := target.Check()
	if err != nil {
		cli.Fatalf("unable to %s %s project: %s", targetName, pack, err)
	}
	// If the pack specifies a version, check it matches the tagged version
	packAppVersion := strings.Split(pack.AppVersion(), "+")[0]
	if packAppVersion != "" {
		pv := version.Version(packAppVersion)
		gv := version.Version(context.BuildVersion.MajorMinorPatch)
		if !pv.Version.LimitedEqual(gv.Version) {
			cli.Warn("using latest git tagged version %s; your code reports version %s, which is ignored", gv, pv)
		}
	}
	return target, context
}
Example #3
0
func Contracts(sous *core.Sous, args []string) {
	contractsFlags.Parse(args)
	args = contractsFlags.Args()
	timeout := *timeoutFlag
	targetName := "app"
	if len(args) != 0 {
		targetName = args[0]
	}
	core.RequireGit()
	core.RequireDocker()

	if *dockerImage != "" {
		cli.Fatalf("-image flag not yet implemented")
	}

	target, context := sous.AssembleTargetContext(targetName)

	sous.RunTarget(target, context)

	cli.Logf("=> Running Contracts")
	cli.Logf(`=> **TIP:** Open another terminal in this directory and type **sous logs -f**`)

	taskHost := core.DivineTaskHost()
	port0, err := ports.GetFreePort()
	if err != nil {
		cli.Fatalf("Unable to get free port: %s", err)
	}

	dr := docker.NewRun(context.DockerTag())
	dr.AddEnv("PORT0", strconv.Itoa(port0))
	dr.AddEnv("TASK_HOST", taskHost)
	dr.StdoutFile = context.FilePath("stdout")
	dr.StderrFile = context.FilePath("stderr")
	container, err := dr.Background().Start()
	if err != nil {
		cli.Fatalf("Unable to start container: %s", err)
	}
	cli.AddCleanupTask(func() error {
		return container.KillIfRunning()
	})

	failed := 0
	for _, c := range theContracts {
		cli.Logf(`===> CHECKING CONTRACT: "%s"`, c.Name)
		cli.Logf(`===> Description: %s`, c.Desc(dr))
		if c.Tips != nil {
			cli.Logf("===> **TIPS for this contract:**")
			cli.LogBulletList("     -", c.Tips(dr))
		}
		failed += within(timeout, func() bool {
			return c.Premise(dr)
		})
	}

	if failed != 0 {
		cli.Fatalf("%d contracts failed.", failed)
	}

	cli.Success()
}
Example #4
0
func Stamp(sous *core.Sous, args []string) {
	target := "app"
	if len(args) == 0 {
		cli.Fatalf("sous stamp requires at least one argument (a docker label)")
	}
	_, context := sous.AssembleTargetContext(target)
	if context.BuildNumber() == 0 {
		cli.Fatalf("no builds yet; sous stamp operates on your last successful build of the app target")
	}

	tag := context.DockerTag()
	run := docker.NewRun(tag)
	run.AddLabels(parseLabels(args))
	run.StdoutFile = "/dev/null"
	run.StderrFile = "/dev/null"
	container, err := run.Background().Start()
	if err != nil {
		cli.Fatalf("Failed to start container for labeling: %s", err)
	}
	if err := container.KillIfRunning(); err != nil {
		cli.Fatalf("Failed to kill labelling container %s: %s", container, err)
	}
	cid := container.CID()
	if err := docker.Commit(cid, tag); err != nil {
		cli.Fatalf("Failed to commit labelled container %s: %s", container, err)
	}
	cli.Successf("Successfully added labels to %s; remember to push.", tag)
}
Example #5
0
func main() {
	if len(os.Args) < 2 {
		usage()
	}
	sousFlags, args := parseFlags(os.Args[2:])
	command := os.Args[1]
	var cfg *config.Config
	var sous *core.Sous
	if command != "config" {
		updateHourly()
		cfg = config.Load()
		trapSignals()
		defer cli.Cleanup()
		sous = core.NewSous(Version, Revision, OS, Arch, loadCommands(), BuildPacks(cfg), sousFlags, cfg)
	} else {
		sous = core.NewSous(Version, Revision, OS, Arch, loadCommands(), nil, sousFlags, nil)
	}
	c, ok := sous.Commands[command]
	if !ok {
		cli.Fatalf("Command %s not recognised; try `sous help`", command)
	}
	// It is the responsibility of the command to exit with an appropriate
	// error code...
	c.Func(sous, args)
	// If it does not, we assume it failed...
	cli.Fatalf("Command did not complete correctly")
}
Example #6
0
func (c *CMD) JSON(v interface{}) {
	o := c.Out()
	if err := json.Unmarshal([]byte(o), &v); err != nil {
		cli.Fatalf("Unable to parse JSON from %s as %T: %s", c, v, err)
	}
	if v == nil {
		cli.Fatalf("Unmarshalled nil")
	}
}
Example #7
0
func RequireVersion(r *version.R) {
	if c := cmd.ExitCode("git", "--version"); c != 0 {
		cli.Fatalf("git required")
	}
	v := version.Version(cmd.Table("git", "--version")[0][2])
	if !r.IsSatisfiedBy(v) {
		cli.Fatalf("you have git version %s; want %s", v, r.Original)
	}
}
Example #8
0
func (c *container) Image() string {
	var dc []DockerContainer
	cmd.JSON(&dc, "docker", "inspect", c.Name())
	if len(dc) == 0 {
		cli.Fatalf("Container %s does not exist.", c)
	}
	if len(dc) != 1 {
		cli.Fatalf("Multiple containers match %s", c)
	}
	return dc[0].Image
}
Example #9
0
func ImageID(image string) string {
	var i []Image
	cmd.JSON(&i, "docker", "inspect", image)
	if len(i) == 0 {
		cli.Fatalf("image missing after pull: %s", image)
	}
	if len(i) != 1 {
		cli.Fatalf("multiple images match %s; ensure sous is using unique tags", image)
	}
	return i[0].ID
}
Example #10
0
func (ts Targets) Add(target Target) {
	n := target.Name()
	if _, ok := ts[n]; ok {
		cli.Fatalf("target %s already added", n)
	}
	_, ok := knownTargets[n]
	if !ok {
		cli.Fatalf("target %s is not known", n)
	}
	ts[n] = target
}
Example #11
0
func getLabelsFromImage(imageTag string) map[string]string {
	var images []*Image
	cmd.JSON(&images, "docker", "inspect", imageTag)
	if len(images) == 0 {
		cli.Fatalf("cannot find image %s", imageTag)
	}
	if len(images) > 1 {
		cli.Fatalf("multiple images named %s, cannot continue", imageTag)
	}
	image := images[0]
	return image.Config.Labels
}
Example #12
0
func (t *AppTarget) PreDockerBuild(c *core.Context) {
	if t.artifactPath == "" {
		cli.Fatalf("Artifact path not set by compile target.")
	}
	if !file.Exists(t.artifactPath) {
		cli.Fatalf("Artifact not at %s", t.artifactPath)
	}
	filename := path.Base(t.artifactPath)
	localArtifact := filename
	file.TemporaryLink(t.artifactPath, "./"+localArtifact)
	t.artifactPath = localArtifact
}
Example #13
0
func Load() *Config {
	if c == nil {
		if !file.ReadJSON(&c, "~/.sous/config") {
			if err := Update(); err != nil {
				cli.Fatalf("Unable to load config: %s", err)
			}
			if !file.ReadJSON(&c, "~/.sous/config") {
				cli.Fatalf("Unable to read %s", "~/.sous/config")
			}
		}
	}
	return c
}
Example #14
0
func ReadJSON(v interface{}, pathFormat string, a ...interface{}) bool {
	b, exists, path := Read(pathFormat, a...)
	if !exists {
		return false
	}
	if err := json.Unmarshal(b, &v); err != nil {
		cli.Fatalf("Unable to parse JSON in %s as %T: %s", path, v, err)
	}
	if v == nil {
		cli.Fatalf("Unmarshalled nil")
	}
	return true
}
Example #15
0
func (t *AppTarget) SetState(fromTarget string, state interface{}) {
	if fromTarget != "compile" {
		return
	}
	m, ok := state.(map[string]string)
	if !ok {
		cli.Fatalf("app target got a %T from compile target, expected map[string]string", state)
	}
	artifactPath, ok := m["artifactPath"]
	if !ok {
		cli.Fatalf("app target got %+v from compile target; expected key 'artifactPath'", m)
	}
	t.artifactPath = artifactPath
}
Example #16
0
func Config(sous *core.Sous, args []string) {
	if len(args) == 0 || len(args) > 2 {
		cli.Fatalf("usage: sous config <key> [<new-value>]")
	}
	if len(args) == 1 {
		if v, ok := config.Properties()[args[0]]; ok {
			cli.Outf(v)
			cli.Success()
		}
		cli.Fatalf("Key %s not found", args[0])
	}
	config.Set(args[0], args[1])
	cli.Logf("Successfully set %s to %s", args[0], args[1])
	cli.Success()
}
Example #17
0
func IndexIsDirty() bool {
	code := cmd.ExitCode("git", "diff-index", "--quiet", "HEAD")
	if code > 1 || code < 0 {
		cli.Fatalf("Unable to determine if git index is dirty; Got exit code %d; want 0-1")
	}
	return code == 1
}
Example #18
0
func getOriginURL() *url.URL {
	table := cmd.Table("git", "remote", "-v")
	if len(table) == 0 {
		cli.Fatalf("no git remotes set up")
	}
	for _, row := range table {
		if row[0] == "origin" {
			u, err := url.Parse(row[1])
			if err != nil {
				cli.Fatalf("unable to parse origin (%s) as URL; %s", row[1], err)
			}
			return u
		}
	}
	return nil
}
Example #19
0
func Ls(sous *core.Sous, args []string) {
	//globalFlag := lsFlags.Bool("g", false, "global: list files in all projects sous has built")
	//lsFlags.Parse(args)
	//global := *globalFlag
	args = lsFlags.Args()
	if len(args) != 0 {
		cli.Fatalf("sous ls does not accept any arguments")
	}
	_, context := sous.AssembleTargetContext("app")
	cli.Outf(" ===> Images")
	images := sous.LsImages(context)
	if len(images) == 0 {
		cli.Logf("  no images for this project")
	}
	for _, image := range images {
		cli.Logf("  %s:%s", image.Name, image.Tag)
	}
	cli.Outf(" ===> Containers")
	containers := sous.LsContainers(context)
	if len(containers) == 0 {
		cli.Logf("  no containers for this project")
	}
	for _, container := range containers {
		cli.Logf("  %s (%s)", container.Name(), container.CID())
	}
	cli.Success()
}
Example #20
0
func WriteJSON(data interface{}, pathFormat string, a ...interface{}) {
	b, err := json.MarshalIndent(data, "", "\t")
	if err != nil {
		cli.Fatalf("Unable to marshal %T object to JSON: %s", data, err)
	}
	Write(b, pathFormat, a...)
}
Example #21
0
func Find(glob string) []string {
	files, err := filepath.Glob(glob)
	if err != nil {
		cli.Fatalf("Unable to search for files matching %s; %s", glob, err)
	}
	return files
}
Example #22
0
func Create(path string) *os.File {
	f, err := os.Create(path)
	if err != nil {
		cli.Fatalf("Unable to write to file: %s", err)
	}
	return f
}
Example #23
0
func RequireDaemon() {
	if c := cmd.ExitCode("docker", "ps"); c != 0 {
		cli.Logf("`docker ps` exited with code %d", c)
		if dockermachine.Installed() {
			vms := dockermachine.RunningVMs()
			if len(vms) != 0 {
				cli.Fatalf(`Tip: eval "$(docker-machine env %s)"`, vms[0])
			}
			vms = dockermachine.VMs()
			switch len(vms) {
			case 0:
				cli.Logf("Tip: you should create a machine using docker-machine")
			case 1:
				start := ""
				if cmd.Stdout("docker-machine", "status", vms[0]) != "Running" {
					start = fmt.Sprintf("docker-machine start %s && ", vms[0])
				}
				cli.Logf(`Tip: %seval "$(docker-machine env %s)"`, start, vms[0])
			default:
				cli.Logf("Tip: start one of your docker machines (%s)",
					strings.Join(vms, ", "))
			}
		}
		cli.Fatal()
	}
}
Example #24
0
// BuildFile builds the specified docker file in the context of the specified
// directory.
func BuildFile(dockerfile, dir, tag string) string {
	if !file.Exists(dockerfile) {
		cli.Fatalf("File does not exist: %s", dockerfile)
	}
	dir = path.Resolve(dir)
	localDockerfile := ".SousDockerfile"
	if file.Exists(localDockerfile) {
		file.Remove(localDockerfile)
	}
	file.RemoveOnExit(localDockerfile)
	// If there is a .gitignore, but no .dockerignore, link it as .dockerignore
	if file.Exists(".gitignore") {
		if file.Exists(".dockerignore") {
			cli.Warn("./.dockerignore found, it is recommended to remove this so Sous can use your .gitignore")
		} else {
			file.TemporaryLink(".gitignore", ".dockerignore")
			// We try to clean this file up early, in preperation for the next build step
			defer file.Remove(".dockerignore")
		}
	}
	file.TemporaryLink(dockerfile, localDockerfile)
	// We try to clean the local Dockerfile up early, in preperation for the next build step
	defer file.Remove(localDockerfile)
	return dockerCmd("build", "-f", localDockerfile, "-t", tag, dir).Out()
}
Example #25
0
func Version(s string) *V {
	v, err := NewVersion(s)
	if err != nil {
		cli.Fatalf("unable to parse version string '%s'; %s", s, err)
	}
	return v
}
Example #26
0
func (p *Pack) dockerFrom(nodeVersion, target string) string {
	if tag, ok := p.Config.AvailableVersions.GetBaseImageTag(nodeVersion, target); ok {
		return tag
	}
	cli.Fatalf("No base image available for NodeJS %s, target: %s", nodeVersion, target)
	return ""
}
Example #27
0
func TemporaryLink(path, newPath string) {
	if Exists(newPath) {
		cli.Fatalf("Unable to link file to %s, it already exists", newPath)
	}
	RemoveOnExit(newPath)
	Link(path, newPath)
}
Example #28
0
func (c *CMD) Out() string {
	out, err := c.OutErr()
	if err != nil {
		cli.Fatalf("Error running %s; %s", c, err)
	}
	return out
}
Example #29
0
func Write(data []byte, pathFormat string, a ...interface{}) {
	p := path.Resolve(pathFormat, a...)
	dir.EnsureExists(path.BaseDir(p))
	err := ioutil.WriteFile(p, data, 0777)
	if err != nil {
		cli.Fatalf("unable to write file %s; %s", p, err)
	}
}
Example #30
0
func (c *Context) TemporaryLinkResource(name string) {
	fileContents, ok := resources.Files[name]
	if !ok {
		cli.Fatalf("Cannot find resource %s, ensure go generate succeeded", name)
	}
	c.SaveFile(fileContents, name)
	file.TemporaryLink(c.FilePath(name), name)
}