Ejemplo n.º 1
0
        public void TestUpdateAssetUrl()
        {
            var projectDir = new UFile(Path.Combine(Environment.CurrentDirectory, "testxk"));
            
            // Create a project with an asset reference a raw file
            var project = new Package { FullPath = projectDir };
            var assetItem = new AssetItem("test", new AssetObjectTest() { Reference =  new AssetReference<AssetObjectTest>(Guid.Empty, "good/location")});
            project.Assets.Add(assetItem);
            var goodAsset = new AssetObjectTest();
            project.Assets.Add(new AssetItem("good/location", goodAsset));

            // Add the project to the session to make sure analysis will run correctly
            var session = new PackageSession(project);

            // Create a session with this project
            var analysis = new PackageAnalysis(project,
                new PackageAnalysisParameters()
                    {
                        IsProcessingAssetReferences = true,
                        ConvertUPathTo = UPathType.Absolute,
                        IsProcessingUPaths = true
                    });
            var result = analysis.Run();
            Assert.IsFalse(result.HasErrors);
            Assert.AreEqual(1, result.Messages.Count);
            Assert.IsTrue(result.Messages[0].ToString().Contains("changed"));

            var asset = (AssetObjectTest)assetItem.Asset;
            Assert.AreEqual(goodAsset.Id, asset.Reference.Id);
            Assert.AreEqual("good/location", asset.Reference.Location);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Performs a wide package validation analysis.
        /// </summary>
        /// <param name="log">The log to output the result of the validation.</param>
        public override void Run(ILogger log)
        {
            if (log == null) throw new ArgumentNullException("log");

            foreach (var package in Session.LocalPackages)
            {
                var analysis = new PackageAnalysis(package, parameters);
                analysis.Run(log);
            }
        }
        /// <summary>
        /// Performs a wide package validation analysis.
        /// </summary>
        /// <param name="log">The log to output the result of the validation.</param>
        public override void Run(ILogger log)
        {
            if (log == null)
            {
                throw new ArgumentNullException("log");
            }

            foreach (var package in Session.LocalPackages)
            {
                var analysis = new PackageAnalysis(package, parameters);
                analysis.Run(log);
            }
        }
Ejemplo n.º 4
0
        public void TestMoveAssetWithUFile()
        {
            var projectDir = new UFile(Path.Combine(Environment.CurrentDirectory, "testxk"));
            var rawAssetPath = new UFile("../image.png");
            var assetPath = new UFile("sub1/sub2/test");

            // Create a project with an asset reference a raw file
            var project = new Package { FullPath = projectDir };
            project.Profiles.Add(new PackageProfile("Shared", new AssetFolder(".")));
            var asset = new AssetObjectTest() { RawAsset = new UFile(rawAssetPath) };
            var assetItem = new AssetItem(assetPath, asset);
            project.Assets.Add(assetItem);

            // Run an asset reference analysis on this project
            var analysis = new PackageAnalysis(project,
                new PackageAnalysisParameters()
                    {
                        ConvertUPathTo = UPathType.Absolute,
                        IsProcessingUPaths = true
                    });
            var result = analysis.Run();
            Assert.IsFalse(result.HasErrors);
            Assert.AreEqual(UPath.Combine(project.RootDirectory, new UFile("sub1/image.png")), asset.RawAsset);

            project.Assets.Remove(assetItem);
            assetItem = new AssetItem("sub1/test", asset);
            project.Assets.Add(assetItem);
            result = analysis.Run();
            Assert.IsFalse(result.HasErrors);
            Assert.AreEqual(UPath.Combine(project.RootDirectory, new UFile("sub1/image.png")), asset.RawAsset);

            project.Assets.Remove(assetItem);
            assetItem = new AssetItem("test", asset);
            project.Assets.Add(assetItem);
            result = analysis.Run();
            Assert.IsFalse(result.HasErrors);
            Assert.AreEqual(UPath.Combine(project.RootDirectory, new UFile("sub1/image.png")), asset.RawAsset);

            analysis.Parameters.ConvertUPathTo = UPathType.Relative;
            result = analysis.Run();
            Assert.IsFalse(result.HasErrors);
            Assert.AreEqual(new UFile("sub1/image.png"), asset.RawAsset);
        }
Ejemplo n.º 5
0
        /// <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;
        }
