1#!/usr/local/bin/python3.8
2
3# Copyright Abel Sinkovics (abel@sinkovics.hu) 2016.
4# Distributed under the Boost Software License, Version 1.0.
5#    (See accompanying file LICENSE_1_0.txt or copy at
6#          http://www.boost.org/LICENSE_1_0.txt)
7
8import os
9import subprocess
10import json
11import argparse
12
13
14def load_json(filename):
15    with open(filename, 'r') as f:
16        return json.load(f)
17
18
19class ChildProcess:
20    def __init__(self, cmd, cwd = os.getcwd()):
21        self.cmd = cmd
22        self.cwd = cwd
23
24    def run(self, cmd):
25        cmd_string = ' '.join(cmd)
26        print 'Running {0}'.format(cmd_string)
27        proc = subprocess.Popen(
28            self.cmd + cmd,
29            cwd = self.cwd,
30            stdout = subprocess.PIPE
31        )
32        out = proc.communicate()[0]
33        if proc.returncode == 0:
34            return out
35        else:
36            raise Exception(
37                'Command {0} exited with {1}'.format(
38                    cmd_string,
39                    proc.returncode
40                )
41            )
42
43    def in_dir(self, cwd):
44        return ChildProcess(self.cmd, cwd)
45
46    def in_subdir(self, subdir):
47        return self.in_dir(os.path.join(self.cwd, subdir))
48
49
50def head_of_master(submodule, git, ref):
51    git.run(['fetch'])
52    return git.run(['show-ref', ref]).split()[0]
53
54
55def build_environment(submodules_file, out_dir, git, repo, action, ref):
56    submodules = load_json(submodules_file)
57    git.run(['clone', repo, out_dir])
58    git_in_boost = git.in_dir(out_dir)
59
60    git_in_boost.run(
61        ['submodule', 'init', '--'] + [k for k in submodules.keys() if k != '']
62    )
63    git_in_boost.run(['submodule', 'update'])
64    if action == 'update':
65        with open(submodules_file, 'w') as f:
66            f.write(json.dumps(
67                dict([
68                    (k, head_of_master(k, git_in_boost.in_subdir(k), ref))
69                    for k, v in submodules.iteritems()
70                ]),
71                sort_keys=True,
72                indent=2
73            ))
74    elif action == 'checkout':
75        for name, commit in submodules.iteritems():
76            git_in_boost.in_subdir(name).run(['checkout', commit])
77    else:
78        raise Exception('Invalid action {0}'.format(action))
79
80
81def main():
82    """The main function of the utility"""
83    parser = argparse.ArgumentParser(
84        description='Manage the build environment of Boost.Metaparse'
85    )
86    parser.add_argument(
87        '--dep_json',
88        required=True,
89        help='The json file describing the dependencies'
90    )
91    parser.add_argument(
92        '--git',
93        required=False,
94        default='git',
95        help='The git command to use'
96    )
97    parser.add_argument(
98        '--out',
99        required=False,
100        default='boost',
101        help='The directory to clone into'
102    )
103    parser.add_argument(
104        '--action',
105        required=True,
106        choices=['update', 'checkout'],
107        help='The action to do with the dependencies'
108    )
109    parser.add_argument(
110        '--boost_repository',
111        required=False,
112        default='https://github.com/boostorg/boost.git',
113        help='The Boost repository to clone'
114    )
115    parser.add_argument(
116        '--ref',
117        required=False,
118        default='origin/master',
119        help='The reference to set to in update'
120    )
121    args = parser.parse_args()
122
123    build_environment(
124        args.dep_json,
125        args.out,
126        ChildProcess([args.git]),
127        args.boost_repository,
128        args.action,
129        args.ref
130    )
131
132
133if __name__ == '__main__':
134    main()
135