diff --git a/drover.py b/drover.py index 9db4e91c8..6d2fb7d70 100755 --- a/drover.py +++ b/drover.py @@ -29,7 +29,7 @@ Example: %(app)s --merge 12345 --branch 187 Example: %(app)s --merge 12345 --local [Merge from branch to branch] ---merge --sbranch --branch +--merge --sbranch --branch Example: %(app)s --merge 12345 --sbranch 248 --branch 249 [Revert from trunk] @@ -62,15 +62,15 @@ def deltree(root): os.unlink(path) os.rmdir(root) -def clobberDir(dir): +def clobberDir(dirname): """Removes a given directory""" - if (os.path.exists(dir)): + if (os.path.exists(dirname)): print dir + " directory found, deleting" # The following line was removed due to access controls in Windows # which make os.unlink(path) calls impossible. #TODO(laforge) : Is this correct? - deltree(dir) + deltree(dirname) def runGcl(subcommand): gcl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gcl") @@ -96,7 +96,7 @@ def getSVNInfo(url, revision): for line in svn_info: match = re.search(r"(.*?):(.*)", line) if match: - info[match.group(1).strip()]=match.group(2).strip() + info[match.group(1).strip()]=match.group(2).strip() return info @@ -137,7 +137,7 @@ def inCheckoutRoot(path): info = getSVNInfo(path, "HEAD") if (not info.has_key("Repository Root")): return False - repo_root = info["Repository Root"]; + repo_root = info["Repository Root"] info = getSVNInfo(os.path.dirname(os.path.abspath(path)), "HEAD") if (info.get("Repository Root", None) != repo_root): return True @@ -146,9 +146,9 @@ def inCheckoutRoot(path): def getRevisionLog(url, revision): """Takes an svn url and gets the associated revision.""" command = 'svn log ' + url + " -r"+str(revision) - svn_log = subprocess.Popen(command, - shell=True, - stdout=subprocess.PIPE, + svn_log = subprocess.Popen(command, + shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines() # Don't include the header lines and the trailing "---..." line and eliminate # any '\r's. @@ -165,12 +165,12 @@ def getSVNVersionInfo(): for line in svn_info: match = re.search(r"svn, version ((\d+)\.(\d+)\.(\d+)) \(r(\d+)\)", line) if match: - info['version']=match.group(1) - info['major']=int(match.group(2)) - info['minor']=int(match.group(3)) - info['patch']=int(match.group(4)) - info['revision']=match.group(5) - return info + info['version'] = match.group(1) + info['major'] = int(match.group(2)) + info['minor'] = int(match.group(3)) + info['patch'] = int(match.group(4)) + info['revision'] = match.group(5) + return info return None @@ -217,32 +217,32 @@ def checkoutRevision(url, revision, branch_url, revert=False): # directories get clobbered and the merge step fails. paths.sort() - # Checkout the directories that already exist + # Checkout the directories that already exist for path in paths: - if (export_map.has_key(path) and not revert): - print "Exclude new directory " + path - continue - subpaths = path.split('/') - subpaths.pop(0) - base = '' - for subpath in subpaths: - base += '/' + subpath - # This logic ensures that you don't empty out any directories - if not os.path.exists("." + base): - command = ('svn update --depth empty ' + "." + base) - print command - os.system(command) + if (export_map.has_key(path) and not revert): + print "Exclude new directory " + path + continue + subpaths = path.split('/') + subpaths.pop(0) + base = '' + for subpath in subpaths: + base += '/' + subpath + # This logic ensures that you don't empty out any directories + if not os.path.exists("." + base): + command = ('svn update --depth empty ' + "." + base) + print command + os.system(command) if (revert): files = getAllFilesInRevision(files_info) else: files = getExistingFilesInRevision(files_info) - - for file in files: - # Prevent the tool from clobbering the src directory - if (file == ""): + + for f in files: + # Prevent the tool from clobbering the src directory + if (f == ""): continue - command = ('svn up ".' + file + '"') + command = ('svn up ".' + f + '"') print command os.system(command) @@ -272,7 +272,7 @@ def exportRevision(url, revision): os.system(command) command = 'svn add .' + path - print command + print command os.system(command) def deleteRevision(url, revision): @@ -298,7 +298,7 @@ def revertExportRevision(url, revision): def revertRevision(url, revision): paths = getBestMergePaths(url, revision) for path in paths: - command = ('svn merge -N -r ' + str(revision) + ":" + str(revision-1) + + command = ('svn merge -N -r ' + str(revision) + ":" + str(revision-1) + " " + url + path + " ." + path) print command os.system(command) @@ -336,12 +336,7 @@ def getBestMergePaths(url, revision): def getBestMergePaths2(files_info, revision): """Takes an svn url and gets the associated revision.""" - - map = dict() - for file_info in files_info: - map[file_info[2]] = file_info[2] - - return map.keys() + return list(set([f[2] for f in files_info])) def getBestExportPathsMap(url, revision): return getBestExportPathsMap2(getFileInfo(url, revision), revision) @@ -353,15 +348,15 @@ def getBestExportPathsMap2(files_info, revision): if export_map_: return export_map_ - map = dict() + result = {} for file_info in files_info: if (file_info[0] == "A"): if(isSVNDirectory("svn://svn.chromium.org/chrome/" + file_info[1], revision)): - map[file_info[2] + "/" + file_info[3]] = "" + result[file_info[2] + "/" + file_info[3]] = "" - export_map_ = map - return map + export_map_ = result + return result def getBestDeletePathsMap(url, revision): return getBestDeletePathsMap2(getFileInfo(url, revision), revision) @@ -373,28 +368,25 @@ def getBestDeletePathsMap2(files_info, revision): if delete_map_: return delete_map_ - map = dict() + result = {} for file_info in files_info: if (file_info[0] == "D"): if(isSVNDirectory("svn://svn.chromium.org/chrome/" + file_info[1], revision)): - map[file_info[2] + "/" + file_info[3]] = "" + result[file_info[2] + "/" + file_info[3]] = "" + + delete_map_ = result + return result - delete_map_ = map - return map def getExistingFilesInRevision(files_info): """Checks for existing files in the revision. - + Anything that's A will require special treatment (either a merge or an export + add) """ - map = [] - for file_info in files_info: - if file_info[0] != "A": - map.append(file_info[2] + "/" + file_info[3]) + return ['%s/%s' % (f[2], f[3]) for f in files_info if f[0] != 'A'] - return map def getAllFilesInRevision(files_info): """Checks for existing files in the revision. @@ -402,23 +394,17 @@ def getAllFilesInRevision(files_info): Anything that's A will require special treatment (either a merge or an export + add) """ - map = [] - for file_info in files_info: - map.append(file_info[2] + "/" + file_info[3]) - return map + return ['%s/%s' % (f[2], f[3]) for f in files_info] def prompt(question): - answer = None - - while not answer: + while True: print question + " [y|n]:", answer = sys.stdin.readline() if answer.lower().startswith('n'): return False elif answer.lower().startswith('y'): return True - else: - answer = None + def text_prompt(question, default): print question + " [" + default + "]:" @@ -427,7 +413,8 @@ def text_prompt(question, default): return default return answer -def main(options, args): + +def drover(options, args): revision = options.revert or options.merge # Initialize some variables used below. They can be overwritten by @@ -442,18 +429,18 @@ def main(options, args): if options.branch: DEFAULT_WORKING += ("_" + options.branch) - if not isMinimumSVNVersion(1,5): + if not isMinimumSVNVersion(1, 5): print "You need to use at least SVN version 1.5.x" - sys.exit(1) + return 1 # Override the default properties if there is a drover.properties file. global file_pattern_ if os.path.exists("drover.properties"): - file = open("drover.properties") - exec(file) - file.close() + f = open("drover.properties") + exec(f) + f.close() if FILE_PATTERN: - file_pattern_ = FILE_PATTERN + file_pattern_ = FILE_PATTERN if options.revert and options.branch: url = BRANCH_URL.replace("$branch", options.branch) @@ -468,21 +455,21 @@ def main(options, args): working = os.getcwd() if not inCheckoutRoot(working): print "'%s' appears not to be the root of a working copy" % working - sys.exit(1) + return 1 if isSVNDirty(): print "Working copy contains uncommitted files" - sys.exit(1) + return 1 command = 'svn log ' + url + " -r "+str(revision) + " -v" os.system(command) if not (options.revertbot or prompt("Is this the correct revision?")): - sys.exit(0) + return 0 if (os.path.exists(working)) and not options.local: if not (options.revertbot or SKIP_CHECK_WORKING or prompt("Working directory: '%s' already exists, clobber?" % working)): - sys.exit(0) + return 0 deltree(working) if not options.local: @@ -533,7 +520,7 @@ def main(options, args): os.unlink(filename) if options.local: - sys.exit(0) + return 0 print author print revision @@ -552,18 +539,19 @@ def main(options, args): print "Deleting the changelist." print "gcl delete " + str(revision) runGcl("delete " + str(revision)) - sys.exit(0) + return 0 # We commit if the reverbot is set to commit automatically, or if this is # not the revertbot and the user agrees. if options.revertbot_commit or (not options.revertbot and prompt("Would you like to commit?")): print "gcl commit " + str(revision) + " --no_presubmit --force" - runGcl("commit " + str(revision) + " --no_presubmit --force") + return runGcl("commit " + str(revision) + " --no_presubmit --force") else: - sys.exit(0) + return 0 -if __name__ == "__main__": + +def main(): option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]}) option_parser.add_option('-m', '--merge', type="int", help='Revision to merge from trunk to branch') @@ -578,7 +566,7 @@ if __name__ == "__main__": option_parser.add_option('-w', '--workdir', help='subdir to use for the revert') option_parser.add_option('-a', '--auditor', - help='overrides the author for reviewer') + help='overrides the author for reviewer') option_parser.add_option('', '--revertbot', action='store_true', default=False) option_parser.add_option('', '--revertbot-commit', action='store_true', @@ -588,14 +576,18 @@ if __name__ == "__main__": if not options.merge and not options.revert: option_parser.error("You need at least --merge or --revert") - sys.exit(1) + return 1 if options.merge and not options.branch and not options.local: option_parser.error("--merge requires either --branch or --local") - sys.exit(1) + return 1 if options.local and (options.revert or options.branch): option_parser.error("--local cannot be used with --revert or --branch") - sys.exit(1) + return 1 + + return drover(options, args) - sys.exit(main(options, args)) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/gcl.py b/gcl.py index 055aa900e..55144ccf4 100755 --- a/gcl.py +++ b/gcl.py @@ -12,7 +12,6 @@ import getpass import os import random import re -import shutil import string import subprocess import sys @@ -127,7 +126,6 @@ def GetCachedFile(filename, max_age=60*60*24*3, use_root=False): Note: The cache will be inconsistent if the same file is retrieved with both use_root=True and use_root=False. Don't be stupid. """ - global FILES_CACHE if filename not in FILES_CACHE: # Don't try to look up twice. FILES_CACHE[filename] = None @@ -173,7 +171,6 @@ def GetCodeReviewSetting(key): """Returns a value for the given key for this repository.""" # Use '__just_initialized' as a flag to determine if the settings were # already initialized. - global CODEREVIEW_SETTINGS if '__just_initialized' not in CODEREVIEW_SETTINGS: settings_file = GetCachedFile(CODEREVIEW_SETTINGS_FILE) if settings_file: @@ -190,10 +187,10 @@ def Warn(msg): ErrorExit(msg, exit=False) -def ErrorExit(msg, exit=True): +def ErrorExit(msg, do_exit=True): """Print an error message to stderr and optionally exit.""" - print >>sys.stderr, msg - if exit: + print >> sys.stderr, msg + if do_exit: sys.exit(1) @@ -776,8 +773,8 @@ def CMDupload(change_info, args): cc_list = GetCodeReviewSetting("CC_LIST") if not no_watchlists and watchers: - # Filter out all empty elements and join by ',' - cc_list = ','.join(filter(None, [cc_list] + watchers)) + # Filter out all empty elements and join by ',' + cc_list = ','.join(filter(None, [cc_list] + watchers)) if cc_list: upload_arg.append("--cc=" + cc_list) upload_arg.append("--description_file=" + desc_file + "") @@ -1178,7 +1175,7 @@ def CMDdiff(args): def CMDsettings(): """Prints code review settings for this checkout.""" # Force load settings - GetCodeReviewSetting("UNKNOWN"); + GetCodeReviewSetting("UNKNOWN") del CODEREVIEW_SETTINGS['__just_initialized'] print '\n'.join(("%s: %s" % (str(k), str(v)) for (k,v) in CODEREVIEW_SETTINGS.iteritems())) diff --git a/gclient.py b/gclient.py index cce785986..5e960aa5a 100644 --- a/gclient.py +++ b/gclient.py @@ -1063,7 +1063,7 @@ def Command(name): def CMDhelp(parser, args): """Prints list of commands or help for a specific command.""" - (options, args) = parser.parse_args(args) + (_, args) = parser.parse_args(args) if len(args) == 1: return Main(args + ['--help']) parser.print_help() @@ -1085,51 +1085,52 @@ def GenUsage(parser, command): def Main(argv): """Doesn't parse the arguments here, just find the right subcommand to execute.""" - # Do it late so all commands are listed. - CMDhelp.usage = ('\n\nCommands are:\n' + '\n'.join([ - ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip()) - for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')])) - parser = optparse.OptionParser(version='%prog ' + __version__) - parser.add_option("-v", "--verbose", action="count", default=0, - help="Produces additional output for diagnostics. Can be " - "used up to three times for more logging info.") - parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename", - default=os.environ.get("GCLIENT_FILE", ".gclient"), - help="Specify an alternate .gclient file") - # Integrate standard options processing. - old_parser = parser.parse_args - def Parse(args): - (options, args) = old_parser(args) - if options.verbose == 2: - logging.basicConfig(level=logging.INFO) - elif options.verbose > 2: - logging.basicConfig(level=logging.DEBUG) - options.entries_filename = options.config_filename + "_entries" - if not hasattr(options, 'revisions'): - # GClient.RunOnDeps expects it even if not applicable. - options.revisions = [] - if not hasattr(options, 'head'): - options.head = None - return (options, args) - parser.parse_args = Parse - # We don't want wordwrapping in epilog (usually examples) - parser.format_epilog = lambda _: parser.epilog or '' - if argv: - command = Command(argv[0]) - if command: - # "fix" the usage and the description now that we know the subcommand. - GenUsage(parser, argv[0]) - return command(parser, argv[1:]) - # Not a known command. Default to help. - GenUsage(parser, 'help') - return CMDhelp(parser, argv) - - -if "__main__" == __name__: try: - sys.exit(Main(sys.argv[1:])) + # Do it late so all commands are listed. + CMDhelp.usage = ('\n\nCommands are:\n' + '\n'.join([ + ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip()) + for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')])) + parser = optparse.OptionParser(version='%prog ' + __version__) + parser.add_option("-v", "--verbose", action="count", default=0, + help="Produces additional output for diagnostics. Can be " + "used up to three times for more logging info.") + parser.add_option("--gclientfile", metavar="FILENAME", + dest="config_filename", + default=os.environ.get("GCLIENT_FILE", ".gclient"), + help="Specify an alternate .gclient file") + # Integrate standard options processing. + old_parser = parser.parse_args + def Parse(args): + (options, args) = old_parser(args) + if options.verbose == 2: + logging.basicConfig(level=logging.INFO) + elif options.verbose > 2: + logging.basicConfig(level=logging.DEBUG) + options.entries_filename = options.config_filename + "_entries" + if not hasattr(options, 'revisions'): + # GClient.RunOnDeps expects it even if not applicable. + options.revisions = [] + if not hasattr(options, 'head'): + options.head = None + return (options, args) + parser.parse_args = Parse + # We don't want wordwrapping in epilog (usually examples) + parser.format_epilog = lambda _: parser.epilog or '' + if argv: + command = Command(argv[0]) + if command: + # "fix" the usage and the description now that we know the subcommand. + GenUsage(parser, argv[0]) + return command(parser, argv[1:]) + # Not a known command. Default to help. + GenUsage(parser, 'help') + return CMDhelp(parser, argv) except gclient_utils.Error, e: print >> sys.stderr, "Error: %s" % str(e) - sys.exit(1) + return 1 + + +if "__main__" == __name__: + sys.exit(Main(sys.argv[1:])) # vim: ts=2:sw=2:tw=80:et: diff --git a/gclient_scm.py b/gclient_scm.py index 56f2119f1..a96e0367b 100644 --- a/gclient_scm.py +++ b/gclient_scm.py @@ -30,11 +30,11 @@ class DiffFilterer(object): self._current_file = "" self._replacement_file = "" - def SetCurrentFile(self, file): - self._current_file = file + def SetCurrentFile(self, current_file): + self._current_file = current_file # Note that we always use '/' as the path separator to be # consistent with svn's cygwin-style output on Windows - self._replacement_file = posixpath.join(self._relpath, file) + self._replacement_file = posixpath.join(self._relpath, current_file) def ReplaceAndPrint(self, line): print(line.replace(self._current_file, self._replacement_file)) @@ -114,15 +114,14 @@ class SCMWrapper(object): class GitWrapper(SCMWrapper): """Wrapper for Git""" - def cleanup(self, options, args, file_list): + @staticmethod + def cleanup(options, args, file_list): """'Cleanup' the repo. There's no real git equivalent for the svn cleanup command, do a no-op. """ - __pychecker__ = 'unusednames=options,args,file_list' def diff(self, options, args, file_list): - __pychecker__ = 'unusednames=options,args,file_list' merge_base = self._Run(['merge-base', 'HEAD', 'origin']) self._Run(['diff', merge_base], redirect_stdout=False) @@ -132,7 +131,6 @@ class GitWrapper(SCMWrapper): Exports into the specified directory, creating the path if it does already exist. """ - __pychecker__ = 'unusednames=options,file_list' assert len(args) == 1 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) if not os.path.exists(export_path): @@ -147,7 +145,6 @@ class GitWrapper(SCMWrapper): The patch file is generated from a diff of the merge base of HEAD and its upstream branch. """ - __pychecker__ = 'unusednames=options,args,file_list' path = os.path.join(self._root_dir, self.relpath) merge_base = self._Run(['merge-base', 'HEAD', 'origin']) command = ['diff', merge_base] @@ -403,7 +400,6 @@ class GitWrapper(SCMWrapper): All reverted files will be appended to file_list. """ - __pychecker__ = 'unusednames=args' path = os.path.join(self._root_dir, self.relpath) if not os.path.isdir(path): # revert won't work if the directory doesn't exist. It needs to @@ -413,7 +409,7 @@ class GitWrapper(SCMWrapper): return self.update(options, [], file_list) default_rev = "refs/heads/master" - url, deps_revision = gclient_utils.SplitUrlRevision(self.url) + _, deps_revision = gclient_utils.SplitUrlRevision(self.url) if not deps_revision: deps_revision = default_rev if deps_revision.startswith('refs/heads/'): @@ -425,7 +421,6 @@ class GitWrapper(SCMWrapper): def revinfo(self, options, args, file_list): """Display revision""" - __pychecker__ = 'unusednames=options,args,file_list' return self._Run(['rev-parse', 'HEAD']) def runhooks(self, options, args, file_list): @@ -433,7 +428,6 @@ class GitWrapper(SCMWrapper): def status(self, options, args, file_list): """Display status information.""" - __pychecker__ = 'unusednames=options,args' if not os.path.isdir(self.checkout_path): print('\n________ couldn\'t run status in %s:\nThe directory ' 'does not exist.' % self.checkout_path) @@ -574,7 +568,8 @@ class GitWrapper(SCMWrapper): # whitespace between projects when syncing. print "" - def _CheckMinVersion(self, min_version): + @staticmethod + def _CheckMinVersion(min_version): (ok, current_version) = scm.GIT.AssertVersion(min_version) if not ok: raise gclient_utils.Error('git version %s < minimum required %s' % @@ -594,31 +589,31 @@ class GitWrapper(SCMWrapper): try: scm.GIT.Capture(['update-index', '--ignore-submodules', '--refresh'], self.checkout_path, print_error=False) - except gclient_utils.CheckCallError, e: - raise gclient_utils.Error('\n____ %s%s\n' - '\tYou have unstaged changes.\n' - '\tPlease commit, stash, or reset.\n' - % (self.relpath, rev_str)) + except gclient_utils.CheckCallError: + raise gclient_utils.Error('\n____ %s%s\n' + '\tYou have unstaged changes.\n' + '\tPlease commit, stash, or reset.\n' + % (self.relpath, rev_str)) try: scm.GIT.Capture(['diff-index', '--cached', '--name-status', '-r', '--ignore-submodules', 'HEAD', '--'], self.checkout_path, print_error=False) - except gclient_utils.CheckCallError, e: - raise gclient_utils.Error('\n____ %s%s\n' - '\tYour index contains uncommitted changes\n' - '\tPlease commit, stash, or reset.\n' - % (self.relpath, rev_str)) + except gclient_utils.CheckCallError: + raise gclient_utils.Error('\n____ %s%s\n' + '\tYour index contains uncommitted changes\n' + '\tPlease commit, stash, or reset.\n' + % (self.relpath, rev_str)) def _CheckDetachedHead(self, rev_str): # HEAD is detached. Make sure it is safe to move away from (i.e., it is # reference by a commit). If not, error out -- most likely a rebase is # in progress, try to detect so we can give a better error. try: - out, err = scm.GIT.Capture( + _, _ = scm.GIT.Capture( ['name-rev', '--no-undefined', 'HEAD'], self.checkout_path, print_error=False) - except gclient_utils.CheckCallError, e: + except gclient_utils.CheckCallError: # Commit is not contained by any rev. See if the user is rebasing: if self._IsRebasing(): # Punt to the user @@ -670,21 +665,18 @@ class SVNWrapper(SCMWrapper): def cleanup(self, options, args, file_list): """Cleanup working copy.""" - __pychecker__ = 'unusednames=file_list,options' command = ['cleanup'] command.extend(args) scm.SVN.Run(command, os.path.join(self._root_dir, self.relpath)) def diff(self, options, args, file_list): # NOTE: This function does not currently modify file_list. - __pychecker__ = 'unusednames=file_list,options' command = ['diff'] command.extend(args) scm.SVN.Run(command, os.path.join(self._root_dir, self.relpath)) def export(self, options, args, file_list): """Export a clean directory tree into the given path.""" - __pychecker__ = 'unusednames=file_list,options' assert len(args) == 1 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) try: @@ -699,7 +691,6 @@ class SVNWrapper(SCMWrapper): def pack(self, options, args, file_list): """Generates a patch file which can be applied to the root of the repository.""" - __pychecker__ = 'unusednames=file_list,options' path = os.path.join(self._root_dir, self.relpath) command = ['diff'] command.extend(args) @@ -847,7 +838,6 @@ class SVNWrapper(SCMWrapper): All reverted files will be appended to file_list, even if Subversion doesn't know about them. """ - __pychecker__ = 'unusednames=args' path = os.path.join(self._root_dir, self.relpath) if not os.path.isdir(path): # svn revert won't work if the directory doesn't exist. It needs to @@ -900,7 +890,6 @@ class SVNWrapper(SCMWrapper): def revinfo(self, options, args, file_list): """Display revision""" - __pychecker__ = 'unusednames=args,file_list,options' return scm.SVN.CaptureBaseRevision(self.checkout_path) def runhooks(self, options, args, file_list): @@ -924,7 +913,8 @@ class SVNWrapper(SCMWrapper): # Find the forth '/' and strip from there. A bit hackish. return '/'.join(self.url.split('/')[:4]) + url - def AddAdditionalFlags(self, command, options, revision): + @staticmethod + def AddAdditionalFlags(command, options, revision): """Add additional flags to command depending on what options are set. command should be a list of strings that represents an svn command. diff --git a/gclient_utils.py b/gclient_utils.py index a052d42ca..276d015c7 100644 --- a/gclient_utils.py +++ b/gclient_utils.py @@ -228,7 +228,7 @@ def SubprocessCallAndFilter(command, in_directory, print_messages, print_stdout, - fail_status=None, filter=None): + fail_status=None, filter_fn=None): """Runs command, a list, in directory in_directory. If print_messages is true, a message indicating what is being done @@ -240,7 +240,7 @@ def SubprocessCallAndFilter(command, Also, if print_stdout is true, the command's stdout is also forwarded to stdout. - If a filter function is specified, it is expected to take a single + If a filter_fn function is specified, it is expected to take a single string argument, and it will be called with each line of the subprocess's output. Each line has had the trailing newline character trimmed. @@ -277,8 +277,8 @@ def SubprocessCallAndFilter(command, sys.stdout.write(in_byte) if in_byte != "\n": in_line += in_byte - if in_byte == "\n" and filter: - filter(in_line) + if in_byte == "\n" and filter_fn: + filter_fn(in_line) in_line = "" in_byte = kid.stdout.read(1) rv = kid.wait() diff --git a/pylintrc b/pylintrc new file mode 100644 index 000000000..40191ab97 --- /dev/null +++ b/pylintrc @@ -0,0 +1,253 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add to the black list. It should be a base name, not a +# path. You may set this option multiple times. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifier separated by comma (,) or put this option +# multiple time. +# C0103: Invalid name "" +# C0111: Missing docstring +# C0302: Too many lines in module (N) +# R0902: Too many instance attributes (N/7) +# R0903: Too few public methods (N/2) +# R0911: Too many return statements (N/6) +# R0912: Too many branches (N/12) +# R0913: Too many arguments (N/5) +# R0914: Too many local variables (N/15) +# R0915: Too many statements (N/50) +# W0122: Use of the exec statement +# W0141: Used builtin function '' +# W0603: Using the global statement +# W0613: Unused argument '' +# W6501: Specify string format arguments as logging function parameters +disable=C0103,C0111,C0302,R0902,R0903,R0911,R0912,R0913,R0914,R0915,W0122,W0141,W0603,W0613,W6501 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Include message's id in output +include-ids=yes + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +# CHANGE: No report. +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (R0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (R0004). +comment=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +# CHANGE: Use " " instead. +indent-string=' ' + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. +generated-members=REQUEST,acl_users,aq_parent + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching names used for dummy variables (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report R0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report R0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report R0402 must +# not be disabled) +int-import-graph= diff --git a/scm.py b/scm.py index 5f3a9bee1..23521b8d9 100644 --- a/scm.py +++ b/scm.py @@ -18,8 +18,8 @@ import xml.dom.minidom import gclient_utils def ValidateEmail(email): - return (re.match(r"^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email) - is not None) + return (re.match(r"^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email) + is not None) def GetCasedPath(path): @@ -121,10 +121,10 @@ class GIT(object): in_directory, print_messages, print_stdout, - filter): + filter_fn): """Runs a command, optionally outputting to stdout. - stdout is passed line-by-line to the given filter function. If + stdout is passed line-by-line to the given filter_fn function. If print_stdout is true, it is also printed to sys.stdout as in Run. Args: @@ -133,7 +133,7 @@ class GIT(object): print_messages: Whether to print status messages to stdout about which commands are being run. print_stdout: Whether to forward program's output to stdout. - filter: A function taking one argument (a string) which will be + filter_fn: A function taking one argument (a string) which will be passed each line (with the ending newline character removed) of program's output for filtering. @@ -146,7 +146,7 @@ class GIT(object): in_directory, print_messages, print_stdout, - filter=filter) + filter_fn=filter_fn) @staticmethod def GetEmail(repo_root): @@ -464,10 +464,10 @@ class SVN(object): in_directory, print_messages, print_stdout, - filter): + filter_fn): """Runs a command, optionally outputting to stdout. - stdout is passed line-by-line to the given filter function. If + stdout is passed line-by-line to the given filter_fn function. If print_stdout is true, it is also printed to sys.stdout as in Run. Args: @@ -476,7 +476,7 @@ class SVN(object): print_messages: Whether to print status messages to stdout about which commands are being run. print_stdout: Whether to forward program's output to stdout. - filter: A function taking one argument (a string) which will be + filter_fn: A function taking one argument (a string) which will be passed each line (with the ending newline character removed) of program's output for filtering. @@ -489,7 +489,7 @@ class SVN(object): in_directory, print_messages, print_stdout, - filter=filter) + filter_fn=filter_fn) @staticmethod def CaptureInfo(relpath, in_directory=None, print_error=True): @@ -507,7 +507,8 @@ class SVN(object): GetNamedNodeText = gclient_utils.GetNamedNodeText GetNodeNamedAttributeText = gclient_utils.GetNodeNamedAttributeText def C(item, f): - if item is not None: return f(item) + if item is not None: + return f(item) # /info/entry/ # url # reposityory/(root|uuid) @@ -516,7 +517,6 @@ class SVN(object): # str() the results because they may be returned as Unicode, which # interferes with the higher layers matching up things in the deps # dictionary. - # TODO(maruel): Fix at higher level instead (!) result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str) result['URL'] = C(GetNamedNodeText(dom, 'url'), str) result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str) @@ -647,11 +647,11 @@ class SVN(object): info.get('Schedule') == 'add') @staticmethod - def GetFileProperty(file, property_name): + def GetFileProperty(filename, property_name): """Returns the value of an SVN property for the given file. Args: - file: The file to check + filename: The file to check property_name: The name of the SVN property, e.g. "svn:mime-type" Returns: @@ -659,7 +659,7 @@ class SVN(object): is not set on the file. If the file is not under version control, the empty string is also returned. """ - output = SVN.Capture(["propget", property_name, file]) + output = SVN.Capture(["propget", property_name, filename]) if (output.startswith("svn: ") and output.endswith("is not under version control")): return "" @@ -685,7 +685,8 @@ class SVN(object): try: # Use "svn info" output instead of os.path.isdir because the latter fails # when the file is deleted. - return SVN._DiffItemInternal(SVN.CaptureInfo(filename), + return SVN._DiffItemInternal(filename, SVN.CaptureInfo(filename), + bogus_dir, full_move=full_move, revision=revision) finally: shutil.rmtree(bogus_dir) @@ -835,8 +836,8 @@ class SVN(object): def ReadSimpleAuth(filename): f = open(filename, 'r') values = {} - def ReadOneItem(type): - m = re.match(r'%s (\d+)' % type, f.readline()) + def ReadOneItem(item_type): + m = re.match(r'%s (\d+)' % item_type, f.readline()) if not m: return None data = f.read(int(m.group(1)))