public sealed override bool Run(PackageTemplateGeneratorParameters parameters) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); parameters.Validate(); var logger = parameters.Logger; var name = parameters.Name; var package = parameters.Package; // Make sure we have a shared profile var sharedProfile = package.Profiles.FindSharedProfile(); if (sharedProfile == null) { sharedProfile = PackageProfile.NewShared(); package.Profiles.Add(sharedProfile); } // Log progress var projectName = name; ProjectTemplateGeneratorHelper.Progress(logger, $"Generating {projectName}...", 0, 1); // Generate the library List<string> generatedFiles; ProjectTemplateGeneratorHelper.AddOption(parameters, "Platforms", AssetRegistry.SupportedPlatforms); var projectGameRef = ProjectTemplateGeneratorHelper.GenerateTemplate(parameters, package, "ProjectLibrary/ProjectLibrary.ttproj", projectName, PlatformType.Shared, null, ProjectType.Library, out generatedFiles); projectGameRef.Type = ProjectType.Library; sharedProfile.ProjectReferences.Add(projectGameRef); // Log done ProjectTemplateGeneratorHelper.Progress(logger, "Done", 1, 1); return true; }
private static ProjectReference FindSharedGameProject(Package package, PackageProfile sharedProfile, ILogger logger) { if (sharedProfile == null) { throw new ArgumentNullException(nameof(sharedProfile)); } // TODO: this is not a reliable way to get a game project see PDX-1128 var gameProjectRef = sharedProfile.ProjectReferences.FirstOrDefault(projectRef => projectRef.Type == ProjectType.Library && projectRef.Location.FullPath.EndsWith("Game.csproj", StringComparison.InvariantCultureIgnoreCase)); if (gameProjectRef == null) { logger.Error($"Unable to find the game project reference from the package [{package.Meta.Name}]"); return(null); } return(gameProjectRef); }
/// <summary> /// Creates a new Xenko package with the specified name /// </summary> /// <param name="name">Name of the package</param> /// <returns>A new package instance</returns> public static Package NewPackage(string name) { var package = new Package { Meta = { Name = name, Version = new PackageVersion("1.0.0.0") }, }; // Add dependency to latest Xenko package package.Meta.Dependencies.Add(XenkoConfig.GetLatestPackageDependency()); // Setup the assets folder by default package.Profiles.Add(PackageProfile.NewShared()); return(package); }
public ProfileViewModel(SessionViewModel session, Package package, PackageProfile profile, PackageViewModel container) : base(session.ServiceProvider) { if (package == null) { throw new ArgumentNullException(nameof(package)); } if (profile == null) { throw new ArgumentNullException(nameof(profile)); } this.session = session; this.package = package; this.profile = profile; Package = container; foreach (var projectReference in profile.ProjectReferences) { var viewModel = new ProjectViewModel(projectReference, this); Projects.Add(viewModel); } }
public static void Build(Package package, string outputDirectory = null) { if (package == null) throw new ArgumentNullException("package"); var meta = new NuGet.ManifestMetadata(); package.Meta.ToNugetManifest(meta); var builder = new NuGet.PackageBuilder(); builder.Populate(meta); // TODO this is not working var files = new List<NuGet.ManifestFile>() { NewFile(@"Bin\**\*.exe", "Bin"), NewFile(@"Bin\**\*.vsix", "Bin"), NewFile(@"Bin\**\*.so", "Bin"), NewFile(@"Bin\**\*.a", "Bin"), NewFile(@"Bin\**\*.md", "Bin"), NewFile(@"Bin\**\*.html", "Bin"), NewFile(@"Bin\**\*.config", "Bin"), NewFile(@"Bin\**\*.dll", "Bin"), NewFile(@"Bin\**\*.xml", "Bin"), NewFile(@"Bin\**\*.winmd", "Bin"), NewFile(@"Targets\*.targets", "Targets"), }; // Handle Assets var rootDir = package.RootDirectory; var newPackage = new Package { Meta = package.Meta }; foreach (var profile in package.Profiles) { var target = "Assets/" + profile.Name; foreach (var assetFolder in profile.AssetFolders) { // TODO: handle exclude in asset folders //files.Add(NewFile(source, target, @"**\*.cs;**\*.hlsl;**\*.csproj;**\*.csproj.user;**\obj\**")); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.pdxsl", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.pdxfx", target)); } var targetProfile = new PackageProfile(profile.Name); targetProfile.AssetFolders.Add(new AssetFolder(target)); newPackage.Profiles.Add(targetProfile); } // Handle templates var targetFolder = new TemplateFolder("Templates"); foreach (var templateFolder in package.TemplateFolders) { var source = templateFolder.Path.MakeRelative(rootDir) + "/**"; UDirectory target = targetFolder.Path; if (templateFolder.Group != null) { target = UPath.Combine(target, templateFolder.Group); } var excludeFiles = templateFolder.Exclude; files.Add(NewFile(source, target, excludeFiles)); // Add template files foreach (var templateFile in templateFolder.Files) { var newTemplateFile = templateFile.MakeRelative(templateFolder.Path); if (templateFolder.Group != null) { newTemplateFile = UPath.Combine(templateFolder.Group, newTemplateFile); } newTemplateFile = UPath.Combine(targetFolder.Path, newTemplateFile); targetFolder.Files.Add(newTemplateFile); } } // Create temp package for archive newPackage.TemplateFolders.Add(targetFolder); var newPackageFileName = "temp" + Guid.NewGuid() + ".pdxpkg"; newPackage.FullPath = package.RootDirectory + "/" + newPackageFileName; var result = newPackage.Save(); if (result.HasErrors) { throw new InvalidOperationException(result.ToText()); // TODO throw error } files.Add(NewFile(newPackageFileName, package.Meta.Name + Package.PackageFileExtension)); // Add files builder.PopulateFiles(package.RootDirectory, files); outputDirectory = outputDirectory ?? Environment.CurrentDirectory; // Save the nupkg var outputPath = GetOutputPath(builder, outputDirectory); bool isExistingPackage = File.Exists(outputPath); if (isExistingPackage) { File.Delete(outputPath); } try { using (Stream stream = File.Create(outputPath)) { builder.Save(stream); } } catch { if (!isExistingPackage && File.Exists(outputPath)) { File.Delete(outputPath); } throw; } File.Delete(newPackage.FullPath); }
public void TestBasicPackageCreateSaveLoad() { var dirPath = DirectoryTestBase + @"TestBasicPackageCreateSaveLoad"; string testGenerated1 = Path.Combine(dirPath, "TestPackage_TestBasicPackageCreateSaveLoad_Generated1.pdxpkg"); string testGenerated2 = Path.Combine(dirPath,"TestPackage_TestBasicPackageCreateSaveLoad_Generated2.pdxpkg"); string referenceFilePath = Path.Combine(dirPath,"TestPackage_TestBasicPackageCreateSaveLoad_Reference.pdxpkg"); // Force the PackageId to be the same each time we run the test // Usually the PackageId is unique and generated each time we create a new project var project = new Package { Id = Guid.Empty, FullPath = testGenerated1 }; var sharedProfile = new PackageProfile("Shared", new AssetFolder(".")); project.Profiles.Add(sharedProfile); var projectReference = new ProjectReference(Guid.Empty, Path.Combine(dirPath, "test.csproj"), ProjectType.Executable); sharedProfile.ProjectReferences.Add(projectReference); var session = new PackageSession(project); // Write the solution when saving session.SolutionPath = Path.Combine(dirPath, "TestPackage_TestBasicPackageCreateSaveLoad_Generated1.sln"); // Delete the solution before saving it if (File.Exists(session.SolutionPath)) { File.Delete(session.SolutionPath); } var result = session.Save(); Assert.IsFalse(result.HasErrors); // Reload the raw package and if UFile and UDirectory were saved relative var rawPackage = (Package)AssetSerializer.Load(testGenerated1); var rawPackageSharedProfile = rawPackage.Profiles.FirstOrDefault(); Assert.IsNotNull(rawPackageSharedProfile); var rawSourceFolder = rawPackage.Profiles.First().AssetFolders.FirstOrDefault(); Assert.IsNotNull(rawSourceFolder); Assert.AreEqual(".", (string)rawSourceFolder.Path); Assert.AreEqual("test.csproj", (string)rawPackageSharedProfile.ProjectReferences[0].Location); // Reload the package directly from the pdxpkg var project2Result = PackageSession.Load(testGenerated1); AssertResult(project2Result); var project2 = project2Result.Session.LocalPackages.FirstOrDefault(); Assert.IsNotNull(project2); Assert.AreEqual(project.Id, project2.Id); Assert.IsTrue(project2.Profiles.Count > 0); Assert.IsTrue(project2.Profiles.First().AssetFolders.Count > 0); var sourceFolder = project.Profiles.First().AssetFolders.First().Path; Assert.AreEqual(sourceFolder, project2.Profiles.First().AssetFolders.First().Path); // Reload the package from the sln var sessionResult = PackageSession.Load(session.SolutionPath); Assert.IsFalse(sessionResult.HasErrors); var sessionReload = sessionResult.Session; Assert.AreEqual(1, sessionReload.LocalPackages.Count()); Assert.AreEqual(project.Id, sessionReload.LocalPackages.First().Id); Assert.AreEqual(1, sessionReload.LocalPackages.First().Profiles.Count); var sharedProfileReload = sessionReload.LocalPackages.First().Profiles.First(); Assert.AreEqual(1, sharedProfileReload.ProjectReferences.Count); Assert.AreEqual(projectReference, sharedProfileReload.ProjectReferences[0]); }
private static void GenerateUnitTestProject(string outputDirectory, string templateFile, string name, string projectNamespace) { var projectTemplate = ProjectTemplate.Load(templateFile); // Force reference to Xenko.Assets (to have acess to SolutionPlatform) projectTemplate.Assemblies.Add(typeof(GraphicsProfile).Assembly.FullName); projectTemplate.Assemblies.Add(typeof(XenkoConfig).Assembly.FullName); var options = new Dictionary <string, object>(); // When generating over an existing set of files, retrieve the existing IDs // for better incrementality Guid projectGuid, assetId; GetExistingGuid(outputDirectory, name + ".Windows.csproj", out projectGuid); GetExistingAssetId(outputDirectory, name + ".xkpkg", out assetId); var session = new PackageSession(); var result = new LoggerResult(); var templateGeneratorParameters = new SessionTemplateGeneratorParameters(); templateGeneratorParameters.OutputDirectory = outputDirectory; templateGeneratorParameters.Session = session; templateGeneratorParameters.Name = name; templateGeneratorParameters.Logger = result; templateGeneratorParameters.Description = new TemplateDescription(); templateGeneratorParameters.Id = assetId; if (!PackageUnitTestGenerator.Default.PrepareForRun(templateGeneratorParameters).Result) { Console.WriteLine(@"Error generating package: PackageUnitTestGenerator.PrepareForRun returned false"); return; } if (!PackageUnitTestGenerator.Default.Run(templateGeneratorParameters)) { Console.WriteLine(@"Error generating package: PackageUnitTestGenerator.Run returned false"); return; } if (result.HasErrors) { Console.WriteLine($"Error generating package: {result.ToText()}"); return; } var package = session.LocalPackages.Single(); var previousCurrent = session.CurrentPackage; session.CurrentPackage = package; // Compute Xenko Sdk relative path // We are supposed to be in standard output binary folder, so Xenko root should be at ..\.. var xenkoPath = UPath.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), new UDirectory(@"..\..")); var xenkoRelativePath = new UDirectory(xenkoPath) .MakeRelative(outputDirectory) .ToString() .Replace('/', '\\'); xenkoRelativePath = xenkoRelativePath.TrimEnd('\\'); options["Namespace"] = projectNamespace ?? name; options["Package"] = package; options["Platforms"] = new List <SolutionPlatform>(AssetRegistry.SupportedPlatforms); options["XenkoSdkRelativeDir"] = xenkoRelativePath; // Generate project template result = projectTemplate.Generate(outputDirectory, name, projectGuid, options); if (result.HasErrors) { Console.WriteLine("Error generating solution: {0}", result.ToText()); return; } var sharedProfile = package.Profiles.FindSharedProfile(); // Setup the assets folder Directory.CreateDirectory(UPath.Combine(outputDirectory, (UDirectory)"Assets/Shared")); // Add Windows test as Shared library var projectWindowsRef = new ProjectReference(projectGuid, UPath.Combine(outputDirectory, (UFile)(name + ".Windows.csproj")), SiliconStudio.Assets.ProjectType.Library); sharedProfile.ProjectReferences.Add(projectWindowsRef); // Generate executable projects for each platform foreach (var platform in AssetRegistry.SupportedPlatforms) { var platformProfile = new PackageProfile(platform.Name) { Platform = platform.Type }; platformProfile.AssetFolders.Add(new AssetFolder("Assets/" + platform.Name)); // Log progress var projectName = name + "." + platform.Type; // Create project reference var projectPlatformRef = new ProjectReference(projectGuid, UPath.Combine(outputDirectory, (UFile)(projectName + ".csproj")), SiliconStudio.Assets.ProjectType.Executable); platformProfile.ProjectReferences.Add(projectPlatformRef); package.Profiles.Add(platformProfile); } session.CurrentPackage = previousCurrent; session.Save(result); if (result.HasErrors) { Console.WriteLine("Error saving package: {0}", result.ToText()); return; } }
/// <summary> /// Builds bundles. It will automatically analyze assets and chunks to determine dependencies and what should be embedded in which bundle. /// Bundle descriptions will be loaded from <see cref="Package.Bundles" /> provided by the <see cref="packageSession" />, and copied to <see cref="outputDirectory" />. /// </summary> /// <param name="logger">The builder logger.</param> /// <param name="packageSession">The project session.</param> /// <param name="profile">The build profile.</param> /// <param name="indexName">Name of the index file.</param> /// <param name="outputDirectory">The output directory.</param> /// <param name="disableCompressionIds">The object id that should be kept uncompressed in the bundle (everything else will be compressed using LZ4).</param> /// <exception cref="System.InvalidOperationException"> /// </exception> public void Build(Logger logger, PackageSession packageSession, PackageProfile profile, string indexName, string outputDirectory, ISet <ObjectId> disableCompressionIds) { if (logger == null) { throw new ArgumentNullException("logger"); } if (packageSession == null) { throw new ArgumentNullException("packageSession"); } if (indexName == null) { throw new ArgumentNullException("indexName"); } if (outputDirectory == null) { throw new ArgumentNullException("outputDirectory"); } if (disableCompressionIds == null) { throw new ArgumentNullException("disableCompressionIds"); } // Load index maps and mount databases var objDatabase = new ObjectDatabase("/data/db", indexName, loadDefaultBundle: false); logger.Info("Generate bundles: Scan assets and their dependencies..."); // Prepare list of bundles gathered from all projects var bundles = new List <Bundle>(); foreach (var project in packageSession.Packages) { bundles.AddRange(project.Bundles); } var databaseFileProvider = new DatabaseFileProvider(objDatabase.AssetIndexMap, objDatabase); AssetManager.GetFileProvider = () => databaseFileProvider; // Pass1: Create ResolvedBundle from user Bundle var resolvedBundles = new Dictionary <string, ResolvedBundle>(); foreach (var bundle in bundles) { if (resolvedBundles.ContainsKey(bundle.Name)) { throw new InvalidOperationException(string.Format("Two bundles with name {0} found", bundle.Name)); } resolvedBundles.Add(bundle.Name, new ResolvedBundle(bundle)); } // Pass2: Enumerate all assets which directly or indirectly belong to an bundle var bundleAssets = new HashSet <string>(); foreach (var bundle in resolvedBundles) { // For each project, we apply asset selectors of current bundle // This will give us a list of "root assets". foreach (var assetSelector in bundle.Value.Source.Selectors) { foreach (var assetLocation in assetSelector.Select(packageSession, objDatabase.AssetIndexMap)) { bundle.Value.AssetUrls.Add(assetLocation); } } // Compute asset dependencies, and fill bundleAssets with list of all assets contained in bundles (directly or indirectly). foreach (var assetUrl in bundle.Value.AssetUrls) { CollectReferences(bundle.Value.Source, bundleAssets, assetUrl, objDatabase.AssetIndexMap); } } // Pass3: Create a default bundle that contains all assets not contained in any bundle (directly or indirectly) var defaultBundle = new Bundle { Name = "default" }; var resolvedDefaultBundle = new ResolvedBundle(defaultBundle); bundles.Add(defaultBundle); resolvedBundles.Add(defaultBundle.Name, resolvedDefaultBundle); foreach (var asset in objDatabase.AssetIndexMap.GetMergedIdMap()) { if (!bundleAssets.Contains(asset.Key)) { resolvedDefaultBundle.AssetUrls.Add(asset.Key); } } // Pass4: Resolve dependencies foreach (var bundle in resolvedBundles) { // Every bundle depends implicitely on default bundle if (bundle.Key != "default") { bundle.Value.Dependencies.Add(resolvedBundles["default"]); } // Add other explicit dependencies foreach (var dependencyName in bundle.Value.Source.Dependencies) { ResolvedBundle dependency; if (!resolvedBundles.TryGetValue(dependencyName, out dependency)) { throw new InvalidOperationException(string.Format("Could not find dependency {0} when processing bundle {1}", dependencyName, bundle.Value.Name)); } bundle.Value.Dependencies.Add(dependency); } } logger.Info("Generate bundles: Assign assets to bundles..."); // Pass5: Topological sort (a.k.a. build order) // If there is a cyclic dependency, an exception will be thrown. var sortedBundles = TopologicalSort(resolvedBundles.Values, assetBundle => assetBundle.Dependencies); // Pass6: Find which ObjectId belongs to which bundle foreach (var bundle in sortedBundles) { // Add objects created by dependencies foreach (var dep in bundle.Dependencies) { // ObjectIds bundle.DependencyObjectIds.UnionWith(dep.DependencyObjectIds); bundle.DependencyObjectIds.UnionWith(dep.ObjectIds); // IndexMap foreach (var asset in dep.DependencyIndexMap.Concat(dep.IndexMap)) { if (!bundle.DependencyIndexMap.ContainsKey(asset.Key)) { bundle.DependencyIndexMap.Add(asset.Key, asset.Value); } } } // Collect assets (object ids and partial index map) from given asset urls // Those not present in dependencies will be added to this bundle foreach (var assetUrl in bundle.AssetUrls) { CollectBundle(bundle, assetUrl, objDatabase.AssetIndexMap); } } logger.Info("Generate bundles: Compress and save bundles to HDD..."); // Mount VFS for output database (currently disabled because already done in ProjectBuilder.CopyBuildToOutput) VirtualFileSystem.MountFileSystem("/data_output", outputDirectory); VirtualFileSystem.CreateDirectory("/data_output/db"); // Mount output database and delete previous bundles that shouldn't exist anymore (others should be overwritten) var outputDatabase = new ObjectDatabase("/data_output/db", loadDefaultBundle: false); try { outputDatabase.LoadBundle("default").GetAwaiter().GetResult(); } catch (Exception) { logger.Info("Generate bundles: Tried to load previous 'default' bundle but it was invalid. Deleting it..."); outputDatabase.BundleBackend.DeleteBundles(x => Path.GetFileNameWithoutExtension(x) == "default"); } var outputBundleBackend = outputDatabase.BundleBackend; var outputGroupBundleBackends = new Dictionary <string, BundleOdbBackend>(); if (profile != null && profile.OutputGroupDirectories != null) { var rootPackage = packageSession.LocalPackages.First(); foreach (var item in profile.OutputGroupDirectories) { var path = Path.Combine(rootPackage.RootDirectory, item.Value); var vfsPath = "/data_group_" + item.Key; var vfsDatabasePath = vfsPath + "/db"; // Mount VFS for output database (currently disabled because already done in ProjectBuilder.CopyBuildToOutput) VirtualFileSystem.MountFileSystem(vfsPath, path); VirtualFileSystem.CreateDirectory(vfsDatabasePath); outputGroupBundleBackends.Add(item.Key, new BundleOdbBackend(vfsDatabasePath)); } } // Pass7: Assign bundle backends foreach (var bundle in sortedBundles) { BundleOdbBackend bundleBackend; if (bundle.Source.OutputGroup == null) { // No output group, use OutputDirectory bundleBackend = outputBundleBackend; } else if (!outputGroupBundleBackends.TryGetValue(bundle.Source.OutputGroup, out bundleBackend)) { // Output group not found in OutputGroupDirectories, let's issue a warning and fallback to OutputDirectory logger.Warning("Generate bundles: Could not find OutputGroup {0} for bundle {1} in ProjectBuildProfile.OutputGroupDirectories", bundle.Source.OutputGroup, bundle.Name); bundleBackend = outputBundleBackend; } bundle.BundleBackend = bundleBackend; } CleanUnknownBundles(outputBundleBackend, resolvedBundles); foreach (var bundleBackend in outputGroupBundleBackends) { CleanUnknownBundles(bundleBackend.Value, resolvedBundles); } // Pass8: Pack actual data foreach (var bundle in sortedBundles) { // Compute dependencies (by bundle names) var dependencies = bundle.Dependencies.Select(x => x.Name).Distinct().ToList(); BundleOdbBackend bundleBackend; if (bundle.Source.OutputGroup == null) { // No output group, use OutputDirectory bundleBackend = outputBundleBackend; } else if (!outputGroupBundleBackends.TryGetValue(bundle.Source.OutputGroup, out bundleBackend)) { // Output group not found in OutputGroupDirectories, let's issue a warning and fallback to OutputDirectory logger.Warning("Generate bundles: Could not find OutputGroup {0} for bundle {1} in ProjectBuildProfile.OutputGroupDirectories", bundle.Source.OutputGroup, bundle.Name); bundleBackend = outputBundleBackend; } objDatabase.CreateBundle(bundle.ObjectIds.ToArray(), bundle.Name, bundleBackend, disableCompressionIds, bundle.IndexMap, dependencies); } logger.Info("Generate bundles: Done"); }
public static void Build(Package package, string specialVersion = null, string outputDirectory = null) { if (package == null) throw new ArgumentNullException("package"); var meta = new NuGet.ManifestMetadata(); package.Meta.ToNugetManifest(meta); // Override version with task SpecialVersion (if specified by user) if (specialVersion != null) { meta.Version = new PackageVersion(package.Meta.Version.ToString().Split('-').First() + "-" + specialVersion).ToString(); } var builder = new NuGet.PackageBuilder(); builder.Populate(meta); var currentAssemblyLocation = Assembly.GetExecutingAssembly().Location; var mainPlatformDirectory = Path.GetFileName(Path.GetDirectoryName(currentAssemblyLocation)); // TODO this is not working // We are excluding everything that is in a folder that starts with a dot (ie. .shadow, .vs) var files = new List<NuGet.ManifestFile>() { NewFile(@"Bin\**\*.exe", "Bin", @"Bin\**\.*\**\*.exe"), NewFile(@"Bin\**\*.vsix", "Bin", @"Bin\**\.*\**\*.vsix"), NewFile(@"Bin\**\*.so", "Bin", @"Bin\**\.*\**\*.so"), NewFile(@"Bin\**\*.a", "Bin", @"Bin\**\.*\**\*.a"), NewFile(@"Bin\**\*.md", "Bin", @"Bin\**\.*\**\*.md"), NewFile(@"Bin\**\*.html", "Bin", @"Bin\**\.*\**\*.html"), NewFile(@"Bin\**\*.config", "Bin", @"Bin\**\.*\**\*.config"), NewFile(@"Bin\**\*.dll", "Bin", @"Bin\**\.*\**\*.dll"), NewFile(@"Bin\**\*.xml", "Bin", @"Bin\**\.*\**\*.xml"), NewFile(@"Bin\**\*.usrdoc", "Bin", @"Bin\**\.*\**\*.usrdoc"), NewFile(@"Bin\**\*.winmd", "Bin", @"Bin\**\.*\**\*.winmd"), NewFile($@"Bin\{mainPlatformDirectory}\ios-tcprelay\*.py",$@"Bin\{mainPlatformDirectory}\ios-tcprelay"), NewFile(@"Targets\*.targets", "Targets"), NewFile($@"Bin\{mainPlatformDirectory}\SiliconStudio.*.pdb", $@"Bin\{mainPlatformDirectory}", @"Bin\**\SiliconStudio.Xenko.Importer*.pdb;Bin\**\SiliconStudio.Assets.Editor.pdb;Bin\**\SiliconStudio.Xenko.Assets.Presentation.pdb;Bin\**\SiliconStudio.Xenko.GameStudio*.pdb;Bin\**\SiliconStudio.Xenko.Assimp.Translation.pdb"), }; // Handle Assets var rootDir = package.RootDirectory; var newPackage = new Package { Meta = package.Meta }; foreach (var profile in package.Profiles) { var target = "Assets/" + profile.Name; foreach (var assetFolder in profile.AssetFolders) { // TODO: handle exclude in asset folders //files.Add(NewFile(source, target, @"**\*.cs;**\*.hlsl;**\*.csproj;**\*.csproj.user;**\obj\**")); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xksl", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkfx", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkfnt", target)); } var targetProfile = new PackageProfile(profile.Name); targetProfile.AssetFolders.Add(new AssetFolder(target)); newPackage.Profiles.Add(targetProfile); } // Handle templates var targetFolder = new TemplateFolder("Templates"); foreach (var templateFolder in package.TemplateFolders) { var source = templateFolder.Path.MakeRelative(rootDir) + "/**"; UDirectory target = targetFolder.Path; if (templateFolder.Group != null) { target = UPath.Combine(target, templateFolder.Group); } var excludeFiles = templateFolder.Exclude; files.Add(NewFile(source, target, excludeFiles)); // Add template files foreach (var templateFile in templateFolder.Files) { var newTemplateFile = templateFile.MakeRelative(templateFolder.Path); if (templateFolder.Group != null) { newTemplateFile = UPath.Combine(templateFolder.Group, newTemplateFile); } newTemplateFile = UPath.Combine(targetFolder.Path, newTemplateFile); targetFolder.Files.Add(newTemplateFile); } } // Create temp package for archive newPackage.TemplateFolders.Add(targetFolder); var newPackageFileName = "temp" + Guid.NewGuid() + ".xkpkg"; newPackage.FullPath = package.RootDirectory + "/" + newPackageFileName; var result = newPackage.Save(); if (result.HasErrors) { throw new InvalidOperationException(result.ToText()); // TODO throw error } files.Add(NewFile(newPackageFileName, package.Meta.Name + Package.PackageFileExtension)); // Add files builder.PopulateFiles(package.RootDirectory, files); outputDirectory = outputDirectory ?? Environment.CurrentDirectory; // Save the nupkg var outputPath = GetOutputPath(builder, outputDirectory); bool isExistingPackage = File.Exists(outputPath); if (isExistingPackage) { File.Delete(outputPath); } try { using (Stream stream = File.Create(outputPath)) { builder.Save(stream); } } catch { if (!isExistingPackage && File.Exists(outputPath)) { File.Delete(outputPath); } throw; } File.Delete(newPackage.FullPath); }
public void TestBasicPackageCreateSaveLoad() { PackageSessionPublicHelper.FindAndSetMSBuildVersion(); var dirPath = DirectoryTestBase + @"TestBasicPackageCreateSaveLoad"; string testGenerated1 = Path.Combine(dirPath, "TestPackage_TestBasicPackageCreateSaveLoad_Generated1.xkpkg"); string testGenerated2 = Path.Combine(dirPath, "TestPackage_TestBasicPackageCreateSaveLoad_Generated2.xkpkg"); string referenceFilePath = Path.Combine(dirPath, "TestPackage_TestBasicPackageCreateSaveLoad_Reference.xkpkg"); // Force the PackageId to be the same each time we run the test // Usually the PackageId is unique and generated each time we create a new project var project = new Package { Id = Guid.Empty, FullPath = testGenerated1 }; var sharedProfile = new PackageProfile("Shared", new AssetFolder(".")); project.Profiles.Add(sharedProfile); var projectReference = new ProjectReference(Guid.Empty, Path.Combine(dirPath, "test.csproj"), ProjectType.Executable); sharedProfile.ProjectReferences.Add(projectReference); var session = new PackageSession(project); // Write the solution when saving session.SolutionPath = Path.Combine(dirPath, "TestPackage_TestBasicPackageCreateSaveLoad_Generated1.sln"); // Delete the solution before saving it if (File.Exists(session.SolutionPath)) { File.Delete(session.SolutionPath); } var result = new LoggerResult(); session.Save(result); Assert.False(result.HasErrors); // Reload the raw package and if UFile and UDirectory were saved relative var rawPackage = AssetFileSerializer.Load <Package>(testGenerated1).Asset; var rawPackageSharedProfile = rawPackage.Profiles.FirstOrDefault(); Assert.NotNull(rawPackageSharedProfile); var rawSourceFolder = rawPackage.Profiles.First().AssetFolders.FirstOrDefault(); Assert.NotNull(rawSourceFolder); Assert.Equal(".", (string)rawSourceFolder.Path); Assert.Equal("test.csproj", (string)rawPackageSharedProfile.ProjectReferences[0].Location); // Reload the package directly from the xkpkg var project2Result = PackageSession.Load(testGenerated1); AssertResult(project2Result); var project2 = project2Result.Session.LocalPackages.FirstOrDefault(); Assert.NotNull(project2); Assert.Equal(project.Id, project2.Id); Assert.True(project2.Profiles.Count > 0); Assert.True(project2.Profiles.First().AssetFolders.Count > 0); Assert.Equal(project2, project2Result.Session.CurrentPackage); // Check that the current package is setup when loading a single package var sourceFolder = project.Profiles.First().AssetFolders.First().Path; Assert.Equal(sourceFolder, project2.Profiles.First().AssetFolders.First().Path); // Reload the package from the sln var sessionResult = PackageSession.Load(session.SolutionPath); Assert.False(sessionResult.HasErrors); var sessionReload = sessionResult.Session; Assert.Equal(1, sessionReload.LocalPackages.Count()); Assert.Equal(project.Id, sessionReload.LocalPackages.First().Id); Assert.Equal(1, sessionReload.LocalPackages.First().Profiles.Count); var sharedProfileReload = sessionReload.LocalPackages.First().Profiles.First(); Assert.Equal(1, sharedProfileReload.ProjectReferences.Count); Assert.Equal(projectReference, sharedProfileReload.ProjectReferences[0]); }
public static void Build(Package package, string specialVersion = null, string outputDirectory = null) { if (package == null) { throw new ArgumentNullException("package"); } var meta = new NuGet.ManifestMetadata(); package.Meta.ToNugetManifest(meta); // Override version with task SpecialVersion (if specified by user) if (specialVersion != null) { meta.Version = new PackageVersion(package.Meta.Version.ToString().Split('-').First() + "-" + specialVersion).ToString(); } var builder = new NuGet.PackageBuilder(); builder.Populate(meta); var currentAssemblyLocation = Assembly.GetExecutingAssembly().Location; var mainPlatformDirectory = Path.GetFileName(Path.GetDirectoryName(currentAssemblyLocation)); // TODO this is not working // We are excluding everything that is in a folder that starts with a dot (ie. .shadow, .vs) var files = new List <NuGet.ManifestFile>() { NewFile(@"Bin\**\*.exe", "Bin", @"Bin\**\.*\**\*.exe"), NewFile(@"Bin\**\*.vsix", "Bin", @"Bin\**\.*\**\*.vsix"), NewFile(@"Bin\**\*.so", "Bin", @"Bin\**\.*\**\*.so"), NewFile(@"Bin\**\*.a", "Bin", @"Bin\**\.*\**\*.a"), NewFile(@"Bin\**\*.md", "Bin", @"Bin\**\.*\**\*.md"), NewFile(@"Bin\**\*.html", "Bin", @"Bin\**\.*\**\*.html"), NewFile(@"Bin\**\*.config", "Bin", @"Bin\**\.*\**\*.config"), NewFile(@"Bin\**\*.dll", "Bin", @"Bin\**\.*\**\*.dll"), NewFile(@"Bin\**\*.xml", "Bin", @"Bin\**\.*\**\*.xml"), NewFile(@"Bin\**\*.usrdoc", "Bin", @"Bin\**\.*\**\*.usrdoc"), NewFile(@"Bin\**\*.winmd", "Bin", @"Bin\**\.*\**\*.winmd"), NewFile($@"Bin\{mainPlatformDirectory}\ios-tcprelay\*.py", $@"Bin\{mainPlatformDirectory}\ios-tcprelay"), NewFile(@"Targets\*.targets", "Targets"), NewFile($@"Bin\{mainPlatformDirectory}\SiliconStudio.*.pdb", $@"Bin\{mainPlatformDirectory}", @"Bin\**\SiliconStudio.Xenko.Importer*.pdb;Bin\**\SiliconStudio.Assets.Editor.pdb;Bin\**\SiliconStudio.Xenko.Assets.Presentation.pdb;Bin\**\SiliconStudio.Xenko.GameStudio*.pdb;Bin\**\SiliconStudio.Xenko.Assimp.Translation.pdb"), }; // Handle Assets var rootDir = package.RootDirectory; var newPackage = new Package { Meta = package.Meta }; foreach (var profile in package.Profiles) { var target = "Assets/" + profile.Name; foreach (var assetFolder in profile.AssetFolders) { // TODO: handle exclude in asset folders //files.Add(NewFile(source, target, @"**\*.cs;**\*.hlsl;**\*.csproj;**\*.csproj.user;**\obj\**")); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xksl", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkfx", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkfnt", target)); } var targetProfile = new PackageProfile(profile.Name); targetProfile.AssetFolders.Add(new AssetFolder(target)); newPackage.Profiles.Add(targetProfile); } // Handle templates var targetFolder = new TemplateFolder("Templates"); foreach (var templateFolder in package.TemplateFolders) { var source = templateFolder.Path.MakeRelative(rootDir) + "/**"; UDirectory target = targetFolder.Path; if (templateFolder.Group != null) { target = UPath.Combine(target, templateFolder.Group); } var excludeFiles = templateFolder.Exclude; files.Add(NewFile(source, target, excludeFiles)); // Add template files foreach (var templateFile in templateFolder.Files) { var newTemplateFile = templateFile.MakeRelative(templateFolder.Path); if (templateFolder.Group != null) { newTemplateFile = UPath.Combine(templateFolder.Group, newTemplateFile); } newTemplateFile = UPath.Combine(targetFolder.Path, newTemplateFile); targetFolder.Files.Add(newTemplateFile); } } // Create temp package for archive newPackage.TemplateFolders.Add(targetFolder); var newPackageFileName = "temp" + Guid.NewGuid() + ".xkpkg"; newPackage.FullPath = package.RootDirectory + "/" + newPackageFileName; var result = newPackage.Save(); if (result.HasErrors) { throw new InvalidOperationException(result.ToText()); // TODO throw error } files.Add(NewFile(newPackageFileName, package.Meta.Name + Package.PackageFileExtension)); // Add files builder.PopulateFiles(package.RootDirectory, files); outputDirectory = outputDirectory ?? Environment.CurrentDirectory; // Save the nupkg var outputPath = GetOutputPath(builder, outputDirectory); bool isExistingPackage = File.Exists(outputPath); if (isExistingPackage) { File.Delete(outputPath); } try { using (Stream stream = File.Create(outputPath)) { builder.Save(stream); } } catch { if (!isExistingPackage && File.Exists(outputPath)) { File.Delete(outputPath); } throw; } File.Delete(newPackage.FullPath); }
public static void Build(ILogger log, Package package, string outputDirectory = null) { if (package == null) { throw new ArgumentNullException(nameof(package)); } var meta = new ManifestMetadata(); PackageStore.ToNugetManifest(package.Meta, meta); // Sanity check: Xenko version should be same between NuGet package and Xenko package var nugetVersion = new PackageVersion(XenkoVersion.NuGetVersion).Version; var packageVersion = package.Meta.Version.Version; if (nugetVersion != packageVersion) { log.Error($"Package has mismatching version: NuGet package version is {nugetVersion} and Xenko Package version is {packageVersion}"); return; } if (nugetVersion.Revision <= 0) { // If 0, we have special cases with NuGet dropping it in install path, could be dangerous and lead to bugs if not properly tested. log.Error($"Package has revision {nugetVersion} but 4th digit needs to be at least 1."); return; } // Override version with NuGet version (4th number is different in Xenko package) meta.Version = XenkoVersion.NuGetVersion; var builder = new NugetPackageBuilder(); builder.Populate(meta); var currentAssemblyLocation = Assembly.GetExecutingAssembly().Location; var mainPlatformDirectory = Path.GetFileName(Path.GetDirectoryName(currentAssemblyLocation)); // TODO this is not working // We are excluding everything that is in a folder that starts with a dot (ie. .shadow, .vs) var files = new List <ManifestFile>() { NewFile(@"Bin\**\*.exe", "Bin", @"Bin\**\.*\**\*.exe;Bin\**\Tools\**.exe"), NewFile(@"Bin\**\*.so", "Bin", @"Bin\**\.*\**\*.so;Bin\Windows\lib\**\*.so"), NewFile(@"Bin\**\*.ssdeps", "Bin", @"Bin\**\.*\**\*.ssdeps"), NewFile(@"Bin\**\*.a", "Bin", @"Bin\**\.*\**\*.a"), NewFile(@"Bin\**\*.md", "Bin", @"Bin\**\.*\**\*.md"), NewFile(@"Bin\**\*.html", "Bin", @"Bin\**\.*\**\*.html"), NewFile(@"Bin\**\*.config", "Bin", @"Bin\**\.*\**\*.config"), NewFile(@"Bin\**\*.dll", "Bin", @"Bin\**\.*\**\*.dll;Bin\Windows\lib\**\*.dll"), NewFile(@"Bin\**\*.xml", "Bin", @"Bin\**\.*\**\*.xml"), NewFile(@"Bin\**\*.usrdoc", "Bin", @"Bin\**\.*\**\*.usrdoc"), NewFile(@"Bin\**\*.winmd", "Bin", @"Bin\**\.*\**\*.winmd"), NewFile(@"Bin\**\*.sh", "Bin", @"Bin\**\.*\**\*.sh"), NewFile(@"Bin\**\*.json", "Bin", @"Bin\**\.*\**\*.json"), NewFile(@"deps\AssemblyProcessor\*.exe", @"deps/AssemblyProcessor"), NewFile(@"deps\AssemblyProcessor\*.dll", @"deps/AssemblyProcessor"), NewFile($@"Bin\{mainPlatformDirectory}\ios-tcprelay\*.py", $@"Bin\{mainPlatformDirectory}\ios-tcprelay"), NewFile(@"Targets\*.targets", "Targets"), NewFile(@"Targets\*.props", "Targets"), NewFile($@"Bin\**\Xenko*.pdb", $@"Bin", @"Bin\**\.*\**\*.pdb;Bin\**\Xenko.Importer*.pdb;Bin\**\Xenko.Assimp.Translation.pdb"), NewFile(@"build\Xenko.targets", @"build"), NewFile(@"build\Xenko.props", @"build"), NewFile(@"tools\**\*.exe", "tools"), NewFile(@"tools\**\*.dll", "tools"), NewFile(@"LICENSE.md", @""), NewFile(@"THIRD PARTY.md", @""), NewFile(@"BACKERS.md", @""), }; // Handle Assets var rootDir = package.RootDirectory; var newPackage = new Package { Meta = AssetCloner.Clone(package.Meta) }; newPackage.Meta.Version = new PackageVersion(meta.Version); foreach (var profile in package.Profiles) { var target = "Assets/" + profile.Name; foreach (var assetFolder in profile.AssetFolders) { files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xk*", target)); } foreach (var resourceFolder in profile.ResourceFolders) { files.Add(NewFile(resourceFolder.MakeRelative(rootDir) + "/**/*.*", "Resources")); } var targetProfile = new PackageProfile(profile.Name); if (profile.AssetFolders.Count > 0) { targetProfile.AssetFolders.Add(new AssetFolder(target)); } if (profile.ResourceFolders.Count > 0) { targetProfile.ResourceFolders.Add("Resources"); } newPackage.Profiles.Add(targetProfile); } //Handle RootAssets foreach (var rootAsset in package.RootAssets) { newPackage.RootAssets.Add(rootAsset); } // Handle templates var targetFolder = new TemplateFolder("Templates"); foreach (var templateFolder in package.TemplateFolders) { var source = templateFolder.Path.MakeRelative(rootDir) + "/**"; UDirectory target = targetFolder.Path; if (templateFolder.Group != null) { target = UPath.Combine(target, templateFolder.Group); } var excludeFiles = templateFolder.Exclude; files.Add(NewFile(source, target, excludeFiles)); // Add template files foreach (var templateFile in templateFolder.Files) { var newTemplateFile = templateFile.MakeRelative(templateFolder.Path); if (templateFolder.Group != null) { newTemplateFile = UPath.Combine(templateFolder.Group, newTemplateFile); } newTemplateFile = UPath.Combine(targetFolder.Path, newTemplateFile); targetFolder.Files.Add(newTemplateFile); } } // Create temp package for archive newPackage.TemplateFolders.Add(targetFolder); var newPackageFileName = "temp" + Guid.NewGuid() + ".xkpkg"; newPackage.FullPath = package.RootDirectory + "/" + newPackageFileName; var result = new LoggerResult(); newPackage.Save(result); if (result.HasErrors) { throw new InvalidOperationException(result.ToText()); // TODO throw error } files.Add(NewFile(newPackageFileName, package.Meta.Name + Package.PackageFileExtension)); // Add files builder.PopulateFiles(package.RootDirectory, files); outputDirectory = outputDirectory ?? Environment.CurrentDirectory; // Save the nupkg var outputPath = GetOutputPath(builder, outputDirectory); bool isExistingPackage = File.Exists(outputPath); if (isExistingPackage) { File.Delete(outputPath); } try { using (Stream stream = File.Create(outputPath)) { builder.Save(stream); } } catch { if (!isExistingPackage && File.Exists(outputPath)) { File.Delete(outputPath); } throw; } File.Delete(newPackage.FullPath); }
private static void GenerateUnitTestProject(string outputDirectory, string templateFile, string name) { var projectTemplate = ProjectTemplate.Load(templateFile); // Force reference to Paradox.Assets (to have acess to SolutionPlatform) projectTemplate.Assemblies.Add(typeof(GraphicsProfile).Assembly.FullName); projectTemplate.Assemblies.Add(typeof(ParadoxConfig).Assembly.FullName); var options = new Dictionary<string, object>(); var session = new PackageSession(); var result = new LoggerResult(); var templateGeneratorParameters = new TemplateGeneratorParameters(); templateGeneratorParameters.OutputDirectory = outputDirectory; templateGeneratorParameters.Session = session; templateGeneratorParameters.Name = name; templateGeneratorParameters.Logger = result; templateGeneratorParameters.Description = new TemplateDescription(); PackageUnitTestGenerator.Default.Generate(templateGeneratorParameters); if (result.HasErrors) { Console.WriteLine("Error generating package: {0}", result.ToText()); return; } var package = templateGeneratorParameters.Package; var previousCurrent = session.CurrentPackage; session.CurrentPackage = package; // Compute Paradox Sdk relative path // We are supposed to be in standard output binary folder, so Paradox root should be at ..\.. var paradoxPath = UDirectory.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), new UDirectory(@"..\..")); var paradoxRelativePath = new UDirectory(paradoxPath) .MakeRelative(outputDirectory) .ToString() .Replace('/', '\\'); paradoxRelativePath = paradoxRelativePath.TrimEnd('\\'); options["Namespace"] = name; options["Package"] = package; options["Platforms"] = new List<SolutionPlatform>(AssetRegistry.SupportedPlatforms); options["ParadoxSdkRelativeDir"] = paradoxRelativePath; // Generate project template var projectGuid = Guid.NewGuid(); result = projectTemplate.Generate(outputDirectory, name, projectGuid, options); if (result.HasErrors) { Console.WriteLine("Error generating solution: {0}", result.ToText()); return; } var sharedProfile = package.Profiles[PlatformType.Shared]; // Setup the assets folder Directory.CreateDirectory(UPath.Combine(outputDirectory, (UDirectory)"Assets/Shared")); // Add Windows test as Shared library var projectWindowsRef = new ProjectReference(); projectWindowsRef.Id = projectGuid; projectWindowsRef.Location = UPath.Combine(outputDirectory, (UFile)(name + ".Windows.csproj")); projectWindowsRef.Type = SiliconStudio.Assets.ProjectType.Library; sharedProfile.ProjectReferences.Add(projectWindowsRef); // Generate executable projects for each platform foreach (var platform in AssetRegistry.SupportedPlatforms) { var platformProfile = new PackageProfile(platform.Name) { Platform = platform.Type }; platformProfile.AssetFolders.Add(new AssetFolder("Assets/"+ platform.Name)); // Log progress var projectName = name + "." + platform.Type; // Create project reference var projectPlatformRef = new ProjectReference(); projectPlatformRef.Id = projectGuid; projectPlatformRef.Location = UPath.Combine(outputDirectory, (UFile)(projectName + ".csproj")); projectPlatformRef.Type = SiliconStudio.Assets.ProjectType.Executable; platformProfile.ProjectReferences.Add(projectPlatformRef); // Add build configuration per platform platform.Properties.CopyTo(platformProfile.Properties, true); package.Profiles.Add(platformProfile); } session.CurrentPackage = previousCurrent; result = session.Save(); if (result.HasErrors) { Console.WriteLine("Error saving package: {0}", result.ToText()); return; } }
public static void UpdatePackagePlatforms(TemplateGeneratorParameters parameters, ICollection <SelectedSolutionPlatform> platforms, DisplayOrientation orientation, Guid sharedProjectGuid, string name, Package package, bool forcePlatformRegeneration) { if (platforms == null) { throw new ArgumentNullException(nameof(platforms)); } var logger = parameters.Logger; // Setup the ProjectGameGuid to be accessible from exec (in order to be able to link to the game project. AddOption(parameters, "ProjectGameGuid", sharedProjectGuid); // Add projects var stepIndex = 0; var stepCount = platforms.Count + 1; var profilesToRemove = package.Profiles.Where(profile => platforms.All(platform => profile.Platform != PlatformType.Shared && platform.Platform.Type != profile.Platform)).ToList(); stepCount += profilesToRemove.Count; foreach (var platform in platforms) { stepIndex++; // Don't add a platform that is already in the package var platformProfile = package.Profiles.FirstOrDefault(profile => profile.Platform == platform.Platform.Type); if (platformProfile != null && !forcePlatformRegeneration) { continue; } var projectGuid = Guid.NewGuid(); if (platformProfile == null) { platformProfile = new PackageProfile(platform.Platform.Name) { Platform = platform.Platform.Type }; platformProfile.AssetFolders.Add(new AssetFolder("Assets/" + platform.Platform.Name)); } else { // We are going to regenerate this platform, so we are removing it before var previousExeProject = platformProfile.ProjectReferences.FirstOrDefault(project => project.Type == ProjectType.Executable); if (previousExeProject != null) { projectGuid = previousExeProject.Id; RemoveProject(previousExeProject, logger); platformProfile.ProjectReferences.Remove(previousExeProject); } } var templatePath = platform.Template?.TemplatePath ?? $"ProjectExecutable.{platform.Platform.Name}/ProjectExecutable.{platform.Platform.Name}.ttproj"; // Log progress var projectName = Utilities.BuildValidNamespaceName(name) + "." + platform.Platform.Name; Progress(logger, $"Generating {projectName}...", stepIndex - 1, stepCount); var graphicsPlatform = platform.Platform.Type.GetDefaultGraphicsPlatform(); var newExeProject = GenerateTemplate(parameters, platforms, package, templatePath, projectName, platform.Platform.Type, platformProfile.Name, graphicsPlatform, ProjectType.Executable, orientation, projectGuid); newExeProject.Type = ProjectType.Executable; platformProfile.ProjectReferences.Add(newExeProject); if (!package.Profiles.Contains(platformProfile)) { package.Profiles.Add(platformProfile); } package.IsDirty = true; } // Remove existing platform profiles foreach (var profileToRemove in profilesToRemove) { package.Profiles.Remove(profileToRemove); package.IsDirty = true; foreach (var projectReference in profileToRemove.ProjectReferences) { // Try to remove the directory Progress(logger, $"Deleting {projectReference.Location}...", stepIndex++, stepCount); RemoveProject(projectReference, logger); } // We are completely removing references from profile profileToRemove.ProjectReferences.Clear(); } }
private static void GenerateUnitTestProject(string outputDirectory, string templateFile, string name, string projectNamespace) { var projectTemplate = ProjectTemplate.Load(templateFile); // Force reference to Xenko.Assets (to have acess to SolutionPlatform) projectTemplate.Assemblies.Add(typeof(GraphicsProfile).Assembly.FullName); projectTemplate.Assemblies.Add(typeof(XenkoConfig).Assembly.FullName); var options = new Dictionary<string, object>(); // When generating over an existing set of files, retrieve the existing IDs // for better incrementality Guid projectGuid, assetId; GetExistingGuid(outputDirectory, name + ".Windows.csproj", out projectGuid); GetExistingAssetId(outputDirectory, name + ".xkpkg", out assetId); var session = new PackageSession(); var result = new LoggerResult(); var templateGeneratorParameters = new SessionTemplateGeneratorParameters(); templateGeneratorParameters.OutputDirectory = outputDirectory; templateGeneratorParameters.Session = session; templateGeneratorParameters.Name = name; templateGeneratorParameters.Logger = result; templateGeneratorParameters.Description = new TemplateDescription(); templateGeneratorParameters.Id = assetId; if (!PackageUnitTestGenerator.Default.PrepareForRun(templateGeneratorParameters).Result) { Console.WriteLine(@"Error generating package: PackageUnitTestGenerator.PrepareForRun returned false"); return; } if (!PackageUnitTestGenerator.Default.Run(templateGeneratorParameters)) { Console.WriteLine(@"Error generating package: PackageUnitTestGenerator.Run returned false"); return; } if (result.HasErrors) { Console.WriteLine($"Error generating package: {result.ToText()}"); return; } var package = session.LocalPackages.Single(); var previousCurrent = session.CurrentPackage; session.CurrentPackage = package; // Compute Xenko Sdk relative path // We are supposed to be in standard output binary folder, so Xenko root should be at ..\.. var xenkoPath = UPath.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), new UDirectory(@"..\..")); var xenkoRelativePath = new UDirectory(xenkoPath) .MakeRelative(outputDirectory) .ToString() .Replace('/', '\\'); xenkoRelativePath = xenkoRelativePath.TrimEnd('\\'); options["Namespace"] = projectNamespace ?? name; options["Package"] = package; options["Platforms"] = new List<SolutionPlatform>(AssetRegistry.SupportedPlatforms); options["XenkoSdkRelativeDir"] = xenkoRelativePath; // Generate project template result = projectTemplate.Generate(outputDirectory, name, projectGuid, options); if (result.HasErrors) { Console.WriteLine("Error generating solution: {0}", result.ToText()); return; } var sharedProfile = package.Profiles.FindSharedProfile(); // Setup the assets folder Directory.CreateDirectory(UPath.Combine(outputDirectory, (UDirectory)"Assets/Shared")); // Add Windows test as Shared library var projectWindowsRef = new ProjectReference { Id = projectGuid, Location = UPath.Combine(outputDirectory, (UFile)(name + ".Windows.csproj")), Type = SiliconStudio.Assets.ProjectType.Library }; sharedProfile.ProjectReferences.Add(projectWindowsRef); // Generate executable projects for each platform foreach (var platform in AssetRegistry.SupportedPlatforms) { var platformProfile = new PackageProfile(platform.Name) { Platform = platform.Type }; platformProfile.AssetFolders.Add(new AssetFolder("Assets/"+ platform.Name)); // Log progress var projectName = name + "." + platform.Type; // Create project reference var projectPlatformRef = new ProjectReference { Id = projectGuid, Location = UPath.Combine(outputDirectory, (UFile)(projectName + ".csproj")), Type = SiliconStudio.Assets.ProjectType.Executable }; platformProfile.ProjectReferences.Add(projectPlatformRef); // Add build configuration per platform platform.Properties.CopyTo(platformProfile.Properties, true); package.Profiles.Add(platformProfile); } session.CurrentPackage = previousCurrent; result = session.Save(); if (result.HasErrors) { Console.WriteLine("Error saving package: {0}", result.ToText()); return; } }
private static void GenerateUnitTestProject(string outputDirectory, string templateFile, string name) { var projectTemplate = ProjectTemplate.Load(templateFile); // Force reference to Paradox.Assets (to have acess to SolutionPlatform) projectTemplate.Assemblies.Add(typeof(GraphicsProfile).Assembly.FullName); projectTemplate.Assemblies.Add(typeof(ParadoxConfig).Assembly.FullName); var options = new Dictionary <string, object>(); var session = new PackageSession(); var result = new LoggerResult(); var templateGeneratorParameters = new TemplateGeneratorParameters(); templateGeneratorParameters.OutputDirectory = outputDirectory; templateGeneratorParameters.Session = session; templateGeneratorParameters.Name = name; templateGeneratorParameters.Logger = result; templateGeneratorParameters.Description = new TemplateDescription(); PackageUnitTestGenerator.Default.Generate(templateGeneratorParameters); if (result.HasErrors) { Console.WriteLine("Error generating package: {0}", result.ToText()); return; } var package = templateGeneratorParameters.Package; var previousCurrent = session.CurrentPackage; session.CurrentPackage = package; // Compute Paradox Sdk relative path // We are supposed to be in standard output binary folder, so Paradox root should be at ..\.. var paradoxPath = UDirectory.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), new UDirectory(@"..\..")); var paradoxRelativePath = new UDirectory(paradoxPath) .MakeRelative(outputDirectory) .ToString() .Replace('/', '\\'); paradoxRelativePath = paradoxRelativePath.TrimEnd('\\'); options["Namespace"] = name; options["Package"] = package; options["Platforms"] = new List <SolutionPlatform>(AssetRegistry.SupportedPlatforms); options["ParadoxSdkRelativeDir"] = paradoxRelativePath; // Generate project template var projectGuid = Guid.NewGuid(); result = projectTemplate.Generate(outputDirectory, name, projectGuid, options); if (result.HasErrors) { Console.WriteLine("Error generating solution: {0}", result.ToText()); return; } var sharedProfile = package.Profiles[PlatformType.Shared]; // Setup the assets folder Directory.CreateDirectory(UPath.Combine(outputDirectory, (UDirectory)"Assets/Shared")); // Add Windows test as Shared library var projectWindowsRef = new ProjectReference(); projectWindowsRef.Id = projectGuid; projectWindowsRef.Location = UPath.Combine(outputDirectory, (UFile)(name + ".Windows.csproj")); projectWindowsRef.Type = SiliconStudio.Assets.ProjectType.Library; sharedProfile.ProjectReferences.Add(projectWindowsRef); // Generate executable projects for each platform foreach (var platform in AssetRegistry.SupportedPlatforms) { var platformProfile = new PackageProfile(platform.Name) { Platform = platform.Type }; platformProfile.AssetFolders.Add(new AssetFolder("Assets/" + platform.Name)); // Log progress var projectName = name + "." + platform.Type; // Create project reference var projectPlatformRef = new ProjectReference(); projectPlatformRef.Id = projectGuid; projectPlatformRef.Location = UPath.Combine(outputDirectory, (UFile)(projectName + ".csproj")); projectPlatformRef.Type = SiliconStudio.Assets.ProjectType.Executable; platformProfile.ProjectReferences.Add(projectPlatformRef); // Add build configuration per platform platform.Properties.CopyTo(platformProfile.Properties, true); package.Profiles.Add(platformProfile); } session.CurrentPackage = previousCurrent; result = session.Save(); if (result.HasErrors) { Console.WriteLine("Error saving package: {0}", result.ToText()); return; } }
public static void Build(ILogger log, Package package, string outputDirectory = null) { if (package == null) { throw new ArgumentNullException(nameof(package)); } var meta = new ManifestMetadata(); PackageStore.ToNugetManifest(package.Meta, meta); // Sanity check: Xenko version should be same between NuGet package and Xenko package var nugetVersion = new PackageVersion(XenkoVersion.NuGetVersion).Version; var packageVersion = package.Meta.Version.Version; if (nugetVersion != packageVersion) { log.Error($"Package has mismatching version: NuGet package version is {nugetVersion} and Xenko Package version is {packageVersion}"); return; } if (nugetVersion.Revision <= 0) { // If 0, we have special cases with NuGet dropping it in install path, could be dangerous and lead to bugs if not properly tested. log.Error($"Package has revision {nugetVersion} but 4th digit needs to be at least 1."); return; } // Override version with NuGet version (4th number is different in Xenko package) meta.Version = XenkoVersion.NuGetVersion; var builder = new NugetPackageBuilder(); builder.Populate(meta); var currentAssemblyLocation = Assembly.GetExecutingAssembly().Location; var mainPlatformDirectory = Path.GetFileName(Path.GetDirectoryName(currentAssemblyLocation)); // TODO this is not working // We are excluding everything that is in a folder that starts with a dot (ie. .shadow, .vs) var files = new List <ManifestFile>() { NewFile(@"Bin\**\*.exe", "Bin", @"Bin\**\.*\**\*.exe;Bin\**\Tools\**.exe"), NewFile(@"Bin\**\*.so", "Bin", @"Bin\**\.*\**\*.so;Bin\Windows\lib\**\*.so"), NewFile(@"Bin\**\*.ssdeps", "Bin", @"Bin\**\.*\**\*.ssdeps"), NewFile(@"Bin\**\*.a", "Bin", @"Bin\**\.*\**\*.a"), NewFile(@"Bin\**\*.md", "Bin", @"Bin\**\.*\**\*.md"), NewFile(@"Bin\**\*.html", "Bin", @"Bin\**\.*\**\*.html"), NewFile(@"Bin\**\*.config", "Bin", @"Bin\**\.*\**\*.config"), NewFile(@"Bin\**\*.dll", "Bin", @"Bin\**\.*\**\*.dll;Bin\Windows\lib\**\*.dll"), NewFile(@"Bin\**\*.xml", "Bin", @"Bin\**\.*\**\*.xml"), NewFile(@"Bin\**\*.usrdoc", "Bin", @"Bin\**\.*\**\*.usrdoc"), NewFile(@"Bin\**\*.winmd", "Bin", @"Bin\**\.*\**\*.winmd"), NewFile(@"Bin\**\*.sh", "Bin", @"Bin\**\.*\**\*.sh"), NewFile(@"Bin\**\*.json", "Bin", @"Bin\**\.*\**\*.json"), NewFile(@"deps\AssemblyProcessor\*.exe", @"deps/AssemblyProcessor"), NewFile(@"deps\AssemblyProcessor\*.dll", @"deps/AssemblyProcessor"), NewFile(@"deps\CoreFX\**\*.*", @"deps\CoreFX"), NewFile($@"Bin\{mainPlatformDirectory}\ios-tcprelay\*.py", $@"Bin\{mainPlatformDirectory}\ios-tcprelay"), NewFile(@"Targets\*.targets", "Targets"), NewFile($@"Bin\{mainPlatformDirectory}\SiliconStudio.*.pdb", $@"Bin\{mainPlatformDirectory}", @"Bin\**\SiliconStudio.Xenko.Importer*.pdb;Bin\**\SiliconStudio.Xenko.Assimp.Translation.pdb"), }; // Handle Assets var rootDir = package.RootDirectory; var newPackage = new Package { Meta = package.Meta }; foreach (var profile in package.Profiles) { var target = "Assets/" + profile.Name; foreach (var assetFolder in profile.AssetFolders) { // TODO: handle exclude in asset folders //files.Add(NewFile(source, target, @"**\*.cs;**\*.hlsl;**\*.csproj;**\*.csproj.user;**\obj\**")); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xksl", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkfx", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkfnt", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xksheet", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkuilib", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xkgfxcomp", target)); files.Add(NewFile(assetFolder.Path.MakeRelative(rootDir) + "/**/*.xktex", target)); var resourceFolder = UPath.Combine(assetFolder.Path, new UDirectory("../../Resources")); if (Directory.Exists(resourceFolder.ToWindowsPath())) { files.Add(NewFile(resourceFolder.MakeRelative(rootDir) + "/**/*.*", "Resources")); } } var targetProfile = new PackageProfile(profile.Name); targetProfile.AssetFolders.Add(new AssetFolder(target)); newPackage.Profiles.Add(targetProfile); } //Handle RootAssets foreach (var rootAsset in package.RootAssets) { newPackage.RootAssets.Add(rootAsset); } // Handle templates var targetFolder = new TemplateFolder("Templates"); foreach (var templateFolder in package.TemplateFolders) { var source = templateFolder.Path.MakeRelative(rootDir) + "/**"; UDirectory target = targetFolder.Path; if (templateFolder.Group != null) { target = UPath.Combine(target, templateFolder.Group); } var excludeFiles = templateFolder.Exclude; files.Add(NewFile(source, target, excludeFiles)); // Add template files foreach (var templateFile in templateFolder.Files) { var newTemplateFile = templateFile.MakeRelative(templateFolder.Path); if (templateFolder.Group != null) { newTemplateFile = UPath.Combine(templateFolder.Group, newTemplateFile); } newTemplateFile = UPath.Combine(targetFolder.Path, newTemplateFile); targetFolder.Files.Add(newTemplateFile); } } // Add files builder.PopulateFiles(package.RootDirectory, files); files.Clear(); var dataFiles = builder.Files.ToList(); builder.ClearFiles(); // Create temp package for archive newPackage.TemplateFolders.Add(targetFolder); var newPackageFileName = "temp" + Guid.NewGuid() + ".xkpkg"; newPackage.FullPath = package.RootDirectory + "/" + newPackageFileName; var result = new LoggerResult(); newPackage.Save(result); if (result.HasErrors) { throw new InvalidOperationException(result.ToText()); // TODO throw error } // Add the package file files.Add(NewFile(newPackageFileName, package.Meta.Name + Package.PackageFileExtension)); // Add entry point to decompress LZMA files.Add(NewFile(@"tools\**\*.exe", "tools")); files.Add(NewFile(@"tools\**\*.dll", "tools")); // Add an empty .xz file so that it gets added to [Content_Types].xml // This file will be removed later files.Add(NewFile(@"tools\data_empty.xz", string.Empty)); // Repopulate with .xkpkg file builder.PopulateFiles(package.RootDirectory, files); outputDirectory = outputDirectory ?? Environment.CurrentDirectory; // Save the nupkg var outputPath = GetOutputPath(builder, outputDirectory); bool isExistingPackage = File.Exists(outputPath); if (isExistingPackage) { File.Delete(outputPath); } try { using (Stream stream = File.Create(outputPath)) { builder.Save(stream); stream.Position = 0; // Add LZMA file as update so that it is stored without compression using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, true)) { // Delete data_empty.xz var dataEntry = archive.GetEntry("data_empty.xz"); dataEntry.Delete(); // Create data.xz (no compression since .xz is already compressed) dataEntry = archive.CreateEntry("data.xz", CompressionLevel.NoCompression); using (var dataStream = dataEntry.Open()) { // Generate LZMA using (var indexedArchive = new IndexedArchive()) { foreach (var file in dataFiles) { indexedArchive.AddFile(Path.Combine(package.RootDirectory, file.SourcePath), file.Path); } indexedArchive.Save(dataStream, new ConsoleProgressReport()); } } } } } catch { if (!isExistingPackage && File.Exists(outputPath)) { File.Delete(outputPath); } throw; } File.Delete(newPackage.FullPath); }