Skip to content

Commit

Permalink
Fix for cake-build#2099. Also matches RFC-02 with a few changes.
Browse files Browse the repository at this point in the history
Differences from RFC-02
1) The cache argument was removed.  A new section was added to the cake.config file [Cache] with 2 possible properties Enabled and Path.  Enabled defaults to false and Path defaults cache under the tools folder.
2) I originally used a time stamp to determine if the cache was valid or not.  I have changed this to use a hash like pull request 2584 used.  I did change it to use SHA1CryptoServiceProvider instead of MD5 since MD5 is not FIPS compliant.
  • Loading branch information
tstewart65 authored and devlead committed Dec 3, 2019
1 parent 8539b72 commit daeecbe
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 54 deletions.
8 changes: 7 additions & 1 deletion src/Cake.Core/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ public static class Settings
public const string ShowProcessCommandLine = "Settings_ShowProcessCommandLine";
}

public static class Cache
{
public const string Enabled = "Cache_Enabled";
public const string Path = "Cache_Path";
}

public static class Paths
{
public const string Tools = "Paths_Tools";
public const string Addins = "Paths_Addins";
public const string Modules = "Paths_Modules";
}
}
}
}
20 changes: 19 additions & 1 deletion src/Cake.Core/Extensions/CakeConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,23 @@ public static DirectoryPath GetModulePath(this ICakeConfiguration configuration,
var toolPath = configuration.GetToolPath(defaultRoot, environment);
return toolPath.Combine("Modules").Collapse();
}

/// <summary>
/// Gets the script cache directory path.
/// </summary>
/// <param name="configuration">The Cake configuration.</param>
/// <param name="defaultRoot">The default root path.</param>
/// <param name="environment">The environment.</param>
/// <returns>The script cache directory path.</returns>
public static DirectoryPath GetScriptCachePath(this ICakeConfiguration configuration, DirectoryPath defaultRoot, ICakeEnvironment environment)
{
var cachePath = configuration.GetValue(Constants.Cache.Path);
if (!string.IsNullOrWhiteSpace(cachePath))
{
return new DirectoryPath(cachePath).MakeAbsolute(environment);
}
var toolPath = configuration.GetToolPath(defaultRoot, environment);
return toolPath.Combine("cache").Collapse();
}
}
}
}
45 changes: 45 additions & 0 deletions src/Cake.Core/Utilities/DisposableStopwatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Diagnostics;

using Cake.Core.Diagnostics;

namespace Cake.Core.Utilities
{
/// <summary>
/// Disposable Stopwatch used for timing how long a section of code takes and writing the result to the log.
/// </summary>
public class DisposableStopwatch : IDisposable
{
private readonly Stopwatch _sw;
private readonly ICakeLog _log;
private readonly string _message;

/// <summary>
/// Initializes a new instance of the <see cref="DisposableStopwatch"/> class.
/// </summary>
/// <param name="log">logger.</param>
/// <param name="message">message.</param>
public DisposableStopwatch(ICakeLog log, string message)
{
_log = log;
_message = message;
_sw = Stopwatch.StartNew();
}

/// <summary>
/// Dispose.
/// </summary>
public void Dispose()
{
if (_sw != null)
{
_sw.Stop();
_log.Verbose("{0}: {1}ms", _message, _sw.ElapsedMilliseconds);
}
}
}
}
65 changes: 65 additions & 0 deletions src/Cake.Core/Utilities/FastHash.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace Cake.Core.Utilities
{
/// <summary>
/// Optimized hash generator. Using SHA1CryptoServiceProvider since it is FIPS compliant.
/// </summary>
public static class FastHash
{
/// <summary>
/// Generates a hash of the passed byte arrays.
/// </summary>
/// <param name="input">The binary data to hash.</param>
/// <returns>The hash value.</returns>
public static string GenerateHash(byte[] input)
{
using (var sha1 = new SHA1CryptoServiceProvider())
{
sha1.TransformBlock(input, 0, input.Length, input, 0);

// Just finalize with empty bytes so we don't have to iterate over the enumerable multiple times
sha1.TransformFinalBlock(Encoding.UTF8.GetBytes(string.Empty), 0, 0);
// Convert to hex string; This method is supposedly faster than the usual StringBuilder approach
return ConvertBits(sha1.Hash);
}
}

/// <summary>
/// Generates a hash of the passed byte arrays.
/// </summary>
/// <param name="inputs">The binary data to hash.</param>
/// <returns>The hash value.</returns>
public static string GenerateHash(IEnumerable<byte[]> inputs)
{
using (var sha1 = new SHA1CryptoServiceProvider())
{
foreach (var input in inputs)
{
sha1.TransformBlock(input, 0, input.Length, input, 0);
}

// Just finalize with empty bytes so we don't have to iterate over the enumerable multiple times
sha1.TransformFinalBlock(Encoding.UTF8.GetBytes(string.Empty), 0, 0);
// Convert to hex string; This method is supposedly faster than the usual StringBuilder approach
return ConvertBits(sha1.Hash);
}
}

private static string ConvertBits(byte[] hash)
{
return BitConverter.ToString(hash)
// without dashes
.Replace("-", string.Empty)
// make lowercase
.ToLower();
}
}
}
5 changes: 5 additions & 0 deletions src/Cake/Arguments/ArgumentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ private bool ParseOption(string name, string value, CakeOptions options)
options.Exclusive = ParseBooleanValue(value);
}

if (name.Equals("recompile", StringComparison.OrdinalIgnoreCase))
{
options.ForceCacheRecompile = ParseBooleanValue(value);
}

if (options.Arguments.ContainsKey(name))
{
_log.Error("Multiple arguments with the same name ({0}).", name);
Expand Down
5 changes: 5 additions & 0 deletions src/Cake/CakeOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ public sealed class CakeOptions
/// </summary>
public bool Exclusive { get; set; }

/// <summary>
/// Gets or sets a value indicating whether or not to recompile the script if a cached output exists.
/// </summary>
public bool ForceCacheRecompile { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="CakeOptions"/> class.
/// </summary>
Expand Down
7 changes: 5 additions & 2 deletions src/Cake/Scripting/Roslyn/RoslynScriptEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Cake.Core.Configuration;
using Cake.Core.Diagnostics;
using Cake.Core.Reflection;
using Cake.Core.Scripting;
Expand All @@ -11,19 +12,21 @@ namespace Cake.Scripting.Roslyn
internal sealed class RoslynScriptEngine : IScriptEngine
{
private readonly CakeOptions _options;
private readonly ICakeConfiguration _configuration;
private readonly IAssemblyLoader _loader;
private readonly ICakeLog _log;

public RoslynScriptEngine(CakeOptions options, IAssemblyLoader loader, ICakeLog log)
public RoslynScriptEngine(CakeOptions options, ICakeConfiguration configuration, IAssemblyLoader loader, ICakeLog log)
{
_options = options;
_configuration = configuration;
_loader = loader;
_log = log;
}

public IScriptSession CreateSession(IScriptHost host)
{
return new RoslynScriptSession(host, _loader, _log, _options);
return new RoslynScriptSession(host, _loader, _log, _options, _configuration);
}
}
}
Loading

0 comments on commit daeecbe

Please sign in to comment.