Merge pull request #453 from aleksijuvani/nuget-in-vs-exporter

Add NuGet support to the Visual Studio exporter
This commit is contained in:
Jason Perkins 2016-04-11 13:30:49 -04:00
commit 002e65d428
12 changed files with 398 additions and 6 deletions

View File

@ -76,6 +76,7 @@
"actions/vstudio/vs2005_csproj.lua",
"actions/vstudio/vs2005_csproj_user.lua",
"actions/vstudio/vs2010.lua",
"actions/vstudio/vs2010_nuget.lua",
"actions/vstudio/vs2010_vcxproj.lua",
"actions/vstudio/vs2010_vcxproj_user.lua",
"actions/vstudio/vs2010_vcxproj_filters.lua",

View File

@ -748,6 +748,13 @@
}
}
api.register {
name = "nuget",
scope = "project",
kind = "list:string",
tokens = true,
}
api.register {
name = "objdir",
scope = "config",

View File

@ -12,6 +12,23 @@
local config = p.config
--
-- All valid .NET Framework versions, from oldest to newest.
--
vstudio.frameworkVersions =
{
"1.0",
"1.1",
"2.0",
"3.0",
"3.5",
"4.0",
"4.5",
"4.6",
}
--
-- Mapping tables from Premake systems and architectures to Visual Studio
-- identifiers. Broken out as tables so new values can be pushed in by

View File

@ -21,6 +21,20 @@
p.escaper(vs2005.esc)
premake.generate(wks, ".sln", vstudio.sln2005.generate)
if _ACTION >= "vs2010" then
-- Skip generation of empty NuGet packages.config files
if p.workspace.hasProject(wks, function(prj) return #prj.nuget > 0 end) then
premake.generate(
{
location = path.join(wks.location, "packages.config"),
workspace = wks
},
nil,
vstudio.nuget2010.generatePackagesConfig
)
end
end
end

View File

@ -29,7 +29,7 @@
"projectProperties",
"configurations",
"applicationIcon",
"assemblyReferences",
"references",
}
function cs2005.generate(prj)
@ -284,13 +284,29 @@
end
--
-- Write out the references item group.
--
cs2005.elements.references = function(prj)
return {
cs2005.assemblyReferences,
cs2005.nuGetReferences,
}
end
function cs2005.references(prj)
_p(1,'<ItemGroup>')
p.callArray(cs2005.elements.references, prj)
_p(1,'</ItemGroup>')
end
--
-- Write the list of assembly (system, or non-sibling) references.
--
function cs2005.assemblyReferences(prj)
_p(1,'<ItemGroup>')
-- C# doesn't support per-configuration links (does it?) so just use
-- the settings from the first available config instead
local cfg = project.getfirstconfig(prj)
@ -314,8 +330,44 @@
_x(2,'<Reference Include="%s" />', name)
end
end)
end
_p(1,'</ItemGroup>')
--
-- Write the list of NuGet references.
--
function cs2005.nuGetReferences(prj)
if _ACTION >= "vs2010" then
for i = 1, #prj.nuget do
local package = prj.nuget[i]
_x(2, '<Reference Include="%s">', vstudio.nuget2010.packageId(package))
-- We need to write HintPaths for all supported framework
-- versions. The last HintPath will override any previous
-- HintPaths (if the condition is met that is).
for _, frameworkVersion in ipairs(cs2005.identifyFrameworkVersions(prj)) do
local assembly = vstudio.path(
prj,
p.filename(
prj.solution,
string.format(
"packages\\%s\\lib\\%s\\%s.dll",
vstudio.nuget2010.packageName(package),
cs2005.formatNuGetFrameworkVersion(frameworkVersion),
vstudio.nuget2010.packageId(package)
)
)
)
_x(3, '<HintPath Condition="Exists(\'%s\')">%s</HintPath>', assembly, assembly)
end
_p(3, '<Private>True</Private>')
_p(2, '</Reference>')
end
end
end
@ -401,6 +453,41 @@
return string.format('Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"', premake.esc(vstudio.projectConfig(cfg)))
end
--
-- Build and return a list of all .NET Framework versions up to and including
-- the project's framework version.
--
function cs2005.identifyFrameworkVersions(prj)
local frameworks = {}
local cfg = p.project.getfirstconfig(prj)
local action = premake.action.current()
local targetFramework = cfg.dotnetframework or action.vstudio.targetFramework
for _, frameworkVersion in ipairs(vstudio.frameworkVersions) do
if frameworkVersion == targetFramework then
break
end
table.insert(frameworks, frameworkVersion)
end
table.insert(frameworks, targetFramework)
return frameworks
end
--
-- When given a .NET Framework version, returns it formatted for NuGet.
--
function cs2005.formatNuGetFrameworkVersion(framework)
return "net" .. framework:gsub("%.", "")
end
---------------------------------------------------------------------------
--
-- Handlers for individual project elements

