| #!/usr/bin/env python |
| # |
| # Copyright 2019 The Cobalt Authors. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| |
| ################################################################################ |
| # API # |
| ################################################################################ |
| |
| |
| def IsWindows(): |
| return _IsWindows() |
| |
| |
| # Platform neutral version os os.path.islink() |
| def IsSymLink(path): |
| return _IsSymLink(path=path) |
| |
| |
| def MakeSymLink(from_folder, link_folder): |
| return _MakeSymLink(from_folder=from_folder, link_folder=link_folder) |
| |
| |
| def ReadSymLink(link_path): |
| return _ReadSymLink(link_path=link_path) |
| |
| |
| def DelSymLink(link_path): |
| return _DelSymLink(link_path=link_path) |
| |
| |
| def Rmtree(path): |
| return _Rmtree(path=path) |
| |
| |
| def OsWalk(root_dir, topdown=True, onerror=None, followlinks=False): |
| return _OsWalk(root_dir=root_dir, |
| topdown=topdown, |
| onerror=onerror, |
| followlinks=followlinks) |
| |
| |
| ################################################################################ |
| # IMPL # |
| ################################################################################ |
| |
| |
| import os |
| import sys |
| |
| import _env |
| |
| |
| def _IsWindows(): |
| return sys.platform in ['win32', 'cygwin'] |
| |
| |
| def _IsSymLink(path): |
| if _IsWindows(): |
| from starboard.build.win_symlink import IsReparsePoint |
| return IsReparsePoint(path) |
| else: |
| return os.path.islink(path) |
| |
| |
| def _MakeSymLink(from_folder, link_folder): |
| if _IsWindows(): |
| from starboard.build.win_symlink import CreateReparsePoint |
| return CreateReparsePoint(from_folder, link_folder) |
| else: |
| os.link(from_folder, link_folder) |
| |
| |
| def _ReadSymLink(link_path): |
| """Returns a absolute path to the folder referred to by the link_path.""" |
| if IsWindows(): |
| from starboard.build.win_symlink import ReadReparsePoint |
| path = ReadReparsePoint(link_path) |
| else: |
| path = os.readlink(link_path) |
| if path and '..' in path: |
| path = os.path.abspath(os.path.normpath(os.path.join(link_path, path))) |
| return path |
| |
| |
| def _DelSymLink(link_path): |
| if IsWindows(): |
| from starboard.build.win_symlink import UnlinkReparsePoint |
| UnlinkReparsePoint(link_path) |
| else: |
| os.unlink(link_path) |
| |
| |
| |
| def _Rmtree(path): |
| if not os.path.exists(path): |
| return |
| if _IsWindows(): |
| from starboard.build.win_symlink import RmtreeShallow |
| RmtreeShallow(path) |
| else: |
| shutil.rmtree(path) |
| |
| def _OsWalk(root_dir, topdown=True, onerror=None, followlinks=False): |
| if IsWindows(): |
| from starboard.build.win_symlink import OsWalk |
| return OsWalk(root_dir, topdown, onerror, followlinks) |
| else: |
| return os.walk(root_dir, topdown, onerror, followlinks) |
| |
| |
| def _IsSamePath(p1, p2): |
| if not p1: |
| p1 = None |
| if not p2: |
| p2 = None |
| if p1 == p2: |
| return True |
| if (not p1) or (not p2): |
| return False |
| p1 = os.path.abspath(os.path.normpath(p1)) |
| p2 = os.path.abspath(os.path.normpath(p2)) |
| if p1 == p2: |
| return True |
| try: |
| return os.stat(p1) == os.stat(p2) |
| except: |
| return False |
| |
| |
| def UnitTest(): |
| """Tests that a small directory hierarchy can be created and then symlinked, |
| and then removed.""" |
| tmp_dir = os.path.join(os.environ['temp'], 'win_symlink') |
| from_dir = os.path.join(tmp_dir, 'from_dir') |
| test_txt = os.path.join(from_dir, 'test.txt') |
| inner_dir = os.path.join(from_dir, 'inner_dir') |
| link_dir = os.path.join(tmp_dir, 'link') |
| link_dir2 = os.path.join(tmp_dir, 'link2') |
| if IsSymLink(link_dir): |
| print "Deleting previous link_dir:", link_dir |
| DelSymLink(link_dir) |
| else: |
| print "Previous link dir does not exist." |
| print "from_dir:", os.path.abspath(from_dir) |
| print "link_dir:", os.path.abspath(link_dir) |
| print "link_dir exists? ", ReadSymLink(link_dir) |
| |
| if not os.path.isdir(from_dir): |
| os.makedirs(from_dir) |
| if not os.path.isdir(inner_dir): |
| os.makedirs(inner_dir) |
| with open(test_txt, 'w') as fd: |
| fd.write('hello world') |
| |
| # Check that the ReadReparsePoint handles non link objects ok. |
| if ReadSymLink(from_dir): |
| raise IOError("Exepected ReadSymLink() to return None for " + from_dir) |
| if ReadSymLink(test_txt): |
| raise IOError("Exepected ReadSymLink() to return None for " + test_txt) |
| |
| MakeSymLink(from_dir, link_dir) |
| |
| link_created_ok = IsSymLink(link_dir) |
| if link_created_ok: |
| print("Link created: " + str(link_created_ok)) |
| else: |
| raise IOError("Failed to create link " + link_dir) |
| |
| if not os.path.exists(link_dir): |
| raise IOError('os.path.exists(link_dir) is False.') |
| |
| MakeSymLink(from_dir, link_dir2) |
| if not IsSymLink(link_dir2): |
| raise IOError("Failed to create link " + link_dir2) |
| DelSymLink(link_dir2) |
| if os.path.exists(link_dir2): |
| raise IOError("Still exists: " + link_dir2) |
| |
| from_dir_2 = ReadSymLink(link_dir) |
| if _IsSamePath(from_dir_2, from_dir): |
| print "Link exists." |
| else: |
| raise IOError("Link mismatch: " + from_dir_2 + ' != ' + from_dir) |
| def GetAllPaths(start_dir, followlinks): |
| paths = [] |
| for root, dirs, files in OsWalk(tmp_dir, followlinks=followlinks): |
| for name in files: |
| path = os.path.join(root, name) |
| paths.append(path) |
| for name in dirs: |
| path = os.path.join(root, name) |
| paths.append(path) |
| return paths |
| def PathTypeToString(path): |
| if IsSymLink(path): |
| return 'link' |
| if os.path.isdir(path): |
| return 'dir' |
| return 'file' |
| paths_nofollow_links = GetAllPaths(tmp_dir, followlinks=False) |
| paths_follow_links = GetAllPaths(tmp_dir, followlinks=True) |
| print '\nOsWalk Follow links:' |
| for path in paths_follow_links: |
| print ' ' + path + ' (' + PathTypeToString(path) + ')' |
| print '\nOsWalk No-Follow links:' |
| for path in paths_nofollow_links: |
| print ' ' + path + ' (' + PathTypeToString(path) + ')' |
| print '' |
| |
| assert(link_dir in paths_nofollow_links) |
| assert(link_dir in paths_follow_links) |
| assert(os.path.join(link_dir, 'test.txt') in paths_follow_links) |
| assert(not os.path.join(link_dir, 'test.txt') in paths_nofollow_links) |
| Rmtree(link_dir) |
| if os.path.exists(link_dir): |
| raise IOError("Link dir " + link_dir + " still exists.") |
| if not os.path.exists(from_dir): |
| raise IOError("From Dir " + from_dir + " was deleted!") |
| print "Test completed." |
| |
| |
| if __name__ == "__main__": |
| UnitTest() |