Skip to content

Commit b565092

Browse files
Krusenmadskristensen
authored andcommitted
Improve 'compilation required' check by checking source file dependencies (#312)
* Check last write time of all dependent files * Add unit tests for Config.CompilationRequired * Add file exists check
1 parent d85662d commit b565092

File tree

6 files changed

+169
-2
lines changed

6 files changed

+169
-2
lines changed

src/WebCompiler/Config/Config.cs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using System.IO;
3+
using System.Linq;
34
using Newtonsoft.Json;
45

56
namespace WebCompiler
@@ -74,15 +75,54 @@ public FileInfo GetAbsoluteOutputFile()
7475
/// <summary>
7576
/// Checks to see if the input file needs compilation
7677
/// </summary>
77-
internal bool CompilationRequired()
78+
public bool CompilationRequired()
7879
{
7980
FileInfo input = GetAbsoluteInputFile();
8081
FileInfo output = GetAbsoluteOutputFile();
8182

8283
if (!output.Exists)
8384
return true;
8485

85-
return input.LastWriteTimeUtc > output.LastWriteTimeUtc;
86+
if (input.LastWriteTimeUtc > output.LastWriteTimeUtc)
87+
return true;
88+
89+
return HasDependenciesNewerThanOutput(input, output);
90+
}
91+
92+
private bool HasDependenciesNewerThanOutput(FileInfo input, FileInfo output)
93+
{
94+
var projectRoot = new FileInfo(FileName).DirectoryName;
95+
var dependencies = DependencyService.GetDependencies(projectRoot, input.FullName);
96+
97+
if (dependencies != null)
98+
{
99+
string key = input.FullName.ToLowerInvariant();
100+
return CheckForNewerDependenciesRecursively(key, dependencies, output);
101+
}
102+
103+
return false;
104+
}
105+
106+
private bool CheckForNewerDependenciesRecursively(string key, Dictionary<string, Dependencies> dependencies, FileInfo output)
107+
{
108+
if (!dependencies.ContainsKey(key))
109+
return false;
110+
111+
foreach (var file in dependencies[key].DependentOn.ToArray())
112+
{
113+
var fileInfo = new FileInfo(file);
114+
115+
if (!fileInfo.Exists)
116+
continue;
117+
118+
if (fileInfo.LastWriteTimeUtc > output.LastWriteTimeUtc)
119+
return true;
120+
121+
if (CheckForNewerDependenciesRecursively(file, dependencies, output))
122+
return true;
123+
}
124+
125+
return false;
86126
}
87127

88128
/// <summary>
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
6+
namespace WebCompilerTest.Config
7+
{
8+
[TestClass]
9+
public class ConfigTest
10+
{
11+
private WebCompiler.Config _config;
12+
13+
private const string dummyConfigFile = "../../artifacts/config/dummy.json";
14+
private const string inputFile = "../../artifacts/config/compilationrequired.scss";
15+
private const string outputFile = "../../artifacts/config/compilationrequired.css";
16+
private const string firstLevelDependencyFile = "../../artifacts/config/dependencies/foo.scss";
17+
private const string secondLevelDependencyFile = "../../artifacts/config/dependencies/sub/bar.scss";
18+
19+
private readonly FileInfo _inputFileInfo = new FileInfo(inputFile);
20+
private readonly FileInfo _outputFileInfo = new FileInfo(outputFile);
21+
private readonly FileInfo _firstLevelDependencyFileInfo = new FileInfo(firstLevelDependencyFile);
22+
private readonly FileInfo _secondLevelDependencyFileInfo = new FileInfo(secondLevelDependencyFile);
23+
24+
private readonly Dictionary<FileInfo, DateTime> _originalLastWriteTimes = new Dictionary<FileInfo, DateTime>();
25+
26+
private DateTime _olderWriteTime;
27+
private DateTime _newerWriteTime;
28+
29+
[TestInitialize]
30+
public void Setup()
31+
{
32+
var configFileInfo = new FileInfo(dummyConfigFile);
33+
34+
_config = new WebCompiler.Config
35+
{
36+
FileName = configFileInfo.FullName,
37+
InputFile = _inputFileInfo.FullName,
38+
OutputFile = _outputFileInfo.FullName
39+
};
40+
41+
// Create dummy output file, only last write time is checked
42+
File.WriteAllText(outputFile, "");
43+
44+
// Backup last write times for cleanup
45+
_originalLastWriteTimes.Add(_inputFileInfo, _inputFileInfo.LastWriteTimeUtc);
46+
_originalLastWriteTimes.Add(_firstLevelDependencyFileInfo, _firstLevelDependencyFileInfo.LastWriteTimeUtc);
47+
_originalLastWriteTimes.Add(_secondLevelDependencyFileInfo, _secondLevelDependencyFileInfo.LastWriteTimeUtc);
48+
49+
var utcNow = DateTime.UtcNow;
50+
51+
_inputFileInfo.LastWriteTimeUtc = utcNow;
52+
_outputFileInfo.LastWriteTimeUtc = utcNow;
53+
_firstLevelDependencyFileInfo.LastWriteTimeUtc = utcNow;
54+
_secondLevelDependencyFileInfo.LastWriteTimeUtc = utcNow;
55+
56+
_olderWriteTime = utcNow.AddHours(-1);
57+
_newerWriteTime = utcNow.AddHours(1);
58+
}
59+
60+
[TestCleanup]
61+
public void Cleanup()
62+
{
63+
if (File.Exists(outputFile))
64+
File.Delete(outputFile);
65+
66+
foreach (var entry in _originalLastWriteTimes)
67+
{
68+
entry.Key.LastWriteTimeUtc = entry.Value;
69+
}
70+
}
71+
72+
[TestMethod, TestCategory("Config")]
73+
public void CompilationRequired_OutputNewerThanEverything_DoesNotRequireCompilation()
74+
{
75+
_inputFileInfo.LastWriteTimeUtc = _olderWriteTime;
76+
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
77+
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
78+
79+
var compilationRequired = _config.CompilationRequired();
80+
81+
Assert.AreEqual(false, compilationRequired);
82+
}
83+
84+
[TestMethod, TestCategory("Config")]
85+
public void CompilationRequired_InputNewerThanOutput_RequiresCompilation()
86+
{
87+
_inputFileInfo.LastWriteTimeUtc = _newerWriteTime;
88+
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
89+
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
90+
91+
var compilationRequired = _config.CompilationRequired();
92+
93+
Assert.AreEqual(true, compilationRequired);
94+
}
95+
96+
[TestMethod, TestCategory("Config")]
97+
public void CompilationRequired_FirstLevelDependencyNewerThanOutput_RequiresCompilation()
98+
{
99+
_inputFileInfo.LastWriteTimeUtc = _olderWriteTime;
100+
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _newerWriteTime;
101+
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
102+
103+
var compilationRequired = _config.CompilationRequired();
104+
105+
Assert.AreEqual(true, compilationRequired);
106+
}
107+
108+
[TestMethod, TestCategory("Config")]
109+
public void CompilationRequired_SecondLevelDependencyNewerThanOutput_RequiresCompilation()
110+
{
111+
_inputFileInfo.LastWriteTimeUtc = _olderWriteTime;
112+
_firstLevelDependencyFileInfo.LastWriteTimeUtc = _olderWriteTime;
113+
_secondLevelDependencyFileInfo.LastWriteTimeUtc = _newerWriteTime;
114+
115+
var compilationRequired = _config.CompilationRequired();
116+
117+
Assert.AreEqual(true, compilationRequired);
118+
}
119+
}
120+
}

src/WebCompilerTest/WebCompilerTest.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
<Compile Include="Compile\ScssOptionsTest.cs" />
6767
<Compile Include="Compile\ScssTest.cs" />
6868
<Compile Include="Compile\LessTest.cs" />
69+
<Compile Include="Config\ConfigTest.cs" />
6970
<Compile Include="Minify\JavaScriptOptionsTests.cs" />
7071
<Compile Include="Minify\CssOptionsTests.cs" />
7172
<Compile Include="Minify\CssMinifierTests.cs" />
@@ -74,6 +75,9 @@
7475
</ItemGroup>
7576
<ItemGroup>
7677
<Content Include="artifacts\less\sub\logo.png" />
78+
<None Include="artifacts\config\compilationrequired.scss" />
79+
<None Include="artifacts\config\dependencies\sub\bar.scss" />
80+
<None Include="artifacts\config\dependencies\foo.scss" />
7781
<None Include="artifacts\handlebarsconfigPartial.json" />
7882
<None Include="artifacts\handlebarsconfig.json" />
7983
<None Include="artifacts\coffeeconfig.json.defaults" />
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "dependencies/foo";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "sub/bar";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+


0 commit comments

Comments
 (0)