blob: 3cd66203f82066fecbee5ce43c4fb83cd0ddb550 [file] [log] [blame]
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +02001#!/usr/bin/env python
2
3#
4# Copyright (c) 2019-2020 Arm Limited. All rights reserved.
5#
6# SPDX-License-Identifier: Apache-2.0
7#
8# Licensed under the Apache License, Version 2.0 (the License); you may
9# not use this file except in compliance with the License.
10# You may obtain a copy of the License at
11#
12# www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an AS IS BASIS, WITHOUT
16# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17# See the License for the specific language governing permissions and
18# limitations under the License.
19#
20
Kristofer Jonssona5e79202020-09-01 16:32:43 +020021import argparse
22import json
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020023import os
24import subprocess
Kristofer Jonssona5e79202020-09-01 16:32:43 +020025import sys
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020026
27def print_args(args, **kwargs):
28 cwd = kwargs['cwd']
29
30 if isinstance(args, list):
31 args = ' '.join(args)
32
33 print('%s$ %s' % (cwd, args))
34
35def check_call(args, **kwargs):
36 print_args(args, **kwargs)
37 return subprocess.check_call(args, **kwargs)
38
39def check_output(args, **kwargs):
40 print_args(args, **kwargs)
41 return subprocess.check_output(args, **kwargs)
42
Kristofer Jonssona5e79202020-09-01 16:32:43 +020043###############################################################################
44# Git class
45###############################################################################
46
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020047class Git(object):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020048 def __init__(self, pwd, path, fetchurl, pushurl=None, revision='origin/master'):
49 self.pwd = pwd
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020050 self.path = path
Kristofer Jonssona5e79202020-09-01 16:32:43 +020051 self.absolutepath = os.path.join(pwd, path)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020052 self.fetchurl = fetchurl
53 self.pushurl = pushurl
54 self.revision = revision
55
56 def init(self):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020057 if not os.path.exists(self.absolutepath):
58 os.makedirs(self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020059
Kristofer Jonssona5e79202020-09-01 16:32:43 +020060 if not os.path.exists(os.path.join(self.absolutepath, '.git')):
61 check_output(['git', 'init'], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020062
63 def remote_add(self, name, fetchurl):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020064 remotes = check_output(['git', 'remote'], cwd=self.absolutepath).decode('utf-8').split('\n')
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020065 if not name in remotes:
Kristofer Jonssona5e79202020-09-01 16:32:43 +020066 check_output(['git', 'remote', 'add', '-m', self.revision, name, self.fetchurl], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020067
68 if self.pushurl:
Kristofer Jonssona5e79202020-09-01 16:32:43 +020069 check_output(['git', 'remote', 'set-url', '--add', '--push', name, self.pushurl], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020070
71 def fetch(self):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020072 check_output(['git', 'fetch'], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020073
74 def checkout(self, revision):
75 rev = self.__get_rev(revision)
Kristofer Jonssona5e79202020-09-01 16:32:43 +020076 check_output(['git', 'checkout', rev], stderr=subprocess.STDOUT, cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020077
78 def clone(self):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020079 if not os.path.exists(os.path.join(self.absolutepath, '.git')):
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020080 self.init()
81 self.remote_add('origin', self.fetchurl)
82 self.fetch()
83 self.checkout(self.revision)
84
85 def rebase(self):
86 rev = self.__get_rev(self.revision)
Kristofer Jonssona5e79202020-09-01 16:32:43 +020087 check_output(['git', 'rebase', rev], cwd=self.absolutepath)
88
89 def set_sha1(self):
90 self.revision = self.__get_rev(self.revision)
91
92 def get_dict(self):
93 data = {}
94 data['path'] = self.path
95 data['fetchurl'] = self.fetchurl
96
97 if self.pushurl:
98 data['pushurl'] = self.pushurl
99
100 data['revision'] = self.revision
101
102 return data
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200103
104 def __get_rev(self, revision):
105 try:
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200106 rev = check_output(['git', 'rev-parse', 'origin/' + self.revision], stderr=subprocess.STDOUT, cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200107 except:
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200108 rev = check_output(['git', 'rev-parse', self.revision], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200109
110 return rev.decode('utf-8').strip()
111
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200112###############################################################################
113# Externals class
114###############################################################################
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200115
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200116class Externals:
117 def __init__(self, config):
118 self.externals = []
119 self.load_config(config)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200120
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200121 def load_config(self, config):
122 self.pwd = os.path.dirname(os.path.realpath(config))
123
124 with open(config, 'r') as fp:
125 data = json.load(fp)
126
127 for ext in data['externals']:
128 git = Git(self.pwd, ext['path'], ext['fetchurl'], ext.get('pushurl', None), ext['revision'])
129 self.externals.append(git)
130
131 def fetch(self):
132 for ext in self.externals:
133 ext.clone()
134 ext.fetch()
135 ext.checkout(ext.revision)
136
137 def set_sha1(self):
138 for ext in self.externals:
139 ext.set_sha1()
140
141 def get_dict(self):
142 data = { 'externals': [] }
143 for ext in self.externals:
144 data['externals'].append(ext.get_dict())
145
146 return data
147
148 def dump(self, fhandle):
149 fhandle.write(json.dumps(self.get_dict(), sort_keys=False, separators=(',', ': '), indent=4))
150
151###############################################################################
152# Handle functions
153###############################################################################
154
155def handle_fetch(args):
156 externals = Externals(args.configuration)
157 externals.fetch()
158
159def handle_dump(args):
160 externals = Externals(args.configuration)
161
162 if args.sha1:
163 externals.set_sha1()
164
165 externals.dump(sys.stdout)
166
167if __name__ == '__main__':
168 parser = argparse.ArgumentParser(description='Fetch external repositories.')
169 parser.add_argument('-c', '--configuration', default='externals.json', help='Externals configuration file')
170 subparsers = parser.add_subparsers()
171
172 subparser = subparsers.add_parser('fetch', description='Fetch external repositories.')
173 subparser.set_defaults(func=handle_fetch)
174
175 subparser = subparsers.add_parser('dump', description='Dump configuration.')
176 subparser.set_defaults(func=handle_dump)
177 subparser.add_argument('-s', '--sha1', action='store_true', help='Replace revision with current SHA-1')
178
179 args = parser.parse_args()
180
181 if 'func' not in args:
182 parser.print_help()
183 sys.exit(2)
184
185 sys.exit(args.func(args))
186