Skip to content

Commit b116953

Browse files
authored
Better group assets for clean (#2863)
For cleaning, group assets by paths with removing the hash part and sort them with mtime within each group to determine their versions.
1 parent 9a387d6 commit b116953

File tree

2 files changed

+95
-15
lines changed

2 files changed

+95
-15
lines changed

lib/webpacker/commands.rb

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@ def initialize(webpacker)
1717
#
1818
def clean(count = 2, age = 3600)
1919
if config.public_output_path.exist? && config.public_manifest_path.exist?
20-
versions
21-
.sort
22-
.reverse
23-
.each_with_index
24-
.drop_while do |(mtime, _), index|
25-
max_age = [0, Time.now - Time.at(mtime)].max
26-
max_age < age || index < count
20+
packs
21+
.map do |paths|
22+
paths.map { |path| [Time.now - File.mtime(path), path] }
23+
.sort
24+
.reject.with_index do |(file_age, _), index|
25+
file_age < age || index < count
26+
end
27+
.map { |_, path| path }
2728
end
28-
.each do |(_, files), index|
29-
files.each do |file|
30-
if File.file?(file)
31-
File.delete(file)
32-
logger.info "Removed #{file}"
33-
end
29+
.flatten
30+
.compact
31+
.each do |file|
32+
if File.file?(file)
33+
File.delete(file)
34+
logger.info "Removed #{file}"
3435
end
3536
end
3637
end
@@ -54,12 +55,15 @@ def compile
5455
end
5556

5657
private
57-
def versions
58+
def packs
5859
all_files = Dir.glob("#{config.public_output_path}/**/*")
5960
manifest_config = Dir.glob("#{config.public_manifest_path}*")
6061

6162
packs = all_files - manifest_config - current_version
62-
packs.reject { |file| File.directory?(file) }.group_by { |file| File.mtime(file).utc.to_i }
63+
packs.reject { |file| File.directory?(file) }.group_by do |path|
64+
base, _, ext = File.basename(path).scan(/(.*)(-[\da-f]+)(\.\w+)/).flatten
65+
"#{File.dirname(path)}/#{base}#{ext}"
66+
end.values
6367
end
6468

6569
def current_version

test/command_test.rb

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,79 @@ def test_clean_command_works_with_nested_hashes_and_without_any_compiled_files
3131
end
3232
end
3333
end
34+
35+
class ClearCommandVersioningTest < Minitest::Test
36+
def setup
37+
@now = Time.parse("2021-01-01 12:34:56 UTC")
38+
# Test assets to be kept and deleted, path and mtime
39+
@prev_files = {
40+
# recent versions to be kept with Webpacker.commands.clean(count = 2)
41+
"js/application-deadbeef.js" => @now - 4000,
42+
"js/common-deadbeee.js" => @now - 4002,
43+
"css/common-deadbeed.css" => @now - 4004,
44+
"media/images/logo-deadbeeb.css" => @now - 4006,
45+
"js/application-1eadbeef.js" => @now - 8000,
46+
"js/common-1eadbeee.js" => @now - 8002,
47+
"css/common-1eadbeed.css" => @now - 8004,
48+
"media/images/logo-1eadbeeb.css" => @now - 8006,
49+
# new files to be kept with Webpacker.commands.clean(age = 3600)
50+
"js/brandnew-0001.js" => @now,
51+
"js/brandnew-0002.js" => @now - 10,
52+
"js/brandnew-0003.js" => @now - 20,
53+
"js/brandnew-0004.js" => @now - 40,
54+
}.transform_keys { |path| "#{Webpacker.config.public_output_path}/#{path}" }
55+
@expired_files = {
56+
# old files that are outside count = 2 or age = 3600 and to be deleted
57+
"js/application-0eadbeef.js" => @now - 9000,
58+
"js/common-0eadbeee.js" => @now - 9002,
59+
"css/common-0eadbeed.css" => @now - 9004,
60+
"js/brandnew-0005.js" => @now - 3640,
61+
}.transform_keys { |path| "#{Webpacker.config.public_output_path}/#{path}" }
62+
@all_files = @prev_files.merge(@expired_files)
63+
@dir_glob_stub = Proc.new { |arg|
64+
case arg
65+
when "#{Webpacker.config.public_output_path}/**/*"
66+
@all_files.keys
67+
else
68+
[]
69+
end
70+
}
71+
@file_mtime_stub = Proc.new { |longpath|
72+
@all_files[longpath]
73+
}
74+
@file_delete_mock = Minitest::Mock.new
75+
@expired_files.keys.each do |longpath|
76+
@file_delete_mock.expect(:delete, 1, [longpath])
77+
end
78+
@file_delete_stub = Proc.new { |longpath|
79+
if @prev_files.has_key?(longpath)
80+
flunk "#{longpath} should not be deleted"
81+
else
82+
@file_delete_mock.delete(longpath)
83+
end
84+
}
85+
end
86+
87+
def time_and_files_stub(&proc)
88+
Time.stub :now, @now do
89+
Dir.stub :glob, @dir_glob_stub do
90+
File.stub :directory?, false do
91+
File.stub :file?, true do
92+
File.stub :mtime, @file_mtime_stub do
93+
File.stub :delete, @file_delete_stub do
94+
yield proc
95+
end
96+
end
97+
end
98+
end
99+
end
100+
end
101+
@file_delete_mock.verify
102+
end
103+
104+
def test_clean_command_with_versioned_files
105+
time_and_files_stub do
106+
assert Webpacker.commands.clean
107+
end
108+
end
109+
end

0 commit comments

Comments
 (0)