// EnsureCode makes sure the code is in the ProjectDir. // NOTE(termie): When launched by kiddie-pool the ProjectPath will be // set to the location where grappler checked out the code and the copy // will be a little superfluous, but in the case where this is being // run in Single Player Mode this copy is necessary to avoid screwing // with the local dir. func (p *Runner) EnsureCode() (string, error) { projectDir := p.ProjectDir() if p.options.DirectMount { return projectDir, nil } // If the target is a tarball feetch and build that if p.options.ProjectURL != "" { resp, err := util.FetchTarball(p.options.ProjectURL) if err != nil { return projectDir, err } err = util.Untargzip(projectDir, resp.Body) if err != nil { return projectDir, err } } else { // We were pointed at a path with ProjectPath, copy it to projectDir ignoreFiles := []string{ p.options.BuildPath(), p.options.ProjectDownloadPath(), p.options.StepPath(), p.options.ContainerPath(), p.options.CachePath(), } var err error // Make sure we don't accidentally recurse or copy extra files ignoreFunc := func(src string, files []os.FileInfo) []string { ignores := []string{} for _, file := range files { abspath, err := filepath.Abs(filepath.Join(src, file.Name())) if err != nil { // Something went sufficiently wrong panic(err) } if util.ContainsString(ignoreFiles, abspath) { ignores = append(ignores, file.Name()) } } return ignores } copyOpts := &shutil.CopyTreeOptions{Ignore: ignoreFunc, CopyFunction: shutil.Copy} os.Rename(projectDir, fmt.Sprintf("%s-%s", projectDir, uuid.NewRandom().String())) err = shutil.CopyTree(p.options.ProjectPath, projectDir, copyOpts) if err != nil { return projectDir, err } } return projectDir, nil }
// Fetch grabs the Step content (or calls FetchScript for script steps). func (s *ExternalStep) Fetch() (string, error) { // NOTE(termie): polymorphism based on kind, we could probably do something // with interfaces here, but this is okay for now if s.IsScript() { return s.FetchScript() } stepPath := filepath.Join(s.options.StepPath(), s.CachedName()) stepExists, err := util.Exists(stepPath) if err != nil { return "", err } if !stepExists { // If we don't have a url already if s.url == "" { // Grab the info about the step from the api // TODO(termie): probably don't need these in global options? apiOptions := api.APIOptions{ BaseURL: s.options.GlobalOptions.BaseURL, AuthToken: s.options.GlobalOptions.AuthToken, } client := api.NewAPIClient(&apiOptions) stepInfo, err := client.GetStepVersion(s.Owner(), s.Name(), s.Version()) if err != nil { if apiErr, ok := err.(*api.APIError); ok && apiErr.StatusCode == 404 { return "", fmt.Errorf("The step \"%s\" was not found", s.ID()) } return "", err } s.url = stepInfo.TarballURL } // If we have a file uri let's just copytree it. if strings.HasPrefix(s.url, "file:///") { if s.options.EnableDevSteps { localPath := s.url[len("file://"):] err = shutil.CopyTree(localPath, stepPath, nil) if err != nil { return "", err } } else { return "", fmt.Errorf("Dev mode is not enabled so refusing to copy local file urls: %s", s.url) } } else { // Grab the tarball and util.Untargzip it resp, err := util.FetchTarball(s.url) if err != nil { return "", err } // Assuming we have a gzip'd tarball at this point err = util.Untargzip(stepPath, resp.Body) if err != nil { return "", err } } } hostStepPath := s.HostPath() err = shutil.CopyTree(stepPath, hostStepPath, nil) if err != nil { return "", nil } // Now that we have the code, load any step config we might find desc, err := ReadStepDesc(s.HostPath("wercker-step.yml")) if err != nil && !os.IsNotExist(err) { // TODO(termie): Log an error instead of printing s.logger.Println("ERROR: Reading wercker-step.yml:", err) } if err == nil { s.stepDesc = desc } return hostStepPath, nil }
// EnsureCode makes sure the code is in the ProjectDir. // NOTE(termie): When launched by kiddie-pool the ProjectPath will be // set to the location where grappler checked out the code and the copy // will be a little superfluous, but in the case where this is being // run in Single Player Mode this copy is necessary to avoid screwing // with the local dir. func (p *Runner) EnsureCode() (string, error) { projectDir := p.ProjectDir() if p.options.DirectMount { return projectDir, nil } // If the target is a tarball feetch and build that if p.options.ProjectURL != "" { resp, err := util.FetchTarball(p.options.ProjectURL) if err != nil { return projectDir, err } err = util.Untargzip(projectDir, resp.Body) if err != nil { return projectDir, err } } else { // We were pointed at a path with ProjectPath, copy it to projectDir ignoreFiles := []string{ p.options.WorkingDir, } oldbuilds, _ := filepath.Abs("./_builds") oldprojects, _ := filepath.Abs("./_projects") oldsteps, _ := filepath.Abs("./_steps") oldcache, _ := filepath.Abs("./_cache") oldcontainers, _ := filepath.Abs("./_containers") deprecatedPaths := []string{ oldbuilds, oldprojects, oldsteps, oldcache, oldcontainers, } var err error // Make sure we don't accidentally recurse or copy extra files ignoreFunc := func(src string, files []os.FileInfo) []string { ignores := []string{} for _, file := range files { abspath, err := filepath.Abs(filepath.Join(src, file.Name())) if err != nil { // Something went sufficiently wrong panic(err) } if util.ContainsString(ignoreFiles, abspath) { ignores = append(ignores, file.Name()) } // TODO(termie): remove this warning after a while if util.ContainsString(deprecatedPaths, abspath) { p.logger.Warnln(fmt.Sprintf("Not ignoring deprecated runtime path, %s. You probably want to delete it so it doesn't get copied into your container. Runtime files are now stored under '.wercker' by default. This message will go away in a future update.", file.Name())) } } return ignores } copyOpts := &shutil.CopyTreeOptions{Ignore: ignoreFunc, CopyFunction: shutil.Copy} os.Rename(projectDir, fmt.Sprintf("%s-%s", projectDir, uuid.NewRandom().String())) err = shutil.CopyTree(p.options.ProjectPath, projectDir, copyOpts) if err != nil { return projectDir, err } } return projectDir, nil }