* Makefile.am:
[monodevelop.git] / main / src / addins / MonoDeveloperExtensions / MonoSolutionItemHandler.cs
blobbe19804edcf5ab287a11e7a37769b4d8aec16c60
1 // MonoSolutionItemHandler.cs
2 //
3 // Author:
4 // Lluis Sanchez Gual <lluis@novell.com>
5 //
6 // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 // THE SOFTWARE.
28 using System;
29 using System.Collections;
30 using System.IO;
31 using MonoDevelop.Core;
32 using MonoDevelop.Core.Execution;
33 using System.Text.RegularExpressions;
34 using MonoDevelop.Projects;
35 using System.CodeDom.Compiler;
36 using MonoDevelop.Ide.Gui;
37 using MonoDevelop.Core.ProgressMonitoring;
38 using MonoDevelop.Projects.Extensions;
40 namespace MonoDeveloper
42 public class MonoSolutionItemHandler: ISolutionItemHandler
44 DotNetProject project;
45 string outFile;
46 ArrayList refNames = new ArrayList ();
47 bool loading;
48 string testFileBase;
49 object unitTest;
51 public MonoSolutionItemHandler (DotNetProject project)
53 this.project = project;
54 project.FileAddedToProject += OnFileAddedToProject;
55 project.FileRemovedFromProject += OnFileRemovedFromProject;
56 project.FileRenamedInProject += OnFileRenamedInProject;
59 public string SourcesFile {
60 get { return outFile + ".sources"; }
63 public bool SyncFileName {
64 get { return false; }
67 public string ItemId {
68 get {
69 if (project.ParentSolution != null)
70 return project.ParentSolution.GetRelativeChildPath (project.FileName);
71 else
72 return project.Name;
76 public void Save (MonoDevelop.Core.IProgressMonitor monitor)
80 internal void Read (MonoMakefile mkfile)
82 loading = true;
84 string basePath = Path.GetDirectoryName (mkfile.FileName);
85 string aname;
87 string targetAssembly = mkfile.GetVariable ("LIBRARY");
88 if (targetAssembly == null) {
89 targetAssembly = mkfile.GetVariable ("PROGRAM");
90 if (Path.GetDirectoryName (targetAssembly) == "")
91 targetAssembly = Path.Combine (basePath, targetAssembly);
92 aname = Path.GetFileName (targetAssembly);
93 } else {
94 aname = Path.GetFileName (targetAssembly);
95 string targetName = mkfile.GetVariable ("LIBRARY_NAME");
96 if (targetName != null) targetAssembly = targetName;
97 targetAssembly = "$(topdir)/class/lib/$(PROFILE)/" + targetAssembly;
100 outFile = Path.Combine (basePath, aname);
101 project.FileName = mkfile.FileName;
103 ArrayList checkedFolders = new ArrayList ();
105 // Parse projects
106 string sources = outFile + ".sources";
107 StreamReader sr = new StreamReader (sources);
108 string line;
109 while ((line = sr.ReadLine ()) != null) {
110 line = line.Trim (' ','\t');
111 if (line != "") {
112 string fname = Path.Combine (basePath, line);
113 project.Files.Add (new ProjectFile (fname));
115 string dir = Path.GetDirectoryName (fname);
116 if (!checkedFolders.Contains (dir)) {
117 checkedFolders.Add (dir);
118 fname = Path.Combine (dir, "ChangeLog");
119 if (File.Exists (fname))
120 project.Files.Add (new ProjectFile (fname, BuildAction.Content));
125 sr.Close ();
127 // Project references
128 string refs = mkfile.GetVariable ("LIB_MCS_FLAGS");
129 if (refs == null || refs == "") refs = mkfile.GetVariable ("LOCAL_MCS_FLAGS");
131 if (refs != null && refs != "") {
132 Regex var = new Regex(@"(.*?/r:(?<ref>.*?)(( |\t)|$).*?)*");
133 Match match = var.Match (refs);
134 if (match.Success) {
135 foreach (Capture c in match.Groups["ref"].Captures)
136 refNames.Add (Path.GetFileNameWithoutExtension (c.Value));
140 int i = basePath.LastIndexOf ("/mcs/", basePath.Length - 2);
141 string topdir = basePath.Substring (0, i + 4);
142 targetAssembly = targetAssembly.Replace ("$(topdir)", topdir);
144 if (mkfile.GetVariable ("NO_TEST") != "yes") {
145 string tname = Path.GetFileNameWithoutExtension (aname) + "_test_";
146 testFileBase = Path.Combine (basePath, tname);
149 foreach (string sconf in MonoMakefileFormat.Configurations) {
150 DotNetProjectConfiguration conf = new DotNetProjectConfiguration (sconf);
151 conf.CompilationParameters = project.LanguageBinding.CreateCompilationParameters (null);
152 conf.OutputDirectory = basePath;
153 conf.OutputAssembly = Path.GetFileName (targetAssembly);
154 project.Configurations.Add (conf);
157 loading = false;
158 IdeApp.Workspace.SolutionLoaded += CombineOpened;
161 public void CombineOpened (object sender, SolutionEventArgs args)
163 if (args.Solution == project.ParentSolution) {
164 foreach (string pref in refNames) {
165 Project p = project.ParentSolution.FindProjectByName (pref);
166 if (p != null) project.References.Add (new ProjectReference (p));
171 static Regex regexError = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*[\+]*))?\)(:|)\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
172 RegexOptions.Compiled | RegexOptions.ExplicitCapture);
174 public BuildResult RunTarget (MonoDevelop.Core.IProgressMonitor monitor, string target, string configuration)
176 if (target == ProjectService.BuildTarget)
177 target = "all";
178 else if (target == ProjectService.CleanTarget)
179 target = "clean";
181 DotNetProjectConfiguration conf = (DotNetProjectConfiguration) project.GetConfiguration (configuration);
183 StringWriter output = new StringWriter ();
184 LogTextWriter tw = new LogTextWriter ();
185 tw.ChainWriter (output);
186 tw.ChainWriter (monitor.Log);
188 ProcessWrapper proc = Runtime.ProcessService.StartProcess ("make", "PROFILE=" + conf.Id + " " + target, conf.OutputDirectory, monitor.Log, tw, null);
189 proc.WaitForOutput ();
191 CompilerResults cr = new CompilerResults (null);
192 string[] lines = output.ToString().Split ('\n');
193 foreach (string line in lines) {
194 CompilerError err = CreateErrorFromString (line);
195 if (err != null) cr.Errors.Add (err);
198 return new BuildResult (cr, output.ToString());
201 private CompilerError CreateErrorFromString (string error_string)
203 // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.
204 if (error_string.StartsWith ("WROTE SYMFILE") ||
205 error_string.StartsWith ("make[") ||
206 error_string.StartsWith ("OffsetTable") ||
207 error_string.StartsWith ("Compilation succeeded") ||
208 error_string.StartsWith ("Compilation failed"))
209 return null;
211 CompilerError error = new CompilerError();
213 Match match=regexError.Match(error_string);
214 if (!match.Success)
215 return null;
217 string level = match.Result("${level}");
218 if (level == "warning")
219 error.IsWarning = true;
220 else if (level != "error")
221 return null;
223 if (String.Empty != match.Result("${file}"))
224 error.FileName = Path.Combine (project.BaseDirectory, match.Result("${file}"));
225 if (String.Empty != match.Result("${line}"))
226 error.Line=Int32.Parse(match.Result("${line}"));
227 if (String.Empty != match.Result("${column}"))
228 error.Column = Int32.Parse(match.Result("${column}"));
229 error.ErrorNumber = match.Result ("${number}");
230 error.ErrorText = match.Result ("${message}");
231 return error;
234 void OnFileAddedToProject (object s, ProjectFileEventArgs e)
236 if (loading) return;
238 if (e.ProjectFile.BuildAction != BuildAction.Compile)
239 return;
241 AddSourceFile (e.ProjectFile.Name);
244 void OnFileRemovedFromProject (object s, ProjectFileEventArgs e)
246 if (loading) return;
248 if (e.ProjectFile.BuildAction != BuildAction.Compile)
249 return;
251 RemoveSourceFile (e.ProjectFile.Name);
254 void OnFileRenamedInProject (object s, ProjectFileRenamedEventArgs e)
256 if (loading) return;
258 if (e.ProjectFile.BuildAction != BuildAction.Compile)
259 return;
261 if (RemoveSourceFile (e.OldName))
262 AddSourceFile (e.NewName);
265 void AddSourceFile (string sourceFile)
267 StreamReader sr = null;
268 StreamWriter sw = null;
270 try {
271 sr = new StreamReader (outFile + ".sources");
272 sw = new StreamWriter (outFile + ".sources.new");
274 string newFile = project.GetRelativeChildPath (sourceFile);
275 if (newFile.StartsWith ("./")) newFile = newFile.Substring (2);
277 string line;
278 while ((line = sr.ReadLine ()) != null) {
279 string file = line.Trim (' ','\t');
280 if (newFile != null && (file == "" || string.Compare (file, newFile) > 0)) {
281 sw.WriteLine (newFile);
282 newFile = null;
284 sw.WriteLine (line);
286 if (newFile != null)
287 sw.WriteLine (newFile);
288 } finally {
289 if (sr != null) sr.Close ();
290 if (sw != null) sw.Close ();
292 File.Delete (outFile + ".sources");
293 File.Move (outFile + ".sources.new", outFile + ".sources");
296 bool RemoveSourceFile (string sourceFile)
298 StreamReader sr = null;
299 StreamWriter sw = null;
300 bool found = false;
302 try {
303 sr = new StreamReader (outFile + ".sources");
304 sw = new StreamWriter (outFile + ".sources.new");
306 string oldFile = project.GetRelativeChildPath (sourceFile);
307 if (oldFile.StartsWith ("./")) oldFile = oldFile.Substring (2);
309 string line;
310 while ((line = sr.ReadLine ()) != null) {
311 string file = line.Trim (' ','\t');
312 if (oldFile != file)
313 sw.WriteLine (line);
314 else
315 found = true;
317 } finally {
318 if (sr != null) sr.Close ();
319 if (sw != null) sw.Close ();
321 if (found) {
322 File.Delete (outFile + ".sources");
323 File.Move (outFile + ".sources.new", outFile + ".sources");
325 return found;
328 public void Dispose ()
330 project.FileAddedToProject -= OnFileAddedToProject;
331 project.FileRemovedFromProject -= OnFileRemovedFromProject;
332 project.FileRenamedInProject -= OnFileRenamedInProject;
333 IdeApp.Workspace.SolutionLoaded -= CombineOpened;
336 public string GetTestFileBase ()
338 return testFileBase;
341 public object UnitTest {
342 get { return unitTest; }
343 set { unitTest = value; }