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