Morpheus / Mbed OS mbed-Client-Morpheus-hg

Dependencies:   mbed-os

neo.py

Committer:
screamer
Date:
2016-03-30
Revision:
4:6e987db7a950
Parent:
3:47aa05d37724
Child:
5:37ac884d9477

File content as of revision 4:6e987db7a950:

#!/usr/bin/env python

import argparse
import sys
import re
import subprocess
import os
import contextlib
import collections

# Subparser handling
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

def subcommand(name, *args, **kwargs):
    def subcommand(command):
        subparser = subparsers.add_parser(name, **kwargs)
    
        for arg in args:
            subparser.add_argument(arg)
    
        def thunk(parsed_args):
            ordered_args = [vars(parsed_args)[arg] for arg in args]
            return command(*ordered_args)
    
        subparser.set_defaults(command=thunk)
        return command
    return subcommand

# Process execution
class ProcessException(Exception):
    pass

def popen(command, stdin=None):
    # print for debugging
    print ' '.join(command)
    proc = subprocess.Popen(command)

    if proc.wait() != 0:
        raise ProcessException(proc.returncode)

def pquery(command, stdin=None):
    proc = subprocess.Popen(command, stdout=subprocess.PIPE)
    stdout, _ = proc.communicate(stdin)

    if proc.returncode != 0:
        raise ProcessException(proc.returncode)

    return stdout

# Directory navigation
@contextlib.contextmanager
def cd(newdir):
    prevdir = os.getcwd()
    os.chdir(newdir)
    try:
        yield
    finally:
        os.chdir(prevdir)

def iterlibs(dir=None):
    for file in os.listdir(dir or os.getcwd()):
        if file.startswith('.'):
            continue
        elif os.path.isfile(file) and file.endswith('.lib'):
            with open(file) as f:
                yield f.read().strip()

def savelib(repo):
    print repo.name, '->', repo.url

    with open(repo.lib, 'w') as f:
        f.write(repo.url + '\n')


# Handling for multiple version controls
class Repo(object):
    def __init__(self, path=None):
        self.path = path or os.getcwd()
        self.name = os.path.basename(self.path)
        self.update()

    @classmethod
    def fromurl(cls, url):
        repo = cls.__new__(cls)

        m = re.match('^(.*/([+a-zA-Z0-9_-]+)/?)(?:#(.*))?$', url)
        repo.repo = m.group(1)
        repo.name = m.group(2)
        repo.hash = m.group(3)

        repo.path = os.path.join(os.getcwd(), repo.name)
        return repo

    @property
    def lib(self):
        return self.path + '.lib'

    @property
    def url(self):
        if self.repo:
            if self.hash:
                return self.repo + '#' + self.hash
            else:
                return self.repo

    def update(self):
        if os.path.isdir(self.path):
            self.type = self.gettype()
            self.hash = self.gethash()

        if os.path.isfile(self.lib):
            with open(self.lib) as f:
                temp = Repo.fromurl(f.read())
                self.repo = temp.repo

    def gettype(self):
        for type, dir in [('git', '.git'), ('hg', '.hg')]:
            if os.path.isdir(os.path.join(self.path, dir)):
                return type

    def gethash(self):
        with cd(self.path):
            if self.type == 'git':
                return pquery(['git', 'rev-parse', '--short', 'HEAD']).strip()
            elif self.type == 'hg':
                return pquery(['hg', 'id', '-i']).strip()

# Clone command
@subcommand('import', 'url',
    help='recursively import a repository')
def import_(url):
    repo = Repo.fromurl(url)

    for type in ['git', 'hg']:
        try:
            popen([type, 'clone', repo.repo])
            break
        except:
            pass

    repo.type = repo.gettype()

    if repo.hash:
        with cd(repo.path):
            popen([repo.type, 'checkout', repo.hash])

    repo.update()

    with cd(repo.path):
        for lib in iterlibs():
            import_(lib)

# Install/uninstall command
@subcommand('add', 'url',
    help='add a library to the current repository')
def add(url):
    cwd = Repo()
    repo = Repo.fromurl(url)

    import_(url)

    repo.update()
    savelib(repo)

    popen([cwd.type, 'add', repo.lib])

@subcommand('remove', 'library',
    help='remove a library from the current repository folder')
def remove(library):
    cwd = Repo()
    repo = Repo(library)

    popen([cwd.type, 'rm', '-f', repo.lib])
    if cwd.type == 'hg':
        popen(['rm', '-f', repo.lib])

    popen(['rm', '-rf', repo.path])

# Synch command
@subcommand('synch',
    help='synchronize lib files')
def synch():
    cwd = Repo()

    for lib in iterlibs():
        repo = Repo.fromurl(lib)
        repo.update()
        if lib == repo.url:
            continue

        savelib(repo)

        if cwd.type == 'git':
            popen([cwd.type, 'add', repo.lib])

# Parse/run command
args = parser.parse_args()
status = args.command(args)
sys.exit(status or 0)