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

feat(copy): introduces CopyGraphOptions with events support #145

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6817504
feat(copy): support mounting existing descriptors from other reposito…
leonardochaia Sep 26, 2024
b453fbc
fix: standard header
leonardochaia Sep 26, 2024
6a7a1e9
chore: adds repository tests
leonardochaia Oct 3, 2024
88c6793
fix: copy test
leonardochaia Oct 17, 2024
4c52467
Merge branch 'main' into feat/improve-copy-performance
leonardochaia Oct 17, 2024
36342c9
Merge branch 'main' into feat/improve-copy-performance
leonardochaia Nov 11, 2024
dbe3509
chore: removes mounting support to be implemented in separate PR
leonardochaia Nov 11, 2024
571820c
refactor: renames class and events as per review
leonardochaia Nov 11, 2024
138120e
chore: adds copy tests
leonardochaia Nov 11, 2024
77e8079
chore: adds overload to prevent breaking change
leonardochaia Nov 11, 2024
06fd442
chore: introduces overloads to keep previous signature on CopyGraphOp…
leonardochaia Nov 11, 2024
5787c04
fix: copy signature
leonardochaia Nov 12, 2024
c9be0a2
Merge branch 'main' into feat/improve-copy-performance
leonardochaia Nov 12, 2024
77ba179
refactor: introduces CopyOptions
leonardochaia Nov 13, 2024
ecaf1b1
Merge remote-tracking branch 'origin/feat/improve-copy-performance' i…
leonardochaia Nov 13, 2024
de9ee0d
Merge branch 'main' into feat/improve-copy-performance
leonardochaia Nov 13, 2024
6ef7e74
chore: adds license
leonardochaia Nov 13, 2024
be7b1c5
Merge remote-tracking branch 'origin/feat/improve-copy-performance' i…
leonardochaia Nov 13, 2024
a12ff78
chore: adds more tests from oras-go
leonardochaia Nov 13, 2024
a7a1baf
chore: adds tests from oras-go
leonardochaia Nov 13, 2024
493a8d9
doc: adds comments to new option structs
leonardochaia Nov 25, 2024
9e40655
refactor: makes copy events async
leonardochaia Nov 25, 2024
68220bd
feat: introduces `InvokeAsync` extension method to support asynchrono…
leonardochaia Nov 26, 2024
e35fc7e
refactor: delegate InvokeAsync to execute handlers in parallel
leonardochaia Nov 29, 2024
827f62b
refactor: Copy events to include sync and async variants.
leonardochaia Nov 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions src/OrasProject.Oras/CopyGraphOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,44 @@
// limitations under the License.

using System;
using System.Threading.Tasks;
using OrasProject.Oras.Oci;

namespace OrasProject.Oras;

/// <summary>
/// CopyGraphOptions contains parameters for <see cref="Extensions.CopyGraphAsync(OrasProject.Oras.ITarget,OrasProject.Oras.ITarget,OrasProject.Oras.Oci.Descriptor,System.Threading.CancellationToken)"/>
/// </summary>
public struct CopyGraphOptions
leonardochaia marked this conversation as resolved.
Show resolved Hide resolved
{
public event Action<Descriptor> PreCopy;

public event Action<Descriptor> PostCopy;

public event Action<Descriptor> CopySkipped;

internal void OnPreCopy(Descriptor descriptor)
/// <summary>
/// PreCopy handles the current descriptor before it is copied.
/// </summary>
public event Func<Descriptor, Task> PreCopy;

/// <summary>
/// PostCopy handles the current descriptor after it is copied.
/// </summary>
public event Func<Descriptor, Task> PostCopy;

/// <summary>
/// CopySkipped will be called when the sub-DAG rooted by the current node
/// is skipped.
/// </summary>
public event Func<Descriptor, Task> CopySkipped;

internal Task OnPreCopyAsync(Descriptor descriptor)
{
PreCopy?.Invoke(descriptor);
return PreCopy?.Invoke(descriptor) ?? Task.CompletedTask;
}

internal void OnPostCopy(Descriptor descriptor)
internal Task OnPostCopyAsync(Descriptor descriptor)
{
PostCopy?.Invoke(descriptor);
return PostCopy?.Invoke(descriptor) ?? Task.CompletedTask;
}

internal void OnCopySkipped(Descriptor descriptor)
internal Task OnCopySkippedAsync(Descriptor descriptor)
{
CopySkipped?.Invoke(descriptor);
return CopySkipped?.Invoke(descriptor) ?? Task.CompletedTask;
}
leonardochaia marked this conversation as resolved.
Show resolved Hide resolved
}
3 changes: 3 additions & 0 deletions src/OrasProject.Oras/CopyOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace OrasProject.Oras;

