Skip to content

Commit e1e5960

Browse files
bliottibboot2
andcommitted
script: Add previous_release.py
closes #18132 added GPG verify for binaries co-authored-by: bboot <[email protected]>
1 parent 8783bcc commit e1e5960

File tree

1 file changed

+222
-0
lines changed

1 file changed

+222
-0
lines changed

contrib/devtools/previous_release.py

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2018-2020 The Bitcoin Core developers
4+
# Distributed under the MIT software license, see the accompanying
5+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
6+
#
7+
# Build previous releases.
8+
9+
import argparse
10+
import contextlib
11+
from fnmatch import fnmatch
12+
import os
13+
from pathlib import Path
14+
import re
15+
import shutil
16+
import subprocess
17+
import sys
18+
import hashlib
19+
20+
21+
@contextlib.contextmanager
22+
def pushd(new_dir) -> None:
23+
previous_dir = os.getcwd()
24+
os.chdir(new_dir)
25+
try:
26+
yield
27+
finally:
28+
os.chdir(previous_dir)
29+
30+
31+
def download_binary(tag, args) -> int:
32+
if Path(tag).is_dir():
33+
if not args.remove_dir:
34+
print('Using cached {}'.format(tag))
35+
return 0
36+
shutil.rmtree(tag)
37+
Path(tag).mkdir()
38+
bin_path = 'bin/bitcoin-core-{}'.format(tag[1:])
39+
match = re.compile('v(.*)(rc[0-9]+)$').search(tag)
40+
if match:
41+
bin_path = 'bin/bitcoin-core-{}/test.{}'.format(
42+
match.group(1), match.group(2))
43+
tarball = 'bitcoin-{tag}-{platform}.tar.gz'.format(
44+
tag=tag[1:], platform=args.platform)
45+
sha256Sums = "SHA256SUMS-{tag}.asc".format(tag=tag[1:])
46+
tarballUrl = 'https://bitcoincore.org/{bin_path}/{tarball}'.format(
47+
bin_path=bin_path, tarball=tarball)
48+
sha256SumsUrl = 'https://bitcoincore.org/{bin_path}/SHA256SUMS.asc'.format(
49+
bin_path=bin_path)
50+
51+
print('Fetching: {tarballUrl}'.format(tarballUrl=tarballUrl))
52+
print('Fetching: {sha256SumsUrl}'.format(sha256SumsUrl=sha256SumsUrl))
53+
54+
header, status = subprocess.Popen(
55+
['curl', '-I', tarballUrl], stdout=subprocess.PIPE).communicate()
56+
if re.search("404 Not Found", header.decode("utf-8")):
57+
print("Binary tag was not found")
58+
return 1
59+
60+
curlCmds = [
61+
['curl', '-O', tarballUrl],
62+
['curl', "-o", sha256Sums, sha256SumsUrl],
63+
]
64+
65+
for cmd in curlCmds:
66+
ret = subprocess.run(cmd).returncode
67+
if ret:
68+
return ret
69+
70+
hasher = hashlib.sha256()
71+
with open(tarball, "rb") as afile:
72+
buf = afile.read()
73+
hasher.update(buf)
74+
afile.close()
75+
tarballHash = hasher.hexdigest()
76+
file = open(sha256Sums, 'r', encoding="utf-8")
77+
lst = list(file.readlines())
78+
file.close()
79+
lastline = lst[len(lst)-1]
80+
81+
for line in lst:
82+
if re.search(tarballHash, line):
83+
print("Checksum matched")
84+
break
85+
elif lastline == line:
86+
print("Checksum did not match")
87+
Path(tarball).unlink()
88+
return 1
89+
90+
# Bitcoin Core Release Signing Keys v0.11.0+
91+
signingKey = "01EA5486DE18A882D4C2684590C8019E36C2E964"
92+
93+
isKeyPresent = subprocess.run(
94+
["gpg", "--list-keys", signingKey]).returncode
95+
if isKeyPresent:
96+
return isKeyPresent
97+
98+
isVerified = subprocess.run(
99+
["gpg", "--verify", sha256Sums]).returncode
100+
if isVerified:
101+
return isVerified
102+
103+
# Extract tarball
104+
ret = subprocess.run(['tar', '-zxf', tarball, '-C', tag,
105+
'--strip-components=1',
106+
'bitcoin-{tag}'.format(tag=tag[1:])]).returncode
107+
if ret:
108+
return ret
109+
110+
Path(tarball).unlink()
111+
Path(sha256Sums).unlink()
112+
return 0
113+
114+
115+
def build_release(tag, args) -> int:
116+
githubUrl = "https://github.com/bitcoin/bitcoin"
117+
if args.remove_dir:
118+
if Path(tag).is_dir():
119+
shutil.rmtree(tag)
120+
if not Path(tag).is_dir():
121+
# fetch new tags
122+
subprocess.run(
123+
["git", "fetch", githubUrl, "--tags"])
124+
output = subprocess.check_output(['git', 'tag', '-l', tag])
125+
if not output:
126+
print('Tag {} not found'.format(tag))
127+
return 1
128+
ret = subprocess.run([
129+
'git', 'clone', githubUrl, tag
130+
]).returncode
131+
if ret:
132+
return ret
133+
with pushd(tag):
134+
ret = subprocess.run(['git', 'checkout', tag]).returncode
135+
if ret:
136+
return ret
137+
host = args.host
138+
if args.depends:
139+
with pushd('depends'):
140+
ret = subprocess.run(['make', 'NO_QT=1']).returncode
141+
if ret:
142+
return ret
143+
host = os.environ.get(
144+
'HOST', subprocess.check_output(['./config.guess']))
145+
config_flags = '--prefix={pwd}/depends/{host} '.format(
146+
pwd=os.getcwd(),
147+
host=host) + args.config_flags
148+
cmds = [
149+
'./autogen.sh',
150+
'./configure {}'.format(config_flags),
151+
'make',
152+
]
153+
for cmd in cmds:
154+
ret = subprocess.run(cmd.split()).returncode
155+
if ret:
156+
return ret
157+
# Move binaries, so they're in the same place as in the
158+
# release download
159+
Path('bin').mkdir(exist_ok=True)
160+
files = ['bitcoind', 'bitcoin-cli', 'bitcoin-tx']
161+
for f in files:
162+
Path('src/'+f).rename('bin/'+f)
163+
return 0
164+
165+
166+
def check_host(args) -> int:
167+
args.host = os.environ.get('HOST', subprocess.check_output(
168+
'./depends/config.guess').decode())
169+
if args.download_binary:
170+
platforms = {
171+
'x86_64-*-linux*': 'x86_64-linux-gnu',
172+
'x86_64-apple-darwin*': 'osx64',
173+
}
174+
args.platform = ''
175+
for pattern, target in platforms.items():
176+
if fnmatch(args.host, pattern):
177+
args.platform = target
178+
if not args.platform:
179+
print('Not sure which binary to download for {}'.format(args.host))
180+
return 1
181+
return 0
182+
183+
184+
def main(args) -> int:
185+
if not Path(args.target_dir).is_dir():
186+
Path(args.target_dir).mkdir(exist_ok=True, parents=True)
187+
print("Releases directory: {}".format(args.target_dir))
188+
ret = check_host(args)
189+
if ret:
190+
return ret
191+
if args.download_binary:
192+
with pushd(args.target_dir):
193+
for tag in args.tags:
194+
ret = download_binary(tag, args)
195+
if ret:
196+
return ret
197+
return 0
198+
args.config_flags = os.environ.get('CONFIG_FLAGS', '')
199+
args.config_flags += ' --without-gui --disable-tests --disable-bench'
200+
with pushd(args.target_dir):
201+
for tag in args.tags:
202+
ret = build_release(tag, args)
203+
if ret:
204+
return ret
205+
return 0
206+
207+
208+
if __name__ == '__main__':
209+
parser = argparse.ArgumentParser(
210+
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
211+
parser.add_argument('-r', '--remove-dir', action='store_true',
212+
help='remove existing directory.')
213+
parser.add_argument('-d', '--depends', action='store_true',
214+
help='use depends.')
215+
parser.add_argument('-b', '--download-binary', action='store_true',
216+
help='download release binary.')
217+
parser.add_argument('-t', '--target-dir', action='store',
218+
help='target directory.', default='releases')
219+
parser.add_argument('tags', nargs='+',
220+
help="release tags. e.g.: v0.18.1 v0.20.0rc2")
221+
args = parser.parse_args()
222+
sys.exit(main(args))

0 commit comments

Comments
 (0)