diff options
author | Steve Block <steveblock@google.com> | 2010-07-08 12:51:48 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-07-09 15:33:40 +0100 |
commit | ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24 (patch) | |
tree | bb45155550ec013adc0ad10f4d7d354c6469b022 /WebKitTools/Scripts/webkitpy/common | |
parent | d4b24d9a829ed7de70381c8b99fb75a07ab40466 (diff) | |
download | external_webkit-ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24.zip external_webkit-ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24.tar.gz external_webkit-ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24.tar.bz2 |
Merge WebKit at r62496: Initial merge by git
Change-Id: Ie3da0770eca22a70a632e3571f31cfabc80facb2
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/common')
-rw-r--r-- | WebKitTools/Scripts/webkitpy/common/checkout/scm.py | 161 | ||||
-rw-r--r-- | WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py | 108 |
2 files changed, 234 insertions, 35 deletions
diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py index fc4c6fd..d7c621c 100644 --- a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py +++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py @@ -31,6 +31,8 @@ import os import re +import sys +import shutil from webkitpy.common.system.executive import Executive, run_command, ScriptError from webkitpy.common.system.user import User @@ -166,82 +168,95 @@ class SCM: return match.group('svn_revision') @staticmethod + def _subclass_must_implement(): + raise NotImplementedError("subclasses must implement") + + @staticmethod def in_working_directory(path): - raise NotImplementedError, "subclasses must implement" + SCM._subclass_must_implement() @staticmethod def find_checkout_root(path): - raise NotImplementedError, "subclasses must implement" + SCM._subclass_must_implement() @staticmethod def commit_success_regexp(): - raise NotImplementedError, "subclasses must implement" + SCM._subclass_must_implement() def working_directory_is_clean(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def clean_working_directory(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def status_command(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() - def add(self, path): - raise NotImplementedError, "subclasses must implement" + def add(self, path, return_exit_code=False): + self._subclass_must_implement() + + def delete(self, path): + self._subclass_must_implement() def changed_files(self, git_commit=None, squash=None): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def changed_files_for_revision(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def added_files(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def conflicted_files(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def display_name(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def create_patch(self, git_commit=None, squash=None): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def committer_email_for_revision(self, revision): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def contents_at_revision(self, path, revision): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def diff_for_revision(self, revision): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() + + def diff_for_file(self, path, log=None): + self._subclass_must_implement() + + def show_head(self, path): + self._subclass_must_implement() def apply_reverse_diff(self, revision): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def revert_files(self, file_paths): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def should_squash(self, squash): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def commit_with_message(self, message, username=None, git_commit=None, squash=None): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def svn_commit_log(self, svn_revision): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() def last_svn_commit_log(self): - raise NotImplementedError, "subclasses must implement" + self._subclass_must_implement() # Subclasses must indicate if they support local commits, # but the SCM baseclass will only call local_commits methods when this is true. @staticmethod def supports_local_commits(): - raise NotImplementedError, "subclasses must implement" + SCM._subclass_must_implement() def remote_merge_base(): - raise NotImplementedError, "subclasses must implement" + SCM._subclass_must_implement() def commit_locally_with_message(self, message): error("Your source control manager does not support local commits.") @@ -261,7 +276,8 @@ class SVN(SCM): def __init__(self, cwd): SCM.__init__(self, cwd) self.cached_version = None - + self._bogus_dir = None + @staticmethod def in_working_directory(path): return os.path.isdir(os.path.join(path, '.svn')) @@ -343,9 +359,23 @@ class SVN(SCM): field_count = 6 if self.svn_version() > "1.6" else 5 return "^(?P<status>[%s]).{%s} (?P<filename>.+)$" % (expected_types, field_count) - def add(self, path): - # path is assumed to be cwd relative? - self.run(["svn", "add", path]) + def _add_parent_directories(self, path): + """Does 'svn add' to the path and its parents.""" + if self.in_working_directory(path): + return + dirname = os.path.dirname(path) + # We have dirname directry - ensure it added. + if dirname != path: + self._add_parent_directories(dirname) + self.add(path) + + def add(self, path, return_exit_code=False): + self._add_parent_directories(os.path.dirname(os.path.abspath(path))) + return self.run(["svn", "add", path], return_exit_code=return_exit_code) + + def delete(self, path): + parent, base = os.path.split(os.path.abspath(path)) + return self.run(["svn", "delete", "--force", base], cwd=parent) def changed_files(self, git_commit=None, squash=None): return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("ACDMR")) @@ -362,6 +392,9 @@ class SVN(SCM): def added_files(self): return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("A")) + def deleted_files(self): + return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("D")) + @staticmethod def supports_local_commits(): return False @@ -391,6 +424,44 @@ class SVN(SCM): # FIXME: This should probably use cwd=self.checkout_root return self.run(['svn', 'diff', '-c', revision]) + def _bogus_dir_name(self): + if sys.platform.startswith("win"): + parent_dir = tempfile.gettempdir() + else: + parent_dir = sys.path[0] # tempdir is not secure. + return os.path.join(parent_dir, "temp_svn_config") + + def _setup_bogus_dir(self, log): + self._bogus_dir = self._bogus_dir_name() + if not os.path.exists(self._bogus_dir): + os.mkdir(self._bogus_dir) + self._delete_bogus_dir = True + else: + self._delete_bogus_dir = False + if log: + log.debug(' Html: temp config dir: "%s".', self._bogus_dir) + + def _teardown_bogus_dir(self, log): + if self._delete_bogus_dir: + shutil.rmtree(self._bogus_dir, True) + if log: + log.debug(' Html: removed temp config dir: "%s".', self._bogus_dir) + self._bogus_dir = None + + def diff_for_file(self, path, log=None): + self._setup_bogus_dir(log) + try: + args = ['svn', 'diff'] + if self._bogus_dir: + args += ['--config-dir', self._bogus_dir] + args.append(path) + return self.run(args) + finally: + self._teardown_bogus_dir(log) + + def show_head(self, path): + return self.run(['svn', 'cat', '-r', 'BASE', path], decode_output=False) + def _repository_url(self): return self.value_from_svn_info(self.checkout_root, 'URL') @@ -435,6 +506,14 @@ class SVN(SCM): # http://svnbook.red-bean.com/en/1.0/ch03s03.html return self.svn_commit_log('BASE') + def propset(self, pname, pvalue, path): + dir, base = os.path.split(path) + return self.run(['svn', 'pset', pname, pvalue, base], cwd=dir) + + def propget(self, pname, path): + dir, base = os.path.split(path) + return self.run(['svn', 'pget', pname, base], cwd=dir).encode('utf-8').rstrip("\n") + # All git-specific logic should go here. class Git(SCM): def __init__(self, cwd): @@ -447,13 +526,18 @@ class Git(SCM): @classmethod def find_checkout_root(cls, path): # "git rev-parse --show-cdup" would be another way to get to the root - (checkout_root, dot_git) = os.path.split(run_command(['git', 'rev-parse', '--git-dir'], cwd=path)) + (checkout_root, dot_git) = os.path.split(run_command(['git', 'rev-parse', '--git-dir'], cwd=(path or "./"))) # If we were using 2.6 # checkout_root = os.path.relpath(checkout_root, path) if not os.path.isabs(checkout_root): # Sometimes git returns relative paths checkout_root = os.path.join(path, checkout_root) return checkout_root @classmethod + def to_object_name(cls, filepath): + root_end_with_slash = os.path.join(cls.find_checkout_root(os.path.dirname(filepath)), '') + return filepath.replace(root_end_with_slash, '') + + @classmethod def read_git_config(cls, key): # FIXME: This should probably use cwd=self.checkout_root. return run_command(["git", "config", key], @@ -494,9 +578,11 @@ class Git(SCM): def _status_regexp(self, expected_types): return '^(?P<status>[%s])\t(?P<filename>.+)$' % expected_types - def add(self, path): - # path is assumed to be cwd relative? - self.run(["git", "add", path]) + def add(self, path, return_exit_code=False): + return self.run(["git", "add", path], return_exit_code=return_exit_code) + + def delete(self, path): + return self.run(["git", "rm", "-f", path]) def _merge_base(self, git_commit, squash): if git_commit: @@ -537,6 +623,9 @@ class Git(SCM): def added_files(self): return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("A")) + def deleted_files(self): + return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("D")) + @staticmethod def supports_local_commits(): return True @@ -569,6 +658,12 @@ class Git(SCM): git_commit = self.git_commit_from_svn_revision(revision) return self.create_patch(git_commit) + def diff_for_file(self, path, log=None): + return self.run(['git', 'diff', 'HEAD', '--', path]) + + def show_head(self, path): + return self.run(['git', 'show', 'HEAD:' + self.to_object_name(path)], decode_output=False) + def committer_email_for_revision(self, revision): git_commit = self.git_commit_from_svn_revision(revision) committer_email = self.run(["git", "log", "-1", "--pretty=format:%ce", git_commit]) diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py index 36a1d1c..eaa3b46 100644 --- a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py +++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py @@ -40,6 +40,7 @@ import subprocess import tempfile import unittest import urllib +import shutil from datetime import date from webkitpy.common.checkout.api import Checkout @@ -63,8 +64,12 @@ def run_silent(args, cwd=None): def write_into_file_at_path(file_path, contents, encoding="utf-8"): - with codecs.open(file_path, "w", encoding) as file: - file.write(contents) + if encoding: + with codecs.open(file_path, "w", encoding) as file: + file.write(contents) + else: + with open(file_path, "w") as file: + file.write(contents) def read_from_path(file_path, encoding="utf-8"): @@ -388,6 +393,11 @@ OcmYex&reD$;sO8*F9L)B # Cannot delete again. self.assertRaises(ScriptError, self.checkout.apply_patch, self._create_patch(git_binary_deletion)) + def _shared_test_add_recursively(self): + os.mkdir("added_dir") + write_into_file_at_path("added_dir/added_file", "new stuff") + self.scm.add("added_dir/added_file") + self.assertTrue("added_dir/added_file" in self.scm.added_files()) class SVNTest(SCMTest): @@ -632,6 +642,60 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== def test_committer_email_for_revision(self): self._shared_test_committer_email_for_revision() + def test_add_recursively(self): + self._shared_test_add_recursively() + + def test_delete(self): + os.chdir(self.svn_checkout_path) + self.scm.delete("test_file") + self.assertTrue("test_file" in self.scm.deleted_files()) + + def test_propset_propget(self): + filepath = os.path.join(self.svn_checkout_path, "test_file") + expected_mime_type = "x-application/foo-bar" + self.scm.propset("svn:mime-type", expected_mime_type, filepath) + self.assertEqual(expected_mime_type, self.scm.propget("svn:mime-type", filepath)) + + def test_show_head(self): + write_into_file_at_path("test_file", u"Hello!", "utf-8") + SVNTestRepository._svn_commit("fourth commit") + self.assertEqual("Hello!", self.scm.show_head('test_file')) + + def test_show_head_binary(self): + data = "\244" + write_into_file_at_path("binary_file", data, encoding=None) + self.scm.add("binary_file") + self.scm.commit_with_message("a test commit") + self.assertEqual(data, self.scm.show_head('binary_file')) + + def do_test_diff_for_file(self): + write_into_file_at_path('test_file', 'some content') + self.scm.commit_with_message("a test commit") + diff = self.scm.diff_for_file('test_file') + self.assertEqual(diff, "") + + write_into_file_at_path("test_file", "changed content") + diff = self.scm.diff_for_file('test_file') + self.assertTrue("-some content" in diff) + self.assertTrue("+changed content" in diff) + + def clean_bogus_dir(self): + self.bogus_dir = self.scm._bogus_dir_name() + if os.path.exists(self.bogus_dir): + shutil.rmtree(self.bogus_dir) + + def test_diff_for_file_with_existing_bogus_dir(self): + self.clean_bogus_dir() + os.mkdir(self.bogus_dir) + self.do_test_diff_for_file() + self.assertTrue(os.path.exists(self.bogus_dir)) + shutil.rmtree(self.bogus_dir) + + def test_diff_for_file_with_missing_bogus_dir(self): + self.clean_bogus_dir() + self.do_test_diff_for_file() + self.assertFalse(os.path.exists(self.bogus_dir)) + class GitTest(SCMTest): @@ -1098,6 +1162,46 @@ class GitSVNTest(SCMTest): def test_committer_email_for_revision(self): self._shared_test_committer_email_for_revision() + def test_add_recursively(self): + self._shared_test_add_recursively() + + def test_delete(self): + self._two_local_commits() + self.scm.delete('test_file_commit1') + self.assertTrue("test_file_commit1" in self.scm.deleted_files()) + + def test_to_object_name(self): + relpath = 'test_file_commit1' + fullpath = os.path.join(self.git_checkout_path, relpath) + self._two_local_commits() + self.assertEqual(relpath, self.scm.to_object_name(fullpath)) + + def test_show_head(self): + self._two_local_commits() + self.assertEqual("more test content", self.scm.show_head('test_file_commit1')) + + def test_show_head_binary(self): + self._two_local_commits() + data = "\244" + write_into_file_at_path("binary_file", data, encoding=None) + self.scm.add("binary_file") + self.scm.commit_locally_with_message("a test commit") + self.assertEqual(data, self.scm.show_head('binary_file')) + + def test_diff_for_file(self): + self._two_local_commits() + write_into_file_at_path('test_file_commit1', "Updated", encoding=None) + + diff = self.scm.diff_for_file('test_file_commit1') + cached_diff = self.scm.diff_for_file('test_file_commit1') + self.assertTrue("+Updated" in diff) + self.assertTrue("-more test content" in diff) + + self.scm.add('test_file_commit1') + + cached_diff = self.scm.diff_for_file('test_file_commit1') + self.assertTrue("+Updated" in cached_diff) + self.assertTrue("-more test content" in cached_diff) if __name__ == '__main__': unittest.main() |