Пример #1
0
        private static void PreLoadPackageDependencies(PackageSession session, ILogger log, Package package, PackageCollection loadedPackages, PackageLoadParameters loadParameters)
        {
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }
            if (log == null)
            {
                throw new ArgumentNullException("log");
            }
            if (package == null)
            {
                throw new ArgumentNullException("package");
            }
            if (loadParameters == null)
            {
                throw new ArgumentNullException("loadParameters");
            }

            // 1. Load store package
            foreach (var packageDependency in package.Meta.Dependencies)
            {
                var loadedPackage = session.Packages.Find(packageDependency);
                if (loadedPackage != null)
                {
                    continue;
                }

                var file = PackageStore.Instance.GetPackageFileName(packageDependency.Name, packageDependency.Version);

                if (file == null)
                {
                    // TODO: We need to support automatic download of packages. This is not supported yet when only Paradox
                    // package is supposed to be installed, but It will be required for full store
                    log.Error("Unable to find package {0} not installed", packageDependency);
                    continue;
                }

                // Recursive load of the system package
                PreLoadPackage(session, log, file, true, loadedPackages, loadParameters);
            }

            // 2. Load local packages
            foreach (var packageReference in package.LocalDependencies)
            {
                // Check that the package was not already loaded, otherwise return the same instance
                if (session.Packages.ContainsById(packageReference.Id))
                {
                    continue;
                }

                // Expand the string of the location
                var newLocation = (UFile)AssetRegistry.ExpandString(session, packageReference.Location);

                var subPackageFilePath = package.RootDirectory != null?UPath.Combine(package.RootDirectory, newLocation) : newLocation;

                // Recursive load
                PreLoadPackage(session, log, subPackageFilePath.FullPath, false, loadedPackages, loadParameters);
            }
        }
Пример #2
0
        /// <summary>
        /// Serializes an <see cref="Asset" /> to the specified stream.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="asset">The asset object.</param>
        /// <param name="log">The logger.</param>
        /// <exception cref="System.ArgumentNullException">
        /// stream
        /// or
        /// assetFileExtension
        /// </exception>
        public static void Save(Stream stream, object asset, ILogger log = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (asset == null)
            {
                return;
            }

            var assetFileExtension = AssetRegistry.GetDefaultExtension(asset.GetType());

            if (assetFileExtension == null)
            {
                throw new ArgumentException("Unable to find a serializer for the specified asset. No asset file extension registered to AssetRegistry");
            }

            var serializer = FindSerializer(assetFileExtension);

            if (serializer == null)
            {
                throw new InvalidOperationException("Unable to find a serializer for [{0}]".ToFormat(assetFileExtension));
            }
            serializer.Save(stream, asset, log);
        }
Пример #3
0
        /// <summary>
        /// Serializes an <see cref="Asset" /> to the specified stream.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="asset">The asset object.</param>
        /// <param name="yamlMetadata"></param>
        /// <param name="log">The logger.</param>
        /// <exception cref="System.ArgumentNullException">
        /// stream
        /// or
        /// assetFileExtension
        /// </exception>
        public static void Save(Stream stream, object asset, AttachedYamlAssetMetadata yamlMetadata, ILogger log = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            if (asset == null)
            {
                return;
            }

            var assetFileExtension = AssetRegistry.GetDefaultExtension(asset.GetType());

            if (assetFileExtension == null)
            {
                throw new ArgumentException("Unable to find a serializer for the specified asset. No asset file extension registered to AssetRegistry");
            }

            var serializer = FindSerializer(assetFileExtension);

            if (serializer == null)
            {
                throw new InvalidOperationException($"Unable to find a serializer for [{assetFileExtension}]");
            }
            serializer.Save(stream, asset, yamlMetadata, log);
        }
Пример #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Asset"/> class.
        /// </summary>
        protected Asset()
        {
            Id   = AssetId.New();
            Tags = new TagCollection();

            // Initializse asset with default versions (same code as in Package..ctor())
            var defaultPackageVersion = AssetRegistry.GetCurrentFormatVersions(GetType());

            if (defaultPackageVersion != null)
            {
                SerializedVersion = new Dictionary <string, PackageVersion>(defaultPackageVersion);
            }
        }
