1cb93a386Sopenharmony_ci#! /usr/bin/env python
2cb93a386Sopenharmony_ci# Copyright 2018 Google LLC.
3cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4cb93a386Sopenharmony_ci
5cb93a386Sopenharmony_ciimport json
6cb93a386Sopenharmony_ciimport md5
7cb93a386Sopenharmony_ciimport multiprocessing
8cb93a386Sopenharmony_ciimport os
9cb93a386Sopenharmony_ciimport shutil
10cb93a386Sopenharmony_ciimport sys
11cb93a386Sopenharmony_ciimport tempfile
12cb93a386Sopenharmony_ciimport urllib
13cb93a386Sopenharmony_ciimport urllib2
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cifrom subprocess import check_call, check_output
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciassert '/' in [os.sep, os.altsep] and os.pardir == '..'
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ciASSETS = 'platform_tools/android/apps/skqp/src/main/assets'
20cb93a386Sopenharmony_ciBUCKET = 'skia-skqp-assets'
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_cidef urlopen(url):
23cb93a386Sopenharmony_ci    cookie = os.environ.get('SKIA_GOLD_COOKIE', '')
24cb93a386Sopenharmony_ci    return urllib2.urlopen(urllib2.Request(url, headers={'Cookie': cookie}))
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cidef make_skqp_model(arg):
27cb93a386Sopenharmony_ci    name, urls, exe = arg
28cb93a386Sopenharmony_ci    tmp = tempfile.mkdtemp()
29cb93a386Sopenharmony_ci    for url in urls:
30cb93a386Sopenharmony_ci        urllib.urlretrieve(url, tmp + '/' + url[url.rindex('/') + 1:])
31cb93a386Sopenharmony_ci    check_call([exe, tmp, ASSETS + '/gmkb/' + name])
32cb93a386Sopenharmony_ci    shutil.rmtree(tmp)
33cb93a386Sopenharmony_ci    sys.stdout.write(name + ' ')
34cb93a386Sopenharmony_ci    sys.stdout.flush()
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_cidef goldgetter(meta, exe):
37cb93a386Sopenharmony_ci    assert os.path.exists(exe)
38cb93a386Sopenharmony_ci    jobs = []
39cb93a386Sopenharmony_ci    for rec in meta:
40cb93a386Sopenharmony_ci        urls = [d['URL'] for d in rec['digests']
41cb93a386Sopenharmony_ci                if d['status'] == 'positive' and
42cb93a386Sopenharmony_ci                (set(d['paramset']['config']) & set(['vk', 'gles']))]
43cb93a386Sopenharmony_ci        if urls:
44cb93a386Sopenharmony_ci            jobs.append((rec['testName'], urls, exe))
45cb93a386Sopenharmony_ci    pool = multiprocessing.Pool(processes=20)
46cb93a386Sopenharmony_ci    pool.map(make_skqp_model, jobs)
47cb93a386Sopenharmony_ci    sys.stdout.write('\n')
48cb93a386Sopenharmony_ci    return set((n for n, _, _ in jobs))
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_cidef gold(first_commit, last_commit):
51cb93a386Sopenharmony_ci    c1, c2 = (check_output(['git', 'rev-parse', c]).strip()
52cb93a386Sopenharmony_ci            for c in (first_commit, last_commit))
53cb93a386Sopenharmony_ci    f = urlopen('https://public-gold.skia.org/json/export?' + urllib.urlencode([
54cb93a386Sopenharmony_ci        ('fbegin', c1),
55cb93a386Sopenharmony_ci        ('fend', c2),
56cb93a386Sopenharmony_ci        ('query', 'config=gles&config=vk&source_type=gm'),
57cb93a386Sopenharmony_ci        ('pos', 'true'),
58cb93a386Sopenharmony_ci        ('neg', 'false'),
59cb93a386Sopenharmony_ci        ('unt', 'false')
60cb93a386Sopenharmony_ci    ]))
61cb93a386Sopenharmony_ci    j = json.load(f)
62cb93a386Sopenharmony_ci    f.close()
63cb93a386Sopenharmony_ci    return j
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_cidef gset(path):
66cb93a386Sopenharmony_ci    s = set()
67cb93a386Sopenharmony_ci    if os.path.isfile(path):
68cb93a386Sopenharmony_ci        with open(path, 'r') as f:
69cb93a386Sopenharmony_ci            for line in f:
70cb93a386Sopenharmony_ci                s.add(line.strip())
71cb93a386Sopenharmony_ci    return s
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_cidef make_rendertest_list(models, good, bad):
74cb93a386Sopenharmony_ci    assert good.isdisjoint(bad)
75cb93a386Sopenharmony_ci    do_score = good & models
76cb93a386Sopenharmony_ci    no_score = bad | (good - models)
77cb93a386Sopenharmony_ci    to_delete = models & bad
78cb93a386Sopenharmony_ci    for d in to_delete:
79cb93a386Sopenharmony_ci        path = ASSETS + '/gmkb/' + d
80cb93a386Sopenharmony_ci        if os.path.isdir(path):
81cb93a386Sopenharmony_ci            shutil.rmtree(path)
82cb93a386Sopenharmony_ci    results = dict()
83cb93a386Sopenharmony_ci    for n in do_score:
84cb93a386Sopenharmony_ci        results[n] = 0
85cb93a386Sopenharmony_ci    for n in no_score:
86cb93a386Sopenharmony_ci        results[n] = -1
87cb93a386Sopenharmony_ci    return ''.join('%s,%d\n' % (n, results[n]) for n in sorted(results))
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_cidef get_digest(path):
90cb93a386Sopenharmony_ci    m = md5.new()
91cb93a386Sopenharmony_ci    with open(path, 'r') as f:
92cb93a386Sopenharmony_ci        m.update(f.read())
93cb93a386Sopenharmony_ci    return m.hexdigest()
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_cidef upload_cmd(path, digest):
96cb93a386Sopenharmony_ci    return ['gsutil', 'cp', path, 'gs://%s/%s' % (BUCKET, digest)]
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_cidef upload_model():
99cb93a386Sopenharmony_ci    bucket_url = 'gs://%s/' % BUCKET
100cb93a386Sopenharmony_ci    extant = set((u.replace(bucket_url, '', 1)
101cb93a386Sopenharmony_ci                  for u in check_output(['gsutil', 'ls', bucket_url]).splitlines() if u))
102cb93a386Sopenharmony_ci    cmds = []
103cb93a386Sopenharmony_ci    filelist = []
104cb93a386Sopenharmony_ci    for dirpath, _, filenames in os.walk(ASSETS + '/gmkb'):
105cb93a386Sopenharmony_ci        for filename in filenames:
106cb93a386Sopenharmony_ci            path = os.path.join(dirpath, filename)
107cb93a386Sopenharmony_ci            digest = get_digest(path)
108cb93a386Sopenharmony_ci            if digest not in extant:
109cb93a386Sopenharmony_ci                cmds.append(upload_cmd(path, digest))
110cb93a386Sopenharmony_ci            filelist.append('%s;%s\n' % (digest, os.path.relpath(path, ASSETS)))
111cb93a386Sopenharmony_ci    tmp = tempfile.mkdtemp()
112cb93a386Sopenharmony_ci    filelist_path = tmp + '/x'
113cb93a386Sopenharmony_ci    with open(filelist_path, 'w') as o:
114cb93a386Sopenharmony_ci        for l in filelist:
115cb93a386Sopenharmony_ci            o.write(l)
116cb93a386Sopenharmony_ci    filelist_digest = get_digest(filelist_path)
117cb93a386Sopenharmony_ci    if filelist_digest not in extant:
118cb93a386Sopenharmony_ci        cmds.append(upload_cmd(filelist_path, filelist_digest))
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci    pool = multiprocessing.Pool(processes=20)
121cb93a386Sopenharmony_ci    pool.map(check_call, cmds)
122cb93a386Sopenharmony_ci    shutil.rmtree(tmp)
123cb93a386Sopenharmony_ci    return filelist_digest
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_cidef remove(x):
126cb93a386Sopenharmony_ci    if os.path.isdir(x) and not os.path.islink(x):
127cb93a386Sopenharmony_ci        shutil.rmtree(x)
128cb93a386Sopenharmony_ci    if os.path.exists(x):
129cb93a386Sopenharmony_ci        os.remove(x)
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_cidef main(first_commit, last_commit):
132cb93a386Sopenharmony_ci    check_call(upload_cmd('/dev/null', get_digest('/dev/null')))
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    os.chdir(os.path.dirname(__file__) + '/../..')
135cb93a386Sopenharmony_ci    remove(ASSETS + '/files.checksum')
136cb93a386Sopenharmony_ci    for d in [ASSETS + '/gmkb', ASSETS + '/skqp', ]:
137cb93a386Sopenharmony_ci        remove(d)
138cb93a386Sopenharmony_ci        os.mkdir(d)
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci    check_call([sys.executable, 'tools/git-sync-deps'],
141cb93a386Sopenharmony_ci               env=dict(os.environ, GIT_SYNC_DEPS_QUIET='T'))
142cb93a386Sopenharmony_ci    build = 'out/ndebug'
143cb93a386Sopenharmony_ci    check_call(['bin/gn', 'gen', build,
144cb93a386Sopenharmony_ci                '--args=cc="clang" cxx="clang++" is_debug=false'])
145cb93a386Sopenharmony_ci    check_call(['ninja', '-C', build,
146cb93a386Sopenharmony_ci                'jitter_gms', 'list_gpu_unit_tests', 'make_skqp_model'])
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_ci    models = goldgetter(gold(first_commit, last_commit), build + '/make_skqp_model')
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci    check_call([build + '/jitter_gms', 'tools/skqp/bad_gms.txt'])
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci    with open(ASSETS + '/skqp/rendertests.txt', 'w') as o:
153cb93a386Sopenharmony_ci        o.write(make_rendertest_list(models, gset('good.txt'), gset('bad.txt')))
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_ci    remove('good.txt')
156cb93a386Sopenharmony_ci    remove('bad.txt')
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci    with open(ASSETS + '/skqp/unittests.txt', 'w') as o:
159cb93a386Sopenharmony_ci        o.write(check_output([build + '/list_gpu_unit_tests']))
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci    with open(ASSETS + '/files.checksum', 'w') as o:
162cb93a386Sopenharmony_ci        o.write(upload_model() + '\n')
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci    sys.stdout.write(ASSETS + '/files.checksum\n')
165cb93a386Sopenharmony_ci    sys.stdout.write(ASSETS + '/skqp/rendertests.txt\n')
166cb93a386Sopenharmony_ci    sys.stdout.write(ASSETS + '/skqp/unittests.txt\n')
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ciif __name__ == '__main__':
169cb93a386Sopenharmony_ci    if len(sys.argv) != 3:
170cb93a386Sopenharmony_ci        sys.stderr.write('Usage:\n  %s C1 C2\n\n' % sys.argv[0])
171cb93a386Sopenharmony_ci        sys.exit(1)
172cb93a386Sopenharmony_ci    main(sys.argv[1], sys.argv[2])
173