locomotivecms_wagon 2.0.0.pre.alpha.3 → 2.0.0.pre.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -6
- data/bin/wagon +1 -1
- data/generators/cloned/config/deploy.yml.tt +3 -2
- data/generators/content_type/app/content_types/%slug%.yml.tt +7 -0
- data/lib/locomotive/wagon/cli.rb +66 -73
- data/lib/locomotive/wagon/commands/clone_command.rb +35 -0
- data/lib/locomotive/wagon/commands/destroy_command.rb +29 -0
- data/lib/locomotive/wagon/commands/loggers/base_logger.rb +31 -0
- data/lib/locomotive/wagon/commands/loggers/pull_logger.rb +23 -0
- data/lib/locomotive/wagon/commands/loggers/push_logger.rb +23 -17
- data/lib/locomotive/wagon/commands/loggers/sync_logger.rb +23 -0
- data/lib/locomotive/wagon/commands/pull_command.rb +55 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/concerns/assets_concern.rb +75 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_base_command.rb +83 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_content_assets_command.rb +24 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_content_entries_command.rb +94 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_content_types_command.rb +42 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_pages_command.rb +54 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_site_command.rb +55 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_snippets_command.rb +29 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_theme_assets_command.rb +29 -0
- data/lib/locomotive/wagon/commands/pull_sub_commands/pull_translations_command.rb +24 -0
- data/lib/locomotive/wagon/commands/push_command.rb +1 -1
- data/lib/locomotive/wagon/commands/push_sub_commands/push_site_command.rb +28 -0
- data/lib/locomotive/wagon/commands/serve_command.rb +1 -1
- data/lib/locomotive/wagon/commands/sync_command.rb +57 -0
- data/lib/locomotive/wagon/commands/sync_sub_commands/concerns/base_concern.rb +41 -0
- data/lib/locomotive/wagon/commands/sync_sub_commands/sync_content_entries_command.rb +9 -0
- data/lib/locomotive/wagon/commands/sync_sub_commands/sync_pages_command.rb +41 -0
- data/lib/locomotive/wagon/commands/sync_sub_commands/sync_translations_command.rb +9 -0
- data/lib/locomotive/wagon/decorators/concerns/to_hash_concern.rb +1 -1
- data/lib/locomotive/wagon/decorators/content_type_decorator.rb +7 -3
- data/lib/locomotive/wagon/decorators/content_type_field_decorator.rb +6 -1
- data/lib/locomotive/wagon/decorators/site_decorator.rb +8 -0
- data/lib/locomotive/wagon/generators/site/base.rb +1 -1
- data/lib/locomotive/wagon/generators/site/cloned.rb +1 -1
- data/lib/locomotive/wagon/generators/site.rb +0 -2
- data/lib/locomotive/wagon/tools/styled_yaml.rb +122 -0
- data/lib/locomotive/wagon/version.rb +1 -1
- data/lib/locomotive/wagon.rb +22 -57
- data/locomotivecms_wagon.gemspec +2 -2
- data/spec/fixtures/cassettes/authenticate.yml +49 -122
- data/spec/fixtures/cassettes/push.yml +8960 -9147
- data/spec/fixtures/default/icon.png +0 -0
- data/spec/integration/commands/push_command_spec.rb +1 -1
- metadata +31 -13
- data/generators/blank/config.ru +0 -3
- data/generators/bootstrap3/config.ru +0 -3
- data/generators/cloned/config.ru +0 -3
- data/generators/foundation5/config.ru +0 -3
- data/generators/line_case/config.ru +0 -3
- data/lib/locomotive/wagon/tools/deployment_connection.rb +0 -120
- data/lib/locomotive/wagon/tools/hosting_api.rb +0 -117
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative './concerns/assets_concern'
|
2
|
+
|
3
|
+
module Locomotive::Wagon
|
4
|
+
|
5
|
+
class PullBaseCommand < Struct.new(:api_client, :current_site, :path)
|
6
|
+
|
7
|
+
include Locomotive::Wagon::AssetsConcern
|
8
|
+
|
9
|
+
def self.pull(api_client, current_site, path)
|
10
|
+
new(api_client, current_site, path).pull
|
11
|
+
end
|
12
|
+
|
13
|
+
def pull
|
14
|
+
instrument do
|
15
|
+
instrument :start
|
16
|
+
self._pull_with_timezone
|
17
|
+
instrument :done
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def _pull_with_timezone
|
22
|
+
Time.use_zone(current_site.try(:timezone)) do
|
23
|
+
_pull
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def instrument(action = nil, payload = {}, &block)
|
28
|
+
name = [instrument_base_name, [*action]].flatten.compact.join('.')
|
29
|
+
ActiveSupport::Notifications.instrument(name, { name: resource_name }.merge(payload), &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def dump(element, options = {})
|
33
|
+
if element.is_a?(Hash)
|
34
|
+
StyledYAML.dump(element.dup.tap do |attributes|
|
35
|
+
[*options[:inline]].each do |name|
|
36
|
+
attributes[name] = StyledYAML.inline(attributes[name])
|
37
|
+
end
|
38
|
+
end)
|
39
|
+
else
|
40
|
+
element.to_yaml
|
41
|
+
end.gsub(/\A---\n/, '')
|
42
|
+
end
|
43
|
+
|
44
|
+
def clean_attributes(attributes)
|
45
|
+
# remove nil or empty values
|
46
|
+
attributes.delete_if { |_, v| v.nil? || v == '' || (v.is_a?(Hash) && v.empty?) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def write_to_file(filepath, content = nil, mode = 'w+', &block)
|
50
|
+
_filepath = File.join(path, filepath)
|
51
|
+
|
52
|
+
folder = File.dirname(_filepath)
|
53
|
+
FileUtils.mkdir_p(folder) unless File.exists?(folder)
|
54
|
+
|
55
|
+
File.open(_filepath, mode) do |file|
|
56
|
+
file.write(content ? content : yield)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def reset_file(filepath)
|
61
|
+
_filepath = File.join(path, filepath)
|
62
|
+
FileUtils.rm(_filepath) if File.exists?(_filepath)
|
63
|
+
end
|
64
|
+
|
65
|
+
def instrument_base_name
|
66
|
+
'wagon.pull'
|
67
|
+
end
|
68
|
+
|
69
|
+
def resource_name
|
70
|
+
self.class.name[/::Pull(\w+)Command$/, 1].underscore
|
71
|
+
end
|
72
|
+
|
73
|
+
def default_locale
|
74
|
+
current_site.locales.first
|
75
|
+
end
|
76
|
+
|
77
|
+
def locales
|
78
|
+
current_site.locales
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullContentAssetsCommand < PullBaseCommand
|
4
|
+
|
5
|
+
def _pull
|
6
|
+
api_client.content_assets.all.each do |asset|
|
7
|
+
write_content_asset(asset)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_content_asset(asset)
|
12
|
+
binary = get_asset_binary(asset.url)
|
13
|
+
write_to_file(content_asset_filepath(asset), binary)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def content_asset_filepath(asset)
|
19
|
+
File.join('public', 'samples', 'all', asset.content_type_text, asset.filename)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullContentEntriesCommand < PullBaseCommand
|
4
|
+
|
5
|
+
def _pull
|
6
|
+
fetch_content_types do |content_type|
|
7
|
+
# delete the previous file
|
8
|
+
reset_file(content_entry_filepath(content_type))
|
9
|
+
|
10
|
+
fetch_content_entries(content_type) do |entries|
|
11
|
+
# entries is a list of max 10 elements (pagination)
|
12
|
+
write_content_entries(content_type, entries)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_content_entries(content_type, entries)
|
18
|
+
_entries = entries.map do |entry|
|
19
|
+
yaml_attributes(content_type, entry)
|
20
|
+
end
|
21
|
+
|
22
|
+
write_to_file(content_entry_filepath(content_type), dump(_entries), 'a')
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def yaml_attributes(content_type, entry)
|
28
|
+
fields = %w(_slug) + content_type.fields.map { |f| f['name'] } + %w(seo_title meta_description meta_keywords)
|
29
|
+
localized_fields = (content_type.attributes['localized_names'] || []) + %w(_slug seo_title meta_description meta_keywords)
|
30
|
+
fields_with_urls = content_type.attributes['urls_names']
|
31
|
+
|
32
|
+
attributes = {}
|
33
|
+
|
34
|
+
fields.each do |name|
|
35
|
+
attributes[name] = if localized_fields.include?(name) && locales.size > 1 && !content_type.attributes['localized_names'].empty?
|
36
|
+
clean_attributes({}.tap do |translations|
|
37
|
+
locales.each { |l| translations[l] = value_of(content_type, entry, l, name) }
|
38
|
+
end)
|
39
|
+
else
|
40
|
+
value_of(content_type, entry, default_locale, name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
{ entry[default_locale].attributes[content_type.label_field_name] => clean_attributes(attributes) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch_content_types(&block)
|
48
|
+
api_client.content_types.all.each do |content_type|
|
49
|
+
content_type.attributes['localized_names'] = content_type.fields.map { |f| f['localized'] ? f['name'] : nil }.compact
|
50
|
+
content_type.attributes['urls_names'] = content_type.fields.map { |f| %w(file text).include?(f['type']) ? f['name'] : nil }.compact
|
51
|
+
yield(content_type)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def fetch_content_entries(content_type, &block)
|
56
|
+
page = 1
|
57
|
+
while page do
|
58
|
+
entries, _next_page = {}, nil
|
59
|
+
|
60
|
+
locales.each do |locale|
|
61
|
+
next if locale != default_locale && content_type.localized_names.empty?
|
62
|
+
|
63
|
+
(_entries = api_client.content_entries(content_type).all(nil, { page: page }, locale)).each do |entry|
|
64
|
+
(entries[entry._id] ||= {})[locale] = entry
|
65
|
+
end
|
66
|
+
|
67
|
+
_next_page = _entries._next_page if _next_page.nil?
|
68
|
+
end
|
69
|
+
|
70
|
+
yield(entries.values)
|
71
|
+
|
72
|
+
page = _next_page
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def value_of(content_type, entry, locale, name)
|
77
|
+
if value = entry[locale].attributes[name]
|
78
|
+
if content_type.attributes['urls_names'].try(:include?, name)
|
79
|
+
replace_asset_urls(value)
|
80
|
+
else
|
81
|
+
value
|
82
|
+
end
|
83
|
+
else
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def content_entry_filepath(content_type)
|
89
|
+
File.join('data', "#{content_type.slug}.yml")
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullContentTypesCommand < PullBaseCommand
|
4
|
+
|
5
|
+
def _pull
|
6
|
+
api_client.content_types.all.each do |content_type|
|
7
|
+
write_content_type(content_type)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_content_type(content_type)
|
12
|
+
yaml = dump(yaml_attributes(content_type), inline: %w(public_submission_account_emails))
|
13
|
+
|
14
|
+
write_to_file(content_type_filepath(content_type), yaml)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def yaml_attributes(content_type)
|
20
|
+
content_type.attributes.slice('name', 'slug', 'description', 'label_field_name', 'order_by', 'order_direction', 'group_by', 'public_submission_enabled', 'public_submission_account_emails', 'display_settings').tap do |attributes|
|
21
|
+
# fields
|
22
|
+
attributes['fields'] = content_type.fields.map { |f| field_yaml_attributes(f) }
|
23
|
+
|
24
|
+
clean_attributes(attributes)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def field_yaml_attributes(field)
|
29
|
+
attributes = field.slice('label', 'type', 'required', 'hint', 'localized', 'select_options', 'class_name', 'inverse_of', 'ui_enabled')
|
30
|
+
|
31
|
+
clean_attributes(attributes)
|
32
|
+
|
33
|
+
{ field['name'] => attributes }
|
34
|
+
end
|
35
|
+
|
36
|
+
def content_type_filepath(content_type)
|
37
|
+
File.join('app', 'content_types', "#{content_type.slug}.yml")
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullPagesCommand < PullBaseCommand
|
4
|
+
|
5
|
+
attr_reader :fullpaths
|
6
|
+
|
7
|
+
def _pull
|
8
|
+
@fullpaths = {}
|
9
|
+
|
10
|
+
locales.each do |locale|
|
11
|
+
api_client.pages.all(locale).each do |page|
|
12
|
+
fullpaths[page._id] = page.fullpath if locale == default_locale
|
13
|
+
write_page(page, locale)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def write_page(page, locale = nil)
|
19
|
+
write_to_file(page_filepath(page, locale)) do
|
20
|
+
<<-EOF
|
21
|
+
#{yaml_attributes(page, locale)}---
|
22
|
+
#{replace_asset_urls(page.template)}
|
23
|
+
EOF
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def yaml_attributes(page, locale)
|
30
|
+
attributes = page.attributes.slice('title', 'slug', 'handle', 'position', 'listed', 'published', 'redirect_url', 'is_layout', 'content_type', 'seo_title', 'meta_description', 'meta_keywords')
|
31
|
+
|
32
|
+
if locale != default_locale
|
33
|
+
attributes.delete_if { |k, _| %w(handle position listed published is_layout content_type).include?(k) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# editable elements
|
37
|
+
attributes['editable_elements'] = page.editable_elements.inject({}) do |hash, el|
|
38
|
+
hash["#{el['block']}/#{el['slug']}"] = replace_asset_urls(el['content']) if el['content']
|
39
|
+
hash
|
40
|
+
end
|
41
|
+
|
42
|
+
clean_attributes(attributes)
|
43
|
+
|
44
|
+
attributes.to_yaml
|
45
|
+
end
|
46
|
+
|
47
|
+
def page_filepath(page, locale)
|
48
|
+
fullpath = locale == default_locale ? page.fullpath : "#{fullpaths[page._id]}.#{locale}"
|
49
|
+
File.join('app', 'views', 'pages', fullpath + '.liquid')
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullSiteCommand < PullBaseCommand
|
4
|
+
|
5
|
+
def _pull
|
6
|
+
attributes = current_site.attributes.slice('name', 'locales', 'domains', 'timezone', 'seo_title', 'meta_keywords', 'meta_description', 'picture_thumbnail_url')
|
7
|
+
|
8
|
+
locales.each_with_index do |locale, index|
|
9
|
+
if index == 0
|
10
|
+
transform_in_default_locale(attributes, locale)
|
11
|
+
else
|
12
|
+
add_other_locale(attributes, locale)
|
13
|
+
end
|
14
|
+
end if locales.size > 1
|
15
|
+
|
16
|
+
write_icon(attributes.delete('picture_thumbnail_url'))
|
17
|
+
|
18
|
+
write_to_file(File.join('config', 'site.yml')) do
|
19
|
+
dump(attributes, inline: %w(locales domains))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def write_icon(url)
|
26
|
+
return if url.blank?
|
27
|
+
|
28
|
+
unless url =~ /\Ahttp:\/\//
|
29
|
+
base = api_client.uri.dup.tap { |u| u.path = '' }.to_s
|
30
|
+
url = URI.join(base, url).to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
File.open(File.join(path, 'icon.png'), 'wb') do |file|
|
34
|
+
file.write Faraday.get(url).body
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def localized_attributes(&block)
|
39
|
+
%w(seo_title meta_keywords meta_description).each do |name|
|
40
|
+
yield(name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def transform_in_default_locale(attributes, locale)
|
45
|
+
localized_attributes { |k| attributes[k] = { locale => attributes[k] } }
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_other_locale(attributes, locale)
|
49
|
+
_site = api_client.current_site.get(locale)
|
50
|
+
localized_attributes { |k| attributes[k][locale] = _site.attributes[k] }
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullSnippetsCommand < PullBaseCommand
|
4
|
+
|
5
|
+
def _pull
|
6
|
+
locales.each do |locale|
|
7
|
+
api_client.snippets.all(locale).each do |snippet|
|
8
|
+
write_snippet(snippet, locale)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def write_snippet(snippet, locale = nil)
|
14
|
+
if (template = snippet.template).present?
|
15
|
+
_template = replace_asset_urls(template)
|
16
|
+
write_to_file(snippet_filepath(snippet, locale), _template)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def snippet_filepath(snippet, locale)
|
23
|
+
filename = locale == default_locale ? snippet.slug : "#{snippet.slug}.#{locale}"
|
24
|
+
File.join('app', 'views', 'snippets', filename + '.liquid')
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullThemeAssetsCommand < PullBaseCommand
|
4
|
+
|
5
|
+
def _pull
|
6
|
+
api_client.theme_assets.all.each do |asset|
|
7
|
+
write_theme_asset(asset)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_theme_asset(asset)
|
12
|
+
binary = get_asset_binary(asset.url)
|
13
|
+
|
14
|
+
if %w(javascript stylesheet).include?(asset.content_type)
|
15
|
+
binary = replace_asset_urls(binary)
|
16
|
+
end
|
17
|
+
|
18
|
+
write_to_file(theme_asset_filepath(asset), binary)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def theme_asset_filepath(asset)
|
24
|
+
File.join('public', asset.folder, asset.local_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PullTranslationsCommand < PullBaseCommand
|
4
|
+
|
5
|
+
def _pull
|
6
|
+
translations = api_client.translations.all.inject({}) do |hash, translation|
|
7
|
+
hash[translation.key] = translation.values
|
8
|
+
hash
|
9
|
+
end
|
10
|
+
|
11
|
+
unless translations.empty?
|
12
|
+
write_to_file(translations_filepath, dump(translations))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def translations_filepath
|
19
|
+
File.join('config', 'translations.yml')
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -13,7 +13,7 @@ module Locomotive::Wagon
|
|
13
13
|
|
14
14
|
class PushCommand < Struct.new(:env, :path, :options, :shell)
|
15
15
|
|
16
|
-
RESOURCES = %w(content_types content_entries pages snippets theme_assets translations).freeze
|
16
|
+
RESOURCES = %w(site content_types content_entries pages snippets theme_assets translations).freeze
|
17
17
|
|
18
18
|
RESOURCES_WITH_CONTENT = %w(content_entries translations).freeze
|
19
19
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class PushSiteCommand < PushBaseCommand
|
4
|
+
|
5
|
+
def entities
|
6
|
+
[repositories.site.first]
|
7
|
+
end
|
8
|
+
|
9
|
+
def decorate(entity)
|
10
|
+
IconSiteDecorator.new(entity)
|
11
|
+
end
|
12
|
+
|
13
|
+
def persist(decorated_entity)
|
14
|
+
_attributes = decorated_entity.to_hash
|
15
|
+
if !_attributes.empty? && api_client.current_site.get.attributes[:picture_url].nil?
|
16
|
+
api_client.current_site.update(_attributes)
|
17
|
+
else
|
18
|
+
raise SkipPersistingException.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def label_for(decorated_entity)
|
23
|
+
decorated_entity.name
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -56,7 +56,7 @@ module Locomotive::Wagon
|
|
56
56
|
|
57
57
|
Locomotive::Steam.configure do |config|
|
58
58
|
config.mode = :test
|
59
|
-
config.adapter = { name: :filesystem, path: path }
|
59
|
+
config.adapter = { name: :filesystem, path: File.expand_path(path) }
|
60
60
|
config.asset_path = File.expand_path(File.join(path, 'public'))
|
61
61
|
|
62
62
|
if port = options[:live_reload_port]
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'locomotive/common'
|
2
|
+
|
3
|
+
require_relative '../tools/styled_yaml'
|
4
|
+
|
5
|
+
require_relative 'loggers/sync_logger'
|
6
|
+
|
7
|
+
require_relative_all 'concerns'
|
8
|
+
require_relative 'sync_sub_commands/concerns/base_concern'
|
9
|
+
|
10
|
+
require_relative 'pull_sub_commands/pull_base_command'
|
11
|
+
require_relative_all 'pull_sub_commands'
|
12
|
+
require_relative_all 'sync_sub_commands'
|
13
|
+
|
14
|
+
module Locomotive::Wagon
|
15
|
+
|
16
|
+
class SyncCommand < Struct.new(:env, :path, :options)
|
17
|
+
|
18
|
+
RESOURCES = %w(pages content_entries translations).freeze
|
19
|
+
|
20
|
+
include ApiConcern
|
21
|
+
include DeployFileConcern
|
22
|
+
include InstrumentationConcern
|
23
|
+
|
24
|
+
def self.sync(env, path, options)
|
25
|
+
self.new(env, path, options).sync
|
26
|
+
end
|
27
|
+
|
28
|
+
def sync
|
29
|
+
SyncLogger.new if options[:verbose]
|
30
|
+
|
31
|
+
api_client = api_site_client(connection_information)
|
32
|
+
site = api_client.current_site.get
|
33
|
+
|
34
|
+
each_resource do |klass|
|
35
|
+
klass.sync(api_client, site, path)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def each_resource
|
42
|
+
RESOURCES.each do |name|
|
43
|
+
next if !options[:resources].blank? && !options[:resources].include?(name)
|
44
|
+
|
45
|
+
klass = "Locomotive::Wagon::Sync#{name.camelcase}Command".constantize
|
46
|
+
|
47
|
+
yield klass
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def connection_information
|
52
|
+
read_deploy_settings(self.env, self.path)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Locomotive::Wagon
|
4
|
+
|
5
|
+
module BaseConcern
|
6
|
+
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
|
11
|
+
alias :_sync :_pull
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
def sync(api_client, current_site, path)
|
18
|
+
new(api_client, current_site, path).sync
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def sync
|
24
|
+
instrument do
|
25
|
+
instrument :start
|
26
|
+
self._sync
|
27
|
+
instrument :done
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def instrument_base_name
|
32
|
+
'wagon.sync'
|
33
|
+
end
|
34
|
+
|
35
|
+
def resource_name
|
36
|
+
self.class.name[/::Sync(\w+)Command$/, 1].underscore
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Locomotive::Wagon
|
2
|
+
|
3
|
+
class SyncPagesCommand < PullPagesCommand
|
4
|
+
|
5
|
+
include Locomotive::Wagon::BaseConcern
|
6
|
+
|
7
|
+
def write_page(page, locale = nil)
|
8
|
+
if attributes = editable_elements_attributes(page, locale)
|
9
|
+
new_content = replace_editable_elements(page_filepath(page, locale), dump(attributes))
|
10
|
+
|
11
|
+
write_to_file(page_filepath(page, locale), new_content)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def editable_elements_attributes(page, locale)
|
18
|
+
list = page.editable_elements.inject({}) do |hash, el|
|
19
|
+
hash["#{el['block']}/#{el['slug']}"] = replace_asset_urls(el['content']) if el['content']
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
|
23
|
+
list.empty? ? nil : { 'editable_elements' => list }
|
24
|
+
end
|
25
|
+
|
26
|
+
def replace_editable_elements(filepath, replacement)
|
27
|
+
content = File.read(File.join(path, filepath))
|
28
|
+
existing = content =~ /\A.*?editable_elements:.*?\n---/m
|
29
|
+
|
30
|
+
content.gsub /\A---(.*?)\n---/m do |s|
|
31
|
+
if existing
|
32
|
+
s.gsub(/editable_elements:\n(.*?)\n(\S)/m) { |_s| "#{replacement}#{$2}" }
|
33
|
+
else
|
34
|
+
s.gsub(/---\Z/) { |_s| "#{replacement}\n---" }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -17,7 +17,7 @@ module Locomotive::Wagon
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def prepare_value_for_hash(value)
|
20
|
-
if value.is_a?(Array) && value.
|
20
|
+
if value.is_a?(Array) && value.any? { |v| v.respond_to?(:__attributes__) }
|
21
21
|
value.map(&:to_hash)
|
22
22
|
elsif value.is_a?(Array) && value.empty?
|
23
23
|
nil # reset the array
|