Exemple #1
0
def Change(change_info, args):
    """Creates/edits a changelist."""
    silent = FilterFlag(args, "--silent")

    # Verify the user is running the change command from a read-write checkout.
    svn_info = SVN.CaptureInfo('.')
    if not svn_info:
        ErrorExit(
            "Current checkout is unversioned.  Please retry with a versioned "
            "directory.")

    if (len(args) == 1):
        filename = args[0]
        f = open(filename, 'rU')
        override_description = f.read()
        f.close()
    else:
        override_description = None

    if change_info.issue and not change_info.NeedsUpload():
        try:
            description = GetIssueDescription(change_info.issue)
        except urllib2.HTTPError, err:
            if err.code == 404:
                # The user deleted the issue in Rietveld, so forget the old issue id.
                description = change_info.description
                change_info.issue = 0
                change_info.Save()
            else:
                ErrorExit("Error getting the description from Rietveld: " +
                          err)
Exemple #2
0
    def Load(changename, local_root, fail_on_not_found, update_status):
        """Gets information about a changelist.

    Args:
      fail_on_not_found: if True, this function will quit the program if the
        changelist doesn't exist.
      update_status: if True, the svn status will be updated for all the files
        and unchanged files will be removed.

    Returns: a ChangeInfo object.
    """
        info_file = GetChangelistInfoFile(changename)
        if not os.path.exists(info_file):
            if fail_on_not_found:
                ErrorExit("Changelist " + changename + " not found.")
            return ChangeInfo(changename,
                              0,
                              0,
                              '',
                              None,
                              local_root,
                              needs_upload=False)
        split_data = ReadFile(info_file).split(ChangeInfo._SEPARATOR, 2)
        if len(split_data) != 3:
            ErrorExit("Changelist file %s is corrupt" % info_file)
        items = split_data[0].split(', ')
        issue = 0
        patchset = 0
        needs_upload = False
        if items[0]:
            issue = int(items[0])
        if len(items) > 1:
            patchset = int(items[1])
        if len(items) > 2:
            needs_upload = (items[2] == "dirty")
        files = []
        for line in split_data[1].splitlines():
            status = line[:7]
            filename = line[7:]
            files.append((status, filename))
        description = split_data[2]
        save = False
        if update_status:
            for item in files:
                filename = os.path.join(local_root, item[1])
                status_result = SVN.CaptureStatus(filename)
                if not status_result or not status_result[0][0]:
                    # File has been reverted.
                    save = True
                    files.remove(item)
                    continue
                status = status_result[0][0]
                if status != item[0]:
                    save = True
                    files[files.index(item)] = (status, item[1])
        change_info = ChangeInfo(changename, issue, patchset, description,
                                 files, local_root, needs_upload)
        if save:
            change_info.Save()
        return change_info
Exemple #3
0
def GenerateDiff(files, root=None):
    """Returns a string containing the diff for the given file list.

  The files in the list should either be absolute paths or relative to the
  given root. If no root directory is provided, the repository root will be
  used.
  """
    previous_cwd = os.getcwd()
    if root is None:
        os.chdir(GetRepositoryRoot())
    else:
        os.chdir(root)

    diff = []
    for filename in files:
        # TODO(maruel): Use SVN.DiffItem().
        # Use svn info output instead of os.path.isdir because the latter fails
        # when the file is deleted.
        if SVN.CaptureInfo(filename).get('Node Kind') == 'directory':
            continue
        # If the user specified a custom diff command in their svn config file,
        # then it'll be used when we do svn diff, which we don't want to happen
        # since we want the unified diff.  Using --diff-cmd=diff doesn't always
        # work, since they can have another diff executable in their path that
        # gives different line endings.  So we use a bogus temp directory as the
        # config directory, which gets around these problems.
        if sys.platform.startswith("win"):
            parent_dir = tempfile.gettempdir()
        else:
            parent_dir = sys.path[0]  # tempdir is not secure.
        bogus_dir = os.path.join(parent_dir, "temp_svn_config")
        if not os.path.exists(bogus_dir):
            os.mkdir(bogus_dir)
        output = RunShell(["svn", "diff", "--config-dir", bogus_dir, filename])
        if output:
            diff.append(output)
        elif SVN.IsMoved(filename):
            #  svn diff on a mv/cp'd file outputs nothing.
            # We put in an empty Index entry so upload.py knows about them.
            diff.append("\nIndex: %s\n" % filename)
        else:
            # The file is not modified anymore. It should be removed from the set.
            pass
    os.chdir(previous_cwd)
    return "".join(diff)
Exemple #4
0
def UnknownFiles(extra_args):
    """Runs svn status and returns unknown files.

  Any args in |extra_args| are passed to the tool to support giving alternate
  code locations.
  """
    return [
        item[1] for item in SVN.CaptureStatus(extra_args) if item[0][0] == '?'
    ]
