clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 #region BSD License
2 /*
3 Copyright (c) 2008 Matthew Holmes (matthew@wildfiregames.com), John Anderson (sontek@gmail.com)
4  
5 Redistribution and use in source and binary forms, with or without modification, are permitted
6 provided that the following conditions are met:
7  
8 * Redistributions of source code must retain the above copyright notice, this list of conditions
9 and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
11 and the following disclaimer in the documentation and/or other materials provided with the
12 distribution.
13 * The name of the author may not be used to endorse or promote products derived from this software
14 without specific prior written permission.
15  
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
17 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24 #endregion
25  
26 using System;
27 using System.Collections.Generic;
28 using System.Collections.Specialized;
29 using System.IO;
30 using Prebuild.Core.Interfaces;
31 using Prebuild.Core.Nodes;
32 using Prebuild.Core.Utilities;
33 using System.CodeDom.Compiler;
34  
35 namespace Prebuild.Core.Targets
36 {
37  
38 /// <summary>
39 ///
40 /// </summary>
41 public abstract class VSGenericTarget : ITarget
42 {
43 #region Fields
44  
45 readonly Dictionary<string, ToolInfo> tools = new Dictionary<string, ToolInfo>();
46 // NameValueCollection CopyFiles = new NameValueCollection();
47 Kernel kernel;
48 #endregion
49  
50 #region Properties
51 /// <summary>
52 /// Gets or sets the solution version.
53 /// </summary>
54 /// <value>The solution version.</value>
55 public abstract string SolutionVersion { get; }
56 /// <summary>
57 /// Gets or sets the product version.
58 /// </summary>
59 /// <value>The product version.</value>
60 public abstract string ProductVersion { get; }
61 /// <summary>
62 /// Gets or sets the schema version.
63 /// </summary>
64 /// <value>The schema version.</value>
65 public abstract string SchemaVersion { get; }
66 /// <summary>
67 /// Gets or sets the name of the version.
68 /// </summary>
69 /// <value>The name of the version.</value>
70 public abstract string VersionName { get; }
71 /// <summary>
72 /// Gets or sets the version.
73 /// </summary>
74 /// <value>The version.</value>
75 public abstract VSVersion Version { get; }
76 /// <summary>
77 /// Gets the name.
78 /// </summary>
79 /// <value>The name.</value>
80 public abstract string Name { get; }
81  
82 protected abstract string GetToolsVersionXml(FrameworkVersion version);
83 public abstract string SolutionTag { get; }
84  
85 #endregion
86  
87 #region Constructors
88  
89 /// <summary>
90 /// Initializes a new instance of the <see cref="VSGenericTarget"/> class.
91 /// </summary>
92 protected VSGenericTarget()
93 {
94 tools["C#"] = new ToolInfo("C#", "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "csproj", "CSHARP", "$(MSBuildBinPath)\\Microsoft.CSHARP.Targets");
95 tools["Database"] = new ToolInfo("Database", "{4F174C21-8C12-11D0-8340-0000F80270F8}", "dbp", "UNKNOWN");
96 tools["Boo"] = new ToolInfo("Boo", "{45CEA7DC-C2ED-48A6-ACE0-E16144C02365}", "booproj", "Boo", "$(BooBinPath)\\Boo.Microsoft.Build.targets");
97 tools["VisualBasic"] = new ToolInfo("VisualBasic", "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}", "vbproj", "VisualBasic", "$(MSBuildBinPath)\\Microsoft.VisualBasic.Targets");
98 tools["Folder"] = new ToolInfo("Folder", "{2150E333-8FDC-42A3-9474-1A3956D46DE8}", null, null);
99 }
100  
101 #endregion
102  
103 #region Private Methods
104  
105 private string MakeRefPath(ProjectNode project)
106 {
107 string ret = "";
108 foreach (ReferencePathNode node in project.ReferencePaths)
109 {
110 try
111 {
112 string fullPath = Helper.ResolvePath(node.Path);
113 if (ret.Length < 1)
114 {
115 ret = fullPath;
116 }
117 else
118 {
119 ret += ";" + fullPath;
120 }
121 }
122 catch (ArgumentException)
123 {
124 kernel.Log.Write(LogType.Warning, "Could not resolve reference path: {0}", node.Path);
125 }
126 }
127  
128 return ret;
129 }
130  
131 private static ProjectNode FindProjectInSolution(string name, SolutionNode solution)
132 {
133 SolutionNode node = solution;
134  
135 while (node.Parent is SolutionNode)
136 node = node.Parent as SolutionNode;
137  
138 return FindProjectInSolutionRecursively(name, node);
139 }
140  
141 private static ProjectNode FindProjectInSolutionRecursively(string name, SolutionNode solution)
142 {
143 if (solution.ProjectsTable.ContainsKey(name))
144 return solution.ProjectsTable[name];
145  
146 foreach (SolutionNode child in solution.Solutions)
147 {
148 ProjectNode node = FindProjectInSolutionRecursively(name, child);
149 if (node != null)
150 return node;
151 }
152  
153 return null;
154 }
155  
156 private void WriteProject(SolutionNode solution, ProjectNode project)
157 {
158 if (!tools.ContainsKey(project.Language))
159 {
160 throw new UnknownLanguageException("Unknown .NET language: " + project.Language);
161 }
162  
163 ToolInfo toolInfo = tools[project.Language];
164 string projectFile = Helper.MakeFilePath(project.FullPath, project.Name, toolInfo.FileExtension);
165 StreamWriter ps = new StreamWriter(projectFile);
166  
167 kernel.CurrentWorkingDirectory.Push();
168 Helper.SetCurrentDir(Path.GetDirectoryName(projectFile));
169  
170 #region Project File
171 using (ps)
172 {
173 string targets = "";
174  
175 if(project.Files.CopyFiles > 0)
176 targets = "Build;CopyFiles";
177 else
178 targets = "Build";
179  
180 ps.WriteLine("<Project DefaultTargets=\"{0}\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" {1}>", targets, GetToolsVersionXml(project.FrameworkVersion));
181 ps.WriteLine(" <PropertyGroup>");
182 ps.WriteLine(" <ProjectType>Local</ProjectType>");
183 ps.WriteLine(" <ProductVersion>{0}</ProductVersion>", ProductVersion);
184 ps.WriteLine(" <SchemaVersion>{0}</SchemaVersion>", SchemaVersion);
185 ps.WriteLine(" <ProjectGuid>{{{0}}}</ProjectGuid>", project.Guid.ToString().ToUpper());
186  
187 // Visual Studio has a hard coded guid for the project type
188 if (project.Type == ProjectType.Web)
189 ps.WriteLine(" <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>");
190 ps.WriteLine(" <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>");
191 ps.WriteLine(" <ApplicationIcon>{0}</ApplicationIcon>", project.AppIcon);
192 ps.WriteLine(" <AssemblyKeyContainerName>");
193 ps.WriteLine(" </AssemblyKeyContainerName>");
194 ps.WriteLine(" <AssemblyName>{0}</AssemblyName>", project.AssemblyName);
195 foreach (ConfigurationNode conf in project.Configurations)
196 {
197 if (conf.Options.KeyFile != "")
198 {
199 ps.WriteLine(" <AssemblyOriginatorKeyFile>{0}</AssemblyOriginatorKeyFile>", conf.Options.KeyFile);
200 ps.WriteLine(" <SignAssembly>true</SignAssembly>");
201 break;
202 }
203 }
204 ps.WriteLine(" <DefaultClientScript>JScript</DefaultClientScript>");
205 ps.WriteLine(" <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>");
206 ps.WriteLine(" <DefaultTargetSchema>IE50</DefaultTargetSchema>");
207 ps.WriteLine(" <DelaySign>false</DelaySign>");
208 ps.WriteLine(" <TargetFrameworkVersion>{0}</TargetFrameworkVersion>", project.FrameworkVersion.ToString().Replace("_", "."));
209  
210 ps.WriteLine(" <OutputType>{0}</OutputType>", project.Type == ProjectType.Web ? ProjectType.Library.ToString() : project.Type.ToString());
211 ps.WriteLine(" <AppDesignerFolder>{0}</AppDesignerFolder>", project.DesignerFolder);
212 ps.WriteLine(" <RootNamespace>{0}</RootNamespace>", project.RootNamespace);
213 ps.WriteLine(" <StartupObject>{0}</StartupObject>", project.StartupObject);
214 if (string.IsNullOrEmpty(project.DebugStartParameters))
215 {
216 ps.WriteLine(" <StartArguments>{0}</StartArguments>", project.DebugStartParameters);
217 }
218 ps.WriteLine(" <FileUpgradeFlags>");
219 ps.WriteLine(" </FileUpgradeFlags>");
220  
221 ps.WriteLine(" </PropertyGroup>");
222  
223 foreach (ConfigurationNode conf in project.Configurations)
224 {
225 ps.Write(" <PropertyGroup ");
226 ps.WriteLine("Condition=\" '$(Configuration)|$(Platform)' == '{0}|{1}' \">", conf.Name, conf.Platform);
227 ps.WriteLine(" <AllowUnsafeBlocks>{0}</AllowUnsafeBlocks>", conf.Options["AllowUnsafe"]);
228 ps.WriteLine(" <BaseAddress>{0}</BaseAddress>", conf.Options["BaseAddress"]);
229 ps.WriteLine(" <CheckForOverflowUnderflow>{0}</CheckForOverflowUnderflow>", conf.Options["CheckUnderflowOverflow"]);
230 ps.WriteLine(" <ConfigurationOverrideFile>");
231 ps.WriteLine(" </ConfigurationOverrideFile>");
232 ps.WriteLine(" <DefineConstants>{0}</DefineConstants>", conf.Options["CompilerDefines"]);
233 ps.WriteLine(" <DocumentationFile>{0}</DocumentationFile>", Helper.NormalizePath(conf.Options["XmlDocFile"].ToString()));
234 ps.WriteLine(" <DebugSymbols>{0}</DebugSymbols>", conf.Options["DebugInformation"]);
235 ps.WriteLine(" <FileAlignment>{0}</FileAlignment>", conf.Options["FileAlignment"]);
236 ps.WriteLine(" <Optimize>{0}</Optimize>", conf.Options["OptimizeCode"]);
237 if (project.Type != ProjectType.Web)
238 ps.WriteLine(" <OutputPath>{0}</OutputPath>",
239 Helper.EndPath(Helper.NormalizePath(conf.Options["OutputPath"].ToString())));
240 else
241 ps.WriteLine(" <OutputPath>{0}</OutputPath>",
242 Helper.EndPath(Helper.NormalizePath("bin\\")));
243  
244 ps.WriteLine(" <RegisterForComInterop>{0}</RegisterForComInterop>", conf.Options["RegisterComInterop"]);
245 ps.WriteLine(" <RemoveIntegerChecks>{0}</RemoveIntegerChecks>", conf.Options["RemoveIntegerChecks"]);
246 ps.WriteLine(" <TreatWarningsAsErrors>{0}</TreatWarningsAsErrors>", conf.Options["WarningsAsErrors"]);
247 ps.WriteLine(" <WarningLevel>{0}</WarningLevel>", conf.Options["WarningLevel"]);
248 ps.WriteLine(" <NoStdLib>{0}</NoStdLib>", conf.Options["NoStdLib"]);
249 ps.WriteLine(" <NoWarn>{0}</NoWarn>", conf.Options["SuppressWarnings"]);
250 ps.WriteLine(" <PlatformTarget>{0}</PlatformTarget>", conf.Platform);
251 ps.WriteLine(" </PropertyGroup>");
252 }
253  
254 //ps.WriteLine(" </Settings>");
255  
256 Dictionary<ReferenceNode, ProjectNode> projectReferences = new Dictionary<ReferenceNode, ProjectNode>();
257 List<ReferenceNode> otherReferences = new List<ReferenceNode>();
258  
259 foreach (ReferenceNode refr in project.References)
260 {
261 ProjectNode projectNode = FindProjectInSolution(refr.Name, solution);
262  
263 if (projectNode == null)
264 otherReferences.Add(refr);
265 else
266 projectReferences.Add(refr, projectNode);
267 }
268 // Assembly References
269 ps.WriteLine(" <ItemGroup>");
270  
271 foreach (ReferenceNode refr in otherReferences)
272 {
273 ps.Write(" <Reference");
274 ps.Write(" Include=\"");
275 ps.Write(refr.Name);
276 ps.WriteLine("\" >");
277 ps.Write(" <Name>");
278 ps.Write(refr.Name);
279 ps.WriteLine("</Name>");
280  
281 if(!String.IsNullOrEmpty(refr.Path))
282 {
283 // Use absolute path to assembly (for determining assembly type)
284 string absolutePath = Path.Combine(project.FullPath, refr.Path);
285 if(File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "exe"))) {
286 // Assembly is an executable (exe)
287 ps.WriteLine(" <HintPath>{0}</HintPath>", Helper.MakeFilePath(refr.Path, refr.Name, "exe"));
288 } else if(File.Exists(Helper.MakeFilePath(absolutePath, refr.Name, "dll"))) {
289 // Assembly is an library (dll)
290 ps.WriteLine(" <HintPath>{0}</HintPath>", Helper.MakeFilePath(refr.Path, refr.Name, "dll"));
291 } else {
292 string referencePath = Helper.MakeFilePath(refr.Path, refr.Name, "dll");
293 kernel.Log.Write(LogType.Warning, "Reference \"{0}\": The specified file doesn't exist.", referencePath);
294 ps.WriteLine(" <HintPath>{0}</HintPath>", Helper.MakeFilePath(refr.Path, refr.Name, "dll"));
295 }
296 }
297  
298 ps.WriteLine(" <Private>{0}</Private>", refr.LocalCopy);
299 ps.WriteLine(" </Reference>");
300 }
301 ps.WriteLine(" </ItemGroup>");
302  
303 //Project References
304 ps.WriteLine(" <ItemGroup>");
305 foreach (KeyValuePair<ReferenceNode, ProjectNode> pair in projectReferences)
306 {
307 ToolInfo tool = tools[pair.Value.Language];
308 if (tools == null)
309 throw new UnknownLanguageException();
310  
311 string path =
312 Helper.MakePathRelativeTo(project.FullPath,
313 Helper.MakeFilePath(pair.Value.FullPath, pair.Value.Name, tool.FileExtension));
314 ps.WriteLine(" <ProjectReference Include=\"{0}\">", path);
315  
316 // TODO: Allow reference to visual basic projects
317 ps.WriteLine(" <Name>{0}</Name>", pair.Value.Name);
318 ps.WriteLine(" <Project>{0}</Project>", pair.Value.Guid.ToString("B").ToUpper());
319 ps.WriteLine(" <Package>{0}</Package>", tool.Guid.ToUpper());
320  
321 //This is the Copy Local flag in VS
322 ps.WriteLine(" <Private>{0}</Private>", pair.Key.LocalCopy);
323  
324 ps.WriteLine(" </ProjectReference>");
325 }
326 ps.WriteLine(" </ItemGroup>");
327  
328 // ps.WriteLine(" </Build>");
329 ps.WriteLine(" <ItemGroup>");
330  
331 // ps.WriteLine(" <Include>");
332 List<string> list = new List<string>();
333  
334 foreach (string path in project.Files)
335 {
336 string lower = path.ToLower();
337 if (lower.EndsWith(".resx"))
338 {
339 string codebehind = String.Format("{0}.Designer{1}", path.Substring(0, path.LastIndexOf('.')), toolInfo.LanguageExtension);
340 if (!list.Contains(codebehind))
341 list.Add(codebehind);
342 }
343  
344 }
345  
346  
347 foreach (string filePath in project.Files)
348 {
349 // Add the filePath with the destination as the key
350 // will use it later to form the copy parameters with Include lists
351 // for each destination
352 if (project.Files.GetBuildAction(filePath) == BuildAction.Copy)
353 continue;
354 // if (file == "Properties\\Bind.Designer.cs")
355 // {
356 // Console.WriteLine("Wait a minute!");
357 // Console.WriteLine(project.Files.GetSubType(file).ToString());
358 // }
359 SubType subType = project.Files.GetSubType(filePath);
360  
361 // Visual Studio chokes on file names if forward slash is used as a path separator
362 // instead of backslash. So we must make sure that all file paths written to the
363 // project file use \ as a path separator.
364 string file = filePath.Replace(@"/", @"\");
365  
366 if (subType != SubType.Code && subType != SubType.Settings && subType != SubType.Designer
367 && subType != SubType.CodeBehind)
368 {
369 ps.WriteLine(" <EmbeddedResource Include=\"{0}\">", file.Substring(0, file.LastIndexOf('.')) + ".resx");
370 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(file));
371 ps.WriteLine(" <SubType>Designer</SubType>");
372 ps.WriteLine(" </EmbeddedResource>");
373 //
374 }
375  
376 if (subType == SubType.Designer)
377 {
378 ps.WriteLine(" <EmbeddedResource Include=\"{0}\">", file);
379  
380 string autogen_name = file.Substring(0, file.LastIndexOf('.')) + ".Designer.cs";
381 string dependent_name = filePath.Substring(0, file.LastIndexOf('.')) + ".cs";
382  
383 // Check for a parent .cs file with the same name as this designer file
384 if (File.Exists(Helper.NormalizePath(dependent_name)))
385 {
386 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(dependent_name));
387 }
388 else
389 {
390 ps.WriteLine(" <Generator>ResXFileCodeGenerator</Generator>");
391 ps.WriteLine(" <LastGenOutput>{0}</LastGenOutput>", Path.GetFileName(autogen_name));
392 ps.WriteLine(" <SubType>" + subType + "</SubType>");
393 }
394  
395 ps.WriteLine(" </EmbeddedResource>");
396 if (File.Exists(Helper.NormalizePath(autogen_name)))
397 {
398 ps.WriteLine(" <Compile Include=\"{0}\">", autogen_name);
399 //ps.WriteLine(" <DesignTime>True</DesignTime>");
400  
401 // If a parent .cs file exists, link this autogen file to it. Otherwise link
402 // to the designer file
403 if (File.Exists(dependent_name))
404 {
405 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(dependent_name));
406 }
407 else
408 {
409 ps.WriteLine(" <AutoGen>True</AutoGen>");
410 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(filePath));
411 }
412  
413 ps.WriteLine(" </Compile>");
414 }
415 list.Add(autogen_name);
416 }
417 if (subType == SubType.Settings)
418 {
419 ps.Write(" <{0} ", project.Files.GetBuildAction(filePath));
420 ps.WriteLine("Include=\"{0}\">", file);
421 string fileName = Path.GetFileName(filePath);
422 if (project.Files.GetBuildAction(filePath) == BuildAction.None)
423 {
424 ps.WriteLine(" <Generator>SettingsSingleFileGenerator</Generator>");
425 ps.WriteLine(" <LastGenOutput>{0}</LastGenOutput>", fileName.Substring(0, fileName.LastIndexOf('.')) + ".Designer.cs");
426 }
427 else
428 {
429 ps.WriteLine(" <SubType>Code</SubType>");
430 ps.WriteLine(" <AutoGen>True</AutoGen>");
431 ps.WriteLine(" <DesignTimeSharedInput>True</DesignTimeSharedInput>");
432 string fileNameShort = fileName.Substring(0, fileName.LastIndexOf('.'));
433 string fileNameShorter = fileNameShort.Substring(0, fileNameShort.LastIndexOf('.'));
434 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(fileNameShorter + ".settings"));
435 }
436 ps.WriteLine(" </{0}>", project.Files.GetBuildAction(filePath));
437 }
438 else if (subType != SubType.Designer)
439 {
440 string path = Helper.NormalizePath(file);
441 string path_lower = path.ToLower();
442  
443 if (!list.Contains(filePath))
444 {
445 ps.Write(" <{0} ", project.Files.GetBuildAction(filePath));
446  
447 int startPos = 0;
448 if (project.Files.GetPreservePath(filePath))
449 {
450 while ((@"./\").IndexOf(file.Substring(startPos, 1)) != -1)
451 startPos++;
452  
453 }
454 else
455 {
456 startPos = file.LastIndexOf(Path.GetFileName(path));
457 }
458  
459 // be sure to write out the path with backslashes so VS recognizes
460 // the file properly.
461 ps.WriteLine("Include=\"{0}\">", file);
462  
463 int last_period_index = file.LastIndexOf('.');
464 string short_file_name = (last_period_index >= 0)
465 ? file.Substring(0, last_period_index)
466 : file;
467 string extension = Path.GetExtension(path);
468 // make this upper case, so that when File.Exists tests for the
469 // existence of a designer file on a case-sensitive platform,
470 // it is correctly identified.
471 string designer_format = string.Format(".Designer{0}", extension);
472  
473 if (path_lower.EndsWith(designer_format.ToLowerInvariant()))
474 {
475 int designer_index = path.IndexOf(designer_format);
476 string file_name = path.Substring(0, designer_index);
477  
478 // There are two corrections to the next lines:
479 // 1. Fix the connection between a designer file and a form
480 // or usercontrol that don't have an associated resx file.
481 // 2. Connect settings files to associated designer files.
482 if (File.Exists(file_name + extension))
483 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(file_name + extension));
484 else if (File.Exists(file_name + ".resx"))
485 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(file_name + ".resx"));
486 else if (File.Exists(file_name + ".settings"))
487 {
488 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(file_name + ".settings"));
489 ps.WriteLine(" <AutoGen>True</AutoGen>");
490 ps.WriteLine(" <DesignTimeSharedInput>True</DesignTimeSharedInput>");
491 }
492 }
493 else if (subType == SubType.CodeBehind)
494 {
495 ps.WriteLine(" <DependentUpon>{0}</DependentUpon>", Path.GetFileName(short_file_name));
496 }
497 if (project.Files.GetIsLink(filePath))
498 {
499 string alias = project.Files.GetLinkPath(filePath);
500 alias += file.Substring(startPos);
501 alias = Helper.NormalizePath(alias);
502 ps.WriteLine(" <Link>{0}</Link>", alias);
503 }
504 else if (project.Files.GetBuildAction(filePath) != BuildAction.None)
505 {
506 if (project.Files.GetBuildAction(filePath) != BuildAction.EmbeddedResource)
507 {
508 ps.WriteLine(" <SubType>{0}</SubType>", subType);
509 }
510 }
511  
512 if (project.Files.GetCopyToOutput(filePath) != CopyToOutput.Never)
513 {
514 ps.WriteLine(" <CopyToOutputDirectory>{0}</CopyToOutputDirectory>", project.Files.GetCopyToOutput(filePath));
515 }
516  
517 ps.WriteLine(" </{0}>", project.Files.GetBuildAction(filePath));
518 }
519 }
520 }
521 ps.WriteLine(" </ItemGroup>");
522  
523 /*
524 * Copy Task
525 *
526 */
527 if ( project.Files.CopyFiles > 0 ) {
528  
529 Dictionary<string, string> IncludeTags = new Dictionary<string, string>();
530 int TagCount = 0;
531  
532 // Handle Copy tasks
533 ps.WriteLine(" <ItemGroup>");
534 foreach (string destPath in project.Files.Destinations)
535 {
536 string tag = "FilesToCopy_" + TagCount.ToString("0000");
537  
538 ps.WriteLine(" <{0} Include=\"{1}\" />", tag, String.Join(";", project.Files.SourceFiles(destPath)));
539 IncludeTags.Add(destPath, tag);
540 TagCount++;
541 }
542  
543 ps.WriteLine(" </ItemGroup>");
544  
545 ps.WriteLine(" <Target Name=\"CopyFiles\">");
546  
547 foreach (string destPath in project.Files.Destinations)
548 {
549 ps.WriteLine(" <Copy SourceFiles=\"@({0})\" DestinationFolder=\"{1}\" />",
550 IncludeTags[destPath], destPath);
551 }
552  
553 ps.WriteLine(" </Target>");
554 }
555  
556 ps.WriteLine(" <Import Project=\"" + toolInfo.ImportProject + "\" />");
557 ps.WriteLine(" <PropertyGroup>");
558 ps.WriteLine(" <PreBuildEvent>");
559 ps.WriteLine(" </PreBuildEvent>");
560 ps.WriteLine(" <PostBuildEvent>");
561 ps.WriteLine(" </PostBuildEvent>");
562 ps.WriteLine(" </PropertyGroup>");
563 ps.WriteLine("</Project>");
564 }
565 #endregion
566  
567 #region User File
568  
569 ps = new StreamWriter(projectFile + ".user");
570 using (ps)
571 {
572 // Get the first configuration from the project.
573 ConfigurationNode firstConfiguration = null;
574  
575 if (project.Configurations.Count > 0)
576 {
577 firstConfiguration = project.Configurations[0];
578 }
579  
580 ps.WriteLine("<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">");
581 //ps.WriteLine( "<VisualStudioProject>" );
582 //ps.WriteLine(" <{0}>", toolInfo.XMLTag);
583 //ps.WriteLine(" <Build>");
584 ps.WriteLine(" <PropertyGroup>");
585 //ps.WriteLine(" <Settings ReferencePath=\"{0}\">", MakeRefPath(project));
586  
587 if (firstConfiguration != null)
588 {
589 ps.WriteLine(" <Configuration Condition=\" '$(Configuration)' == '' \">{0}</Configuration>", firstConfiguration.Name);
590 ps.WriteLine(" <Platform Condition=\" '$(Platform)' == '' \">{0}</Platform>", firstConfiguration.Platform);
591 }
592  
593 ps.WriteLine(" <ReferencePath>{0}</ReferencePath>", MakeRefPath(project));
594 ps.WriteLine(" <LastOpenVersion>{0}</LastOpenVersion>", ProductVersion);
595 ps.WriteLine(" <ProjectView>ProjectFiles</ProjectView>");
596 ps.WriteLine(" <ProjectTrust>0</ProjectTrust>");
597 ps.WriteLine(" </PropertyGroup>");
598 foreach (ConfigurationNode conf in project.Configurations)
599 {
600 ps.Write(" <PropertyGroup");
601 ps.Write(" Condition = \" '$(Configuration)|$(Platform)' == '{0}|{1}' \"", conf.Name, conf.Platform);
602 ps.WriteLine(" />");
603 }
604 ps.WriteLine("</Project>");
605 }
606 #endregion
607  
608 kernel.CurrentWorkingDirectory.Pop();
609 }
610  
611 private void WriteSolution(SolutionNode solution, bool writeSolutionToDisk)
612 {
613 kernel.Log.Write("Creating {0} solution and project files", VersionName);
614  
615 foreach (SolutionNode child in solution.Solutions)
616 {
617 kernel.Log.Write("...Creating folder: {0}", child.Name);
618 WriteSolution(child, false);
619 }
620  
621 foreach (ProjectNode project in solution.Projects)
622 {
623 kernel.Log.Write("...Creating project: {0}", project.Name);
624 WriteProject(solution, project);
625 }
626  
627 foreach (DatabaseProjectNode project in solution.DatabaseProjects)
628 {
629 kernel.Log.Write("...Creating database project: {0}", project.Name);
630 WriteDatabaseProject(solution, project);
631 }
632  
633 if (writeSolutionToDisk) // only write main solution
634 {
635 kernel.Log.Write("");
636 string solutionFile = Helper.MakeFilePath(solution.FullPath, solution.Name, "sln");
637  
638 using (StreamWriter ss = new StreamWriter(solutionFile))
639 {
640 kernel.CurrentWorkingDirectory.Push();
641 Helper.SetCurrentDir(Path.GetDirectoryName(solutionFile));
642  
643 ss.WriteLine("Microsoft Visual Studio Solution File, Format Version {0}", SolutionVersion);
644 ss.WriteLine(SolutionTag);
645  
646 WriteProjectDeclarations(ss, solution, solution);
647  
648 ss.WriteLine("Global");
649  
650 ss.WriteLine("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
651 foreach (ConfigurationNode conf in solution.Configurations)
652 {
653 ss.WriteLine("\t\t{0} = {0}", conf.NameAndPlatform);
654 }
655 ss.WriteLine("\tEndGlobalSection");
656  
657 ss.WriteLine("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
658 WriteConfigurationLines(solution.Configurations, solution, ss);
659 ss.WriteLine("\tEndGlobalSection");
660  
661 if (solution.Solutions.Count > 0)
662 {
663 ss.WriteLine("\tGlobalSection(NestedProjects) = preSolution");
664 foreach (SolutionNode embeddedSolution in solution.Solutions)
665 {
666 WriteNestedProjectMap(ss, embeddedSolution);
667 }
668 ss.WriteLine("\tEndGlobalSection");
669 }
670  
671 ss.WriteLine("EndGlobal");
672 }
673  
674 kernel.CurrentWorkingDirectory.Pop();
675 }
676 }
677  
678 private void WriteProjectDeclarations(TextWriter writer, SolutionNode actualSolution, SolutionNode embeddedSolution)
679 {
680 foreach (SolutionNode childSolution in embeddedSolution.Solutions)
681 {
682 WriteEmbeddedSolution(writer, childSolution);
683 WriteProjectDeclarations(writer, actualSolution, childSolution);
684 }
685  
686 foreach (ProjectNode project in embeddedSolution.Projects)
687 {
688 WriteProject(actualSolution, writer, project);
689 }
690  
691 foreach (DatabaseProjectNode dbProject in embeddedSolution.DatabaseProjects)
692 {
693 WriteProject(actualSolution, writer, dbProject);
694 }
695  
696 if (actualSolution.Guid == embeddedSolution.Guid)
697 {
698 WriteSolutionFiles(actualSolution, writer);
699 }
700 }
701  
702 private static void WriteNestedProjectMap(TextWriter writer, SolutionNode embeddedSolution)
703 {
704 foreach (ProjectNode project in embeddedSolution.Projects)
705 {
706 WriteNestedProject(writer, embeddedSolution, project.Guid);
707 }
708  
709 foreach (DatabaseProjectNode dbProject in embeddedSolution.DatabaseProjects)
710 {
711 WriteNestedProject(writer, embeddedSolution, dbProject.Guid);
712 }
713  
714 foreach (SolutionNode child in embeddedSolution.Solutions)
715 {
716 WriteNestedProject(writer, embeddedSolution, child.Guid);
717 WriteNestedProjectMap(writer, child);
718 }
719 }
720  
721 private static void WriteNestedProject(TextWriter writer, SolutionNode solution, Guid projectGuid)
722 {
723 WriteNestedFolder(writer, solution.Guid, projectGuid);
724 }
725  
726 private static void WriteNestedFolder(TextWriter writer, Guid parentGuid, Guid childGuid)
727 {
728 writer.WriteLine("\t\t{0} = {1}",
729 childGuid.ToString("B").ToUpper(),
730 parentGuid.ToString("B").ToUpper());
731 }
732  
733 private static void WriteConfigurationLines(IEnumerable<ConfigurationNode> configurations, SolutionNode solution, TextWriter ss)
734 {
735 foreach (ProjectNode project in solution.Projects)
736 {
737 foreach (ConfigurationNode conf in configurations)
738 {
739 ss.WriteLine("\t\t{0}.{1}.ActiveCfg = {1}",
740 project.Guid.ToString("B").ToUpper(),
741 conf.NameAndPlatform);
742  
743 ss.WriteLine("\t\t{0}.{1}.Build.0 = {1}",
744 project.Guid.ToString("B").ToUpper(),
745 conf.NameAndPlatform);
746 }
747 }
748  
749 foreach (SolutionNode child in solution.Solutions)
750 {
751 WriteConfigurationLines(configurations, child, ss);
752 }
753 }
754  
755 private void WriteSolutionFiles(SolutionNode solution, TextWriter ss)
756 {
757 if(solution.Files != null && solution.Files.Count > 0)
758 WriteProject(ss, "Folder", solution.Guid, "Solution Files", "Solution Files", solution.Files);
759 }
760  
761 private void WriteEmbeddedSolution(TextWriter writer, SolutionNode embeddedSolution)
762 {
763 WriteProject(writer, "Folder", embeddedSolution.Guid, embeddedSolution.Name, embeddedSolution.Name, embeddedSolution.Files);
764 }
765  
766 private void WriteProject(SolutionNode solution, TextWriter ss, ProjectNode project)
767 {
768 WriteProject(ss, solution, project.Language, project.Guid, project.Name, project.FullPath);
769 }
770  
771 private void WriteProject(SolutionNode solution, TextWriter ss, DatabaseProjectNode dbProject)
772 {
773 if (solution.Files != null && solution.Files.Count > 0)
774 WriteProject(ss, solution, "Database", dbProject.Guid, dbProject.Name, dbProject.FullPath);
775 }
776  
777 const string ProjectDeclarationBeginFormat = "Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"";
778 const string ProjectDeclarationEndFormat = "EndProject";
779  
780 private void WriteProject(TextWriter ss, SolutionNode solution, string language, Guid guid, string name, string projectFullPath)
781 {
782 if (!tools.ContainsKey(language))
783 throw new UnknownLanguageException("Unknown .NET language: " + language);
784  
785 ToolInfo toolInfo = tools[language];
786  
787 string path = Helper.MakePathRelativeTo(solution.FullPath, projectFullPath);
788  
789 path = Helper.MakeFilePath(path, name, toolInfo.FileExtension);
790  
791 WriteProject(ss, language, guid, name, path);
792 }
793  
794 private void WriteProject(TextWriter writer, string language, Guid projectGuid, string name, string location)
795 {
796 WriteProject(writer, language, projectGuid, name, location, null);
797 }
798  
799 private void WriteProject(TextWriter writer, string language, Guid projectGuid, string name, string location, FilesNode files)
800 {
801 if (!tools.ContainsKey(language))
802 throw new UnknownLanguageException("Unknown .NET language: " + language);
803  
804 ToolInfo toolInfo = tools[language];
805  
806 writer.WriteLine(ProjectDeclarationBeginFormat,
807 toolInfo.Guid,
808 name,
809 location,
810 projectGuid.ToString("B").ToUpper());
811  
812 if (files != null)
813 {
814 writer.WriteLine("\tProjectSection(SolutionItems) = preProject");
815  
816 foreach (string file in files)
817 writer.WriteLine("\t\t{0} = {0}", file);
818  
819 writer.WriteLine("\tEndProjectSection");
820 }
821  
822 writer.WriteLine(ProjectDeclarationEndFormat);
823 }
824  
825 private void WriteDatabaseProject(SolutionNode solution, DatabaseProjectNode project)
826 {
827 string projectFile = Helper.MakeFilePath(project.FullPath, project.Name, "dbp");
828 IndentedTextWriter ps = new IndentedTextWriter(new StreamWriter(projectFile), " ");
829  
830 kernel.CurrentWorkingDirectory.Push();
831  
832 Helper.SetCurrentDir(Path.GetDirectoryName(projectFile));
833  
834 using (ps)
835 {
836 ps.WriteLine("# Microsoft Developer Studio Project File - Database Project");
837 ps.WriteLine("Begin DataProject = \"{0}\"", project.Name);
838 ps.Indent++;
839 ps.WriteLine("MSDTVersion = \"80\"");
840 // TODO: Use the project.Files property
841 if (ContainsSqlFiles(Path.GetDirectoryName(projectFile)))
842 WriteDatabaseFoldersAndFiles(ps, Path.GetDirectoryName(projectFile));
843  
844 ps.WriteLine("Begin DBRefFolder = \"Database References\"");
845 ps.Indent++;
846 foreach (DatabaseReferenceNode reference in project.References)
847 {
848 ps.WriteLine("Begin DBRefNode = \"{0}\"", reference.Name);
849 ps.Indent++;
850 ps.WriteLine("ConnectStr = \"{0}\"", reference.ConnectionString);
851 ps.WriteLine("Provider = \"{0}\"", reference.ProviderId.ToString("B").ToUpper());
852 //ps.WriteLine("Colorizer = 5");
853 ps.Indent--;
854 ps.WriteLine("End");
855 }
856 ps.Indent--;
857 ps.WriteLine("End");
858 ps.Indent--;
859 ps.WriteLine("End");
860  
861 ps.Flush();
862 }
863  
864 kernel.CurrentWorkingDirectory.Pop();
865 }
866  
867 private static bool ContainsSqlFiles(string folder)
868 {
869 if(Directory.GetFiles(folder, "*.sql").Length > 0)
870 return true; // if the folder contains 1 .sql file, that's good enough
871  
872 foreach (string child in Directory.GetDirectories(folder))
873 {
874 if (ContainsSqlFiles(child))
875 return true; // if 1 child folder contains a .sql file, still good enough
876 }
877  
878 return false;
879 }
880  
881 private static void WriteDatabaseFoldersAndFiles(IndentedTextWriter writer, string folder)
882 {
883 foreach (string child in Directory.GetDirectories(folder))
884 {
885 if (ContainsSqlFiles(child))
886 {
887 writer.WriteLine("Begin Folder = \"{0}\"", Path.GetFileName(child));
888 writer.Indent++;
889 WriteDatabaseFoldersAndFiles(writer, child);
890 writer.Indent--;
891 writer.WriteLine("End");
892 }
893 }
894 foreach (string file in Directory.GetFiles(folder, "*.sql"))
895 {
896 writer.WriteLine("Script = \"{0}\"", Path.GetFileName(file));
897 }
898 }
899  
900 private void CleanProject(ProjectNode project)
901 {
902 kernel.Log.Write("...Cleaning project: {0}", project.Name);
903  
904 ToolInfo toolInfo = tools[project.Language];
905 string projectFile = Helper.MakeFilePath(project.FullPath, project.Name, toolInfo.FileExtension);
906 string userFile = projectFile + ".user";
907  
908 Helper.DeleteIfExists(projectFile);
909 Helper.DeleteIfExists(userFile);
910 }
911  
912 private void CleanSolution(SolutionNode solution)
913 {
914 kernel.Log.Write("Cleaning {0} solution and project files", VersionName, solution.Name);
915  
916 string slnFile = Helper.MakeFilePath(solution.FullPath, solution.Name, "sln");
917 string suoFile = Helper.MakeFilePath(solution.FullPath, solution.Name, "suo");
918  
919 Helper.DeleteIfExists(slnFile);
920 Helper.DeleteIfExists(suoFile);
921  
922 foreach (ProjectNode project in solution.Projects)
923 {
924 CleanProject(project);
925 }
926  
927 kernel.Log.Write("");
928 }
929  
930 #endregion
931  
932 #region ITarget Members
933  
934 /// <summary>
935 /// Writes the specified kern.
936 /// </summary>
937 /// <param name="kern">The kern.</param>
938 public virtual void Write(Kernel kern)
939 {
940 if (kern == null)
941 {
942 throw new ArgumentNullException("kern");
943 }
944 kernel = kern;
945 foreach (SolutionNode sol in kernel.Solutions)
946 {
947 WriteSolution(sol, true);
948 }
949 kernel = null;
950 }
951  
952 /// <summary>
953 /// Cleans the specified kern.
954 /// </summary>
955 /// <param name="kern">The kern.</param>
956 public virtual void Clean(Kernel kern)
957 {
958 if (kern == null)
959 {
960 throw new ArgumentNullException("kern");
961 }
962 kernel = kern;
963 foreach (SolutionNode sol in kernel.Solutions)
964 {
965 CleanSolution(sol);
966 }
967 kernel = null;
968 }
969  
970 #endregion
971 }
972 }