assets-publisher-for-hanami 2.0.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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.travis.yml +13 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +257 -0
- data/Rakefile +2 -0
- data/assets-publisher-for-hanami.gemspec +33 -0
- data/bin/setup +7 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/asset.rb +81 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/types/asset-type.rb +41 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/types/javascript-type.rb +20 -0
- data/lib/cabeza-de-termo/assets-publisher/assets/types/stylesheet-type.rb +20 -0
- data/lib/cabeza-de-termo/assets-publisher/clock-cards/clock-card-machine.rb +43 -0
- data/lib/cabeza-de-termo/assets-publisher/clock-cards/clock-card.rb +47 -0
- data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/compilation-job.rb +80 -0
- data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/compilation-jobs-builder.rb +52 -0
- data/lib/cabeza-de-termo/assets-publisher/compilation-jobs/one-file-per-asset-builder.rb +66 -0
- data/lib/cabeza-de-termo/assets-publisher/compilers/command-line-compiler.rb +26 -0
- data/lib/cabeza-de-termo/assets-publisher/compilers/compiler.rb +50 -0
- data/lib/cabeza-de-termo/assets-publisher/compilers/tilt-compiler.rb +47 -0
- data/lib/cabeza-de-termo/assets-publisher/configuration/configuration.rb +66 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/asset-not-found-error.rb +12 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/compilation-job-failed-error.rb +14 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/compilation-job-not-supported-error.rb +14 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/error.rb +6 -0
- data/lib/cabeza-de-termo/assets-publisher/errors/unknown-asset-location-error.rb +12 -0
- data/lib/cabeza-de-termo/assets-publisher/helpers/helper.rb +27 -0
- data/lib/cabeza-de-termo/assets-publisher/locations/absolute-location.rb +25 -0
- data/lib/cabeza-de-termo/assets-publisher/locations/location.rb +54 -0
- data/lib/cabeza-de-termo/assets-publisher/locations/source-location.rb +13 -0
- data/lib/cabeza-de-termo/assets-publisher/publisher.rb +142 -0
- data/lib/cabeza-de-termo/assets-publisher/source-finders/assets-finder.rb +44 -0
- data/lib/cabeza-de-termo/assets-publisher/source-finders/assets-source.rb +31 -0
- data/lib/cabeza-de-termo/assets-publisher/version.rb +7 -0
- metadata +191 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'cabeza-de-termo/assets/library'
|
2
|
+
require 'cabeza-de-termo/assets/rendering-scope-adaptors/hanami-rendering-scope'
|
3
|
+
|
4
|
+
module CabezaDeTermo
|
5
|
+
module AssetsPublisher
|
6
|
+
class AssetType
|
7
|
+
def html_for(asset_uri)
|
8
|
+
CdT.subclass_responsibility
|
9
|
+
end
|
10
|
+
|
11
|
+
# Collect the assets to publish from the rendering_scope
|
12
|
+
def collect_assets_from(rendering_scope)
|
13
|
+
collect_uri_from(rendering_scope).collect do |uri|
|
14
|
+
new_asset_from_uri(uri)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Answer a new Asset from the uri and type
|
19
|
+
def new_asset_from_uri(uri)
|
20
|
+
Asset.on_uri self, uri
|
21
|
+
end
|
22
|
+
|
23
|
+
# Collect the javascripts uri from the rendering_scope
|
24
|
+
def collect_uri_from(rendering_scope)
|
25
|
+
CdT.subclass_responsibility
|
26
|
+
end
|
27
|
+
|
28
|
+
def compiler()
|
29
|
+
CdT.subclass_responsibility
|
30
|
+
end
|
31
|
+
|
32
|
+
def rendering_scope_assets_collector()
|
33
|
+
configuration.rendering_scope_assets_collector
|
34
|
+
end
|
35
|
+
|
36
|
+
def configuration()
|
37
|
+
Publisher.configuration
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'asset-type'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
class JavascriptType < AssetType
|
6
|
+
def html_for(asset_uri)
|
7
|
+
"<script src=\"#{asset_uri}\" type=\"text/javascript\"></script>"
|
8
|
+
end
|
9
|
+
|
10
|
+
# Collect the javascripts uri from the rendering_scope
|
11
|
+
def collect_uri_from(rendering_scope)
|
12
|
+
rendering_scope_assets_collector.javascripts_from rendering_scope
|
13
|
+
end
|
14
|
+
|
15
|
+
def compiler()
|
16
|
+
configuration.javascripts_compiler
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'asset-type'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
class StylesheetType < AssetType
|
6
|
+
def html_for(asset_uri)
|
7
|
+
"<link href=\"#{asset_uri}\" type=\"text/css\" rel=\"stylesheet\">"
|
8
|
+
end
|
9
|
+
|
10
|
+
# Collect the javascripts uri from the rendering_scope
|
11
|
+
def collect_uri_from(rendering_scope)
|
12
|
+
rendering_scope_assets_collector.stylesheets_from rendering_scope
|
13
|
+
end
|
14
|
+
|
15
|
+
def compiler()
|
16
|
+
configuration.stylesheets_compiler
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module CabezaDeTermo
|
2
|
+
module AssetsPublisher
|
3
|
+
# An object to detect if a compilation job needs to run or not.
|
4
|
+
class ClockCardMachine
|
5
|
+
def initialize()
|
6
|
+
@clock_cards = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def is_outdated?(compilation_job)
|
10
|
+
return true unless has_record_on?(compilation_job.id)
|
11
|
+
|
12
|
+
clock_cards_not_match? clock_cards[compilation_job.id], compilation_job.clock_card
|
13
|
+
end
|
14
|
+
|
15
|
+
def register_modifications_on(compilation_job)
|
16
|
+
clock_cards.delete(compilation_job.id)
|
17
|
+
|
18
|
+
CdT.object compilation_job.clock_card,
|
19
|
+
if_not_nil: proc { |card| clock_cards[compilation_job.id] = card unless card.has_assets_missing? }
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def clock_cards
|
25
|
+
@clock_cards
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_record_on?(id)
|
29
|
+
clock_cards.key?(id)
|
30
|
+
end
|
31
|
+
|
32
|
+
def clock_cards_not_match?(expected_card, card)
|
33
|
+
!clock_cards_match?(expected_card, card)
|
34
|
+
end
|
35
|
+
|
36
|
+
def clock_cards_match?(expected_card, card)
|
37
|
+
return false unless expected_card.size == card.size
|
38
|
+
|
39
|
+
expected_card.all_marks? { |uri, time| time == card.time_for(uri) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module CabezaDeTermo
|
2
|
+
module AssetsPublisher
|
3
|
+
class ClockCard
|
4
|
+
def initialize(&block)
|
5
|
+
@marks = {}
|
6
|
+
|
7
|
+
block.call(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Accesing
|
11
|
+
|
12
|
+
def set_mark_for(asset_uri, time)
|
13
|
+
marks[asset_uri] = time
|
14
|
+
end
|
15
|
+
|
16
|
+
def time_for(asset_uri)
|
17
|
+
marks[asset_uri]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Asking
|
21
|
+
|
22
|
+
def has_time_for?(asset_uri)
|
23
|
+
marks.key?(asset_uri)
|
24
|
+
end
|
25
|
+
|
26
|
+
def all_marks?(&block)
|
27
|
+
marks.all?(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_assets_missing?()
|
31
|
+
marks.any? { |uri, timestamp| timestamp == :not_found }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Querying
|
35
|
+
|
36
|
+
def size()
|
37
|
+
marks.size
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def marks()
|
43
|
+
@marks
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'cabeza-de-termo/assets-publisher/clock-cards/clock-card'
|
2
|
+
|
3
|
+
module CabezaDeTermo
|
4
|
+
module AssetsPublisher
|
5
|
+
class CompilationJob
|
6
|
+
def initialize(assets: nil, destination: nil)
|
7
|
+
@assets = assets
|
8
|
+
@destination = destination
|
9
|
+
end
|
10
|
+
|
11
|
+
# Accessors
|
12
|
+
|
13
|
+
def assets()
|
14
|
+
@assets
|
15
|
+
end
|
16
|
+
|
17
|
+
def destination()
|
18
|
+
@destination
|
19
|
+
end
|
20
|
+
|
21
|
+
def id()
|
22
|
+
@destination.uri.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
# Asking
|
26
|
+
def empty?()
|
27
|
+
assets.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
# File names
|
31
|
+
|
32
|
+
def source_filenames
|
33
|
+
assets.collect { |asset| asset.real_path.to_s }
|
34
|
+
end
|
35
|
+
|
36
|
+
def destination_filename
|
37
|
+
destination.real_path.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
# Compiling
|
41
|
+
|
42
|
+
def compile_with(compiler)
|
43
|
+
validate_source_assets
|
44
|
+
compiler.compile_job self
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
# Html
|
49
|
+
|
50
|
+
# Answer the asset html to include in a template.
|
51
|
+
def html
|
52
|
+
destination.html
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_source_assets()
|
56
|
+
assets.each { |asset| asset.validate_real_path }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Clock card
|
60
|
+
|
61
|
+
def clock_card()
|
62
|
+
ClockCard.new do |card|
|
63
|
+
assets.each do |asset|
|
64
|
+
card.set_mark_for(asset.uri.to_s, asset.modification_time)
|
65
|
+
end
|
66
|
+
|
67
|
+
card.set_mark_for(destination.uri.to_s, destination.modification_time)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def source_folders()
|
72
|
+
configuration.source_folders.collect { |path| Pathname(path).expand_path.to_s }
|
73
|
+
end
|
74
|
+
|
75
|
+
def configuration()
|
76
|
+
Publisher.configuration
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module CabezaDeTermo
|
2
|
+
module AssetsPublisher
|
3
|
+
class CompilationJobsBuilder
|
4
|
+
# Answer a new collection of compilation jobs for the assets
|
5
|
+
def self.jobs_for(asset_type, assets)
|
6
|
+
self.new(asset_type).jobs_for(assets)
|
7
|
+
end
|
8
|
+
|
9
|
+
def jobs_for(assets)
|
10
|
+
CdT.subclass_responsibility
|
11
|
+
end
|
12
|
+
|
13
|
+
# Initializing
|
14
|
+
|
15
|
+
def initialize(asset_type)
|
16
|
+
@asset_type = asset_type
|
17
|
+
end
|
18
|
+
|
19
|
+
# Accessing
|
20
|
+
|
21
|
+
def asset_type()
|
22
|
+
@asset_type
|
23
|
+
end
|
24
|
+
|
25
|
+
# Configuration
|
26
|
+
|
27
|
+
# Answer the Publisher configuration.
|
28
|
+
def configuration
|
29
|
+
Publisher.configuration
|
30
|
+
end
|
31
|
+
|
32
|
+
def compiled_assets_folder
|
33
|
+
configuration.published_assets_subfolder
|
34
|
+
end
|
35
|
+
|
36
|
+
# Answer the uri of the compiled asset
|
37
|
+
def compiled_uri
|
38
|
+
Pathname.new('/') + compiled_assets_folder + compiled_filename
|
39
|
+
end
|
40
|
+
|
41
|
+
def compiled_filename
|
42
|
+
CdT.subclass_responsibility
|
43
|
+
end
|
44
|
+
|
45
|
+
# Published asset
|
46
|
+
|
47
|
+
def asset_to_publish()
|
48
|
+
Asset.on_uri(asset_type, compiled_uri)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative 'compilation-jobs-builder'
|
2
|
+
require_relative 'compilation-job'
|
3
|
+
|
4
|
+
module CabezaDeTermo
|
5
|
+
module AssetsPublisher
|
6
|
+
class OneFilePerAssetBuilder < CompilationJobsBuilder
|
7
|
+
# Answer a collection of CompilationJob to send to a Compiler.
|
8
|
+
def jobs_for(assets)
|
9
|
+
assets.collect { |asset| new_compilation_job_for asset }
|
10
|
+
end
|
11
|
+
|
12
|
+
# Answer a new CompilationJob for a single asset to send to a Compiler
|
13
|
+
def new_compilation_job_for(asset)
|
14
|
+
@asset = asset
|
15
|
+
CompilationJob.new(assets: assets_to_compile, destination: asset_to_compile_to)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Answer the current asset
|
19
|
+
def asset()
|
20
|
+
@asset
|
21
|
+
end
|
22
|
+
|
23
|
+
# Answer the asset to compile. If the asset has an absolute location
|
24
|
+
# we won't compile it
|
25
|
+
def assets_to_compile()
|
26
|
+
if asset.location.is_absolute?
|
27
|
+
asset.validate_real_path
|
28
|
+
return []
|
29
|
+
end
|
30
|
+
|
31
|
+
[asset]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Answer the asset that will hold the compiled assets.
|
35
|
+
def asset_to_compile_to()
|
36
|
+
return asset if asset.location.is_absolute?
|
37
|
+
|
38
|
+
asset_to_publish
|
39
|
+
.set_uri_parameters(timestamp_string)
|
40
|
+
end
|
41
|
+
|
42
|
+
def compiled_filename
|
43
|
+
return asset.uri if ['.css', '.js'].include?(asset.uri.extname)
|
44
|
+
Pathname.new(remove_last_extension_from_uri)
|
45
|
+
end
|
46
|
+
|
47
|
+
def remove_last_extension_from_uri
|
48
|
+
asset.uri.to_s.split('.')[0..-2].join('.')
|
49
|
+
end
|
50
|
+
|
51
|
+
# Uri timestamp
|
52
|
+
|
53
|
+
# Answer if we must append a timestamp to the relative assets or not
|
54
|
+
def add_timestamps?()
|
55
|
+
configuration.add_timestamps_to_published_assets?
|
56
|
+
end
|
57
|
+
|
58
|
+
# Answer the timestamp string to add to this asset.
|
59
|
+
def timestamp_string()
|
60
|
+
return nil unless add_timestamps?
|
61
|
+
|
62
|
+
Time.now.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'open3'
|
3
|
+
require_relative 'compiler'
|
4
|
+
|
5
|
+
module CabezaDeTermo
|
6
|
+
module AssetsPublisher
|
7
|
+
class CommandLineCompiler < Compiler
|
8
|
+
def initialize(&block)
|
9
|
+
super()
|
10
|
+
@block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile_assets()
|
14
|
+
@block.call(self, compilation_job)
|
15
|
+
end
|
16
|
+
|
17
|
+
def command_line(*args)
|
18
|
+
ouput, status = Open3.capture2e(*args)
|
19
|
+
|
20
|
+
raise_compilation_failed_error(ouput.strip) unless status.success?
|
21
|
+
|
22
|
+
ouput
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'tilt'
|
3
|
+
require 'cabeza-de-termo/assets-publisher/errors/compilation-job-not-supported-error'
|
4
|
+
require 'cabeza-de-termo/assets-publisher/errors/compilation-job-failed-error'
|
5
|
+
|
6
|
+
module CabezaDeTermo
|
7
|
+
module AssetsPublisher
|
8
|
+
class Compiler
|
9
|
+
def compile_job(compilation_job)
|
10
|
+
return if compilation_job.empty?
|
11
|
+
|
12
|
+
@compilation_job = compilation_job
|
13
|
+
|
14
|
+
ensure_destination_folder_exists
|
15
|
+
|
16
|
+
compile_assets
|
17
|
+
end
|
18
|
+
|
19
|
+
def compilation_job()
|
20
|
+
@compilation_job
|
21
|
+
end
|
22
|
+
|
23
|
+
def source_assets()
|
24
|
+
@compilation_job.assets
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def compile_assets()
|
30
|
+
CdT.subclass_responsibility
|
31
|
+
end
|
32
|
+
|
33
|
+
def ensure_destination_folder_exists()
|
34
|
+
destination_folder.mkpath
|
35
|
+
end
|
36
|
+
|
37
|
+
def destination_folder()
|
38
|
+
compilation_job.destination.real_path.dirname
|
39
|
+
end
|
40
|
+
|
41
|
+
def raise_compilation_job_not_supported_error()
|
42
|
+
raise CompilationJobNotSupportedError.new(self, compilation_job)
|
43
|
+
end
|
44
|
+
|
45
|
+
def raise_compilation_failed_error(message)
|
46
|
+
raise CompilationJobFailedError.new(self, compilation_job, message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|