dassets 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +42 -10
- data/lib/dassets.rb +16 -28
- data/lib/dassets/asset_file.rb +36 -33
- data/lib/dassets/default_cache.rb +29 -0
- data/lib/dassets/digest_cmd.rb +36 -0
- data/lib/dassets/engine.rb +0 -2
- data/lib/dassets/file_store.rb +36 -0
- data/lib/dassets/runner.rb +2 -9
- data/lib/dassets/server/request.rb +5 -5
- data/lib/dassets/source_cache.rb +39 -0
- data/lib/dassets/source_file.rb +37 -13
- data/lib/dassets/version.rb +1 -1
- data/test/support/config/assets.rb +1 -0
- data/test/system/digest_cmd_run_tests.rb +37 -39
- data/test/system/rack_tests.rb +3 -7
- data/test/unit/asset_file_tests.rb +72 -40
- data/test/unit/config_tests.rb +3 -17
- data/test/unit/dassets_tests.rb +8 -42
- data/test/unit/default_cache_tests.rb +27 -0
- data/test/unit/{cmds/digest_cmd_tests.rb → digest_cmd_tests.rb} +4 -4
- data/test/unit/file_store_tests.rb +30 -0
- data/test/unit/server/request_tests.rb +7 -11
- data/test/unit/server/response_tests.rb +4 -5
- data/test/unit/source_cache_tests.rb +50 -0
- data/test/unit/source_file_tests.rb +28 -29
- metadata +16 -31
- data/lib/dassets/cmds/cache_cmd.rb +0 -33
- data/lib/dassets/cmds/digest_cmd.rb +0 -53
- data/lib/dassets/digests.rb +0 -61
- data/test/support/app/assets/.digests +0 -5
- data/test/support/app/assets/public/file1.txt +0 -1
- data/test/support/app/assets/public/file2.txt +0 -1
- data/test/support/app/assets/public/grumpy_cat.jpg +0 -0
- data/test/support/app/assets/public/nested/a-thing.txt.no-use +0 -4
- data/test/support/app/assets/public/nested/file3.txt +0 -0
- data/test/support/app_public/.gitkeep +0 -0
- data/test/support/example.digests +0 -3
- data/test/system/cache_cmd_run_tests.rb +0 -27
- data/test/unit/cmds/cache_cmd_tests.rb +0 -33
- data/test/unit/digests_tests.rb +0 -79
data/lib/dassets/source_file.rb
CHANGED
@@ -7,6 +7,16 @@ module Dassets
|
|
7
7
|
|
8
8
|
class SourceFile
|
9
9
|
|
10
|
+
def self.find_by_digest_path(path)
|
11
|
+
# always look at the freshest source list to make sure you get all sources
|
12
|
+
# not just the ones Dassets has cached
|
13
|
+
sources = Dassets::SourceList.new(Dassets.config).map{ |p| self.new(p) }
|
14
|
+
|
15
|
+
# get the last matching one in case two sources have the same digest path
|
16
|
+
# the last one *should* be correct since it was last to be digested
|
17
|
+
sources.select{ |s| s.digest_path == path }.last || NullSourceFile.new(path)
|
18
|
+
end
|
19
|
+
|
10
20
|
attr_reader :file_path
|
11
21
|
|
12
22
|
def initialize(file_path)
|
@@ -14,19 +24,8 @@ module Dassets
|
|
14
24
|
@ext_list = File.basename(@file_path).split('.').reverse
|
15
25
|
end
|
16
26
|
|
17
|
-
def
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
def digest
|
22
|
-
return if !self.exists?
|
23
|
-
|
24
|
-
Dassets::AssetFile.new(self.digest_path, self.fingerprint).tap do |asset_file|
|
25
|
-
FileUtils.mkdir_p(File.dirname(asset_file.output_path))
|
26
|
-
File.open(asset_file.output_path, "w"){ |f| f.write(self.compiled) }
|
27
|
-
Dassets.digests[self.digest_path] = self.fingerprint
|
28
|
-
Dassets.digests.save!
|
29
|
-
end
|
27
|
+
def asset_file
|
28
|
+
@asset_file ||= Dassets::AssetFile.new(self.digest_path)
|
30
29
|
end
|
31
30
|
|
32
31
|
def digest_path
|
@@ -52,6 +51,18 @@ module Dassets
|
|
52
51
|
@fingerprint ||= Digest::MD5.new.hexdigest(self.compiled)
|
53
52
|
end
|
54
53
|
|
54
|
+
def exists?
|
55
|
+
File.file?(@file_path)
|
56
|
+
end
|
57
|
+
|
58
|
+
def mtime
|
59
|
+
File.mtime(@file_path).httpdate
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(other_source_file)
|
63
|
+
self.file_path == other_source_file.file_path
|
64
|
+
end
|
65
|
+
|
55
66
|
private
|
56
67
|
|
57
68
|
def digest_dirname(file_path, source_path)
|
@@ -68,4 +79,17 @@ module Dassets
|
|
68
79
|
|
69
80
|
end
|
70
81
|
|
82
|
+
class NullSourceFile < SourceFile
|
83
|
+
attr_reader :file_path, :digest_path, :compiled, :fingerprint
|
84
|
+
def initialize(digest_path)
|
85
|
+
@file_path = ''
|
86
|
+
@ext_list = []
|
87
|
+
@digest_path = digest_path
|
88
|
+
end
|
89
|
+
def digest; end
|
90
|
+
def ==(other_source_file)
|
91
|
+
self.file_path == other_source_file.file_path
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
71
95
|
end
|
data/lib/dassets/version.rb
CHANGED
@@ -7,62 +7,60 @@ module Dassets
|
|
7
7
|
class DigestCmdRunTests < Assert::Context
|
8
8
|
desc "the DigestCmd"
|
9
9
|
setup do
|
10
|
-
Dassets.
|
11
|
-
Dassets.
|
10
|
+
Dassets.config.file_store = 'public'
|
11
|
+
clear_store_path(Dassets.config.file_store.root)
|
12
12
|
Dassets.digest_source_files
|
13
13
|
|
14
14
|
@addfile = 'addfile.txt'
|
15
|
-
@
|
16
|
-
|
17
|
-
@
|
18
|
-
@
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
FileUtils.
|
26
|
-
FileUtils.rm @rmfile_path
|
27
|
-
File.open(@updfile_path, "w+"){ |f| f.write('an update') }
|
15
|
+
@addfile_src = source_path(@addfile)
|
16
|
+
|
17
|
+
@rmfile = 'file1.txt'
|
18
|
+
@rmfile_src = source_path(@rmfile)
|
19
|
+
@rmfile_contents = File.read(@rmfile_src)
|
20
|
+
|
21
|
+
FileUtils.touch @addfile_src
|
22
|
+
@addfile_out = store_path(@addfile)
|
23
|
+
|
24
|
+
@rmfile_out = store_path(@rmfile)
|
25
|
+
FileUtils.rm @rmfile_src
|
28
26
|
end
|
29
27
|
teardown do
|
30
|
-
File.open(@
|
31
|
-
|
32
|
-
FileUtils.rm @addfile_path
|
28
|
+
File.open(@rmfile_src, "w"){ |f| f.write @rmfile_contents }
|
29
|
+
FileUtils.rm @addfile_src
|
33
30
|
|
34
|
-
Dassets.reset
|
35
|
-
Dassets.init
|
36
31
|
Dassets.digest_source_files
|
32
|
+
clear_store_path(Dassets.config.file_store.root)
|
33
|
+
Dassets.digest_source_files
|
34
|
+
Dassets.config.file_store = NullFileStore.new
|
37
35
|
end
|
38
36
|
|
39
37
|
should "update the digests on all source files when run with no given paths" do
|
40
|
-
|
41
|
-
assert_equal 5, Dassets.digests.paths.size
|
42
|
-
assert_not_includes @addfile, Dassets.digests.paths
|
43
|
-
assert_includes @rmfile, Dassets.digests.paths
|
44
|
-
assert_equal @orig_updfile_md5, Dassets.digests[@updfile]
|
45
|
-
|
38
|
+
clear_store_path(Dassets.config.file_store.root)
|
46
39
|
Dassets.digest_source_files
|
47
40
|
|
48
|
-
|
49
|
-
|
50
|
-
assert_includes @addfile, Dassets.digests.paths
|
51
|
-
assert_not_includes @rmfile, Dassets.digests.paths
|
52
|
-
assert_not_equal @orig_updfile_md5, Dassets.digests[@updfile]
|
41
|
+
assert_file_exists @addfile_out
|
42
|
+
assert_not_file_exists @rmfile_out
|
53
43
|
end
|
54
44
|
|
55
45
|
should "update the digests on a single source file when given its path" do
|
56
|
-
|
57
|
-
|
46
|
+
clear_store_path(Dassets.config.file_store.root)
|
47
|
+
Dassets.digest_source_files([@addfile_src])
|
58
48
|
|
59
|
-
|
49
|
+
assert_file_exists @addfile_out
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def source_path(file)
|
55
|
+
File.join(File.join(Dassets.config.source_path, file))
|
56
|
+
end
|
57
|
+
|
58
|
+
def store_path(file)
|
59
|
+
Dassets.config.file_store.store_path(Dassets::AssetFile.new(file).url)
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
assert_includes @addfile, Dassets.digests.paths
|
64
|
-
assert_includes @rmfile, Dassets.digests.paths
|
65
|
-
assert_equal @orig_updfile_md5, Dassets.digests[@updfile]
|
62
|
+
def clear_store_path(path)
|
63
|
+
Dir.glob(File.join(path, '*')).each{ |p| FileUtils.rm_r(p) } if path
|
66
64
|
end
|
67
65
|
|
68
66
|
end
|
data/test/system/rack_tests.rb
CHANGED
@@ -10,12 +10,8 @@ module Dassets
|
|
10
10
|
|
11
11
|
desc "the middleware in a rack app"
|
12
12
|
setup do
|
13
|
-
Dassets.init
|
14
13
|
app.use Dassets::Server
|
15
14
|
end
|
16
|
-
teardown do
|
17
|
-
Dassets.reset
|
18
|
-
end
|
19
15
|
|
20
16
|
def app
|
21
17
|
@app ||= SinatraApp
|
@@ -29,13 +25,13 @@ module Dassets
|
|
29
25
|
should "return a successful response" do
|
30
26
|
resp = get '/file1-daa05c683a4913b268653f7a7e36a5b4.txt'
|
31
27
|
assert_equal 200, resp.status
|
32
|
-
assert_equal Dassets['
|
28
|
+
assert_equal Dassets['file1.txt'].content, resp.body
|
33
29
|
end
|
34
30
|
|
35
31
|
should "return a successful response with no body on HEAD requests" do
|
36
32
|
resp = head '/file2-9bbe1047cffbb590f59e0e5aeff46ae4.txt'
|
37
33
|
assert_equal 200, resp.status
|
38
|
-
assert_equal Dassets['
|
34
|
+
assert_equal Dassets['file2.txt'].size.to_s, resp.headers['Content-Length']
|
39
35
|
assert_empty resp.body
|
40
36
|
end
|
41
37
|
|
@@ -45,7 +41,7 @@ module Dassets
|
|
45
41
|
desc "requesting an existing asset file that has not been modified"
|
46
42
|
setup do
|
47
43
|
@resp = get('/file1-daa05c683a4913b268653f7a7e36a5b4.txt', {}, {
|
48
|
-
'HTTP_IF_MODIFIED_SINCE' => Dassets['
|
44
|
+
'HTTP_IF_MODIFIED_SINCE' => Dassets['file1.txt'].mtime.to_s
|
49
45
|
})
|
50
46
|
end
|
51
47
|
|
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'assert'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'dassets/file_store'
|
4
|
+
require 'dassets/source_cache'
|
2
5
|
require 'dassets/asset_file'
|
3
6
|
|
4
7
|
class Dassets::AssetFile
|
@@ -6,69 +9,98 @@ class Dassets::AssetFile
|
|
6
9
|
class BaseTests < Assert::Context
|
7
10
|
desc "Dassets::AssetFile"
|
8
11
|
setup do
|
9
|
-
@asset_file = Dassets::AssetFile.new('file1.txt'
|
12
|
+
@asset_file = Dassets::AssetFile.new('file1.txt')
|
10
13
|
end
|
11
14
|
subject{ @asset_file }
|
12
15
|
|
13
|
-
should
|
14
|
-
should
|
15
|
-
should
|
16
|
-
should have_imeth :content, :mtime, :size, :mime_type, :exists?, :==
|
16
|
+
should have_readers :digest_path, :dirname, :extname, :basename, :source_cache
|
17
|
+
should have_imeths :digest!, :url, :fingerprint, :content
|
18
|
+
should have_imeths :href, :mtime, :size, :mime_type, :exists?, :==
|
17
19
|
|
18
|
-
should "know its
|
19
|
-
assert_equal 'file1.txt', subject.
|
20
|
-
assert_equal 'abc123', subject.md5
|
21
|
-
end
|
22
|
-
|
23
|
-
should "know its dirname, extname, and basename" do
|
20
|
+
should "know its digest path, dirname, extname, and basename" do
|
21
|
+
assert_equal 'file1.txt', subject.digest_path
|
24
22
|
assert_equal '.', subject.dirname
|
25
23
|
assert_equal '.txt', subject.extname
|
26
24
|
assert_equal 'file1', subject.basename
|
27
25
|
end
|
28
26
|
|
29
|
-
should "
|
30
|
-
assert_equal
|
27
|
+
should "use its source file attrs as its own" do
|
28
|
+
assert_equal subject.source_cache.mtime, subject.mtime
|
29
|
+
assert_equal Rack::Utils.bytesize(subject.content), subject.size
|
30
|
+
assert_equal "text/plain", subject.mime_type
|
31
|
+
assert subject.exists?
|
32
|
+
|
33
|
+
null_file = Dassets::AssetFile.new('')
|
34
|
+
assert_nil null_file.mtime
|
35
|
+
assert_nil null_file.size
|
36
|
+
assert_nil null_file.mime_type
|
37
|
+
assert_not null_file.exists?
|
38
|
+
end
|
39
|
+
|
40
|
+
should "know its source cache" do
|
41
|
+
assert_not_nil subject.source_cache
|
42
|
+
assert_kind_of Dassets::SourceCache, subject.source_cache
|
43
|
+
assert_equal subject.digest_path, subject.source_cache.digest_path
|
44
|
+
end
|
45
|
+
|
46
|
+
should "have a fingerprint" do
|
47
|
+
assert_not_nil subject.fingerprint
|
48
|
+
end
|
49
|
+
|
50
|
+
should "get its fingerprint from its source cache if none is given" do
|
51
|
+
af = Dassets::AssetFile.new('file1.txt')
|
52
|
+
assert_equal af.source_cache.fingerprint, af.fingerprint
|
53
|
+
end
|
54
|
+
|
55
|
+
should "know it's content" do
|
56
|
+
assert_equal "file1.txt\n", subject.content
|
57
|
+
|
58
|
+
null_file = Dassets::AssetFile.new('')
|
59
|
+
assert_nil null_file.content
|
60
|
+
end
|
61
|
+
|
62
|
+
should "get its content from its source cache if no output file" do
|
63
|
+
digest_path = 'nested/a-thing.txt.no-use'
|
64
|
+
exp_content = "thing\n\nDUMB\nUSELESS"
|
31
65
|
|
32
|
-
|
33
|
-
assert_equal
|
66
|
+
without_output = Dassets::AssetFile.new(digest_path)
|
67
|
+
assert_equal exp_content, without_output.content
|
34
68
|
end
|
35
69
|
|
36
|
-
should "build it's url from the path and the
|
37
|
-
|
70
|
+
should "build it's url from the path and the fingerprint" do
|
71
|
+
assert_match /^file1-[a-f0-9]{32}\.txt$/, subject.url
|
38
72
|
|
39
|
-
nested = Dassets::AssetFile.new('nested/file1.txt'
|
40
|
-
assert_equal "nested/file1
|
73
|
+
nested = Dassets::AssetFile.new('nested/file1.txt')
|
74
|
+
assert_equal "nested/file1-.txt", nested.url
|
41
75
|
end
|
42
76
|
|
43
77
|
should "build it's href from the url" do
|
44
|
-
|
78
|
+
assert_match /^\/file1-[a-f0-9]{32}\.txt$/, subject.href
|
45
79
|
|
46
|
-
nested = Dassets::AssetFile.new('nested/file1.txt'
|
47
|
-
assert_equal "/nested/file1
|
80
|
+
nested = Dassets::AssetFile.new('nested/file1.txt')
|
81
|
+
assert_equal "/nested/file1-.txt", nested.href
|
48
82
|
end
|
49
83
|
|
50
|
-
|
51
|
-
abs_file_path = File.join(Dassets.config.output_path, 'file1.txt')
|
52
|
-
exp_md5 = 'daa05c683a4913b268653f7a7e36a5b4'
|
53
|
-
file = Dassets::AssetFile.from_abs_path(abs_file_path)
|
84
|
+
end
|
54
85
|
|
55
|
-
|
56
|
-
|
86
|
+
class DigestTests < BaseTests
|
87
|
+
desc "being digested with an output path configured"
|
88
|
+
setup do
|
89
|
+
Dassets.config.file_store = 'public'
|
90
|
+
@save_path = @asset_file.digest!
|
91
|
+
@outfile = Dassets.config.file_store.store_path(@asset_file.url)
|
92
|
+
end
|
93
|
+
teardown do
|
94
|
+
Dassets.config.file_store = Dassets::NullFileStore.new
|
57
95
|
end
|
58
96
|
|
59
|
-
should "
|
60
|
-
assert_equal
|
61
|
-
|
62
|
-
assert_equal File.size?(subject.output_path), subject.size
|
63
|
-
assert_equal "text/plain", subject.mime_type
|
64
|
-
assert subject.exists?
|
97
|
+
should "return the asset file url" do
|
98
|
+
assert_equal @outfile, @save_path
|
99
|
+
end
|
65
100
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
assert_nil null_file.size
|
70
|
-
assert_nil null_file.mime_type
|
71
|
-
assert_not null_file.exists?
|
101
|
+
should "compile and write an asset file to the output path" do
|
102
|
+
assert_file_exists @outfile
|
103
|
+
assert_equal subject.content, File.read(@outfile)
|
72
104
|
end
|
73
105
|
|
74
106
|
end
|
data/test/unit/config_tests.rb
CHANGED
@@ -12,9 +12,10 @@ class Dassets::Config
|
|
12
12
|
end
|
13
13
|
subject{ @config }
|
14
14
|
|
15
|
-
should have_option :root_path,
|
15
|
+
should have_option :root_path, Pathname, :required => true
|
16
16
|
should have_option :assets_file, Pathname, :default => ENV['DASSETS_ASSETS_FILE']
|
17
|
-
should have_options :source_path, :
|
17
|
+
should have_options :source_path, :source_filter, :file_store
|
18
|
+
|
18
19
|
should have_reader :engines
|
19
20
|
should have_imeth :source, :engine
|
20
21
|
|
@@ -23,16 +24,6 @@ class Dassets::Config
|
|
23
24
|
assert_equal exp_path, subject.source_path
|
24
25
|
end
|
25
26
|
|
26
|
-
should "should use `apps/assets/public` as the default output path" do
|
27
|
-
exp_path = Dassets.config.root_path.join("app/assets/public").to_s
|
28
|
-
assert_equal exp_path, subject.output_path
|
29
|
-
end
|
30
|
-
|
31
|
-
should "should use `app/assets/.digests` as the default digests file path" do
|
32
|
-
exp_path = Dassets.config.root_path.join("app/assets/.digests").to_s
|
33
|
-
assert_equal exp_path, subject.digests_path.to_s
|
34
|
-
end
|
35
|
-
|
36
27
|
should "set the source path and filter proc with the `sources` method" do
|
37
28
|
path = Dassets::RootPath.new 'app/asset_files'
|
38
29
|
filter = proc{ |paths| [] }
|
@@ -63,11 +54,6 @@ class Dassets::Config
|
|
63
54
|
assert_equal '', subject.engines['empty'].compile('some content')
|
64
55
|
end
|
65
56
|
|
66
|
-
should "should use `apps/assets/public` as the default files path" do
|
67
|
-
exp_path = Dassets.config.root_path.join("app/assets/public").to_s
|
68
|
-
assert_equal exp_path, subject.output_path
|
69
|
-
end
|
70
|
-
|
71
57
|
end
|
72
58
|
|
73
59
|
end
|
data/test/unit/dassets_tests.rb
CHANGED
@@ -8,50 +8,27 @@ module Dassets
|
|
8
8
|
desc "Dassets"
|
9
9
|
subject{ Dassets }
|
10
10
|
|
11
|
-
should have_imeths :config, :
|
12
|
-
should have_imeths :configure, :reset, :init, :[]
|
11
|
+
should have_imeths :config, :configure, :init, :[]
|
13
12
|
should have_imeths :digest_source_files
|
14
13
|
|
15
14
|
should "return a `Config` instance with the `config` method" do
|
16
15
|
assert_kind_of Config, subject.config
|
17
16
|
end
|
18
17
|
|
19
|
-
should "
|
20
|
-
subject.reset
|
21
|
-
assert_empty subject.sources
|
22
|
-
|
23
|
-
subject.init
|
24
|
-
assert_not_empty subject.sources
|
25
|
-
end
|
26
|
-
|
27
|
-
should "read/parse the digests on init" do
|
28
|
-
subject.reset
|
29
|
-
assert_empty subject.digests.paths
|
30
|
-
|
31
|
-
subject.init
|
32
|
-
assert_not_empty subject.digests.paths
|
33
|
-
end
|
34
|
-
|
35
|
-
should "return asset files given a their path using the index operator" do
|
36
|
-
subject.init
|
18
|
+
should "return asset files given a their digest path using the index operator" do
|
37
19
|
file = subject['nested/file3.txt']
|
38
20
|
|
39
21
|
assert_kind_of Dassets::AssetFile, file
|
40
|
-
assert_equal 'nested/file3.txt', file.
|
41
|
-
assert_equal 'd41d8cd98f00b204e9800998ecf8427e', file.
|
42
|
-
|
43
|
-
subject.reset
|
22
|
+
assert_equal 'nested/file3.txt', file.digest_path
|
23
|
+
assert_equal 'd41d8cd98f00b204e9800998ecf8427e', file.fingerprint
|
44
24
|
end
|
45
25
|
|
46
|
-
should "return an asset file with
|
47
|
-
file = subject['path/not/found.txt']
|
48
|
-
assert_equal '', file.md5
|
49
|
-
|
50
|
-
subject.init
|
26
|
+
should "return an asset file with unknown source if digest path not found" do
|
51
27
|
file = subject['path/not/found.txt']
|
52
|
-
assert_equal '', file.md5
|
53
28
|
|
54
|
-
|
29
|
+
assert_kind_of Dassets::SourceCache, file.source_cache
|
30
|
+
assert_kind_of Dassets::NullSourceFile, file.source_cache.source_file
|
31
|
+
assert_not file.source_cache.exists?
|
55
32
|
end
|
56
33
|
|
57
34
|
end
|
@@ -69,17 +46,6 @@ module Dassets
|
|
69
46
|
assert_equal exp_list, Dassets::SourceList.new(config)
|
70
47
|
end
|
71
48
|
|
72
|
-
should "filter out any paths in the output path" do
|
73
|
-
config = Dassets::Config.new
|
74
|
-
config.source_path = "source_files" # test/support/source_files
|
75
|
-
config.output_path = "source_files/nested"
|
76
|
-
exp_list = [
|
77
|
-
'test1.txt', '_ignored.txt'
|
78
|
-
].map{ |p| File.expand_path(p, config.source_path) }.sort
|
79
|
-
|
80
|
-
assert_equal exp_list, Dassets::SourceList.new(config)
|
81
|
-
end
|
82
|
-
|
83
49
|
should "run the supplied source filter on the paths" do
|
84
50
|
config = Dassets::Config.new
|
85
51
|
config.source_path = "source_files" # test/support/source_files
|