nanoc-cli 4.11.13

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