|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +import argparse |
| 4 | +import os |
| 5 | +import subprocess |
| 6 | +import sys |
| 7 | + |
| 8 | +def setup(): |
| 9 | + global args, workdir |
| 10 | + programs = ['ruby', 'git', 'apt-cacher-ng'] |
| 11 | + if args.kvm: |
| 12 | + programs += ['python-vm-builder', 'qemu-kvm', 'qemu-utils'] |
| 13 | + elif args.docker: |
| 14 | + programs += ['docker.io'] |
| 15 | + else: |
| 16 | + programs += ['lxc', 'debootstrap'] |
| 17 | + subprocess.check_call(['sudo', 'apt-get', 'install', '-qq'] + programs) |
| 18 | + if not os.path.isdir('gitian.sigs'): |
| 19 | + subprocess.check_call(['git', 'clone', 'https://github.com/bitcoin-core/gitian.sigs.git']) |
| 20 | + if not os.path.isdir('bitcoin-detached-sigs'): |
| 21 | + subprocess.check_call(['git', 'clone', 'https://github.com/bitcoin-core/bitcoin-detached-sigs.git']) |
| 22 | + if not os.path.isdir('gitian-builder'): |
| 23 | + subprocess.check_call(['git', 'clone', 'https://github.com/devrandom/gitian-builder.git']) |
| 24 | + os.chdir('gitian-builder') |
| 25 | + make_image_prog = ['bin/make-base-vm', '--suite', 'bionic', '--arch', 'amd64'] |
| 26 | + if args.docker: |
| 27 | + make_image_prog += ['--docker'] |
| 28 | + elif not args.kvm: |
| 29 | + make_image_prog += ['--lxc'] |
| 30 | + subprocess.check_call(make_image_prog) |
| 31 | + os.chdir(workdir) |
| 32 | + |
| 33 | +def build(): |
| 34 | + global args, workdir |
| 35 | + |
| 36 | + os.makedirs('bitcoin-binaries/' + args.version, exist_ok=True) |
| 37 | + print('\nBuilding Dependencies\n') |
| 38 | + os.chdir('gitian-builder') |
| 39 | + os.makedirs('inputs', exist_ok=True) |
| 40 | + |
| 41 | + subprocess.check_call(['wget', '-N', '-P', 'inputs', 'http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz']) |
| 42 | + subprocess.check_call(['wget', '-N', '-P', 'inputs', 'https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch']) |
| 43 | + subprocess.check_call(['make', '-C', '../bitcoin/depends', 'download', 'SOURCES_PATH=' + os.getcwd() + '/cache/common']) |
| 44 | + |
| 45 | + if args.linux: |
| 46 | + print('\nCompiling ' + args.version + ' Linux') |
| 47 | + subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml']) |
| 48 | + subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-linux', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml']) |
| 49 | + subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/'+args.version, shell=True) |
| 50 | + |
| 51 | + if args.windows: |
| 52 | + print('\nCompiling ' + args.version + ' Windows') |
| 53 | + subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']) |
| 54 | + subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']) |
| 55 | + subprocess.check_call('mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz', shell=True) |
| 56 | + subprocess.check_call('mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/'+args.version, shell=True) |
| 57 | + |
| 58 | + if args.macos: |
| 59 | + print('\nCompiling ' + args.version + ' MacOS') |
| 60 | + subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']) |
| 61 | + subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']) |
| 62 | + subprocess.check_call('mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz', shell=True) |
| 63 | + subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/'+args.version, shell=True) |
| 64 | + |
| 65 | + os.chdir(workdir) |
| 66 | + |
| 67 | + if args.commit_files: |
| 68 | + print('\nCommitting '+args.version+' Unsigned Sigs\n') |
| 69 | + os.chdir('gitian.sigs') |
| 70 | + subprocess.check_call(['git', 'add', args.version+'-linux/'+args.signer]) |
| 71 | + subprocess.check_call(['git', 'add', args.version+'-win-unsigned/'+args.signer]) |
| 72 | + subprocess.check_call(['git', 'add', args.version+'-osx-unsigned/'+args.signer]) |
| 73 | + subprocess.check_call(['git', 'commit', '-a', '-m', 'Add '+args.version+' unsigned sigs for '+args.signer]) |
| 74 | + os.chdir(workdir) |
| 75 | + |
| 76 | +def sign(): |
| 77 | + global args, workdir |
| 78 | + os.chdir('gitian-builder') |
| 79 | + |
| 80 | + if args.windows: |
| 81 | + print('\nSigning ' + args.version + ' Windows') |
| 82 | + subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) |
| 83 | + subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) |
| 84 | + subprocess.check_call('mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/'+args.version, shell=True) |
| 85 | + subprocess.check_call('mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/'+args.version, shell=True) |
| 86 | + |
| 87 | + if args.macos: |
| 88 | + print('\nSigning ' + args.version + ' MacOS') |
| 89 | + subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) |
| 90 | + subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) |
| 91 | + subprocess.check_call('mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/'+args.version+'/bitcoin-'+args.version+'-osx.dmg', shell=True) |
| 92 | + |
| 93 | + os.chdir(workdir) |
| 94 | + |
| 95 | + if args.commit_files: |
| 96 | + print('\nCommitting '+args.version+' Signed Sigs\n') |
| 97 | + os.chdir('gitian.sigs') |
| 98 | + subprocess.check_call(['git', 'add', args.version+'-win-signed/'+args.signer]) |
| 99 | + subprocess.check_call(['git', 'add', args.version+'-osx-signed/'+args.signer]) |
| 100 | + subprocess.check_call(['git', 'commit', '-a', '-m', 'Add '+args.version+' signed binary sigs for '+args.signer]) |
| 101 | + os.chdir(workdir) |
| 102 | + |
| 103 | +def verify(): |
| 104 | + global args, workdir |
| 105 | + os.chdir('gitian-builder') |
| 106 | + |
| 107 | + print('\nVerifying v'+args.version+' Linux\n') |
| 108 | + subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml']) |
| 109 | + print('\nVerifying v'+args.version+' Windows\n') |
| 110 | + subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']) |
| 111 | + print('\nVerifying v'+args.version+' MacOS\n') |
| 112 | + subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']) |
| 113 | + print('\nVerifying v'+args.version+' Signed Windows\n') |
| 114 | + subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) |
| 115 | + print('\nVerifying v'+args.version+' Signed MacOS\n') |
| 116 | + subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-signed', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) |
| 117 | + |
| 118 | + os.chdir(workdir) |
| 119 | + |
| 120 | +def main(): |
| 121 | + global args, workdir |
| 122 | + |
| 123 | + parser = argparse.ArgumentParser(usage='%(prog)s [options] signer version') |
| 124 | + parser.add_argument('-c', '--commit', action='store_true', dest='commit', help='Indicate that the version argument is for a commit or branch') |
| 125 | + parser.add_argument('-u', '--url', dest='url', default='https://github.com/bitcoin/bitcoin', help='Specify the URL of the repository. Default is %(default)s') |
| 126 | + parser.add_argument('-v', '--verify', action='store_true', dest='verify', help='Verify the Gitian build') |
| 127 | + parser.add_argument('-b', '--build', action='store_true', dest='build', help='Do a Gitian build') |
| 128 | + parser.add_argument('-s', '--sign', action='store_true', dest='sign', help='Make signed binaries for Windows and MacOS') |
| 129 | + parser.add_argument('-B', '--buildsign', action='store_true', dest='buildsign', help='Build both signed and unsigned binaries') |
| 130 | + parser.add_argument('-o', '--os', dest='os', default='lwm', help='Specify which Operating Systems the build is for. Default is %(default)s. l for Linux, w for Windows, m for MacOS') |
| 131 | + parser.add_argument('-j', '--jobs', dest='jobs', default='2', help='Number of processes to use. Default %(default)s') |
| 132 | + parser.add_argument('-m', '--memory', dest='memory', default='2000', help='Memory to allocate in MiB. Default %(default)s') |
| 133 | + parser.add_argument('-k', '--kvm', action='store_true', dest='kvm', help='Use KVM instead of LXC') |
| 134 | + parser.add_argument('-d', '--docker', action='store_true', dest='docker', help='Use Docker instead of LXC') |
| 135 | + parser.add_argument('-S', '--setup', action='store_true', dest='setup', help='Set up the Gitian building environment. Uses LXC. If you want to use KVM, use the --kvm option. Only works on Debian-based systems (Ubuntu, Debian)') |
| 136 | + parser.add_argument('-D', '--detach-sign', action='store_true', dest='detach_sign', help='Create the assert file for detached signing. Will not commit anything.') |
| 137 | + parser.add_argument('-n', '--no-commit', action='store_false', dest='commit_files', help='Do not commit anything to git') |
| 138 | + parser.add_argument('signer', help='GPG signer to sign each build assert file') |
| 139 | + parser.add_argument('version', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified') |
| 140 | + |
| 141 | + args = parser.parse_args() |
| 142 | + workdir = os.getcwd() |
| 143 | + |
| 144 | + args.linux = 'l' in args.os |
| 145 | + args.windows = 'w' in args.os |
| 146 | + args.macos = 'm' in args.os |
| 147 | + |
| 148 | + if args.buildsign: |
| 149 | + args.build=True |
| 150 | + args.sign=True |
| 151 | + |
| 152 | + if args.kvm and args.docker: |
| 153 | + raise Exception('Error: cannot have both kvm and docker') |
| 154 | + |
| 155 | + args.sign_prog = 'true' if args.detach_sign else 'gpg --detach-sign' |
| 156 | + |
| 157 | + # Set enviroment variable USE_LXC or USE_DOCKER, let gitian-builder know that we use lxc or docker |
| 158 | + if args.docker: |
| 159 | + os.environ['USE_DOCKER'] = '1' |
| 160 | + elif not args.kvm: |
| 161 | + os.environ['USE_LXC'] = '1' |
| 162 | + |
| 163 | + # Disable for MacOS if no SDK found |
| 164 | + if args.macos and not os.path.isfile('gitian-builder/inputs/MacOSX10.11.sdk.tar.gz'): |
| 165 | + print('Cannot build for MacOS, SDK does not exist. Will build for other OSes') |
| 166 | + args.macos = False |
| 167 | + |
| 168 | + script_name = os.path.basename(sys.argv[0]) |
| 169 | + # Signer and version shouldn't be empty |
| 170 | + if args.signer == '': |
| 171 | + print(script_name+': Missing signer.') |
| 172 | + print('Try '+script_name+' --help for more information') |
| 173 | + exit(1) |
| 174 | + if args.version == '': |
| 175 | + print(script_name+': Missing version.') |
| 176 | + print('Try '+script_name+' --help for more information') |
| 177 | + exit(1) |
| 178 | + |
| 179 | + # Add leading 'v' for tags |
| 180 | + args.commit = ('' if args.commit else 'v') + args.version |
| 181 | + print(args.commit) |
| 182 | + |
| 183 | + if args.setup: |
| 184 | + setup() |
| 185 | + |
| 186 | + os.chdir('bitcoin') |
| 187 | + subprocess.check_call(['git', 'fetch']) |
| 188 | + subprocess.check_call(['git', 'checkout', args.commit]) |
| 189 | + os.chdir(workdir) |
| 190 | + |
| 191 | + if args.build: |
| 192 | + build() |
| 193 | + |
| 194 | + if args.sign: |
| 195 | + sign() |
| 196 | + |
| 197 | + if args.verify: |
| 198 | + verify() |
| 199 | + |
| 200 | +if __name__ == '__main__': |
| 201 | + main() |
0 commit comments