mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Auto-Update esphomelib dev version (#134)
* Auto-Update esphomelib dev version * Lint
This commit is contained in:
		| @@ -13,23 +13,15 @@ from esphomeyaml.const import CONF_BAUD_RATE, CONF_BUILD_PATH, CONF_DOMAIN, CONF | |||||||
|     CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_USE_CUSTOM_CODE, \ |     CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_USE_CUSTOM_CODE, \ | ||||||
|     CONF_WIFI, ESP_PLATFORM_ESP8266 |     CONF_WIFI, ESP_PLATFORM_ESP8266 | ||||||
| from esphomeyaml.core import ESPHomeYAMLError | from esphomeyaml.core import ESPHomeYAMLError | ||||||
| from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \ | from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, \ | ||||||
|     add_job, color, flush_tasks, indent, quote, statement |     _EXPRESSIONS, add, \ | ||||||
|  |     add_job, color, flush_tasks, indent, quote, statement, relative_path | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
| PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ota', 'mqtt', 'web_server', 'i2c'] | PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ota', 'mqtt', 'web_server', 'i2c'] | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_name(config): |  | ||||||
|     return config[CONF_ESPHOMEYAML][CONF_NAME] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_base_path(config): |  | ||||||
|     build_path = config[CONF_ESPHOMEYAML].get(CONF_BUILD_PATH, get_name(config)) |  | ||||||
|     return os.path.join(os.path.dirname(core.CONFIG_PATH), build_path) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_serial_ports(): | def get_serial_ports(): | ||||||
|     # from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py |     # from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py | ||||||
|     from serial.tools.list_ports import comports |     from serial.tools.list_ports import comports | ||||||
| @@ -148,17 +140,19 @@ def write_cpp(config): | |||||||
|                 exp = exp.rhs |                 exp = exp.rhs | ||||||
|         all_code.append(unicode(statement(exp))) |         all_code.append(unicode(statement(exp))) | ||||||
|  |  | ||||||
|     writer.write_platformio_project(config, get_base_path(config)) |     build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH]) | ||||||
|  |     writer.write_platformio_project(config, build_path) | ||||||
|  |  | ||||||
|     code_s = indent('\n'.join(line.rstrip() for line in all_code)) |     code_s = indent('\n'.join(line.rstrip() for line in all_code)) | ||||||
|     cpp_path = os.path.join(get_base_path(config), 'src', 'main.cpp') |     cpp_path = os.path.join(build_path, 'src', 'main.cpp') | ||||||
|     writer.write_cpp(code_s, cpp_path) |     writer.write_cpp(code_s, cpp_path) | ||||||
|     return 0 |     return 0 | ||||||
|  |  | ||||||
|  |  | ||||||
| def compile_program(args, config): | def compile_program(args, config): | ||||||
|     _LOGGER.info("Compiling app...") |     _LOGGER.info("Compiling app...") | ||||||
|     command = ['platformio', 'run', '-d', get_base_path(config)] |     build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH]) | ||||||
|  |     command = ['platformio', 'run', '-d', build_path] | ||||||
|     if args.verbose: |     if args.verbose: | ||||||
|         command.append('-v') |         command.append('-v') | ||||||
|     return run_platformio(*command) |     return run_platformio(*command) | ||||||
| @@ -177,8 +171,8 @@ def get_upload_host(config): | |||||||
| def upload_using_esptool(config, port): | def upload_using_esptool(config, port): | ||||||
|     import esptool |     import esptool | ||||||
|  |  | ||||||
|     name = get_name(config) |     build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH]) | ||||||
|     path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin') |     path = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin') | ||||||
|     # pylint: disable=protected-access |     # pylint: disable=protected-access | ||||||
|     return run_platformio('esptool.py', '--before', 'default_reset', '--after', 'hard_reset', |     return run_platformio('esptool.py', '--before', 'default_reset', '--after', 'hard_reset', | ||||||
|                           '--chip', 'esp8266', '--port', port, 'write_flash', '0x0', |                           '--chip', 'esp8266', '--port', port, 'write_flash', '0x0', | ||||||
| @@ -187,13 +181,14 @@ def upload_using_esptool(config, port): | |||||||
|  |  | ||||||
| def upload_program(config, args, port): | def upload_program(config, args, port): | ||||||
|     _LOGGER.info("Uploading binary...") |     _LOGGER.info("Uploading binary...") | ||||||
|  |     build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH]) | ||||||
|  |  | ||||||
|     # if upload is to a serial port use platformio, otherwise assume ota |     # if upload is to a serial port use platformio, otherwise assume ota | ||||||
|     serial_port = port.startswith('/') or port.startswith('COM') |     serial_port = port.startswith('/') or port.startswith('COM') | ||||||
|     if port != 'OTA' and serial_port: |     if port != 'OTA' and serial_port: | ||||||
|         if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy: |         if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy: | ||||||
|             return upload_using_esptool(config, port) |             return upload_using_esptool(config, port) | ||||||
|         command = ['platformio', 'run', '-d', get_base_path(config), |         command = ['platformio', 'run', '-d', build_path, | ||||||
|                    '-t', 'upload', '--upload-port', port] |                    '-t', 'upload', '--upload-port', port] | ||||||
|         if args.verbose: |         if args.verbose: | ||||||
|             command.append('-v') |             command.append('-v') | ||||||
| @@ -213,7 +208,7 @@ def upload_program(config, args, port): | |||||||
|     from esphomeyaml.components import ota |     from esphomeyaml.components import ota | ||||||
|     from esphomeyaml import espota |     from esphomeyaml import espota | ||||||
|  |  | ||||||
|     bin_file = os.path.join(get_base_path(config), '.pioenvs', get_name(config), 'firmware.bin') |     bin_file = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin') | ||||||
|     if args.host_port is not None: |     if args.host_port is not None: | ||||||
|         host_port = args.host_port |         host_port = args.host_port | ||||||
|     else: |     else: | ||||||
|   | |||||||
| @@ -242,3 +242,4 @@ CONFIG_PATH = None | |||||||
| ESP_PLATFORM = '' | ESP_PLATFORM = '' | ||||||
| BOARD = '' | BOARD = '' | ||||||
| RAW_CONFIG = None | RAW_CONFIG = None | ||||||
|  | NAME = '' | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
|  | import logging | ||||||
| import os | import os | ||||||
| import re | import re | ||||||
|  | import subprocess | ||||||
|  |  | ||||||
| import voluptuous as vol | import voluptuous as vol | ||||||
|  |  | ||||||
| @@ -15,6 +17,8 @@ from esphomeyaml.core import ESPHomeYAMLError | |||||||
| from esphomeyaml.helpers import App, NoArg, Pvariable, add, const_char_p, esphomelib_ns, \ | from esphomeyaml.helpers import App, NoArg, Pvariable, add, const_char_p, esphomelib_ns, \ | ||||||
|     relative_path |     relative_path | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
| LIBRARY_URI_REPO = u'https://github.com/OttoWinter/esphomelib.git' | LIBRARY_URI_REPO = u'https://github.com/OttoWinter/esphomelib.git' | ||||||
|  |  | ||||||
| BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout'] | BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout'] | ||||||
| @@ -42,11 +46,20 @@ def validate_board(value): | |||||||
| def validate_simple_esphomelib_version(value): | def validate_simple_esphomelib_version(value): | ||||||
|     value = cv.string_strict(value) |     value = cv.string_strict(value) | ||||||
|     if value.upper() == 'LATEST': |     if value.upper() == 'LATEST': | ||||||
|         return LIBRARY_URI_REPO + '#v{}'.format(ESPHOMELIB_VERSION) |         return { | ||||||
|  |             CONF_REPOSITORY: LIBRARY_URI_REPO, | ||||||
|  |             CONF_TAG: 'v' + ESPHOMELIB_VERSION, | ||||||
|  |         } | ||||||
|     elif value.upper() == 'DEV': |     elif value.upper() == 'DEV': | ||||||
|         return LIBRARY_URI_REPO |         return { | ||||||
|  |             CONF_REPOSITORY: LIBRARY_URI_REPO, | ||||||
|  |             CONF_BRANCH: 'master' | ||||||
|  |         } | ||||||
|     elif VERSION_REGEX.match(value) is not None: |     elif VERSION_REGEX.match(value) is not None: | ||||||
|         return LIBRARY_URI_REPO + '#v{}'.format(value) |         return { | ||||||
|  |             CONF_REPOSITORY: LIBRARY_URI_REPO, | ||||||
|  |             CONF_TAG: 'v' + value, | ||||||
|  |         } | ||||||
|     return value |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -60,12 +73,11 @@ def validate_local_esphomelib_version(value): | |||||||
|     return value |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
| def convert_esphomelib_version_schema(value): | def validate_commit(value): | ||||||
|     if CONF_COMMIT in value: |     value = cv.string(value) | ||||||
|         return value[CONF_REPOSITORY] + '#' + value[CONF_COMMIT] |     if re.match(r"^[0-9a-f]{7,}$", value) is None: | ||||||
|     if CONF_BRANCH in value: |         raise vol.Invalid("Commit option only accepts commit hashes in hex format.") | ||||||
|         return value[CONF_REPOSITORY] + '#' + value[CONF_BRANCH] |     return value | ||||||
|     return value[CONF_REPOSITORY] + '#' + value[CONF_TAG] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ESPHOMELIB_VERSION_SCHEMA = vol.Any( | ESPHOMELIB_VERSION_SCHEMA = vol.Any( | ||||||
| @@ -76,12 +88,11 @@ ESPHOMELIB_VERSION_SCHEMA = vol.Any( | |||||||
|     vol.All( |     vol.All( | ||||||
|         vol.Schema({ |         vol.Schema({ | ||||||
|             vol.Optional(CONF_REPOSITORY, default=LIBRARY_URI_REPO): cv.string, |             vol.Optional(CONF_REPOSITORY, default=LIBRARY_URI_REPO): cv.string, | ||||||
|             vol.Optional(CONF_COMMIT, 'tag'): cv.string, |             vol.Optional(CONF_COMMIT): validate_commit, | ||||||
|             vol.Optional(CONF_BRANCH, 'tag'): cv.string, |             vol.Optional(CONF_BRANCH): cv.string, | ||||||
|             vol.Optional(CONF_TAG, 'tag'): cv.string, |             vol.Optional(CONF_TAG): cv.string, | ||||||
|         }), |         }), | ||||||
|         cv.has_at_most_one_key(CONF_COMMIT, CONF_BRANCH, CONF_TAG), |         cv.has_at_most_one_key(CONF_COMMIT, CONF_BRANCH, CONF_TAG) | ||||||
|         convert_esphomelib_version_schema |  | ||||||
|     ), |     ), | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -138,6 +149,10 @@ def validate_arduino_version(value): | |||||||
|         raise NotImplementedError |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def default_build_path(): | ||||||
|  |     return core.NAME | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = vol.Schema({ | CONFIG_SCHEMA = vol.Schema({ | ||||||
|     vol.Required(CONF_NAME): cv.valid_name, |     vol.Required(CONF_NAME): cv.valid_name, | ||||||
|     vol.Required(CONF_PLATFORM): vol.All(vol.Upper, cv.one_of('ESP8266', 'ESPRESSIF8266', |     vol.Required(CONF_PLATFORM): vol.All(vol.Upper, cv.one_of('ESP8266', 'ESPRESSIF8266', | ||||||
| @@ -146,7 +161,7 @@ CONFIG_SCHEMA = vol.Schema({ | |||||||
|     vol.Optional(CONF_ESPHOMELIB_VERSION, default='latest'): ESPHOMELIB_VERSION_SCHEMA, |     vol.Optional(CONF_ESPHOMELIB_VERSION, default='latest'): ESPHOMELIB_VERSION_SCHEMA, | ||||||
|     vol.Optional(CONF_ARDUINO_VERSION, default='recommended'): validate_arduino_version, |     vol.Optional(CONF_ARDUINO_VERSION, default='recommended'): validate_arduino_version, | ||||||
|     vol.Optional(CONF_USE_CUSTOM_CODE, default=False): cv.boolean, |     vol.Optional(CONF_USE_CUSTOM_CODE, default=False): cv.boolean, | ||||||
|     vol.Optional(CONF_BUILD_PATH): cv.string, |     vol.Optional(CONF_BUILD_PATH, default=default_build_path): cv.string, | ||||||
|  |  | ||||||
|     vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)), |     vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)), | ||||||
|     vol.Optional(CONF_ON_BOOT): vol.All(cv.ensure_list, [automation.validate_automation({ |     vol.Optional(CONF_ON_BOOT): vol.All(cv.ensure_list, [automation.validate_automation({ | ||||||
| @@ -173,14 +188,52 @@ def preload_core_config(config): | |||||||
|         raise ESPHomeYAMLError("esphomeyaml.platform not specified.") |         raise ESPHomeYAMLError("esphomeyaml.platform not specified.") | ||||||
|     if CONF_BOARD not in core_conf: |     if CONF_BOARD not in core_conf: | ||||||
|         raise ESPHomeYAMLError("esphomeyaml.board not specified.") |         raise ESPHomeYAMLError("esphomeyaml.board not specified.") | ||||||
|  |     if CONF_NAME not in core_conf: | ||||||
|  |         raise ESPHomeYAMLError("esphomeyaml.name not specified.") | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         core.ESP_PLATFORM = validate_platform(core_conf[CONF_PLATFORM]) |         core.ESP_PLATFORM = validate_platform(core_conf[CONF_PLATFORM]) | ||||||
|         core.BOARD = validate_board(core_conf[CONF_BOARD]) |         core.BOARD = validate_board(core_conf[CONF_BOARD]) | ||||||
|  |         core.NAME = cv.valid_name(core_conf[CONF_NAME]) | ||||||
|     except vol.Invalid as e: |     except vol.Invalid as e: | ||||||
|         raise ESPHomeYAMLError(unicode(e)) |         raise ESPHomeYAMLError(unicode(e)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def run_command(*args): | ||||||
|  |     p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||||||
|  |     stdout, stderr = p.communicate() | ||||||
|  |     rc = p.returncode | ||||||
|  |     return rc, stdout, stderr | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def update_esphomelib_repo(config): | ||||||
|  |     esphomelib_version = config[CONF_ESPHOMELIB_VERSION] | ||||||
|  |     if CONF_REPOSITORY not in esphomelib_version: | ||||||
|  |         return | ||||||
|  |  | ||||||
|  |     build_path = relative_path(config[CONF_BUILD_PATH]) | ||||||
|  |     esphomelib_path = os.path.join(build_path, '.piolibdeps', 'esphomelib') | ||||||
|  |     is_default_branch = all(x not in esphomelib_version | ||||||
|  |                             for x in (CONF_BRANCH, CONF_TAG, CONF_COMMIT)) | ||||||
|  |     if not (CONF_BRANCH in esphomelib_version or is_default_branch): | ||||||
|  |         # Git commit hash or tag cannot be updated | ||||||
|  |         return | ||||||
|  |  | ||||||
|  |     rc, _, _ = run_command('git', '-C', esphomelib_path, '--help') | ||||||
|  |     if rc != 0: | ||||||
|  |         # git not installed or repo not downloaded yet | ||||||
|  |         return | ||||||
|  |     rc, _, _ = run_command('git', '-C', esphomelib_path, 'diff-index', '--quiet', 'HEAD', '--') | ||||||
|  |     if rc != 0: | ||||||
|  |         # local changes, cannot update | ||||||
|  |         _LOGGER.warn("Local changes in esphomelib copy from git. Will not auto-update.") | ||||||
|  |         return | ||||||
|  |     rc, _, _ = run_command('git', '-C', esphomelib_path, 'pull') | ||||||
|  |     if rc != 0: | ||||||
|  |         _LOGGER.warn("Couldn't auto-update local git copy of esphomelib.") | ||||||
|  |         return | ||||||
|  |  | ||||||
|  |  | ||||||
| def to_code(config): | def to_code(config): | ||||||
|     add(App.set_name(config[CONF_NAME])) |     add(App.set_name(config[CONF_NAME])) | ||||||
|  |  | ||||||
| @@ -197,3 +250,5 @@ def to_code(config): | |||||||
|         rhs = App.register_component(LoopTrigger.new()) |         rhs = App.register_component(LoopTrigger.new()) | ||||||
|         trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs) |         trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs) | ||||||
|         automation.build_automation(trigger, NoArg, conf) |         automation.build_automation(trigger, NoArg, conf) | ||||||
|  |  | ||||||
|  |     update_esphomelib_repo(config) | ||||||
|   | |||||||
| @@ -9,10 +9,11 @@ import os | |||||||
| import random | import random | ||||||
| import subprocess | import subprocess | ||||||
|  |  | ||||||
|  | from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_BUILD_PATH | ||||||
| from esphomeyaml.core import ESPHomeYAMLError | from esphomeyaml.core import ESPHomeYAMLError | ||||||
| from esphomeyaml import const, core, __main__ | from esphomeyaml import const, core, __main__ | ||||||
| from esphomeyaml.__main__ import get_serial_ports, get_base_path, get_name | from esphomeyaml.__main__ import get_serial_ports | ||||||
| from esphomeyaml.helpers import quote | from esphomeyaml.helpers import quote, relative_path | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     import tornado |     import tornado | ||||||
| @@ -161,10 +162,10 @@ class DownloadBinaryRequestHandler(BaseHandler): | |||||||
|         config_file = os.path.join(CONFIG_DIR, configuration) |         config_file = os.path.join(CONFIG_DIR, configuration) | ||||||
|         core.CONFIG_PATH = config_file |         core.CONFIG_PATH = config_file | ||||||
|         config = __main__.read_config(core.CONFIG_PATH) |         config = __main__.read_config(core.CONFIG_PATH) | ||||||
|         name = get_name(config) |         build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH]) | ||||||
|         path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin') |         path = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin') | ||||||
|         self.set_header('Content-Type', 'application/octet-stream') |         self.set_header('Content-Type', 'application/octet-stream') | ||||||
|         self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(name)) |         self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(core.NAME)) | ||||||
|         with open(path, 'rb') as f: |         with open(path, 'rb') as f: | ||||||
|             while 1: |             while 1: | ||||||
|                 data = f.read(16384)  # or some other nice-sized chunk |                 data = f.read(16384)  # or some other nice-sized chunk | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ from esphomeyaml import core | |||||||
| from esphomeyaml.config import iter_components | from esphomeyaml.config import iter_components | ||||||
| from esphomeyaml.const import ARDUINO_VERSION_ESP32_DEV, CONF_ARDUINO_VERSION, CONF_BOARD, \ | from esphomeyaml.const import ARDUINO_VERSION_ESP32_DEV, CONF_ARDUINO_VERSION, CONF_BOARD, \ | ||||||
|     CONF_BOARD_FLASH_MODE, CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, CONF_LOCAL, CONF_NAME, \ |     CONF_BOARD_FLASH_MODE, CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, CONF_LOCAL, CONF_NAME, \ | ||||||
|     CONF_USE_CUSTOM_CODE, ESP_PLATFORM_ESP32 |     CONF_USE_CUSTOM_CODE, ESP_PLATFORM_ESP32, CONF_REPOSITORY, CONF_COMMIT, CONF_BRANCH, CONF_TAG | ||||||
| from esphomeyaml.core import ESPHomeYAMLError | from esphomeyaml.core import ESPHomeYAMLError | ||||||
| from esphomeyaml.core_config import VERSION_REGEX | from esphomeyaml.core_config import VERSION_REGEX | ||||||
| from esphomeyaml.helpers import relative_path | from esphomeyaml.helpers import relative_path | ||||||
| @@ -111,8 +111,13 @@ def get_ini_content(config, path): | |||||||
|     lib_version = config[CONF_ESPHOMEYAML][CONF_ESPHOMELIB_VERSION] |     lib_version = config[CONF_ESPHOMEYAML][CONF_ESPHOMELIB_VERSION] | ||||||
|     lib_path = os.path.join(path, 'lib') |     lib_path = os.path.join(path, 'lib') | ||||||
|     dst_path = os.path.join(lib_path, 'esphomelib') |     dst_path = os.path.join(lib_path, 'esphomelib') | ||||||
|     if isinstance(lib_version, (str, unicode)): |     if CONF_REPOSITORY in lib_version: | ||||||
|         lib_deps.add(lib_version) |         tag = next((lib_version[x] for x in (CONF_COMMIT, CONF_BRANCH, CONF_TAG) | ||||||
|  |                     if x in lib_version), None) | ||||||
|  |         if tag is None: | ||||||
|  |             lib_deps.add(lib_version[CONF_REPOSITORY]) | ||||||
|  |         else: | ||||||
|  |             lib_deps.add(lib_version[CONF_REPOSITORY] + '#' + tag) | ||||||
|         if os.path.islink(dst_path): |         if os.path.islink(dst_path): | ||||||
|             os.unlink(dst_path) |             os.unlink(dst_path) | ||||||
|     else: |     else: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user