mirror of
https://github.com/Relintai/scons_gd.git
synced 2025-02-10 16:40:14 +01:00
4057 lines
133 KiB
Python
4057 lines
133 KiB
Python
# MIT License
|
|
#
|
|
# Copyright The SCons Foundation
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
import SCons.compat
|
|
import os
|
|
import os.path
|
|
import sys
|
|
import time
|
|
import unittest
|
|
import shutil
|
|
import stat
|
|
|
|
from TestCmd import TestCmd, IS_WINDOWS
|
|
|
|
import SCons.Errors
|
|
import SCons.Node.FS
|
|
import SCons.Util
|
|
import SCons.Warnings
|
|
import SCons.Environment
|
|
|
|
built_it = None
|
|
|
|
scanner_count = 0
|
|
|
|
|
|
class Scanner:
|
|
def __init__(self, node=None):
|
|
global scanner_count
|
|
scanner_count = scanner_count + 1
|
|
self.hash = scanner_count
|
|
self.node = node
|
|
|
|
def path(self, env, dir, target=None, source=None):
|
|
return ()
|
|
|
|
def __call__(self, node, env, path):
|
|
return [self.node]
|
|
|
|
def __hash__(self):
|
|
return self.hash
|
|
|
|
def select(self, node):
|
|
return self
|
|
|
|
def recurse_nodes(self, nodes):
|
|
return nodes
|
|
|
|
|
|
class Environment:
|
|
def __init__(self):
|
|
self.scanner = Scanner()
|
|
|
|
def Dictionary(self, *args):
|
|
return {}
|
|
|
|
def autogenerate(self, **kw):
|
|
return {}
|
|
|
|
def get_scanner(self, skey):
|
|
return self.scanner
|
|
|
|
def Override(self, overrides):
|
|
return self
|
|
|
|
def _update(self, dict):
|
|
pass
|
|
|
|
|
|
class Action:
|
|
def __call__(self, targets, sources, env, **kw):
|
|
global built_it
|
|
if kw.get('execute', 1):
|
|
built_it = 1
|
|
return 0
|
|
|
|
def show(self, string):
|
|
pass
|
|
|
|
def get_contents(self, target, source, env):
|
|
return bytearray("", 'utf-8')
|
|
|
|
def genstring(self, target, source, env):
|
|
return ""
|
|
|
|
def strfunction(self, targets, sources, env):
|
|
return ""
|
|
|
|
def get_implicit_deps(self, target, source, env):
|
|
return []
|
|
|
|
|
|
class Builder:
|
|
def __init__(self, factory, action=Action()):
|
|
self.factory = factory
|
|
self.env = Environment()
|
|
self.overrides = {}
|
|
self.action = action
|
|
self.target_scanner = None
|
|
self.source_scanner = None
|
|
|
|
def targets(self, t):
|
|
return [t]
|
|
|
|
def source_factory(self, name):
|
|
return self.factory(name)
|
|
|
|
|
|
class _tempdirTestCase(unittest.TestCase):
|
|
def setUp(self):
|
|
self.save_cwd = os.getcwd()
|
|
self.test = TestCmd(workdir='')
|
|
# FS doesn't like the cwd to be something other than its root.
|
|
os.chdir(self.test.workpath(""))
|
|
self.fs = SCons.Node.FS.FS()
|
|
|
|
def tearDown(self):
|
|
os.chdir(self.save_cwd)
|
|
|
|
|
|
class VariantDirTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test variant dir functionality"""
|
|
test = TestCmd(workdir='')
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
f1 = fs.File('build/test1')
|
|
fs.VariantDir('build', 'src')
|
|
f2 = fs.File('build/test2')
|
|
d1 = fs.Dir('build')
|
|
assert f1.srcnode().get_internal_path() == os.path.normpath('src/test1'), f1.srcnode().get_internal_path()
|
|
assert f2.srcnode().get_internal_path() == os.path.normpath('src/test2'), f2.srcnode().get_internal_path()
|
|
assert d1.srcnode().get_internal_path() == 'src', d1.srcnode().get_internal_path()
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
f1 = fs.File('build/test1')
|
|
fs.VariantDir('build', '.')
|
|
f2 = fs.File('build/test2')
|
|
d1 = fs.Dir('build')
|
|
assert f1.srcnode().get_internal_path() == 'test1', f1.srcnode().get_internal_path()
|
|
assert f2.srcnode().get_internal_path() == 'test2', f2.srcnode().get_internal_path()
|
|
assert d1.srcnode().get_internal_path() == '.', d1.srcnode().get_internal_path()
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
fs.VariantDir('build/var1', 'src')
|
|
fs.VariantDir('build/var2', 'src')
|
|
f1 = fs.File('build/var1/test1')
|
|
f2 = fs.File('build/var2/test1')
|
|
assert f1.srcnode().get_internal_path() == os.path.normpath('src/test1'), f1.srcnode().get_internal_path()
|
|
assert f2.srcnode().get_internal_path() == os.path.normpath('src/test1'), f2.srcnode().get_internal_path()
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
fs.VariantDir('../var1', 'src')
|
|
fs.VariantDir('../var2', 'src')
|
|
f1 = fs.File('../var1/test1')
|
|
f2 = fs.File('../var2/test1')
|
|
assert f1.srcnode().get_internal_path() == os.path.normpath('src/test1'), f1.srcnode().get_internal_path()
|
|
assert f2.srcnode().get_internal_path() == os.path.normpath('src/test1'), f2.srcnode().get_internal_path()
|
|
|
|
# Set up some files
|
|
test.subdir('work', ['work', 'src'])
|
|
test.subdir(['work', 'build'], ['work', 'build', 'var1'])
|
|
test.subdir(['work', 'build', 'var2'])
|
|
test.subdir('rep1', ['rep1', 'src'])
|
|
test.subdir(['rep1', 'build'], ['rep1', 'build', 'var1'])
|
|
test.subdir(['rep1', 'build', 'var2'])
|
|
|
|
# A source file in the source directory
|
|
test.write(['work', 'src', 'test.in'], 'test.in')
|
|
|
|
# A source file in a subdir of the source directory
|
|
test.subdir(['work', 'src', 'new_dir'])
|
|
test.write(['work', 'src', 'new_dir', 'test9.out'], 'test9.out\n')
|
|
|
|
# A source file in the repository
|
|
test.write(['rep1', 'src', 'test2.in'], 'test2.in')
|
|
|
|
# Some source files in the variant directory
|
|
test.write(['work', 'build', 'var2', 'test.in'], 'test.old')
|
|
test.write(['work', 'build', 'var2', 'test2.in'], 'test2.old')
|
|
|
|
# An old derived file in the variant directories
|
|
test.write(['work', 'build', 'var1', 'test.out'], 'test.old')
|
|
test.write(['work', 'build', 'var2', 'test.out'], 'test.old')
|
|
|
|
# And just in case we are weird, a derived file in the source
|
|
# dir.
|
|
test.write(['work', 'src', 'test.out'], 'test.out.src')
|
|
|
|
# A derived file in the repository
|
|
test.write(['rep1', 'build', 'var1', 'test2.out'], 'test2.out_rep')
|
|
test.write(['rep1', 'build', 'var2', 'test2.out'], 'test2.out_rep')
|
|
|
|
os.chdir(test.workpath('work'))
|
|
|
|
fs = SCons.Node.FS.FS(test.workpath('work'))
|
|
fs.VariantDir('build/var1', 'src', duplicate=0)
|
|
fs.VariantDir('build/var2', 'src')
|
|
f1 = fs.File('build/var1/test.in')
|
|
f1out = fs.File('build/var1/test.out')
|
|
f1out.builder = 1
|
|
f1out_2 = fs.File('build/var1/test2.out')
|
|
f1out_2.builder = 1
|
|
f2 = fs.File('build/var2/test.in')
|
|
f2out = fs.File('build/var2/test.out')
|
|
f2out.builder = 1
|
|
f2out_2 = fs.File('build/var2/test2.out')
|
|
f2out_2.builder = 1
|
|
fs.Repository(test.workpath('rep1'))
|
|
|
|
assert f1.srcnode().get_internal_path() == os.path.normpath('src/test.in'), \
|
|
f1.srcnode().get_internal_path()
|
|
# str(node) returns source path for duplicate = 0
|
|
assert str(f1) == os.path.normpath('src/test.in'), str(f1)
|
|
# Build path does not exist
|
|
assert not f1.exists()
|
|
# ...but the actual file is not there...
|
|
assert not os.path.exists(f1.get_abspath())
|
|
# And duplicate=0 should also work just like a Repository
|
|
assert f1.rexists()
|
|
# rfile() should point to the source path
|
|
assert f1.rfile().get_internal_path() == os.path.normpath('src/test.in'), \
|
|
f1.rfile().get_internal_path()
|
|
|
|
assert f2.srcnode().get_internal_path() == os.path.normpath('src/test.in'), \
|
|
f2.srcnode().get_internal_path()
|
|
# str(node) returns build path for duplicate = 1
|
|
assert str(f2) == os.path.normpath('build/var2/test.in'), str(f2)
|
|
# Build path exists
|
|
assert f2.exists()
|
|
# ...and exists() should copy the file from src to build path
|
|
assert test.read(['work', 'build', 'var2', 'test.in']) == bytearray('test.in', 'utf-8'), \
|
|
test.read(['work', 'build', 'var2', 'test.in'])
|
|
# Since exists() is true, so should rexists() be
|
|
assert f2.rexists()
|
|
|
|
f3 = fs.File('build/var1/test2.in')
|
|
f4 = fs.File('build/var2/test2.in')
|
|
|
|
assert f3.srcnode().get_internal_path() == os.path.normpath('src/test2.in'), \
|
|
f3.srcnode().get_internal_path()
|
|
# str(node) returns source path for duplicate = 0
|
|
assert str(f3) == os.path.normpath('src/test2.in'), str(f3)
|
|
# Build path does not exist
|
|
assert not f3.exists()
|
|
# Source path does not either
|
|
assert not f3.srcnode().exists()
|
|
# But we do have a file in the Repository
|
|
assert f3.rexists()
|
|
# rfile() should point to the source path
|
|
assert f3.rfile().get_internal_path() == os.path.normpath(test.workpath('rep1/src/test2.in')), \
|
|
f3.rfile().get_internal_path()
|
|
|
|
assert f4.srcnode().get_internal_path() == os.path.normpath('src/test2.in'), \
|
|
f4.srcnode().get_internal_path()
|
|
# str(node) returns build path for duplicate = 1
|
|
assert str(f4) == os.path.normpath('build/var2/test2.in'), str(f4)
|
|
# Build path should exist
|
|
assert f4.exists()
|
|
# ...and copy over the file into the local build path
|
|
assert test.read(['work', 'build', 'var2', 'test2.in']) == bytearray('test2.in', 'utf-8')
|
|
# should exist in repository, since exists() is true
|
|
assert f4.rexists()
|
|
# rfile() should point to ourselves
|
|
assert f4.rfile().get_internal_path() == os.path.normpath('build/var2/test2.in'), \
|
|
f4.rfile().get_internal_path()
|
|
|
|
f5 = fs.File('build/var1/test.out')
|
|
f6 = fs.File('build/var2/test.out')
|
|
|
|
assert f5.exists()
|
|
# We should not copy the file from the source dir, since this is
|
|
# a derived file.
|
|
assert test.read(['work', 'build', 'var1', 'test.out']) == bytearray('test.old', 'utf-8')
|
|
|
|
assert f6.exists()
|
|
# We should not copy the file from the source dir, since this is
|
|
# a derived file.
|
|
assert test.read(['work', 'build', 'var2', 'test.out']) == bytearray('test.old', 'utf-8')
|
|
|
|
f7 = fs.File('build/var1/test2.out')
|
|
f8 = fs.File('build/var2/test2.out')
|
|
|
|
assert not f7.exists()
|
|
assert f7.rexists()
|
|
r = f7.rfile().get_internal_path()
|
|
expect = os.path.normpath(test.workpath('rep1/build/var1/test2.out'))
|
|
assert r == expect, (repr(r), repr(expect))
|
|
|
|
assert not f8.exists()
|
|
assert f8.rexists()
|
|
assert f8.rfile().get_internal_path() == os.path.normpath(test.workpath('rep1/build/var2/test2.out')), \
|
|
f8.rfile().get_internal_path()
|
|
|
|
# Verify the Mkdir and Link actions are called
|
|
d9 = fs.Dir('build/var2/new_dir')
|
|
f9 = fs.File('build/var2/new_dir/test9.out')
|
|
|
|
class MkdirAction(Action):
|
|
def __init__(self, dir_made):
|
|
self.dir_made = dir_made
|
|
|
|
def __call__(self, target, source, env, executor=None):
|
|
if executor:
|
|
target = executor.get_all_targets()
|
|
source = executor.get_all_sources()
|
|
self.dir_made.extend(target)
|
|
|
|
save_Link = SCons.Node.FS.Link
|
|
link_made = []
|
|
|
|
def link_func(target, source, env, link_made=link_made):
|
|
link_made.append(target)
|
|
|
|
SCons.Node.FS.Link = link_func
|
|
|
|
try:
|
|
dir_made = []
|
|
d9.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
|
|
d9.reset_executor()
|
|
f9.exists()
|
|
expect = os.path.join('build', 'var2', 'new_dir')
|
|
assert dir_made[0].get_internal_path() == expect, dir_made[0].get_internal_path()
|
|
expect = os.path.join('build', 'var2', 'new_dir', 'test9.out')
|
|
assert link_made[0].get_internal_path() == expect, link_made[0].get_internal_path()
|
|
assert f9.linked
|
|
finally:
|
|
SCons.Node.FS.Link = save_Link
|
|
|
|
# Test for an interesting pathological case...we have a source
|
|
# file in a build path, but not in a source path. This can
|
|
# happen if you switch from duplicate=1 to duplicate=0, then
|
|
# delete a source file. At one time, this would cause exists()
|
|
# to return a 1 but get_contents() to throw.
|
|
test.write(['work', 'build', 'var1', 'asourcefile'], 'stuff')
|
|
f10 = fs.File('build/var1/asourcefile')
|
|
assert f10.exists()
|
|
assert f10.get_contents() == bytearray('stuff', 'utf-8'), f10.get_contents()
|
|
|
|
f11 = fs.File('src/file11')
|
|
t, m = f11.alter_targets()
|
|
bdt = [n.get_internal_path() for n in t]
|
|
var1_file11 = os.path.normpath('build/var1/file11')
|
|
var2_file11 = os.path.normpath('build/var2/file11')
|
|
assert bdt == [var1_file11, var2_file11], bdt
|
|
|
|
f12 = fs.File('src/file12')
|
|
f12.builder = 1
|
|
bdt, m = f12.alter_targets()
|
|
assert bdt == [], [n.get_internal_path() for n in bdt]
|
|
|
|
d13 = fs.Dir('src/new_dir')
|
|
t, m = d13.alter_targets()
|
|
bdt = [n.get_internal_path() for n in t]
|
|
var1_new_dir = os.path.normpath('build/var1/new_dir')
|
|
var2_new_dir = os.path.normpath('build/var2/new_dir')
|
|
assert bdt == [var1_new_dir, var2_new_dir], bdt
|
|
|
|
# Test that an IOError trying to Link a src file
|
|
# into a VariantDir ends up throwing a StopError.
|
|
fIO = fs.File("build/var2/IOError")
|
|
|
|
save_Link = SCons.Node.FS.Link
|
|
|
|
def Link_IOError(target, source, env):
|
|
raise IOError(17, "Link_IOError")
|
|
|
|
SCons.Node.FS.Link = SCons.Action.Action(Link_IOError, None)
|
|
|
|
test.write(['work', 'src', 'IOError'], "work/src/IOError\n")
|
|
|
|
try:
|
|
exc_caught = 0
|
|
try:
|
|
fIO.exists()
|
|
except SCons.Errors.StopError:
|
|
exc_caught = 1
|
|
assert exc_caught, "Should have caught a StopError"
|
|
|
|
finally:
|
|
SCons.Node.FS.Link = save_Link
|
|
|
|
# Test to see if Link() works...
|
|
test.subdir('src', 'build')
|
|
test.write('src/foo', 'src/foo\n')
|
|
os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
|
|
SCons.Node.FS.Link(fs.File(test.workpath('build/foo')),
|
|
fs.File(test.workpath('src/foo')),
|
|
None)
|
|
os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
|
|
st = os.stat(test.workpath('build/foo'))
|
|
assert (stat.S_IMODE(st.st_mode) & stat.S_IWRITE), \
|
|
stat.S_IMODE(st.st_mode)
|
|
|
|
# This used to generate a UserError when we forbid the source
|
|
# directory from being outside the top-level SConstruct dir.
|
|
fs = SCons.Node.FS.FS()
|
|
fs.VariantDir('build', '/test/foo')
|
|
|
|
exc_caught = 0
|
|
try:
|
|
try:
|
|
fs = SCons.Node.FS.FS()
|
|
fs.VariantDir('build', 'build/src')
|
|
except SCons.Errors.UserError:
|
|
exc_caught = 1
|
|
assert exc_caught, "Should have caught a UserError."
|
|
finally:
|
|
test.unlink("src/foo")
|
|
test.unlink("build/foo")
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
fs.VariantDir('build', 'src1')
|
|
|
|
# Calling the same VariantDir twice should work fine.
|
|
fs.VariantDir('build', 'src1')
|
|
|
|
# Trying to move a variant dir to a second source dir
|
|
# should blow up
|
|
try:
|
|
fs.VariantDir('build', 'src2')
|
|
except SCons.Errors.UserError:
|
|
pass
|
|
else:
|
|
assert 0, "Should have caught a UserError."
|
|
|
|
# Test against a former bug. Make sure we can get a repository
|
|
# path for the variant directory itself!
|
|
fs = SCons.Node.FS.FS(test.workpath('work'))
|
|
|
|
# not needed this subdir is created above near line 188
|
|
# test.subdir('work')
|
|
fs.VariantDir('build/var3', 'src', duplicate=0)
|
|
d1 = fs.Dir('build/var3')
|
|
r = d1.rdir()
|
|
assert r == d1, "%s != %s" % (r, d1)
|
|
|
|
# verify the link creation attempts in file_link()
|
|
class LinkSimulator:
|
|
"""A class to intercept os.[sym]link() calls and track them."""
|
|
|
|
def __init__(self, duplicate, link, symlink, copy):
|
|
self.duplicate = duplicate
|
|
self.have = {'hard': link, 'soft': symlink, 'copy': copy}
|
|
|
|
self.links_to_be_called = []
|
|
for link in self.duplicate.split('-'):
|
|
if self.have[link]:
|
|
self.links_to_be_called.append(link)
|
|
|
|
def link_fail(self, src, dest):
|
|
next_link = self.links_to_be_called.pop(0)
|
|
assert next_link == "hard", \
|
|
"Wrong link order: expected %s to be called " \
|
|
"instead of hard" % next_link
|
|
raise OSError("Simulating hard link creation error.")
|
|
|
|
def symlink_fail(self, src, dest):
|
|
next_link = self.links_to_be_called.pop(0)
|
|
assert next_link == "soft", \
|
|
"Wrong link order: expected %s to be called " \
|
|
"instead of soft" % next_link
|
|
raise OSError("Simulating symlink creation error.")
|
|
|
|
def copy(self, src, dest):
|
|
next_link = self.links_to_be_called.pop(0)
|
|
assert next_link == "copy", \
|
|
"Wrong link order: expected %s to be called " \
|
|
"instead of copy" % next_link
|
|
# copy succeeds, but use the real copy
|
|
self.have['copy'](src, dest)
|
|
|
|
# end class LinkSimulator
|
|
|
|
try:
|
|
SCons.Node.FS.set_duplicate("no-link-order")
|
|
assert 0, "Expected exception when passing an invalid duplicate to set_duplicate"
|
|
except SCons.Errors.InternalError:
|
|
pass
|
|
|
|
for duplicate in SCons.Node.FS.Valid_Duplicates:
|
|
# save the real functions for later restoration
|
|
try:
|
|
real_link = os.link
|
|
except AttributeError:
|
|
real_link = None
|
|
try:
|
|
real_symlink = os.symlink
|
|
except AttributeError:
|
|
real_symlink = None
|
|
|
|
# Disable symlink and link for now in win32.
|
|
# We don't have a consistant plan to make these work as yet
|
|
# They are only supported with PY3
|
|
if sys.platform == 'win32':
|
|
real_symlink = None
|
|
real_link = None
|
|
|
|
real_copy = shutil.copy2
|
|
|
|
simulator = LinkSimulator(duplicate, real_link, real_symlink, real_copy)
|
|
|
|
# override the real functions with our simulation
|
|
os.link = simulator.link_fail
|
|
os.symlink = simulator.symlink_fail
|
|
shutil.copy2 = simulator.copy
|
|
|
|
try:
|
|
|
|
SCons.Node.FS.set_duplicate(duplicate)
|
|
|
|
src_foo = test.workpath('src', 'foo')
|
|
build_foo = test.workpath('build', 'foo')
|
|
|
|
test.write(src_foo, 'src/foo\n')
|
|
os.chmod(src_foo, stat.S_IRUSR)
|
|
try:
|
|
SCons.Node.FS.Link(fs.File(build_foo),
|
|
fs.File(src_foo),
|
|
None)
|
|
finally:
|
|
os.chmod(src_foo, stat.S_IRUSR | stat.S_IWRITE)
|
|
test.unlink(src_foo)
|
|
test.unlink(build_foo)
|
|
|
|
finally:
|
|
# restore the real functions
|
|
if real_link:
|
|
os.link = real_link
|
|
else:
|
|
delattr(os, 'link')
|
|
if real_symlink:
|
|
os.symlink = real_symlink
|
|
else:
|
|
delattr(os, 'symlink')
|
|
shutil.copy2 = real_copy
|
|
|
|
# Test VariantDir "reflection," where a same-named subdirectory
|
|
# exists underneath a variant_dir.
|
|
fs = SCons.Node.FS.FS()
|
|
fs.VariantDir('work/src/b1/b2', 'work/src')
|
|
|
|
dir_list = [
|
|
'work/src',
|
|
'work/src/b1',
|
|
'work/src/b1/b2',
|
|
'work/src/b1/b2/b1',
|
|
'work/src/b1/b2/b1/b2',
|
|
'work/src/b1/b2/b1/b2/b1',
|
|
'work/src/b1/b2/b1/b2/b1/b2',
|
|
]
|
|
|
|
srcnode_map = {
|
|
'work/src/b1/b2': 'work/src',
|
|
'work/src/b1/b2/f': 'work/src/f',
|
|
'work/src/b1/b2/b1': 'work/src/b1/',
|
|
'work/src/b1/b2/b1/f': 'work/src/b1/f',
|
|
'work/src/b1/b2/b1/b2': 'work/src/b1/b2',
|
|
'work/src/b1/b2/b1/b2/f': 'work/src/b1/b2/f',
|
|
'work/src/b1/b2/b1/b2/b1': 'work/src/b1/b2/b1',
|
|
'work/src/b1/b2/b1/b2/b1/f': 'work/src/b1/b2/b1/f',
|
|
'work/src/b1/b2/b1/b2/b1/b2': 'work/src/b1/b2/b1/b2',
|
|
'work/src/b1/b2/b1/b2/b1/b2/f': 'work/src/b1/b2/b1/b2/f',
|
|
}
|
|
|
|
alter_map = {
|
|
'work/src': 'work/src/b1/b2',
|
|
'work/src/f': 'work/src/b1/b2/f',
|
|
'work/src/b1': 'work/src/b1/b2/b1',
|
|
'work/src/b1/f': 'work/src/b1/b2/b1/f',
|
|
}
|
|
|
|
errors = 0
|
|
|
|
for dir in dir_list:
|
|
dnode = fs.Dir(dir)
|
|
f = dir + '/f'
|
|
fnode = fs.File(dir + '/f')
|
|
|
|
dp = dnode.srcnode().get_internal_path()
|
|
expect = os.path.normpath(srcnode_map.get(dir, dir))
|
|
if dp != expect:
|
|
print("Dir `%s' srcnode() `%s' != expected `%s'" % (dir, dp, expect))
|
|
errors = errors + 1
|
|
|
|
fp = fnode.srcnode().get_internal_path()
|
|
expect = os.path.normpath(srcnode_map.get(f, f))
|
|
if fp != expect:
|
|
print("File `%s' srcnode() `%s' != expected `%s'" % (f, fp, expect))
|
|
errors = errors + 1
|
|
|
|
for dir in dir_list:
|
|
dnode = fs.Dir(dir)
|
|
f = dir + '/f'
|
|
fnode = fs.File(dir + '/f')
|
|
|
|
t, m = dnode.alter_targets()
|
|
tp = t[0].get_internal_path()
|
|
expect = os.path.normpath(alter_map.get(dir, dir))
|
|
if tp != expect:
|
|
print("Dir `%s' alter_targets() `%s' != expected `%s'" % (dir, tp, expect))
|
|
errors = errors + 1
|
|
|
|
t, m = fnode.alter_targets()
|
|
tp = t[0].get_internal_path()
|
|
expect = os.path.normpath(alter_map.get(f, f))
|
|
if tp != expect:
|
|
print("File `%s' alter_targets() `%s' != expected `%s'" % (f, tp, expect))
|
|
errors = errors + 1
|
|
|
|
self.assertFalse(errors)
|
|
|
|
|
|
class BaseTestCase(_tempdirTestCase):
|
|
def test_stat(self):
|
|
"""Test the Base.stat() method"""
|
|
test = self.test
|
|
test.write("e1", "e1\n")
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
e1 = fs.Entry('e1')
|
|
s = e1.stat()
|
|
assert s is not None, s
|
|
|
|
e2 = fs.Entry('e2')
|
|
s = e2.stat()
|
|
assert s is None, s
|
|
|
|
def test_getmtime(self):
|
|
"""Test the Base.getmtime() method"""
|
|
test = self.test
|
|
test.write("file", "file\n")
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
file = fs.Entry('file')
|
|
assert file.getmtime()
|
|
|
|
file = fs.Entry('nonexistent')
|
|
mtime = file.getmtime()
|
|
assert mtime is None, mtime
|
|
|
|
def test_getsize(self):
|
|
"""Test the Base.getsize() method"""
|
|
test = self.test
|
|
test.write("file", "file\n")
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
file = fs.Entry('file')
|
|
size = file.getsize()
|
|
assert size == 5, size
|
|
|
|
file = fs.Entry('nonexistent')
|
|
size = file.getsize()
|
|
assert size is None, size
|
|
|
|
def test_isdir(self):
|
|
"""Test the Base.isdir() method"""
|
|
test = self.test
|
|
test.subdir('dir')
|
|
test.write("file", "file\n")
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
dir = fs.Entry('dir')
|
|
assert dir.isdir()
|
|
|
|
file = fs.Entry('file')
|
|
assert not file.isdir()
|
|
|
|
nonexistent = fs.Entry('nonexistent')
|
|
assert not nonexistent.isdir()
|
|
|
|
def test_isfile(self):
|
|
"""Test the Base.isfile() method"""
|
|
test = self.test
|
|
test.subdir('dir')
|
|
test.write("file", "file\n")
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
dir = fs.Entry('dir')
|
|
assert not dir.isfile()
|
|
|
|
file = fs.Entry('file')
|
|
assert file.isfile()
|
|
|
|
nonexistent = fs.Entry('nonexistent')
|
|
assert not nonexistent.isfile()
|
|
|
|
@unittest.skipUnless(sys.platform != 'win32' and hasattr(os, 'symlink'),
|
|
"symlink is not used on Windows")
|
|
def test_islink(self):
|
|
"""Test the Base.islink() method"""
|
|
test = self.test
|
|
test.subdir('dir')
|
|
test.write("file", "file\n")
|
|
test.symlink("symlink", "symlink")
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
dir = fs.Entry('dir')
|
|
assert not dir.islink()
|
|
|
|
file = fs.Entry('file')
|
|
assert not file.islink()
|
|
|
|
symlink = fs.Entry('symlink')
|
|
assert symlink.islink()
|
|
|
|
nonexistent = fs.Entry('nonexistent')
|
|
assert not nonexistent.islink()
|
|
|
|
|
|
class DirNodeInfoTestCase(_tempdirTestCase):
|
|
def test___init__(self):
|
|
"""Test DirNodeInfo initialization"""
|
|
ddd = self.fs.Dir('ddd')
|
|
ni = SCons.Node.FS.DirNodeInfo()
|
|
|
|
|
|
class DirBuildInfoTestCase(_tempdirTestCase):
|
|
def test___init__(self):
|
|
"""Test DirBuildInfo initialization"""
|
|
ddd = self.fs.Dir('ddd')
|
|
bi = SCons.Node.FS.DirBuildInfo()
|
|
|
|
|
|
class FileNodeInfoTestCase(_tempdirTestCase):
|
|
def test___init__(self):
|
|
"""Test FileNodeInfo initialization"""
|
|
fff = self.fs.File('fff')
|
|
ni = SCons.Node.FS.FileNodeInfo()
|
|
assert isinstance(ni, SCons.Node.FS.FileNodeInfo)
|
|
|
|
def test_update(self):
|
|
"""Test updating a File.NodeInfo with on-disk information"""
|
|
test = self.test
|
|
fff = self.fs.File('fff')
|
|
|
|
ni = SCons.Node.FS.FileNodeInfo()
|
|
|
|
test.write('fff', "fff\n")
|
|
|
|
st = os.stat('fff')
|
|
|
|
ni.update(fff)
|
|
|
|
assert hasattr(ni, 'timestamp')
|
|
assert hasattr(ni, 'size')
|
|
|
|
ni.timestamp = 0
|
|
ni.size = 0
|
|
|
|
ni.update(fff)
|
|
|
|
mtime = st[stat.ST_MTIME]
|
|
assert ni.timestamp == mtime, (ni.timestamp, mtime)
|
|
size = st.st_size
|
|
assert ni.size == size, (ni.size, size)
|
|
|
|
import time
|
|
time.sleep(2)
|
|
|
|
test.write('fff', "fff longer size, different time stamp\n")
|
|
|
|
st = os.stat('fff')
|
|
|
|
mtime = st[stat.ST_MTIME]
|
|
assert ni.timestamp != mtime, (ni.timestamp, mtime)
|
|
size = st.st_size
|
|
assert ni.size != size, (ni.size, size)
|
|
|
|
|
|
class FileBuildInfoTestCase(_tempdirTestCase):
|
|
def test___init__(self):
|
|
"""Test File.BuildInfo initialization"""
|
|
fff = self.fs.File('fff')
|
|
bi = SCons.Node.FS.FileBuildInfo()
|
|
assert bi, bi
|
|
|
|
def test_convert_to_sconsign(self):
|
|
"""Test converting to .sconsign file format"""
|
|
fff = self.fs.File('fff')
|
|
bi = SCons.Node.FS.FileBuildInfo()
|
|
assert hasattr(bi, 'convert_to_sconsign')
|
|
|
|
def test_convert_from_sconsign(self):
|
|
"""Test converting from .sconsign file format"""
|
|
fff = self.fs.File('fff')
|
|
bi = SCons.Node.FS.FileBuildInfo()
|
|
assert hasattr(bi, 'convert_from_sconsign')
|
|
|
|
def test_prepare_dependencies(self):
|
|
"""Test that we have a prepare_dependencies() method"""
|
|
fff = self.fs.File('fff')
|
|
bi = SCons.Node.FS.FileBuildInfo()
|
|
bi.prepare_dependencies()
|
|
|
|
def test_format(self):
|
|
"""Test the format() method"""
|
|
f1 = self.fs.File('f1')
|
|
bi1 = SCons.Node.FS.FileBuildInfo()
|
|
|
|
self.fs.File('n1')
|
|
self.fs.File('n2')
|
|
self.fs.File('n3')
|
|
|
|
s1sig = SCons.Node.FS.FileNodeInfo()
|
|
s1sig.csig = 1
|
|
d1sig = SCons.Node.FS.FileNodeInfo()
|
|
d1sig.timestamp = 2
|
|
i1sig = SCons.Node.FS.FileNodeInfo()
|
|
i1sig.size = 3
|
|
|
|
bi1.bsources = [self.fs.File('s1')]
|
|
bi1.bdepends = [self.fs.File('d1')]
|
|
bi1.bimplicit = [self.fs.File('i1')]
|
|
bi1.bsourcesigs = [s1sig]
|
|
bi1.bdependsigs = [d1sig]
|
|
bi1.bimplicitsigs = [i1sig]
|
|
bi1.bact = 'action'
|
|
bi1.bactsig = 'actionsig'
|
|
|
|
expect_lines = [
|
|
's1: 1 None None',
|
|
'd1: None 2 None',
|
|
'i1: None None 3',
|
|
'actionsig [action]',
|
|
]
|
|
|
|
expect = '\n'.join(expect_lines)
|
|
format = bi1.format()
|
|
assert format == expect, (repr(expect), repr(format))
|
|
|
|
|
|
class FSTestCase(_tempdirTestCase):
|
|
def test_needs_normpath(self):
|
|
"""Test the needs_normpath Regular expression
|
|
|
|
This test case verifies that the regular expression used to
|
|
determine whether a path needs normalization works as
|
|
expected.
|
|
"""
|
|
needs_normpath_match = SCons.Node.FS.needs_normpath_match
|
|
|
|
do_not_need_normpath = [
|
|
".",
|
|
"/",
|
|
"/a",
|
|
"/aa",
|
|
"/a/",
|
|
"/aa/",
|
|
"/a/b",
|
|
"/aa/bb",
|
|
"/a/b/",
|
|
"/aa/bb/",
|
|
|
|
"",
|
|
"a",
|
|
"aa",
|
|
"a/",
|
|
"aa/",
|
|
"a/b",
|
|
"aa/bb",
|
|
"a/b/",
|
|
"aa/bb/",
|
|
|
|
"a.",
|
|
"a..",
|
|
"/a.",
|
|
"/a..",
|
|
"a./",
|
|
"a../",
|
|
"/a./",
|
|
"/a../",
|
|
|
|
".a",
|
|
"..a",
|
|
"/.a",
|
|
"/..a",
|
|
".a/",
|
|
"..a/",
|
|
"/.a/",
|
|
"/..a/",
|
|
]
|
|
for p in do_not_need_normpath:
|
|
assert needs_normpath_match(p) is None, p
|
|
|
|
needs_normpath = [
|
|
"//",
|
|
"//a",
|
|
"//aa",
|
|
"//a/",
|
|
"//a/",
|
|
"/aa//",
|
|
|
|
"//a/b",
|
|
"//aa/bb",
|
|
"//a/b/",
|
|
"//aa/bb/",
|
|
|
|
"/a//b",
|
|
"/aa//bb",
|
|
"/a/b//",
|
|
"/aa/bb//",
|
|
|
|
"/a/b//",
|
|
"/aa/bb//",
|
|
|
|
"a//",
|
|
"aa//",
|
|
"a//b",
|
|
"aa//bb",
|
|
"a//b/",
|
|
"aa//bb/",
|
|
"a/b//",
|
|
"aa/bb//",
|
|
|
|
"..",
|
|
"/.",
|
|
"/..",
|
|
"./",
|
|
"../",
|
|
"/./",
|
|
"/../",
|
|
|
|
"a/.",
|
|
"a/..",
|
|
"./a",
|
|
"../a",
|
|
"a/./a",
|
|
"a/../a",
|
|
]
|
|
for p in needs_normpath:
|
|
assert needs_normpath_match(p) is not None, p
|
|
|
|
def test_runTest(self):
|
|
"""Test FS (file system) Node operations
|
|
|
|
This test case handles all of the file system node
|
|
tests in one environment, so we don't have to set up a
|
|
complicated directory structure for each test individually.
|
|
"""
|
|
test = self.test
|
|
|
|
test.subdir('sub', ['sub', 'dir'])
|
|
|
|
wp = test.workpath('')
|
|
sub = test.workpath('sub', '')
|
|
sub_dir = test.workpath('sub', 'dir', '')
|
|
sub_dir_foo = test.workpath('sub', 'dir', 'foo', '')
|
|
sub_dir_foo_bar = test.workpath('sub', 'dir', 'foo', 'bar', '')
|
|
sub_foo = test.workpath('sub', 'foo', '')
|
|
|
|
os.chdir(sub_dir)
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
e1 = fs.Entry('e1')
|
|
assert isinstance(e1, SCons.Node.FS.Entry)
|
|
|
|
d1 = fs.Dir('d1')
|
|
assert isinstance(d1, SCons.Node.FS.Dir)
|
|
assert d1.cwd is d1, d1
|
|
|
|
f1 = fs.File('f1', directory=d1)
|
|
assert isinstance(f1, SCons.Node.FS.File)
|
|
|
|
d1_f1 = os.path.join('d1', 'f1')
|
|
assert f1.get_internal_path() == d1_f1, "f1.path %s != %s" % (f1.get_internal_path(), d1_f1)
|
|
assert str(f1) == d1_f1, "str(f1) %s != %s" % (str(f1), d1_f1)
|
|
|
|
x1 = d1.File('x1')
|
|
assert isinstance(x1, SCons.Node.FS.File)
|
|
assert str(x1) == os.path.join('d1', 'x1')
|
|
|
|
x2 = d1.Dir('x2')
|
|
assert isinstance(x2, SCons.Node.FS.Dir)
|
|
assert str(x2) == os.path.join('d1', 'x2')
|
|
|
|
x3 = d1.Entry('x3')
|
|
assert isinstance(x3, SCons.Node.FS.Entry)
|
|
assert str(x3) == os.path.join('d1', 'x3')
|
|
|
|
assert d1.File(x1) == x1
|
|
assert d1.Dir(x2) == x2
|
|
assert d1.Entry(x3) == x3
|
|
|
|
x1.cwd = d1
|
|
|
|
x4 = x1.File('x4')
|
|
assert str(x4) == os.path.join('d1', 'x4')
|
|
|
|
x5 = x1.Dir('x5')
|
|
assert str(x5) == os.path.join('d1', 'x5')
|
|
|
|
x6 = x1.Entry('x6')
|
|
assert str(x6) == os.path.join('d1', 'x6')
|
|
x7 = x1.Entry('x7')
|
|
assert str(x7) == os.path.join('d1', 'x7')
|
|
|
|
assert x1.File(x4) == x4
|
|
assert x1.Dir(x5) == x5
|
|
assert x1.Entry(x6) == x6
|
|
assert x1.Entry(x7) == x7
|
|
|
|
assert x1.Entry(x5) == x5
|
|
try:
|
|
x1.File(x5)
|
|
except TypeError:
|
|
pass
|
|
else:
|
|
raise Exception("did not catch expected TypeError")
|
|
|
|
assert x1.Entry(x4) == x4
|
|
try:
|
|
x1.Dir(x4)
|
|
except TypeError:
|
|
pass
|
|
else:
|
|
raise Exception("did not catch expected TypeError")
|
|
|
|
x6 = x1.File(x6)
|
|
assert isinstance(x6, SCons.Node.FS.File)
|
|
|
|
x7 = x1.Dir(x7)
|
|
assert isinstance(x7, SCons.Node.FS.Dir)
|
|
|
|
seps = [os.sep]
|
|
if os.sep != '/':
|
|
seps = seps + ['/']
|
|
|
|
drive, path = os.path.splitdrive(os.getcwd())
|
|
|
|
def _do_Dir_test(lpath, path_, abspath_, up_path_, sep, fileSys=fs, drive=drive):
|
|
dir = fileSys.Dir(lpath.replace('/', sep))
|
|
|
|
if os.sep != '/':
|
|
path_ = path_.replace('/', os.sep)
|
|
abspath_ = abspath_.replace('/', os.sep)
|
|
up_path_ = up_path_.replace('/', os.sep)
|
|
|
|
def strip_slash(p, drive=drive):
|
|
if p[-1] == os.sep and len(p) > 1:
|
|
p = p[:-1]
|
|
if p[0] == os.sep:
|
|
p = drive + p
|
|
return p
|
|
|
|
path = strip_slash(path_)
|
|
abspath = strip_slash(abspath_)
|
|
up_path = strip_slash(up_path_)
|
|
|
|
name = abspath.split(os.sep)[-1]
|
|
|
|
if not name:
|
|
if drive:
|
|
name = drive
|
|
else:
|
|
name = os.sep
|
|
|
|
if dir.up() is None:
|
|
dir_up_path = dir.get_internal_path()
|
|
else:
|
|
dir_up_path = dir.up().get_internal_path()
|
|
|
|
assert dir.name == name, \
|
|
"dir.name %s != expected name %s" % \
|
|
(dir.name, name)
|
|
assert dir.get_internal_path() == path, \
|
|
"dir.path %s != expected path %s" % \
|
|
(dir.get_internal_path(), path)
|
|
assert str(dir) == path, \
|
|
"str(dir) %s != expected path %s" % \
|
|
(str(dir), path)
|
|
assert dir.get_abspath() == abspath, \
|
|
"dir.abspath %s != expected absolute path %s" % \
|
|
(dir.get_abspath(), abspath)
|
|
assert dir_up_path == up_path, \
|
|
"dir.up().path %s != expected parent path %s" % \
|
|
(dir_up_path, up_path)
|
|
|
|
for sep in seps:
|
|
|
|
def Dir_test(lpath, path_, abspath_, up_path_, sep=sep, func=_do_Dir_test):
|
|
return func(lpath, path_, abspath_, up_path_, sep)
|
|
|
|
Dir_test('/', '/', '/', '/')
|
|
Dir_test('', './', sub_dir, sub)
|
|
Dir_test('foo', 'foo/', sub_dir_foo, './')
|
|
Dir_test('foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
|
|
Dir_test('/foo', '/foo/', '/foo/', '/')
|
|
Dir_test('/foo/bar', '/foo/bar/', '/foo/bar/', '/foo/')
|
|
Dir_test('..', sub, sub, wp)
|
|
Dir_test('foo/..', './', sub_dir, sub)
|
|
Dir_test('../foo', sub_foo, sub_foo, sub)
|
|
Dir_test('.', './', sub_dir, sub)
|
|
Dir_test('./.', './', sub_dir, sub)
|
|
Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
|
|
Dir_test('#../foo', sub_foo, sub_foo, sub)
|
|
Dir_test('#/../foo', sub_foo, sub_foo, sub)
|
|
Dir_test('#foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
|
|
Dir_test('#/foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
|
|
Dir_test('#', './', sub_dir, sub)
|
|
|
|
try:
|
|
f2 = fs.File(sep.join(['f1', 'f2']), directory=d1)
|
|
except TypeError as x:
|
|
assert str(x) == ("Tried to lookup File '%s' as a Dir." %
|
|
d1_f1), x
|
|
except:
|
|
raise
|
|
|
|
try:
|
|
dir = fs.Dir(sep.join(['d1', 'f1']))
|
|
except TypeError as x:
|
|
assert str(x) == ("Tried to lookup File '%s' as a Dir." %
|
|
d1_f1), x
|
|
except:
|
|
raise
|
|
|
|
try:
|
|
f2 = fs.File('d1')
|
|
except TypeError as x:
|
|
assert str(x) == ("Tried to lookup Dir '%s' as a File." %
|
|
'd1'), x
|
|
except:
|
|
raise
|
|
|
|
# Test that just specifying the drive works to identify
|
|
# its root directory.
|
|
p = os.path.abspath(test.workpath('root_file'))
|
|
drive, path = os.path.splitdrive(p)
|
|
if drive:
|
|
# The assert below probably isn't correct for the general
|
|
# case, but it works for Windows, which covers a lot
|
|
# of ground...
|
|
dir = fs.Dir(drive)
|
|
assert str(dir) == drive + os.sep, str(dir)
|
|
|
|
# Make sure that lookups with and without the drive are
|
|
# equivalent.
|
|
p = os.path.abspath(test.workpath('some/file'))
|
|
drive, path = os.path.splitdrive(p)
|
|
|
|
e1 = fs.Entry(p)
|
|
e2 = fs.Entry(path)
|
|
assert e1 is e2, (e1, e2)
|
|
a = str(e1)
|
|
b = str(e2)
|
|
assert a == b, ("Strings should match for same file/node\n%s\n%s" % (a, b))
|
|
|
|
# Test for a bug in 0.04 that did not like looking up
|
|
# dirs with a trailing slash on Windows.
|
|
d = fs.Dir('./')
|
|
assert d.get_internal_path() == '.', d.get_abspath()
|
|
d = fs.Dir('foo/')
|
|
assert d.get_internal_path() == 'foo', d.get_abspath()
|
|
|
|
# Test for sub-classing of node building.
|
|
global built_it
|
|
|
|
built_it = None
|
|
assert not built_it
|
|
d1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
|
|
d1.builder_set(Builder(fs.File))
|
|
d1.reset_executor()
|
|
d1.env_set(Environment())
|
|
d1.build()
|
|
assert built_it
|
|
|
|
built_it = None
|
|
assert not built_it
|
|
f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
|
|
f1.builder_set(Builder(fs.File))
|
|
f1.reset_executor()
|
|
f1.env_set(Environment())
|
|
f1.build()
|
|
assert built_it
|
|
|
|
def match(path, expect):
|
|
expect = expect.replace('/', os.sep)
|
|
assert path == expect, "path %s != expected %s" % (path, expect)
|
|
|
|
e1 = fs.Entry("d1")
|
|
assert e1.__class__.__name__ == 'Dir'
|
|
match(e1.get_internal_path(), "d1")
|
|
match(e1.dir.get_internal_path(), ".")
|
|
|
|
e2 = fs.Entry("d1/f1")
|
|
assert e2.__class__.__name__ == 'File'
|
|
match(e2.get_internal_path(), "d1/f1")
|
|
match(e2.dir.get_internal_path(), "d1")
|
|
|
|
e3 = fs.Entry("e3")
|
|
assert e3.__class__.__name__ == 'Entry'
|
|
match(e3.get_internal_path(), "e3")
|
|
match(e3.dir.get_internal_path(), ".")
|
|
|
|
e4 = fs.Entry("d1/e4")
|
|
assert e4.__class__.__name__ == 'Entry'
|
|
match(e4.get_internal_path(), "d1/e4")
|
|
match(e4.dir.get_internal_path(), "d1")
|
|
|
|
e5 = fs.Entry("e3/e5")
|
|
assert e3.__class__.__name__ == 'Dir'
|
|
match(e3.get_internal_path(), "e3")
|
|
match(e3.dir.get_internal_path(), ".")
|
|
assert e5.__class__.__name__ == 'Entry'
|
|
match(e5.get_internal_path(), "e3/e5")
|
|
match(e5.dir.get_internal_path(), "e3")
|
|
|
|
e6 = fs.Dir("d1/e4")
|
|
assert e6 is e4
|
|
assert e4.__class__.__name__ == 'Dir'
|
|
match(e4.get_internal_path(), "d1/e4")
|
|
match(e4.dir.get_internal_path(), "d1")
|
|
|
|
e7 = fs.File("e3/e5")
|
|
assert e7 is e5
|
|
assert e5.__class__.__name__ == 'File'
|
|
match(e5.get_internal_path(), "e3/e5")
|
|
match(e5.dir.get_internal_path(), "e3")
|
|
|
|
fs.chdir(fs.Dir('subdir'))
|
|
f11 = fs.File("f11")
|
|
match(f11.get_internal_path(), "subdir/f11")
|
|
d12 = fs.Dir("d12")
|
|
e13 = fs.Entry("subdir/e13")
|
|
match(e13.get_internal_path(), "subdir/subdir/e13")
|
|
fs.chdir(fs.Dir('..'))
|
|
|
|
# Test scanning
|
|
f1.builder_set(Builder(fs.File))
|
|
f1.env_set(Environment())
|
|
xyz = fs.File("xyz")
|
|
f1.builder.target_scanner = Scanner(xyz)
|
|
|
|
f1.scan()
|
|
assert f1.implicit[0].get_internal_path() == "xyz"
|
|
f1.implicit = []
|
|
f1.scan()
|
|
assert f1.implicit == []
|
|
f1.implicit = None
|
|
f1.scan()
|
|
assert f1.implicit[0].get_internal_path() == "xyz"
|
|
|
|
# Test underlying scanning functionality in get_found_includes()
|
|
env = Environment()
|
|
f12 = fs.File("f12")
|
|
t1 = fs.File("t1")
|
|
|
|
deps = f12.get_found_includes(env, None, t1)
|
|
assert deps == [], deps
|
|
|
|
class MyScanner(Scanner):
|
|
call_count = 0
|
|
|
|
def __call__(self, node, env, path):
|
|
self.call_count = self.call_count + 1
|
|
return Scanner.__call__(self, node, env, path)
|
|
|
|
s = MyScanner(xyz)
|
|
|
|
deps = f12.get_found_includes(env, s, t1)
|
|
assert deps == [xyz], deps
|
|
assert s.call_count == 1, s.call_count
|
|
|
|
f12.built()
|
|
|
|
deps = f12.get_found_includes(env, s, t1)
|
|
assert deps == [xyz], deps
|
|
assert s.call_count == 2, s.call_count
|
|
|
|
env2 = Environment()
|
|
|
|
deps = f12.get_found_includes(env2, s, t1)
|
|
assert deps == [xyz], deps
|
|
assert s.call_count == 3, s.call_count
|
|
|
|
# Make sure we can scan this file even if the target isn't
|
|
# a file that has a scanner (it might be an Alias, e.g.).
|
|
class DummyNode:
|
|
pass
|
|
|
|
deps = f12.get_found_includes(env, s, DummyNode())
|
|
assert deps == [xyz], deps
|
|
|
|
# Test building a file whose directory is not there yet...
|
|
f1 = fs.File(test.workpath("foo/bar/baz/ack"))
|
|
assert not f1.dir.exists()
|
|
f1.prepare()
|
|
f1.build()
|
|
assert f1.dir.exists()
|
|
|
|
os.chdir('..')
|
|
|
|
# Test getcwd()
|
|
fs = SCons.Node.FS.FS()
|
|
assert str(fs.getcwd()) == ".", str(fs.getcwd())
|
|
fs.chdir(fs.Dir('subdir'))
|
|
# The cwd's path is always "."
|
|
assert str(fs.getcwd()) == ".", str(fs.getcwd())
|
|
assert fs.getcwd().get_internal_path() == 'subdir', fs.getcwd().get_internal_path()
|
|
fs.chdir(fs.Dir('../..'))
|
|
assert fs.getcwd().get_internal_path() == test.workdir, fs.getcwd().get_internal_path()
|
|
|
|
f1 = fs.File(test.workpath("do_i_exist"))
|
|
assert not f1.exists()
|
|
test.write("do_i_exist", "\n")
|
|
assert not f1.exists(), "exists() call not cached"
|
|
f1.built()
|
|
assert f1.exists(), "exists() call caching not reset"
|
|
test.unlink("do_i_exist")
|
|
assert f1.exists()
|
|
f1.built()
|
|
assert not f1.exists()
|
|
|
|
# For some reason, in Windows, the \x1a character terminates
|
|
# the reading of files in text mode. This tests that
|
|
# get_contents() returns the binary contents.
|
|
test.write("binary_file", "Foo\x1aBar")
|
|
f1 = fs.File(test.workpath("binary_file"))
|
|
assert f1.get_contents() == bytearray("Foo\x1aBar", 'utf-8'), \
|
|
f1.get_contents()
|
|
|
|
# This tests to make sure we can decode UTF-8 text files.
|
|
test_string = "Foo\x1aBar"
|
|
test.write("utf8_file", test_string.encode('utf-8'))
|
|
f1 = fs.File(test.workpath("utf8_file"))
|
|
assert f1.get_text_contents() == "Foo\x1aBar", \
|
|
f1.get_text_contents()
|
|
|
|
# Check for string which doesn't have BOM and isn't valid
|
|
# ASCII
|
|
test_string = b'Gan\xdfauge'
|
|
test.write('latin1_file', test_string)
|
|
f1 = fs.File(test.workpath("latin1_file"))
|
|
assert f1.get_text_contents() == test_string.decode('latin-1'), \
|
|
f1.get_text_contents()
|
|
|
|
def nonexistent(method, s):
|
|
try:
|
|
x = method(s, create=0)
|
|
except SCons.Errors.UserError:
|
|
pass
|
|
else:
|
|
raise Exception("did not catch expected UserError")
|
|
|
|
nonexistent(fs.Entry, 'nonexistent')
|
|
nonexistent(fs.Entry, 'nonexistent/foo')
|
|
|
|
nonexistent(fs.File, 'nonexistent')
|
|
nonexistent(fs.File, 'nonexistent/foo')
|
|
|
|
nonexistent(fs.Dir, 'nonexistent')
|
|
nonexistent(fs.Dir, 'nonexistent/foo')
|
|
|
|
test.write("preserve_me", "\n")
|
|
assert os.path.exists(test.workpath("preserve_me"))
|
|
f1 = fs.File(test.workpath("preserve_me"))
|
|
f1.prepare()
|
|
assert os.path.exists(test.workpath("preserve_me"))
|
|
|
|
test.write("remove_me", "\n")
|
|
assert os.path.exists(test.workpath("remove_me"))
|
|
f1 = fs.File(test.workpath("remove_me"))
|
|
f1.builder = Builder(fs.File)
|
|
f1.env_set(Environment())
|
|
f1.prepare()
|
|
assert not os.path.exists(test.workpath("remove_me"))
|
|
|
|
e = fs.Entry('e_local')
|
|
assert not hasattr(e, '_local')
|
|
e.set_local()
|
|
assert e._local == 1
|
|
f = fs.File('e_local')
|
|
assert f._local == 1
|
|
f = fs.File('f_local')
|
|
assert f._local == 0
|
|
|
|
# XXX test_is_up_to_date() for directories
|
|
|
|
# XXX test_sconsign() for directories
|
|
|
|
# XXX test_set_signature() for directories
|
|
|
|
# XXX test_build() for directories
|
|
|
|
# XXX test_root()
|
|
|
|
# test Entry.get_contents()
|
|
e = fs.Entry('does_not_exist')
|
|
c = e.get_contents()
|
|
assert c == "", c
|
|
assert e.__class__ == SCons.Node.FS.Entry
|
|
|
|
test.write("file", "file\n")
|
|
try:
|
|
e = fs.Entry('file')
|
|
c = e.get_contents()
|
|
assert c == bytearray("file\n", 'utf-8'), c
|
|
assert e.__class__ == SCons.Node.FS.File
|
|
finally:
|
|
test.unlink("file")
|
|
|
|
# test Entry.get_text_contents()
|
|
e = fs.Entry('does_not_exist')
|
|
c = e.get_text_contents()
|
|
assert c == "", c
|
|
assert e.__class__ == SCons.Node.FS.Entry
|
|
|
|
test.write("file", "file\n")
|
|
try:
|
|
e = fs.Entry('file')
|
|
c = e.get_text_contents()
|
|
assert c == "file\n", c
|
|
assert e.__class__ == SCons.Node.FS.File
|
|
finally:
|
|
test.unlink("file")
|
|
|
|
test.subdir("dir")
|
|
e = fs.Entry('dir')
|
|
c = e.get_contents()
|
|
assert c == "", c
|
|
assert e.__class__ == SCons.Node.FS.Dir
|
|
|
|
c = e.get_text_contents()
|
|
try:
|
|
eval('assert c == "", c')
|
|
except SyntaxError:
|
|
assert c == ""
|
|
|
|
if sys.platform != 'win32' and hasattr(os, 'symlink'):
|
|
os.symlink('nonexistent', test.workpath('dangling_symlink'))
|
|
e = fs.Entry('dangling_symlink')
|
|
c = e.get_contents()
|
|
assert e.__class__ == SCons.Node.FS.Entry, e.__class__
|
|
assert c == "", c
|
|
c = e.get_text_contents()
|
|
assert c == "", c
|
|
|
|
test.write("tstamp", "tstamp\n")
|
|
try:
|
|
# Okay, *this* manipulation accomodates Windows FAT file systems
|
|
# that only have two-second granularity on their timestamps.
|
|
# We round down the current time to the nearest even integer
|
|
# value, subtract two to make sure the timestamp is not "now,"
|
|
# and then convert it back to a float.
|
|
tstamp = float(int(time.time() // 2) * 2) - 2.0
|
|
os.utime(test.workpath("tstamp"), (tstamp - 2.0, tstamp))
|
|
f = fs.File("tstamp")
|
|
t = f.get_timestamp()
|
|
assert t == tstamp, "expected %f, got %f" % (tstamp, t)
|
|
finally:
|
|
test.unlink("tstamp")
|
|
|
|
test.subdir('tdir1')
|
|
d = fs.Dir('tdir1')
|
|
t = d.get_timestamp()
|
|
assert t == 0, "expected 0, got %s" % str(t)
|
|
|
|
test.subdir('tdir2')
|
|
f1 = test.workpath('tdir2', 'file1')
|
|
f2 = test.workpath('tdir2', 'file2')
|
|
test.write(f1, 'file1\n')
|
|
test.write(f2, 'file2\n')
|
|
current_time = float(int(time.time() // 2) * 2)
|
|
t1 = current_time - 4.0
|
|
t2 = current_time - 2.0
|
|
os.utime(f1, (t1 - 2.0, t1))
|
|
os.utime(f2, (t2 - 2.0, t2))
|
|
d = fs.Dir('tdir2')
|
|
fs.File(f1)
|
|
fs.File(f2)
|
|
t = d.get_timestamp()
|
|
assert t == t2, "expected %f, got %f" % (t2, t)
|
|
|
|
skey = fs.Entry('eee.x').scanner_key()
|
|
assert skey == '.x', skey
|
|
skey = fs.Entry('eee.xyz').scanner_key()
|
|
assert skey == '.xyz', skey
|
|
|
|
skey = fs.File('fff.x').scanner_key()
|
|
assert skey == '.x', skey
|
|
skey = fs.File('fff.xyz').scanner_key()
|
|
assert skey == '.xyz', skey
|
|
|
|
skey = fs.Dir('ddd.x').scanner_key()
|
|
assert skey is None, skey
|
|
|
|
test.write("i_am_not_a_directory", "\n")
|
|
try:
|
|
exc_caught = 0
|
|
try:
|
|
fs.Dir(test.workpath("i_am_not_a_directory"))
|
|
except TypeError:
|
|
exc_caught = 1
|
|
assert exc_caught, "Should have caught a TypeError"
|
|
finally:
|
|
test.unlink("i_am_not_a_directory")
|
|
|
|
exc_caught = 0
|
|
try:
|
|
fs.File(sub_dir)
|
|
except TypeError:
|
|
exc_caught = 1
|
|
assert exc_caught, "Should have caught a TypeError"
|
|
|
|
# XXX test_is_up_to_date()
|
|
|
|
d = fs.Dir('dir')
|
|
r = d.remove()
|
|
assert r is None, r
|
|
|
|
f = fs.File('does_not_exist')
|
|
r = f.remove()
|
|
assert r is None, r
|
|
|
|
test.write('exists', "exists\n")
|
|
f = fs.File('exists')
|
|
r = f.remove()
|
|
assert r, r
|
|
assert not os.path.exists(test.workpath('exists')), "exists was not removed"
|
|
|
|
if sys.platform != 'win32' and hasattr(os, 'symlink'):
|
|
symlink = test.workpath('symlink')
|
|
os.symlink(test.workpath('does_not_exist'), symlink)
|
|
assert os.path.islink(symlink)
|
|
f = fs.File('symlink')
|
|
r = f.remove()
|
|
assert r, r
|
|
assert not os.path.islink(symlink), "symlink was not removed"
|
|
|
|
test.write('can_not_remove', "can_not_remove\n")
|
|
test.writable(test.workpath('.'), 0)
|
|
fp = open(test.workpath('can_not_remove'))
|
|
|
|
f = fs.File('can_not_remove')
|
|
exc_caught = 0
|
|
try:
|
|
r = f.remove()
|
|
except OSError:
|
|
exc_caught = 1
|
|
|
|
fp.close()
|
|
|
|
assert exc_caught, "Should have caught an OSError, r = " + str(r)
|
|
|
|
f = fs.Entry('foo/bar/baz')
|
|
assert f.for_signature() == 'baz', f.for_signature()
|
|
assert f.get_string(0) == os.path.normpath('foo/bar/baz'), \
|
|
f.get_string(0)
|
|
assert f.get_string(1) == 'baz', f.get_string(1)
|
|
|
|
def test_drive_letters(self):
|
|
"""Test drive-letter look-ups"""
|
|
|
|
test = self.test
|
|
|
|
test.subdir('sub', ['sub', 'dir'])
|
|
|
|
def drive_workpath(dirs, test=test):
|
|
x = test.workpath(*dirs)
|
|
drive, path = os.path.splitdrive(x)
|
|
return 'X:' + path
|
|
|
|
wp = drive_workpath([''])
|
|
|
|
if wp[-1] in (os.sep, '/'):
|
|
tmp = os.path.split(wp[:-1])[0]
|
|
else:
|
|
tmp = os.path.split(wp)[0]
|
|
|
|
parent_tmp = os.path.split(tmp)[0]
|
|
if parent_tmp == 'X:':
|
|
parent_tmp = 'X:' + os.sep
|
|
|
|
tmp_foo = os.path.join(tmp, 'foo')
|
|
|
|
foo = drive_workpath(['foo'])
|
|
foo_bar = drive_workpath(['foo', 'bar'])
|
|
sub = drive_workpath(['sub', ''])
|
|
sub_dir = drive_workpath(['sub', 'dir', ''])
|
|
sub_dir_foo = drive_workpath(['sub', 'dir', 'foo', ''])
|
|
sub_dir_foo_bar = drive_workpath(['sub', 'dir', 'foo', 'bar', ''])
|
|
sub_foo = drive_workpath(['sub', 'foo', ''])
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
seps = [os.sep]
|
|
if os.sep != '/':
|
|
seps = seps + ['/']
|
|
|
|
def _do_Dir_test(lpath, path_, up_path_, sep, fileSys=fs):
|
|
dir = fileSys.Dir(lpath.replace('/', sep))
|
|
|
|
if os.sep != '/':
|
|
path_ = path_.replace('/', os.sep)
|
|
up_path_ = up_path_.replace('/', os.sep)
|
|
|
|
def strip_slash(p):
|
|
if p[-1] == os.sep and len(p) > 3:
|
|
p = p[:-1]
|
|
return p
|
|
|
|
path = strip_slash(path_)
|
|
up_path = strip_slash(up_path_)
|
|
name = path.split(os.sep)[-1]
|
|
|
|
assert dir.name == name, \
|
|
"dir.name %s != expected name %s" % \
|
|
(dir.name, name)
|
|
assert dir.get_internal_path() == path, \
|
|
"dir.path %s != expected path %s" % \
|
|
(dir.get_internal_path(), path)
|
|
assert str(dir) == path, \
|
|
"str(dir) %s != expected path %s" % \
|
|
(str(dir), path)
|
|
assert dir.up().get_internal_path() == up_path, \
|
|
"dir.up().path %s != expected parent path %s" % \
|
|
(dir.up().get_internal_path(), up_path)
|
|
|
|
save_os_path = os.path
|
|
save_os_sep = os.sep
|
|
try:
|
|
import ntpath
|
|
os.path = ntpath
|
|
os.sep = '\\'
|
|
SCons.Node.FS.initialize_do_splitdrive()
|
|
|
|
for sep in seps:
|
|
def Dir_test(lpath, path_, up_path_, sep=sep, func=_do_Dir_test):
|
|
return func(lpath, path_, up_path_, sep)
|
|
|
|
Dir_test('#X:', wp, tmp)
|
|
Dir_test('X:foo', foo, wp)
|
|
Dir_test('X:foo/bar', foo_bar, foo)
|
|
Dir_test('X:/foo', 'X:/foo', 'X:/')
|
|
Dir_test('X:/foo/bar', 'X:/foo/bar/', 'X:/foo/')
|
|
Dir_test('X:..', tmp, parent_tmp)
|
|
Dir_test('X:foo/..', wp, tmp)
|
|
Dir_test('X:../foo', tmp_foo, tmp)
|
|
Dir_test('X:.', wp, tmp)
|
|
Dir_test('X:./.', wp, tmp)
|
|
Dir_test('X:foo/./bar', foo_bar, foo)
|
|
Dir_test('#X:../foo', tmp_foo, tmp)
|
|
Dir_test('#X:/../foo', tmp_foo, tmp)
|
|
Dir_test('#X:foo/bar', foo_bar, foo)
|
|
Dir_test('#X:/foo/bar', foo_bar, foo)
|
|
Dir_test('#X:/', wp, tmp)
|
|
finally:
|
|
os.path = save_os_path
|
|
os.sep = save_os_sep
|
|
SCons.Node.FS.initialize_do_splitdrive()
|
|
|
|
def test_unc_path(self):
|
|
"""Test UNC path look-ups"""
|
|
|
|
test = self.test
|
|
|
|
test.subdir('sub', ['sub', 'dir'])
|
|
|
|
def strip_slash(p):
|
|
if p[-1] == os.sep and len(p) > 3:
|
|
p = p[:-1]
|
|
return p
|
|
|
|
def unc_workpath(dirs, test=test):
|
|
import ntpath
|
|
x = test.workpath(*dirs)
|
|
drive, path = ntpath.splitdrive(x)
|
|
try:
|
|
unc, path = ntpath.splitunc(path)
|
|
except AttributeError:
|
|
# could be python 3.7 or newer, make sure splitdrive can do UNC
|
|
assert ntpath.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive'
|
|
path = strip_slash(path)
|
|
return '//' + path[1:]
|
|
|
|
wp = unc_workpath([''])
|
|
|
|
if wp[-1] in (os.sep, '/'):
|
|
tmp = os.path.split(wp[:-1])[0]
|
|
else:
|
|
tmp = os.path.split(wp)[0]
|
|
|
|
parent_tmp = os.path.split(tmp)[0]
|
|
|
|
tmp_foo = os.path.join(tmp, 'foo')
|
|
|
|
foo = unc_workpath(['foo'])
|
|
foo_bar = unc_workpath(['foo', 'bar'])
|
|
sub = unc_workpath(['sub', ''])
|
|
sub_dir = unc_workpath(['sub', 'dir', ''])
|
|
sub_dir_foo = unc_workpath(['sub', 'dir', 'foo', ''])
|
|
sub_dir_foo_bar = unc_workpath(['sub', 'dir', 'foo', 'bar', ''])
|
|
sub_foo = unc_workpath(['sub', 'foo', ''])
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
seps = [os.sep]
|
|
if os.sep != '/':
|
|
seps = seps + ['/']
|
|
|
|
def _do_Dir_test(lpath, path, up_path, sep, fileSys=fs):
|
|
dir = fileSys.Dir(lpath.replace('/', sep))
|
|
|
|
if os.sep != '/':
|
|
path = path.replace('/', os.sep)
|
|
up_path = up_path.replace('/', os.sep)
|
|
|
|
if path == os.sep + os.sep:
|
|
name = os.sep + os.sep
|
|
else:
|
|
name = path.split(os.sep)[-1]
|
|
|
|
if dir.up() is None:
|
|
dir_up_path = dir.get_internal_path()
|
|
else:
|
|
dir_up_path = dir.up().get_internal_path()
|
|
|
|
assert dir.name == name, \
|
|
"dir.name %s != expected name %s" % \
|
|
(dir.name, name)
|
|
assert dir.get_internal_path() == path, \
|
|
"dir.path %s != expected path %s" % \
|
|
(dir.get_internal_path(), path)
|
|
assert str(dir) == path, \
|
|
"str(dir) %s != expected path %s" % \
|
|
(str(dir), path)
|
|
assert dir_up_path == up_path, \
|
|
"dir.up().path %s != expected parent path %s" % \
|
|
(dir.up().get_internal_path(), up_path)
|
|
|
|
save_os_path = os.path
|
|
save_os_sep = os.sep
|
|
try:
|
|
import ntpath
|
|
os.path = ntpath
|
|
os.sep = '\\'
|
|
SCons.Node.FS.initialize_do_splitdrive()
|
|
|
|
for sep in seps:
|
|
def Dir_test(lpath, path_, up_path_, sep=sep, func=_do_Dir_test):
|
|
return func(lpath, path_, up_path_, sep)
|
|
|
|
Dir_test('//foo', '//foo', '//')
|
|
Dir_test('//foo/bar', '//foo/bar', '//foo')
|
|
Dir_test('//', '//', '//')
|
|
Dir_test('//..', '//', '//')
|
|
Dir_test('//foo/..', '//', '//')
|
|
Dir_test('//../foo', '//foo', '//')
|
|
Dir_test('//.', '//', '//')
|
|
Dir_test('//./.', '//', '//')
|
|
Dir_test('//foo/./bar', '//foo/bar', '//foo')
|
|
Dir_test('//foo/../bar', '//bar', '//')
|
|
Dir_test('//foo/../../bar', '//bar', '//')
|
|
Dir_test('//foo/bar/../..', '//', '//')
|
|
Dir_test('#//', wp, tmp)
|
|
Dir_test('#//../foo', tmp_foo, tmp)
|
|
Dir_test('#//../foo', tmp_foo, tmp)
|
|
Dir_test('#//foo/bar', foo_bar, foo)
|
|
Dir_test('#//foo/bar', foo_bar, foo)
|
|
Dir_test('#//', wp, tmp)
|
|
finally:
|
|
os.path = save_os_path
|
|
os.sep = save_os_sep
|
|
SCons.Node.FS.initialize_do_splitdrive()
|
|
|
|
def test_target_from_source(self):
|
|
"""Test the method for generating target nodes from sources"""
|
|
fs = self.fs
|
|
|
|
x = fs.File('x.c')
|
|
t = x.target_from_source('pre-', '-suf')
|
|
assert str(t) == 'pre-x-suf', str(t)
|
|
assert t.__class__ == SCons.Node.FS.Entry
|
|
|
|
y = fs.File('dir/y')
|
|
t = y.target_from_source('pre-', '-suf')
|
|
assert str(t) == os.path.join('dir', 'pre-y-suf'), str(t)
|
|
assert t.__class__ == SCons.Node.FS.Entry
|
|
|
|
z = fs.File('zz')
|
|
t = z.target_from_source('pre-', '-suf', lambda x: x[:-1])
|
|
assert str(t) == 'pre-z-suf', str(t)
|
|
assert t.__class__ == SCons.Node.FS.Entry
|
|
|
|
d = fs.Dir('ddd')
|
|
t = d.target_from_source('pre-', '-suf')
|
|
assert str(t) == 'pre-ddd-suf', str(t)
|
|
assert t.__class__ == SCons.Node.FS.Entry
|
|
|
|
e = fs.Entry('eee')
|
|
t = e.target_from_source('pre-', '-suf')
|
|
assert str(t) == 'pre-eee-suf', str(t)
|
|
assert t.__class__ == SCons.Node.FS.Entry
|
|
|
|
def test_same_name(self):
|
|
"""Test that a local same-named file isn't found for a Dir lookup"""
|
|
test = self.test
|
|
fs = self.fs
|
|
|
|
test.subdir('subdir')
|
|
test.write(['subdir', 'build'], "subdir/build\n")
|
|
|
|
subdir = fs.Dir('subdir')
|
|
fs.chdir(subdir, change_os_dir=True)
|
|
self.fs._lookup('#build/file', subdir, SCons.Node.FS.File)
|
|
|
|
def test_above_root(self):
|
|
"""Testing looking up a path above the root directory"""
|
|
test = self.test
|
|
fs = self.fs
|
|
|
|
d1 = fs.Dir('d1')
|
|
d2 = d1.Dir('d2')
|
|
dirs = os.path.normpath(d2.get_abspath()).split(os.sep)
|
|
above_path = os.path.join(*['..'] * len(dirs) + ['above'])
|
|
above = d2.Dir(above_path)
|
|
|
|
def test_lookup_abs(self):
|
|
"""Exercise the _lookup_abs function"""
|
|
test = self.test
|
|
fs = self.fs
|
|
|
|
root = fs.Dir('/')
|
|
d = root._lookup_abs('/tmp/foo-nonexistent/nonexistent-dir', SCons.Node.FS.Dir)
|
|
assert d.__class__ == SCons.Node.FS.Dir, str(d.__class__)
|
|
|
|
@unittest.skipUnless(sys.platform == "win32", "requires Windows")
|
|
def test_lookup_uncpath(self):
|
|
"""Testing looking up a UNC path on Windows"""
|
|
test = self.test
|
|
fs = self.fs
|
|
path = '//servername/C$/foo'
|
|
f = self.fs._lookup('//servername/C$/foo', fs.Dir('#'), SCons.Node.FS.File)
|
|
# before the fix in this commit, this returned 'C:\servername\C$\foo'
|
|
# Should be a normalized Windows UNC path as below.
|
|
assert str(f) == r'\\servername\C$\foo', \
|
|
'UNC path %s got looked up as %s' % (path, f)
|
|
|
|
@unittest.skipUnless(sys.platform.startswith == "win32", "requires Windows")
|
|
def test_unc_drive_letter(self):
|
|
"""Test drive-letter lookup for windows UNC-style directories"""
|
|
share = self.fs.Dir(r'\\SERVER\SHARE\Directory')
|
|
assert str(share) == r'\\SERVER\SHARE\Directory', str(share)
|
|
|
|
@unittest.skipUnless(sys.platform == "win32", "requires Windows")
|
|
def test_UNC_dirs_2689(self):
|
|
"""Test some UNC dirs that printed incorrectly and/or caused
|
|
infinite recursion errors prior to r5180 (SCons 2.1)."""
|
|
fs = self.fs
|
|
p = fs.Dir(r"\\computername\sharename").get_abspath()
|
|
assert p == r"\\computername\sharename", p
|
|
p = fs.Dir(r"\\\computername\sharename").get_abspath()
|
|
assert p == r"\\computername\sharename", p
|
|
|
|
def test_rel_path(self):
|
|
"""Test the rel_path() method"""
|
|
test = self.test
|
|
fs = self.fs
|
|
|
|
d1 = fs.Dir('d1')
|
|
d1_f = d1.File('f')
|
|
d1_d2 = d1.Dir('d2')
|
|
d1_d2_f = d1_d2.File('f')
|
|
|
|
d3 = fs.Dir('d3')
|
|
d3_f = d3.File('f')
|
|
d3_d4 = d3.Dir('d4')
|
|
d3_d4_f = d3_d4.File('f')
|
|
|
|
cases = [
|
|
d1, d1, '.',
|
|
d1, d1_f, 'f',
|
|
d1, d1_d2, 'd2',
|
|
d1, d1_d2_f, 'd2/f',
|
|
d1, d3, '../d3',
|
|
d1, d3_f, '../d3/f',
|
|
d1, d3_d4, '../d3/d4',
|
|
d1, d3_d4_f, '../d3/d4/f',
|
|
|
|
d1_f, d1, '.',
|
|
d1_f, d1_f, 'f',
|
|
d1_f, d1_d2, 'd2',
|
|
d1_f, d1_d2_f, 'd2/f',
|
|
d1_f, d3, '../d3',
|
|
d1_f, d3_f, '../d3/f',
|
|
d1_f, d3_d4, '../d3/d4',
|
|
d1_f, d3_d4_f, '../d3/d4/f',
|
|
|
|
d1_d2, d1, '..',
|
|
d1_d2, d1_f, '../f',
|
|
d1_d2, d1_d2, '.',
|
|
d1_d2, d1_d2_f, 'f',
|
|
d1_d2, d3, '../../d3',
|
|
d1_d2, d3_f, '../../d3/f',
|
|
d1_d2, d3_d4, '../../d3/d4',
|
|
d1_d2, d3_d4_f, '../../d3/d4/f',
|
|
|
|
d1_d2_f, d1, '..',
|
|
d1_d2_f, d1_f, '../f',
|
|
d1_d2_f, d1_d2, '.',
|
|
d1_d2_f, d1_d2_f, 'f',
|
|
d1_d2_f, d3, '../../d3',
|
|
d1_d2_f, d3_f, '../../d3/f',
|
|
d1_d2_f, d3_d4, '../../d3/d4',
|
|
d1_d2_f, d3_d4_f, '../../d3/d4/f',
|
|
]
|
|
|
|
if sys.platform in ('win32',):
|
|
x_d1 = fs.Dir(r'X:\d1')
|
|
x_d1_d2 = x_d1.Dir('d2')
|
|
y_d1 = fs.Dir(r'Y:\d1')
|
|
y_d1_d2 = y_d1.Dir('d2')
|
|
y_d2 = fs.Dir(r'Y:\d2')
|
|
|
|
win32_cases = [
|
|
x_d1, x_d1, '.',
|
|
x_d1, x_d1_d2, 'd2',
|
|
x_d1, y_d1, r'Y:\d1',
|
|
x_d1, y_d1_d2, r'Y:\d1\d2',
|
|
x_d1, y_d2, r'Y:\d2',
|
|
]
|
|
|
|
cases.extend(win32_cases)
|
|
|
|
failed = 0
|
|
while cases:
|
|
dir, other, expect = cases[:3]
|
|
expect = os.path.normpath(expect)
|
|
del cases[:3]
|
|
result = dir.rel_path(other)
|
|
if result != expect:
|
|
if failed == 0: print()
|
|
fmt = " dir_path(%(dir)s, %(other)s) => '%(result)s' did not match '%(expect)s'"
|
|
print(fmt % locals())
|
|
failed = failed + 1
|
|
assert failed == 0, "%d rel_path() cases failed" % failed
|
|
|
|
def test_proxy(self):
|
|
"""Test a Node.FS object wrapped in a proxy instance"""
|
|
f1 = self.fs.File('fff')
|
|
|
|
class MyProxy(SCons.Util.Proxy):
|
|
__str__ = SCons.Util.Delegate('__str__')
|
|
|
|
p = MyProxy(f1)
|
|
f2 = self.fs.Entry(p)
|
|
assert f1 is f2, (f1, str(f1), f2, str(f2))
|
|
|
|
|
|
class DirTestCase(_tempdirTestCase):
|
|
|
|
def test__morph(self):
|
|
"""Test handling of actions when morphing an Entry into a Dir"""
|
|
test = self.test
|
|
e = self.fs.Entry('eee')
|
|
x = e.get_executor()
|
|
x.add_pre_action('pre')
|
|
x.add_post_action('post')
|
|
e.must_be_same(SCons.Node.FS.Dir)
|
|
a = x.get_action_list()
|
|
assert 'pre' in a, a
|
|
assert 'post' in a, a
|
|
|
|
def test_subclass(self):
|
|
"""Test looking up subclass of Dir nodes"""
|
|
|
|
class DirSubclass(SCons.Node.FS.Dir):
|
|
pass
|
|
|
|
sd = self.fs._lookup('special_dir', None, DirSubclass, create=1)
|
|
sd.must_be_same(SCons.Node.FS.Dir)
|
|
|
|
def test_get_env_scanner(self):
|
|
"""Test the Dir.get_env_scanner() method
|
|
"""
|
|
import SCons.Defaults
|
|
d = self.fs.Dir('ddd')
|
|
s = d.get_env_scanner(Environment())
|
|
assert s is SCons.Defaults.DirEntryScanner, s
|
|
|
|
def test_get_target_scanner(self):
|
|
"""Test the Dir.get_target_scanner() method
|
|
"""
|
|
import SCons.Defaults
|
|
d = self.fs.Dir('ddd')
|
|
s = d.get_target_scanner()
|
|
assert s is SCons.Defaults.DirEntryScanner, s
|
|
|
|
def test_scan(self):
|
|
"""Test scanning a directory for in-memory entries
|
|
"""
|
|
fs = self.fs
|
|
|
|
dir = fs.Dir('ddd')
|
|
fs.File(os.path.join('ddd', 'f1'))
|
|
fs.File(os.path.join('ddd', 'f2'))
|
|
fs.File(os.path.join('ddd', 'f3'))
|
|
fs.Dir(os.path.join('ddd', 'd1'))
|
|
fs.Dir(os.path.join('ddd', 'd1', 'f4'))
|
|
fs.Dir(os.path.join('ddd', 'd1', 'f5'))
|
|
dir.scan()
|
|
kids = sorted([x.get_internal_path() for x in dir.children(None)])
|
|
assert kids == [os.path.join('ddd', 'd1'),
|
|
os.path.join('ddd', 'f1'),
|
|
os.path.join('ddd', 'f2'),
|
|
os.path.join('ddd', 'f3')], kids
|
|
|
|
def test_get_contents(self):
|
|
"""Test getting the contents for a directory.
|
|
"""
|
|
test = self.test
|
|
|
|
test.subdir('d')
|
|
test.write(['d', 'g'], "67890\n")
|
|
test.write(['d', 'f'], "12345\n")
|
|
test.subdir(['d', 'sub'])
|
|
test.write(['d', 'sub', 'h'], "abcdef\n")
|
|
test.subdir(['d', 'empty'])
|
|
|
|
d = self.fs.Dir('d')
|
|
g = self.fs.File(os.path.join('d', 'g'))
|
|
f = self.fs.File(os.path.join('d', 'f'))
|
|
h = self.fs.File(os.path.join('d', 'sub', 'h'))
|
|
e = self.fs.Dir(os.path.join('d', 'empty'))
|
|
s = self.fs.Dir(os.path.join('d', 'sub'))
|
|
|
|
files = d.get_contents().split('\n')
|
|
|
|
assert e.get_contents() == '', e.get_contents()
|
|
assert e.get_text_contents() == '', e.get_text_contents()
|
|
assert e.get_csig() + " empty" == files[0], files
|
|
assert f.get_csig() + " f" == files[1], files
|
|
assert g.get_csig() + " g" == files[2], files
|
|
assert s.get_csig() + " sub" == files[3], files
|
|
|
|
def test_hash_chunksize(self):
|
|
"""
|
|
Test verifying that File.get_csig() correctly uses hash_chunksize. This
|
|
variable is documented as the hash chunksize in kilobytes. This test
|
|
verifies that if the file size is less than the hash chunksize,
|
|
get_contents() is called; otherwise, it verifies that get_contents()
|
|
is not called.
|
|
"""
|
|
chunksize_bytes = SCons.Node.FS.File.hash_chunksize
|
|
test = self.test
|
|
|
|
test.subdir('chunksize_dir')
|
|
test.write(['chunksize_dir', 'f1'], 'a' * (chunksize_bytes // 1024 - 1))
|
|
test.write(['chunksize_dir', 'f2'], 'a' * (chunksize_bytes // 1024))
|
|
test.write(['chunksize_dir', 'f3'], 'a' * (chunksize_bytes + 1))
|
|
|
|
dir = self.fs.Dir('chunksize_dir')
|
|
f1 = dir.File('f1')
|
|
f2 = dir.File('f2')
|
|
f3 = dir.File('f3')
|
|
|
|
# Expect f1 and f2 to call get_contents(), while f3 will not because it
|
|
# should do reads of chunksize kilobytes at a time.
|
|
expected_get_contents_calls = {f1, f2}
|
|
self.actual_get_contents_calls = 0
|
|
|
|
def get_contents_override(file_object):
|
|
self.actual_get_contents_calls += 1
|
|
if file_object in expected_get_contents_calls:
|
|
return file_object._old_get_contents()
|
|
else:
|
|
raise Exception('get_contents was unexpectedly called on node '
|
|
'%s' % file_object)
|
|
|
|
SCons.Node.FS.File._old_get_contents = SCons.Node.FS.File.get_contents
|
|
SCons.Node.FS.File.get_contents = get_contents_override.__get__(
|
|
None, SCons.Node.FS)
|
|
|
|
# Call get_csig() to test get_contents() usage. The actual results of
|
|
# the calls to get_csig() are not relevant for this test. If an
|
|
# exception is raised, we must first reset the get_contents function
|
|
# before reraising it or other tests will fail too.
|
|
exception = None
|
|
try:
|
|
f1.get_csig()
|
|
f2.get_csig()
|
|
f3.get_csig()
|
|
except Exception as e:
|
|
exception = e
|
|
|
|
SCons.Node.FS.File.get_contents = SCons.Node.FS.File._old_get_contents
|
|
delattr(SCons.Node.FS.File, '_old_get_contents')
|
|
|
|
if exception:
|
|
raise exception
|
|
|
|
assert self.actual_get_contents_calls == len(expected_get_contents_calls), \
|
|
self.actual_get_contents_calls
|
|
|
|
def test_implicit_re_scans(self):
|
|
"""Test that adding entries causes a directory to be re-scanned
|
|
"""
|
|
|
|
fs = self.fs
|
|
|
|
dir = fs.Dir('ddd')
|
|
|
|
fs.File(os.path.join('ddd', 'f1'))
|
|
dir.scan()
|
|
kids = sorted([x.get_internal_path() for x in dir.children()])
|
|
assert kids == [os.path.join('ddd', 'f1')], kids
|
|
|
|
fs.File(os.path.join('ddd', 'f2'))
|
|
dir.scan()
|
|
kids = sorted([x.get_internal_path() for x in dir.children()])
|
|
assert kids == [os.path.join('ddd', 'f1'),
|
|
os.path.join('ddd', 'f2')], kids
|
|
|
|
def test_entry_exists_on_disk(self):
|
|
"""Test the Dir.entry_exists_on_disk() method
|
|
"""
|
|
test = self.test
|
|
|
|
does_not_exist = self.fs.Dir('does_not_exist')
|
|
assert not does_not_exist.entry_exists_on_disk('foo')
|
|
|
|
test.subdir('d')
|
|
test.write(['d', 'exists'], "d/exists\n")
|
|
test.write(['d', 'Case-Insensitive'], "d/Case-Insensitive\n")
|
|
|
|
d = self.fs.Dir('d')
|
|
assert d.entry_exists_on_disk('exists')
|
|
assert not d.entry_exists_on_disk('does_not_exist')
|
|
|
|
if os.path.normcase("TeSt") != os.path.normpath("TeSt") or sys.platform == "cygwin":
|
|
assert d.entry_exists_on_disk('case-insensitive')
|
|
|
|
def test_rentry_exists_on_disk(self):
|
|
"""Test the Dir.rentry_exists_on_disk() method
|
|
"""
|
|
test = self.test
|
|
|
|
does_not_exist = self.fs.Dir('does_not_exist')
|
|
assert not does_not_exist.rentry_exists_on_disk('foo')
|
|
|
|
test.subdir('d')
|
|
test.write(['d', 'exists'], "d/exists\n")
|
|
test.write(['d', 'Case-Insensitive'], "d/Case-Insensitive\n")
|
|
|
|
test.subdir('r')
|
|
test.write(['r', 'rexists'], "r/rexists\n")
|
|
|
|
d = self.fs.Dir('d')
|
|
r = self.fs.Dir('r')
|
|
d.addRepository(r)
|
|
|
|
assert d.rentry_exists_on_disk('exists')
|
|
assert d.rentry_exists_on_disk('rexists')
|
|
assert not d.rentry_exists_on_disk('does_not_exist')
|
|
|
|
if os.path.normcase("TeSt") != os.path.normpath("TeSt") or sys.platform == "cygwin":
|
|
assert d.rentry_exists_on_disk('case-insensitive')
|
|
|
|
def test_srcdir_list(self):
|
|
"""Test the Dir.srcdir_list() method
|
|
"""
|
|
src = self.fs.Dir('src')
|
|
bld = self.fs.Dir('bld')
|
|
sub1 = bld.Dir('sub')
|
|
sub2 = sub1.Dir('sub')
|
|
sub3 = sub2.Dir('sub')
|
|
self.fs.VariantDir(bld, src, duplicate=0)
|
|
self.fs.VariantDir(sub2, src, duplicate=0)
|
|
|
|
def check(result, expect):
|
|
result = list(map(str, result))
|
|
expect = list(map(os.path.normpath, expect))
|
|
assert result == expect, result
|
|
|
|
s = src.srcdir_list()
|
|
check(s, [])
|
|
|
|
s = bld.srcdir_list()
|
|
check(s, ['src'])
|
|
|
|
s = sub1.srcdir_list()
|
|
check(s, ['src/sub'])
|
|
|
|
s = sub2.srcdir_list()
|
|
check(s, ['src', 'src/sub/sub'])
|
|
|
|
s = sub3.srcdir_list()
|
|
check(s, ['src/sub', 'src/sub/sub/sub'])
|
|
|
|
self.fs.VariantDir('src/b1/b2', 'src')
|
|
b1 = src.Dir('b1')
|
|
b1_b2 = b1.Dir('b2')
|
|
b1_b2_b1 = b1_b2.Dir('b1')
|
|
b1_b2_b1_b2 = b1_b2_b1.Dir('b2')
|
|
b1_b2_b1_b2_sub = b1_b2_b1_b2.Dir('sub')
|
|
|
|
s = b1.srcdir_list()
|
|
check(s, [])
|
|
|
|
s = b1_b2.srcdir_list()
|
|
check(s, ['src'])
|
|
|
|
s = b1_b2_b1.srcdir_list()
|
|
check(s, ['src/b1'])
|
|
|
|
s = b1_b2_b1_b2.srcdir_list()
|
|
check(s, ['src/b1/b2'])
|
|
|
|
s = b1_b2_b1_b2_sub.srcdir_list()
|
|
check(s, ['src/b1/b2/sub'])
|
|
|
|
def test_srcdir_duplicate(self):
|
|
"""Test the Dir.srcdir_duplicate() method
|
|
"""
|
|
test = self.test
|
|
|
|
test.subdir('src0')
|
|
test.write(['src0', 'exists'], "src0/exists\n")
|
|
|
|
bld0 = self.fs.Dir('bld0')
|
|
src0 = self.fs.Dir('src0')
|
|
self.fs.VariantDir(bld0, src0, duplicate=0)
|
|
|
|
n = bld0.srcdir_duplicate('does_not_exist')
|
|
assert n is None, n
|
|
assert not os.path.exists(test.workpath('bld0', 'does_not_exist'))
|
|
|
|
n = bld0.srcdir_duplicate('exists')
|
|
assert str(n) == os.path.normpath('src0/exists'), str(n)
|
|
assert not os.path.exists(test.workpath('bld0', 'exists'))
|
|
|
|
test.subdir('src1')
|
|
test.write(['src1', 'exists'], "src0/exists\n")
|
|
|
|
bld1 = self.fs.Dir('bld1')
|
|
src1 = self.fs.Dir('src1')
|
|
self.fs.VariantDir(bld1, src1, duplicate=1)
|
|
|
|
n = bld1.srcdir_duplicate('does_not_exist')
|
|
assert n is None, n
|
|
assert not os.path.exists(test.workpath('bld1', 'does_not_exist'))
|
|
|
|
n = bld1.srcdir_duplicate('exists')
|
|
assert str(n) == os.path.normpath('bld1/exists'), str(n)
|
|
assert os.path.exists(test.workpath('bld1', 'exists'))
|
|
|
|
def test_srcdir_find_file(self):
|
|
"""Test the Dir.srcdir_find_file() method
|
|
"""
|
|
test = self.test
|
|
|
|
def return_true(node):
|
|
return 1
|
|
|
|
SCons.Node._is_derived_map[2] = return_true
|
|
SCons.Node._exists_map[5] = return_true
|
|
|
|
test.subdir('src0')
|
|
test.write(['src0', 'on-disk-f1'], "src0/on-disk-f1\n")
|
|
test.write(['src0', 'on-disk-f2'], "src0/on-disk-f2\n")
|
|
test.write(['src0', 'on-disk-e1'], "src0/on-disk-e1\n")
|
|
test.write(['src0', 'on-disk-e2'], "src0/on-disk-e2\n")
|
|
|
|
bld0 = self.fs.Dir('bld0')
|
|
src0 = self.fs.Dir('src0')
|
|
self.fs.VariantDir(bld0, src0, duplicate=0)
|
|
|
|
derived_f = src0.File('derived-f')
|
|
derived_f._func_is_derived = 2
|
|
exists_f = src0.File('exists-f')
|
|
exists_f._func_exists = 5
|
|
|
|
derived_e = src0.Entry('derived-e')
|
|
derived_e._func_is_derived = 2
|
|
exists_e = src0.Entry('exists-e')
|
|
exists_e._func_exists = 5
|
|
|
|
def check(result, expect):
|
|
result = list(map(str, result))
|
|
expect = list(map(os.path.normpath, expect))
|
|
assert result == expect, result
|
|
|
|
# First check from the source directory.
|
|
n = src0.srcdir_find_file('does_not_exist')
|
|
assert n == (None, None), n
|
|
|
|
n = src0.srcdir_find_file('derived-f')
|
|
check(n, ['src0/derived-f', 'src0'])
|
|
n = src0.srcdir_find_file('exists-f')
|
|
check(n, ['src0/exists-f', 'src0'])
|
|
n = src0.srcdir_find_file('on-disk-f1')
|
|
check(n, ['src0/on-disk-f1', 'src0'])
|
|
|
|
n = src0.srcdir_find_file('derived-e')
|
|
check(n, ['src0/derived-e', 'src0'])
|
|
n = src0.srcdir_find_file('exists-e')
|
|
check(n, ['src0/exists-e', 'src0'])
|
|
n = src0.srcdir_find_file('on-disk-e1')
|
|
check(n, ['src0/on-disk-e1', 'src0'])
|
|
|
|
# Now check from the variant directory.
|
|
n = bld0.srcdir_find_file('does_not_exist')
|
|
assert n == (None, None), n
|
|
|
|
n = bld0.srcdir_find_file('derived-f')
|
|
check(n, ['src0/derived-f', 'bld0'])
|
|
n = bld0.srcdir_find_file('exists-f')
|
|
check(n, ['src0/exists-f', 'bld0'])
|
|
n = bld0.srcdir_find_file('on-disk-f2')
|
|
check(n, ['src0/on-disk-f2', 'bld0'])
|
|
|
|
n = bld0.srcdir_find_file('derived-e')
|
|
check(n, ['src0/derived-e', 'bld0'])
|
|
n = bld0.srcdir_find_file('exists-e')
|
|
check(n, ['src0/exists-e', 'bld0'])
|
|
n = bld0.srcdir_find_file('on-disk-e2')
|
|
check(n, ['src0/on-disk-e2', 'bld0'])
|
|
|
|
test.subdir('src1')
|
|
test.write(['src1', 'on-disk-f1'], "src1/on-disk-f1\n")
|
|
test.write(['src1', 'on-disk-f2'], "src1/on-disk-f2\n")
|
|
test.write(['src1', 'on-disk-e1'], "src1/on-disk-e1\n")
|
|
test.write(['src1', 'on-disk-e2'], "src1/on-disk-e2\n")
|
|
|
|
bld1 = self.fs.Dir('bld1')
|
|
src1 = self.fs.Dir('src1')
|
|
self.fs.VariantDir(bld1, src1, duplicate=1)
|
|
|
|
derived_f = src1.File('derived-f')
|
|
derived_f._func_is_derived = 2
|
|
exists_f = src1.File('exists-f')
|
|
exists_f._func_exists = 5
|
|
|
|
derived_e = src1.Entry('derived-e')
|
|
derived_e._func_is_derived = 2
|
|
exists_e = src1.Entry('exists-e')
|
|
exists_e._func_exists = 5
|
|
|
|
# First check from the source directory.
|
|
n = src1.srcdir_find_file('does_not_exist')
|
|
assert n == (None, None), n
|
|
|
|
n = src1.srcdir_find_file('derived-f')
|
|
check(n, ['src1/derived-f', 'src1'])
|
|
n = src1.srcdir_find_file('exists-f')
|
|
check(n, ['src1/exists-f', 'src1'])
|
|
n = src1.srcdir_find_file('on-disk-f1')
|
|
check(n, ['src1/on-disk-f1', 'src1'])
|
|
|
|
n = src1.srcdir_find_file('derived-e')
|
|
check(n, ['src1/derived-e', 'src1'])
|
|
n = src1.srcdir_find_file('exists-e')
|
|
check(n, ['src1/exists-e', 'src1'])
|
|
n = src1.srcdir_find_file('on-disk-e1')
|
|
check(n, ['src1/on-disk-e1', 'src1'])
|
|
|
|
# Now check from the variant directory.
|
|
n = bld1.srcdir_find_file('does_not_exist')
|
|
assert n == (None, None), n
|
|
|
|
n = bld1.srcdir_find_file('derived-f')
|
|
check(n, ['bld1/derived-f', 'src1'])
|
|
n = bld1.srcdir_find_file('exists-f')
|
|
check(n, ['bld1/exists-f', 'src1'])
|
|
n = bld1.srcdir_find_file('on-disk-f2')
|
|
check(n, ['bld1/on-disk-f2', 'bld1'])
|
|
|
|
n = bld1.srcdir_find_file('derived-e')
|
|
check(n, ['bld1/derived-e', 'src1'])
|
|
n = bld1.srcdir_find_file('exists-e')
|
|
check(n, ['bld1/exists-e', 'src1'])
|
|
n = bld1.srcdir_find_file('on-disk-e2')
|
|
check(n, ['bld1/on-disk-e2', 'bld1'])
|
|
|
|
def test_dir_on_disk(self):
|
|
"""Test the Dir.dir_on_disk() method"""
|
|
self.test.subdir('sub', ['sub', 'exists'])
|
|
self.test.write(['sub', 'file'], "self/file\n")
|
|
sub = self.fs.Dir('sub')
|
|
|
|
r = sub.dir_on_disk('does_not_exist')
|
|
assert not r, r
|
|
|
|
r = sub.dir_on_disk('exists')
|
|
assert r, r
|
|
|
|
r = sub.dir_on_disk('file')
|
|
assert not r, r
|
|
|
|
def test_file_on_disk(self):
|
|
"""Test the Dir.file_on_disk() method"""
|
|
self.test.subdir('sub', ['sub', 'dir'])
|
|
self.test.write(['sub', 'exists'], "self/exists\n")
|
|
sub = self.fs.Dir('sub')
|
|
|
|
r = sub.file_on_disk('does_not_exist')
|
|
assert not r, r
|
|
|
|
r = sub.file_on_disk('exists')
|
|
assert r, r
|
|
|
|
r = sub.file_on_disk('dir')
|
|
assert not r, r
|
|
|
|
|
|
class EntryTestCase(_tempdirTestCase):
|
|
def test_runTest(self):
|
|
"""Test methods specific to the Entry sub-class.
|
|
"""
|
|
test = TestCmd(workdir='')
|
|
# FS doesn't like the cwd to be something other than its root.
|
|
os.chdir(test.workpath(""))
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
e1 = fs.Entry('e1')
|
|
e1.rfile()
|
|
assert e1.__class__ is SCons.Node.FS.File, e1.__class__
|
|
|
|
test.subdir('e3d')
|
|
test.write('e3f', "e3f\n")
|
|
|
|
e3d = fs.Entry('e3d')
|
|
e3d.get_contents()
|
|
assert e3d.__class__ is SCons.Node.FS.Dir, e3d.__class__
|
|
|
|
e3f = fs.Entry('e3f')
|
|
e3f.get_contents()
|
|
assert e3f.__class__ is SCons.Node.FS.File, e3f.__class__
|
|
|
|
e3n = fs.Entry('e3n')
|
|
e3n.get_contents()
|
|
assert e3n.__class__ is SCons.Node.FS.Entry, e3n.__class__
|
|
|
|
test.subdir('e4d')
|
|
test.write('e4f', "e4f\n")
|
|
|
|
e4d = fs.Entry('e4d')
|
|
exists = e4d.exists()
|
|
assert e4d.__class__ is SCons.Node.FS.Dir, e4d.__class__
|
|
assert exists, "e4d does not exist?"
|
|
|
|
e4f = fs.Entry('e4f')
|
|
exists = e4f.exists()
|
|
assert e4f.__class__ is SCons.Node.FS.File, e4f.__class__
|
|
assert exists, "e4f does not exist?"
|
|
|
|
e4n = fs.Entry('e4n')
|
|
exists = e4n.exists()
|
|
assert e4n.__class__ is SCons.Node.FS.File, e4n.__class__
|
|
assert not exists, "e4n exists?"
|
|
|
|
class MyCalc:
|
|
def __init__(self, val):
|
|
self.max_drift = 0
|
|
|
|
class M:
|
|
def __init__(self, val):
|
|
self.val = val
|
|
|
|
def collect(self, args):
|
|
result = 0
|
|
for a in args:
|
|
result += a
|
|
return result
|
|
|
|
def signature(self, executor):
|
|
return self.val + 222
|
|
|
|
self.module = M(val)
|
|
|
|
test.subdir('e5d')
|
|
test.write('e5f', "e5f\n")
|
|
|
|
def test_Entry_Entry_lookup(self):
|
|
"""Test looking up an Entry within another Entry"""
|
|
self.fs.Entry('#topdir')
|
|
self.fs.Entry('#topdir/a/b/c')
|
|
|
|
|
|
class FileTestCase(_tempdirTestCase):
|
|
|
|
def test_subclass(self):
|
|
"""Test looking up subclass of File nodes"""
|
|
|
|
class FileSubclass(SCons.Node.FS.File):
|
|
pass
|
|
|
|
sd = self.fs._lookup('special_file', None, FileSubclass, create=1)
|
|
sd.must_be_same(SCons.Node.FS.File)
|
|
|
|
def test_Dirs(self):
|
|
"""Test the File.Dirs() method"""
|
|
fff = self.fs.File('subdir/fff')
|
|
# This simulates that the SConscript file that defined
|
|
# fff is in subdir/.
|
|
fff.cwd = self.fs.Dir('subdir')
|
|
d1 = self.fs.Dir('subdir/d1')
|
|
d2 = self.fs.Dir('subdir/d2')
|
|
dirs = fff.Dirs(['d1', 'd2'])
|
|
assert dirs == [d1, d2], list(map(str, dirs))
|
|
|
|
def test_exists(self):
|
|
"""Test the File.exists() method"""
|
|
fs = self.fs
|
|
test = self.test
|
|
|
|
src_f1 = fs.File('src/f1')
|
|
assert not src_f1.exists(), "%s apparently exists?" % src_f1
|
|
|
|
test.subdir('src')
|
|
test.write(['src', 'f1'], "src/f1\n")
|
|
|
|
assert not src_f1.exists(), "%s did not cache previous exists() value" % src_f1
|
|
src_f1.clear()
|
|
assert src_f1.exists(), "%s apparently does not exist?" % src_f1
|
|
|
|
test.subdir('build')
|
|
fs.VariantDir('build', 'src')
|
|
build_f1 = fs.File('build/f1')
|
|
|
|
assert build_f1.exists(), "%s did not realize that %s exists" % (build_f1, src_f1)
|
|
assert os.path.exists(build_f1.get_abspath()), "%s did not get duplicated on disk" % build_f1.get_abspath()
|
|
|
|
test.unlink(['src', 'f1'])
|
|
src_f1.clear() # so the next exists() call will look on disk again
|
|
|
|
assert build_f1.exists(), "%s did not cache previous exists() value" % build_f1
|
|
build_f1.clear()
|
|
build_f1.linked = None
|
|
assert not build_f1.exists(), "%s did not realize that %s disappeared" % (build_f1, src_f1)
|
|
assert not os.path.exists(build_f1.get_abspath()), "%s did not get removed after %s was removed" % (
|
|
build_f1, src_f1)
|
|
|
|
def test_changed(self):
|
|
"""
|
|
Verify that changes between BuildInfo's list of souces, depends, and implicit
|
|
dependencies do not corrupt content signature values written to .SConsign
|
|
when using CacheDir and Timestamp-MD5 decider.
|
|
This is for issue #2980
|
|
"""
|
|
|
|
# node should have
|
|
# 1 source (for example main.cpp)
|
|
# 0 depends
|
|
# N implicits (for example ['alpha.h', 'beta.h', 'gamma.h', '/usr/bin/g++'])
|
|
|
|
class ChangedNode(SCons.Node.FS.File):
|
|
def __init__(self, name, directory=None, fs=None):
|
|
super().__init__(name, directory, fs)
|
|
self.name = name
|
|
self.Tag('found_includes', [])
|
|
self.stored_info = None
|
|
self.build_env = None
|
|
self.changed_since_last_build = 4
|
|
self.timestamp = 1
|
|
|
|
def get_stored_info(self):
|
|
return self.stored_info
|
|
|
|
def get_build_env(self):
|
|
return self.build_env
|
|
|
|
def get_timestamp(self):
|
|
""" Fake timestamp so they always match"""
|
|
return self.timestamp
|
|
|
|
def get_contents(self):
|
|
return self.name
|
|
|
|
def get_ninfo(self):
|
|
""" mocked to ensure csig will equal the filename"""
|
|
if self.ninfo is not None:
|
|
return self.ninfo
|
|
self.ninfo = FakeNodeInfo(self.name, self.timestamp)
|
|
return self.ninfo
|
|
|
|
def get_csig(self):
|
|
ninfo = self.get_ninfo()
|
|
try:
|
|
return ninfo.csig
|
|
except AttributeError:
|
|
pass
|
|
|
|
return "Should Never Happen"
|
|
|
|
class ChangedEnvironment(SCons.Environment.Base):
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.decide_source = self._changed_timestamp_then_content
|
|
|
|
class FakeNodeInfo:
|
|
def __init__(self, csig, timestamp):
|
|
self.csig = csig
|
|
self.timestamp = timestamp
|
|
|
|
# Create nodes
|
|
fs = SCons.Node.FS.FS()
|
|
d = self.fs.Dir('.')
|
|
|
|
node = ChangedNode('main.o', d, fs) # main.o
|
|
s1 = ChangedNode('main.cpp', d, fs) # main.cpp
|
|
s1.timestamp = 2 # this changed
|
|
i1 = ChangedNode('alpha.h', d, fs) # alpha.h - The bug is caused because the second build adds this file
|
|
i1.timestamp = 2 # This is the new file.
|
|
i2 = ChangedNode('beta.h', d, fs) # beta.h
|
|
i3 = ChangedNode('gamma.h', d, fs) # gamma.h - In the bug beta.h's csig from binfo overwrites this ones
|
|
i4 = ChangedNode('/usr/bin/g++', d, fs) # /usr/bin/g++
|
|
|
|
node.add_source([s1])
|
|
node.add_dependency([])
|
|
node.implicit = [i1, i2, i3, i4]
|
|
node.implicit_set = set()
|
|
# node._add_child(node.implicit, node.implicit_set, [n7, n8, n9])
|
|
# node._add_child(node.implicit, node.implicit_set, [n10, n11, n12])
|
|
|
|
# Mock out node's scan method
|
|
# node.scan = lambda *args: None
|
|
|
|
# Mock out nodes' children() ?
|
|
# Should return Node's.
|
|
# All those nodes should have changed_since_last_build set to match Timestamp-MD5's
|
|
# decider method...
|
|
|
|
# Generate sconsign entry needed
|
|
sconsign_entry = SCons.SConsign.SConsignEntry()
|
|
sconsign_entry.binfo = node.new_binfo()
|
|
sconsign_entry.ninfo = node.new_ninfo()
|
|
|
|
# mock out loading info from sconsign
|
|
# This will cause node.get_stored_info() to return our freshly created sconsign_entry
|
|
node.stored_info = sconsign_entry
|
|
|
|
# binfo = information from previous build (from sconsign)
|
|
# We'll set the following attributes (which are lists): "bsources", "bsourcesigs",
|
|
# "bdepends","bdependsigs", "bimplicit", "bimplicitsigs"
|
|
bi = sconsign_entry.binfo
|
|
bi.bsources = ['main.cpp']
|
|
bi.bsourcesigs = [FakeNodeInfo('main.cpp', 1), ]
|
|
|
|
bi.bdepends = []
|
|
bi.bdependsigs = []
|
|
|
|
bi.bimplicit = ['beta.h', 'gamma.h']
|
|
bi.bimplicitsigs = [FakeNodeInfo('beta.h', 1), FakeNodeInfo('gamma.h', 1)]
|
|
|
|
ni = sconsign_entry.ninfo
|
|
# We'll set the following attributes (which are lists): sources, depends, implicit lists
|
|
|
|
# Set timestamp-md5
|
|
# Call changed
|
|
# Check results
|
|
node.build_env = ChangedEnvironment()
|
|
|
|
changed = node.changed()
|
|
|
|
# change to true to debug
|
|
if False:
|
|
print("Changed:%s" % changed)
|
|
print("%15s -> csig:%s" % (s1.name, s1.ninfo.csig))
|
|
print("%15s -> csig:%s" % (i1.name, i1.ninfo.csig))
|
|
print("%15s -> csig:%s" % (i2.name, i2.ninfo.csig))
|
|
print("%15s -> csig:%s" % (i3.name, i3.ninfo.csig))
|
|
print("%15s -> csig:%s" % (i4.name, i4.ninfo.csig))
|
|
|
|
self.assertEqual(
|
|
i2.name,
|
|
i2.ninfo.csig,
|
|
"gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig,
|
|
)
|
|
|
|
|
|
class GlobTestCase(_tempdirTestCase):
|
|
def setUp(self):
|
|
_tempdirTestCase.setUp(self)
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
self.fs = fs
|
|
|
|
# Make entries on disk that will not have Nodes, so we can verify
|
|
# the behavior of looking for things on disk.
|
|
self.test.write('disk-bbb', "disk-bbb\n")
|
|
self.test.write('disk-aaa', "disk-aaa\n")
|
|
self.test.write('disk-ccc', "disk-ccc\n")
|
|
self.test.write('#disk-hash', "#disk-hash\n")
|
|
self.test.subdir('disk-sub')
|
|
self.test.write(['disk-sub', 'disk-ddd'], "disk-sub/disk-ddd\n")
|
|
self.test.write(['disk-sub', 'disk-eee'], "disk-sub/disk-eee\n")
|
|
self.test.write(['disk-sub', 'disk-fff'], "disk-sub/disk-fff\n")
|
|
|
|
# Make some entries that have both Nodes and on-disk entries,
|
|
# so we can verify what we do with
|
|
self.test.write('both-aaa', "both-aaa\n")
|
|
self.test.write('both-bbb', "both-bbb\n")
|
|
self.test.write('both-ccc', "both-ccc\n")
|
|
self.test.write('#both-hash', "#both-hash\n")
|
|
self.test.subdir('both-sub1')
|
|
self.test.write(['both-sub1', 'both-ddd'], "both-sub1/both-ddd\n")
|
|
self.test.write(['both-sub1', 'both-eee'], "both-sub1/both-eee\n")
|
|
self.test.write(['both-sub1', 'both-fff'], "both-sub1/both-fff\n")
|
|
self.test.subdir('both-sub2')
|
|
self.test.write(['both-sub2', 'both-ddd'], "both-sub2/both-ddd\n")
|
|
self.test.write(['both-sub2', 'both-eee'], "both-sub2/both-eee\n")
|
|
self.test.write(['both-sub2', 'both-fff'], "both-sub2/both-fff\n")
|
|
|
|
self.both_aaa = fs.File('both-aaa')
|
|
self.both_bbb = fs.File('both-bbb')
|
|
self.both_ccc = fs.File('both-ccc')
|
|
self._both_hash = fs.File('./#both-hash')
|
|
self.both_sub1 = fs.Dir('both-sub1')
|
|
self.both_sub1_both_ddd = self.both_sub1.File('both-ddd')
|
|
self.both_sub1_both_eee = self.both_sub1.File('both-eee')
|
|
self.both_sub1_both_fff = self.both_sub1.File('both-fff')
|
|
self.both_sub2 = fs.Dir('both-sub2')
|
|
self.both_sub2_both_ddd = self.both_sub2.File('both-ddd')
|
|
self.both_sub2_both_eee = self.both_sub2.File('both-eee')
|
|
self.both_sub2_both_fff = self.both_sub2.File('both-fff')
|
|
|
|
# Make various Nodes (that don't have on-disk entries) so we
|
|
# can verify how we match them.
|
|
self.ggg = fs.File('ggg')
|
|
self.hhh = fs.File('hhh')
|
|
self.iii = fs.File('iii')
|
|
self._hash = fs.File('./#hash')
|
|
self.subdir1 = fs.Dir('subdir1')
|
|
self.subdir1_lll = self.subdir1.File('lll')
|
|
self.subdir1_jjj = self.subdir1.File('jjj')
|
|
self.subdir1_kkk = self.subdir1.File('kkk')
|
|
self.subdir2 = fs.Dir('subdir2')
|
|
self.subdir2_lll = self.subdir2.File('lll')
|
|
self.subdir2_kkk = self.subdir2.File('kkk')
|
|
self.subdir2_jjj = self.subdir2.File('jjj')
|
|
self.sub = fs.Dir('sub')
|
|
self.sub_dir3 = self.sub.Dir('dir3')
|
|
self.sub_dir3_kkk = self.sub_dir3.File('kkk')
|
|
self.sub_dir3_jjj = self.sub_dir3.File('jjj')
|
|
self.sub_dir3_lll = self.sub_dir3.File('lll')
|
|
|
|
def do_cases(self, cases, **kwargs):
|
|
|
|
# First, execute all of the cases with string=True and verify
|
|
# that we get the expected strings returned. We do this first
|
|
# so the Glob() calls don't add Nodes to the self.fs file system
|
|
# hierarchy.
|
|
|
|
import copy
|
|
strings_kwargs = copy.copy(kwargs)
|
|
strings_kwargs['strings'] = True
|
|
for input, string_expect, node_expect in cases:
|
|
r = sorted(self.fs.Glob(input, **strings_kwargs))
|
|
assert r == string_expect, "Glob(%s, strings=True) expected %s, got %s" % (input, string_expect, r)
|
|
|
|
# Now execute all of the cases without string=True and look for
|
|
# the expected Nodes to be returned. If we don't have a list of
|
|
# actual expected Nodes, that means we're expecting a search for
|
|
# on-disk-only files to have returned some newly-created nodes.
|
|
# Verify those by running the list through str() before comparing
|
|
# them with the expected list of strings.
|
|
for input, string_expect, node_expect in cases:
|
|
r = self.fs.Glob(input, **kwargs)
|
|
if node_expect:
|
|
r = sorted(r, key=lambda a: a.get_internal_path())
|
|
result = []
|
|
for n in node_expect:
|
|
if isinstance(n, str):
|
|
n = self.fs.Entry(n)
|
|
result.append(n)
|
|
fmt = lambda n: "%s %s" % (repr(n), repr(str(n)))
|
|
else:
|
|
r = sorted(map(str, r))
|
|
result = string_expect
|
|
fmt = lambda n: n
|
|
if r != result:
|
|
import pprint
|
|
print("Glob(%s) expected:" % repr(input))
|
|
pprint.pprint(list(map(fmt, result)))
|
|
print("Glob(%s) got:" % repr(input))
|
|
pprint.pprint(list(map(fmt, r)))
|
|
self.fail()
|
|
|
|
def test_exact_match(self):
|
|
"""Test globbing for exact Node matches"""
|
|
join = os.path.join
|
|
|
|
cases = (
|
|
('ggg', ['ggg'], [self.ggg]),
|
|
|
|
('subdir1', ['subdir1'], [self.subdir1]),
|
|
|
|
('subdir1/jjj', [join('subdir1', 'jjj')], [self.subdir1_jjj]),
|
|
|
|
('disk-aaa', ['disk-aaa'], None),
|
|
|
|
('disk-sub', ['disk-sub'], None),
|
|
|
|
('both-aaa', ['both-aaa'], []),
|
|
)
|
|
|
|
self.do_cases(cases)
|
|
|
|
def test_subdir_matches(self):
|
|
"""Test globbing for exact Node matches in subdirectories"""
|
|
join = os.path.join
|
|
|
|
cases = (
|
|
('*/jjj',
|
|
[join('subdir1', 'jjj'), join('subdir2', 'jjj')],
|
|
[self.subdir1_jjj, self.subdir2_jjj]),
|
|
|
|
('*/disk-ddd',
|
|
[join('disk-sub', 'disk-ddd')],
|
|
None),
|
|
)
|
|
|
|
self.do_cases(cases)
|
|
|
|
def test_asterisk1(self):
|
|
"""Test globbing for simple asterisk Node matches (1)"""
|
|
cases = (
|
|
('h*',
|
|
['hhh'],
|
|
[self.hhh]),
|
|
|
|
('*',
|
|
['#both-hash', '#hash',
|
|
'both-aaa', 'both-bbb', 'both-ccc',
|
|
'both-sub1', 'both-sub2',
|
|
'ggg', 'hhh', 'iii',
|
|
'sub', 'subdir1', 'subdir2'],
|
|
[self._both_hash, self._hash,
|
|
self.both_aaa, self.both_bbb, self.both_ccc, 'both-hash',
|
|
self.both_sub1, self.both_sub2,
|
|
self.ggg, 'hash', self.hhh, self.iii,
|
|
self.sub, self.subdir1, self.subdir2]),
|
|
)
|
|
|
|
self.do_cases(cases, ondisk=False)
|
|
|
|
def test_asterisk2(self):
|
|
"""Test globbing for simple asterisk Node matches (2)"""
|
|
cases = (
|
|
('disk-b*',
|
|
['disk-bbb'],
|
|
None),
|
|
|
|
('*',
|
|
['#both-hash', '#disk-hash', '#hash',
|
|
'both-aaa', 'both-bbb', 'both-ccc',
|
|
'both-sub1', 'both-sub2',
|
|
'disk-aaa', 'disk-bbb', 'disk-ccc', 'disk-sub',
|
|
'ggg', 'hhh', 'iii',
|
|
'sub', 'subdir1', 'subdir2'],
|
|
['./#both-hash', './#disk-hash', './#hash',
|
|
'both-aaa', 'both-bbb', 'both-ccc', 'both-hash',
|
|
'both-sub1', 'both-sub2',
|
|
'disk-aaa', 'disk-bbb', 'disk-ccc', 'disk-sub',
|
|
'ggg', 'hash', 'hhh', 'iii',
|
|
'sub', 'subdir1', 'subdir2']),
|
|
)
|
|
|
|
self.do_cases(cases)
|
|
|
|
def test_question_mark(self):
|
|
"""Test globbing for simple question-mark Node matches"""
|
|
join = os.path.join
|
|
|
|
cases = (
|
|
('ii?',
|
|
['iii'],
|
|
[self.iii]),
|
|
|
|
('both-sub?/both-eee',
|
|
[join('both-sub1', 'both-eee'), join('both-sub2', 'both-eee')],
|
|
[self.both_sub1_both_eee, self.both_sub2_both_eee]),
|
|
|
|
('subdir?/jjj',
|
|
[join('subdir1', 'jjj'), join('subdir2', 'jjj')],
|
|
[self.subdir1_jjj, self.subdir2_jjj]),
|
|
|
|
('disk-cc?',
|
|
['disk-ccc'],
|
|
None),
|
|
)
|
|
|
|
self.do_cases(cases)
|
|
|
|
def test_does_not_exist(self):
|
|
"""Test globbing for things that don't exist"""
|
|
|
|
cases = (
|
|
('does_not_exist', [], []),
|
|
('no_subdir/*', [], []),
|
|
('subdir?/no_file', [], []),
|
|
)
|
|
|
|
self.do_cases(cases)
|
|
|
|
def test_subdir_asterisk(self):
|
|
"""Test globbing for asterisk Node matches in subdirectories"""
|
|
join = os.path.join
|
|
|
|
cases = (
|
|
('*/k*',
|
|
[join('subdir1', 'kkk'), join('subdir2', 'kkk')],
|
|
[self.subdir1_kkk, self.subdir2_kkk]),
|
|
|
|
('both-sub?/*',
|
|
[join('both-sub1', 'both-ddd'),
|
|
join('both-sub1', 'both-eee'),
|
|
join('both-sub1', 'both-fff'),
|
|
join('both-sub2', 'both-ddd'),
|
|
join('both-sub2', 'both-eee'),
|
|
join('both-sub2', 'both-fff')],
|
|
[self.both_sub1_both_ddd,
|
|
self.both_sub1_both_eee,
|
|
self.both_sub1_both_fff,
|
|
self.both_sub2_both_ddd,
|
|
self.both_sub2_both_eee,
|
|
self.both_sub2_both_fff],
|
|
),
|
|
|
|
('subdir?/*',
|
|
[join('subdir1', 'jjj'),
|
|
join('subdir1', 'kkk'),
|
|
join('subdir1', 'lll'),
|
|
join('subdir2', 'jjj'),
|
|
join('subdir2', 'kkk'),
|
|
join('subdir2', 'lll')],
|
|
[self.subdir1_jjj, self.subdir1_kkk, self.subdir1_lll,
|
|
self.subdir2_jjj, self.subdir2_kkk, self.subdir2_lll]),
|
|
|
|
('sub/*/*',
|
|
[join('sub', 'dir3', 'jjj'),
|
|
join('sub', 'dir3', 'kkk'),
|
|
join('sub', 'dir3', 'lll')],
|
|
[self.sub_dir3_jjj, self.sub_dir3_kkk, self.sub_dir3_lll]),
|
|
|
|
('*/k*',
|
|
[join('subdir1', 'kkk'), join('subdir2', 'kkk')],
|
|
None),
|
|
|
|
('subdir?/*',
|
|
[join('subdir1', 'jjj'),
|
|
join('subdir1', 'kkk'),
|
|
join('subdir1', 'lll'),
|
|
join('subdir2', 'jjj'),
|
|
join('subdir2', 'kkk'),
|
|
join('subdir2', 'lll')],
|
|
None),
|
|
|
|
('sub/*/*',
|
|
[join('sub', 'dir3', 'jjj'),
|
|
join('sub', 'dir3', 'kkk'),
|
|
join('sub', 'dir3', 'lll')],
|
|
None),
|
|
)
|
|
|
|
self.do_cases(cases)
|
|
|
|
def test_subdir_question(self):
|
|
"""Test globbing for question-mark Node matches in subdirectories"""
|
|
join = os.path.join
|
|
|
|
cases = (
|
|
('*/?kk',
|
|
[join('subdir1', 'kkk'), join('subdir2', 'kkk')],
|
|
[self.subdir1_kkk, self.subdir2_kkk]),
|
|
|
|
('subdir?/l?l',
|
|
[join('subdir1', 'lll'), join('subdir2', 'lll')],
|
|
[self.subdir1_lll, self.subdir2_lll]),
|
|
|
|
('*/disk-?ff',
|
|
[join('disk-sub', 'disk-fff')],
|
|
None),
|
|
|
|
('subdir?/l?l',
|
|
[join('subdir1', 'lll'), join('subdir2', 'lll')],
|
|
None),
|
|
)
|
|
|
|
self.do_cases(cases)
|
|
|
|
def test_sort(self):
|
|
"""Test whether globbing sorts"""
|
|
join = os.path.join
|
|
# At least sometimes this should return out-of-order items
|
|
# if Glob doesn't sort.
|
|
# It's not a very good test though since it depends on the
|
|
# order returned by glob, which might already be sorted.
|
|
g = self.fs.Glob('disk-sub/*', strings=True)
|
|
expect = [
|
|
os.path.join('disk-sub', 'disk-ddd'),
|
|
os.path.join('disk-sub', 'disk-eee'),
|
|
os.path.join('disk-sub', 'disk-fff'),
|
|
]
|
|
assert g == expect, str(g) + " is not sorted, but should be!"
|
|
|
|
g = self.fs.Glob('disk-*', strings=True)
|
|
expect = ['disk-aaa', 'disk-bbb', 'disk-ccc', 'disk-sub']
|
|
assert g == expect, str(g) + " is not sorted, but should be!"
|
|
|
|
|
|
class RepositoryTestCase(_tempdirTestCase):
|
|
|
|
def setUp(self):
|
|
_tempdirTestCase.setUp(self)
|
|
|
|
self.test.subdir('rep1', 'rep2', 'rep3', 'work')
|
|
|
|
self.rep1 = self.test.workpath('rep1')
|
|
self.rep2 = self.test.workpath('rep2')
|
|
self.rep3 = self.test.workpath('rep3')
|
|
|
|
os.chdir(self.test.workpath('work'))
|
|
|
|
self.fs = SCons.Node.FS.FS()
|
|
self.fs.Repository(self.rep1, self.rep2, self.rep3)
|
|
|
|
def test_getRepositories(self):
|
|
"""Test the Dir.getRepositories() method"""
|
|
self.fs.Repository('foo')
|
|
self.fs.Repository(os.path.join('foo', 'bar'))
|
|
self.fs.Repository('bar/foo')
|
|
self.fs.Repository('bar')
|
|
|
|
expect = [
|
|
self.rep1,
|
|
self.rep2,
|
|
self.rep3,
|
|
'foo',
|
|
os.path.join('foo', 'bar'),
|
|
os.path.join('bar', 'foo'),
|
|
'bar'
|
|
]
|
|
|
|
rep = self.fs.Dir('#').getRepositories()
|
|
r = [os.path.normpath(str(x)) for x in rep]
|
|
assert r == expect, r
|
|
|
|
def test_get_all_rdirs(self):
|
|
"""Test the Dir.get_all_rdirs() method"""
|
|
self.fs.Repository('foo')
|
|
self.fs.Repository(os.path.join('foo', 'bar'))
|
|
self.fs.Repository('bar/foo')
|
|
self.fs.Repository('bar')
|
|
|
|
expect = [
|
|
'.',
|
|
self.rep1,
|
|
self.rep2,
|
|
self.rep3,
|
|
'foo',
|
|
os.path.join('foo', 'bar'),
|
|
os.path.join('bar', 'foo'),
|
|
'bar'
|
|
]
|
|
|
|
rep = self.fs.Dir('#').get_all_rdirs()
|
|
r = [os.path.normpath(str(x)) for x in rep]
|
|
assert r == expect, r
|
|
|
|
def test_rentry(self):
|
|
"""Test the Base.entry() method"""
|
|
return_true = lambda: 1
|
|
return_false = lambda: 0
|
|
|
|
d1 = self.fs.Dir('d1')
|
|
d2 = self.fs.Dir('d2')
|
|
d3 = self.fs.Dir('d3')
|
|
|
|
e1 = self.fs.Entry('e1')
|
|
e2 = self.fs.Entry('e2')
|
|
e3 = self.fs.Entry('e3')
|
|
|
|
f1 = self.fs.File('f1')
|
|
f2 = self.fs.File('f2')
|
|
f3 = self.fs.File('f3')
|
|
|
|
self.test.write([self.rep1, 'd2'], "")
|
|
self.test.subdir([self.rep2, 'd3'])
|
|
self.test.write([self.rep3, 'd3'], "")
|
|
|
|
self.test.write([self.rep1, 'e2'], "")
|
|
self.test.subdir([self.rep2, 'e3'])
|
|
self.test.write([self.rep3, 'e3'], "")
|
|
|
|
self.test.write([self.rep1, 'f2'], "")
|
|
self.test.subdir([self.rep2, 'f3'])
|
|
self.test.write([self.rep3, 'f3'], "")
|
|
|
|
r = d1.rentry()
|
|
assert r is d1, r
|
|
|
|
r = d2.rentry()
|
|
assert r is not d2, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep1, 'd2'), r
|
|
|
|
r = d3.rentry()
|
|
assert r is not d3, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep2, 'd3'), r
|
|
|
|
r = e1.rentry()
|
|
assert r is e1, r
|
|
|
|
r = e2.rentry()
|
|
assert r is not e2, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep1, 'e2'), r
|
|
|
|
r = e3.rentry()
|
|
assert r is not e3, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep2, 'e3'), r
|
|
|
|
r = f1.rentry()
|
|
assert r is f1, r
|
|
|
|
r = f2.rentry()
|
|
assert r is not f2, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep1, 'f2'), r
|
|
|
|
r = f3.rentry()
|
|
assert r is not f3, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep2, 'f3'), r
|
|
|
|
def test_rdir(self):
|
|
"""Test the Dir.rdir() method"""
|
|
|
|
def return_true(obj):
|
|
return 1
|
|
|
|
def return_false(obj):
|
|
return 0
|
|
|
|
SCons.Node._exists_map[5] = return_true
|
|
SCons.Node._exists_map[6] = return_false
|
|
SCons.Node._is_derived_map[2] = return_true
|
|
SCons.Node._is_derived_map[3] = return_false
|
|
|
|
d1 = self.fs.Dir('d1')
|
|
d2 = self.fs.Dir('d2')
|
|
d3 = self.fs.Dir('d3')
|
|
|
|
self.test.subdir([self.rep1, 'd2'])
|
|
self.test.write([self.rep2, 'd3'], "")
|
|
self.test.subdir([self.rep3, 'd3'])
|
|
|
|
r = d1.rdir()
|
|
assert r is d1, r
|
|
|
|
r = d2.rdir()
|
|
assert r is not d2, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep1, 'd2'), r
|
|
|
|
r = d3.rdir()
|
|
assert r is not d3, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep3, 'd3'), r
|
|
|
|
e1 = self.fs.Dir('e1')
|
|
e1._func_exists = 6
|
|
e2 = self.fs.Dir('e2')
|
|
e2._func_exists = 6
|
|
|
|
# Make sure we match entries in repositories,
|
|
# regardless of whether they're derived or not.
|
|
|
|
re1 = self.fs.Entry(os.path.join(self.rep1, 'e1'))
|
|
re1._func_exists = 5
|
|
re1._func_is_derived = 2
|
|
re2 = self.fs.Entry(os.path.join(self.rep2, 'e2'))
|
|
re2._func_exists = 5
|
|
re2._func_is_derived = 3
|
|
|
|
r = e1.rdir()
|
|
assert r is re1, r
|
|
|
|
r = e2.rdir()
|
|
assert r is re2, r
|
|
|
|
def test_rfile(self):
|
|
"""Test the File.rfile() method"""
|
|
|
|
def return_true(obj):
|
|
return 1
|
|
|
|
def return_false(obj):
|
|
return 0
|
|
|
|
SCons.Node._exists_map[5] = return_true
|
|
SCons.Node._exists_map[6] = return_false
|
|
SCons.Node._is_derived_map[2] = return_true
|
|
SCons.Node._is_derived_map[3] = return_false
|
|
|
|
f1 = self.fs.File('f1')
|
|
f2 = self.fs.File('f2')
|
|
f3 = self.fs.File('f3')
|
|
|
|
self.test.write([self.rep1, 'f2'], "")
|
|
self.test.subdir([self.rep2, 'f3'])
|
|
self.test.write([self.rep3, 'f3'], "")
|
|
|
|
r = f1.rfile()
|
|
assert r is f1, r
|
|
|
|
r = f2.rfile()
|
|
assert r is not f2, r
|
|
r = str(r)
|
|
assert r == os.path.join(self.rep1, 'f2'), r
|
|
|
|
r = f3.rfile()
|
|
assert r is not f3, r
|
|
r = f3.rstr()
|
|
assert r == os.path.join(self.rep3, 'f3'), r
|
|
|
|
e1 = self.fs.File('e1')
|
|
e1._func_exists = 6
|
|
e2 = self.fs.File('e2')
|
|
e2._func_exists = 6
|
|
|
|
# Make sure we match entries in repositories,
|
|
# regardless of whether they're derived or not.
|
|
|
|
re1 = self.fs.Entry(os.path.join(self.rep1, 'e1'))
|
|
re1._func_exists = 5
|
|
re1._func_is_derived = 2
|
|
re2 = self.fs.Entry(os.path.join(self.rep2, 'e2'))
|
|
re2._func_exists = 5
|
|
re2._func_is_derived = 3
|
|
|
|
r = e1.rfile()
|
|
assert r is re1, r
|
|
|
|
r = e2.rfile()
|
|
assert r is re2, r
|
|
|
|
def test_Rfindalldirs(self):
|
|
"""Test the Rfindalldirs() methods"""
|
|
fs = self.fs
|
|
test = self.test
|
|
|
|
d1 = fs.Dir('d1')
|
|
d2 = fs.Dir('d2')
|
|
rep1_d1 = fs.Dir(test.workpath('rep1', 'd1'))
|
|
rep2_d1 = fs.Dir(test.workpath('rep2', 'd1'))
|
|
rep3_d1 = fs.Dir(test.workpath('rep3', 'd1'))
|
|
sub = fs.Dir('sub')
|
|
sub_d1 = sub.Dir('d1')
|
|
rep1_sub_d1 = fs.Dir(test.workpath('rep1', 'sub', 'd1'))
|
|
rep2_sub_d1 = fs.Dir(test.workpath('rep2', 'sub', 'd1'))
|
|
rep3_sub_d1 = fs.Dir(test.workpath('rep3', 'sub', 'd1'))
|
|
|
|
r = fs.Top.Rfindalldirs((d1,))
|
|
assert r == [d1], list(map(str, r))
|
|
|
|
r = fs.Top.Rfindalldirs((d1, d2))
|
|
assert r == [d1, d2], list(map(str, r))
|
|
|
|
r = fs.Top.Rfindalldirs(('d1',))
|
|
assert r == [d1, rep1_d1, rep2_d1, rep3_d1], list(map(str, r))
|
|
|
|
r = fs.Top.Rfindalldirs(('#d1',))
|
|
assert r == [d1, rep1_d1, rep2_d1, rep3_d1], list(map(str, r))
|
|
|
|
r = sub.Rfindalldirs(('d1',))
|
|
assert r == [sub_d1, rep1_sub_d1, rep2_sub_d1, rep3_sub_d1], list(map(str, r))
|
|
|
|
r = sub.Rfindalldirs(('#d1',))
|
|
assert r == [d1, rep1_d1, rep2_d1, rep3_d1], list(map(str, r))
|
|
|
|
r = fs.Top.Rfindalldirs(('d1', d2))
|
|
assert r == [d1, rep1_d1, rep2_d1, rep3_d1, d2], list(map(str, r))
|
|
|
|
def test_rexists(self):
|
|
"""Test the Entry.rexists() method"""
|
|
fs = self.fs
|
|
test = self.test
|
|
|
|
test.write([self.rep1, 'f2'], "")
|
|
test.write([self.rep2, "i_exist"], "\n")
|
|
test.write(["work", "i_exist_too"], "\n")
|
|
|
|
fs.VariantDir('build', '.')
|
|
|
|
f = fs.File(test.workpath("work", "i_do_not_exist"))
|
|
assert not f.rexists()
|
|
|
|
f = fs.File(test.workpath("work", "i_exist"))
|
|
assert f.rexists()
|
|
|
|
f = fs.File(test.workpath("work", "i_exist_too"))
|
|
assert f.rexists()
|
|
|
|
f1 = fs.File(os.path.join('build', 'f1'))
|
|
assert not f1.rexists()
|
|
|
|
f2 = fs.File(os.path.join('build', 'f2'))
|
|
assert f2.rexists()
|
|
|
|
def test_FAT_timestamps(self):
|
|
"""Test repository timestamps on FAT file systems"""
|
|
fs = self.fs
|
|
test = self.test
|
|
|
|
test.write(["rep2", "tstamp"], "tstamp\n")
|
|
try:
|
|
# Okay, *this* manipulation accomodates Windows FAT file systems
|
|
# that only have two-second granularity on their timestamps.
|
|
# We round down the current time to the nearest even integer
|
|
# value, subtract two to make sure the timestamp is not "now,"
|
|
# and then convert it back to a float.
|
|
tstamp = float(int(time.time() // 2) * 2) - 2.0
|
|
os.utime(test.workpath("rep2", "tstamp"), (tstamp - 2.0, tstamp))
|
|
f = fs.File("tstamp")
|
|
t = f.get_timestamp()
|
|
assert t == tstamp, "expected %f, got %f" % (tstamp, t)
|
|
finally:
|
|
test.unlink(["rep2", "tstamp"])
|
|
|
|
def test_get_contents(self):
|
|
"""Ensure get_contents() returns binary contents from Repositories"""
|
|
fs = self.fs
|
|
test = self.test
|
|
|
|
test.write(["rep3", "contents"], "Con\x1aTents\n")
|
|
try:
|
|
c = fs.File("contents").get_contents()
|
|
assert c == bytearray("Con\x1aTents\n", 'utf-8'), "got '%s'" % c
|
|
finally:
|
|
test.unlink(["rep3", "contents"])
|
|
|
|
def test_get_text_contents(self):
|
|
"""Ensure get_text_contents() returns text contents from
|
|
Repositories"""
|
|
fs = self.fs
|
|
test = self.test
|
|
|
|
# Use a test string that has a file terminator in it to make
|
|
# sure we read the entire file, regardless of its contents.
|
|
test_string = "Con\x1aTents\n"
|
|
|
|
# Test with ASCII.
|
|
test.write(["rep3", "contents"], test_string.encode('ascii'))
|
|
try:
|
|
c = fs.File("contents").get_text_contents()
|
|
assert test_string == c, "got %s" % repr(c)
|
|
finally:
|
|
test.unlink(["rep3", "contents"])
|
|
|
|
# Test with utf-8
|
|
test.write(["rep3", "contents"], test_string.encode('utf-8'))
|
|
try:
|
|
c = fs.File("contents").get_text_contents()
|
|
assert test_string == c, "got %s" % repr(c)
|
|
finally:
|
|
test.unlink(["rep3", "contents"])
|
|
|
|
# Test with utf-16
|
|
test.write(["rep3", "contents"], test_string.encode('utf-16'))
|
|
try:
|
|
c = fs.File("contents").get_text_contents()
|
|
assert test_string == c, "got %s" % repr(c)
|
|
finally:
|
|
test.unlink(["rep3", "contents"])
|
|
|
|
# def test_is_up_to_date(self):
|
|
|
|
|
|
class find_fileTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Testing find_file function"""
|
|
test = TestCmd(workdir='')
|
|
test.write('./foo', 'Some file\n')
|
|
test.write('./foo2', 'Another file\n')
|
|
test.subdir('same')
|
|
test.subdir('bar')
|
|
test.write(['bar', 'on_disk'], 'Another file\n')
|
|
test.write(['bar', 'same'], 'bar/same\n')
|
|
|
|
fs = SCons.Node.FS.FS(test.workpath(""))
|
|
# FS doesn't like the cwd to be something other than its root.
|
|
os.chdir(test.workpath(""))
|
|
|
|
node_derived = fs.File(test.workpath('bar/baz'))
|
|
node_derived.builder_set(1) # Any non-zero value.
|
|
node_pseudo = fs.File(test.workpath('pseudo'))
|
|
node_pseudo.set_src_builder(1) # Any non-zero value.
|
|
|
|
paths = tuple(map(fs.Dir, ['.', 'same', './bar']))
|
|
nodes = [SCons.Node.FS.find_file('foo', paths),
|
|
SCons.Node.FS.find_file('baz', paths),
|
|
SCons.Node.FS.find_file('pseudo', paths),
|
|
SCons.Node.FS.find_file('same', paths)
|
|
]
|
|
|
|
file_names = list(map(str, nodes))
|
|
file_names = list(map(os.path.normpath, file_names))
|
|
expect = ['./foo', './bar/baz', './pseudo', './bar/same']
|
|
expect = list(map(os.path.normpath, expect))
|
|
assert file_names == expect, file_names
|
|
|
|
# Make sure we don't blow up if there's already a File in place
|
|
# of a directory that we'd otherwise try to search. If this
|
|
# is broken, we'll see an exception like "Tried to lookup File
|
|
# 'bar/baz' as a Dir.
|
|
SCons.Node.FS.find_file('baz/no_file_here', paths)
|
|
|
|
import io
|
|
save_sys_stdout = sys.stdout
|
|
|
|
try:
|
|
sio = io.StringIO()
|
|
sys.stdout = sio
|
|
SCons.Node.FS.find_file('foo2', paths, verbose="xyz")
|
|
expect = " xyz: looking for 'foo2' in '.' ...\n" + \
|
|
" xyz: ... FOUND 'foo2' in '.'\n"
|
|
c = sio.getvalue()
|
|
assert c == expect, c
|
|
|
|
sio = io.StringIO()
|
|
sys.stdout = sio
|
|
SCons.Node.FS.find_file('baz2', paths, verbose=1)
|
|
expect = " find_file: looking for 'baz2' in '.' ...\n" + \
|
|
" find_file: looking for 'baz2' in 'same' ...\n" + \
|
|
" find_file: looking for 'baz2' in 'bar' ...\n"
|
|
c = sio.getvalue()
|
|
assert c == expect, c
|
|
|
|
sio = io.StringIO()
|
|
sys.stdout = sio
|
|
SCons.Node.FS.find_file('on_disk', paths, verbose=1)
|
|
expect = " find_file: looking for 'on_disk' in '.' ...\n" + \
|
|
" find_file: looking for 'on_disk' in 'same' ...\n" + \
|
|
" find_file: looking for 'on_disk' in 'bar' ...\n" + \
|
|
" find_file: ... FOUND 'on_disk' in 'bar'\n"
|
|
c = sio.getvalue()
|
|
assert c == expect, c
|
|
finally:
|
|
sys.stdout = save_sys_stdout
|
|
|
|
|
|
class StringDirTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test using a string as the second argument of
|
|
File() and Dir()"""
|
|
|
|
test = TestCmd(workdir='')
|
|
test.subdir('sub')
|
|
fs = SCons.Node.FS.FS(test.workpath(''))
|
|
|
|
d = fs.Dir('sub', '.')
|
|
assert str(d) == 'sub', str(d)
|
|
assert d.exists()
|
|
f = fs.File('file', 'sub')
|
|
assert str(f) == os.path.join('sub', 'file')
|
|
assert not f.exists()
|
|
|
|
|
|
class stored_infoTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test how we store build information"""
|
|
test = TestCmd(workdir='')
|
|
test.subdir('sub')
|
|
fs = SCons.Node.FS.FS(test.workpath(''))
|
|
|
|
d = fs.Dir('sub')
|
|
f = fs.File('file1', d)
|
|
bi = f.get_stored_info()
|
|
assert hasattr(bi, 'ninfo')
|
|
|
|
class MySConsign:
|
|
class Null:
|
|
def __init__(self):
|
|
self.xyzzy = 7
|
|
|
|
def get_entry(self, name):
|
|
return self.Null()
|
|
|
|
def test_sconsign(node):
|
|
return MySConsign()
|
|
|
|
f = fs.File('file2', d)
|
|
SCons.Node.FS._sconsign_map[2] = test_sconsign
|
|
f.dir._func_sconsign = 2
|
|
bi = f.get_stored_info()
|
|
assert bi.xyzzy == 7, bi
|
|
|
|
|
|
class has_src_builderTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test the has_src_builder() method"""
|
|
test = TestCmd(workdir='')
|
|
fs = SCons.Node.FS.FS(test.workpath(''))
|
|
os.chdir(test.workpath(''))
|
|
test.subdir('sub1')
|
|
|
|
sub1 = fs.Dir('sub1', '.')
|
|
f1 = fs.File('f1', sub1)
|
|
f2 = fs.File('f2', sub1)
|
|
f3 = fs.File('f3', sub1)
|
|
|
|
h = f1.has_src_builder()
|
|
assert not h, h
|
|
h = f1.has_builder()
|
|
assert not h, h
|
|
|
|
b1 = Builder(fs.File)
|
|
sub1.set_src_builder(b1)
|
|
|
|
test.write(['sub1', 'f2'], "sub1/f2\n")
|
|
h = f1.has_src_builder() # cached from previous call
|
|
assert not h, h
|
|
h = f1.has_builder() # cached from previous call
|
|
assert not h, h
|
|
h = f2.has_src_builder()
|
|
assert not h, h
|
|
h = f2.has_builder()
|
|
assert not h, h
|
|
h = f3.has_src_builder()
|
|
assert h, h
|
|
h = f3.has_builder()
|
|
assert h, h
|
|
assert f3.builder is b1, f3.builder
|
|
|
|
|
|
class prepareTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test the prepare() method"""
|
|
|
|
class MyFile(SCons.Node.FS.File):
|
|
def _createDir(self, update=None):
|
|
raise SCons.Errors.StopError
|
|
|
|
def exists(self):
|
|
return None
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
file = MyFile('foo', fs.Dir('.'), fs)
|
|
|
|
exc_caught = 0
|
|
try:
|
|
file.prepare()
|
|
except SCons.Errors.StopError:
|
|
exc_caught = 1
|
|
assert exc_caught, "Should have caught a StopError."
|
|
|
|
class MkdirAction(Action):
|
|
def __init__(self, dir_made):
|
|
self.dir_made = dir_made
|
|
|
|
def __call__(self, target, source, env, executor=None):
|
|
if executor:
|
|
target = executor.get_all_targets()
|
|
source = executor.get_all_sources()
|
|
self.dir_made.extend(target)
|
|
|
|
dir_made = []
|
|
new_dir = fs.Dir("new_dir")
|
|
new_dir.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
|
|
new_dir.reset_executor()
|
|
xyz = fs.File(os.path.join("new_dir", "xyz"))
|
|
|
|
xyz.set_state(SCons.Node.up_to_date)
|
|
xyz.prepare()
|
|
assert dir_made == [], dir_made
|
|
|
|
xyz.set_state(0)
|
|
xyz.prepare()
|
|
assert dir_made[0].get_internal_path() == "new_dir", dir_made[0]
|
|
|
|
dir = fs.Dir("dir")
|
|
dir.prepare()
|
|
|
|
@unittest.skipIf(IS_WINDOWS, "No symlinks on windows")
|
|
@unittest.skipUnless(hasattr(os, 'symlink'), "Platform doesn't support symlink")
|
|
class CleanSymlinksTestCase(_tempdirTestCase):
|
|
|
|
def test_cleans_symlinks(self):
|
|
"""Test the prepare() method will cleanup symlinks."""
|
|
|
|
test = self.test
|
|
|
|
with open(test.workpath("foo"), "w") as foo:
|
|
foo.write("baz")
|
|
|
|
os.symlink(test.workpath("foo"), test.workpath("bar"))
|
|
bar = self.fs.File(test.workpath("bar"))
|
|
bar.side_effect = True
|
|
bar.set_state(0)
|
|
assert bar.exists(), "Symlink %s should not exist after prepare"%str(bar)
|
|
|
|
bar.prepare()
|
|
try:
|
|
os.lstat(test.workpath("bar"))
|
|
assert False, "bar should not exist"
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
try:
|
|
os.stat(test.workpath("foo"))
|
|
except FileNotFoundError:
|
|
test.fail('Real file %s should not be removed'%test.workpath('foo'))
|
|
|
|
def test_cleans_dangling_symlinks(self):
|
|
"""Test the prepare() method will cleanup dangling symlinks."""
|
|
test = self.test
|
|
|
|
with open(test.workpath("foo"), "w") as foo:
|
|
foo.write("baz")
|
|
|
|
os.symlink(test.workpath("foo"), test.workpath("bar"))
|
|
os.remove(test.workpath("foo"))
|
|
try:
|
|
os.stat(test.workpath("foo"))
|
|
assert False, "foo should not exist"
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
bar = self.fs.File(test.workpath("bar"))
|
|
bar.side_effect = True
|
|
bar.set_state(0)
|
|
|
|
# Dangling links should report not exists
|
|
assert not bar.exists()
|
|
|
|
bar.prepare()
|
|
try:
|
|
os.lstat(test.workpath("bar"))
|
|
assert False, "bar [%s] should not exist"%test.workpath("bar")
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
|
|
class SConstruct_dirTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test setting the SConstruct directory"""
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
fs.set_SConstruct_dir(fs.Dir('xxx'))
|
|
assert fs.SConstruct_dir.get_internal_path() == 'xxx'
|
|
|
|
|
|
class CacheDirTestCase(unittest.TestCase):
|
|
|
|
def test_get_cachedir_csig(self):
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
f9 = fs.File('f9')
|
|
r = f9.get_cachedir_csig()
|
|
exsig = SCons.Util.MD5signature(SCons.Util.NOFILE)
|
|
assert r == exsig, r
|
|
|
|
|
|
class clearTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test clearing FS nodes of cached data."""
|
|
fs = SCons.Node.FS.FS()
|
|
test = TestCmd(workdir='')
|
|
|
|
e = fs.Entry('e')
|
|
assert not e.exists()
|
|
assert not e.rexists()
|
|
assert str(e) == 'e', str(e)
|
|
e.clear()
|
|
assert not e.exists()
|
|
assert not e.rexists()
|
|
assert str(e) == 'e', str(e)
|
|
|
|
d = fs.Dir(test.workpath('d'))
|
|
test.subdir('d')
|
|
assert d.exists()
|
|
assert d.rexists()
|
|
assert str(d) == test.workpath('d'), str(d)
|
|
fs.rename(test.workpath('d'), test.workpath('gone'))
|
|
# Verify caching is active
|
|
assert d.exists(), 'caching not active'
|
|
assert d.rexists()
|
|
assert str(d) == test.workpath('d'), str(d)
|
|
# Now verify clear() resets the cache
|
|
d.clear()
|
|
assert not d.exists()
|
|
assert not d.rexists()
|
|
assert str(d) == test.workpath('d'), str(d)
|
|
|
|
f = fs.File(test.workpath('f'))
|
|
test.write(test.workpath('f'), 'file f')
|
|
assert f.exists()
|
|
assert f.rexists()
|
|
assert str(f) == test.workpath('f'), str(f)
|
|
# Verify caching is active
|
|
test.unlink(test.workpath('f'))
|
|
assert f.exists()
|
|
assert f.rexists()
|
|
assert str(f) == test.workpath('f'), str(f)
|
|
# Now verify clear() resets the cache
|
|
f.clear()
|
|
assert not f.exists()
|
|
assert not f.rexists()
|
|
assert str(f) == test.workpath('f'), str(f)
|
|
# Now verify clear() resets optional File-specific attributes
|
|
optional_attrs = ['cachedir_csig', 'cachesig', 'contentsig']
|
|
for attr in optional_attrs:
|
|
setattr(f, attr, 'xyz')
|
|
f.clear()
|
|
for attr in optional_attrs:
|
|
assert not hasattr(f, attr), attr
|
|
|
|
|
|
class disambiguateTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test calling the disambiguate() method."""
|
|
test = TestCmd(workdir='')
|
|
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
ddd = fs.Dir('ddd')
|
|
d = ddd.disambiguate()
|
|
assert d is ddd, d
|
|
|
|
fff = fs.File('fff')
|
|
f = fff.disambiguate()
|
|
assert f is fff, f
|
|
|
|
test.subdir('edir')
|
|
test.write('efile', "efile\n")
|
|
|
|
edir = fs.Entry(test.workpath('edir'))
|
|
d = edir.disambiguate()
|
|
assert d.__class__ is ddd.__class__, d.__class__
|
|
|
|
efile = fs.Entry(test.workpath('efile'))
|
|
f = efile.disambiguate()
|
|
assert f.__class__ is fff.__class__, f.__class__
|
|
|
|
test.subdir('build')
|
|
test.subdir(['build', 'bdir'])
|
|
test.write(['build', 'bfile'], "build/bfile\n")
|
|
|
|
test.subdir('src')
|
|
test.write(['src', 'bdir'], "src/bdir\n")
|
|
test.subdir(['src', 'bfile'])
|
|
|
|
test.subdir(['src', 'edir'])
|
|
test.write(['src', 'efile'], "src/efile\n")
|
|
|
|
fs.VariantDir(test.workpath('build'), test.workpath('src'))
|
|
|
|
build_bdir = fs.Entry(test.workpath('build/bdir'))
|
|
d = build_bdir.disambiguate()
|
|
assert d is build_bdir, d
|
|
assert d.__class__ is ddd.__class__, d.__class__
|
|
|
|
build_bfile = fs.Entry(test.workpath('build/bfile'))
|
|
f = build_bfile.disambiguate()
|
|
assert f is build_bfile, f
|
|
assert f.__class__ is fff.__class__, f.__class__
|
|
|
|
build_edir = fs.Entry(test.workpath('build/edir'))
|
|
d = build_edir.disambiguate()
|
|
assert d.__class__ is ddd.__class__, d.__class__
|
|
|
|
build_efile = fs.Entry(test.workpath('build/efile'))
|
|
f = build_efile.disambiguate()
|
|
assert f.__class__ is fff.__class__, f.__class__
|
|
|
|
build_nonexistant = fs.Entry(test.workpath('build/nonexistant'))
|
|
f = build_nonexistant.disambiguate()
|
|
assert f.__class__ is fff.__class__, f.__class__
|
|
|
|
|
|
class postprocessTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test calling the postprocess() method."""
|
|
fs = SCons.Node.FS.FS()
|
|
|
|
e = fs.Entry('e')
|
|
e.postprocess()
|
|
|
|
d = fs.Dir('d')
|
|
d.postprocess()
|
|
|
|
f = fs.File('f')
|
|
f.postprocess()
|
|
|
|
|
|
class SpecialAttrTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test special attributes of file nodes."""
|
|
test = TestCmd(workdir='')
|
|
fs = SCons.Node.FS.FS(test.workpath('work'))
|
|
|
|
f = fs.Entry('foo/bar/baz.blat').get_subst_proxy()
|
|
|
|
s = str(f.dir)
|
|
assert s == os.path.normpath('foo/bar'), s
|
|
assert f.dir.is_literal(), f.dir
|
|
for_sig = f.dir.for_signature()
|
|
assert for_sig == 'bar', for_sig
|
|
|
|
s = str(f.file)
|
|
assert s == 'baz.blat', s
|
|
assert f.file.is_literal(), f.file
|
|
for_sig = f.file.for_signature()
|
|
assert for_sig == 'baz.blat_file', for_sig
|
|
|
|
s = str(f.base)
|
|
assert s == os.path.normpath('foo/bar/baz'), s
|
|
assert f.base.is_literal(), f.base
|
|
for_sig = f.base.for_signature()
|
|
assert for_sig == 'baz.blat_base', for_sig
|
|
|
|
s = str(f.filebase)
|
|
assert s == 'baz', s
|
|
assert f.filebase.is_literal(), f.filebase
|
|
for_sig = f.filebase.for_signature()
|
|
assert for_sig == 'baz.blat_filebase', for_sig
|
|
|
|
s = str(f.suffix)
|
|
assert s == '.blat', s
|
|
assert f.suffix.is_literal(), f.suffix
|
|
for_sig = f.suffix.for_signature()
|
|
assert for_sig == 'baz.blat_suffix', for_sig
|
|
|
|
s = str(f.get_abspath())
|
|
assert s == test.workpath('work', 'foo', 'bar', 'baz.blat'), s
|
|
assert f.abspath.is_literal(), f.abspath
|
|
for_sig = f.abspath.for_signature()
|
|
assert for_sig == 'baz.blat_abspath', for_sig
|
|
|
|
s = str(f.posix)
|
|
assert s == 'foo/bar/baz.blat', s
|
|
assert f.posix.is_literal(), f.posix
|
|
if f.posix != f:
|
|
for_sig = f.posix.for_signature()
|
|
assert for_sig == 'baz.blat_posix', for_sig
|
|
|
|
s = str(f.windows)
|
|
assert s == 'foo\\bar\\baz.blat', repr(s)
|
|
assert f.windows.is_literal(), f.windows
|
|
if f.windows != f:
|
|
for_sig = f.windows.for_signature()
|
|
assert for_sig == 'baz.blat_windows', for_sig
|
|
|
|
# Deprecated synonym for the .windows suffix.
|
|
s = str(f.win32)
|
|
assert s == 'foo\\bar\\baz.blat', repr(s)
|
|
assert f.win32.is_literal(), f.win32
|
|
if f.win32 != f:
|
|
for_sig = f.win32.for_signature()
|
|
assert for_sig == 'baz.blat_windows', for_sig
|
|
|
|
# And now, combinations!!!
|
|
s = str(f.srcpath.base)
|
|
assert s == os.path.normpath('foo/bar/baz'), s
|
|
s = str(f.srcpath.dir)
|
|
assert s == str(f.srcdir), s
|
|
s = str(f.srcpath.posix)
|
|
assert s == 'foo/bar/baz.blat', s
|
|
s = str(f.srcpath.windows)
|
|
assert s == 'foo\\bar\\baz.blat', s
|
|
s = str(f.srcpath.win32)
|
|
assert s == 'foo\\bar\\baz.blat', s
|
|
|
|
# Test what happens with VariantDir()
|
|
fs.VariantDir('foo', 'baz')
|
|
|
|
s = str(f.srcpath)
|
|
assert s == os.path.normpath('baz/bar/baz.blat'), s
|
|
assert f.srcpath.is_literal(), f.srcpath
|
|
g = f.srcpath.get()
|
|
assert isinstance(g, SCons.Node.FS.File), g.__class__
|
|
|
|
s = str(f.srcdir)
|
|
assert s == os.path.normpath('baz/bar'), s
|
|
assert f.srcdir.is_literal(), f.srcdir
|
|
g = f.srcdir.get()
|
|
assert isinstance(g, SCons.Node.FS.Dir), g.__class__
|
|
|
|
# And now what happens with VariantDir() + Repository()
|
|
fs.Repository(test.workpath('repository'))
|
|
|
|
f = fs.Entry('foo/sub/file.suffix').get_subst_proxy()
|
|
test.subdir('repository',
|
|
['repository', 'baz'],
|
|
['repository', 'baz', 'sub'])
|
|
|
|
rd = test.workpath('repository', 'baz', 'sub')
|
|
rf = test.workpath('repository', 'baz', 'sub', 'file.suffix')
|
|
test.write(rf, "\n")
|
|
|
|
s = str(f.srcpath)
|
|
assert s == os.path.normpath('baz/sub/file.suffix'), s
|
|
assert f.srcpath.is_literal(), f.srcpath
|
|
g = f.srcpath.get()
|
|
# Gets disambiguated to SCons.Node.FS.File by get_subst_proxy().
|
|
assert isinstance(g, SCons.Node.FS.File), g.__class__
|
|
|
|
s = str(f.srcdir)
|
|
assert s == os.path.normpath('baz/sub'), s
|
|
assert f.srcdir.is_literal(), f.srcdir
|
|
g = f.srcdir.get()
|
|
assert isinstance(g, SCons.Node.FS.Dir), g.__class__
|
|
|
|
s = str(f.rsrcpath)
|
|
assert s == rf, s
|
|
assert f.rsrcpath.is_literal(), f.rsrcpath
|
|
g = f.rsrcpath.get()
|
|
assert isinstance(g, SCons.Node.FS.File), g.__class__
|
|
|
|
s = str(f.rsrcdir)
|
|
assert s == rd, s
|
|
assert f.rsrcdir.is_literal(), f.rsrcdir
|
|
g = f.rsrcdir.get()
|
|
assert isinstance(g, SCons.Node.FS.Dir), g.__class__
|
|
|
|
# Check that attempts to access non-existent attributes of the
|
|
# subst proxy generate the right exceptions and messages.
|
|
caught = None
|
|
try:
|
|
fs.Dir('ddd').get_subst_proxy().no_such_attr
|
|
except AttributeError as e:
|
|
assert str(e) == "Dir instance 'ddd' has no attribute 'no_such_attr'", e
|
|
caught = 1
|
|
assert caught, "did not catch expected AttributeError"
|
|
|
|
caught = None
|
|
try:
|
|
fs.Entry('eee').get_subst_proxy().no_such_attr
|
|
except AttributeError as e:
|
|
# Gets disambiguated to File instance by get_subst_proxy().
|
|
assert str(e) == "File instance 'eee' has no attribute 'no_such_attr'", e
|
|
caught = 1
|
|
assert caught, "did not catch expected AttributeError"
|
|
|
|
caught = None
|
|
try:
|
|
fs.File('fff').get_subst_proxy().no_such_attr
|
|
except AttributeError as e:
|
|
assert str(e) == "File instance 'fff' has no attribute 'no_such_attr'", e
|
|
caught = 1
|
|
assert caught, "did not catch expected AttributeError"
|
|
|
|
|
|
class SaveStringsTestCase(unittest.TestCase):
|
|
def runTest(self):
|
|
"""Test caching string values of nodes."""
|
|
test = TestCmd(workdir='')
|
|
|
|
def setup(fs):
|
|
fs.Dir('src')
|
|
fs.Dir('d0')
|
|
fs.Dir('d1')
|
|
|
|
d0_f = fs.File('d0/f')
|
|
d1_f = fs.File('d1/f')
|
|
d0_b = fs.File('d0/b')
|
|
d1_b = fs.File('d1/b')
|
|
d1_f.duplicate = 1
|
|
d1_b.duplicate = 1
|
|
d0_b.builder = 1
|
|
d1_b.builder = 1
|
|
|
|
return [d0_f, d1_f, d0_b, d1_b]
|
|
|
|
def modify(nodes):
|
|
d0_f, d1_f, d0_b, d1_b = nodes
|
|
d1_f.duplicate = 0
|
|
d1_b.duplicate = 0
|
|
d0_b.builder = 0
|
|
d1_b.builder = 0
|
|
|
|
fs1 = SCons.Node.FS.FS(test.workpath('fs1'))
|
|
nodes = setup(fs1)
|
|
fs1.VariantDir('d0', 'src', duplicate=0)
|
|
fs1.VariantDir('d1', 'src', duplicate=1)
|
|
|
|
s = list(map(str, nodes))
|
|
expect = list(map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b']))
|
|
assert s == expect, s
|
|
|
|
modify(nodes)
|
|
|
|
s = list(map(str, nodes))
|
|
expect = list(map(os.path.normpath, ['src/f', 'src/f', 'd0/b', 'd1/b']))
|
|
assert s == expect, s
|
|
|
|
SCons.Node.FS.save_strings(1)
|
|
fs2 = SCons.Node.FS.FS(test.workpath('fs2'))
|
|
nodes = setup(fs2)
|
|
fs2.VariantDir('d0', 'src', duplicate=0)
|
|
fs2.VariantDir('d1', 'src', duplicate=1)
|
|
|
|
s = list(map(str, nodes))
|
|
expect = list(map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b']))
|
|
assert s == expect, s
|
|
|
|
modify(nodes)
|
|
|
|
s = list(map(str, nodes))
|
|
expect = list(map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b']))
|
|
assert s == expect, 'node str() not cached: %s' % s
|
|
|
|
|
|
class AbsolutePathTestCase(unittest.TestCase):
|
|
def test_root_lookup_equivalence(self):
|
|
"""Test looking up /fff vs. fff in the / directory"""
|
|
test = TestCmd(workdir='')
|
|
|
|
fs = SCons.Node.FS.FS('/')
|
|
|
|
save_cwd = os.getcwd()
|
|
try:
|
|
os.chdir('/')
|
|
fff1 = fs.File('fff')
|
|
fff2 = fs.File('/fff')
|
|
assert fff1 is fff2, "fff and /fff returned different Nodes!"
|
|
finally:
|
|
os.chdir(save_cwd)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|
|
|
|
# Local Variables:
|
|
# tab-width:4
|
|
# indent-tabs-mode:nil
|
|
# End:
|
|
# vim: set expandtab tabstop=4 shiftwidth=4:
|