Ticket #451: pep8.diff
| File pep8.diff, 81.1 KB (added by jrabbit, 5 years ago) |
|---|
-
haikuporter
30 30 # -- HaikuPorts options ------------------------------------------------------- 31 31 32 32 # location of haikuports.conf 33 33 34 haikuPortsConf = '/boot/common/etc/haikuports.conf' 34 35 35 36 # create new type 'ShellType' for identifying lists of shell commands 37 38 36 39 class shell(list): 37 pass 40 41 pass 42 43 38 44 ShellType = shell 39 45 40 46 # create new type 'StatusType' for identifying the port's status on a platform 41 47 # the possible states are defined in the 'Config' class (reStatusType) 48 49 42 50 class status(str): 43 pass 51 52 pass 53 54 44 55 StatusType = status 45 56 46 57 # allowed types of the /etc/haikuports.conf values 58 47 59 confTypes = {} 48 60 confTypes['PACKAGES_PATH'] = [types.StringType] 49 61 confTypes['PATCH_OPTIONS'] = [types.StringType] 50 62 51 63 # allowed types of the BepFile values 64 52 65 bepTypes = {} 53 bepTypes['DESCRIPTION'] = [types.StringType, types.ListType]54 bepTypes['HOMEPAGE'] = [types.StringType]55 bepTypes['SRC_URI'] = [types.StringType, types.ListType]66 bepTypes['DESCRIPTION'] = [types.StringType, types.ListType] 67 bepTypes['HOMEPAGE'] = [types.StringType] 68 bepTypes['SRC_URI'] = [types.StringType, types.ListType] 56 69 bepTypes['CHECKSUM_MD5'] = [types.StringType] 57 bepTypes['REVISION'] = [types.IntType]70 bepTypes['REVISION'] = [types.IntType] 58 71 bepTypes['STATUS_HAIKU'] = [StatusType] 59 bepTypes['DEPEND'] = [types.StringType, types.ListType, types.NoneType]60 bepTypes['BUILD'] = [ShellType]61 bepTypes['INSTALL'] = [ShellType]62 bepTypes['TEST'] = [ShellType]63 bepTypes['MESSAGE'] = [types.StringType]64 bepTypes['LICENSE'] = [types.StringType, types.ListType]65 bepTypes['COPYRIGHT'] = [types.StringType, types.ListType]72 bepTypes['DEPEND'] = [types.StringType, types.ListType, types.NoneType] 73 bepTypes['BUILD'] = [ShellType] 74 bepTypes['INSTALL'] = [ShellType] 75 bepTypes['TEST'] = [ShellType] 76 bepTypes['MESSAGE'] = [types.StringType] 77 bepTypes['LICENSE'] = [types.StringType, types.ListType] 78 bepTypes['COPYRIGHT'] = [types.StringType, types.ListType] 66 79 67 # is field # default 68 bepDefaults = {} # required? # value 69 bepDefaults['DESCRIPTION'] = [True, None ] 70 bepDefaults['HOMEPAGE'] = [True, None ] 71 bepDefaults['SRC_URI'] = [True, None ] 72 bepDefaults['CHECKSUM_MD5'] = [False, None ] 73 bepDefaults['REVISION'] = [True, None ] 74 bepDefaults['WORKING'] = [False, True ] 75 bepDefaults['STATUS_HAIKU'] = [False, 'untested' ] 76 bepDefaults['DEPEND'] = [False, None ] 77 bepDefaults['BUILD'] = [False, shell() ] 78 bepDefaults['INSTALL'] = [False, shell() ] 79 bepDefaults['TEST'] = [False, shell() ] 80 bepDefaults['MESSAGE'] = [False, None ] 81 bepDefaults['LICENSE'] = [False, None ] 82 bepDefaults['COPYRIGHT'] = [False, None ] 80 # is field.... #....default 83 81 82 bepDefaults = {} # required?.... #....value 83 bepDefaults['DESCRIPTION'] = [True, None] 84 bepDefaults['HOMEPAGE'] = [True, None] 85 bepDefaults['SRC_URI'] = [True, None] 86 bepDefaults['CHECKSUM_MD5'] = [False, None] 87 bepDefaults['REVISION'] = [True, None] 88 bepDefaults['WORKING'] = [False, True] 89 bepDefaults['STATUS_HAIKU'] = [False, 'untested'] 90 bepDefaults['DEPEND'] = [False, None] 91 bepDefaults['BUILD'] = [False, shell()] 92 bepDefaults['INSTALL'] = [False, shell()] 93 bepDefaults['TEST'] = [False, shell()] 94 bepDefaults['MESSAGE'] = [False, None] 95 bepDefaults['LICENSE'] = [False, None] 96 bepDefaults['COPYRIGHT'] = [False, None] 97 84 98 # names of directories 99 85 100 paths = {} 86 paths['work'] = "work"87 paths['patches'] = "patches"88 paths['download'] = "download"89 paths['distro'] = "distro"90 paths['licenses'] = "licesnes"101 paths['work'] = 'work' 102 paths['patches'] = 'patches' 103 paths['download'] = 'download' 104 paths['distro'] = 'distro' 105 paths['licenses'] = 'licesnes' 91 106 92 107 # regex to split bep filenames into port / version 108 93 109 regExp = {} 94 regExp['portname'] = '^(?P<name>[\w\-\+]+?)' 95 regExp['portversion'] = '(?P<version>[\w]*?[\d]+([\w\-\\.\+])*)' 96 regExp['portfullname'] = regExp['portname'] + '-' + regExp['portversion'] 97 regExp['bepfilename'] = regExp['portfullname'] + '\.bep$' 110 regExp['portname'] = '^(?P<name>[\w\-\+]+?)' 111 regExp['portversion'] = '(?P<version>[\w]*?[\d]+([\w\-\\.\+])*)' 112 regExp['portfullname'] = regExp['portname'] + '-' + regExp['portversion' 113 ] 114 regExp['bepfilename'] = regExp['portfullname'] + '\.bep$' 98 115 99 116 # -- capture output of shell command ----------------------------------------- 100 117 118 101 119 def getCommandOutput(command): 102 status, data = commands.getstatusoutput(command) 103 if os.WEXITSTATUS(status) != 0: 104 sys.exit('\'%s\' failed with exit code %d' % (command, os.WEXITSTATUS(status))) 105 return data 120 (status, data) = commands.getstatusoutput(command) 121 if os.WEXITSTATUS(status) != 0: 122 sys.exit('\'%s\' failed with exit code %d' % (command, 123 os.WEXITSTATUS(status))) 124 return data 106 125 126 107 127 # -- Set up locale for thousands seperators ---------------------------------- 128 129 108 130 def _temp(lc=locale.localeconv()): 109 lc.update({'thousands_sep':',','grouping':[3,3,0]})110 return lc131 lc.update({'thousands_sep': ',', 'grouping': [3, 3, 0]}) 132 return lc 111 133 134 112 135 def FindDirectory(aDir, subDirPath): 113 result = commands.getoutput('finddir %s' % aDir) + '/' + subDirPath114 return result136 result = commands.getoutput('finddir %s' % aDir) + '/' + subDirPath 137 return result 115 138 116 139 117 locale.localeconv =_temp140 locale.localeconv = _temp 118 141 119 142 # -- Main Program ------------------------------------------------------------ 120 143 144 121 145 class HaikuPorter: 122 def __init__(self, options, args):123 # read global settings124 mainConfig = Config(haikuPortsConf)125 self.confKeys = mainConfig.getKeys()126 self.options = options127 146 128 for key in self.confKeys: 129 try: 130 if type(self.confKeys[key]) not in confTypes[key]: 131 sys.exit("Error: Invalid value type for " + key + ". Expecting " + str(confTypes[key])) 132 except KeyError, e: 133 print "Warning: Unknown key label '" + key + "' in " + haikuPortsConf + ". Ignoring." 147 def __init__(self, options, args): 134 148 135 self.packagesPath = self.confKeys['PACKAGES_PATH'] 136 if self.packagesPath[-1] == '/': 137 # strip trailing '/' 138 self.packagesPath = self.packagesPath[:-1] 149 # read global settings 139 150 140 # if requested, list all ports in the HaikuPorts tree 141 if options.list: 142 self.searchPorts(None) 143 sys.exit() 151 mainConfig = Config(haikuPortsConf) 152 self.confKeys = mainConfig.getKeys() 153 self.options = options 144 154 145 # if requested, search for a port 146 if options.search: 147 if len(args) == 0: 148 print "You need to specifiy a search string." 149 print "Invoke '" + sys.argv[0] + " -h' for usage information." 150 sys.exit(1) 155 for key in self.confKeys: 156 try: 157 if type(self.confKeys[key]) not in confTypes[key]: 158 sys.exit('Error: Invalid value type for ' + key 159 + '. Expecting ' + str(confTypes[key])) 160 except KeyError, e: 161 print "Warning: Unknown key label '" + key + "' in "\ 162 + haikuPortsConf + '. Ignoring.' 151 163 152 self.searchPorts(args[0]) 153 sys.exit() 164 self.packagesPath = self.confKeys['PACKAGES_PATH'] 165 if self.packagesPath[-1] == '/': 154 166 155 # if requested, checkout or update ports tree 156 if options.get: 157 self.updatePortsTree() 158 sys.exit() 167 # strip trailing '/' 159 168 160 # if requested, print the location of the haikuports source tree 161 if options.tree: 162 print self.packagesPath 163 sys.exit() 164 165 # if requested, scan the ports tree for problems 166 if options.lint: 167 self.checkSourceTree() 168 sys.exit() 169 170 # if there is no argument given, exit 171 if len(args) == 0: 172 print "You need to specifiy at least a port name." 173 print "Invoke '" + sys.argv[0] + " -h' for usage information." 174 sys.exit(1) 175 else: 176 port = args[0] 177 178 # split the argument into a port name and a version 179 reWithVersion = re.compile(regExp['portfullname']) 180 reWithoutVersion = re.compile(regExp['portname'] + '$') 181 if reWithVersion.match(port): # with version 182 m = reWithVersion.match(port) 183 self.portName = m.group("name") 184 self.portVersion = m.group("version") 185 elif reWithoutVersion.match(port): # without version 186 m = reWithoutVersion.match(port) 187 self.portName = m.group("name") 188 self.portVersion = None 189 else: # invalid argument 190 sys.exit("Error: Invalid port name " + port) 169 self.packagesPath = self.packagesPath[:-1] 191 170 192 # find the port in the HaikuPorts tree 193 self.portCategory = self.getCategory(self.portName) 194 if self.portCategory == None: 195 sys.exit("Error: Port " + self.portName + " not found.") 171 # if requested, list all ports in the HaikuPorts tree 196 172 197 # create full paths for the directories 198 self.portDir = self.packagesPath + '/' + self.portCategory + '/' + self.portName 199 self.downloadDir= self.portDir + '/' + paths['download'] 200 self.workDir = self.portDir + '/' + paths['work'] 201 self.patchesDir = self.portDir + '/' + paths['patches'] 202 self.distroDir = self.portDir + '/' + paths['distro'] 173 if options.list: 174 self.searchPorts(None) 175 sys.exit() 203 176 204 # if the port version was not specified, list available versions 205 if self.portVersion == None: 206 versions = [] 207 reBepFile = re.compile(regExp['bepfilename']) 208 dirList = os.listdir(self.portDir) 209 for item in dirList: 210 m = reBepFile.match(item) 211 if m: 212 versions.append([m.group("version"), item]) 213 if len(versions) > 1: 214 print "Following versions of %s are available:" % (self.portName) 215 for version in versions: 216 print " " + version[0] 217 sys.exit("Run haikuporter again, specifiying a port version") 218 elif len(versions) == 1: 219 self.portVersion = versions[0][0] 220 else: 221 sys.exit("Error: .bep files for " + self.portName +" not found.") 177 # if requested, search for a port 222 178 223 # show port description, if requested 224 if options.about: 225 self.printDescription() 226 sys.exit() 179 if options.search: 180 if len(args) == 0: 181 print 'You need to specifiy a search string.' 182 print "Invoke '" + sys.argv[0]\ 183 + " -h' for usage information." 184 sys.exit(1) 227 185 228 # read data from the bep file 229 self.parseBepFile()186 self.searchPorts(args[0]) 187 sys.exit() 230 188 231 # warn when the port is not stable on this platform 232 self.platform = self.detectOS() 233 if self.platform == None: 234 sys.exit("Error: Unknown OS platform!") 235 else: 236 if self.bepKeys['STATUS_' + self.platform] != "stable": 237 print "Warning: This port is " + self.bepKeys['STATUS_' + self.platform] + " on this platform." 238 if not self.options.yes: 239 answer = raw_input("Continue (y/n + enter)? ") 240 if answer == '': 241 sys.exit(1) 242 if answer[0].lower() == 'y': 243 print " ok" 244 else: 245 sys.exit(1) 189 # if requested, checkout or update ports tree 246 190 247 if self.bepKeys['MESSAGE']: 248 print self.bepKeys['MESSAGE'] 249 if not self.options.yes: 250 answer = raw_input("Continue (y/n + enter)? ") 251 if answer == '': 252 sys.exit(1) 253 if answer[0].lower() == 'y': 254 print " ok" 255 else: 256 sys.exit(1) 191 if options.get: 192 self.updatePortsTree() 193 sys.exit() 257 194 258 # clean the work dir and don't build when making a source archive 259 if options.archive: 260 options.build = False 261 options.clean = True 262 options.patch = True 195 # if requested, print the location of the haikuports source tree 263 196 264 # clean the work directory, if requested 265 if options.clean: 266 self.cleanWorkDirectory()197 if options.tree: 198 print self.packagesPath 199 sys.exit() 267 200 268 # don't build when not patching 269 if not options.patch: 270 options.build = False 201 # if requested, scan the ports tree for problems 271 202 272 self.checkDependencies() # check dependencies 273 self.downloadSource() # fetch sources 274 self.checksumSource() # calculate checksum 275 self.unpackSource() # unpack source archive 276 if options.patch: 277 self.patchSource() # apply patches 278 if options.build: 279 self.buildPort() # build 280 if options.install: 281 self.installPort() # install 282 if options.distro: 283 self.makePackage() # distro 284 if options.archive: 285 self.makePatchedArchive() # create patched source archive 286 if options.test: 287 self.testPort() # run tests 203 if options.lint: 204 self.checkSourceTree() 205 sys.exit() 288 206 289 def printDescription(self): 290 """Show port description""" 207 # if there is no argument given, exit 291 208 292 bepFilename = self.portDir + '/' + self.portName + '-' + self.portVersion + ".bep" 209 if len(args) == 0: 210 print 'You need to specifiy at least a port name.' 211 print "Invoke '" + sys.argv[0]\ 212 + " -h' for usage information." 213 sys.exit(1) 214 else: 215 port = args[0] 293 216 294 reOptionValue = re.compile('^(?P<key>[A-Z0-9_]*)\s*=\s*"(?P<value>.*)(?<!\\\\)"\s*$') 295 reComment = re.compile('^\s*#.*$') 296 reEmptyLine = re.compile('^\s*$') 217 # split the argument into a port name and a version 297 218 298 if not os.path.exists(bepFilename): 299 sys.exit("Error: " + self.portName + " version " + self.portVersion + " not found.") 219 reWithVersion = re.compile(regExp['portfullname']) 220 reWithoutVersion = re.compile(regExp['portname'] + '$') 221 if reWithVersion.match(port): # with version 222 m = reWithVersion.match(port) 223 self.portName = m.group('name') 224 self.portVersion = m.group('version') 225 elif reWithoutVersion.match(port): 300 226 301 fp = open(bepFilename) 302 lineCount = 0 227 # without version 303 228 304 line = fp.readline() 305 lineCount += 1 229 m = reWithoutVersion.match(port) 230 self.portName = m.group('name') 231 self.portVersion = None 232 else: 306 233 307 print '*'*80 234 # invalid argument 308 235 309 while line != "": 310 # empty line or comment 311 if reEmptyLine.match(line) or reComment.match(line): 312 pass 313 # value option (single line) (check BEFORE list option) 314 elif reOptionValue.match(line): 315 m = reOptionValue.match(line) 316 key = m.group("key") 317 value = m.group("value") 318 319 if 'DESCRIPTION' in key: 320 print key.capitalize()+":",value 321 elif 'HOMEPAGE' in key: 322 print key.capitalize()+":",value 236 sys.exit('Error: Invalid port name ' + port) 323 237 324 line = fp.readline() 325 lineCount += 1 238 # find the port in the HaikuPorts tree 326 239 327 print '*'*80 240 self.portCategory = self.getCategory(self.portName) 241 if self.portCategory == None: 242 sys.exit('Error: Port ' + self.portName + ' not found.') 328 243 329 fp.close() 244 # create full paths for the directories 330 245 246 self.portDir = self.packagesPath + '/' + self.portCategory + '/'\ 247 + self.portName 248 self.downloadDir = self.portDir + '/' + paths['download'] 249 self.workDir = self.portDir + '/' + paths['work'] 250 self.patchesDir = self.portDir + '/' + paths['patches'] 251 self.distroDir = self.portDir + '/' + paths['distro'] 331 252 332 def setFlag(self, name): 333 open('%s/%s-%s.%s' %(self.workDir, self.portName, self.portVersion, name), 'w').close() 253 # if the port version was not specified, list available versions 334 254 255 if self.portVersion == None: 256 versions = [] 257 reBepFile = re.compile(regExp['bepfilename']) 258 dirList = os.listdir(self.portDir) 259 for item in dirList: 260 m = reBepFile.match(item) 261 if m: 262 versions.append([m.group('version'), item]) 263 if len(versions) > 1: 264 print 'Following versions of %s are available:'\ 265 % self.portName 266 for version in versions: 267 print ' ' + version[0] 268 sys.exit('Run haikuporter again, specifiying a port version' 269 ) 270 elif len(versions) == 1: 271 self.portVersion = versions[0][0] 272 else: 273 sys.exit('Error: .bep files for ' + self.portName 274 + ' not found.') 335 275 336 def checkFlag(self, name): 337 if os.path.exists('%s/%s-%s.%s' %(self.workDir, self.portName, self.portVersion, name)): 338 return True 339 else: 340 return False 276 # show port description, if requested 341 277 278 if options.about: 279 self.printDescription() 280 sys.exit() 342 281 343 def updatePortsTree(self): 344 """Get/Update the port tree via svn""" 345 print "Refreshing the port tree: " + self.packagesPath 346 if os.path.exists(self.packagesPath + "/.svn"): 347 check_call(['svn', 'update', self.packagesPath]) 348 else: 349 check_call(['svn', 'checkout', 'http://ports.haiku-files.org/svn/haikuports/trunk', self.packagesPath]) 282 # read data from the bep file 350 283 284 self.parseBepFile() 351 285 352 def validateBepFile(self, bepFilePath, exitOnError=True): 353 """Validate the keys/values in a bep file""" 354 bepConfig = Config(bepFilePath) 355 self.bepKeys = bepConfig.getKeys() 286 # warn when the port is not stable on this platform 356 287 357 # check whether all required fields are present 358 for key in bepDefaults: 359 if key not in self.bepKeys and bepDefaults[key][0]: 360 print "Error: Required field '" + key + "' not present in " + bepFilePath 361 if exitOnError: 362 sys.exit(1) 288 self.platform = self.detectOS() 289 if self.platform == None: 290 sys.exit('Error: Unknown OS platform!') 291 else: 292 if self.bepKeys['STATUS_' + self.platform] != 'stable': 293 print 'Warning: This port is ' + self.bepKeys['STATUS_' 294 + self.platform] + ' on this platform.' 295 if not self.options.yes: 296 answer = raw_input('Continue (y/n + enter)? ') 297 if answer == '': 298 sys.exit(1) 299 if answer[0].lower() == 'y': 300 print ' ok' 301 else: 302 sys.exit(1) 363 303 364 # check validity of BepFile values 365 for key in self.bepKeys: 366 try: 367 if type(self.bepKeys[key]) not in bepTypes[key]: 368 print "Error: Invalid value type for " + key + ". Expecting " + str(bepTypes[key]) 369 if exitOnError: 370 sys.exit(1) 371 except KeyError, e: 372 print "Warning: Unknown key label '" + key 304 if self.bepKeys['MESSAGE']: 305 print self.bepKeys['MESSAGE'] 306 if not self.options.yes: 307 answer = raw_input('Continue (y/n + enter)? ') 308 if answer == '': 309 sys.exit(1) 310 if answer[0].lower() == 'y': 311 print ' ok' 312 else: 313 sys.exit(1) 373 314 374 # Check for a valid license file 375 if 'LICENSE' in self.bepKeys: 376 fileList = [] 377 bepLicense = [] 378 if type(self.bepKeys['LICENSE']) == type(str()): 379 bepLicense.append(self.bepKeys['LICENSE']) 380 else: 381 bepLicense = self.bepKeys['LICENSE'] 382 for item in bepLicense: 383 dirname = FindDirectory('B_SYSTEM_DIRECTORY', 'data/licenses') 384 for filename in os.listdir(dirname): 385 fileList.append(filename) 386 haikuLicenseList = fileList 387 if item not in fileList: 388 fileList = [] 389 dirname = os.path.dirname(bepFilePath) + "/licenses" 390 print "Try looking in " + dirname 391 if os.path.exists(dirname): 392 for filename in os.listdir(dirname): 393 fileList.append(filename) 394 if item not in fileList: 395 print "\n######## Error: No match found for License " + item + " ########\n" 396 print "Valid license filenames included with Haiku are: " 397 print haikuLicenseList 398 print "\n" 399 if exitOnError: 400 sys.exit(1) 401 else: 402 print "Matching License (" + item + ") found in " + dirname 403 404 # TODO Disable warnings if an OPD file is found 405 if not 'LICENSE' in self.bepKeys or not self.bepKeys['LICENSE']: 406 print "Warning: No LICENSE found in bep file" 315 # clean the work dir and don't build when making a source archive 407 316 408 if not 'COPYRIGHT' in self.bepKeys or not self.bepKeys['COPYRIGHT']: 409 print "Warning: No COPYRIGHT found in bep file" 317 if options.archive: 318 options.build = False 319 options.clean = True 320 options.patch = True 410 321 322 # clean the work directory, if requested 411 323 412 def parseBepFile(self): 413 """Parse the BepFile of the specified port""" 414 bepFilename = self.portDir + '/' + self.portName + "-" + self.portVersion + ".bep" 415 if not os.path.exists(bepFilename): 416 sys.exit("Error: " + self.portName + " version " + self.portVersion + " not found.") 417 418 self.validateBepFile(bepFilename) 324 if options.clean: 325 self.cleanWorkDirectory() 419 326 420 # set default values when not provided 421 for key in bepDefaults: 422 if key not in self.bepKeys: 423 self.bepKeys[key] = bepDefaults[key][1] 327 # don't build when not patching 424 328 425 # convert each None/string value into a list (with respectively 0 or 1 element) 426 # (simplifies implementation ahead) 427 for key in bepTypes: 428 if types.ListType in bepTypes[key]: 429 if self.bepKeys[key] == None: 430 self.bepKeys[key] = [] 431 elif type(self.bepKeys[key]) == types.StringType: 432 self.bepKeys[key] = [self.bepKeys[key]] 329 if not options.patch: 330 options.build = False 433 331 434 #for key in self.bepKeys: 435 # print key + " = " + str(self.bepKeys[key]) 332 self.checkDependencies() # check dependencies 333 self.downloadSource() # fetch sources 334 self.checksumSource() # calculate checksum 335 self.unpackSource() # unpack source archive 336 if options.patch: 337 self.patchSource() # apply patches 338 if options.build: 339 self.buildPort() # build 340 if options.install: 341 self.installPort() # install 342 if options.distro: 343 self.makePackage() # distro 344 if options.archive: 345 self.makePatchedArchive() # create patched source archive 346 if options.test: 347 self.testPort() # run tests 436 348 349 def printDescription(self): 350 """Show port description""" 437 351 438 def detectOS(self): 439 """Detect the platform we're running on""" 440 name = getCommandOutput('uname -s') 441 if name == "Haiku": 442 return name.upper() 443 # Support for R5, R5bone, dano, and Zeta has been dropped. 444 else: 445 return None 352 bepFilename = self.portDir + '/' + self.portName + '-'\ 353 + self.portVersion + '.bep' 446 354 355 reOptionValue = \ 356 re.compile('^(?P<key>[A-Z0-9_]*)\s*=\s*"(?P<value>.*)(?<!\\\\)"\s*$' 357 ) 358 reComment = re.compile('^\s*#.*$') 359 reEmptyLine = re.compile('^\s*$') 447 360 448 def searchPorts(self, regExp): 449 """Search for a port in the HaikuPorts tree""" 450 if regExp: 451 reSearch = re.compile(regExp) 452 hierarchy = [] 453 os.chdir(self.packagesPath) 454 dirList = os.listdir(self.packagesPath) 455 for category in dirList: 456 if os.path.isdir(category) and (category[0] != '.'): 457 subdirList = os.listdir(category) 458 # remove items starting with '.' 459 subdirList.sort() 460 for portName in subdirList: 461 if portName[0][0] != '.' and (not regExp or reSearch.search(portName)): 462 print category + "/" + portName 361 if not os.path.exists(bepFilename): 362 sys.exit('Error: ' + self.portName + ' version ' 363 + self.portVersion + ' not found.') 463 364 365 fp = open(bepFilename) 366 lineCount = 0 464 367 465 def getCategory(self, portName): 466 """Find location of the specified port in the HaikuPorts tree""" 467 hierarchy = [] 468 os.chdir(self.packagesPath) 469 dirList = os.listdir(self.packagesPath) 470 for item in dirList: 471 if os.path.isdir(item) and (item[0] != '.'): 472 subdirList = os.listdir(item) 473 # remove items starting with '.' 474 subdirList.sort() 475 while subdirList[0][0] == '.': 476 del subdirList[0] 477 # locate port 478 try: 479 if subdirList.index(portName) >= 0: 480 # port was found in the category specified by 'item' 481 return item 482 except ValueError: 483 pass 484 hierarchy.append([item, subdirList]) 485 return None 368 line = fp.readline() 369 lineCount += 1 486 370 371 print '*' * 80 487 372 488 def cleanWorkDirectory(self): 489 """Clean the working directory""" 490 if os.path.exists(self.workDir): 491 print "Cleaning work directory..." 492 shutil.rmtree(self.workDir) 373 while line != '': 493 374 375 # empty line or comment 494 376 495 def checkDependencies(self): 496 """Print the list of ports this one depends on""" 497 if self.bepKeys['DEPEND'] == []: 498 print "No dependencies" 499 return 500 print "This port depends on the following ports:" 501 for item in self.bepKeys['DEPEND']: 502 print " " + item 503 print "Please verify that you have these installed.", 504 if not self.options.yes: 505 answer = raw_input("Continue (y/n + enter)? ") 506 if answer == '': 507 sys.exit(1) 508 if answer[0].lower() == 'y': 509 print " ok" 510 else: 511 sys.exit(1) 377 if reEmptyLine.match(line) or reComment.match(line): 378 pass 379 elif reOptionValue.match(line): 512 380 381 # value option (single line) (check BEFORE list option) 513 382 514 def downloadSource(self): 515 """Fetch the source archive""" 383 m = reOptionValue.match(line) 384 key = m.group('key') 385 value = m.group('value') 516 386 517 for src_uri in self.bepKeys['SRC_URI']: 518 # Examine the uri to determine if we need to perform a checkout instead of download 519 if re.match('^cvs.*$|^svn.*$|^hg.*$|^git.*$|^bzr.*$', src_uri): 520 self.checkoutSource(src_uri) 521 return 387 if 'DESCRIPTION' in key: 388 print key.capitalize() + ':', value 389 elif 'HOMEPAGE' in key: 390 print key.capitalize() + ':', value 522 391 523 try: 524 # Need to make a request to get the actual uri in case it is an http redirect 525 uri_request = urllib2.urlopen(src_uri) 526 src_uri = uri_request.geturl() 392 line = fp.readline() 393 lineCount += 1 527 394 528 self.src_local = src_uri[src_uri.rindex('/') + 1:] 529 fp = self.downloadDir + '/' + self.src_local 530 if os.path.isfile(fp): 531 print 'File already exists: ' + fp + '\nSkipping download ...' 532 return 533 else: 534 # create download dir and cd into it 535 if not os.path.exists(self.downloadDir): 536 os.mkdir(self.downloadDir) 395 print '*' * 80 537 396 538 os.chdir(self.downloadDir)397 fp.close() 539 398 540 print "\nDownloading: " + src_uri 541 check_call(['wget', '-c', '--tries=3', src_uri]) 542 # succesfully downloaded source archive 543 return 544 except: 545 print "Warning: download error, trying next location." 399 def setFlag(self, name): 400 open('%s/%s-%s.%s' % (self.workDir, self.portName, 401 self.portVersion, name), 'w').close() 546 402 547 # failed to fetch source 548 sys.exit("Error: Failed to download source package from all locations.") 403 def checkFlag(self, name): 404 if os.path.exists('%s/%s-%s.%s' % (self.workDir, self.portName, 405 self.portVersion, name)): 406 return True 407 else: 408 return False 549 409 410 def updatePortsTree(self): 411 """Get/Update the port tree via svn""" 550 412 551 def checkoutSource(self, uri): 552 """Parse the uri and execute the appropriate command to check the source out""" 413 print 'Refreshing the port tree: ' + self.packagesPath 414 if os.path.exists(self.packagesPath + '/.svn'): 415 check_call(['svn', 'update', self.packagesPath]) 416 else: 417 check_call(['svn', 'checkout', 418 'http://ports.haiku-files.org/svn/haikuports/trunk' \ 419 , self.packagesPath]) 553 420 554 if self.checkFlag('checkout') and not self.options.force: 555 print "Source already checked out. Skipping ..." 556 return 421 def validateBepFile(self, bepFilePath, exitOnError=True): 422 """Validate the keys/values in a bep file""" 557 423 558 # If the work dir exists we need to clean it out 559 if os.path.exists(self.workDir): 560 shutil.rmtree(self.workDir) 424 bepConfig = Config(bepFilePath) 425 self.bepKeys = bepConfig.getKeys() 561 426 562 print "Source checkout: " + uri 427 # check whether all required fields are present 563 428 564 # Attempt to parse a uri with a + in it. ex: hg+http://blah 565 # Even if it doesn't find the 'type' it should extract 'real_uri' and 'rev' 566 m = re.match('^((?P<type>\w*)\+)?(?P<real_uri>.+?)(#(?P<rev>.+))?$', uri) 567 if not m or not m.group("real_uri"): 568 sys.exit("Error: Couldn't parse repository URI") 429 for key in bepDefaults: 430 if key not in self.bepKeys and bepDefaults[key][0]: 431 print "Error: Required field '" + key\ 432 + "' not present in " + bepFilePath 433 if exitOnError: 434 sys.exit(1) 569 435 570 type = m.group("type") 571 real_uri = m.group("real_uri") 572 rev = m.group("rev") 436 # check validity of BepFile values 573 437 574 # Attempt to parse a uri without a + in it. ex: svn://blah 575 # TODO improve the regex above to fallback to this pattern 576 if not type: 577 m = re.match("^(\w*).*$", real_uri) 578 if m: 579 type = m.group(1) 438 for key in self.bepKeys: 439 try: 440 if type(self.bepKeys[key]) not in bepTypes[key]: 441 print 'Error: Invalid value type for ' + key\ 442 + '. Expecting ' + str(bepTypes[key]) 443 if exitOnError: 444 sys.exit(1) 445 except KeyError, e: 446 print "Warning: Unknown key label '" + key 580 447 581 if not type: 582 sys.exit("Error: Couldn't determine repository type") 448 # Check for a valid license file 583 449 584 # Set the name of the directory to check out sources into 585 checkoutDir = self.portName + "-" + self.portVersion 450 if 'LICENSE' in self.bepKeys: 451 fileList = [] 452 bepLicense = [] 453 if type(self.bepKeys['LICENSE']) == type(str()): 454 bepLicense.append(self.bepKeys['LICENSE']) 455 else: 456 bepLicense = self.bepKeys['LICENSE'] 457 for item in bepLicense: 458 dirname = FindDirectory('B_SYSTEM_DIRECTORY', 459 'data/licenses') 460 for filename in os.listdir(dirname): 461 fileList.append(filename) 462 haikuLicenseList = fileList 463 if item not in fileList: 464 fileList = [] 465 dirname = os.path.dirname(bepFilePath) + '/licenses' 466 print 'Try looking in ' + dirname 467 if os.path.exists(dirname): 468 for filename in os.listdir(dirname): 469 fileList.append(filename) 470 if item not in fileList: 471 print '\n######## Error: No match found for License '\ 472 + item + ' ########\n' 473 print 'Valid license filenames included with Haiku are: ' 474 print haikuLicenseList 475 print '\n' 476 if exitOnError: 477 sys.exit(1) 478 else: 479 print 'Matching License (' + item + ') found in '\ 480 + dirname 586 481 587 # Start building the command to perform the checkout 588 if type == 'cvs': 589 # Chop off the leading cvs:// part of the uri 590 real_uri = real_uri[real_uri.index("cvs://") + 6:] 591 # Extract the cvs module from the uri and remove it from real_uri 592 module = real_uri[real_uri.rfind('/') + 1:] 593 real_uri = real_uri[:real_uri.rfind('/')] 594 checkoutCommand = "cvs -d" + real_uri + " co -P" 595 if rev: 596 # For CVS 'rev' specifies a date 597 checkoutCommand += " -D" + rev 598 checkoutCommand += " -d " + checkoutDir + " " + module 482 # TODO Disable warnings if an OPD file is found 599 483 600 elif type == 'svn': 601 checkoutCommand = "svn co --non-interactive --trust-server-cert" 602 if rev: 603 checkoutCommand += " -r " + rev 604 checkoutCommand += " " + real_uri + " " + checkoutDir 484 if not 'LICENSE' in self.bepKeys or not self.bepKeys['LICENSE']: 485 print 'Warning: No LICENSE found in bep file' 605 486 606 elif type == 'hg': 607 checkoutCommand = "hg clone" 608 if rev: 609 checkoutCommand += " -r " + rev 610 checkoutCommand += " " + real_uri + " " + checkoutDir 487 if not 'COPYRIGHT' in self.bepKeys\ 488 or not self.bepKeys['COPYRIGHT']: 489 print 'Warning: No COPYRIGHT found in bep file' 611 490 612 elif type == 'bzr': 613 #http://doc.bazaar.canonical.com/bzr-0.10/bzr_man.htm#bzr-branch-from-location-to-location 614 checkoutCommand = "bzr checkout --lightweight" 615 if rev: 616 checkoutCommand += " -r " + rev 617 checkoutCommand += " " + real_uri + " " + checkoutDir 491 def parseBepFile(self): 492 """Parse the BepFile of the specified port""" 618 493 619 else: 620 #TODO Skip the initial checkout if a rev is specified? 621 checkoutCommand = "git clone " + real_uri + " " + checkoutDir 622 if rev: 623 checkoutCommand += " && cd " + checkoutDir + " && git checkout " + rev 494 bepFilename = self.portDir + '/' + self.portName + '-'\ 495 + self.portVersion + '.bep' 496 if not os.path.exists(bepFilename): 497 sys.exit('Error: ' + self.portName + ' version ' 498 + self.portVersion + ' not found.') 624 499 625 # create the work dir 626 if not os.path.exists(self.workDir): 627 os.mkdir(self.workDir) 500 self.validateBepFile(bepFilename) 628 501 629 try: 630 check_call(checkoutCommand, shell=True, cwd=self.workDir) 631 except (OSError, CalledProcessError), e: 632 if self.prompt_installer(checkoutCommand.split()[0]): 633 check_call(checkoutCommand, shell=True, cwd=self.workDir) 634 else: 635 sys.exit() 636 637 # Set the 'checkout' flag to signal that the checkout is complete 638 # This also tells haikuporter not to attempt an unpack step 639 self.setFlag('checkout') 502 # set default values when not provided 640 503 504 for key in bepDefaults: 505 if key not in self.bepKeys: 506 self.bepKeys[key] = bepDefaults[key][1] 641 507 642 def checksumSource(self): 643 if self.bepKeys['CHECKSUM_MD5']: 644 sys.stdout.write('Calculating checksum -') 645 sys.stdout.flush() 646 h = hashlib.md5() 647 f = open(self.downloadDir + "/" + self.src_local, 'rb') 648 while True: 649 d = f.read(16384) 650 if not d: 651 break 652 h.update(d) 653 f.close() 654 if h.hexdigest() == self.bepKeys['CHECKSUM_MD5']: 655 sys.stdout.write(' OK\n') 656 else: 657 sys.stdout.write(' FAILED\n') 658 sys.exit(1) 659 sys.stdout.flush() 660 else: 661 # The checkout flag only gets set when a source checkout is performed 662 # If it exists we don't need to warn about the missing bep field 663 if not self.checkFlag('checkout'): 664 print "Warning: CHECKSUM_MD5 key not found in bep file." 508 # convert each None/string value into a list 509 # (with respectively 0 or 1 element) 510 # ....(simplifies implementation ahead) 665 511 512 for key in bepTypes: 513 if types.ListType in bepTypes[key]: 514 if self.bepKeys[key] == None: 515 self.bepKeys[key] = [] 516 elif type(self.bepKeys[key]) == types.StringType: 517 self.bepKeys[key] = [self.bepKeys[key]] 666 518 667 def unpackSource(self):668 """Unpack the source archive (into the work directory)""" 519 # for key in self.bepKeys: 520 # ....print key + " = " + str(self.bepKeys[key]) 669 521 670 # If the source came from a vcs there is no unpack step 671 if self.checkFlag('checkout'): 672 return 522 def detectOS(self): 523 """Detect the platform we're running on""" 673 524 674 # create work dir 675 if not os.path.exists(self.workDir): 676 os.mkdir(self.workDir) 525 name = getCommandOutput('uname -s') 526 if name == 'Haiku': 527 return name.upper() 528 else: 677 529 678 # Check to see if the source archive was already unpacked. 679 if self.checkFlag('unpack') and not self.options.force: 680 return 530 # Support for R5, R5bone, dano, and Zeta has been dropped. 681 531 682 # unpack source archive 683 print "Unpacking " + self.src_local 684 archiveFullPath = self.downloadDir + "/" + self.src_local 685 if tarfile.is_tarfile(archiveFullPath): 686 tf = tarfile.open(self.downloadDir + "/" + self.src_local, 'r') 687 tf.extractall(self.workDir) 688 tf.close() 689 elif zipfile.is_zipfile(archiveFullPath): 690 zf = zipfile.ZipFile(self.downloadDir + "/" + self.src_local, 'r') 691 zf.extractall(self.workDir) 692 zf.close() 693 elif archiveFullPath.split("/")[-1].split(".")[-1] == "xz": 694 try: 695 Popen(['xz', '-d', '-k', archiveFullPath]) 696 except (OSError, CalledProcessError), e: 697 #run the installoptionalsoftware prompt 698 if self.prompt_installer('xz'): 699 Popen(['xz', '-d', '-k', archiveFullPath]) 700 else: 701 sys.exit() 702 tar = archiveFullPath[:-3] 703 if tarfile.is_tarfile(tar): 704 tf = tarfile.open(tar, 'r') 705 tf.extractall(self.workDir) 706 tf.close() 707 else: 708 sys.exit("Error: Unrecognized archive type.") 532 return None 709 533 710 self.setFlag('unpack') 534 def searchPorts(self, regExp): 535 """Search for a port in the HaikuPorts tree""" 711 536 537 if regExp: 538 reSearch = re.compile(regExp) 539 hierarchy = [] 540 os.chdir(self.packagesPath) 541 dirList = os.listdir(self.packagesPath) 542 for category in dirList: 543 if os.path.isdir(category) and category[0] != '.': 544 subdirList = os.listdir(category) 712 545 713 def patchSource(self): 714 """Apply the Haiku patches to the source directory""" 546 # remove items starting with '.' 715 547 716 # Check to see if the patch was already applied to the source. 717 if self.checkFlag('patch') and not self.options.force: 718 return 548 subdirList.sort() 549 for portName in subdirList: 550 if portName[0][0] != '.' and (not regExp 551 or reSearch.search(portName)): 552 print category + '/' + portName 719 553 720 patchFilePath = self.patchesDir + '/' + self.portName + '-' + self.portVersion + '.patch' 721 if os.path.exists(patchFilePath): 722 patchOptions = "" 723 if 'PATCH_OPTIONS' in self.confKeys: 724 patchOptions += self.confKeys['PATCH_OPTIONS'] 725 check_call('patch -p0 ' + patchOptions + ' -i ' + patchFilePath, shell=True, cwd=self.workDir) 726 else: 727 print "No patching required" 728 self.setFlag('patch') 554 def getCategory(self, portName): 555 """Find location of the specified port in the HaikuPorts tree""" 729 556 557 hierarchy = [] 558 os.chdir(self.packagesPath) 559 dirList = os.listdir(self.packagesPath) 560 for item in dirList: 561 if os.path.isdir(item) and item[0] != '.': 562 subdirList = os.listdir(item) 730 563 731 def buildPort(self): 732 """Build the sources""" 564 # remove items starting with '.' 733 565 734 # Make sure the bep file for the package has a BUILD section. 735 if (not 'BUILD' in self.bepKeys) or (not self.bepKeys['BUILD']):736 sys.exit('Error: Invalid bep file with no BUILD section.') 566 subdirList.sort() 567 while subdirList[0][0] == '.': 568 del subdirList[0] 737 569 738 # Check to see if a previous build was already done. 739 if self.checkFlag('build') and not self.options.force: 740 return 570 # locate port 741 571 742 self.runCommandSequence(self.bepKeys['BUILD'], self.workDir) 572 try: 573 if subdirList.index(portName) >= 0: 743 574 744 self.setFlag('build') 575 # port was found in the category specified by 'item' 745 576 577 return item 578 except ValueError: 579 pass 580 hierarchy.append([item, subdirList]) 581 return None 746 582 747 def installPort(self):748 """Install the binaries onto the system"""583 def cleanWorkDirectory(self): 584 """Clean the working directory""" 749 585 750 # Make sure the bep file for the package has an INSTALL section. 751 if (not 'INSTALL' in self.bepKeys) or (not self.bepKeys['INSTALL']): 752 sys.exit('Error: bep file has no INSTALL section.')586 if os.path.exists(self.workDir): 587 print 'Cleaning work directory...' 588 shutil.rmtree(self.workDir) 753 589 754 # Check if port is python or perl as installing them with haikuporter may break haikuporter 755 if ((self.portName == "python") or (self.portName == "perl")): 756 sys.exit('Error: cannot install ' + self.portName + ' using haikuporter. Build to a package instead.') 757 print "Installing ..." 590 def checkDependencies(self): 591 """Print the list of ports this one depends on""" 758 592 759 self.runCommandSequence(self.bepKeys['INSTALL'], self.workDir) 593 if self.bepKeys['DEPEND'] == []: 594 print 'No dependencies' 595 return 596 print 'This port depends on the following ports:' 597 for item in self.bepKeys['DEPEND']: 598 print ' ' + item 599 print 'Please verify that you have these installed.', 600 if not self.options.yes: 601 answer = raw_input('Continue (y/n + enter)? ') 602 if answer == '': 603 sys.exit(1) 604 if answer[0].lower() == 'y': 605 print ' ok' 606 else: 607 sys.exit(1) 760 608 609 def downloadSource(self): 610 """Fetch the source archive""" 761 611 762 def testPort(self): 763 """Test the resulting binaries""" 612 for src_uri in self.bepKeys['SRC_URI']: 764 613 765 # Make sure the bep file for the package has a TEST section. 766 if (not 'TEST' in self.bepKeys) or (not self.bepKeys['TEST']): 767 sys.exit('Error: bep file has no TEST section.') 614 # Examine the uri to determine if we need to perform a checkout instead of download 768 615 769 print "Testing ..." 616 if re.match('^cvs.*$|^svn.*$|^hg.*$|^git.*$|^bzr.*$', 617 src_uri): 618 self.checkoutSource(src_uri) 619 return 770 620 771 self.runCommandSequence(self.bepKeys['TEST'], self.workDir) 621 try: 772 622 623 # Need to make a request to get the actual uri in case it is an http redirect 773 624 774 def generatePackageDescription(self, opdFile): 775 """Create an OptionalPackageDescription file for inclusion in a package""" 625 uri_request = urllib2.urlopen(src_uri) 626 src_uri = uri_request.geturl() 776 627 777 print "Generating OptionalPackageDescription file ..." 628 self.src_local = src_uri[src_uri.rindex('/') + 1:] 629 fp = self.downloadDir + '/' + self.src_local 630 if os.path.isfile(fp): 631 print 'File already exists: ' + fp\ 632 + '\nSkipping download ...' 633 return 634 else: 778 635 779 opd = open(opdFile, 'w') 636 # create download dir and cd into it 780 637 781 opd.write('Package:\t' + self.portName + '\n'); 782 opd.write('Version:\t' + self.portVersion + '\n') 783 opd.write('URL:\t\t' + self.bepKeys['HOMEPAGE'] + '\n') 638 if not os.path.exists(self.downloadDir): 639 os.mkdir(self.downloadDir) 784 640 785 # These keys aren't mandatory so we need to check if they exist 786 if self.bepKeys['LICENSE']: 787 for license in self.bepKeys['LICENSE']: 788 opd.write('License:\t' + license + '\n') 641 os.chdir(self.downloadDir) 789 642 790 if self.bepKeys['COPYRIGHT']: 791 for copyright in self.bepKeys['COPYRIGHT']: 792 opd.write('Copyright:\t' + copyright + '\n') 643 print '\nDownloading: ' + src_uri 644 check_call(['wget', '-c', '--tries=3', src_uri]) 793 645 794 opd.close() 646 # succesfully downloaded source archive 795 647 648 return 649 except: 650 print 'Warning: download error, trying next location.' 796 651 797 def makePackage(self): 798 """Create a package suitable for distribution""" 652 # failed to fetch source 799 653 800 print "Creating distribution package ..." 654 sys.exit('Error: Failed to download source package from all locations.' 655 ) 801 656 802 # Make sure the bep file for the package has an INSTALL section. 803 if (not 'INSTALL' in self.bepKeys) or (not self.bepKeys['INSTALL']): 804 sys.exit('Error: bep file has no INSTALL section.') 657 def checkoutSource(self, uri): 658 """Parse the uri and execute the appropriate command to check the source out""" 805 659 806 # if the distro dir still exists from a previous run then remove it 807 shutil.rmtree(self.distroDir, True) 660 if self.checkFlag('checkout') and not self.options.force: 661 print 'Source already checked out. Skipping ...' 662 return 808 663 809 # create distro dir 810 if not os.path.exists(self.distroDir): 811 os.mkdir(self.distroDir) 664 # If the work dir exists we need to clean it out 812 665 813 self.runCommandSequence(self.bepKeys['INSTALL'], self.workDir, True) 666 if os.path.exists(self.workDir): 667 shutil.rmtree(self.workDir) 814 668 815 if not os.path.exists(self.distroDir + '/boot'): 816 sys.exit('Error: No installed files detected in packaging directory. Check bep file for correctness') 669 print 'Source checkout: ' + uri 817 670 818 opdFound = False 819 for f in os.listdir(self.portDir): 820 if 'licenses' in f: 821 shutil.copytree(self.portDir + '/' + f, self.distroDir + '/boot/common/data/licenses') 671 # Attempt to parse a uri with a + in it. ex: hg+http://blah 672 # Even if it doesn't find the 'type' it should extract 'real_uri' and 'rev' 822 673 823 if 'OptionalPackageDescription' in f: 824 opdFound = True 825 print "Copying OptionalPackageDescription to distro directory ..." 826 shutil.copyfile(self.portDir + '/' + f, self.distroDir + '/boot/.OptionalPackageDescription') 674 m = \ 675 re.match('^((?P<type>\w*)\+)?(?P<real_uri>.+?)(#(?P<rev>.+))?$' 676 , uri) 677 if not m or not m.group('real_uri'): 678 sys.exit("Error: Couldn't parse repository URI") 827 679 828 if not opdFound: 829 self.generatePackageDescription(self.distroDir + '/boot/.OptionalPackageDescription') 680 type = m.group('type') 681 real_uri = m.group('real_uri') 682 rev = m.group('rev') 830 683 831 # go to distro dir for making zip package 832 os.chdir(self.distroDir) 684 # Attempt to parse a uri without a + in it. ex: svn://blah 685 # TODO improve the regex above to fallback to this pattern 833 686 834 package = self.portName + '-' + self.portVersion 835 836 # set haikuversion to HAIKUVERSION, if it is empty then don't add a dash. 837 haikuversion = '' 838 if os.environ.has_key('HAIKUVERSION'): 839 haikuversion = '-' + os.environ['HAIKUVERSION'] 687 if not type: 688 m = re.match("^(\w*).*$", real_uri) 689 if m: 690 type = m.group(1) 840 691 841 gcc = getCommandOutput('setgcc') 842 gcc = gcc.split(': ')[1].split('/') 843 arch = '-' + gcc[0] 844 gcc = '-' + gcc[1] 692 if not type: 693 sys.exit("Error: Couldn't determine repository type") 845 694 846 date = time.strftime("-%Y-%m-%d", time.localtime()) 695 # Set the name of the directory to check out sources into 847 696 848 zipFile = self.portDir + '/' + package + haikuversion + arch + gcc + date + '.zip' 697 checkoutDir = self.portName + '-' + self.portVersion 849 698 850 zipRootDir = self.distroDir + '/boot' 699 # Start building the command to perform the checkout 851 700 852 packageFiles = '' 701 if type == 'cvs': 853 702 854 # Add the files/dirs in self.distroDir/boot to the list of items to zip 855 for f in os.listdir(zipRootDir): 856 packageFiles += f + ' ' 703 # Chop off the leading cvs:// part of the uri 857 704 858 # Zip the package and save it in the root of the port dir 859 check_call('zip -9ry ' + zipFile + ' ' + packageFiles + ' -x *.svn*', shell=True, cwd=zipRootDir) 705 real_uri = real_uri[real_uri.index('cvs://') + 6:] 860 706 861 # Clean up after ourselves 862 shutil.rmtree(self.distroDir) 707 # Extract the cvs module from the uri and remove it from real_uri 863 708 864 print 'Package saved to: ' + zipFile 709 module = real_uri[real_uri.rfind('/') + 1:] 710 real_uri = real_uri[:real_uri.rfind('/')] 711 checkoutCommand = 'cvs -d' + real_uri + ' co -P' 712 if rev: 865 713 714 # For CVS 'rev' specifies a date 866 715 867 def makePatchedArchive(self): 868 """Create a patched source archive""" 716 checkoutCommand += ' -D' + rev 717 checkoutCommand += ' -d ' + checkoutDir + ' ' + module 718 elif type == 'svn': 869 719 870 print "Creating patched source archive ..." 720 checkoutCommand = \ 721 'svn co --non-interactive --trust-server-cert' 722 if rev: 723 checkoutCommand += ' -r ' + rev 724 checkoutCommand += ' ' + real_uri + ' ' + checkoutDir 725 elif type == 'hg': 871 726 872 # Set the path and filename for the archive. 873 date = time.strftime("-%Y-%m-%d", time.localtime()) 874 archiveFile = self.portDir + '/' + self.portName + '-' + self.portVersion + '_haiku' + date + '.tar.xz' 727 checkoutCommand = 'hg clone' 728 if rev: 729 checkoutCommand += ' -r ' + rev 730 checkoutCommand += ' ' + real_uri + ' ' + checkoutDir 731 elif type == 'bzr': 875 732 876 sourceFiles = "" 733 # http://doc.bazaar.canonical.com/bzr-0.10/bzr_man.htm#bzr-branch-from-location-to-location 877 734 878 # Build the list of dirs to archive. 879 # Since we don't know the name we have to iterate over the dir. 880 for f in os.listdir(self.workDir): 881 if os.path.isdir(self.workDir + '/' + f): 882 sourceFiles += ' ' + f 735 checkoutCommand = 'bzr checkout --lightweight' 736 if rev: 737 checkoutCommand += ' -r ' + rev 738 checkoutCommand += ' ' + real_uri + ' ' + checkoutDir 739 else: 883 740 884 # Make sure we found something to archive 885 if not sourceFiles: 886 sys.exit("Error: No source directories found in work dir.") 741 # TODO Skip the initial checkout if a rev is specified? 887 742 888 # Archive the package and save it in the root of the port dir. 889 check_call('tar cJvf ' + archiveFile + ' ' + sourceFiles, shell=True, cwd=self.workDir) 743 checkoutCommand = 'git clone ' + real_uri + ' '\ 744 + checkoutDir 745 if rev: 746 checkoutCommand += ' && cd ' + checkoutDir\ 747 + ' && git checkout ' + rev 890 748 891 # Clean up after ourselves 892 shutil.rmtree(self.workDir) 749 # create the work dir 893 750 894 print 'Archive saved to: ' + archiveFile 751 if not os.path.exists(self.workDir): 752 os.mkdir(self.workDir) 895 753 896 def prompt_installer(self, name): 897 apps = {'xz': 'XZ-Utils', 'git': 'Git', 'hg': 'mercurial', 898 'cvs': 'cvs', 'bzr' : 'bazaar'} #map command to package 899 if self.options.yes: 900 check_call('installoptionalpackage' + " " + str(apps[name]), shell=True) 901 return True 902 response = raw_input("Do you want to install %s? [Y/n]" % name) 903 if response in ["y", "Y", "\n", "yes", '']: 904 check_call('installoptionalpackage' + " " + str(apps[name]), shell=True) 905 return True 906 else: 907 print "In order to install this package you need to run:" 908 print "installoptionalpackage %s" % apps[name] 909 print "later or let Haikuporter install it for you." 910 return False 754 try: 755 check_call(checkoutCommand, shell=True, cwd=self.workDir) 756 except (OSError, CalledProcessError), e: 757 if self.prompt_installer(checkoutCommand.split()[0]): 758 check_call(checkoutCommand, shell=True, 759 cwd=self.workDir) 760 else: 761 sys.exit() 911 762 912 def runCommandSequence(self, rawCommandList, dir, packageMode=False): 913 """Run a sequence of shell commands from a bep file""" 763 # Set the 'checkout' flag to signal that the checkout is complete 764 # This also tells haikuporter not to attempt an unpack step 914 765 915 # Convert rawCommandList to a string with a newline after each entry 916 # Use 'set -e' as the first command so that the shell aborts immediately 917 commandString = 'set -e\n' 918 for command in rawCommandList: 919 commandString += command + '\n' 766 self.setFlag('checkout') 920 767 921 shellEnv = None 768 def checksumSource(self): 769 if self.bepKeys['CHECKSUM_MD5']: 770 sys.stdout.write('Calculating checksum -') 771 sys.stdout.flush() 772 h = hashlib.md5() 773 f = open(self.downloadDir + '/' + self.src_local, 'rb') 774 while True: 775 d = f.read(16384) 776 if not d: 777 break 778 h.update(d) 779 f.close() 780 if h.hexdigest() == self.bepKeys['CHECKSUM_MD5']: 781 sys.stdout.write(' OK\n') 782 else: 783 sys.stdout.write(' FAILED\n') 784 sys.exit(1) 785 sys.stdout.flush() 786 else: 922 787 923 if packageMode: 924 shellEnv = os.environ 925 shellEnv['DESTDIR'] = self.distroDir 788 # The checkout flag only gets set when a source checkout is performed 789 # If it exists we don't need to warn about the missing bep field 926 790 927 check_call(commandString, shell=True, cwd=dir, env=shellEnv) 791 if not self.checkFlag('checkout'): 792 print 'Warning: CHECKSUM_MD5 key not found in bep file.' 928 793 794 def unpackSource(self): 795 """Unpack the source archive (into the work directory)""" 929 796 930 def checkSourceTree(self): 931 print "Checking HaikuPorts tree at: " + self.packagesPath 797 # If the source came from a vcs there is no unpack step 932 798 933 for category in os.listdir(self.packagesPath):934 categoryFullPath = self.packagesPath + '/' + category 799 if self.checkFlag('checkout'): 800 return 935 801 936 if os.path.isdir(categoryFullPath) and (category[0] != '.'): 937 print "Category: " + category 802 # create work dir 938 803 939 for port in os.listdir(categoryFullPath):940 portFullPath = categoryFullPath + '/' + port 804 if not os.path.exists(self.workDir): 805 os.mkdir(self.workDir) 941 806 942 if os.path.isdir(portFullPath) and (port[0] != '.'): 943 print "\tPort: " + port 807 # Check to see if the source archive was already unpacked. 944 808 945 for bep in os.listdir(portFullPath):946 bepFullPath = portFullPath + '/' + bep 809 if self.checkFlag('unpack') and not self.options.force: 810 return 947 811 948 if os.path.isfile(bepFullPath) and bep[-4:] == ".bep": 949 reWithVersion = re.compile(regExp['bepfilename']) 950 #reWithVersion = re.compile('^(?P<name>[a-z0-9\-_]*)-(?P<version>([\d]+[a-z\\.])*[\d]*)?$') 951 m = reWithVersion.match(bep) 952 if m and m.group("name") and m.group("version"): # with version 953 print "\t\tName/Version: " + m.group("name") + "\t" + m.group("version") 954 self.validateBepFile(bepFullPath, False) 955 else: # invalid argument 956 print("Error: Couldn't parse port/version info: " + bep) 812 # unpack source archive 957 813 814 print 'Unpacking ' + self.src_local 815 archiveFullPath = self.downloadDir + '/' + self.src_local 816 if tarfile.is_tarfile(archiveFullPath): 817 tf = tarfile.open(self.downloadDir + '/' + self.src_local, 818 'r') 819 tf.extractall(self.workDir) 820 tf.close() 821 elif zipfile.is_zipfile(archiveFullPath): 822 zf = zipfile.ZipFile(self.downloadDir + '/' 823 + self.src_local, 'r') 824 zf.extractall(self.workDir) 825 zf.close() 826 elif archiveFullPath.split('/')[-1].split('.')[-1] == 'xz': 827 try: 828 Popen(['xz', '-d', '-k', archiveFullPath]) 829 except (OSError, CalledProcessError), e: 830 831 # run the installoptionalsoftware prompt 832 833 if self.prompt_installer('xz'): 834 Popen(['xz', '-d', '-k', archiveFullPath]) 835 else: 836 sys.exit() 837 tar = archiveFullPath[:-3] 838 if tarfile.is_tarfile(tar): 839 tf = tarfile.open(tar, 'r') 840 tf.extractall(self.workDir) 841 tf.close() 842 else: 843 sys.exit('Error: Unrecognized archive type.') 844 845 self.setFlag('unpack') 846 847 def patchSource(self): 848 """Apply the Haiku patches to the source directory""" 849 850 # Check to see if the patch was already applied to the source. 851 852 if self.checkFlag('patch') and not self.options.force: 853 return 854 855 patchFilePath = self.patchesDir + '/' + self.portName + '-'\ 856 + self.portVersion + '.patch' 857 if os.path.exists(patchFilePath): 858 patchOptions = '' 859 if 'PATCH_OPTIONS' in self.confKeys: 860 patchOptions += self.confKeys['PATCH_OPTIONS'] 861 check_call('patch -p0 ' + patchOptions + ' -i ' 862 + patchFilePath, shell=True, cwd=self.workDir) 863 else: 864 print 'No patching required' 865 self.setFlag('patch') 866 867 def buildPort(self): 868 """Build the sources""" 869 870 # Make sure the bep file for the package has a BUILD section. 871 872 if not 'BUILD' in self.bepKeys or not self.bepKeys['BUILD']: 873 sys.exit('Error: Invalid bep file with no BUILD section.') 874 875 # Check to see if a previous build was already done. 876 877 if self.checkFlag('build') and not self.options.force: 878 return 879 880 self.runCommandSequence(self.bepKeys['BUILD'], self.workDir) 881 882 self.setFlag('build') 883 884 def installPort(self): 885 """Install the binaries onto the system""" 886 887 # Make sure the bep file for the package has an INSTALL section. 888 889 if not 'INSTALL' in self.bepKeys or not self.bepKeys['INSTALL']: 890 sys.exit('Error: bep file has no INSTALL section.') 891 892 # Check if port is python or perl as installing them with haikuporter may break haikuporter 893 894 if self.portName == 'python' or self.portName == 'perl': 895 sys.exit('Error: cannot install ' + self.portName 896 + ' using haikuporter. Build to a package instead.' 897 ) 898 print 'Installing ...' 899 900 self.runCommandSequence(self.bepKeys['INSTALL'], self.workDir) 901 902 def testPort(self): 903 """Test the resulting binaries""" 904 905 # Make sure the bep file for the package has a TEST section. 906 907 if not 'TEST' in self.bepKeys or not self.bepKeys['TEST']: 908 sys.exit('Error: bep file has no TEST section.') 909 910 print 'Testing ...' 911 912 self.runCommandSequence(self.bepKeys['TEST'], self.workDir) 913 914 def generatePackageDescription(self, opdFile): 915 """Create an OptionalPackageDescription file for inclusion in a package""" 916 917 print 'Generating OptionalPackageDescription file ...' 918 919 opd = open(opdFile, 'w') 920 921 opd.write('Package:\t' + self.portName + '\n') 922 opd.write('Version:\t' + self.portVersion + '\n') 923 opd.write('URL:\t\t' + self.bepKeys['HOMEPAGE'] + '\n') 924 925 # These keys aren't mandatory so we need to check if they exist 926 927 if self.bepKeys['LICENSE']: 928 for license in self.bepKeys['LICENSE']: 929 opd.write('License:\t' + license + '\n') 930 931 if self.bepKeys['COPYRIGHT']: 932 for copyright in self.bepKeys['COPYRIGHT']: 933 opd.write('Copyright:\t' + copyright + '\n') 934 935 opd.close() 936 937 def makePackage(self): 938 """Create a package suitable for distribution""" 939 940 print 'Creating distribution package ...' 941 942 # Make sure the bep file for the package has an INSTALL section. 943 944 if not 'INSTALL' in self.bepKeys or not self.bepKeys['INSTALL']: 945 sys.exit('Error: bep file has no INSTALL section.') 946 947 # if the distro dir still exists from a previous run then remove it 948 949 shutil.rmtree(self.distroDir, True) 950 951 # create distro dir 952 953 if not os.path.exists(self.distroDir): 954 os.mkdir(self.distroDir) 955 956 self.runCommandSequence(self.bepKeys['INSTALL'], self.workDir, 957 True) 958 959 if not os.path.exists(self.distroDir + '/boot'): 960 sys.exit('Error: No installed files detected in packaging directory. Check bep file for correctness' 961 ) 962 963 opdFound = False 964 for f in os.listdir(self.portDir): 965 if 'licenses' in f: 966 shutil.copytree(self.portDir + '/' + f, self.distroDir 967 + '/boot/common/data/licenses') 968 969 if 'OptionalPackageDescription' in f: 970 opdFound = True 971 print 'Copying OptionalPackageDescription to distro directory ...' 972 shutil.copyfile(self.portDir + '/' + f, self.distroDir 973 + '/boot/.OptionalPackageDescription') 974 975 if not opdFound: 976 self.generatePackageDescription(self.distroDir 977 + '/boot/.OptionalPackageDescription') 978 979 # go to distro dir for making zip package 980 981 os.chdir(self.distroDir) 982 983 package = self.portName + '-' + self.portVersion 984 985 # set haikuversion to HAIKUVERSION, if it is empty then don't add a dash. 986 987 haikuversion = '' 988 if 'HAIKUVERSION' in os.environ: 989 haikuversion = '-' + os.environ['HAIKUVERSION'] 990 991 gcc = getCommandOutput('setgcc') 992 gcc = gcc.split(': ')[1].split('/') 993 arch = '-' + gcc[0] 994 gcc = '-' + gcc[1] 995 996 date = time.strftime('-%Y-%m-%d', time.localtime()) 997 998 zipFile = self.portDir + '/' + package + haikuversion + arch\ 999 + gcc + date + '.zip' 1000 1001 zipRootDir = self.distroDir + '/boot' 1002 1003 packageFiles = '' 1004 1005 # Add the files/dirs in self.distroDir/boot to the list of items to zip 1006 1007 for f in os.listdir(zipRootDir): 1008 packageFiles += f + ' ' 1009 1010 # Zip the package and save it in the root of the port dir 1011 1012 check_call('zip -9ry ' + zipFile + ' ' + packageFiles 1013 + ' -x *.svn*', shell=True, cwd=zipRootDir) 1014 1015 # Clean up after ourselves 1016 1017 shutil.rmtree(self.distroDir) 1018 1019 print 'Package saved to: ' + zipFile 1020 1021 def makePatchedArchive(self): 1022 """Create a patched source archive""" 1023 1024 print 'Creating patched source archive ...' 1025 1026 # Set the path and filename for the archive. 1027 1028 date = time.strftime('-%Y-%m-%d', time.localtime()) 1029 archiveFile = self.portDir + '/' + self.portName + '-'\ 1030 + self.portVersion + '_haiku' + date + '.tar.xz' 1031 1032 sourceFiles = '' 1033 1034 # Build the list of dirs to archive. 1035 # Since we don't know the name we have to iterate over the dir. 1036 1037 for f in os.listdir(self.workDir): 1038 if os.path.isdir(self.workDir + '/' + f): 1039 sourceFiles += ' ' + f 1040 1041 # Make sure we found something to archive 1042 1043 if not sourceFiles: 1044 sys.exit('Error: No source directories found in work dir.') 1045 1046 # Archive the package and save it in the root of the port dir. 1047 1048 check_call('tar cJvf ' + archiveFile + ' ' + sourceFiles, 1049 shell=True, cwd=self.workDir) 1050 1051 # Clean up after ourselves 1052 1053 shutil.rmtree(self.workDir) 1054 1055 print 'Archive saved to: ' + archiveFile 1056 1057 def prompt_installer(self, name): 1058 apps = { # map command to package 1059 'xz': 'XZ-Utils', 1060 'git': 'Git', 1061 'hg': 'mercurial', 1062 'cvs': 'cvs', 1063 'bzr': 'bazaar', 1064 } 1065 if self.options.yes: 1066 check_call('installoptionalpackage' + ' ' 1067 + str(apps[name]), shell=True) 1068 return True 1069 response = raw_input('Do you want to install %s? [Y/n]' % name) 1070 if response in ['y', 'Y', '\n', 'yes', '']: 1071 check_call('installoptionalpackage' + ' ' 1072 + str(apps[name]), shell=True) 1073 return True 1074 else: 1075 print 'In order to install this package you need to run installoptionalpackage %s later or let Haikuporter install it for you.'\ 1076 % apps[name] 1077 return False 1078 1079 def runCommandSequence( 1080 self, 1081 rawCommandList, 1082 dir, 1083 packageMode=False, 1084 ): 1085 """Run a sequence of shell commands from a bep file""" 1086 1087 # Convert rawCommandList to a string with a newline after each entry 1088 # Use 'set -e' as the first command so that the shell aborts immediately 1089 1090 commandString = 'set -e\n' 1091 for command in rawCommandList: 1092 commandString += command + '\n' 1093 1094 shellEnv = None 1095 1096 if packageMode: 1097 shellEnv = os.environ 1098 shellEnv['DESTDIR'] = self.distroDir 1099 1100 check_call(commandString, shell=True, cwd=dir, env=shellEnv) 1101 1102 def checkSourceTree(self): 1103 print 'Checking HaikuPorts tree at: ' + self.packagesPath 1104 1105 for category in os.listdir(self.packagesPath): 1106 categoryFullPath = self.packagesPath + '/' + category 1107 1108 if os.path.isdir(categoryFullPath) and category[0] != '.': 1109 print 'Category: ' + category 1110 1111 for port in os.listdir(categoryFullPath): 1112 portFullPath = categoryFullPath + '/' + port 1113 1114 if os.path.isdir(portFullPath) and port[0] != '.': 1115 print '\tPort: ' + port 1116 1117 for bep in os.listdir(portFullPath): 1118 bepFullPath = portFullPath + '/' + bep 1119 1120 if os.path.isfile(bepFullPath) and bep[-4:]\ 1121 == '.bep': 1122 reWithVersion = \ 1123 re.compile(regExp['bepfilename']) 1124 1125 # reWithVersion = re.compile('^(?P<name>[a-z0-9\-_]*)-(?P<version>([\d]+[a-z\\.])*[\d]*)?$') 1126 1127 m = reWithVersion.match(bep) 1128 if m and m.group('name')\ 1129 and m.group('version'): # with version 1130 print '\t\tName/Version: '\ 1131 + m.group('name') + '\t' + m.group('version') 1132 self.validateBepFile(bepFullPath, 1133 False) 1134 else: 1135 1136 # invalid argument 1137 1138 print "Error: Couldn't parse port/version info: "\ 1139 + bep 1140 1141 958 1142 # -- /etc/haikuports.conf and *.bep parser ----------------------------------- 959 1143 1144 960 1145 class Config: 961 def __init__(self, filename):962 # regular expressions for parsing the config file963 reOptionValue = re.compile('^(?P<key>[A-Z0-9_]*)\s*=\s*"(?P<value>.*)(?<!\\\\)"\s*$')964 reOptionList = re.compile('^(?P<key>[A-Z0-9_]*)\s*=\s*"(?P<item>.*)\s*$')965 reLastListItem = re.compile('^\s+(?P<item>.*)(?<!\\\\)"\s*$')966 reListItem = re.compile('^\s+(?P<item>.*)\s*$')967 1146 968 reShellStart = re.compile('^(?P<key>[A-Z_]*)\s*\{\s*$') 969 reShellEnd = re.compile('^\}\s*$') 1147 def __init__(self, filename): 970 1148 971 reComment = re.compile('^\s*#.*$') 972 reEmptyLine = re.compile('^\s*$') 1149 # regular expressions for parsing the config file 973 1150 974 reNoneType = re.compile('^\s*$') 975 reIntType = re.compile('^[0-9]+$') 976 reBooleanType = re.compile('^yes$|^no$') 977 reStatusType = re.compile('^broken$|^untested$|^unstable$|^stable$') 1151 reOptionValue = \ 1152 re.compile('^(?P<key>[A-Z0-9_]*)\s*=\s*"(?P<value>.*)(?<!\\\\)"\s*$' 1153 ) 1154 reOptionList = \ 1155 re.compile('^(?P<key>[A-Z0-9_]*)\s*=\s*"(?P<item>.*)\s*$') 1156 reLastListItem = re.compile('^\s+(?P<item>.*)(?<!\\\\)"\s*$') 1157 reListItem = re.compile('^\s+(?P<item>.*)\s*$') 978 1158 979 self.options = {} 1159 reShellStart = re.compile('^(?P<key>[A-Z_]*)\s*\{\s*$') 1160 reShellEnd = re.compile('^\}\s*$') 980 1161 981 self.filename = filename 1162 reComment = re.compile('^\s*#.*$') 1163 reEmptyLine = re.compile('^\s*$') 982 1164 983 try: 984 self.file = open(self.filename, 'rb') 985 except: 986 sys.exit("Error: Can't find config file: " + self.filename) 1165 reNoneType = re.compile('^\s*$') 1166 reIntType = re.compile('^[0-9]+$') 1167 reBooleanType = re.compile('^yes$|^no$') 1168 reStatusType = \ 1169 re.compile('^broken$|^untested$|^unstable$|^stable$') 987 1170 988 self.lineCount = 0 989 self.nextLine() 990 # TODO: store all options in a list? 991 while self.line != "": 992 # empty line or comment 993 if reEmptyLine.match(self.line) or reComment.match(self.line): 994 pass 995 # value option (single line) (check BEFORE list option) 996 elif reOptionValue.match(self.line): 997 #print "[OV] " + self.line.strip('\n') 998 m = reOptionValue.match(self.line) 999 key = m.group("key") 1000 value = m.group("value") 1001 if reNoneType.match(value): # NoneType 1002 self.options[key] = None 1003 elif reIntType.match(value): # IntType 1004 self.options[key] = int(value) 1005 elif reBooleanType.match(value): # BooleanType 1006 if value == "yes": 1007 self.options[key] = True 1008 else: 1009 self.options[key] = False 1010 elif reStatusType.match(value): # StatusType 1011 self.options[key] = status(value) 1012 else: # StringType 1013 self.options[key] = value 1014 # list option (multiline) 1015 elif reOptionList.match(self.line): 1016 #print "[OL] " + self.line.strip('\n') 1017 m = reOptionList.match(self.line) 1018 key = m.group("key") 1019 self.options[key] = [m.group("item")] 1020 self.nextLine() 1021 while self.line != "": 1022 # empty line or comment 1023 if reEmptyLine.match(self.line) or reComment.match(self.line): 1024 pass 1025 # last list item (check BEFORE list item) 1026 elif reLastListItem.match(self.line): 1027 #print "[LL] " + self.line.strip('\n') 1028 m = reLastListItem.match(self.line) 1029 self.options[key].append(m.group("item")) 1030 break 1031 # list item 1032 elif reListItem.match(self.line): 1033 #print "[LI] " + self.line.strip('\n') 1034 m = reListItem.match(self.line) 1035 self.options[key].append(m.group("item")) 1036 # unrecognized syntax 1037 else: 1038 self.illegalSyntax() 1039 self.nextLine() 1040 # shell commands (multiline) 1041 elif reShellStart.match(self.line): 1042 #print "[SS] " + self.line.strip('\n') 1043 m = reShellStart.match(self.line) 1044 key = m.group("key") 1045 self.options[key] = shell() 1046 self.nextLine() 1047 while self.line != "": 1048 # empty line or comment 1049 if reEmptyLine.match(self.line) or reComment.match(self.line): 1050 pass 1051 # last list item (check BEFORE list item) 1052 elif reShellEnd.match(self.line): 1053 #print "[SE] " + self.line.strip('\n') 1054 break 1055 # list item 1056 elif reListItem.match(self.line): 1057 #print "[SI] " + self.line.strip('\n') 1058 m = reListItem.match(self.line) 1059 self.options[key].append(m.group("item")) 1060 # unrecognized syntax 1061 else: 1062 self.illegalSyntax() 1063 self.nextLine() 1064 # unrecognized syntax 1065 else: 1066 self.illegalSyntax() 1067 self.nextLine() 1068 self.file.close() 1069 #for key in self.options: 1070 # print key + " = " + str(self.options[key]) 1171 self.options = {} 1071 1172 1072 def nextLine(self): 1073 self.line = self.file.readline() 1074 self.lineCount = self.lineCount + 1 1173 self.filename = filename 1075 1174 1076 def illegalSyntax(self):1077 print "Error: Illegal syntax in " + self.filename + " at line " + str(self.lineCount) + ":" 1078 print " " + self.line 1079 sys.exit(1)1175 try: 1176 self.file = open(self.filename, 'rb') 1177 except: 1178 sys.exit("Error: Can't find config file: " + self.filename) 1080 1179 1081 def getKeys(self): 1082 return self.options 1180 self.lineCount = 0 1181 self.nextLine() 1083 1182 1084 def valueOf(self, key): 1085 try: 1086 value = self.options[key] 1087 return value 1088 except KeyError: # an unspecified option is the same as an empty one 1089 return "" 1183 # TODO: store all options in a list? 1090 1184 1185 while self.line != '': 1186 1187 # empty line or comment 1188 1189 if reEmptyLine.match(self.line)\ 1190 or reComment.match(self.line): 1191 pass 1192 elif reOptionValue.match(self.line): 1193 1194 # value option (single line) (check BEFORE list option) 1195 # print "[OV] " + self.line.strip('\n') 1196 1197 m = reOptionValue.match(self.line) 1198 key = m.group('key') 1199 value = m.group('value') 1200 if reNoneType.match(value): # NoneType 1201 self.options[key] = None 1202 elif reIntType.match(value): 1203 1204 # IntType 1205 1206 self.options[key] = int(value) 1207 elif reBooleanType.match(value): 1208 1209 # BooleanType 1210 1211 if value == 'yes': 1212 self.options[key] = True 1213 else: 1214 self.options[key] = False 1215 elif reStatusType.match(value): 1216 1217 # StatusType 1218 1219 self.options[key] = status(value) 1220 else: 1221 1222 # StringType 1223 1224 self.options[key] = value 1225 elif reOptionList.match(self.line): 1226 1227 # list option (multiline) 1228 # print "[OL] " + self.line.strip('\n') 1229 1230 m = reOptionList.match(self.line) 1231 key = m.group('key') 1232 self.options[key] = [m.group('item')] 1233 self.nextLine() 1234 while self.line != '': 1235 1236 # empty line or comment 1237 1238 if reEmptyLine.match(self.line)\ 1239 or reComment.match(self.line): 1240 pass 1241 elif reLastListItem.match(self.line): 1242 1243 # last list item (check BEFORE list item) 1244 # print "[LL] " + self.line.strip('\n') 1245 1246 m = reLastListItem.match(self.line) 1247 self.options[key].append(m.group('item')) 1248 break 1249 elif reListItem.match(self.line): 1250 1251 # list item 1252 # print "[LI] " + self.line.strip('\n') 1253 1254 m = reListItem.match(self.line) 1255 self.options[key].append(m.group('item')) 1256 else: 1257 1258 # unrecognized syntax 1259 1260 self.illegalSyntax() 1261 self.nextLine() 1262 elif reShellStart.match(self.line): 1263 1264 # shell commands (multiline) 1265 # print "[SS] " + self.line.strip('\n') 1266 1267 m = reShellStart.match(self.line) 1268 key = m.group('key') 1269 self.options[key] = shell() 1270 self.nextLine() 1271 while self.line != '': 1272 1273 # empty line or comment 1274 1275 if reEmptyLine.match(self.line)\ 1276 or reComment.match(self.line): 1277 pass 1278 elif reShellEnd.match(self.line): 1279 1280 # last list item (check BEFORE list item) 1281 # print "[SE] " + self.line.strip('\n') 1282 1283 break 1284 elif reListItem.match(self.line): 1285 1286 # list item 1287 # print "[SI] " + self.line.strip('\n') 1288 1289 m = reListItem.match(self.line) 1290 self.options[key].append(m.group('item')) 1291 else: 1292 1293 # unrecognized syntax 1294 1295 self.illegalSyntax() 1296 self.nextLine() 1297 else: 1298 1299 # unrecognized syntax 1300 1301 self.illegalSyntax() 1302 self.nextLine() 1303 self.file.close() 1304 1305 # for key in self.options: 1306 # ....print key + " = " + str(self.options[key]) 1307 1308 def nextLine(self): 1309 self.line = self.file.readline() 1310 self.lineCount = self.lineCount + 1 1311 1312 def illegalSyntax(self): 1313 print 'Error: Illegal syntax in ' + self.filename + ' at line '\ 1314 + str(self.lineCount) + ':' 1315 print ' ' + self.line 1316 sys.exit(1) 1317 1318 def getKeys(self): 1319 return self.options 1320 1321 def valueOf(self, key): 1322 try: 1323 value = self.options[key] 1324 return value 1325 except KeyError: 1326 1327 # an unspecified option is the same as an empty one 1328 1329 return '' 1330 1331 1091 1332 # -- Command line argument parsing ------------------------------------------- 1092 1333 1093 parser = OptionParser(usage="usage: %prog [options] portname[-portversion]", 1094 version="%prog " + info['version']) 1334 parser = \ 1335 OptionParser(usage='usage: %prog [options] portname[-portversion]', 1336 version='%prog ' + info['version']) 1095 1337 1096 parser.add_option("-l", "--list", 1097 action="store_true", dest="list", default=False, 1098 help="list available ports") 1338 parser.add_option( 1339 '-l', 1340 '--list', 1341 action='store_true', 1342 dest='list', 1343 default=False, 1344 help='list available ports', 1345 ) 1099 1346 1100 parser.add_option("-a", "--about", 1101 action="store_true", dest="about", default=False, 1102 help="show description of the specified port") 1347 parser.add_option( 1348 '-a', 1349 '--about', 1350 action='store_true', 1351 dest='about', 1352 default=False, 1353 help='show description of the specified port', 1354 ) 1103 1355 1104 parser.add_option("-s", "--search", 1105 action="store_true", dest="search", default=False, 1106 help="search for a port (regex)") 1356 parser.add_option( 1357 '-s', 1358 '--search', 1359 action='store_true', 1360 dest='search', 1361 default=False, 1362 help='search for a port (regex)', 1363 ) 1107 1364 1108 parser.add_option("-p", "--nopatch", 1109 action="store_false", dest="patch", default=True, 1110 help="don't patch the sources, just download and unpack") 1365 parser.add_option( 1366 '-p', 1367 '--nopatch', 1368 action='store_false', 1369 dest='patch', 1370 default=True, 1371 help="don't patch the sources, just download and unpack", 1372 ) 1111 1373 1112 parser.add_option("-b", "--nobuild", 1113 action="store_false", dest="build", default=True, 1114 help="don't build the port, just download, unpack and patch") 1374 parser.add_option( 1375 '-b', 1376 '--nobuild', 1377 action='store_false', 1378 dest='build', 1379 default=True, 1380 help="don't build the port, just download, unpack and patch", 1381 ) 1115 1382 1116 parser.add_option("-i", "--install", 1117 action="store_true", dest="install", default=False, 1118 help="also install the port (the default is to only build)") 1119 1120 parser.add_option("-d", "--distro", 1121 action="store_true", dest="distro", default=False, 1122 help="make distribution package of the specified port (include download, unpack, patch, build)") 1383 parser.add_option( 1384 '-i', 1385 '--install', 1386 action='store_true', 1387 dest='install', 1388 default=False, 1389 help='also install the port (the default is to only build)', 1390 ) 1123 1391 1124 parser.add_option("-c", "--clean", 1125 action="store_true", dest="clean", default=False, 1126 help="clean the working directory of the specified port") 1392 parser.add_option( 1393 '-d', 1394 '--distro', 1395 action='store_true', 1396 dest='distro', 1397 default=False, 1398 help='make distribution package of the specified port (include download, unpack, patch, build)' 1399 , 1400 ) 1127 1401 1128 parser.add_option("-g", "--get", 1129 action="store_true", dest="get", default=False, 1130 help="get/update the ports tree") 1402 parser.add_option( 1403 '-c', 1404 '--clean', 1405 action='store_true', 1406 dest='clean', 1407 default=False, 1408 help='clean the working directory of the specified port', 1409 ) 1131 1410 1132 parser.add_option("-f", "--force", 1133 action="store_true", dest="force", default=False, 1134 help="force to perform the steps (unpack, patch, build)") 1411 parser.add_option( 1412 '-g', 1413 '--get', 1414 action='store_true', 1415 dest='get', 1416 default=False, 1417 help='get/update the ports tree', 1418 ) 1135 1419 1136 parser.add_option("-z", "--archive", 1137 action="store_true", dest="archive", default=False, 1138 help="Create a patched source archive as <package>_haiku.tar.xz") 1420 parser.add_option( 1421 '-f', 1422 '--force', 1423 action='store_true', 1424 dest='force', 1425 default=False, 1426 help='force to perform the steps (unpack, patch, build)', 1427 ) 1139 1428 1140 parser.add_option("-t", "--tree", 1141 action="store_true", dest="tree", default=False, 1142 help="Print out the location of the haikuports source tree") 1429 parser.add_option( 1430 '-z', 1431 '--archive', 1432 action='store_true', 1433 dest='archive', 1434 default=False, 1435 help='Create a patched source archive as <package>_haiku.tar.xz', 1436 ) 1143 1437 1144 parser.add_option("-y", "--yes", 1145 action="store_true", dest="yes", default=False, 1146 help="Answer yes to all questions") 1147 1148 parser.add_option("--test", 1149 action="store_true", dest="test", default=False, 1150 help="Run tests on resulting binaries") 1151 1152 parser.add_option("--lint", 1153 action="store_true", dest="lint", default=False, 1154 help="Scan the ports tree for problems") 1438 parser.add_option( 1439 '-t', 1440 '--tree', 1441 action='store_true', 1442 dest='tree', 1443 default=False, 1444 help='Print out the location of the haikuports source tree', 1445 ) 1155 1446 1447 parser.add_option( 1448 '-y', 1449 '--yes', 1450 action='store_true', 1451 dest='yes', 1452 default=False, 1453 help='Answer yes to all questions', 1454 ) 1455 1456 parser.add_option('--test', action='store_true', dest='test', 1457 default=False, help='Run tests on resulting binaries') 1458 1459 parser.add_option('--lint', action='store_true', dest='lint', 1460 default=False, help='Scan the ports tree for problems' 1461 ) 1462 1156 1463 (options, args) = parser.parse_args() 1157 1464 1158 1465 haikuporter = HaikuPorter(options, args) 1159
