Not all Android source trees support build IDs and tags. When no build tag is requested, rather than try to match the build IDs just sync the branch tips of the upstream and downstream source trees. Also select two Android Oreo release candidates as the default branches. The fact that there are frozen branches and that the diff is small serve as a good showcase of the tool. Change-Id: Ifdefd79fb6b32c6b83e0aee390dd5a435b6a61fc
173 lines
5.3 KiB
Python
173 lines
5.3 KiB
Python
#!/usr/bin/python
|
|
"""Diff a repo (downstream) and its upstream.
|
|
|
|
This script:
|
|
1. Downloads a repo source tree with specified manifest URL, branch
|
|
and release tag.
|
|
2. Retrieves the BUILD_ID from $downstream/build/core/build_id.mk.
|
|
3. Downloads the upstream using the BUILD_ID.
|
|
4. Diffs each project in these two repos.
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import repo_diff_downstream
|
|
|
|
HELP_MSG = "Diff a repo (downstream) and its upstream"
|
|
|
|
DOWNSTREAM_WORKSPACE = "downstream"
|
|
UPSTREAM_WORKSPACE = "upstream"
|
|
|
|
DEFAULT_MANIFEST_URL = "https://android.googlesource.com/platform/manifest"
|
|
DEFAULT_MANIFEST_BRANCH = "android-8.0.0_r10"
|
|
DEFAULT_UPSTREAM_MANIFEST_URL = "https://android.googlesource.com/platform/manifest"
|
|
DEFAULT_UPSTREAM_MANIFEST_BRANCH = "android-8.0.0_r1"
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
DEFAULT_EXCLUSIONS_FILE = os.path.join(SCRIPT_DIR, "exclusions.txt")
|
|
|
|
|
|
def parse_args():
|
|
"""Parse args."""
|
|
|
|
parser = argparse.ArgumentParser(description=HELP_MSG)
|
|
|
|
parser.add_argument("-u", "--manifest-url",
|
|
help="manifest url",
|
|
default=DEFAULT_MANIFEST_URL)
|
|
parser.add_argument("-b", "--manifest-branch",
|
|
help="manifest branch",
|
|
default=DEFAULT_MANIFEST_BRANCH)
|
|
parser.add_argument("-r", "--upstream-manifest-url",
|
|
help="upstream manifest url",
|
|
default=DEFAULT_UPSTREAM_MANIFEST_URL)
|
|
parser.add_argument("-a", "--upstream-manifest-branch",
|
|
help="upstream manifest branch",
|
|
default=DEFAULT_UPSTREAM_MANIFEST_BRANCH)
|
|
parser.add_argument("-e", "--exclusions-file",
|
|
help="exclusions file",
|
|
default=DEFAULT_EXCLUSIONS_FILE)
|
|
parser.add_argument("-t", "--tag",
|
|
help="release tag (optional). If not set then will"
|
|
"sync the latest in the branch.")
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def repo_init(url, rev, workspace):
|
|
"""Repo init with specific url and rev.
|
|
|
|
Args:
|
|
url: manifest url
|
|
rev: manifest branch, or rev
|
|
workspace: the folder to init and sync code
|
|
"""
|
|
|
|
print("repo init:\n url: %s\n rev: %s\n workspace: %s" %
|
|
(url, rev, workspace))
|
|
|
|
subprocess.check_output("repo init --manifest-url=%s --manifest-branch=%s" %
|
|
(url, rev), cwd=workspace, shell=True)
|
|
|
|
|
|
def repo_sync(workspace, retry=5):
|
|
"""Repo sync."""
|
|
|
|
count = 0
|
|
while count < retry:
|
|
count += 1
|
|
print("repo sync (retry=%d/%d):\n workspace: %s" %
|
|
(count, retry, workspace))
|
|
|
|
try:
|
|
subprocess.check_output(("repo sync --jobs=24 --current-branch --quiet "
|
|
"--no-tags --no-clone-bundle"),
|
|
cwd=workspace, shell=True)
|
|
except subprocess.CalledProcessError as e:
|
|
print "Error: %s" % e.output
|
|
# Stop retrying if the repo sync was successful
|
|
else:
|
|
break
|
|
|
|
|
|
def get_commit_with_keyword(project_path, keyword):
|
|
"""Get the latest commit in $project_path with the specific keyword."""
|
|
|
|
return subprocess.check_output(("git -C %s "
|
|
"rev-list --max-count=1 --grep=\"%s\" "
|
|
"HEAD") %
|
|
(project_path, keyword), shell=True).rstrip()
|
|
|
|
|
|
def get_build_id(workspace):
|
|
"""Get BUILD_ID defined in $workspace/build/core/build_id.mk."""
|
|
|
|
path = os.path.join(workspace, "build", "core", "build_id.mk")
|
|
return subprocess.check_output("source %s && echo $BUILD_ID" % path,
|
|
shell=True).rstrip()
|
|
|
|
|
|
def repo_sync_specific_release(url, branch, tag, workspace):
|
|
"""Repo sync source with the specific release tag."""
|
|
|
|
if not os.path.exists(workspace):
|
|
os.makedirs(workspace)
|
|
|
|
manifest_path = os.path.join(workspace, ".repo", "manifests")
|
|
|
|
repo_init(url, branch, workspace)
|
|
if tag:
|
|
rev = get_commit_with_keyword(manifest_path, tag)
|
|
if not rev:
|
|
raise(ValueError("could not find a manifest revision for tag " + tag))
|
|
repo_init(url, rev, workspace)
|
|
repo_sync(workspace)
|
|
|
|
|
|
def diff(manifest_url, manifest_branch, tag, upstream_manifest_url,
|
|
upstream_manifest_branch, exclusions_file):
|
|
"""Syncs and diffs an Android workspace against an upstream workspace."""
|
|
|
|
workspace = os.path.abspath(DOWNSTREAM_WORKSPACE)
|
|
upstream_workspace = os.path.abspath(UPSTREAM_WORKSPACE)
|
|
# repo sync downstream source tree
|
|
repo_sync_specific_release(
|
|
manifest_url,
|
|
manifest_branch,
|
|
tag,
|
|
workspace)
|
|
|
|
build_id = None
|
|
if tag:
|
|
# get the build_id so that we know which rev of upstream we need
|
|
build_id = get_build_id(workspace)
|
|
if not build_id:
|
|
raise(ValueError("Error: could not find the Build ID of " + workspace))
|
|
|
|
# repo sync upstream source tree
|
|
repo_sync_specific_release(
|
|
upstream_manifest_url,
|
|
upstream_manifest_branch,
|
|
build_id,
|
|
upstream_workspace)
|
|
|
|
# do the comparison
|
|
repo_diff_downstream.diff(
|
|
upstream_workspace,
|
|
workspace,
|
|
os.path.abspath("project.csv"),
|
|
os.path.abspath("commit.csv"),
|
|
os.path.abspath(exclusions_file),
|
|
)
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
|
|
diff(args.manifest_url, args.manifest_branch, args.tag,
|
|
args.upstream_manifest_url, args.upstream_manifest_branch,
|
|
args.exclusions_file)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|