Commits

Jason Perkins committed 89bff0c

Add support for solution groups

  • Participants
  • Parent commits 6ac4b37

Comments (0)

Files changed (8)

src/actions/vstudio/vs2005_solution.lua

 	local sln2005 = premake.vstudio.sln2005
 	local solution = premake.solution
 	local project = premake5.project
+	local tree = premake.tree
 
 
 --
 		_p('\239\187\191')
 
 		sln2005.header(sln)
-
-		for prj in premake.solution.eachproject_ng(sln) do
-			sln2005.project_ng(prj)
-		end
+		sln2005.projects(sln)
 
 		_p('Global')
 		sln2005.configurationPlatforms(sln)
 		sln2005.properties(sln)
+		sln2005.NestedProjects(sln)
 		_p('EndGlobal')
 	end
 
 
 
 --
--- Write out an entry for a project
+-- Write out the list of projects and groups contained by the solution.
 --
 
-	function sln2005.project_ng(prj)
-		-- Build a relative path from the solution file to the project file
-		local slnpath = premake.solution.getlocation(prj.solution)
-		local prjpath = vstudio.projectfile(prj)
-		prjpath = path.translate(path.getrelative(slnpath, prjpath))
+	function sln2005.projects(sln)
+		local tr = solution.grouptree(sln)
+		tree.traverse(tr, {
+			onleaf = function(n)
+				local prj = n.project
+
+				-- Build a relative path from the solution file to the project file
+				local slnpath = premake.solution.getlocation(prj.solution)
+				local prjpath = vstudio.projectfile(prj)
+				prjpath = path.translate(path.getrelative(slnpath, prjpath))
 		
-		_x('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(prj), prj.name, prjpath, prj.uuid)
-		if _ACTION < "vs2012" then
-			sln2005.projectdependencies_ng(prj)
-		end
-		_p('EndProject')
+				_x('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(prj), prj.name, prjpath, prj.uuid)
+				if _ACTION < "vs2012" then
+					sln2005.projectdependencies_ng(prj)
+				end
+				_p('EndProject')
+			end,
+			
+			onbranch = function(n)
+				_x('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "%s", "%s", "{%s}"', n.name, n.name, n.uuid)
+				_p('EndProject')
+			end,				
+		})
 	end
 
 
 		_p('\t\tHideSolutionNode = FALSE')
 		_p('\tEndGlobalSection')
 	end
+
+
+--
+-- Write out the NestedProjects block, which describes the structure of
+-- any solution groups.
+--
+
+	function sln2005.NestedProjects(sln)
+		local tr = solution.grouptree(sln)
+		if #tr.children > 0 and #tr.children[1].children > 0 then
+			_p(1,'GlobalSection(NestedProjects) = preSolution')
+			tree.traverse(tr, {
+				onnode = function(n)
+					if n.parent.uuid then
+						_p(2,'{%s} = {%s}', (n.project or n).uuid, n.parent.uuid)
+					end
+				end
+			})
+			_p(1,'EndGlobalSection')
+		end
+	end
 
 	function api.reset()
 		api.scope = {
-			root = { 
+			root = {
 				configset = configset.root,
 				blocks = {}  -- TODO: remove this when switch-over to new APIs is done
 			}
 
 		return cfg
 	end
-	
+
+
+--
+-- Begin a new solution group, which will contain any subsequent projects.
+--
+
+	function group(name)
+		api.scope.group = name
+	end
+
+
 	local function createproject(name, sln, isUsage)
 		local prj = premake5.project.new(sln, name)
 
 		
 		prj.script = _SCRIPT
 		prj.usage = isUsage;
+		prj.group = api.scope.group or ""
 
 		return prj;
 	end
 	end
 
 
+--
+-- Define a new solution object.
+--
+
 	function solution(name)
 		if not name then
 			if type(premake.CurrentContainer) == "project" then
 		end
 
 		-- add an empty, global configuration
-		configuration { }
+		configuration {}
 		
 		-- this is the new place for storing scoped objects
 		api.scope.solution = premake.CurrentContainer
 		api.scope.project = nil
+		api.scope.group = nil
 		
 		return premake.CurrentContainer
 	end

src/base/solution.lua

 	local project = premake5.project
 	local configset = premake.configset
 	local context = premake.context
+	local tree = premake.tree
 
 
 -- The list of defined solutions (which contain projects, etc.)
 
 
 --
+-- Retrieve the tree of project groups.
+--
+-- @param sln
+--    The solution to query.
+-- @return
+--    The tree of project groups defined for the solution.
+--
+
+	function solution.grouptree(sln)
+		-- check for a previously cached tree
+		if sln.grouptree then
+			return sln.grouptree
+		end
+		
+		local tr = tree.new()
+		sln.grouptree = tr
+
+		for prj in solution.eachproject_ng(sln) do
+			local prjpath = path.join(prj.group, prj.name)
+			local node = tree.add(tr, prjpath, function(n) n.uuid = os.uuid(n.path) end)
+			node.project = prj
+		end
+
+		tree.sort(tr)		
+		return tr
+	end
+
+
+--
 -- Retrieve the solution's file system location.
 --
 -- @param sln

src/host/string_hash.c

 	}
 
 	return hash;
-}	
+}

src/project/project.lua

 		cset.basedir = cwd
 		cset.location = cwd
 		cset.filename = name
-		cset.uuid = os.uuid()
+		cset.uuid = os.uuid(name)
 		prj.configset = cset
 
 		-- attach a type descriptor

tests/actions/vstudio/sln2005/test_nested_projects.lua

+--
+-- tests/actions/vstudio/sln2005/test_nested_projects.lua
+-- Check Visual Studio 2005+ Nested Projects solution block.
+-- Copyright (c) 2012 Jason Perkins and the Premake project
+--
+
+	T.vstudio_sln2005_nested_projects = { }
+	local suite = T.vstudio_sln2005_nested_projects
+	local sln2005 = premake.vstudio.sln2005
+
+
+--
+-- Setup 
+--
+
+	local sln
+	
+	function suite.setup()
+		_ACTION = "vs2008"
+		sln = solution "MySolution"
+		configurations { "Debug", "Release" }
+		language "C++"
+	end
+	
+	local function prepare()
+		sln2005.NestedProjects(sln)
+	end
+
+
+--
+-- This block should only be written if solution groups are present.
+--
+
+	function suite.isEmpty_onNoGroups()		
+		project "MyProject"
+		prepare()
+		test.isemptycapture()
+	end
+
+
+--
+-- Check nesting with a single group and project.
+--
+
+	function suite.onSingleGroup()
+		group "Alpha"
+		project "MyProject"
+		prepare()
+		test.capture [[
+	GlobalSection(NestedProjects) = preSolution
+		{42B5DBC6-AE1F-903D-F75D-41E363076E92} = {0B5CD40C-7770-FCBD-40F2-9F1DACC5F8EE}
+	EndGlobalSection
+		]]
+	end
+
+
+--
+-- Check nesting with multiple levels of groups.
+--
+
+	function suite.onNestedGroups()
+		group "Alpha/Beta"
+		project "MyProject"
+		prepare()
+		test.capture [[
+	GlobalSection(NestedProjects) = preSolution
+		{96080FE9-82C0-5036-EBC7-2992D79EEB26} = {0B5CD40C-7770-FCBD-40F2-9F1DACC5F8EE}
+		{42B5DBC6-AE1F-903D-F75D-41E363076E92} = {96080FE9-82C0-5036-EBC7-2992D79EEB26}
+	EndGlobalSection
+		]]
+	end
+
+--
+-- Ungrouped projects should not appear in the list.
+--
+
+	function suite.onUngroupedProject()
+		group "Alpha"
+		project "MyProject"
+		group ""
+		project "MyProject2"
+		prepare()
+		test.capture [[
+	GlobalSection(NestedProjects) = preSolution
+		{42B5DBC6-AE1F-903D-F75D-41E363076E92} = {0B5CD40C-7770-FCBD-40F2-9F1DACC5F8EE}
+	EndGlobalSection
+		]]
+	end
+	

tests/actions/vstudio/sln2005/test_projects.lua

 -- Setup 
 --
 
-	local sln, prj
+	local sln
 	
 	function suite.setup()
-		_ACTION = "vs2005"
-		sln, prj = test.createsolution()
-		uuid "AE61726D-187C-E440-BD07-2556188A6565"
+		_ACTION = "vs2008"
+		sln = solution "MySolution"
+		configurations { "Debug", "Release" }		
 	end
 	
 	local function prepare()
-		prj = premake.solution.getproject_ng(sln, 1)
-		sln2005.project_ng(prj)
+		sln2005.projects(sln)
 	end
 
 
 --
 
 	function suite.structureIsOkay_onCpp()
+		project "MyProject"
 		prepare()
 		test.capture [[
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyProject", "MyProject.vcproj", "{AE61726D-187C-E440-BD07-2556188A6565}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyProject", "MyProject.vcproj", "{42B5DBC6-AE1F-903D-F75D-41E363076E92}"
 EndProject
 		]]
 	end
 --
 
 	function suite.structureIsOkay_onCSharp()
+		project "MyProject"
 		language "C#"
 		prepare()
 		test.capture [[
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyProject", "MyProject.csproj", "{AE61726D-187C-E440-BD07-2556188A6565}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyProject", "MyProject.csproj", "{42B5DBC6-AE1F-903D-F75D-41E363076E92}"
 EndProject
 		]]
 	end
 --
 
 	function suite.projectNamesAreEscaped()
-		prj.name = 'My "x64" Project'
-		filename ('My "x64" Project')
+		project 'My "x64" Project'
+		filename 'My "x64" Project'
 		prepare()
 		test.capture [[
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "My &quot;x64&quot; Project", "My &quot;x64&quot; Project.vcproj", "{AE61726D-187C-E440-BD07-2556188A6565}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "My &quot;x64&quot; Project", "My &quot;x64&quot; Project.vcproj", "{48E4ED8F-34DD-0CE2-5D0F-F2664967ECED}"
 EndProject
 		]]
 	end
+
+
+--
+-- Check the structure of a top-level group entry.
+--
+
+	function suite.onSingleTopLevelGroup()
+		group "Alpha"
+		project "MyProject"
+		prepare()
+		test.capture [[
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Alpha", "Alpha", "{0B5CD40C-7770-FCBD-40F2-9F1DACC5F8EE}"
+EndProject
+		]]
+	end
+
+
+
+--
+-- Nested groups should be listed individually.
+--
+
+	function suite.OnNestedGroups()
+		group "Alpha/Beta"
+		project "MyProject"
+		prepare()
+		test.capture [[
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Alpha", "Alpha", "{0B5CD40C-7770-FCBD-40F2-9F1DACC5F8EE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Beta", "Beta", "{96080FE9-82C0-5036-EBC7-2992D79EEB26}"
+EndProject
+		]]
+	end

tests/premake4.lua

 	-- Visual Studio 2005-2010 solutions
 	dofile("actions/vstudio/sln2005/test_dependencies.lua")
 	dofile("actions/vstudio/sln2005/test_header.lua")
+	dofile("actions/vstudio/sln2005/test_nested_projects.lua")
 	dofile("actions/vstudio/sln2005/test_projects.lua")
 	dofile("actions/vstudio/sln2005/test_platforms.lua")