github.com/btwiuse/jiri@v0.0.0-20191125065820-53353bcfef54/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  
    10  	"github.com/btwiuse/jiri"
    11  	"github.com/btwiuse/jiri/gitutil"
    12  	"github.com/btwiuse/jiri/tool"
    13  )
    14  
    15  type ReferenceState struct {
    16  	Name     string
    17  	Revision string
    18  }
    19  
    20  type BranchState struct {
    21  	*ReferenceState
    22  	Tracking *ReferenceState
    23  }
    24  
    25  type ProjectState struct {
    26  	Branches       []BranchState
    27  	CurrentBranch  BranchState
    28  	HasUncommitted bool
    29  	HasUntracked   bool
    30  	Project        Project
    31  }
    32  
    33  func setProjectState(jirix *jiri.X, state *ProjectState, checkDirty bool, ch chan<- error) {
    34  	var err error
    35  	scm := gitutil.New(jirix, gitutil.RootDirOpt(state.Project.Path))
    36  	branches, err := scm.GetAllBranchesInfo()
    37  	if err != nil {
    38  		ch <- err
    39  		return
    40  	}
    41  	state.CurrentBranch = BranchState{
    42  		&ReferenceState{
    43  			Name: "",
    44  		},
    45  		nil,
    46  	}
    47  	for _, branch := range branches {
    48  		b := BranchState{
    49  			&ReferenceState{
    50  				Name:     branch.Name,
    51  				Revision: branch.Revision,
    52  			},
    53  			nil,
    54  		}
    55  		if branch.Tracking != nil {
    56  			b.Tracking = &ReferenceState{
    57  				Name:     branch.Tracking.Name,
    58  				Revision: branch.Tracking.Revision,
    59  			}
    60  		}
    61  		state.Branches = append(state.Branches, b)
    62  		if branch.IsHead {
    63  			state.CurrentBranch = b
    64  		}
    65  	}
    66  	if state.CurrentBranch.Name == "" {
    67  		if state.CurrentBranch.Revision, err = scm.CurrentRevision(); err != nil {
    68  			ch <- err
    69  			return
    70  		}
    71  	}
    72  	if checkDirty {
    73  		state.HasUncommitted, err = scm.HasUncommittedChanges()
    74  		if err != nil {
    75  			ch <- fmt.Errorf("Cannot get uncommited changes for project %q: %v", state.Project.Name, err)
    76  			return
    77  		}
    78  		state.HasUntracked, err = scm.HasUntrackedFiles()
    79  		if err != nil {
    80  			ch <- fmt.Errorf("Cannot get untracked changes for project %q: %v", state.Project.Name, err)
    81  			return
    82  		}
    83  	}
    84  	ch <- nil
    85  }
    86  
    87  func GetProjectStates(jirix *jiri.X, projects Projects, checkDirty bool) (map[ProjectKey]*ProjectState, error) {
    88  	jirix.TimerPush("Get project states")
    89  	defer jirix.TimerPop()
    90  	states := make(map[ProjectKey]*ProjectState, len(projects))
    91  	sem := make(chan error, len(projects))
    92  	for key, project := range projects {
    93  		state := &ProjectState{
    94  			Project: project,
    95  		}
    96  		states[key] = state
    97  		// jirix is not threadsafe, so we make a clone for each goroutine.
    98  		go setProjectState(jirix.Clone(tool.ContextOpts{}), state, checkDirty, sem)
    99  	}
   100  	for _ = range projects {
   101  		err := <-sem
   102  		if err != nil {
   103  			return nil, err
   104  		}
   105  	}
   106  	return states, nil
   107  }
   108  
   109  func GetProjectState(jirix *jiri.X, project Project, checkDirty bool) (*ProjectState, error) {
   110  	sem := make(chan error, 1)
   111  	state := &ProjectState{
   112  		Project: project,
   113  	}
   114  	setProjectState(jirix, state, checkDirty, sem)
   115  	return state, <-sem
   116  }