From 4055a933203f69be0d7569b6b688ada878e05a99 Mon Sep 17 00:00:00 2001 From: Dustin Oprea Date: Sat, 1 Feb 2020 03:09:48 -0500 Subject: [PATCH 01/13] README.rst: Drop broken donate link --- svn/resources/README.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/svn/resources/README.rst b/svn/resources/README.rst index bb51e9c..396e1cc 100644 --- a/svn/resources/README.rst +++ b/svn/resources/README.rst @@ -1,5 +1,3 @@ -|donate| - |Build\_Status| |Coverage\_Status| @@ -280,9 +278,6 @@ diff(start_revision, end_revision) Finds all the diff between start and end revision id. Here another key of 'diff' is added which shows the diff of files. -.. |donate| image:: https://pledgie.com/campaigns/31718.png?skin_name=chrome - :alt: Click here to lend your support to: PySvn and make a donation at pledgie.com ! - :target: https://pledgie.com/campaigns/31718 .. |Build_Status| image:: https://travis-ci.org/dsoprea/PySvn.svg?branch=master :target: https://travis-ci.org/dsoprea/PySvn .. |Coverage_Status| image:: https://coveralls.io/repos/github/dsoprea/PySvn/badge.svg?branch=master From 362790134b9848b30cae7a7828662c61ac01ea72 Mon Sep 17 00:00:00 2001 From: Rohin Knight Date: Thu, 4 Apr 2019 16:24:31 +1300 Subject: [PATCH 02/13] Hide command prompt on Windows when running subprocess --- svn/common_base.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/svn/common_base.py b/svn/common_base.py index 5e3db98..dd16cd7 100644 --- a/svn/common_base.py +++ b/svn/common_base.py @@ -1,4 +1,5 @@ import os +import sys import subprocess import logging @@ -17,13 +18,22 @@ def external_command(self, cmd, success_code=0, do_combine=False, env['LANG'] = svn.config.CONSOLE_ENCODING env.update(environment) - p = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - cwd=wd, - env=env) - + kwargs = { + 'stdout': subprocess.PIPE, + 'stderr': subprocess.STDOUT, + 'cwd': wd, + 'env': env, + } + + try: + # Don't open Command Prompt on Windows + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + kwargs['startupinfo'] = startupinfo + except AttributeError: + pass + + p = subprocess.Popen(cmd, **kwargs) stdout = p.stdout.read() r = p.wait() p.stdout.close() From a94170d21bcf7df11c68949c189c326d654f01e8 Mon Sep 17 00:00:00 2001 From: hzsunshx Date: Tue, 18 Dec 2018 13:22:08 +0800 Subject: [PATCH 03/13] Add svn blame support Add new command and add test_blame test case. --- svn/common.py | 37 +++++++++++++++++++++++++++++++++++++ svn/common_base.py | 1 + svn/resources/README.rst | 19 +++++++++++++++++++ tests/test_common.py | 10 +++++++++- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/svn/common.py b/svn/common.py index e3dcda6..33bed6e 100644 --- a/svn/common.py +++ b/svn/common.py @@ -287,6 +287,43 @@ def export(self, to_path, revision=None, force=False): cmd.append('--force') if force else None self.run_command('export', cmd) + + def blame(self, rel_filepath, + revision_from=None, revision_to=None): + """ + svn usage: blame [-r M:N] TARGET[@REV] + """ + + full_url_or_path = self.__url_or_path + "/" + rel_filepath + + args = [] + if revision_from or revision_to: + if not revision_from: + revision_from = '1' + + if not revision_to: + revision_to = 'HEAD' + + args += ['-r', str(revision_from) + ':' + str(revision_to)] + + result = self.run_command( + "blame", args + ["--xml", full_url_or_path], do_combine=True) + + root = xml.etree.ElementTree.fromstring(result) + + for entry in root.findall("target/entry"): + commit = entry.find("commit") + author = entry.find("commit/author") + date_ = entry.find("commit/date") + if author is None or date_ is None: + continue + info = { + 'line_number': int(entry.attrib['line-number']), + "commit_author": self.__element_text(author), + "commit_date": dateutil.parser.parse(date_.text), + "commit_revision": int(commit.attrib["revision"]), + } + yield info def status(self, rel_path=None): full_url_or_path = self.__url_or_path diff --git a/svn/common_base.py b/svn/common_base.py index dd16cd7..3808394 100644 --- a/svn/common_base.py +++ b/svn/common_base.py @@ -13,6 +13,7 @@ class CommonBase(object): def external_command(self, cmd, success_code=0, do_combine=False, return_binary=False, environment={}, wd=None): _LOGGER.debug("RUN: %s" % (cmd,)) + # print("RUN:", cmd) env = os.environ.copy() env['LANG'] = svn.config.CONSOLE_ENCODING diff --git a/svn/resources/README.rst b/svn/resources/README.rst index 396e1cc..d56227c 100644 --- a/svn/resources/README.rst +++ b/svn/resources/README.rst @@ -25,6 +25,7 @@ Functions currently implemented: - commit - update - cleanup +- blame In addition, there is also an "admin" class (`svn.admin.Admin`) that provides a `create` method with which to create repositories. @@ -278,6 +279,24 @@ diff(start_revision, end_revision) Finds all the diff between start and end revision id. Here another key of 'diff' is added which shows the diff of files. +blame(rel_filepath, revision=None) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Blame specified file :: + + import svn.local + + l = svn.local.LocalClient('/tmp/test_repo.co') + + for line_info in l.blame("version.py"): + print(line_info) + + # { + # 'line_number': 1, + # 'commit_revision': 1222, + # 'commit_author': 'codeskyblue', + # 'commit_date': datetime.datetime(2018, 12, 20, 3, 25, 13, 479212, tzinfo=tzutc())} + .. |Build_Status| image:: https://travis-ci.org/dsoprea/PySvn.svg?branch=master :target: https://travis-ci.org/dsoprea/PySvn .. |Coverage_Status| image:: https://coveralls.io/repos/github/dsoprea/PySvn/badge.svg?branch=master diff --git a/tests/test_common.py b/tests/test_common.py index 444a514..134c1d3 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -257,7 +257,15 @@ def test_info(self): self.assertEqual( actual_answer['repository/uuid'], '13f79535-47bb-0310-9956-ffa450edef68') - + + def test_blame(self): + cc = self.__get_cc() + actual_answer = cc.blame('abdera/abdera2/README', revision_to=1173209) + ans = next(actual_answer) + self.assertEqual(ans['line_number'], 1) + self.assertEqual(ans['commit_revision'], 1173209) + self.assertEqual(ans['commit_author'], 'jmsnell') + def test_info_revision(self): cc = self.__get_cc() actual_answer = cc.info(revision=1000000) From 266acfe5bb8e5d483839828cbf02ef58971f49ba Mon Sep 17 00:00:00 2001 From: Sven 'xoryo Date: Tue, 24 Jul 2018 22:16:29 +0200 Subject: [PATCH 04/13] Adding search option to log along with test case --- svn/common.py | 5 ++++- svn/resources/README.rst | 4 ++-- tests/test_common.py | 11 +++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/svn/common.py b/svn/common.py index 33bed6e..a141435 100644 --- a/svn/common.py +++ b/svn/common.py @@ -185,7 +185,7 @@ def cat(self, rel_filepath, revision=None): def log_default(self, timestamp_from_dt=None, timestamp_to_dt=None, limit=None, rel_filepath=None, stop_on_copy=False, revision_from=None, revision_to=None, changelist=False, - use_merge_history=False): + use_merge_history=False, search=None): """Allow for the most-likely kind of log listing: the complete list, a FROM and TO timestamp, a FROM timestamp only, or a quantity limit. """ @@ -233,6 +233,9 @@ def log_default(self, timestamp_from_dt=None, timestamp_to_dt=None, if stop_on_copy is True: args += ['--stop-on-copy'] + if search is not None: + args += ['--search', search] + if use_merge_history is True: args += ['--use-merge-history'] diff --git a/svn/resources/README.rst b/svn/resources/README.rst index d56227c..cf0db1b 100644 --- a/svn/resources/README.rst +++ b/svn/resources/README.rst @@ -134,8 +134,8 @@ Get file-data as string:: l = svn.local.LocalClient('/tmp/test_repo') content = l.cat('test_file') -log_default(timestamp_from_dt=None, timestamp_to_dt=None, limit=None, rel_filepath='', stop_on_copy=False, revision_from=None, revision_to=None, changelist=False) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +log_default(timestamp_from_dt=None, timestamp_to_dt=None, limit=None, rel_filepath='', stop_on_copy=False, revision_from=None, revision_to=None, changelist=False, search=None) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Perform a log-listing that can be bounded by time or revision number and/or take a maximum- count:: diff --git a/tests/test_common.py b/tests/test_common.py index 134c1d3..bcb23c6 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -282,6 +282,17 @@ def test_log(self): cc.log_default(revision_from=1761404, revision_to=1761403) self.assertEqual(next(actual_answer).author, 'sseifert') + def test_search(self): + """ + Checking log search + :return: + """ + + cc = self.__get_cc() + actual_answer = \ + cc.log_default(search='Get ready to tag httpd 2.4.34', revision_from=1835550, revision_to=1836000) + self.assertEqual(next(actual_answer).author, 'jim') + def test_cat(self): """ Checking cat From 966757745daae5373d6e1c5b73411d7774540add Mon Sep 17 00:00:00 2001 From: James Tavares Date: Tue, 31 Jul 2018 13:28:36 -0400 Subject: [PATCH 05/13] Adding .eggs setuptools cache folder to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d712718..df6b755 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ venv* .tox /pip-selfcheck.json /man +.eggs From 5c26ab9a7a028ddf1dcd989e80fc56cde892147d Mon Sep 17 00:00:00 2001 From: a_rubashev Date: Tue, 5 Mar 2019 18:25:52 +0200 Subject: [PATCH 06/13] svn status can now include changelists' items --- svn/common.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/svn/common.py b/svn/common.py index a141435..8f06b75 100644 --- a/svn/common.py +++ b/svn/common.py @@ -328,7 +328,7 @@ def blame(self, rel_filepath, } yield info - def status(self, rel_path=None): + def status(self, rel_path=None, include_changelists=False): full_url_or_path = self.__url_or_path if rel_path is not None: full_url_or_path += '/' + rel_path @@ -341,6 +341,9 @@ def status(self, rel_path=None): root = xml.etree.ElementTree.fromstring(raw) list_ = root.findall('target/entry') + if include_changelists is True: + list_ += root.findall('changelist/entry') + for entry in list_: entry_attr = entry.attrib name = entry_attr['path'] From ab1db5789e63c060fce342c2ae73074df5552b03 Mon Sep 17 00:00:00 2001 From: Matt Bradshaw Date: Mon, 23 Jul 2018 06:59:54 -0400 Subject: [PATCH 07/13] Expose the LOG_STATUS namedtuple to library consumers --- svn/common.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/svn/common.py b/svn/common.py index 8f06b75..cd43850 100644 --- a/svn/common.py +++ b/svn/common.py @@ -20,6 +20,9 @@ 'type', 'revision', ]) +LOG_ENTRY = collections.namedtuple( + 'LogEntry', + ('date', 'msg', 'revision', 'author', 'changelist')) class CommonClient(svn.common_base.CommonBase): @@ -248,10 +251,6 @@ def log_default(self, timestamp_from_dt=None, timestamp_to_dt=None, do_combine=True) root = xml.etree.ElementTree.fromstring(result) - named_fields = ['date', 'msg', 'revision', 'author', 'changelist'] - c = collections.namedtuple( - 'LogEntry', - named_fields) # Merge history can create nested log entries, so use iter instead of findall for e in root.iter('logentry'): @@ -278,7 +277,7 @@ def log_default(self, timestamp_from_dt=None, timestamp_to_dt=None, else: log_entry['changelist'] = None - yield c(**log_entry) + yield LOG_ENTRY(**log_entry) def export(self, to_path, revision=None, force=False): cmd = [] From 5ee62e06723ee95fd55f6052697d6dca971564da Mon Sep 17 00:00:00 2001 From: James Tavares Date: Tue, 31 Jul 2018 15:48:18 -0400 Subject: [PATCH 08/13] Added LocalClient.propset() and fixed bug in CommonClient.properties() - Allow for the setting of properties via LocalClient.propset() - Fix bug in CommonClient.properties() that caused an exception when proplist had zero entries in it --- svn/common.py | 5 +++++ svn/local.py | 10 ++++++++++ svn/resources/README.rst | 1 + tests/test_common.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/svn/common.py b/svn/common.py index cd43850..6df57a9 100644 --- a/svn/common.py +++ b/svn/common.py @@ -160,6 +160,11 @@ def properties(self, rel_path=None): # query the proper list of this path root = xml.etree.ElementTree.fromstring(result) target_elem = root.find('target') + + # check for empty property list + if target_elem is None: + return {} + property_names = [p.attrib["name"] for p in target_elem.findall('property')] diff --git a/svn/local.py b/svn/local.py index bb03fd5..8c7b820 100644 --- a/svn/local.py +++ b/svn/local.py @@ -46,3 +46,13 @@ def cleanup(self): 'cleanup', [], wd=self.path) + + def propset(self, property_name, property_value, rel_path=None): + '''Set a property on a relative path''' + if rel_path is None: + rel_path = '.' + + self.run_command( + 'propset', + [property_name, property_value, rel_path], + wd=self.path) diff --git a/svn/resources/README.rst b/svn/resources/README.rst index cf0db1b..d52166e 100644 --- a/svn/resources/README.rst +++ b/svn/resources/README.rst @@ -20,6 +20,7 @@ Functions currently implemented: - cat - diff - diff_summary +- propset - status - add - commit diff --git a/tests/test_common.py b/tests/test_common.py index bcb23c6..1ef4400 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -335,3 +335,33 @@ def test_force_export(self): def test_cleanup(self): self.__temp_lc.cleanup() + + def test_properties(self): + '''Tests CommonClient.properties() and LocalClient.propset()''' + l = self.__temp_lc + + # Test propset with rel_path omitted + self.assertTrue('prop1' not in l.properties()) + l.propset('prop1', 'value1') + self.assertTrue('prop1' in l.properties() and + l.properties()['prop1'] == 'value1') + + # Add a file + filepath = os.path.join(self.__temp_co_path, 'propfile2') + with open(filepath, 'w') as f: + pass + + l.add('propfile2') + + # properties should be empty until we add some + self.assertTrue(l.properties(rel_path='propfile2') == {}) + + # Test with rel_path='propfile2' + self.assertTrue('prop2' not in l.properties(rel_path='propfile2')) + l.propset('prop2', 'value2', rel_path='propfile2') + self.assertTrue('prop2' in l.properties(rel_path='propfile2') and + l.properties(rel_path='propfile2')['prop2'] == 'value2') + + # Cross-check + self.assertTrue('prop1' not in l.properties(rel_path='propfile2')) + self.assertTrue('prop2' not in l.properties()) From 6b941f531a3c18ee81bbd3071c25b14d6c715bde Mon Sep 17 00:00:00 2001 From: James Tavares Date: Tue, 31 Jul 2018 15:49:15 -0400 Subject: [PATCH 09/13] Add no_ignore option to status() - Added no_ignore=False option to CommonClient.status(). Setting to true causes --no-ignore option to be passed to svn, so as to include ignored files in the result. - Added tests for 'ignored' and 'unversioned' files. --- svn/common.py | 8 ++++++-- tests/test_common.py | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/svn/common.py b/svn/common.py index 6df57a9..b3805f4 100644 --- a/svn/common.py +++ b/svn/common.py @@ -332,14 +332,18 @@ def blame(self, rel_filepath, } yield info - def status(self, rel_path=None, include_changelists=False): + def status(self, rel_path=None, no_ignore=False, include_changelists=False): full_url_or_path = self.__url_or_path if rel_path is not None: full_url_or_path += '/' + rel_path + cmd = ['--xml', full_url_or_path] + if no_ignore: + cmd.append('--no-ignore') + raw = self.run_command( 'status', - ['--xml', full_url_or_path], + cmd, do_combine=True) root = xml.etree.ElementTree.fromstring(raw) diff --git a/tests/test_common.py b/tests/test_common.py index 1ef4400..653f44b 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -79,7 +79,7 @@ def tearDown(self): _LOGGER.exception("Could not cleanup temporary repository path: [%s]", self.__temp_repo_path) def __stage_co_directory_1(self): - """Establish a new file, an added file, a committed file, and a changed file.""" + """Establish a new file, an added file, a committed file, a changed file, and an ignored file.""" # Create a file that will not be committed. @@ -117,6 +117,15 @@ def __stage_co_directory_1(self): self.__temp_lc.add(rel_filepath_deleted) + # Create a file that will be ignored + + rel_filepath_ignored = 'ignored' + filepath = os.path.join(self.__temp_co_path, rel_filepath_ignored) + with open(filepath, 'w') as f: + pass + + self.__temp_lc.propset('svn:ignore', 'ignored') + # Commit the new files. self.__temp_lc.commit("Initial commit.") @@ -143,11 +152,18 @@ def __stage_co_directory_1(self): self.__temp_lc.add(rel_filepath) + # Create a file that will not be added + + rel_filepath = 'unversioned' + filepath = os.path.join(self.__temp_co_path, rel_filepath) + with open(filepath, 'w') as f: + pass + def test_status(self): self.__stage_co_directory_1() status = {} - for s in self.__temp_lc.status(): + for s in self.__temp_lc.status(no_ignore=True): _LOGGER.debug("STATUS: %s", s) filename = os.path.basename(s.name) @@ -162,6 +178,27 @@ def test_status(self): committed_deleted = status['committed_deleted'] self.assertTrue(committed_deleted is not None and committed_deleted.type == svn.constants.ST_MISSING) + ignored = status['ignored'] + self.assertTrue(ignored is not None and ignored.type == svn.constants.ST_IGNORED) + + ignored = status['unversioned'] + self.assertTrue(ignored is not None and ignored.type == svn.constants.ST_UNVERSIONED) + + # Test that ignored files are hidden when no_ignore=False + status = {} + for s in self.__temp_lc.status(): + _LOGGER.debug("STATUS: %s", s) + + filename = os.path.basename(s.name) + status[filename] = s + + self.assertTrue('ignored' not in status) + + # ..but spot check that others are not hidden + added = status['added'] + self.assertTrue(added is not None and added.type == svn.constants.ST_ADDED) + + def test_update(self): self.__stage_co_directory_1() self.__temp_lc.commit("Second commit.") From 19bd3033e54d700148b8e2947c6fa61bfe80c663 Mon Sep 17 00:00:00 2001 From: Jeremy Miller Date: Wed, 13 Sep 2017 23:01:02 -0500 Subject: [PATCH 10/13] added third slash to file to prevent failed assertion: assertion failed (svn_uri_is_canonical(url, scratch_pool)) --- tests/test_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_common.py b/tests/test_common.py index 653f44b..7e070ad 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -57,7 +57,7 @@ def __setup_test_environment(self): self.__temp_co_path = self.__get_temp_path_to_use() _LOGGER.debug("CO_PATH: {}".format(self.__temp_co_path)) - r = svn.remote.RemoteClient('file://' + self.__temp_repo_path) + r = svn.remote.RemoteClient('file:///' + self.__temp_repo_path) r.checkout(self.__temp_co_path) # Create a client for it. From 6e05fd7dded979353cf8efaaa00b59a026495ad7 Mon Sep 17 00:00:00 2001 From: Jeremy Miller Date: Thu, 14 Sep 2017 07:01:44 -0500 Subject: [PATCH 11/13] Preserve unix filepath behavior --- tests/test_common.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_common.py b/tests/test_common.py index 7e070ad..5056c94 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -57,7 +57,10 @@ def __setup_test_environment(self): self.__temp_co_path = self.__get_temp_path_to_use() _LOGGER.debug("CO_PATH: {}".format(self.__temp_co_path)) - r = svn.remote.RemoteClient('file:///' + self.__temp_repo_path) + if self.__temp_repo_path[0] == '/': + r = svn.remote.RemoteClient('file://' + self.__temp_repo_path) + else: + r = svn.remote.RemoteClient('file:///' + self.__temp_repo_path) r.checkout(self.__temp_co_path) # Create a client for it. From dcf87443a4f7f471889dbfdbe968a2dbda2105c3 Mon Sep 17 00:00:00 2001 From: Jeremy Miller Date: Thu, 14 Sep 2017 19:41:08 -0500 Subject: [PATCH 12/13] Improve diff command 1. Changed split from == to 67 ='s to match the output. Original would break on equality checks in many languages. 2. Improved handling of diff on directories so that the root directory does not cause an exception. 3. Included unit test for the diff change. 4. Added unit test for properties. --- svn/common.py | 31 +++++++++++++++++++++++++++---- tests/test_admin.py | 7 ++++++- tests/test_common.py | 24 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/svn/common.py b/svn/common.py index b3805f4..402b7b9 100644 --- a/svn/common.py +++ b/svn/common.py @@ -505,13 +505,36 @@ def diff(self, old, new, rel_path=None): '--new', '{0}@{1}'.format(full_url_or_path, new)], do_combine=True) file_to_diff = {} + + # A diff has this form, potentially repeating for multiple files. + # + # Index: relative/filename.txt + # =================================================================== + # The diff content + # + # Here we split diffs into files by the index section, pick up the + # file name, then split again to pick up the content. for non_empty_diff in filter(None, diff_result.decode('utf8').split('Index: ')): - split_diff = non_empty_diff.split('==') - file_to_diff[split_diff[0].strip().strip('/')] = split_diff[-1].strip('=').strip() + split_diff = non_empty_diff.split('='*67) + index_filename = split_diff[0].strip().strip('/') + file_to_diff[index_filename] = split_diff[-1].strip() diff_summaries = self.diff_summary(old, new, rel_path) + + # Allocate summary info to the text for each change. + # Not all diffs necessarily affect file text (directory changes, for example). for diff_summary in diff_summaries: - diff_summary['diff'] = \ - file_to_diff[diff_summary['path'].split(full_url_or_path)[-1].strip('/')] + diff_summary['diff'] = '' + if 'path' in diff_summary: + # Summary file paths are absolute, while diff file indexes are relative. + # We try to match them up, first checking the root of the diff. + summary_index = diff_summary['path'][len(full_url_or_path):].strip('/') + # If the diff was conducted directly on the file, not a directory, the + # above will fail to find the relative file name, so we look for that directly. + if summary_index == '': + summary_index = os.path.basename(full_url_or_path) + # If we can match a diff to a summary, we attach it. + if summary_index in file_to_diff: + diff_summary['diff'] = file_to_diff[summary_index] return diff_summaries @property diff --git a/tests/test_admin.py b/tests/test_admin.py index 9e9a7b6..b1d5477 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -35,7 +35,12 @@ def test_create_repository(self): a.create(temp_path) # Do a read. - rc = svn.remote.RemoteClient('file://' + temp_path) + # Duck-type identification of path type (Windows, Linux, etc.) to ensure + # file uri canonicity is enforced. URI must be file:///. + if temp_path[0] == '/': + rc = svn.remote.RemoteClient('file://' + temp_path) + else: + rc = svn.remote.RemoteClient('file:///' + temp_path) info = rc.info() _LOGGER.debug("Info from new repository: [%s]", str(info)) finally: diff --git a/tests/test_common.py b/tests/test_common.py index 5056c94..1d6cbbb 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -57,6 +57,8 @@ def __setup_test_environment(self): self.__temp_co_path = self.__get_temp_path_to_use() _LOGGER.debug("CO_PATH: {}".format(self.__temp_co_path)) + # Duck-type identification of path type (Windows, Linux, etc.) to ensure + # file uri canonicity is enforced. URI must be file:///. if self.__temp_repo_path[0] == '/': r = svn.remote.RemoteClient('file://' + self.__temp_repo_path) else: @@ -265,6 +267,18 @@ def test_diff(self): 'http://svn.apache.org/repos/asf/sling/trunk/pom.xml' \ in individual_diff[diff_key]) + def test_diff_separator(self): + """ + Checking diff + :return: + """ + cc = self.__get_cc() + change = '502054' + file_cluster_event = 'activemq/activecluster/trunk/src/main/java/org/apache/activecluster/ClusterEvent.java' + actual_answer = cc.diff('0', change, file_cluster_event)[0] + self.assertTrue('static final int UPDATE_NODE = 2' in actual_answer['diff']) + self.assertTrue('else if (type == FAILED_NODE)' in actual_answer['diff']) + def test_list(self): """ Checking list @@ -376,6 +390,16 @@ def test_force_export(self): def test_cleanup(self): self.__temp_lc.cleanup() + def test_properties_cc(self): + """ + '''Tests CommonClient.properties()''' + """ + cc = self.__get_cc() + props = cc.properties('activemq/activecluster/trunk/src/main/java/org/apache/activecluster@1808406') + self.assertFalse(bool(props)) + props = cc.properties('activemq/activecluster/trunk/src/main/java/org/apache/activecluster/Cluster.java@1808406') + self.assertEqual(props['svn:eol-style'], 'native') + def test_properties(self): '''Tests CommonClient.properties() and LocalClient.propset()''' l = self.__temp_lc From a1c68c45ab90694785f2eea6e0fae7527c30e030 Mon Sep 17 00:00:00 2001 From: jforand Date: Wed, 25 Apr 2018 23:42:29 -0400 Subject: [PATCH 13/13] Add another test for properties --- tests/test_common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_common.py b/tests/test_common.py index 1d6cbbb..2f4f264 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -400,6 +400,9 @@ def test_properties_cc(self): props = cc.properties('activemq/activecluster/trunk/src/main/java/org/apache/activecluster/Cluster.java@1808406') self.assertEqual(props['svn:eol-style'], 'native') + actual_answer = cc.properties(rel_path='whirr/tags/release-0.7.0/services/zookeeper') + self.assertDictEqual(actual_answer, {'svn:ignore': '\n'.join(['.project', '.classpath', '.settings', 'target', ''])}) + def test_properties(self): '''Tests CommonClient.properties() and LocalClient.propset()''' l = self.__temp_lc