Source code for pyscaffold.contrib.setuptools_scm.git

from .config import Configuration
from .utils import do_ex, trace, has_command
from .version import meta

from os.path import isfile, join
import warnings


try:
    from os.path import samefile
except ImportError:
    from .win_py31_compat import samefile


DEFAULT_DESCRIBE = "git describe --dirty --tags --long --match *.*"


[docs]class GitWorkdir(object): """experimental, may change at any time""" def __init__(self, path): self.path = path
[docs] def do_ex(self, cmd): return do_ex(cmd, cwd=self.path)
[docs] @classmethod def from_potential_worktree(cls, wd): real_wd, _, ret = do_ex("git rev-parse --show-toplevel", wd) if ret: return trace("real root", real_wd) if not samefile(real_wd, wd): return return cls(real_wd)
[docs] def is_dirty(self): out, _, _ = self.do_ex("git status --porcelain --untracked-files=no") return bool(out)
[docs] def get_branch(self): branch, err, ret = self.do_ex("git rev-parse --abbrev-ref HEAD") if ret: trace("branch err", branch, err, ret) return return branch
[docs] def is_shallow(self): return isfile(join(self.path, ".git/shallow"))
[docs] def fetch_shallow(self): self.do_ex("git fetch --unshallow")
[docs] def node(self): rev_node, _, ret = self.do_ex("git rev-parse --verify --quiet HEAD") if not ret: return rev_node[:7]
[docs] def count_all_nodes(self): revs, _, _ = self.do_ex("git rev-list HEAD") return revs.count("\n") + 1
[docs]def warn_on_shallow(wd): """experimental, may change at any time""" if wd.is_shallow(): warnings.warn('"%s" is shallow and may cause errors' % (wd.path,))
[docs]def fetch_on_shallow(wd): """experimental, may change at any time""" if wd.is_shallow(): warnings.warn('"%s" was shallow, git fetch was used to rectify') wd.fetch_shallow()
[docs]def fail_on_shallow(wd): """experimental, may change at any time""" if wd.is_shallow(): raise ValueError( "%r is shallow, please correct with " '"git fetch --unshallow"' % wd.path )
[docs]def parse( root, describe_command=DEFAULT_DESCRIBE, pre_parse=warn_on_shallow, config=None ): """ :param pre_parse: experimental pre_parse action, may change at any time """ if not config: config = Configuration(root=root) if not has_command("git"): return wd = GitWorkdir.from_potential_worktree(config.absolute_root) if wd is None: return if pre_parse: pre_parse(wd) out, unused_err, ret = wd.do_ex(describe_command) if ret: # If 'git describe' failed, try to get the information otherwise. rev_node = wd.node() dirty = wd.is_dirty() if rev_node is None: return meta("0.0", distance=0, dirty=dirty, config=config) return meta( "0.0", distance=wd.count_all_nodes(), node="g" + rev_node, dirty=dirty, branch=wd.get_branch(), config=config, ) else: tag, number, node, dirty = _git_parse_describe(out) branch = wd.get_branch() if number: return meta( tag, config=config, distance=number, node=node, dirty=dirty, branch=branch, ) else: return meta(tag, config=config, node=node, dirty=dirty, branch=branch)
def _git_parse_describe(describe_output): # 'describe_output' looks e.g. like 'v1.5.0-0-g4060507' or # 'v1.15.1rc1-37-g9bd1298-dirty'. if describe_output.endswith("-dirty"): dirty = True describe_output = describe_output[:-6] else: dirty = False tag, number, node = describe_output.rsplit("-", 2) number = int(number) return tag, number, node, dirty