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)) | ||