Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IContextCache to deploy connectors #13287

Merged
merged 7 commits into from Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 36 additions & 37 deletions src/Umbraco.Core/Deploy/ArtifactBase.cs
@@ -1,50 +1,49 @@
namespace Umbraco.Cms.Core.Deploy
namespace Umbraco.Cms.Core.Deploy;

/// <summary>
/// Provides a base class to all artifacts.
/// </summary>
public abstract class ArtifactBase<TUdi> : IArtifact
where TUdi : Udi
{
/// <summary>
/// Provides a base class to all artifacts.
/// </summary>
public abstract class ArtifactBase<TUdi> : IArtifact
where TUdi : Udi
protected ArtifactBase(TUdi udi, IEnumerable<ArtifactDependency>? dependencies = null)
{
protected ArtifactBase(TUdi udi, IEnumerable<ArtifactDependency>? dependencies = null)
{
Udi = udi ?? throw new ArgumentNullException("udi");
Name = Udi.ToString();
Udi = udi ?? throw new ArgumentNullException("udi");
Name = Udi.ToString();

_dependencies = dependencies ?? Enumerable.Empty<ArtifactDependency>();
_checksum = new Lazy<string>(GetChecksum);
}

private readonly Lazy<string> _checksum;
_dependencies = dependencies ?? Enumerable.Empty<ArtifactDependency>();
_checksum = new Lazy<string>(GetChecksum);
}

private IEnumerable<ArtifactDependency> _dependencies;
private readonly Lazy<string> _checksum;

protected abstract string GetChecksum();
private IEnumerable<ArtifactDependency> _dependencies;

Udi IArtifactSignature.Udi => Udi;
protected abstract string GetChecksum();

public TUdi Udi { get; set; }
Udi IArtifactSignature.Udi => Udi;

public string Checksum => _checksum.Value;
public TUdi Udi { get; set; }

/// <summary>
/// Prevents the <see cref="Checksum" /> property from being serialized.
/// </summary>
/// <remarks>
/// Note that we can't use <see cref="NonSerializedAttribute"/> here as that works only on fields, not properties. And we want to avoid using [JsonIgnore]
/// as that would require an external dependency in Umbraco.Cms.Core.
/// So using this method of excluding properties from serialized data, documented here: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
/// </remarks>
public bool ShouldSerializeChecksum() => false;
public string Checksum => _checksum.Value;

public IEnumerable<ArtifactDependency> Dependencies
{
get => _dependencies;
set => _dependencies = value.OrderBy(x => x.Udi);
}
/// <summary>
/// Prevents the <see cref="Checksum" /> property from being serialized.
/// </summary>
/// <remarks>
/// Note that we can't use <see cref="NonSerializedAttribute"/> here as that works only on fields, not properties. And we want to avoid using [JsonIgnore]
/// as that would require an external dependency in Umbraco.Cms.Core.
/// So using this method of excluding properties from serialized data, documented here: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
/// </remarks>
public bool ShouldSerializeChecksum() => false;

public IEnumerable<ArtifactDependency> Dependencies
{
get => _dependencies;
set => _dependencies = value.OrderBy(x => x.Udi);
}

public string Name { get; set; }
public string Name { get; set; }

public string Alias { get; set; } = string.Empty;
}
public string Alias { get; set; } = string.Empty;
}
37 changes: 37 additions & 0 deletions src/Umbraco.Core/Deploy/ArtifactDeployState.cs
Expand Up @@ -44,3 +44,40 @@ public abstract class ArtifactDeployState
/// </remarks>
protected abstract IArtifact GetArtifactAsIArtifact();
}

/// <summary>
/// Represent the state of an artifact being deployed.
/// </summary>
/// <typeparam name="TArtifact">The type of the artifact.</typeparam>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
public class ArtifactDeployState<TArtifact, TEntity> : ArtifactDeployState
where TArtifact : IArtifact
{
/// <summary>
/// Initializes a new instance of the <see cref="ArtifactDeployState{TArtifact,TEntity}" /> class.
/// </summary>
/// <param name="art">The artifact.</param>
/// <param name="entity">The entity.</param>
/// <param name="connector">The service connector deploying the artifact.</param>
/// <param name="nextPass">The next pass number.</param>
public ArtifactDeployState(TArtifact art, TEntity? entity, IServiceConnector connector, int nextPass)
{
Artifact = art;
Entity = entity;
Connector = connector;
NextPass = nextPass;
}

/// <summary>
/// Gets or sets the artifact.
/// </summary>
public new TArtifact Artifact { get; set; }

/// <summary>
/// Gets or sets the entity.
/// </summary>
public TEntity? Entity { get; set; }

/// <inheritdoc />
protected sealed override IArtifact GetArtifactAsIArtifact() => Artifact;
}
38 changes: 0 additions & 38 deletions src/Umbraco.Core/Deploy/ArtifactDeployStateOfTArtifactTEntity.cs

This file was deleted.

