OLD | NEW |
| (Empty) |
1 # Copyright (c) 2009, Google Inc. All rights reserved. | |
2 # Copyright (c) 2009 Apple Inc. All rights reserved. | |
3 # | |
4 # Redistribution and use in source and binary forms, with or without | |
5 # modification, are permitted provided that the following conditions are | |
6 # met: | |
7 # | |
8 # * Redistributions of source code must retain the above copyright | |
9 # notice, this list of conditions and the following disclaimer. | |
10 # * Redistributions in binary form must reproduce the above | |
11 # copyright notice, this list of conditions and the following disclaimer | |
12 # in the documentation and/or other materials provided with the | |
13 # distribution. | |
14 # * Neither the name of Google Inc. nor the names of its | |
15 # contributors may be used to endorse or promote products derived from | |
16 # this software without specific prior written permission. | |
17 # | |
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 # | |
30 # Python module for interacting with an SCM system (like SVN or Git) | |
31 | |
32 import logging | |
33 import re | |
34 import sys | |
35 | |
36 from webkitpy.common.system.executive import Executive | |
37 from webkitpy.common.system.filesystem import FileSystem | |
38 | |
39 _log = logging.getLogger(__name__) | |
40 | |
41 | |
42 # SCM methods are expected to return paths relative to self.checkout_root. | |
43 class SCM: | |
44 | |
45 # Arguments are generally unused in abstract base methods below. | |
46 # pylint: disable=unused-argument | |
47 | |
48 def __init__(self, cwd, executive=None, filesystem=None): | |
49 self.cwd = cwd | |
50 self._executive = executive or Executive() | |
51 self._filesystem = filesystem or FileSystem() | |
52 self.checkout_root = self.find_checkout_root(self.cwd) | |
53 | |
54 # A wrapper used by subclasses to create processes. | |
55 def _run(self, | |
56 args, | |
57 cwd=None, | |
58 # pylint: disable=redefined-builtin | |
59 input=None, | |
60 timeout_seconds=None, | |
61 error_handler=None, | |
62 return_exit_code=False, | |
63 return_stderr=True, | |
64 decode_output=True): | |
65 # FIXME: We should set cwd appropriately. | |
66 return self._executive.run_command(args, | |
67 cwd=cwd, | |
68 input=input, | |
69 timeout_seconds=timeout_seconds, | |
70 error_handler=error_handler, | |
71 return_exit_code=return_exit_code, | |
72 return_stderr=return_stderr, | |
73 decode_output=decode_output) | |
74 | |
75 # SCM always returns repository relative path, but sometimes we need | |
76 # absolute paths to pass to rm, etc. | |
77 def absolute_path(self, repository_relative_path): | |
78 return self._filesystem.join(self.checkout_root, repository_relative_pat
h) | |
79 | |
80 def _run_status_and_extract_filenames(self, status_command, status_regexp): | |
81 filenames = [] | |
82 # We run with cwd=self.checkout_root so that returned-paths are root-rel
ative. | |
83 for line in self._run(status_command, cwd=self.checkout_root).splitlines
(): | |
84 match = re.search(status_regexp, line) | |
85 if not match: | |
86 continue | |
87 # status = match.group('status') | |
88 filename = match.group('filename') | |
89 filenames.append(filename) | |
90 return filenames | |
91 | |
92 @staticmethod | |
93 def _subclass_must_implement(): | |
94 raise NotImplementedError("subclasses must implement") | |
95 | |
96 @classmethod | |
97 def in_working_directory(cls, path, executive=None): | |
98 SCM._subclass_must_implement() | |
99 | |
100 def find_checkout_root(self, path): | |
101 SCM._subclass_must_implement() | |
102 | |
103 def add_all(self, pathspec=None): | |
104 self._subclass_must_implement() | |
105 | |
106 def add(self, path, return_exit_code=False, recurse=True): | |
107 self.add_list([path], return_exit_code, recurse) | |
108 | |
109 def add_list(self, paths, return_exit_code=False, recurse=True): | |
110 self._subclass_must_implement() | |
111 | |
112 def delete(self, path): | |
113 self.delete_list([path]) | |
114 | |
115 def delete_list(self, paths): | |
116 self._subclass_must_implement() | |
117 | |
118 def move(self, origin, destination): | |
119 self._subclass_must_implement() | |
120 | |
121 def exists(self, path): | |
122 self._subclass_must_implement() | |
123 | |
124 def unstaged_changes(self): | |
125 self._subclass_must_implement() | |
126 | |
127 def changed_files(self, git_commit=None): | |
128 self._subclass_must_implement() | |
129 | |
130 def _added_files(self): | |
131 self._subclass_must_implement() | |
132 | |
133 def _deleted_files(self): | |
134 self._subclass_must_implement() | |
135 | |
136 def display_name(self): | |
137 self._subclass_must_implement() | |
138 | |
139 def commit_position(self, path): | |
140 """Returns the latest chromium commit position found in the checkout.""" | |
141 self._subclass_must_implement() | |
142 | |
143 def timestamp_of_revision(self, path, revision): | |
144 self._subclass_must_implement() | |
145 | |
146 def blame(self, path): | |
147 self._subclass_must_implement() | |
148 | |
149 def has_working_directory_changes(self, pathspec=None): | |
150 self._subclass_must_implement() | |
151 | |
152 #-------------------------------------------------------------------------- | |
153 # Subclasses must indicate if they support local commits, | |
154 # but the SCM baseclass will only call local_commits methods when this is tr
ue. | |
155 @staticmethod | |
156 def supports_local_commits(): | |
157 SCM._subclass_must_implement() | |
158 | |
159 def commit_locally_with_message(self, message): | |
160 _log.error("Your source control manager does not support local commits."
) | |
161 sys.exit(1) | |
OLD | NEW |