v.io/jiri@v0.0.0-20160715023856-abfb8b131290/project/state.go (about) 1 // Copyright 2015 The Vanadium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package project 6 7 import ( 8 "fmt" 9 "path/filepath" 10 11 "v.io/jiri" 12 "v.io/jiri/gitutil" 13 "v.io/jiri/runutil" 14 "v.io/jiri/tool" 15 ) 16 17 type BranchState struct { 18 HasGerritMessage bool 19 Name string 20 } 21 22 type ProjectState struct { 23 Branches []BranchState 24 CurrentBranch string 25 HasUncommitted bool 26 HasUntracked bool 27 Project Project 28 } 29 30 func setProjectState(jirix *jiri.X, state *ProjectState, checkDirty bool, ch chan<- error) { 31 var err error 32 switch state.Project.Protocol { 33 case "git": 34 scm := gitutil.New(jirix.NewSeq(), gitutil.RootDirOpt(state.Project.Path)) 35 var branches []string 36 branches, state.CurrentBranch, err = scm.GetBranches() 37 if err != nil { 38 ch <- err 39 return 40 } 41 for _, branch := range branches { 42 file := filepath.Join(state.Project.Path, jiri.ProjectMetaDir, branch, ".gerrit_commit_message") 43 hasFile := true 44 if _, err := jirix.NewSeq().Stat(file); err != nil { 45 if !runutil.IsNotExist(err) { 46 ch <- err 47 return 48 } 49 hasFile = false 50 } 51 state.Branches = append(state.Branches, BranchState{ 52 Name: branch, 53 HasGerritMessage: hasFile, 54 }) 55 } 56 if checkDirty { 57 state.HasUncommitted, err = scm.HasUncommittedChanges() 58 if err != nil { 59 ch <- err 60 return 61 } 62 state.HasUntracked, err = scm.HasUntrackedFiles() 63 if err != nil { 64 ch <- err 65 return 66 } 67 } 68 default: 69 ch <- UnsupportedProtocolErr(state.Project.Protocol) 70 return 71 } 72 ch <- nil 73 } 74 75 func GetProjectStates(jirix *jiri.X, checkDirty bool) (map[ProjectKey]*ProjectState, error) { 76 projects, err := LocalProjects(jirix, FastScan) 77 if err != nil { 78 return nil, err 79 } 80 states := make(map[ProjectKey]*ProjectState, len(projects)) 81 sem := make(chan error, len(projects)) 82 for key, project := range projects { 83 state := &ProjectState{ 84 Project: project, 85 } 86 states[key] = state 87 // jirix is not threadsafe, so we make a clone for each goroutine. 88 go setProjectState(jirix.Clone(tool.ContextOpts{}), state, checkDirty, sem) 89 } 90 for _ = range projects { 91 err := <-sem 92 if err != nil { 93 return nil, err 94 } 95 } 96 return states, nil 97 } 98 99 func GetProjectState(jirix *jiri.X, key ProjectKey, checkDirty bool) (*ProjectState, error) { 100 projects, err := LocalProjects(jirix, FastScan) 101 if err != nil { 102 return nil, err 103 } 104 sem := make(chan error, 1) 105 for k, project := range projects { 106 if k == key { 107 state := &ProjectState{ 108 Project: project, 109 } 110 setProjectState(jirix, state, checkDirty, sem) 111 return state, <-sem 112 } 113 } 114 return nil, fmt.Errorf("failed to find project key %v", key) 115 }