Exemple #1
0
def git_commit(name, repository, branch_name=None):
    """Return the a Commit object if 'name' is a patch name or Git commit.
    The patch names allowed are in the form '<branch>:<patch>' and can
    be followed by standard symbols used by git rev-parse. If <patch>
    is '{base}', it represents the bottom of the stack. If <patch> is
    {public}, it represents the public branch corresponding to the stack as
    described in the 'publish' command.
    """
    # Try a [branch:]patch name first
    branch, patch = parse_rev(name)
    if not branch:
        branch = branch_name or repository.current_branch_name

    # The stack base
    if patch.startswith('{base}'):
        base_id = repository.get_stack(branch).base.sha1
        return repository.rev_parse(base_id + strip_prefix('{base}', patch))
    elif patch.startswith('{public}'):
        public_ref = get_public_ref(branch)
        return repository.rev_parse(public_ref +
                                    strip_prefix('{public}', patch),
                                    discard_stderr=True)

    # Other combination of branch and patch
    try:
        return repository.rev_parse('patches/%s/%s' % (branch, patch),
                                    discard_stderr=True)
    except RepositoryException:
        pass

    # Try a Git commit
    try:
        return repository.rev_parse(name, discard_stderr=True)
    except RepositoryException:
        raise CmdException('%s: Unknown patch or revision name' % name)
Exemple #2
0
def get_head_file():
    """Return the name of the file pointed to by the HEAD symref.
    Throw an exception if HEAD is detached."""
    try:
        return strip_prefix(
            'refs/heads/', GRun('symbolic-ref', '-q', 'HEAD'
                                ).output_one_line())
    except GitRunException:
        raise DetachedHeadException()
Exemple #3
0
def get_head_file():
    """Return the name of the file pointed to by the HEAD symref.
    Throw an exception if HEAD is detached."""
    try:
        return strip_prefix(
            'refs/heads/',
            GRun('symbolic-ref', '-q', 'HEAD').output_one_line())
    except GitRunException:
        raise DetachedHeadException()
Exemple #4
0
 def metavar(self):
     o = self.get_option()
     if not o.takes_value():
         return None
     if o.metavar:
         return o.metavar
     for flag in self.pargs:
         if flag.startswith('--'):
             return utils.strip_prefix('--', flag).upper()
     raise Exception('Cannot determine metavar')
Exemple #5
0
 def metavar(self):
     o = self.get_option()
     if not o.takes_value():
         return None
     if o.metavar:
         return o.metavar
     for flag in self.pargs:
         if flag.startswith('--'):
             return utils.strip_prefix('--', flag).upper()
     raise Exception('Cannot determine metavar')
Exemple #6
0
def git_commit(name, repository, branch_name = None):
    """Return the a Commit object if 'name' is a patch name or Git commit.
    The patch names allowed are in the form '<branch>:<patch>' and can
    be followed by standard symbols used by git rev-parse. If <patch>
    is '{base}', it represents the bottom of the stack. If <patch> is
    {public}, it represents the public branch corresponding to the stack as
    described in the 'publish' command.
    """
    # Try a [branch:]patch name first
    branch, patch = parse_rev(name)
    if not branch:
        branch = branch_name or repository.current_branch_name

    # The stack base
    if patch.startswith('{base}'):
        base_id = repository.get_stack(branch).base.sha1
        return repository.rev_parse(base_id +
                                    strip_prefix('{base}', patch))
    elif patch.startswith('{public}'):
        public_ref = get_public_ref(branch)
        return repository.rev_parse(public_ref +
                                    strip_prefix('{public}', patch),
                                    discard_stderr = True)

    # Other combination of branch and patch
    try:
        return repository.rev_parse('patches/%s/%s' % (branch, patch),
                                    discard_stderr = True)
    except libgit.RepositoryException:
        pass

    # Try a Git commit
    try:
        return repository.rev_parse(name, discard_stderr = True)
    except libgit.RepositoryException:
        raise CmdException('%s: Unknown patch or revision name' % name)
Exemple #7
0
 def _parse_metadata(repo, metadata):
     """Parse a stack log metadata string."""
     if not metadata.startswith('Version:'):
         raise LogParseException('Malformed log metadata')
     metadata = metadata.splitlines()
     version_str = utils.strip_prefix('Version:', metadata.pop(0)).strip()
     try:
         version = int(version_str)
     except ValueError:
         raise LogParseException('Malformed version number: %r' %
                                 version_str)
     if version < 1:
         raise LogException('Log is version %d, which is too old' % version)
     if version > 1:
         raise LogException('Log is version %d, which is too new' % version)
     parsed = {}
     key = None
     for line in metadata:
         if line.startswith(' '):
             assert key is not None
             parsed[key].append(line.strip())
         else:
             key, val = [x.strip() for x in line.split(':', 1)]
             if val:
                 parsed[key] = val
             else:
                 parsed[key] = []
     prev = parsed['Previous']
     if prev == 'None':
         prev = None
     else:
         prev = repo.get_commit(prev)
     head = repo.get_commit(parsed['Head'])
     lists = {'Applied': [], 'Unapplied': [], 'Hidden': []}
     patches = {}
     for lst in lists:
         for entry in parsed[lst]:
             pn, sha1 = [x.strip() for x in entry.split(':')]
             lists[lst].append(pn)
             patches[pn] = repo.get_commit(sha1)
     return (
         prev,
         head,
         lists['Applied'],
         lists['Unapplied'],
         lists['Hidden'],
         patches,
     )
Exemple #8
0
def git_describe_version():
    path = sys.path[0]
    try:
        v = Run('git', 'describe', '--tags', '--abbrev=4'
                ).cwd(path).output_one_line()
    except RunException as e:
        raise VersionUnavailable(str(e))
    if not re.match(r'^v[0-9]', v):
        raise VersionUnavailable('%s: bad version' % v)
    try:
        dirty = Run('git', 'diff-index', '--name-only', 'HEAD'
                    ).cwd(path).raw_output()
    except RunException as e:
        raise VersionUnavailable(str(e))
    if dirty:
        v += '-dirty'
    return utils.strip_prefix('v', v)
Exemple #9
0
 def __parse_metadata(repo, metadata):
     """Parse a stack log metadata string."""
     if not metadata.startswith('Version:'):
         raise LogParseException('Malformed log metadata')
     metadata = metadata.splitlines()
     version_str = utils.strip_prefix('Version:', metadata.pop(0)).strip()
     try:
         version = int(version_str)
     except ValueError:
         raise LogParseException(
             'Malformed version number: %r' % version_str)
     if version < 1:
         raise LogException('Log is version %d, which is too old' % version)
     if version > 1:
         raise LogException('Log is version %d, which is too new' % version)
     parsed = {}
     for line in metadata:
         if line.startswith(' '):
             parsed[key].append(line.strip())
         else:
             key, val = [x.strip() for x in line.split(':', 1)]
             if val:
                 parsed[key] = val
             else:
                 parsed[key] = []
     prev = parsed['Previous']
     if prev == 'None':
         prev = None
     else:
         prev = repo.get_commit(prev)
     head = repo.get_commit(parsed['Head'])
     lists = { 'Applied': [], 'Unapplied': [], 'Hidden': [] }
     patches = {}
     for lst in lists.keys():
         for entry in parsed[lst]:
             pn, sha1 = [x.strip() for x in entry.split(':')]
             lists[lst].append(pn)
             patches[pn] = repo.get_commit(sha1)
     return (prev, head, lists['Applied'], lists['Unapplied'],
             lists['Hidden'], patches)
Exemple #10
0
def append_alias_commands(cmd_list):
    for (name, command) in config.getstartswith('stgit.alias.'):
        name = utils.strip_prefix('stgit.alias.', name)
        cmd_list[name] = (CommandAlias(name, command),
                          'Alias commands', command)
