7
7
namespace DotNetOpenAuth . BuildTasks {
8
8
using System ;
9
9
using System . Collections . Generic ;
10
+ using System . Collections . ObjectModel ;
10
11
using System . Diagnostics . Contracts ;
11
12
using System . Globalization ;
12
13
using System . IO ;
@@ -42,6 +43,8 @@ public class MergeProjectWithVSTemplate : Task {
42
43
[ Required ]
43
44
public ITaskItem [ ] DestinationTemplates { get ; set ; }
44
45
46
+ public ITaskItem [ ] SourcePathExceptions { get ; set ; }
47
+
45
48
/// <summary>
46
49
/// Gets or sets the maximum length a project item's relative path should
47
50
/// be limited to, artificially renaming them as necessary.
@@ -87,81 +90,50 @@ public override bool Execute() {
87
90
88
91
// Figure out where every project item is in source, and where it will go in the destination,
89
92
// taking into account a given maximum path length that may require that we shorten the path.
90
- var sourceToDestinationProjectItemMap = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
91
- //var oversizedItemPaths = projectItems.Where(item => item.Include.Length > this.MaximumRelativePathLength);
92
- foreach ( var item in projectItems ) {
93
- var source = item . Include ;
94
- var dest = item . Include ;
95
-
96
- // if (this.MaximumRelativePathLength > 0) {
97
- // if (item.Include.Length > this.MaximumRelativePathLength) {
98
- // string leafName = Path.GetFileName(item.Include);
99
- // int targetLeafLength = leafName.Length - (item.Include.Length - this.MaximumRelativePathLength);
100
- // string shortenedFileName = CreateUniqueShortFileName(leafName, targetLeafLength);
101
- // string shortenedRelativePath = Path.Combine(Path.GetDirectoryName(item.Include), shortenedFileName);
102
- // if (shortenedRelativePath.Length <= this.MaximumRelativePathLength) {
103
- // this.Log.LogMessage(
104
- // "Renaming long project item '{0}' to '{1}' within project template to avoid MAX_PATH issues. The instantiated project will remain unchanged.",
105
- // item.Include,
106
- // shortenedRelativePath);
107
- // projectItem.SetAttributeValue("TargetFileName", Path.GetFileName(item.Include));
108
- // projectItem.Value = shortenedFileName;
109
- // string originalFullPath = Path.Combine(projectDirectory, item.Include);
110
- // string shortenedFullPath = Path.Combine(projectDirectory, shortenedRelativePath);
111
- // if (File.Exists(shortenedFullPath)) {
112
- // File.Delete(shortenedFullPath); // File.Move can't overwrite files
113
- // }
114
- // File.Move(originalFullPath, shortenedFullPath);
115
-
116
- // // Document the change so the build system can account for it.
117
- // TaskItem shortChange = new TaskItem(originalFullPath);
118
- // shortChange.SetMetadata("ShortPath", shortenedFullPath);
119
- // shortenedItems.Add(shortChange);
120
- // } else {
121
- // this.Log.LogError(
122
- // "Project item '{0}' exceeds maximum allowable length {1} by {2} characters and it cannot be sufficiently shortened. Estimated full path is: '{3}'.",
123
- // item.Include,
124
- // this.MaximumRelativePathLength,
125
- // item.Include.Length - this.MaximumRelativePathLength,
126
- // item.Include);
127
- // }
128
- // }
129
- //}
130
-
131
- sourceToDestinationProjectItemMap [ source ] = dest ;
132
- }
93
+ PathSegment root = new PathSegment ( ) ;
94
+ root . Add ( projectItems . Select ( item => item . Include ) ) ;
95
+ root . EnsureSelfAndChildrenNoLongerThan ( this . MaximumRelativePathLength ) ;
133
96
134
97
// Collect the project items from the project that are appropriate
135
98
// to include in the .vstemplate file.
136
- var itemsByFolder = from item in projectItems
137
- orderby item . Include
138
- group item by Path . GetDirectoryName ( item . Include ) ;
139
-
140
- foreach ( var folder in itemsByFolder ) {
99
+ foreach ( var folder in root . SelfAndDescendents . Where ( path => ! path . IsLeaf && path . LeafChildren . Any ( ) ) ) {
141
100
XElement parentNode = projectElement ;
142
- parentNode = FindOrCreateParent ( folder . Key , projectElement ) ;
143
- //parentNode.SetAttributeValue("TargetFolderName", folder.Key);
101
+ parentNode = FindOrCreateParent ( folder . CurrentPath , projectElement ) ;
102
+ if ( folder . NameChanged ) {
103
+ parentNode . SetAttributeValue ( "TargetFolderName" , folder . OriginalName ) ;
104
+ }
144
105
145
- foreach ( var item in folder ) {
146
- bool replaceParameters = this . ReplaceParametersExtensions . Contains ( Path . GetExtension ( item . Include ) ) ;
106
+ foreach ( var item in folder . LeafChildren ) {
147
107
var itemName = XName . Get ( "ProjectItem" , VSTemplateNamespace ) ;
148
- var projectItem = parentNode . Elements ( itemName ) . FirstOrDefault ( el => string . Equals ( el . Value , Path . GetFileName ( item . Include ) , StringComparison . OrdinalIgnoreCase ) ) ;
108
+ // The project item MAY be hard-coded in the .vstemplate file, under the original name.
109
+ var projectItem = parentNode . Elements ( itemName ) . FirstOrDefault ( el => string . Equals ( el . Value , Path . GetFileName ( item . OriginalName ) , StringComparison . OrdinalIgnoreCase ) ) ;
149
110
if ( projectItem == null ) {
150
- projectItem = new XElement ( itemName , Path . GetFileName ( item . Include ) ) ;
111
+ projectItem = new XElement ( itemName , item . CurrentName ) ;
151
112
parentNode . Add ( projectItem ) ;
152
113
}
153
- if ( replaceParameters ) {
114
+ if ( item . NameChanged ) {
115
+ projectItem . Value = item . CurrentName ; // set Value in case it was a hard-coded item in the .vstemplate file.
116
+ projectItem . SetAttributeValue ( "TargetFileName" , item . OriginalName ) ;
117
+ }
118
+ if ( this . ReplaceParametersExtensions . Contains ( Path . GetExtension ( item . OriginalPath ) ) ) {
154
119
projectItem . SetAttributeValue ( "ReplaceParameters" , "true" ) ;
155
120
}
156
121
}
157
122
}
158
123
159
124
template . Save ( this . DestinationTemplates [ iTemplate ] . ItemSpec ) ;
160
- foreach ( var pair in sourceToDestinationProjectItemMap ) {
161
- TaskItem item = new TaskItem ( Path . Combine ( Path . GetDirectoryName ( this . SourceTemplates [ iTemplate ] . ItemSpec ) , pair . Key ) ) ;
162
- item . SetMetadata ( "SourceFullPath" , Path . GetFullPath ( Path . Combine ( Path . GetDirectoryName ( this . SourceTemplates [ iTemplate ] . ItemSpec ) , pair . Key ) ) ) ;
163
- item . SetMetadata ( "DestinationFullPath" , Path . GetFullPath ( Path . Combine ( Path . GetDirectoryName ( this . DestinationTemplates [ iTemplate ] . ItemSpec ) , pair . Value ) ) ) ;
125
+ foreach ( var pair in root . LeafDescendents ) {
126
+ TaskItem item = new TaskItem ( Path . Combine ( Path . GetDirectoryName ( this . SourceTemplates [ iTemplate ] . ItemSpec ) , pair . OriginalPath ) ) ;
127
+ string apparentSource = Path . Combine ( Path . GetDirectoryName ( this . SourceTemplates [ iTemplate ] . ItemSpec ) , pair . OriginalPath ) ;
128
+ var sourcePathException = this . SourcePathExceptions . FirstOrDefault ( ex => string . Equals ( ex . ItemSpec , apparentSource ) ) ;
129
+ if ( sourcePathException != null ) {
130
+ item . SetMetadata ( "SourceFullPath" , sourcePathException . GetMetadata ( "ActualSource" ) ) ;
131
+ } else {
132
+ item . SetMetadata ( "SourceFullPath" , Path . GetFullPath ( apparentSource ) ) ;
133
+ }
134
+ item . SetMetadata ( "DestinationFullPath" , Path . GetFullPath ( Path . Combine ( Path . GetDirectoryName ( this . DestinationTemplates [ iTemplate ] . ItemSpec ) , pair . CurrentPath ) ) ) ;
164
135
item . SetMetadata ( "RecursiveDir" , Path . GetDirectoryName ( this . SourceTemplates [ iTemplate ] . ItemSpec ) ) ;
136
+ item . SetMetadata ( "Transform" , this . ReplaceParametersExtensions . Contains ( Path . GetExtension ( pair . OriginalName ) ) ? "true" : "false" ) ;
165
137
projectItemsToCopy . Add ( item ) ;
166
138
}
167
139
}
@@ -171,27 +143,6 @@ orderby item.Include
171
143
return ! Log . HasLoggedErrors ;
172
144
}
173
145
174
- private static string CreateUniqueShortFileName ( string fileName , int targetLength ) {
175
- Contract . Requires < ArgumentException > ( ! string . IsNullOrEmpty ( fileName ) ) ;
176
- Contract . Ensures ( ! string . IsNullOrEmpty ( Contract . Result < string > ( ) ) ) ;
177
-
178
- // The filename may already full within the target length.
179
- if ( fileName . Length <= targetLength ) {
180
- return fileName ;
181
- }
182
-
183
- string hashSuffix = Utilities . SuppressCharacters ( Math . Abs ( fileName . GetHashCode ( ) % 0xfff ) . ToString ( "x" ) , Path . GetInvalidFileNameChars ( ) , '_' ) ;
184
- string fileNameWithoutExtension = Path . GetFileNameWithoutExtension ( fileName ) ;
185
- string extension = Path . GetExtension ( fileName ) ;
186
- string hashSuffixWithExtension = hashSuffix + extension ;
187
-
188
- // If the target length is itself shorter than the hash code, then we won't meet our goal,
189
- // but at least put the hash in there so it's unique, and we'll return a string that's too long.
190
- string shortenedFileName = fileName . Substring ( 0 , Math . Max ( 0 , targetLength - hashSuffixWithExtension . Length ) ) + hashSuffixWithExtension ;
191
-
192
- return shortenedFileName ;
193
- }
194
-
195
146
private static XElement FindOrCreateParent ( string directoryName , XElement projectElement ) {
196
147
Contract . Requires < ArgumentNullException > ( projectElement != null ) ;
197
148
0 commit comments