From e352fb05c099df3d7da629ee1652dec88cc57aea Mon Sep 17 00:00:00 2001 From: Thomas Nagy Date: Thu, 2 Mar 2017 20:45:01 +0100 Subject: [PATCH] UNC path fixes --- ChangeLog | 1 + tests/apis/wscript | 49 ++++++++++++++++++--- waflib/Node.py | 5 +++ waflib/Utils.py | 8 ++-- waflib/extras/unc.py | 102 ------------------------------------------- 5 files changed, 53 insertions(+), 112 deletions(-) delete mode 100644 waflib/extras/unc.py diff --git a/ChangeLog b/ChangeLog index 9f8f018b..62324d29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ NEW IN WAF 2.0.0 * Provide a new priority system to improve scalability on complex builds * Provide TaskGroup objects to improve scalability on complex builds * Force new files into the build directory by default (use Node objects to bypass) +* Process support for building over UNC paths * Simplify the Task class hierarchy; TaskBase is removed * New ant_glob(..., generator=True) now returns a Python generator * Accept nested lists and generators in bld(source=...) diff --git a/tests/apis/wscript b/tests/apis/wscript index bba9bed4..75ecb83c 100755 --- a/tests/apis/wscript +++ b/tests/apis/wscript @@ -3,12 +3,6 @@ import os, shutil from waflib import Node, Build, Utils, Logs -def tt(msg, result, expected): - color = 'RED' - if result == expected: - color = 'GREEN' - Logs.pprint(color, msg.ljust(20) + " %r" % result) - def exists(path): try: os.stat(path) @@ -40,6 +34,15 @@ def configure(ctx): def test(ctx): bld = Build.BuildContext() + errors = [] + def tt(msg, result, expected): + color = 'RED' + if result == expected: + color = 'GREEN' + else: + errors.append(result) + Logs.pprint(color, msg.ljust(20) + " %r" % result) + # 1. absdir is wrong, keep the drive letter # 2. split should use os.sep @@ -119,7 +122,7 @@ def test(ctx): nf.write("aha") nf.get_bld_sig() tt('find_resource src/abc', bld.srcnode.find_resource(['abc']), nf) - tt('find_or_declare src/abc', bld.srcnode.find_or_declare(['abc']), nf) + tt('find_or_declare src/abc', bld.srcnode.find_or_declare(['abc']), bld.bldnode.make_node(['abc'])) tt('src.get_bld()', bld.srcnode.get_bld(), bld.bldnode) tt('bld.get_src()', bld.bldnode.get_src(), bld.srcnode) @@ -141,3 +144,35 @@ def test(ctx): tt("ant_glob ->", len(bld.srcnode.ant_glob('*.txt', flat=False)), 1) #print("ant_glob src ->", bld.srcnode.ant_glob('*.txt')) + def abspath(self): + try: + return self.cache_abspath + except AttributeError: + pass + if not self.parent: + val = '' + elif not self.parent.name: + val = self.name + '\\' + else: + val = self.parent.abspath().rstrip('\\') + '\\' + self.name + self.cache_abspath = val + return val + + # the local class will be unused soon enough + old_abspath = bld.node_class.abspath + bld.node_class.abspath = abspath + + unc1 = '\\\\computer\\share\\file' + lst = Utils.split_path_win32(unc1) + node = bld.root.make_node(lst) + tt('UNC head node', lst[0], '\\\\computer') + tt('UNC share path', node.abspath(), unc1) + + unc2 = '\\\\?\\C:\\foo' + lst = Utils.split_path_win32(unc2) + node = bld.root.make_node(lst) + tt('UNC long path', node.abspath(), 'C:\\foo') + + if errors: + bld.fatal('There are test failures ^^') + diff --git a/waflib/Node.py b/waflib/Node.py index c9da4133..39eb86d9 100644 --- a/waflib/Node.py +++ b/waflib/Node.py @@ -340,6 +340,11 @@ class Node(object): if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] + if lst and lst[0].startswith('\\\\') and not self.parent: + node = self.ctx.root.make_node(lst[0]) + node.cache_isdir = True + return node.find_node(lst[1:]) + cur = self for x in lst: if x == '..': diff --git a/waflib/Utils.py b/waflib/Utils.py index 6cb0f94a..62fae456 100644 --- a/waflib/Utils.py +++ b/waflib/Utils.py @@ -461,14 +461,16 @@ def split_path_cygwin(path): re_sp = re.compile('[/\\\\]+') def split_path_win32(path): if path.startswith('\\\\'): - ret = re_sp.split(path)[2:] - ret[0] = '\\' + ret[0] + ret = re_sp.split(path)[1:] + ret[0] = '\\\\' + ret[0] + if ret[0] == '\\\\?': + return ret[1:] return ret return re_sp.split(path) msysroot = None def split_path_msys(path): - if path.startswith(('/', '\\')) and not path.startswith(('\\', '\\\\')): + if path.startswith(('/', '\\')) and not path.startswith(('//', '\\\\')): # msys paths can be in the form /usr/bin global msysroot if not msysroot: diff --git a/waflib/extras/unc.py b/waflib/extras/unc.py deleted file mode 100644 index 81865b7e..00000000 --- a/waflib/extras/unc.py +++ /dev/null @@ -1,102 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 -# Thomas Nagy, 2014 (ita) - -""" -This module enables automatic handling of network paths of the form \\server\share for both input -and output files. While a typical script may require the following:: - - import os - def build(bld): - - node = bld.root.make_node('\\\\COMPUTER\\share\\test.txt') - - # mark the server/share levels as folders - k = node.parent - while k: - k.cache_isdir = True - k = k.parent - - # create the folder structure - if node.parent.height() > 2: - node.parent.mkdir() - - # then the task generator - def myfun(tsk): - tsk.outputs[0].write("data") - bld(rule=myfun, source='wscript', target=[nd]) - -this tool will make the process much easier, for example:: - - def configure(conf): - conf.load('unc') # do not import the module directly - - def build(bld): - def myfun(tsk): - tsk.outputs[0].write("data") - bld(rule=myfun, source='wscript', target='\\\\COMPUTER\\share\\test.txt') - bld(rule=myfun, source='\\\\COMPUTER\\share\\test.txt', target='\\\\COMPUTER\\share\\test2.txt') -""" - -import os -from waflib import Node, Utils, Context - -def find_resource(self, lst): - if isinstance(lst, str): - lst = [x for x in Utils.split_path(lst) if x and x != '.'] - - if lst[0].startswith('\\\\'): - if len(lst) < 3: - return None - node = self.ctx.root.make_node(lst[0]).make_node(lst[1]) - node.cache_isdir = True - node.parent.cache_isdir = True - - ret = node.search_node(lst[2:]) - if not ret: - ret = node.find_node(lst[2:]) - if ret and os.path.isdir(ret.abspath()): - return None - return ret - - return self.find_resource_orig(lst) - -def find_or_declare(self, lst): - if isinstance(lst, str): - lst = [x for x in Utils.split_path(lst) if x and x != '.'] - - if lst[0].startswith('\\\\'): - if len(lst) < 3: - return None - node = self.ctx.root.make_node(lst[0]).make_node(lst[1]) - node.cache_isdir = True - node.parent.cache_isdir = True - ret = node.find_node(lst[2:]) - if not ret: - ret = node.make_node(lst[2:]) - if not os.path.isfile(ret.abspath()): - ret.parent.mkdir() - return ret - - return self.find_or_declare_orig(lst) - -def abspath(self): - """For MAX_PATH limitations""" - ret = self.abspath_orig() - if not ret.startswith("\\"): - return "\\\\?\\" + ret - return ret - -if Utils.is_win32: - Node.Node.find_resource_orig = Node.Node.find_resource - Node.Node.find_resource = find_resource - - Node.Node.find_or_declare_orig = Node.Node.find_or_declare - Node.Node.find_or_declare = find_or_declare - - Node.Node.abspath_orig = Node.Node.abspath - Node.Node.abspath = abspath - - for k in list(Context.cache_modules.keys()): - Context.cache_modules["\\\\?\\" + k] = Context.cache_modules[k] -