Exemple #11
0
def append_alias_commands(cmd_list):
    for (name, command) in config.getstartswith('stgit.alias.'):
        name = utils.strip_prefix('stgit.alias.', name)
        cmd_list[name] = (CommandAlias(name,
                                       command), 'Alias commands', command)
Exemple #12
0
 def current_branch_name(self):
     """Return the name of the current branch."""
     return utils.strip_prefix('refs/heads/', self.head_ref)
Exemple #13
0
def func(parser, options, args):
    """Publish the stack changes."""
    repository = directory.repository
    stack = repository.get_stack(options.branch)

    if not args:
        public_ref = common.get_public_ref(stack.name)
    elif len(args) == 1:
        public_ref = args[0]
    else:
        parser.error('incorrect number of arguments')

    if not public_ref.startswith('refs/heads/'):
        public_ref = 'refs/heads/' + public_ref

    # just clone the stack if the public ref does not exist
    if not repository.refs.exists(public_ref):
        if options.unpublished or options.last:
            raise common.CmdException('"%s" does not exist' % public_ref)
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Created "%s"' % public_ref)
        return

    public_head = repository.refs.get(public_ref)
    public_tree = public_head.data.tree

    # find the last published patch
    if options.last:
        last = __get_last(stack, public_tree)
        if not last:
            raise common.CmdException(
                'Unable to find the last published patch '
                '(possibly rebased stack)'
            )
        out.info('%s' % last)
        return

    # check for same tree (already up to date)
    if public_tree.sha1 == stack.head.data.tree.sha1:
        out.info('"%s" already up to date' % public_ref)
        return

    # check for unpublished patches
    if options.unpublished:
        published = set(__get_published(stack, public_tree))
        for p in stack.patchorder.applied:
            if p not in published:
                out.stdout(p)
        return

    if options.overwrite:
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Overwrote "%s"' % public_ref)
        return

    # check for rebased stack. In this case we emulate a merge with the stack
    # base by setting two parents.
    merge_bases = set(repository.get_merge_bases(public_head, stack.base))
    if public_head in merge_bases:
        # fast-forward the public ref
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Fast-forwarded "%s"' % public_ref)
        return
    if stack.base not in merge_bases:
        message = 'Merge %s into %s' % (
            repository.describe(stack.base).strip(),
            utils.strip_prefix('refs/heads/', public_ref),
        )
        public_head = __create_commit(
            repository,
            stack.head.data.tree,
            [public_head, stack.base],
            options,
            message,
        )
        repository.refs.set(public_ref, public_head, 'publish')
        out.info('Merged the stack base into "%s"' % public_ref)
        return

    # check for new patches from the last publishing. This is done by checking
    # whether the public tree is the same as the bottom of the checked patch.
    # If older patches were modified, new patches cannot be detected. The new
    # patches and their metadata are pushed directly to the published head.
    for p in stack.patchorder.applied:
        pc = stack.patches.get(p).commit
        if public_tree.sha1 == pc.data.parent.data.tree.sha1:
            if pc.data.is_nochange():
                out.info('Ignored new empty patch "%s"' % p)
                continue
            cd = pc.data.set_parent(public_head)
            public_head = repository.commit(cd)
            public_tree = public_head.data.tree
            out.info('Published new patch "%s"' % p)

    # create a new commit (only happens if no new patches are detected)
    if public_tree.sha1 != stack.head.data.tree.sha1:
        public_head = __create_commit(repository, stack.head.data.tree,
                                      [public_head], options)

    # update the public head
    repository.refs.set(public_ref, public_head, 'publish')
    out.info('Updated "%s"' % public_ref)