View File

@ -0,0 +1,83 @@
--
-- vs2010_nuget.lua
-- Generate a NuGet packages.config file.
-- Copyright (c) 2016 Jason Perkins and the Premake project
--
premake.vstudio.nuget2010 = {}
local p = premake
local vstudio = p.vstudio
local nuget2010 = p.vstudio.nuget2010
--
-- These functions take the package string as an argument and give you
-- information about it.
--
function nuget2010.packageName(package)
return package:gsub(":", ".")
end
function nuget2010.packageId(package)
return package:sub(0, package:find(":") - 1)
end
function nuget2010.packageVersion(package)
return package:sub(package:find(":") + 1, -1)
end
local function packageProject(wks, package)
for prj in p.workspace.eachproject(wks) do
for i = 1, #prj.nuget do
local projectPackage = prj.nuget[i]
if projectPackage == package then
return prj
end
end
end
end
function nuget2010.packageFramework(wks, package)
local prj = packageProject(wks, package)
if p.project.iscpp(prj) then
return "native"
elseif p.project.isdotnet(prj) then
local cfg = p.project.getfirstconfig(prj)
local action = premake.action.current()
local framework = cfg.dotnetframework or action.vstudio.targetFramework
return cs2005.formatNuGetFrameworkVersion(framework)
end
end
--
-- Generates the packages.config file.
--
function nuget2010.generatePackagesConfig(obj)
local wks = obj.workspace
local packages = {}
for prj in p.workspace.eachproject(wks) do
for i = 1, #prj.nuget do
local package = prj.nuget[i]
if not packages[package] then
packages[package] = true
end
end
end
p.w('<?xml version="1.0" encoding="utf-8"?>')
p.push('<packages>')
for package in pairs(packages) do
p.x('<package id="%s" version="%s" targetFramework="%s" />', nuget2010.packageId(package), nuget2010.packageVersion(package), nuget2010.packageFramework(wks, package))
end
p.pop('</packages>')
end

View File

@ -46,6 +46,7 @@
m.projectReferences,
m.importLanguageTargets,
m.importExtensionTargets,
m.ensureNuGetPackageBuildImports,
}
end
@ -1385,6 +1386,7 @@
return {
m.importGroupTargets,
m.importRuleTargets,
m.importNuGetTargets,
m.importBuildCustomizationsTargets
}
end
@ -1412,6 +1414,17 @@
end
end
local function nuGetTargetsFile(prj, package)
return p.vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s\\build\\native\\%s.targets", vstudio.nuget2010.packageName(package), vstudio.nuget2010.packageId(package))))
end
function m.importNuGetTargets(prj)
for i = 1, #prj.nuget do
local targetsFile = nuGetTargetsFile(prj, prj.nuget[i])
p.x('<Import Project="%s" Condition="Exists(\'%s\')" />', targetsFile, targetsFile)
end
end
function m.importBuildCustomizationsTargets(prj)
for i, build in ipairs(prj.buildcustomizations) do
p.w('<Import Project="$(VCTargetsPath)\\%s.targets" />', path.translate(build))
@ -1420,6 +1433,21 @@
function m.ensureNuGetPackageBuildImports(prj)
p.push('<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">')
p.push('<PropertyGroup>')
p.x('<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>')
p.pop('</PropertyGroup>')
for i = 1, #prj.nuget do
local targetsFile = nuGetTargetsFile(prj, prj.nuget[i])
p.x('<Error Condition="!Exists(\'%s\')" Text="$([System.String]::Format(\'$(ErrorText)\', \'%s\'))" />', targetsFile, targetsFile)
end
p.pop('</Target>')
end
function m.importDefaultProps(prj)
p.w('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />')
end

View File

