summaryrefslogtreecommitdiff
path: root/ghwt.py
blob: fc6db5d3c6b9eaf8d31519f1c82927da55cfdd65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env python3

# Copyright 2016 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# ghwt - GitHub WrapTool
#
# An emergency wraptool(1) replacement downloader that downloads
# directly from GitHub in case wrapdb.mesonbuild.com is down.

import urllib.request, json, sys, os, shutil, subprocess
import configparser, hashlib

req_timeout = 600.0
private_repos = {'meson', 'wrapweb', 'meson-ci'}
spdir = 'subprojects'

def gh_get(url):
    r = urllib.request.urlopen(url, timeout=req_timeout)
    jd = json.loads(r.read().decode('utf-8'))
    return jd

def list_projects():
    jd = gh_get('https://api.github.com/orgs/mesonbuild/repos')
    entries = [entry['name'] for entry in jd]
    entries = [e for e in entries if e not in private_repos]
    entries.sort()
    for i in entries:
        print(i)
    return 0

def unpack(sproj, branch):
    tmpdir = os.path.join(spdir, sproj + '_ghwt')
    shutil.rmtree(tmpdir, ignore_errors=True)
    subprocess.check_call(['git', 'clone', '-b', branch, f'https://github.com/mesonbuild/{sproj}.git', tmpdir])
    usfile = os.path.join(tmpdir, 'upstream.wrap')
    assert os.path.isfile(usfile)
    config = configparser.ConfigParser(interpolation=None)
    config.read(usfile)
    outdir = os.path.join(spdir, sproj)
    if 'directory' in config['wrap-file']:
        outdir = os.path.join(spdir, config['wrap-file']['directory'])
    if os.path.isdir(outdir):
        print(f'Subproject is already there. To update, nuke the {outdir} dir and reinstall.')
        shutil.rmtree(tmpdir)
        return 1
    us_url = config['wrap-file']['source_url']
    us = urllib.request.urlopen(us_url, timeout=req_timeout).read()
    h = hashlib.sha256()
    h.update(us)
    dig = h.hexdigest()
    should = config['wrap-file']['source_hash']
    if dig != should:
        print('Incorrect hash on download.')
        print(' expected:', should)
        print(' obtained:', dig)
        return 1
    ofilename = os.path.join(spdir, config['wrap-file']['source_filename'])
    with open(ofilename, 'wb') as ofile:
        ofile.write(us)
    if 'lead_directory_missing' in config['wrap-file']:
        os.mkdir(outdir)
        shutil.unpack_archive(ofilename, outdir)
    else:
        shutil.unpack_archive(ofilename, spdir)
        assert os.path.isdir(outdir)
    shutil.move(os.path.join(tmpdir, '.git'), outdir)
    subprocess.check_call(['git', 'reset', '--hard'], cwd=outdir)
    shutil.rmtree(tmpdir)
    shutil.rmtree(os.path.join(outdir, '.git'))
    os.unlink(ofilename)

def install(sproj, requested_branch=None):
    if not os.path.isdir(spdir):
        print('Run this in your source root and make sure there is a subprojects directory in it.')
        return 1
    blist = gh_get(f'https://api.github.com/repos/mesonbuild/{sproj}/branches')
    blist = [b['name'] for b in blist]
    blist = [b for b in blist if b != 'master']
    blist.sort()
    branch = blist[-1]
    if requested_branch is not None:
        if requested_branch in blist:
            branch = requested_branch
        else:
            print('Could not find user-requested branch', requested_branch)
            print('Available branches for', sproj, ':')
            print(blist)
            return 1
    print('Using branch', branch)
    return unpack(sproj, branch)

def print_help():
    print('Usage:')
    print(sys.argv[0], 'list')
    print(sys.argv[0], 'install', 'package_name', '[branch_name]')

def run(args):
    if not args or args[0] == '-h' or args[0] == '--help':
        print_help()
        return 1
    command = args[0]
    args = args[1:]
    if command == 'list':
        list_projects()
        return 0
    elif command == 'install':
        if len(args) == 1:
            return install(args[0])
        elif len(args) == 2:
            return install(args[0], args[1])
        else:
            print_help()
            return 1
    else:
        print('Unknown command')
        return 1

if __name__ == '__main__':
    print('This is an emergency wrap downloader. Use only when wrapdb is down.')
    sys.exit(run(sys.argv[1:]))