Example #1
0
        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());
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }