manifest: refactor git checks into project commands

It's nicer for the user of the manifest library (e.g. 'west diff') to
decide what should happen if git is not available, so move some
warning calls about missing git into project.py, and add a new helper
for dealing with dying when git is not found.

This lets us keep using log.wrn() for this detection, which we are
about to stop doing from manifest.py.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Martí Bolívar 2020-01-22 07:14:31 -08:00 committed by Marti Bolivar
parent 5e06d90b7c
commit c4a3bb8cb7
2 changed files with 28 additions and 15 deletions

View File

@ -6,7 +6,7 @@
'''West project commands'''
import argparse
from functools import partial
from functools import partial, lru_cache
import os
from os.path import join, relpath, basename, dirname, exists, isdir
import shutil
@ -181,8 +181,7 @@ class Init(_ProjectCommand):
if args.local and (args.manifest_url or args.manifest_rev):
log.die('-l cannot be combined with -m or --mr')
if shutil.which('git') is None:
log.die("can't find git; install it or ensure it's on your PATH")
die_if_no_git()
if args.local:
topdir = self.local(args)
@ -379,6 +378,8 @@ class List(_ProjectCommand):
def do_run(self, args, user_args):
def sha_thunk(project):
die_if_no_git()
if not project.is_cloned():
log.die(f'cannot get sha for uncloned project {project.name}; '
f'run "west update {project.name}" and retry')
@ -388,6 +389,8 @@ class List(_ProjectCommand):
return f'{"N/A":40}'
def cloned_thunk(project):
die_if_no_git()
return "cloned" if project.is_cloned() else "not-cloned"
def delay(func, project):
@ -519,6 +522,8 @@ class Diff(_ProjectCommand):
return parser
def do_run(self, args, ignored):
die_if_no_git()
failed = []
for project in self._cloned_projects(args):
log.banner(f'diff for {project.name_and_path}:')
@ -544,6 +549,8 @@ class Status(_ProjectCommand):
return parser
def do_run(self, args, user_args):
die_if_no_git()
failed = []
for project in self._cloned_projects(args):
log.banner(f'status of {project.name_and_path}:')
@ -612,6 +619,8 @@ class Update(_ProjectCommand):
return parser
def do_run(self, args, user_args):
die_if_no_git()
self.args = args
if args.exclude_west:
log.wrn('ignoring --exclude-west')
@ -1046,6 +1055,22 @@ def _post_checkout_help(project, branch, sha, is_ancestor):
log.dbg('(To do this automatically in the future,',
'use "west update --rebase".)')
@lru_cache(maxsize=1)
def warn_once_if_no_git():
# Using an LRU cache means this gets called once. Afterwards, the
# memoized return value (None) is simply returned from the cache,
# so the warning is emitted only once per process invocation.
if shutil.which('git') is None:
log.wrn('git is not installed or cannot be found; this may fail')
@lru_cache(maxsize=1)
def die_if_no_git():
# Using an LRU cache means this only calls shutil.which() once.
# This is useful when the function is called multiple times, e.g.
# from the west list thunk for computing a SHA.
if shutil.which('git') is None:
log.die("can't find git; install it or ensure it's on your PATH")
#
# Special files and directories in the west workspace.
#

View File

@ -11,10 +11,8 @@ import collections
import configparser
import enum
import errno
from functools import lru_cache
import os
from pathlib import PurePath, Path
import shutil
import shlex
import subprocess
@ -1156,8 +1154,6 @@ class Project:
raised if git finishes with a non-zero return code
:param cwd: directory to run git in (default: ``self.abspath``)
'''
_warn_once_if_no_git()
if isinstance(cmd, str):
cmd_list = shlex.split(cmd)
else:
@ -1452,14 +1448,6 @@ _EARLIEST_VER_STR = '0.6.99' # we introduced the version feature after 0.6
_EARLIEST_VER = parse_version(_EARLIEST_VER_STR)
_DEFAULT_REV = 'master'
@lru_cache(maxsize=1)
def _warn_once_if_no_git():
# Using an LRU cache means this gets called once. Afterwards, the
# (nonexistent) memoized result is simply returned from the cache,
# so the warning is emitted only once per process invocation.
if shutil.which('git') is None:
log.wrn('Git is not installed or cannot be found')
def _mpath(cp=None, topdir=None):
# Return the value of the manifest.path configuration option
# in *cp*, a ConfigParser. If not given, create a new one and