diff options
| -rw-r--r-- | git_config.py | 7 | ||||
| -rw-r--r-- | manifest_xml.py | 3 | ||||
| -rw-r--r-- | platform_utils.py | 31 | ||||
| -rw-r--r-- | project.py | 20 | ||||
| -rw-r--r-- | subcmds/sync.py | 20 | ||||
| -rw-r--r-- | tests/test_platform_utils.py | 50 |
6 files changed, 80 insertions, 51 deletions
diff --git a/git_config.py b/git_config.py index 778e81a4..bc70d160 100644 --- a/git_config.py +++ b/git_config.py | |||
| @@ -352,8 +352,8 @@ class GitConfig(object): | |||
| 352 | Trace(': parsing %s', self.file) | 352 | Trace(': parsing %s', self.file) |
| 353 | with open(self._json) as fd: | 353 | with open(self._json) as fd: |
| 354 | return json.load(fd) | 354 | return json.load(fd) |
| 355 | except (IOError, ValueError): | 355 | except (IOError, ValueErrorl): |
| 356 | platform_utils.remove(self._json) | 356 | platform_utils.remove(self._json, missing_ok=True) |
| 357 | return None | 357 | return None |
| 358 | 358 | ||
| 359 | def _SaveJson(self, cache): | 359 | def _SaveJson(self, cache): |
| @@ -361,8 +361,7 @@ class GitConfig(object): | |||
| 361 | with open(self._json, 'w') as fd: | 361 | with open(self._json, 'w') as fd: |
| 362 | json.dump(cache, fd, indent=2) | 362 | json.dump(cache, fd, indent=2) |
| 363 | except (IOError, TypeError): | 363 | except (IOError, TypeError): |
| 364 | if os.path.exists(self._json): | 364 | platform_utils.remove(self._json, missing_ok=True) |
| 365 | platform_utils.remove(self._json) | ||
| 366 | 365 | ||
| 367 | def _ReadGit(self): | 366 | def _ReadGit(self): |
| 368 | """ | 367 | """ |
diff --git a/manifest_xml.py b/manifest_xml.py index 135c91fb..86f20202 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
| @@ -270,8 +270,7 @@ class XmlManifest(object): | |||
| 270 | self.Override(name) | 270 | self.Override(name) |
| 271 | 271 | ||
| 272 | # Old versions of repo would generate symlinks we need to clean up. | 272 | # Old versions of repo would generate symlinks we need to clean up. |
| 273 | if os.path.lexists(self.manifestFile): | 273 | platform_utils.remove(self.manifestFile, missing_ok=True) |
| 274 | platform_utils.remove(self.manifestFile) | ||
| 275 | # This file is interpreted as if it existed inside the manifest repo. | 274 | # This file is interpreted as if it existed inside the manifest repo. |
| 276 | # That allows us to use <include> with the relative file name. | 275 | # That allows us to use <include> with the relative file name. |
| 277 | with open(self.manifestFile, 'w') as fp: | 276 | with open(self.manifestFile, 'w') as fp: |
diff --git a/platform_utils.py b/platform_utils.py index 5741f4d3..0203249a 100644 --- a/platform_utils.py +++ b/platform_utils.py | |||
| @@ -127,28 +127,27 @@ def rename(src, dst): | |||
| 127 | shutil.move(src, dst) | 127 | shutil.move(src, dst) |
| 128 | 128 | ||
| 129 | 129 | ||
| 130 | def remove(path): | 130 | def remove(path, missing_ok=False): |
| 131 | """Remove (delete) the file path. This is a replacement for os.remove that | 131 | """Remove (delete) the file path. This is a replacement for os.remove that |
| 132 | allows deleting read-only files on Windows, with support for long paths and | 132 | allows deleting read-only files on Windows, with support for long paths and |
| 133 | for deleting directory symbolic links. | 133 | for deleting directory symbolic links. |
| 134 | 134 | ||
| 135 | Availability: Unix, Windows.""" | 135 | Availability: Unix, Windows.""" |
| 136 | if isWindows(): | 136 | longpath = _makelongpath(path) if isWindows() else path |
| 137 | longpath = _makelongpath(path) | 137 | try: |
| 138 | try: | 138 | os.remove(longpath) |
| 139 | os.remove(longpath) | 139 | except OSError as e: |
| 140 | except OSError as e: | 140 | if e.errno == errno.EACCES: |
| 141 | if e.errno == errno.EACCES: | 141 | os.chmod(longpath, stat.S_IWRITE) |
| 142 | os.chmod(longpath, stat.S_IWRITE) | 142 | # Directory symbolic links must be deleted with 'rmdir'. |
| 143 | # Directory symbolic links must be deleted with 'rmdir'. | 143 | if islink(longpath) and isdir(longpath): |
| 144 | if islink(longpath) and isdir(longpath): | 144 | os.rmdir(longpath) |
| 145 | os.rmdir(longpath) | ||
| 146 | else: | ||
| 147 | os.remove(longpath) | ||
| 148 | else: | 145 | else: |
| 149 | raise | 146 | os.remove(longpath) |
| 150 | else: | 147 | elif missing_ok and e.errno == errno.ENOENT: |
| 151 | os.remove(path) | 148 | pass |
| 149 | else: | ||
| 150 | raise | ||
| 152 | 151 | ||
| 153 | 152 | ||
| 154 | def walk(top, topdown=True, onerror=None, followlinks=False): | 153 | def walk(top, topdown=True, onerror=None, followlinks=False): |
| @@ -1182,10 +1182,8 @@ class Project(object): | |||
| 1182 | self._InitMRef() | 1182 | self._InitMRef() |
| 1183 | else: | 1183 | else: |
| 1184 | self._InitMirrorHead() | 1184 | self._InitMirrorHead() |
| 1185 | try: | 1185 | platform_utils.remove(os.path.join(self.gitdir, 'FETCH_HEAD'), |
| 1186 | platform_utils.remove(os.path.join(self.gitdir, 'FETCH_HEAD')) | 1186 | missing_ok=True) |
| 1187 | except OSError: | ||
| 1188 | pass | ||
| 1189 | return True | 1187 | return True |
| 1190 | 1188 | ||
| 1191 | def PostRepoUpgrade(self): | 1189 | def PostRepoUpgrade(self): |
| @@ -2307,15 +2305,12 @@ class Project(object): | |||
| 2307 | cmd.append('+refs/tags/*:refs/tags/*') | 2305 | cmd.append('+refs/tags/*:refs/tags/*') |
| 2308 | 2306 | ||
| 2309 | ok = GitCommand(self, cmd, bare=True).Wait() == 0 | 2307 | ok = GitCommand(self, cmd, bare=True).Wait() == 0 |
| 2310 | if os.path.exists(bundle_dst): | 2308 | platform_utils.remove(bundle_dst, missing_ok=True) |
| 2311 | platform_utils.remove(bundle_dst) | 2309 | platform_utils.remove(bundle_tmp, missing_ok=True) |
| 2312 | if os.path.exists(bundle_tmp): | ||
| 2313 | platform_utils.remove(bundle_tmp) | ||
| 2314 | return ok | 2310 | return ok |
| 2315 | 2311 | ||
| 2316 | def _FetchBundle(self, srcUrl, tmpPath, dstPath, quiet, verbose): | 2312 | def _FetchBundle(self, srcUrl, tmpPath, dstPath, quiet, verbose): |
| 2317 | if os.path.exists(dstPath): | 2313 | platform_utils.remove(dstPath, missing_ok=True) |
| 2318 | platform_utils.remove(dstPath) | ||
| 2319 | 2314 | ||
| 2320 | cmd = ['curl', '--fail', '--output', tmpPath, '--netrc', '--location'] | 2315 | cmd = ['curl', '--fail', '--output', tmpPath, '--netrc', '--location'] |
| 2321 | if quiet: | 2316 | if quiet: |
| @@ -2739,10 +2734,7 @@ class Project(object): | |||
| 2739 | # If the source file doesn't exist, ensure the destination | 2734 | # If the source file doesn't exist, ensure the destination |
| 2740 | # file doesn't either. | 2735 | # file doesn't either. |
| 2741 | if name in symlink_files and not os.path.lexists(src): | 2736 | if name in symlink_files and not os.path.lexists(src): |
| 2742 | try: | 2737 | platform_utils.remove(dst, missing_ok=True) |
| 2743 | platform_utils.remove(dst) | ||
| 2744 | except OSError: | ||
| 2745 | pass | ||
| 2746 | 2738 | ||
| 2747 | except OSError as e: | 2739 | except OSError as e: |
| 2748 | if e.errno == errno.EPERM: | 2740 | if e.errno == errno.EPERM: |
diff --git a/subcmds/sync.py b/subcmds/sync.py index c99b06ca..3211cbb1 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
| @@ -767,13 +767,9 @@ later is required to fix a server side protocol bug. | |||
| 767 | set(new_copyfile_paths)) | 767 | set(new_copyfile_paths)) |
| 768 | 768 | ||
| 769 | for need_remove_file in need_remove_files: | 769 | for need_remove_file in need_remove_files: |
| 770 | try: | 770 | # Try to remove the updated copyfile or linkfile. |
| 771 | platform_utils.remove(need_remove_file) | 771 | # So, if the file is not exist, nothing need to do. |
| 772 | except OSError as e: | 772 | platform_utils.remove(need_remove_file, missing_ok=True) |
| 773 | if e.errno == errno.ENOENT: | ||
| 774 | # Try to remove the updated copyfile or linkfile. | ||
| 775 | # So, if the file is not exist, nothing need to do. | ||
| 776 | pass | ||
| 777 | 773 | ||
| 778 | # Create copy-link-files.json, save dest path of "copyfile" and "linkfile". | 774 | # Create copy-link-files.json, save dest path of "copyfile" and "linkfile". |
| 779 | with open(copylinkfile_path, 'w', encoding='utf-8') as fp: | 775 | with open(copylinkfile_path, 'w', encoding='utf-8') as fp: |
| @@ -1171,10 +1167,7 @@ class _FetchTimes(object): | |||
| 1171 | with open(self._path) as f: | 1167 | with open(self._path) as f: |
| 1172 | self._times = json.load(f) | 1168 | self._times = json.load(f) |
| 1173 | except (IOError, ValueError): | 1169 | except (IOError, ValueError): |
| 1174 | try: | 1170 | platform_utils.remove(self._path, missing_ok=True) |
| 1175 | platform_utils.remove(self._path) | ||
| 1176 | except OSError: | ||
| 1177 | pass | ||
| 1178 | self._times = {} | 1171 | self._times = {} |
| 1179 | 1172 | ||
| 1180 | def Save(self): | 1173 | def Save(self): |
| @@ -1192,10 +1185,7 @@ class _FetchTimes(object): | |||
| 1192 | with open(self._path, 'w') as f: | 1185 | with open(self._path, 'w') as f: |
| 1193 | json.dump(self._times, f, indent=2) | 1186 | json.dump(self._times, f, indent=2) |
| 1194 | except (IOError, TypeError): | 1187 | except (IOError, TypeError): |
| 1195 | try: | 1188 | platform_utils.remove(self._path, missing_ok=True) |
| 1196 | platform_utils.remove(self._path) | ||
| 1197 | except OSError: | ||
| 1198 | pass | ||
| 1199 | 1189 | ||
| 1200 | # This is a replacement for xmlrpc.client.Transport using urllib2 | 1190 | # This is a replacement for xmlrpc.client.Transport using urllib2 |
| 1201 | # and supporting persistent-http[s]. It cannot change hosts from | 1191 | # and supporting persistent-http[s]. It cannot change hosts from |
diff --git a/tests/test_platform_utils.py b/tests/test_platform_utils.py new file mode 100644 index 00000000..55b7805c --- /dev/null +++ b/tests/test_platform_utils.py | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | # Copyright 2021 The Android Open Source Project | ||
| 2 | # | ||
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | # you may not use this file except in compliance with the License. | ||
| 5 | # You may obtain a copy of the License at | ||
| 6 | # | ||
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | # | ||
| 9 | # Unless required by applicable law or agreed to in writing, software | ||
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | # See the License for the specific language governing permissions and | ||
| 13 | # limitations under the License. | ||
| 14 | |||
| 15 | """Unittests for the platform_utils.py module.""" | ||
| 16 | |||
| 17 | import os | ||
| 18 | import tempfile | ||
| 19 | import unittest | ||
| 20 | |||
| 21 | import platform_utils | ||
| 22 | |||
| 23 | |||
| 24 | class RemoveTests(unittest.TestCase): | ||
| 25 | """Check remove() helper.""" | ||
| 26 | |||
| 27 | def testMissingOk(self): | ||
| 28 | """Check missing_ok handling.""" | ||
| 29 | with tempfile.TemporaryDirectory() as tmpdir: | ||
| 30 | path = os.path.join(tmpdir, 'test') | ||
| 31 | |||
| 32 | # Should not fail. | ||
| 33 | platform_utils.remove(path, missing_ok=True) | ||
| 34 | |||
| 35 | # Should fail. | ||
| 36 | self.assertRaises(OSError, platform_utils.remove, path) | ||
| 37 | self.assertRaises(OSError, platform_utils.remove, path, missing_ok=False) | ||
| 38 | |||
| 39 | # Should not fail if it exists. | ||
| 40 | open(path, 'w').close() | ||
| 41 | platform_utils.remove(path, missing_ok=True) | ||
| 42 | self.assertFalse(os.path.exists(path)) | ||
| 43 | |||
| 44 | open(path, 'w').close() | ||
| 45 | platform_utils.remove(path) | ||
| 46 | self.assertFalse(os.path.exists(path)) | ||
| 47 | |||
| 48 | open(path, 'w').close() | ||
| 49 | platform_utils.remove(path, missing_ok=False) | ||
| 50 | self.assertFalse(os.path.exists(path)) | ||
