From 09abcce174f8dc4e612f5cd98b07dffced5b38cd Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bruyère Date: Mon, 6 May 2019 00:37:48 +0200 Subject: wip --- Samples/CrowIDE/src/Project.cs | 519 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 519 insertions(+) create mode 100644 Samples/CrowIDE/src/Project.cs (limited to 'Samples/CrowIDE/src/Project.cs') diff --git a/Samples/CrowIDE/src/Project.cs b/Samples/CrowIDE/src/Project.cs new file mode 100644 index 00000000..a3ffa636 --- /dev/null +++ b/Samples/CrowIDE/src/Project.cs @@ -0,0 +1,519 @@ +// +// Project.cs +// +// Author: +// jp <> +// +// Copyright (c) 2013-2017 Jean-Philippe Bruyère +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Xml; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CSharp; +using System.CodeDom.Compiler; +using Crow; +using System.Text.RegularExpressions; + +namespace Crow.Coding { + public class Project : IValueChange { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged (string MemberName, object _value) { + ValueChanged.Raise (this, new ValueChangeEventArgs (MemberName, _value)); + } + #endregion + + bool isLoaded = false; + bool isExpanded; + XmlDocument xmlDoc; + XmlNode nodeProject; + XmlNode nodeProps; + XmlNodeList nodesItems; + SolutionProject solutionProject; + Crow.Command cmdSave, cmdOpen, cmdCompile, cmdSetAsStartProj, cmdNewFile; + + #region CTOR + public Project (Solution sol, SolutionProject sp) { + solutionProject = sp; + + solution = sol; + + cmdSave = new Crow.Command (new Action (() => Save ())) { Caption = "Save", Icon = new SvgPicture ("#CrowIDE.icons.save.svg"), CanExecute = true }; + cmdOpen = new Crow.Command (new Action (() => Load ())) { Caption = "Open", Icon = new SvgPicture ("#CrowIDE.icons.open.svg"), CanExecute = false }; + cmdCompile = new Crow.Command (new Action (() => Compile ())) { + Caption = "Compile", + Icon = "#CrowIDE.icons.compile.svg" + }; + cmdSetAsStartProj = new Crow.Command (new Action (() => setAsStartupProject ())) { + Caption = "Set as Startup Project" + }; + cmdNewFile = new Crow.Command (new Action (() => AddNewFile ())) { + Caption = "Add New File", + Icon = new SvgPicture ("#CrowIDE.icons.blank-file.svg"), + CanExecute = true + }; + + Commands = new List (new Crow.Command[] { cmdOpen, cmdSave, cmdSetAsStartProj, cmdCompile, cmdNewFile }); + + Load (); + } + #endregion + + public Solution solution; + public List Commands; + public CompilerResults CompilationResults; + public List dependantProjects = new List (); + public Project ParentProject = null; + List rootItems; + List flattenNodes; + + public string Name { + get { return solutionProject.ProjectName; } + } + public bool IsLoaded { + get { return isLoaded; } + set { + if (isLoaded == value) + return; + isLoaded = value; + NotifyValueChanged ("IsLoaded", isLoaded); + } + } + public bool IsExpanded { + get { return isExpanded; } + set { + if (value == isExpanded) + return; + isExpanded = value; + NotifyValueChanged ("IsExpanded", isExpanded); + } + } + public bool IsStartupProject { + get { return solution.StartupProject == this; } + } + public string Path { + get { return System.IO.Path.Combine (solution.SolutionFolder, solutionProject.RelativePath.Replace ('\\', '/')); } + } + public string RootDir { + get { return System.IO.Path.GetDirectoryName (Path); } + } + + + + public List RootItems { + get { return rootItems; } + } + + void buildTreeNodes () { + ProjectNode root = new ProjectNode (this, ItemType.VirtualGroup, RootNamespace); + List items = new List (); + foreach (XmlNode i in nodesItems) { + foreach (XmlNode f in i.ChildNodes) { + items.Add (new ProjectItem (this, f)); + } + } + + flattenNodes = new List (); + + ProjectNode refs = new ProjectNode (this, ItemType.ReferenceGroup, "References"); + root.AddChild (refs); + + foreach (ProjectItem pn in items) { + switch (pn.Type) { + case ItemType.Reference: + refs.AddChild (pn); + flattenNodes.Add (pn); + break; + case ItemType.ProjectReference: + ProjectReference pr = new ProjectReference (pn); + refs.AddChild (pr); + flattenNodes.Add (pr); + break; + case ItemType.Compile: + case ItemType.None: + case ItemType.EmbeddedResource: + ProjectNode curNode = root; + string[] folds = pn.Path.Split ('/'); + for (int i = 0; i < folds.Length - 1; i++) { + ProjectNode nextNode = curNode.ChildNodes.FirstOrDefault (n => n.DisplayName == folds[i] && n.Type == ItemType.VirtualGroup); + if (nextNode == null) { + nextNode = new ProjectNode (this, ItemType.VirtualGroup, folds[i]); + curNode.AddChild (nextNode); + } + curNode = nextNode; + } + ProjectNode f = null; + switch (pn.Extension) { + /*case ".cs": + f = new CSProjectFile (pn); + break;*/ + case ".crow": + case ".template": + case ".goml": + case ".itemp": + case ".imtl": + f = new ImlProjectItem (pn); + break; + case ".style": + f = new StyleProjectItem (pn); + break; + default: + f = new ProjectFile (pn); + break; + } + curNode.AddChild (f); + flattenNodes.Add (f); + break; + } + } + root.SortChilds (); + + rootItems = root.ChildNodes; + } + + #region Project properties + public string ToolsVersion { + get { return nodeProject?.Attributes["ToolsVersion"]?.Value; } + } + public string DefaultTargets { + get { return nodeProject?.Attributes["DefaultTargets"]?.Value; } + } + public string ProjectGuid { + get { return solutionProject.ProjectGuid; } + } + public string AssemblyName { + get { return nodeProps["AssemblyName"]?.InnerText; } + } + public string OutputType { + get { return nodeProps["OutputType"]?.InnerText; } + } + public string RootNamespace { + get { return nodeProps["RootNamespace"]?.InnerText; } + } + public bool AllowUnsafeBlocks { + get { + return nodeProps["AllowUnsafeBlocks"] == null ? false : + bool.Parse (nodeProps["AllowUnsafeBlocks"]?.InnerText); + } + } + public bool NoStdLib { + get { + return nodeProps["NoStdLib"] == null ? false : + bool.Parse (nodeProps["NoStdLib"]?.InnerText); + } + } + public bool TreatWarningsAsErrors { + get { + return nodeProps["TreatWarningsAsErrors"] == null ? false : + bool.Parse (nodeProps["TreatWarningsAsErrors"]?.InnerText); + } + } + public bool SignAssembly { + get { return bool.Parse (nodeProps["SignAssembly"]?.InnerText); } + } + public string TargetFrameworkVersion { + get { return nodeProps["TargetFrameworkVersion"]?.InnerText; } + } + public string Description { + get { return nodeProps["Description"]?.InnerText; } + } + public string OutputPath { + get { return nodeProps["OutputPath"]?.InnerText; } + } + public string IntermediateOutputPath { + get { return nodeProps["IntermediateOutputPath"]?.InnerText; } + } + public string StartupObject { + get { return nodeProps["StartupObject"]?.InnerText; } + } + public bool DebugSymbols { + get { return nodeProps["DebugSymbols"] == null ? false : bool.Parse (nodeProps["DebugSymbols"]?.InnerText); } + } + public int WarningLevel { + get { return nodeProps["WarningLevel"] == null ? 0 : int.Parse (nodeProps["WarningLevel"]?.InnerText); } + } + + #endregion + + + public void AddNewFile () { + Window.Show (CrowIDE.MainIFace, "#CrowIDE.ui.NewFile.crow", true).DataSource = this; + } + + public void Load () { + + xmlDoc = new XmlDocument (); + using (Stream ins = new FileStream (this.Path, FileMode.Open)) { + xmlDoc.Load (new XmlTextReader (ins) { Namespaces = false }); + } + + nodeProject = xmlDoc.SelectSingleNode ("Project"); + XmlNodeList nodesProps = xmlDoc.SelectNodes ("/Project/PropertyGroup"); + + foreach (XmlNode n in nodesProps) { + if (n.Attributes["Condition"] == null) + nodeProps = n; + } + nodesItems = xmlDoc.SelectNodes ("/Project/ItemGroup"); + + if (ProjectGuid != solutionProject.ProjectGuid) + throw new Exception ("Project GUID not matching with solution"); + + buildTreeNodes (); + + IsLoaded = true; + } + + public void Save () { + + } + + void setAsStartupProject () { + solution.StartupProject = this; + } + static Regex regexDirTokens = new Regex (@"\$\(([^\)]*)\)|([^\$]*)"); + + string getDirectoryWithTokens (string dir) { + Match m = regexDirTokens.Match (dir); + string tmp = ""; + while (m.Success) { + if (m.Value == @"$(SolutionDir)") + tmp = System.IO.Path.Combine (tmp, solution.SolutionFolder); + else if (m.Value == @"$(Configuration)") + tmp = System.IO.Path.Combine (tmp, "Debug"); + else + tmp = System.IO.Path.Combine (tmp, m.Value); + + if (tmp.EndsWith (@"\") || tmp.EndsWith (@"/")) + tmp = tmp.Remove (tmp.Length - 1); + + m = m.NextMatch (); + } + return tmp; + } + public string Compile () { + if (ParentProject != null) + ParentProject.Compile (); + + CSharpCodeProvider cp = new CSharpCodeProvider (); + CompilerParameters parameters = new CompilerParameters (); + + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p == null) + throw new Exception ("referenced project not found"); + parameters.ReferencedAssemblies.Add (p.Compile ()); + } + + string outputDir = getDirectoryWithTokens (this.OutputPath); + string objDir = getDirectoryWithTokens (this.IntermediateOutputPath); + + Directory.CreateDirectory (outputDir); + Directory.CreateDirectory (objDir); + + parameters.OutputAssembly = System.IO.Path.Combine (outputDir, this.AssemblyName); + + // True - exe file generation, false - dll file generation + if (this.OutputType == "Library") { + parameters.GenerateExecutable = false; + parameters.CompilerOptions += " /target:library"; + parameters.OutputAssembly += ".dll"; + } else { + parameters.GenerateExecutable = true; + parameters.CompilerOptions += " /target:exe"; + parameters.OutputAssembly += ".exe"; + parameters.MainClass = this.StartupObject; + } + + parameters.GenerateInMemory = false; + parameters.IncludeDebugInformation = this.DebugSymbols; + parameters.TreatWarningsAsErrors = this.TreatWarningsAsErrors; + parameters.WarningLevel = this.WarningLevel; + parameters.CompilerOptions += " /noconfig"; + if (this.AllowUnsafeBlocks) + parameters.CompilerOptions += " /unsafe"; + parameters.CompilerOptions += " /delaysign+"; + parameters.CompilerOptions += " /debug:full /debug+"; + parameters.CompilerOptions += " /optimize-"; + parameters.CompilerOptions += " /define:\"DEBUG;TRACE\""; + parameters.CompilerOptions += " /nostdlib"; + + + + foreach (ProjectItem pi in flattenNodes.Where (p => p.Type == ItemType.Reference)) { + + if (string.IsNullOrEmpty (pi.HintPath)) { + parameters.CompilerOptions += " /reference:/usr/lib/mono/4.5/" + pi.Path + ".dll"; + continue; + } + parameters.ReferencedAssemblies.Add (pi.Path); + string fullHintPath = System.IO.Path.GetFullPath (System.IO.Path.Combine (RootDir, pi.HintPath.Replace ('\\', '/'))); + if (File.Exists (fullHintPath)) { + string outPath = System.IO.Path.Combine (outputDir, System.IO.Path.GetFileName (fullHintPath)); + if (!File.Exists (outPath)) + File.Copy (fullHintPath, outPath); + } + } + parameters.CompilerOptions += " /reference:/usr/lib/mono/4.5/System.Core.dll"; + parameters.CompilerOptions += " /reference:/usr/lib/mono/4.5/mscorlib.dll"; + //parameters.ReferencedAssemblies.Add ("System.Core"); + //parameters.ReferencedAssemblies.Add ("mscorlib.dll"); + + + IEnumerable pfs = flattenNodes.OfType (); + + foreach (ProjectFile pi in pfs.Where (p => p.Type == ItemType.EmbeddedResource)) { + + string absPath = pi.AbsolutePath; + string logicName = pi.LogicalName; + if (string.IsNullOrEmpty (logicName)) + parameters.CompilerOptions += string.Format (" /resource:{0},{1}", absPath, this.Name + "." + pi.Path.Replace ('/', '.')); + else + parameters.CompilerOptions += string.Format (" /resource:{0},{1}", absPath, logicName); + } + foreach (ProjectFile pi in pfs.Where (p => p.Type == ItemType.None)) { + if (pi.CopyToOutputDirectory == CopyToOutputState.Never) + continue; + string source = pi.AbsolutePath; + string target = System.IO.Path.Combine (outputDir, pi.Path); + Directory.CreateDirectory (System.IO.Path.GetDirectoryName (target)); + + if (File.Exists (target)) { + if (pi.CopyToOutputDirectory == CopyToOutputState.PreserveNewest) { + if (DateTime.Compare ( + System.IO.File.GetLastWriteTime (source), + System.IO.File.GetLastWriteTime (target)) < 0) + continue; + } + File.Delete (target); + } + System.Diagnostics.Debug.WriteLine ("copy " + source + " to " + target); + File.Copy (source, target); + } + string[] files = pfs.Where (p => p.Type == ItemType.Compile).Select (p => p.AbsolutePath).ToArray (); + + System.Diagnostics.Debug.WriteLine ("---- start compilation of :" + parameters.OutputAssembly); + System.Diagnostics.Debug.WriteLine (parameters.CompilerOptions); + + CompilationResults = cp.CompileAssemblyFromFile (parameters, files); + + solution.UpdateErrorList (); + + return parameters.OutputAssembly; + } + + public bool TryGetProjectFileFromAbsolutePath (string absolutePath, out ProjectFile pi) { + pi = flattenNodes.OfType ().FirstOrDefault + (pp => pp.AbsolutePath == absolutePath); + return pi != null; + } + public bool TryGetProjectFileFromPath (string path, out ProjectFile pi) { + if (path.StartsWith ("#", StringComparison.Ordinal)) + pi = flattenNodes.OfType ().FirstOrDefault + (pp => pp.Type == ItemType.EmbeddedResource && pp.ResourceID == path.Substring (1)); + else + pi = flattenNodes.OfType ().FirstOrDefault (pp => pp.Path == path); + + if (pi != null) + return true; + + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p == null) + throw new Exception ("referenced project not found"); + if (p.TryGetProjectFileFromPath (path, out pi)) + return true; + } + //TODO: search referenced assemblies + return false; + } + + public void GetDefaultTemplates () { + IEnumerable tmpFiles = + flattenNodes.OfType ().Where (pp => pp.Extension == ".template"); + + foreach (ProjectFile pi in tmpFiles.Where ( + pp => pp.Type == ItemType.None && pp.CopyToOutputDirectory != CopyToOutputState.Never)) { + + string clsName = System.IO.Path.GetFileNameWithoutExtension (pi.Path); + if (solution.DefaultTemplates.ContainsKey (clsName)) + continue; + solution.DefaultTemplates[clsName] = pi.AbsolutePath; + } + foreach (ProjectFile pi in tmpFiles.Where (pp => pp.Type == ItemType.EmbeddedResource)) { + string resId = pi.ResourceID; + string clsName = resId.Substring (0, resId.Length - 9); + if (solution.DefaultTemplates.ContainsKey (clsName)) + continue; + solution.DefaultTemplates[clsName] = pi.Path; + } + + foreach (Project p in ReferencedProjects) + p.GetDefaultTemplates (); + } + // void searchTemplatesIn(Assembly assembly){ + // if (assembly == null) + // return; + // foreach (string resId in assembly + // .GetManifestResourceNames () + // .Where (r => r.EndsWith (".template", StringComparison.OrdinalIgnoreCase))) { + // string clsName = resId.Substring (0, resId.Length - 9); + // if (DefaultTemplates.ContainsKey (clsName)) + // continue; + // DefaultTemplates[clsName] = "#" + resId; + // } + // } + + public List ReferencedProjects { + get { + List tmp = new List (); + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p != null) + tmp.Add (p); + } + return tmp; + } + } + + public void GetStyling () { + try { + foreach (ProjectFile pi in flattenNodes.OfType ().Where (pp => pp.Type == ItemType.EmbeddedResource && pp.Extension == ".style")) { + using (Stream s = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (pi.Source))) { + new StyleReader (solution.Styling, s, pi.ResourceID); + } + } + } catch (Exception ex) { + Console.WriteLine (ex.ToString ()); + } + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p == null) + throw new Exception ("referenced project not found"); + p.GetStyling (); + } + + //TODO:get styling from referenced assemblies + } + } +} + -- cgit v1.3.1-4-g156e