Пример #5
0
        private static List <Tuple <UFile, UDirectory> > ListAssetFiles(ILogger log, Package package, CancellationToken?cancelToken)
        {
            var listFiles = new List <Tuple <UFile, UDirectory> >();

            // TODO Check how to handle refresh correctly as a public API
            if (package.RootDirectory == null)
            {
                throw new InvalidOperationException("Package RootDirectory is null");
            }

            if (!Directory.Exists(package.RootDirectory))
            {
                throw new InvalidOperationException("Package RootDirectory [{0}] does not exist".ToFormat(package.RootDirectory));
            }

            // Iterate on each source folders
            foreach (var sourceFolder in package.GetDistinctAssetFolderPaths())
            {
                // Lookup all files
                foreach (var directory in FileUtility.EnumerateDirectories(sourceFolder, SearchDirection.Down))
                {
                    var files = directory.GetFiles();

                    foreach (var filePath in files)
                    {
                        // Don't load package via this method
                        if (filePath.FullName.EndsWith(PackageFileExtension))
                        {
                            continue;
                        }

                        // Make an absolute path from the root of this package
                        var fileUPath = new UFile(filePath.FullName);
                        if (fileUPath.GetFileExtension() == null)
                        {
                            continue;
                        }

                        // If this kind of file an asset file?
                        if (!AssetRegistry.IsAssetFileExtension(fileUPath.GetFileExtension()))
                        {
                            continue;
                        }

                        listFiles.Add(new Tuple <UFile, UDirectory>(fileUPath, sourceFolder));
                    }
                }
            }

            return(listFiles);
        }
Пример #6
0
        internal AssetToImportMergeGroup(AssetToImportByImporter parent, AssetItem item)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            this.Parent = parent;
            Item        = item;
            Merges      = new List <AssetToImportMerge>();
            Enabled     = true;
            var assetDescription = AssetRegistry.GetDescription(item.Asset.GetType());

            Log = new LoggerResult(string.Format("Import {0} {1}", assetDescription != null ? assetDescription.DisplayName : "Asset", item));
        }
Пример #7
0
        PackageUpgrader CheckPackageUpgrade(ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage)
        {
            // Don't do anything if source is a system (read-only) package for now
            // We only want to process local packages
            if (dependentPackage.IsSystem)
            {
                return(null);
            }

            // Check if package might need upgrading
            var dependentPackagePreviousMinimumVersion = dependency.Version.MinVersion;

            if (dependentPackagePreviousMinimumVersion < dependencyPackage.Meta.Version)
            {
                // Find upgrader for given package
                // Note: If no upgrader is found, we assume it is still compatible with previous versions, so do nothing
                var packageUpgrader = AssetRegistry.GetPackageUpgrader(dependencyPackage.Meta.Name);
                if (packageUpgrader != null)
                {
                    // Check if upgrade is necessary
                    if (dependency.Version.MinVersion >= packageUpgrader.Attribute.PackageUpdatedVersionRange.MinVersion)
                    {
                        return(null);
                    }

                    // Check if upgrade is allowed
                    if (dependency.Version.MinVersion < packageUpgrader.Attribute.PackageMinimumVersion)
                    {
                        // Throw an exception, because the package update is not allowed and can't be done
                        throw new InvalidOperationException(string.Format("Upgrading package [{0}] to use [{1}] from version [{2}] to [{3}] is not supported", dependentPackage.Meta.Name, dependencyPackage.Meta.Name, dependentPackagePreviousMinimumVersion, dependencyPackage.Meta.Version));
                    }

                    log.Info("Upgrading package [{0}] to use [{1}] from version [{2}] to [{3}] will be required", dependentPackage.Meta.Name, dependencyPackage.Meta.Name, dependentPackagePreviousMinimumVersion, dependencyPackage.Meta.Version);
                    return(packageUpgrader);
                }
            }

            return(null);
        }
Пример #8
0
        /// <summary>
        /// Fixes asset import that were imported by the previous method. Add a AssetImport.SourceHash and ImporterId
        /// </summary>
        /// <param name="item">The item.</param>
        private static void FixAssetImport(AssetItem item)
        {
            // TODO: this whole method is a temporary migration. This should be removed in the next version

            var assetImport = item.Asset as AssetImport;

            if (assetImport == null || assetImport.Source == null)
            {
                return;
            }

            // If the asset has a source but no import base, then we are going to simulate an original import
            if (assetImport.Base == null)
            {
                var fileExtension = assetImport.Source.GetFileExtension();

                var assetImportBase = (AssetImport)AssetCloner.Clone(assetImport);
                assetImportBase.SetAsRootImport();
                assetImportBase.SetDefaults();

                // Setup default importer
                if (!String.IsNullOrEmpty(fileExtension))
                {
                    var importerId = AssetRegistry.FindImporterByExtension(fileExtension).FirstOrDefault();
                    if (importerId != null)
                    {
                        assetImport.ImporterId = importerId.Id;
                    }
                }
                var assetImportTracked = assetImport as AssetImportTracked;
                if (assetImportTracked != null)
                {
                    assetImportTracked.SourceHash = ObjectId.Empty;
                }

                assetImport.Base = new AssetBase(assetImportBase);
                item.IsDirty     = true;
            }
        }
 protected override bool CanVisit(object obj)
 {
     return(!AssetRegistry.IsContentType(obj?.GetType()) && base.CanVisit(obj));
 }
