nanoc-cli 4.11.13

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.
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ usage 'shell'
4
+ summary 'open a shell on the Nanoc environment'
5
+ aliases 'console', 'sh'
6
+ description "
7
+ Open an IRB shell on a context that contains @items, @layouts, and @config.
8
+ "
9
+ flag :p, :preprocess, 'run preprocessor'
10
+ no_params
11
+
12
+ module Nanoc::CLI::Commands
13
+ class Shell < ::Nanoc::CLI::CommandRunner
14
+ def run
15
+ require 'pry'
16
+
17
+ # Needed to make pry behave properly sometimes -- see nanoc/nanoc#1309
18
+ Signal.trap('SIGINT') { raise Interrupt }
19
+
20
+ @site = load_site
21
+ Nanoc::Core::Compiler.new_for(@site).run_until_preprocessed if options[:preprocess]
22
+
23
+ Nanoc::Core::Context.new(env).pry
24
+ end
25
+
26
+ def env
27
+ self.class.env_for_site(@site)
28
+ end
29
+
30
+ def self.reps_for(site)
31
+ Nanoc::Core::ItemRepRepo.new.tap do |reps|
32
+ action_provider = Nanoc::Core::ActionProvider.named(site.config.action_provider).for(site)
33
+ builder = Nanoc::Core::ItemRepBuilder.new(site, action_provider, reps)
34
+ builder.run
35
+ end
36
+ end
37
+
38
+ def self.view_context_for(site)
39
+ Nanoc::Core::ViewContextForShell.new(
40
+ items: site.items,
41
+ reps: reps_for(site),
42
+ )
43
+ end
44
+
45
+ def self.env_for_site(site)
46
+ view_context = view_context_for(site)
47
+
48
+ {
49
+ items: Nanoc::Core::ItemCollectionWithRepsView.new(site.items, view_context),
50
+ layouts: Nanoc::Core::LayoutCollectionView.new(site.layouts, view_context),
51
+ config: Nanoc::Core::ConfigView.new(site.config, view_context),
52
+ }
53
+ end
54
+ end
55
+ end
56
+
57
+ runner Nanoc::CLI::Commands::Shell
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ usage 'show-data'
4
+ aliases :debug
5
+ summary 'show data in this site'
6
+ description <<~EOS
7
+ Show information about all items, item representations and layouts in the
8
+ current site, along with dependency information.
9
+ EOS
10
+ no_params
11
+
12
+ module Nanoc::CLI::Commands
13
+ class ShowData < ::Nanoc::CLI::CommandRunner
14
+ def run
15
+ site = load_site
16
+ res = Nanoc::Core::Compiler.new_for(site).run_until_precompiled
17
+
18
+ items = site.items
19
+ layouts = site.layouts
20
+ reps = res.fetch(:reps)
21
+ dependency_store = res.fetch(:dependency_store)
22
+ outdatedness_checker = res.fetch(:outdatedness_checker)
23
+
24
+ # Print data
25
+ print_item_dependencies(items, dependency_store)
26
+ print_item_rep_paths(items, reps)
27
+ print_item_rep_outdatedness(items, outdatedness_checker, reps)
28
+ print_layouts(layouts, outdatedness_checker)
29
+ end
30
+
31
+ protected
32
+
33
+ def sorted_with_prev(objects)
34
+ prev = nil
35
+ objects.sort_by(&:identifier).each do |object|
36
+ yield(object, prev)
37
+ prev = object
38
+ end
39
+ end
40
+
41
+ def sorted_reps_with_prev(items, reps)
42
+ prev = nil
43
+ items.sort_by(&:identifier).each do |item|
44
+ reps[item].sort_by { |r| r.name.to_s }.each do |rep|
45
+ yield(rep, prev)
46
+ prev = rep
47
+ end
48
+ end
49
+ end
50
+
51
+ def print_header(title)
52
+ header = '=' * 78
53
+ header[3..(title.length + 5)] = " #{title} "
54
+
55
+ puts
56
+ puts header
57
+ puts
58
+ end
59
+
60
+ def print_item_dependencies(items, dependency_store)
61
+ print_header('Item dependencies')
62
+
63
+ puts 'Legend:'
64
+ puts ' r = dependency on raw content'
65
+ puts ' a = dependency on attributes'
66
+ puts ' c = dependency on compiled content'
67
+ puts ' p = dependency on the path'
68
+ puts
69
+
70
+ sorter =
71
+ lambda do |dep|
72
+ case dep
73
+ when Nanoc::Core::Document
74
+ dep.from.identifier.to_s
75
+ else
76
+ ''
77
+ end
78
+ end
79
+
80
+ sorted_with_prev(items) do |item, prev|
81
+ puts if prev
82
+ puts "item #{item.identifier} depends on:"
83
+ dependencies =
84
+ dependency_store
85
+ .dependencies_causing_outdatedness_of(item)
86
+ .sort_by(&sorter)
87
+ dependencies.each do |dep|
88
+ pred = dep.from
89
+
90
+ type =
91
+ case pred
92
+ when Nanoc::Core::Layout
93
+ 'layout'
94
+ when Nanoc::Core::Item
95
+ 'item'
96
+ when Nanoc::Core::Configuration
97
+ 'config'
98
+ when Nanoc::Core::ItemCollection
99
+ 'items'
100
+ when Nanoc::Core::LayoutCollection
101
+ 'layouts'
102
+ else
103
+ raise Nanoc::Core::Errors::InternalInconsistency, "unexpected pred type #{pred}"
104
+ end
105
+
106
+ pred_identifier =
107
+ case pred
108
+ when Nanoc::Core::Document
109
+ pred.identifier.to_s
110
+ when Nanoc::Core::Configuration
111
+ nil
112
+ when Nanoc::Core::IdentifiableCollection
113
+ case dep.props.raw_content
114
+ when true
115
+ 'matching any'
116
+ else
117
+ "matching any of #{dep.props.raw_content.sort.join(', ')}"
118
+ end
119
+ else
120
+ raise Nanoc::Core::Errors::InternalInconsistency, "unexpected pred type #{pred}"
121
+ end
122
+
123
+ if pred
124
+ puts " [ #{format '%6s', type} ] (#{dep.props}) #{pred_identifier}"
125
+ else
126
+ puts ' ( removed item )'
127
+ end
128
+ end
129
+ puts ' (nothing)' if dependencies.empty?
130
+ end
131
+ end
132
+
133
+ def print_item_rep_paths(items, reps)
134
+ print_header('Item representation paths')
135
+
136
+ sorted_reps_with_prev(items, reps) do |rep, prev|
137
+ puts if prev
138
+ puts "item #{rep.item.identifier}, rep #{rep.name}:"
139
+ if rep.raw_paths.empty?
140
+ puts ' (not written)'
141
+ end
142
+ length = rep.raw_paths.keys.map { |s| s.to_s.length }.max
143
+ rep.raw_paths.each do |snapshot_name, raw_paths|
144
+ raw_paths.each do |raw_path|
145
+ puts format(" [ %-#{length}s ] %s", snapshot_name, raw_path)
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ def print_item_rep_outdatedness(items, outdatedness_checker, reps)
152
+ print_header('Item representation outdatedness')
153
+
154
+ sorted_reps_with_prev(items, reps) do |rep, prev|
155
+ puts if prev
156
+ puts "item #{rep.item.identifier}, rep #{rep.name}:"
157
+ print_outdatedness_reasons_for(rep, outdatedness_checker)
158
+ end
159
+ end
160
+
161
+ def print_layouts(layouts, outdatedness_checker)
162
+ print_header('Layouts')
163
+
164
+ sorted_with_prev(layouts) do |layout, prev|
165
+ puts if prev
166
+ puts "layout #{layout.identifier}:"
167
+ print_outdatedness_reasons_for(layout, outdatedness_checker)
168
+ end
169
+ end
170
+
171
+ def print_outdatedness_reasons_for(obj, outdatedness_checker)
172
+ reasons = outdatedness_checker.outdatedness_reasons_for(obj)
173
+ if reasons.any?
174
+ puts ' is outdated:'
175
+ reasons.each do |reason|
176
+ puts " - #{reason.message}"
177
+ end
178
+ else
179
+ puts ' is not outdated'
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ runner Nanoc::CLI::Commands::ShowData
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ summary 'show all available plugins'
4
+ aliases :info
5
+ usage 'show-plugins [options]'
6
+ description <<~EOS
7
+ Show a list of available plugins, including filters and data sources.
8
+ If the current directory contains a Nanoc web site, the plugins defined in this site will be shown as well.
9
+ EOS
10
+ no_params
11
+
12
+ module Nanoc::CLI::Commands
13
+ class ShowPlugins < ::Nanoc::CLI::CommandRunner
14
+ # rubocop:disable Style/MutableConstant
15
+ # These constants are intended to be mutated (through #add_plugin_class)
16
+
17
+ PLUGIN_CLASS_ORDER = [
18
+ Nanoc::Core::Filter,
19
+ Nanoc::Core::DataSource,
20
+ ]
21
+
22
+ PLUGIN_CLASSES = {
23
+ Nanoc::Core::Filter => 'Filters',
24
+ Nanoc::Core::DataSource => 'Data Sources',
25
+ }
26
+
27
+ # rubocop:enable Style/MutableConstant
28
+
29
+ def run
30
+ # Get list of plugins (before and after)
31
+ plugins_before = PLUGIN_CLASSES.keys.each_with_object({}) { |c, acc| acc[c] = c.all }
32
+ site = load_site
33
+ site&.code_snippets
34
+ plugins_after = PLUGIN_CLASSES.keys.each_with_object({}) { |c, acc| acc[c] = c.all }
35
+
36
+ # Divide list of plugins into builtin and custom
37
+ plugins_builtin = plugins_before
38
+ plugins_custom = plugins_after.each_with_object({}) do |(superclass, klasses), acc|
39
+ acc[superclass] = klasses - plugins_before[superclass]
40
+ end
41
+
42
+ # Find max identifiers length
43
+ all_identifiers = plugins_after.values.flatten.map(&:identifiers)
44
+ max_identifiers_length = all_identifiers.map(&:to_s).map(&:size).max
45
+
46
+ PLUGIN_CLASS_ORDER.each do |superclass|
47
+ plugins_with_this_superclass = {
48
+ builtin: plugins_builtin.fetch(superclass, []),
49
+ custom: plugins_custom.fetch(superclass, []),
50
+ }
51
+
52
+ # Print kind
53
+ kind = name_for_plugin_class(superclass)
54
+ puts "#{kind}:"
55
+ puts
56
+
57
+ # Print plugins organised by subtype
58
+ %i[builtin custom].each do |type|
59
+ # Find relevant plugins
60
+ relevant_plugins = plugins_with_this_superclass[type]
61
+
62
+ # Print type
63
+ puts " #{type}:"
64
+ if relevant_plugins.empty?
65
+ puts ' (none)'
66
+ next
67
+ end
68
+
69
+ # Print plugins
70
+ relevant_plugins.sort_by { |k| k.identifiers.join(', ') }.each do |plugin|
71
+ # Display
72
+ puts format(
73
+ " %-#{max_identifiers_length}s (%s)",
74
+ plugin.identifiers.join(', '),
75
+ plugin.to_s.sub(/^::/, ''),
76
+ )
77
+ end
78
+ end
79
+
80
+ puts
81
+ end
82
+ end
83
+
84
+ def self.add_plugin_class(klass, name)
85
+ PLUGIN_CLASS_ORDER << klass
86
+ PLUGIN_CLASSES[klass] = name
87
+ end
88
+
89
+ private
90
+
91
+ def name_for_plugin_class(klass)
92
+ PLUGIN_CLASSES[klass.to_s]
93
+ end
94
+ end
95
+ end
96
+
97
+ runner Nanoc::CLI::Commands::ShowPlugins
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ usage 'view [options]'
4
+ summary 'start the web server that serves static files'
5
+ description <<~EOS
6
+ Start the static web server. Unless specified, the web server will run on port
7
+ 3000 and listen on all IP addresses. Running this static web server requires
8
+ `adsf` (not `asdf`!).
9
+ EOS
10
+
11
+ required :H, :handler, 'specify the handler to use (webrick/mongrel/...)'
12
+ required :o, :host, 'specify the host to listen on (default: 127.0.0.1)', default: '127.0.0.1'
13
+ required :p, :port, 'specify the port to listen on (default: 3000)', transform: Nanoc::CLI::Transform::Port, default: 3000
14
+ flag :L, :'live-reload', 'reload on changes'
15
+ no_params
16
+
17
+ module Nanoc::CLI::Commands
18
+ class View < ::Nanoc::CLI::CommandRunner
19
+ DEFAULT_HANDLER_NAME = :thin
20
+
21
+ def run
22
+ load_adsf
23
+
24
+ config = Nanoc::Core::ConfigLoader.new.new_from_cwd
25
+
26
+ # Create output dir so that viewer/watcher doesn’t explode.
27
+ FileUtils.mkdir_p(config.output_dir)
28
+
29
+ server =
30
+ Adsf::Server.new(
31
+ root: File.absolute_path(config.output_dir),
32
+ live: options[:'live-reload'],
33
+ index_filenames: config[:index_filenames],
34
+ host: options[:host],
35
+ port: options[:port],
36
+ handler: options[:handler],
37
+ )
38
+
39
+ server.run
40
+ end
41
+
42
+ protected
43
+
44
+ def load_adsf
45
+ # Load adsf
46
+ begin
47
+ require 'adsf'
48
+ return
49
+ rescue LoadError
50
+ $stderr.puts "Could not find the required 'adsf' gem, " \
51
+ 'which is necessary for the view command.'
52
+ end
53
+
54
+ # Check asdf
55
+ begin
56
+ require 'asdf'
57
+ $stderr.puts "You appear to have 'asdf' installed, " \
58
+ "but not 'adsf'. Please install 'adsf' (check the spelling)!"
59
+ rescue LoadError
60
+ end
61
+
62
+ # Done
63
+ exit 1
64
+ end
65
+ end
66
+ end
67
+
68
+ runner Nanoc::CLI::Commands::View
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc::CLI::CompileListeners
4
+ class Abstract
5
+ def initialize(*)
6
+ super()
7
+ end
8
+
9
+ def self.enable_for?(command_runner, site) # rubocop:disable Lint/UnusedMethodArgument
10
+ true
11
+ end
12
+
13
+ # @abstract
14
+ def start
15
+ raise NotImplementedError, "Subclasses of #{self.class} must implement #start"
16
+ end
17
+
18
+ # @abstract
19
+ def stop; end
20
+
21
+ def wrapped_start
22
+ @_notification_names = []
23
+ start
24
+ end
25
+
26
+ def wrapped_stop
27
+ stop
28
+
29
+ Nanoc::Core::NotificationCenter.sync
30
+
31
+ @_notification_names.each do |name|
32
+ Nanoc::Core::NotificationCenter.remove(name, self)
33
+ end
34
+ end
35
+
36
+ def run_while
37
+ wrapped_start
38
+ yield
39
+ ensure
40
+ wrapped_stop
41
+ end
42
+
43
+ def start_safely
44
+ wrapped_start
45
+ @_started = true
46
+ end
47
+
48
+ def stop_safely
49
+ wrapped_stop if @_started
50
+ @_started = false
51
+ end
52
+
53
+ def on(sym)
54
+ @_notification_names << sym
55
+ Nanoc::Core::NotificationCenter.on(sym, self) { |*args| yield(*args) }
56
+ end
57
+ end
58
+ end