1#!/usr/bin/env python3 2 3import os.path 4import re 5import sys 6 7WINDOWS = [ 8 # --------------------- ----------------- # 9 # Runtime ID Platform # 10 # --------------------- ----------------- # 11 ( 'win-x64', 'x64' ), 12 ( 'win-x86', 'Win32' ), 13 # --------------------- ----------------- # 14] 15 16MACOS = [ 17 # --------------------- ----------------- # 18 # Runtime ID Codename # 19 # --------------------- ----------------- # 20 ( 'osx-x64', 'sierra' ), 21 # --------------------- ----------------- # 22] 23 24LINUX = [ 25 # --------------------- ----------------- # 26 # Runtime ID Docker Image # 27 # --------------------- ----------------- # 28 ( 'linux-x64', 'debian:stretch' ), 29 # --------------------- ----------------- # 30] 31 32EXTRAS = [ 'LICENSE', 'AUTHORS', 'ChangeLog' ] 33 34PROPSFILE = 'libsodium.props' 35MAKEFILE = 'Makefile' 36BUILDDIR = 'build' 37CACHEDIR = 'cache' 38TEMPDIR = 'temp' 39 40PACKAGE = 'libsodium' 41LIBRARY = 'libsodium' 42 43DOCKER = 'sudo docker' 44 45class Version: 46 47 def __init__(self, libsodium_version, package_version): 48 self.libsodium_version = libsodium_version 49 self.package_version = package_version 50 51 self.builddir = os.path.join(BUILDDIR, libsodium_version) 52 self.tempdir = os.path.join(TEMPDIR, libsodium_version) 53 self.projfile = os.path.join(self.builddir, '{0}.{1}.pkgproj'.format(PACKAGE, package_version)) 54 self.propsfile = os.path.join(self.builddir, '{0}.props'.format(PACKAGE)) 55 self.pkgfile = os.path.join(BUILDDIR, '{0}.{1}.nupkg'.format(PACKAGE, package_version)) 56 57class WindowsItem: 58 59 def __init__(self, version, rid, platform): 60 self.url = 'https://download.libsodium.org/libsodium/releases/libsodium-{0}-msvc.zip'.format(version.libsodium_version) 61 self.cachefile = os.path.join(CACHEDIR, re.sub(r'[^A-Za-z0-9.]', '-', self.url)) 62 self.packfile = os.path.join(version.builddir, 'runtimes', rid, 'native', LIBRARY + '.dll') 63 self.itemfile = '{0}/Release/v140/dynamic/libsodium.dll'.format(platform) 64 self.tempdir = os.path.join(version.tempdir, rid) 65 self.tempfile = os.path.join(self.tempdir, os.path.normpath(self.itemfile)) 66 67 def make(self, f): 68 f.write('\n') 69 f.write('{0}: {1}\n'.format(self.packfile, self.tempfile)) 70 f.write('\t@mkdir -p $(dir $@)\n') 71 f.write('\tcp -f $< $@\n') 72 f.write('\n') 73 f.write('{0}: {1}\n'.format(self.tempfile, self.cachefile)) 74 f.write('\t@mkdir -p $(dir $@)\n') 75 f.write('\tcd {0} && unzip -q -DD -o {1} \'{2}\'\n'.format( 76 self.tempdir, 77 os.path.relpath(self.cachefile, self.tempdir), 78 self.itemfile 79 )) 80 81class MacOSItem: 82 83 def __init__(self, version, rid, codename): 84 self.url = 'https://bintray.com/homebrew/bottles/download_file?file_path=libsodium-{0}.{1}.bottle.tar.gz'.format(version.libsodium_version, codename) 85 self.cachefile = os.path.join(CACHEDIR, re.sub(r'[^A-Za-z0-9.]', '-', self.url)) 86 self.packfile = os.path.join(version.builddir, 'runtimes', rid, 'native', LIBRARY + '.dylib') 87 self.itemfile = 'libsodium/{0}/lib/libsodium.dylib'.format(version.libsodium_version) 88 self.tempdir = os.path.join(version.tempdir, rid) 89 self.tempfile = os.path.join(self.tempdir, os.path.normpath(self.itemfile)) 90 91 def make(self, f): 92 f.write('\n') 93 f.write('{0}: {1}\n'.format(self.packfile, self.tempfile)) 94 f.write('\t@mkdir -p $(dir $@)\n') 95 f.write('\tcp -f $< $@\n') 96 f.write('\n') 97 f.write('{0}: {1}\n'.format(self.tempfile, self.cachefile)) 98 f.write('\t@mkdir -p $(dir $@)\n') 99 f.write('\tcd {0} && tar xzmf {1} \'{2}\'\n'.format( 100 self.tempdir, 101 os.path.relpath(self.cachefile, self.tempdir), 102 os.path.dirname(self.itemfile) 103 )) 104 105class LinuxItem: 106 107 def __init__(self, version, rid, docker_image): 108 self.url = 'https://download.libsodium.org/libsodium/releases/libsodium-{0}.tar.gz'.format(version.libsodium_version) 109 self.cachefile = os.path.join(CACHEDIR, re.sub(r'[^A-Za-z0-9.]', '-', self.url)) 110 self.packfile = os.path.join(version.builddir, 'runtimes', rid, 'native', LIBRARY + '.so') 111 self.tempdir = os.path.join(version.tempdir, rid) 112 self.tempfile = os.path.join(self.tempdir, 'libsodium.so') 113 self.docker_image = docker_image 114 self.recipe = rid 115 116 def make(self, f): 117 recipe = self.recipe 118 while not os.path.exists(os.path.join('recipes', recipe)): 119 m = re.fullmatch(r'([^.-]+)((([.][^.-]+)*)[.][^.-]+)?([-].*)?', recipe) 120 if m.group(5) is None: 121 recipe = 'build' 122 break 123 elif m.group(2) is None: 124 recipe = m.group(1) 125 else: 126 recipe = m.group(1) + m.group(3) + m.group(5) 127 128 f.write('\n') 129 f.write('{0}: {1}\n'.format(self.packfile, self.tempfile)) 130 f.write('\t@mkdir -p $(dir $@)\n') 131 f.write('\tcp -f $< $@\n') 132 f.write('\n') 133 f.write('{0}: {1}\n'.format(self.tempfile, self.cachefile)) 134 f.write('\t@mkdir -p $(dir $@)\n') 135 f.write('\t{0} run --rm '.format(DOCKER) + 136 '-v $(abspath recipes):/io/recipes ' + 137 '-v $(abspath $<):/io/libsodium.tar.gz ' + 138 '-v $(abspath $(dir $@)):/io/output ' + 139 '{0} sh -x -e /io/recipes/{1}\n'.format(self.docker_image, recipe)) 140 141class ExtraItem: 142 143 def __init__(self, version, filename): 144 self.url = 'https://download.libsodium.org/libsodium/releases/libsodium-{0}.tar.gz'.format(version.libsodium_version) 145 self.cachefile = os.path.join(CACHEDIR, re.sub(r'[^A-Za-z0-9.]', '-', self.url)) 146 self.packfile = os.path.join(version.builddir, filename) 147 self.itemfile = 'libsodium-{0}/{1}'.format(version.libsodium_version, filename) 148 self.tempdir = os.path.join(version.tempdir, 'extras') 149 self.tempfile = os.path.join(self.tempdir, os.path.normpath(self.itemfile)) 150 151 def make(self, f): 152 f.write('\n') 153 f.write('{0}: {1}\n'.format(self.packfile, self.tempfile)) 154 f.write('\t@mkdir -p $(dir $@)\n') 155 f.write('\tcp -f $< $@\n') 156 f.write('\n') 157 f.write('{0}: {1}\n'.format(self.tempfile, self.cachefile)) 158 f.write('\t@mkdir -p $(dir $@)\n') 159 f.write('\tcd {0} && tar xzmf {1} \'{2}\'\n'.format( 160 self.tempdir, 161 os.path.relpath(self.cachefile, self.tempdir), 162 self.itemfile 163 )) 164 165def main(args): 166 m = re.fullmatch(r'((\d+\.\d+\.\d+)(\.\d+)?)(?:-(\w+(?:[_.-]\w+)*))?', args[1]) if len(args) == 2 else None 167 168 if m is None: 169 print('Usage:') 170 print(' python3 prepare.py <version>') 171 print() 172 print('Examples:') 173 print(' python3 prepare.py 1.0.16-preview-01') 174 print(' python3 prepare.py 1.0.16-preview-02') 175 print(' python3 prepare.py 1.0.16-preview-03') 176 print(' python3 prepare.py 1.0.16') 177 print(' python3 prepare.py 1.0.16.1-preview-01') 178 print(' python3 prepare.py 1.0.16.1') 179 print(' python3 prepare.py 1.0.16.2') 180 return 1 181 182 version = Version(m.group(2), m.group(0)) 183 184 items = [ WindowsItem(version, rid, platform) for (rid, platform) in WINDOWS ] + \ 185 [ MacOSItem(version, rid, codename) for (rid, codename) in MACOS ] + \ 186 [ LinuxItem(version, rid, docker_image) for (rid, docker_image) in LINUX ] + \ 187 [ ExtraItem(version, filename) for filename in EXTRAS ] 188 189 downloads = {item.cachefile: item.url for item in items} 190 191 with open(MAKEFILE, 'w') as f: 192 f.write('all: {0}\n'.format(version.pkgfile)) 193 194 for download in sorted(downloads): 195 f.write('\n') 196 f.write('{0}:\n'.format(download)) 197 f.write('\t@mkdir -p $(dir $@)\n') 198 f.write('\tcurl -f#Lo $@ \'{0}\'\n'.format(downloads[download])) 199 200 for item in items: 201 item.make(f) 202 203 f.write('\n') 204 f.write('{0}: {1}\n'.format(version.propsfile, PROPSFILE)) 205 f.write('\t@mkdir -p $(dir $@)\n') 206 f.write('\tcp -f $< $@\n') 207 208 f.write('\n') 209 f.write('{0}: {1}\n'.format(version.projfile, version.propsfile)) 210 f.write('\t@mkdir -p $(dir $@)\n') 211 f.write('\techo \'' + 212 '<Project Sdk="Microsoft.NET.Sdk">' + 213 '<Import Project="{0}" />'.format(os.path.relpath(version.propsfile, os.path.dirname(version.projfile))) + 214 '<PropertyGroup>' + 215 '<Version>{0}</Version>'.format(version.package_version) + 216 '</PropertyGroup>' + 217 '</Project>\' > $@\n') 218 219 f.write('\n') 220 f.write('{0}:'.format(version.pkgfile)) 221 f.write(' \\\n\t\t{0}'.format(version.projfile)) 222 f.write(' \\\n\t\t{0}'.format(version.propsfile)) 223 for item in items: 224 f.write(' \\\n\t\t{0}'.format(item.packfile)) 225 f.write('\n') 226 f.write('\t@mkdir -p $(dir $@)\n') 227 f.write('\t{0} run --rm '.format(DOCKER) + 228 '-v $(abspath recipes):/io/recipes ' + 229 '-v $(abspath $(dir $<)):/io/input ' + 230 '-v $(abspath $(dir $@)):/io/output ' + 231 '{0} sh -x -e /io/recipes/{1} {2}\n'.format('microsoft/dotnet:2.0-sdk', 'pack', os.path.relpath(version.projfile, version.builddir))) 232 233 f.write('\n') 234 f.write('test: {0}\n'.format(version.pkgfile)) 235 f.write('\t{0} run --rm '.format(DOCKER) + 236 '-v $(abspath recipes):/io/recipes ' + 237 '-v $(abspath $(dir $<)):/io/packages ' + 238 '{0} sh -x -e /io/recipes/{1} "{2}"\n'.format('microsoft/dotnet:2.0-sdk', 'test', version.package_version)) 239 240 print('prepared', MAKEFILE, 'to make', version.pkgfile, 'for libsodium', version.libsodium_version) 241 return 0 242 243if __name__ == '__main__': 244 sys.exit(main(sys.argv)) 245