diff --git a/src/base/tree.lua b/src/base/tree.lua index 36cbb5ac..6f55a1d8 100644 --- a/src/base/tree.lua +++ b/src/base/tree.lua @@ -228,6 +228,7 @@ function tree.trimroot(tr) local trimmed + -- start by removing single-children folders from the top of the tree while #tr.children == 1 do local node = tr.children[1] @@ -237,8 +238,7 @@ end -- remove this node from the tree, and move its children up a level - trimmed = node.path - + trimmed = true local numChildren = #node.children for i = 1, numChildren do local child = node.children[i] @@ -247,13 +247,33 @@ end end + -- found the top, now remove any single-children ".." folders from here + local dotdot + local count = #tr.children + repeat + dotdot = false + for i = 1, count do + local node = tr.children[i] + if node.name == ".." and #node.children == 1 then + local child = node.children[1] + child.parent = node.parent + tr.children[i] = child + trimmed = true + dotdot = true + end + end + until not dotdot + -- if nodes were removed, adjust the paths on all remaining nodes if trimmed then - local trimlen = #trimmed + 2 tree.traverse(tr, { onnode = function(node) - node.path = node.path:sub(trimlen) + if node.parent.path then + node.path = path.join(node.parent.path, node.name) + else + node.path = node.name + end end - }) + }, false) end end diff --git a/src/project/project.lua b/src/project/project.lua index 93b04627..ec957c1a 100755 --- a/src/project/project.lua +++ b/src/project/project.lua @@ -65,54 +65,6 @@ end --- --- Return an iterator for the list of source code files contained by a project. --- --- @param prj --- The project to query. --- @return --- A source code file iterator, which returns file configuration objects. --- These file configurations contain: --- --- fullpath - the relative path from the project to the file --- vpath - the file's virtual path, if specified, or fullpath if not --- - - function project.eachfile(prj) - -- make sure I have the project, and not it's root configuration - prj = prj.project or prj - - -- find *all* files referenced by the project, regardless of configuration, - -- and cache the list for future calls - if not prj.files then - local files = {} - for _, block in ipairs(prj.blocks) do - for _, file in ipairs(block.files) do - if not files[file] then - local fcfg = project.getfileconfig(prj, file) - - -- add it both indexed for iteration and keyed for quick tests - table.insert(files, file) - files[file] = fcfg - end - end - end - prj.files = files - end - - local files = prj.files - local i = 0 - - return function() - i = i + 1 - if i <= #files then - local filename = files[i] - return files[filename] - end - end - end - - -- -- Locate a project by name; case insensitive. -- @@ -305,14 +257,28 @@ -- function project.getsourcetree(prj) + -- make sure I have the project, and not it's root configuration + prj = prj.project or prj + -- check for a previously cached tree if prj.sourcetree then return prj.sourcetree end - - local tr = premake.tree.new(prj.name) - for fcfg in project.eachfile(prj) do + -- find *all* files referenced by the project, regardless of configuration + local files = {} + for _, block in ipairs(prj.blocks) do + for _, file in ipairs(block.files) do + files[file] = file + end + end + + -- create a tree from the file list + local tr = premake.tree.new(prj.name) + + for file in pairs(files) do + local fcfg = project.getfileconfig(prj, file) + -- The tree represents the logical source code tree to be displayed -- in the IDE, not the physical organization of the file system. So -- virtual paths are used when adding nodes. @@ -324,10 +290,10 @@ end end) - -- Store additional path information for file (leaf) nodes - node.abspath = fcfg.abspath - node.relpath = fcfg.relpath - node.vpath = fcfg.vpath + -- Store full file configuration in file (leaf) nodes + for key, value in pairs(fcfg) do + node[key] = value + end end premake.tree.trimroot(tr) diff --git a/tests/base/test_tree.lua b/tests/base/test_tree.lua index 8675f573..c9ffee08 100644 --- a/tests/base/test_tree.lua +++ b/tests/base/test_tree.lua @@ -202,6 +202,51 @@ end +-- +-- A ".." folder containing a single subfolder should never appear +-- at the top of the source tree. +-- + + function suite.trimroot_removesDotDot_onTopLevelSiblings() + tree.add(tr, "../../tests/test_hello.c") + tree.add(tr, "../src/test.c") + tree.trimroot(tr) + prepare() + test.capture [[ + tests + test_hello.c + src + test.c + ]] + end + + function suite.trimroot_removesDotDot_onTopLevel() + tree.add(tr, "../tests/test_hello.c") + tree.add(tr, "src/test.c") + tree.trimroot(tr) + prepare() + test.capture [[ + tests + test_hello.c + src + test.c + ]] + end + + function suite.trimroot_removesDotDot_onMultipleNestings() + tree.add(tr, "../../../tests/test_hello.c") + tree.add(tr, "../src/test.c") + tree.trimroot(tr) + prepare() + test.capture [[ + tests + test_hello.c + src + test.c + ]] + end + + -- -- When nodes are trimmed, the paths on the remaining nodes should -- be updated to reflect the new hierarchy. @@ -211,6 +256,13 @@ tree.add(tr, "A/1") tree.add(tr, "A/2") tree.trimroot(tr) - prepare() test.isequal("1", tr.children[1].path) end + + + function suite.trimroot_updatesPaths_onDotDotRemoved() + tree.add(tr, "../../../tests/test_hello.c") + tree.add(tr, "../src/test.c") + tree.trimroot(tr) + test.isequal("tests", tr.children[1].path) + end diff --git a/tests/premake4.lua b/tests/premake4.lua index dca693c7..381bb3b6 100644 --- a/tests/premake4.lua +++ b/tests/premake4.lua @@ -63,7 +63,6 @@ dofile("test_project.lua") dofile("project/test_baking.lua") dofile("project/test_eachconfig.lua") - dofile("project/test_eachfile.lua") dofile("project/test_filtering.lua") dofile("project/test_getconfig.lua") dofile("project/test_hasconfig.lua") diff --git a/tests/project/test_eachfile.lua b/tests/project/test_eachfile.lua deleted file mode 100644 index 533fefbd..00000000 --- a/tests/project/test_eachfile.lua +++ /dev/null @@ -1,84 +0,0 @@ --- --- tests/project/test_eachfile.lua --- Automated test suite for the file iteration function. --- Copyright (c) 2011-2012 Jason Perkins and the Premake project --- - - T.project_eachfile = { } - local suite = T.project_eachfile - local project = premake5.project - - --- --- Setup and teardown --- - - local sln, prj - function suite.setup() - sln, prj = test.createsolution() - end - - local function prepare(field) - if not field then - field = "relpath" - end - for file in project.eachfile(prj) do - _p(2, file[field]) - end - end - - --- --- Sanity check that all files are returned, with project relative paths. --- - - function suite.listsAllFiles() - files { "hello.h", "hello.c" } - prepare() - test.capture [[ - hello.h - hello.c - ]] - end - --- --- Ensure that the virtual path field defaults to the real file path. --- - - function suite.vpathsAreNil_onNoVpaths() - files { "hello.h", "hello.c" } - prepare("vpath") - test.capture [[ - hello.h - hello.c - ]] - end - --- --- If a virtual path is specified, the vpath field should be set. --- - - function suite.vpathSet_onVpath() - files { "hello.h", "hello.c" } - vpaths { Headers = "**.h" } - prepare("vpath") - test.capture [[ - Headers/hello.h - hello.c - ]] - end - --- --- A file listed in a configuration should be included in the list. --- - - function suite.includesFile_setInConfiguration() - files { "hello.h" } - configuration { "Debug" } - files { "hello.c" } - prepare() - test.capture [[ - hello.h - hello.c - ]] - end