2 // Import.cs: Represents a single Import element in an MSBuild project.
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2006 Marek Sieradzki
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using Microsoft.Build.Framework;
35 using Mono.XBuild.Utilities;
37 namespace Microsoft.Build.BuildEngine {
39 XmlElement importElement;
41 ImportedProject originalProject;
42 string evaluatedProjectPath;
44 static string DotConfigExtensionsPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
45 Path.Combine ("xbuild", "tasks"));
46 const string MacOSXExternalXBuildDir = "/Library/Frameworks/Mono.framework/External/xbuild";
47 static string PathSeparatorAsString = Path.PathSeparator.ToString ();
49 internal Import (XmlElement importElement, Project project, ImportedProject originalProject)
51 if (importElement == null)
52 throw new ArgumentNullException ("importElement");
54 throw new ArgumentNullException ("project");
56 this.project = project;
57 this.importElement = importElement;
58 this.originalProject = originalProject;
60 if (ProjectPath == String.Empty)
61 throw new InvalidProjectFileException ("The required attribute \"Project\" is missing from element <Import>.");
63 if (ConditionParser.ParseAndEvaluate (Condition, project)) {
64 evaluatedProjectPath = EvaluateProjectPath (ProjectPath);
65 evaluatedProjectPath = GetFullPath ();
66 if (EvaluatedProjectPath == String.Empty)
67 throw new InvalidProjectFileException ("The required attribute \"Project\" is missing from element <Import>.");
72 internal void Evaluate (bool ignoreMissingImports)
74 string filename = evaluatedProjectPath;
75 // NOTE: it's a hack to transform Microsoft.CSharp.Targets to Microsoft.CSharp.targets
76 if (Path.HasExtension (filename))
77 filename = Path.ChangeExtension (filename, Path.GetExtension (filename));
79 if (!File.Exists (filename)) {
80 if (ignoreMissingImports) {
81 project.LogWarning (project.FullFileName, "Could not find project file {0}, to import. Ignoring.", filename);
84 throw new InvalidProjectFileException (String.Format ("Imported project: \"{0}\" does not exist.", filename));
88 ImportedProject importedProject = new ImportedProject ();
89 importedProject.Load (filename);
91 project.ProcessElements (importedProject.XmlDocument.DocumentElement, importedProject);
94 string EvaluateProjectPath (string file)
97 if (EvaluateAsMSBuildExtensionsPath (file, "MSBuildExtensionsPath", out ret) ||
98 EvaluateAsMSBuildExtensionsPath (file, "MSBuildExtensionsPath32", out ret) ||
99 EvaluateAsMSBuildExtensionsPath (file, "MSBuildExtensionsPath64", out ret))
102 return EvaluatePath (file);
105 bool EvaluateAsMSBuildExtensionsPath (string file, string property_name, out string epath)
108 string property_ref = String.Format ("$({0})", property_name);
109 if (file.IndexOf (property_ref) < 0)
112 // This is a *HACK* to support multiple paths for
113 // MSBuildExtensionsPath property. Normally it would
114 // get resolved to a single value, but here we special
115 // case it and try ~/.config/xbuild/tasks and any
116 // paths specified in the env var $MSBuildExtensionsPath .
118 // The property itself will resolve to the default
119 // location though, so you get in any other part of the
122 string envvar = Environment.GetEnvironmentVariable (property_name);
123 envvar = String.Join (PathSeparatorAsString, new string [] {
124 (envvar ?? String.Empty),
125 // For mac osx, look in the 'External' dir on macosx,
127 MSBuildUtils.RunningOnMac ? MacOSXExternalXBuildDir : String.Empty,
128 DotConfigExtensionsPath});
130 string [] paths = envvar.Split (new char [] {Path.PathSeparator}, StringSplitOptions.RemoveEmptyEntries);
131 foreach (string path in paths) {
132 if (!Directory.Exists (path)) {
133 project.ParentEngine.LogMessage (MessageImportance.Low, "Extension path '{0}' not found, ignoring.", path);
137 string pfile = Path.GetFullPath (file.Replace ("\\", "/").Replace (
138 property_ref, path + Path.DirectorySeparatorChar));
140 var evaluated_path = EvaluatePath (pfile);
141 if (File.Exists (evaluated_path)) {
142 project.ParentEngine.LogMessage (MessageImportance.Low,
143 "{0}: Importing project {1} from extension path {2}", project.FullFileName, evaluated_path, path);
147 project.ParentEngine.LogMessage (MessageImportance.Low,
148 "{0}: Couldn't find project {1} for extension path {2}", project.FullFileName, evaluated_path, path);
154 string EvaluatePath (string path)
156 var exp = new Expression ();
157 exp.Parse (path, ParseOptions.Split);
158 return (string) exp.ConvertTo (project, typeof (string));
161 string GetFullPath ()
163 string file = EvaluatedProjectPath;
165 if (!Path.IsPathRooted (EvaluatedProjectPath)) {
167 if (originalProject == null) {
168 if (project.FullFileName != String.Empty) // Path.GetDirectoryName throws exception on String.Empty
169 dir = Path.GetDirectoryName (project.FullFileName);
171 if (originalProject.FullFileName != String.Empty)
172 dir = Path.GetDirectoryName (originalProject.FullFileName);
175 file = Path.Combine (dir, EvaluatedProjectPath);
178 return MSBuildUtils.FromMSBuildPath (file);
181 public string Condition {
183 string s = importElement.GetAttribute ("Condition");
184 return s == String.Empty ? null : s;
188 public string EvaluatedProjectPath {
189 get { return evaluatedProjectPath; }
192 public bool IsImported {
193 get { return originalProject != null; }
196 public string ProjectPath {
197 get { return importElement.GetAttribute ("Project"); }