Skip to content

Commit 846c7e2

Browse files
humitosericholscher
authored andcommitted
Do not fail when unlinking an non-existing path (#4760)
* Do not fail when unlinking an non-existing path If we try to unlink a path that doesn't exist, we need to do nothing instead of failing hard and logging an exception on Sentry. * Rename unlink to safe_unlink
1 parent bd4c82b commit 846c7e2

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

readthedocs/core/symlink.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363

6464
from readthedocs.builds.models import Version
6565
from readthedocs.core.utils.extend import SettingsOverrideObject
66-
from readthedocs.core.utils import safe_makedirs
66+
from readthedocs.core.utils import safe_makedirs, safe_unlink
6767
from readthedocs.projects import constants
6868
from readthedocs.projects.models import Domain
6969
from readthedocs.projects.utils import run
@@ -95,7 +95,7 @@ def sanity_check(self):
9595
log.info(constants.LOG_TEMPLATE.format(
9696
project=self.project.slug, version='',
9797
msg="Removing single version symlink"))
98-
os.unlink(self.project_root)
98+
safe_unlink(self.project_root)
9999
safe_makedirs(self.project_root)
100100
elif (self.project.single_version and
101101
not os.path.islink(self.project_root) and
@@ -164,7 +164,7 @@ def remove_symlink_cname(self, domain):
164164
log.info(constants.LOG_TEMPLATE.format(project=self.project.slug,
165165
version='', msg=log_msg))
166166
symlink = os.path.join(self.CNAME_ROOT, domain.domain)
167-
os.unlink(symlink)
167+
safe_unlink(symlink)
168168

169169
def symlink_subprojects(self):
170170
"""
@@ -210,7 +210,7 @@ def symlink_subprojects(self):
210210
if os.path.exists(self.subproject_root):
211211
for subproj in os.listdir(self.subproject_root):
212212
if subproj not in subprojects:
213-
os.unlink(os.path.join(self.subproject_root, subproj))
213+
safe_unlink(os.path.join(self.subproject_root, subproj))
214214

215215
def symlink_translations(self):
216216
"""
@@ -227,7 +227,7 @@ def symlink_translations(self):
227227
# Make sure the language directory is a directory
228228
language_dir = os.path.join(self.project_root, self.project.language)
229229
if os.path.islink(language_dir):
230-
os.unlink(language_dir)
230+
safe_unlink(language_dir)
231231
if not os.path.lexists(language_dir):
232232
safe_makedirs(language_dir)
233233

@@ -246,7 +246,7 @@ def symlink_translations(self):
246246
lang not in ['projects', self.project.language]):
247247
to_delete = os.path.join(self.project_root, lang)
248248
if os.path.islink(to_delete):
249-
os.unlink(to_delete)
249+
safe_unlink(to_delete)
250250
else:
251251
shutil.rmtree(to_delete)
252252

@@ -262,7 +262,7 @@ def symlink_single_version(self):
262262
# Clean up symlinks
263263
symlink = self.project_root
264264
if os.path.islink(symlink):
265-
os.unlink(symlink)
265+
safe_unlink(symlink)
266266
if os.path.exists(symlink):
267267
shutil.rmtree(symlink)
268268

@@ -300,7 +300,7 @@ def symlink_versions(self):
300300
if os.path.exists(version_dir):
301301
for old_ver in os.listdir(version_dir):
302302
if old_ver not in versions:
303-
os.unlink(os.path.join(version_dir, old_ver))
303+
safe_unlink(os.path.join(version_dir, old_ver))
304304

305305
def get_default_version(self):
306306
"""Look up project default version, return None if not found."""

readthedocs/core/utils/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,20 @@ def safe_makedirs(directory_name):
225225
if e.errno == errno.EEXIST:
226226
pass
227227
raise
228+
229+
230+
def safe_unlink(path):
231+
"""
232+
Unlink ``path`` symlink using ``os.unlink``.
233+
234+
This helper handles the exception ``FileNotFoundError`` to avoid logging in
235+
cases where the symlink does not exist already and there is nothing to
236+
unlink.
237+
238+
:param path: symlink path to unlink
239+
:type path: str
240+
"""
241+
try:
242+
os.unlink(path)
243+
except FileNotFoundError:
244+
log.warning('Unlink failed. Path %s does not exists', path)

readthedocs/projects/tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from readthedocs.config import ConfigError
3737
from readthedocs.core.resolver import resolve_path
3838
from readthedocs.core.symlink import PublicSymlink, PrivateSymlink
39-
from readthedocs.core.utils import send_email, broadcast
39+
from readthedocs.core.utils import send_email, broadcast, safe_unlink
4040
from readthedocs.doc_builder.config import load_yaml_config
4141
from readthedocs.doc_builder.constants import DOCKER_LIMITS
4242
from readthedocs.doc_builder.environments import (
@@ -973,7 +973,7 @@ def remove_orphan_symlinks():
973973
for cname in orphan_cnames:
974974
orphan_domain_path = os.path.join(domain_path, cname)
975975
log.info('Unlinking orphan CNAME: %s', orphan_domain_path)
976-
os.unlink(orphan_domain_path)
976+
safe_unlink(orphan_domain_path)
977977

978978

979979
@app.task(queue='web')

0 commit comments

Comments
 (0)