blob: c3d4a7e2413f0929430121c4f778511ea650e12f [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package project
import (
"fmt"
"go.fuchsia.dev/jiri"
"go.fuchsia.dev/jiri/gitutil"
"go.fuchsia.dev/jiri/tool"
)
type ReferenceState struct {
Name string
Revision string
}
type BranchState struct {
*ReferenceState
Tracking *ReferenceState
}
type ProjectState struct {
Branches []BranchState
CurrentBranch BranchState
HasUncommitted bool
HasUntracked bool
Project Project
}
func setProjectState(jirix *jiri.X, state *ProjectState, checkDirty bool, ch chan<- error) {
var err error
scm := gitutil.New(jirix, gitutil.RootDirOpt(state.Project.Path))
branches, err := scm.GetAllBranchesInfo()
if err != nil {
ch <- err
return
}
state.CurrentBranch = BranchState{
&ReferenceState{
Name: "",
},
nil,
}
for _, branch := range branches {
b := BranchState{
&ReferenceState{
Name: branch.Name,
Revision: branch.Revision,
},
nil,
}
if branch.Tracking != nil {
b.Tracking = &ReferenceState{
Name: branch.Tracking.Name,
Revision: branch.Tracking.Revision,
}
}
state.Branches = append(state.Branches, b)
if branch.IsHead {
state.CurrentBranch = b
}
}
if state.CurrentBranch.Name == "" {
if state.CurrentBranch.Revision, err = scm.CurrentRevision(); err != nil {
ch <- err
return
}
}
if checkDirty {
state.HasUncommitted, err = scm.HasUncommittedChanges()
if err != nil {
ch <- fmt.Errorf("Cannot get uncommited changes for project %q: %v", state.Project.Name, err)
return
}
state.HasUntracked, err = scm.HasUntrackedFiles()
if err != nil {
ch <- fmt.Errorf("Cannot get untracked changes for project %q: %v", state.Project.Name, err)
return
}
}
ch <- nil
}
func GetProjectStates(jirix *jiri.X, projects Projects, checkDirty bool) (map[ProjectKey]*ProjectState, error) {
jirix.TimerPush("Get project states")
defer jirix.TimerPop()
states := make(map[ProjectKey]*ProjectState, len(projects))
sem := make(chan error, len(projects))
for key, project := range projects {
state := &ProjectState{
Project: project,
}
states[key] = state
// jirix is not threadsafe, so we make a clone for each goroutine.
go setProjectState(jirix.Clone(tool.ContextOpts{}), state, checkDirty, sem)
}
for range projects {
err := <-sem
if err != nil {
return nil, err
}
}
return states, nil
}
func GetProjectState(jirix *jiri.X, project Project, checkDirty bool) (*ProjectState, error) {
sem := make(chan error, 1)
state := &ProjectState{
Project: project,
}
setProjectState(jirix, state, checkDirty, sem)
return state, <-sem
}