~siborgium/src-tree

aa08282c6750c49ec46d7f955351b93c64d52bb4 — Sergey Smirnykh 1 year, 9 months ago
initial commit
1 files changed, 122 insertions(+), 0 deletions(-)

A src-tree
A  => src-tree +122 -0
@@ 1,122 @@
#!/usr/bin/env python3

import argparse
import yaml
import git
from pathlib import Path
import shutil
import sys

def repo_name_from_url(url):
    print(url)
    lastslash = url.rfind('/')
    if lastslash < 0:
        raise Exception('Malformed url')
    lastslash = lastslash + 1

    end = url.rfind('.git')
    if end < 0:
        return url[lastslash:]

    return url[lastslash:end]


def parse_config_file(config):
    with open(config, 'r') as configfile:
        config = yaml.safe_load(configfile)

    # schemas are cool, but let's keep it simple for now
    if not 'repositories' in config:
        raise Exception('Configuration file invalid: repositories not defined')

    repositories = config['repositories']
    if not all(['url' in repo for repo in repositories]):
        raise Exception('Configuration file invalid: not all repositories have url')

    return config


# https://chase-seibert.github.io/blog/2014/03/21/python-multilevel-argparse.html
class SrcTree(object):
    def __init__(self):
        parser = argparse.ArgumentParser(
            prog = 'src-tree',
            description = 'A simple script to setup and build source tree',
            usage = 'src-tree <command> [<args>]')
        parser.add_argument('command')

        args = parser.parse_args(sys.argv[1:2])
        if not hasattr(self, args.command):
            print('Unrecognized command')
            parser.print_help()
            exit(1)
        getattr(self, args.command)()

    def clone(self):
        parser = argparse.ArgumentParser(
            description='Clone source tree consisting of multiple repos as described by config file')
        parser.add_argument('config')
        parser.add_argument('--root')
        args = parser.parse_args(sys.argv[2:])

        config = parse_config_file(args.config)
      
        root = Path(args.root) if args.root is not None else Path.cwd()

        for repo in config['repositories']:
            url = repo['url']
            name = repo['name'] if 'name' in repo else repo_name_from_url(url)
            branch = repo['branch'] if 'branch' in repo else 'trunk'

            cloneto = root / name
            git.Repo.clone_from(url, cloneto, single_branch = True, branch = branch)

    def link(self):
        parser = argparse.ArgumentParser(
            description='Link build directory of multiple repos as described by config file')
        parser.add_argument('config')
        parser.add_argument('--builddir', required=True)
        parser.add_argument('--targetdir')
        parser.add_argument('--root')
        parser.add_argument('--force', default = False)

        args = parser.parse_args(sys.argv[2:])

        config = parse_config_file(args.config)

        root = Path(args.root) if args.root is not None else Path.cwd()
        targetdir = root / (args.targetdir if args.targetdir is not None else args.builddir)
        targetdir.mkdir(parents = True, exist_ok = True)

        for repo in config['repositories']:
            name = repo['name'] if 'name' in repo else repo_name_from_url(repo['url'])
            dir = root / name / args.builddir
            print(name)
            print('{} => {}', repo['url'], dir)

            if dir.is_symlink():
                dir.unlink(missing_ok=True)

            if dir.exists() and not dir.is_dir():
                raise Exception(f'builddir=\'{dir}\' is not a directory')

            if dir.is_dir():
                count = 0
                for _ in dir.iterdir():
                    count = count + 1
                if count == 0:
                    dir.rmdir()
                elif not dir.args.force:
                    raise Exception(f'builddir=\'{dir}\' is not a symlink')
                else:
                    print(f'Warning: builddir=\'{dir}\' is not a symlink, removing anyway...', file = sys.stderr)
                    shutil.rmtree(dir)

            print(dir)
            dir.parent.mkdir(parents = True, exist_ok = True)
            dir.symlink_to(targetdir)
           


if __name__ == '__main__':
    SrcTree()