1#! /usr/bin/env python 2 3# Copyright 2018 Google LLC. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7 8from __future__ import print_function 9from subprocess import call, check_output, CalledProcessError 10import os 11import re 12import sys 13import tempfile 14 15 16HEADER = '''<!DOCTYPE html> 17<html lang="en"> 18<head> 19<meta charset="utf-8"> 20<title>SkQP Pre-built APKs</title> 21<meta name="viewport" content="width=device-width, initial-scale=1.0"> 22<style> 23body { 24font-family:sans-serif; 25max-width:50em; 26margin:8px auto; 27padding:0 8px; 28} 29table { max-width:100%; border-collapse: collapse; } 30td { padding:12px 8px; vertical-align:top; } 31tr:nth-child(even) {background: #F2F2F2; color:#000;} 32tr:nth-child(odd) {background: #FFFFFF; color:#000;} 33</style> 34</head> 35<body> 36<h1>SkQP Pre-built APKs</h1> 37''' 38FOOTER = '</body>\n</html>\n' 39 40BUCKET = 'skia-skqp' 41 42NAME_FMT = 'skqp-universal-%s.apk' 43 44 45def get_existing_files(): 46 cmd = ['gsutil', 'ls', 'gs://' + BUCKET] 47 try: 48 output = check_output(cmd) 49 except (OSError, CalledProcessError): 50 sys.stderr.write('command: "%s" failed.\n' % ' '.join(cmd)) 51 sys.exit(1) 52 result = set() 53 regex = re.compile('gs://%s/%s' % (BUCKET, NAME_FMT % '([0-9a-f]+)')) 54 for line in output.split('\n'): 55 m = regex.match(line.strip()) 56 if m is not None: 57 result.add(m.group(1)) 58 return result 59 60 61def find(v, extant): 62 l = min(16, len(v)) 63 while l > 8: 64 if v[:l] in extant: 65 return v[:l] 66 l -= 1 67 return None 68 69 70def nowrap(s): 71 return (s.replace(' ', u'\u00A0'.encode('utf-8')) 72 .replace('-', u'\u2011'.encode('utf-8'))) 73 74 75def rev_parse(arg): 76 if isinstance(arg, tuple): 77 remote_url, branch = arg 78 for remote in check_output(['git', 'remote']).strip().split('\n'): 79 remote = remote.strip() 80 url = check_output(['git', 'remote', 'get-url', remote]).strip() 81 if url == remote_url: 82 arg = remote + '/' + branch 83 break 84 return check_output(['git', 'rev-parse', arg]).strip() 85 86 87def table(o, remote, branch, excludes): 88 env_copy = os.environ.copy() 89 env_copy['TZ'] = '' 90 extant = get_existing_files() 91 92 commits = [rev_parse((remote, branch))] 93 for exclude in excludes: 94 commits.append('^' + rev_parse(exclude)) 95 96 o.write('<h2>Remote: %s<br>Branch: %s</h2>\n' % (remote, branch)) 97 o.write('<table>\n<tr><th>APK</th><th>Date</th><th>Commit</th></tr>\n') 98 git_cmd = ['git', 'log', '--format=%H;%cd;%<(100,trunc)%s', 99 '--date=format-local:%Y-%m-%d %H:%M:%S %Z'] + commits 100 commits = check_output(git_cmd, env=env_copy) 101 for line in commits.split('\n'): 102 line = line.strip() 103 if not line: 104 continue 105 commit, date, subj = line.split(';', 2) 106 short = find(commit, extant) 107 if short is not None: 108 apk_name = NAME_FMT % short 109 url = 'https://storage.googleapis.com/%s/%s' % (BUCKET, apk_name) 110 else: 111 apk_name, url = '', '' 112 commit_url = '%s/+/%s' % (remote, commit) 113 o.write('<tr>\n<td><a href="%s">%s</a></td>\n' 114 '<td>%s</td>\n<td><a href="%s">%s</a></td>\n</tr>\n' % 115 (url, nowrap(apk_name), nowrap(date), commit_url, subj)) 116 o.write('</table>\n') 117 118 119def main(): 120 origin = 'https://skia.googlesource.com/skia' 121 aosp_skqp = 'https://android.googlesource.com/platform/external/skqp' 122 123 assert '/' in [os.sep, os.altsep] and '..' == os.pardir 124 os.chdir(os.path.join(os.path.dirname(__file__), '../..')) 125 d = tempfile.mkdtemp() 126 path = os.path.join(d, 'apklist.html') 127 with open(path, 'w') as o: 128 o.write(HEADER) 129 table(o, origin, 'skqp/dev', [(origin, 'master'), '3e34285f2a0']) 130 table(o, origin, 'skqp/release', [(origin, 'master'), '09ab171c5c0']) 131 table(o, aosp_skqp, 'pie-cts-dev', ['f084c17322']) 132 o.write(FOOTER) 133 print(path) 134 call([sys.executable, 'bin/sysopen', path]) 135 gscmd = 'gsutil -h "Content-Type:text/html" cp "%s" gs://skia-skqp/apklist' 136 print(gscmd % path) 137 138 139if __name__ == '__main__': 140 main() 141 142