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); }