public void TestMixedSlash() { var assetPath1 = new UFile("/a\\b/c\\d.txt"); var assetPath2 = new UFile("/a/b/c/d.txt"); Assert.Equal(assetPath1.ToString(), assetPath2.ToString()); }
protected override bool Generate(SessionTemplateGeneratorParameters parameters) { if (parameters is null) { throw new ArgumentNullException(nameof(parameters)); } parameters.Validate(); var description = (TemplateSampleDescription)parameters.Description; var log = parameters.Logger; // The package might depend on other packages which need to be copied together when instanciating it. // However some of these packages might be in a parent folder, which can result in undesired behavior when copied. // Setting this to true will enforce all package dependencies to be moved to a folder local to the project bool doMoveParentDependencies = true; var regexes = new List <Tuple <Regex, MatchEvaluator> >(); var patternName = description.PatternName ?? description.DefaultOutputName; // Samples don't support spaces / dot in name (we would need to separate package name, package short name and namespace renaming for that) var parametersName = parameters.Name.Replace(" ", string.Empty) .Replace(".", string.Empty); if (patternName != parametersName) { // Make sure the target name is a safe for use everywhere, since both an asset or script might reference a filename // in which case they should match and be valid in that context string validNamespaceName = Utilities.BuildValidNamespaceName(parametersName); // Rename for general occurences of template name regexes.Add(new Tuple <Regex, MatchEvaluator>(new Regex($@"\b{patternName}\b"), match => validNamespaceName)); // Rename App as well (used in code) -- this is the only pattern of "package short name" that we have so far in Windows samples regexes.Add(new Tuple <Regex, MatchEvaluator>(new Regex($@"\b{patternName}App\b"), match => validNamespaceName)); } var outputDirectory = parameters.OutputDirectory; if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } // Write .gitignore WriteGitIgnore(parameters); UFile projectOutputFile = null; UFile projectInputFile = null; // Process files foreach (var directory in FileUtility.EnumerateDirectories(description.TemplateDirectory, SearchDirection.Down)) { foreach (var file in directory.GetFiles()) { // If the file is ending with the Template extension or a directory with the sample extension, don;t copy it if (file.FullName.EndsWith(TemplateDescription.FileExtension) || string.Compare(directory.Name, TemplateDescription.FileExtension, StringComparison.OrdinalIgnoreCase) == 0) { continue; } var relativeFile = new UFile(file.FullName).MakeRelative(description.TemplateDirectory); // Replace the name in the files if necessary foreach (var nameRegex in regexes) { relativeFile = nameRegex.Item1.Replace(relativeFile, nameRegex.Item2); } // Create the output directory if needed var outputFile = UPath.Combine(outputDirectory, relativeFile); var outputFileDirectory = outputFile.GetParent(); // Determine if we are processing the main game project var isPackageFile = projectOutputFile is null && Path.GetExtension(file.FullName).ToLowerInvariant() == ".csproj" && !Path.GetFileNameWithoutExtension(file.FullName).EndsWith(".Windows"); if (isPackageFile) { projectInputFile = file.FullName; projectOutputFile = outputFile; } if (!Directory.Exists(outputFileDirectory)) { Directory.CreateDirectory(outputFileDirectory); } if (IsBinaryFile(file.FullName)) { File.Copy(file.FullName, outputFile, true); } else { ProcessTextFile(file.FullName, outputFile, regexes, (isPackageFile && doMoveParentDependencies)); } } } if (projectOutputFile != null) { var inputProject = (SolutionProject)Package.LoadProject(log, projectInputFile); var outputProject = (SolutionProject)Package.LoadProject(log, projectOutputFile); var msbuildProject = VSProjectHelper.LoadProject(outputProject.FullPath, platform: "NoPlatform"); // If requested, add reference to Stride.Games.Testing if (parameters.TryGetTag(AddGamesTestingKey)) { var items = msbuildProject.AddItem("PackageReference", "Stride.Games.Testing", new[] { new KeyValuePair <string, string>("Version", StrideVersion.NuGetVersion), new KeyValuePair <string, string>("PrivateAssets", "contentfiles;analyzers") }); foreach (var item in items) { foreach (var metadata in item.Metadata) { metadata.Xml.ExpressedAsAttribute = true; } } } // Copy dependency files locally // We only want to copy the asset files. The raw files are in Resources and the game assets are in Assets. // If we copy each file locally they will be included in the package and we can then delete the dependency packages. foreach (var projectReference in msbuildProject.GetItems("ProjectReference").ToList()) { var packageDirectory = UPath.Combine(inputProject.FullPath.GetFullDirectory(), (UFile)projectReference.EvaluatedInclude).GetFullDirectory(); foreach (var directory in FileUtility.EnumerateDirectories(packageDirectory, SearchDirection.Down)) { foreach (var file in directory.GetFiles()) { // If the file is ending with the Template extension or a directory with the sample extension, don`t copy it if (file.FullName.EndsWith(TemplateDescription.FileExtension) || string.Compare(directory.Name, TemplateDescription.FileExtension, StringComparison.OrdinalIgnoreCase) == 0) { continue; } var relativeFile = new UFile(file.FullName).MakeRelative(packageDirectory); var relativeFilename = relativeFile.ToString(); bool isAsset = relativeFilename.Contains("Assets"); bool isResource = relativeFilename.Contains("Resources"); if (!isAsset && !isResource) { continue; } // Replace the name in the files if necessary foreach (var nameRegex in regexes) { relativeFile = nameRegex.Item1.Replace(relativeFile, nameRegex.Item2); } var outputFile = UPath.Combine(outputDirectory, relativeFile); { // Create the output directory if needed var outputFileDirectory = outputFile.GetParent(); if (!Directory.Exists(outputFileDirectory)) { Directory.CreateDirectory(outputFileDirectory); } } if (IsBinaryFile(file.FullName)) { File.Copy(file.FullName, outputFile, true); } else { ProcessTextFile(file.FullName, outputFile, regexes); } } } msbuildProject.RemoveItem(projectReference); } // Save csproj without ProjectReferences msbuildProject.Save(); msbuildProject.ProjectCollection.UnloadAllProjects(); msbuildProject.ProjectCollection.Dispose(); // Add package to session var loadParams = PackageLoadParameters.Default(); loadParams.GenerateNewAssetIds = true; loadParams.LoadMissingDependencies = false; var session = parameters.Session; // We should switch to loading .csproj once all samples are upgraded var loadedProject = session.AddExistingProject(projectOutputFile, log, loadParams); RemoveUnusedAssets(loadedProject.Package, session); parameters.Tags.Add(GeneratedPackageKey, loadedProject.Package); } else { log.Error("Unable to find generated package for this template."); } // Make sure we transfer overrides, etc. from what we deserialized to the asset graphs that we are going to save right after ApplyMetadata(parameters); return(true); }
public void TestMixedSlash() { var assetPath1 = new UFile("/a\\b/c\\d.txt"); var assetPath2 = new UFile("/a/b/c/d.txt"); Assert.AreEqual(assetPath1.ToString(), assetPath2.ToString()); }
private static Process FindVisualStudioInstance(UFile solutionPath) { // NOTE: this code is very hackish and does not 100% ensure that the correct instance of VS will be activated. var processes = Process.GetProcessesByName("devenv"); foreach (var process in processes) { // Get instances that have a solution with the same name currently open (The solution name is displayed in the title bar). if (process.MainWindowTitle.ToLowerInvariant().StartsWith(solutionPath.GetFileNameWithoutExtension().ToLowerInvariant())) { // If there is a matching instance, get its command line. var query = $"SELECT CommandLine FROM Win32_Process WHERE ProcessId = {process.Id}"; using (var managementObjectSearcher = new ManagementObjectSearcher(query)) { var managementObject = managementObjectSearcher.Get().Cast <ManagementObject>().First(); var commandLine = managementObject["CommandLine"].ToString(); if (commandLine.ToLowerInvariant().Replace("/", "\\").Contains(solutionPath.ToString().ToLowerInvariant().Replace("/", "\\"))) { return(process); } } } } return(null); }
protected override bool Generate(SessionTemplateGeneratorParameters parameters) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } parameters.Validate(); var description = (TemplateSampleDescription)parameters.Description; var log = parameters.Logger; // The package might depend on other packages which need to be copied together when instanciating it. // However some of these packages might be in a parent folder, which can result in undesired behavior when copied. // Setting this to true will enforce all package dependencies to be moved to a folder local to the project bool doMoveParentDependencies = true; var packageFile = Path.ChangeExtension(description.FullPath, Package.PackageFileExtension); if (!File.Exists(packageFile)) { log.Error($"Unable to find package [{packageFile}]"); return(false); } var packageLoadResult = new LoggerResult(); var package = Package.Load(packageLoadResult, packageFile, new PackageLoadParameters { AutoLoadTemporaryAssets = false, AutoCompileProjects = false, LoadAssemblyReferences = false, }); packageLoadResult.CopyTo(log); if (packageLoadResult.HasErrors) { return(false); } // We are going to replace all projects id by new ids var idsToReplace = package.Profiles.SelectMany(profile => profile.ProjectReferences).Select(project => project.Id).Distinct().ToDictionary(guid => guid.ToString("D"), guid => Guid.NewGuid(), StringComparer.OrdinalIgnoreCase); idsToReplace.Add(package.Id.ToString("D"), Guid.NewGuid()); // Add dependencies foreach (var packageReference in package.LocalDependencies) { description.FullPath.GetFullDirectory(); var referencePath = UPath.Combine(description.FullPath.GetFullDirectory(), packageReference.Location); if (!File.Exists(referencePath)) { log.Error($"Unable to find dependency package [{referencePath}]"); return(false); } var referenceLoadResult = new LoggerResult(); var reference = Package.Load(referenceLoadResult, referencePath, new PackageLoadParameters { AutoLoadTemporaryAssets = false, AutoCompileProjects = false, LoadAssemblyReferences = false, }); referenceLoadResult.CopyTo(log); if (referenceLoadResult.HasErrors) { return(false); } var extraIdsToReplace = reference.Profiles.SelectMany(profile => profile.ProjectReferences).Select(project => project.Id).Distinct().ToDictionary(guid => guid.ToString("D"), guid => Guid.NewGuid(), StringComparer.OrdinalIgnoreCase); idsToReplace.AddRange(extraIdsToReplace); } var guidRegexPattern = new StringBuilder(); guidRegexPattern.Append("("); guidRegexPattern.Append(string.Join("|", idsToReplace.Keys)); guidRegexPattern.Append(")"); var regexes = new List <Tuple <Regex, MatchEvaluator> >(); var guidRegex = new Tuple <Regex, MatchEvaluator>(new Regex(guidRegexPattern.ToString(), RegexOptions.IgnoreCase), match => idsToReplace[match.Groups[1].Value].ToString("D")); regexes.Add(guidRegex); var patternName = description.PatternName ?? description.DefaultOutputName; // Samples don't support spaces and dot in name (we would need to separate package name, package short name and namespace renaming for that). var parametersName = parameters.Name.Replace(" ", string.Empty).Replace(".", string.Empty); if (patternName != parametersName) { // Make sure the target name is a safe for use everywhere, since both an asset or script might reference a filename // in which case they should match and be valid in that context string validNamespaceName = Utilities.BuildValidNamespaceName(parametersName); // Rename for general occurences of template name regexes.Add(new Tuple <Regex, MatchEvaluator>(new Regex($@"\b{patternName}\b"), match => validNamespaceName)); // Rename App as well (used in code) -- this is the only pattern of "package short name" that we have so far in Windows samples regexes.Add(new Tuple <Regex, MatchEvaluator>(new Regex($@"\b{patternName}App\b"), match => validNamespaceName)); } var outputDirectory = parameters.OutputDirectory; if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } //write gitignore WriteGitIgnore(parameters); UFile packageOutputFile = null; // Process files foreach (var directory in FileUtility.EnumerateDirectories(description.TemplateDirectory, SearchDirection.Down)) { foreach (var file in directory.GetFiles()) { // If the file is ending with the Template extension or a directory with the sample extension, don;t copy it if (file.FullName.EndsWith(TemplateDescription.FileExtension) || string.Compare(directory.Name, TemplateDescription.FileExtension, StringComparison.OrdinalIgnoreCase) == 0) { continue; } var relativeFile = new UFile(file.FullName).MakeRelative(description.TemplateDirectory); // Replace the name in the files if necessary foreach (var nameRegex in regexes) { relativeFile = nameRegex.Item1.Replace(relativeFile, nameRegex.Item2); } // Create the output directory if needed var outputFile = UPath.Combine(outputDirectory, relativeFile); var outputFileDirectory = outputFile.GetParent(); // Grab the name of the output package file var isPackageFile = (packageOutputFile == null && file.FullName.EndsWith(Package.PackageFileExtension)); if (isPackageFile) { packageOutputFile = outputFile; } if (!Directory.Exists(outputFileDirectory)) { Directory.CreateDirectory(outputFileDirectory); } if (IsBinaryFile(file.FullName)) { File.Copy(file.FullName, outputFile, true); } else { ProcessTextFile(file.FullName, outputFile, regexes, (isPackageFile && doMoveParentDependencies)); } } } // Copy dependency files locally // We only want to copy the asset files. The raw files are in Resources and the game assets are in Assets. // If we copy each file locally they will be included in the package and we can then delete the dependency packages. foreach (var packageReference in package.LocalDependencies) { var packageDirectory = packageReference.Location.GetFullDirectory(); foreach (var directory in FileUtility.EnumerateDirectories(packageDirectory, SearchDirection.Down)) { foreach (var file in directory.GetFiles()) { // If the file is ending with the Template extension or a directory with the sample extension, don`t copy it if (file.FullName.EndsWith(TemplateDescription.FileExtension) || string.Compare(directory.Name, TemplateDescription.FileExtension, StringComparison.OrdinalIgnoreCase) == 0) { continue; } var relativeFile = new UFile(file.FullName).MakeRelative(packageDirectory); var relativeFilename = relativeFile.ToString(); bool isAsset = relativeFilename.Contains("Assets"); bool isResource = relativeFilename.Contains("Resources"); if (!isAsset && !isResource) { continue; } // Replace the name in the files if necessary foreach (var nameRegex in regexes) { relativeFile = nameRegex.Item1.Replace(relativeFile, nameRegex.Item2); } var outputFile = UPath.Combine(outputDirectory, relativeFile); { // Create the output directory if needed var outputFileDirectory = outputFile.GetParent(); if (!Directory.Exists(outputFileDirectory)) { Directory.CreateDirectory(outputFileDirectory); } } if (IsBinaryFile(file.FullName)) { File.Copy(file.FullName, outputFile, true); } else { ProcessTextFile(file.FullName, outputFile, regexes); } } } } if (packageOutputFile != null) { // Add package to session var loadParams = PackageLoadParameters.Default(); loadParams.ForceNugetRestore = true; loadParams.GenerateNewAssetIds = true; loadParams.LoadMissingDependencies = false; var session = parameters.Session; var loadedPackage = session.AddExistingPackage(packageOutputFile, log, loadParams); RemoveUnusedAssets(loadedPackage, session); parameters.Tags.Add(GeneratedPackageKey, loadedPackage); } else { log.Error("Unable to find generated package for this template"); } // Make sure we transfer overrides, etc. from what we deserialized to the asset graphs that we are going to save right after. ApplyMetadata(parameters); return(true); }