nanoc 4.9.1 → 4.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ab127f94d9ffc710fc374831e36f805e16e1fd1bf1dcadfc65d48ce8009d4f8
4
- data.tar.gz: 4f167936c1d475ce4625875ec5788d99d1f0e22fb0499644e5c632d26bfe0ef1
3
+ metadata.gz: b913559b6a6971b80377035d086779ac7d799a7ffee38289778bec2e8a82cd7c
4
+ data.tar.gz: 28bb11a9f2146ace9c6a018a69bc11c766bfe29ee08fbce18923f4686bda8379
5
5
  SHA512:
6
- metadata.gz: 3ce94577815ee770cb5e572d232357a60fd4447ab68c101d0a6215e9b45c1f25866433ac90e478475dbccf92cbbf97d5a01c1b6a40198a715a6e5364f68f6064
7
- data.tar.gz: 38dec7119c8a3239ec8ab5a2922fe4aca8857645446100f6601bffebe75c6ff2414d0b0886bebc633b95f7df8c12ef25a6d59926e1101cc63917584ad13170de
6
+ metadata.gz: 9862f93c33f34a75792f371ff106bfe9119f61c0e052e648ef8caa66364e81adc91ec36d015b22f8f9faea4479839fe013edb388886785b7149089428bb57b69
7
+ data.tar.gz: 75f1f8f4039bc15ba041861696b80ededbf7fb67ed18f57b2c1b4e0cd65efef46a331e5ea6e659de37eb1e8c5f05dfea39a097a2d5f4d25a493410fd77e2ec3b
data/NEWS.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Nanoc news
2
2
 
