Diff
Modified: trunk/Tools/ChangeLog (269890 => 269891)
--- trunk/Tools/ChangeLog 2020-11-17 03:05:46 UTC (rev 269890)
+++ trunk/Tools/ChangeLog 2020-11-17 03:15:47 UTC (rev 269891)
@@ -1,3 +1,43 @@
+2020-11-16 Jonathan Bedard <[email protected]>
+
+ [webkitscmpy] Generalize parts of local.Scm class
+ https://bugs.webkit.org/show_bug.cgi?id=218935
+ <rdar://problem/71395688>
+
+ Rubber-stamped by Aakash Jain.
+
+ * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Bump version.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py:
+ (Scm):
+ (Scm.Exception): Moved to ScmBase.
+ (Scm.__init__): Move branches logic to ScmBase.
+ (Scm.is_svn): Moved to ScmBase.
+ (Scm.is_git): Ditto.
+ (Scm.default_branch): Ditto.
+ (Scm.branches): Ditto.
+ (Scm.tags): Ditto.
+ (Scm.find): Ditto.
+ (Scm.commit): Ditto.
+ (Scm.prioritize_branches): Ditto.
+ (Scm.log): Ditto.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py:
+ (Svn.commit): Passing branch to self.info is redundant.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/__init__.py:
+ * Scripts/libraries/webkitscmpy/webkitscmpy/scm_base.py: Added.
+ (ScmBase): Base class for all local and remote Scm objects.
+ (ScmBase.Exception): Moved from local.Scm.
+ (ScmBase.__init__): Ditto.
+ (ScmBase.is_svn): Ditto.
+ (ScmBase.is_git): Ditto.
+ (ScmBase.default_branch): Ditto.
+ (ScmBase.branches): Ditto.
+ (ScmBase.tags): Ditto.
+ (ScmBase.commit): Ditto.
+ (ScmBase.prioritize_branches): Ditto.
+ (ScmBase.find): Ditto.
+ (ScmBase.log): Ditto.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/test/svn_unittest.py:
+
2020-11-16 Ling Ho <[email protected]>
Updated contributors.json to remove inactive committers and reviewers.
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (269890 => 269891)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2020-11-17 03:05:46 UTC (rev 269890)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2020-11-17 03:15:47 UTC (rev 269891)
@@ -46,12 +46,13 @@
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
)
-version = Version(0, 3, 0)
+version = Version(0, 3, 1)
AutoInstall.register(Package('dateutil', Version(2, 8, 1), pypi_name='python-dateutil'))
from webkitscmpy.contributor import Contributor
from webkitscmpy.commit import Commit
+from webkitscmpy.scm_base import ScmBase
from webkitscmpy import local
from webkitscmpy import mocks
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py (269890 => 269891)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py 2020-11-17 03:05:46 UTC (rev 269890)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py 2020-11-17 03:15:47 UTC (rev 269891)
@@ -21,21 +21,15 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import logging
import os
import re
import six
-import sys
-from logging import NullHandler
from webkitcorepy import run
-from webkitscmpy import log, Commit
+from webkitscmpy import ScmBase
-class Scm(object):
- class Exception(RuntimeError):
- pass
-
+class Scm(ScmBase):
# Projects can define for themselves what constitutes a development vs a production branch,
# the following idioms seem common enough to be shared.
DEV_BRANCHES = re.compile(r'.*[(eng)(dev)(bug)]/.+')
@@ -64,113 +58,22 @@
raise OSError("'{}' is not a known SCM type".format(path))
def __init__(self, path, dev_branches=None, prod_branches=None):
- if not isinstance(path, str):
- raise ValueError('')
+ super(Scm, self).__init__(dev_branches=dev_branches, prod_branches=prod_branches)
+
+ if not isinstance(path, six.string_types):
+ raise ValueError("Expected 'path' to be a string type, not '{}'".format(type(path)))
self.path = path
- self.dev_branches = dev_branches or self.DEV_BRANCHES
- self.prod_branches = prod_branches or self.PROD_BRANCHES
-
@property
- def is_svn(self):
- return False
-
- @property
- def is_git(self):
- return False
-
- @property
def root_path(self):
raise NotImplementedError()
@property
- def default_branch(self):
- raise NotImplementedError()
-
- @property
def branch(self):
raise NotImplementedError()
- @property
- def branches(self):
- raise NotImplementedError()
-
- @property
- def tags(self):
- raise NotImplementedError()
-
def remote(self, name=None):
raise NotImplementedError()
- def find(self, argument):
- if not isinstance(argument, six.string_types):
- raise ValueError("Expected 'argument' to be a string, not '{}'".format(type(argument)))
-
- offset = 0
- if '~' in argument:
- for s in argument.split('~')[1:]:
- if s and not s.isdigit():
- raise ValueError("'{}' is not a valid argument to Scm.find()".format(argument))
- offset += int(s) if s else 1
- argument = argument.split('~')[0]
-
- if argument == 'HEAD':
- result = self.commit()
-
- elif argument in self.branches:
- result = self.commit(branch=argument)
-
- elif argument in self.tags:
- result = self.commit(tag=argument)
-
- else:
- if offset:
- raise ValueError("'~' offsets are not supported for revisions and identifiers")
-
- parsed_commit = Commit.parse(argument)
- return self.commit(
- hash=parsed_commit.hash,
- revision=parsed_commit.revision,
- identifier=parsed_commit.identifier,
- branch=parsed_commit.branch,
- )
-
- if not offset:
- return result
-
- return self.commit(
- identifier=result.identifier - offset,
- branch=result.branch,
- )
-
def checkout(self, argument):
raise NotImplementedError()
-
- def commit(self, hash=None, revision=None, identifier=None, branch=None, tag=None):
- raise NotImplementedError()
-
- def prioritize_branches(self, branches):
- if len(branches) == 1:
- return branches[0]
-
- default_branch = self.default_branch
- if default_branch in branches:
- return default_branch
-
- # We don't have enough information to determine a branch. We will attempt to first use the branch specified
- # by the caller, then the one then checkout is currently on. If both those fail, we will pick one of the
- # other branches. We prefer production branches first, then any branch which isn't explicitly labeled a
- # dev branch. We then sort the list of candidate branches and pick the smallest
- filtered_candidates = [candidate for candidate in branches if self.prod_branches.match(candidate)]
- if not filtered_candidates:
- filtered_candidates = [candidate for candidate in branches if not self.dev_branches.match(candidate)]
- if not filtered_candidates:
- filtered_candidates = branches
- return sorted(filtered_candidates)[0]
-
- @classmethod
- def log(cls, message, level=logging.WARNING):
- if not log.handlers or all([isinstance(handle, NullHandler) for handle in log.handlers]):
- sys.stderr.write(message + '\n')
- else:
- log.log(level, message)
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py (269890 => 269891)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py 2020-11-17 03:05:46 UTC (rev 269890)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py 2020-11-17 03:15:47 UTC (rev 269891)
@@ -311,7 +311,7 @@
raise ValueError('Cannot define both tag and revision')
revision = Commit._parse_revision(revision, do_assert=True)
branch = self._branch_for(revision)
- info = self.info(cached=True, branch=branch, revision=revision)
+ info = self.info(cached=True, revision=revision)
else:
if branch and tag:
Copied: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/scm_base.py (from rev 269890, trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py) (0 => 269891)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/scm_base.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/scm_base.py 2020-11-17 03:15:47 UTC (rev 269891)
@@ -0,0 +1,134 @@
+# Copyright (C) 2020 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import re
+import six
+import sys
+
+from logging import NullHandler
+from webkitscmpy import Commit, log
+
+
+class ScmBase(object):
+ class Exception(RuntimeError):
+ pass
+
+ # Projects can define for themselves what constitutes a development vs a production branch,
+ # the following idioms seem common enough to be shared.
+ DEV_BRANCHES = re.compile(r'.*[(eng)(dev)(bug)]/.+')
+ PROD_BRANCHES = re.compile(r'\S+-[\d+\.]+-branch')
+
+ def __init__(self, dev_branches=None, prod_branches=None):
+ self.dev_branches = dev_branches or self.DEV_BRANCHES
+ self.prod_branches = prod_branches or self.PROD_BRANCHES
+ self.path = None
+
+ @property
+ def is_svn(self):
+ return False
+
+ @property
+ def is_git(self):
+ return False
+
+ @property
+ def default_branch(self):
+ raise NotImplementedError()
+
+ @property
+ def branches(self):
+ raise NotImplementedError()
+
+ @property
+ def tags(self):
+ raise NotImplementedError()
+
+ def commit(self, hash=None, revision=None, identifier=None, branch=None, tag=None):
+ raise NotImplementedError()
+
+ def prioritize_branches(self, branches):
+ if len(branches) == 1:
+ return branches[0]
+
+ default_branch = self.default_branch
+ if default_branch in branches:
+ return default_branch
+
+ # We don't have enough information to determine a branch. We will attempt to first use the branch specified
+ # by the caller, then the one then checkout is currently on. If both those fail, we will pick one of the
+ # other branches. We prefer production branches first, then any branch which isn't explicitly labeled a
+ # dev branch. We then sort the list of candidate branches and pick the smallest
+ filtered_candidates = [candidate for candidate in branches if self.prod_branches.match(candidate)]
+ if not filtered_candidates:
+ filtered_candidates = [candidate for candidate in branches if not self.dev_branches.match(candidate)]
+ if not filtered_candidates:
+ filtered_candidates = branches
+ return sorted(filtered_candidates)[0]
+
+ def find(self, argument):
+ if not isinstance(argument, six.string_types):
+ raise ValueError("Expected 'argument' to be a string, not '{}'".format(type(argument)))
+
+ offset = 0
+ if '~' in argument:
+ for s in argument.split('~')[1:]:
+ if s and not s.isdigit():
+ raise ValueError("'{}' is not a valid argument to Scm.find()".format(argument))
+ offset += int(s) if s else 1
+ argument = argument.split('~')[0]
+
+ if argument == 'HEAD':
+ result = self.commit()
+
+ elif argument in self.branches:
+ result = self.commit(branch=argument)
+
+ elif argument in self.tags:
+ result = self.commit(tag=argument)
+
+ else:
+ if offset:
+ raise ValueError("'~' offsets are not supported for revisions and identifiers")
+
+ parsed_commit = Commit.parse(argument)
+ return self.commit(
+ hash=parsed_commit.hash,
+ revision=parsed_commit.revision,
+ identifier=parsed_commit.identifier,
+ branch=parsed_commit.branch,
+ )
+
+ if not offset:
+ return result
+
+ return self.commit(
+ identifier=result.identifier - offset,
+ branch=result.branch,
+ )
+
+ @classmethod
+ def log(cls, message, level=logging.WARNING):
+ if not log.handlers or all([isinstance(handle, NullHandler) for handle in log.handlers]):
+ sys.stderr.write(message + '\n')
+ else:
+ log.log(level, message)