func buildCabinet(repo *graph.Repository, id string) error { // Build the cabinet data head, err := repo.Head() if err != nil { return fmt.Errorf("build: get repo head: %s", err) } data := &CabFile{ Repo: repo.String(), Created: time.Now(), Head: head, } deps, err := Deps.RepoDeps(repo) if err != nil { return fmt.Errorf("build: scan dependencies: %s", err) } for _, dep := range deps { rv, err := NewRepoVersion(dep) if err != nil { return fmt.Errorf("build: %s", err) } data.Deps = append(data.Deps, rv) } if *cabTest { // Test the packages in the repository test := exec.Command("go", "test", repo.String()) test.Dir = os.TempDir() test.Stdout = os.Stdout test.Stderr = os.Stderr if err := test.Run(); err != nil { return fmt.Errorf("build: `go test` failed: %s", err) } } // Make the $REPO/.rx directory repoRx := filepath.Join(repo.Root, ".rx") if err := os.MkdirAll(repoRx, 0755); err != nil { return fmt.Errorf("build: create .rx: %s", err) } filename := filepath.Join(repoRx, "cabinet-"+id) // Open the file, but fail if it already exists file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) if err != nil { return fmt.Errorf("build: open cabinet: %s", err) } defer file.Close() if err := gob.NewEncoder(file).Encode(data); err != nil { return fmt.Errorf("build: encoding cabinet: %s", err) } log.Printf("Cabinet written to %q", filename) return nil }
// Apply attempts to locate the repository and pin it to the head version. func (dep *RepoVersion) Apply() error { // Find the repository var repo *graph.Repository for _, pkg := range dep.Packages { // Make sure the package is installed and up-to-date get := exec.Command("go", "get", "-d", pkg) get.Dir = os.TempDir() get.Stdout = os.Stdout get.Stderr = os.Stderr if err := get.Run(); err != nil { continue } // Scan for new packages if err := Deps.Scan(dep.Pattern); err != nil { continue } // See if we found the package we wanted p, ok := Deps.Package[pkg] if !ok { continue } // Get the repository r, ok := Deps.Repository[p.RepoRoot] if !ok { continue } repo = r break } if repo == nil { return fmt.Errorf("apply(%q@%q): unable to locate repository", dep.Pattern, dep.Head) } // Get fallback in case the update fails fallback, err := repo.Head() if err != nil { return fmt.Errorf("apply(%q@%q): unable to determine fallback version", dep.Pattern, dep.Head) } // Pin the version if err := repo.ToRev(dep.Head); err != nil { if ferr := repo.ToRev(fallback); ferr != nil { return fmt.Errorf("apply(%q): pin(%q) [%s] and fallback(%q) [%s] failed", dep.Pattern, dep.Head, err, fallback, ferr) } return fmt.Errorf("apply(%q@%q): pin failed: %s", dep.Pattern, dep.Head, err) } log.Printf("Pinned %s @ %s", dep.Pattern, dep.Head) return nil }
// NewRepoVersion creates a repo version object suitable for storing into cabinets, etc. func NewRepoVersion(repo *graph.Repository) (*RepoVersion, error) { head, err := repo.Head() if err != nil { return nil, fmt.Errorf("get %s head: %s", repo, err) } return &RepoVersion{ Pattern: repo.String(), Packages: repo.Packages, Head: head, }, nil }