public void Test() { string root = Path.Combine(TemporaryDirectory, "testDeployment"); Directory.CreateDirectory(root); File.WriteAllText( Path.Combine(root, TestServerManifestName), @"included1.dll included1.pdb excluded1.txt subdir" + Path.DirectorySeparatorChar + "included2.exe" + Environment.NewLine + AppDeployment.BuildXLBrandingManifestFileName); File.WriteAllText(Path.Combine(root, "included1.dll"), "test"); // Include pdbs to aid with call stacks when debugging File.WriteAllText(Path.Combine(root, "included1.pdb"), "test"); File.WriteAllText(Path.Combine(root, "excluded1.txt"), "test"); File.WriteAllText(Path.Combine(root, "excluded2.dll"), "test"); File.WriteAllText(Path.Combine(root, AppDeployment.BuildXLBrandingManifestFileName), "test"); Directory.CreateDirectory(Path.Combine(root, "subdir")); File.WriteAllText(Path.Combine(root, "subdir", "included2.exe"), "test"); // Create an initial app deployment and verify it is correct AppDeployment deployment = AppDeployment.ReadDeploymentManifest(root, TestServerManifestName); // Verify the file count. PDB files should only be included for the server deployment. XAssert.AreEqual(4, deployment.GetRelevantRelativePaths(forServerDeployment: true).Count()); XAssert.AreEqual(3, deployment.GetRelevantRelativePaths(forServerDeployment: false).Count()); Fingerprint originalHash = deployment.TimestampBasedHash; // Now mess with files that should not impact the state and make sure they are excluded // This file is excluded because of the extension. It is in the manifest UpdateFile(Path.Combine(root, "excluded1.txt")); // This file is excluded because it isn't in the deployment manifest UpdateFile(Path.Combine(root, "excluded2.dll")); AppDeployment deployment2 = AppDeployment.ReadDeploymentManifest(root, TestServerManifestName); XAssert.AreEqual( deployment.TimestampBasedHash.ToHex(), deployment2.TimestampBasedHash.ToHex()); // Mess with a file that is in the deployment and check that the hash does change UpdateFile(Path.Combine(root, "subdir", "included2.exe")); AppDeployment deployment3 = AppDeployment.ReadDeploymentManifest(root, TestServerManifestName); XAssert.AreNotEqual( deployment.TimestampBasedHash.ToHex(), deployment3.TimestampBasedHash.ToHex()); }
private static ServerDeploymentCacheCreated CreateServerDeployment(string destDir, AppDeployment clientApp) { Stopwatch st = Stopwatch.StartNew(); // Every time the server cache gets created, a file with the result of GetDeploymentHash is created, so we avoid computing this again // The assumption is that nobody but this process modifies the server cache folder string serverDeploymentHashFile = Path.Combine(destDir, ServerDeploymentHashFilename); // Deletes the existing cache directory if it exists, so we avoid accumulating garbage. if (Directory.Exists(destDir)) { // Check if the main root process (likely bxl.exe) is in use before attempting to delete, so we avoid partially deleting files // Not completely bullet proof (there can be a race) but it is highly unlikely the process starts to be in use right after this check KillServer(destDir); // Delete the deployment hash file first to make sure the deployment cache cannot be used in case the // cleanup of the other files is interrupted. PoisonServerDeployment(destDir); // Remove all files regardless of files being readonly FileUtilities.DeleteDirectoryContents(destDir, true); } // Perform the deployment AppDeployment serverDeployment = AppDeployment.ReadDeploymentManifest(clientApp.BaseDirectory, AppDeployment.ServerDeploymentManifestFileName); HashSet <string> directories = new HashSet <string>(); List <KeyValuePair <string, string> > filesToCopy = new List <KeyValuePair <string, string> >(); foreach (string path in serverDeployment.GetRelevantRelativePaths(forServerDeployment: true).Concat(new string[] { AppDeployment.ServerDeploymentManifestFileName })) { string targetPath = Path.Combine(destDir, path); string sourcePath = Path.Combine(clientApp.BaseDirectory, path); string directory = Path.GetDirectoryName(targetPath); if (directories.Add(directory)) { FileUtilities.CreateDirectory(directory); } filesToCopy.Add(new KeyValuePair <string, string>(sourcePath, targetPath)); } // Because some deployments use virtualized vpak, using a very parallelized copy is beneficial Parallel.ForEach( filesToCopy, new ParallelOptions() { MaxDegreeOfParallelism = 50, }, (fileToCopy) => { if (File.Exists(fileToCopy.Key)) { File.Copy(fileToCopy.Key, fileToCopy.Value); } }); #if !FEATURE_CORECLR var ngenExe = Path.Combine(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), @"ngen.exe"); var destExe = Path.Combine(destDir, System.AppDomain.CurrentDomain.FriendlyName); // queue:1 means it runs in the background var ngenArgs = "install " + destExe + " /queue:1"; bool runNgen = File.Exists(ngenExe); if (runNgen) { ProcessStartInfo startInfo = new ProcessStartInfo(ngenExe, ngenArgs); startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; Process.Start(startInfo); } #endif using (var file = new StreamWriter(File.OpenWrite(serverDeploymentHashFile))) { file.WriteLine(clientApp.TimestampBasedHash); // This isn't actually consumed. It is only used for debugging file.WriteLine("Debug info:"); #if !FEATURE_CORECLR if (runNgen) { file.WriteLine("Ran Ngen: " + ngenExe + " " + ngenArgs); } #endif file.WriteLine(clientApp.TimestampBasedHashDebug); } ServerDeploymentCacheCreated cacheCreated = default(ServerDeploymentCacheCreated); cacheCreated.TimeToCreateServerCacheMilliseconds = st.ElapsedMilliseconds; return(cacheCreated); }
private static ServerDeploymentCacheCreated CreateServerDeployment(string destDir, AppDeployment clientApp) { Stopwatch st = Stopwatch.StartNew(); // Check if the main server process is in use before attempting to delete the deployment, this way we avoid partially deleting files // due to access permission issues. This is not completely bullet proof (there can be a race) but it is highly unlikely the // process starts to be in use right after this check KillServer(destDir); // Deletes the existing cache directory if it exists, so we avoid accumulating garbage. if (Directory.Exists(destDir)) { // Remove all files regardless of files being readonly FileUtilities.DeleteDirectoryContents(destDir, true); } // Perform the deployment AppDeployment serverDeployment = AppDeployment.ReadDeploymentManifest(clientApp.BaseDirectory, AppDeployment.ServerDeploymentManifestFileName); HashSet <string> directories = new HashSet <string>(); List <KeyValuePair <string, string> > filesToCopy = new List <KeyValuePair <string, string> >(); foreach (string path in serverDeployment.GetRelevantRelativePaths(forServerDeployment: true).Concat(new string[] { AppDeployment.ServerDeploymentManifestFileName })) { string targetPath = Path.Combine(destDir, path); string sourcePath = Path.Combine(clientApp.BaseDirectory, path); string directory = Path.GetDirectoryName(targetPath); if (directories.Add(directory)) { FileUtilities.CreateDirectory(directory); } filesToCopy.Add(new KeyValuePair <string, string>(sourcePath, targetPath)); } // Because some deployments use virtualized vpak, using a very parallelized copy is beneficial Parallel.ForEach( filesToCopy, new ParallelOptions() { MaxDegreeOfParallelism = 50, }, (fileToCopy) => { if (File.Exists(fileToCopy.Key)) { File.Copy(fileToCopy.Key, fileToCopy.Value); } }); #if NET_FRAMEWORK var ngenExe = Path.Combine(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), @"ngen.exe"); var destExe = Path.Combine(destDir, System.AppDomain.CurrentDomain.FriendlyName); // queue:1 means it runs in the background if (File.Exists(ngenExe)) { var ngenArgs = "install " + destExe + " /queue:1"; ProcessStartInfo startInfo = new ProcessStartInfo(ngenExe, ngenArgs); startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; Process.Start(startInfo); } #endif ServerDeploymentCacheCreated cacheCreated = default(ServerDeploymentCacheCreated); cacheCreated.TimeToCreateServerCacheMilliseconds = st.ElapsedMilliseconds; return(cacheCreated); }