func installFn(cmd *Command, args []string) error { configureLogging() if len(args) > 0 { return fmt.Errorf("Too many arguments for 'install'") } // set unset paramters to the defaults if lockFileName == "" { lockFileName = defaultLockFileName } if targetPath == "" { targetPath = defaultTargetPath } log.Debug("lock file: %v", lockFileName) log.Debug("target path: %v", targetPath) // get dependencies from the lockfile deplist, err := LoadGrapnelDepsfile(lockFileName) if err != nil { return err } else if deplist == nil { // TODO: fail over to update instead? return fmt.Errorf("Cannot open lock file: '%s'", lockFileName) } log.Info("loaded %d dependency definitions", len(deplist)) log.Info("installing to: %v", targetPath) if err := os.MkdirAll(targetPath, 0755); err != nil { return err } libs := []*Library{} // cleanup defer func() { for _, lib := range libs { lib.Destroy() } }() // resolve all the dependencies resolver, err := getResolver() if err != nil { return err } libs, err = resolver.ResolveDependencies(deplist) if err != nil { return err } // install all the dependencies log.Info("Resolved %v dependencies. Installing.", len(libs)) resolver.InstallLibraries(targetPath, libs) log.Info("Install complete") return nil }
func StartGitDaemon(basePath string) error { if gitDaemon != nil { return nil } cwd, err := os.Getwd() if err != nil { return err } log.Info("Using CWD: %v", basePath) cmd := exec.Command("git", "daemon", "--reuseaddr", "--base-path="+basePath, "--port=9999", "--export-all", "--informative-errors", "--verbose") var outbuf bytes.Buffer cmd.Stdout = bufio.NewWriter(&outbuf) cmd.Stderr = cmd.Stdout cmd.Dir = cwd // start the daemon if err = cmd.Start(); err != nil { return err } gitDaemon = cmd // wait for the daemon to be ready to use for { data := outbuf.String() if strings.Contains(data, "Ready to rumble") { <-time.After(1 * time.Second) // wait a second os.Stdout.WriteString(data) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr break } } // wait for it to halt asynchronously go func() { log.Info("git daemon stopped: %v", gitDaemon.Wait()) gitDaemon = nil }() return nil }
func TestGitSource(t *testing.T) { InitTestLogging() // construct a repo basePath := BuildTestGitRepo("gitrepo") defer os.Remove(basePath) // start a daemon to serve the repo defer StopGitDaemon() if err := StartGitDaemon(basePath); err != nil { t.Error("%v", err) } // map a dependency to the repo var err error var dep *Dependency dep, err = NewDependency("foo/bar/baz", "git://localhost:9999/gitrepo", "1.0") if err != nil { t.Error("%v", err) } log.Info("version: %v", dep.VersionSpec.String()) // test the resolver libsrc := &GitSCM{} if _, err = libsrc.Resolve(dep); err != nil { t.Error("%v", err) } }
// Copies a file tree from src to dest func CopyFileTree(dest string, src string) error { return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { if err != nil { log.Info("%s", err.Error()) return fmt.Errorf("Error while walking file tree") } relativePath, _ := filepath.Rel(src, path) destPath := filepath.Join(dest, relativePath) if info.IsDir() { // create target directory if it's not already there if !Exists(destPath) { if err := os.MkdirAll(destPath, 0755); err != nil { return err } } } else { log.Debug("Copying: %s", destPath) if (info.Mode() & os.ModeSymlink) == os.ModeSymlink { if err := CopySymlink(path, destPath); err != nil { return fmt.Errorf("Could not copy symlink '%s' to '%s'", path, destPath) } } else if err := CopyFileContents(path, destPath); err != nil { return fmt.Errorf("Could not copy file '%s' to '%s'", path, destPath) } } return nil }) }
func GetDirectories(src string) ([]string, error) { results := []string{} err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error { if err != nil { log.Info("%s", err.Error()) return fmt.Errorf("Error while walking file tree") } relativePath, _ := filepath.Rel(src, path) if info.IsDir() && relativePath != "." { results = append(results, relativePath) } return nil }) return results, err }
func updateFn(cmd *Command, args []string) error { configureLogging() if len(args) > 0 { return fmt.Errorf("Too many arguments for 'update'") } // set unset paramters to the defaults if packageFileName == "" { packageFileName = defaultPackageFileName if lockFileName == "" { // set to default iff there was no package filename set lockFileName = defaultLockFileName } } else if lockFileName == "" { // compose a new lock file path out of the old package path lockFileName = path.Join(path.Dir(packageFileName), "grapnel-lock.toml") } if targetPath == "" { targetPath = defaultTargetPath } log.Debug("package file: %v", packageFileName) log.Debug("lock file: %v", lockFileName) log.Debug("target path: %v", targetPath) // get dependencies from the grapnel file log.Info("loading package file: '%s'", packageFileName) deplist, err := LoadGrapnelDepsfile(packageFileName) if err != nil { return err } else if deplist == nil { // TODO: fail over to update instead? return fmt.Errorf("Cannot open grapnel file: '%s'", packageFileName) } log.Info("loaded %d dependency definitions", len(deplist)) // open it now before we expend any real effort lockFile, err := os.Create(lockFileName) defer lockFile.Close() if err != nil { log.Error("Cannot open lock file: '%s'", lockFileName) return err } log.Info("installing to: %v", targetPath) if err := os.MkdirAll(targetPath, 0755); err != nil { return err } libs := []*Library{} // cleanup defer func() { for _, lib := range libs { lib.Destroy() } }() // resolve all the dependencies resolver, err := getResolver() if err != nil { return err } libs, err = resolver.ResolveDependencies(deplist) if err != nil { return err } // install all the dependencies log.Info("Resolved %v dependencies. Installing.", len(libs)) resolver.InstallLibraries(targetPath, libs) // write the library data out log.Info("Writing lock file") for _, lib := range libs { lib.ToToml(lockFile) } if createDsd { log.Info("Writing dsd file") dsdFileName := path.Join(path.Dir(lockFileName), "grapnel-dsd.sh") if err := resolver.ToDsd(dsdFileName, libs); err != nil { return err } } log.Info("Update complete") return nil }
func (self *GitSCM) Resolve(dep *Dependency) (*Library, error) { lib := NewLibrary(dep) // fix the tag, and default branch if lib.Branch == "" { lib.Branch = "master" } if lib.Tag == "" { lib.Tag = "HEAD" } log.Info("Fetching Git Dependency: '%s'", lib.Import) // create a dedicated directory and a context for commands tempRoot, err := ioutil.TempDir("", "") if err != nil { return nil, err } lib.TempDir = tempRoot cmd := NewRunContext(tempRoot) // use the configured url and acquire the depified branch log.Info("Fetching remote data for %s", lib.Import) if lib.Url == nil { // try all supported protocols against a URL composed from the import for _, protocol := range []string{"http", "https", "git", "ssh"} { packageUrl := protocol + "://" + lib.Import log.Warn("Synthesizing url from import: '%s'", packageUrl) if err := cmd.Run("git", "clone", packageUrl, "-b", lib.Branch, tempRoot); err != nil { log.Warn("Failed to fetch: '%s'", packageUrl) continue } lib.Url, _ = url.Parse(packageUrl) // pin URL break } if err != nil { return nil, fmt.Errorf("Cannot download dependency: '%s'", lib.Import) } } else if err := cmd.Run("git", "clone", lib.Url.String(), "-b", lib.Branch, tempRoot); err != nil { return nil, fmt.Errorf("Cannot download dependency: '%s'", lib.Url.String()) } // move to the specified commit/tag/hash // check out a depific commit - may be a tag, commit hash or HEAD if err := cmd.Run("git", "checkout", lib.Tag); err != nil { return nil, fmt.Errorf("Failed to checkout tag: '%s'", lib.Tag) } // Pin the Tag to a commit hash if we just have "HEAD" as the 'Tag' if lib.Tag == "HEAD" { if err := cmd.Run("git", "rev-list", "--all", "--max-count=1"); err != nil { return nil, fmt.Errorf("Failed to checkout tag: '%s'", lib.Tag) } else { lib.Tag = strings.TrimSpace(cmd.CombinedOutput) } } // Stop now if we have no semantic version information if lib.VersionSpec.IsUnversioned() { lib.Version = NewVersion(-1, -1, -1) log.Warn("Resolved: %v (unversioned)", lib.Import) stripGitRepo(lib.TempDir) return lib, nil } // find latest version match if err := cmd.Run("git", "for-each-ref", "refs/tags", "--sort=taggerdate", "--format=%(refname:short)"); err != nil { return nil, fmt.Errorf("Failed to acquire ref list for depenency") } else { for _, line := range strings.Split(cmd.CombinedOutput, "\n") { log.Debug("%v", line) if ver, err := ParseVersion(line); err == nil { log.Debug("ver: %v", ver) if dep.VersionSpec.IsSatisfiedBy(ver) { lib.Tag = line lib.Version = ver // move to this tag in the history if err := cmd.Run("git", "checkout", lib.Tag); err != nil { return nil, fmt.Errorf("Failed to checkout tag: '%s'", lib.Tag) } break } } else { log.Debug("Parse git tag err: %v", err) } } } // fail if the tag cannot be determined. if lib.Version == nil { return nil, fmt.Errorf("Cannot find a tag for dependency version specification: %v.", lib.VersionSpec) } log.Info("Resolved: %s %v", lib.Import, lib.Version) stripGitRepo(lib.TempDir) return lib, nil }
func (self *ArchiveSCM) Resolve(dep *Dependency) (*Library, error) { lib := NewLibrary(dep) // create a dedicated directory and a context for commands tempRoot, err := ioutil.TempDir("", "") if err != nil { return nil, err } lib.TempDir = tempRoot cmd := NewRunContext(tempRoot) // prep archive file for write filename := filepath.Join(tempRoot, filepath.Base(lib.Dependency.Url.Path)) file, err := os.OpenFile(filename, os.O_CREATE, 0) if err != nil { return nil, fmt.Errorf("Cannot open archive for writing: %v", err) } defer file.Close() // get the targeted archive response, err := http.Get(lib.Dependency.Url.String()) if err != nil { return nil, fmt.Errorf("Cannot download archive: %v", err) } if err := response.Write(file); err != nil { return nil, fmt.Errorf("Cannot write archive: %v", err) } file.Close() log.Info("Wrote: %s", filename) // extract the file // TODO: change to using built-in libraries whenever possible. switch filepath.Ext(filename) { case "zip": cmd.Run("unzip", filename) case "tar.gz": cmd.Run("tar", "xzf", filename) case "tar": cmd.Run("tar", "xf", filename) } os.Remove(filename) // Stop now if we have no semantic version information if lib.VersionSpec.IsUnversioned() { lib.Version = NewVersion(-1, -1, -1) log.Warn("Resolved: %v (unversioned)", lib.Import) return lib, nil } // get the version number from the filename if ver, err := ParseVersion(filepath.Base(filename)); err == nil { log.Debug("ver: %v", ver) if dep.VersionSpec.IsSatisfiedBy(ver) { lib.Version = ver } } else { log.Debug("Parse archive version err: %v", err) } // fail if the tag cannot be determined. if lib.Version == nil { return nil, fmt.Errorf("Cannot find a version specification on archive: %v.", lib.VersionSpec) } log.Info("Resolved: %s %v", lib.Import, lib.Version) return lib, nil }