2014-08-13 10:39:27 +01:00
//
// Project.cs: Project class
//
// Author:
// Marek Sieradzki (marek.sieradzki@gmail.com)
// Ankit Jain (jankit@novell.com)
//
// (C) 2005 Marek Sieradzki
// Copyright 2011 Novell, Inc (http://www.novell.com)
//
// 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.Collections ;
using System.Collections.Generic ;
using System.Collections.Specialized ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using System.Text ;
using System.Xml ;
using System.Xml.Schema ;
using Microsoft.Build.Framework ;
using Microsoft.Build.Utilities ;
using Mono.XBuild.Framework ;
using Mono.XBuild.CommandLine ;
namespace Microsoft.Build.BuildEngine {
public class Project {
bool buildEnabled ;
Dictionary < string , List < string > > conditionedProperties ;
string [ ] defaultTargets ;
Encoding encoding ;
BuildItemGroup evaluatedItems ;
BuildItemGroup evaluatedItemsIgnoringCondition ;
Dictionary < string , BuildItemGroup > evaluatedItemsByName ;
Dictionary < string , BuildItemGroup > evaluatedItemsByNameIgnoringCondition ;
BuildPropertyGroup evaluatedProperties ;
string firstTargetName ;
string fullFileName ;
BuildPropertyGroup globalProperties ;
GroupingCollection groupingCollection ;
bool isDirty ;
bool isValidated ;
BuildItemGroupCollection itemGroups ;
ImportCollection imports ;
List < string > initialTargets ;
Dictionary < string , BuildItemGroup > last_item_group_containing ;
bool needToReevaluate ;
Engine parentEngine ;
BuildPropertyGroupCollection propertyGroups ;
string schemaFile ;
TaskDatabase taskDatabase ;
TargetCollection targets ;
DateTime timeOfLastDirty ;
UsingTaskCollection usingTasks ;
XmlDocument xmlDocument ;
bool unloaded ;
bool initialTargetsBuilt ;
bool building ;
BuildSettings current_settings ;
Stack < Batch > batches ;
// This is used to keep track of "current" file,
// which is then used to set the reserved properties
// $(MSBuildThisFile*)
Stack < string > this_file_property_stack ;
ProjectLoadSettings project_load_settings ;
static string extensions_path ;
static XmlNamespaceManager manager ;
static string ns = "http://schemas.microsoft.com/developer/msbuild/2003" ;
public Project ( )
: this ( Engine . GlobalEngine )
{
}
public Project ( Engine engine ) : this ( engine , null )
{
}
public Project ( Engine engine , string toolsVersion )
{
parentEngine = engine ;
ToolsVersion = toolsVersion ;
buildEnabled = ParentEngine . BuildEnabled ;
xmlDocument = new XmlDocument ( ) ;
xmlDocument . PreserveWhitespace = false ;
xmlDocument . AppendChild ( xmlDocument . CreateElement ( "Project" , XmlNamespace ) ) ;
xmlDocument . DocumentElement . SetAttribute ( "xmlns" , ns ) ;
fullFileName = String . Empty ;
timeOfLastDirty = DateTime . Now ;
current_settings = BuildSettings . None ;
project_load_settings = ProjectLoadSettings . None ;
encoding = null ;
initialTargets = new List < string > ( ) ;
defaultTargets = new string [ 0 ] ;
batches = new Stack < Batch > ( ) ;
this_file_property_stack = new Stack < string > ( ) ;
globalProperties = new BuildPropertyGroup ( null , this , null , false ) ;
foreach ( BuildProperty bp in parentEngine . GlobalProperties )
GlobalProperties . AddProperty ( bp . Clone ( true ) ) ;
ProcessXml ( ) ;
}
[MonoTODO ("Not tested")]
public void AddNewImport ( string importLocation ,
string importCondition )
{
if ( importLocation = = null )
throw new ArgumentNullException ( "importLocation" ) ;
XmlElement importElement = xmlDocument . CreateElement ( "Import" , XmlNamespace ) ;
xmlDocument . DocumentElement . AppendChild ( importElement ) ;
importElement . SetAttribute ( "Project" , importLocation ) ;
if ( ! String . IsNullOrEmpty ( importCondition ) )
importElement . SetAttribute ( "Condition" , importCondition ) ;
AddImport ( importElement , null , false ) ;
MarkProjectAsDirty ( ) ;
NeedToReevaluate ( ) ;
}
public BuildItem AddNewItem ( string itemName ,
string itemInclude )
{
return AddNewItem ( itemName , itemInclude , false ) ;
}
[MonoTODO ("Adds item not in the same place as MS")]
public BuildItem AddNewItem ( string itemName ,
string itemInclude ,
bool treatItemIncludeAsLiteral )
{
BuildItemGroup big ;
if ( itemGroups . Count = = 0 )
big = AddNewItemGroup ( ) ;
else {
if ( last_item_group_containing . ContainsKey ( itemName ) ) {
big = last_item_group_containing [ itemName ] ;
} else {
// FIXME: not tested
BuildItemGroup [ ] groups = new BuildItemGroup [ itemGroups . Count ] ;
itemGroups . CopyTo ( groups , 0 ) ;
big = groups [ 0 ] ;
}
}
BuildItem item = big . AddNewItem ( itemName , itemInclude , treatItemIncludeAsLiteral ) ;
MarkProjectAsDirty ( ) ;
NeedToReevaluate ( ) ;
return item ;
}
[MonoTODO ("Not tested")]
public BuildItemGroup AddNewItemGroup ( )
{
XmlElement element = xmlDocument . CreateElement ( "ItemGroup" , XmlNamespace ) ;
xmlDocument . DocumentElement . AppendChild ( element ) ;
BuildItemGroup big = new BuildItemGroup ( element , this , null , false ) ;
itemGroups . Add ( big ) ;
MarkProjectAsDirty ( ) ;
NeedToReevaluate ( ) ;
return big ;
}
[MonoTODO ("Ignores insertAtEndOfProject")]
public BuildPropertyGroup AddNewPropertyGroup ( bool insertAtEndOfProject )
{
XmlElement element = xmlDocument . CreateElement ( "PropertyGroup" , XmlNamespace ) ;
xmlDocument . DocumentElement . AppendChild ( element ) ;
BuildPropertyGroup bpg = new BuildPropertyGroup ( element , this , null , false ) ;
propertyGroups . Add ( bpg ) ;
MarkProjectAsDirty ( ) ;
NeedToReevaluate ( ) ;
return bpg ;
}
[MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
public void AddNewUsingTaskFromAssemblyFile ( string taskName ,
string assemblyFile )
{
if ( taskName = = null )
throw new ArgumentNullException ( "taskName" ) ;
if ( assemblyFile = = null )
throw new ArgumentNullException ( "assemblyFile" ) ;
XmlElement element = xmlDocument . CreateElement ( "UsingTask" , XmlNamespace ) ;
xmlDocument . DocumentElement . AppendChild ( element ) ;
element . SetAttribute ( "TaskName" , taskName ) ;
element . SetAttribute ( "AssemblyFile" , assemblyFile ) ;
UsingTask ut = new UsingTask ( element , this , null ) ;
usingTasks . Add ( ut ) ;
MarkProjectAsDirty ( ) ;
}
[MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
public void AddNewUsingTaskFromAssemblyName ( string taskName ,
string assemblyName )
{
if ( taskName = = null )
throw new ArgumentNullException ( "taskName" ) ;
if ( assemblyName = = null )
throw new ArgumentNullException ( "assemblyName" ) ;
XmlElement element = xmlDocument . CreateElement ( "UsingTask" , XmlNamespace ) ;
xmlDocument . DocumentElement . AppendChild ( element ) ;
element . SetAttribute ( "TaskName" , taskName ) ;
element . SetAttribute ( "AssemblyName" , assemblyName ) ;
UsingTask ut = new UsingTask ( element , this , null ) ;
usingTasks . Add ( ut ) ;
MarkProjectAsDirty ( ) ;
}
[MonoTODO ("Not tested")]
public bool Build ( )
{
return Build ( new string [ 0 ] ) ;
}
[MonoTODO ("Not tested")]
public bool Build ( string targetName )
{
if ( targetName = = null )
return Build ( ( string [ ] ) null ) ;
else
return Build ( new string [ 1 ] { targetName } ) ;
}
[MonoTODO ("Not tested")]
public bool Build ( string [ ] targetNames )
{
return Build ( targetNames , null ) ;
}
[MonoTODO ("Not tested")]
public bool Build ( string [ ] targetNames ,
IDictionary targetOutputs )
{
return Build ( targetNames , targetOutputs , BuildSettings . None ) ;
}
[MonoTODO ("Not tested")]
public bool Build ( string [ ] targetNames ,
IDictionary targetOutputs ,
BuildSettings buildFlags )
{
bool result = false ;
ParentEngine . StartProjectBuild ( this , targetNames ) ;
// Invoking this to emit a warning in case of unsupported
// ToolsVersion
GetToolsVersionToUse ( true ) ;
string current_directory = Environment . CurrentDirectory ;
try {
current_settings = buildFlags ;
if ( ! String . IsNullOrEmpty ( fullFileName ) )
Directory . SetCurrentDirectory ( Path . GetDirectoryName ( fullFileName ) ) ;
building = true ;
result = BuildInternal ( targetNames , targetOutputs , buildFlags ) ;
} catch ( InvalidProjectFileException ie ) {
ParentEngine . LogErrorWithFilename ( fullFileName , ie . Message ) ;
ParentEngine . LogMessage ( MessageImportance . Low , String . Format ( "{0}: {1}" , fullFileName , ie . ToString ( ) ) ) ;
} catch ( Exception e ) {
ParentEngine . LogErrorWithFilename ( fullFileName , e . Message ) ;
ParentEngine . LogMessage ( MessageImportance . Low , String . Format ( "{0}: {1}" , fullFileName , e . ToString ( ) ) ) ;
throw ;
} finally {
ParentEngine . EndProjectBuild ( this , result ) ;
current_settings = BuildSettings . None ;
Directory . SetCurrentDirectory ( current_directory ) ;
building = false ;
}
return result ;
}
bool BuildInternal ( string [ ] targetNames ,
IDictionary targetOutputs ,
BuildSettings buildFlags )
{
CheckUnloaded ( ) ;
if ( buildFlags = = BuildSettings . None ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
ProcessBeforeAndAfterTargets ( ) ;
if ( targetNames = = null | | targetNames . Length = = 0 ) {
if ( defaultTargets ! = null & & defaultTargets . Length ! = 0 ) {
targetNames = defaultTargets ;
} else if ( firstTargetName ! = null ) {
targetNames = new string [ 1 ] { firstTargetName } ;
} else {
if ( targets = = null | | targets . Count = = 0 ) {
LogError ( fullFileName , "No target found in the project" ) ;
return false ;
}
return false ;
}
}
if ( ! initialTargetsBuilt ) {
foreach ( string target in initialTargets ) {
if ( ! BuildTarget ( target . Trim ( ) , targetOutputs ) )
return false ;
}
initialTargetsBuilt = true ;
}
foreach ( string target in targetNames ) {
if ( target = = null )
throw new ArgumentNullException ( "Target name cannot be null" ) ;
if ( ! BuildTarget ( target . Trim ( ) , targetOutputs ) )
return false ;
}
return true ;
}
bool BuildTarget ( string target_name , IDictionary targetOutputs )
{
if ( target_name = = null )
throw new ArgumentException ( "targetNames cannot contain null strings" ) ;
if ( ! targets . Exists ( target_name ) ) {
LogError ( fullFileName , "Target named '{0}' not found in the project." , target_name ) ;
return false ;
}
string key = GetKeyForTarget ( target_name ) ;
if ( ! targets [ target_name ] . Build ( key ) )
return false ;
ITaskItem [ ] outputs ;
if ( ParentEngine . BuiltTargetsOutputByName . TryGetValue ( key , out outputs ) ) {
if ( targetOutputs ! = null )
targetOutputs . Add ( target_name , outputs ) ;
}
return true ;
}
internal string GetKeyForTarget ( string target_name )
{
return GetKeyForTarget ( target_name , true ) ;
}
internal string GetKeyForTarget ( string target_name , bool include_global_properties )
{
// target name is case insensitive
return fullFileName + ":" + target_name . ToLowerInvariant ( ) +
( include_global_properties ? ( ":" + GlobalPropertiesToString ( GlobalProperties ) )
: String . Empty ) ;
}
string GlobalPropertiesToString ( BuildPropertyGroup bgp )
{
StringBuilder sb = new StringBuilder ( ) ;
foreach ( BuildProperty bp in bgp )
sb . AppendFormat ( " {0}:{1}" , bp . Name , bp . FinalValue ) ;
return sb . ToString ( ) ;
}
void ProcessBeforeAndAfterTargets ( )
{
var beforeTable = Targets . AsIEnumerable ( )
. SelectMany ( target = > GetTargetNamesFromString ( target . BeforeTargets ) ,
( target , before_target ) = > new { before_target , name = target . Name } )
. ToLookup ( x = > x . before_target , x = > x . name )
. ToDictionary ( x = > x . Key , x = > x . Distinct ( ) . ToList ( ) ) ;
foreach ( var pair in beforeTable ) {
if ( targets . Exists ( pair . Key ) )
targets [ pair . Key ] . BeforeThisTargets = pair . Value ;
else
LogWarning ( FullFileName , "Target '{0}', not found in the project" , pair . Key ) ;
}
var afterTable = Targets . AsIEnumerable ( )
. SelectMany ( target = > GetTargetNamesFromString ( target . AfterTargets ) ,
( target , after_target ) = > new { after_target , name = target . Name } )
. ToLookup ( x = > x . after_target , x = > x . name )
. ToDictionary ( x = > x . Key , x = > x . Distinct ( ) . ToList ( ) ) ;
foreach ( var pair in afterTable ) {
if ( targets . Exists ( pair . Key ) )
targets [ pair . Key ] . AfterThisTargets = pair . Value ;
else
LogWarning ( FullFileName , "Target '{0}', not found in the project" , pair . Key ) ;
}
}
string [ ] GetTargetNamesFromString ( string targets )
{
Expression expr = new Expression ( ) ;
expr . Parse ( targets , ParseOptions . AllowItemsNoMetadataAndSplit ) ;
return ( string [ ] ) expr . ConvertTo ( this , typeof ( string [ ] ) ) ;
}
[MonoTODO]
public string [ ] GetConditionedPropertyValues ( string propertyName )
{
if ( conditionedProperties . ContainsKey ( propertyName ) )
return conditionedProperties [ propertyName ] . ToArray ( ) ;
else
return new string [ 0 ] ;
}
public BuildItemGroup GetEvaluatedItemsByName ( string itemName )
{
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
if ( evaluatedItemsByName . ContainsKey ( itemName ) )
return evaluatedItemsByName [ itemName ] ;
else
return new BuildItemGroup ( this ) ;
}
public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition ( string itemName )
{
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
if ( evaluatedItemsByNameIgnoringCondition . ContainsKey ( itemName ) )
return evaluatedItemsByNameIgnoringCondition [ itemName ] ;
else
return new BuildItemGroup ( this ) ;
}
public string GetEvaluatedProperty ( string propertyName )
{
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
if ( propertyName = = null )
throw new ArgumentNullException ( "propertyName" ) ;
BuildProperty bp = evaluatedProperties [ propertyName ] ;
return bp = = null ? null : ( string ) bp ;
}
[MonoTODO ("We should remember that node and not use XPath to get it")]
public string GetProjectExtensions ( string id )
{
if ( id = = null | | id = = String . Empty )
return String . Empty ;
XmlNode node = xmlDocument . SelectSingleNode ( String . Format ( "/tns:Project/tns:ProjectExtensions/tns:{0}" , id ) , XmlNamespaceManager ) ;
if ( node = = null )
return String . Empty ;
else
return node . InnerXml ;
}
public void Load ( string projectFileName )
{
Load ( projectFileName , ProjectLoadSettings . None ) ;
}
public void Load ( string projectFileName , ProjectLoadSettings settings )
{
project_load_settings = settings ;
if ( String . IsNullOrEmpty ( projectFileName ) )
throw new ArgumentNullException ( "projectFileName" ) ;
if ( ! File . Exists ( projectFileName ) )
throw new ArgumentException ( String . Format ( "Project file {0} not found" , projectFileName ) ,
"projectFileName" ) ;
this . fullFileName = Utilities . FromMSBuildPath ( Path . GetFullPath ( projectFileName ) ) ;
PushThisFileProperty ( fullFileName ) ;
string filename = fullFileName ;
if ( String . Compare ( Path . GetExtension ( fullFileName ) , ".sln" , true ) = = 0 ) {
Project tmp_project = ParentEngine . CreateNewProject ( ) ;
tmp_project . FullFileName = filename ;
SolutionParser sln_parser = new SolutionParser ( ) ;
sln_parser . ParseSolution ( fullFileName , tmp_project , delegate ( int errorNumber , string message ) {
LogWarning ( filename , message ) ;
} ) ;
filename = fullFileName + ".proj" ;
try {
tmp_project . Save ( filename ) ;
ParentEngine . RemoveLoadedProject ( tmp_project ) ;
DoLoad ( new StreamReader ( filename ) ) ;
} finally {
if ( Environment . GetEnvironmentVariable ( "XBUILD_EMIT_SOLUTION" ) = = null )
File . Delete ( filename ) ;
}
} else {
DoLoad ( new StreamReader ( filename ) ) ;
}
}
[MonoTODO ("Not tested")]
public void Load ( TextReader textReader )
{
Load ( textReader , ProjectLoadSettings . None ) ;
}
public void Load ( TextReader textReader , ProjectLoadSettings projectLoadSettings )
{
project_load_settings = projectLoadSettings ;
if ( ! string . IsNullOrEmpty ( fullFileName ) )
PushThisFileProperty ( fullFileName ) ;
DoLoad ( textReader ) ;
}
public void LoadXml ( string projectXml )
{
LoadXml ( projectXml , ProjectLoadSettings . None ) ;
}
public void LoadXml ( string projectXml , ProjectLoadSettings projectLoadSettings )
{
project_load_settings = projectLoadSettings ;
if ( ! string . IsNullOrEmpty ( fullFileName ) )
PushThisFileProperty ( fullFileName ) ;
DoLoad ( new StringReader ( projectXml ) ) ;
MarkProjectAsDirty ( ) ;
}
public void MarkProjectAsDirty ( )
{
isDirty = true ;
timeOfLastDirty = DateTime . Now ;
}
[MonoTODO ("Not tested")]
public void RemoveAllItemGroups ( )
{
int length = ItemGroups . Count ;
BuildItemGroup [ ] groups = new BuildItemGroup [ length ] ;
ItemGroups . CopyTo ( groups , 0 ) ;
for ( int i = 0 ; i < length ; i + + )
RemoveItemGroup ( groups [ i ] ) ;
MarkProjectAsDirty ( ) ;
NeedToReevaluate ( ) ;
}
[MonoTODO ("Not tested")]
public void RemoveAllPropertyGroups ( )
{
int length = PropertyGroups . Count ;
BuildPropertyGroup [ ] groups = new BuildPropertyGroup [ length ] ;
PropertyGroups . CopyTo ( groups , 0 ) ;
for ( int i = 0 ; i < length ; i + + )
RemovePropertyGroup ( groups [ i ] ) ;
MarkProjectAsDirty ( ) ;
NeedToReevaluate ( ) ;
}
[MonoTODO]
public void RemoveItem ( BuildItem itemToRemove )
{
if ( itemToRemove = = null )
throw new ArgumentNullException ( "itemToRemove" ) ;
if ( ! itemToRemove . FromXml & & ! itemToRemove . HasParentItem )
throw new InvalidOperationException ( "The object passed in is not part of the project." ) ;
BuildItemGroup big = itemToRemove . ParentItemGroup ;
if ( big . Count = = 1 ) {
// ParentItemGroup for items from xml and that have parent is the same
groupingCollection . Remove ( big ) ;
} else {
if ( big . ParentProject ! = this )
throw new InvalidOperationException ( "The object passed in is not part of the project." ) ;
if ( itemToRemove . FromXml )
big . RemoveItem ( itemToRemove ) ;
else
big . RemoveItem ( itemToRemove . ParentItem ) ;
}
MarkProjectAsDirty ( ) ;
NeedToReevaluate ( ) ;
}
[MonoTODO ("Not tested")]
public void RemoveItemGroup ( BuildItemGroup itemGroupToRemove )
{
if ( itemGroupToRemove = = null )
throw new ArgumentNullException ( "itemGroupToRemove" ) ;
groupingCollection . Remove ( itemGroupToRemove ) ;
MarkProjectAsDirty ( ) ;
}
[MonoTODO]
// NOTE: does not modify imported projects
public void RemoveItemGroupsWithMatchingCondition ( string matchingCondition )
{
throw new NotImplementedException ( ) ;
}
[MonoTODO]
public void RemoveItemsByName ( string itemName )
{
if ( itemName = = null )
throw new ArgumentNullException ( "itemName" ) ;
throw new NotImplementedException ( ) ;
}
[MonoTODO ("Not tested")]
public void RemovePropertyGroup ( BuildPropertyGroup propertyGroupToRemove )
{
if ( propertyGroupToRemove = = null )
throw new ArgumentNullException ( "propertyGroupToRemove" ) ;
groupingCollection . Remove ( propertyGroupToRemove ) ;
MarkProjectAsDirty ( ) ;
}
[MonoTODO]
// NOTE: does not modify imported projects
public void RemovePropertyGroupsWithMatchingCondition ( string matchCondition )
{
throw new NotImplementedException ( ) ;
}
[MonoTODO]
public void ResetBuildStatus ( )
{
// hack to allow built targets to be removed
building = true ;
Reevaluate ( ) ;
building = false ;
}
public void Save ( string projectFileName )
{
Save ( projectFileName , Encoding . Default ) ;
isDirty = false ;
}
[MonoTODO ("Ignores encoding")]
public void Save ( string projectFileName , Encoding encoding )
{
xmlDocument . Save ( projectFileName ) ;
isDirty = false ;
}
public void Save ( TextWriter outTextWriter )
{
xmlDocument . Save ( outTextWriter ) ;
isDirty = false ;
}
public void SetImportedProperty ( string propertyName ,
string propertyValue ,
string condition ,
Project importProject )
{
SetImportedProperty ( propertyName , propertyValue , condition , importProject ,
PropertyPosition . UseExistingOrCreateAfterLastPropertyGroup ) ;
}
public void SetImportedProperty ( string propertyName ,
string propertyValue ,
string condition ,
Project importedProject ,
PropertyPosition position )
{
SetImportedProperty ( propertyName , propertyValue , condition , importedProject ,
PropertyPosition . UseExistingOrCreateAfterLastPropertyGroup , false ) ;
}
[MonoTODO]
public void SetImportedProperty ( string propertyName ,
string propertyValue ,
string condition ,
Project importedProject ,
PropertyPosition position ,
bool treatPropertyValueAsLiteral )
{
throw new NotImplementedException ( ) ;
}
public void SetProjectExtensions ( string id , string xmlText )
{
if ( id = = null )
throw new ArgumentNullException ( "id" ) ;
if ( xmlText = = null )
throw new ArgumentNullException ( "xmlText" ) ;
XmlNode projectExtensions , node ;
projectExtensions = xmlDocument . SelectSingleNode ( "/tns:Project/tns:ProjectExtensions" , XmlNamespaceManager ) ;
if ( projectExtensions = = null ) {
projectExtensions = xmlDocument . CreateElement ( "ProjectExtensions" , XmlNamespace ) ;
xmlDocument . DocumentElement . AppendChild ( projectExtensions ) ;
node = xmlDocument . CreateElement ( id , XmlNamespace ) ;
node . InnerXml = xmlText ;
projectExtensions . AppendChild ( node ) ;
} else {
node = xmlDocument . SelectSingleNode ( String . Format ( "/tns:Project/tns:ProjectExtensions/tns:{0}" , id ) , XmlNamespaceManager ) ;
if ( node = = null ) {
node = xmlDocument . CreateElement ( id , XmlNamespace ) ;
projectExtensions . AppendChild ( node ) ;
}
node . InnerXml = xmlText ;
}
MarkProjectAsDirty ( ) ;
}
public void SetProperty ( string propertyName ,
string propertyValue )
{
SetProperty ( propertyName , propertyValue , "true" ,
PropertyPosition . UseExistingOrCreateAfterLastPropertyGroup , false ) ;
}
public void SetProperty ( string propertyName ,
string propertyValue ,
string condition )
{
SetProperty ( propertyName , propertyValue , condition ,
PropertyPosition . UseExistingOrCreateAfterLastPropertyGroup ) ;
}
public void SetProperty ( string propertyName ,
string propertyValue ,
string condition ,
PropertyPosition position )
{
SetProperty ( propertyName , propertyValue , condition ,
PropertyPosition . UseExistingOrCreateAfterLastPropertyGroup , false ) ;
}
[MonoTODO]
public void SetProperty ( string propertyName ,
string propertyValue ,
string condition ,
PropertyPosition position ,
bool treatPropertyValueAsLiteral )
{
throw new NotImplementedException ( ) ;
}
internal void Unload ( )
{
unloaded = true ;
}
internal void CheckUnloaded ( )
{
if ( unloaded )
throw new InvalidOperationException ( "This project object has been unloaded from the MSBuild engine and is no longer valid." ) ;
}
internal void NeedToReevaluate ( )
{
needToReevaluate = true ;
}
// Does the actual loading.
void DoLoad ( TextReader textReader )
{
try {
ParentEngine . RemoveLoadedProject ( this ) ;
xmlDocument . Load ( textReader ) ;
if ( xmlDocument . DocumentElement . Name = = "VisualStudioProject" )
throw new InvalidProjectFileException ( String . Format (
"Project file '{0}' is a VS2003 project, which is not " +
"supported by xbuild. You need to convert it to msbuild " +
"format to build with xbuild." , fullFileName ) ) ;
if ( SchemaFile ! = null ) {
xmlDocument . Schemas . Add ( XmlSchema . Read (
new StreamReader ( SchemaFile ) , ValidationCallBack ) ) ;
xmlDocument . Validate ( ValidationCallBack ) ;
}
if ( xmlDocument . DocumentElement . Name ! = "Project" ) {
throw new InvalidProjectFileException ( String . Format (
"The element <{0}> is unrecognized, or not supported in this context." , xmlDocument . DocumentElement . Name ) ) ;
}
if ( xmlDocument . DocumentElement . GetAttribute ( "xmlns" ) ! = ns ) {
throw new InvalidProjectFileException (
@"The default XML namespace of the project must be the MSBuild XML namespace." +
" If the project is authored in the MSBuild 2003 format, please add " +
"xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
"If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format. " ) ;
}
ProcessXml ( ) ;
ParentEngine . AddLoadedProject ( this ) ;
} catch ( Exception e ) {
throw new InvalidProjectFileException ( String . Format ( "{0}: {1}" ,
fullFileName , e . Message ) , e ) ;
} finally {
if ( textReader ! = null )
textReader . Close ( ) ;
}
}
void Reevaluate ( )
{
ProcessXml ( ) ;
}
void ProcessXml ( )
{
groupingCollection = new GroupingCollection ( this ) ;
imports = new ImportCollection ( groupingCollection ) ;
usingTasks = new UsingTaskCollection ( this ) ;
itemGroups = new BuildItemGroupCollection ( groupingCollection ) ;
propertyGroups = new BuildPropertyGroupCollection ( groupingCollection ) ;
targets = new TargetCollection ( this ) ;
last_item_group_containing = new Dictionary < string , BuildItemGroup > ( ) ;
string effective_tools_version = GetToolsVersionToUse ( false ) ;
taskDatabase = new TaskDatabase ( ) ;
taskDatabase . CopyTasks ( ParentEngine . GetDefaultTasks ( effective_tools_version ) ) ;
initialTargets = new List < string > ( ) ;
defaultTargets = new string [ 0 ] ;
PrepareForEvaluate ( effective_tools_version ) ;
ProcessElements ( xmlDocument . DocumentElement , null ) ;
isDirty = false ;
Evaluate ( ) ;
}
void ProcessProjectAttributes ( XmlAttributeCollection attributes )
{
foreach ( XmlAttribute attr in attributes ) {
switch ( attr . Name ) {
case "InitialTargets" :
initialTargets . AddRange ( attr . Value . Split (
new char [ ] { ';' , ' ' } ,
StringSplitOptions . RemoveEmptyEntries ) ) ;
break ;
case "DefaultTargets" :
// first non-empty DefaultTargets found is used
if ( defaultTargets = = null | | defaultTargets . Length = = 0 )
defaultTargets = attr . Value . Split ( new char [ ] { ';' , ' ' } ,
StringSplitOptions . RemoveEmptyEntries ) ;
EvaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildProjectDefaultTargets" ,
DefaultTargets , PropertyType . Reserved ) ) ;
break ;
}
}
}
internal void ProcessElements ( XmlElement rootElement , ImportedProject ip )
{
ProcessProjectAttributes ( rootElement . Attributes ) ;
foreach ( XmlNode xn in rootElement . ChildNodes ) {
if ( xn is XmlElement ) {
XmlElement xe = ( XmlElement ) xn ;
switch ( xe . Name ) {
case "ProjectExtensions" :
AddProjectExtensions ( xe ) ;
break ;
case "Warning" :
case "Message" :
case "Error" :
AddMessage ( xe ) ;
break ;
case "Target" :
AddTarget ( xe , ip ) ;
break ;
case "UsingTask" :
AddUsingTask ( xe , ip ) ;
break ;
case "Import" :
AddImport ( xe , ip , true ) ;
break ;
case "ImportGroup" :
AddImportGroup ( xe , ip , true ) ;
break ;
case "ItemGroup" :
AddItemGroup ( xe , ip ) ;
break ;
case "PropertyGroup" :
AddPropertyGroup ( xe , ip ) ;
break ;
case "Choose" :
AddChoose ( xe , ip ) ;
break ;
case "ItemDefinitionGroup" :
AddItemDefinitionGroup ( xe ) ;
break ;
default :
var pf = ip = = null ? null : string . Format ( " '{0}'" , ip . FullFileName ) ;
throw new InvalidProjectFileException ( String . Format ( "Invalid element '{0}' in project file{1}." , xe . Name , pf ) ) ;
}
}
}
}
void PrepareForEvaluate ( string effective_tools_version )
{
evaluatedItems = new BuildItemGroup ( null , this , null , true ) ;
evaluatedItemsIgnoringCondition = new BuildItemGroup ( null , this , null , true ) ;
evaluatedItemsByName = new Dictionary < string , BuildItemGroup > ( StringComparer . OrdinalIgnoreCase ) ;
evaluatedItemsByNameIgnoringCondition = new Dictionary < string , BuildItemGroup > ( StringComparer . OrdinalIgnoreCase ) ;
if ( building & & current_settings = = BuildSettings . None )
RemoveBuiltTargets ( ) ;
InitializeProperties ( effective_tools_version ) ;
}
void Evaluate ( )
{
groupingCollection . Evaluate ( ) ;
//FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
foreach ( UsingTask usingTask in UsingTasks )
usingTask . Evaluate ( ) ;
}
// Removes entries of all earlier built targets for this project
void RemoveBuiltTargets ( )
{
ParentEngine . ClearBuiltTargetsForProject ( this ) ;
}
void InitializeProperties ( string effective_tools_version )
{
BuildProperty bp ;
evaluatedProperties = new BuildPropertyGroup ( null , null , null , true ) ;
conditionedProperties = new Dictionary < string , List < string > > ( ) ;
foreach ( BuildProperty gp in GlobalProperties ) {
bp = new BuildProperty ( gp . Name , gp . Value , PropertyType . Global ) ;
evaluatedProperties . AddProperty ( bp ) ;
}
foreach ( BuildProperty gp in GlobalProperties )
ParentEngine . GlobalProperties . AddProperty ( gp ) ;
// add properties that we dont have from parent engine's
// global properties
foreach ( BuildProperty gp in ParentEngine . GlobalProperties ) {
if ( evaluatedProperties [ gp . Name ] = = null ) {
bp = new BuildProperty ( gp . Name , gp . Value , PropertyType . Global ) ;
evaluatedProperties . AddProperty ( bp ) ;
}
}
foreach ( DictionaryEntry de in Environment . GetEnvironmentVariables ( ) ) {
bp = new BuildProperty ( ( string ) de . Key , ( string ) de . Value , PropertyType . Environment ) ;
evaluatedProperties . AddProperty ( bp ) ;
}
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildProjectFile" , Path . GetFileName ( fullFileName ) ,
PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildProjectFullPath" , fullFileName , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildProjectName" ,
Path . GetFileNameWithoutExtension ( fullFileName ) ,
PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildProjectExtension" ,
Path . GetExtension ( fullFileName ) ,
PropertyType . Reserved ) ) ;
string toolsPath = parentEngine . Toolsets [ effective_tools_version ] . ToolsPath ;
if ( toolsPath = = null )
throw new Exception ( String . Format ( "Invalid tools version '{0}', no tools path set for this." , effective_tools_version ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildBinPath" , toolsPath , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildToolsPath" , toolsPath , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildToolsRoot" , Path . GetDirectoryName ( toolsPath ) , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildToolsVersion" , effective_tools_version , PropertyType . Reserved ) ) ;
SetExtensionsPathProperties ( DefaultExtensionsPath ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildProjectDefaultTargets" , DefaultTargets , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "OS" , OS , PropertyType . Environment ) ) ;
#if XBUILD_12
// see http://msdn.microsoft.com/en-us/library/vstudio/hh162058(v=vs.120).aspx
if ( effective_tools_version = = "12.0" ) {
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildToolsPath32" , toolsPath , PropertyType . Reserved ) ) ;
var frameworkToolsPath = ToolLocationHelper . GetPathToDotNetFramework ( TargetDotNetFrameworkVersion . Version451 ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildFrameworkToolsPath" , frameworkToolsPath , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildFrameworkToolsPath32" , frameworkToolsPath , PropertyType . Reserved ) ) ;
}
#endif
// FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
string projectDir ;
if ( FullFileName = = String . Empty )
projectDir = Environment . CurrentDirectory ;
else
projectDir = Path . GetDirectoryName ( FullFileName ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildProjectDirectory" , projectDir , PropertyType . Reserved ) ) ;
if ( this_file_property_stack . Count > 0 )
// Just re-inited the properties, but according to the stack,
// we should have a MSBuild*This* property set
SetMSBuildThisFileProperties ( this_file_property_stack . Peek ( ) ) ;
}
internal void SetExtensionsPathProperties ( string extn_path )
{
if ( ! String . IsNullOrEmpty ( extn_path ) ) {
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildExtensionsPath" , extn_path , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildExtensionsPath32" , extn_path , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildExtensionsPath64" , extn_path , PropertyType . Reserved ) ) ;
}
}
// precedence:
// ToolsVersion property
// ToolsVersion attribute on the project
// parentEngine's DefaultToolsVersion
string GetToolsVersionToUse ( bool emitWarning )
{
if ( ! String . IsNullOrEmpty ( ToolsVersion ) )
return ToolsVersion ;
if ( ! HasToolsVersionAttribute )
return parentEngine . DefaultToolsVersion ;
if ( parentEngine . Toolsets [ DefaultToolsVersion ] = = null ) {
if ( emitWarning )
LogWarning ( FullFileName , "Project has unknown ToolsVersion '{0}'. Using the default tools version '{1}' instead." ,
DefaultToolsVersion , parentEngine . DefaultToolsVersion ) ;
return parentEngine . DefaultToolsVersion ;
}
return DefaultToolsVersion ;
}
void AddProjectExtensions ( XmlElement xmlElement )
{
}
void AddMessage ( XmlElement xmlElement )
{
}
void AddTarget ( XmlElement xmlElement , ImportedProject importedProject )
{
Target target = new Target ( xmlElement , this , importedProject ) ;
targets . AddTarget ( target ) ;
if ( firstTargetName = = null )
firstTargetName = target . Name ;
}
void AddUsingTask ( XmlElement xmlElement , ImportedProject importedProject )
{
UsingTask usingTask ;
usingTask = new UsingTask ( xmlElement , this , importedProject ) ;
UsingTasks . Add ( usingTask ) ;
}
void AddImport ( XmlElement xmlElement , ImportedProject importingProject , bool evaluate_properties )
{
// eval all the properties etc till the import
if ( evaluate_properties ) {
groupingCollection . Evaluate ( EvaluationType . Property | EvaluationType . Choose ) ;
}
try {
PushThisFileProperty ( importingProject ! = null ? importingProject . FullFileName : FullFileName ) ;
string project_attribute = xmlElement . GetAttribute ( "Project" ) ;
if ( String . IsNullOrEmpty ( project_attribute ) )
throw new InvalidProjectFileException ( "The required attribute \"Project\" is missing from element <Import>." ) ;
Import . ForEachExtensionPathTillFound ( xmlElement , this , importingProject ,
( importPath , from_source_msg ) = > AddSingleImport ( xmlElement , importPath , importingProject , from_source_msg ) ) ;
} finally {
PopThisFileProperty ( ) ;
}
}
void AddImportGroup ( XmlElement xmlElement , ImportedProject importedProject , bool evaluate_properties )
{
// eval all the properties etc till the import group
if ( evaluate_properties ) {
groupingCollection . Evaluate ( EvaluationType . Property | EvaluationType . Choose ) ;
}
string condition_attribute = xmlElement . GetAttribute ( "Condition" ) ;
if ( ! ConditionParser . ParseAndEvaluate ( condition_attribute , this ) )
return ;
foreach ( XmlNode xn in xmlElement . ChildNodes ) {
if ( xn is XmlElement ) {
XmlElement xe = ( XmlElement ) xn ;
switch ( xe . Name ) {
case "Import" :
AddImport ( xe , importedProject , evaluate_properties ) ;
break ;
default :
throw new InvalidProjectFileException ( String . Format ( "Invalid element '{0}' inside ImportGroup in project file '{1}'." , xe . Name , importedProject . FullFileName ) ) ;
}
}
}
}
void AddItemDefinitionGroup ( XmlElement xmlElement )
{
string condition_attribute = xmlElement . GetAttribute ( "Condition" ) ;
if ( ! ConditionParser . ParseAndEvaluate ( condition_attribute , this ) )
return ;
foreach ( XmlNode xn in xmlElement . ChildNodes ) {
// TODO: Add all nodes to some internal dictionary?
}
}
bool AddSingleImport ( XmlElement xmlElement , string projectPath , ImportedProject importingProject , string from_source_msg )
{
Import import = new Import ( xmlElement , projectPath , this , importingProject ) ;
if ( ! ConditionParser . ParseAndEvaluate ( import . Condition , this ) ) {
ParentEngine . LogMessage ( MessageImportance . Low ,
"Not importing project '{0}' as the condition '{1}' is false" ,
import . ProjectPath , import . Condition ) ;
return false ;
}
Import existingImport ;
if ( Imports . TryGetImport ( import , out existingImport ) ) {
if ( importingProject = = null )
LogWarning ( fullFileName ,
"Cannot import project '{0}' again. It was already imported by " +
"'{1}'. Ignoring." ,
projectPath , existingImport . ContainedInProjectFileName ) ;
else
LogWarning ( importingProject ! = null ? importingProject . FullFileName : fullFileName ,
"A circular reference was found involving the import of '{0}'. " +
"It was earlier imported by '{1}'. Only " +
"the first import of this file will be used, ignoring others." ,
import . EvaluatedProjectPath , existingImport . ContainedInProjectFileName ) ;
return true ;
}
if ( String . Compare ( fullFileName , import . EvaluatedProjectPath ) = = 0 ) {
LogWarning ( importingProject ! = null ? importingProject . FullFileName : fullFileName ,
"The main project file was imported here, which creates a circular " +
"reference. Ignoring this import." ) ;
return true ;
}
if ( project_load_settings ! = ProjectLoadSettings . IgnoreMissingImports & &
! import . CheckEvaluatedProjectPathExists ( ) )
return false ;
Imports . Add ( import ) ;
string importingFile = importingProject ! = null ? importingProject . FullFileName : FullFileName ;
ParentEngine . LogMessage ( MessageImportance . Low ,
"{0}: Importing project {1} {2}" ,
importingFile , import . EvaluatedProjectPath , from_source_msg ) ;
import . Evaluate ( project_load_settings = = ProjectLoadSettings . IgnoreMissingImports ) ;
return true ;
}
void AddItemGroup ( XmlElement xmlElement , ImportedProject importedProject )
{
BuildItemGroup big = new BuildItemGroup ( xmlElement , this , importedProject , false ) ;
ItemGroups . Add ( big ) ;
}
void AddPropertyGroup ( XmlElement xmlElement , ImportedProject importedProject )
{
BuildPropertyGroup bpg = new BuildPropertyGroup ( xmlElement , this , importedProject , false ) ;
PropertyGroups . Add ( bpg ) ;
}
void AddChoose ( XmlElement xmlElement , ImportedProject importedProject )
{
BuildChoose bc = new BuildChoose ( xmlElement , this , importedProject ) ;
groupingCollection . Add ( bc ) ;
}
static void ValidationCallBack ( object sender , ValidationEventArgs e )
{
Console . WriteLine ( "Validation Error: {0}" , e . Message ) ;
}
public bool BuildEnabled {
get {
return buildEnabled ;
}
set {
buildEnabled = value ;
}
}
[MonoTODO]
public Encoding Encoding {
get { return encoding ; }
}
public string DefaultTargets {
get {
return String . Join ( "; " , defaultTargets ) ;
}
set {
xmlDocument . DocumentElement . SetAttribute ( "DefaultTargets" , value ) ;
if ( value ! = null )
defaultTargets = value . Split ( new char [ ] { ';' , ' ' } ,
StringSplitOptions . RemoveEmptyEntries ) ;
}
}
public BuildItemGroup EvaluatedItems {
get {
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
return evaluatedItems ;
}
}
public BuildItemGroup EvaluatedItemsIgnoringCondition {
get {
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
return evaluatedItemsIgnoringCondition ;
}
}
internal IDictionary < string , BuildItemGroup > EvaluatedItemsByName {
get {
// FIXME: do we need to do this here?
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
return evaluatedItemsByName ;
}
}
internal IEnumerable EvaluatedItemsByNameAsDictionaryEntries {
get {
if ( EvaluatedItemsByName . Count = = 0 )
yield break ;
foreach ( KeyValuePair < string , BuildItemGroup > pair in EvaluatedItemsByName ) {
foreach ( BuildItem bi in pair . Value )
yield return new DictionaryEntry ( pair . Key , bi . ConvertToITaskItem ( null , ExpressionOptions . ExpandItemRefs ) ) ;
}
}
}
internal IDictionary < string , BuildItemGroup > EvaluatedItemsByNameIgnoringCondition {
get {
// FIXME: do we need to do this here?
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
return evaluatedItemsByNameIgnoringCondition ;
}
}
// For batching implementation
Dictionary < string , BuildItemGroup > perBatchItemsByName ;
Dictionary < string , BuildItemGroup > commonItemsByName ;
struct Batch {
public Dictionary < string , BuildItemGroup > perBatchItemsByName ;
public Dictionary < string , BuildItemGroup > commonItemsByName ;
public Batch ( Dictionary < string , BuildItemGroup > perBatchItemsByName , Dictionary < string , BuildItemGroup > commonItemsByName )
{
this . perBatchItemsByName = perBatchItemsByName ;
this . commonItemsByName = commonItemsByName ;
}
}
Stack < Batch > Batches {
get { return batches ; }
}
internal void PushBatch ( Dictionary < string , BuildItemGroup > perBatchItemsByName , Dictionary < string , BuildItemGroup > commonItemsByName )
{
batches . Push ( new Batch ( perBatchItemsByName , commonItemsByName ) ) ;
SetBatchedItems ( perBatchItemsByName , commonItemsByName ) ;
}
internal void PopBatch ( )
{
batches . Pop ( ) ;
if ( batches . Count > 0 ) {
Batch b = batches . Peek ( ) ;
SetBatchedItems ( b . perBatchItemsByName , b . commonItemsByName ) ;
} else {
SetBatchedItems ( null , null ) ;
}
}
void SetBatchedItems ( Dictionary < string , BuildItemGroup > perBatchItemsByName , Dictionary < string , BuildItemGroup > commonItemsByName )
{
this . perBatchItemsByName = perBatchItemsByName ;
this . commonItemsByName = commonItemsByName ;
}
// Honors batching
internal bool TryGetEvaluatedItemByNameBatched ( string itemName , out BuildItemGroup group )
{
if ( perBatchItemsByName ! = null & & perBatchItemsByName . TryGetValue ( itemName , out group ) )
return true ;
if ( commonItemsByName ! = null & & commonItemsByName . TryGetValue ( itemName , out group ) )
return true ;
group = null ;
return EvaluatedItemsByName . TryGetValue ( itemName , out group ) ;
}
internal string GetMetadataBatched ( string itemName , string metadataName )
{
BuildItemGroup group = null ;
if ( itemName = = null ) {
//unqualified, all items in a batch(bucket) have the
//same metadata values
group = GetFirst < BuildItemGroup > ( perBatchItemsByName . Values ) ;
if ( group = = null )
group = GetFirst < BuildItemGroup > ( commonItemsByName . Values ) ;
} else {
//qualified
TryGetEvaluatedItemByNameBatched ( itemName , out group ) ;
}
if ( group ! = null ) {
foreach ( BuildItem item in group ) {
if ( item . HasMetadata ( metadataName ) )
return item . GetEvaluatedMetadata ( metadataName ) ;
}
}
return String . Empty ;
}
internal IEnumerable < BuildItemGroup > GetAllItemGroups ( )
{
if ( perBatchItemsByName = = null & & commonItemsByName = = null )
foreach ( BuildItemGroup group in EvaluatedItemsByName . Values )
yield return group ;
if ( perBatchItemsByName ! = null )
foreach ( BuildItemGroup group in perBatchItemsByName . Values )
yield return group ;
if ( commonItemsByName ! = null )
foreach ( BuildItemGroup group in commonItemsByName . Values )
yield return group ;
}
T GetFirst < T > ( ICollection < T > list )
{
if ( list = = null )
return default ( T ) ;
foreach ( T t in list )
return t ;
return default ( T ) ;
}
2015-04-07 09:35:12 +01:00
internal string ThisFileFullPath {
get { return this_file_property_stack . Peek ( ) ; }
}
2014-08-13 10:39:27 +01:00
// Used for MSBuild*This* set of properties
internal void PushThisFileProperty ( string full_filename )
{
string last_file = this_file_property_stack . Count = = 0 ? String . Empty : this_file_property_stack . Peek ( ) ;
this_file_property_stack . Push ( full_filename ) ;
if ( last_file ! = full_filename )
// first time, or different from previous one
SetMSBuildThisFileProperties ( full_filename ) ;
}
internal void PopThisFileProperty ( )
{
string last_file = this_file_property_stack . Pop ( ) ;
if ( this_file_property_stack . Count > 0 & & last_file ! = this_file_property_stack . Peek ( ) )
SetMSBuildThisFileProperties ( this_file_property_stack . Peek ( ) ) ;
}
void SetMSBuildThisFileProperties ( string full_filename )
{
if ( String . IsNullOrEmpty ( full_filename ) )
return ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildThisFile" , Path . GetFileName ( full_filename ) , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildThisFileFullPath" , full_filename , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildThisFileName" , Path . GetFileNameWithoutExtension ( full_filename ) , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildThisFileExtension" , Path . GetExtension ( full_filename ) , PropertyType . Reserved ) ) ;
string project_dir = Path . GetDirectoryName ( full_filename ) + Path . DirectorySeparatorChar ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildThisFileDirectory" , project_dir , PropertyType . Reserved ) ) ;
evaluatedProperties . AddProperty ( new BuildProperty ( "MSBuildThisFileDirectoryNoRoot" ,
project_dir . Substring ( Path . GetPathRoot ( project_dir ) . Length ) ,
PropertyType . Reserved ) ) ;
}
internal void LogWarning ( string filename , string message , params object [ ] messageArgs )
{
BuildWarningEventArgs bwea = new BuildWarningEventArgs (
null , null , filename , 0 , 0 , 0 , 0 , String . Format ( message , messageArgs ) ,
null , null ) ;
ParentEngine . EventSource . FireWarningRaised ( this , bwea ) ;
}
internal void LogError ( string filename , string message ,
params object [ ] messageArgs )
{
BuildErrorEventArgs beea = new BuildErrorEventArgs (
null , null , filename , 0 , 0 , 0 , 0 , String . Format ( message , messageArgs ) ,
null , null ) ;
ParentEngine . EventSource . FireErrorRaised ( this , beea ) ;
}
internal static string DefaultExtensionsPath {
get {
if ( extensions_path = = null ) {
// NOTE: code from mcs/tools/gacutil/driver.cs
PropertyInfo gac = typeof ( System . Environment ) . GetProperty (
"GacPath" , BindingFlags . Static | BindingFlags . NonPublic ) ;
if ( gac ! = null ) {
MethodInfo get_gac = gac . GetGetMethod ( true ) ;
string gac_path = ( string ) get_gac . Invoke ( null , null ) ;
extensions_path = Path . GetFullPath ( Path . Combine (
gac_path , Path . Combine ( ".." , "xbuild" ) ) ) ;
}
}
return extensions_path ;
}
}
public BuildPropertyGroup EvaluatedProperties {
get {
if ( needToReevaluate ) {
needToReevaluate = false ;
Reevaluate ( ) ;
}
return evaluatedProperties ;
}
}
internal IEnumerable EvaluatedPropertiesAsDictionaryEntries {
get {
foreach ( BuildProperty bp in EvaluatedProperties )
yield return new DictionaryEntry ( bp . Name , bp . Value ) ;
}
}
public string FullFileName {
get { return fullFileName ; }
set { fullFileName = value ; }
}
public BuildPropertyGroup GlobalProperties {
get { return globalProperties ; }
set {
if ( value = = null )
throw new ArgumentNullException ( "value" ) ;
if ( value . FromXml )
throw new InvalidOperationException ( "GlobalProperties can not be set to persisted property group." ) ;
globalProperties = value ;
}
}
public bool IsDirty {
get { return isDirty ; }
}
public bool IsValidated {
get { return isValidated ; }
set { isValidated = value ; }
}
public BuildItemGroupCollection ItemGroups {
get { return itemGroups ; }
}
public ImportCollection Imports {
get { return imports ; }
}
public string InitialTargets {
get {
return String . Join ( "; " , initialTargets . ToArray ( ) ) ;
}
set {
initialTargets . Clear ( ) ;
xmlDocument . DocumentElement . SetAttribute ( "InitialTargets" , value ) ;
if ( value ! = null )
initialTargets . AddRange ( value . Split (
new char [ ] { ';' , ' ' } , StringSplitOptions . RemoveEmptyEntries ) ) ;
}
}
public Engine ParentEngine {
get { return parentEngine ; }
}
public BuildPropertyGroupCollection PropertyGroups {
get { return propertyGroups ; }
}
public string SchemaFile {
get { return schemaFile ; }
set { schemaFile = value ; }
}
public TargetCollection Targets {
get { return targets ; }
}
public DateTime TimeOfLastDirty {
get { return timeOfLastDirty ; }
}
public UsingTaskCollection UsingTasks {
get { return usingTasks ; }
}
[MonoTODO]
public string Xml {
get { return xmlDocument . InnerXml ; }
}
// corresponds to the xml attribute
public string DefaultToolsVersion {
get {
if ( xmlDocument ! = null )
return xmlDocument . DocumentElement . GetAttribute ( "ToolsVersion" ) ;
return null ;
}
set {
if ( xmlDocument ! = null )
xmlDocument . DocumentElement . SetAttribute ( "ToolsVersion" , value ) ;
}
}
public bool HasToolsVersionAttribute {
get {
return xmlDocument ! = null & & xmlDocument . DocumentElement . HasAttribute ( "ToolsVersion" ) ;
}
}
public string ToolsVersion {
get ; internal set ;
}
internal Dictionary < string , BuildItemGroup > LastItemGroupContaining {
get { return last_item_group_containing ; }
}
internal ProjectLoadSettings ProjectLoadSettings {
get { return project_load_settings ; }
set { project_load_settings = value ; }
}
internal static XmlNamespaceManager XmlNamespaceManager {
get {
if ( manager = = null ) {
manager = new XmlNamespaceManager ( new NameTable ( ) ) ;
manager . AddNamespace ( "tns" , ns ) ;
}
return manager ;
}
}
internal TaskDatabase TaskDatabase {
get { return taskDatabase ; }
}
internal XmlDocument XmlDocument {
get { return xmlDocument ; }
}
internal static string XmlNamespace {
get { return ns ; }
}
static string OS {
get {
PlatformID pid = Environment . OSVersion . Platform ;
switch ( ( int ) pid ) {
case 128 :
case 4 :
return "Unix" ;
case 6 :
return "OSX" ;
default :
return "Windows_NT" ;
}
}
}
}
}