Skip to content

Commit

Permalink
feat: Semantic versioning added to Manifest modification API (#41)
Browse files Browse the repository at this point in the history
* dependencies & scope registries getter added

* try get dependency/scope registry APIs

* scope registry manipulation API update

* set dependency API update

* minor refactor changes

* semantic version implementation

* Version renamed to SemanticVersion & constructor is public

* SemanticVersion public fields replaced with properties

* redundant namespace qualifier removed

* semantic version summary & minor improvements iteration

* public interface methods & properties have summary now
* additional SemanticVersion cunstructor added

* minor description fixes for Dependency class

Co-authored-by: Stanislav Osipov <[email protected]>

* minor description fixes for Manifest class

Co-authored-by: Stanislav Osipov <[email protected]>

* minor description fixes for Manifest class

Co-authored-by: Stanislav Osipov <[email protected]>

Co-authored-by: Alexey Yaremenko <[email protected]>
Co-authored-by: Stanislav Osipov <[email protected]>
  • Loading branch information
3 people authored Jul 30, 2020
1 parent 27143d0 commit 3900619
Show file tree
Hide file tree
Showing 5 changed files with 438 additions and 29 deletions.
55 changes: 52 additions & 3 deletions Editor/Manifest/Dependency.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;

namespace StansAssets.Foundation.Editor
{
Expand All @@ -8,15 +9,41 @@ namespace StansAssets.Foundation.Editor
public class Dependency
{
/// <summary>
/// The dependency name.
/// The <see cref="Dependency"/> name.
/// </summary>
public string Name { get; }

/// <summary>
/// The dependency version.
/// The <see cref="Dependency"/> version.
/// </summary>
public string Version { get; private set; }

/// <summary>
/// `true` if the <see cref="Dependency"/> has <see cref="SemanticVersion"/>; otherwise, `false`.
/// </summary>
public bool HasSemanticVersion { get; private set; }

/// <summary>
/// The <see cref="Dependency"/> semantic version.
/// </summary>
public SemanticVersion SemanticVersion { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="Dependency"/> class with provided properties.
/// </summary>
/// <param name="fullName"><see cref="Dependency"/> full name which contains name and version (e.g. '[email protected]').</param>
public Dependency(string fullName)
{
if (TryGetNameAndVersion(fullName, out string name, out string version))
{
Name = name;
Version = version;
TryAssignSemanticVersion();
}
else
throw new ArgumentException("Dependency fullName has wrong format");
}

/// <summary>
/// Initializes a new instance of the <see cref="Dependency"/> class with provided properties.
/// </summary>
Expand All @@ -26,6 +53,27 @@ public Dependency(string name, string version)
{
Name = name;
Version = version;
TryAssignSemanticVersion();
}

internal static bool TryGetNameAndVersion(string fullName, out string name, out string version)
{
name = version = null;
var dependencyData = fullName.Split('@');
if (dependencyData.Length == 2)
{
name = dependencyData[0];
version = dependencyData[1];
return true;
}
return false;
}

void TryAssignSemanticVersion()
{
HasSemanticVersion = SemanticVersion.TryCreateSemanticVersion(Version, out var semanticVersion);
if (HasSemanticVersion)
SemanticVersion = semanticVersion;
}

/// <summary>
Expand All @@ -35,6 +83,7 @@ public Dependency(string name, string version)
public void SetVersion(string version)
{
Version = version;
TryAssignSemanticVersion();
}

/// <summary>
Expand Down
157 changes: 145 additions & 12 deletions Editor/Manifest/Manifest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;

Expand Down Expand Up @@ -68,6 +69,48 @@ public void Fetch()
}
}

/// <summary>
/// Gets the <see cref="Dependency"/> associated with the specified name.
/// </summary>
/// <param name="name">The name of the <see cref="Dependency"/> to get.</param>
/// <param name="dependency">When this method returns, contains the <see cref="Dependency"/> associated with the specified name,
/// if the name is found; otherwise, `null`. This parameter is passed uninitialized.</param>
/// <returns>true if the <see cref="Manifest"/> contains a <see cref="Dependency"/> with the specified name; otherwise, false.</returns>
public bool TryGetDependency(string name, out Dependency dependency)
{
return m_Dependencies.TryGetValue(name, out dependency);
}

/// <summary>
/// Gets the <see cref="ScopeRegistry"/> associated with the specified url.
/// </summary>
/// <param name="url">The url of the <see cref="ScopeRegistry"/> to get.</param>
/// <param name="registry">When this method returns, contains the <see cref="ScopeRegistry"/> associated with the specified url,
/// if the url is found; otherwise, `null`. This parameter is passed uninitialized.</param>
/// <returns>true if the <see cref="Manifest"/> contains a <see cref="ScopeRegistry"/> with the specified url; otherwise, false.</returns>
public bool TryGetScopeRegistry(string url, out ScopeRegistry registry)
{
return m_ScopeRegistries.TryGetValue(url, out registry);
}

/// <summary>
/// Returns dependencies of the manifest.
/// </summary>
/// <returns>Dependencies of the manifest.</returns>
public IEnumerable<Dependency> GetDependencies()
{
return m_Dependencies.Values;
}

/// <summary>
/// Returns scope registries of the manifest.
/// </summary>
/// <returns>Scope registries of the manifest.</returns>
public IEnumerable<ScopeRegistry> GetScopeRegistries()
{
return m_ScopeRegistries.Values;
}

/// <summary>
/// Returns dependency by a provided name.
/// </summary>
Expand All @@ -89,29 +132,119 @@ public ScopeRegistry GetScopeRegistry(string url)
}

/// <summary>
/// Adds scope registry.
/// Sets <see cref="ScopeRegistry"/> by given url. If manifest already contains <see cref="ScopeRegistry"/> with given url,
/// existing <see cref="ScopeRegistry"/> will be overwritten.
/// </summary>
/// <param name="registry">An entry to add.</param>
public void AddScopeRegistry(ScopeRegistry registry)
/// <param name="url">Scope registry url.</param>
/// <param name="registry"><see cref="ScopeRegistry"/> to set.</param>
public void SetScopeRegistry(string url, ScopeRegistry registry)
{
if (!IsRegistryExists(registry.Url))
m_ScopeRegistries[url] = registry;
}

/// <summary>
/// Adds <see cref="ScopeRegistry"/> with the provided properties. If manifest already contains <see cref="ScopeRegistry"/> with given url,
/// provided scopes will be merged with existing <see cref="ScopeRegistry"/> scopes.
/// Name of existing <see cref="ScopeRegistry"/> won't be updated.
/// </summary>
/// <param name="url">Scope registry url.</param>
/// <param name="name">Scope registry name.</param>
/// <param name="scopes">Scope registry scopes.</param>
/// <returns>New <see cref="ScopeRegistry"/> with provided properties or existing with updated scopes, if <see cref="Manifest"/>
/// already contains <see cref="ScopeRegistry"/> with given name.</returns>
public ScopeRegistry AddScopeRegistry(string url, string name, IEnumerable<string> scopes)
{
ScopeRegistry registry;
if (!IsScopeRegistryExists(url))
{
m_ScopeRegistries.Add(registry.Url, registry);
registry = new ScopeRegistry(name, url, scopes);
SetScopeRegistry(url, registry);
}
else
{
registry = GetScopeRegistry(url);
foreach (var scope in scopes)
{
if (!registry.HasScope(scope))
{
registry.AddScope(scope);
}
}
}
return registry;
}

/// <summary>
/// Adds dependency.
/// Sets <see cref="Dependency"/> by given full name. If manifest already contains <see cref="Dependency"/> with given name, its'
/// <see cref="SemanticVersion"/>s will be taken into account. <see cref="Dependency"/> with higher <see cref="SemanticVersion"/>
/// will be placed into the <see cref="Manifest"/>.
/// </summary>
/// <param name="fullName">Dependency full name.</param>
/// <returns>New or existing <see cref="Dependency"/> with given name.</returns>
/// <exception cref="ArgumentException">Thrown when dependency fullName has wrong format</exception>
public Dependency SetOrUpdateDependency(string fullName)
{
if (Dependency.TryGetNameAndVersion(fullName, out string name, out string version))
{
return SetOrUpdateDependency(name, version);
}

throw new ArgumentException("Dependency fullName has wrong format");
}

/// <summary>
/// Sets <see cref="Dependency"/> by given name. If manifest already contains <see cref="Dependency"/> with given name, its'
/// <see cref="SemanticVersion"/>s will be taken into account. <see cref="Dependency"/> with higher <see cref="SemanticVersion"/>
/// will be placed into the <see cref="Manifest"/>.
/// </summary>
/// <param name="name">Dependency name.</param>
/// <param name="version">Dependency version.</param>
public void AddDependency(string name, string version)
/// <param name="version">Dependency name.</param>
/// <returns>New or existing <see cref="Dependency"/> with given name.</returns>
public Dependency SetOrUpdateDependency(string name, string version)
{
if (!IsDependencyExists(name))
if (IsDependencyExists(name))
{
var dependency = new Dependency(name, version);
m_Dependencies.Add(dependency.Name, dependency);
var newDependency = new Dependency(name, version);
var existingDependency = GetDependency(name);
// We have to be sure that both Dependencies have Semantic Version
if (newDependency.HasSemanticVersion && existingDependency.HasSemanticVersion)
{
if (newDependency.SemanticVersion > existingDependency.SemanticVersion)
{
// Set new Dependency because it has higher Semantic Version
SetDependency(name, version);
}
}
else
SetDependency(name, version);
}
else
SetDependency(name, version);

return GetDependency(name);
}

/// <summary>
/// Sets <see cref="Dependency"/> by given full name. If manifest already contains <see cref="Dependency"/> with given name,
/// existing <see cref="Dependency"/> will be overwritten.
/// </summary>
/// <param name="fullName">Dependency full name.</param>
public void SetDependency(string fullName)
{
var dependency = new Dependency(fullName);
m_Dependencies[dependency.Name] = dependency;
}

/// <summary>
/// Sets <see cref="Dependency"/> by given name. If manifest already contains <see cref="Dependency"/> with given name,
/// existing <see cref="Dependency"/> will be overwritten.
/// </summary>
/// <param name="name">Dependency name.</param>
/// <param name="version">Dependency version.</param>
public void SetDependency(string name, string version)
{
var dependency = new Dependency(name, version);
m_Dependencies[dependency.Name] = dependency;
}

/// <summary>
Expand Down Expand Up @@ -147,7 +280,7 @@ public void ApplyChanges()
/// </summary>
/// <param name="url">ScopeRegistry url to search for.</param>
/// <returns>`true` if scoped registry found, `false` otherwise.</returns>
public bool IsRegistryExists(string url)
public bool IsScopeRegistryExists(string url)
{
return m_ScopeRegistries.ContainsKey(url);
}
Expand Down
29 changes: 15 additions & 14 deletions Editor/Manifest/ScopeRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,36 @@ public class ScopeRegistry
/// <summary>
/// Registry scopes.
/// </summary>
public HashSet<string> Scopes { get; }
public IEnumerable<string> Scopes => m_Scopes;

readonly HashSet<string> m_Scopes;

/// <summary>
/// Initializes a new instance of <see cref="ScopeRegistry"/> class with the provided properties.
/// </summary>
/// <param name="name">Name of new scope registry.</param>
/// <param name="url">Url of new scope registry.</param>
/// <param name="scopes">Scopes of new scope registry.</param>
public ScopeRegistry(string name, string url, HashSet<string> scopes)
public ScopeRegistry(string name, string url, IEnumerable<string> scopes)
{
Name = name;
Url = url;
Scopes = scopes;
m_Scopes = new HashSet<string>(scopes);
}

/// <summary>
/// Initializes a new instance of <see cref="ScopeRegistry"/> class with the provided data.
/// </summary>
/// <param name="dictionary">Data to fill this object. Must contain <see cref="k_KeyName">name</see>,
/// <see cref="k_KeyUrl">url</see> and <see cref="k_KeyScopes">scopes</see>.</param>
/// <param name="dictionary">Data to fill this object. Must contain name, url and scopes.</param>
public ScopeRegistry(Dictionary<string, object> dictionary)
{
Name = (string) dictionary[k_KeyName];
Url = (string) dictionary[k_KeyUrl];
var scopes = (List<object>) dictionary[k_KeyScopes];
Scopes = new HashSet<string>();
m_Scopes = new HashSet<string>();
foreach (var scope in scopes)
{
Scopes.Add((string) scope);
m_Scopes.Add((string) scope);
}
}

Expand All @@ -64,7 +65,7 @@ public ScopeRegistry(Dictionary<string, object> dictionary)
/// <returns>'true' if this ScopeRegistry contains scope, `false` otherwise.</returns>
public bool HasScope(string scope)
{
return Scopes.Contains(scope);
return m_Scopes.Contains(scope);
}

/// <summary>
Expand All @@ -74,7 +75,7 @@ public bool HasScope(string scope)
public void AddScope(string scope)
{
if (!HasScope(scope))
Scopes.Add(scope);
m_Scopes.Add(scope);
}

/// <summary>
Expand All @@ -84,8 +85,8 @@ public void AddScope(string scope)
public override int GetHashCode() {
int hash = 0;
if (!string.IsNullOrEmpty(Url)) hash ^= Url.GetHashCode();
if (Scopes != null) {
foreach (var scope in Scopes) {
if (m_Scopes != null) {
foreach (var scope in m_Scopes) {
hash ^= scope.GetHashCode();
}
}
Expand All @@ -101,8 +102,8 @@ public override bool Equals(object obj)
{
return obj is ScopeRegistry other &&
Url == other.Url &&
Scopes != null && other.Scopes != null &&
new HashSet<string>(Scopes).SetEquals(other.Scopes);
m_Scopes != null && other.Scopes != null &&
m_Scopes.SetEquals(other.Scopes);
}

/// <summary>
Expand All @@ -114,7 +115,7 @@ public Dictionary<string, object> ToDictionary()
Dictionary<string,object> result = new Dictionary<string, object>();
result.Add(k_KeyName,Name);
result.Add(k_KeyUrl,Url);
result.Add(k_KeyScopes,Scopes.ToList());
result.Add(k_KeyScopes,m_Scopes.ToList());
return result;
}
}
Expand Down
Loading

0 comments on commit 3900619

Please sign in to comment.