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