fronde 0.4.0 → 0.5.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 +4 -4
- data/lib/ext/r18n.rb +20 -0
- data/lib/ext/time.rb +6 -16
- data/lib/ext/time_no_time.rb +23 -0
- data/lib/fronde/cli/commands.rb +16 -12
- data/lib/fronde/cli/data/gitignore +0 -1
- data/lib/fronde/cli/opt_parse.rb +4 -7
- data/lib/fronde/cli/throbber.rb +24 -13
- data/lib/fronde/cli.rb +3 -2
- data/lib/fronde/config/data/org-config.el +3 -2
- data/lib/fronde/config/data/ox-fronde.el +72 -35
- data/lib/fronde/config/data/themes/umaneti/css/htmlize.css +364 -0
- data/lib/fronde/config/data/themes/umaneti/css/style.css +250 -0
- data/lib/fronde/config/data/themes/umaneti/img/bottom.png +0 -0
- data/lib/fronde/config/data/themes/umaneti/img/content.png +0 -0
- data/lib/fronde/config/data/themes/umaneti/img/tic.png +0 -0
- data/lib/fronde/config/data/themes/umaneti/img/top.png +0 -0
- data/lib/fronde/config/helpers.rb +0 -18
- data/lib/fronde/config/lisp.rb +13 -3
- data/lib/fronde/config.rb +40 -26
- data/lib/fronde/emacs.rb +1 -1
- data/lib/fronde/index/data/all_tags.org +6 -1
- data/lib/fronde/index/data/template.org +8 -4
- data/lib/fronde/index/org_generator.rb +2 -0
- data/lib/fronde/index.rb +12 -15
- data/lib/fronde/org/file.rb +39 -27
- data/lib/fronde/org/file_extracter.rb +15 -12
- data/lib/fronde/org.rb +11 -9
- data/lib/fronde/slug.rb +39 -12
- data/lib/fronde/source/gemini.rb +0 -5
- data/lib/fronde/source/html.rb +5 -5
- data/lib/fronde/source.rb +13 -8
- data/lib/fronde/sync/neocities.rb +220 -0
- data/lib/fronde/sync/rsync.rb +46 -0
- data/lib/fronde/sync.rb +32 -0
- data/lib/fronde/templater.rb +18 -11
- data/lib/fronde/version.rb +1 -1
- data/lib/tasks/org.rake +12 -17
- data/lib/tasks/site.rake +10 -13
- data/lib/tasks/sync.rake +13 -36
- data/lib/tasks/tags.rake +2 -2
- data/locales/en.yml +1 -0
- data/locales/fr.yml +1 -0
- metadata +49 -10
@@ -0,0 +1,220 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'time'
|
5
|
+
require 'yaml'
|
6
|
+
require 'net/http'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'digest/sha1'
|
9
|
+
|
10
|
+
module Fronde
|
11
|
+
module Sync
|
12
|
+
# Everything needed to connect to neocities
|
13
|
+
class Neocities
|
14
|
+
PROTECTED_FILES = %w[index.html neocities.png not_found.html].freeze
|
15
|
+
|
16
|
+
def initialize(connection_spec, public_folder, verbose: false, &block)
|
17
|
+
@verbose = verbose
|
18
|
+
@endpoint = @website_name = @authorization = nil
|
19
|
+
extract_connection_details connection_spec
|
20
|
+
@public_folder = public_folder
|
21
|
+
@connection = init_connection
|
22
|
+
return unless block
|
23
|
+
|
24
|
+
yield self
|
25
|
+
finish
|
26
|
+
end
|
27
|
+
|
28
|
+
def remote_list
|
29
|
+
remote = call build_request('/list')
|
30
|
+
JSON.parse(remote.body)['files'].map do |stat|
|
31
|
+
stat['updated_at'] = Time.parse(stat['updated_at'])
|
32
|
+
stat
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def local_list
|
37
|
+
Dir.chdir(@public_folder) do
|
38
|
+
Dir['**/*'].map { |file| neocities_stat(file) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def info
|
43
|
+
info = call build_request('/info')
|
44
|
+
JSON.parse(info.body)['info']
|
45
|
+
end
|
46
|
+
|
47
|
+
def finish
|
48
|
+
@connection.finish if @connection.started?
|
49
|
+
end
|
50
|
+
|
51
|
+
def pull(test: false)
|
52
|
+
file_list = remote_list
|
53
|
+
finish
|
54
|
+
orphans = select_orphans(file_list, local_list) do |path|
|
55
|
+
warn "deleting #{path}" if @verbose
|
56
|
+
|
57
|
+
"#{@public_folder}/#{path}"
|
58
|
+
end
|
59
|
+
File.unlink(*orphans) unless test
|
60
|
+
download_all file_list, test: test
|
61
|
+
nil # Mute this method
|
62
|
+
end
|
63
|
+
|
64
|
+
def push(test: false)
|
65
|
+
file_list = local_list
|
66
|
+
remove_remote_orphans file_list, test: test
|
67
|
+
upload_all file_list, test: test
|
68
|
+
finish
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def neocities_stat(file)
|
74
|
+
stat = File.stat(file)
|
75
|
+
data = {
|
76
|
+
'path' => file,
|
77
|
+
'is_directory' => stat.directory?,
|
78
|
+
'updated_at' => stat.mtime.round.utc
|
79
|
+
}
|
80
|
+
return data if data['is_directory']
|
81
|
+
|
82
|
+
data['size'] = stat.size
|
83
|
+
data['sha1_hash'] = Digest::SHA1.hexdigest File.read(file)
|
84
|
+
data
|
85
|
+
end
|
86
|
+
|
87
|
+
def select_orphans(to_apply, current_list, &block)
|
88
|
+
paths_to_apply = to_apply.map { _1['path'] }
|
89
|
+
current_paths = current_list.map { _1['path'] }
|
90
|
+
(current_paths - paths_to_apply).filter_map(&block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def remove_remote_orphans(file_list, test: false)
|
94
|
+
request = build_request '/delete', :post
|
95
|
+
orphan_paths = select_orphans(file_list, remote_list) do |path|
|
96
|
+
# Never remove the following files. If needed you can still
|
97
|
+
# overwrite them. And in any case, neocities will not allow
|
98
|
+
# the index.html file to be removed.
|
99
|
+
next if PROTECTED_FILES.include? path
|
100
|
+
|
101
|
+
warn "deleting #{path}" if @verbose
|
102
|
+
path
|
103
|
+
end
|
104
|
+
request.form_data = { 'filenames[]' => orphan_paths }
|
105
|
+
return if test
|
106
|
+
|
107
|
+
call request
|
108
|
+
end
|
109
|
+
|
110
|
+
def download_all(file_list, test: false)
|
111
|
+
publish_domain = "#{@website_name}.#{@endpoint.host}"
|
112
|
+
Dir.chdir(@public_folder) do
|
113
|
+
Net::HTTP.start(publish_domain, use_ssl: true) do |http|
|
114
|
+
file_list.each do |file_data|
|
115
|
+
path = file_data['path']
|
116
|
+
file_data['uri'] = "https://#{publish_domain}/#{path}"
|
117
|
+
download_file http, file_data, test: test
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def download_file(http, file_data, test: false)
|
124
|
+
path = file_data['path']
|
125
|
+
if file_data['is_directory']
|
126
|
+
warn "#{path}/" if @verbose
|
127
|
+
FileUtils.mkdir_p path unless test
|
128
|
+
return
|
129
|
+
end
|
130
|
+
|
131
|
+
warn path if @verbose
|
132
|
+
|
133
|
+
content = fetch_file_content(
|
134
|
+
http, file_data['uri'], file_data['sha1_hash']
|
135
|
+
)
|
136
|
+
return unless content && !test
|
137
|
+
|
138
|
+
save_file path, content, file_data['updated_at']
|
139
|
+
end
|
140
|
+
|
141
|
+
def fetch_file_content(http, uri, sha1sum)
|
142
|
+
# Neocities redirect HTML file to location without extension and
|
143
|
+
# redirect index.html file to /
|
144
|
+
uri = uri.delete_suffix('index.html').delete_suffix('.html')
|
145
|
+
content = http.get(uri).body
|
146
|
+
check = Digest::SHA1.hexdigest content
|
147
|
+
return content if check == sha1sum
|
148
|
+
|
149
|
+
warn "SHA1 hash differ for #{uri}"
|
150
|
+
end
|
151
|
+
|
152
|
+
def save_file(path, content, updated_at)
|
153
|
+
File.write path, content
|
154
|
+
FileUtils.touch path, mtime: updated_at
|
155
|
+
path
|
156
|
+
end
|
157
|
+
|
158
|
+
def prepare_files_to_upload(file_list)
|
159
|
+
Dir.chdir(@public_folder) do
|
160
|
+
file_list.filter_map do |file_data|
|
161
|
+
# No need to push intermediary directories, they are created
|
162
|
+
# on the fly
|
163
|
+
next if file_data['is_directory']
|
164
|
+
|
165
|
+
path = file_data['path']
|
166
|
+
warn path if @verbose
|
167
|
+
[path, File.new(path)]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def upload_all(file_list, test: false)
|
173
|
+
form_data = prepare_files_to_upload file_list
|
174
|
+
return if test
|
175
|
+
|
176
|
+
request = build_request '/upload', :post
|
177
|
+
request.set_form form_data, 'multipart/form-data'
|
178
|
+
call request
|
179
|
+
end
|
180
|
+
|
181
|
+
def extract_connection_details(connection_spec)
|
182
|
+
# Do not put your password into the fronde config. The password
|
183
|
+
# is expectfed to be found in a specific config file (not to be
|
184
|
+
# shared).
|
185
|
+
@website_name, endpoint = connection_spec.split('@', 2)
|
186
|
+
endpoint ||= 'neocities.org'
|
187
|
+
@endpoint = URI("https://#{endpoint}/api")
|
188
|
+
# Will raise Errno::ENOENT if file does not exist
|
189
|
+
credentials = YAML.load_file('.credentials')
|
190
|
+
# Will raise KeyError if not set
|
191
|
+
password = credentials.fetch("#{@website_name}_neocities_pass")
|
192
|
+
authorization = [[@website_name, password].join(':')].pack('m0')
|
193
|
+
@authorization = "Basic #{authorization}"
|
194
|
+
end
|
195
|
+
|
196
|
+
def build_request(path, method = :get)
|
197
|
+
uri = @endpoint.dup
|
198
|
+
uri.path += path
|
199
|
+
klass = Kernel.const_get "Net::HTTP::#{method.to_s.capitalize}"
|
200
|
+
klass.new uri
|
201
|
+
end
|
202
|
+
|
203
|
+
def call(request)
|
204
|
+
request['Authorization'] = @authorization
|
205
|
+
@connection.start unless @connection.started?
|
206
|
+
outcome = @connection.request request
|
207
|
+
return outcome if outcome.is_a? Net::HTTPSuccess
|
208
|
+
|
209
|
+
raise JSON.parse(outcome.body).inspect
|
210
|
+
end
|
211
|
+
|
212
|
+
def init_connection
|
213
|
+
http = Net::HTTP.new @endpoint.host, 443
|
214
|
+
http.use_ssl = true
|
215
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
216
|
+
http
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../config'
|
4
|
+
|
5
|
+
module Fronde
|
6
|
+
module Sync
|
7
|
+
# Everything needed to push or pull data with rsync
|
8
|
+
class Rsync
|
9
|
+
def initialize(remote_path, local_path, verbose: false)
|
10
|
+
@verbose = verbose
|
11
|
+
@remote_path = remote_path
|
12
|
+
@local_path = "#{local_path}/"
|
13
|
+
end
|
14
|
+
|
15
|
+
def pull(test: false)
|
16
|
+
run command(test: test) + [@remote_path, @local_path]
|
17
|
+
end
|
18
|
+
|
19
|
+
def push(test: false)
|
20
|
+
run command(test: test) + [@local_path, @remote_path]
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def run(cmd)
|
26
|
+
warn cmd.join(' ') if @verbose
|
27
|
+
# Be precise about Kernel to allow mock in rspec
|
28
|
+
Kernel.system(*cmd)
|
29
|
+
end
|
30
|
+
|
31
|
+
def command(test: false)
|
32
|
+
rsync_command = Fronde::CONFIG.get('rsync')
|
33
|
+
return rsync_command unless rsync_command.nil?
|
34
|
+
|
35
|
+
optstring = []
|
36
|
+
optstring << 'n' if test
|
37
|
+
if @verbose
|
38
|
+
optstring << 'v'
|
39
|
+
else
|
40
|
+
optstring << 'q'
|
41
|
+
end
|
42
|
+
['rsync', "-#{optstring.join}rlt", '--delete']
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/fronde/sync.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'config'
|
4
|
+
require_relative 'sync/rsync'
|
5
|
+
require_relative 'sync/neocities'
|
6
|
+
|
7
|
+
module Fronde
|
8
|
+
# Entrypoint for synchronization with remote public server
|
9
|
+
module Sync
|
10
|
+
class Error < ::StandardError; end
|
11
|
+
|
12
|
+
ALLOWED_SYNCER = %w[rsync neocities].freeze
|
13
|
+
|
14
|
+
def self.extract_method_and_remote(type)
|
15
|
+
remote_path = Fronde::CONFIG.get("#{type}_remote")
|
16
|
+
raise Error, "No #{type} remote path set" if remote_path.nil?
|
17
|
+
|
18
|
+
method, remote = remote_path.split(':', 2)
|
19
|
+
return [method, remote] if ALLOWED_SYNCER.include?(method)
|
20
|
+
|
21
|
+
['rsync', remote_path]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.pull_or_push(direction, type, test: false, verbose: false)
|
25
|
+
method, remote_path = extract_method_and_remote type
|
26
|
+
public_folder = Fronde::CONFIG.get("#{type}_public_folder")
|
27
|
+
klass = Kernel.const_get("::Fronde::Sync::#{method.capitalize}")
|
28
|
+
syncer = klass.new(remote_path, public_folder, verbose: verbose)
|
29
|
+
Thread.new { syncer.send(direction, test: test) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/fronde/templater.rb
CHANGED
@@ -103,6 +103,18 @@ module Fronde
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
+
def warn_no_element(source)
|
107
|
+
pub_folder = Fronde::CONFIG.get('html_public_folder').sub(
|
108
|
+
/^#{Dir.pwd}/, '.'
|
109
|
+
)
|
110
|
+
warn(
|
111
|
+
R18n.t.fronde.error.templater.no_element_found(
|
112
|
+
source: source, file: "#{pub_folder}#{@org_file.pub_file}"
|
113
|
+
)
|
114
|
+
)
|
115
|
+
'' # Return empty string
|
116
|
+
end
|
117
|
+
|
106
118
|
def extract_content
|
107
119
|
# We must either have a source or a content key
|
108
120
|
source = @config.delete 'source'
|
@@ -111,19 +123,14 @@ module Fronde
|
|
111
123
|
end
|
112
124
|
|
113
125
|
node = @dom.css(source)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
source: source,
|
119
|
-
file: Fronde::CONFIG.get('html_public_folder') + @org_file.pub_file
|
120
|
-
)
|
121
|
-
)
|
122
|
-
return ''
|
126
|
+
if node.any?
|
127
|
+
# Put it back in config
|
128
|
+
@config['source'] = node
|
129
|
+
return node.to_s
|
123
130
|
end
|
124
131
|
|
125
|
-
|
126
|
-
|
132
|
+
# Do nothing if we don’t have a reliable content to work with
|
133
|
+
warn_no_element source
|
127
134
|
end
|
128
135
|
|
129
136
|
def check_path(file_name)
|
data/lib/fronde/version.rb
CHANGED
data/lib/tasks/org.rake
CHANGED
@@ -8,8 +8,7 @@ require_relative '../fronde/cli/throbber'
|
|
8
8
|
require 'rake/clean'
|
9
9
|
|
10
10
|
CLOBBER.push(
|
11
|
-
'var/lib/org-config.el', '.
|
12
|
-
'lib/htmlize.el'
|
11
|
+
'var/lib/org-config.el', 'lib/htmlize.el'
|
13
12
|
)
|
14
13
|
|
15
14
|
namespace :org do
|
@@ -26,19 +25,16 @@ namespace :org do
|
|
26
25
|
else
|
27
26
|
Fronde::CLI::Throbber.run(download, R18n.t.fronde.tasks.org.downloading)
|
28
27
|
end
|
29
|
-
rescue RuntimeError
|
28
|
+
rescue RuntimeError, Interrupt
|
30
29
|
warn R18n.t.fronde.tasks.org.no_download if verbose
|
31
30
|
end
|
32
31
|
|
33
32
|
desc 'Compile Org'
|
34
33
|
multitask compile: ['var/tmp/org.tar.gz', 'lib'] do |task|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
rescue RuntimeError
|
40
|
-
next
|
41
|
-
end
|
34
|
+
# No need to force fetch last version as it is only interesting as
|
35
|
+
# part of the upgrade task
|
36
|
+
org_version = Fronde::Org.last_version
|
37
|
+
|
42
38
|
org_dir = "lib/org-#{org_version}"
|
43
39
|
next if Dir.exist?("#{org_dir}/lisp")
|
44
40
|
|
@@ -54,6 +50,8 @@ namespace :org do
|
|
54
50
|
else
|
55
51
|
Fronde::CLI::Throbber.run(build, R18n.t.fronde.tasks.org.installing)
|
56
52
|
end
|
53
|
+
rescue RuntimeError, Interrupt
|
54
|
+
next
|
57
55
|
end
|
58
56
|
|
59
57
|
directory 'lib'
|
@@ -76,10 +74,6 @@ namespace :org do
|
|
76
74
|
Fronde::CONFIG.write_org_lisp_config
|
77
75
|
end
|
78
76
|
|
79
|
-
file '.dir-locals.el' => 'var/lib/org-config.el' do
|
80
|
-
Fronde::Config::Helpers.write_dir_locals
|
81
|
-
end
|
82
|
-
|
83
77
|
file '.gitignore' do
|
84
78
|
next if File.exist? '.gitignore'
|
85
79
|
|
@@ -91,9 +85,10 @@ namespace :org do
|
|
91
85
|
|
92
86
|
desc 'Install Org'
|
93
87
|
multitask install: ['org:compile', '.gitignore'] do
|
94
|
-
#
|
95
|
-
#
|
96
|
-
|
88
|
+
# lib/htmlize.el and lib/ox-gmi.el cannot be generated in parallel
|
89
|
+
# of org:compilation, as it will leads to a weird SSL error. Thus
|
90
|
+
# finishing file generation "manually" here.
|
91
|
+
Rake::Task['var/lib/org-config.el'].invoke
|
97
92
|
sources = Fronde::CONFIG.sources
|
98
93
|
sources.each { mkdir_p _1['path'] }
|
99
94
|
|
data/lib/tasks/site.rake
CHANGED
@@ -10,7 +10,7 @@ namespace :site do
|
|
10
10
|
task :build, [:force?] => ['var/lib/org-config.el'] do |_, args|
|
11
11
|
args.with_defaults(force?: false)
|
12
12
|
build_index = Thread.new do
|
13
|
-
all_index = Fronde::Index.
|
13
|
+
all_index = Fronde::Index.all_blog_index
|
14
14
|
all_index.each do |index|
|
15
15
|
index.write_all_org(verbose: verbose)
|
16
16
|
end
|
@@ -25,19 +25,11 @@ namespace :site do
|
|
25
25
|
end
|
26
26
|
all_indexes = build_index[:all_indexes]
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
Fronde::Emacs.new(verbose: verbose).publish
|
32
|
-
end
|
33
|
-
Fronde::CLI::Throbber.run(build_html, R18n.t.fronde.tasks.site.building)
|
34
|
-
|
35
|
-
# :nocov:
|
36
|
-
rescue RuntimeError
|
37
|
-
warn R18n.t.fronde.tasks.site.aborting
|
38
|
-
next
|
28
|
+
build_html = Thread.new do
|
29
|
+
rm_r 'var/tmp/timestamps', force: true if args[:force?]
|
30
|
+
Fronde::Emacs.new(verbose: verbose).publish
|
39
31
|
end
|
40
|
-
|
32
|
+
Fronde::CLI::Throbber.run(build_html, R18n.t.fronde.tasks.site.building)
|
41
33
|
|
42
34
|
if all_indexes.any?
|
43
35
|
if verbose
|
@@ -65,6 +57,11 @@ namespace :site do
|
|
65
57
|
Fronde::CLI::Throbber.run(
|
66
58
|
customize_html, R18n.t.fronde.tasks.site.customizing
|
67
59
|
)
|
60
|
+
# :nocov:
|
61
|
+
rescue RuntimeError, Interrupt
|
62
|
+
warn R18n.t.fronde.tasks.site.aborting
|
63
|
+
next
|
64
|
+
# :nocov:
|
68
65
|
end
|
69
66
|
|
70
67
|
desc 'Cleanup orphaned published files'
|
data/lib/tasks/sync.rake
CHANGED
@@ -1,40 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../fronde/config'
|
4
|
+
require_relative '../fronde/sync'
|
4
5
|
require_relative '../fronde/cli/throbber'
|
5
6
|
|
6
|
-
module Fronde
|
7
|
-
class SyncError < ::StandardError; end
|
8
|
-
end
|
9
|
-
|
10
|
-
def rsync_command(test = nil)
|
11
|
-
rsync_command = Fronde::CONFIG.get('rsync')
|
12
|
-
return rsync_command unless rsync_command.nil?
|
13
|
-
|
14
|
-
optstring = []
|
15
|
-
optstring << 'n' if test
|
16
|
-
if verbose
|
17
|
-
optstring << 'v'
|
18
|
-
else
|
19
|
-
optstring << 'q'
|
20
|
-
end
|
21
|
-
"rsync -#{optstring.join}rlt --delete"
|
22
|
-
end
|
23
|
-
|
24
|
-
def pull_or_push(direction, type, test)
|
25
|
-
remote_path = Fronde::CONFIG.get("#{type}_remote")
|
26
|
-
raise Fronde::SyncError, "No #{type} remote path set" if remote_path.nil?
|
27
|
-
|
28
|
-
public_folder = Fronde::CONFIG.get("#{type}_public_folder")
|
29
|
-
# Default is to push
|
30
|
-
cmd = ["#{public_folder}/", remote_path]
|
31
|
-
cmd.reverse! if direction == :pull
|
32
|
-
rsync = rsync_command(test)
|
33
|
-
Thread.new do
|
34
|
-
sh "#{rsync} #{cmd.join(' ')}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
7
|
def source_types
|
39
8
|
Fronde::CONFIG.sources.map(&:type).uniq
|
40
9
|
end
|
@@ -43,7 +12,9 @@ namespace :sync do
|
|
43
12
|
desc 'Push changes to server'
|
44
13
|
task :push, :test? do |_, args|
|
45
14
|
source_types.each do |type|
|
46
|
-
publish_thread = pull_or_push(
|
15
|
+
publish_thread = Fronde::Sync.pull_or_push(
|
16
|
+
:push, type, test: args[:test?], verbose: verbose
|
17
|
+
)
|
47
18
|
if verbose
|
48
19
|
publish_thread.join
|
49
20
|
else
|
@@ -51,16 +22,20 @@ namespace :sync do
|
|
51
22
|
publish_thread, format('Publishing %<fmt>s:', fmt: type)
|
52
23
|
)
|
53
24
|
end
|
54
|
-
rescue Fronde::
|
25
|
+
rescue Fronde::Sync::Error => e
|
55
26
|
warn e
|
56
27
|
next
|
57
28
|
end
|
29
|
+
rescue RuntimeError, Interrupt
|
30
|
+
next
|
58
31
|
end
|
59
32
|
|
60
33
|
desc 'Pull changes from server'
|
61
34
|
task :pull, :test? do |_, args|
|
62
35
|
source_types.each do |type|
|
63
|
-
pull_thread = pull_or_push(
|
36
|
+
pull_thread = Fronde::Sync.pull_or_push(
|
37
|
+
:pull, type, test: args[:test?], verbose: verbose
|
38
|
+
)
|
64
39
|
if verbose
|
65
40
|
pull_thread.join
|
66
41
|
else
|
@@ -68,9 +43,11 @@ namespace :sync do
|
|
68
43
|
pull_thread, format('Pulling %<fmt>s:', fmt: type)
|
69
44
|
)
|
70
45
|
end
|
71
|
-
rescue Fronde::
|
46
|
+
rescue Fronde::Sync::Error => e
|
72
47
|
warn e
|
73
48
|
next
|
74
49
|
end
|
50
|
+
rescue RuntimeError, Interrupt
|
51
|
+
next
|
75
52
|
end
|
76
53
|
end
|
data/lib/tasks/tags.rake
CHANGED
@@ -5,7 +5,7 @@ require_relative '../fronde/index'
|
|
5
5
|
namespace :tags do
|
6
6
|
desc 'List all tags by name'
|
7
7
|
task :name do
|
8
|
-
Fronde::Index.
|
8
|
+
Fronde::Index.all_blog_index do |index|
|
9
9
|
next if index.empty?
|
10
10
|
|
11
11
|
puts index.sort_by(:name).join("\n")
|
@@ -14,7 +14,7 @@ namespace :tags do
|
|
14
14
|
|
15
15
|
desc 'List all tags by weight'
|
16
16
|
task :weight do
|
17
|
-
Fronde::Index.
|
17
|
+
Fronde::Index.all_blog_index do |index|
|
18
18
|
next if index.empty?
|
19
19
|
|
20
20
|
puts index.sort_by(:weight).join("\n")
|
data/locales/en.yml
CHANGED