1import os, os.path, shutil, sys, subprocess 2from .utils import * 3from .config import * 4 5class Batch(object): 6 def __init__(self, bconf): 7 self.bconf = bconf 8 self.commands = [] 9 10 self.add(self.vcvars_cmd) 11 self.add('echo on') 12 if self.bconf.vc_version == 'vc14': 13 # I don't know why vcvars doesn't configure this under vc14 14 self.add('set include=%s\\include;%%include%%' % self.bconf.windows_sdk_path) 15 if self.bconf.bitness == 32: 16 self.add('set lib=%s\\lib;%%lib%%' % self.bconf.windows_sdk_path) 17 self.add('set path=%s\\bin;%%path%%' % self.bconf.windows_sdk_path) 18 else: 19 self.add('set lib=%s\\lib\\x64;%%lib%%' % self.bconf.windows_sdk_path) 20 self.add('set path=%s\\bin\\x64;%%path%%' % self.bconf.windows_sdk_path) 21 self.add(self.nasm_cmd) 22 23 self.add('set path=%s;%%path%%' % self.bconf.extra_bin_paths[self.bconf.bitness]['rc_bin']) 24 25 def add(self, cmd): 26 self.commands.append(cmd) 27 28 # if patch fails to apply hunks, it exits with nonzero code. 29 # if patch doesn't find the patch file to apply, it exits with a zero code! 30 ERROR_CHECK = 'IF %ERRORLEVEL% NEQ 0 exit %errorlevel%' 31 32 def batch_text(self): 33 return ("\n" + self.ERROR_CHECK + "\n").join(self.commands) 34 35 @property 36 def vcvars_bitness_parameter(self): 37 params = { 38 32: 'x86', 39 64: 'amd64', 40 } 41 return params[self.bconf.bitness] 42 43 @property 44 def vcvars_relative_path(self): 45 return 'vc/vcvarsall.bat' 46 47 @property 48 def vc_path(self): 49 if self.bconf.vc_version in self.bconf.vc_paths and self.bconf.vc_paths[self.bconf.vc_version]: 50 path = self.bconf.vc_paths[self.bconf.vc_version] 51 if not os.path.join(path, self.vcvars_relative_path): 52 raise Exception('vcvars not found in specified path') 53 return path 54 else: 55 for path in self.bconf.default_vc_paths[self.bconf.vc_version]: 56 if os.path.exists(os.path.join(path, self.vcvars_relative_path)): 57 return path 58 raise Exception('No usable vc path found') 59 60 @property 61 def vcvars_path(self): 62 return os.path.join(self.vc_path, self.vcvars_relative_path) 63 64 @property 65 def vcvars_cmd(self): 66 # https://msdn.microsoft.com/en-us/library/x4d2c09s.aspx 67 return "call \"%s\" %s" % ( 68 self.vcvars_path, 69 self.vcvars_bitness_parameter, 70 ) 71 72 @property 73 def nasm_cmd(self): 74 return "set path=%s;%%path%%\n" % self.bconf.nasm_path 75 76class Builder(object): 77 def __init__(self, **kwargs): 78 self.bconf = kwargs.pop('bconf') 79 self.use_dlls = False 80 81 @contextlib.contextmanager 82 def execute_batch(self): 83 batch = Batch(self.bconf) 84 yield batch 85 with open('doit.bat', 'w') as f: 86 f.write(batch.batch_text()) 87 if False: 88 print("Executing:") 89 with open('doit.bat', 'r') as f: 90 print(f.read()) 91 sys.stdout.flush() 92 rv = subprocess.call(['doit.bat']) 93 if rv != 0: 94 print("\nFailed to execute the following commands:\n") 95 with open('doit.bat', 'r') as f: 96 print(f.read()) 97 sys.stdout.flush() 98 exit(3) 99 100class StandardBuilder(Builder): 101 @property 102 def state_tag(self): 103 return self.output_dir_path 104 105 @property 106 def bin_path(self): 107 return os.path.join(self.bconf.archives_path, self.output_dir_path, 'dist', 'bin') 108 109 @property 110 def include_path(self): 111 return os.path.join(self.bconf.archives_path, self.output_dir_path, 'dist', 'include') 112 113 @property 114 def lib_path(self): 115 return os.path.join(self.bconf.archives_path, self.output_dir_path, 'dist', 'lib') 116 117 @property 118 def dll_paths(self): 119 raise NotImplementedError 120 121 @property 122 def builder_name(self): 123 return self.__class__.__name__.replace('Builder', '').lower() 124 125 @property 126 def my_version(self): 127 return getattr(self.bconf, '%s_version' % self.builder_name) 128 129 @property 130 def output_dir_path(self): 131 return '%s-%s-%s' % (self.builder_name, self.my_version, self.bconf.vc_tag) 132 133 def standard_fetch_extract(self, url_template): 134 url = url_template % dict( 135 my_version=self.my_version, 136 ) 137 fetch(url) 138 archive_basename = os.path.basename(url) 139 archive_name = archive_basename.replace('.tar.gz', '') 140 untar(self.bconf, archive_name) 141 142 suffixed_dir = self.output_dir_path 143 if os.path.exists(suffixed_dir): 144 shutil.rmtree(suffixed_dir) 145 os.rename(archive_name, suffixed_dir) 146 return suffixed_dir 147