private async Task UpgradeProject(MSBuildWorkspace workspace, UFile projectPath) { // Upgrade .csproj file // TODO: Use parsed file? var fileContents = File.ReadAllText(projectPath); // Rename referenced to the package, shaders and effects var newFileContents = fileContents.Replace(".pdx", ".xk"); // Rename variables newFileContents = newFileContents.Replace("Paradox", "Xenko"); // Save file if there were any changes if (newFileContents != fileContents) { File.WriteAllText(projectPath, newFileContents); } // Upgrade source code var project = await workspace.OpenProjectAsync(projectPath.ToWindowsPath()); var compilation = await project.GetCompilationAsync(); var tasks = compilation.SyntaxTrees.Select(syntaxTree => Task.Run(() => UpgradeSourceFile(syntaxTree))).ToList(); await Task.WhenAll(tasks); }
/// <summary> /// Saves this package and all dirty assets. See remarks. /// </summary> /// <param name="log">The log.</param> /// <exception cref="System.ArgumentNullException">log</exception> /// <remarks>When calling this method directly, it does not handle moving assets between packages. /// Call <see cref="PackageSession.Save" /> instead.</remarks> public void Save(ILogger log) { if (log == null) throw new ArgumentNullException(nameof(log)); if (FullPath == null) { log.Error(this, null, AssetMessageCode.PackageCannotSave, "null"); return; } // Use relative paths when saving var analysis = new PackageAnalysis(this, new PackageAnalysisParameters() { SetDirtyFlagOnAssetWhenFixingUFile = false, ConvertUPathTo = UPathType.Relative, IsProcessingUPaths = true }); analysis.Run(log); try { // Update source folders UpdateSourceFolders(); if (IsDirty) { try { // Notifies the dependency manager that a package with the specified path is being saved if (session != null && session.HasDependencyManager) { session.DependencyManager.AddFileBeingSaveDuringSessionSave(FullPath); } AssetSerializer.Save(FullPath, this); // Move the package if the path has changed if (previousPackagePath != null && previousPackagePath != packagePath) { filesToDelete.Add(previousPackagePath); } previousPackagePath = packagePath; IsDirty = false; } catch (Exception ex) { log.Error(this, null, AssetMessageCode.PackageCannotSave, ex, FullPath); return; } // Delete obsolete files foreach (var file in filesToDelete) { if (File.Exists(file.FullPath)) { try { File.Delete(file.FullPath); } catch (Exception ex) { log.Error(this, null, AssetMessageCode.AssetCannotDelete, ex, file.FullPath); } } } filesToDelete.Clear(); } //batch projects var vsProjs = new Dictionary<string, Project>(); foreach (var asset in Assets) { if (asset.IsDirty) { var assetPath = asset.FullPath; try { //Handle the ProjectSourceCodeAsset differently then regular assets in regards of Path var sourceCodeAsset = asset.Asset as ProjectSourceCodeAsset; if (sourceCodeAsset != null) { var profile = Profiles.FindSharedProfile(); var lib = profile?.ProjectReferences.FirstOrDefault(x => x.Type == ProjectType.Library && asset.Location.FullPath.StartsWith(x.Location.GetFileName())); if (lib == null) continue; var projectFullPath = UPath.Combine(RootDirectory, lib.Location); var fileFullPath = UPath.Combine(RootDirectory, asset.Location); var filePath = fileFullPath.MakeRelative(projectFullPath.GetFullDirectory()); var codeFile = new UFile(filePath + AssetRegistry.GetDefaultExtension(sourceCodeAsset.GetType())); Project project; if (!vsProjs.TryGetValue(projectFullPath, out project)) { project = VSProjectHelper.LoadProject(projectFullPath); vsProjs.Add(projectFullPath, project); } //check if the item is already there, this is possible when saving the first time when creating from a template if (project.Items.All(x => x.EvaluatedInclude != codeFile.ToWindowsPath())) { project.AddItem(AssetRegistry.GetDefaultExtension(sourceCodeAsset.GetType()) == ".cs" ? "Compile" : "None", codeFile.ToWindowsPath()); //todo None case needs Generator and LastGenOutput properties support! (eg xksl) } asset.SourceProject = projectFullPath; asset.SourceFolder = RootDirectory.GetFullDirectory(); sourceCodeAsset.ProjectInclude = codeFile; sourceCodeAsset.ProjectName = Path.GetFileNameWithoutExtension(projectFullPath.ToWindowsPath()); sourceCodeAsset.AbsoluteSourceLocation = UPath.Combine(projectFullPath.GetFullDirectory(), codeFile); sourceCodeAsset.AbsoluteProjectLocation = projectFullPath; assetPath = sourceCodeAsset.AbsoluteSourceLocation; } // Notifies the dependency manager that an asset with the specified path is being saved if (session != null && session.HasDependencyManager) { session.DependencyManager.AddFileBeingSaveDuringSessionSave(assetPath); } // Incject a copy of the base into the current asset when saving var assetBase = asset.Asset.Base; if (assetBase != null && !assetBase.IsRootImport) { var assetBaseItem = session != null ? session.FindAsset(assetBase.Id) : Assets.Find(assetBase.Id); if (assetBaseItem != null) { var newBase = (Asset)AssetCloner.Clone(assetBaseItem.Asset); newBase.Base = null; asset.Asset.Base = new AssetBase(asset.Asset.Base.Location, newBase); } } AssetSerializer.Save(assetPath, asset.Asset); asset.IsDirty = false; } catch (Exception ex) { log.Error(this, asset.ToReference(), AssetMessageCode.AssetCannotSave, ex, assetPath); } } } foreach (var project in vsProjs.Values) { project.Save(); project.ProjectCollection.UnloadAllProjects(); project.ProjectCollection.Dispose(); } Assets.IsDirty = false; // Save properties like the Xenko version used PackageSessionHelper.SaveProperties(this); } finally { // Rollback all relative UFile to absolute paths analysis.Parameters.ConvertUPathTo = UPathType.Absolute; analysis.Run(); } }
/// <summary> /// Saves this package and all dirty assets. See remarks. /// </summary> /// <param name="log">The log.</param> /// <exception cref="System.ArgumentNullException">log</exception> /// <remarks>When calling this method directly, it does not handle moving assets between packages. /// Call <see cref="PackageSession.Save" /> instead.</remarks> public void Save(ILogger log) { if (log == null) throw new ArgumentNullException(nameof(log)); if (FullPath == null) { log.Error(this, null, AssetMessageCode.PackageCannotSave, "null"); return; } // Use relative paths when saving var analysis = new PackageAnalysis(this, new PackageAnalysisParameters() { SetDirtyFlagOnAssetWhenFixingUFile = false, ConvertUPathTo = UPathType.Relative, IsProcessingUPaths = true, AssetTemplatingRemoveUnusedBaseParts = true, }); analysis.Run(log); try { // Update source folders UpdateSourceFolders(); if (IsDirty) { List<UFile> filesToDeleteLocal; lock (filesToDelete) { filesToDeleteLocal = filesToDelete.ToList(); filesToDelete.Clear(); } try { AssetSerializer.Save(FullPath, this); // Move the package if the path has changed if (previousPackagePath != null && previousPackagePath != packagePath) { filesToDeleteLocal.Add(previousPackagePath); } previousPackagePath = packagePath; IsDirty = false; } catch (Exception ex) { log.Error(this, null, AssetMessageCode.PackageCannotSave, ex, FullPath); return; } // Delete obsolete files foreach (var file in filesToDeleteLocal) { if (File.Exists(file.FullPath)) { try { File.Delete(file.FullPath); } catch (Exception ex) { log.Error(this, null, AssetMessageCode.AssetCannotDelete, ex, file.FullPath); } } } } //batch projects var vsProjs = new Dictionary<string, Project>(); foreach (var asset in Assets) { if (asset.IsDirty) { var assetPath = asset.FullPath; try { //Handle the ProjectSourceCodeAsset differently then regular assets in regards of Path var sourceCodeAsset = asset.Asset as ProjectSourceCodeAsset; if (sourceCodeAsset != null) { var profile = Profiles.FindSharedProfile(); var lib = profile?.ProjectReferences.FirstOrDefault(x => x.Type == ProjectType.Library && asset.Location.FullPath.StartsWith(x.Location.GetFileName())); if (lib == null) continue; var projectFullPath = UPath.Combine(RootDirectory, lib.Location); var fileFullPath = UPath.Combine(RootDirectory, asset.Location); var filePath = fileFullPath.MakeRelative(projectFullPath.GetFullDirectory()); var codeFile = new UFile(filePath + AssetRegistry.GetDefaultExtension(sourceCodeAsset.GetType())); Project project; if (!vsProjs.TryGetValue(projectFullPath, out project)) { project = VSProjectHelper.LoadProject(projectFullPath); vsProjs.Add(projectFullPath, project); } asset.SourceProject = projectFullPath; asset.SourceFolder = RootDirectory.GetFullDirectory(); sourceCodeAsset.ProjectInclude = codeFile; sourceCodeAsset.ProjectName = Path.GetFileNameWithoutExtension(projectFullPath.ToWindowsPath()); sourceCodeAsset.AbsoluteSourceLocation = UPath.Combine(projectFullPath.GetFullDirectory(), codeFile); sourceCodeAsset.AbsoluteProjectLocation = projectFullPath; assetPath = sourceCodeAsset.AbsoluteSourceLocation; //check if the item is already there, this is possible when saving the first time when creating from a template if (project.Items.All(x => x.EvaluatedInclude != codeFile.ToWindowsPath())) { var generatorAsset = sourceCodeAsset as ProjectCodeGeneratorAsset; if (generatorAsset != null) { generatorAsset.GeneratedAbsolutePath = new UFile(generatorAsset.AbsoluteSourceLocation).GetFullPathWithoutExtension() + ".cs"; generatorAsset.GeneratedInclude = new UFile(generatorAsset.ProjectInclude).GetFullPathWithoutExtension() + ".cs"; project.AddItem("None", codeFile.ToWindowsPath(), new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("Generator", generatorAsset.Generator), new KeyValuePair<string, string>("LastGenOutput", new UFile(generatorAsset.GeneratedInclude).GetFileNameWithExtension()) }); project.AddItem("Compile", new UFile(generatorAsset.GeneratedInclude).ToWindowsPath(), new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("AutoGen", "True"), new KeyValuePair<string, string>("DesignTime", "True"), new KeyValuePair<string, string>("DesignTimeSharedInput", "True"), new KeyValuePair<string, string>("DependentUpon", new UFile(generatorAsset.ProjectInclude).GetFileNameWithExtension()) }); } else { project.AddItem("Compile", codeFile.ToWindowsPath()); } } } // Inject a copy of the base into the current asset when saving var assetBase = asset.Asset.Base; if (assetBase != null && !assetBase.IsRootImport) { asset.Asset.Base = UpdateAssetBase(assetBase); } // Update base for BaseParts if (asset.Asset.BaseParts != null) { var baseParts = asset.Asset.BaseParts; for (int i = 0; i < baseParts.Count; i++) { var basePart = baseParts[i]; baseParts[i] = UpdateAssetBase(basePart); } } AssetSerializer.Save(assetPath, asset.Asset); asset.IsDirty = false; } catch (Exception ex) { log.Error(this, asset.ToReference(), AssetMessageCode.AssetCannotSave, ex, assetPath); } } } foreach (var project in vsProjs.Values) { project.Save(); project.ProjectCollection.UnloadAllProjects(); project.ProjectCollection.Dispose(); } Assets.IsDirty = false; // Save properties like the Xenko version used PackageSessionHelper.SaveProperties(this); } finally { // Rollback all relative UFile to absolute paths analysis.Parameters.ConvertUPathTo = UPathType.Absolute; analysis.Run(); } }
private async Task UpgradeProject(MSBuildWorkspace workspace, UFile projectPath) { // Upgrade .csproj file // TODO: Use parsed file? var fileContents = File.ReadAllText(projectPath); // Rename referenced to the package, shaders and effects var newFileContents = fileContents.Replace(".pdx", ".xk"); // Rename variables newFileContents = newFileContents.Replace("Paradox", "Xenko"); // Create fallback for old environment variable var index = newFileContents.IndexOf("<SiliconStudioCurrentPackagePath>", StringComparison.InvariantCulture); if (index >= 0) { newFileContents = newFileContents.Insert(index, "<SiliconStudioXenkoDir Condition=\"'$(SiliconStudioXenkoDir)' == ''\">$(SiliconStudioParadoxDir)</SiliconStudioXenkoDir>\n "); } // Save file if there were any changes if (newFileContents != fileContents) { File.WriteAllText(projectPath, newFileContents); } // Upgrade source code var project = await workspace.OpenProjectAsync(projectPath.ToWindowsPath()); var compilation = await project.GetCompilationAsync(); var tasks = compilation.SyntaxTrees.Select(syntaxTree => Task.Run(() => UpgradeSourceFile(syntaxTree))).ToList(); await Task.WhenAll(tasks); }