Skip to content
Permalink
Browse files

[Assets] Rework package dependencies

  • Loading branch information
xen2 committed Sep 20, 2018
1 parent f375ae1 commit dc4ef281f38037dd96824b4c63c074a3d93118ea
@@ -100,7 +100,7 @@ public void TestPackageLoadingWithAssets()
Assert.NotNull(project);
Assert.True(3 == project.Assets.Count, "Invalid number of assets loaded");

Assert.True(1 == project.Container.LoadedDependencies.Count, "Expecting subproject");
Assert.True(1 == project.Container.FlattenedDependencies.Count, "Expecting subproject");

Assert.NotEqual(AssetId.Empty, project.Assets.First().Id);

@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using Xenko.Core.Assets.Analysis;
using Xenko.Core.Extensions;

namespace Xenko.Core.Assets.Compiler
{
@@ -74,7 +75,7 @@ private void CollectReferences(Package package, HashSet<AssetItem> assetsReferen
}

// 2. Process referenced packages as well (for their roots)
foreach (var dependency in package.Container.LoadedDependencies)
foreach (var dependency in package.Container.FlattenedDependencies.Select(x => x.Package).NotNull())
{
CollectReferences(dependency, assetsReferenced, packagesProcessed);
}
@@ -196,9 +196,6 @@ public Package()
// TODO: turn that internal!
public List<AssetItem> TemporaryAssets { get; } = new List<AssetItem>();

[DataMemberIgnore]
public List<LockFileLibrary> TopLevelDependencies { get; } = new List<LockFileLibrary>();

/// <summary>
/// Gets the path to the package file. May be null if the package was not loaded or saved.
/// </summary>
@@ -4,7 +4,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using Xenko.Core.Extensions;
using Xenko.Core.IO;
using Xenko.Core.Serialization;
using Xenko.Core.Serialization.Contents;
@@ -40,9 +40,10 @@ internal static IEnumerable<Package> GetPackagesWithDependencies(this Package cu

var session = currentPackage.Session;

foreach (var package in currentPackage.Container.LoadedDependencies)
foreach (var dependency in currentPackage.Container.FlattenedDependencies)
{
yield return package;
if (dependency.Package != null)
yield return dependency.Package;
}
}

@@ -102,7 +103,7 @@ private static void FillPackageDependencies(Package rootPackage, ICollection<Pac
throw new InvalidOperationException("Cannot query package with dependencies when it is not attached to a session");
}

foreach (var dependency in rootPackage.Container.LoadedDependencies)
foreach (var dependency in rootPackage.Container.FlattenedDependencies.Select(x => x.Package).NotNull())
{
if (!packagesFound.Contains(dependency))
packagesFound.Add(dependency);
@@ -190,7 +190,7 @@ private async Task PreLoadPackageDependencies(ILogger log, SolutionProject proje
await VSProjectHelper.RestoreNugetPackages(log, project.FullPath);

project.FlattenedDependencies.Clear();
project.LoadedDependencies.Clear();
project.DirectDependencies.Clear();
var projectAssetsJsonPath = Path.Combine(project.FullPath.GetFullDirectory(), @"obj", LockFileFormat.AssetsFileName);
if (File.Exists(projectAssetsJsonPath))
{
@@ -249,7 +249,7 @@ private async Task PreLoadPackageDependencies(ILogger log, SolutionProject proje
}

if (loadedPackage != null)
project.LoadedDependencies.Add(loadedPackage);
projectDependency.Package = loadedPackage;
}

// Load some informations about the project
@@ -25,8 +25,6 @@ namespace Xenko.Core.Assets
{
public abstract class PackageContainer
{
private PackageSession session;

public PackageContainer([NotNull] Package package)
{
Package = package;
@@ -42,7 +40,9 @@ public PackageContainer([NotNull] Package package)
[NotNull]
public Package Package { get; }

public ObservableCollection<Package> LoadedDependencies { get; } = new ObservableCollection<Package>();
public ObservableCollection<DependencyRange> DirectDependencies { get; } = new ObservableCollection<DependencyRange>();

public ObservableCollection<Dependency> FlattenedDependencies { get; } = new ObservableCollection<Dependency>();

/// <summary>
/// Saves this package and all dirty assets. See remarks.
@@ -243,6 +243,11 @@ public Dependency(string name, PackageVersion version, DependencyType type)
Type = type;
}

public Dependency(Package package) : this(package.Meta.Name, package.Meta.Version, DependencyType.Package)
{
Package = package;
}

public string Name { get; set; }

public string MSBuildProject { get; set; }
@@ -251,6 +256,8 @@ public Dependency(string name, PackageVersion version, DependencyType type)

public DependencyType Type { get; set; }

public Package Package { get; set; }

public override string ToString()
{
return $"{Name} {Version} ({Type})";
@@ -277,11 +284,13 @@ public DependencyRange(string name, PackageVersionRange versionRange, Dependency

public class SolutionProject : PackageContainer
{
private PackageSession session;
private readonly Package package;
protected SolutionProject([NotNull] Package package) : base(package)
{
DirectDependencies.CollectionChanged += DirectDependencies_CollectionChanged;
}

public SolutionProject([NotNull] Package package, Guid projectGuid, string fullPath)
: base(package)
: this(package)
{
VSProject = new VisualStudio.Project(projectGuid, VisualStudio.KnownProjectTypeGuid.CSharp, Path.GetFileNameWithoutExtension(fullPath), fullPath, Guid.Empty,
Enumerable.Empty<VisualStudio.Section>(),
@@ -290,7 +299,7 @@ public SolutionProject([NotNull] Package package, Guid projectGuid, string fullP
}

public SolutionProject([NotNull] Package package, VisualStudio.Project vsProject)
: base(package)
: this(package)
{
VSProject = vsProject;
}
@@ -305,13 +314,70 @@ public SolutionProject([NotNull] Package package, VisualStudio.Project vsProject

public bool IsImplicitProject { get; set; }

public bool TrackDirectDependencies { get; set; }

public string Name => VSProject.Name;

public UFile FullPath => VSProject.FullPath;

public ObservableCollection<DependencyRange> DirectDependencies { get; } = new ObservableCollection<DependencyRange>();
private void DirectDependencies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Ignore collection being filled during dependency resolution
if (Package.State < PackageState.DependenciesReady)
return;

public ObservableCollection<Dependency> FlattenedDependencies { get; } = new ObservableCollection<Dependency>();
var projectFile = FullPath;
var msbuildProject = VSProjectHelper.LoadProject(projectFile.ToWindowsPath());
var isProjectDirty = false;

if (e.OldItems != null && e.OldItems.Count > 0)
{
foreach (DependencyRange dependency in e.OldItems)
{
switch (dependency.Type)
{
case DependencyType.Package:
{
var matchingReferences = msbuildProject.GetItems("PackageReference").Where(packageReference => packageReference.EvaluatedInclude == dependency.Name && packageReference.GetMetadataValue("Version") == dependency.VersionRange.ToString()).ToList();
isProjectDirty = matchingReferences.Count > 0;
msbuildProject.RemoveItems(matchingReferences);
break;
}
case DependencyType.Project:
{
var matchingReferences = msbuildProject.GetItems("ProjectReference").Where(projectReference => (UFile)projectReference.EvaluatedInclude == ((UFile)dependency.MSBuildProject).MakeRelative(projectFile.GetFullDirectory())).ToList();
isProjectDirty = matchingReferences.Count > 0;
msbuildProject.RemoveItems(matchingReferences);
break;
}
}
}
}

if (e.NewItems != null && e.NewItems.Count > 0)
{
foreach (DependencyRange dependency in e.NewItems)
{
switch (dependency.Type)
{
case DependencyType.Package:
msbuildProject.AddItem("PackageReference", dependency.Name, new[] { new KeyValuePair<string, string>("Version", dependency.VersionRange.ToString()) });
isProjectDirty = true;
break;
case DependencyType.Project:
msbuildProject.AddItem("ProjectReference", ((UFile)dependency.MSBuildProject).MakeRelative(projectFile.GetFullDirectory()).ToWindowsPath());
isProjectDirty = true;
break;
}
}
}

if (isProjectDirty)
msbuildProject.Save();

msbuildProject.ProjectCollection.UnloadAllProjects();
msbuildProject.ProjectCollection.Dispose();
}

protected override void SavePackage()
{
@@ -30,6 +30,7 @@
using Xenko.Assets.Models;
using Xenko.Assets.Rendering;
using Xenko.Assets.Templates;
using Xenko.Core.Extensions;

namespace Xenko.Assets.Presentation.Templates
{
@@ -147,7 +148,7 @@ protected override bool Generate(SessionTemplateGeneratorParameters parameters)
// Load missing references
session.LoadMissingDependencies(parameters.Logger);
// Load dependency assets (needed for camera script template)
session.LoadMissingAssets(parameters.Logger, project.LoadedDependencies);
session.LoadMissingAssets(parameters.Logger, project.FlattenedDependencies.Select(x => x.Package).NotNull());

// Add Effects as an asset folder in order to load xksl
package.AssetFolders.Add(new AssetFolder("Effects"));
@@ -15,6 +15,7 @@
using Xenko.Core.Presentation.Windows;
using Xenko.Assets.Templates;
using Xenko.Core.Assets.Editor.Components.TemplateDescriptions;
using Xenko.Core.Extensions;

namespace Xenko.Assets.Presentation.Templates
{
@@ -93,7 +94,7 @@ protected sealed override bool Generate(SessionTemplateGeneratorParameters param
// Load missing references
session.LoadMissingDependencies(parameters.Logger);
// Load dependency assets (needed for camera script template)
session.LoadMissingAssets(parameters.Logger, project.LoadedDependencies);
session.LoadMissingAssets(parameters.Logger, project.FlattenedDependencies.Select(x => x.Package).NotNull());

// Log done
ProjectTemplateGeneratorHelper.Progress(logger, "Done", 1, 1);
@@ -14,12 +14,11 @@ public abstract class PackageReferenceViewModel : SessionObjectViewModel, ICompa
{
private readonly DependencyCategoryViewModel dependencies;

protected PackageReferenceViewModel(PackageViewModel target, PackageViewModel referencer, DependencyCategoryViewModel dependencies)
: base(target.SafeArgument(nameof(target)).Session)
protected PackageReferenceViewModel(PackageViewModel referencer, DependencyCategoryViewModel dependencies)
: base(referencer.SafeArgument(nameof(referencer)).Session)
{
this.dependencies = dependencies;
Referencer = referencer;
Target = target;
}

/// <summary>
@@ -30,13 +29,13 @@ protected PackageReferenceViewModel(PackageViewModel target, PackageViewModel re
/// <summary>
/// Gets the target package of this package reference.
/// </summary>
public PackageViewModel Target { get; }
public PackageViewModel Target { get; protected set; }

public override string TypeDisplayName => "Package Reference";

public override IEnumerable<IDirtiable> Dirtiables => dependencies.Dirtiables;

public override bool IsEditable => Referencer.IsEditable && Target.IsEditable;
public override bool IsEditable => Referencer.IsEditable;

/// <inheritdoc/>
public int CompareTo(PackageReferenceViewModel other)
@@ -67,4 +66,35 @@ protected override void UpdateIsDeletedStatus()
}
}
}

public class DirectDependencyReferenceViewModel : PackageReferenceViewModel
{
private readonly DependencyRange dependency;

public DirectDependencyReferenceViewModel(DependencyRange dependency, PackageViewModel referencer, DependencyCategoryViewModel dependencies, bool canUndoRedoCreation)
: base(referencer, dependencies)
{
this.dependency = dependency;
InitialUndelete(canUndoRedoCreation);
}

public override string Name
{
get => dependency.Name;
set => throw new InvalidOperationException("The name of a package reference cannot be set");
}

public override void AddReference()
{
if (!Referencer.Package.Container.DirectDependencies.Contains(dependency))
{
Referencer.Package.Container.DirectDependencies.Add(dependency);
}
}

public override void RemoveReference()
{
Referencer.Package.Container.DirectDependencies.Remove(dependency);
}
}
}

0 comments on commit dc4ef28

Please sign in to comment.
You can’t perform that action at this time.