-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ensure Gradle home is completely empty for build, but sync download c…
…ache for performance
- Loading branch information
Showing
6 changed files
with
286 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
UET/Redpoint.Uet.BuildPipeline/BuildGraph/Gradle/DefaultGradleWorkspace.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
namespace Redpoint.Uet.BuildPipeline.BuildGraph.Gradle | ||
{ | ||
using Microsoft.Extensions.Logging; | ||
using Redpoint.IO; | ||
using Redpoint.Uet.Workspace; | ||
using Redpoint.Uet.Workspace.Descriptors; | ||
using System; | ||
using System.Threading.Tasks; | ||
|
||
internal class DefaultGradleWorkspace : IGradleWorkspace | ||
{ | ||
private readonly IDynamicWorkspaceProvider _dynamicWorkspaceProvider; | ||
private readonly ILogger<DefaultGradleWorkspace> _logger; | ||
|
||
public DefaultGradleWorkspace( | ||
IDynamicWorkspaceProvider dynamicWorkspaceProvider, | ||
ILogger<DefaultGradleWorkspace> logger) | ||
{ | ||
_dynamicWorkspaceProvider = dynamicWorkspaceProvider; | ||
_logger = logger; | ||
} | ||
|
||
public async Task<GradleWorkspaceInstance> GetGradleWorkspaceInstance(CancellationToken cancellationToken) | ||
{ | ||
IWorkspace? gradleDownloadCache = null; | ||
IWorkspace? gradleTemporaryWorkspace = null; | ||
|
||
var ok = false; | ||
try | ||
{ | ||
gradleDownloadCache = await _dynamicWorkspaceProvider.GetWorkspaceAsync(new TemporaryWorkspaceDescriptor | ||
{ | ||
Name = "GradleDownloadCache", | ||
}, cancellationToken).ConfigureAwait(false); | ||
|
||
var gradleTemporaryWorkspaceAttempt = 0; | ||
do | ||
{ | ||
gradleTemporaryWorkspace = await _dynamicWorkspaceProvider.GetWorkspaceAsync(new TemporaryWorkspaceDescriptor | ||
{ | ||
Name = $"GradleHome_{Environment.ProcessId}_{gradleTemporaryWorkspaceAttempt}", | ||
}, cancellationToken).ConfigureAwait(false); | ||
|
||
_logger.LogInformation($"Checking the following Gradle home: {gradleTemporaryWorkspace.Path}"); | ||
|
||
// If the gradle home has any files in it, delete them. The gradle home must be wiped out before/after each | ||
// build. | ||
try | ||
{ | ||
foreach (var entry in new DirectoryInfo(gradleTemporaryWorkspace.Path).GetFileSystemInfos()) | ||
{ | ||
_logger.LogInformation($"Deleting file/directory from previous Gradle home: {entry.FullName}"); | ||
if (entry is DirectoryInfo directory) | ||
{ | ||
directory.Delete(true); | ||
} | ||
else | ||
{ | ||
entry.Delete(); | ||
} | ||
|
||
cancellationToken.ThrowIfCancellationRequested(); | ||
} | ||
} | ||
catch | ||
{ | ||
_logger.LogInformation($"Unable to use that Gradle home as one or more existing files/directories could not be removed."); | ||
gradleTemporaryWorkspaceAttempt++; | ||
await gradleTemporaryWorkspace.DisposeAsync().ConfigureAwait(false); | ||
gradleTemporaryWorkspace = null; | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
continue; | ||
} | ||
|
||
// We have a Gradle home we can use. | ||
break; | ||
} while (true); | ||
|
||
_logger.LogInformation($"Using the following Gradle home: {gradleTemporaryWorkspace.Path}"); | ||
|
||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
||
var centralCacheSafeToUse = Path.Combine(gradleDownloadCache.Path, "safe-to-use"); | ||
var centralCacheModules2 = Path.Combine(gradleDownloadCache.Path, "modules-2"); | ||
var centralCacheWrapper = Path.Combine(gradleDownloadCache.Path, "wrapper"); | ||
if (File.Exists(centralCacheSafeToUse) && Directory.Exists(centralCacheModules2)) | ||
{ | ||
var homeCacheModules2 = Path.Combine(gradleTemporaryWorkspace.Path, "caches", "modules-2"); | ||
var homeCacheWrapper = Path.Combine(gradleTemporaryWorkspace.Path, "wrapper"); | ||
|
||
_logger.LogInformation($"Copying the existing Gradle download cache from '{centralCacheModules2}' to '{homeCacheModules2}': {gradleTemporaryWorkspace.Path}"); | ||
await DirectoryAsync.CopyAsync(centralCacheModules2, homeCacheModules2, true); | ||
|
||
_logger.LogInformation($"Copying the existing Gradle wrapper from '{centralCacheWrapper}' to '{homeCacheWrapper}': {gradleTemporaryWorkspace.Path}"); | ||
await DirectoryAsync.CopyAsync(centralCacheWrapper, homeCacheWrapper, true); | ||
} | ||
|
||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
||
ok = true; | ||
return new GradleWorkspaceInstance(_logger, gradleDownloadCache, gradleTemporaryWorkspace); | ||
} | ||
finally | ||
{ | ||
if (!ok) | ||
{ | ||
if (gradleDownloadCache != null) | ||
{ | ||
try | ||
{ | ||
await gradleDownloadCache.DisposeAsync().ConfigureAwait(false); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogWarning($"Failed to release Gradle download cache: {ex}"); | ||
} | ||
} | ||
|
||
if (gradleTemporaryWorkspace != null) | ||
{ | ||
try | ||
{ | ||
await gradleTemporaryWorkspace.DisposeAsync().ConfigureAwait(false); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogWarning($"Failed to release Gradle home: {ex}"); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
121 changes: 121 additions & 0 deletions
121
UET/Redpoint.Uet.BuildPipeline/BuildGraph/Gradle/GradleWorkspaceInstance.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
namespace Redpoint.Uet.BuildPipeline.BuildGraph.Gradle | ||
{ | ||
using Microsoft.Extensions.Logging; | ||
using Redpoint.IO; | ||
using Redpoint.Uet.Workspace; | ||
using System; | ||
using System.Threading.Tasks; | ||
|
||
internal class GradleWorkspaceInstance : IAsyncDisposable | ||
{ | ||
private readonly ILogger _logger; | ||
private readonly IWorkspace _gradleDownloadCache; | ||
private readonly IWorkspace _gradleTemporaryWorkspace; | ||
private bool _buildSuccessful; | ||
|
||
public GradleWorkspaceInstance( | ||
ILogger logger, | ||
IWorkspace gradleDownloadCache, | ||
IWorkspace gradleTemporaryWorkspace) | ||
{ | ||
_logger = logger; | ||
_gradleDownloadCache = gradleDownloadCache; | ||
_gradleTemporaryWorkspace = gradleTemporaryWorkspace; | ||
_buildSuccessful = false; | ||
} | ||
|
||
public string GradleHomePath => _gradleTemporaryWorkspace.Path; | ||
|
||
public void MarkBuildAsSuccessful() | ||
{ | ||
_buildSuccessful = true; | ||
} | ||
|
||
public async ValueTask DisposeAsync() | ||
{ | ||
if (_buildSuccessful) | ||
{ | ||
// If the build was successful, copy the Gradle download cache back. | ||
var centralCacheSafeToUse = Path.Combine(_gradleDownloadCache.Path, "safe-to-use"); | ||
var centralCacheModules2 = Path.Combine(_gradleDownloadCache.Path, "modules-2"); | ||
var centralCacheWrapper = Path.Combine(_gradleDownloadCache.Path, "wrapper"); | ||
|
||
var homeCacheModules2 = Path.Combine(_gradleTemporaryWorkspace.Path, "caches", "modules-2"); | ||
var homeCacheWrapper = Path.Combine(_gradleTemporaryWorkspace.Path, "wrapper"); | ||
|
||
try | ||
{ | ||
_logger.LogInformation($"Removing existing download cache so we can copy across the new version from the build: {_gradleDownloadCache.Path}"); | ||
if (File.Exists(centralCacheSafeToUse)) | ||
{ | ||
File.Delete(centralCacheSafeToUse); | ||
} | ||
|
||
do | ||
{ | ||
try | ||
{ | ||
if (Directory.Exists(homeCacheModules2)) | ||
{ | ||
await DirectoryAsync.DeleteAsync(centralCacheModules2, true); | ||
} | ||
if (Directory.Exists(homeCacheWrapper)) | ||
{ | ||
await DirectoryAsync.DeleteAsync(centralCacheWrapper, true); | ||
} | ||
break; | ||
} | ||
catch (IOException ex) when (ex.Message.Contains("The directory is not empty.", StringComparison.Ordinal)) | ||
{ | ||
_logger.LogInformation("Can't remove existing central cache yet, trying again in 1 second..."); | ||
await Task.Delay(1000); | ||
continue; | ||
} | ||
} | ||
while (true); | ||
|
||
if (Directory.Exists(homeCacheModules2)) | ||
{ | ||
_logger.LogInformation($"Copying home Gradle download cache from '{homeCacheModules2}' to central download cache at '{centralCacheModules2}'."); | ||
await DirectoryAsync.CopyAsync(homeCacheModules2, centralCacheModules2, true); | ||
} | ||
|
||
if (Directory.Exists(homeCacheWrapper)) | ||
{ | ||
_logger.LogInformation($"Copying home Gradle wrapper from '{homeCacheWrapper}' to central download cache at '{centralCacheWrapper}'."); | ||
await DirectoryAsync.CopyAsync(homeCacheWrapper, centralCacheWrapper, true); | ||
} | ||
|
||
_logger.LogInformation($"Marking central download cache as safe to use."); | ||
File.WriteAllText(centralCacheSafeToUse, "ok"); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogWarning($"Failed to copy download cache back to central download cache; it will not be used until a successful copy occurs again: {ex}"); | ||
} | ||
} | ||
else | ||
{ | ||
_logger.LogInformation($"Not syncing download cache to central download cache as the build was not successful."); | ||
} | ||
|
||
try | ||
{ | ||
await _gradleDownloadCache.DisposeAsync().ConfigureAwait(false); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogWarning($"Failed to release Gradle download cache: {ex}"); | ||
} | ||
|
||
try | ||
{ | ||
await _gradleTemporaryWorkspace.DisposeAsync().ConfigureAwait(false); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogWarning($"Failed to release Gradle home: {ex}"); | ||
} | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
UET/Redpoint.Uet.BuildPipeline/BuildGraph/Gradle/IGradleWorkspace.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace Redpoint.Uet.BuildPipeline.BuildGraph.Gradle | ||
{ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
internal interface IGradleWorkspace | ||
{ | ||
Task<GradleWorkspaceInstance> GetGradleWorkspaceInstance(CancellationToken cancellationToken); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters