diff options
author | Andreas Haas <Hinsbart@users.noreply.github.com> | 2017-10-03 00:13:40 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-03 00:13:40 +0200 |
commit | b0194a33f65970948ef66819913bf3034a3a22e8 (patch) | |
tree | 35e21b53b10bbd525506bb5b72b7f89214e1234f /modules/mono/editor/GodotSharpTools | |
parent | 5cd68abf8896fd86a33c048d6fece61c3cd3f8e5 (diff) | |
parent | d5caf71c3fcdeb422d1b0ea97a836fcdb57a8713 (diff) |
Merge pull request #11739 from neikeq/tengo-el-mono
Moved mono module here
Diffstat (limited to 'modules/mono/editor/GodotSharpTools')
10 files changed, 830 insertions, 0 deletions
diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs new file mode 100644 index 0000000000..256e64ddde --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Security; +using Microsoft.Build.Framework; + +namespace GodotSharpTools.Build +{ + public class BuildInstance : IDisposable + { + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static string godot_icall_BuildInstance_get_MSBuildPath(); + + private static string MSBuildPath + { + get { return godot_icall_BuildInstance_get_MSBuildPath(); } + } + + private string solution; + private string config; + + private Process process; + + private int exitCode; + public int ExitCode { get { return exitCode; } } + + public bool IsRunning { get { return process != null && !process.HasExited; } } + + public BuildInstance(string solution, string config) + { + this.solution = solution; + this.config = config; + } + + public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null) + { + string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties); + + ProcessStartInfo startInfo = new ProcessStartInfo(MSBuildPath, compilerArgs); + + // No console output, thanks + startInfo.RedirectStandardOutput = true; + startInfo.RedirectStandardError = true; + startInfo.UseShellExecute = false; + + // Needed when running from Developer Command Prompt for VS + RemovePlatformVariable(startInfo.EnvironmentVariables); + + using (Process process = new Process()) + { + process.StartInfo = startInfo; + + process.Start(); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + process.WaitForExit(); + + exitCode = process.ExitCode; + } + + return true; + } + + public bool BuildAsync(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null) + { + if (process != null) + throw new InvalidOperationException("Already in use"); + + string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties); + + ProcessStartInfo startInfo = new ProcessStartInfo("msbuild", compilerArgs); + + // No console output, thanks + startInfo.RedirectStandardOutput = true; + startInfo.RedirectStandardError = true; + startInfo.UseShellExecute = false; + + // Needed when running from Developer Command Prompt for VS + RemovePlatformVariable(startInfo.EnvironmentVariables); + + process = new Process(); + process.StartInfo = startInfo; + process.EnableRaisingEvents = true; + process.Exited += new EventHandler(BuildProcess_Exited); + + process.Start(); + + return true; + } + + private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties) + { + string arguments = string.Format("{0} /v:normal /t:Build /p:{1} /l:{2},{3};{4}", + solution, + "Configuration=" + config, + typeof(GodotBuildLogger).FullName, + loggerAssemblyPath, + loggerOutputDir + ); + + if (customProperties != null) + { + foreach (string customProperty in customProperties) + { + arguments += " /p:" + customProperty; + } + } + + return arguments; + } + + private void RemovePlatformVariable(StringDictionary environmentVariables) + { + // EnvironmentVariables is case sensitive? Seriously? + + List<string> platformEnvironmentVariables = new List<string>(); + + foreach (string env in environmentVariables.Keys) + { + if (env.ToUpper() == "PLATFORM") + platformEnvironmentVariables.Add(env); + } + + foreach (string env in platformEnvironmentVariables) + environmentVariables.Remove(env); + } + + private void BuildProcess_Exited(object sender, System.EventArgs e) + { + exitCode = process.ExitCode; + + godot_icall_BuildInstance_ExitCallback(solution, config, exitCode); + + Dispose(); + } + + public void Dispose() + { + if (process != null) + { + process.Dispose(); + process = null; + } + } + } + + public class GodotBuildLogger : ILogger + { + public string Parameters { get; set; } + public LoggerVerbosity Verbosity { get; set; } + + public void Initialize(IEventSource eventSource) + { + if (null == Parameters) + throw new LoggerException("Log directory was not set."); + + string[] parameters = Parameters.Split(';'); + + string logDir = parameters[0]; + + if (String.IsNullOrEmpty(logDir)) + throw new LoggerException("Log directory was not set."); + + if (parameters.Length > 1) + throw new LoggerException("Too many parameters passed."); + + string logFile = Path.Combine(logDir, "msbuild_log.txt"); + string issuesFile = Path.Combine(logDir, "msbuild_issues.csv"); + + try + { + if (!Directory.Exists(logDir)) + Directory.CreateDirectory(logDir); + + this.logStreamWriter = new StreamWriter(logFile); + this.issuesStreamWriter = new StreamWriter(issuesFile); + } + catch (Exception ex) + { + if + ( + ex is UnauthorizedAccessException + || ex is ArgumentNullException + || ex is PathTooLongException + || ex is DirectoryNotFoundException + || ex is NotSupportedException + || ex is ArgumentException + || ex is SecurityException + || ex is IOException + ) + { + throw new LoggerException("Failed to create log file: " + ex.Message); + } + else + { + // Unexpected failure + throw; + } + } + + eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted); + eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted); + eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised); + eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised); + eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised); + eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished); + } + + void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e) + { + string line = String.Format("{0}({1},{2}): error {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message); + + if (e.ProjectFile.Length > 0) + line += string.Format(" [{0}]", e.ProjectFile); + + WriteLine(line); + + string errorLine = String.Format(@"error,{0},{1},{2},{3},{4},{5}", + e.File.CsvEscape(), e.LineNumber, e.ColumnNumber, + e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile.CsvEscape()); + issuesStreamWriter.WriteLine(errorLine); + } + + void eventSource_WarningRaised(object sender, BuildWarningEventArgs e) + { + string line = String.Format("{0}({1},{2}): warning {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, e.ProjectFile); + + if (e.ProjectFile != null && e.ProjectFile.Length > 0) + line += string.Format(" [{0}]", e.ProjectFile); + + WriteLine(line); + + string warningLine = String.Format(@"warning,{0},{1},{2},{3},{4},{5}", + e.File.CsvEscape(), e.LineNumber, e.ColumnNumber, + e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile != null ? e.ProjectFile.CsvEscape() : string.Empty); + issuesStreamWriter.WriteLine(warningLine); + } + + void eventSource_MessageRaised(object sender, BuildMessageEventArgs e) + { + // BuildMessageEventArgs adds Importance to BuildEventArgs + // Let's take account of the verbosity setting we've been passed in deciding whether to log the message + if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal)) + || (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal)) + || (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed)) + ) + { + WriteLineWithSenderAndMessage(String.Empty, e); + } + } + + void eventSource_TaskStarted(object sender, TaskStartedEventArgs e) + { + // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName + // To keep this log clean, this logger will ignore these events. + } + + void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e) + { + WriteLine(e.Message); + indent++; + } + + void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e) + { + indent--; + WriteLine(e.Message); + } + + /// <summary> + /// Write a line to the log, adding the SenderName + /// </summary> + private void WriteLineWithSender(string line, BuildEventArgs e) + { + if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/)) + { + // Well, if the sender name is MSBuild, let's leave it out for prettiness + WriteLine(line); + } + else + { + WriteLine(e.SenderName + ": " + line); + } + } + + /// <summary> + /// Write a line to the log, adding the SenderName and Message + /// (these parameters are on all MSBuild event argument objects) + /// </summary> + private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e) + { + if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/)) + { + // Well, if the sender name is MSBuild, let's leave it out for prettiness + WriteLine(line + e.Message); + } + else + { + WriteLine(e.SenderName + ": " + line + e.Message); + } + } + + private void WriteLine(string line) + { + for (int i = indent; i > 0; i--) + { + logStreamWriter.Write("\t"); + } + logStreamWriter.WriteLine(line); + } + + public void Shutdown() + { + logStreamWriter.Close(); + issuesStreamWriter.Close(); + } + + public bool IsVerbosityAtLeast(LoggerVerbosity checkVerbosity) + { + return this.Verbosity >= checkVerbosity; + } + + private StreamWriter logStreamWriter; + private StreamWriter issuesStreamWriter; + private int indent; + } +} diff --git a/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs b/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs new file mode 100644 index 0000000000..303be3b732 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Diagnostics; + +namespace GodotSharpTools.Editor +{ + public class MonoDevelopInstance + { + private Process process; + private string solutionFile; + + public void Execute(string[] files) + { + bool newWindow = process == null || process.HasExited; + + List<string> args = new List<string>(); + + args.Add("--ipc-tcp"); + + if (newWindow) + args.Add("\"" + Path.GetFullPath(solutionFile) + "\""); + + foreach (var file in files) + { + int semicolonIndex = file.IndexOf(';'); + + string filePath = semicolonIndex < 0 ? file : file.Substring(0, semicolonIndex); + string cursor = semicolonIndex < 0 ? string.Empty : file.Substring(semicolonIndex); + + args.Add("\"" + Path.GetFullPath(filePath.NormalizePath()) + cursor + "\""); + } + + if (newWindow) + { + ProcessStartInfo startInfo = new ProcessStartInfo(MonoDevelopFile, string.Join(" ", args)); + process = Process.Start(startInfo); + } + else + { + Process.Start(MonoDevelopFile, string.Join(" ", args)); + } + } + + public MonoDevelopInstance(string solutionFile) + { + this.solutionFile = solutionFile; + } + + private static string MonoDevelopFile + { + get + { + return "monodevelop"; + } + } + } +} diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj new file mode 100644 index 0000000000..981083a3c2 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>GodotSharpTools</RootNamespace> + <AssemblyName>GodotSharpTools</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>full</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="Microsoft.Build" /> + <Reference Include="Microsoft.Build.Framework" /> + </ItemGroup> + <ItemGroup> + <Compile Include="StringExtensions.cs" /> + <Compile Include="Build\BuildSystem.cs" /> + <Compile Include="Editor\MonoDevelopInstance.cs" /> + <Compile Include="Project\ProjectExtensions.cs" /> + <Compile Include="Project\ProjectGenerator.cs" /> + <Compile Include="Project\ProjectUtils.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln b/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln new file mode 100644 index 0000000000..7eabcdff5d --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln @@ -0,0 +1,17 @@ +
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpTools", "GodotSharpTools.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs b/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs new file mode 100644 index 0000000000..0cbafdc20d --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs @@ -0,0 +1,14 @@ +<Properties StartupItem="GodotSharpTools.csproj"> + <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" /> + <MonoDevelop.Ide.Workbench ActiveDocument="Build/BuildSystem.cs"> + <Files> + <File FileName="Build/ProjectExtensions.cs" Line="1" Column="1" /> + <File FileName="Build/ProjectGenerator.cs" Line="1" Column="1" /> + <File FileName="Build/BuildSystem.cs" Line="37" Column="14" /> + </Files> + </MonoDevelop.Ide.Workbench> + <MonoDevelop.Ide.DebuggingService.Breakpoints> + <BreakpointStore /> + </MonoDevelop.Ide.DebuggingService.Breakpoints> + <MonoDevelop.Ide.DebuggingService.PinnedWatches /> +</Properties>
\ No newline at end of file diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs new file mode 100644 index 0000000000..6a97731539 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.Build.Construction; + +namespace GodotSharpTools.Project +{ + public static class ProjectExtensions + { + public static bool HasItem(this ProjectRootElement root, string itemType, string include) + { + string includeNormalized = include.NormalizePath(); + + foreach (var itemGroup in root.ItemGroups) + { + if (itemGroup.Condition.Length != 0) + continue; + + foreach (var item in itemGroup.Items) + { + if (item.ItemType == itemType) + { + if (item.Include.NormalizePath() == includeNormalized) + return true; + } + } + } + + return false; + } + + public static void AddItemChecked(this ProjectRootElement root, string itemType, string include) + { + if (!root.HasItem(itemType, include)) + { + root.AddItem(itemType, include); + } + } + + public static Guid GetGuid(this ProjectRootElement root) + { + foreach (var property in root.Properties) + { + if (property.Name == "ProjectGuid") + return Guid.Parse(property.Value); + } + + return Guid.Empty; + } + } +} diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs new file mode 100644 index 0000000000..6bf54a0156 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs @@ -0,0 +1,216 @@ +using System; +using System.IO; +using Microsoft.Build.Construction; + +namespace GodotSharpTools.Project +{ + public static class ProjectGenerator + { + public static string GenCoreApiProject(string dir, string[] compileItems) + { + string path = Path.Combine(dir, CoreApiProject + ".csproj"); + + ProjectPropertyGroupElement mainGroup; + var root = CreateLibraryProject(CoreApiProject, out mainGroup); + + mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml")); + mainGroup.SetProperty("RootNamespace", "Godot"); + + GenAssemblyInfoFile(root, dir, CoreApiProject, + new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProject + "\")]" }, + new string[] { "System.Runtime.CompilerServices" }); + + foreach (var item in compileItems) + { + root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\")); + } + + root.Save(path); + + return root.GetGuid().ToString().ToUpper(); + } + + public static string GenEditorApiProject(string dir, string coreApiHintPath, string[] compileItems) + { + string path = Path.Combine(dir, EditorApiProject + ".csproj"); + + ProjectPropertyGroupElement mainGroup; + var root = CreateLibraryProject(EditorApiProject, out mainGroup); + + mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml")); + mainGroup.SetProperty("RootNamespace", "Godot"); + + GenAssemblyInfoFile(root, dir, EditorApiProject); + + foreach (var item in compileItems) + { + root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\")); + } + + var coreApiRef = root.AddItem("Reference", CoreApiProject); + coreApiRef.AddMetadata("HintPath", coreApiHintPath); + coreApiRef.AddMetadata("Private", "False"); + + root.Save(path); + + return root.GetGuid().ToString().ToUpper(); + } + + public static string GenGameProject(string dir, string name, string[] compileItems) + { + string path = Path.Combine(dir, name + ".csproj"); + + ProjectPropertyGroupElement mainGroup; + var root = CreateLibraryProject(name, out mainGroup); + + mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)")); + mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj")); + mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)")); + + var toolsGroup = root.AddPropertyGroup(); + toolsGroup.Condition = " '$(Configuration)|$(Platform)' == 'Tools|AnyCPU' "; + toolsGroup.AddProperty("DebugSymbols", "true"); + toolsGroup.AddProperty("DebugType", "full"); + toolsGroup.AddProperty("Optimize", "false"); + toolsGroup.AddProperty("DefineConstants", "DEBUG;TOOLS;"); + toolsGroup.AddProperty("ErrorReport", "prompt"); + toolsGroup.AddProperty("WarningLevel", "4"); + toolsGroup.AddProperty("ConsolePause", "false"); + + var coreApiRef = root.AddItem("Reference", CoreApiProject); + coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProject + ".dll")); + coreApiRef.AddMetadata("Private", "False"); + + var editorApiRef = root.AddItem("Reference", EditorApiProject); + editorApiRef.Condition = " '$(Configuration)' == 'Tools' "; + editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProject + ".dll")); + editorApiRef.AddMetadata("Private", "False"); + + GenAssemblyInfoFile(root, dir, name); + + foreach (var item in compileItems) + { + root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\")); + } + + root.Save(path); + + return root.GetGuid().ToString().ToUpper(); + } + + public static void GenAssemblyInfoFile(ProjectRootElement root, string dir, string name, string[] assemblyLines = null, string[] usingDirectives = null) + { + + string propertiesDir = Path.Combine(dir, "Properties"); + if (!Directory.Exists(propertiesDir)) + Directory.CreateDirectory(propertiesDir); + + string usingDirectivesText = string.Empty; + + if (usingDirectives != null) + { + foreach (var usingDirective in usingDirectives) + usingDirectivesText += "\nusing " + usingDirective + ";"; + } + + string assemblyLinesText = string.Empty; + + if (assemblyLines != null) + { + foreach (var assemblyLine in assemblyLines) + assemblyLinesText += string.Join("\n", assemblyLines) + "\n"; + } + + string content = string.Format(assemblyInfoTemplate, usingDirectivesText, name, assemblyLinesText); + + string assemblyInfoFile = Path.Combine(propertiesDir, "AssemblyInfo.cs"); + + File.WriteAllText(assemblyInfoFile, content); + + root.AddItem("Compile", assemblyInfoFile.RelativeToPath(dir).Replace("/", "\\")); + } + + public static ProjectRootElement CreateLibraryProject(string name, out ProjectPropertyGroupElement mainGroup) + { + var root = ProjectRootElement.Create(); + root.DefaultTargets = "Build"; + + mainGroup = root.AddPropertyGroup(); + mainGroup.AddProperty("Configuration", "Debug").Condition = " '$(Configuration)' == '' "; + mainGroup.AddProperty("Platform", "AnyCPU").Condition = " '$(Platform)' == '' "; + mainGroup.AddProperty("ProjectGuid", "{" + Guid.NewGuid().ToString().ToUpper() + "}"); + mainGroup.AddProperty("OutputType", "Library"); + mainGroup.AddProperty("OutputPath", Path.Combine("bin", "$(Configuration)")); + mainGroup.AddProperty("RootNamespace", name); + mainGroup.AddProperty("AssemblyName", name); + mainGroup.AddProperty("TargetFrameworkVersion", "v4.5"); + + var debugGroup = root.AddPropertyGroup(); + debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "; + debugGroup.AddProperty("DebugSymbols", "true"); + debugGroup.AddProperty("DebugType", "full"); + debugGroup.AddProperty("Optimize", "false"); + debugGroup.AddProperty("DefineConstants", "DEBUG;"); + debugGroup.AddProperty("ErrorReport", "prompt"); + debugGroup.AddProperty("WarningLevel", "4"); + debugGroup.AddProperty("ConsolePause", "false"); + + var releaseGroup = root.AddPropertyGroup(); + releaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "; + releaseGroup.AddProperty("DebugType", "full"); + releaseGroup.AddProperty("Optimize", "true"); + releaseGroup.AddProperty("ErrorReport", "prompt"); + releaseGroup.AddProperty("WarningLevel", "4"); + releaseGroup.AddProperty("ConsolePause", "false"); + + // References + var referenceGroup = root.AddItemGroup(); + referenceGroup.AddItem("Reference", "System"); + + root.AddImport(Path.Combine("$(MSBuildBinPath)", "Microsoft.CSharp.targets").Replace("/", "\\")); + + return root; + } + + private static void AddItems(ProjectRootElement elem, string groupName, params string[] items) + { + var group = elem.AddItemGroup(); + + foreach (var item in items) + { + group.AddItem(groupName, item); + } + } + + public const string CoreApiProject = "GodotSharp"; + public const string EditorApiProject = "GodotSharpEditor"; + + private const string assemblyInfoTemplate = +@"using System.Reflection;{0} + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle(""{1}"")] +[assembly: AssemblyDescription("""")] +[assembly: AssemblyConfiguration("""")] +[assembly: AssemblyCompany("""")] +[assembly: AssemblyProduct("""")] +[assembly: AssemblyCopyright("""")] +[assembly: AssemblyTrademark("""")] +[assembly: AssemblyCulture("""")] + +// The assembly version has the format ""{{Major}}.{{Minor}}.{{Build}}.{{Revision}}"". +// The form ""{{Major}}.{{Minor}}.*"" will automatically update the build and revision, +// and ""{{Major}}.{{Minor}}.{{Build}}.*"" will update just the revision. + +[assembly: AssemblyVersion(""1.0.*"")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("""")] +{2}"; + } +} diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs new file mode 100644 index 0000000000..a50b4fb064 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; +using Microsoft.Build.Construction; + +namespace GodotSharpTools.Project +{ + public static class ProjectUtils + { + public static void AddItemToProjectChecked(string projectPath, string itemType, string include) + { + var dir = Directory.GetParent(projectPath).FullName; + var root = ProjectRootElement.Open(projectPath); + root.AddItemChecked(itemType, include.RelativeToPath(dir).Replace("/", "\\")); + root.Save(); + } + } +} diff --git a/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..7115d8fc71 --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("GodotSharpTools")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("ignacio")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/modules/mono/editor/GodotSharpTools/StringExtensions.cs b/modules/mono/editor/GodotSharpTools/StringExtensions.cs new file mode 100644 index 0000000000..b66c86f8ce --- /dev/null +++ b/modules/mono/editor/GodotSharpTools/StringExtensions.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; + +namespace GodotSharpTools +{ + public static class StringExtensions + { + public static string RelativeToPath(this string path, string dir) + { + // Make sure the directory ends with a path separator + dir = Path.Combine(dir, " ").TrimEnd(); + + if (Path.DirectorySeparatorChar == '\\') + dir = dir.Replace("/", "\\") + "\\"; + + Uri fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute); + Uri relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute); + + return relRoot.MakeRelativeUri(fullPath).ToString(); + } + + public static string NormalizePath(this string path) + { + bool rooted = path.IsAbsolutePath(); + + path = path.Replace('\\', '/'); + + string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + + path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim(); + + return rooted ? Path.DirectorySeparatorChar.ToString() + path : path; + } + + private static readonly string driveRoot = Path.GetPathRoot(Environment.CurrentDirectory); + + public static bool IsAbsolutePath(this string path) + { + return path.StartsWith("/") || path.StartsWith("\\") || path.StartsWith(driveRoot); + } + + public static string CsvEscape(this string value, char delimiter = ',') + { + bool hasSpecialChar = value.IndexOfAny(new char[] { '\"', '\n', '\r', delimiter }) != -1; + + if (hasSpecialChar) + return "\"" + value.Replace("\"", "\"\"") + "\""; + + return value; + } + } +} |