1509 lines
No EOL
68 KiB
C#
1509 lines
No EOL
68 KiB
C#
#region BSD License
|
|
|
|
/*
|
|
Copyright (c) 2008 Matthew Holmes (matthew@wildfiregames.com), John Anderson (sontek@gmail.com)
|
|
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted
|
|
provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
|
and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
|
and the following disclaimer in the documentation and/or other materials provided with the
|
|
distribution.
|
|
* The name of the author may not be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
|
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#endregion
|
|
|
|
using Prebuild.Core.Interfaces;
|
|
using Prebuild.Core.Nodes;
|
|
using Prebuild.Core.Utilities;
|
|
using System;
|
|
using System.CodeDom.Compiler;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace Prebuild.Core.Targets;
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
public abstract class VSGenericTarget : ITarget
|
|
{
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="VSGenericTarget" /> class.
|
|
/// </summary>
|
|
protected VSGenericTarget()
|
|
{
|
|
tools["C#"] = new ToolInfo("C#", "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "csproj", "CSHARP",
|
|
"$(MSBuildBinPath)\\Microsoft.CSharp.targets");
|
|
tools["Database"] = new ToolInfo("Database", "{4F174C21-8C12-11D0-8340-0000F80270F8}", "dbp", "UNKNOWN");
|
|
tools["Boo"] = new ToolInfo("Boo", "{45CEA7DC-C2ED-48A6-ACE0-E16144C02365}", "booproj", "Boo",
|
|
"$(BooBinPath)\\Boo.Microsoft.Build.targets");
|
|
tools["VisualBasic"] = new ToolInfo("VisualBasic", "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}", "vbproj",
|
|
"VisualBasic", "$(MSBuildBinPath)\\Microsoft.VisualBasic.Targets");
|
|
tools["Folder"] = new ToolInfo("Folder", "{2150E333-8FDC-42A3-9474-1A3956D46DE8}", null, null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Fields
|
|
|
|
private readonly Dictionary<string, ToolInfo> tools = new();
|
|
|
|
// NameValueCollection CopyFiles = new NameValueCollection();
|
|
private Kernel kernel;
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// Gets or sets the solution version.
|
|
/// </summary>
|
|
/// <value>The solution version.</value>
|
|
public abstract string SolutionVersion { get; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the product version.
|
|
/// </summary>
|
|
/// <value>The product version.</value>
|
|
public abstract string ProductVersion { get; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
/// <value>The schema version.</value>
|
|
public abstract string SchemaVersion { get; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the name of the version.
|
|
/// </summary>
|
|
/// <value>The name of the version.</value>
|
|
public abstract string VersionName { get; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the version.
|
|
/// </summary>
|
|
/// <value>The version.</value>
|
|
public abstract VSVersion Version { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the name.
|
|
/// </summary>
|
|
/// <value>The name.</value>
|
|
public abstract string Name { get; }
|
|
|
|
protected abstract string GetToolsVersionXml(FrameworkVersion version);
|
|
public abstract string SolutionTag { get; }
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private string MakeRefPath(ProjectNode project)
|
|
{
|
|
var ret = "";
|
|
foreach (var node in project.ReferencePaths)
|
|
try
|
|
{
|
|
var fullPath = Helper.ResolvePath(node.Path);
|
|
if (ret.Length < 1)
|
|
ret = fullPath;
|
|
else
|
|
ret += ";" + fullPath;
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
kernel.Log.Write(LogType.Warning, "Could not resolve reference path: {0}", node.Path);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
private static ProjectNode FindProjectInSolution(string name, SolutionNode solution)
|
|
{
|
|
var node = solution;
|
|
|
|
while (node.Parent is SolutionNode)
|
|
node = node.Parent as SolutionNode;
|
|
|
|
return FindProjectInSolutionRecursively(name, node);
|
|
}
|
|
|
|
private static ProjectNode FindProjectInSolutionRecursively(string name, SolutionNode solution)
|
|
{
|
|
if (solution.ProjectsTable.ContainsKey(name))
|
|
return solution.ProjectsTable[name];
|
|
|
|
foreach (var child in solution.Solutions)
|
|
{
|
|
var node = FindProjectInSolutionRecursively(name, child);
|
|
if (node != null)
|
|
return node;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void WriteProject(SolutionNode solution, ProjectNode project)
|
|
{
|
|
if (!tools.ContainsKey(project.Language))
|
|
throw new UnknownLanguageException("Unknown .NET language: " + project.Language);
|
|
|
|
var toolInfo = tools[project.Language];
|
|
var projectFile = Helper.MakeFilePath(project.FullPath, project.Name, toolInfo.FileExtension);
|
|
var ps = new StreamWriter(projectFile);
|
|
|
|
kernel.CurrentWorkingDirectory.Push();
|
|
Helper.SetCurrentDir(Path.GetDirectoryName(projectFile));
|
|
|
|
var fv = project.FrameworkVersion;
|
|
if (fv > FrameworkVersion.v4_8)
|
|
// Write the newer .csproj file format
|
|
WriteProjectDotNet(solution, project, ps);
|
|
else
|
|
WriteProjectFramework(solution, project, toolInfo, projectFile, ps);
|
|
|
|
kernel.CurrentWorkingDirectory.Pop();
|
|
}
|
|
|
|
private void WriteProjectFramework(SolutionNode solution, ProjectNode project, ToolInfo toolInfo,
|
|
string projectFile, StreamWriter ps)
|
|
{
|
|
#region Project File
|
|
|
|
using (ps)
|
|
{
|
|
var targets = "";
|
|
|
|
if (project.Files.CopyFiles > 0)
|
|
targets = "Build;CopyFiles";
|
|
else
|
|
targets = "Build";
|
|
|
|
ps.WriteLine(
|
|
"<Project DefaultTargets=\"{0}\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" {1}>",
|
|
targets, GetToolsVersionXml(project.FrameworkVersion));
|
|
ps.WriteLine(" <PropertyGroup>");
|
|
ps.WriteLine(" <ProjectType>Local</ProjectType>");
|
|
ps.WriteLine(" <ProductVersion>{0}</ProductVersion>", ProductVersion);
|
|
ps.WriteLine(" <SchemaVersion>{0}</SchemaVersion>", SchemaVersion);
|
|
ps.WriteLine(" <ProjectGuid>{{{0}}}</ProjectGuid>", project.Guid.ToString().ToUpper());
|
|
|
|
// Visual Studio has a hard coded guid for the project type
|
|
if (project.Type == ProjectType.Web)
|
|
ps.WriteLine(
|
|
" <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>");
|
|
ps.WriteLine(" <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>");
|
|
ps.WriteLine(" <ApplicationIcon>{0}</ApplicationIcon>", project.AppIcon);
|
|
ps.WriteLine(" <AssemblyKeyContainerName>");
|
|
ps.WriteLine(" </AssemblyKeyContainerName>");
|
|
ps.WriteLine(" <AssemblyName>{0}</AssemblyName>", project.AssemblyName);
|
|
foreach (var conf in project.Configurations)
|
|
if (conf.Options.KeyFile != "")
|
|
{
|
|
ps.WriteLine(" <AssemblyOriginatorKeyFile>{0}</AssemblyOriginatorKeyFile>", conf.Options.KeyFile);
|
|
ps.WriteLine(" <SignAssembly>true</SignAssembly>");
|
|
break;
|
|
}
|
|
|
|
ps.WriteLine(" <DefaultClientScript>JScript</DefaultClientScript>");
|
|
ps.WriteLine(" <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>");
|
|
ps.WriteLine(" <DefaultTargetSchema>IE50</DefaultTargetSchema>");
|
|
ps.WriteLine(" <DelaySign>false</DelaySign>");
|
|
ps.WriteLine(" <TargetFrameworkVersion>{0}</TargetFrameworkVersion>",
|
|
project.FrameworkVersion.ToString().Replace("_", "."));
|
|
|
|
ps.WriteLine(" <OutputType>{0}</OutputType>",
|
|
project.Type == ProjectType.Web ? ProjectType.Library.ToString() : project.Type.ToString());
|
|
ps.WriteLine(" <AppDesignerFolder>{0}</AppDesignerFolder>", project.DesignerFolder);
|
|
ps.WriteLine(" <RootNamespace>{0}</RootNamespace>", project.RootNamespace);
|
|
ps.WriteLine(" <StartupObject>{0}</StartupObject>", project.StartupObject);
|
|
if (string.IsNullOrEmpty(project.DebugStartParameters))
|
|
ps.WriteLine(" <StartArguments>{0}</StartArguments>", project.DebugStartParameters);
|
|
ps.WriteLine(" <FileUpgradeFlags>");
|
|
ps.WriteLine(" </FileUpgradeFlags>");
|
|
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
if (!string.IsNullOrEmpty(project.ApplicationManifest))
|
|
{
|
|
ps.WriteLine(" <PropertyGroup>");
|
|
ps.WriteLine(" <ApplicationManifest>" + project.ApplicationManifest + "</ApplicationManifest>");
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
}
|
|
|
|
foreach (var conf in project.Configurations)
|
|
{
|
|
ps.Write(" <PropertyGroup ");
|
|
ps.WriteLine("Condition=\" '$(Configuration)|$(Platform)' == '{0}|{1}' \">", conf.Name, conf.Platform);
|
|
ps.WriteLine(" <AllowUnsafeBlocks>{0}</AllowUnsafeBlocks>", conf.Options["AllowUnsafe"]);
|
|
ps.WriteLine(" <BaseAddress>{0}</BaseAddress>", conf.Options["BaseAddress"]);
|
|
ps.WriteLine(" <CheckForOverflowUnderflow>{0}</CheckForOverflowUnderflow>",
|
|
conf.Options["CheckUnderflowOverflow"]);
|
|
ps.WriteLine(" <ConfigurationOverrideFile>");
|
|
ps.WriteLine(" </ConfigurationOverrideFile>");
|
|
var defConstants = conf.Options["CompilerDefines"].ToString() == ""
|
|
? kernel.ForcedConditionals
|
|
: conf.Options["CompilerDefines"] + ";" + kernel.ForcedConditionals;
|
|
if (!string.IsNullOrEmpty(project.FrameworkVersionForConditional))
|
|
{
|
|
if (string.IsNullOrEmpty(defConstants))
|
|
defConstants = project.FrameworkVersionForConditional + ";";
|
|
else if (defConstants.IndexOf(project.FrameworkVersionForConditional) < 0)
|
|
defConstants += project.FrameworkVersionForConditional + ";";
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(defConstants))
|
|
ps.WriteLine(" <DefineConstants>{0}</DefineConstants>", defConstants);
|
|
|
|
ps.WriteLine(" <DocumentationFile>{0}</DocumentationFile>",
|
|
Helper.NormalizePath(conf.Options["XmlDocFile"].ToString()));
|
|
ps.WriteLine(" <DebugSymbols>{0}</DebugSymbols>", conf.Options["DebugInformation"]);
|
|
ps.WriteLine(" <FileAlignment>{0}</FileAlignment>", conf.Options["FileAlignment"]);
|
|
ps.WriteLine(" <Optimize>{0}</Optimize>", conf.Options["OptimizeCode"]);
|
|
if (project.Type != ProjectType.Web)
|
|
ps.WriteLine(" <OutputPath>{0}</OutputPath>",
|
|
Helper.EndPath(Helper.NormalizePath(conf.Options["OutputPath"].ToString())));
|
|
else
|
|
ps.WriteLine(" <OutputPath>{0}</OutputPath>",
|
|
Helper.EndPath(Helper.NormalizePath("bin\\")));
|
|
|
|
ps.WriteLine(" <RegisterForComInterop>{0}</RegisterForComInterop>",
|
|
conf.Options["RegisterComInterop"]);
|
|
ps.WriteLine(" <RemoveIntegerChecks>{0}</RemoveIntegerChecks>", conf.Options["RemoveIntegerChecks"]);
|
|
ps.WriteLine(" <TreatWarningsAsErrors>{0}</TreatWarningsAsErrors>", conf.Options["WarningsAsErrors"]);
|
|
ps.WriteLine(" <WarningLevel>{0}</WarningLevel>", conf.Options["WarningLevel"]);
|
|
ps.WriteLine(" <NoStdLib>{0}</NoStdLib>", conf.Options["NoStdLib"]);
|
|
ps.WriteLine(" <NoWarn>{0}</NoWarn>", conf.Options["SuppressWarnings"]);
|
|
ps.WriteLine(" <PlatformTarget>{0}</PlatformTarget>", conf.Platform);
|
|
ps.WriteLine(" <Prefer32Bit>{0}</Prefer32Bit>", conf.Options["Prefer32Bit"]);
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
}
|
|
|
|
//ps.WriteLine(" </Settings>");
|
|
|
|
// Output warnings if NET6 stuff is in a Framework4 definition
|
|
if (project.ProjectReferences.Count > 0)
|
|
kernel.Log.Write(LogType.Warning, "ProjectReference is not processed for Frameworks.");
|
|
if (project.PackageReferences.Count > 0)
|
|
kernel.Log.Write(LogType.Warning, "PackageReference is not processed for Frameworks.");
|
|
|
|
// Output the ItemGroup for project.References
|
|
WriteProjectReferences(solution, project, ps);
|
|
|
|
//ps.WriteLine(" </Build>");
|
|
ps.WriteLine(" <ItemGroup>");
|
|
|
|
//ps.WriteLine(" <Include>");
|
|
var list = new List<string>();
|
|
|
|
foreach (var path in project.Files)
|
|
{
|
|
var lower = path.ToLower();
|
|
if (lower.EndsWith(".resx"))
|
|
{
|
|
var codebehind = string.Format("{0}.Designer{1}", path.Substring(0, path.LastIndexOf('.')),
|
|
toolInfo.LanguageExtension);
|
|
if (!list.Contains(codebehind))
|
|
list.Add(codebehind);
|
|
}
|
|
}
|
|
|
|
#region Files
|
|
|
|
foreach (var filePath in project.Files)
|
|
{
|
|
// Add the filePath with the destination as the key
|
|
// will use it later to form the copy parameters with Include lists
|
|
// for each destination
|
|
if (project.Files.GetBuildAction(filePath) == BuildAction.Copy)
|
|
continue;
|
|
//if (file == "Properties\\Bind.Designer.cs")
|
|
//{
|
|
// Console.WriteLine("Wait a minute!");
|
|
// Console.WriteLine(project.Files.GetSubType(file).ToString());
|
|
//}
|
|
var subType = project.Files.GetSubType(filePath);
|
|
|
|
// Visual Studio chokes on file names if forward slash is used as a path separator
|
|
// instead of backslash. So we must make sure that all file paths written to the
|
|
// project file use \ as a path separator.
|
|
var file = filePath.Replace(@"/", @"\");
|
|
|
|
if (subType != SubType.Code && subType != SubType.Settings && subType != SubType.Designer
|
|
&& subType != SubType.CodeBehind)
|
|
{
|
|
ps.WriteLine(" <EmbeddedResource Include=\"{0}\">",
|
|
file.Substring(0, file.LastIndexOf('.')) + ".resx");
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(file));
|
|
ps.WriteLine(" <SubType>Designer</SubType>");
|
|
ps.WriteLine(" </EmbeddedResource>");
|
|
//
|
|
}
|
|
|
|
if (subType == SubType.Designer)
|
|
{
|
|
ps.WriteLine(" <EmbeddedResource Include=\"{0}\">", file);
|
|
|
|
var autogen_name = file.Substring(0, file.LastIndexOf('.')) + ".Designer.cs";
|
|
var dependent_name = filePath.Substring(0, file.LastIndexOf('.')) + ".cs";
|
|
|
|
// Check for a parent .cs file with the same name as this designer file
|
|
if (File.Exists(Helper.NormalizePath(dependent_name)))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(dependent_name));
|
|
}
|
|
else
|
|
{
|
|
ps.WriteLine(" <Generator>ResXFileCodeGenerator</Generator>");
|
|
ps.WriteLine(" <LastGenOutput>{0}</LastGenOutput>", Path.GetFileName(autogen_name));
|
|
ps.WriteLine(" <SubType>" + subType + "</SubType>");
|
|
}
|
|
|
|
ps.WriteLine(" </EmbeddedResource>");
|
|
if (File.Exists(Helper.NormalizePath(autogen_name)))
|
|
{
|
|
ps.WriteLine(" <Compile Include=\"{0}\">", autogen_name);
|
|
//ps.WriteLine(" <DesignTime>True</DesignTime>");
|
|
|
|
// If a parent .cs file exists, link this autogen file to it. Otherwise link
|
|
// to the designer file
|
|
if (File.Exists(dependent_name))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(dependent_name));
|
|
}
|
|
else
|
|
{
|
|
ps.WriteLine(" <AutoGen>True</AutoGen>");
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(filePath));
|
|
}
|
|
|
|
ps.WriteLine(" </Compile>");
|
|
}
|
|
|
|
list.Add(autogen_name);
|
|
}
|
|
|
|
if (subType == SubType.Settings)
|
|
{
|
|
ps.Write(" <{0} ", project.Files.GetBuildAction(filePath));
|
|
ps.WriteLine(" Include=\"{0}\">", file);
|
|
var fileName = Path.GetFileName(filePath);
|
|
if (project.Files.GetBuildAction(filePath) == BuildAction.None)
|
|
{
|
|
ps.WriteLine(" <Generator>SettingsSingleFileGenerator</Generator>");
|
|
ps.WriteLine(" <LastGenOutput>{0}</LastGenOutput>",
|
|
fileName.Substring(0, fileName.LastIndexOf('.')) + ".Designer.cs");
|
|
}
|
|
else
|
|
{
|
|
ps.WriteLine(" <SubType>Code</SubType>");
|
|
ps.WriteLine(" <AutoGen>True</AutoGen>");
|
|
ps.WriteLine(" <DesignTimeSharedInput>True</DesignTimeSharedInput>");
|
|
var fileNameShort = fileName.Substring(0, fileName.LastIndexOf('.'));
|
|
var fileNameShorter = fileNameShort.Substring(0, fileNameShort.LastIndexOf('.'));
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(fileNameShorter + ".settings"));
|
|
}
|
|
|
|
ps.WriteLine(" </{0}>", project.Files.GetBuildAction(filePath));
|
|
}
|
|
else if (subType != SubType.Designer)
|
|
{
|
|
var path = Helper.NormalizePath(file);
|
|
var path_lower = path.ToLower();
|
|
|
|
if (!list.Contains(filePath))
|
|
{
|
|
ps.Write(" <{0} ", project.Files.GetBuildAction(filePath));
|
|
|
|
var startPos = 0;
|
|
if (project.Files.GetPreservePath(filePath))
|
|
while (@"./\".IndexOf(file.Substring(startPos, 1)) != -1)
|
|
startPos++;
|
|
else
|
|
startPos = file.LastIndexOf(Path.GetFileName(path));
|
|
|
|
// be sure to write out the path with backslashes so VS recognizes
|
|
// the file properly.
|
|
ps.WriteLine(" Include=\"{0}\">", file);
|
|
|
|
var last_period_index = file.LastIndexOf('.');
|
|
var short_file_name = last_period_index >= 0
|
|
? file.Substring(0, last_period_index)
|
|
: file;
|
|
var extension = Path.GetExtension(path);
|
|
// make this upper case, so that when File.Exists tests for the
|
|
// existence of a designer file on a case-sensitive platform,
|
|
// it is correctly identified.
|
|
var designer_format = string.Format(".Designer{0}", extension);
|
|
|
|
if (path_lower.EndsWith(designer_format.ToLowerInvariant()))
|
|
{
|
|
var designer_index = path.IndexOf(designer_format);
|
|
var file_name = path.Substring(0, designer_index);
|
|
|
|
// There are two corrections to the next lines:
|
|
// 1. Fix the connection between a designer file and a form
|
|
// or usercontrol that don't have an associated resx file.
|
|
// 2. Connect settings files to associated designer files.
|
|
if (File.Exists(file_name + extension))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(file_name + extension));
|
|
}
|
|
else if (File.Exists(file_name + ".resx"))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(file_name + ".resx"));
|
|
}
|
|
else if (File.Exists(file_name + ".settings"))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(file_name + ".settings"));
|
|
ps.WriteLine(" <AutoGen>True</AutoGen>");
|
|
ps.WriteLine(" <DesignTimeSharedInput>True</DesignTimeSharedInput>");
|
|
}
|
|
}
|
|
else if (subType == SubType.CodeBehind)
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(short_file_name));
|
|
}
|
|
|
|
if (project.Files.GetIsLink(filePath))
|
|
{
|
|
var alias = project.Files.GetLinkPath(filePath);
|
|
alias += file.Substring(startPos);
|
|
alias = Helper.NormalizePath(alias);
|
|
ps.WriteLine(" <Link>{0}</Link>", alias);
|
|
}
|
|
else if (project.Files.GetBuildAction(filePath) != BuildAction.None)
|
|
{
|
|
if (project.Files.GetBuildAction(filePath) != BuildAction.EmbeddedResource)
|
|
ps.WriteLine(" <SubType>{0}</SubType>", subType);
|
|
}
|
|
|
|
if (project.Files.GetCopyToOutput(filePath) != CopyToOutput.Never)
|
|
ps.WriteLine(" <CopyToOutputDirectory>{0}</CopyToOutputDirectory>",
|
|
project.Files.GetCopyToOutput(filePath));
|
|
|
|
ps.WriteLine(" </{0}>", project.Files.GetBuildAction(filePath));
|
|
}
|
|
}
|
|
}
|
|
|
|
ps.WriteLine(" </ItemGroup>");
|
|
|
|
#endregion
|
|
|
|
/*
|
|
* Copy Task
|
|
*
|
|
*/
|
|
if (project.Files.CopyFiles > 0)
|
|
{
|
|
var IncludeTags = new Dictionary<string, string>();
|
|
var TagCount = 0;
|
|
|
|
// Handle Copy tasks
|
|
ps.WriteLine(" <ItemGroup>");
|
|
foreach (var destPath in project.Files.Destinations)
|
|
{
|
|
var tag = "FilesToCopy_" + TagCount.ToString("0000");
|
|
|
|
ps.WriteLine(" <{0} Include=\"{1}\" />", tag,
|
|
string.Join(";", project.Files.SourceFiles(destPath)));
|
|
IncludeTags.Add(destPath, tag);
|
|
TagCount++;
|
|
}
|
|
|
|
ps.WriteLine(" </ItemGroup>");
|
|
|
|
ps.WriteLine(" <Target Name=\"CopyFiles\" AfterTargets=\"AfterBuild\">");
|
|
|
|
foreach (var destPath in project.Files.Destinations)
|
|
ps.WriteLine(" <Copy SourceFiles=\"@({0})\" DestinationFolder=\"{1}\" />",
|
|
IncludeTags[destPath], destPath);
|
|
|
|
ps.WriteLine(" </Target>");
|
|
}
|
|
|
|
ps.WriteLine(" <Import Project=\"" + toolInfo.ImportProject + "\" />");
|
|
ps.WriteLine(" <PropertyGroup>");
|
|
ps.WriteLine(" <PreBuildEvent>");
|
|
ps.WriteLine(" </PreBuildEvent>");
|
|
ps.WriteLine(" <PostBuildEvent>");
|
|
ps.WriteLine(" </PostBuildEvent>");
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
ps.WriteLine("</Project>");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region User File
|
|
|
|
ps = new StreamWriter(projectFile + ".user");
|
|
using (ps)
|
|
{
|
|
// Get the first configuration from the project.
|
|
ConfigurationNode firstConfiguration = null;
|
|
|
|
if (project.Configurations.Count > 0) firstConfiguration = project.Configurations[0];
|
|
|
|
ps.WriteLine("<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">");
|
|
//ps.WriteLine( "<VisualStudioProject>" );
|
|
//ps.WriteLine(" <{0}>", toolInfo.XMLTag);
|
|
//ps.WriteLine(" <Build>");
|
|
ps.WriteLine(" <PropertyGroup>");
|
|
//ps.WriteLine(" <Settings ReferencePath=\"{0}\">", MakeRefPath(project));
|
|
|
|
if (firstConfiguration != null)
|
|
{
|
|
ps.WriteLine(" <Configuration Condition=\" '$(Configuration)' == '' \">{0}</Configuration>",
|
|
firstConfiguration.Name);
|
|
ps.WriteLine(" <Platform Condition=\" '$(Platform)' == '' \">{0}</Platform>",
|
|
firstConfiguration.Platform);
|
|
}
|
|
|
|
ps.WriteLine(" <ReferencePath>{0}</ReferencePath>", MakeRefPath(project));
|
|
ps.WriteLine(" <LastOpenVersion>{0}</LastOpenVersion>", ProductVersion);
|
|
ps.WriteLine(" <ProjectView>ProjectFiles</ProjectView>");
|
|
ps.WriteLine(" <ProjectTrust>0</ProjectTrust>");
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
foreach (var conf in project.Configurations)
|
|
{
|
|
ps.Write(" <PropertyGroup");
|
|
ps.Write(" Condition = \" '$(Configuration)|$(Platform)' == '{0}|{1}' \"", conf.Name, conf.Platform);
|
|
ps.WriteLine(" />");
|
|
}
|
|
|
|
ps.WriteLine("</Project>");
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
private void WriteProjectReferences(SolutionNode solution, ProjectNode project, StreamWriter ps)
|
|
{
|
|
var projectReferences = new Dictionary<ReferenceNode, ProjectNode>();
|
|
var otherReferences = new List<ReferenceNode>();
|
|
|
|
foreach (var refr in project.References)
|
|
{
|
|
var projectNode = FindProjectInSolution(refr.Name, solution);
|
|
|
|
if (projectNode == null)
|
|
otherReferences.Add(refr);
|
|
else
|
|
projectReferences.Add(refr, projectNode);
|
|
}
|
|
|
|
// Assembly References
|
|
if (otherReferences.Count > 0)
|
|
{
|
|
ps.WriteLine(" <ItemGroup>");
|
|
|
|
foreach (var refr in otherReferences)
|
|
{
|
|
ps.Write(" <Reference");
|
|
ps.Write(" Include=\"");
|
|
ps.Write(refr.Name);
|
|
ps.WriteLine("\" >");
|
|
ps.Write(" <Name>");
|
|
ps.Write(refr.Name);
|
|
ps.WriteLine("</Name>");
|
|
|
|
if (!string.IsNullOrEmpty(refr.Path))
|
|
{
|
|
// Use absolute path to assembly (for determining assembly type)
|
|
var absolutePath = Path.Combine(project.FullPath, refr.Path);
|
|
if (File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "exe")))
|
|
{
|
|
// Assembly is an executable (exe)
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>", Helper.MakeFilePath(refr.Path, refr.Name, "exe"));
|
|
}
|
|
else if (File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "dll")))
|
|
{
|
|
// Assembly is an library (dll)
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>", Helper.MakeFilePath(refr.Path, refr.Name, "dll"));
|
|
}
|
|
else
|
|
{
|
|
var referencePath = Helper.MakeFilePath(refr.Path, refr.Name, "dll");
|
|
kernel.Log.Write(LogType.Warning, "Reference \"{0}\": The specified file doesn't exist.",
|
|
referencePath);
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>", Helper.MakeFilePath(refr.Path, refr.Name, "dll"));
|
|
}
|
|
}
|
|
|
|
ps.WriteLine(" <Private>{0}</Private>", refr.LocalCopy);
|
|
ps.WriteLine(" </Reference>");
|
|
}
|
|
|
|
ps.WriteLine(" </ItemGroup>");
|
|
ps.WriteLine();
|
|
}
|
|
|
|
//Project References
|
|
if (projectReferences.Count > 0)
|
|
{
|
|
ps.WriteLine(" <ItemGroup>");
|
|
foreach (var pair in projectReferences)
|
|
{
|
|
var tool = tools[pair.Value.Language];
|
|
if (tools == null)
|
|
throw new UnknownLanguageException();
|
|
|
|
var path =
|
|
Helper.MakePathRelativeTo(project.FullPath,
|
|
Helper.MakeFilePath(pair.Value.FullPath, pair.Value.Name, tool.FileExtension));
|
|
ps.WriteLine(" <ProjectReference Include=\"{0}\">", path);
|
|
|
|
// TODO: Allow reference to visual basic projects
|
|
ps.WriteLine(" <Name>{0}</Name>", pair.Value.Name);
|
|
ps.WriteLine(" <Project>{0}</Project>", pair.Value.Guid.ToString("B").ToUpper());
|
|
ps.WriteLine(" <Package>{0}</Package>", tool.Guid.ToUpper());
|
|
|
|
//This is the Copy Local flag in VS
|
|
ps.WriteLine(" <Private>{0}</Private>", pair.Key.LocalCopy);
|
|
|
|
ps.WriteLine(" </ProjectReference>");
|
|
}
|
|
|
|
ps.WriteLine(" </ItemGroup>");
|
|
ps.WriteLine();
|
|
}
|
|
}
|
|
|
|
private void WriteTextGeneratorNodes(ProjectNode project, StreamWriter ps)
|
|
{
|
|
foreach(TextGenNode node in project.TextGenNodes)
|
|
{
|
|
string pathText = Path.Combine("Prebuild", "bootstrap", "SnapWrap.dll");
|
|
string filePath = Path.Combine(project.Path, node.Name);
|
|
string outputFile = Path.Combine(project.Path, node.OutputName);
|
|
|
|
ps.WriteLine(" <Target Name=\"Prebuild\" BeforeTargets=\"PreBuildEvent\">");
|
|
ps.WriteLine($" <Exec Command='dotnet \"$(SolutionDir){pathText}\" \"$({node.SourceDirectory}){node.Name}\" \"$(ProjectDir){node.OutputName}\" \"{node.Libraries}\"' />");
|
|
ps.WriteLine($" </Target>");
|
|
}
|
|
}
|
|
|
|
private void WriteProjectDotNet(SolutionNode solution, ProjectNode project, StreamWriter ps)
|
|
{
|
|
#region Project File
|
|
|
|
var listFiles = project.Files.Count > 0;
|
|
var prebuild = string.Empty;
|
|
var postbuild = string.Empty;
|
|
using (ps)
|
|
{
|
|
ps.WriteLine("<Project Sdk=\"Microsoft.NET.Sdk\">");
|
|
ps.WriteLine();
|
|
|
|
ps.WriteLine(" <PropertyGroup>");
|
|
ps.WriteLine($" <TargetFramework>{project.FrameworkVersion.ToString().Replace("_", ".")}</TargetFramework>");
|
|
ps.WriteLine(" <PreserveCompilationContext>false</PreserveCompilationContext>");
|
|
ps.WriteLine(" <OutputType>{0}</OutputType>",
|
|
project.Type == ProjectType.Web ? ProjectType.Library.ToString() : project.Type.ToString());
|
|
ps.WriteLine(" <GenerateAssemblyInfo>false</GenerateAssemblyInfo>");
|
|
if (project.FrameworkVersion == FrameworkVersion.netstandard2_0)
|
|
ps.WriteLine(" <RuntimeFrameworkVersion>5.0.0</RuntimeFrameworkVersion>");
|
|
ps.WriteLine(" <ImplicitUsings>disable</ImplicitUsings>");
|
|
ps.WriteLine(" <AssemblyName>{0}</AssemblyName>", project.AssemblyName);
|
|
ps.WriteLine(" <Deterministic>true</Deterministic>");
|
|
//ps.WriteLine(" <EnableDefaultCompileItems>false</EnableDefaultCompileItems>");
|
|
ps.WriteLine(" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>");
|
|
if (!solution.Options.UseDepsFile)
|
|
ps.WriteLine(" <GenerateDependencyFile>false</GenerateDependencyFile>");
|
|
if (listFiles)
|
|
ps.WriteLine(" <EnableDefaultItems>false</EnableDefaultItems>");
|
|
|
|
if (project.CopyLocalLockFileAssemblies)
|
|
ps.WriteLine(
|
|
$" <CopyLocalLockFileAssemblies>{project.CopyLocalLockFileAssemblies}</CopyLocalLockFileAssemblies>");
|
|
|
|
if(project.FrameworkVersion >= FrameworkVersion.net7_0)
|
|
{
|
|
if(project.MauiSettings != null)
|
|
{
|
|
ps.WriteLine(project.MauiSettings);
|
|
}
|
|
}
|
|
|
|
if(project.Nullable)
|
|
ps.WriteLine($" <Nullable>{project.NullableStr}</Nullable>");
|
|
|
|
if(project.AppIcon != "")
|
|
{
|
|
|
|
ps.WriteLine($" <ApplicationIcon>{project.AppIcon}</ApplicationIcon>");
|
|
}
|
|
ps.WriteLine($" <SelfContained>{solution.Options.SelfContained}</SelfContained>");
|
|
if (solution.Options.UseRuntimeIdentifier)
|
|
{
|
|
var RID = "unknown";
|
|
|
|
if (OperatingSystem.IsLinux()) RID = "linux-x64";
|
|
|
|
if (OperatingSystem.IsWindows()) RID = "win-x64";
|
|
|
|
if (OperatingSystem.IsMacOS()) RID = "macos-x64";
|
|
|
|
ps.WriteLine($"<RuntimeIdentifier>{RID}</RuntimeIdentifier>");
|
|
}
|
|
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
ps.WriteLine();
|
|
|
|
foreach (var conf in project.Configurations)
|
|
if (conf.Name == "unknown")
|
|
{
|
|
ps.WriteLine(" <PropertyGroup>");
|
|
foreach (var opt in conf.Options.AllDefined())
|
|
ps.WriteLine(" <{0}>{1}</{0}>", opt,
|
|
Helper.EndPath(Helper.NormalizePath(conf.Options[opt].ToString())));
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
ps.WriteLine();
|
|
}
|
|
else
|
|
{
|
|
ps.Write(" <PropertyGroup ");
|
|
ps.WriteLine("Condition=\" '$(Configuration)|$(Platform)' == '{0}|{1}' \">", conf.Name,
|
|
conf.Platform);
|
|
ps.WriteLine(" <AllowUnsafeBlocks>{0}</AllowUnsafeBlocks>", conf.Options["AllowUnsafe"]);
|
|
ps.WriteLine(" <BaseAddress>{0}</BaseAddress>", conf.Options["BaseAddress"]);
|
|
if ((bool)conf.Options["CheckUnderflowOverflow"])
|
|
ps.WriteLine(" <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>");
|
|
ps.WriteLine(" <ConfigurationOverrideFile>");
|
|
ps.WriteLine(" </ConfigurationOverrideFile>");
|
|
if (string.IsNullOrEmpty(conf.Options["CompilerDefines"].ToString()))
|
|
{
|
|
ps.WriteLine(" <DefineConstants>{0}</DefineConstants>", kernel.ForcedConditionals);
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrEmpty(kernel.ForcedConditionals))
|
|
ps.WriteLine(" <DefineConstants>{0}</DefineConstants>", conf.Options["CompilerDefines"]);
|
|
else
|
|
ps.WriteLine(" <DefineConstants>{0}</DefineConstants>",
|
|
conf.Options["CompilerDefines"] + ";" + kernel.ForcedConditionals);
|
|
}
|
|
|
|
ps.WriteLine(" <DocumentationFile>{0}</DocumentationFile>",
|
|
Helper.NormalizePath(conf.Options["XmlDocFile"].ToString()));
|
|
ps.WriteLine(" <DebugSymbols>{0}</DebugSymbols>", conf.Options["DebugInformation"]);
|
|
ps.WriteLine(" <FileAlignment>{0}</FileAlignment>", conf.Options["FileAlignment"]);
|
|
ps.WriteLine(" <Optimize>{0}</Optimize>", conf.Options["OptimizeCode"]);
|
|
//ps.WriteLine(" <TieredCompilation>false</TieredCompilation>");
|
|
ps.WriteLine(" <TieredCompilationQuickJit>false</TieredCompilationQuickJit>");
|
|
ps.WriteLine(" <UseCommonOutputDirectory>{0}</UseCommonOutputDirectory>",
|
|
conf.Options["UseCommonOutputDirectory"]);
|
|
ps.WriteLine(" <AppendTargetFrameworkToOutputPath>{0}</AppendTargetFrameworkToOutputPath>",
|
|
conf.Options["AppendTargetFrameworkToOutputPath"]);
|
|
ps.WriteLine(" <AppendRuntimeIdentifierToOutputPath>{0}</AppendRuntimeIdentifierToOutputPath>",
|
|
conf.Options["AppendRuntimeIdentifierToOutputPath"]);
|
|
|
|
if (!listFiles && (bool)conf.Options["EnableDefaultItems"] == false)
|
|
ps.WriteLine(" <EnableDefaultItems>false</EnableDefaultItems>");
|
|
|
|
if (project.Type != ProjectType.Web)
|
|
ps.WriteLine(" <OutputPath>{0}</OutputPath>",
|
|
Helper.EndPath(Helper.NormalizePath(conf.Options["OutputPath"].ToString())));
|
|
else
|
|
ps.WriteLine(" <OutputPath>{0}</OutputPath>",
|
|
Helper.EndPath(Helper.NormalizePath("bin\\")));
|
|
|
|
ps.WriteLine(" <RegisterForComInterop>{0}</RegisterForComInterop>",
|
|
conf.Options["RegisterComInterop"]);
|
|
ps.WriteLine(" <RemoveIntegerChecks>{0}</RemoveIntegerChecks>",
|
|
conf.Options["RemoveIntegerChecks"]);
|
|
ps.WriteLine(" <TreatWarningsAsErrors>{0}</TreatWarningsAsErrors>",
|
|
conf.Options["WarningsAsErrors"]);
|
|
ps.WriteLine(" <WarningLevel>{0}</WarningLevel>", conf.Options["WarningLevel"]);
|
|
ps.WriteLine(" <NoStdLib>{0}</NoStdLib>", conf.Options["NoStdLib"]);
|
|
ps.WriteLine(" <NoWarn>{0}</NoWarn>", conf.Options["SuppressWarnings"]);
|
|
ps.WriteLine(" <PlatformTarget>{0}</PlatformTarget>", conf.Platform);
|
|
|
|
if (conf.Options["PreBuildEvent"] != null && conf.Options["PreBuildEvent"].ToString().Length != 0)
|
|
prebuild = conf.Options["PreBuildEvent"].ToString();
|
|
if (conf.Options["PostBuildEvent"] != null && conf.Options["PostBuildEvent"].ToString().Length != 0)
|
|
postbuild = conf.Options["PostBuildEvent"].ToString();
|
|
|
|
ps.WriteLine(" </PropertyGroup>");
|
|
}
|
|
|
|
if (project.ProjectReferences.Count > 0)
|
|
{
|
|
ps.WriteLine(" <ItemGroup>");
|
|
foreach (var refer in project.ProjectReferences)
|
|
ps.WriteLine(" <ProjectReference Include=\"{0}\" />", refer.Include);
|
|
ps.WriteLine(" </ItemGroup>");
|
|
ps.WriteLine();
|
|
}
|
|
|
|
if (project.PackageReferences.Count > 0)
|
|
{
|
|
ps.WriteLine(" <ItemGroup>");
|
|
foreach (var pack in project.PackageReferences)
|
|
ps.WriteLine(" <PackageReference Include=\"{0}\" Version=\"{1}\" />",
|
|
pack.Name, pack.Version);
|
|
ps.WriteLine(" </ItemGroup>");
|
|
ps.WriteLine();
|
|
}
|
|
|
|
// Output the ItemGroup for project.References
|
|
WriteProjectReferencesDotNet(solution, project, ps);
|
|
|
|
WriteTextGeneratorNodes(project, ps);
|
|
|
|
if (project.Files.Count > 0)
|
|
{
|
|
var list = new List<string>();
|
|
ps.WriteLine(" <ItemGroup>");
|
|
foreach (var filePath in project.Files)
|
|
{
|
|
// Add the filePath with the destination as the key
|
|
// will use it later to form the copy parameters with Include lists
|
|
// for each destination
|
|
if (project.Files.GetBuildAction(filePath) == BuildAction.Copy)
|
|
continue;
|
|
//if (file == "Properties\\Bind.Designer.cs")
|
|
//{
|
|
// Console.WriteLine("Wait a minute!");
|
|
// Console.WriteLine(project.Files.GetSubType(file).ToString());
|
|
//}
|
|
var subType = project.Files.GetSubType(filePath);
|
|
|
|
// Visual Studio chokes on file names if forward slash is used as a path separator
|
|
// instead of backslash. So we must make sure that all file paths written to the
|
|
// project file use \ as a path separator.
|
|
var file = filePath.Replace(@"/", @"\");
|
|
|
|
if (subType != SubType.Code && subType != SubType.Settings && subType != SubType.Designer
|
|
&& subType != SubType.CodeBehind)
|
|
{
|
|
ps.WriteLine(" <EmbeddedResource Include=\"{0}\">",
|
|
file.Substring(0, file.LastIndexOf('.')) + ".resx");
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(file));
|
|
ps.WriteLine(" <SubType>Designer</SubType>");
|
|
ps.WriteLine(" </EmbeddedResource>");
|
|
//
|
|
}
|
|
|
|
if (subType == SubType.Designer)
|
|
{
|
|
ps.WriteLine(" <EmbeddedResource Include=\"{0}\">", file);
|
|
|
|
var autogen_name = file.Substring(0, file.LastIndexOf('.')) + ".Designer.cs";
|
|
var dependent_name = filePath.Substring(0, file.LastIndexOf('.')) + ".cs";
|
|
|
|
// Check for a parent .cs file with the same name as this designer file
|
|
if (File.Exists(Helper.NormalizePath(dependent_name)))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(dependent_name));
|
|
}
|
|
else
|
|
{
|
|
ps.WriteLine(" <Generator>ResXFileCodeGenerator</Generator>");
|
|
ps.WriteLine(" <LastGenOutput>{0}</LastGenOutput>", Path.GetFileName(autogen_name));
|
|
ps.WriteLine(" <SubType>" + subType + "</SubType>");
|
|
}
|
|
|
|
ps.WriteLine(" </EmbeddedResource>");
|
|
if (File.Exists(Helper.NormalizePath(autogen_name)))
|
|
{
|
|
ps.WriteLine(" <Compile Include=\"{0}\">", autogen_name);
|
|
//ps.WriteLine(" <DesignTime>True</DesignTime>");
|
|
|
|
// If a parent .cs file exists, link this autogen file to it. Otherwise link
|
|
// to the designer file
|
|
if (File.Exists(dependent_name))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(dependent_name));
|
|
}
|
|
else
|
|
{
|
|
ps.WriteLine(" <AutoGen>True</AutoGen>");
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(filePath));
|
|
}
|
|
|
|
ps.WriteLine(" </Compile>");
|
|
}
|
|
|
|
list.Add(autogen_name);
|
|
}
|
|
|
|
if (subType == SubType.Settings)
|
|
{
|
|
ps.Write(" <{0} ", project.Files.GetBuildAction(filePath));
|
|
ps.WriteLine("Include=\"{0}\">", file);
|
|
var fileName = Path.GetFileName(filePath);
|
|
if (project.Files.GetBuildAction(filePath) == BuildAction.None)
|
|
{
|
|
ps.WriteLine(" <Generator>SettingsSingleFileGenerator</Generator>");
|
|
ps.WriteLine(" <LastGenOutput>{0}</LastGenOutput>",
|
|
fileName.Substring(0, fileName.LastIndexOf('.')) + ".Designer.cs");
|
|
}
|
|
else
|
|
{
|
|
ps.WriteLine(" <SubType>Code</SubType>");
|
|
ps.WriteLine(" <AutoGen>True</AutoGen>");
|
|
ps.WriteLine(" <DesignTimeSharedInput>True</DesignTimeSharedInput>");
|
|
var fileNameShort = fileName.Substring(0, fileName.LastIndexOf('.'));
|
|
var fileNameShorter = fileNameShort.Substring(0, fileNameShort.LastIndexOf('.'));
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(fileNameShorter + ".settings"));
|
|
}
|
|
|
|
ps.WriteLine(" </{0}>", project.Files.GetBuildAction(filePath));
|
|
}
|
|
else if (subType != SubType.Designer)
|
|
{
|
|
var path = Helper.NormalizePath(file);
|
|
var path_lower = path.ToLower();
|
|
|
|
if (!list.Contains(filePath))
|
|
{
|
|
ps.Write(" <{0} ", project.Files.GetBuildAction(filePath));
|
|
|
|
var startPos = 0;
|
|
if (project.Files.GetPreservePath(filePath))
|
|
while (@"./\".IndexOf(file.Substring(startPos, 1)) != -1)
|
|
startPos++;
|
|
else
|
|
startPos = file.LastIndexOf(Path.GetFileName(path));
|
|
|
|
// be sure to write out the path with backslashes so VS recognizes
|
|
// the file properly.
|
|
ps.WriteLine("Include=\"{0}\">", file);
|
|
|
|
var last_period_index = file.LastIndexOf('.');
|
|
var short_file_name = last_period_index >= 0
|
|
? file.Substring(0, last_period_index)
|
|
: file;
|
|
var extension = Path.GetExtension(path);
|
|
// make this upper case, so that when File.Exists tests for the
|
|
// existence of a designer file on a case-sensitive platform,
|
|
// it is correctly identified.
|
|
var designer_format = string.Format(".Designer{0}", extension);
|
|
|
|
if (path_lower.EndsWith(designer_format.ToLowerInvariant()))
|
|
{
|
|
var designer_index = path.IndexOf(designer_format);
|
|
var file_name = path.Substring(0, designer_index);
|
|
|
|
// There are two corrections to the next lines:
|
|
// 1. Fix the connection between a designer file and a form
|
|
// or usercontrol that don't have an associated resx file.
|
|
// 2. Connect settings files to associated designer files.
|
|
if (File.Exists(file_name + extension))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(file_name + extension));
|
|
}
|
|
else if (File.Exists(file_name + ".resx"))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(file_name + ".resx"));
|
|
}
|
|
else if (File.Exists(file_name + ".settings"))
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(file_name + ".settings"));
|
|
ps.WriteLine(" <AutoGen>True</AutoGen>");
|
|
ps.WriteLine(" <DesignTimeSharedInput>True</DesignTimeSharedInput>");
|
|
}
|
|
}
|
|
else if (subType == SubType.CodeBehind)
|
|
{
|
|
ps.WriteLine(" <DependentUpon>{0}</DependentUpon>",
|
|
Path.GetFileName(short_file_name));
|
|
}
|
|
|
|
if (project.Files.GetIsLink(filePath))
|
|
{
|
|
var alias = project.Files.GetLinkPath(filePath);
|
|
alias += file.Substring(startPos);
|
|
alias = Helper.NormalizePath(alias);
|
|
ps.WriteLine(" <Link>{0}</Link>", alias);
|
|
}
|
|
else if (project.Files.GetBuildAction(filePath) != BuildAction.None)
|
|
{
|
|
if (project.Files.GetBuildAction(filePath) != BuildAction.EmbeddedResource)
|
|
ps.WriteLine(" <SubType>{0}</SubType>", subType);
|
|
}
|
|
|
|
if (project.Files.GetCopyToOutput(filePath) != CopyToOutput.Never)
|
|
ps.WriteLine(" <CopyToOutputDirectory>{0}</CopyToOutputDirectory>",
|
|
project.Files.GetCopyToOutput(filePath));
|
|
|
|
ps.WriteLine(" </{0}>", project.Files.GetBuildAction(filePath));
|
|
}
|
|
}
|
|
}
|
|
|
|
ps.WriteLine(" </ItemGroup>");
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(prebuild))
|
|
{
|
|
ps.WriteLine(" <Target Name=\"PreBuild\" BeforeTargets=\"PreBuildEvent\">");
|
|
ps.WriteLine(" <Exec Command = \"{0}\" />", prebuild);
|
|
ps.WriteLine(" </Target>");
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(postbuild))
|
|
{
|
|
ps.WriteLine(" <Target Name = \"PostBuild\" AfterTargets = \"PostBuildEvent\">");
|
|
ps.WriteLine(" <Exec Command = \"{0}\" />", postbuild);
|
|
ps.WriteLine(" </Target>");
|
|
}
|
|
|
|
ps.WriteLine("</Project>");
|
|
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
private void WriteProjectReferencesDotNet(SolutionNode solution, ProjectNode project, StreamWriter ps)
|
|
{
|
|
var projectReferences = new Dictionary<ReferenceNode, ProjectNode>();
|
|
var otherReferences = new List<ReferenceNode>();
|
|
|
|
foreach (var refr in project.References)
|
|
{
|
|
var projectNode = FindProjectInSolution(refr.Name, solution);
|
|
|
|
if (projectNode == null)
|
|
otherReferences.Add(refr);
|
|
else
|
|
projectReferences.Add(refr, projectNode);
|
|
}
|
|
|
|
// Assembly References
|
|
if (otherReferences.Count > 0)
|
|
{
|
|
ps.WriteLine(" <ItemGroup>");
|
|
|
|
foreach (var refr in otherReferences)
|
|
{
|
|
ps.Write(" <Reference");
|
|
//ps.Write(" Update=\"");
|
|
ps.Write(" Include=\"");
|
|
ps.Write(refr.Name);
|
|
ps.WriteLine("\" >");
|
|
ps.Write(" <Name>");
|
|
ps.Write(refr.Name);
|
|
ps.WriteLine("</Name>");
|
|
|
|
if (!string.IsNullOrEmpty(refr.Path))
|
|
{
|
|
// Use absolute path to assembly (for determining assembly type)
|
|
var absolutePath = Path.Combine(project.FullPath, refr.Path);
|
|
if (File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "exe")))
|
|
{
|
|
// Assembly is an executable (exe)
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>",
|
|
Helper.MakeFilePath(refr.Path, refr.Name, "exe"));
|
|
}
|
|
else if (File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "dll")))
|
|
{
|
|
// Assembly is an library (dll)
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>",
|
|
Helper.MakeFilePath(refr.Path, refr.Name, "dll"));
|
|
}
|
|
else
|
|
{
|
|
var referencePath = Helper.MakeFilePath(refr.Path, refr.Name, "dll");
|
|
kernel.Log.Write(LogType.Warning, "Reference \"{0}\": The specified file doesn't exist.",
|
|
referencePath);
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>",
|
|
Helper.MakeFilePath(refr.Path, refr.Name, "dll"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this may be wrong
|
|
// Use absolute path to assembly (for determining assembly type)
|
|
var absolutePath = Path.Combine(project.FullPath, MakeRefPath(project));
|
|
if (File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "exe")))
|
|
// Assembly is an executable (exe)
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>",
|
|
Helper.MakeFilePath(absolutePath, refr.Name, "exe"));
|
|
else if (File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "dll")))
|
|
// Assembly is an library (dll)
|
|
ps.WriteLine(" <HintPath>{0}</HintPath>",
|
|
Helper.MakeFilePath(absolutePath, refr.Name, "dll"));
|
|
// string referencePath = Helper.MakeFilePath(refr.Path, refr.Name, "dll");
|
|
// kernel.Log.Write(LogType.Warning, "Reference \"{0}\": The specified file doesn't exist.", referencePath);
|
|
// ps.WriteLine(" <HintPath>{0}</HintPath>", Helper.MakeFilePath(absolutePath, refr.Name, "dll"));
|
|
}
|
|
|
|
ps.WriteLine(" <Private>{0}</Private>", refr.LocalCopy);
|
|
ps.WriteLine(" </Reference>");
|
|
}
|
|
|
|
ps.WriteLine(" </ItemGroup>");
|
|
ps.WriteLine();
|
|
}
|
|
|
|
//Project References
|
|
if (projectReferences.Count > 0)
|
|
{
|
|
ps.WriteLine(" <ItemGroup>");
|
|
foreach (var pair in projectReferences)
|
|
{
|
|
var tool = tools[pair.Value.Language];
|
|
if (tools == null)
|
|
throw new UnknownLanguageException();
|
|
|
|
var path =
|
|
Helper.MakePathRelativeTo(project.FullPath,
|
|
Helper.MakeFilePath(pair.Value.FullPath, pair.Value.Name, tool.FileExtension));
|
|
ps.WriteLine(" <ProjectReference Include=\"{0}\" />", path);
|
|
}
|
|
|
|
ps.WriteLine(" </ItemGroup>");
|
|
ps.WriteLine();
|
|
}
|
|
}
|
|
|
|
private void WriteSolution(SolutionNode solution, bool writeSolutionToDisk)
|
|
{
|
|
kernel.Log.Write("Creating {0} solution and project files", VersionName);
|
|
|
|
foreach (var child in solution.Solutions)
|
|
{
|
|
kernel.Log.Write("...Creating folder: {0}", child.Name);
|
|
WriteSolution(child, false);
|
|
}
|
|
|
|
foreach (var project in solution.Projects)
|
|
{
|
|
kernel.Log.Write("...Creating project: {0}", project.Name);
|
|
WriteProject(solution, project);
|
|
}
|
|
|
|
foreach (var project in solution.DatabaseProjects)
|
|
{
|
|
kernel.Log.Write("...Creating database project: {0}", project.Name);
|
|
WriteDatabaseProject(solution, project);
|
|
}
|
|
|
|
if (writeSolutionToDisk) // only write main solution
|
|
{
|
|
kernel.Log.Write("");
|
|
var solutionFile = Helper.MakeFilePath(solution.FullPath, solution.Name, "sln");
|
|
|
|
using (var ss = new StreamWriter(solutionFile))
|
|
{
|
|
kernel.CurrentWorkingDirectory.Push();
|
|
Helper.SetCurrentDir(Path.GetDirectoryName(solutionFile));
|
|
|
|
ss.WriteLine("Microsoft Visual Studio Solution File, Format Version {0}", SolutionVersion);
|
|
ss.WriteLine(SolutionTag);
|
|
|
|
WriteProjectDeclarations(ss, solution, solution);
|
|
|
|
ss.WriteLine("Global");
|
|
|
|
ss.WriteLine("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
|
|
foreach (var conf in solution.Configurations) ss.WriteLine("\t\t{0} = {0}", conf.NameAndPlatform);
|
|
ss.WriteLine("\tEndGlobalSection");
|
|
|
|
ss.WriteLine("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
|
|
WriteConfigurationLines(solution.Configurations, solution, ss);
|
|
ss.WriteLine("\tEndGlobalSection");
|
|
|
|
if (solution.Solutions.Count > 0)
|
|
{
|
|
ss.WriteLine("\tGlobalSection(NestedProjects) = preSolution");
|
|
foreach (var embeddedSolution in solution.Solutions) WriteNestedProjectMap(ss, embeddedSolution);
|
|
ss.WriteLine("\tEndGlobalSection");
|
|
}
|
|
|
|
ss.WriteLine("EndGlobal");
|
|
}
|
|
|
|
kernel.CurrentWorkingDirectory.Pop();
|
|
}
|
|
}
|
|
|
|
private void WriteProjectDeclarations(TextWriter writer, SolutionNode actualSolution, SolutionNode embeddedSolution)
|
|
{
|
|
foreach (var childSolution in embeddedSolution.Solutions)
|
|
{
|
|
WriteEmbeddedSolution(writer, childSolution);
|
|
WriteProjectDeclarations(writer, actualSolution, childSolution);
|
|
}
|
|
|
|
foreach (var project in embeddedSolution.Projects) WriteProject(actualSolution, writer, project);
|
|
|
|
foreach (var dbProject in embeddedSolution.DatabaseProjects) WriteProject(actualSolution, writer, dbProject);
|
|
|
|
if (actualSolution.Guid == embeddedSolution.Guid) WriteSolutionFiles(actualSolution, writer);
|
|
}
|
|
|
|
private static void WriteNestedProjectMap(TextWriter writer, SolutionNode embeddedSolution)
|
|
{
|
|
foreach (var project in embeddedSolution.Projects) WriteNestedProject(writer, embeddedSolution, project.Guid);
|
|
|
|
foreach (var dbProject in embeddedSolution.DatabaseProjects)
|
|
WriteNestedProject(writer, embeddedSolution, dbProject.Guid);
|
|
|
|
foreach (var child in embeddedSolution.Solutions)
|
|
{
|
|
WriteNestedProject(writer, embeddedSolution, child.Guid);
|
|
WriteNestedProjectMap(writer, child);
|
|
}
|
|
}
|
|
|
|
private static void WriteNestedProject(TextWriter writer, SolutionNode solution, Guid projectGuid)
|
|
{
|
|
WriteNestedFolder(writer, solution.Guid, projectGuid);
|
|
}
|
|
|
|
private static void WriteNestedFolder(TextWriter writer, Guid parentGuid, Guid childGuid)
|
|
{
|
|
writer.WriteLine("\t\t{0} = {1}",
|
|
childGuid.ToString("B").ToUpper(),
|
|
parentGuid.ToString("B").ToUpper());
|
|
}
|
|
|
|
private static void WriteConfigurationLines(IEnumerable<ConfigurationNode> configurations, SolutionNode solution,
|
|
TextWriter ss)
|
|
{
|
|
foreach (var project in solution.Projects)
|
|
foreach (var conf in configurations)
|
|
{
|
|
ss.WriteLine("\t\t{0}.{1}.ActiveCfg = {1}",
|
|
project.Guid.ToString("B").ToUpper(),
|
|
conf.NameAndPlatform);
|
|
|
|
ss.WriteLine("\t\t{0}.{1}.Build.0 = {1}",
|
|
project.Guid.ToString("B").ToUpper(),
|
|
conf.NameAndPlatform);
|
|
}
|
|
|
|
foreach (var child in solution.Solutions) WriteConfigurationLines(configurations, child, ss);
|
|
}
|
|
|
|
private void WriteSolutionFiles(SolutionNode solution, TextWriter ss)
|
|
{
|
|
if (solution.Files != null && solution.Files.Count > 0)
|
|
WriteProject(ss, "Folder", solution.Guid, "Solution Files", "Solution Files", solution.Files);
|
|
}
|
|
|
|
private void WriteEmbeddedSolution(TextWriter writer, SolutionNode embeddedSolution)
|
|
{
|
|
WriteProject(writer, "Folder", embeddedSolution.Guid, embeddedSolution.Name, embeddedSolution.Name,
|
|
embeddedSolution.Files);
|
|
}
|
|
|
|
private void WriteProject(SolutionNode solution, TextWriter ss, ProjectNode project)
|
|
{
|
|
WriteProject(ss, solution, project.Language, project.Guid, project.Name, project.FullPath);
|
|
}
|
|
|
|
private void WriteProject(SolutionNode solution, TextWriter ss, DatabaseProjectNode dbProject)
|
|
{
|
|
if (solution.Files != null && solution.Files.Count > 0)
|
|
WriteProject(ss, solution, "Database", dbProject.Guid, dbProject.Name, dbProject.FullPath);
|
|
}
|
|
|
|
private const string ProjectDeclarationBeginFormat = "Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"";
|
|
private const string ProjectDeclarationEndFormat = "EndProject";
|
|
|
|
private void WriteProject(TextWriter ss, SolutionNode solution, string language, Guid guid, string name,
|
|
string projectFullPath)
|
|
{
|
|
if (!tools.ContainsKey(language))
|
|
throw new UnknownLanguageException("Unknown .NET language: " + language);
|
|
|
|
var toolInfo = tools[language];
|
|
|
|
var path = Helper.MakePathRelativeTo(solution.FullPath, projectFullPath);
|
|
|
|
path = Helper.MakeFilePath(path, name, toolInfo.FileExtension);
|
|
|
|
WriteProject(ss, language, guid, name, path);
|
|
}
|
|
|
|
private void WriteProject(TextWriter writer, string language, Guid projectGuid, string name, string location)
|
|
{
|
|
WriteProject(writer, language, projectGuid, name, location, null);
|
|
}
|
|
|
|
private void WriteProject(TextWriter writer, string language, Guid projectGuid, string name, string location,
|
|
FilesNode files)
|
|
{
|
|
if (!tools.ContainsKey(language))
|
|
throw new UnknownLanguageException("Unknown .NET language: " + language);
|
|
|
|
var toolInfo = tools[language];
|
|
|
|
writer.WriteLine(ProjectDeclarationBeginFormat,
|
|
toolInfo.Guid,
|
|
name,
|
|
location,
|
|
projectGuid.ToString("B").ToUpper());
|
|
|
|
if (files != null)
|
|
{
|
|
writer.WriteLine("\tProjectSection(SolutionItems) = preProject");
|
|
|
|
foreach (var file in files)
|
|
writer.WriteLine("\t\t{0} = {0}", file);
|
|
|
|
writer.WriteLine("\tEndProjectSection");
|
|
}
|
|
|
|
writer.WriteLine(ProjectDeclarationEndFormat);
|
|
}
|
|
|
|
private void WriteDatabaseProject(SolutionNode solution, DatabaseProjectNode project)
|
|
{
|
|
var projectFile = Helper.MakeFilePath(project.FullPath, project.Name, "dbp");
|
|
var ps = new IndentedTextWriter(new StreamWriter(projectFile), " ");
|
|
|
|
kernel.CurrentWorkingDirectory.Push();
|
|
|
|
Helper.SetCurrentDir(Path.GetDirectoryName(projectFile));
|
|
|
|
using (ps)
|
|
{
|
|
ps.WriteLine("# Microsoft Developer Studio Project File - Database Project");
|
|
ps.WriteLine("Begin DataProject = \"{0}\"", project.Name);
|
|
ps.Indent++;
|
|
ps.WriteLine("MSDTVersion = \"80\"");
|
|
// TODO: Use the project.Files property
|
|
if (ContainsSqlFiles(Path.GetDirectoryName(projectFile)))
|
|
WriteDatabaseFoldersAndFiles(ps, Path.GetDirectoryName(projectFile));
|
|
|
|
ps.WriteLine("Begin DBRefFolder = \"Database References\"");
|
|
ps.Indent++;
|
|
foreach (var reference in project.References)
|
|
{
|
|
ps.WriteLine("Begin DBRefNode = \"{0}\"", reference.Name);
|
|
ps.Indent++;
|
|
ps.WriteLine("ConnectStr = \"{0}\"", reference.ConnectionString);
|
|
ps.WriteLine("Provider = \"{0}\"", reference.ProviderId.ToString("B").ToUpper());
|
|
//ps.WriteLine("Colorizer = 5");
|
|
ps.Indent--;
|
|
ps.WriteLine("End");
|
|
}
|
|
|
|
ps.Indent--;
|
|
ps.WriteLine("End");
|
|
ps.Indent--;
|
|
ps.WriteLine("End");
|
|
|
|
ps.Flush();
|
|
}
|
|
|
|
kernel.CurrentWorkingDirectory.Pop();
|
|
}
|
|
|
|
private static bool ContainsSqlFiles(string folder)
|
|
{
|
|
if (Directory.GetFiles(folder, "*.sql").Length > 0)
|
|
return true; // if the folder contains 1 .sql file, that's good enough
|
|
|
|
foreach (var child in Directory.GetDirectories(folder))
|
|
if (ContainsSqlFiles(child))
|
|
return true; // if 1 child folder contains a .sql file, still good enough
|
|
|
|
return false;
|
|
}
|
|
|
|
private static void WriteDatabaseFoldersAndFiles(IndentedTextWriter writer, string folder)
|
|
{
|
|
foreach (var child in Directory.GetDirectories(folder))
|
|
if (ContainsSqlFiles(child))
|
|
{
|
|
writer.WriteLine("Begin Folder = \"{0}\"", Path.GetFileName(child));
|
|
writer.Indent++;
|
|
WriteDatabaseFoldersAndFiles(writer, child);
|
|
writer.Indent--;
|
|
writer.WriteLine("End");
|
|
}
|
|
|
|
foreach (var file in Directory.GetFiles(folder, "*.sql"))
|
|
writer.WriteLine("Script = \"{0}\"", Path.GetFileName(file));
|
|
}
|
|
|
|
private void CleanProject(ProjectNode project)
|
|
{
|
|
kernel.Log.Write("...Cleaning project: {0}", project.Name);
|
|
|
|
var toolInfo = tools[project.Language];
|
|
var projectFile = Helper.MakeFilePath(project.FullPath, project.Name, toolInfo.FileExtension);
|
|
var userFile = projectFile + ".user";
|
|
|
|
Helper.DeleteIfExists(projectFile);
|
|
Helper.DeleteIfExists(userFile);
|
|
|
|
var projectobj = Helper.MakeFilePath(project.FullPath, "obj");
|
|
Helper.DeleteFolderIfExists(projectobj);
|
|
}
|
|
|
|
private void CleanSolution(SolutionNode solution)
|
|
{
|
|
kernel.Log.Write("Cleaning {0} solution and project files", VersionName, solution.Name);
|
|
|
|
var slnFile = Helper.MakeFilePath(solution.FullPath, solution.Name, "sln");
|
|
var suoFile = Helper.MakeFilePath(solution.FullPath, solution.Name, "suo");
|
|
|
|
Helper.DeleteIfExists(slnFile);
|
|
Helper.DeleteIfExists(suoFile);
|
|
|
|
foreach (var project in solution.Projects) CleanProject(project);
|
|
|
|
kernel.Log.Write("");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ITarget Members
|
|
|
|
/// <summary>
|
|
/// Writes the specified kern.
|
|
/// </summary>
|
|
/// <param name="kern">The kern.</param>
|
|
public virtual void Write(Kernel kern)
|
|
{
|
|
if (kern == null) throw new ArgumentNullException("kern");
|
|
kernel = kern;
|
|
foreach (var sol in kernel.Solutions) WriteSolution(sol, true);
|
|
kernel = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cleans the specified kern.
|
|
/// </summary>
|
|
/// <param name="kern">The kern.</param>
|
|
public virtual void Clean(Kernel kern)
|
|
{
|
|
if (kern == null) throw new ArgumentNullException("kern");
|
|
kernel = kern;
|
|
foreach (var sol in kernel.Solutions) CleanSolution(sol);
|
|
kernel = null;
|
|
}
|
|
|
|
#endregion
|
|
} |