// Clone clones a git repository to a specific target directory func (h *stiGit) Clone(source, target string, c api.CloneConfig) error { if util.UsingCygwinGit { var err error target, err = util.ToSlashCygwin(target) if err != nil { return err } } // NOTE, we don NOT pass in both stdout and stderr, because // with running with --quiet, and no output heading to stdout, hangs were occurring with the coordination // of underlying channel management in the Go layer when dealing with the Go Cmd wrapper around // git, sending of stdout/stderr to the Pipes created here, and the glog routines sent to pipeToLog // // It was agreed that we wanted to keep --quiet and no stdout output ....leaving stderr only since // --quiet does not suppress that anyway reduced the frequency of the hang, but it still occurred. // the pipeToLog method has been left for now for historical purposes, but if this implemenetation // of git clone holds, we'll want to delete that at some point. cloneArgs := append([]string{"clone"}, cloneConfigToArgs(c)...) cloneArgs = append(cloneArgs, []string{source, target}...) errReader, errWriter, _ := os.Pipe() opts := util.CommandOpts{Stderr: errWriter} err := h.RunWithOptions(opts, "git", cloneArgs...) errWriter.Close() if err != nil { out, _ := ioutil.ReadAll(errReader) // If we captured errors via stderr, print them out. if len(out) > 0 { glog.Errorf("Clone failed: source %s, target %s, with output %s", source, target, out) } return err } return nil }
// CreateLocalGitDirectoryWithSubmodule creates a git directory with a submodule func CreateLocalGitDirectoryWithSubmodule(t *testing.T) string { cr := util.NewCommandRunner() submodule := CreateLocalGitDirectory(t) defer os.RemoveAll(submodule) if util.UsingCygwinGit { var err error submodule, err = util.ToSlashCygwin(submodule) if err != nil { t.Fatal(err) } } dir := CreateEmptyLocalGitDirectory(t) err := cr.RunWithOptions(util.CommandOpts{Dir: dir}, "git", "submodule", "add", submodule, "submodule") if err != nil { t.Fatal(err) } return dir }
// Download downloads the application source code from the Git repository // and checkout the Ref specified in the config. func (c *Clone) Download(config *api.Config) (*api.SourceInfo, error) { targetSourceDir := filepath.Join(config.WorkingDir, api.Source) config.WorkingSourceDir = targetSourceDir ok, err := c.ValidCloneSpec(config.Source) if err != nil { return nil, err } if !ok { glog.Errorf("Clone.Download was passed an invalid source %s", config.Source) return nil, fmt.Errorf("invalid source %s", config.Source) } ref := "HEAD" if config.Ref != "" { ref = config.Ref } if strings.HasPrefix(config.Source, "file://") { s := strings.TrimPrefix(config.Source, "file://") if util.UsingCygwinGit { var err error s, err = util.ToSlashCygwin(s) if err != nil { glog.V(0).Infof("error: Cygwin path conversion failed: %v", err) return nil, err } } config.Source = "file://" + s } if len(config.ContextDir) > 0 { targetSourceDir = filepath.Join(config.WorkingDir, api.ContextTmp) glog.V(1).Infof("Downloading %q (%q) ...", config.Source, config.ContextDir) } else { glog.V(1).Infof("Downloading %q ...", config.Source) } if !config.IgnoreSubmodules { glog.V(2).Infof("Cloning sources into %q", targetSourceDir) } else { glog.V(2).Infof("Cloning sources (ignoring submodules) into %q", targetSourceDir) } cloneConfig := api.CloneConfig{Quiet: true} err = c.Clone(config.Source, targetSourceDir, cloneConfig) if err != nil { glog.V(0).Infof("error: git clone failed: %v", err) return nil, err } err = c.Checkout(targetSourceDir, ref) if err != nil { return nil, err } glog.V(1).Infof("Checked out %q", ref) if !config.IgnoreSubmodules { err = c.SubmoduleUpdate(targetSourceDir, true, true) if err != nil { return nil, err } glog.V(1).Infof("Updated submodules for %q", ref) } // Record Git's knowledge about file permissions if runtime.GOOS == "windows" { filemodes, err := c.LsTree(filepath.Join(targetSourceDir, config.ContextDir), ref, true) if err != nil { return nil, err } for _, filemode := range filemodes { c.Chmod(filepath.Join(targetSourceDir, config.ContextDir, filemode.Name()), os.FileMode(filemode.Mode())&os.ModePerm) } } info := c.GetInfo(targetSourceDir) if len(config.ContextDir) > 0 { originalTargetDir := filepath.Join(config.WorkingDir, api.Source) c.RemoveDirectory(originalTargetDir) path := filepath.Join(targetSourceDir, config.ContextDir) err := c.CopyContents(path, originalTargetDir) if err != nil { return nil, err } c.RemoveDirectory(targetSourceDir) } if len(config.ContextDir) > 0 { info.ContextDir = config.ContextDir } return info, nil }