fronde 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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