Skip to content
Snippets Groups Projects
Commit 4d76d7ff authored by Haibo Huang's avatar Haibo Huang Committed by android-build-merger
Browse files

Merge "[Updater] Prefer url similar to previous one"

am: 70480f5a

Change-Id: I3935274771feb2a25f9e7b6cca46f93927ac4365
parents 26ec9bd8 70480f5a
No related branches found
No related tags found
No related merge requests found
...@@ -15,10 +15,24 @@ ...@@ -15,10 +15,24 @@
python_binary_host { python_binary_host {
name: "external_updater", name: "external_updater",
main: "external_updater.py", main: "external_updater.py",
srcs: [
"external_updater.py",
],
libs: [
"external_updater_lib",
],
}
python_library_host {
name: "external_updater_lib",
srcs: [ srcs: [
"*.py", "*.py",
"metadata.proto", "metadata.proto",
], ],
exclude_srcs: [
"*_test.py",
"external_updater.py",
],
libs: [ libs: [
"python-symbol", "python-symbol",
"libprotobuf-python", "libprotobuf-python",
...@@ -41,3 +55,13 @@ python_binary_host { ...@@ -41,3 +55,13 @@ python_binary_host {
}, },
} }
python_test_host {
name: "external_updater_test",
main: "external_updater_test.py",
srcs: [
"external_updater_test.py",
],
libs: [
"external_updater_lib",
],
}
# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for external updater."""
import unittest
import github_archive_updater
class ExternalUpdaterTest(unittest.TestCase):
"""Unit tests for external updater."""
def test_url_selection(self):
"""Tests that GithubArchiveUpdater can choose the right url."""
prefix = "https://github.com/author/project/"
urls = [
prefix + "releases/download/ver-1.0/ver-1.0-binary.zip",
prefix + "releases/download/ver-1.0/ver-1.0-binary.tar.gz",
prefix + "releases/download/ver-1.0/ver-1.0-src.zip",
prefix + "releases/download/ver-1.0/ver-1.0-src.tar.gz",
prefix + "archive/ver-1.0.zip",
prefix + "archive/ver-1.0.tar.gz",
]
previous_url = prefix + "releases/download/ver-0.9/ver-0.9-src.tar.gz"
url = github_archive_updater.choose_best_url(urls, previous_url)
expected_url = prefix + "releases/download/ver-1.0/ver-1.0-src.tar.gz"
self.assertEqual(url, expected_url)
previous_url = prefix + "archive/ver-0.9.zip"
url = github_archive_updater.choose_best_url(urls, previous_url)
expected_url = prefix + "archive/ver-1.0.zip"
self.assertEqual(url, expected_url)
if __name__ == '__main__':
unittest.main()
...@@ -22,6 +22,7 @@ def _run(cmd, cwd): ...@@ -22,6 +22,7 @@ def _run(cmd, cwd):
return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=True, cwd=cwd) check=True, cwd=cwd)
def fetch(proj_path, remote_names): def fetch(proj_path, remote_names):
"""Runs git fetch. """Runs git fetch.
...@@ -31,6 +32,7 @@ def fetch(proj_path, remote_names): ...@@ -31,6 +32,7 @@ def fetch(proj_path, remote_names):
""" """
_run(['git', 'fetch', '--multiple'] + remote_names, cwd=proj_path) _run(['git', 'fetch', '--multiple'] + remote_names, cwd=proj_path)
def add_remote(proj_path, name, url): def add_remote(proj_path, name, url):
"""Adds a git remote. """Adds a git remote.
...@@ -41,6 +43,7 @@ def add_remote(proj_path, name, url): ...@@ -41,6 +43,7 @@ def add_remote(proj_path, name, url):
""" """
_run(['git', 'remote', 'add', name, url], cwd=proj_path) _run(['git', 'remote', 'add', name, url], cwd=proj_path)
def list_remotes(proj_path): def list_remotes(proj_path):
"""Lists all Git remotes. """Lists all Git remotes.
...@@ -54,6 +57,7 @@ def list_remotes(proj_path): ...@@ -54,6 +57,7 @@ def list_remotes(proj_path):
lines = out.stdout.decode('utf-8').splitlines() lines = out.stdout.decode('utf-8').splitlines()
return dict([line.split()[0:2] for line in lines]) return dict([line.split()[0:2] for line in lines])
def get_commits_ahead(proj_path, branch, base_branch): def get_commits_ahead(proj_path, branch, base_branch):
"""Lists commits in `branch` but not `base_branch`.""" """Lists commits in `branch` but not `base_branch`."""
out = _run(['git', 'rev-list', '--left-only', out = _run(['git', 'rev-list', '--left-only',
...@@ -61,11 +65,13 @@ def get_commits_ahead(proj_path, branch, base_branch): ...@@ -61,11 +65,13 @@ def get_commits_ahead(proj_path, branch, base_branch):
proj_path) proj_path)
return out.stdout.decode('utf-8').splitlines() return out.stdout.decode('utf-8').splitlines()
def get_commit_time(proj_path, commit): def get_commit_time(proj_path, commit):
"""Gets commit time of one commit.""" """Gets commit time of one commit."""
out = _run(['git', 'show', '-s', '--format=%ct', commit], cwd=proj_path) out = _run(['git', 'show', '-s', '--format=%ct', commit], cwd=proj_path)
return datetime.datetime.fromtimestamp(int(out.stdout)) return datetime.datetime.fromtimestamp(int(out.stdout))
def list_remote_branches(proj_path, remote_name): def list_remote_branches(proj_path, remote_name):
"""Lists all branches for a remote.""" """Lists all branches for a remote."""
out = _run(['git', 'branch', '-r'], cwd=proj_path) out = _run(['git', 'branch', '-r'], cwd=proj_path)
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
import json import json
import re import re
import shutil
import urllib.request import urllib.request
import archive_utils import archive_utils
...@@ -29,6 +28,39 @@ GITHUB_URL_PATTERN = (r'^https:\/\/github.com\/([-\w]+)\/([-\w]+)\/' + ...@@ -29,6 +28,39 @@ GITHUB_URL_PATTERN = (r'^https:\/\/github.com\/([-\w]+)\/([-\w]+)\/' +
GITHUB_URL_RE = re.compile(GITHUB_URL_PATTERN) GITHUB_URL_RE = re.compile(GITHUB_URL_PATTERN)
def _edit_distance(str1, str2):
prev = list(range(0, len(str2) + 1))
for i, chr1 in enumerate(str1):
cur = [i + 1]
for j, chr2 in enumerate(str2):
if chr1 == chr2:
cur.append(prev[j])
else:
cur.append(min(prev[j + 1], prev[j], cur[j]) + 1)
prev = cur
return prev[len(str2)]
def choose_best_url(urls, previous_url):
"""Returns the best url to download from a list of candidate urls.
This function calculates similarity between previous url and each of new
urls. And returns the one best matches previous url.
Similarity is measured by editing distance.
Args:
urls: Array of candidate urls.
previous_url: String of the url used previously.
Returns:
One url from `urls`.
"""
return min(urls, default=None,
key=lambda url: _edit_distance(
url, previous_url))
class GithubArchiveUpdater(): class GithubArchiveUpdater():
"""Updater for archives from GitHub. """Updater for archives from GitHub.
...@@ -98,18 +130,18 @@ class GithubArchiveUpdater(): ...@@ -98,18 +130,18 @@ class GithubArchiveUpdater():
""" """
supported_assets = [ supported_assets = [
a for a in self.data['assets'] a['browser_download_url'] for a in self.data['assets']
if archive_utils.is_supported_archive(a['browser_download_url'])] if archive_utils.is_supported_archive(a['browser_download_url'])]
# Finds the minimum sized archive to download. # Adds source code urls.
minimum_asset = min( supported_assets.append(
supported_assets, key=lambda asset: asset['size'], default=None) 'https://github.com/{}/{}/archive/{}.tar.gz'.format(
if minimum_asset is not None: self.owner, self.repo, self.data.get('tag_name')))
latest_url = minimum_asset.get('browser_download_url') supported_assets.append(
else: 'https://github.com/{}/{}/archive/{}.zip'.format(
# Guess the tarball url for source code. self.owner, self.repo, self.data.get('tag_name')))
latest_url = 'https://github.com/{}/{}/archive/{}.tar.gz'.format(
self.owner, self.repo, self.data.get('tag_name')) latest_url = choose_best_url(supported_assets, self.old_url.value)
temporary_dir = None temporary_dir = None
try: try:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment