/// <summary> /// Adds manifest references - a public method that calls into private recursive method /// that updates file and assembly references. /// </summary> /// <param name="manifest">Manifest whose references are to be updated</param> /// <param name="addDeploy">Specifies is '.deploy' should be appended</param> /// <param name="fromDirectory">Directory at which to begin the recursive search</param> /// <param name="filesToIgnore">Files that should not be included in the manifest</param> /// <param name="lockedFileReporter">Delegate via which locked files will be reported</param> /// <param name="sender">Sender</param> /// <param name="updateProgress">UpdateProgress event handler</param> /// <param name="overwrite">Overwrite event handler</param> /// <param name="errors">List of errors</param> public static void AddReferences(ApplicationManifest manifest, bool addDeploy, string fromDirectory, List <string> filesToIgnore, LockedFileReporter lockedFileReporter, object sender, UpdateProgressEventHandler updateProgress, OverwriteEventHandler overwrite, ArrayList errors) { if ((manifest == null) || (fromDirectory == null)) { return; } // Strip a leading .\ from the path, if present if ((fromDirectory.Length >= 2) && fromDirectory.Substring(0, 2) == ".\\") { fromDirectory = fromDirectory.Substring(2); } // If stripping a leading .\ yields an empty string, use "." if (fromDirectory == "") { fromDirectory = "."; } // Append a trailing \ if necessary if (fromDirectory.LastIndexOf('\\') != fromDirectory.Length - 1) { fromDirectory += '\\'; } // Add application manifest file to the ignore list string manifestName = (manifest.AssemblyIdentity.Name + ".manifest").ToLower(); filesToIgnore.Add(manifestName); // We need to add the full path as well since the addDeploy // method is using the full filename for comparison. filesToIgnore.Add(manifest.SourcePath + manifestName); if (addDeploy) { filesToIgnore.Add(manifestName + ".deploy"); filesToIgnore.Add(manifest.SourcePath + manifestName + ".deploy"); } // Set the source path for the new references manifest.SourcePath = fromDirectory; updateProgress?.Invoke(sender, new UpdateProgressEventArgs(Action.Begin, "")); // Recursively search fromDirectory to get new references AddReferences(manifest, addDeploy, fromDirectory, fromDirectory, "", filesToIgnore, lockedFileReporter, sender, updateProgress, overwrite, errors); updateProgress?.Invoke(sender, new UpdateProgressEventArgs(Action.SearchComplete, "")); }
/// <summary> /// Adds/updates references, using a breadth-first recursive descent model. /// </summary> /// <param name="manifest">Manifest whose references are to be updated</param> /// <param name="addDeploy">Specifies if '.deploy' should be appended</param> /// <param name="root">Directory where search began (does not change during descent)</param> /// <param name="searchDirectory">Directory to examine for references and subdirectories</param> /// <param name="relativePath">Path from origin directory (codeBase) to current directory</param> /// <param name="filesToIgnore">Files that should not be included in the manifest</param> /// <param name="lockedFileReporter">Delegate via which locked files will be reported</param> /// <param name="sender">Sender</param> /// <param name="updateProgress">UpdateProgress event handler</param> /// <param name="overwrite">Overwrite event handler</param> /// <param name="errors">List of errors</param> private static void AddReferences(ApplicationManifest manifest, bool addDeploy, string root, string searchDirectory, string relativePath, List <string> filesToIgnore, LockedFileReporter lockedFileReporter, object sender, UpdateProgressEventHandler updateProgress, OverwriteEventHandler overwrite, ArrayList errors) { if ((manifest == null) || (searchDirectory == null)) { return; } // Process files in current directory string[] files; try { files = Directory.GetFiles(searchDirectory); } catch (System.UnauthorizedAccessException) { return; } if (addDeploy) { files = AppendDeploy(filesToIgnore, files, overwrite, errors); } bool launcherBasedDeployment = false; string launcherPath = addDeploy ? Path.Combine(root, LauncherUtil.LauncherFilename + ".deploy") : Path.Combine(root, LauncherUtil.LauncherFilename); if (File.Exists(launcherPath)) { launcherBasedDeployment = true; } List <BaseReference> assembliesToRemove = new List <BaseReference>(); List <BaseReference> filesToRemove = new List <BaseReference>(); foreach (string filePath in files) { bool bRelativePath = false; // Generate codebase from filePath string codebase = filePath; if (codebase == null) { // This could be true if we renamed a file continue; } string extension = Path.GetExtension(codebase).ToLower(); // Strip a leading .\ from the path, if present if ((codebase.Length >= 2) && codebase.Substring(0, 2) == ".\\") { bRelativePath = true; codebase = codebase.Substring(2); } // See if this file is in the ignore list. // Ignorelist of the .manifest file is using the fullpath at // the very beggining so if a -fd . is used it does not find it. if (filesToIgnore.Contains(codebase.ToLower()) || (bRelativePath && extension == ".manifest" && filesToIgnore.Contains(Path.GetFullPath(codebase).ToLower()))) { continue; } // Strip the root path from the filename, if present if (codebase.StartsWith(root)) { codebase = codebase.Substring(root.Length); } // See if this file is in the ignore list if (filesToIgnore.Contains(codebase.ToLower()) || Path.GetExtension(codebase).ToLower() == ".netmodule" || (Path.GetExtension(codebase).ToLower() == ".deploy") && Path.GetExtension(codebase.Substring(0, codebase.Length - 7)).ToLower() == ".netmodule") { continue; } // Use the presence/absence of metadata to indicate whether // the file is an assembly or just a regular sort of file. AssemblyIdentity assembly = null; // If this is a Launcher-based deployment, all files except Launcher should be added as simple files // Launcher-based deployments are used for .NET (Core) apps - assembly identity cannot be positively // obtained from all types of .NET (Core) assemblies, requiring us to use simple file references. if (string.Equals(filePath, launcherPath, StringComparison.OrdinalIgnoreCase) || !launcherBasedDeployment) { try { assembly = AssemblyIdentity.FromFile(filePath); } catch (BadImageFormatException) { // The file does not have a manifest in it } catch (System.Net.WebException) { // Internet connection might not be available } } bool isAssembly = (assembly != null); // Make sure the file isn't locked, print an error message if // it is. Without this test, ManifestUtil will throw an // exception later when it tries to compute the file's hash. try { FileInfo f = new FileInfo(filePath); Stream s = f.OpenRead(); s.Close(); } catch (System.Exception) { lockedFileReporter?.Invoke(filePath); continue; } // Create a reference and add it to the appropriate collection. Action action = Action.AlreadyPresent; if (isAssembly) { if (!CollectionContains(manifest.AssemblyReferences, codebase, assembliesToRemove)) { AssemblyReference newref = new AssemblyReference { TargetPath = codebase }; manifest.AssemblyReferences.Add(newref); action = Action.Added; // Determine if this is the EntryPoint string strippedPath = codebase; if (strippedPath.ToLower().EndsWith(".deploy")) { strippedPath = strippedPath.Substring(0, codebase.Length - 7).ToLower(); } if (manifest.EntryPoint != null && (String.Compare(manifest.EntryPoint.TargetPath, strippedPath, true, CultureInfo.InvariantCulture) == 0)) { manifest.EntryPoint = newref; } } } else { if (!CollectionContains(manifest.FileReferences, codebase, filesToRemove)) { FileReference newref = new FileReference { TargetPath = codebase }; manifest.FileReferences.Add(newref); action = Action.Added; } } if (updateProgress != null) { updateProgress(sender, new UpdateProgressEventArgs(action, codebase)); } } // Remove files that were replaced because of renames. foreach (BaseReference reference in assembliesToRemove) { manifest.AssemblyReferences.Remove(reference as AssemblyReference); } foreach (BaseReference reference in filesToRemove) { manifest.FileReferences.Remove(reference as FileReference); } // Descend to subfolders string[] subdirs = Directory.GetDirectories(searchDirectory); foreach (string eachSubdir in subdirs) { string subdir = Path.GetFileName(eachSubdir); string newRelativePath; if ((relativePath.Length == 0) || (relativePath == ".")) { newRelativePath = subdir; } else { newRelativePath = relativePath + "\\" + subdir; } AddReferences(manifest, addDeploy, root, eachSubdir, newRelativePath, filesToIgnore, lockedFileReporter, sender, updateProgress, overwrite, errors); } }