| Index: gcl.py
|
| diff --git a/gcl.py b/gcl.py
|
| index 2911b1212b5ce382e4026b583e91cf5399947d3c..87417a1ed9203ab10cef407c02de0a3e9eec6213 100755
|
| --- a/gcl.py
|
| +++ b/gcl.py
|
| @@ -10,6 +10,7 @@ import getpass
|
| import os
|
| import random
|
| import re
|
| +import shutil
|
| import string
|
| import subprocess
|
| import sys
|
| @@ -21,7 +22,7 @@ import xml.dom.minidom
|
| # gcl now depends on gclient.
|
| import gclient
|
|
|
| -__version__ = '1.0'
|
| +__version__ = '1.1.1'
|
|
|
|
|
| CODEREVIEW_SETTINGS = {
|
| @@ -33,8 +34,7 @@ CODEREVIEW_SETTINGS = {
|
|
|
| # globals that store the root of the current repository and the directory where
|
| # we store information about changelists.
|
| -repository_root = ""
|
| -gcl_info_dir = ""
|
| +REPOSITORY_ROOT = ""
|
|
|
| # Filename where we store repository specific information for gcl.
|
| CODEREVIEW_SETTINGS_FILE = "codereview.settings"
|
| @@ -42,8 +42,8 @@ CODEREVIEW_SETTINGS_FILE = "codereview.settings"
|
| # Warning message when the change appears to be missing tests.
|
| MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!"
|
|
|
| -# Caches whether we read the codereview.settings file yet or not.
|
| -read_gcl_info = False
|
| +# Global cache of files cached in GetCacheDir().
|
| +FILES_CACHE = {}
|
|
|
|
|
| ### SVN Functions
|
| @@ -91,69 +91,99 @@ def GetRepositoryRoot():
|
|
|
| The directory is returned as an absolute path.
|
| """
|
| - global repository_root
|
| - if not repository_root:
|
| + global REPOSITORY_ROOT
|
| + if not REPOSITORY_ROOT:
|
| infos = gclient.CaptureSVNInfo(os.getcwd(), print_error=False)
|
| cur_dir_repo_root = infos.get("Repository Root")
|
| if not cur_dir_repo_root:
|
| raise Exception("gcl run outside of repository")
|
|
|
| - repository_root = os.getcwd()
|
| + REPOSITORY_ROOT = os.getcwd()
|
| while True:
|
| - parent = os.path.dirname(repository_root)
|
| + parent = os.path.dirname(REPOSITORY_ROOT)
|
| if (gclient.CaptureSVNInfo(parent, print_error=False).get(
|
| "Repository Root") != cur_dir_repo_root):
|
| break
|
| - repository_root = parent
|
| - return repository_root
|
| + REPOSITORY_ROOT = parent
|
| + return REPOSITORY_ROOT
|
|
|
|
|
| def GetInfoDir():
|
| """Returns the directory where gcl info files are stored."""
|
| - global gcl_info_dir
|
| - if not gcl_info_dir:
|
| - gcl_info_dir = os.path.join(GetRepositoryRoot(), '.svn', 'gcl_info')
|
| - return gcl_info_dir
|
| + return os.path.join(GetRepositoryRoot(), '.svn', 'gcl_info')
|
|
|
|
|
| -def GetCodeReviewSetting(key):
|
| - """Returns a value for the given key for this repository."""
|
| - global read_gcl_info
|
| - if not read_gcl_info:
|
| - read_gcl_info = True
|
| +def GetChangesDir():
|
| + """Returns the directory where gcl change files are stored."""
|
| + return os.path.join(GetInfoDir(), 'changes')
|
| +
|
| +
|
| +def GetCacheDir():
|
| + """Returns the directory where gcl change files are stored."""
|
| + return os.path.join(GetInfoDir(), 'cache')
|
| +
|
| +
|
| +def GetCachedFile(filename, max_age=60*60*24*3, use_root=False):
|
| + """Retrieves a file from the repository and caches it in GetCacheDir() for
|
| + max_age seconds.
|
| +
|
| + use_root: If False, look up the arborescence for the first match, otherwise go
|
| + directory to the root repository.
|
| +
|
| + Note: The cache will be inconsistent if the same file is retrieved with both
|
| + use_root=True and use_root=False on the same file. Don't be stupid.
|
| + """
|
| + global FILES_CACHE
|
| + if filename not in FILES_CACHE:
|
| + # Don't try to look up twice.
|
| + FILES_CACHE[filename] = None
|
| # First we check if we have a cached version.
|
| - cached_settings_file = os.path.join(GetInfoDir(), CODEREVIEW_SETTINGS_FILE)
|
| - if (not os.path.exists(cached_settings_file) or
|
| - os.stat(cached_settings_file).st_mtime > 60*60*24*3):
|
| + cached_file = os.path.join(GetCacheDir(), filename)
|
| + if (not os.path.exists(cached_file) or
|
| + os.stat(cached_file).st_mtime > max_age):
|
| dir_info = gclient.CaptureSVNInfo(".")
|
| repo_root = dir_info["Repository Root"]
|
| - url_path = dir_info["URL"]
|
| - settings = ""
|
| + if use_root:
|
| + url_path = repo_root
|
| + else:
|
| + url_path = dir_info["URL"]
|
| + content = ""
|
| while True:
|
| # Look for the codereview.settings file at the current level.
|
| - svn_path = url_path + "/" + CODEREVIEW_SETTINGS_FILE
|
| - settings, rc = RunShellWithReturnCode(["svn", "cat", svn_path])
|
| + svn_path = url_path + "/" + filename
|
| + content, rc = RunShellWithReturnCode(["svn", "cat", svn_path])
|
| if not rc:
|
| - # Exit the loop if the file was found.
|
| + # Exit the loop if the file was found. Override content.
|
| break
|
| # Make sure to mark settings as empty if not found.
|
| - settings = ""
|
| + content = ""
|
| if url_path == repo_root:
|
| # Reached the root. Abandoning search.
|
| - break;
|
| + break
|
| # Go up one level to try again.
|
| url_path = os.path.dirname(url_path)
|
| -
|
| # Write a cached version even if there isn't a file, so we don't try to
|
| # fetch it each time.
|
| - WriteFile(cached_settings_file, settings)
|
| + WriteFile(cached_file, content)
|
| + else:
|
| + content = ReadFile(cached_settings_file)
|
| + # Keep the content cached in memory.
|
| + FILES_CACHE[filename] = content
|
| + return FILES_CACHE[filename]
|
| +
|
|
|
| - output = ReadFile(cached_settings_file)
|
| - for line in output.splitlines():
|
| +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:
|
| + for line in GetCachedFile(CODEREVIEW_SETTINGS_FILE).splitlines():
|
| if not line or line.startswith("#"):
|
| continue
|
| k, v = line.split(": ", 1)
|
| CODEREVIEW_SETTINGS[k] = v
|
| + CODEREVIEW_SETTINGS.setdefault('__just_initialized', None)
|
| return CODEREVIEW_SETTINGS.get(key, "")
|
|
|
|
|
| @@ -373,7 +403,7 @@ def GetChangelistInfoFile(changename):
|
| """Returns the file that stores information about a changelist."""
|
| if not changename or re.search(r'[^\w-]', changename):
|
| ErrorExit("Invalid changelist name: " + changename)
|
| - return os.path.join(GetInfoDir(), changename)
|
| + return os.path.join(GetChangesDir(), changename)
|
|
|
|
|
| def LoadChangelistInfoForMultiple(changenames, fail_on_not_found=True,
|
| @@ -442,7 +472,7 @@ def LoadChangelistInfo(changename, fail_on_not_found=True,
|
|
|
| def GetCLs():
|
| """Returns a list of all the changelists in this repository."""
|
| - cls = os.listdir(GetInfoDir())
|
| + cls = os.listdir(GetChangesDir())
|
| if CODEREVIEW_SETTINGS_FILE in cls:
|
| cls.remove(CODEREVIEW_SETTINGS_FILE)
|
| return cls
|
| @@ -1020,10 +1050,21 @@ def main(argv=None):
|
| Help()
|
| return 0;
|
|
|
| - # Create the directory where we store information about changelists if it
|
| + # Create the directories where we store information about changelists if it
|
| # doesn't exist.
|
| if not os.path.exists(GetInfoDir()):
|
| os.mkdir(GetInfoDir())
|
| + if not os.path.exists(GetChangesDir()):
|
| + os.mkdir(GetChangesDir())
|
| + # For smooth upgrade support, move the files in GetInfoDir() to
|
| + # GetChangesDir().
|
| + # TODO(maruel): Remove this code in August 2009.
|
| + for file in os.listdir(unicode(GetInfoDir())):
|
| + file_path = os.path.join(unicode(GetInfoDir()), file)
|
| + if os.path.isfile(file_path) and file != CODEREVIEW_SETTINGS_FILE:
|
| + shutil.move(file_path, GetChangesDir())
|
| + if not os.path.exists(GetCacheDir()):
|
| + os.mkdir(GetCacheDir())
|
|
|
| # Commands that don't require an argument.
|
| command = argv[1]
|
|
|