Пример #10
0
 public AssetUpgraderCollection(Type assetType, int currentVersion)
 {
     this.currentVersion = currentVersion;
     AssetRegistry.AssertAssetType(assetType);
     AssetType = assetType;
 }
 public static bool IsPackageFile(string filePath)
 {
     return(AssetRegistry.GetAssetTypeFromFileExtension(Path.GetExtension(filePath)) == typeof(Package));
 }
Пример #12
0
        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);
        }
Пример #13
0
 public AssetUpgraderCollection(Type assetType, PackageVersion currentVersion)
 {
     this.currentVersion = currentVersion;
     AssetRegistry.IsAssetType(assetType, true);
     AssetType = assetType;
 }
Пример #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Asset"/> class.
 /// </summary>
 protected Asset()
 {
     Id   = Guid.NewGuid();
     Tags = new TagCollection();
     SerializedVersion = AssetRegistry.GetCurrentFormatVersion(GetType());
 }
Пример #15
0
        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);
        }
Пример #16
0
        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);
        }
Пример #17
0
        /// <summary>
        /// Loads a package from specified file path.
        /// </summary>
        /// <param name="filePath">The file path to a package file.</param>
        /// <param name="sessionResult">The session result.</param>
        /// <param name="loadParameters">The load parameters.</param>
        /// <returns>A package.</returns>
        /// <exception cref="System.ArgumentNullException">filePath</exception>
        /// <exception cref="System.ArgumentException">File [{0}] must exist.ToFormat(filePath);filePath</exception>
        public static void Load(string filePath, PackageSessionResult sessionResult, PackageLoadParameters loadParameters = null)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException("filePath");
            }
            if (sessionResult == null)
            {
                throw new ArgumentNullException("sessionResult");
            }

            // Make sure with have valid parameters
            loadParameters = loadParameters ?? PackageLoadParameters.Default();

            // Make sure to use a full path.
            filePath = FileUtility.GetAbsolutePath(filePath);

            if (!File.Exists(filePath))
            {
                throw new ArgumentException("File [{0}] must exist".ToFormat(filePath), "filePath");
            }

            try
            {
                // Enable reference analysis caching during loading
                AssetReferenceAnalysis.EnableCaching = true;

                using (var profile = Profiler.Begin(PackageSessionProfilingKeys.Loading))
                {
                    sessionResult.Clear();
                    sessionResult.Progress("Loading..", 0, 1);

                    var session = new PackageSession();

                    var packagePaths = new List <string>();

                    // If we have a solution, load all packages
                    if (PackageSessionHelper.IsSolutionFile(filePath))
                    {
                        PackageSessionHelper.LoadSolution(session, filePath, packagePaths, sessionResult);
                    }
                    else if (PackageSessionHelper.IsPackageFile(filePath))
                    {
                        packagePaths.Add(filePath);
                    }
                    else
                    {
                        sessionResult.Error("Unsupported file extension (only .sln or {0} are supported)", Package.PackageFileExtension);
                        return;
                    }

                    var cancelToken = loadParameters.CancelToken;

                    // Load all packages
                    var packagesLoaded = new PackageCollection();
                    foreach (var packageFilePath in packagePaths)
                    {
                        PreLoadPackage(session, sessionResult, packageFilePath, false, packagesLoaded, loadParameters);

                        // Output the session only if there is no cancellation
                        if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
                        {
                            return;
                        }
                    }

                    // Load all missing references/dependencies
                    session.LoadMissingReferences(sessionResult, loadParameters);

                    // Fix relative references
                    var analysis        = new PackageSessionAnalysis(session, GetPackageAnalysisParametersForLoad());
                    var analysisResults = analysis.Run();
                    analysisResults.CopyTo(sessionResult);

                    // Run custom package session analysis
                    foreach (var type in AssetRegistry.GetPackageSessionAnalysisTypes())
                    {
                        var pkgAnalysis = (PackageSessionAnalysisBase)Activator.CreateInstance(type);
                        pkgAnalysis.Session = session;
                        var results = pkgAnalysis.Run();
                        results.CopyTo(sessionResult);
                    }

                    // Output the session only if there is no cancellation
                    if (!cancelToken.HasValue || !cancelToken.Value.IsCancellationRequested)
                    {
                        sessionResult.Session = session;

                        // Defer the initialization of the dependency manager
                        //session.DependencyManager.InitializeDeferred();
                    }

                    // The session is not dirty when loading it
                    session.IsDirty = false;
                }
            }
            finally
            {
                // Disable reference analysis caching after loading
                AssetReferenceAnalysis.EnableCaching = false;
            }
        }