blob: 1f541a1eb1372cd70d5f517fa6b6a629cf3deae1 [file] [log] [blame]
mikeNG1fb4c972016-08-26 01:49:28 -04001#!/usr/bin/env python
2# Copyright (C) 2012-2013, The CyanogenMod Project
3# (C) 2017, The LineageOS Project
4# (C) 2017, The BlissRoms Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18from __future__ import print_function
19
20import base64
21import json
22import netrc
23import os
24import re
25import sys
26try:
27 # For python3
28 import urllib.error
29 import urllib.parse
30 import urllib.request
31except ImportError:
32 # For python2
33 import imp
34 import urllib2
35 import urlparse
36 urllib = imp.new_module('urllib')
37 urllib.error = urllib2
38 urllib.parse = urlparse
39 urllib.request = urllib2
40
41from xml.etree import ElementTree
42
43product = sys.argv[1]
44
45if len(sys.argv) > 2:
46 depsonly = sys.argv[2]
47else:
48 depsonly = None
49
50try:
51 device = product[product.index("_") + 1:]
52except:
53 device = product
54
55if not depsonly:
56 print("Device %s not found. Attempting to retrieve device repository from BlissRoms-Devices (http://github.com/BlissRoms-Devices)." % device)
57
58repositories = []
59
60try:
61 authtuple = netrc.netrc().authenticators("api.github.com")
62
63 if authtuple:
64 auth_string = ('%s:%s' % (authtuple[0], authtuple[2])).encode()
65 githubauth = base64.encodestring(auth_string).decode().replace('\n', '')
66 else:
67 githubauth = None
68except:
69 githubauth = None
70
71def add_auth(githubreq):
72 if githubauth:
73 githubreq.add_header("Authorization","Basic %s" % githubauth)
74
75if not depsonly:
76 githubreq = urllib.request.Request("https://api.github.com/search/repositories?q=%s+user:BlissRoms-Devices+in:name+fork:true" % device)
77 add_auth(githubreq)
78 try:
79 result = json.loads(urllib.request.urlopen(githubreq).read().decode())
80 except urllib.error.URLError:
81 print("Failed to search GitHub")
82 sys.exit()
83 except ValueError:
84 print("Failed to parse return data from GitHub")
85 sys.exit()
86 for res in result.get('items', []):
87 repositories.append(res)
88
89local_manifests = r'.repo/local_manifests'
90if not os.path.exists(local_manifests): os.makedirs(local_manifests)
91
92def exists_in_tree(lm, path):
93 for child in lm.getchildren():
94 if child.attrib['path'] == path:
95 return True
96 return False
97
98# in-place prettyprint formatter
99def indent(elem, level=0):
100 i = "\n" + level*" "
101 if len(elem):
102 if not elem.text or not elem.text.strip():
103 elem.text = i + " "
104 if not elem.tail or not elem.tail.strip():
105 elem.tail = i
106 for elem in elem:
107 indent(elem, level+1)
108 if not elem.tail or not elem.tail.strip():
109 elem.tail = i
110 else:
111 if level and (not elem.tail or not elem.tail.strip()):
112 elem.tail = i
113
114def get_from_manifest(devicename):
115 try:
116 lm = ElementTree.parse(".repo/local_manifests/roomservice.xml")
117 lm = lm.getroot()
118 except:
119 lm = ElementTree.Element("manifest")
120
121 for localpath in lm.findall("project"):
122 if re.search("android_device_.*_%s$" % device, localpath.get("name")):
123 return localpath.get("path")
124
125 return None
126
127def is_in_manifest(projectpath):
128 try:
129 lm = ElementTree.parse(".repo/local_manifests/roomservice.xml")
130 lm = lm.getroot()
131 except:
132 lm = ElementTree.Element("manifest")
133
134 for localpath in lm.findall("project"):
135 if localpath.get("path") == projectpath:
136 return True
137
138 # Search in main manifest, too
139 try:
140 lm = ElementTree.parse(".repo/manifest.xml")
141 lm = lm.getroot()
142 except:
143 lm = ElementTree.Element("manifest")
144
145 for localpath in lm.findall("project"):
146 if localpath.get("path") == projectpath:
147 return True
148
149 # Add Bliss manifest
150 try:
151 lm = ElementTree.parse(".repo/manifests/bliss.xml")
152 lm = lm.getroot()
153 except:
154 lm = ElementTree.Element("manifest")
155
156 for localpath in lm.findall("project"):
157 if localpath.get("path") == projectpath:
158 return True
159
160 return False
161
162def add_to_manifest(repositories, fallback_branch = None):
163 try:
164 lm = ElementTree.parse(".repo/local_manifests/roomservice.xml")
165 lm = lm.getroot()
166 except:
167 lm = ElementTree.Element("manifest")
168
169 for repository in repositories:
170 repo_name = repository['repository']
171 repo_target = repository['target_path']
172 print('Checking if %s is fetched from %s' % (repo_target, repo_name))
173 if is_in_manifest(repo_target):
174 print('BlissRoms-Devices/%s already fetched to %s' % (repo_name, repo_target))
175 continue
176
177 print('Adding dependency: BlissRoms-Devices/%s -> %s' % (repo_name, repo_target))
178 project = ElementTree.Element("project", attrib = { "path": repo_target,
179 "remote": "github", "name": "BlissRoms-Devices/%s" % repo_name })
180
181 if 'branch' in repository:
182 project.set('revision',repository['branch'])
183 elif fallback_branch:
184 print("Using fallback branch %s for %s" % (fallback_branch, repo_name))
185 project.set('revision', fallback_branch)
186 else:
187 print("Using default branch for %s" % repo_name)
188
189 lm.append(project)
190
191 indent(lm, 0)
192 raw_xml = ElementTree.tostring(lm).decode()
193 raw_xml = '<?xml version="1.0" encoding="UTF-8"?>\n' + raw_xml
194
195 f = open('.repo/local_manifests/roomservice.xml', 'w')
196 f.write(raw_xml)
197 f.close()
198
199def fetch_dependencies(repo_path, fallback_branch = None):
200 print('Looking for dependencies in %s' % repo_path)
201 dependencies_path = repo_path + '/bliss.dependencies'
202 syncable_repos = []
203 verify_repos = []
204
205 if os.path.exists(dependencies_path):
206 dependencies_file = open(dependencies_path, 'r')
207 dependencies = json.loads(dependencies_file.read())
208 fetch_list = []
209
210 for dependency in dependencies:
211 if not is_in_manifest(dependency['target_path']):
212 fetch_list.append(dependency)
213 syncable_repos.append(dependency['target_path'])
214 verify_repos.append(dependency['target_path'])
215 elif re.search("android_device_.*_.*$", dependency['repository']):
216 verify_repos.append(dependency['target_path'])
217
218 dependencies_file.close()
219
220 if len(fetch_list) > 0:
221 print('Adding dependencies to manifest')
222 add_to_manifest(fetch_list, fallback_branch)
223 else:
224 print('Dependencies file not found, bailing out.')
225
226 if len(syncable_repos) > 0:
227 print('Syncing dependencies')
228 os.system('repo sync --force-sync %s' % ' '.join(syncable_repos))
229
230 for deprepo in verify_repos:
231 fetch_dependencies(deprepo)
232
233def has_branch(branches, revision):
234 return revision in [branch['name'] for branch in branches]
235
236if depsonly:
237 repo_path = get_from_manifest(device)
238 if repo_path:
239 fetch_dependencies(repo_path)
240 else:
241 print("Trying dependencies-only mode on a non-existing device tree?")
242
243 sys.exit()
244
245else:
246 for repository in repositories:
247 repo_name = repository['name']
248 if re.match(r"^android_device_[^_]*_" + device + "$", repo_name):
249 print("Found repository: %s" % repository['name'])
250
251 manufacturer = repo_name.replace("android_device_", "").replace("_" + device, "")
252
253 ## Default branch to sync
254 default_revision = "o8.0"
255 print("Default revision: %s" % default_revision)
256 print("Checking branch info")
257 githubreq = urllib.request.Request(repository['branches_url'].replace('{/branch}', ''))
258 add_auth(githubreq)
259 result = json.loads(urllib.request.urlopen(githubreq).read().decode())
260
261 ## Try tags, too, since that's what releases use
262 if not has_branch(result, default_revision):
263 githubreq = urllib.request.Request(repository['tags_url'].replace('{/tag}', ''))
264 add_auth(githubreq)
265 result.extend (json.loads(urllib.request.urlopen(githubreq).read().decode()))
266
267 repo_path = "device/%s/%s" % (manufacturer, device)
268 adding = {'repository':repo_name,'target_path':repo_path}
269
270 fallback_branch = None
271 if not has_branch(result, default_revision):
272 if os.getenv('ROOMSERVICE_BRANCHES'):
273 fallbacks = list(filter(bool, os.getenv('ROOMSERVICE_BRANCHES').split(' ')))
274 for fallback in fallbacks:
275 if has_branch(result, fallback):
276 print("Using fallback branch: %s" % fallback)
277 fallback_branch = fallback
278 break
279
280 if not fallback_branch:
281 print("Default revision %s not found in %s. Bailing." % (default_revision, repo_name))
282 print("Branches found:")
283 for branch in [branch['name'] for branch in result]:
284 print(branch)
285 print("Use the ROOMSERVICE_BRANCHES environment variable to specify a list of fallback branches.")
286 sys.exit()
287
288 add_to_manifest([adding], fallback_branch)
289
290 print("Syncing repository to retrieve project.")
291 os.system('repo sync --force-sync %s' % repo_path)
292 print("Repository synced!")
293
294 fetch_dependencies(repo_path, fallback_branch)
295 print("Done")
296 sys.exit()
297
298print("Repository for %s not found in the BlissRoms-Devices Github repository list. If this is in error, you may need to manually add it to your local_manifests/roomservice.xml." % device)
299