Ejemplo n.º 6
0
        /// <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();
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Load assets and perform package analysis.
        /// </summary>
        /// <param name="package">The package.</param>
        /// <param name="log">The log.</param>
        /// <param name="loadParametersArg">The load parameters argument.</param>
        /// <returns></returns>
        internal bool LoadAssets(ILogger log, PackageLoadParameters loadParametersArg)
        {
            var loadParameters = loadParametersArg ?? PackageLoadParameters.Default();

            try
            {
                // Load assets
                if (loadParameters.AutoLoadTemporaryAssets)
                {
                    LoadTemporaryAssets(log, loadParameters.AssetFiles, loadParameters.CancelToken, loadParameters.AssetFilter);
                }

                // Convert UPath to absolute
                if (loadParameters.ConvertUPathToAbsolute)
                {
                    var analysis = new PackageAnalysis(this, 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
                LoadTemplates(log);

                return true;
            }
            catch (Exception ex)
            {
                log.Error("Error while pre-loading package [{0}]", ex, FullPath);

                return false;
            }
        }
Ejemplo n.º 8
0
        /// <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();
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Adds an existing package to the current session and runs the package analysis before adding it.
        /// </summary>
        /// <param name="package">The package to add</param>
        /// <param name="logger">The logger</param>
        public void AddExistingPackage(Package package, ILogger logger)
        {
            if (package == null) throw new ArgumentNullException(nameof(package));
            if (logger == null) throw new ArgumentNullException(nameof(logger));

            if (packages.Contains(package))
            {
                return;
            }

            // Preset the session on the package to allow the session to look for existing asset
            this.Packages.Add(package);

            // Run analysis after
            var analysis = new PackageAnalysis(package, GetPackageAnalysisParametersForLoad());
            analysis.Run(logger);

        }
Ejemplo n.º 10
0
        /// <summary>
        /// Adds an existing package to the current session.
        /// </summary>
        /// <param name="packagePath">The package path.</param>
        /// <param name="logger">The session result.</param>
        /// <param name="loadParametersArg">The load parameters argument.</param>
        /// <exception cref="System.ArgumentNullException">packagePath</exception>
        /// <exception cref="System.ArgumentException">Invalid relative path. Expecting an absolute package path;packagePath</exception>
        /// <exception cref="System.IO.FileNotFoundException">Unable to find package</exception>
        public Package AddExistingPackage(UFile packagePath, ILogger logger, PackageLoadParameters loadParametersArg = null)
        {
            if (packagePath == null) throw new ArgumentNullException("packagePath");
            if (logger == null) throw new ArgumentNullException("logger");
            if (!packagePath.IsAbsolute) throw new ArgumentException("Invalid relative path. Expecting an absolute package path", "packagePath");
            if (!File.Exists(packagePath)) throw new FileNotFoundException("Unable to find package", packagePath);

            var loadParameters = loadParametersArg ?? PackageLoadParameters.Default();

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

                var packagesLoaded = new PackageCollection();

                package = PreLoadPackage(this, logger, packagePath, false, packagesLoaded, loadParameters);

                // Load all missing references/dependencies
                LoadMissingReferences(logger, loadParameters);

                // Load assets
                TryLoadAssets(this, logger, package, loadParameters);

                // Run analysis after
                foreach (var packageToAdd in packagesLoaded)
                {
                    var analysis = new PackageAnalysis(packageToAdd, GetPackageAnalysisParametersForLoad());
                    analysis.Run(logger);
                }
            }
            finally
            {
                // Disable reference analysis caching after loading
                AssetReferenceAnalysis.EnableCaching = false;
            }
            return package;
        }
Ejemplo n.º 11
0
        /// <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();
            }
        }
Ejemplo n.º 12
0
        /// <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, PackageSaveParameters saveParameters = null)
        {
            if (log == null) throw new ArgumentNullException(nameof(log));

            if (FullPath == null)
            {
                log.Error(this, null, AssetMessageCode.PackageCannotSave, "null");
                return;
            }

            saveParameters = saveParameters ?? PackageSaveParameters.Default();

            // Use relative paths when saving
            var analysis = new PackageAnalysis(this, new PackageAnalysisParameters()
            {
                SetDirtyFlagOnAssetWhenFixingUFile = false,
                ConvertUPathTo = UPathType.Relative,
                IsProcessingUPaths = true,
            });
            analysis.Run(log);

            var assetsFiltered = false;
            try
            {
                // Update source folders
                UpdateSourceFolders(Assets);

                if (IsDirty)
                {
                    List<UFile> filesToDeleteLocal;
                    lock (filesToDelete)
                    {
                        filesToDeleteLocal = filesToDelete.ToList();
                        filesToDelete.Clear();
                    }

                    try
                    {
                        AssetFileSerializer.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)
                {
                    var assetSaved = false;
                    if (asset.IsDirty)
                    {
                        if (saveParameters.AssetFilter?.Invoke(asset) ?? true)
                        {
                            SaveSingleAsset_NoUpdateSourceFolder(asset, log);
                        }
                        else
                        {
                            assetsFiltered = true;
                        }
                    }

                    // Add new files to .csproj
                    var projectAsset = asset.Asset as IProjectAsset;
                    if (projectAsset != null)
                    {
                        var projectFullPath = asset.SourceProject;
                        var projectInclude = asset.GetProjectInclude();

                        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 != projectInclude))
                        {
                            var generatorAsset = projectAsset as IProjectFileGeneratorAsset;
                            if (generatorAsset != null)
                            {
                                var generatedInclude = asset.GetGeneratedInclude();

                                project.AddItem("None", projectInclude,
                                    new List<KeyValuePair<string, string>>
                                    {
                                    new KeyValuePair<string, string>("Generator", generatorAsset.Generator),
                                    new KeyValuePair<string, string>("LastGenOutput", new UFile(generatedInclude).GetFileNameWithExtension())
                                    });

                                project.AddItem("Compile", generatedInclude,
                                    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(projectInclude).GetFileNameWithExtension())
                                    });
                            }
                            else
                            {
                                project.AddItem("Compile", projectInclude);
                            }
                        }
                    }
                }

                foreach (var project in vsProjs.Values)
                {
                    project.Save();
                    project.ProjectCollection.UnloadAllProjects();
                    project.ProjectCollection.Dispose();
                }

                // If some assets were filtered out, Assets is still dirty
                Assets.IsDirty = assetsFiltered;

                // 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();
            }
        }