Exemple #14
0
def func(parser, options, args):
    """Publish the stack changes."""
    repository = directory.repository
    stack = repository.get_stack(options.branch)

    if not args:
        public_ref = common.get_public_ref(stack.name)
    elif len(args) == 1:
        public_ref = args[0]
    else:
        parser.error('incorrect number of arguments')

    if not public_ref.startswith('refs/heads/'):
        public_ref = 'refs/heads/' + public_ref

    # just clone the stack if the public ref does not exist
    if not repository.refs.exists(public_ref):
        if options.unpublished or options.last:
            raise common.CmdException('"%s" does not exist' % public_ref)
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Created "%s"' % public_ref)
        return

    public_head = repository.refs.get(public_ref)
    public_tree = public_head.data.tree

    # find the last published patch
    if options.last:
        last = __get_last(stack, public_tree)
        if not last:
            raise common.CmdException('Unable to find the last published patch '
                                      '(possibly rebased stack)')
        out.info('%s' % last)
        return

    # check for same tree (already up to date)
    if public_tree.sha1 == stack.head.data.tree.sha1:
        out.info('"%s" already up to date' % public_ref)
        return

    # check for unpublished patches
    if options.unpublished:
        published = set(__get_published(stack, public_tree))
        for p in stack.patchorder.applied:
            if p not in published:
                print p
        return

    # check for rebased stack. In this case we emulate a merge with the stack
    # base by setting two parents.
    merge_bases = set(repository.get_merge_bases(public_head, stack.base))
    if public_head in merge_bases:
        # fast-forward the public ref
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Fast-forwarded "%s"' % public_ref)
        return
    if not stack.base in merge_bases:
        message = 'Merge %s into %s' % (repository.describe(stack.base).strip(),
                                        utils.strip_prefix('refs/heads/',
                                                           public_ref))
        public_head = __create_commit(repository, stack.head.data.tree,
                                      [public_head, stack.base], options,
                                      message)
        repository.refs.set(public_ref, public_head, 'publish')
        out.info('Merged the stack base into "%s"' % public_ref)
        return

    # check for new patches from the last publishing. This is done by checking
    # whether the public tree is the same as the bottom of the checked patch.
    # If older patches were modified, new patches cannot be detected. The new
    # patches and their metadata are pushed directly to the published head.
    for p in stack.patchorder.applied:
        pc = stack.patches.get(p).commit
        if public_tree.sha1 == pc.data.parent.data.tree.sha1:
            if pc.data.is_nochange():
                out.info('Ignored new empty patch "%s"' % p)
                continue
            cd = pc.data.set_parent(public_head)
            public_head = repository.commit(cd)
            public_tree = public_head.data.tree
            out.info('Published new patch "%s"' % p)

    # create a new commit (only happens if no new patches are detected)
    if public_tree.sha1 != stack.head.data.tree.sha1:
        public_head = __create_commit(repository, stack.head.data.tree,
                                      [public_head], options)

    # update the public head
    repository.refs.set(public_ref, public_head, 'publish')
    out.info('Updated "%s"' % public_ref)
Exemple #15
0
 def current_branch_name(self):
     """Return the name of the current branch."""
     return utils.strip_prefix('refs/heads/', self.head_ref)
Exemple #16
0
    path = sys.path[0]
    try:
        v = run.Run('git', 'describe', '--tags', '--abbrev=4'
                    ).cwd(path).output_one_line()
    except run.RunException, e:
        raise VersionUnavailable(str(e))
    if not re.match(r'^v[0-9]', v):
        raise VersionUnavailable('%s: bad version' % v)
    try:
        dirty = run.Run('git', 'diff-index', '--name-only', 'HEAD'
                        ).cwd(path).raw_output()
    except run.RunException, e:
        raise VersionUnavailable(str(e))
    if dirty:
        v += '-dirty'
    return utils.strip_prefix('v', v)

def builtin_version():
    try:
        import builtin_version as bv
    except ImportError:
        raise VersionUnavailable()
    else:
        return bv.version

def _builtin_version_file(ext = 'py'):
    return os.path.join(sys.path[0], 'stgit', 'builtin_version.%s' % ext)

def write_builtin_version():
    try:
        v = git_describe_version()