21 changes: 21 additions & 0 deletions src/Umbraco.Core/Deploy/ContextCache/DeployContextCache.cs
@@ -0,0 +1,21 @@
namespace Umbraco.Cms.Core.Deploy;

/// <summary>
/// A context cache that stores items on the <see cref="IDeployContext" />.
/// </summary>
/// <seealso cref="Umbraco.Cms.Core.Deploy.DictionaryCache" />
public sealed class DeployContextCache : DictionaryCache
{
/// <summary>
/// The prefix added to the <see cref="IDeployContext" /> item keys.
/// </summary>
public const string Prefix = "ContextCache.";

/// <summary>
/// Initializes a new instance of the <see cref="DeployContextCache" /> class.
/// </summary>
/// <param name="deployContext">The deploy context.</param>
public DeployContextCache(IDeployContext deployContext)
: base(deployContext.Items, Prefix)
{ }
}
82 changes: 82 additions & 0 deletions src/Umbraco.Core/Deploy/ContextCache/DictionaryCache.cs
@@ -0,0 +1,82 @@
using Umbraco.Extensions;

namespace Umbraco.Cms.Core.Deploy;

/// <summary>
/// A context cache that stores items in a dictionary.
/// </summary>
/// <seealso cref="Umbraco.Cms.Core.Deploy.IContextCache" />
public class DictionaryCache : IContextCache
{
/// <summary>
/// The items.
/// </summary>
protected readonly IDictionary<string, object> _items;

/// <summary>
/// The prefix.
/// </summary>
protected readonly string? _prefix;

/// <summary>
/// Initializes a new instance of the <see cref="DictionaryCache" /> class.
/// </summary>
public DictionaryCache()
: this(new Dictionary<string, object>(), null)
{ }

/// <summary>
/// Initializes a new instance of the <see cref="DictionaryCache" /> class.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="prefix">The prefix to add to all keys.</param>
/// <exception cref="System.ArgumentNullException">items</exception>
protected DictionaryCache(IDictionary<string, object> items, string? prefix)
{
_items = items ?? throw new ArgumentNullException(nameof(items));
_prefix = prefix;
}

/// <inheritdoc />
public void Create<T>(string key, T item)
{
var prefixedKey = _prefix + key;
if (item != null)
{
_items[prefixedKey] = item;
}
}

/// <inheritdoc />
public T? GetOrCreate<T>(string key, Func<T?> factory)
{
var prefixedKey = _prefix + key;
if (_items.TryGetValue(prefixedKey, out var itemValue) &&
itemValue is T item)
{
return item;
}

var factoryItem = factory();
if (factoryItem != null)
{
_items[prefixedKey] = factoryItem;
return factoryItem;
}

return default;
}

/// <inheritdoc />
public void Clear()
{
if (string.IsNullOrEmpty(_prefix))
{
_items.Clear();
}
else
{
_items.RemoveAll(x => x.Key.StartsWith(_prefix, StringComparison.Ordinal));
}
}
}
34 changes: 34 additions & 0 deletions src/Umbraco.Core/Deploy/ContextCache/PassThroughCache.cs
@@ -0,0 +1,34 @@
namespace Umbraco.Cms.Core.Deploy;

/// <summary>
/// A pass through context cache that always creates the items.
/// </summary>
/// <seealso cref="Umbraco.Cms.Core.Deploy.IContextCache" />
public sealed class PassThroughCache : IContextCache
{
/// <summary>
/// Gets the instance.
/// </summary>
/// <value>
/// The instance.
/// </value>
public static PassThroughCache Instance { get; } = new PassThroughCache();

/// <summary>
/// Prevents a default instance of the <see cref="PassThroughCache"/> class from being created.
/// </summary>
private PassThroughCache()
{ }

/// <inheritdoc />
public void Create<T>(string key, T item)
{ }

/// <inheritdoc />
public T? GetOrCreate<T>(string key, Func<T?> factory)
=> factory();

/// <inheritdoc />
public void Clear()
{ }
}
31 changes: 31 additions & 0 deletions src/Umbraco.Core/Deploy/IContextCache.cs
@@ -0,0 +1,31 @@
namespace Umbraco.Cms.Core.Deploy;

/// <summary>
/// Represents a context cache used by Deploy operations.
/// </summary>
public interface IContextCache
{
/// <summary>
/// Creates the item on the context cache using the specified <paramref name="key" />.
/// </summary>
/// <typeparam name="T">The type of the cached item.</typeparam>
/// <param name="key">The key of the cached item.</param>
/// <param name="item">The item.</param>
void Create<T>(string key, T item);

/// <summary>
/// Gets an item from the context cache or creates and stores it using the specified <paramref name="key" />.
/// </summary>
/// <typeparam name="T">The type of the cached item.</typeparam>
/// <param name="key">The key of the cached item.</param>
/// <param name="factory">The factory method to create the item (if it doesn't exist yet).</param>
/// <returns>
/// The item.
/// </returns>
T? GetOrCreate<T>(string key, Func<T?> factory);

/// <summary>
/// Clears all cached items on this context.
/// </summary>
void Clear();
}