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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/bin/fronde +15 -30
  3. data/lib/ext/nil_time.rb +25 -0
  4. data/lib/ext/r18n.rb +17 -0
  5. data/lib/ext/time.rb +49 -0
  6. data/lib/fronde/cli/commands.rb +92 -103
  7. data/lib/fronde/cli/data/Rakefile +8 -0
  8. data/lib/fronde/cli/data/config.yml +13 -0
  9. data/lib/fronde/cli/data/gitignore +7 -0
  10. data/lib/fronde/cli/data/zsh_completion +37 -0
  11. data/lib/fronde/cli/helpers.rb +55 -0
  12. data/lib/fronde/cli/opt_parse.rb +143 -0
  13. data/lib/fronde/cli/throbber.rb +99 -0
  14. data/lib/fronde/cli.rb +41 -42
  15. data/lib/fronde/config/data/org-config.el +24 -0
  16. data/lib/fronde/config/{ox-fronde.el → data/ox-fronde.el} +1 -1
  17. data/lib/fronde/config/helpers.rb +80 -0
  18. data/lib/fronde/config/lisp.rb +70 -0
  19. data/lib/fronde/config.rb +135 -99
  20. data/lib/fronde/emacs.rb +23 -20
  21. data/lib/fronde/index/atom_generator.rb +55 -66
  22. data/lib/fronde/index/data/all_tags.org +14 -0
  23. data/lib/fronde/index/data/template.org +22 -0
  24. data/lib/fronde/index/data/template.xml +37 -0
  25. data/lib/fronde/index/org_generator.rb +70 -88
  26. data/lib/fronde/index.rb +56 -82
  27. data/lib/fronde/org/file.rb +287 -0
  28. data/lib/fronde/org/file_extracter.rb +98 -0
  29. data/lib/fronde/org.rb +103 -0
  30. data/lib/fronde/preview.rb +43 -39
  31. data/lib/fronde/slug.rb +27 -0
  32. data/lib/fronde/source/gemini.rb +39 -0
  33. data/lib/fronde/source/html.rb +67 -0
  34. data/lib/fronde/source.rb +204 -0
  35. data/lib/fronde/templater.rb +94 -71
  36. data/lib/fronde/version.rb +1 -1
  37. data/lib/tasks/cli.rake +33 -0
  38. data/lib/tasks/org.rake +63 -43
  39. data/lib/tasks/site.rake +68 -30
  40. data/lib/tasks/sync.rake +41 -21
  41. data/lib/tasks/tags.rake +11 -7
  42. data/locales/en.yml +60 -14
  43. data/locales/fr.yml +68 -14
  44. metadata +57 -156
  45. data/lib/fronde/config/lisp_config.rb +0 -340
  46. data/lib/fronde/config/org-config.el +0 -19
  47. data/lib/fronde/org_file/class_methods.rb +0 -72
  48. data/lib/fronde/org_file/extracter.rb +0 -72
  49. data/lib/fronde/org_file/htmlizer.rb +0 -43
  50. data/lib/fronde/org_file.rb +0 -298
  51. 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'
@@ -2,117 +2,140 @@
2
2
 
3
3
  require 'nokogiri'
4
4
  require 'digest/md5'
5
- require 'fronde/org_file'
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, opts = {})
12
+ def initialize(source, dom, config = {})
11
13
  @dom = dom
12
14
  @org_file = source
13
- @position = opts['type'] || 'after'
14
- @content = extract_content opts
15
- @element = @dom.css(opts['selector'])
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
- flag_head
22
- content = @org_file.format(@content)
23
- @element.each do |e|
24
- insert_new_node_at e, content
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.to_a.filter(&:comment?).each do |c|
30
- return true if c.text == @check_line
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
- false
50
+
51
+ check_path(file_name)
33
52
  end
34
53
 
35
54
  class << self
36
- def customize_output(file_name, source = nil)
37
- templates_to_apply = filter_templates(file_name)
38
- return if templates_to_apply.empty?
39
- if source.nil?
40
- sourcepath = Fronde::OrgFile.source_for_target(file_name)
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
- templates_to_apply.each do |t|
45
- tpl = Fronde::Templater.new(source, dom, t)
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 filter_templates(file_name)
55
- templates = Fronde::Config.get('templates')
56
- return [] if templates.nil? || templates.empty?
57
- templates.filter { |t| check_required_keys(t, file_name) }
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
- file = File.new file_name, 'r'
62
- dom = Nokogiri::HTML file
63
- file.close
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
- file = File.new file_name, 'w'
69
- dom.write_to file
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 flag_head
97
- @dom.xpath('//head').first.prepend_child("<!--#{@check_line}-->\n")
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
- elem.add_previous_sibling content
98
+ element.add_previous_sibling content
104
99
  when 'replace'
105
- elem.replace content
100
+ element.replace content
106
101
  else
107
- elem.add_next_sibling content
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 extract_content(opts)
112
- return opts['content'] if opts['content']
113
- # If we don't have a content option, then we must have a source
114
- # one.
115
- @dom.css(opts['source']).unlink.to_s
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Fronde
4
4
  # @return [String] the version number of the current Fronde release.
5
- VERSION = '0.3.3'
5
+ VERSION = '0.4.0'
6
6
  end
@@ -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
- # Fronde::Config is required by Fronde::Utils
6
- require 'fronde/utils'
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/tmp/org.tar.gz', 'var/tmp/last_org_version',
12
- 'var/lib/org-config.el', '.dir-locals.el', 'lib/htmlize.el'
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
- download = Thread.new do
29
- Thread.current[:org_version] = Fronde::Config.org_last_version
30
- Fronde::Utils.download_org
31
- end
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.join
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::Utils.throbber(download, 'Downloading Org:')
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
- task compile: 'var/tmp/org.tar.gz' do |task|
42
- org_version = Fronde::Config.org_last_version
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
- sh "tar -C lib -xzf #{task.prerequisites[0]}"
47
- mv "lib/org-mode-release_#{org_version}", org_dir
48
- sh make_org_cmd(org_dir, 'compile')
49
- sh make_org_cmd(org_dir, 'autoloads')
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 "#{org_version} has been locally installed"
53
+ warn R18n.t.fronde.tasks.org.installed(version: org_version)
58
54
  else
59
- Fronde::Utils.throbber(build, 'Installing Org:')
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.el/plain/ox-gmi.el'
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::Config.write_org_lisp_config
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', '.dir-locals.el'] do
89
- mkdir_p "#{Fronde::Config.get('public_folder')}/assets"
90
- Fronde::Config.sources.each do |s|
91
- mkdir_p s['path'] unless Dir.exist? s['path']
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