/// <summary> /// Performs first part of the loading sequence, by deserializing the package but without processing anything yet. /// </summary> /// <param name="log">The log.</param> /// <param name="filePath">The file path.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException"> /// log /// or /// filePath /// </exception> internal static Package LoadRaw(ILogger log, string filePath) { if (log == null) { throw new ArgumentNullException("log"); } if (filePath == null) { throw new ArgumentNullException("filePath"); } filePath = FileUtility.GetAbsolutePath(filePath); if (!File.Exists(filePath)) { log.Error("Package file [{0}] was not found", filePath); return(null); } try { var package = AssetSerializer.Load <Package>(filePath, log); package.FullPath = filePath; package.IsDirty = false; return(package); } catch (Exception ex) { log.Error("Error while pre-loading package [{0}]", ex, filePath); } return(null); }
/// <summary> /// Loads the templates. /// </summary> /// <param name="log">The log result.</param> private void LoadTemplates(ILogger log) { foreach (var templateDir in TemplateFolders) { foreach (var filePath in templateDir.Files) { try { var file = new FileInfo(filePath); if (!file.Exists) { log.Warning("Template [{0}] does not exist ", file); continue; } var templateDescription = AssetSerializer.Load <TemplateDescription>(file.FullName); templateDescription.FullPath = file.FullName; Templates.Add(templateDescription); } catch (Exception ex) { log.Error("Error while loading template from [{0}]", ex, filePath); } } } }
/// <summary> /// Gets the package identifier from file. /// </summary> /// <param name="filePath">The file path.</param> /// <returns>Guid.</returns> /// <exception cref="System.ArgumentNullException"> /// log /// or /// filePath /// </exception> public static Guid GetPackageIdFromFile(string filePath) { if (filePath == null) { throw new ArgumentNullException("filePath"); } return(AssetSerializer.Load <Package>(filePath).Id); }
private static Asset LoadAsset(ILogger log, string assetFullPath, string assetPath, UFile fileUPath) { AssetMigration.MigrateAssetIfNeeded(log, assetFullPath); var asset = AssetSerializer.Load <Asset>(assetFullPath); // Set location on source code asset var sourceCodeAsset = asset as SourceCodeAsset; if (sourceCodeAsset != null) { // Use an id generated from the location instead of the default id sourceCodeAsset.Id = SourceCodeAsset.GenerateGuidFromLocation(assetPath); sourceCodeAsset.AbsoluteSourceLocation = fileUPath; } return(asset); }
private static Asset LoadAsset(ILogger log, string assetFullPath, string assetPath, UFile fileUPath, byte[] assetContent) { var asset = assetContent != null ? (Asset)AssetSerializer.Load(new MemoryStream(assetContent), Path.GetExtension(assetFullPath), log) : AssetSerializer.Load <Asset>(assetFullPath, log); // Set location on source code asset var sourceCodeAsset = asset as SourceCodeAsset; if (sourceCodeAsset != null) { // Use an id generated from the location instead of the default id sourceCodeAsset.Id = SourceCodeAsset.GenerateGuidFromLocation(assetPath); sourceCodeAsset.AbsoluteSourceLocation = fileUPath; } return(asset); }
/// <summary> /// Performs first part of the loading sequence, by deserializing the package but without processing anything yet. /// </summary> /// <param name="log">The log.</param> /// <param name="filePath">The file path.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException"> /// log /// or /// filePath /// </exception> internal static Package LoadRaw(ILogger log, string filePath) { if (log == null) { throw new ArgumentNullException("log"); } if (filePath == null) { throw new ArgumentNullException("filePath"); } filePath = FileUtility.GetAbsolutePath(filePath); if (!File.Exists(filePath)) { log.Error("Package file [{0}] was not found", filePath); return(null); } try { bool aliasOccurred; var packageFile = new PackageLoadingAssetFile(filePath, Path.GetDirectoryName(filePath)); AssetMigration.MigrateAssetIfNeeded(log, packageFile); var package = packageFile.AssetContent != null ? (Package)AssetSerializer.Load(new MemoryStream(packageFile.AssetContent), Path.GetExtension(filePath), log, out aliasOccurred) : AssetSerializer.Load <Package>(filePath, log, out aliasOccurred); package.FullPath = filePath; package.IsDirty = packageFile.AssetContent != null || aliasOccurred; return(package); } catch (Exception ex) { log.Error("Error while pre-loading package [{0}]", ex, filePath); } return(null); }
/// <summary> /// Loads only the package description but not assets or plugins. /// </summary> /// <param name="log">The log to receive error messages.</param> /// <param name="filePath">The file path.</param> /// <param name="loadParametersArg">The load parameters argument.</param> /// <returns>A package.</returns> /// <exception cref="System.ArgumentNullException">log /// or /// filePath</exception> public static Package Load(ILogger log, string filePath, PackageLoadParameters loadParametersArg = null) { if (log == null) { throw new ArgumentNullException("log"); } if (filePath == null) { throw new ArgumentNullException("filePath"); } filePath = FileUtility.GetAbsolutePath(filePath); if (!File.Exists(filePath)) { log.Error("Package file [{0}] was not found", filePath); return(null); } var loadParameters = loadParametersArg ?? PackageLoadParameters.Default(); try { var package = AssetSerializer.Load <Package>(filePath); package.FullPath = filePath; package.IsDirty = false; // Load assembly references if (loadParameters.LoadAssemblyReferences) { package.LoadAssemblyReferencesForPackage(log, loadParameters); } // Load assets if (loadParameters.AutoLoadTemporaryAssets) { package.LoadTemporaryAssets(log, loadParameters.CancelToken); } // Convert UPath to absolute if (loadParameters.ConvertUPathToAbsolute) { var analysis = new PackageAnalysis(package, new PackageAnalysisParameters() { ConvertUPathTo = UPathType.Absolute, IsProcessingUPaths = true, // This is done already by Package.Load SetDirtyFlagOnAssetWhenFixingAbsoluteUFile = true // When loading tag attributes that have an absolute file }); analysis.Run(log); } // Load templates package.LoadTemplates(log); return(package); } catch (Exception ex) { log.Error("Error while pre-loading package [{0}]", ex, filePath); } return(null); }
/// <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("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); IsDirty = false; } catch (Exception ex) { log.Error(this, null, AssetMessageCode.PackageCannotSave, ex, FullPath); return; } } foreach (var asset in Assets) { if (asset.IsDirty) { var assetPath = asset.FullPath; try { // 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); } } } Assets.IsDirty = false; // Save properties like the Paradox version used PackageSessionHelper.SaveProperties(this); } finally { // Rollback all relative UFile to absolute paths analysis.Parameters.ConvertUPathTo = UPathType.Absolute; analysis.Run(); } }
public static bool MigrateAssetIfNeeded(AssetMigrationContext context, PackageLoadingAssetFile loadAsset, string dependencyName, PackageVersion untilVersion = null) { var assetFullPath = loadAsset.FilePath.FullPath; // Determine if asset was Yaml or not var assetFileExtension = Path.GetExtension(assetFullPath); if (assetFileExtension == null) { return(false); } assetFileExtension = assetFileExtension.ToLowerInvariant(); var serializer = AssetSerializer.FindSerializer(assetFileExtension); if (!(serializer is AssetYamlSerializer)) { return(false); } // We've got a Yaml asset, let's get expected and serialized versions var serializedVersion = PackageVersion.Zero; PackageVersion expectedVersion; Type assetType; // Read from Yaml file the asset version and its type (to get expected version) // Note: It tries to read as few as possible (SerializedVersion is expected to be right after Id, so it shouldn't try to read further than that) using (var assetStream = loadAsset.OpenStream()) using (var streamReader = new StreamReader(assetStream)) { var yamlEventReader = new EventReader(new Parser(streamReader)); // Skip header yamlEventReader.Expect <StreamStart>(); yamlEventReader.Expect <DocumentStart>(); var mappingStart = yamlEventReader.Expect <MappingStart>(); var yamlSerializerSettings = YamlSerializer.GetSerializerSettings(); var tagTypeRegistry = yamlSerializerSettings.TagTypeRegistry; bool typeAliased; assetType = tagTypeRegistry.TypeFromTag(mappingStart.Tag, out typeAliased); var expectedVersions = AssetRegistry.GetCurrentFormatVersions(assetType); expectedVersion = expectedVersions?.FirstOrDefault(x => x.Key == dependencyName).Value ?? PackageVersion.Zero; Scalar assetKey; while ((assetKey = yamlEventReader.Allow <Scalar>()) != null) { // Only allow Id before SerializedVersion if (assetKey.Value == nameof(Asset.Id)) { yamlEventReader.Skip(); } else if (assetKey.Value == nameof(Asset.SerializedVersion)) { // Check for old format: only a scalar var scalarVersion = yamlEventReader.Allow <Scalar>(); if (scalarVersion != null) { serializedVersion = PackageVersion.Parse("0.0." + Convert.ToInt32(scalarVersion.Value, CultureInfo.InvariantCulture)); // Let's update to new format using (var yamlAsset = loadAsset.AsYamlAsset()) { yamlAsset.DynamicRootNode.RemoveChild(nameof(Asset.SerializedVersion)); AssetUpgraderBase.SetSerializableVersion(yamlAsset.DynamicRootNode, dependencyName, serializedVersion); var baseBranch = yamlAsset.DynamicRootNode[Asset.BaseProperty]; if (baseBranch != null) { var baseAsset = baseBranch["Asset"]; if (baseAsset != null) { baseAsset.RemoveChild(nameof(Asset.SerializedVersion)); AssetUpgraderBase.SetSerializableVersion(baseAsset, dependencyName, serializedVersion); } } } } else { // New format: package => version mapping yamlEventReader.Expect <MappingStart>(); while (!yamlEventReader.Accept <MappingEnd>()) { var packageName = yamlEventReader.Expect <Scalar>().Value; var packageVersion = PackageVersion.Parse(yamlEventReader.Expect <Scalar>().Value); // For now, we handle only one dependency at a time if (packageName == dependencyName) { serializedVersion = packageVersion; } } yamlEventReader.Expect <MappingEnd>(); } break; } else { // If anything else than Id or SerializedVersion, let's stop break; } } } if (serializedVersion > expectedVersion) { // Try to open an asset newer than what we support (probably generated by a newer Xenko) throw new InvalidOperationException($"Asset of type {assetType} has been serialized with newer version {serializedVersion}, but only version {expectedVersion} is supported. Was this asset created with a newer version of Xenko?"); } if (serializedVersion < expectedVersion) { // Perform asset upgrade context.Log.Verbose("{0} needs update, from version {1} to version {2}", Path.GetFullPath(assetFullPath), serializedVersion, expectedVersion); using (var yamlAsset = loadAsset.AsYamlAsset()) { var yamlRootNode = yamlAsset.RootNode; // Check if there is any asset updater var assetUpgraders = AssetRegistry.GetAssetUpgraders(assetType, dependencyName); if (assetUpgraders == null) { throw new InvalidOperationException($"Asset of type {assetType} should be updated from version {serializedVersion} to {expectedVersion}, but no asset migration path was found"); } // Instantiate asset updaters var currentVersion = serializedVersion; while (currentVersion != expectedVersion) { PackageVersion targetVersion; // This will throw an exception if no upgrader is available for the given version, exiting the loop in case of error. var upgrader = assetUpgraders.GetUpgrader(currentVersion, out targetVersion); // Stop if the next version would be higher than what is expected if (untilVersion != null && targetVersion > untilVersion) { break; } upgrader.Upgrade(context, dependencyName, currentVersion, targetVersion, yamlRootNode, loadAsset); currentVersion = targetVersion; } // Make sure asset is updated to latest version YamlNode serializedVersionNode; PackageVersion newSerializedVersion = null; if (yamlRootNode.Children.TryGetValue(new YamlScalarNode(nameof(Asset.SerializedVersion)), out serializedVersionNode)) { var newSerializedVersionForDefaultPackage = ((YamlMappingNode)serializedVersionNode).Children[new YamlScalarNode(dependencyName)]; newSerializedVersion = PackageVersion.Parse(((YamlScalarNode)newSerializedVersionForDefaultPackage).Value); } if (untilVersion == null && newSerializedVersion != expectedVersion) { throw new InvalidOperationException($"Asset of type {assetType} was migrated, but still its new version {newSerializedVersion} doesn't match expected version {expectedVersion}."); } context.Log.Info("{0} updated from version {1} to version {2}", Path.GetFullPath(assetFullPath), serializedVersion, expectedVersion); } return(true); } return(false); }
public static bool MigrateAssetIfNeeded(AssetMigrationContext context, PackageLoadingAssetFile loadAsset) { var assetFullPath = loadAsset.FilePath.FullPath; // Determine if asset was Yaml or not var assetFileExtension = Path.GetExtension(assetFullPath); if (assetFileExtension == null) { return(false); } assetFileExtension = assetFileExtension.ToLowerInvariant(); var serializer = AssetSerializer.FindSerializer(assetFileExtension); if (!(serializer is AssetYamlSerializer)) { return(false); } // We've got a Yaml asset, let's get expected and serialized versions var serializedVersion = 0; int expectedVersion; Type assetType; // Read from Yaml file the asset version and its type (to get expected version) // Note: It tries to read as few as possible (SerializedVersion is expected to be right after Id, so it shouldn't try to read further than that) using (var assetStream = loadAsset.OpenStream()) using (var streamReader = new StreamReader(assetStream)) { var yamlEventReader = new EventReader(new Parser(streamReader)); // Skip header yamlEventReader.Expect <StreamStart>(); yamlEventReader.Expect <DocumentStart>(); var mappingStart = yamlEventReader.Expect <MappingStart>(); var yamlSerializerSettings = YamlSerializer.GetSerializerSettings(); var tagTypeRegistry = yamlSerializerSettings.TagTypeRegistry; bool typeAliased; assetType = tagTypeRegistry.TypeFromTag(mappingStart.Tag, out typeAliased); expectedVersion = AssetRegistry.GetCurrentFormatVersion(assetType); Scalar assetKey; while ((assetKey = yamlEventReader.Allow <Scalar>()) != null) { // Only allow Id before SerializedVersion if (assetKey.Value == "Id") { yamlEventReader.Skip(); continue; } if (assetKey.Value == "SerializedVersion") { serializedVersion = Convert.ToInt32(yamlEventReader.Expect <Scalar>().Value, CultureInfo.InvariantCulture); break; } } } if (serializedVersion > expectedVersion) { // Try to open an asset newer than what we support (probably generated by a newer Paradox) throw new InvalidOperationException(string.Format("Asset of type {0} has been serialized with newer version {1}, but only version {2} is supported. Was this asset created with a newer version of Paradox?", assetType, serializedVersion, expectedVersion)); } if (serializedVersion < expectedVersion) { // Perform asset upgrade context.Log.Verbose("{0} needs update, from version {1} to version {2}", Path.GetFullPath(assetFullPath), serializedVersion, expectedVersion); // transform the stream into string. string assetAsString; using (var assetStream = loadAsset.OpenStream()) using (var assetStreamReader = new StreamReader(assetStream, Encoding.UTF8)) { assetAsString = assetStreamReader.ReadToEnd(); } // Load the asset as a YamlNode object var input = new StringReader(assetAsString); var yamlStream = new YamlStream(); yamlStream.Load(input); var yamlRootNode = (YamlMappingNode)yamlStream.Documents[0].RootNode; // Check if there is any asset updater var assetUpgraders = AssetRegistry.GetAssetUpgraders(assetType); if (assetUpgraders == null) { throw new InvalidOperationException(string.Format("Asset of type {0} should be updated from version {1} to {2}, but no asset migration path was found", assetType, serializedVersion, expectedVersion)); } // Instantiate asset updaters var currentVersion = serializedVersion; while (currentVersion != expectedVersion) { int targetVersion; // This will throw an exception if no upgrader is available for the given version, exiting the loop in case of error. var upgrader = assetUpgraders.GetUpgrader(currentVersion, out targetVersion); upgrader.Upgrade(context, currentVersion, targetVersion, yamlRootNode, loadAsset); currentVersion = targetVersion; } // Make sure asset is updated to latest version YamlNode serializedVersionNode; var newSerializedVersion = 0; if (yamlRootNode.Children.TryGetValue(new YamlScalarNode("SerializedVersion"), out serializedVersionNode)) { newSerializedVersion = Convert.ToInt32(((YamlScalarNode)serializedVersionNode).Value); } if (newSerializedVersion != expectedVersion) { throw new InvalidOperationException(string.Format("Asset of type {0} was migrated, but still its new version {1} doesn't match expected version {2}.", assetType, newSerializedVersion, expectedVersion)); } context.Log.Info("{0} updated from version {1} to version {2}", Path.GetFullPath(assetFullPath), serializedVersion, expectedVersion); var preferredIndent = YamlSerializer.GetSerializerSettings().PreferredIndent; // Save asset back to disk using (var memoryStream = new MemoryStream()) { using (var streamWriter = new StreamWriter(memoryStream)) { yamlStream.Save(streamWriter, true, preferredIndent); } loadAsset.AssetContent = memoryStream.ToArray(); } return(true); } return(false); }
public static bool MigrateAssetIfNeeded(ILogger log, string assetFullPath) { // Determine if asset was Yaml or not var assetFileExtension = Path.GetExtension(assetFullPath); if (assetFileExtension == null) { return(false); } assetFileExtension = assetFileExtension.ToLowerInvariant(); var serializer = AssetSerializer.FindSerializer(assetFileExtension); if (!(serializer is AssetYamlSerializer)) { return(false); } // We've got a Yaml asset, let's get expected and serialized versions var serializedVersion = 0; var expectedVersion = 0; Type assetType; // Read from Yaml file the asset version and its type (to get expected version) // Note: It tries to read as few as possible (SerializedVersion is expected to be right after Id, so it shouldn't try to read further than that) using (var streamReader = new StreamReader(assetFullPath)) { var yamlEventReader = new EventReader(new Parser(streamReader)); // Skip header yamlEventReader.Expect <StreamStart>(); yamlEventReader.Expect <DocumentStart>(); var mappingStart = yamlEventReader.Expect <MappingStart>(); var yamlSerializerSettings = YamlSerializer.GetSerializerSettings(); var tagTypeRegistry = yamlSerializerSettings.TagTypeRegistry; assetType = tagTypeRegistry.TypeFromTag(mappingStart.Tag); expectedVersion = AssetRegistry.GetFormatVersion(assetType); Scalar assetKey; while ((assetKey = yamlEventReader.Allow <Scalar>()) != null) { // Only allow Id before SerializedVersion if (assetKey.Value == "Id") { yamlEventReader.Skip(); continue; } if (assetKey.Value == "SerializedVersion") { serializedVersion = Convert.ToInt32(yamlEventReader.Expect <Scalar>().Value, CultureInfo.InvariantCulture); break; } } } if (serializedVersion > expectedVersion) { // Try to open an asset newer than what we support (probably generated by a newer Paradox) throw new InvalidOperationException(string.Format("Asset of type {0} has been serialized with newer version {1}, but only version {2} is supported. Was this asset created with a newer version of Paradox?", assetType, serializedVersion, expectedVersion)); } if (serializedVersion < expectedVersion) { // Perform asset upgrade log.Info("{0} needs update, from version {0} to version {1}", Path.GetFullPath(assetFullPath), serializedVersion, expectedVersion); // Load the asset as a YamlNode object var input = new StringReader(File.ReadAllText(assetFullPath)); var yamlStream = new YamlStream(); yamlStream.Load(input); var yamlRootNode = (YamlMappingNode)yamlStream.Documents[0].RootNode; // Check if there is any asset updater var assetUpdaterTypes = AssetRegistry.GetFormatVersionUpdaterTypes(assetType); if (assetUpdaterTypes == null) { throw new InvalidOperationException(string.Format("Asset of type {0} should be updated from version {1} to {2}, but no asset migration path was found", assetType, serializedVersion, expectedVersion)); } // Instantiate asset updaters var assetUpgraders = assetUpdaterTypes.Select(x => (IAssetUpgrader)Activator.CreateInstance(x)).ToArray(); // TODO: Select best asset updater if more than one (need to check from what to what version they update, score, if multiple need to be chained, etc...) // I think it's better to wait for some actual scenarios to implement this right the first time if (assetUpgraders.Length != 1) { throw new InvalidOperationException(string.Format("Asset of type {0} has multiple migration paths, but selecting the right one is not implemented yet.", assetType)); } // Perform upgrade assetUpgraders[0].Upgrade(log, yamlRootNode); // Make sure asset is updated to latest version YamlNode serializedVersionNode; serializedVersion = 0; if (yamlRootNode.Children.TryGetValue(new YamlScalarNode("SerializedVersion"), out serializedVersionNode)) { serializedVersion = Convert.ToInt32(((YamlScalarNode)serializedVersionNode).Value); } if (serializedVersion != expectedVersion) { throw new InvalidOperationException(string.Format("Asset of type {0} was migrated, but still its new version {1} doesn't match expected version {2}.", assetType, serializedVersion, expectedVersion)); } var preferredIndent = YamlSerializer.GetSerializerSettings().PreferredIndent; // Save asset back to disk using (var streamWriter = new StreamWriter(assetFullPath)) yamlStream.Save(streamWriter, true, preferredIndent); return(true); } return(false); }