blob: 0be9cc34d7b43dfa751cfc5d41e2c5d04253d795 [file] [log] [blame]
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +02001#!/usr/bin/env python
2
3#
Kristofer Jonssone98770c2022-02-28 14:28:39 +01004# Copyright (c) 2019-2020,2022 Arm Limited. All rights reserved.
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +02005#
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 Jonssone98770c2022-02-28 14:28:39 +010048 def __init__(self, pwd, path, name, fetchurl, pushurl=None, revision='origin/master'):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020049 self.pwd = pwd
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020050 self.path = path
Kristofer Jonssone98770c2022-02-28 14:28:39 +010051 self.name = name
Kristofer Jonssona5e79202020-09-01 16:32:43 +020052 self.absolutepath = os.path.join(pwd, path)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020053 self.fetchurl = fetchurl
54 self.pushurl = pushurl
55 self.revision = revision
56
Kristofer Jonssone98770c2022-02-28 14:28:39 +010057 def checkout_and_update(self):
58 self.init()
59 self.remote_add(self.name, self.revision, self.fetchurl, self.pushurl)
60 self.fetch(self.name)
61 self.checkout(self.name, self.revision)
62
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020063 def init(self):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020064 if not os.path.exists(self.absolutepath):
65 os.makedirs(self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020066
Kristofer Jonssona5e79202020-09-01 16:32:43 +020067 if not os.path.exists(os.path.join(self.absolutepath, '.git')):
68 check_output(['git', 'init'], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020069
Kristofer Jonssone98770c2022-02-28 14:28:39 +010070 def remote_add(self, name, revision, fetchurl, pushurl):
71 remotes = self.__get_remotes()
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020072
Kristofer Jonssone98770c2022-02-28 14:28:39 +010073 if name in remotes:
74 if fetchurl != remotes[name]['fetch']:
75 raise Exception("Fetch url '%s' from repository for remote '%s' does not match fetch url '%s' from manifest." % (fetchurl, name, remotes[name]['fetch']))
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020076
Kristofer Jonssone98770c2022-02-28 14:28:39 +010077 if pushurl not in (None, remotes[name]['push']):
78 raise Exception("Push url '%s' from repository for remote '%s' does not match push url '%s' from manifest." % (pushurl, name, remotes[name]['push']))
79 else:
80 check_output(['git', 'remote', 'add', '-m', revision, name, fetchurl], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020081
Kristofer Jonssone98770c2022-02-28 14:28:39 +010082 if pushurl:
83 check_output(['git', 'remote', 'set-url', '--add', '--push', name, pushurl], cwd=self.absolutepath)
84
85 def fetch(self, name):
86 check_output(['git', 'fetch', name], cwd=self.absolutepath)
87
88 def checkout(self, name, revision):
89 rev = self.__get_rev(name, revision)
Kristofer Jonssona5e79202020-09-01 16:32:43 +020090 check_output(['git', 'checkout', rev], stderr=subprocess.STDOUT, cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +020091
Kristofer Jonssone98770c2022-02-28 14:28:39 +010092 def get_dict(self, sha1):
Kristofer Jonssona5e79202020-09-01 16:32:43 +020093 data = {}
94 data['path'] = self.path
Kristofer Jonssone98770c2022-02-28 14:28:39 +010095 data['name'] = self.name
Kristofer Jonssona5e79202020-09-01 16:32:43 +020096 data['fetchurl'] = self.fetchurl
97
98 if self.pushurl:
99 data['pushurl'] = self.pushurl
100
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100101 if sha1:
102 data['revision'] = self.__get_rev(self.name, self.revision)
103 else:
104 data['revision'] = self.revision
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200105
106 return data
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200107
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100108 def __get_rev(self, name, revision):
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200109 try:
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100110 rev = check_output(['git', 'rev-parse', name + '/' + revision], stderr=subprocess.STDOUT, cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200111 except:
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100112 rev = check_output(['git', 'rev-parse', revision], cwd=self.absolutepath)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200113
114 return rev.decode('utf-8').strip()
115
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100116 def __get_remotes(self):
117 remotes = {}
Kristofer Jonsson7ac76382022-03-01 14:45:29 +0100118 for remote in check_output(['git', 'remote'], cwd=self.absolutepath).decode('utf-8').splitlines():
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100119 fetch = check_output(['git', 'remote', 'get-url', remote], cwd=self.absolutepath).decode('utf-8').strip()
120 push = check_output(['git', 'remote', 'get-url', '--push', remote], cwd=self.absolutepath).decode('utf-8').strip()
121 remotes[remote] = { 'fetch': fetch, 'push': push }
122
123 return remotes
124
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200125###############################################################################
126# Externals class
127###############################################################################
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200128
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200129class Externals:
130 def __init__(self, config):
131 self.externals = []
132 self.load_config(config)
Kristofer Jonsson6d63f5f2020-04-20 13:40:49 +0200133
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200134 def load_config(self, config):
135 self.pwd = os.path.dirname(os.path.realpath(config))
136
137 with open(config, 'r') as fp:
138 data = json.load(fp)
139
140 for ext in data['externals']:
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100141 git = Git(self.pwd, ext['path'], ext.get('name', 'origin'), ext['fetchurl'], ext.get('pushurl', None), ext['revision'])
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200142 self.externals.append(git)
143
144 def fetch(self):
145 for ext in self.externals:
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100146 ext.checkout_and_update()
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200147
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100148 def get_dict(self, sha1):
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200149 data = { 'externals': [] }
150 for ext in self.externals:
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100151 data['externals'].append(ext.get_dict(sha1))
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200152
153 return data
154
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100155 def dump(self, fhandle, sha1):
156 fhandle.write(json.dumps(self.get_dict(sha1), sort_keys=False, separators=(',', ': '), indent=4))
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200157
158###############################################################################
159# Handle functions
160###############################################################################
161
162def handle_fetch(args):
163 externals = Externals(args.configuration)
164 externals.fetch()
165
166def handle_dump(args):
167 externals = Externals(args.configuration)
Kristofer Jonssone98770c2022-02-28 14:28:39 +0100168 externals.dump(sys.stdout, args.sha1)
Kristofer Jonssona5e79202020-09-01 16:32:43 +0200169
170if __name__ == '__main__':
171 parser = argparse.ArgumentParser(description='Fetch external repositories.')
172 parser.add_argument('-c', '--configuration', default='externals.json', help='Externals configuration file')
173 subparsers = parser.add_subparsers()
174
175 subparser = subparsers.add_parser('fetch', description='Fetch external repositories.')
176 subparser.set_defaults(func=handle_fetch)
177
178 subparser = subparsers.add_parser('dump', description='Dump configuration.')
179 subparser.set_defaults(func=handle_dump)
180 subparser.add_argument('-s', '--sha1', action='store_true', help='Replace revision with current SHA-1')
181
182 args = parser.parse_args()
183
184 if 'func' not in args:
185 parser.print_help()
186 sys.exit(2)
187
188 sys.exit(args.func(args))
189