-
Notifications
You must be signed in to change notification settings - Fork 2
/
updater.py
106 lines (75 loc) · 2.67 KB
/
updater.py
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
"""
Usage:
updater.py check <repo> <path>
updater.py update <repo> <path>
"""
import sys
import tarfile
from pathlib import Path
import requests
from docopt import docopt
ASSET_ID_FILE = '.asset_id'
CURRENT_PATH = 'current'
RELEASES_PATH = 'releases'
RELEASE_URL = 'https://api.github.com/repos/{repo}/releases'
def _release_filter(release):
return not release['draft'] and not release['prerelease'] and release['assets']
def get_latest_release_asset(repo):
with requests.get(RELEASE_URL.format(repo=repo)) as response:
response.raise_for_status()
data = response.json()
release = next(filter(_release_filter, data), None)
if release is None:
raise ValueError("Unable to find matching release")
return release['assets'][0]
def check_for_update(args):
repo = args['<repo>']
deploy_path = Path(args['<path>']).resolve()
if not deploy_path.is_dir():
sys.exit("Website not deployed")
asset_id_file = deploy_path / CURRENT_PATH / ASSET_ID_FILE
if not asset_id_file.exists():
sys.exit("No assets currently deployed")
with open(str(asset_id_file)) as f:
current_id = f.read().strip().splitlines()[0]
if not current_id:
sys.exit("No assets currently deployed")
asset = get_latest_release_asset(repo)
if str(asset['id']) != current_id:
sys.exit("Assets out of date")
sys.exit(0)
def do_update(args):
deploy_path = Path(args['<path>']).resolve()
releases_dir = deploy_path / RELEASES_PATH
current_link = deploy_path / CURRENT_PATH
asset = get_latest_release_asset(args['<repo>'])
# Requires that the asset be '<name>.tar.gz'
release_name = asset['name'].rsplit('.', 2)[0]
release_dir = releases_dir / release_name
if not release_dir.exists():
release_dir.mkdir(parents=True)
with requests.get(
asset['url'], stream=True,
headers={
'Accept': 'application/octet-stream',
}
) as response:
with tarfile.open(fileobj=response.raw, mode='r|*') as tarball:
tarball.extractall(path=str(release_dir))
# Record the ID of this asset for later update checks
with open(str(release_dir / ASSET_ID_FILE), 'w') as f:
print(asset['id'], file=f)
if current_link.is_symlink():
current_link.unlink()
current_link.symlink_to(release_dir, target_is_directory=True)
print('Deployed', release_name)
def main():
args = docopt(__doc__)
if args['check']:
check_for_update(args)
elif args['update']:
do_update(args)
else:
raise ValueError("Invalid arguments from docopt")
if __name__ == '__main__':
main()