fronde 0.3.3 → 0.4.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/bin/fronde +15 -30
- data/lib/ext/nil_time.rb +25 -0
- data/lib/ext/r18n.rb +17 -0
- data/lib/ext/time.rb +49 -0
- data/lib/fronde/cli/commands.rb +92 -103
- data/lib/fronde/cli/data/Rakefile +8 -0
- data/lib/fronde/cli/data/config.yml +13 -0
- data/lib/fronde/cli/data/gitignore +7 -0
- data/lib/fronde/cli/data/zsh_completion +37 -0
- data/lib/fronde/cli/helpers.rb +55 -0
- data/lib/fronde/cli/opt_parse.rb +143 -0
- data/lib/fronde/cli/throbber.rb +99 -0
- data/lib/fronde/cli.rb +41 -42
- data/lib/fronde/config/data/org-config.el +24 -0
- data/lib/fronde/config/{ox-fronde.el → data/ox-fronde.el} +1 -1
- data/lib/fronde/config/helpers.rb +80 -0
- data/lib/fronde/config/lisp.rb +70 -0
- data/lib/fronde/config.rb +135 -99
- data/lib/fronde/emacs.rb +23 -20
- data/lib/fronde/index/atom_generator.rb +55 -66
- data/lib/fronde/index/data/all_tags.org +14 -0
- data/lib/fronde/index/data/template.org +22 -0
- data/lib/fronde/index/data/template.xml +37 -0
- data/lib/fronde/index/org_generator.rb +70 -88
- data/lib/fronde/index.rb +56 -82
- data/lib/fronde/org/file.rb +287 -0
- data/lib/fronde/org/file_extracter.rb +98 -0
- data/lib/fronde/org.rb +103 -0
- data/lib/fronde/preview.rb +43 -39
- data/lib/fronde/slug.rb +27 -0
- data/lib/fronde/source/gemini.rb +39 -0
- data/lib/fronde/source/html.rb +67 -0
- data/lib/fronde/source.rb +204 -0
- data/lib/fronde/templater.rb +94 -71
- data/lib/fronde/version.rb +1 -1
- data/lib/tasks/cli.rake +33 -0
- data/lib/tasks/org.rake +63 -43
- data/lib/tasks/site.rake +68 -30
- data/lib/tasks/sync.rake +41 -21
- data/lib/tasks/tags.rake +11 -7
- data/locales/en.yml +60 -14
- data/locales/fr.yml +68 -14
- metadata +57 -156
- data/lib/fronde/config/lisp_config.rb +0 -340
- data/lib/fronde/config/org-config.el +0 -19
- data/lib/fronde/org_file/class_methods.rb +0 -72
- data/lib/fronde/org_file/extracter.rb +0 -72
- data/lib/fronde/org_file/htmlizer.rb +0 -43
- data/lib/fronde/org_file.rb +0 -298
- data/lib/fronde/utils.rb +0 -229
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fronde
|
4
|
+
class Source
|
5
|
+
# Specific settings for HTML {Fronde::Source}
|
6
|
+
class Html < Source
|
7
|
+
def org_config
|
8
|
+
config = super
|
9
|
+
config[0]['theme'] = @config['theme']
|
10
|
+
config
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def org_default_postamble
|
15
|
+
<<~POSTAMBLE
|
16
|
+
<p><span class="author">#{R18n.t.fronde.org.postamble.written_by}</span>
|
17
|
+
#{R18n.t.fronde.org.postamble.with_emacs_html}</p>
|
18
|
+
<p class="date">#{R18n.t.fronde.org.postamble.last_modification}</p>
|
19
|
+
<p class="validation">%v</p>
|
20
|
+
POSTAMBLE
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def fill_in_specific_config
|
27
|
+
@config.merge!(
|
28
|
+
'type' => 'html', 'ext' => '.html', 'mime_type' => 'text/html',
|
29
|
+
'folder' => CONFIG.get('html_public_folder')
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def org_publish_options
|
34
|
+
if @config['is_blog']
|
35
|
+
@config['atom_feed'] = <<~ATOMFEED
|
36
|
+
<link rel="alternate" type="application/atom+xml" title="#{@config['title']}"
|
37
|
+
href="#{@config['domain']}#{public_absolute_path}feeds/index.xml" />
|
38
|
+
ATOMFEED
|
39
|
+
end
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
def org_default_options # rubocop:disable Metrics/MethodLength
|
44
|
+
defaults = {
|
45
|
+
'publishing-function' => 'org-html-publish-to-html',
|
46
|
+
'html-head-include-default-style' => 't',
|
47
|
+
'html-head-include-scripts' => 't',
|
48
|
+
'html-head' => '{{ atom_feed }}',
|
49
|
+
'html-postamble' => Html.org_default_postamble
|
50
|
+
}
|
51
|
+
return defaults if @config['theme'] == 'default'
|
52
|
+
|
53
|
+
defaults.merge(
|
54
|
+
'html-head-include-default-style' => 'nil',
|
55
|
+
'html-head-include-scripts' => 'nil',
|
56
|
+
'html-head' => <<~HTMLHEAD
|
57
|
+
<link rel="stylesheet" type="text/css" media="screen"
|
58
|
+
href="{{ domain }}/assets/{{ theme }}/css/style.css">
|
59
|
+
<link rel="stylesheet" type="text/css" media="screen"
|
60
|
+
href="{{ domain }}/assets/{{ theme }}/css/htmlize.css">
|
61
|
+
{{ atom_feed }}
|
62
|
+
HTMLHEAD
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fronde
|
4
|
+
# Wrapper for each possible project source.
|
5
|
+
# Must be subclassed by specific source type (like Gemini or HTML)
|
6
|
+
class Source
|
7
|
+
def initialize(source_config)
|
8
|
+
@config = {
|
9
|
+
'recursive' => true, 'is_blog' => false,
|
10
|
+
'domain' => CONFIG.get('domain'), 'atom_feed' => '',
|
11
|
+
'org-options' => {
|
12
|
+
'section-numbers' => 'nil', 'with-toc' => 'nil'
|
13
|
+
}
|
14
|
+
}.merge(source_config)
|
15
|
+
clean_config
|
16
|
+
org_publish_options
|
17
|
+
render_heading
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key)
|
21
|
+
@config[key]
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(key, value)
|
25
|
+
@config[key] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
@config['type']
|
30
|
+
end
|
31
|
+
|
32
|
+
def recursive?
|
33
|
+
!!@config['recursive']
|
34
|
+
end
|
35
|
+
|
36
|
+
def blog?
|
37
|
+
!!@config['is_blog']
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_h
|
41
|
+
@config
|
42
|
+
end
|
43
|
+
|
44
|
+
def source_for?(file_name)
|
45
|
+
relative_file_path = file_name.delete_prefix "#{@config['path']}/"
|
46
|
+
# file_name does not begin with source path.
|
47
|
+
return false if relative_file_path == file_name
|
48
|
+
|
49
|
+
# Looks like a file at a deeper level, but current source is not
|
50
|
+
# recursive.
|
51
|
+
return false if relative_file_path.include?('/') && !recursive?
|
52
|
+
|
53
|
+
# We don’t check file if the file really exist as the current
|
54
|
+
# check may be done before the file is actually written.
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def source_for(file_name)
|
59
|
+
relative_file_path = file_name.delete_prefix "#{publication_path}/"
|
60
|
+
# file_name does not begin with source path.
|
61
|
+
return nil if relative_file_path == file_name
|
62
|
+
|
63
|
+
# Looks like a file at a deeper level, but current source is not
|
64
|
+
# recursive.
|
65
|
+
return nil if relative_file_path.include?('/') && !recursive?
|
66
|
+
|
67
|
+
# Looks like a match. But does a source file for this one actually
|
68
|
+
# exists?
|
69
|
+
relative_source_path = relative_file_path.sub(
|
70
|
+
/#{@config['ext']}\z/, '.org'
|
71
|
+
)
|
72
|
+
source_path = File.join(@config['path'], relative_source_path)
|
73
|
+
return nil unless File.file?(source_path)
|
74
|
+
|
75
|
+
source_path
|
76
|
+
end
|
77
|
+
|
78
|
+
def target_for(file_name)
|
79
|
+
target = File.expand_path file_name
|
80
|
+
target.delete_prefix! "#{Dir.pwd}/"
|
81
|
+
target.sub!(/\.org\z/, @config['ext'])
|
82
|
+
project_relative_path = @config['path'].delete_prefix("#{Dir.pwd}/")
|
83
|
+
target.delete_prefix! "#{project_relative_path}/"
|
84
|
+
public_absolute_path + target
|
85
|
+
end
|
86
|
+
|
87
|
+
def exclude_file?(file_name)
|
88
|
+
# Obviously excluding index itself for blogs
|
89
|
+
return true if file_name == File.join(@config['path'], 'index.org')
|
90
|
+
|
91
|
+
exclusion_rules = @config['exclude']
|
92
|
+
return false unless exclusion_rules
|
93
|
+
|
94
|
+
file_name.match? exclusion_rules
|
95
|
+
end
|
96
|
+
|
97
|
+
def org_config
|
98
|
+
name = @config['name']
|
99
|
+
[{ 'name' => name, 'attributes' => org_project_config },
|
100
|
+
{ 'name' => "#{name}-assets", 'attributes' => org_assets_config }]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return the publication absolute path on file system.
|
104
|
+
#
|
105
|
+
# The returned string never end with a slash (/).
|
106
|
+
#
|
107
|
+
# Use {Fronde::Source#public_absolute_path} to get the absolute path
|
108
|
+
# of this project, as seen from a web browser.
|
109
|
+
#
|
110
|
+
# @return [String] the absolute path to the target dir of this project
|
111
|
+
def publication_path
|
112
|
+
return @config['publication_path'] if @config['publication_path']
|
113
|
+
|
114
|
+
publish_in = [File.expand_path(@config['folder']), @config['target']]
|
115
|
+
@config['publication_path'] = publish_in.join('/').delete_suffix('/')
|
116
|
+
end
|
117
|
+
|
118
|
+
# Return the absolute path as seen in User Agent.
|
119
|
+
#
|
120
|
+
# The returned string always end with a slash (/).
|
121
|
+
#
|
122
|
+
# Use {Fronde::Source#publication_path} to locate published file on
|
123
|
+
# the file system.
|
124
|
+
#
|
125
|
+
# @return [String] the absolute path to this project
|
126
|
+
def public_absolute_path
|
127
|
+
return @config['public_absolute_path'] if @config['public_absolute_path']
|
128
|
+
|
129
|
+
@config['public_absolute_path'] = "/#{@config['target']}/".squeeze('/')
|
130
|
+
end
|
131
|
+
|
132
|
+
class << self
|
133
|
+
def canonical_config(config)
|
134
|
+
config = { 'path' => config } if config.is_a?(String)
|
135
|
+
config['type'] ||= 'html'
|
136
|
+
config
|
137
|
+
end
|
138
|
+
|
139
|
+
def new_from_config(config)
|
140
|
+
klass_name = config['type'].capitalize
|
141
|
+
klass = Kernel.const_get("::Fronde::Source::#{klass_name}")
|
142
|
+
klass.new(config)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def clean_config
|
149
|
+
fill_in_specific_config
|
150
|
+
@config['name'] ||= @config['path'].sub(/^[.~]*\//, '').tr('/.', '-')
|
151
|
+
@config['title'] ||= @config['path']
|
152
|
+
@config['target'] ||= File.basename(@config['path']).delete_prefix '.'
|
153
|
+
@config['target'] = '' if @config['target'] == '.'
|
154
|
+
@config['path'] = File.expand_path(@config['path'])
|
155
|
+
@config['theme'] ||= CONFIG.get('theme', 'default')
|
156
|
+
# Blog are necessarily recursive to allow publication of tags and feeds
|
157
|
+
@config['recursive'] = true if @config['is_blog']
|
158
|
+
end
|
159
|
+
|
160
|
+
def org_publish_options
|
161
|
+
type = @config['type']
|
162
|
+
options = org_default_options.merge(
|
163
|
+
@config['org-options'],
|
164
|
+
CONFIG.get("org-#{type}", {}),
|
165
|
+
@config["org-#{type}"] || {}
|
166
|
+
)
|
167
|
+
@config['org-options'] = options
|
168
|
+
end
|
169
|
+
|
170
|
+
def render_heading
|
171
|
+
heading_key = "#{@config['type']}-head"
|
172
|
+
heading = @config.dig 'org-options', heading_key
|
173
|
+
@config['org-options'][heading_key] = \
|
174
|
+
Config::Helpers.render_liquid_template(
|
175
|
+
heading, to_h
|
176
|
+
)
|
177
|
+
end
|
178
|
+
|
179
|
+
def org_project_config
|
180
|
+
attributes = {
|
181
|
+
'base-directory' => @config['path'],
|
182
|
+
'base-extension' => 'org',
|
183
|
+
'publishing-directory' => publication_path,
|
184
|
+
'recursive' => @config['recursive']
|
185
|
+
}.merge(@config['org-options'])
|
186
|
+
exclude = @config['exclude']
|
187
|
+
attributes['exclude'] = exclude if exclude
|
188
|
+
attributes.sort.to_h # Have lisp config sorted
|
189
|
+
end
|
190
|
+
|
191
|
+
def org_assets_config
|
192
|
+
{
|
193
|
+
'base-directory' => @config['path'],
|
194
|
+
'base-extension' => %w[gif jpg png svg pdf].join('\\\\|'),
|
195
|
+
'publishing-directory' => publication_path,
|
196
|
+
'publishing-function' => 'org-publish-attachment',
|
197
|
+
'recursive' => @config['recursive']
|
198
|
+
}
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
require_relative 'source/gemini'
|
204
|
+
require_relative 'source/html'
|
data/lib/fronde/templater.rb
CHANGED
@@ -2,117 +2,140 @@
|
|
2
2
|
|
3
3
|
require 'nokogiri'
|
4
4
|
require 'digest/md5'
|
5
|
-
|
5
|
+
require_relative 'org/file'
|
6
6
|
|
7
7
|
module Fronde
|
8
|
+
class NoHeadError < ::StandardError; end
|
9
|
+
|
8
10
|
# Insert custom part inside generated HTML files.
|
9
11
|
class Templater
|
10
|
-
def initialize(source, dom,
|
12
|
+
def initialize(source, dom, config = {})
|
11
13
|
@dom = dom
|
12
14
|
@org_file = source
|
13
|
-
@
|
14
|
-
|
15
|
-
@
|
16
|
-
digest = Digest::MD5.hexdigest(@content)
|
17
|
-
@check_line = " Fronde Template: #{digest} "
|
15
|
+
@config = { 'type' => 'after' }.merge(config)
|
16
|
+
digest = Digest::MD5.hexdigest(config.to_s)
|
17
|
+
@config['check_line'] = " Fronde Template: #{digest} "
|
18
18
|
end
|
19
19
|
|
20
20
|
def apply
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
# Flag the file for this template
|
22
|
+
head = @dom.xpath('//head').first
|
23
|
+
raise NoHeadError, self unless head
|
24
|
+
|
25
|
+
head.prepend_child("<!--#{@config['check_line']}-->")
|
26
|
+
content = @org_file.format extract_content
|
27
|
+
# Remove source element if necessary to avoid doubling it during
|
28
|
+
# the insert action
|
29
|
+
@config['source'].unlink if @config.has_key? 'source'
|
30
|
+
# Insert new content
|
31
|
+
@dom.css(@config['selector']).each do |element|
|
32
|
+
insert_new_node_at element, content
|
25
33
|
end
|
26
34
|
end
|
27
35
|
|
28
36
|
def in_head?
|
29
|
-
@dom.xpath('//head').children.
|
30
|
-
|
37
|
+
@dom.xpath('//head').children.any? do |child|
|
38
|
+
next false unless child.comment?
|
39
|
+
|
40
|
+
child.text == @config['check_line']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid?(file_name)
|
45
|
+
return false unless @config.has_key?('selector')
|
46
|
+
|
47
|
+
unless @config.has_key?('content') || @config.has_key?('source')
|
48
|
+
return false
|
31
49
|
end
|
32
|
-
|
50
|
+
|
51
|
+
check_path(file_name)
|
33
52
|
end
|
34
53
|
|
35
54
|
class << self
|
36
|
-
def customize_output(file_name
|
37
|
-
|
38
|
-
|
39
|
-
if source.
|
40
|
-
|
41
|
-
source = Fronde::OrgFile.new(sourcepath)
|
42
|
-
end
|
55
|
+
def customize_output(file_name)
|
56
|
+
source = Fronde::Org::File.new(file_name)
|
57
|
+
# Return if no org file found for this published file
|
58
|
+
return if source.file.end_with?(file_name)
|
59
|
+
|
43
60
|
dom = open_dom(file_name)
|
44
|
-
|
45
|
-
|
46
|
-
next if tpl.in_head?
|
47
|
-
tpl.apply
|
48
|
-
end
|
49
|
-
write_dom(file_name, dom)
|
61
|
+
updated = apply_templates(source, dom, file_name)
|
62
|
+
write_dom(file_name, dom) if updated
|
50
63
|
end
|
51
64
|
|
52
65
|
private
|
53
66
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
67
|
+
def apply_templates(source, dom, file_name)
|
68
|
+
Fronde::CONFIG.get('templates', []).map do |config|
|
69
|
+
template = Fronde::Templater.new(source, dom, config)
|
70
|
+
next if !template.valid?(file_name) || template.in_head?
|
71
|
+
|
72
|
+
template.apply
|
73
|
+
true
|
74
|
+
rescue NoHeadError
|
75
|
+
warn R18n.t.fronde.error.templater.no_head_element(file: file_name)
|
76
|
+
next
|
77
|
+
end.any?
|
58
78
|
end
|
59
79
|
|
60
80
|
def open_dom(file_name)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
dom
|
81
|
+
File.open(file_name, 'r') do |file|
|
82
|
+
Nokogiri::HTML file
|
83
|
+
end
|
65
84
|
end
|
66
85
|
|
67
86
|
def write_dom(file_name, dom)
|
68
|
-
|
69
|
-
|
70
|
-
file.close
|
71
|
-
end
|
72
|
-
|
73
|
-
def check_path(file_name, pathes)
|
74
|
-
pub_folder = Fronde::Config.get('public_folder')
|
75
|
-
if pathes.is_a?(Array)
|
76
|
-
pathes.each do |tp|
|
77
|
-
return true if File.fnmatch?("#{pub_folder}#{tp}",
|
78
|
-
file_name, File::FNM_DOTMATCH)
|
79
|
-
end
|
80
|
-
return false
|
87
|
+
File.open(file_name, 'w') do |file|
|
88
|
+
dom.write_to file
|
81
89
|
end
|
82
|
-
File.fnmatch?("#{pub_folder}#{pathes}",
|
83
|
-
file_name, File::FNM_DOTMATCH)
|
84
|
-
end
|
85
|
-
|
86
|
-
def check_required_keys(opts, file_name)
|
87
|
-
return false unless opts.has_key?('selector')
|
88
|
-
return false unless opts.has_key?('content') || opts.has_key?('source')
|
89
|
-
return check_path(file_name, opts['path']) if opts.has_key?('path')
|
90
|
-
true
|
91
90
|
end
|
92
91
|
end
|
93
92
|
|
94
93
|
private
|
95
94
|
|
96
|
-
def
|
97
|
-
@
|
98
|
-
end
|
99
|
-
|
100
|
-
def insert_new_node_at(elem, content)
|
101
|
-
case @position
|
95
|
+
def insert_new_node_at(element, content)
|
96
|
+
case @config['type']
|
102
97
|
when 'before'
|
103
|
-
|
98
|
+
element.add_previous_sibling content
|
104
99
|
when 'replace'
|
105
|
-
|
100
|
+
element.replace content
|
106
101
|
else
|
107
|
-
|
102
|
+
element.add_next_sibling content
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def extract_content
|
107
|
+
# We must either have a source or a content key
|
108
|
+
source = @config.delete 'source'
|
109
|
+
unless source.is_a?(String) && source != ''
|
110
|
+
return @config['content'] || ''
|
111
|
+
end
|
112
|
+
|
113
|
+
node = @dom.css(source)
|
114
|
+
# Do nothing if we don’t have a reliable content to work with
|
115
|
+
unless node.any?
|
116
|
+
warn(
|
117
|
+
R18n.t.fronde.error.templater.no_element_found(
|
118
|
+
source: source,
|
119
|
+
file: Fronde::CONFIG.get('html_public_folder') + @org_file.pub_file
|
120
|
+
)
|
121
|
+
)
|
122
|
+
return ''
|
108
123
|
end
|
124
|
+
|
125
|
+
@config['source'] = node
|
126
|
+
node.to_s
|
109
127
|
end
|
110
128
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
129
|
+
def check_path(file_name)
|
130
|
+
paths = @config['path']
|
131
|
+
return true unless paths
|
132
|
+
|
133
|
+
paths = [paths] unless paths.is_a? Array
|
134
|
+
|
135
|
+
pub_folder = Fronde::CONFIG.get('html_public_folder')
|
136
|
+
paths.any? do |template_path|
|
137
|
+
File.fnmatch?("#{pub_folder}#{template_path}", file_name)
|
138
|
+
end
|
116
139
|
end
|
117
140
|
end
|
118
141
|
end
|
data/lib/fronde/version.rb
CHANGED
data/lib/tasks/cli.rake
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../fronde/cli/opt_parse'
|
4
|
+
|
5
|
+
namespace :cli do
|
6
|
+
desc 'Generate an autocomplete file for zsh'
|
7
|
+
task :zsh_complete do
|
8
|
+
data = {}
|
9
|
+
all_commands = Fronde::CLI::OptParse::FRONDE_COMMANDS
|
10
|
+
data['commands'] = all_commands.filter_map do |command, options|
|
11
|
+
next if options[:alias] || command == 'basic'
|
12
|
+
|
13
|
+
opts = (options[:opts] || []).map do |opt|
|
14
|
+
opt_config = Fronde::CLI::OptParse::FRONDE_OPTIONS[opt]
|
15
|
+
keyword = nil
|
16
|
+
unless opt_config[:boolean]
|
17
|
+
keyword = opt_config[:keyword] || opt_config[:long].upcase
|
18
|
+
end
|
19
|
+
{ 'short' => opt,
|
20
|
+
'long' => "--#{opt_config[:long]}",
|
21
|
+
'keyword' => keyword }
|
22
|
+
end
|
23
|
+
|
24
|
+
translation = R18n.t.fronde.bin.commands[command].tr("'", '’')
|
25
|
+
{ 'name' => command,
|
26
|
+
'translation' => translation,
|
27
|
+
'options' => opts }
|
28
|
+
end
|
29
|
+
source = File.expand_path '../fronde/cli/data/zsh_completion', __dir__
|
30
|
+
template = Liquid::Template.parse(File.read(source))
|
31
|
+
puts template.render(data)
|
32
|
+
end
|
33
|
+
end
|
data/lib/tasks/org.rake
CHANGED
@@ -2,61 +2,57 @@
|
|
2
2
|
|
3
3
|
require 'open-uri'
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
require_relative '../fronde/config'
|
6
|
+
require_relative '../fronde/cli/throbber'
|
7
7
|
|
8
8
|
require 'rake/clean'
|
9
9
|
|
10
10
|
CLOBBER.push(
|
11
|
-
'var/
|
12
|
-
'
|
11
|
+
'var/lib/org-config.el', '.dir-locals.el',
|
12
|
+
'lib/htmlize.el'
|
13
13
|
)
|
14
14
|
|
15
|
-
def make_org_cmd(org_dir, target)
|
16
|
-
make = ['make', '-C', org_dir, target]
|
17
|
-
return make.join(' ') if verbose
|
18
|
-
make.insert(3, '-s')
|
19
|
-
make << 'EMACSQ="emacs -Q --eval \'(setq inhibit-message t)\'"'
|
20
|
-
make.join(' ')
|
21
|
-
end
|
22
|
-
|
23
15
|
namespace :org do
|
24
16
|
directory 'var/tmp'
|
25
17
|
|
26
18
|
desc 'Download last version of Org'
|
27
19
|
file 'var/tmp/org.tar.gz' => 'var/tmp' do
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
# Weird Rake issue, still executing the task even if the file exists
|
21
|
+
next if File.exist? 'var/tmp/org.tar.gz'
|
22
|
+
|
23
|
+
download = Thread.new { Fronde::Org.download }
|
32
24
|
if verbose
|
33
|
-
download.
|
34
|
-
warn "Org version #{download[:org_version]} has been downloaded"
|
25
|
+
warn R18n.t.fronde.tasks.org.downloaded(version: download.value)
|
35
26
|
else
|
36
|
-
Fronde::
|
27
|
+
Fronde::CLI::Throbber.run(download, R18n.t.fronde.tasks.org.downloading)
|
37
28
|
end
|
29
|
+
rescue RuntimeError
|
30
|
+
warn R18n.t.fronde.tasks.org.no_download if verbose
|
38
31
|
end
|
39
32
|
|
40
33
|
desc 'Compile Org'
|
41
|
-
|
42
|
-
|
34
|
+
multitask compile: ['var/tmp/org.tar.gz', 'lib'] do |task|
|
35
|
+
begin
|
36
|
+
# No need to force fetch last version as it is only interesting as
|
37
|
+
# part of the upgrade task
|
38
|
+
org_version = Fronde::Org.last_version
|
39
|
+
rescue RuntimeError
|
40
|
+
next
|
41
|
+
end
|
43
42
|
org_dir = "lib/org-#{org_version}"
|
44
43
|
next if Dir.exist?("#{org_dir}/lisp")
|
44
|
+
|
45
45
|
build = Thread.new do
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
Dir.glob('lib/org-[0-9.]*').each do |ov|
|
51
|
-
next if ov == org_dir
|
52
|
-
rm_r ov
|
53
|
-
end
|
46
|
+
Fronde::Org.compile(
|
47
|
+
task.prerequisites[0], org_version, org_dir, verbose: verbose
|
48
|
+
)
|
49
|
+
Dir.glob('lib/org-[0-9.]*').each { rm_r _1 unless _1 == org_dir }
|
54
50
|
end
|
55
51
|
if verbose
|
56
52
|
build.join
|
57
|
-
warn
|
53
|
+
warn R18n.t.fronde.tasks.org.installed(version: org_version)
|
58
54
|
else
|
59
|
-
Fronde::
|
55
|
+
Fronde::CLI::Throbber.run(build, R18n.t.fronde.tasks.org.installing)
|
60
56
|
end
|
61
57
|
end
|
62
58
|
|
@@ -71,35 +67,59 @@ namespace :org do
|
|
71
67
|
|
72
68
|
file 'lib/ox-gmi.el' => 'lib' do
|
73
69
|
ox_gmi = URI(
|
74
|
-
'https://git.umaneti.net/ox-gmi
|
70
|
+
'https://git.umaneti.net/ox-gmi/plain/ox-gmi.el'
|
75
71
|
).open.read
|
76
72
|
File.write 'lib/ox-gmi.el', ox_gmi
|
77
73
|
end
|
78
74
|
|
79
75
|
file 'var/lib/org-config.el' => ['lib/htmlize.el', 'lib/ox-gmi.el'] do
|
80
|
-
Fronde::
|
76
|
+
Fronde::CONFIG.write_org_lisp_config
|
81
77
|
end
|
82
78
|
|
83
79
|
file '.dir-locals.el' => 'var/lib/org-config.el' do
|
84
|
-
Fronde::Config.write_dir_locals
|
80
|
+
Fronde::Config::Helpers.write_dir_locals
|
81
|
+
end
|
82
|
+
|
83
|
+
file '.gitignore' do
|
84
|
+
next if File.exist? '.gitignore'
|
85
|
+
|
86
|
+
upstream = File.expand_path(
|
87
|
+
'../fronde/cli/data/gitignore', __dir__
|
88
|
+
)
|
89
|
+
cp upstream, '.gitignore'
|
85
90
|
end
|
86
91
|
|
87
92
|
desc 'Install Org'
|
88
|
-
multitask install: ['org:compile', '.
|
89
|
-
|
90
|
-
|
91
|
-
|
93
|
+
multitask install: ['org:compile', '.gitignore'] do
|
94
|
+
# I need a fully installed org mode to correctly generate the lisp
|
95
|
+
# config
|
96
|
+
Rake::Task['.dir-locals.el'].invoke
|
97
|
+
sources = Fronde::CONFIG.sources
|
98
|
+
sources.each { mkdir_p _1['path'] }
|
99
|
+
|
100
|
+
outputs = sources.map { _1['type'] }.uniq
|
101
|
+
if outputs.include?('html')
|
102
|
+
mkdir_p "#{Fronde::CONFIG.get('html_public_folder')}/assets"
|
103
|
+
end
|
104
|
+
if outputs.include?('gemini')
|
105
|
+
mkdir_p Fronde::CONFIG.get('gemini_public_folder')
|
92
106
|
end
|
93
107
|
end
|
94
108
|
|
95
|
-
# The following task only run the clobber task (not provided by us)
|
96
|
-
# and the org:install one, which is already tested. Thus, we can
|
97
|
-
# safely remove it from coverage.
|
98
|
-
# :nocov:
|
99
109
|
desc 'Upgrade Org'
|
100
110
|
task :upgrade do
|
101
111
|
Rake::Task['clobber'].execute
|
112
|
+
if File.exist? 'var/tmp/org.tar.gz'
|
113
|
+
# Cleanup cached tarball only if a new version is available.
|
114
|
+
# Also cached the new remote org version in the same time.
|
115
|
+
org_version = Fronde::Org.current_version
|
116
|
+
begin
|
117
|
+
last_version = Fronde::Org.last_version(force: true)
|
118
|
+
rescue RuntimeError
|
119
|
+
last_version = org_version
|
120
|
+
end
|
121
|
+
File.unlink 'var/tmp/org.tar.gz' unless org_version == last_version
|
122
|
+
end
|
102
123
|
Rake::Task['org:install'].invoke
|
103
124
|
end
|
104
|
-
# :nocov:
|
105
125
|
end
|