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

Improve 'compilation required' check by checking source file dependencies #312

Merged
merged 3 commits into from
May 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 42 additions & 2 deletions src/WebCompiler/Config/Config.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;

namespace WebCompiler
Expand Down Expand Up @@ -74,15 +75,54 @@ public FileInfo GetAbsoluteOutputFile()
/// <summary>
/// Checks to see if the input file needs compilation
/// </summary>
internal bool CompilationRequired()
public bool CompilationRequired()
{
FileInfo input = GetAbsoluteInputFile();
FileInfo output = GetAbsoluteOutputFile();

if (!output.Exists)
return true;

return input.LastWriteTimeUtc > output.LastWriteTimeUtc;
if (input.LastWriteTimeUtc > output.LastWriteTimeUtc)
return true;

return HasDependenciesNewerThanOutput(input, output);
}

private bool HasDependenciesNewerThanOutput(FileInfo input, FileInfo output)
{
var projectRoot = new FileInfo(FileName).DirectoryName;
var dependencies = DependencyService.GetDependencies(projectRoot, input.FullName);

if (dependencies != null)
{
string key = input.FullName.ToLowerInvariant();
return CheckForNewerDependenciesRecursively(key, dependencies, output);
}

return false;
}

private bool CheckForNewerDependenciesRecursively(string key, Dictionary<string, Dependencies> dependencies, FileInfo output)
{
if (!dependencies.ContainsKey(key))
return false;

foreach (var file in dependencies[key].DependentOn.ToArray())
{
var fileInfo = new FileInfo(file);

if (!fileInfo.Exists)
continue;

if (fileInfo.LastWriteTimeUtc > output.LastWriteTimeUtc)
return true;

if (CheckForNewerDependenciesRecursively(file, dependencies, output))
return true;
}

return false;
}

/// <summary>
Expand Down
120 changes: 120 additions & 0 deletions src/WebCompilerTest/Config/ConfigTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace WebCompilerTest.Config
{
[TestClass]
public class ConfigTest
{
private WebCompiler.Config _config;

private const string dummyConfigFile = "../../artifacts/config/dummy.json";
private const string inputFile = "../../artifacts/config/compilationrequired.scss";
private const string outputFile = "../../artifacts/config/compilationrequired.css";
private const string firstLevelDependencyFile = "../../artifacts/config/dependencies/foo.scss";
private const string secondLevelDependencyFile = "../../artifacts/config/dependencies/sub/bar.scss";

private readonly FileInfo _inputFileInfo = new FileInfo(inputFile);
private readonly FileInfo _outputFileInfo = new FileInfo(outputFile);
private readonly FileInfo _firstLevelDependencyFileInfo = new FileInfo(firstLevelDependencyFile);
private readonly FileInfo _secondLevelDependencyFileInfo = new FileInfo(secondLevelDependencyFile);

private readonly Dictionary<FileInfo, DateTime> _originalLastWriteTimes = new Dictionary<FileInfo, DateTime>();

private DateTime _olderWriteTime;
private DateTime _newerWriteTime;

[TestInitialize]
public void Setup()
{
var configFileInfo = new FileInfo(dummyConfigFile);

_config = new WebCompiler.Config
{
FileName = configFileInfo.FullName,
InputFile = _inputFileInfo.FullName,
OutputFile = _outputFileInfo.FullName
};

// Create dummy output file, only last write time is checked
File.WriteAllText(outputFile, "");

// Backup last write times for cleanup
_originalLastWriteTimes.Add(_inputFileInfo, _inputFileInfo.LastWriteTimeUtc);
_originalLastWriteTimes.Add(_firstLevelDependencyFileInfo, _firstLevelDependencyFileInfo.LastWriteTimeUtc);
_originalLastWriteTimes.Add(_secondLevelDependencyFileInfo, _secondLevelDependencyFileInfo.LastWriteTimeUtc);

var utcNow = DateTime.UtcNow;

_inputFileInfo.LastWriteTimeUtc = utcNow;
_outputFileInfo.LastWriteTimeUtc = utcNow;
_firstLevelDependencyFileInfo.LastWriteTimeUtc = utcNow;
_secondLevelDependencyFileInfo.LastWriteTimeUtc = utcNow;

_olderWriteTime = utcNow.AddHours(-1);
_newerWriteTime = utcNow.AddHours(1);
}

[TestCleanup]
public void Cleanup()
{
if (File.Exists(outputFile))
File.Delete(outputFile);

foreach (var entry in _originalLastWriteTimes)
{
entry.Key.LastWriteTimeUtc = entry.Value;
}
}

[TestMethod, TestCategory("Config")]
public void CompilationRequired_OutputNewerThanEverything_DoesNotRequireCompilation()
{
_inputFileInfo.LastWriteTimeUtc = _olderWriteTime;
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;

var compilationRequired = _config.CompilationRequired();

Assert.AreEqual(false, compilationRequired);
}

[TestMethod, TestCategory("Config")]
public void CompilationRequired_InputNewerThanOutput_RequiresCompilation()
{
_inputFileInfo.LastWriteTimeUtc = _newerWriteTime;
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;

var compilationRequired = _config.CompilationRequired();

Assert.AreEqual(true, compilationRequired);
}

[TestMethod, TestCategory("Config")]
public void CompilationRequired_FirstLevelDependencyNewerThanOutput_RequiresCompilation()
{
_inputFileInfo.LastWriteTimeUtc = _olderWriteTime;
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _newerWriteTime;
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;

var compilationRequired = _config.CompilationRequired();

Assert.AreEqual(true, compilationRequired);
}

[TestMethod, TestCategory("Config")]
public void CompilationRequired_SecondLevelDependencyNewerThanOutput_RequiresCompilation()
{
_inputFileInfo.LastWriteTimeUtc = _olderWriteTime;
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _newerWriteTime;

var compilationRequired = _config.CompilationRequired();

Assert.AreEqual(true, compilationRequired);
}
}
}
4 changes: 4 additions & 0 deletions src/WebCompilerTest/WebCompilerTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<Compile Include="Compile\ScssOptionsTest.cs" />
<Compile Include="Compile\ScssTest.cs" />
<Compile Include="Compile\LessTest.cs" />
<Compile Include="Config\ConfigTest.cs" />
<Compile Include="Minify\JavaScriptOptionsTests.cs" />
<Compile Include="Minify\CssOptionsTests.cs" />
<Compile Include="Minify\CssMinifierTests.cs" />
Expand All @@ -74,6 +75,9 @@
</ItemGroup>
<ItemGroup>
<Content Include="artifacts\less\sub\logo.png" />
<None Include="artifacts\config\compilationrequired.scss" />
<None Include="artifacts\config\dependencies\sub\bar.scss" />
<None Include="artifacts\config\dependencies\foo.scss" />
<None Include="artifacts\handlebarsconfigPartial.json" />
<None Include="artifacts\handlebarsconfig.json" />
<None Include="artifacts\coffeeconfig.json.defaults" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "dependencies/foo";
1 change: 1 addition & 0 deletions src/WebCompilerTest/artifacts/config/dependencies/foo.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "sub/bar";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@