maglove 0.8.1 → 1.0.2
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 +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +157 -0
- data/Gemfile.lock +59 -49
- data/bin/maglove +13 -13
- data/data/maglove/export.haml +11 -0
- data/data/maglove/index.haml +17 -0
- data/data/maglove/maglove.css +62 -0
- data/data/maglove/maglove.haml +18 -0
- data/data/maglove/maglove.js +68 -0
- data/lib/block_resolver.rb +6 -0
- data/lib/ext/thor/option.rb +43 -0
- data/lib/magloft/api.rb +39 -0
- data/lib/magloft/api_caller.rb +67 -0
- data/lib/magloft/remote_collection.rb +50 -0
- data/lib/magloft/remote_resource.rb +124 -0
- data/lib/magloft/transformable.rb +11 -0
- data/lib/magloft/typeloft_block.rb +18 -0
- data/lib/magloft/typeloft_image.rb +18 -0
- data/lib/magloft/typeloft_template.rb +18 -0
- data/lib/magloft/typeloft_theme.rb +41 -0
- data/lib/magloft.rb +3 -0
- data/lib/maglove/application.rb +10 -12
- data/lib/maglove/asset/theme.rb +37 -32
- data/lib/maglove/commands/assets.rb +85 -0
- data/lib/maglove/commands/base.rb +55 -0
- data/lib/maglove/commands/fonts.rb +69 -0
- data/lib/maglove/commands/main.rb +24 -0
- data/lib/maglove/commands/theme.rb +197 -0
- data/lib/maglove/helper/log_helper.rb +3 -18
- data/lib/maglove/middleware/live_reload.rb +97 -0
- data/lib/maglove/phantom_script.rb +9 -10
- data/lib/maglove/server.rb +46 -78
- data/lib/maglove/tilt/coffee_template.rb +7 -6
- data/lib/maglove/tilt/haml_template.rb +4 -4
- data/lib/maglove/tilt/js_template.rb +8 -8
- data/lib/maglove/tilt/less_template.rb +5 -4
- data/lib/maglove/tilt/scss_template.rb +17 -11
- data/lib/maglove/tilt/yaml_template.rb +3 -2
- data/lib/maglove/version.rb +1 -1
- data/lib/maglove/workspace.rb +41 -0
- data/lib/maglove.rb +38 -49
- data/lib/powersnap.rb +24 -0
- data/lib/workspace/workspace_dir/archive.rb +18 -0
- data/lib/workspace/workspace_dir.rb +98 -0
- data/lib/workspace/workspace_file/archive.rb +45 -0
- data/lib/workspace/workspace_file/media.rb +19 -0
- data/lib/workspace/workspace_file/net.rb +18 -0
- data/lib/workspace/workspace_file/parse.rb +21 -0
- data/lib/workspace/workspace_file.rb +99 -0
- data/lib/workspace.rb +11 -0
- data/maglove.gemspec +12 -12
- metadata +100 -86
- data/data/maglove/dump.haml +0 -58
- data/data/maglove/sdk.haml +0 -27
- data/lib/ext/commander/command.rb +0 -32
- data/lib/ext/commander/methods.rb +0 -8
- data/lib/maglove/asset/base_theme.rb +0 -17
- data/lib/maglove/command/compile.rb +0 -44
- data/lib/maglove/command/compress.rb +0 -28
- data/lib/maglove/command/copy.rb +0 -35
- data/lib/maglove/command/core.rb +0 -23
- data/lib/maglove/command/font.rb +0 -80
- data/lib/maglove/command/server.rb +0 -16
- data/lib/maglove/command/sync.rb +0 -17
- data/lib/maglove/command/theme.rb +0 -175
- data/lib/maglove/command/util.rb +0 -45
- data/lib/maglove/helper/asset_helper.rb +0 -24
- data/lib/maglove/helper/command_helper.rb +0 -67
- data/lib/maglove/helper/theme_helper.rb +0 -105
- data/lib/maglove/server/hpub.rb +0 -185
- data/lib/maglove/template/tumblr.rb +0 -81
- data/lib/maglove/tilt/twig_template.rb +0 -49
@@ -0,0 +1,67 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class ApiCaller < Dialers::Caller
|
3
|
+
MAX_RETRIES = 0
|
4
|
+
TIMEOUT_IN_SECONDS = 600
|
5
|
+
MAGLOFT_API_URL = "https://www.magloft.dev"
|
6
|
+
MAGLOFT_CDN_URL = "https://cdn.magloft.dev/"
|
7
|
+
|
8
|
+
setup_api(url: MAGLOFT_API_URL) do |faraday|
|
9
|
+
faraday.request :json
|
10
|
+
faraday.request :request_headers, accept: "application/json"
|
11
|
+
faraday.response :json
|
12
|
+
faraday.adapter :net_http
|
13
|
+
faraday.options.timeout = TIMEOUT_IN_SECONDS
|
14
|
+
faraday.options.open_timeout = TIMEOUT_IN_SECONDS
|
15
|
+
faraday.ssl.verify = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def http_call(request_options, current_retries = 0)
|
19
|
+
request_options.headers["X-Magloft-Accesstoken"] = Api.client.token
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def transform(response)
|
24
|
+
self.class.short_circuits.search_for_stops(response)
|
25
|
+
Transformable.new(response)
|
26
|
+
end
|
27
|
+
|
28
|
+
short_circuits.add(
|
29
|
+
if: -> (response) { Dialers::Status.new(response.status).server_error? },
|
30
|
+
do: -> (response) { fail Dialers::ServerError, response }
|
31
|
+
)
|
32
|
+
|
33
|
+
short_circuits.add(
|
34
|
+
if: -> (response) { Dialers::Status.new(response.status).is?(404) },
|
35
|
+
do: -> (response) { fail Dialers::NotFoundError, response }
|
36
|
+
)
|
37
|
+
|
38
|
+
short_circuits.add(
|
39
|
+
if: -> (response) { Dialers::Status.new(response.status).is?(409) },
|
40
|
+
do: -> (response) { fail ConflictError, response }
|
41
|
+
)
|
42
|
+
|
43
|
+
short_circuits.add(
|
44
|
+
if: -> (response) { Dialers::Status.new(response.status).is?(400) },
|
45
|
+
do: -> (response) { fail ValidationError, response }
|
46
|
+
)
|
47
|
+
|
48
|
+
short_circuits.add(
|
49
|
+
if: -> (response) { Dialers::Status.new(response.status).is?(422) },
|
50
|
+
do: -> (response) { fail ValidationError, response }
|
51
|
+
)
|
52
|
+
|
53
|
+
short_circuits.add(
|
54
|
+
if: -> (response) { Dialers::Status.new(response.status).is?(401) },
|
55
|
+
do: -> (response) { fail UnauthorizedError, response }
|
56
|
+
)
|
57
|
+
|
58
|
+
class ConflictError < Dialers::ErrorWithResponse
|
59
|
+
end
|
60
|
+
|
61
|
+
class ValidationError < Dialers::ErrorWithResponse
|
62
|
+
end
|
63
|
+
|
64
|
+
class UnauthorizedError < Dialers::ErrorWithResponse
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class RemoteCollection
|
3
|
+
def initialize(resource_class, filter = {})
|
4
|
+
@resource_class = resource_class
|
5
|
+
@filter = filter
|
6
|
+
end
|
7
|
+
|
8
|
+
def new(attributes)
|
9
|
+
@resource_class.new(attributes.merge(@filter))
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(id)
|
13
|
+
@resource_class.where(@filter.merge(id: id)).first
|
14
|
+
end
|
15
|
+
|
16
|
+
def where(params)
|
17
|
+
@resource_class.where(params.merge(@filter))
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_one(params)
|
21
|
+
@resource_class.find_one(params.merge(@filter))
|
22
|
+
end
|
23
|
+
|
24
|
+
def all
|
25
|
+
@resource_class.where(@filter)
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(name, *args, &block)
|
29
|
+
if name[0..7] == "find_by_" and args.length == 1
|
30
|
+
attribute = name[8..-1].to_sym
|
31
|
+
if @resource_class.remote_attributes.include?(attribute)
|
32
|
+
params = {}
|
33
|
+
params[attribute] = args.first
|
34
|
+
return self.find_one(params.merge(@filter))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def respond_to_missing?(method_name, include_private = false)
|
41
|
+
method_name.to_s.start_with?('find_by_') || super
|
42
|
+
end
|
43
|
+
|
44
|
+
def create(attributes = {})
|
45
|
+
entity = @resource_class.new(attributes.merge(@filter))
|
46
|
+
entity.save
|
47
|
+
entity
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class RemoteResource
|
3
|
+
attr_accessor :changed_data, :id
|
4
|
+
attr_reader :destroyed
|
5
|
+
|
6
|
+
def initialize(attributes = {})
|
7
|
+
allowed_attributes = attributes.slice(*self.class.remote_attributes)
|
8
|
+
Dialers::AssignAttributes.call(self, allowed_attributes.without(:id))
|
9
|
+
end
|
10
|
+
|
11
|
+
def changed?
|
12
|
+
self.changed_data.keys.count > 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def destroyed?
|
16
|
+
self.destroyed == true
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
return false if destroyed? or !changed?
|
21
|
+
if self.changed_data.keys.count > 0
|
22
|
+
if self.id.nil?
|
23
|
+
transformable = Api.client.api_caller.post(self.class.endpoint, self.changed_data)
|
24
|
+
else
|
25
|
+
transformable = Api.client.api_caller.put("#{self.class.endpoint}/#{self.id}", self.changed_data.without(:id))
|
26
|
+
end
|
27
|
+
transformable.transform_to_existing(self)
|
28
|
+
self.clear_changed_data!
|
29
|
+
end
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
return false if self.id.nil? or self.destroyed?
|
35
|
+
transformable = Api.client.api_caller.delete("#{self.class.endpoint}/#{self.id}")
|
36
|
+
transformable.transform_to_existing(self)
|
37
|
+
@destroyed = true
|
38
|
+
self.clear_changed_data!
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def changed_data
|
43
|
+
@changed_data ||= {}
|
44
|
+
end
|
45
|
+
|
46
|
+
def clear_changed_data!
|
47
|
+
self.changed_data = {}
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_data(key, value)
|
52
|
+
if self.send(key) != value
|
53
|
+
instance_variable_set("@#{key}", value)
|
54
|
+
changed_data[key] = value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class << self
|
59
|
+
def remote_attributes
|
60
|
+
@remote_attributes ||= []
|
61
|
+
end
|
62
|
+
|
63
|
+
def remote_attribute(*args)
|
64
|
+
args.each do |arg|
|
65
|
+
remote_attributes.push(arg)
|
66
|
+
self.class_eval("attr_accessor :#{arg}")
|
67
|
+
self.class_eval("def #{arg}=(val);update_data(:#{arg}, val);end")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def endpoint(path = nil)
|
72
|
+
if path.nil?
|
73
|
+
@endpoint
|
74
|
+
else
|
75
|
+
@endpoint = path
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def find(id)
|
80
|
+
api.get("#{endpoint}/#{id}").transform_to_one(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def find_one(params)
|
84
|
+
where(params).first
|
85
|
+
end
|
86
|
+
|
87
|
+
def where(params)
|
88
|
+
api.get(endpoint, params).transform_to_many(self)
|
89
|
+
end
|
90
|
+
|
91
|
+
def all
|
92
|
+
api.get(endpoint).transform_to_many(self)
|
93
|
+
end
|
94
|
+
|
95
|
+
def create(attributes = {})
|
96
|
+
entity = self.new(attributes)
|
97
|
+
entity.save
|
98
|
+
entity
|
99
|
+
end
|
100
|
+
|
101
|
+
def method_missing(name, *args, &block)
|
102
|
+
if name[0..7] == "find_by_" and args.length == 1
|
103
|
+
attribute = name[8..-1].to_sym
|
104
|
+
if remote_attributes.include?(attribute)
|
105
|
+
params = {}
|
106
|
+
params[attribute] = args.first
|
107
|
+
return self.find_one(params)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
super
|
111
|
+
end
|
112
|
+
|
113
|
+
def respond_to_missing?(method_name, include_private = false)
|
114
|
+
method_name.to_s.start_with?('find_by_') || super
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def api
|
120
|
+
Api.client.api_caller
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class Transformable < Dialers::Transformable
|
3
|
+
def transform_attributes_to_object(entity_class_or_decider, attributes)
|
4
|
+
super.clear_changed_data!
|
5
|
+
end
|
6
|
+
|
7
|
+
def transform_to_existing(entity)
|
8
|
+
Dialers::AssignAttributes.call(entity, raw_data)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class TypeloftBlock < RemoteResource
|
3
|
+
endpoint "api/maglove/v1/typeloft_blocks"
|
4
|
+
remote_attribute :identifier, :name, :contents, :typeloft_theme_id, :user_id, :created_at, :updated_at
|
5
|
+
attr_accessor :thumbnail_policy
|
6
|
+
|
7
|
+
def upload_thumbnail(file_path)
|
8
|
+
return false if thumbnail_policy.nil?
|
9
|
+
conn = Faraday.new(url: thumbnail_policy["url"]) do |f|
|
10
|
+
f.ssl.verify = false
|
11
|
+
f.headers = thumbnail_policy["headers"]
|
12
|
+
f.adapter :net_http
|
13
|
+
end
|
14
|
+
response = conn.put(nil, File.read(file_path))
|
15
|
+
return (response.status == 200)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class TypeloftImage < RemoteResource
|
3
|
+
endpoint "api/maglove/v1/typeloft_images"
|
4
|
+
remote_attribute :title, :user_id, :typeloft_folder_id, :typeloft_theme_id, :remote_file, :md5
|
5
|
+
attr_accessor :policy, :content_type
|
6
|
+
|
7
|
+
def upload(file_path)
|
8
|
+
return false if policy.nil?
|
9
|
+
conn = Faraday.new(url: policy["url"]) do |f|
|
10
|
+
f.ssl.verify = false
|
11
|
+
f.headers = policy["headers"]
|
12
|
+
f.adapter :net_http
|
13
|
+
end
|
14
|
+
response = conn.put(nil, File.read(file_path))
|
15
|
+
return (response.status == 200)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class TypeloftTemplate < RemoteResource
|
3
|
+
endpoint "api/maglove/v1/typeloft_templates"
|
4
|
+
remote_attribute :identifier, :title, :contents, :public, :position, :typeloft_theme_id, :user_id, :created_at, :updated_at
|
5
|
+
attr_accessor :thumbnail_policy
|
6
|
+
|
7
|
+
def upload_thumbnail(file_path)
|
8
|
+
return false if thumbnail_policy.nil?
|
9
|
+
conn = Faraday.new(url: thumbnail_policy["url"]) do |f|
|
10
|
+
f.ssl.verify = false
|
11
|
+
f.headers = thumbnail_policy["headers"]
|
12
|
+
f.adapter :net_http
|
13
|
+
end
|
14
|
+
response = conn.put(nil, File.read(file_path))
|
15
|
+
return (response.status == 200)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MagLoft
|
2
|
+
class TypeloftTheme < RemoteResource
|
3
|
+
endpoint "api/maglove/v1/typeloft_themes"
|
4
|
+
remote_attribute :identifier, :name, :description, :base_version, :widgets, :fonts, :user_id, :screenshots, :active
|
5
|
+
attr_accessor :stylesheet_policy, :javascript_policy
|
6
|
+
|
7
|
+
def typeloft_templates
|
8
|
+
RemoteCollection.new(TypeloftTemplate, { typeloft_theme_id: self.id })
|
9
|
+
end
|
10
|
+
|
11
|
+
def typeloft_images
|
12
|
+
RemoteCollection.new(TypeloftImage, { typeloft_theme_id: self.id })
|
13
|
+
end
|
14
|
+
|
15
|
+
def typeloft_blocks
|
16
|
+
RemoteCollection.new(TypeloftBlock, { typeloft_theme_id: self.id })
|
17
|
+
end
|
18
|
+
|
19
|
+
def upload_javascript(file_path)
|
20
|
+
return false if javascript_policy.nil?
|
21
|
+
conn = Faraday.new(url: javascript_policy["url"]) do |f|
|
22
|
+
f.ssl.verify = false
|
23
|
+
f.headers = javascript_policy["headers"]
|
24
|
+
f.adapter :net_http
|
25
|
+
end
|
26
|
+
response = conn.put(nil, File.read(file_path))
|
27
|
+
return (response.status == 200)
|
28
|
+
end
|
29
|
+
|
30
|
+
def upload_stylesheet(file_path)
|
31
|
+
return false if stylesheet_policy.nil?
|
32
|
+
conn = Faraday.new(url: stylesheet_policy["url"]) do |f|
|
33
|
+
f.ssl.verify = false
|
34
|
+
f.headers = stylesheet_policy["headers"]
|
35
|
+
f.adapter :net_http
|
36
|
+
end
|
37
|
+
response = conn.put(nil, File.read(file_path))
|
38
|
+
return (response.status == 200)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/magloft.rb
ADDED
data/lib/maglove/application.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module MagLove
|
2
2
|
class Application
|
3
3
|
include Commander::Methods
|
4
|
-
|
4
|
+
|
5
5
|
def run
|
6
6
|
program :version, MagLove::VERSION
|
7
7
|
program :description, 'MagLoft Themes Toolkit'
|
@@ -12,17 +12,16 @@ module MagLove
|
|
12
12
|
logger.level = :debug
|
13
13
|
end
|
14
14
|
global_option '--verbosity LEVEL', 'Specify verbosity level (*info*, debug, warn, error)' do |verbosity|
|
15
|
-
verbosity = "info"
|
15
|
+
verbosity = "info" unless ["info", "debug", "warn", "error"].include?(verbosity.to_s)
|
16
16
|
logger.level = verbosity.to_sym
|
17
17
|
end
|
18
18
|
widgets_path = "widgets"
|
19
19
|
global_option '--widgets-path PATH', 'Specify path to custom widgets' do |path|
|
20
|
-
error!("▸ Invalid widgets path: #{path}")
|
20
|
+
error!("▸ Invalid widgets path: #{path}") unless File.directory?(path)
|
21
21
|
widgets_path = path
|
22
22
|
end
|
23
|
-
global_option '--production'
|
24
23
|
default_command :help
|
25
|
-
|
24
|
+
|
26
25
|
# Register Widgets
|
27
26
|
if File.directory?(widgets_path)
|
28
27
|
Dir["#{widgets_path}/**/*.rb"].each do |widget_path|
|
@@ -31,9 +30,9 @@ module MagLove
|
|
31
30
|
Hamloft.register_widget(klass_name.constantize)
|
32
31
|
end
|
33
32
|
end
|
34
|
-
|
33
|
+
|
35
34
|
logger.level = ENV["LOG_LEVEL"].to_sym if ENV["LOG_LEVEL"]
|
36
|
-
|
35
|
+
|
37
36
|
MagLove::Command::Theme.new.run
|
38
37
|
MagLove::Command::Core.new.run
|
39
38
|
MagLove::Command::Compile.new.run
|
@@ -43,18 +42,17 @@ module MagLove
|
|
43
42
|
MagLove::Command::Font.new.run
|
44
43
|
MagLove::Command::Sync.new.run
|
45
44
|
MagLove::Command::Server.new.run
|
46
|
-
|
45
|
+
|
47
46
|
# allow colons
|
48
|
-
ARGV[0] = ARGV[0].
|
49
|
-
|
47
|
+
ARGV[0] = ARGV[0].tr(":", "-") if ARGV[0]
|
48
|
+
|
50
49
|
# merge first two commands
|
51
50
|
if ARGV.length > 1 and defined_commands.keys.include?("#{ARGV[0]}-#{ARGV[1]}")
|
52
51
|
ARGV[0] = "#{ARGV[0]}-#{ARGV[1]}"
|
53
52
|
ARGV.slice!(1)
|
54
53
|
end
|
55
|
-
|
54
|
+
|
56
55
|
run!
|
57
56
|
end
|
58
|
-
|
59
57
|
end
|
60
58
|
end
|
data/lib/maglove/asset/theme.rb
CHANGED
@@ -1,42 +1,48 @@
|
|
1
|
+
require "tilt"
|
2
|
+
require "sass"
|
3
|
+
require "less"
|
4
|
+
require "maglove/tilt/haml_template"
|
5
|
+
require "maglove/tilt/less_template"
|
6
|
+
require "maglove/tilt/scss_template"
|
7
|
+
require "maglove/tilt/coffee_template"
|
8
|
+
require "maglove/tilt/js_template"
|
9
|
+
require "maglove/tilt/yaml_template"
|
10
|
+
|
1
11
|
module MagLove
|
2
12
|
module Asset
|
3
13
|
class Theme
|
4
|
-
include
|
14
|
+
include Workspace
|
5
15
|
include MagLove::Helper::LogHelper
|
6
|
-
|
7
|
-
attr_reader :mtime, :path, :theme, :valid, :locals, :contents
|
16
|
+
attr_reader :mtime, :path, :valid, :contents, :options
|
8
17
|
|
9
18
|
OUTPUT_MAPPING = {
|
10
19
|
"haml" => "html",
|
11
|
-
"twig" => "html",
|
12
20
|
"less" => "css",
|
13
21
|
"scss" => "css",
|
14
22
|
"coffee" => "js",
|
15
23
|
"yml" => "json"
|
16
24
|
}
|
17
25
|
|
18
|
-
def initialize(path,
|
26
|
+
def initialize(path, options = {})
|
19
27
|
@path = path
|
20
|
-
@
|
21
|
-
@locals = locals
|
28
|
+
@options = options
|
22
29
|
@mtime = File.mtime(absolute_path)
|
23
30
|
begin
|
24
31
|
if ::Tilt[input_type]
|
25
32
|
template = ::Tilt.new(absolute_path)
|
26
|
-
|
27
|
-
@contents = template.render(Object.new, locals)
|
33
|
+
@contents = template.render(Object.new, @options.merge(base_path: theme_base_dir.to_s))
|
28
34
|
else
|
29
35
|
@contents = File.read(absolute_path)
|
30
36
|
end
|
31
|
-
rescue
|
37
|
+
rescue StandardError => e
|
32
38
|
error("▸ #{e.message}")
|
33
39
|
end
|
34
40
|
end
|
35
|
-
|
41
|
+
|
36
42
|
def input_type
|
37
|
-
File.extname(path).
|
43
|
+
File.extname(path).delete("\.")
|
38
44
|
end
|
39
|
-
|
45
|
+
|
40
46
|
def output_type
|
41
47
|
OUTPUT_MAPPING[input_type] or input_type
|
42
48
|
end
|
@@ -48,41 +54,40 @@ module MagLove
|
|
48
54
|
def write!
|
49
55
|
write_to!(output_path)
|
50
56
|
end
|
51
|
-
|
57
|
+
|
52
58
|
def write_to!(path)
|
53
|
-
return false
|
59
|
+
return false unless valid?
|
54
60
|
FileUtils.mkdir_p(File.dirname(path))
|
55
|
-
|
56
|
-
File.open("#{path}+", 'wb') do |f|
|
57
|
-
f.write @contents
|
58
|
-
end
|
59
|
-
|
60
|
-
# Atomic write
|
61
|
+
File.open("#{path}+", 'wb') { |f| f.write @contents }
|
61
62
|
FileUtils.mv("#{path}+", path)
|
62
|
-
|
63
|
-
# Set mtime correctly
|
64
63
|
File.utime(mtime, mtime, path)
|
65
|
-
|
66
64
|
true
|
67
65
|
ensure
|
68
|
-
# Ensure tmp file gets cleaned up
|
69
66
|
FileUtils.rm("#{path}+") if File.exist?("#{path}+")
|
70
67
|
end
|
71
|
-
|
68
|
+
|
72
69
|
def absolute_path
|
73
|
-
|
70
|
+
if @options[:base]
|
71
|
+
File.absolute_path("src/base/#{theme_config(:base_version)}/#{path}")
|
72
|
+
else
|
73
|
+
File.absolute_path("src/themes/#{@options[:theme]}/#{path}")
|
74
|
+
end
|
74
75
|
end
|
75
76
|
|
76
77
|
def logical_path
|
77
|
-
return false
|
78
|
-
|
78
|
+
return false unless valid?
|
79
|
+
dirname = File.dirname(path)
|
80
|
+
if dirname == "/"
|
81
|
+
"#{File.basename(path, '.*')}.#{output_type}"
|
82
|
+
else
|
83
|
+
"#{dirname}/#{File.basename(path, '.*')}.#{output_type}"
|
84
|
+
end
|
79
85
|
end
|
80
86
|
|
81
87
|
def output_path
|
82
|
-
return false
|
83
|
-
"dist/themes/#{theme}/#{logical_path}"
|
88
|
+
return false unless valid?
|
89
|
+
"dist/themes/#{@options[:theme]}/#{logical_path}"
|
84
90
|
end
|
85
|
-
|
86
91
|
end
|
87
92
|
end
|
88
93
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module MagLove
|
2
|
+
module Commands
|
3
|
+
class Assets < Base
|
4
|
+
class_option :theme, type: :string, required: true, validator: OptionValidator
|
5
|
+
|
6
|
+
desc "compile", "Compile all assets"
|
7
|
+
def compile
|
8
|
+
invoke(:clean)
|
9
|
+
invoke(:images)
|
10
|
+
invoke(:javascript)
|
11
|
+
invoke(:stylesheet)
|
12
|
+
invoke(:yaml)
|
13
|
+
invoke(:templates)
|
14
|
+
invoke(:blocks)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "clean", "Clean theme dist directory"
|
18
|
+
def clean
|
19
|
+
info("▸ Cleaning up Theme Directory")
|
20
|
+
theme_dir(root: "dist").reset!
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "images", "Copy images"
|
24
|
+
def images
|
25
|
+
info("▸ Copying Images")
|
26
|
+
workspace_dir("src/base/#{theme_config(:base_version)}").files("images/**/*.{jpg,png,gif,svg}").each do |file|
|
27
|
+
debug("~> Copying #{file}")
|
28
|
+
file.asset(theme: options.theme, base: true).write!
|
29
|
+
end
|
30
|
+
theme_dir.files("images/**/*.{jpg,png,gif,svg}").each do |file|
|
31
|
+
debug("~> Copying #{file}")
|
32
|
+
file.asset.write!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "javascript", "Compile JavaScript"
|
37
|
+
def javascript
|
38
|
+
info("▸ Compiling JavaScript")
|
39
|
+
theme_dir.file("theme.coffee").asset.write!
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "stylesheet", "Compile Stylesheet"
|
43
|
+
def stylesheet
|
44
|
+
info("▸ Compiling Stylesheet")
|
45
|
+
theme_dir.files("theme.{scss,less}").first.asset.write!
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "yaml", "Compile YAML Manifest"
|
49
|
+
def yaml
|
50
|
+
info("▸ Compiling YAML Manifest")
|
51
|
+
theme_dir.file("theme.yml").asset.write!
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "templates", "Compile HAML Templates"
|
55
|
+
def templates
|
56
|
+
info("▸ Compiling HAML Templates")
|
57
|
+
asset_uri = "file://#{workspace_dir('dist').absolute_path}"
|
58
|
+
theme_config(:templates).each do |template|
|
59
|
+
debug "~> processing template #{template}"
|
60
|
+
template_file = theme_dir.file("templates/#{template}.haml")
|
61
|
+
error!("~> Template '#{template}' does not exist!") if template_file.nil?
|
62
|
+
contents = template_file.asset(asset_uri: asset_uri).contents
|
63
|
+
html_contents = gem_dir.file("export.haml").read_hamloft(theme: options.theme, contents: contents, asset_uri: asset_uri)
|
64
|
+
theme_dir(root: "dist").file("templates/#{template}.html").write(html_contents)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "blocks", "Compile HAML Blocks"
|
69
|
+
def blocks
|
70
|
+
info("▸ Compiling HAML Blocks")
|
71
|
+
if theme_dir.dir("blocks").exists?
|
72
|
+
asset_uri = "file://#{workspace_dir('dist').absolute_path}"
|
73
|
+
theme_dir.dir("blocks").files("**/*.haml").each do |block_file|
|
74
|
+
debug "~> processing block #{block_file.basename}"
|
75
|
+
contents = block_file.asset(asset_uri: asset_uri).contents
|
76
|
+
html_contents = gem_dir.file("export.haml").read_hamloft(theme: options.theme, contents: contents, asset_uri: asset_uri)
|
77
|
+
theme_dir(root: "dist").file("blocks/#{block_file.basename}.html").write(html_contents)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
debug "~> no blocks available"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "maglove/helper/log_helper"
|
2
|
+
require "maglove/asset/theme"
|
3
|
+
module MagLove
|
4
|
+
module Commands
|
5
|
+
class Base < Thor
|
6
|
+
include MagLove::Helper::LogHelper
|
7
|
+
include Workspace
|
8
|
+
|
9
|
+
def initialize(args, opts, config)
|
10
|
+
namespace = self.class.name.split("::").last.underscore
|
11
|
+
command = config[:current_command].name
|
12
|
+
Logging.mdc["full_command"] = "#{namespace}:#{command}"
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def magloft_api
|
19
|
+
@magloft_api ||= MagLoft::Api.client(options[:token])
|
20
|
+
end
|
21
|
+
|
22
|
+
def reset_invocations(*commands)
|
23
|
+
reset_command_invocations(self.class, *commands)
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset_command_invocations(parent, *commands)
|
27
|
+
if commands.length.zero?
|
28
|
+
@_invocations[parent] = []
|
29
|
+
else
|
30
|
+
commands.each do |command|
|
31
|
+
@_invocations[parent].delete(command.to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module OptionValidator
|
38
|
+
def self.validate(switch, value)
|
39
|
+
case switch
|
40
|
+
when "--theme"
|
41
|
+
File.directory?("src/themes/#{value}")
|
42
|
+
else
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.message(switch, value)
|
48
|
+
case switch
|
49
|
+
when "--theme"
|
50
|
+
"The theme '#{value}' does not exist!"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|