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  }