func vet(path string) { // parse the Drone yml file script, err := script.ParseBuildFile(path) if err != nil { log.Err(err.Error()) os.Exit(1) return } // print the Drone yml as parsed out, _ := goyaml.Marshal(script) log.Noticef("parsed yaml:\n%s", string(out)) }
func (b *Builder) setup() error { // temp directory to store all files required // to generate the Docker image. dir, err := ioutil.TempDir("", "drone-") if err != nil { return err } // clean up after our mess. defer os.RemoveAll(dir) // make sure the image isn't empty. this would be bad if len(b.Build.Image) == 0 { log.Err("Fatal Error, No Docker Image specified") return fmt.Errorf("Error: missing Docker image") } // if we're using an alias for the build name we // should substitute it now if alias, ok := builders[b.Build.Image]; ok { b.Build.Image = alias.Tag } // if this is a local repository we should symlink // to the source code in our temp directory if b.Repo.IsLocal() { // this is where we used to use symlinks. We should // talk to the docker team about this, since copying // the entire repository is slow :( // // see https://github.com/dotcloud/docker/pull/3567 //src := filepath.Join(dir, "src") //err = os.Symlink(b.Repo.Path, src) //if err != nil { // return err //} src := filepath.Join(dir, "src") cmd := exec.Command("cp", "-a", b.Repo.Path, src) if err := cmd.Run(); err != nil { return err } } // start all services required for the build // that will get linked to the container. for _, service := range b.Build.Services { // Parse the name of the Docker image // And then construct a fully qualified image name owner, name, tag := parseImageName(service) cname := fmt.Sprintf("%s/%s:%s", owner, name, tag) // Get the image info img, err := b.dockerClient.Images.Inspect(cname) if err != nil { // Get the image if it doesn't exist if err := b.dockerClient.Images.Pull(cname); err != nil { return fmt.Errorf("Error: Unable to pull image %s", cname) } img, err = b.dockerClient.Images.Inspect(cname) if err != nil { return fmt.Errorf("Error: Invalid or unknown image %s", cname) } } // debugging log.Infof("starting service container %s", cname) // Run the contianer run, err := b.dockerClient.Containers.RunDaemonPorts(cname, img.Config.ExposedPorts) if err != nil { return err } // Get the container info info, err := b.dockerClient.Containers.Inspect(run.ID) if err != nil { // on error kill the container since it hasn't yet been // added to the array and would therefore not get // removed in the defer statement. b.dockerClient.Containers.Stop(run.ID, 10) b.dockerClient.Containers.Remove(run.ID) return err } // Add the running service to the list b.services = append(b.services, info) } if err := b.writeIdentifyFile(dir); err != nil { return err } if err := b.writeBuildScript(dir); err != nil { return err } if err := b.writeProxyScript(dir); err != nil { return err } if err := b.writeDockerfile(dir); err != nil { return err } // debugging log.Info("creating build image") // check for build container (ie bradrydzewski/go:1.2) // and download if it doesn't already exist if _, err := b.dockerClient.Images.Inspect(b.Build.Image); err == docker.ErrNotFound { // download the image if it doesn't exist if err := b.dockerClient.Images.Pull(b.Build.Image); err != nil { return err } } else if err != nil { log.Errf("failed to inspect image %s", b.Build.Image) } // create the Docker image id := createUID() if err := b.dockerClient.Images.Build(id, dir); err != nil { return err } // debugging log.Infof("copying repository to %s", b.Repo.Dir) // get the image details b.image, err = b.dockerClient.Images.Inspect(id) if err != nil { // if we have problems with the image make sure // we remove it before we exit b.dockerClient.Images.Remove(id) return err } return nil }
func run(path string) { dockerClient := docker.New() // parse the Drone yml file s, err := script.ParseBuildFile(path) if err != nil { log.Err(err.Error()) os.Exit(1) return } // get the repository root directory dir := filepath.Dir(path) code := repo.Repo{ Name: dir, Branch: "HEAD", // should we do this? Path: dir, } // does the local repository match the // $GOPATH/src/{package} pattern? This is // important so we know the target location // where the code should be copied inside // the container. if gopath, ok := getRepoPath(dir); ok { code.Dir = gopath } else if gopath, ok := getGoPath(dir); ok { // in this case we found a GOPATH and // reverse engineered the package path code.Dir = gopath } else { // otherwise just use directory name code.Dir = filepath.Base(dir) } // this is where the code gets uploaded to the container // TODO move this code to the build package code.Dir = filepath.Join("/var/cache/drone/src", filepath.Clean(code.Dir)) // track all build results var builders []*build.Builder // ssh key to import into container var key []byte if len(*identity) != 0 { key, err = ioutil.ReadFile(*identity) if err != nil { fmt.Printf("[Error] Could not find or read identity file %s\n", *identity) os.Exit(1) return } } builds := []*script.Build{s} // loop through and create builders for _, b := range builds { //script.Builds { builder := build.New(dockerClient) builder.Build = b builder.Repo = &code builder.Key = key builder.Stdout = os.Stdout builder.Timeout = *timeout if *parallel == true { var buf bytes.Buffer builder.Stdout = &buf } builders = append(builders, builder) } switch *parallel { case false: runSequential(builders) case true: runParallel(builders) } // if in parallel mode, print out the buffer // if we had a failure for _, builder := range builders { if builder.BuildState.ExitCode == 0 { continue } if buf, ok := builder.Stdout.(*bytes.Buffer); ok { log.Noticef("printing stdout for failed build %s", builder.Build.Name) println(buf.String()) } } // this exit code is initially 0 and will // be set to an error code if any of the // builds fail. var exit int fmt.Printf("\nDrone Build Results \033[90m(%v)\033[0m\n", len(builders)) // loop through and print results for _, builder := range builders { build := builder.Build res := builder.BuildState duration := time.Duration(res.Finished - res.Started) switch { case builder.BuildState.ExitCode == 0: fmt.Printf(" \033[32m\u2713\033[0m %v \033[90m(%v)\033[0m\n", build.Name, humanizeDuration(duration*time.Second)) case builder.BuildState.ExitCode != 0: fmt.Printf(" \033[31m\u2717\033[0m %v \033[90m(%v)\033[0m\n", build.Name, humanizeDuration(duration*time.Second)) exit = builder.BuildState.ExitCode } } os.Exit(exit) }