summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/common/checkout
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-07-08 12:51:48 +0100
committerSteve Block <steveblock@google.com>2010-07-09 15:33:40 +0100
commitca9cb53ed1119a3fd98fafa0972ffeb56dee1c24 (patch)
treebb45155550ec013adc0ad10f4d7d354c6469b022 /WebKitTools/Scripts/webkitpy/common/checkout
parentd4b24d9a829ed7de70381c8b99fb75a07ab40466 (diff)
downloadexternal_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/checkout')
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/scm.py161
-rw-r--r--WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py108
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()