Package buildbot :: Package scripts :: Module base
[frames] | no frames]

Source Code for Module buildbot.scripts.base

  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16  from __future__ import with_statement 
 17   
 18  import os 
 19  import copy 
 20  import stat 
 21  from twisted.python import usage, runtime 
 22   
23 -def isBuildmasterDir(dir):
24 def print_error(error_message): 25 print "%s\ninvalid buildmaster directory '%s'" % (error_message, dir)
26 27 buildbot_tac = os.path.join(dir, "buildbot.tac") 28 try: 29 contents = open(buildbot_tac).read() 30 except IOError, exception: 31 print_error("error reading '%s': %s" % \ 32 (buildbot_tac, exception.strerror)) 33 return False 34 35 if "Application('buildmaster')" not in contents: 36 print_error("unexpected content in '%s'" % buildbot_tac) 37 return False 38 39 return True 40
41 -def getConfigFileWithFallback(basedir, defaultName='master.cfg'):
42 configFile = os.path.abspath(os.path.join(basedir, defaultName)) 43 if os.path.exists(configFile): 44 return configFile 45 # execute the .tac file to see if its configfile location exists 46 tacFile = os.path.join(basedir, 'buildbot.tac') 47 if os.path.exists(tacFile): 48 # don't mess with the global namespace 49 tacGlobals = {} 50 execfile(tacFile, tacGlobals) 51 return tacGlobals["configfile"] 52 # No config file found; return default location and fail elsewhere 53 return configFile
54
55 -class SubcommandOptions(usage.Options):
56 # subclasses should set this to a list-of-lists in order to source the 57 # .buildbot/options file. Note that this *only* works with optParameters, 58 # not optFlags. Example: 59 # buildbotOptions = [ [ 'optfile-name', 'parameter-name' ], .. ] 60 buildbotOptions = None 61 62 # set this to options that must have non-None values 63 requiredOptions = [] 64
65 - def __init__(self, *args):
66 # for options in self.buildbotOptions, optParameters, and the options 67 # file, change the default in optParameters to the value in the options 68 # file, call through to the constructor, and then change it back. 69 # Options uses reflect.accumulateClassList, so this *must* be a class 70 # attribute; however, we do not want to permanently change the class. 71 # So we patch it temporarily and restore it after. 72 cls = self.__class__ 73 if hasattr(cls, 'optParameters'): 74 old_optParameters = cls.optParameters 75 cls.optParameters = op = copy.deepcopy(cls.optParameters) 76 if self.buildbotOptions: 77 optfile = self.optionsFile = self.loadOptionsFile() 78 for optfile_name, option_name in self.buildbotOptions: 79 for i in range(len(op)): 80 if (op[i][0] == option_name 81 and optfile_name in optfile): 82 op[i] = list(op[i]) 83 op[i][2] = optfile[optfile_name] 84 usage.Options.__init__(self, *args) 85 if hasattr(cls, 'optParameters'): 86 cls.optParameters = old_optParameters
87
88 - def loadOptionsFile(self, _here=None):
89 """Find the .buildbot/options file. Crawl from the current directory 90 up towards the root, and also look in ~/.buildbot . The first directory 91 that's owned by the user and has the file we're looking for wins. 92 Windows skips the owned-by-user test. 93 94 @rtype: dict 95 @return: a dictionary of names defined in the options file. If no 96 options file was found, return an empty dict. 97 """ 98 99 here = _here or os.path.abspath(os.getcwd()) 100 101 if runtime.platformType == 'win32': 102 # never trust env-vars, use the proper API 103 from win32com.shell import shellcon, shell 104 appdata = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0) 105 home = os.path.join(appdata, "buildbot") 106 else: 107 home = os.path.expanduser("~/.buildbot") 108 109 searchpath = [] 110 toomany = 20 111 while True: 112 searchpath.append(os.path.join(here, ".buildbot")) 113 next = os.path.dirname(here) 114 if next == here: 115 break # we've hit the root 116 here = next 117 toomany -= 1 # just in case 118 if toomany == 0: 119 print ("I seem to have wandered up into the infinite glories " 120 "of the heavens. Oops.") 121 break 122 123 searchpath.append(home) 124 125 localDict = {} 126 127 for d in searchpath: 128 if os.path.isdir(d): 129 if runtime.platformType != 'win32': 130 if os.stat(d)[stat.ST_UID] != os.getuid(): 131 print "skipping %s because you don't own it" % d 132 continue # security, skip other people's directories 133 optfile = os.path.join(d, "options") 134 if os.path.exists(optfile): 135 try: 136 with open(optfile, "r") as f: 137 options = f.read() 138 exec options in localDict 139 except: 140 print "error while reading %s" % optfile 141 raise 142 break 143 144 for k in localDict.keys(): 145 if k.startswith("__"): 146 del localDict[k] 147 return localDict
148
149 - def postOptions(self):
150 missing = [ k for k in self.requiredOptions if self[k] is None ] 151 if missing: 152 if len(missing) > 1: 153 msg = 'Required arguments missing: ' + ', '.join(missing) 154 else: 155 msg = 'Required argument missing: ' + missing[0] 156 raise usage.UsageError(msg)
157
158 -class BasedirMixin(object):
159 160 """SubcommandOptions Mixin to handle subcommands that take a basedir 161 argument""" 162
163 - def parseArgs(self, *args):
164 if len(args) > 0: 165 self['basedir'] = args[0] 166 else: 167 # Use the current directory if no basedir was specified. 168 self['basedir'] = os.getcwd() 169 if len(args) > 1: 170 raise usage.UsageError("I wasn't expecting so many arguments")
171
172 - def postOptions(self):
173 # get an unambiguous, epxnaed basedir, including expanding '~', which 174 # may be useful in a .buildbot/config file 175 self['basedir'] = os.path.abspath(os.path.expanduser(self['basedir']))
176