Added workaround for DirectoryScanner bug that finds multiple files. Then implemented...
[mono.git] / mcs / class / Microsoft.Build / Microsoft.Build.Evaluation / ProjectItem.cs
1 //
2 // ProjectItem.cs
3 //
4 // Author:
5 //   Leszek Ciesielski (skolima@gmail.com)
6 //   Rolf Bjarne Kvinge (rolf@xamarin.com)
7 //   Atsushi Enomoto (atsushi@xamarin.com)
8 //
9 // (C) 2011 Leszek Ciesielski
10 // Copyright (C) 2011,2013 Xamarin Inc.
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Collections.Generic;
34 using System.Diagnostics;
35 using System.Linq;
36 using Microsoft.Build.Construction;
37 using System.IO;
38 using Microsoft.Build.Framework;
39
40 namespace Microsoft.Build.Evaluation
41 {
42         [DebuggerDisplay ("{ItemType}={EvaluatedInclude} [{UnevaluatedInclude}] #DirectMetadata={DirectMetadataCount}")]
43         public class ProjectItem
44         {
45                 internal ProjectItem (Project project, ProjectItemElement xml, string evaluatedInclude)
46                 {
47                         this.project = project;
48                         this.xml = xml;
49                         if (project.ItemDefinitions.ContainsKey (ItemType))
50                                 foreach (var md in project.ItemDefinitions [ItemType].Metadata)
51                                         metadata.Add (md);
52                         foreach (var md in xml.Metadata)
53                                 metadata.Add (new ProjectMetadata (project, ItemType, metadata, m => metadata.Remove (m), md));
54                         this.evaluated_include = evaluatedInclude;
55                         is_imported = project.ProjectCollection.OngoingImports.Any ();                  
56                 }
57                 
58                 readonly Project project;
59                 readonly ProjectItemElement xml;
60                 readonly List<ProjectMetadata> metadata = new List<ProjectMetadata> ();
61                 readonly bool is_imported;
62                 readonly string evaluated_include;
63                 
64                 internal string RecursiveDir { get; set; }
65
66                 public ProjectMetadata GetMetadata (string name)
67                 {
68                         return metadata.FirstOrDefault (m => m.Name == name);
69                 }
70                 
71                 static readonly char [] path_sep = {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
72                 
73                 static readonly Dictionary<string,Func<ProjectItem,string>> well_known_metadata = new Dictionary<string, Func<ProjectItem,string>> {
74                                 {"FullPath", p => Path.Combine (p.Project.GetFullPath (p.evaluated_include)) },
75                                 {"RootDir", p => Path.GetPathRoot (p.Project.GetFullPath (p.evaluated_include)) },
76                                 {"Filename", p => Path.GetFileNameWithoutExtension (p.evaluated_include) },
77                                 {"Extension", p => Path.GetExtension (p.evaluated_include) },
78                                 {"RelativeDir", p => {
79                                         var idx = p.evaluated_include.LastIndexOfAny (path_sep);
80                                         return idx < 0 ? string.Empty : p.evaluated_include.Substring (0, idx + 1); }
81                                         },
82                                 {"Directory", p => {
83                                         var fp = p.Project.GetFullPath (p.evaluated_include);
84                                         return Path.GetDirectoryName (fp).Substring (Path.GetPathRoot (fp).Length); }
85                                         },
86                                 {"RecursiveDir", p => p.RecursiveDir },
87                                 {"Identity", p => p.EvaluatedInclude },
88                                 {"ModifiedTime", p => new FileInfo (p.Project.GetFullPath (p.evaluated_include)).LastWriteTime.ToString ("yyyy-MM-dd HH:mm:ss.fffffff") },
89                                 {"CreatedTime", p => new FileInfo (p.Project.GetFullPath (p.evaluated_include)).CreationTime.ToString ("yyyy-MM-dd HH:mm:ss.fffffff") },
90                                 {"AccessedTime", p => new FileInfo (p.Project.GetFullPath (p.evaluated_include)).LastAccessTime.ToString ("yyyy-MM-dd HH:mm:ss.fffffff") },
91                                 };
92
93                 public string GetMetadataValue (string name)
94                 {
95                         var wellKnown = well_known_metadata.FirstOrDefault (p => p.Key.Equals (name, StringComparison.OrdinalIgnoreCase));
96                         if (wellKnown.Value != null)
97                                 return wellKnown.Value (this);
98                         var m = GetMetadata (name);
99                         return m != null ? m.EvaluatedValue : string.Empty;
100                 }
101
102                 public bool HasMetadata (string name)
103                 {
104                         return GetMetadata (name) != null;
105                 }
106
107                 public bool RemoveMetadata (string name)
108                 {
109                         var m = GetMetadata (name);
110                         if (m == null)
111                                 return false;
112                         return metadata.Remove (m);
113                 }
114
115                 public void Rename (string name)
116                 {
117                         throw new NotImplementedException ();
118                 }
119
120                 public ProjectMetadata SetMetadataValue (string name, string unevaluatedValue)
121                 {
122                         // This has to do several tasks:
123                         // - it cannot directly change Xml.Metadata because the ProjectItemElement might be shared
124                         //   among multiple ProjectItems.
125                         // - hence it has to create another ProjectItemElement instance and add it to the project
126                         //   XML construction, with specific Include value that is assigned to this instance, and
127                         //   metadata values that are assigned to this instance.
128                         throw new NotImplementedException ();
129                 }
130
131                 public IEnumerable<ProjectMetadata> DirectMetadata {
132                         get {
133                                 var list = new List<ProjectMetadata> ();
134                                 foreach (var xm in xml.Metadata)
135                                         yield return new ProjectMetadata (project, ItemType, list, p => list.Remove (p), xm);
136                         }
137                 }
138
139                 public int DirectMetadataCount {
140                         get { return xml.Metadata.Count; }
141                 }
142
143                 public string EvaluatedInclude {
144                         get { return evaluated_include; }
145                 }
146
147                 public bool IsImported {
148                         get { return is_imported; }
149                 }
150
151                 public string ItemType {
152                         get { return Xml.ItemType; }
153                         set { Xml.ItemType = value; }
154                 }
155
156                 public ICollection<ProjectMetadata> Metadata {
157                         get { return metadata; }
158                 }
159
160                 public int MetadataCount {
161                         get { return metadata.Count; }
162                 }
163
164                 public Project Project {
165                         get { return project; }
166                 }
167
168                 public string UnevaluatedInclude {
169                         get { return Xml.Include; }
170                         set { Xml.Include = value; }
171                 }
172
173                 public ProjectItemElement Xml {
174                         get { return xml; }
175                 }               
176         }
177 }