Home

Random SCM and Python Fun @ 2009-08-03 21:56:05
Filed under: Code  Tech  Python 
The following code abstracts getting branch lists from Mercurial and Git. I may continue fleshing it out for use with the distributed SCM presence system ... or it might just be prototype code, I don't know.

The output I got from my test repos looked like this:

['master']
['default', 'pep8', 'package_creator', 'package_manager', 'repository']


Enjoy, or else!!!!

import os
import re
import subprocess


class SCM(object):
    """
    Parent class for all SCM's.
    """

    def __init__(self, bin=None):
        """
        Creates the instance.

        :Parameters:
           - `bin`: if a binary is required it's location is here.
        """
        self.__bin = bin

    def _execute(self, command):
        """
        Helps execute shell commands.

        :Parameters:
           - `command`: the command to execute.
        """
        process = subprocess.Popen(command, shell=True,
            stdin=subprocess.PIPE, stdout=subprocess.PIPE,
            stderr=subprocess.PIPE, close_fds=True)
        return process.stdout, process.stderr

    def _branch_parser(self, data):
        """
        Parses the branch return results. Defaults to a pass through.

        :Parameters:
           - `data`: the data to parse.
        """
        return data

    def get_branches(self, repo_path):
        """
        Get a list of branches.

        :Parameters:
           - `repo_path`: path on the file system to the repository.
        """
        raise NotImplementedError("_get_branches must be implemented")

    # read-only properties
    bin = property(lambda s: s.__bin)


class Git(SCM):
    """
    The Git SCM.
    """

    def _branch_parser(self, data):
        """
        Parses the branch return results. Defaults to a pass through.

        :Parameters:
           - `data`: the data to parse.
        """
        return re.findall("\* ([^ ]*)\n", data)

    def get_branches(self, repo_path):
        """
        Get a list of branches.

        :Parameters:
           - `repo_path`: path on the file system to the repository.
        """
        out, err = self._execute("%s branch" % self.bin)
        error_info = err.read()
        if error_info:
            raise Exception(error_info)
        return self._branch_parser(out.read())


class Mercurial(SCM):
    """
    The Mercurial (hg) SCM.
    """

    def get_branches(self, repo_path):
        """
        Get a list of branches.

        :Parameters:
           - `repo_path`: path on the file system to the repository.
        """
        from mercurial import ui, hg
        a = hg.repository(ui.ui(), path=repo_path)
        return a.branchmap().keys()


class Repository(object):
    """
    An SCM agnostic repository class.
    """

    def __init__(self, name, location, clone_url, repo_class,
        repo_args=[], repo_kwargs={}):
        """
        Creates an instance of the repostory representation.

        :Parameters:
           - `name`: a nice name for the repository.
           - `location`: location on the filesystem of the repository.
           - `clone_url`: how to clone the repository.
           - `repo_class`: the class to use when getting data from the repo.
           - `repo_args`: non-keyword args to pass through to the repo class.
           - `repo_kwargs`: keword args to pass through to the repo class.
        """
        self.__name = name
        self.__location = location
        self.__repo_class = repo_class
        self.__obj = self.__repo_class(*repo_args, **repo_kwargs)

    def __repr__(self):
        """
        String representation of this instance.
        """
        return "<Repository %s: type='%s',class='%s'>" % (
            self.name, self.location, self.__repo_class.__name__)

    def _get_branches(self):
        """
        Gets all branches in this instance of a repository.
        """
        os.chdir(self.__location)
        return self.__obj.get_branches(self.__location)

    # read-only properties
    name = property(lambda s: s.__name)
    location = property(lambda s: s.__location)
    repo_class = property(lambda s: s.__repo_class)
    branches = property(lambda s: s._get_branches())


# Examples
g = Repository('pyclean', '/home/steve/Tech/pyclean/', 'http://stevemilner.org', Git, ['/usr/bin/git'])
print g.branches
m = Repository('winlibre', '/tmp/winlibre/', 'http://stevemilner.org', Mercurial)
print m.branches

 digg it   seed it   del.icio.us   ma.gnolia
Tags:       Log in to post comments.


 
A Django joint.
© 2007-2009 Steve 'Ashcrow' Milner | Studio7designs | Arbutus Photography