From 9a7b82d61fb4664dc44a45a8ca410af008474fbf Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 30 Apr 2019 09:45:25 +0200 Subject: [PATCH] idf.py: Detect symlinks on Windows during fullclean Closes https://github.com/espressif/esp-idf/issues/3377 --- tools/idf.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/idf.py b/tools/idf.py index cdce7b7cc..e4d31c7c3 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -286,6 +286,27 @@ def clean(action, args): def reconfigure(action, args): _ensure_build_directory(args, True) + +def _delete_windows_symlinks(directory): + """ + It deletes symlinks recursively on Windows. It is useful for Python 2 which doesn't detect symlinks on Windows. + """ + deleted_paths = [] + if os.name == 'nt': + import ctypes + for root, dirnames, filenames in os.walk(directory): + for d in dirnames: + full_path = os.path.join(root, d) + try: + full_path = full_path.decode('utf-8') + except Exception: + pass + if ctypes.windll.kernel32.GetFileAttributesW(full_path) & 0x0400: + os.rmdir(full_path) + deleted_paths.append(full_path) + return deleted_paths + + def fullclean(action, args): build_dir = args.build_dir if not os.path.isdir(build_dir): @@ -303,8 +324,16 @@ def fullclean(action, args): if os.path.exists(red): raise FatalError("Refusing to automatically delete files in directory containing '%s'. Delete files manually if you're sure." % red) # OK, delete everything in the build directory... + # Note: Python 2.7 doesn't detect symlinks on Windows (it is supported form 3.2). Tools promising to not + # follow symlinks will actually follow them. Deleting the build directory with symlinks deletes also items + # outside of this directory. + deleted_symlinks = _delete_windows_symlinks(build_dir) + if args.verbose and len(deleted_symlinks) > 1: + print('The following symlinks were identified and removed:\n%s' % "\n".join(deleted_symlinks)) for f in os.listdir(build_dir): # TODO: once we are Python 3 only, this can be os.scandir() f = os.path.join(build_dir, f) + if args.verbose: + print('Removing: %s' % f) if os.path.isdir(f): shutil.rmtree(f) else: