| Index: recipe_engine/fetch.py
|
| diff --git a/recipe_engine/fetch.py b/recipe_engine/fetch.py
|
| index a6f082ad23af8898a3ce140526b74baa3cdb3380..8f417bf34906bf9da46a318720484a0ff8546544 100644
|
| --- a/recipe_engine/fetch.py
|
| +++ b/recipe_engine/fetch.py
|
| @@ -31,14 +31,6 @@
|
| LOGGER = logging.getLogger(__name__)
|
|
|
|
|
| -def has_interesting_changes(spec, changed_files):
|
| - # TODO(iannucci): analyze bundle_extra_paths.txt too.
|
| - return (
|
| - 'infra/config/recipes.cfg' in changed_files or
|
| - any(f.startswith(spec.recipes_path) for f in changed_files)
|
| - )
|
| -
|
| -
|
| class FetchError(Exception):
|
| pass
|
|
|
| @@ -56,12 +48,9 @@
|
| # commit_timestamp (int): the unix commit timestamp for this commit
|
| # message_lines (tuple(str)): the message of this commit
|
| # spec (package_pb2.Package): the parsed infra/config/recipes.cfg file or None.
|
| -# roll_candidate (bool): if this commit contains changes which are known to
|
| -# affect the behavior of the recipes (i.e. modifications within recipe_path
|
| -# and/or modifications to recipes.cfg)
|
| CommitMetadata = namedtuple(
|
| '_CommitMetadata',
|
| - 'revision author_email commit_timestamp message_lines spec roll_candidate')
|
| + 'revision author_email commit_timestamp message_lines spec')
|
|
|
|
|
| class Backend(object):
|
| @@ -125,7 +114,11 @@
|
|
|
| The refspec will be resolved if it's not absolute.
|
|
|
| - Returns (CommitMetadata).
|
| + Returns {
|
| + 'author': '<author name>',
|
| + 'message': '<commit message>',
|
| + 'spec': package_pb2.Package or None, # the parsed recipes.cfg file.
|
| + }
|
| """
|
| revision = self.resolve_refspec(refspec)
|
| cache = self._GIT_METADATA_CACHE.setdefault(self.repo_url, {})
|
| @@ -147,16 +140,18 @@
|
| return refspec
|
| return self._resolve_refspec_impl(refspec)
|
|
|
| - def updates(self, revision, other_revision):
|
| + def updates(self, revision, other_revision, paths):
|
| """Returns a list of revisions |revision| through |other_revision|
|
| (inclusive).
|
|
|
| + If |paths| is a non-empty list, the history is scoped just to these paths.
|
| +
|
| Returns list(CommitMetadata) - The commit metadata in the range
|
| (revision,other_revision].
|
| """
|
| self.assert_resolved(revision)
|
| self.assert_resolved(other_revision)
|
| - return self._updates_impl(revision, other_revision)
|
| + return self._updates_impl(revision, other_revision, paths)
|
|
|
| ### direct overrides. These are public methods which must be overridden.
|
|
|
| @@ -190,9 +185,11 @@
|
| ### private overrides. Override these in the implementations, but don't call
|
| ### externally.
|
|
|
| - def _updates_impl(self, revision, other_revision):
|
| + def _updates_impl(self, revision, other_revision, paths):
|
| """Returns a list of revisions |revision| through |other_revision|. This
|
| includes |revision| and |other_revision|.
|
| +
|
| + If |paths| is a non-empty list, the history is scoped just to these paths.
|
|
|
| Args:
|
| revision (str) - the first git commit
|
| @@ -248,15 +245,6 @@
|
|
|
| Raises GitError on failure.
|
| """
|
| - if self._GIT_BINARY.endswith('.bat'):
|
| - # On the esteemed Windows Operating System, '^' is an escape character.
|
| - # Since .bat files are running cmd.exe under the hood, they interpret this
|
| - # escape character. We need to ultimately get a single ^, so we need two
|
| - # ^'s for when we invoke the .bat, and each of those needs to be escaped
|
| - # when the bat ultimately invokes the git.exe binary. This leaves us with
|
| - # a total of 4x the ^'s that we originally wanted. Hooray.
|
| - args = [a.replace('^', '^^^^') for a in args]
|
| -
|
| cmd = [
|
| self._GIT_BINARY,
|
| '-C', self.checkout_dir,
|
| @@ -339,13 +327,15 @@
|
| except GitError:
|
| self._git('reset', '-q', '--hard', revision)
|
|
|
| - def _updates_impl(self, revision, other_revision):
|
| + def _updates_impl(self, revision, other_revision, paths):
|
| args = [
|
| 'rev-list',
|
| '--reverse',
|
| '--topo-order',
|
| '%s..%s' % (revision, other_revision),
|
| ]
|
| + if paths:
|
| + args.extend(['--'] + paths)
|
| return [
|
| self.commit_metadata(rev)
|
| for rev in self._git(*args).strip().split('\n')
|
| @@ -377,14 +367,9 @@
|
| except GitError:
|
| spec = None
|
|
|
| - # check diff to see if it touches anything interesting.
|
| - changed_files = set(self._git(
|
| - 'diff-tree', '-r', '--no-commit-id', '--name-only', '%s^!' % revision)
|
| - .splitlines())
|
| -
|
| return CommitMetadata(revision, meta[0],
|
| int(meta[1]), tuple(meta[2:]),
|
| - spec, has_interesting_changes(spec, changed_files))
|
| + spec)
|
|
|
| class GitilesFetchError(FetchError):
|
| """An HTTP error that occurred during Gitiles fetching."""
|
| @@ -408,22 +393,16 @@
|
| # commit (str) - the git commit hash
|
| # author_email (str) - the author email for this commit
|
| # message_lines (tuple) - the lines of the commit message
|
| -# changed_files (frozenset) - all paths touched by this commit
|
| class _GitilesCommitJson(namedtuple(
|
| '_GitilesCommitJson',
|
| - 'commit author_email commit_timestamp message_lines changed_files')):
|
| + 'commit author_email commit_timestamp message_lines')):
|
| @classmethod
|
| def from_raw_json(cls, raw):
|
| - mod_files = set()
|
| - for entry in raw['tree_diff']:
|
| - mod_files.add(entry['old_path'])
|
| - mod_files.add(entry['new_path'])
|
| return cls(
|
| raw['commit'],
|
| raw['author']['email'],
|
| calendar.timegm(time.strptime(raw['committer']['time'])),
|
| tuple(raw['message'].splitlines()),
|
| - frozenset(mod_files),
|
| )
|
|
|
|
|
| @@ -453,13 +432,8 @@
|
| raise GitilesFetchError(resp.status_code, resp.text)
|
| return resp
|
|
|
| - def _fetch_gitiles_committish_json(self, url_fmt, *args):
|
| + def _fetch_gitiles_json(self, url_fmt, *args):
|
| """Fetches a remote URL path and expects a JSON object on success.
|
| -
|
| - This appends two GET params to url_fmt:
|
| - format=JSON - Does what you expect
|
| - name-status=1 - Ensures that commit objects returned have a 'tree_diff'
|
| - member which shows the diff for that commit.
|
|
|
| Args:
|
| url_fmt (str) - the url path fragment as a python %format string, like
|
| @@ -469,7 +443,7 @@
|
|
|
| Returns the decoded JSON object
|
| """
|
| - resp = self._fetch_gitiles(url_fmt+'?name-status=1&format=JSON', *args)
|
| + resp = self._fetch_gitiles(url_fmt, *args)
|
| if not resp.text.startswith(self._GERRIT_XSRF_HEADER):
|
| raise GitilesFetchError(resp.status_code, 'Missing XSRF prefix')
|
| return json.loads(resp.text[len(self._GERRIT_XSRF_HEADER):])
|
| @@ -492,7 +466,7 @@
|
| if refspec in c:
|
| return c[refspec]
|
|
|
| - raw = self._fetch_gitiles_committish_json('+/%s', refspec)
|
| + raw = self._fetch_gitiles_json('+/%s?format=JSON', refspec)
|
| ret = _GitilesCommitJson.from_raw_json(raw)
|
| if self.is_resolved_revision(refspec):
|
| c[refspec] = ret
|
| @@ -551,13 +525,14 @@
|
| with tarfile.open(fileobj=StringIO(archive_response.content)) as tf:
|
| tf.extractall(recipes_path)
|
|
|
| - def _updates_impl(self, revision, other_revision):
|
| + def _updates_impl(self, revision, other_revision, paths):
|
| self.assert_remote('_updates_impl')
|
|
|
| # TODO(iannucci): implement paging
|
|
|
| - log_json = self._fetch_gitiles_committish_json(
|
| - '+log/%s..%s', revision, other_revision)
|
| + # To include info about touched paths (tree_diff), pass name-status=1 below.
|
| + log_json = self._fetch_gitiles_json(
|
| + '+log/%s..%s?name-status=1&format=JSON', revision, other_revision)
|
|
|
| c = self._COMMIT_JSON_CACHE.setdefault(self.repo_url, {})
|
|
|
| @@ -565,7 +540,18 @@
|
| for entry in log_json['log']:
|
| commit = entry['commit']
|
| c[commit] = _GitilesCommitJson.from_raw_json(entry)
|
| - results.append(commit)
|
| +
|
| + matched = False
|
| + for path in paths:
|
| + for diff_entry in entry['tree_diff']:
|
| + if (diff_entry['old_path'].startswith(path) or
|
| + diff_entry['new_path'].startswith(path)):
|
| + matched = True
|
| + break
|
| + if matched:
|
| + break
|
| + if matched or not paths:
|
| + results.append(commit)
|
|
|
| results.reverse()
|
| return map(self.commit_metadata, results)
|
| @@ -590,5 +576,4 @@
|
| rev_json.author_email,
|
| rev_json.commit_timestamp,
|
| rev_json.message_lines,
|
| - spec,
|
| - has_interesting_changes(spec, rev_json.changed_files))
|
| + spec)
|
|
|