Exemple #5
0
  def Load(changename, local_root, fail_on_not_found, update_status):
    """Gets information about a changelist.

    Args:
      fail_on_not_found: if True, this function will quit the program if the
        changelist doesn't exist.
      update_status: if True, the svn status will be updated for all the files
        and unchanged files will be removed.

    Returns: a ChangeInfo object.
    """
    info_file = GetChangelistInfoFile(changename)
    if not os.path.exists(info_file):
      if fail_on_not_found:
        ErrorExit("Changelist " + changename + " not found.")
      return ChangeInfo(changename, 0, 0, '', None, local_root, None, False)
    content = gclient_utils.FileRead(info_file)
    save = False
    try:
      values = ChangeInfo._LoadNewFormat(content)
    except ValueError:
      try:
        values = ChangeInfo._LoadOldFormat(content)
        save = True
      except ValueError:
        ErrorExit(
            ('Changelist file %s is corrupt.\n'
            'Either run "gcl delete %s" or manually edit the file') % (
                info_file, changename))
    files = values['files']
    if update_status:
      for item in files[:]:
        status_result = SVN.CaptureStatus(item[1], local_root)
        if not status_result or not status_result[0][0]:
          # File has been reverted.
          save = True
          files.remove(item)
          continue
        status = status_result[0][0]
        if status != item[0]:
          save = True
          files[files.index(item)] = (status, item[1])
    change_info = ChangeInfo(
        changename,
        values['issue'],
        values['patchset'],
        values['description'],
        files,
        local_root,
        values.get('rietveld'),
        values['needs_upload'])
    if save:
      change_info.Save()
    return change_info
Exemple #6
0
def GetRepositoryRoot():
  """Returns the top level directory of the current repository.

  The directory is returned as an absolute path.
  """
  global REPOSITORY_ROOT
  if not REPOSITORY_ROOT:
    REPOSITORY_ROOT = SVN.GetCheckoutRoot(os.getcwd())
    if not REPOSITORY_ROOT:
      raise gclient_utils.Error("gcl run outside of repository")
  return REPOSITORY_ROOT
Exemple #7
0
def GetRepositoryRoot():
    """Returns the top level directory of the current repository.

  The directory is returned as an absolute path.
  """
    global REPOSITORY_ROOT
    if not REPOSITORY_ROOT:
        infos = SVN.CaptureInfo(os.getcwd(), print_error=False)
        cur_dir_repo_root = infos.get("Repository Root")
        if not cur_dir_repo_root:
            raise gclient_utils.Error("gcl run outside of repository")

        REPOSITORY_ROOT = os.getcwd()
        while True:
            parent = os.path.dirname(REPOSITORY_ROOT)
            if (SVN.CaptureInfo(parent,
                                print_error=False).get("Repository Root") !=
                    cur_dir_repo_root):
                break
            REPOSITORY_ROOT = parent
    return REPOSITORY_ROOT
Exemple #8
0
def CMDchange(args):
  """Creates or edits a changelist.

  Only scans the current directory and subdirectories.
  """
  # Verify the user is running the change command from a read-write checkout.
  svn_info = SVN.CaptureLocalInfo([], '.')
  if not svn_info:
    ErrorExit("Current checkout is unversioned.  Please retry with a versioned "
              "directory.")

  if len(args) == 0:
    # Generate a random changelist name.
    changename = GenerateChangeName()
  elif args[0] == '--force':
    changename = GenerateChangeName()
  else:
    changename = args[0]
  change_info = ChangeInfo.Load(changename, GetRepositoryRoot(), False, True)

  if len(args) == 2:
    if not os.path.isfile(args[1]):
      ErrorExit('The change "%s" doesn\'t exist.' % args[1])
    f = open(args[1], 'rU')
    override_description = f.read()
    f.close()
  else:
    override_description = None

  if change_info.issue and not change_info.NeedsUpload():
    try:
      description = change_info.GetIssueDescription()
    except urllib2.HTTPError, err:
      if err.code == 404:
        # The user deleted the issue in Rietveld, so forget the old issue id.
        description = change_info.description
        change_info.issue = 0
        change_info.Save()
      else:
        ErrorExit("Error getting the description from Rietveld: " + err)
Exemple #9
0
def GetModifiedFiles():
    """Returns a set that maps from changelist name to (status,filename) tuples.

  Files not in a changelist have an empty changelist name.  Filenames are in
  relation to the top level directory of the current repository.  Note that
  only the current directory and subdirectories are scanned, in order to
  improve performance while still being flexible.
  """
    files = {}

    # Since the files are normalized to the root folder of the repositary, figure
    # out what we need to add to the paths.
    dir_prefix = os.getcwd()[len(GetRepositoryRoot()):].strip(os.sep)

    # Get a list of all files in changelists.
    files_in_cl = {}
    for cl in GetCLs():
        change_info = ChangeInfo.Load(cl,
                                      GetRepositoryRoot(),
                                      fail_on_not_found=True,
                                      update_status=False)
        for status, filename in change_info.GetFiles():
            files_in_cl[filename] = change_info.name

    # Get all the modified files.
    status_result = SVN.CaptureStatus(None)
    for line in status_result:
        status = line[0]
        filename = line[1]
        if status[0] == "?":
            continue
        if dir_prefix:
            filename = os.path.join(dir_prefix, filename)
        change_list_name = ""
        if filename in files_in_cl:
            change_list_name = files_in_cl[filename]
        files.setdefault(change_list_name, []).append((status, filename))

    return files
