nanoc 4.11.14 → 4.11.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +16 -0
  3. data/lib/nanoc.rb +4 -2
  4. data/lib/nanoc/data_sources/filesystem.rb +9 -3
  5. data/lib/nanoc/extra.rb +1 -0
  6. data/lib/nanoc/extra/core_ext.rb +0 -1
  7. data/lib/nanoc/extra/srcset_parser.rb +79 -0
  8. data/lib/nanoc/filters/erb.rb +1 -5
  9. data/lib/nanoc/filters/relativize_paths.rb +62 -10
  10. data/lib/nanoc/helpers/rendering.rb +5 -4
  11. data/lib/nanoc/orig_cli.rb +0 -5
  12. data/lib/nanoc/rule_dsl.rb +1 -0
  13. data/lib/nanoc/rule_dsl/action_provider.rb +1 -1
  14. data/lib/nanoc/rule_dsl/compiler_dsl.rb +1 -1
  15. data/lib/nanoc/rule_dsl/errors.rb +25 -0
  16. data/lib/nanoc/rule_dsl/rules_loader.rb +1 -1
  17. data/lib/nanoc/version.rb +1 -1
  18. metadata +37 -33
  19. data/lib/nanoc/base.rb +0 -13
  20. data/lib/nanoc/base/changes_stream.rb +0 -53
  21. data/lib/nanoc/base/errors.rb +0 -65
  22. data/lib/nanoc/checking.rb +0 -14
  23. data/lib/nanoc/checking/check.rb +0 -93
  24. data/lib/nanoc/checking/checks.rb +0 -14
  25. data/lib/nanoc/checking/checks/css.rb +0 -16
  26. data/lib/nanoc/checking/checks/external_links.rb +0 -151
  27. data/lib/nanoc/checking/checks/html.rb +0 -16
  28. data/lib/nanoc/checking/checks/internal_links.rb +0 -95
  29. data/lib/nanoc/checking/checks/mixed_content.rb +0 -37
  30. data/lib/nanoc/checking/checks/stale.rb +0 -41
  31. data/lib/nanoc/checking/checks/w3c_validator.rb +0 -31
  32. data/lib/nanoc/checking/dsl.rb +0 -27
  33. data/lib/nanoc/checking/issue.rb +0 -16
  34. data/lib/nanoc/checking/loader.rb +0 -50
  35. data/lib/nanoc/checking/runner.rb +0 -136
  36. data/lib/nanoc/deploying.rb +0 -10
  37. data/lib/nanoc/deploying/deployer.rb +0 -45
  38. data/lib/nanoc/deploying/deployers.rb +0 -11
  39. data/lib/nanoc/deploying/deployers/fog.rb +0 -220
  40. data/lib/nanoc/deploying/deployers/git.rb +0 -112
  41. data/lib/nanoc/deploying/deployers/rsync.rb +0 -68
  42. data/lib/nanoc/extra/core_ext/pathname.rb +0 -27
  43. data/lib/nanoc/orig_cli/commands/check.rb +0 -43
  44. data/lib/nanoc/orig_cli/commands/deploy.rb +0 -126
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc::Deploying
4
- # Represents a deployer, an object that allows uploading the compiled site
5
- # to a specific (remote) location.
6
- #
7
- # @abstract Subclass and override {#run} to implement a custom filter.
8
- #
9
- # @api private
10
- class Deployer
11
- extend DDPlugin::Plugin
12
-
13
- # @return [String] The path to the directory that contains the files to
14
- # upload. It should not have a trailing slash.
15
- attr_reader :source_path
16
-
17
- # @return [Hash] The deployer configuration
18
- attr_reader :config
19
-
20
- # @return [Boolean] true if the deployer should only show what would be
21
- # deployed instead of doing the actual deployment
22
- attr_reader :dry_run
23
- alias dry_run? dry_run
24
-
25
- # @param [String] source_path The path to the directory that contains the
26
- # files to upload. It should not have a trailing slash.
27
- #
28
- # @return [Hash] config The deployer configuration
29
- #
30
- # @param [Boolean] dry_run true if the deployer should
31
- # only show what would be deployed instead actually deploying
32
- def initialize(source_path, config, dry_run: false)
33
- @source_path = source_path
34
- @config = config
35
- @dry_run = dry_run
36
- end
37
-
38
- # Performs the actual deployment.
39
- #
40
- # @abstract
41
- def run
42
- raise NotImplementedError.new('Nanoc::Deploying::Deployer subclasses must implement #run')
43
- end
44
- end
45
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tty-command'
4
-
5
- # @api private
6
- module Nanoc::Deploying::Deployers
7
- end
8
-
9
- require_relative 'deployers/fog'
10
- require_relative 'deployers/git'
11
- require_relative 'deployers/rsync'
@@ -1,220 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc::Deploying::Deployers
4
- # A deployer that deploys a site using [fog](https://github.com/fog/fog).
5
- #
6
- # @example A deployment configuration with public and staging configurations
7
- #
8
- # deploy:
9
- # public:
10
- # kind: fog
11
- # bucket: nanoc-site
12
- # cdn_id: XXXXXX
13
- # preprod:
14
- # kind: fog
15
- # provider: local
16
- # local_root: ~/myCloud
17
- # bucket: nanoc-site
18
- # staging:
19
- # kind: fog
20
- # provider: local
21
- # local_root: ~/myCloud
22
- # bucket: nanoc-site-staging
23
- #
24
- # @api private
25
- class Fog < ::Nanoc::Deploying::Deployer
26
- identifier :fog
27
-
28
- class FogWrapper
29
- def initialize(directory, is_dry_run)
30
- @directory = directory
31
- @is_dry_run = is_dry_run
32
- end
33
-
34
- def upload(source_filename, destination_key)
35
- log_effectful("uploading #{source_filename} -> #{destination_key}")
36
-
37
- unless dry_run?
38
- File.open(source_filename) do |io|
39
- @directory.files.create(
40
- key: destination_key,
41
- body: io,
42
- public: true,
43
- )
44
- end
45
- end
46
- end
47
-
48
- def remove(keys)
49
- keys.each do |key|
50
- log_effectful("removing #{key}")
51
-
52
- unless dry_run?
53
- @directory.files.get(key).destroy
54
- end
55
- end
56
- end
57
-
58
- def invalidate(keys, cdn, distribution)
59
- keys.each_slice(1000) do |keys_slice|
60
- keys_slice.each do |key|
61
- log_effectful("invalidating #{key}")
62
- end
63
-
64
- unless dry_run?
65
- cdn.post_invalidation(distribution, keys_slice)
66
- end
67
- end
68
- end
69
-
70
- def dry_run?
71
- @is_dry_run
72
- end
73
-
74
- def log_effectful(str)
75
- if @is_dry_run
76
- puts "[dry run] #{str}"
77
- else
78
- puts str
79
- end
80
- end
81
- end
82
-
83
- # @see Nanoc::Deploying::Deployer#run
84
- def run
85
- require 'fog/core'
86
-
87
- src = File.expand_path(source_path)
88
- bucket = config[:bucket] || config[:bucket_name]
89
- path = config[:path]
90
- cdn_id = config[:cdn_id]
91
-
92
- if path&.end_with?('/')
93
- raise "The path `#{path}` is not supposed to have a trailing slash"
94
- end
95
-
96
- connection = connect
97
- directory = get_or_create_bucket(connection, bucket, path)
98
- wrapper = FogWrapper.new(directory, dry_run?)
99
-
100
- remote_files = list_remote_files(directory)
101
- etags = read_etags(remote_files)
102
-
103
- modified_keys, retained_keys = upload_all(src, path, etags, wrapper)
104
-
105
- removed_keys = remote_files.map(&:key) - retained_keys - modified_keys
106
- wrapper.remove(removed_keys)
107
-
108
- if cdn_id
109
- cdn = ::Fog::CDN.new(config_for_fog)
110
- distribution = cdn.get_distribution(cdn_id)
111
- wrapper.invalidate(modified_keys + removed_keys, cdn, distribution)
112
- end
113
- end
114
-
115
- private
116
-
117
- def config_for_fog
118
- config.dup.tap do |c|
119
- c.delete(:bucket)
120
- c.delete(:bucket_name)
121
- c.delete(:path)
122
- c.delete(:cdn_id)
123
- c.delete(:kind)
124
- end
125
- end
126
-
127
- def connect
128
- ::Fog::Storage.new(config_for_fog)
129
- rescue ArgumentError
130
- require "fog/#{config[:provider]}"
131
- ::Fog::Storage.new(config_for_fog)
132
- end
133
-
134
- def get_or_create_bucket(connection, bucket, path)
135
- directory =
136
- begin
137
- connection.directories.get(bucket, prefix: path)
138
- rescue ::Excon::Errors::NotFound
139
- nil
140
- end
141
-
142
- if directory
143
- directory
144
- elsif dry_run?
145
- puts '[dry run] creating bucket'
146
- else
147
- puts 'creating bucket'
148
- connection.directories.create(key: bucket, prefix: path)
149
- end
150
- end
151
-
152
- def remote_key_for_local_filename(local_filename, src, path)
153
- relative_local_filename = local_filename.sub(/\A#{src}\//, '')
154
-
155
- if path
156
- File.join(path, relative_local_filename)
157
- else
158
- relative_local_filename
159
- end
160
- end
161
-
162
- def list_remote_files(directory)
163
- if directory
164
- [].tap do |files|
165
- directory.files.each { |file| files << file }
166
- end
167
- else
168
- []
169
- end
170
- end
171
-
172
- def list_local_files(src)
173
- Dir[src + '/**/*'].select { |f| File.file?(f) }
174
- end
175
-
176
- def upload_all(src, path, etags, wrapper)
177
- modified_keys = []
178
- retained_keys = []
179
-
180
- local_files = list_local_files(src)
181
- local_files.each do |file_path|
182
- key = remote_key_for_local_filename(file_path, src, path)
183
- if needs_upload?(key, file_path, etags)
184
- wrapper.upload(file_path, key)
185
- modified_keys.push(key)
186
- else
187
- retained_keys.push(key)
188
- end
189
- end
190
-
191
- [modified_keys, retained_keys]
192
- end
193
-
194
- def needs_upload?(key, file_path, etags)
195
- remote_etag = etags[key]
196
- return true if remote_etag.nil?
197
-
198
- local_etag = calc_local_etag(file_path)
199
- remote_etag != local_etag
200
- end
201
-
202
- def read_etags(files)
203
- case config[:provider]
204
- when 'aws'
205
- files.each_with_object({}) do |file, etags|
206
- etags[file.key] = file.etag
207
- end
208
- else
209
- {}
210
- end
211
- end
212
-
213
- def calc_local_etag(file_path)
214
- case config[:provider]
215
- when 'aws'
216
- Digest::MD5.file(file_path).hexdigest
217
- end
218
- end
219
- end
220
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc::Deploying::Deployers
4
- # A deployer that deploys a site using [Git](https://git-scm.com).
5
- #
6
- # @example A deployment configuration for GitHub Pages:
7
- #
8
- # deploy:
9
- # default:
10
- # kind: git
11
- # remote: git@github.com:myself/myproject.git
12
- # branch: gh-pages
13
- # forced: true
14
- #
15
- class Git < ::Nanoc::Deploying::Deployer
16
- identifier :git
17
-
18
- module Errors
19
- class Generic < ::Nanoc::Core::Error
20
- end
21
-
22
- class OutputDirDoesNotExist < Generic
23
- def initialize(path)
24
- super("The directory to deploy, #{path}, does not exist.")
25
- end
26
- end
27
-
28
- class OutputDirIsNotAGitRepo < Generic
29
- def initialize(path)
30
- super("The directory to deploy, #{path}, is not a Git repository.")
31
- end
32
- end
33
-
34
- class RemoteDoesNotExist < Generic
35
- def initialize(remote)
36
- super("The remote to deploy to, #{remote}, does not exist.")
37
- end
38
- end
39
-
40
- class BranchDoesNotExist < Generic
41
- def initialize(branch)
42
- super("The branch to deploy, #{branch}, does not exist.")
43
- end
44
- end
45
- end
46
-
47
- def run
48
- unless File.exist?(source_path)
49
- raise Errors::OutputDirDoesNotExist.new(source_path)
50
- end
51
-
52
- remote = config.fetch(:remote, 'origin')
53
- branch = config.fetch(:branch, 'master')
54
- forced = config.fetch(:forced, false)
55
-
56
- puts "Deploying via Git to branch “#{branch}” on remote “#{remote}”…"
57
-
58
- Dir.chdir(source_path) do
59
- unless File.exist?('.git')
60
- raise Errors::OutputDirIsNotAGitRepo.new(source_path)
61
- end
62
-
63
- # Verify existence of remote, if remote is not a URL
64
- if remote_is_name?(remote)
65
- begin
66
- run_cmd(%W[git config --get remote.#{remote}.url])
67
- rescue TTY::Command::ExitError
68
- raise Errors::RemoteDoesNotExist.new(remote)
69
- end
70
- end
71
-
72
- # If the branch exists then switch to it, otherwise prompt the user to create one.
73
- begin
74
- run_cmd_unless_dry(%W[git checkout #{branch}])
75
- rescue TTY::Command::ExitError
76
- raise Errors::BranchDoesNotExist.new(branch)
77
- end
78
-
79
- return if clean_repo?
80
-
81
- msg = "Automated commit at #{Time.now.utc} by Nanoc #{Nanoc::VERSION}"
82
- author = 'Nanoc <>'
83
- run_cmd_unless_dry(%w[git add -A])
84
- run_cmd_unless_dry(%W[git commit -a --author #{author} -m #{msg}])
85
-
86
- if forced
87
- run_cmd_unless_dry(%W[git push -f #{remote} #{branch}])
88
- else
89
- run_cmd_unless_dry(%W[git push #{remote} #{branch}])
90
- end
91
- end
92
- end
93
-
94
- private
95
-
96
- def remote_is_name?(remote)
97
- remote !~ /:\/\/|@.+:/
98
- end
99
-
100
- def run_cmd(cmd, dry_run: false)
101
- TTY::Command.new(printer: :null).run(*cmd, dry_run: dry_run)
102
- end
103
-
104
- def run_cmd_unless_dry(cmd)
105
- run_cmd(cmd, dry_run: dry_run)
106
- end
107
-
108
- def clean_repo?
109
- TTY::Command.new(printer: :null).run('git status --porcelain').out.empty?
110
- end
111
- end
112
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc::Deploying::Deployers
4
- # A deployer that deploys a site using rsync.
5
- #
6
- # The configuration has should include a `:dst` value, a string containing
7
- # the destination to where rsync should upload its data. It will likely be
8
- # in `host:path` format. It should not end with a slash. For example,
9
- # `"example.com:/var/www/sites/mysite/html"`.
10
- #
11
- # @example A deployment configuration with public and staging configurations
12
- #
13
- # deploy:
14
- # public:
15
- # kind: rsync
16
- # dst: "ectype:sites/stoneship/public"
17
- # staging:
18
- # kind: rsync
19
- # dst: "ectype:sites/stoneship-staging/public"
20
- # options: [ "-glpPrtvz" ]
21
- #
22
- # @api private
23
- class Rsync < ::Nanoc::Deploying::Deployer
24
- identifier :rsync
25
-
26
- # Default rsync options
27
- DEFAULT_OPTIONS = [
28
- '--group',
29
- '--links',
30
- '--perms',
31
- '--partial',
32
- '--progress',
33
- '--recursive',
34
- '--times',
35
- '--verbose',
36
- '--compress',
37
- '--exclude=".hg"',
38
- '--exclude=".svn"',
39
- '--exclude=".git"',
40
- ].freeze
41
-
42
- # @see Nanoc::Deploying::Deployer#run
43
- def run
44
- # Get params
45
- src = source_path + '/'
46
- dst = config[:dst]
47
- options = config[:options] || DEFAULT_OPTIONS
48
-
49
- # Validate
50
- raise 'No dst found in deployment configuration' if dst.nil?
51
- raise 'dst requires no trailing slash' if dst[-1, 1] == '/'
52
-
53
- # Run
54
- if dry_run
55
- warn 'Performing a dry-run; no actions will actually be performed'
56
- run_shell_cmd(['echo', 'rsync', options, src, dst].flatten)
57
- else
58
- run_shell_cmd(['rsync', options, src, dst].flatten)
59
- end
60
- end
61
-
62
- private
63
-
64
- def run_shell_cmd(cmd)
65
- TTY::Command.new(printer: :null).run(*cmd)
66
- end
67
- end
68
- end