@ -82,6 +82,7 @@ return {
"actions/vstudio/sln2005/test_projects.lua",
"actions/vstudio/sln2005/test_platforms.lua",
"actions/vstudio/sln2005/test_sections.lua",
"actions/vstudio/sln2005/test_nuget_packages_config.lua",
-- Visual Studio 2002-2008 C/C++ projects
"actions/vstudio/vc200x/test_assembly_refs.lua",
@ -134,6 +135,7 @@ return {
"actions/vstudio/vc2010/test_target_machine.lua",
"actions/vstudio/vc2010/test_user_file.lua",
"actions/vstudio/vc2010/test_vectorextensions.lua",
"actions/vstudio/vc2010/test_ensure_nuget_imports.lua",
-- Makefile tests
"actions/make/test_make_escaping.lua",

View File

@ -16,14 +16,14 @@
local wks, prj
function suite.setup()
premake.action.set("vs2008")
premake.action.set("vs2010")
wks = test.createWorkspace()
language "C#"
end
local function prepare(platform)
prj = test.getproject(wks, 1)
cs2005.assemblyReferences(prj)
cs2005.references(prj)
end
@ -142,3 +142,50 @@
]]
end
--
-- NuGet packages should get references.
--
function suite.nuGetPackages()
dotnetframework "4.5"
nuget { "Newtonsoft.Json:7.0.1" }
prepare()
test.capture [[
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net35\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net35\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
]]
end
--
-- NuGet packages shouldn't get HintPaths for .NET Framework
-- versions that the project doesn't support.
--
function suite.nuGetPackages_olderNET()
dotnetframework "3.0"
nuget { "Newtonsoft.Json:7.0.1" }
prepare()
test.capture [[
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll</HintPath>
<HintPath Condition="Exists('packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll')">packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
]]
end

View File

@ -0,0 +1,43 @@
--
-- tests/actions/vstudio/sln2005/test_nuget_packages_config.lua
-- Validate generation of NuGet packages.config file for Visual Studio 2010 and newer.
-- Copyright (c) 2016 Jason Perkins and the Premake project
--
local suite = test.declare("vstudio_sln2005_nuget_packages_config")
local nuget2010 = premake.vstudio.nuget2010
--
-- Setup
--
local wks
function suite.setup()
premake.action.set("vs2010")
wks = test.createWorkspace()
end
local function prepare()
local prj = premake.solution.getproject(wks, 1)
nuget2010.generatePackagesConfig({ workspace = wks })
end
--
-- Writes the packages.config file properly.
--
function suite.structureIsCorrect()
nuget { "boost:1.59.0-b1", "sdl2.v140:2.0.3", "sdl2.v140.redist:2.0.3" }
prepare()
test.capture [[
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.59.0-b1" targetFramework="native" />
<package id="sdl2.v140" version="2.0.3" targetFramework="native" />
<package id="sdl2.v140.redist" version="2.0.3" targetFramework="native" />
</packages>
]]
end

View File

@ -0,0 +1,46 @@
--
-- tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua
-- Check the EnsureNuGetPackageBuildImports block of a VS 2010 project.
-- Copyright (c) 2016 Jason Perkins and the Premake project
--
local suite = test.declare("vs2010_ensure_nuget_imports")
local vc2010 = premake.vstudio.vc2010
local project = premake.project
--
-- Setup
--
local wks
function suite.setup()
premake.action.set("vs2010")
wks = test.createWorkspace()
end
local function prepare()
local prj = premake.solution.getproject(wks, 1)
vc2010.ensureNuGetPackageBuildImports(prj)
end
--
-- Writes the pre-build check that makes sure that all packages are installed.
--
function suite.structureIsCorrect()
nuget { "boost:1.59.0-b1", "sdl2.v140:2.0.3", "sdl2.v140.redist:2.0.3" }
prepare()
test.capture [[
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\boost.1.59.0-b1\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\boost.1.59.0-b1\build\native\boost.targets'))" />
<Error Condition="!Exists('packages\sdl2.v140.2.0.3\build\native\sdl2.v140.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\sdl2.v140.2.0.3\build\native\sdl2.v140.targets'))" />
<Error Condition="!Exists('packages\sdl2.v140.redist.2.0.3\build\native\sdl2.v140.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\sdl2.v140.redist.2.0.3\build\native\sdl2.v140.redist.targets'))" />
</Target>
]]
end

View File

@ -58,6 +58,23 @@
end
--
-- Writes entries for NuGet packages.
--
function suite.addsImport_onEachNuGetPackage()
nuget { "boost:1.59.0-b1", "sdl2.v140:2.0.3", "sdl2.v140.redist:2.0.3" }
prepare()
test.capture [[
<ImportGroup Label="ExtensionTargets">
<Import Project="packages\boost.1.59.0-b1\build\native\boost.targets" Condition="Exists('packages\boost.1.59.0-b1\build\native\boost.targets')" />
<Import Project="packages\sdl2.v140.2.0.3\build\native\sdl2.v140.targets" Condition="Exists('packages\sdl2.v140.2.0.3\build\native\sdl2.v140.targets')" />
<Import Project="packages\sdl2.v140.redist.2.0.3\build\native\sdl2.v140.redist.targets" Condition="Exists('packages\sdl2.v140.redist.2.0.3\build\native\sdl2.v140.redist.targets')" />
</ImportGroup>
]]
end
--
-- Rule files use a project relative path.
--