Exemple #10
0
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. 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.
        try:
            cached_file = os.path.join(GetCacheDir(), filename)
        except gclient_utils.Error:
            return None
        if (not os.path.exists(cached_file)
                or os.stat(cached_file).st_mtime > max_age):
            local_dir = os.path.dirname(os.path.abspath(filename))
            local_base = os.path.basename(filename)
            dir_info = SVN.CaptureInfo(".")
            repo_root = dir_info["Repository Root"]
            if use_root:
                url_path = repo_root
            else:
                url_path = dir_info["URL"]
            content = ""
            while True:
                # First, look for a locally modified version of the file if we can.
                r = ""
                if not use_root:
                    local_path = os.path.join(local_dir, local_base)
                    r = SVN.CaptureStatus((local_path, ))
                rc = -1
                if r:
                    status = r[0][0]
                    rc = 0
                if not rc and status[0] in ('A', 'M'):
                    content = ReadFile(local_path)
                    rc = 0
                else:
                    # Look in the repository if we didn't find something local.
                    svn_path = url_path + "/" + filename
                    content, rc = RunShellWithReturnCode(
                        ["svn", "cat", svn_path])

                if not rc:
                    # Exit the loop if the file was found. Override content.
                    break
                # Make sure to mark settings as empty if not found.
                content = ""
                if url_path == repo_root:
                    # Reached the root. Abandoning search.
                    break
                # Go up one level to try again.
                url_path = os.path.dirname(url_path)
                local_dir = os.path.dirname(local_dir)
            # Write a cached version even if there isn't a file, so we don't try to
            # fetch it each time.
            WriteFile(cached_file, content)
        else:
            content = ReadFile(cached_file)
        # Keep the content cached in memory.
        FILES_CACHE[filename] = content
    return FILES_CACHE[filename]
Exemple #11
0
def UnknownFiles():
  """Runs svn status and returns unknown files."""
  return [item[1] for item in SVN.CaptureStatus([]) if item[0][0] == '?']
Exemple #12
0
def GenerateDiff(files, root=None):
  return SVN.GenerateDiff(files, root=root)
Exemple #13
0
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. Don't be stupid.
  """
  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.
    try:
      cached_file = os.path.join(GetCacheDir(), filename)
    except gclient_utils.Error:
      return None
    if (not os.path.exists(cached_file) or
        (time.time() - os.stat(cached_file).st_mtime) > max_age):
      dir_info = SVN.CaptureInfo('.')
      repo_root = dir_info['Repository Root']
      if use_root:
        url_path = repo_root
      else:
        url_path = dir_info['URL']
      while True:
        # Look in the repository at the current level for the file.
        for _ in range(5):
          content = None
          try:
            # Take advantage of the fact that svn won't output to stderr in case
            # of success but will do in case of failure so don't mind putting
            # stderr into content_array.
            content_array = []
            svn_path = url_path + '/' + filename
            args = ['svn', 'cat', svn_path]
            if sys.platform != 'darwin':
              # MacOSX 10.5.2 has a bug with svn 1.4.4 that will trigger the
              # 'Can\'t get username or password' and can be fixed easily.
              # The fix doesn't work if the user upgraded to svn 1.6.x. Bleh.
              # I don't have time to fix their broken stuff.
              args.append('--non-interactive')
            gclient_utils.CheckCallAndFilter(
                args, cwd='.', filter_fn=content_array.append)
            # Exit the loop if the file was found. Override content.
            content = '\n'.join(content_array)
            break
          except gclient_utils.Error:
            if content_array[0].startswith(
                'svn: Can\'t get username or password'):
              ErrorExit('Your svn credentials expired. Please run svn update '
                        'to fix the cached credentials')
            if content_array[0].startswith('svn: Can\'t get password'):
              ErrorExit('If are using a Mac and svn --version shows 1.4.x, '
                  'please hack gcl.py to remove --non-interactive usage, it\'s'
                  'a bug on your installed copy')
            if not content_array[0].startswith('svn: File not found:'):
              # Try again.
              continue
        if content:
          break
        if url_path == repo_root:
          # Reached the root. Abandoning search.
          break
        # Go up one level to try again.
        url_path = os.path.dirname(url_path)
      if content is not None or filename != CODEREVIEW_SETTINGS_FILE:
        # Write a cached version even if there isn't a file, so we don't try to
        # fetch it each time. codereview.settings must always be present so do
        # not cache negative.
        gclient_utils.FileWrite(cached_file, content or '')
    else:
      content = gclient_utils.FileRead(cached_file, 'r')
    # Keep the content cached in memory.
    FILES_CACHE[filename] = content
  return FILES_CACHE[filename]
Exemple #14
0
def GenerateDiff(files):
  return SVN.GenerateDiff(
      files, GetRepositoryRoot(), full_move=False, revision=None)