/// <summary>
/// CopyOptions contains parameters for <see cref="Extensions.CopyAsync(OrasProject.Oras.ITarget,string,OrasProject.Oras.ITarget,string,System.Threading.CancellationToken)"/>
/// </summary>
public struct CopyOptions
{
public CopyGraphOptions CopyGraphOptions;
Expand Down
12 changes: 6 additions & 6 deletions src/OrasProject.Oras/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ public static Task<Descriptor> CopyAsync(this ITarget src, string srcRef, ITarge
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static async Task<Descriptor> CopyAsync(this ITarget src, string srcRef, ITarget dst, string dstRef, CopyOptions? copyOptions = default, CancellationToken cancellationToken = default)
public static async Task<Descriptor> CopyAsync(this ITarget src, string srcRef, ITarget dst, string dstRef, CopyOptions copyOptions = default, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(dstRef))
{
dstRef = srcRef;
}
var root = await src.ResolveAsync(srcRef, cancellationToken).ConfigureAwait(false);
await src.CopyGraphAsync(dst, root, copyOptions?.CopyGraphOptions, cancellationToken).ConfigureAwait(false);
await src.CopyGraphAsync(dst, root, copyOptions.CopyGraphOptions, cancellationToken).ConfigureAwait(false);
await dst.TagAsync(root, dstRef, cancellationToken).ConfigureAwait(false);
return root;
}
Expand All @@ -73,12 +73,12 @@ public static Task CopyGraphAsync(this ITarget src, ITarget dst, Descriptor node
return src.CopyGraphAsync(dst, node, new CopyGraphOptions(), cancellationToken);
}

public static async Task CopyGraphAsync(this ITarget src, ITarget dst, Descriptor node, CopyGraphOptions? copyGraphOptions = default, CancellationToken cancellationToken = default)
public static async Task CopyGraphAsync(this ITarget src, ITarget dst, Descriptor node, CopyGraphOptions copyGraphOptions = default, CancellationToken cancellationToken = default)
{
// check if node exists in target
if (await dst.ExistsAsync(node, cancellationToken).ConfigureAwait(false))
{
copyGraphOptions?.OnCopySkipped(node);
await copyGraphOptions.OnCopySkippedAsync(node);
leonardochaia marked this conversation as resolved.
Show resolved Hide resolved
return;
}

Expand All @@ -92,12 +92,12 @@ public static async Task CopyGraphAsync(this ITarget src, ITarget dst, Descripto
}

// perform the copy
copyGraphOptions?.OnPreCopy(node);
await copyGraphOptions.OnPreCopyAsync(node);
var dataStream = await src.FetchAsync(node, cancellationToken).ConfigureAwait(false);
await dst.PushAsync(node, dataStream, cancellationToken).ConfigureAwait(false);

// we copied it
copyGraphOptions?.OnPostCopy(node);
await copyGraphOptions.OnPostCopyAsync(node);
}
}

22 changes: 17 additions & 5 deletions tests/OrasProject.Oras.Tests/CopyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,19 @@ void GenerateManifest(Descriptor config, params Descriptor[] layers)
// Tag root node in source
await src.TagAsync(root, refTag, CancellationToken.None);

// Prepare copy options with OnCopySkipped
// Prepare copy options with OnCopySkippedAsync
var skippedCount = 0;
var copyOptions = new CopyOptions
{
CopyGraphOptions = new CopyGraphOptions()
{
}
};
copyOptions.CopyGraphOptions.CopySkipped += d => skippedCount++;
copyOptions.CopyGraphOptions.CopySkipped += d =>
{
skippedCount++;
return Task.CompletedTask;
};

// Copy with the source tag
var gotDesc = await src.CopyAsync(refTag, dst, "", copyOptions, CancellationToken.None);
Expand All @@ -229,7 +233,7 @@ void GenerateManifest(Descriptor config, params Descriptor[] layers)
gotDesc = await dst.ResolveAsync(newTag, CancellationToken.None);
Assert.Equal(root, gotDesc);

// Verify the OnCopySkipped invocation count
// Verify the OnCopySkippedAsync invocation count
Assert.Equal(1, skippedCount);
}

Expand Down Expand Up @@ -419,8 +423,16 @@ void GenerateIndex(params Descriptor[] manifests)
}
};

copyOptions.CopyGraphOptions.PreCopy += d => preCopyCount++;
copyOptions.CopyGraphOptions.PostCopy += d => postCopyCount++;
copyOptions.CopyGraphOptions.PreCopy += d =>
{
preCopyCount++;
return Task.CompletedTask;
};
copyOptions.CopyGraphOptions.PostCopy += d =>
{
postCopyCount++;
return Task.CompletedTask;
};

var expectedDesc = descs[6];
var gotDesc = await src.CopyAsync(refTag, dst, "", copyOptions, cancellationToken);
Expand Down
Loading