Merge "jiri: fix typo and add example for "jiri test run -pkgs""
diff --git a/cl.go b/cl.go
index 8926d37..77e72b2 100644
--- a/cl.go
+++ b/cl.go
@@ -331,6 +331,31 @@
#
`
+// currentProject returns the Project containing the current working directory.
+// The current working directory must be inside JIRI_ROOT.
+func currentProject(jirix *jiri.X) (project.Project, error) {
+ dir, err := os.Getwd()
+ if err != nil {
+ return project.Project{}, fmt.Errorf("os.Getwd() failed: %v", err)
+ }
+
+ // Error if current working dir is not inside jirix.Root.
+ if !strings.HasPrefix(dir, jirix.Root) {
+ return project.Project{}, fmt.Errorf("'jiri cl mail' must be run from within a project in JIRI_ROOT")
+ }
+
+ // Walk up the path until we find a project at that path, or hit the jirix.Root.
+ for dir != jirix.Root {
+ p, err := project.ProjectAtPath(jirix, dir)
+ if err != nil {
+ dir = filepath.Dir(dir)
+ continue
+ }
+ return p, nil
+ }
+ return project.Project{}, fmt.Errorf("directory %q is not contained in a project", dir)
+}
+
// runCLMail is a wrapper that sets up and runs a review instance.
func runCLMail(jirix *jiri.X, _ []string) error {
// Sanity checks for the <presubmitFlag> flag.
@@ -341,14 +366,17 @@
host := hostFlag
if host == "" {
- var err error
- if host, err = project.GerritHost(jirix); err != nil {
+ p, err := currentProject(jirix)
+ if err != nil {
return err
}
+ if p.GerritHost == "" {
+ return fmt.Errorf("No gerrit host found. Please use the '--host' flag, or add a 'gerrithost' attribute for project %q.", p.Name)
+ }
+ host = p.GerritHost
}
// Create and run the review.
-
review, err := newReview(jirix, gerrit.CLOpts{
Autosubmit: autosubmitFlag,
Ccs: parseEmails(ccsFlag),
diff --git a/googlesource/.api b/googlesource/.api
index 6101b39..067834e 100644
--- a/googlesource/.api
+++ b/googlesource/.api
@@ -1,5 +1,5 @@
pkg googlesource, func GetRepoStatuses(*jiri.X, string) (RepoStatuses, error)
-pkg googlesource, func IsGoogleSourceHost(string) bool
+pkg googlesource, func IsGoogleSourceRemote(string) bool
pkg googlesource, type RepoStatus struct
pkg googlesource, type RepoStatus struct, Branches map[string]string
pkg googlesource, type RepoStatus struct, CloneUrl string
diff --git a/googlesource/googlesource.go b/googlesource/googlesource.go
index 01547a9..0642db6 100644
--- a/googlesource/googlesource.go
+++ b/googlesource/googlesource.go
@@ -100,6 +100,17 @@
// GetRepoStatuses returns the RepoStatus of all public projects hosted on the
// remote host. Host must be a googlesource host.
+//
+// NOTE(nlacasse): Googlesource uses gitiles as its git repo browser. gitiles
+// has a completely undocumented feature that allows one to query the state of
+// all repositories in a single request. See "doGetJson" method in
+// https://gerrit.googlesource.com/gitiles/+/master/gitiles-servlet/src/main/java/com/google/gitiles/RepositoryIndexServlet.java
+//
+// It's possible that gitiles will stop responding to this request at some
+// future version, or that googlesource will move away from gitiles entirely.
+// If that happens we can still get all the repo information in one request by
+// using the /projects/ endpoint on Gerrit. See
+// https://review.typo3.org/Documentation/rest-api-projects.html#list-projects
func GetRepoStatuses(jirix *jiri.X, host string) (RepoStatuses, error) {
u, err := url.Parse(host)
if err != nil {
@@ -109,6 +120,7 @@
return nil, fmt.Errorf("remote host scheme is not http(s): %s", host)
}
+ u.Path = "/"
q := u.Query()
q.Set("format", "json")
q.Set("b", "master")
@@ -141,9 +153,9 @@
return repoStatuses, nil
}
-var googleSourceHostRegExp = regexp.MustCompile(`(?i)https?://.*\.googlesource.com/.*`)
+var googleSourceRemoteRegExp = regexp.MustCompile(`(?i)https?://.*\.googlesource.com.*`)
-// IsGoogleSourceHost returns true if the host url is a googlesource url.
-func IsGoogleSourceHost(host string) bool {
- return googleSourceHostRegExp.MatchString(host)
+// IsGoogleSourceRemote returns true if the host url is a googlesource remote.
+func IsGoogleSourceRemote(host string) bool {
+ return googleSourceRemoteRegExp.MatchString(host)
}
diff --git a/jiritest/.api b/jiritest/.api
index ebd8c36..5ba67b4 100644
--- a/jiritest/.api
+++ b/jiritest/.api
@@ -1,6 +1,5 @@
pkg jiritest, func NewFakeJiriRoot(*testing.T) (*FakeJiriRoot, func())
pkg jiritest, func NewX(*testing.T) (*jiri.X, func())
-pkg jiritest, method (FakeJiriRoot) AddHost(project.Host) error
pkg jiritest, method (FakeJiriRoot) AddProject(project.Project) error
pkg jiritest, method (FakeJiriRoot) AddTool(project.Tool) error
pkg jiritest, method (FakeJiriRoot) CreateRemoteProject(string) error
diff --git a/jiritest/fake.go b/jiritest/fake.go
index c3e8195..517ec84 100644
--- a/jiritest/fake.go
+++ b/jiritest/fake.go
@@ -86,21 +86,6 @@
t.Fatal(err)
}
- // Add "gerrit" and "git" hosts to the manifest, as required by the "jiri"
- // tool.
- if err := fake.AddHost(project.Host{
- Name: "gerrit",
- Location: "git://example.com/gerrit",
- }); err != nil {
- t.Fatal(err)
- }
- if err := fake.AddHost(project.Host{
- Name: "git",
- Location: "git://example.com/git",
- }); err != nil {
- t.Fatal(err)
- }
-
// Update the contents of the fake JIRI_ROOT instance based on
// the information recorded in the remote manifest.
if err := fake.UpdateUniverse(false); err != nil {
@@ -120,19 +105,6 @@
}
}
-// AddHost adds the given host to a remote manifest.
-func (fake FakeJiriRoot) AddHost(host project.Host) error {
- manifest, err := fake.ReadRemoteManifest()
- if err != nil {
- return err
- }
- manifest.Hosts = append(manifest.Hosts, host)
- if err := fake.WriteRemoteManifest(manifest); err != nil {
- return err
- }
- return nil
-}
-
// AddProject adds the given project to a remote manifest.
func (fake FakeJiriRoot) AddProject(project project.Project) error {
manifest, err := fake.ReadRemoteManifest()
diff --git a/project/.api b/project/.api
index 5e8cc9a..ddf91f4 100644
--- a/project/.api
+++ b/project/.api
@@ -7,9 +7,7 @@
pkg project, func CurrentManifest(*jiri.X) (*Manifest, error)
pkg project, func CurrentProjectKey(*jiri.X) (ProjectKey, error)
pkg project, func DataDirPath(*jiri.X, string) (string, error)
-pkg project, func GerritHost(*jiri.X) (string, error)
pkg project, func GetProjectStates(*jiri.X, bool) (map[ProjectKey]*ProjectState, error)
-pkg project, func GitHost(*jiri.X) (string, error)
pkg project, func InstallTools(*jiri.X, string) error
pkg project, func LocalProjects(*jiri.X, ScanMode) (Projects, error)
pkg project, func MakeProjectKey(string, string) ProjectKey
@@ -17,6 +15,7 @@
pkg project, func ManifestFromFile(*jiri.X, string) (*Manifest, error)
pkg project, func ParseNames(*jiri.X, []string, map[string]struct{}) (Projects, error)
pkg project, func PollProjects(*jiri.X, map[string]struct{}) (Update, error)
+pkg project, func ProjectAtPath(*jiri.X, string) (Project, error)
pkg project, func ProjectFromFile(*jiri.X, string) (*Project, error)
pkg project, func ReadManifest(*jiri.X) (Projects, Tools, error)
pkg project, func TransitionBinDir(*jiri.X) error
@@ -43,10 +42,6 @@
pkg project, type FileImport struct
pkg project, type FileImport struct, File string
pkg project, type FileImport struct, XMLName struct{}
-pkg project, type GitHook struct
-pkg project, type GitHook struct, Name string
-pkg project, type GitHook struct, Path string
-pkg project, type GitHook struct, XMLName struct{}
pkg project, type Hook struct
pkg project, type Hook struct, Args []HookArg
pkg project, type Hook struct, Interpreter string
@@ -58,12 +53,6 @@
pkg project, type HookArg struct, Arg string
pkg project, type HookArg struct, XMLName struct{}
pkg project, type Hooks map[string]Hook
-pkg project, type Host struct
-pkg project, type Host struct, GitHooks []GitHook
-pkg project, type Host struct, Location string
-pkg project, type Host struct, Name string
-pkg project, type Host struct, XMLName struct{}
-pkg project, type Hosts map[string]Host
pkg project, type Import struct
pkg project, type Import struct, Manifest string
pkg project, type Import struct, Root string
@@ -72,13 +61,14 @@
pkg project, type Manifest struct
pkg project, type Manifest struct, FileImports []FileImport
pkg project, type Manifest struct, Hooks []Hook
-pkg project, type Manifest struct, Hosts []Host
pkg project, type Manifest struct, Imports []Import
pkg project, type Manifest struct, Label string
pkg project, type Manifest struct, Projects []Project
pkg project, type Manifest struct, Tools []Tool
pkg project, type Manifest struct, XMLName struct{}
pkg project, type Project struct
+pkg project, type Project struct, GerritHost string
+pkg project, type Project struct, GitHooks string
pkg project, type Project struct, Name string
pkg project, type Project struct, Path string
pkg project, type Project struct, Protocol string
diff --git a/project/paths.go b/project/paths.go
index 2c0a2d9..7e81e78 100644
--- a/project/paths.go
+++ b/project/paths.go
@@ -18,7 +18,7 @@
// breaks. We should revisit the whole data directory thing, and in particular
// see if we can get rid of tools having to know their own names.
func DataDirPath(jirix *jiri.X, toolName string) (string, error) {
- _, projects, tools, _, err := readManifest(jirix)
+ projects, tools, _, err := readManifest(jirix)
if err != nil {
return "", err
}
@@ -40,25 +40,3 @@
}
return filepath.Join(project.Path, tool.Data), nil
}
-
-func getHost(jirix *jiri.X, name string) (string, error) {
- hosts, _, _, _, err := readManifest(jirix)
- if err != nil {
- return "", err
- }
- host, found := hosts[name]
- if !found {
- return "", fmt.Errorf("host %s not found in manifest", name)
- }
- return host.Location, nil
-}
-
-// GerritHost returns the URL that hosts the Gerrit code review system.
-func GerritHost(jirix *jiri.X) (string, error) {
- return getHost(jirix, "gerrit")
-}
-
-// GitHost returns the URL that hosts the git repositories.
-func GitHost(jirix *jiri.X) (string, error) {
- return getHost(jirix, "git")
-}
diff --git a/project/project.go b/project/project.go
index a877633..85421c1 100644
--- a/project/project.go
+++ b/project/project.go
@@ -9,6 +9,7 @@
"encoding/xml"
"fmt"
"io/ioutil"
+ "net/url"
"os"
"path/filepath"
"sort"
@@ -41,7 +42,6 @@
// Manifest represents a setting used for updating the universe.
type Manifest struct {
Hooks []Hook `xml:"hooks>hook"`
- Hosts []Host `xml:"hosts>host"`
Imports []Import `xml:"imports>import"`
FileImports []FileImport `xml:"imports>fileimport"`
Label string `xml:"label,attr,omitempty"`
@@ -80,16 +80,12 @@
var (
newlineBytes = []byte("\n")
emptyHooksBytes = []byte("\n <hooks></hooks>\n")
- emptyGitHooksBytes = []byte("\n <githooks></githooks>\n")
- emptyHostsBytes = []byte("\n <hosts></hosts>\n")
emptyImportsBytes = []byte("\n <imports></imports>\n")
emptyProjectsBytes = []byte("\n <projects></projects>\n")
emptyToolsBytes = []byte("\n <tools></tools>\n")
endElemBytes = []byte("/>\n")
endHookBytes = []byte("></hook>\n")
- endGitHookBytes = []byte("></githook>\n")
- endHostBytes = []byte("></host>\n")
endImportBytes = []byte("></import>\n")
endFileImportBytes = []byte("></fileimport>\n")
endProjectBytes = []byte("></project>\n")
@@ -106,7 +102,6 @@
x.Label = m.Label
// First make copies of all slices.
x.Hooks = append([]Hook(nil), m.Hooks...)
- x.Hosts = append([]Host(nil), m.Hosts...)
x.Imports = append([]Import(nil), m.Imports...)
x.FileImports = append([]FileImport(nil), m.FileImports...)
x.Projects = append([]Project(nil), m.Projects...)
@@ -115,9 +110,6 @@
for index, hook := range x.Hooks {
x.Hooks[index].Args = append([]HookArg(nil), hook.Args...)
}
- for index, host := range x.Hosts {
- x.Hosts[index].GitHooks = append([]GitHook(nil), host.GitHooks...)
- }
return x
}
@@ -134,14 +126,10 @@
// It's hard (impossible?) to get xml.Marshal to elide some of the empty
// elements, or produce short empty elements, so we post-process the data.
data = bytes.Replace(data, emptyHooksBytes, newlineBytes, -1)
- data = bytes.Replace(data, emptyGitHooksBytes, newlineBytes, -1)
- data = bytes.Replace(data, emptyHostsBytes, newlineBytes, -1)
data = bytes.Replace(data, emptyImportsBytes, newlineBytes, -1)
data = bytes.Replace(data, emptyProjectsBytes, newlineBytes, -1)
data = bytes.Replace(data, emptyToolsBytes, newlineBytes, -1)
data = bytes.Replace(data, endHookBytes, endElemBytes, -1)
- data = bytes.Replace(data, endGitHookBytes, endElemBytes, -1)
- data = bytes.Replace(data, endHostBytes, endElemBytes, -1)
data = bytes.Replace(data, endImportBytes, endElemBytes, -1)
data = bytes.Replace(data, endFileImportBytes, endElemBytes, -1)
data = bytes.Replace(data, endProjectBytes, endElemBytes, -1)
@@ -172,11 +160,6 @@
}
func (m *Manifest) fillDefaults() error {
- for index := range m.Hosts {
- if err := m.Hosts[index].validate(); err != nil {
- return err
- }
- }
for index := range m.Imports {
if err := m.Imports[index].fillDefaults(); err != nil {
return err
@@ -201,11 +184,6 @@
}
func (m *Manifest) unfillDefaults() error {
- for index := range m.Hosts {
- if err := m.Hosts[index].validate(); err != nil {
- return err
- }
- }
for index := range m.Imports {
if err := m.Imports[index].unfillDefaults(); err != nil {
return err
@@ -253,37 +231,6 @@
XMLName struct{} `xml:"arg"`
}
-// Hosts map host name to their detailed description.
-type Hosts map[string]Host
-
-// Host represents the locations of git and gerrit repository hosts.
-type Host struct {
- // Name is the host name.
- Name string `xml:"name,attr,omitempty"`
- // Location is the url of the host.
- Location string `xml:"location,attr,omitempty"`
- // Git hooks to apply to repos from this host.
- GitHooks []GitHook `xml:"githooks>githook"`
- XMLName struct{} `xml:"host"`
-}
-
-func (h *Host) validate() error {
- if len(h.GitHooks) > 0 && h.Name != "git" {
- return fmt.Errorf("bad host: githook provided for non-git host: %+v", *h)
- }
- return nil
-}
-
-// GitHook represents the name and source of git hooks.
-type GitHook struct {
- // The hook name, as required by git (e.g. commit-msg, pre-rebase, etc.)
- Name string `xml:"name,attr,omitempty"`
- // The filename of the hook implementation. When editing the manifest,
- // specify this path as relative to the manifest dir.
- Path string `xml:"path,attr,omitempty"`
- XMLName struct{} `xml:"githook"`
-}
-
// Import represents a remote manifest import.
type Import struct {
// Manifest file to use from the remote manifest project.
@@ -427,7 +374,12 @@
// Revision is the revision the project should be advanced to
// during "jiri update". If not set, "HEAD" is used as the
// default.
- Revision string `xml:"revision,attr,omitempty"`
+ Revision string `xml:"revision,attr,omitempty"`
+ // GerritHost is the gerrit host where project CLs will be sent.
+ GerritHost string `xml:"gerrithost,attr,omitempty"`
+ // GitHooks is a directory containing git hooks that will be installed for
+ // this project.
+ GitHooks string `xml:"githooks,attr,omitempty"`
XMLName struct{} `xml:"project"`
}
@@ -642,18 +594,15 @@
manifest.Projects = append(manifest.Projects, project)
}
- // Add all hosts, tools, and hooks from the current manifest to the
+ // Add all tools and hooks from the current manifest to the
// snapshot manifest.
- hosts, _, tools, hooks, err := readManifest(jirix)
+ _, tools, hooks, err := readManifest(jirix)
if err != nil {
return err
}
for _, tool := range tools {
manifest.Tools = append(manifest.Tools, tool)
}
- for _, host := range hosts {
- manifest.Hosts = append(manifest.Hosts, host)
- }
for _, hook := range hooks {
manifest.Hooks = append(manifest.Hooks, hook)
}
@@ -797,14 +746,14 @@
if err != nil {
return nil, err
}
- _, remoteProjects, _, _, err := readManifest(jirix)
+ remoteProjects, _, _, err := readManifest(jirix)
if err != nil {
return nil, err
}
// Compute difference between local and remote.
update := Update{}
- ops := computeOperations(localProjects, remoteProjects, false, nil)
+ ops := computeOperations(localProjects, remoteProjects, false, "")
s := jirix.NewSeq()
for _, op := range ops {
name := op.Project().Name
@@ -861,7 +810,7 @@
// ReadManifest retrieves and parses the manifest that determines what
// projects and tools are part of the jiri universe.
func ReadManifest(jirix *jiri.X) (Projects, Tools, error) {
- _, p, t, _, e := readManifest(jirix)
+ p, t, _, e := readManifest(jirix)
return p, t, e
}
@@ -879,19 +828,19 @@
}, "get manifest origin").Done()
}
-func readManifest(jirix *jiri.X) (Hosts, Projects, Tools, Hooks, error) {
+func readManifest(jirix *jiri.X) (Projects, Tools, Hooks, error) {
jirix.TimerPush("read manifest")
defer jirix.TimerPop()
file, err := jirix.ResolveManifestPath(jirix.Manifest())
if err != nil {
- return nil, nil, nil, nil, err
+ return nil, nil, nil, err
}
var imp importer
- hosts, projects, tools, hooks := Hosts{}, Projects{}, Tools{}, Hooks{}
- if err := imp.Load(jirix, jirix.Root, file, "", hosts, projects, tools, hooks); err != nil {
- return nil, nil, nil, nil, err
+ projects, tools, hooks := Projects{}, Tools{}, Hooks{}
+ if err := imp.Load(jirix, jirix.Root, file, "", projects, tools, hooks); err != nil {
+ return nil, nil, nil, err
}
- return hosts, projects, tools, hooks, nil
+ return projects, tools, hooks, nil
}
func updateManifestProjects(jirix *jiri.X) error {
@@ -944,13 +893,13 @@
if err := updateManifestProjects(jirix); err != nil {
return err
}
- remoteHosts, remoteProjects, remoteTools, remoteHooks, err := readManifest(jirix)
+ remoteProjects, remoteTools, remoteHooks, err := readManifest(jirix)
if err != nil {
return err
}
s := jirix.NewSeq()
// 1. Update all local projects to match their remote counterparts.
- if err := updateProjects(jirix, remoteProjects, gc, remoteHosts); err != nil {
+ if err := updateProjects(jirix, remoteProjects, gc); err != nil {
return err
}
// 2. Build all tools in a temporary directory.
@@ -1214,9 +1163,9 @@
return true, nil
}
-// projectAtPath returns a Project struct corresponding to the project at the
+// ProjectAtPath returns a Project struct corresponding to the project at the
// path in the filesystem.
-func projectAtPath(jirix *jiri.X, path string) (Project, error) {
+func ProjectAtPath(jirix *jiri.X, path string) (Project, error) {
metadataFile := filepath.Join(path, jiri.ProjectMetaDir, jiri.ProjectMetaFile)
project, err := ProjectFromFile(jirix, metadataFile)
if err != nil {
@@ -1234,7 +1183,7 @@
return err
}
if isLocal {
- project, err := projectAtPath(jirix, path)
+ project, err := ProjectAtPath(jirix, path)
if err != nil {
return err
}
@@ -1465,13 +1414,13 @@
return nil
}
-func (imp *importer) Load(jirix *jiri.X, root, file, key string, hosts Hosts, projects Projects, tools Tools, hooks Hooks) error {
+func (imp *importer) Load(jirix *jiri.X, root, file, key string, projects Projects, tools Tools, hooks Hooks) error {
return imp.importNoCycles(file, key, func() error {
- return imp.load(jirix, root, file, hosts, projects, tools, hooks)
+ return imp.load(jirix, root, file, projects, tools, hooks)
})
}
-func (imp *importer) load(jirix *jiri.X, root, file string, hosts Hosts, projects Projects, tools Tools, hooks Hooks) error {
+func (imp *importer) load(jirix *jiri.X, root, file string, projects Projects, tools Tools, hooks Hooks) error {
m, err := ManifestFromFile(jirix, file)
if err != nil {
return err
@@ -1491,14 +1440,14 @@
return err
}
}
- if err := imp.Load(jirix, newRoot, newFile, _import.remoteKey(), hosts, projects, tools, hooks); err != nil {
+ if err := imp.Load(jirix, newRoot, newFile, _import.remoteKey(), projects, tools, hooks); err != nil {
return err
}
}
// Process all file imports.
for _, fileImport := range m.FileImports {
newFile := filepath.Join(filepath.Dir(file), fileImport.File)
- if err := imp.Load(jirix, root, newFile, "", hosts, projects, tools, hooks); err != nil {
+ if err := imp.Load(jirix, root, newFile, "", projects, tools, hooks); err != nil {
return err
}
}
@@ -1520,10 +1469,6 @@
hook.Path = filepath.Join(project.Path, hook.Path)
hooks[hook.Name] = hook
}
- // Process all hosts.
- for _, host := range m.Hosts {
- hosts[host.Name] = host
- }
return nil
}
@@ -1554,10 +1499,7 @@
localProject = &p
}
// Since &remote.Project is never nil, we'll never produce a delete op.
- //
- // TODO(toddw): How do we retrieve the hosts, which are necessary for
- // githooks to be installed during the create operation?
- op := computeOp(localProject, &remote.Project, false, nil)
+ op := computeOp(localProject, &remote.Project, false, newRoot)
if err := op.Test(jirix, newFsUpdates()); err != nil {
return err
}
@@ -1624,6 +1566,24 @@
}
}
+// collectGoogleSourceHosts returns a slice of googlesource hosts for the given
+// projects. Each host will appear once in the slice.
+func collectGoogleSourceHosts(ps Projects) []string {
+ hostsMap := map[string]bool{}
+ for _, p := range ps {
+ if !googlesource.IsGoogleSourceRemote(p.Remote) {
+ continue
+ }
+ u, err := url.Parse(p.Remote)
+ if err != nil {
+ continue
+ }
+ host := u.Scheme + "://" + u.Host
+ hostsMap[host] = true
+ }
+ return set.StringBool.ToSlice(hostsMap)
+}
+
// getRemoteHeadRevisions attempts to get the repo statuses from remote for HEAD
// projects so we can detect when a local project is already up-to-date.
func getRemoteHeadRevisions(jirix *jiri.X, remoteProjects Projects) {
@@ -1637,21 +1597,24 @@
if !someAtHead {
return
}
- gitHost, gitHostErr := GitHost(jirix)
- if gitHostErr != nil || !googlesource.IsGoogleSourceHost(gitHost) {
- return
- }
- repoStatuses, err := googlesource.GetRepoStatuses(jirix, gitHost)
- if err != nil {
- // Log the error but don't fail.
- fmt.Fprintf(jirix.Stderr(), "Error fetching repo statuses from remote: %v\n", err)
- return
+ gsHosts := collectGoogleSourceHosts(remoteProjects)
+ allRepoStatuses := googlesource.RepoStatuses{}
+ for _, host := range gsHosts {
+ repoStatuses, err := googlesource.GetRepoStatuses(jirix, host)
+ if err != nil {
+ // Log the error but don't fail.
+ fmt.Fprintf(jirix.Stderr(), "Error fetching repo statuses from remote: %v\n", err)
+ continue
+ }
+ for repo, status := range repoStatuses {
+ allRepoStatuses[repo] = status
+ }
}
for name, rp := range remoteProjects {
if rp.Revision != "HEAD" {
continue
}
- status, ok := repoStatuses[rp.Name]
+ status, ok := allRepoStatuses[rp.Name]
if !ok {
continue
}
@@ -1664,7 +1627,7 @@
}
}
-func updateProjects(jirix *jiri.X, remoteProjects Projects, gc bool, hosts Hosts) error {
+func updateProjects(jirix *jiri.X, remoteProjects Projects, gc bool) error {
jirix.TimerPush("update projects")
defer jirix.TimerPop()
@@ -1677,7 +1640,7 @@
return err
}
getRemoteHeadRevisions(jirix, remoteProjects)
- ops := computeOperations(localProjects, remoteProjects, gc, hosts)
+ ops := computeOperations(localProjects, remoteProjects, gc, "")
updates := newFsUpdates()
for _, op := range ops {
if err := op.Test(jirix, updates); err != nil {
@@ -1820,7 +1783,7 @@
// createOperation represents the creation of a project.
type createOperation struct {
commonOperation
- hosts Hosts
+ root string
}
func (op createOperation) Run(jirix *jiri.X, manifest *Manifest) (e error) {
@@ -1847,24 +1810,32 @@
// overriding existing hooks. Customizing your git hooks with jiri is a bad
// idea anyway, since jiri won't know to not delete the project when you
// switch between manifests or do a cleanup.
- host, found := op.hosts["git"]
- if found && strings.HasPrefix(op.project.Remote, host.Location) {
- gitHookDir := filepath.Join(tmpDir, ".git", "hooks")
- for _, githook := range host.GitHooks {
- // TODO(nlacasse): GitHook paths are relative to the manifest
- // file. Currently all manifests live in
- // JIRI_ROOT/.manifest/v2, but that is changing. I think
- // GitHooks should be associated with projects, and their paths
- // should be relative to the project root.
- mdir := filepath.Join(jirix.Root, ".manifest", "v2")
- src, err := s.ReadFile(filepath.Join(mdir, githook.Path))
+ gitHooksDstDir := filepath.Join(tmpDir, ".git", "hooks")
+ if op.project.GitHooks != "" {
+ gitHooksSrcDir := filepath.Join(jirix.Root, op.root, op.project.GitHooks)
+ // Copy the specified GitHooks directory into the project's git
+ // hook directory. We walk the file system, creating directories
+ // and copying files as we encounter them.
+ copyFn := func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
- dst := filepath.Join(gitHookDir, githook.Name)
- if err := s.WriteFile(dst, src, perm).Done(); err != nil {
+ relPath, err := filepath.Rel(gitHooksSrcDir, path)
+ if err != nil {
return err
}
+ dst := filepath.Join(gitHooksDstDir, relPath)
+ if info.IsDir() {
+ return s.MkdirAll(dst, perm).Done()
+ }
+ src, err := s.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ return s.WriteFile(dst, src, perm).Done()
+ }
+ if err := filepath.Walk(gitHooksSrcDir, copyFn); err != nil {
+ return err
}
}
@@ -2125,7 +2096,7 @@
// system and manifest file respectively) and outputs a collection of
// operations that describe the actions needed to update the target
// projects.
-func computeOperations(localProjects, remoteProjects Projects, gc bool, hosts Hosts) operations {
+func computeOperations(localProjects, remoteProjects Projects, gc bool, root string) operations {
result := operations{}
allProjects := map[ProjectKey]bool{}
for _, p := range localProjects {
@@ -2142,13 +2113,13 @@
if project, ok := remoteProjects[key]; ok {
remote = &project
}
- result = append(result, computeOp(local, remote, gc, hosts))
+ result = append(result, computeOp(local, remote, gc, root))
}
sort.Sort(result)
return result
}
-func computeOp(local, remote *Project, gc bool, hosts Hosts) operation {
+func computeOp(local, remote *Project, gc bool, root string) operation {
switch {
case local != nil && remote != nil:
if local.Path != remote.Path {
@@ -2183,7 +2154,7 @@
destination: remote.Path,
project: *remote,
source: "",
- }, hosts}
+ }, root}
default:
panic("jiri: computeOp called with nil local and remote")
}
diff --git a/project/project_test.go b/project/project_test.go
index 6981995..346a37d 100644
--- a/project/project_test.go
+++ b/project/project_test.go
@@ -118,16 +118,6 @@
}
manifest.Projects = append(manifest.Projects, project)
}
- manifest.Hosts = []project.Host{
- {
- Name: "gerrit",
- Location: "git://example.com/gerrit",
- },
- {
- Name: "git",
- Location: "git://example.com/git",
- },
- }
commitManifest(t, jirix, &manifest, dir)
}
@@ -932,14 +922,6 @@
},
},
},
- Hosts: []project.Host{
- {
- Name: "git",
- GitHooks: []project.GitHook{
- {Name: "githook"},
- },
- },
- },
Imports: []project.Import{
{
Manifest: "manifest",
@@ -958,6 +940,8 @@
},
Projects: []project.Project{
{
+ GerritHost: "https://test-review.googlesource.com",
+ GitHooks: "path/to/githooks",
Name: "project",
Path: "path",
Protocol: "git",
@@ -982,20 +966,13 @@
<arg>bar</arg>
</hook>
</hooks>
- <hosts>
- <host name="git">
- <githooks>
- <githook name="githook"/>
- </githooks>
- </host>
- </hosts>
<imports>
<import manifest="manifest" remote="remote"/>
<import name="localimport"/>
<fileimport file="fileimport"/>
</imports>
<projects>
- <project name="project" path="path" remote="remote" remotebranch="otherbranch" revision="rev"/>
+ <project name="project" path="path" remote="remote" remotebranch="otherbranch" revision="rev" gerrithost="https://test-review.googlesource.com" githooks="path/to/githooks"/>
</projects>
<tools>
<tool data="tooldata" name="tool" project="toolproject"/>