~siborgium/src-tree

3337dabebd09be792194a3045f01ede920132303 — Sergey Smirnykh 1 year, 3 months ago 02f0a3d
checkout command, dry parsers a bit
1 files changed, 59 insertions(+), 14 deletions(-)

M src-tree
M src-tree => src-tree +59 -14
@@ 47,49 47,94 @@ class SrcTree(object):
        parser.add_argument('command')

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

    def _parse_args(self, parser):
        parser.add_argument('--root', help = 'Source tree root')
        args = parser.parse_args(sys.argv[2:])

        self.root = Path(args.root) if args.root is not None else Path.cwd()
        self.root = self.root.absolute()
        return args

    def clone(self):
        parser = argparse.ArgumentParser(
            description='Clone source tree consisting of multiple repos as described by config file')
        parser.add_argument('config', help = 'Configuration file')
        parser.add_argument('--root', help = 'Source tree root')
        args = parser.parse_args(sys.argv[2:])
        parser.add_argument('--missing', default = False, help = 'Only clone if the directory not exists')
        args = self._parse_args(parser)

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

        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
            cloneto = self.root / name
            if cloneto.exists():
                if args.missing:
                    continue
                raise Exception(f'\'{cloneto}\' already exists')
            print(f'Cloning \'{cloneto.relative_to(Path.cwd())}\' <- \'{url}\'')
            git.Repo.clone_from(url, cloneto, single_branch = True, branch = branch)

    def checkout(self):
        parser = argparse.ArgumentParser(
            description='Checkout each repo to specified ref')
        parser.add_argument('config', help = 'Configuration file')
        parser.add_argument('--force', default = False, help = 'Discard any changes')
        args = self._parse_args(parser)

        config = parse_config_file(args.config)
      
        for repo in config['repositories']:
            name = repo['name'] if 'name' in repo else repo_name_from_url(repo['url'])
            branch = repo['branch'] if 'branch' in repo else 'trunk'
            url = repo['url']
            dir = self.root / name
            repo = git.Repo(dir)

            if repo.remotes.origin.url != url:
                if args.force:
                    print(f'Setting origin url to \'{url}\'')
                    repo.remotes.origin.url = url
                    repo.remotes.origin.fetch()

            if branch not in repo.heads:
                print(f'Branch \'{dir.relative_to(Path.cwd())}:{branch}\' does not exist, creating')
                head = repo.create_head(branch, origin.refs[branch])
            else:
                head = repo.heads[branch]

            try:
                diff = repo.index.diff(None)
                if len(diff) != 0:
                    print(f'Warning: \'{dir.relative_to(Path.cwd())}\' is dirty')
                print(f'Checkout \'{dir.relative_to(Path.cwd())}:{branch}\'')
                head.checkout()
            except git.GitCommandError:
                if args.force:
                    print('Resetting index and working tree (--force specified)')
                    repo.head.reference = head
                    repo.head.reset(index=True, working_tree=True)

    def link(self):
        parser = argparse.ArgumentParser(
            description='Link build directory of multiple repos as described by config file')
        parser.add_argument('config', help = 'Configuration file')
        parser.add_argument('--builddir', required=True, help = 'Build directory name')
        parser.add_argument('--targetdir', help = 'Target directory to which all directories will be linked. Defaults to builddir.')
        parser.add_argument('--root', help = 'Source tree root')
        parser.add_argument('--force', default = False, help = 'Remove builddir along with its contents if it exists')

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

        config = parse_config_file(args.config)

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

        if Path(args.builddir).is_absolute():
            raise Exception(f'builddir=\'{args.builddir}\' must be relative')



@@ 102,7 147,7 @@ class SrcTree(object):

        for repo in config['repositories']:
            name = repo['name'] if 'name' in repo else repo_name_from_url(repo['url'])
            dir = root / name / args.builddir
            dir = self.root / name / args.builddir
            if not dir.parent.is_dir():
                shutil.rmtree(targetdir)
                raise Exception(f'{dir.parent} is not a directory')


@@ 128,7 173,7 @@ class SrcTree(object):
            dir.parent.mkdir(parents = True, exist_ok = True)
            print(f'Linking \'{dir.relative_to(Path.cwd())}\' -> \'{targetdir}\'')
            dir.symlink_to(targetdir)
           



if __name__ == '__main__':