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