Modifications for misc

This commit is contained in:
Adrien Ferrand 2019-04-17 14:15:44 +02:00
parent 410e74c4a1
commit ddbf9b6389
4 changed files with 29 additions and 28 deletions

View file

@ -2,42 +2,32 @@
This compat module handles various platform specific calls that do not fall into one
particular category.
"""
import ctypes
from __future__ import absolute_import
import errno
import os # pylint: disable=os-module-forbidden
import select
import stat
import sys
try:
from win32com.shell import shell as shellwin32 # pylint: disable=import-error
except ImportError: # pragma: no cover
shellwin32 = None # type: ignore
from certbot import errors
from certbot.compat import os
UNPRIVILEGED_SUBCOMMANDS_ALLOWED = [
'certificates', 'enhance', 'revoke', 'delete',
'register', 'unregister', 'config_changes', 'plugins']
def raise_for_non_administrative_windows_rights(subcommand):
def raise_for_non_administrative_windows_rights():
# type: () -> None
"""
On Windows, raise if current shell does not have the administrative rights.
Do nothing on Linux.
:param str subcommand: The subcommand (like 'certonly') passed to the certbot client.
:raises .errors.Error: If the provided subcommand must be run on a shell with
administrative rights, and current shell does not have these rights.
:raises .errors.Error: If the current shell does not have administrative rights on Windows.
"""
# Why not simply try ctypes.windll.shell32.IsUserAnAdmin() and catch AttributeError ?
# Because windll exists only on a Windows runtime, and static code analysis engines
# do not like at all non existent objects when run from Linux (even if we handle properly
# all the cases in the code).
# So we access windll only by reflection to trick theses engines.
if hasattr(ctypes, 'windll') and subcommand not in UNPRIVILEGED_SUBCOMMANDS_ALLOWED:
windll = getattr(ctypes, 'windll')
if windll.shell32.IsUserAnAdmin() == 0:
raise errors.Error(
'Error, "{0}" subcommand must be run on a shell with administrative rights.'
.format(subcommand))
if shellwin32 and shellwin32.IsUserAnAdmin() == 0: # pragma: no cover
raise errors.Error('Error, certbot must be run on a shell with administrative rights.')
def os_geteuid():
@ -57,9 +47,9 @@ def os_geteuid():
def os_rename(src, dst):
# type: (str, str) -> None
"""
Rename a file to a destination path and handles situations where the destination exists.
:param str src: The current file path.
:param str dst: The new file path.
"""
@ -75,7 +65,7 @@ def os_rename(src, dst):
# We should never go on this line. Either we are on Linux and os.rename has succeeded,
# either we are on Windows, and only Python >= 3.4 is supported where os.replace is
# available.
raise RuntimeError('Error: tried to run os_rename on Python < 3.3. '
raise RuntimeError('Error: tried to run os.replace on Python < 3.3. '
'Certbot supports only Python 3.4 >= on Windows.')
getattr(os, 'replace')(src, dst)

View file

@ -29,3 +29,14 @@ std_sys.modules[__name__ + '.path'] = path
# Clean all remaining importables that are not from the core os module.
del ourselves, std_os, std_sys
# Because of the blocking strategy on file handlers on Windows, rename to not behave as expected
# with POSIX systems: an exception will be raised if dst already exists. Hopefully there is
# os.replace on Windows for Python 3, that will do the same than on POSIX. Hopefully also, only
# Python 3 is supported for Certbot. So we can rely on os.rename on Linux, and os.replace
# on Windows.
def rename(*unused_args, **unused_kwargs): # pylint: disable=function-redefined
"""Method os.rename() is forbidden"""
raise RuntimeError('Usage of os.rename() is forbidden. ' # pragma: no cover
'Use certbot.compat.misc.os_rename() instead.')

View file

@ -1359,7 +1359,7 @@ def main(cli_args=None):
# On windows, shell without administrative right cannot create symlinks required by certbot.
# So we check the rights before continuing.
misc.raise_for_non_administrative_windows_rights(config.verb)
misc.raise_for_non_administrative_windows_rights()
try:
log.post_arg_parse_setup(config)

View file

@ -1,10 +1,10 @@
"""Tests for certbot.compat."""
"""Tests for certbot.compat.misc"""
import certbot.tests.util as test_util
from certbot.compat import misc
from certbot.compat import os
class OsReplaceTest(test_util.TempDirTestCase):
class OsRenameTest(test_util.TempDirTestCase):
"""Test to ensure consistent behavior of os_rename method"""
def test_os_rename_to_existing_file(self):