view hq/main.py @ 9:0d741a309fdb

add a directory command
author Jeff Hammel <jhammel@mozilla.com>
date Tue, 12 Mar 2013 14:06:29 -0700
parents d1aa54a8fd89
children 5ea675cfecd9
line wrap: on
line source

#!/usr/bin/env python

"""
mercurial queue extension front-end policy manager
"""

# TODO: migrate to http://k0s.org/hg/CommandParser/

import os
import subprocess
import sys

from command import CommandParser

call = subprocess.check_output

class HQ(object):
    """
    mercurial queue extension front-end policy manager
    """

    def __init__(self, queue_host=None, network=True, root=None, binary='hg'):
        """initialize global options"""
        # TODO: look at hgrc file
        # for [defaults] repository_host
        # XXX ???

        # check for network
        self.network = network

        self.queue_host = queue_host

        if root is None:
            root = call(['hg', 'root']).strip()
        self.root = root

        self.binary = binary

    ### subcommands

    def clone(self, repo, patch=None, queue=None):
        """
        clone the repository and begin a patch queue
        - path: name of a new patch to initiate
        - queue: name of the remote queue
        """
        directory = repo.rsplit('/', 1)
        call(['hg', 'clone', repo, directory])
        os.chdir(directory)
        call(['hg', 'qinit', '-c'])
        if queue:
            # pull from the given repository
            self._patch_command(*['hg', 'pull', '--update', queue])
        else:
            # (optionally) setup a new repo
            pass # TODO

        if patch:
            # create a new patch
            call(['hg', 'qnew', patch])

    def commit(self, message):
        """
        commit a patch and push it to the master repository
        - message : commit message
        """
        call(['hg', 'qrefresh'])
        call(['hg', 'qcommit', '-m', message])
        if self.network:
            self._patch_command(*['hg', 'push'])

    def pull(self, repo=None):
        """
        pull from the root repository
        """
        # TODO: commit prior to realignment
        call(['hg', 'qpop', '--all'])
        call(['hg', 'pull'] + repo and [repo] or [])
        call(['hg', 'qpush', '--all'])

    def goto(self, patch):
        """
        go to a specific patch and apply it
        - patch: name of patch to go to
        """
        # TODO
        process = subprocess.Popen(['hg', 'qapplied'], stdout=subprocess.PIPE)
        stdout, stderr = process.communicate()
        applied = [ i.strip() for i in stdout.splitlines()
                    if i ]
        raise NotImplementedError

    def files(self):
        """
        list the files added by the top patch
        """
        # TODO: should only list top-level directories, otherwise it's silly
        _oldcwd = os.getcwd()
        process = subprocess.Popen("hg qdiff | grep '^+++ ' | sed 's/+++ b\///'", stdout=subprocess.PIPE)
        stdout, stderr = process.communicate()
        return stdout

    def status(self):
        """
        display status
        """

        # TODO: once this is on CommandParser, there should be a utility in
        # command parser to allow aliases; e.g. if you do ``st = status`` at
        # the class scope, you can run through the methods and only display
        # one as canon but allow aliases as such.
        # Alternatively, you can allow any short non-ambiguous abbreviation.

        return '\n'.join([self._call(i).strip() for i in ('root', 'status', 'qseries')])

    def directory(self):
        """
        patch queue directory
        """
        patch_dir = os.path.join(self.root, '.hg', 'patches')
        return patch_dir if os.path.isdir(patch_dir) else None

    ### internals

    def _call(self, *args):
        command = [self.binary] + list(args)
        return call(command, cwd=self.root)

    def _patch_repo(self):
        """the location of the patch repository"""
        root = subprocess.Popen(['hg', 'root'], stdout=subprocess.PIPE).communicate()[0]
        return os.path.join(root, '.hg', 'patches')

    def _patch_command(self, *command):
        """perform a command in the patch repository"""
        _oldpwd = os.getcwd()
        os.chdir(self._patch_repo())
        call(command)
        os.chdir(_oldpwd)

def main(args=sys.argv[1:]):
    parser = CommandParser(HQ)
    options, args = parser.parse_args(args)
    parser.invoke(args)

if __name__ == '__main__':
    main()