3
+ ## 4.9.2 (2018-03-30)
4
+
5
+ Fixes:
6
+
7
+ * Fixed bug which caused `output_dir` not to be ignored when checking for excludes in pruner (#1313, #1324)
8
+ * Fixed bug which caused `Filter#depend_on` not to create a proper dependency when the depended-on item has no representations (#1330)
9
+
10
+ Enhancements:
11
+
12
+ * Made Nanoc use hardlinks instead of copying files when possible (#1321) [Antonio Terceiro]
13
+ * Made Nanoc show an understandable error when a filter returns `nil` by accident (#1323, #1326)
14
+ * Made the checks also consider `.xhtml` and `.htm` files (#1328, #1329)
15
+ * Made Nanoc not report thread exceptions, which would freeze Ruby (#1332)
16
+
3
17
  ## 4.9.1 (2018-02-22)
4
18
 
5
19
  Fixes:
@@ -54,6 +54,7 @@ require 'stringio'
54
54
  require 'tempfile'
55
55
  require 'time'
56
56
  require 'timeout'
57
+ require 'tomlrb'
57
58
  require 'tmpdir'
58
59
  require 'uri'
59
60
  require 'yaml'
@@ -224,6 +224,18 @@ module Nanoc::Int
224
224
  end
225
225
  end
226
226
 
227
+ class OutputNotWritten < Generic
228
+ def initialize(filter_name, output_filename)
229
+ super("The #{filter_name.inspect} filter did not write anything to the required output file, #{output_filename}.")
230
+ end
231
+ end
232
+
233
+ class FilterReturnedNil < Generic
234
+ def initialize(filter_name)
235
+ super("The #{filter_name.inspect} filter returned nil, but is required to return a String.")
236
+ end
237
+ end
238
+
227
239
  class InternalInconsistency < Generic
228
240
  end
229
241
  end
@@ -91,4 +91,10 @@ module Nanoc
91
91
  end
92
92
  end
93
93
 
94
+ # Tracking issue:
95
+ # https://github.com/nanoc/features/issues/24
94
96
  Nanoc::Feature.define('live_cmd', version: '4.9')
97
+
98
+ # Tracking issue:
99
+ # https://github.com/nanoc/features/issues/40
100
+ Nanoc::Feature.define('toml', version: '4.9')
@@ -28,7 +28,12 @@ module Nanoc::Int
28
28
 
29
29
  # @return [String]
30
30
  def self.config_filename_for_cwd
31
- filenames = %w[nanoc.yaml config.yaml]
31
+ filenames =
32
+ if Nanoc::Feature.enabled?(Nanoc::Feature::TOML)
33
+ %w[nanoc.yaml config.yaml nanoc.toml]
34
+ else
35
+ %w[nanoc.yaml config.yaml]
36
+ end
32
37
  candidate = filenames.find { |f| File.file?(f) }
33
38
  candidate && File.expand_path(candidate)
34
39
  end
@@ -41,7 +46,7 @@ module Nanoc::Int
41
46
  # Read
42
47
  config =
43
48
  apply_parent_config(
44
- Nanoc::Int::Configuration.new(hash: YAML.load_file(filename)),
49
+ Nanoc::Int::Configuration.new(hash: load_file(filename)),
45
50
  [filename],
46
51
  ).with_defaults
47
52
 
@@ -49,6 +54,17 @@ module Nanoc::Int
49
54
  config.with_environment
50
55
  end
51
56
 
57
+ def load_file(filename)
58
+ case File.extname(filename)
59
+ when '.yaml'
60
+ YAML.load_file(filename)
61
+ when '.toml'
62
+ Tomlrb.load_file(filename)
63
+ else
64
+ raise Nanoc::Int::Errors::InternalInconsistency, 'Unhandled config file extension'
65
+ end
66
+ end
67
+
52
68
  # @api private
53
69
  def apply_parent_config(config, processed_paths = [])
54
70
  parent_path = config[:parent_config_file]
@@ -66,7 +82,7 @@ module Nanoc::Int
66
82
  end
67
83
 
68
84
  # Load
69
- parent_config = Nanoc::Int::Configuration.new(hash: YAML.load_file(parent_path))
85
+ parent_config = Nanoc::Int::Configuration.new(hash: load_file(parent_path))
70
86
  full_parent_config = apply_parent_config(parent_config, processed_paths + [parent_path])
71
87
  full_parent_config.merge(config.without(:parent_config_file))
72
88
  end
@@ -23,6 +23,8 @@ module Nanoc::Int
23
23
  def bounce(_obj, raw_content: false, attributes: false, compiled_content: false, path: false); end
24
24
  end
25
25
 
26
+ attr_reader :dependency_store
27
+
26
28
  def initialize(dependency_store)
27
29
  @dependency_store = dependency_store
28
30
  @stack = []
@@ -3,12 +3,6 @@
3
3
  module Nanoc
4
4
  module Int
5
5
  class Executor
6
- class OutputNotWrittenError < ::Nanoc::Error
7
- def initialize(filter_name, output_filename)
8
- super("The #{filter_name.inspect} filter did not write anything to the required output file, #{output_filename}.")
9
- end
10
- end
11
-
12
6
  def initialize(rep, compilation_context, dependency_tracker)
13
7
  @rep = rep
14
8
  @compilation_context = compilation_context
@@ -35,11 +29,6 @@ module Nanoc
35
29
 
36
30
  # Store
37
31
  @compilation_context.snapshot_repo.set(@rep, :last, last)
38
-
39
- # Check whether file was written
40
- if filter.class.to_binary? && !File.file?(filter.output_filename)
41
- raise OutputNotWrittenError.new(filter_name, filter.output_filename)
42
- end
43
32
  ensure
44
33
  Nanoc::Int::NotificationCenter.post(:filtering_ended, @rep, filter_name)
45
34
  end
@@ -87,6 +87,11 @@ module Nanoc
87
87
  (@to || :text) == :binary
88
88
  end
89
89
 
90
+ # @api private
91
+ def to_text?
92
+ (@to || :text) == :text
93
+ end
94
+
90
95
  # @return [Boolean]
91
96
  #
92
97
  # @api private
@@ -149,7 +154,7 @@ module Nanoc
149
154
  # @api private
150
155
  def setup_and_run(*args)
151
156
  self.class.setup
152
- run(*args)
157
+ run(*args).tap { |res| verify(res) }
153
158
  end
154
159
 
155
160
  # Runs the filter on the given content or filename.
@@ -170,6 +175,18 @@ module Nanoc
170
175
  raise NotImplementedError.new('Nanoc::Filter subclasses must implement #run')
171
176
  end
172
177
 
178
+ def verify(res)
179
+ if self.class.to_binary?
180
+ unless File.file?(output_filename)
181
+ raise Nanoc::Int::Errors::OutputNotWritten.new(self.class.identifier, output_filename)
182
+ end
183
+ elsif self.class.to_text?
184
+ unless res
185
+ raise Nanoc::Int::Errors::FilterReturnedNil.new(self.class.identifier)
186
+ end
187
+ end
188
+ end
189
+
173
190
  # Returns a filename that is used to write data to. This method is only
174
191
  # used on binary items. When running a binary filter on a file, the
175
192
  # resulting file must end up in the location returned by this method.
@@ -211,6 +228,7 @@ module Nanoc
211
228
  # @return [void]
212
229
  def depend_on(items)
213
230
  items.flat_map(&:reps).flat_map(&:raw_path)
231
+ items.each(&:raw_filename)
214
232
  end
215
233
  end
216
234
  end
@@ -48,7 +48,13 @@ module Nanoc::Int
48
48
  is_modified = is_created || !FileUtils.identical?(raw_path, temp_path)
49
49
 
50
50
  # Write
51
- FileUtils.cp(temp_path, raw_path) if is_modified
51
+ if is_modified
52
+ begin
53
+ FileUtils.ln(temp_path, raw_path, force: true)
54
+ rescue Errno::EXDEV
55
+ FileUtils.cp(temp_path, raw_path)
56
+ end
57
+ end
52
58
 
53
59
  item_rep.modified = is_modified
54
60
 
@@ -6,6 +6,8 @@ module Nanoc
6
6
  #
7
7
  # @api private
8
8
  class Pruner
9
+ include Nanoc::Int::ContractsSupport
10
+
9
11
  # @param [Nanoc::Int::Configuration] config
10
12
  #
11
13
  # @param [Nanoc::Int::ItemRepRepo] reps
@@ -22,9 +24,6 @@ module Nanoc
22
24
  @exclude = Set.new(exclude)
23
25
  end
24
26
 
25
- # Prunes all output files not managed by Nanoc.
26
- #
27
- # @return [void]
28
27
  def run
29
28
  return unless File.directory?(@config[:output_dir])
30
29
 
@@ -35,18 +34,13 @@ module Nanoc
35
34
  remove_empty_directories(present_dirs)
36
35
  end
37
36
 
38
- def exclude?(component)
39
- @exclude.include?(component)
40
- end
41
-
42
- # @param [String] filename The filename to check
43
- #
44
- # @return [Boolean] true if the given file is excluded, false otherwise
37
+ contract String => C::Bool
45
38
  def filename_excluded?(filename)
46
39
  pathname = Pathname.new(strip_output_dir(filename))
47
40
  @exclude.any? { |e| pathname_components(pathname).include?(e) }
48
41
  end
49
42
 
43
+ contract String => String
50
44
  def strip_output_dir(filename)
51
45
  if filename.start_with?(@config[:output_dir])
52
46
  filename[@config[:output_dir].size..-1]
@@ -55,6 +49,7 @@ module Nanoc
55
49
  end
56
50
  end
57
51
 
52
+ contract Pathname => C::ArrayOf[String]
58
53
  def pathname_components(pathname)
59
54
  components = []
60
55
  tmp = pathname
@@ -67,22 +62,27 @@ module Nanoc
67
62
  components.reverse
68
63
  end
69
64
 
65
+ contract C::ArrayOf[String], C::ArrayOf[String] => self
70
66
  # @api private
71
67
  def remove_stray_files(present_files, compiled_files)
72
68
  (present_files - compiled_files).each do |f|
73
- delete_file(f) unless exclude?(f)
69
+ delete_file(f) unless filename_excluded?(f)
74
70
  end
71
+ self
75
72
  end
76
73
 
74
+ contract C::ArrayOf[String] => self
77
75
  # @api private
78
76
  def remove_empty_directories(present_dirs)
79
77
  present_dirs.reverse_each do |dir|
80
78
  next if Dir.foreach(dir) { |n| break true if n !~ /\A\.\.?\z/ }
81
- next if exclude?(dir)
79
+ next if filename_excluded?(dir)
82
80
  delete_dir(dir)
83
81
  end
82
+ self
84
83
  end
85
84
 
85
+ contract String => C::ArrayOf[C::ArrayOf[String]]
86
86
  # @api private
87
87
  def files_and_dirs_in(dir)
88
88
  present_files = []
@@ -91,15 +91,13 @@ module Nanoc
91
91
  expanded_dir = File.expand_path(dir)
92
92
 
93
93
  Find.find(dir) do |f|
94
- basename = File.basename(f)
95
-
96
94
  case File.ftype(f)
97
95
  when 'file'
98
- unless exclude?(basename)
96
+ unless filename_excluded?(f)
99
97
  present_files << f
100
98
  end
101
99
  when 'directory'
102
- if exclude?(basename)
100
+ if filename_excluded?(f)
103
101
  Find.prune
104
102
  elsif expanded_dir != File.expand_path(f)
105
103
  present_dirs << f
@@ -45,6 +45,7 @@ module Nanoc
45
45
 
46
46
  # @api private
47
47
  def raw_filename
48
+ @context.dependency_tracker.bounce(_unwrap, raw_content: true)
48
49
  _unwrap.content.filename
49
50
  end
50
51
  end
@@ -58,5 +58,10 @@ module Nanoc::Checking
58
58
  def add_issue(desc, subject: nil)
59
59
  @issues << Issue.new(desc, subject, self.class)
60
60
  end
61
+
62
+ # @private
63
+ def output_html_filenames
64
+ output_filenames.select { |f| File.extname(f) =~ /\A\.x?html?\z/ }
65
+ end
61
66
  end
62
67
  end
@@ -10,7 +10,7 @@ module ::Nanoc::Checking::Checks
10
10
  def run
11
11
  # Find all broken external hrefs
12
12
  # TODO: de-duplicate this (duplicated in internal links check)
13
- filenames = output_filenames.select { |f| File.extname(f) == '.html' && !excluded_file?(f) }
13
+ filenames = output_html_filenames.reject { |f| excluded_file?(f) }
14
14
  hrefs_with_filenames = ::Nanoc::Extra::LinkCollector.new(filenames, :external).filenames_per_href
15
15
  results = select_invalid(hrefs_with_filenames.keys)
16
16
 
@@ -15,7 +15,7 @@ module Nanoc::Checking::Checks
15
15
  # @return [void]
16
16
  def run
17
17
  # TODO: de-duplicate this (duplicated in external links check)
18
- filenames = output_filenames.select { |f| File.extname(f) == '.html' }
18
+ filenames = output_html_filenames
19
19
  hrefs_with_filenames = ::Nanoc::Extra::LinkCollector.new(filenames, :internal).filenames_per_href
20
20
  resource_uris_with_filenames = ::Nanoc::Extra::LinkCollector.new(filenames, :internal).filenames_per_resource_uri
21
21
 
@@ -11,7 +11,7 @@ module Nanoc::Checking::Checks
11
11
  PROTOCOL_PATTERN = /^(\w+):\/\//
12
12
 
13
13
  def run
14
- filenames = output_filenames.select { |f| File.extname(f) == '.html' }
14
+ filenames = output_html_filenames
15
15
  resource_uris_with_filenames = ::Nanoc::Extra::LinkCollector.new(filenames).filenames_per_resource_uri
16
16
 
17
17
  resource_uris_with_filenames.each_pair do |uri, fns|
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nanoc::Deploying::Deployers
4
- # A deployer that deploys a site using [fog](https://github.com/geemus/fog).
4
+ # A deployer that deploys a site using [fog](https://github.com/fog/fog).
5
5
  #
6
6
  # @example A deployment configuration with public and staging configurations
7
7
  #
@@ -25,6 +25,12 @@ module Nanoc
25
25
  skip "Could not find external command \"#{cmd}\"" unless command?(cmd)
26
26
  end
27
27
 
28
+ def skip_unless_gem_available(gem)
29
+ require gem
30
+ rescue LoadError
31
+ skip "Could not load gem \"#{gem}\""
32
+ end
33
+
28
34
  def sleep_until(max: 3.0)
29
35
  start = Time.now
30
36
  loop do
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Nanoc
4
4
  # The current Nanoc version.
5
- VERSION = '4.9.1'
5
+ VERSION = '4.9.2'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.1
4
+ version: 4.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-22 00:00:00.000000000 Z
11
+ date: 2018-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: '1.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: tomlrb
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.2'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.2'
139
153
  description: Nanoc is a static-site generator focused on flexibility. It transforms
140
154
  content from a format such as Markdown or AsciiDoc into another format, usually
141
155
  HTML, and lays out pages consistently to retain the site’s look and feel throughout.