wasStitchNET – Diff between revs 20 and 21

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 20 Rev 21
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 // 2 // Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 //
3 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // 3 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
4 // rights of fair usage, the disclaimer and warranty conditions. // 4 // rights of fair usage, the disclaimer and warranty conditions. //
5 /////////////////////////////////////////////////////////////////////////// 5 ///////////////////////////////////////////////////////////////////////////
6   6  
7 using System; 7 using System;
8 using System.Collections.Generic; 8 using System.Collections.Generic;
9 using System.IO; 9 using System.IO;
10 using System.Linq; 10 using System.Linq;
11 using System.Text.RegularExpressions; 11 using System.Text.RegularExpressions;
12 using System.Threading.Tasks; 12 using System.Threading.Tasks;
13 using System.Xml.Linq; 13 using System.Xml.Linq;
14 using wasDAVClient; 14 using wasDAVClient;
15 using wasSharp; 15 using wasSharp;
16 using wasSharp.Sets; 16 using wasSharp.Sets;
17 using wasSharpNET.IO.Utilities; 17 using wasSharpNET.IO.Utilities;
18 using wasStitchNET.Structures; 18 using wasStitchNET.Structures;
19 using XML = wasStitchNET.Patchers.XML; 19 using XML = wasStitchNET.Patchers.XML;
20   20  
21 namespace wasStitchNET.Repository.Stitching 21 namespace wasStitchNET.Repository.Stitching
22 { 22 {
23 public class Stitching 23 public class Stitching
24 { 24 {
25 /// <summary> 25 /// <summary>
26 /// Delegate to subscribe to for stitch progress events. 26 /// Delegate to subscribe to for stitch progress events.
27 /// </summary> 27 /// </summary>
28 /// <param name="sender">the sender</param> 28 /// <param name="sender">the sender</param>
29 /// <param name="e">stitch progress event arguments</param> 29 /// <param name="e">stitch progress event arguments</param>
30 public delegate void StitchProgressEventHandler(object sender, StitchProgressEventArgs e); 30 public delegate void StitchProgressEventHandler(object sender, StitchProgressEventArgs e);
31   31  
32 /// <summary> 32 /// <summary>
33 /// Stitch progress event handler. 33 /// Stitch progress event handler.
34 /// </summary> 34 /// </summary>
35 public event StitchProgressEventHandler OnProgressUpdate; 35 public event StitchProgressEventHandler OnProgressUpdate;
36   36  
37 /// <summary> 37 /// <summary>
38 /// Commodity method to raise stitching progress events. 38 /// Commodity method to raise stitching progress events.
39 /// </summary> 39 /// </summary>
40 /// <param name="status">the current stitching status</param> 40 /// <param name="status">the current stitching status</param>
41 private void StitchProgressUpdate(string status) 41 private void StitchProgressUpdate(string status)
42 { 42 {
43 // Make sure someone is listening to event 43 // Make sure someone is listening to event
44 if (OnProgressUpdate == null) return; 44 if (OnProgressUpdate == null) return;
45   45  
46 var args = new StitchProgressEventArgs(status); 46 var args = new StitchProgressEventArgs(status);
47 OnProgressUpdate(this, args); 47 OnProgressUpdate(this, args);
48 } 48 }
49   49  
50 /// <summary> 50 /// <summary>
51 /// Stitch! 51 /// Stitch!
52 /// </summary> 52 /// </summary>
53 /// <param name="client">the was DAV client to use</param> 53 /// <param name="client">the was DAV client to use</param>
54 /// <param name="server">the repository URL to stitch from</param> 54 /// <param name="server">the repository URL to stitch from</param>
55 /// <param name="version">the release to stitch to</param> 55 /// <param name="version">the release to stitch to</param>
56 /// <param name="path">the path to the local files to be stitched</param> 56 /// <param name="path">the path to the local files to be stitched</param>
57 /// <param name="nopatch">true if files should not be patched</param> 57 /// <param name="nopatch">true if files should not be patched</param>
58 /// <param name="clean">whether to perform a clean stitching by removing local files</param> 58 /// <param name="clean">whether to perform a clean stitching by removing local files</param>
59 /// <param name="force">whether to force stitching repository paths</param> 59 /// <param name="force">whether to force stitching repository paths</param>
60 /// <param name="noverify">true if remote files should not be checked against official checksum</param> 60 /// <param name="noverify">true if remote files should not be checked against official checksum</param>
61 /// <param name="dryrun">whether to perform a dryrun run operation without making any changes</param> 61 /// <param name="dryrun">whether to perform a dryrun run operation without making any changes</param>
62 /// <returns>true if stitching completed successfully</returns> 62 /// <returns>true if stitching completed successfully</returns>
63 public async Task<bool> Stitch(Client client, string server, string version, string path, 63 public async Task<bool> Stitch(Client client, string server, string version, string path,
64 bool nopatch = false, 64 bool nopatch = false,
65 bool clean = false, bool force = false, bool noverify = false, bool dryrun = false) 65 bool clean = false, bool force = false, bool noverify = false, bool dryrun = false)
66 { 66 {
67 // Set the server. 67 // Set the server.
68 client.Server = server; 68 client.Server = server;
69   69  
70 // The repository path to the version to update. 70 // The repository path to the version to update.
71 var updateVersionPath = @"/" + 71 var updateVersionPath = @"/" +
72 string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH, 72 string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH,
73 STITCH_CONSTANTS.PROGRESSIVE_PATH, 73 STITCH_CONSTANTS.PROGRESSIVE_PATH,
74 version); 74 version);
75 // Check that the repository has the requested version. 75 // Check that the repository has the requested version.
76 StitchProgressUpdate("Attempting to retrieve remote repository update version folder."); 76 StitchProgressUpdate("Attempting to retrieve remote repository update version folder.");
77 try 77 try
78 { 78 {
79 if (!client.GetFolder(updateVersionPath).Result.IsCollection) 79 if (!client.GetFolder(updateVersionPath).Result.IsCollection)
80 throw new Exception(); 80 throw new Exception();
81 } 81 }
82 catch (Exception) 82 catch (Exception)
83 { 83 {
84 throw new StitchException("The repository does not have requested version available."); 84 throw new StitchException("The repository does not have requested version available.");
85 } 85 }
86   86  
87 // The repository path to the checksum file of the version to update. 87 // The repository path to the checksum file of the version to update.
88 var updateChecksumPath = string.Join(@"/", updateVersionPath, STITCH_CONSTANTS.UPDATE_CHECKSUM_FILE); 88 var updateChecksumPath = string.Join(@"/", updateVersionPath, STITCH_CONSTANTS.UPDATE_CHECKSUM_FILE);
89   89  
90 // Attempt to retrieve remote checksum file and normalize the hash. 90 // Attempt to retrieve remote checksum file and normalize the hash.
91 StitchProgressUpdate("Retrieving remote repository checksum file."); 91 StitchProgressUpdate("Retrieving remote repository checksum file.");
92 string updateChecksum; 92 string updateChecksum;
93 try 93 try
94 { 94 {
95 using (var stream = client.Download(updateChecksumPath).Result) 95 using (var stream = client.Download(updateChecksumPath).Result)
96 { 96 {
97 using (var reader = new StreamReader(stream)) 97 using (var reader = new StreamReader(stream))
98 { 98 {
99 // Trim any spaces since we only care about a single-line hash. 99 // Trim any spaces since we only care about a single-line hash.
100 updateChecksum = Regex.Replace(reader.ReadToEnd(), @"\s+", string.Empty); 100 updateChecksum = Regex.Replace(reader.ReadToEnd(), @"\s+", string.Empty);
101 } 101 }
102 } 102 }
103 } 103 }
104 catch (Exception ex) 104 catch (Exception ex)
105 { 105 {
106 throw new StitchException("Unable to retrieve repository checksum file.", ex); 106 throw new StitchException("Unable to retrieve repository checksum file.", ex);
107 } 107 }
108   108  
109 if (string.IsNullOrEmpty(updateChecksum)) 109 if (string.IsNullOrEmpty(updateChecksum))
110 throw new StitchException("Empty repository update checksum."); 110 throw new StitchException("Empty repository update checksum.");
111   111  
112 // Hash the remote repository files. 112 // Hash the remote repository files.
113 StitchProgressUpdate("Hashing remote repository checksum files."); 113 StitchProgressUpdate("Hashing remote repository checksum files.");
114 string remoteChecksum; 114 string remoteChecksum;
115 try 115 try
116 { 116 {
117 remoteChecksum = await Hashing.HashRemoteFiles(client, 117 remoteChecksum = await Hashing.HashRemoteFiles(client,
118 string.Join(@"/", version, STITCH_CONSTANTS.UPDATE_DATA_PATH)); 118 string.Join(@"/", version, STITCH_CONSTANTS.UPDATE_DATA_PATH));
119 } 119 }
120 catch (Exception ex) 120 catch (Exception ex)
121 { 121 {
122 throw new StitchException("Unable to compute remote checksum.", ex); 122 throw new StitchException("Unable to compute remote checksum.", ex);
123 } 123 }
124   124  
125 if (string.IsNullOrEmpty(remoteChecksum)) 125 if (string.IsNullOrEmpty(remoteChecksum))
126 throw new StitchException("Empty remote checksum."); 126 throw new StitchException("Empty remote checksum.");
127   127  
128 // Check that the repository checksum file matches the repository file hash. 128 // Check that the repository checksum file matches the repository file hash.
129 StitchProgressUpdate("Comparing remote repository checksum against remote repository files checksum."); 129 StitchProgressUpdate("Comparing remote repository checksum against remote repository files checksum.");
130 if (!string.Equals(updateChecksum, remoteChecksum, StringComparison.OrdinalIgnoreCase)) 130 if (!string.Equals(updateChecksum, remoteChecksum, StringComparison.OrdinalIgnoreCase))
131 throw new StitchException("Repository file checksum mismatch."); 131 throw new StitchException("Repository file checksum mismatch.");
132   132  
133 // Check that the computed repository file checksum matches the official repository checksum file. 133 // Check that the computed repository file checksum matches the official repository checksum file.
134 if (!noverify) 134 if (!noverify)
135 { 135 {
136 StitchProgressUpdate("Preparing to verify remote repository file checksum to official checksum."); 136 StitchProgressUpdate("Preparing to verify remote repository file checksum to official checksum.");
137   137  
138 // Retrieve the official repository checksum file for the requested stitch version. 138 // Retrieve the official repository checksum file for the requested stitch version.
139 StitchProgressUpdate("Retrieving official repository checksum for requested release version."); 139 StitchProgressUpdate("Retrieving official repository checksum for requested release version.");
140 string officialChecksum; 140 string officialChecksum;
141 try 141 try
142 { 142 {
143 // Point the server to the official server. 143 // Point the server to the official server.
144 client.Server = STITCH_CONSTANTS.OFFICIAL_UPDATE_SERVER; 144 client.Server = STITCH_CONSTANTS.OFFICIAL_UPDATE_SERVER;
145 using (var stream = client.Download(updateChecksumPath).Result) 145 using (var stream = client.Download(updateChecksumPath).Result)
146 { 146 {
147 using (var reader = new StreamReader(stream)) 147 using (var reader = new StreamReader(stream))
148 { 148 {
149 // Trim any spaces since we only care about a single-line hash. 149 // Trim any spaces since we only care about a single-line hash.
150 officialChecksum = Regex.Replace(reader.ReadToEnd(), @"\s+", string.Empty); 150 officialChecksum = Regex.Replace(reader.ReadToEnd(), @"\s+", string.Empty);
151 } 151 }
152 } 152 }
153 } 153 }
154 catch (Exception ex) 154 catch (Exception ex)
155 { 155 {
156 throw new StitchException("Unable to retrieve official repository checksum file.", ex); 156 throw new StitchException("Unable to retrieve official repository checksum file.", ex);
157 } 157 }
158 finally 158 finally
159 { 159 {
160 client.Server = server; 160 client.Server = server;
161 } 161 }
162   162  
163 if (string.IsNullOrEmpty(officialChecksum)) 163 if (string.IsNullOrEmpty(officialChecksum))
164 throw new StitchException("Unable to retrieve official repository checksum file."); 164 throw new StitchException("Unable to retrieve official repository checksum file.");
165   165  
166 // Compare the official checksum to the repository file checksum. 166 // Compare the official checksum to the repository file checksum.
167 StitchProgressUpdate( 167 StitchProgressUpdate(
168 $"Comparing official repository checksum ({officialChecksum}) against remote repository files checksum ({remoteChecksum})."); 168 $"Comparing official repository checksum ({officialChecksum}) against remote repository files checksum ({remoteChecksum}).");
169 if (!string.Equals(officialChecksum, remoteChecksum, StringComparison.OrdinalIgnoreCase)) 169 if (!string.Equals(officialChecksum, remoteChecksum, StringComparison.OrdinalIgnoreCase))
170 throw new StitchException("Repository file checksum does not match official repository checksum."); 170 throw new StitchException("Repository file checksum does not match official repository checksum.");
171 } 171 }
172   172  
173   173  
174 var stitchOptions = new StitchOptions(); 174 var stitchOptions = new StitchOptions();
175 var optionsPath = @"/" + 175 var optionsPath = @"/" +
176 string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH, STITCH_CONSTANTS.PROGRESSIVE_PATH, 176 string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH, STITCH_CONSTANTS.PROGRESSIVE_PATH,
177 version, STITCH_CONSTANTS.UPDATE_OPTIONS_FILE); 177 version, STITCH_CONSTANTS.UPDATE_OPTIONS_FILE);
178   178  
179 // Retrieve the repository upgrade options file. 179 // Retrieve the repository upgrade options file.
180 StitchProgressUpdate("Retrieving remote repository options."); 180 StitchProgressUpdate("Retrieving remote repository options.");
181 try 181 try
182 { 182 {
183 using (var stream = client.Download(optionsPath).Result) 183 using (var stream = client.Download(optionsPath).Result)
184 { 184 {
185 stitchOptions = stitchOptions.Load(stream); 185 stitchOptions = stitchOptions.Load(stream);
186 } 186 }
187 } 187 }
188 catch (Exception ex) 188 catch (Exception ex)
189 { 189 {
190 throw new StitchException("Unable to retrieve repository options.", ex); 190 throw new StitchException("Unable to retrieve repository options.", ex);
191 } 191 }
192   192  
193 // Retrieve the remote repository release files. 193 // Retrieve the remote repository release files.
194 StitchProgressUpdate("Retrieving remote repository release files."); 194 StitchProgressUpdate("Retrieving remote repository release files.");
195 var remoteFiles = new HashSet<StitchFile>(); 195 var remoteFiles = new HashSet<StitchFile>();
196 try 196 try
197 { 197 {
198 remoteFiles.UnionWith( 198 remoteFiles.UnionWith(
199 Files.LoadRemoteFiles(client, 199 Files.LoadRemoteFiles(client,
200 string.Join(@"/", version, STITCH_CONSTANTS.UPDATE_DATA_PATH), 200 string.Join(@"/", version, STITCH_CONSTANTS.UPDATE_DATA_PATH),
201 @"/" + string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH, STITCH_CONSTANTS.PROGRESSIVE_PATH, 201 @"/" + string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH, STITCH_CONSTANTS.PROGRESSIVE_PATH,
202 version, STITCH_CONSTANTS.UPDATE_DATA_PATH) 202 version, STITCH_CONSTANTS.UPDATE_DATA_PATH)
203 )); 203 ));
204 } 204 }
205 catch (Exception ex) 205 catch (Exception ex)
206 { 206 {
207 throw new StitchException("Unable to download repository release files.", ex); 207 throw new StitchException("Unable to download repository release files.", ex);
208 } 208 }
209   209  
210 // Retrieve local path files. 210 // Retrieve local path files.
211 StitchProgressUpdate("Retrieving local path files."); 211 StitchProgressUpdate("Retrieving local path files.");
212 var localFiles = new HashSet<StitchFile>(); 212 var localFiles = new HashSet<StitchFile>();
213 try 213 try
214 { 214 {
215 localFiles.UnionWith(Files.LoadLocalFiles(path, 215 localFiles.UnionWith(Files.LoadLocalFiles(path,
216 path, 216 path,
217 Path.DirectorySeparatorChar)); 217 Path.DirectorySeparatorChar));
218 } 218 }
219 catch (Exception ex) 219 catch (Exception ex)
220 { 220 {
221 throw new StitchException("Unable to load local files.", ex); 221 throw new StitchException("Unable to load local files.", ex);
222 } 222 }
223   223  
224 // Files to be wiped. 224 // Files to be wiped.
225 var wipeFiles = new HashSet<StitchFile>(); 225 var wipeFiles = new HashSet<StitchFile>();
226 if (clean) 226 if (clean)
227 switch (stitchOptions.Force || force) 227 switch (stitchOptions.Force || force)
228 { 228 {
229 case true: 229 case true:
230 wipeFiles.UnionWith(localFiles.Except(remoteFiles)); 230 wipeFiles.UnionWith(localFiles.Except(remoteFiles));
231 break; 231 break;
232   232  
233 default: 233 default:
234 wipeFiles.UnionWith( 234 wipeFiles.UnionWith(
235 localFiles.Except(remoteFiles) 235 localFiles.Except(remoteFiles)
236 .Where( 236 .Where(
237 o => 237 o =>
238 stitchOptions.FileExcludes.Path.All( 238 stitchOptions.FileExcludes.Path.All(
239 p => 239 p =>
240 o.Path.SequenceExcept(p.PathSplit(Path.DirectorySeparatorChar)) 240 o.Path.SequenceExcept(p.PathSplit(Path.DirectorySeparatorChar))
241 .Count() 241 .Count()
242 .Equals(o.Path.Count())))); 242 .Equals(o.Path.Count()))));
243 break; 243 break;
244 } 244 }
245   245  
246 // Files to be stitched. 246 // Files to be stitched.
247 var stitchFiles = new HashSet<StitchFile>(); 247 var stitchFiles = new HashSet<StitchFile>();
248 // If the force option was specified then stitch all the files that are not in the remote 248 // If the force option was specified then stitch all the files that are not in the remote
249 // repository by ignoring any excludes. 249 // repository by ignoring any excludes.
250 switch (stitchOptions.Force || force) 250 switch (stitchOptions.Force || force)
251 { 251 {
252 case true: 252 case true:
253 stitchFiles.UnionWith(remoteFiles.Except(localFiles)); 253 stitchFiles.UnionWith(remoteFiles.Except(localFiles));
254 break; 254 break;
255   255  
256 default: 256 default:
257 stitchFiles.UnionWith( 257 stitchFiles.UnionWith(
258 remoteFiles.Except(localFiles) 258 remoteFiles.Except(localFiles)
259 .Where( 259 .Where(
260 o => 260 o =>
261 stitchOptions.FileExcludes.Path.All( 261 stitchOptions.FileExcludes.Path.All(
262 p => 262 p =>
263 o.Path.SequenceExcept(p.PathSplit(Path.DirectorySeparatorChar)) 263 o.Path.SequenceExcept(p.PathSplit(Path.DirectorySeparatorChar))
264 .Count() 264 .Count()
265 .Equals(o.Path.Count())))); 265 .Equals(o.Path.Count()))));
266 break; 266 break;
267 } 267 }
268   268  
269 // Wipe local files and directories that have to be removed. 269 // Wipe local files and directories that have to be removed.
270 StitchProgressUpdate("Removing local files and folders."); 270 StitchProgressUpdate("Removing local files and folders.");
271 var directories = new Queue<string>(); 271 var directories = new Queue<string>();
272 foreach (var file in wipeFiles) 272 foreach (var file in wipeFiles)
273 { 273 {
274 var deletePath = string.Join(Path.DirectorySeparatorChar.ToString(), 274 var deletePath = string.Join(Path.DirectorySeparatorChar.ToString(),
275 path, 275 path,
276 string.Join(Path.DirectorySeparatorChar.ToString(), file.Path)); 276 string.Join(Path.DirectorySeparatorChar.ToString(), file.Path));
277 try 277 try
278 { 278 {
279 switch (file.PathType) 279 switch (file.PathType)
280 { 280 {
281 case StitchPathType.PATH_FILE: 281 case StitchPathType.PATH_FILE:
282 if (!dryrun) 282 if (!dryrun)
283 File.Delete(deletePath); 283 File.Delete(deletePath);
284 break; 284 break;
285   285  
286 case StitchPathType.PATH_DIRECTORY: // we cannot delete the directories right away. 286 case StitchPathType.PATH_DIRECTORY: // we cannot delete the directories right away.
287 directories.Enqueue(deletePath); 287 directories.Enqueue(deletePath);
288 break; 288 break;
289 } 289 }
290 } 290 }
291 catch (Exception ex) 291 catch (Exception ex)
292 { 292 {
293 throw new StitchException("Unable remove local files.", ex); 293 throw new StitchException("Unable remove local files.", ex);
294 } 294 }
295 } 295 }
296   296  
297 directories = new Queue<string>(directories.OrderByDescending(o => o)); 297 directories = new Queue<string>(directories.OrderByDescending(o => o));
298   298  
299 while (directories.Any()) 299 while (directories.Any())
300 { 300 {
301 var deletePath = directories.Dequeue(); 301 var deletePath = directories.Dequeue();
302 try 302 try
303 { 303 {
304 if (!dryrun) 304 if (!dryrun)
305 Directory.Delete(deletePath); 305 Directory.Delete(deletePath);
306 } 306 }
307 catch (Exception ex) 307 catch (Exception ex)
308 { 308 {
309 throw new StitchException("Unable remove local directories.", ex); 309 throw new StitchException("Unable remove local directories.", ex);
310 } 310 }
311 } 311 }
312   312  
313 // Stitch files that have to be stitched. 313 // Stitch files that have to be stitched.
314 StitchProgressUpdate("Stitching files."); 314 StitchProgressUpdate("Stitching files.");
315 foreach (var file in stitchFiles) 315 foreach (var file in stitchFiles)
316 try 316 try
317 { 317 {
318 var stitchRemotePath = @"/" + string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH, 318 var stitchRemotePath = @"/" + string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH,
319 STITCH_CONSTANTS.PROGRESSIVE_PATH, 319 STITCH_CONSTANTS.PROGRESSIVE_PATH,
320 version, STITCH_CONSTANTS.UPDATE_DATA_PATH, 320 version, STITCH_CONSTANTS.UPDATE_DATA_PATH,
321 string.Join("/", file.Path)); 321 string.Join("/", file.Path));
322 var stitchLocalPath = string.Join(Path.DirectorySeparatorChar.ToString(), 322 var stitchLocalPath = string.Join(Path.DirectorySeparatorChar.ToString(),
323 path.PathSplit(Path.DirectorySeparatorChar) 323 path.PathSplit(Path.DirectorySeparatorChar)
324 .Concat(file.Path)); 324 .Concat(file.Path));
325   325  
326 switch (file.PathType) 326 switch (file.PathType)
327 { 327 {
328 case StitchPathType.PATH_DIRECTORY: 328 case StitchPathType.PATH_DIRECTORY:
329 // Create the directory. 329 // Create the directory.
330 if (!dryrun) 330 if (!dryrun)
331 Directory.CreateDirectory(stitchLocalPath); 331 Directory.CreateDirectory(stitchLocalPath);
332 continue; 332 continue;
333 case StitchPathType.PATH_FILE: 333 case StitchPathType.PATH_FILE:
334 // Create the directory to the stitch file. 334 // Create the directory to the stitch file.
335 if (!dryrun) 335 if (!dryrun)
336 Directory.CreateDirectory( 336 Directory.CreateDirectory(
337 string.Join(Path.DirectorySeparatorChar.ToString(), 337 string.Join(Path.DirectorySeparatorChar.ToString(),
338 stitchLocalPath.PathSplit(Path.DirectorySeparatorChar).Reverse() 338 stitchLocalPath.PathSplit(Path.DirectorySeparatorChar).Reverse()
339 .Skip(1) 339 .Skip(1)
340 .Reverse())); 340 .Reverse()));
341 break; 341 break;
342 } 342 }
343   343  
344 using (var memoryStream = new MemoryStream()) 344 using (var memoryStream = new MemoryStream())
345 { 345 {
346 using (var stream = client.Download(stitchRemotePath).Result) 346 using (var stream = client.Download(stitchRemotePath).Result)
347 { 347 {
348 stream.CopyTo(memoryStream); 348 stream.CopyTo(memoryStream);
349 } 349 }
350 memoryStream.Position = 0L; 350 memoryStream.Position = 0L;
351 if (!dryrun) 351 if (!dryrun)
352 using (var fileStream = 352 using (var fileStream =
353 IOExtensions.GetWriteStream(stitchLocalPath, FileMode.Create, 353 IOExtensions.GetWriteStream(stitchLocalPath, FileMode.Create,
354 FileAccess.Write, FileShare.None, STITCH_CONSTANTS.LOCAL_FILE_ACCESS_TIMEOUT)) 354 FileAccess.Write, FileShare.None, STITCH_CONSTANTS.LOCAL_FILE_ACCESS_TIMEOUT))
355 { 355 {
356 memoryStream.CopyTo(fileStream); 356 memoryStream.CopyTo(fileStream);
357 } 357 }
358 } 358 }
359 } 359 }
360 catch (Exception ex) 360 catch (Exception ex)
361 { 361 {
362 throw new StitchException("Unable to stitch files.", ex); 362 throw new StitchException("Unable to stitch files.", ex);
363 } 363 }
364   364  
365 // If no file patches was requested then do not patch and the process is complete. 365 // If no file patches was requested then do not patch and the process is complete.
366 if (nopatch) 366 if (nopatch)
367 return true; 367 return true;
368   368  
369 StitchProgressUpdate("Patching files."); 369 StitchProgressUpdate("Patching files.");
370   370  
371 // Retrive working file. 371 // Retrive working file.
372 var workingFilePath = string.Join(Path.DirectorySeparatorChar.ToString(), 372 var workingFilePath = string.Join(Path.DirectorySeparatorChar.ToString(),
373 path, Constants.WORKING_CONFIGURATION_FILE); 373 path, STITCH_CONSTANTS.WORKING_CONFIGURATION_FILE);
374   374  
375 StitchProgressUpdate("Parsing working file to be patched."); 375 StitchProgressUpdate("Parsing working file to be patched.");
376 XDocument workingFile; 376 XDocument workingFile;
377 try 377 try
378 { 378 {
379 workingFile = XDocument.Load(workingFilePath); 379 workingFile = XDocument.Load(workingFilePath);
380 } 380 }
381 catch (Exception ex) 381 catch (Exception ex)
382 { 382 {
383 throw new StitchException("Unable to parse working file to be patched.", ex); 383 throw new StitchException("Unable to parse working file to be patched.", ex);
384 } 384 }
385   385  
386 // Retrieve default file. 386 // Retrieve default file.
387 StitchProgressUpdate("Parsing default file to be patched."); 387 StitchProgressUpdate("Parsing default file to be patched.");
388 XDocument defaultFile; 388 XDocument defaultFile;
389 try 389 try
390 { 390 {
391 defaultFile = XDocument.Load(string.Join(Path.DirectorySeparatorChar.ToString(), 391 defaultFile = XDocument.Load(string.Join(Path.DirectorySeparatorChar.ToString(),
392 path, Constants.DEFAULT_CONFIGURATION_FILE)); 392 path, STITCH_CONSTANTS.DEFAULT_CONFIGURATION_FILE));
393 } 393 }
394 catch (Exception ex) 394 catch (Exception ex)
395 { 395 {
396 throw new StitchException("Unable to parse default file to be patched.", ex); 396 throw new StitchException("Unable to parse default file to be patched.", ex);
397 } 397 }
398   398  
399 // XPaths to exclude from patching. 399 // XPaths to exclude from patching.
400 var excludeXPaths = new HashSet<string>(); 400 var excludeXPaths = new HashSet<string>();
401 if (stitchOptions.ConfigurationExcludes != null) 401 if (stitchOptions.ConfigurationExcludes != null)
402 excludeXPaths.UnionWith(stitchOptions.ConfigurationExcludes.Tag); 402 excludeXPaths.UnionWith(stitchOptions.ConfigurationExcludes.Tag);
403   403  
404 // XPaths to force whilst patching. 404 // XPaths to force whilst patching.
405 var forceXPaths = new HashSet<string>(); 405 var forceXPaths = new HashSet<string>();
406 if (stitchOptions.ConfigurationForce != null) 406 if (stitchOptions.ConfigurationForce != null)
407 forceXPaths.UnionWith(stitchOptions.ConfigurationForce.Tag); 407 forceXPaths.UnionWith(stitchOptions.ConfigurationForce.Tag);
408   408  
409 // Patch the file. 409 // Patch the file.
410 StitchProgressUpdate("Patching file."); 410 StitchProgressUpdate("Patching file.");
411 var patchedFile = XML 411 var patchedFile = XML
412 .PatchXDocument(workingFile, defaultFile, forceXPaths, excludeXPaths); 412 .PatchXDocument(workingFile, defaultFile, forceXPaths, excludeXPaths);
413 if (patchedFile == null) 413 if (patchedFile == null)
414 throw new StitchException("Unable to patch XML files."); 414 throw new StitchException("Unable to patch XML files.");
415   415  
416 // Create a backup for the file to be patched. 416 // Create a backup for the file to be patched.
417 StitchProgressUpdate("Creating a backup of the file to be patched."); 417 StitchProgressUpdate("Creating a backup of the file to be patched.");
418 try 418 try
419 { 419 {
420 if (!dryrun) 420 if (!dryrun)
421 File.Copy(workingFilePath, 421 File.Copy(workingFilePath,
422 string.Join(Path.DirectorySeparatorChar.ToString(), 422 string.Join(Path.DirectorySeparatorChar.ToString(),
423 path, Constants.BACKUP_CONFIGURATION_FILE), true); 423 path, STITCH_CONSTANTS.BACKUP_CONFIGURATION_FILE), true);
424 } 424 }
425 catch (Exception ex) 425 catch (Exception ex)
426 { 426 {
427 throw new StitchException("Unable to create patched file backup.", ex); 427 throw new StitchException("Unable to create patched file backup.", ex);
428 } 428 }
429   429  
430 // Write the patched file. 430 // Write the patched file.
431 StitchProgressUpdate("Saving the patched file."); 431 StitchProgressUpdate("Saving the patched file.");
432 try 432 try
433 { 433 {
434 if (!dryrun) 434 if (!dryrun)
435 patchedFile.Save(string.Join(Path.DirectorySeparatorChar.ToString(), 435 patchedFile.Save(string.Join(Path.DirectorySeparatorChar.ToString(),
436 path, Constants.WORKING_CONFIGURATION_FILE)); 436 path, STITCH_CONSTANTS.WORKING_CONFIGURATION_FILE));
437 } 437 }
438 catch (Exception ex) 438 catch (Exception ex)
439 { 439 {
440 throw new StitchException("Unable to save patched file.", ex); 440 throw new StitchException("Unable to save patched file.", ex);
441 } 441 }
442   442  
443 StitchProgressUpdate("Stitching successful."); 443 StitchProgressUpdate("Stitching successful.");
444 return true; 444 return true;
445 } 445 }
446 } 446 }
447 } 447 }
448   448  
449
Generated by GNU Enscript 1.6.5.90.
449
Generated by GNU Enscript 1.6.5.90.
450   450  
451   451  
452   452