fronde 0.3.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 +7 -0
- data/LICENSE +14 -0
- data/bin/fronde +45 -0
- data/lib/fronde/cli.rb +60 -0
- data/lib/fronde/cli/commands.rb +115 -0
- data/lib/fronde/config.rb +137 -0
- data/lib/fronde/config/lisp_config.rb +269 -0
- data/lib/fronde/config/org-config.el +17 -0
- data/lib/fronde/config/ox-fronde.el +114 -0
- data/lib/fronde/emacs.rb +37 -0
- data/lib/fronde/index.rb +130 -0
- data/lib/fronde/index/atom_generator.rb +86 -0
- data/lib/fronde/index/org_generator.rb +114 -0
- data/lib/fronde/org_file.rb +301 -0
- data/lib/fronde/org_file/class_methods.rb +72 -0
- data/lib/fronde/org_file/extracter.rb +72 -0
- data/lib/fronde/org_file/htmlizer.rb +43 -0
- data/lib/fronde/preview.rb +55 -0
- data/lib/fronde/templater.rb +118 -0
- data/lib/fronde/utils.rb +214 -0
- data/lib/fronde/version.rb +6 -0
- data/lib/tasks/org.rake +96 -0
- data/lib/tasks/site.rake +55 -0
- data/lib/tasks/sync.rake +34 -0
- data/lib/tasks/tags.rake +19 -0
- data/locales/en.yml +37 -0
- data/locales/fr.yml +37 -0
- metadata +267 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c646347a1cdbe6537384936ec392c1848617524fd7557f3c32566adb14e3c357
|
4
|
+
data.tar.gz: 41785e0d542baa6ac44c8e2f7b8d12d26db6ea5a5e10349ea4002d71b25f435d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ecac97edd7c48c3cd808c906195b11e941f84db6254f0548af1d951e8bba215a6545616cc8b425977b5453b158f5b3032e08d4cf702b1087f110054770e3c739
|
7
|
+
data.tar.gz: adb5628d1999d54284ad38c614ca29bd76b287124fb4ebc434a465225f3c1fb97acf1cce4e844de05aaf66b35c40be8216b9045535dfb05370c77eecb0cb4bde
|
data/LICENSE
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
2
|
+
Version 2, December 2004
|
3
|
+
|
4
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
5
|
+
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
7
|
+
copies of this license document, and changing it is allowed as long
|
8
|
+
as the name is changed.
|
9
|
+
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
12
|
+
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
14
|
+
|
data/bin/fronde
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'r18n-core'
|
6
|
+
require 'fronde/utils'
|
7
|
+
require 'fronde/version'
|
8
|
+
require 'fronde/cli'
|
9
|
+
|
10
|
+
R18n.default_places = File.expand_path('../locales', __dir__)
|
11
|
+
R18n.set Fronde::Config.settings['lang']
|
12
|
+
|
13
|
+
optparser = OptionParser.new
|
14
|
+
optparser.version = Fronde::VERSION
|
15
|
+
|
16
|
+
Fronde::Utils::FRONDE_OPTIONS.each do |k, opt|
|
17
|
+
optparser.send(opt[:meth] || :on, *Fronde::Utils.decorate_option(k))
|
18
|
+
end
|
19
|
+
|
20
|
+
params = {}
|
21
|
+
optparser.parse!(into: params)
|
22
|
+
|
23
|
+
if params[:version]
|
24
|
+
warn optparser.ver
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
if ARGV[0] == 'help'
|
29
|
+
params[:help] = true
|
30
|
+
ARGV.shift
|
31
|
+
end
|
32
|
+
fronde = Fronde::CLI.new(params)
|
33
|
+
command = "fronde_#{ARGV[0]}".to_sym
|
34
|
+
cmd_err = !fronde.respond_to?(command)
|
35
|
+
if params[:help] || cmd_err
|
36
|
+
cmd_err = false if params[:help] && !ARGV[0]
|
37
|
+
fronde.fronde_help(ARGV[0], error: cmd_err)
|
38
|
+
end
|
39
|
+
ARGV.shift
|
40
|
+
|
41
|
+
init_cmds = [:fronde_init, :fronde_config]
|
42
|
+
unless File.exist?('config.yml') || init_cmds.include?(command)
|
43
|
+
fronde.fronde_init
|
44
|
+
end
|
45
|
+
fronde.send command
|
data/lib/fronde/cli.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'fronde/cli/commands'
|
5
|
+
|
6
|
+
module Fronde
|
7
|
+
# Fronde CLI app
|
8
|
+
class CLI
|
9
|
+
def initialize(opts = {})
|
10
|
+
@options = { verbose: false }.merge(opts)
|
11
|
+
init_required_files
|
12
|
+
init_rake
|
13
|
+
end
|
14
|
+
|
15
|
+
include Fronde::CLICommands
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def init_required_files
|
20
|
+
init_rakefile unless File.exist?('Rakefile')
|
21
|
+
init_gitignore unless File.exist?('.gitignore')
|
22
|
+
end
|
23
|
+
|
24
|
+
def init_rake
|
25
|
+
@rake = Rake.application
|
26
|
+
Rake.verbose(false) unless @options[:verbose]
|
27
|
+
@rake.raw_load_rakefile
|
28
|
+
end
|
29
|
+
|
30
|
+
def init_rakefile
|
31
|
+
rakefile = <<~RAKE
|
32
|
+
# frozen_string_literal: true
|
33
|
+
|
34
|
+
require 'fronde/config'
|
35
|
+
require 'r18n-core'
|
36
|
+
|
37
|
+
fronde_spec = Gem::Specification.find_by_name 'fronde'
|
38
|
+
R18n.default_places = "\#{fronde_spec.gem_dir}/locales"
|
39
|
+
R18n.set(Fronde::Config.settings['lang'] || 'en')
|
40
|
+
R18n::Filters.on(:named_variables)
|
41
|
+
|
42
|
+
Dir.glob("\#{fronde_spec.gem_dir}/lib/tasks/*.rake").each { |r| import r }
|
43
|
+
|
44
|
+
task default: 'site:build'
|
45
|
+
RAKE
|
46
|
+
IO.write 'Rakefile', rakefile
|
47
|
+
end
|
48
|
+
|
49
|
+
def init_gitignore
|
50
|
+
gitignore = <<~GITIGNORE
|
51
|
+
.dir-locals.el
|
52
|
+
Rakefile
|
53
|
+
lib
|
54
|
+
public_html
|
55
|
+
var
|
56
|
+
GITIGNORE
|
57
|
+
IO.write '.gitignore', gitignore
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fronde
|
4
|
+
# Fronde commands
|
5
|
+
module CLICommands
|
6
|
+
def fronde_init
|
7
|
+
cnf = @options.merge
|
8
|
+
cnf.delete(:verbose)
|
9
|
+
cnf.transform_keys!(&:to_s)
|
10
|
+
Fronde::Config.save(Fronde::Config.settings.merge(cnf))
|
11
|
+
@rake.options.build_all = true
|
12
|
+
@rake.invoke_task('org:install')
|
13
|
+
return if File.exist? 'src/index.org'
|
14
|
+
Fronde::OrgFile.new('src/index.org', @options).write
|
15
|
+
fronde_open 'src/index.org'
|
16
|
+
end
|
17
|
+
alias_method :fronde_config, :fronde_init
|
18
|
+
|
19
|
+
def fronde_build
|
20
|
+
@rake.options.build_all = true
|
21
|
+
task = 'site:build'
|
22
|
+
task = "#{task}[true]" if @options[:force]
|
23
|
+
@rake.invoke_task task
|
24
|
+
end
|
25
|
+
|
26
|
+
def fronde_preview
|
27
|
+
Thread.new do
|
28
|
+
sleep 1
|
29
|
+
port = Fronde::Config.settings.dig('preview', 'server_port') || 5000
|
30
|
+
uri = "http://127.0.0.1:#{port}/"
|
31
|
+
current_os = Fronde::Utils.current_os
|
32
|
+
case current_os
|
33
|
+
when 'windows'
|
34
|
+
system 'start', uri
|
35
|
+
when 'apple'
|
36
|
+
system 'open', uri
|
37
|
+
else
|
38
|
+
system 'gio', 'open', uri
|
39
|
+
end
|
40
|
+
end
|
41
|
+
@rake.invoke_task('site:preview')
|
42
|
+
end
|
43
|
+
|
44
|
+
def fronde_open(file_path = ARGV[0])
|
45
|
+
editor = ENV['EDITOR'] || ENV['VISUAL'] || 'emacs'
|
46
|
+
cmd = [editor]
|
47
|
+
if file_path.nil? || !File.file?(file_path)
|
48
|
+
# file_path may be updated with title given in options
|
49
|
+
file_path = create_new_file(file_path)
|
50
|
+
# Only move to the end of file for new file. Let the editor handle
|
51
|
+
# the best position for already existing files
|
52
|
+
cmd << '+6'
|
53
|
+
end
|
54
|
+
cmd << file_path
|
55
|
+
system(*cmd)
|
56
|
+
end
|
57
|
+
alias_method :fronde_edit, :fronde_open
|
58
|
+
|
59
|
+
def fronde_publish
|
60
|
+
@rake.invoke_task('sync:push')
|
61
|
+
end
|
62
|
+
|
63
|
+
def fronde_help(command = 'basic', error: false)
|
64
|
+
warn R18n.t.fronde.bin.error.no_command if error
|
65
|
+
cmd = Fronde::Utils.resolve_possible_alias(command)
|
66
|
+
cmd_opt = Fronde::Utils::FRONDE_COMMANDS[cmd]
|
67
|
+
label = cmd_opt[:label] || command
|
68
|
+
warn format("%<label>s\n\n", label: R18n.t.fronde.bin.usage(label))
|
69
|
+
if R18n.t.fronde.bin.commands[cmd].translated?
|
70
|
+
warn format("%<label>s\n\n", label: R18n.t.fronde.bin.commands[cmd])
|
71
|
+
end
|
72
|
+
warn help_command_body(cmd).join("\n")
|
73
|
+
exit 1 if error
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def new_file_name(file_path)
|
80
|
+
file_path = File.expand_path(file_path || '')
|
81
|
+
return file_path if file_path[-4..] == '.org'
|
82
|
+
# file_path seems to be a dir path. Thus we have to create the new
|
83
|
+
# filename from its title
|
84
|
+
title = @options[:title]
|
85
|
+
# No title, nor a reliable file_path? Better abort
|
86
|
+
return nil if title.nil? || title == ''
|
87
|
+
filename = "#{Fronde::OrgFile.slug(title)}.org"
|
88
|
+
File.join file_path, filename
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_new_file(file_path)
|
92
|
+
filename = new_file_name(file_path)
|
93
|
+
if filename.nil?
|
94
|
+
warn R18n.t.fronde.bin.error.no_file
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
FileUtils.mkdir_p File.dirname(filename)
|
98
|
+
Fronde::OrgFile.new(filename, @options).write
|
99
|
+
filename
|
100
|
+
end
|
101
|
+
|
102
|
+
def help_command_body(command)
|
103
|
+
body = [
|
104
|
+
R18n.t.fronde.bin.options.cmd_title,
|
105
|
+
Fronde::Utils.summarize_command(command)
|
106
|
+
]
|
107
|
+
return body unless command == 'basic'
|
108
|
+
body + [
|
109
|
+
'',
|
110
|
+
R18n.t.fronde.bin.commands.cmd_title,
|
111
|
+
Fronde::Utils.list_commands
|
112
|
+
]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'fronde/config/lisp_config'
|
5
|
+
|
6
|
+
module Fronde
|
7
|
+
# Wrapper for configuration
|
8
|
+
#
|
9
|
+
# This class is a singleton interface, which share the static website
|
10
|
+
# being build settings among different steps or tasks.
|
11
|
+
#
|
12
|
+
# It expects the website author to holds their custom settings in a
|
13
|
+
# YAML file named ~config.yml~ available at the root of their
|
14
|
+
# project.
|
15
|
+
#
|
16
|
+
# For example, with the given config file:
|
17
|
+
#
|
18
|
+
# #+begin_src
|
19
|
+
# ---
|
20
|
+
# title: My website
|
21
|
+
# author: Alice Doe
|
22
|
+
# #+end_src
|
23
|
+
#
|
24
|
+
# Settings will be available like this:
|
25
|
+
#
|
26
|
+
# #+begin_src
|
27
|
+
# Fronde::Config.settings['author']
|
28
|
+
# => "Alice Doe"
|
29
|
+
# #+end_src
|
30
|
+
class Config
|
31
|
+
extend Fronde::LispConfig
|
32
|
+
|
33
|
+
class << self
|
34
|
+
# Access the current website settings
|
35
|
+
#
|
36
|
+
# If the settings have not been loaded yet, this method is
|
37
|
+
# responsible for calling the one, which actually loads them.
|
38
|
+
#
|
39
|
+
# @return [Hash] the website settings
|
40
|
+
def settings
|
41
|
+
return load_settings unless @config
|
42
|
+
@config
|
43
|
+
end
|
44
|
+
|
45
|
+
# Save the settings given as a parameter to the ~config.yml~ file.
|
46
|
+
#
|
47
|
+
# Not only this method overwrite the old settings, but it replace
|
48
|
+
# the current shared settings with the ones given in
|
49
|
+
# parameter. Later call to
|
50
|
+
# {file:Fronde/Config.html#settings-class_method settings}
|
51
|
+
# will, obviously, use these new settings.
|
52
|
+
#
|
53
|
+
# @param new_config [Hash] the settings to save
|
54
|
+
# @return [Hash] the new settings after save
|
55
|
+
def save(new_config)
|
56
|
+
# Do not save obvious default config values. We'll always try to
|
57
|
+
# save author and lang as they default on system variables,
|
58
|
+
# which may be different from a system to another. Thus it may
|
59
|
+
# be confusing if one use fronde on two different computer and
|
60
|
+
# these params always change.
|
61
|
+
new_config.delete_if do |k, v|
|
62
|
+
['domain', 'public_folder', 'templates', 'theme'].include?(k) \
|
63
|
+
&& v == default_settings[k]
|
64
|
+
end
|
65
|
+
IO.write 'config.yml', new_config.to_yaml
|
66
|
+
load_settings # Reload config, taking default settings into account
|
67
|
+
end
|
68
|
+
|
69
|
+
# Load the given settings as if they comes from the ~config.yml~ file.
|
70
|
+
#
|
71
|
+
# This method is handy for testing purpose. Later call to
|
72
|
+
# {file:Fronde/Config.html#settings-class_method settings} will
|
73
|
+
# use these new settings.
|
74
|
+
#
|
75
|
+
# @param config [Hash] the settings to artificially load
|
76
|
+
# @return [Hash] the new settings
|
77
|
+
def load_test(config)
|
78
|
+
@sources = nil # Reset sources
|
79
|
+
@config = default_settings.merge config
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return the qualified projects sources list.
|
83
|
+
#
|
84
|
+
# @return [Array] the fully qualified projects sources list
|
85
|
+
def sources
|
86
|
+
return @sources if @sources
|
87
|
+
default_sources = [{ 'path' => 'src', 'target' => '.' }]
|
88
|
+
@sources = (settings['sources'] || default_sources).map do |s|
|
89
|
+
build_source(s)
|
90
|
+
end.compact
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def load_settings
|
96
|
+
@sources = nil
|
97
|
+
conf_file = 'config.yml'
|
98
|
+
if File.exist? conf_file
|
99
|
+
@config = default_settings.merge(YAML.load_file(conf_file)).freeze
|
100
|
+
else
|
101
|
+
@config = default_settings
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def extract_lang_from_env(default)
|
106
|
+
(ENV['LANG'] || default).split('_', 2).first
|
107
|
+
end
|
108
|
+
|
109
|
+
def default_settings
|
110
|
+
return @default_settings if @default_settings
|
111
|
+
@default_settings = {
|
112
|
+
'author' => (ENV['USER'] || ''),
|
113
|
+
'domain' => '',
|
114
|
+
'lang' => extract_lang_from_env('en'),
|
115
|
+
'public_folder' => 'public_html',
|
116
|
+
'templates' => [],
|
117
|
+
'theme' => 'default'
|
118
|
+
}.freeze
|
119
|
+
end
|
120
|
+
|
121
|
+
def build_source(seed)
|
122
|
+
opts = { 'recursive' => true, 'is_blog' => false }
|
123
|
+
case seed
|
124
|
+
when String
|
125
|
+
opts['path'] = seed
|
126
|
+
when Hash
|
127
|
+
opts.merge! seed
|
128
|
+
end
|
129
|
+
return nil unless opts.has_key?('path')
|
130
|
+
opts['path'] = File.expand_path(opts['path'])
|
131
|
+
opts['name'] ||= File.basename(opts['path']).sub(/^\./, '')
|
132
|
+
opts['target'] ||= opts['name']
|
133
|
+
opts
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,269 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'fronde/version'
|
6
|
+
|
7
|
+
module Fronde
|
8
|
+
# This module contains utilitary methods to ease ~org-config.el~
|
9
|
+
# file generation
|
10
|
+
module LispConfig
|
11
|
+
# Fetch and return the last published version of Org.
|
12
|
+
#
|
13
|
+
# @return [String] the new x.x.x version string of Org
|
14
|
+
def org_last_version
|
15
|
+
return @org_version if @org_version
|
16
|
+
if File.exist?('var/tmp/last_org_version')
|
17
|
+
@org_version = IO.read('var/tmp/last_org_version')
|
18
|
+
return @org_version
|
19
|
+
end
|
20
|
+
versions = JSON.parse(
|
21
|
+
URI('https://updates.orgmode.org/data/releases').open.read
|
22
|
+
).sort { |a, b| b['date'] <=> a['date'] }
|
23
|
+
@org_version = versions.first['version']
|
24
|
+
FileUtils.mkdir_p 'var/tmp'
|
25
|
+
IO.write('var/tmp/last_org_version', @org_version)
|
26
|
+
@org_version
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate emacs lisp configuration file for Org and write it.
|
30
|
+
#
|
31
|
+
# This method saves the generated configuration in the file
|
32
|
+
# ~org-config.el~ at the root of your project, overwriting it if it
|
33
|
+
# existed already.
|
34
|
+
#
|
35
|
+
# @return [Integer] the length written (as returned by the
|
36
|
+
# underlying ~IO.write~ method call)
|
37
|
+
def write_org_lisp_config(with_tags: false)
|
38
|
+
projects = org_generate_projects(with_tags: with_tags)
|
39
|
+
workdir = Dir.pwd
|
40
|
+
content = IO.read(File.expand_path('./org-config.el', __dir__))
|
41
|
+
.gsub('__VERSION__', Fronde::VERSION)
|
42
|
+
.gsub('__WORK_DIR__', workdir)
|
43
|
+
.gsub('__FRONDE_DIR__', __dir__)
|
44
|
+
.gsub('__ORG_VER__', org_last_version)
|
45
|
+
.gsub('__ALL_PROJECTS__', all_projects(projects))
|
46
|
+
.gsub('__THEME_CONFIG__', org_default_theme_config)
|
47
|
+
.gsub('__ALL_PROJECTS_NAMES__', project_names(projects))
|
48
|
+
.gsub('__LONG_DATE_FMT__', r18n_full_datetime_format)
|
49
|
+
.gsub('__AUTHOR_EMAIL__', settings['author_email'] || '')
|
50
|
+
.gsub('__AUTHOR_NAME__', settings['author'])
|
51
|
+
FileUtils.mkdir_p "#{workdir}/var/lib"
|
52
|
+
IO.write("#{workdir}/var/lib/org-config.el", content)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Generate emacs directory variables file.
|
56
|
+
#
|
57
|
+
# This method generate the file ~.dir-locals.el~, which is
|
58
|
+
# responsible to load fronde Org settings when visiting an Org file
|
59
|
+
# of this fronde instance.
|
60
|
+
#
|
61
|
+
# @return [Integer] the length written (as returned by the
|
62
|
+
# underlying ~IO.write~ method call)
|
63
|
+
def write_dir_locals
|
64
|
+
workdir = Dir.pwd
|
65
|
+
# rubocop:disable Layout/LineLength
|
66
|
+
IO.write(
|
67
|
+
"#{workdir}/.dir-locals.el",
|
68
|
+
"((org-mode . ((eval . (load-file \"#{workdir}/var/lib/org-config.el\")))))"
|
69
|
+
)
|
70
|
+
# rubocop:enable Layout/LineLength
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def r18n_full_datetime_format
|
76
|
+
locale = R18n.get.locale
|
77
|
+
date_fmt = R18n.t.fronde.index.full_date_format(
|
78
|
+
date: locale.full_format
|
79
|
+
)
|
80
|
+
date_fmt = locale.year_format.sub('_', date_fmt)
|
81
|
+
time_fmt = locale.time_format.delete('_').strip
|
82
|
+
R18n.t.fronde.index.full_date_with_time_format(
|
83
|
+
date: date_fmt, time: time_fmt
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def ruby_to_lisp_boolean(value)
|
88
|
+
return 't' if value == true
|
89
|
+
'nil'
|
90
|
+
end
|
91
|
+
|
92
|
+
def project_names(projects)
|
93
|
+
names = projects.keys.map do |p|
|
94
|
+
["\"#{p}\"", "\"#{p}-assets\""]
|
95
|
+
end.flatten
|
96
|
+
unless settings['theme'] == 'default'
|
97
|
+
names << "\"theme-#{settings['theme']}\""
|
98
|
+
end
|
99
|
+
sources.each do |s|
|
100
|
+
# Default theme defined in settings is already included
|
101
|
+
next unless s['theme'] && s['theme'] != settings['theme']
|
102
|
+
# Never include theme named 'default' as it does not rely on any
|
103
|
+
# file to export.
|
104
|
+
next if s['theme'] == 'default'
|
105
|
+
theme = "\"theme-#{s['theme']}\""
|
106
|
+
next if names.include? theme
|
107
|
+
names << theme
|
108
|
+
end
|
109
|
+
names.join(' ')
|
110
|
+
end
|
111
|
+
|
112
|
+
def all_projects(projects)
|
113
|
+
projects.values.join("\n").strip
|
114
|
+
.gsub(/\n\s*\n/, "\n")
|
115
|
+
.gsub(/\n/, "\n ")
|
116
|
+
end
|
117
|
+
|
118
|
+
# Return the full path to the publication path of a given project
|
119
|
+
# configuration.
|
120
|
+
#
|
121
|
+
# @param project [Hash] a project configuration (as extracted from
|
122
|
+
# the ~sources~ key)
|
123
|
+
# @return [String] the full path to the target dir of this project
|
124
|
+
def publication_path(project)
|
125
|
+
publish_in = [Dir.pwd, settings['public_folder']]
|
126
|
+
publish_in << project['target'] unless project['target'] == '.'
|
127
|
+
publish_in.join('/')
|
128
|
+
end
|
129
|
+
|
130
|
+
def org_project(project_name, opts)
|
131
|
+
publish_in = publication_path(opts)
|
132
|
+
other_lines = [
|
133
|
+
format(':recursive %<value>s',
|
134
|
+
value: ruby_to_lisp_boolean(opts['recursive']))
|
135
|
+
]
|
136
|
+
if opts['exclude']
|
137
|
+
other_lines << format(':exclude "%<value>s"',
|
138
|
+
value: opts['exclude'])
|
139
|
+
end
|
140
|
+
themeconf = org_theme_config(opts['theme'])
|
141
|
+
<<~ORGPROJECT
|
142
|
+
("#{project_name}"
|
143
|
+
:base-directory "#{opts['path']}"
|
144
|
+
:base-extension "org"
|
145
|
+
#{other_lines.join("\n ")}
|
146
|
+
:publishing-directory "#{publish_in}"
|
147
|
+
:publishing-function org-html-publish-to-html
|
148
|
+
#{opts['org_headers']})
|
149
|
+
("#{project_name}-assets"
|
150
|
+
:base-directory "#{opts['path']}"
|
151
|
+
:base-extension "jpg\\\\\\|gif\\\\\\|png\\\\\\|svg\\\\\\|pdf"
|
152
|
+
#{other_lines[0]}
|
153
|
+
:publishing-directory "#{publish_in}"
|
154
|
+
:publishing-function org-publish-attachment)
|
155
|
+
#{themeconf}
|
156
|
+
ORGPROJECT
|
157
|
+
end
|
158
|
+
|
159
|
+
def org_default_postamble
|
160
|
+
<<~POSTAMBLE
|
161
|
+
<p><span class="author">#{R18n.t.fronde.org.postamble.written_by}</span>
|
162
|
+
#{R18n.t.fronde.org.postamble.with_emacs}</p>
|
163
|
+
<p class="date">#{R18n.t.fronde.org.postamble.last_modification}</p>
|
164
|
+
<p class="validation">%v</p>
|
165
|
+
POSTAMBLE
|
166
|
+
end
|
167
|
+
|
168
|
+
def org_default_html_head
|
169
|
+
<<~HTMLHEAD
|
170
|
+
<link rel="stylesheet" type="text/css" media="screen"
|
171
|
+
href="__DOMAIN__/assets/__THEME__/css/style.css">
|
172
|
+
<link rel="stylesheet" type="text/css" media="screen"
|
173
|
+
href="__DOMAIN__/assets/__THEME__/css/htmlize.css">
|
174
|
+
__ATOM_FEED__
|
175
|
+
HTMLHEAD
|
176
|
+
end
|
177
|
+
|
178
|
+
def org_default_html_options(project)
|
179
|
+
defaults = {
|
180
|
+
'section-numbers' => 'nil',
|
181
|
+
'with-toc' => 'nil',
|
182
|
+
'html-postamble' => org_default_postamble,
|
183
|
+
'html-head' => '__ATOM_FEED__',
|
184
|
+
'html-head-include-default-style' => 't',
|
185
|
+
'html-head-include-scripts' => 't'
|
186
|
+
}
|
187
|
+
curtheme = project['theme'] || settings['theme']
|
188
|
+
return defaults if curtheme.nil? || curtheme == 'default'
|
189
|
+
defaults['html-head'] = org_default_html_head
|
190
|
+
defaults['html-head-include-default-style'] = 'nil'
|
191
|
+
defaults['html-head-include-scripts'] = 'nil'
|
192
|
+
defaults
|
193
|
+
end
|
194
|
+
|
195
|
+
def expand_vars_in_html_head(head, project)
|
196
|
+
curtheme = project['theme'] || settings['theme']
|
197
|
+
# Head may be frozen when coming from settings
|
198
|
+
head = head.gsub('__THEME__', curtheme)
|
199
|
+
.gsub('__DOMAIN__', settings['domain'])
|
200
|
+
return head.gsub('__ATOM_FEED__', '') unless project['is_blog']
|
201
|
+
atomfeed = <<~ATOMFEED
|
202
|
+
<link rel="alternate" type="application/atom+xml" title="Atom 1.0"
|
203
|
+
href="#{settings['domain']}/feeds/index.xml" />
|
204
|
+
ATOMFEED
|
205
|
+
head.gsub('__ATOM_FEED__', atomfeed)
|
206
|
+
end
|
207
|
+
|
208
|
+
def cast_lisp_value(value)
|
209
|
+
return 't' if value.is_a?(TrueClass)
|
210
|
+
return 'nil' if value.nil? || value.is_a?(FalseClass)
|
211
|
+
value.strip.gsub(/"/, '\"')
|
212
|
+
end
|
213
|
+
|
214
|
+
def build_project_org_headers(project)
|
215
|
+
orgtplopts = org_default_html_options(project).merge(
|
216
|
+
settings['org-html'] || {}, project['org-html'] || {}
|
217
|
+
)
|
218
|
+
orgtpl = []
|
219
|
+
lisp_keywords = ['t', 'nil', '1', '-1', '0'].freeze
|
220
|
+
orgtplopts.each do |k, v|
|
221
|
+
v = expand_vars_in_html_head(v, project) if k == 'html-head'
|
222
|
+
val = cast_lisp_value(v)
|
223
|
+
if lisp_keywords.include? val
|
224
|
+
orgtpl << ":#{k} #{val}"
|
225
|
+
else
|
226
|
+
orgtpl << ":#{k} \"#{val}\""
|
227
|
+
end
|
228
|
+
end
|
229
|
+
orgtpl.join("\n ")
|
230
|
+
end
|
231
|
+
|
232
|
+
def org_generate_projects(with_tags: false)
|
233
|
+
projects = {}
|
234
|
+
projects_sources = sources
|
235
|
+
if with_tags
|
236
|
+
tags_conf = build_source('tags')
|
237
|
+
tags_conf['recursive'] = false
|
238
|
+
projects_sources << tags_conf
|
239
|
+
end
|
240
|
+
projects_sources.each do |opts|
|
241
|
+
opts['org_headers'] = build_project_org_headers(opts)
|
242
|
+
projects[opts['name']] = org_project(opts['name'], opts)
|
243
|
+
end
|
244
|
+
projects
|
245
|
+
end
|
246
|
+
|
247
|
+
def org_default_theme_config
|
248
|
+
theme_config = org_theme_config(settings['theme'])
|
249
|
+
return theme_config if theme_config == ''
|
250
|
+
output = theme_config.split("\n").map do |line|
|
251
|
+
" #{line}"
|
252
|
+
end
|
253
|
+
format("\n%<conf>s", conf: output.join("\n"))
|
254
|
+
end
|
255
|
+
|
256
|
+
def org_theme_config(theme)
|
257
|
+
return '' if theme.nil? || theme == 'default'
|
258
|
+
workdir = Dir.pwd
|
259
|
+
<<~THEMECONFIG
|
260
|
+
("theme-#{theme}"
|
261
|
+
:base-directory "#{workdir}/themes/#{theme}"
|
262
|
+
:base-extension "jpg\\\\\\|gif\\\\\\|png\\\\\\|js\\\\\\|css\\\\\\|otf\\\\\\|ttf\\\\\\|woff2?"
|
263
|
+
:recursive t
|
264
|
+
:publishing-directory "#{workdir}/#{settings['public_folder']}/assets/#{theme}"
|
265
|
+
:publishing-function org-publish-attachment)
|
266
|
+
THEMECONFIG
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|