between_meals 0.0.6 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e58d518baa0534eecc6de15ac0fb0f7f09a6069f6fb870a60c55adf2cf2f8404
4
+ data.tar.gz: 44aaa21c488bea122a228466f0c30f5d0c9eab3ff778b3f60242cccaf2020ee6
5
+ SHA512:
6
+ metadata.gz: 7a44420814d8e34888bea5be482a7d8b43d30979c0c8369cb11e0b13ff4cddc36e0a3da29a955d70917ba9b878fa75213640b718658c0f4b6fabbd199e002f8a
7
+ data.tar.gz: 12dece7d9a249c883bef1eb0c6460977998fbc7b7e6ba90ecaf5bb7912d374df72b919bd78b1aece7548e1063664e04b6d80007ad5c68baaf2a587060cc6a0aa
data/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # Between Meals
2
2
 
3
- [![Build Status](https://travis-ci.org/facebook/between-meals.svg)](http://travis-ci.org/facebook/between-meals)
3
+ [![TravisCI](https://travis-ci.org/facebook/between-meals.svg)](http://travis-ci.org/facebook/between-meals)
4
+ [![CircleCI](https://circleci.com/gh/facebook/between-meals.svg?style=svg)](https://circleci.com/gh/facebook/between-meals)
4
5
 
5
6
  ## Intro
6
7
  Ohai!
7
8
 
8
- Between Meals is the library for calculating what Chef objects where modified
9
+ Between Meals is the library for calculating what Chef objects were modified
9
10
  between two revisions in a version control system. It is also the library
10
- that that backs Taste Tester and Grocery Delivery.
11
+ that backs Taste Tester and Grocery Delivery.
11
12
 
12
13
  It currently supports SVN, GIT and HG, but plugins can easily be written for
13
14
  other source control systems.
@@ -22,3 +23,6 @@ functions.
22
23
  * Mixlib::ShellOut
23
24
  * Rugged
24
25
 
26
+ ## License
27
+
28
+ See the `LICENSE` file in this repo.
@@ -37,15 +37,11 @@ module BetweenMeals
37
37
  end
38
38
 
39
39
  def self.info(msg)
40
- if @@logger
41
- @@logger.info(msg)
42
- end
40
+ @@logger&.info(msg)
43
41
  end
44
42
 
45
43
  def self.debug(msg)
46
- if @@logger
47
- @@logger.debug(msg)
48
- end
44
+ @@logger&.debug(msg)
49
45
  end
50
46
 
51
47
  def info(msg)
@@ -58,3 +54,4 @@ module BetweenMeals
58
54
  end
59
55
  end
60
56
  end
57
+ # rubocop:enable ClassVars
@@ -14,50 +14,111 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- # rubocop:disable ClassVars
18
17
  module BetweenMeals
19
18
  module Changes
20
19
  # Changeset aware cookbook
21
20
  class Cookbook < Change
22
- def self.meaningful_cookbook_file?(path, cookbook_dirs)
23
- cookbook_dirs.each do |dir|
24
- re = %r{^#{dir}/([^/]+)/.*}
25
- m = path.match(re)
26
- debug("[cookbook] #{path} meaningful? [#{re}]: #{m}")
27
- return true if m
28
- end
29
- false
21
+ def self.meaningful_cookbook_file?(path)
22
+ !explode_path(path).nil?
30
23
  end
31
24
 
32
- def self.explode_path(path, cookbook_dirs)
33
- cookbook_dirs.each do |dir|
25
+ def self.explode_path(path)
26
+ @cookbook_dirs.each do |dir|
34
27
  re = %r{^#{dir}/([^/]+)/.*}
35
28
  debug("[cookbook] Matching #{path} against ^#{re}")
36
29
  m = path.match(re)
37
30
  next unless m
31
+
38
32
  info("Cookbook is #{m[1]}")
39
33
  return {
40
34
  :cookbook_dir => dir,
41
- :name => m[1] }
35
+ :name => m[1],
36
+ }
42
37
  end
43
38
  nil
44
39
  end
45
40
 
41
+ def self.map_symlinks(files)
42
+ # For each symlink get the source path, if any files have changed under
43
+ # the source path, fake them as coming from the symlink path. This
44
+ # allows the normal cookbook logic to just work.
45
+ symlinks = {}
46
+ @cookbook_dirs.each do |dir|
47
+ dir = File.join(@repo_dir, dir)
48
+ # Find symlinks in each cookbook_dir
49
+ links = Dir.foreach(dir).select do |d|
50
+ File.symlink?(File.join(dir, d))
51
+ end
52
+ links.each do |link|
53
+ link = File.join(dir, link)
54
+ next if symlinks[link]
55
+
56
+ source = File.realpath(link)
57
+ repo = File.join(@repo_dir, '/')
58
+ # maps absolute symlink path to relative source and link paths
59
+ symlinks[link] = {
60
+ 'source' => source.gsub(repo, ''),
61
+ 'link' => link.gsub(repo, ''),
62
+ }
63
+ end
64
+ end
65
+
66
+ # Create the file hash expected for each file that is a link or coming
67
+ # from a linked directory but fake the source path as a symlink path.
68
+ # Hacky but works :)
69
+ links_to_append = []
70
+ symlinks.each_value do |lrp| # link_abs_path, link_relative_path
71
+ files.each do |f|
72
+ # a symlink will never have trailing '/', add one.
73
+ f[:path] += '/' if f[:path] == lrp['link']
74
+
75
+ # If a metadata file in the path of a symlink target directory has a
76
+ # deleted status, check if a metadata file exists in the symlink
77
+ # source directory. If so, mark it as modified to prevent deletion.
78
+ symlink_source_dir = File.join(@repo_dir, lrp['source'])
79
+ if (f[:path] == File.join(lrp['link'], 'metadata.rb') ||
80
+ f[:path] == File.join(lrp['link'], 'metadata.json')) &&
81
+ f[:status] == :deleted &&
82
+ (File.file?(File.join(symlink_source_dir, 'metadata.rb')) ||
83
+ File.file?(File.join(symlink_source_dir, 'metadata.json')))
84
+ f[:status] = :modified
85
+ end
86
+
87
+ next unless f[:path].start_with?(lrp['source'])
88
+
89
+ # This make a deep dup of the file hash
90
+ l = Marshal.load(Marshal.dump(f))
91
+ l[:path].gsub!(lrp['source'], lrp['link'])
92
+ links_to_append << l
93
+ end
94
+ end
95
+ links_to_append
96
+ end
97
+
46
98
  def initialize(files, cookbook_dirs)
47
99
  @files = files
48
- @name = self.class.explode_path(
49
- files.sample[:path],
50
- cookbook_dirs
51
- )[:name]
52
- # if metadata.rb is being deleted
100
+ @cookbook_dirs = cookbook_dirs
101
+ @name = self.class.explode_path(files.sample[:path])[:name]
102
+ # if metadata.(json|rb) is being deleted and we aren't also
103
+ # adding/modifying one of those two,
53
104
  # cookbook is marked for deletion
54
105
  # otherwise it was modified
55
106
  # and will be re-uploaded
56
107
  if files.
57
108
  select { |x| x[:status] == :deleted }.
58
- map { |x| x[:path].match(%{.*metadata\.rb$}) }.
109
+ map do |x|
110
+ x[:path].match(
111
+ %{^(#{cookbook_dirs.join('|')})/[^/]+/metadata\.(rb|json)$},
112
+ )
113
+ end.
59
114
  compact.
60
- any?
115
+ any? &&
116
+ files.reject { |x| x[:status] == :deleted }.
117
+ map do |x|
118
+ x[:path].match(
119
+ %{^(#{cookbook_dirs.join('|')})/[^/]+/metadata\.(rb|json)$},
120
+ )
121
+ end.none?
61
122
  @status = :deleted
62
123
  else
63
124
  @status = :modified
@@ -66,16 +127,22 @@ module BetweenMeals
66
127
 
67
128
  # Given a list of changed files
68
129
  # create a list of Cookbook objects
69
- def self.find(list, cookbook_dirs, logger)
130
+ def self.find(list, cookbook_dirs, logger, repo, track_symlinks = false)
131
+ # rubocop:disable ClassVars
70
132
  @@logger = logger
133
+ # rubocop:enable ClassVars
71
134
  return [] if list.nil? || list.empty?
135
+
72
136
  # rubocop:disable MultilineBlockChain
137
+ @repo_dir = File.realpath(repo.repo_path)
138
+ @cookbook_dirs = cookbook_dirs
139
+ list += map_symlinks(list) if track_symlinks
73
140
  list.
74
141
  group_by do |x|
75
142
  # Group by prefix of cookbok_dir + cookbook_name
76
143
  # so that we treat deletes and modifications across
77
144
  # two locations separately
78
- g = self.explode_path(x[:path], cookbook_dirs)
145
+ g = self.explode_path(x[:path])
79
146
  g[:cookbook_dir] + '/' + g[:name] if g
80
147
  end.
81
148
  map do |_, change|
@@ -83,10 +150,10 @@ module BetweenMeals
83
150
  # Changes to OWNERS or other stuff that might end up
84
151
  # in [core, other, secure] dirs are ignored
85
152
  is_cookbook = change.select do |c|
86
- self.meaningful_cookbook_file?(c[:path], cookbook_dirs)
153
+ self.meaningful_cookbook_file?(c[:path])
87
154
  end.any?
88
155
  if is_cookbook
89
- BetweenMeals::Changes::Cookbook.new(change, cookbook_dirs)
156
+ BetweenMeals::Changes::Cookbook.new(change, @cookbook_dirs)
90
157
  end
91
158
  end.compact
92
159
  # rubocop:enable MultilineBlockChain
@@ -14,7 +14,6 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- # rubocop:disable ClassVars
18
17
  module BetweenMeals
19
18
  module Changes
20
19
  # Changeset aware databag
@@ -37,8 +36,11 @@ module BetweenMeals
37
36
  end
38
37
 
39
38
  def self.find(list, databag_dir, logger)
39
+ # rubocop:disable ClassVars
40
40
  @@logger = logger
41
+ # rubocop:enable ClassVars
41
42
  return [] if list.nil? || list.empty?
43
+
42
44
  list.
43
45
  select { |x| self.name_from_path(x[:path], databag_dir) }.
44
46
  map do |x|
@@ -14,13 +14,12 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- # rubocop:disable ClassVars
18
17
  module BetweenMeals
19
18
  module Changes
20
19
  # Changeset aware role
21
20
  class Role < Change
22
21
  def self.name_from_path(path, role_dir)
23
- re = %r{^#{role_dir}/(.+)\.rb}
22
+ re = %r{^#{role_dir}/(.+)\.(?:rb|json)}
24
23
  debug("[role] Matching #{path} against #{re}")
25
24
  m = path.match(re)
26
25
  if m
@@ -38,8 +37,11 @@ module BetweenMeals
38
37
  # Given a list of changed files
39
38
  # create a list of Role objects
40
39
  def self.find(list, role_dir, logger)
40
+ # rubocop:disable ClassVars
41
41
  @@logger = logger
42
+ # rubocop:enable ClassVars
42
43
  return [] if list.nil? || list.empty?
44
+
43
45
  list.
44
46
  select { |x| self.name_from_path(x[:path], role_dir) }.
45
47
  map do |x|
@@ -27,15 +27,19 @@ module BetweenMeals
27
27
  # Basically, you always want to use BetweenMeals::Changes through this
28
28
  # helper class.
29
29
  class Changeset
30
- class ReferenceError < Exception
30
+ class ReferenceError < RuntimeError
31
31
  end
32
-
33
- def initialize(logger, repo, start_ref, end_ref, locations)
32
+ # rubocop:disable Metrics/ParameterLists
33
+ def initialize(
34
+ logger, repo, start_ref, end_ref, locations, track_symlinks = false
35
+ )
36
+ # rubocop:enable Metrics/ParameterLists
34
37
  @logger = logger
35
38
  @repo = repo
36
39
  @cookbook_dirs = locations[:cookbook_dirs].dup
37
40
  @role_dir = locations[:role_dir]
38
41
  @databag_dir = locations[:databag_dir]
42
+ @track_symlinks = track_symlinks
39
43
  # Figure out which files changed if refs provided
40
44
  # or return all files (full upload) otherwise
41
45
  if start_ref
@@ -49,7 +53,9 @@ module BetweenMeals
49
53
  end
50
54
 
51
55
  def cookbooks
52
- BetweenMeals::Changes::Cookbook.find(@files, @cookbook_dirs, @logger)
56
+ BetweenMeals::Changes::Cookbook.find(
57
+ @files, @cookbook_dirs, @logger, @repo, @track_symlinks
58
+ )
53
59
  end
54
60
 
55
61
  def roles
@@ -27,17 +27,26 @@ module BetweenMeals
27
27
  end
28
28
 
29
29
  def cmd(params, cwd = nil)
30
- unless cwd
31
- cwd = File.expand_path(@cwd)
32
- end
30
+ cwd ||= File.expand_path(@cwd)
33
31
  cmd = "#{@bin} #{params}"
34
32
  @logger.info("Running \"#{cmd}\"")
35
33
  c = Mixlib::ShellOut.new(
36
34
  cmd,
37
- :cwd => cwd
35
+ :cwd => cwd,
36
+ :env => {
37
+ # macOS needs /usr/local/bin as hg cannot be installed in /bin or
38
+ # /usr/bin
39
+ 'PATH' => '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin',
40
+ },
38
41
  )
39
42
  c.run_command
40
- c.error!
43
+ if c.error?
44
+ # Let's make sure the error goes to the logs
45
+ @logger.error("#{@bin} failed: #{c.format_for_exception}")
46
+ # if our logger is STDOUT, we'll double log when we throw
47
+ # the exception, but that's OK
48
+ c.error!
49
+ end
41
50
  c
42
51
  end
43
52
  end
@@ -26,6 +26,8 @@ module BetweenMeals
26
26
  class Knife
27
27
  include BetweenMeals::Util
28
28
 
29
+ attr_accessor :cookbook_dirs
30
+
29
31
  def initialize(opts = {})
30
32
  @logger = opts[:logger] || nil
31
33
  @user = opts[:user] || ENV['USER']
@@ -37,11 +39,20 @@ module BetweenMeals
37
39
  @config = opts[:config] ||
38
40
  "#{@home}/.chef/knife-#{@user}-taste-tester.rb"
39
41
  @knife = opts[:bin] || 'knife'
42
+ @knife_verb_option = ''
43
+ unless @logger.nil?
44
+ if @logger.level == Logger::DEBUG
45
+ @knife_verb_option = '-VV'
46
+ elsif @logger.level == Logger::INFO
47
+ @knife_verb_option = '-V'
48
+ end
49
+ end
40
50
  @berks = opts[:berks_bin] || 'berks'
41
51
  @berks_config = opts[:berks_config]
42
52
  @pem = opts[:pem] ||
43
53
  "#{@home}/.chef/#{@user}-taste-tester.pem"
44
54
  @role_dir = opts[:role_dir]
55
+ @role_type = opts[:role_type] || 'rb'
45
56
  @cookbook_dirs = opts[:cookbook_dirs]
46
57
  @databag_dir = opts[:databag_dir]
47
58
  @checksum_dir = opts[:checksum_dir]
@@ -51,30 +62,34 @@ module BetweenMeals
51
62
 
52
63
  def role_upload_all
53
64
  if File.exists?(@role_dir)
54
- roles = File.join(@role_dir, '*.rb')
55
- exec!("#{@knife} role from file #{roles} -c #{@config}", @logger)
65
+ roles = File.join(@role_dir, "*.#{@role_type}")
66
+ exec!("#{@knife} role from file #{roles} #{@knife_verb_option} " +
67
+ "-c #{@config}", @logger)
56
68
  end
57
69
  end
58
70
 
59
71
  def role_upload(roles)
60
72
  if roles.any?
61
- roles = roles.map { |x| File.join(@role_dir, "#{x.name}.rb") }.join(' ')
62
- exec!("#{@knife} role from file #{roles} -c #{@config}", @logger)
73
+ roles = roles.map do |x|
74
+ File.join(@role_dir, "#{x.name}.#{@role_type}")
75
+ end.join(' ')
76
+ exec!("#{@knife} role from file #{roles} #{@knife_verb_option} " +
77
+ "-c #{@config}", @logger)
63
78
  end
64
79
  end
65
80
 
66
81
  def role_delete(roles)
67
82
  if roles.any?
68
83
  roles.each do |role|
69
- exec!(
70
- "#{@knife} role delete #{role.name} --yes -c #{@config}", @logger
71
- )
84
+ exec!("#{@knife} role delete #{role.name} #{@knife_verb_option} " +
85
+ "--yes -c #{@config}", @logger)
72
86
  end
73
87
  end
74
88
  end
75
89
 
76
90
  def cookbook_upload_all
77
- exec!("#{@knife} cookbook upload -a -c #{@config}", @logger)
91
+ exec!("#{@knife} cookbook upload -a #{@knife_verb_option} " +
92
+ "-c #{@config}", @logger)
78
93
  end
79
94
 
80
95
  def berks_cookbook_upload_all
@@ -94,7 +109,8 @@ module BetweenMeals
94
109
  def cookbook_upload(cookbooks)
95
110
  if cookbooks.any?
96
111
  cookbooks = cookbooks.map(&:name).join(' ')
97
- exec!("#{@knife} cookbook upload #{cookbooks} -c #{@config}", @logger)
112
+ exec!("#{@knife} cookbook upload #{cookbooks} #{@knife_verb_option} " +
113
+ "-c #{@config}", @logger)
98
114
  end
99
115
  end
100
116
 
@@ -108,6 +124,7 @@ module BetweenMeals
108
124
  @cookbook_dirs.each do |path|
109
125
  cookbooks.each do |cb|
110
126
  next unless File.exists?("#{path}/#{cb}")
127
+
111
128
  @logger.warn("Running berkshelf on cookbook: #{cb}")
112
129
  exec!("cd #{path}/#{cb} && #{@berks} install #{berks_config} && " +
113
130
  "#{@berks} upload #{berks_config}", @logger)
@@ -120,7 +137,8 @@ module BetweenMeals
120
137
  if cookbooks.any?
121
138
  cookbooks.each do |cookbook|
122
139
  exec!("#{@knife} cookbook delete #{cookbook.name}" +
123
- " --purge -a --yes -c #{@config}", @logger)
140
+ " --purge -a --yes #{@knife_verb_option} -c #{@config}",
141
+ @logger)
124
142
  end
125
143
  end
126
144
  end
@@ -143,8 +161,9 @@ module BetweenMeals
143
161
  File.join(@databag_dir, dbname, "#{x.item}.json")
144
162
  end.join(' ')
145
163
  exec!(
146
- "#{@knife} data bag from file #{dbname} #{dbitems} -c #{@config}",
147
- @logger
164
+ "#{@knife} data bag from file #{dbname} #{dbitems} " +
165
+ "#{@knife_verb_option} -c #{@config}",
166
+ @logger,
148
167
  )
149
168
  end
150
169
  end
@@ -155,7 +174,7 @@ module BetweenMeals
155
174
  databags.group_by(&:name).each do |dbname, dbs|
156
175
  dbs.each do |db|
157
176
  exec!("#{@knife} data bag delete #{dbname} #{db.item}" +
158
- " --yes -c #{@config}", @logger)
177
+ " --yes #{@knife_verb_option} -c #{@config}", @logger)
159
178
  end
160
179
  delete_databag_if_empty(dbname)
161
180
  end
@@ -180,8 +199,11 @@ BLOCK
180
199
  cfg << " \"#{dir}\",\n"
181
200
  end
182
201
  cfg << "]\n"
183
- unless File.directory?(File.dirname(@config))
184
- Dir.mkdir(File.dirname(@config), 0755)
202
+ begin
203
+ Dir.mkdir(File.dirname(@config), 0o755)
204
+ rescue Errno::EEXIST
205
+ # not an error if it's already there.
206
+ nil
185
207
  end
186
208
  if !File.exists?(@config) ||
187
209
  ::Digest::MD5.hexdigest(cfg) !=
@@ -220,7 +242,14 @@ zvgEHqbS0/QkJGOZ+UifPRanTDuGYQkPdHHOER4UghbM+Kz5rZbBicJ3bCyNOsah
220
242
  IAMAEpsWX2s2A6phgMCx7kH6wMmoZn3hb7Thh9+PfR8Jtp2/7k+ibCeF4gEWUCs5
221
243
  6wX4GR84dwyhG80yd4TP8Qo=
222
244
  -----END PRIVATE KEY-----
223
- BLOCK
245
+ BLOCK
246
+
247
+ begin
248
+ Dir.mkdir(File.dirname(@pem), 0o755)
249
+ rescue Errno::EEXIST
250
+ # not an error if it's already there.
251
+ nil
252
+ end
224
253
 
225
254
  unless File.exists?(@pem)
226
255
  @logger.info("Generating #{@pem}")
@@ -232,22 +261,25 @@ IAMAEpsWX2s2A6phgMCx7kH6wMmoZn3hb7Thh9+PfR8Jtp2/7k+ibCeF4gEWUCs5
232
261
 
233
262
  def create_databag_if_missing(databag)
234
263
  s = Mixlib::ShellOut.new("#{@knife} data bag list" +
235
- " --format json -c #{@config}").run_command
264
+ " --format json #{@knife_verb_option} " +
265
+ "-c #{@config}").run_command
236
266
  s.error!
237
- db = JSON.load(s.stdout)
267
+ db = JSON.parse(s.stdout)
238
268
  unless db.include?(databag)
239
- exec!("#{@knife} data bag create #{databag} -c #{@config}", @logger)
269
+ exec!("#{@knife} data bag create #{databag} #{@knife_verb_option} " +
270
+ "-c #{@config}", @logger)
240
271
  end
241
272
  end
242
273
 
243
274
  def delete_databag_if_empty(databag)
244
275
  s = Mixlib::ShellOut.new("#{@knife} data bag show #{databag}" +
245
- " --format json -c #{@config}").run_command
276
+ " --format json #{@knife_verb_option} " +
277
+ "-c #{@config}").run_command
246
278
  s.error!
247
- db = JSON.load(s.stdout)
279
+ db = JSON.parse(s.stdout)
248
280
  if db.empty?
249
- exec!("#{@knife} data bag delete #{databag} --yes -c #{@config}",
250
- @logger)
281
+ exec!("#{@knife} data bag delete #{databag} --yes " +
282
+ "#{@knife_verb_option} -c #{@config}", @logger)
251
283
  end
252
284
  end
253
285
  end
@@ -27,7 +27,7 @@ module BetweenMeals
27
27
  @repo = nil
28
28
  @bin = nil
29
29
  setup
30
- rescue
30
+ rescue StandardError
31
31
  @logger.warn("Unable to read repo from #{File.expand_path(repo_path)}")
32
32
  exit(1)
33
33
  end
@@ -54,7 +54,7 @@ module BetweenMeals
54
54
  logger.info("Repo found to be #{klass.to_s.split('::').last}")
55
55
  return r
56
56
  end
57
- rescue
57
+ rescue StandardError
58
58
  logger.debug("Skipping #{klass}")
59
59
  end
60
60
  end
@@ -29,7 +29,7 @@ module BetweenMeals
29
29
  if File.exists?(File.expand_path(@repo_path))
30
30
  begin
31
31
  @repo = Rugged::Repository.new(File.expand_path(@repo_path))
32
- rescue
32
+ rescue StandardError
33
33
  @repo = nil
34
34
  end
35
35
  else
@@ -60,7 +60,7 @@ module BetweenMeals
60
60
  {
61
61
  :message => msg,
62
62
  :update_ref => 'HEAD',
63
- }
63
+ },
64
64
  )
65
65
  end
66
66
 
@@ -86,10 +86,10 @@ module BetweenMeals
86
86
  stdout = @cmd.diff(start_ref, end_ref).stdout
87
87
  begin
88
88
  parse_status(stdout).compact
89
- rescue => e
89
+ rescue StandardError => e
90
90
  # We've seen some weird non-reproducible failures here
91
91
  @logger.error(
92
- 'Something went wrong. Please please report this output.'
92
+ 'Something went wrong. Please report this output.',
93
93
  )
94
94
  @logger.error(e)
95
95
  stdout.lines.each do |line|
@@ -112,8 +112,9 @@ module BetweenMeals
112
112
  if @cmd.merge_base(rev, master).stdout.strip == rev
113
113
  return true
114
114
  end
115
+
115
116
  return false
116
- rescue
117
+ rescue StandardError
117
118
  return false
118
119
  end
119
120
 
@@ -153,62 +154,63 @@ module BetweenMeals
153
154
 
154
155
  # rubocop:disable MultilineBlockChain
155
156
  changes.lines.map do |line|
156
- case line
157
- when /^A\s+(\S+)$/
157
+ parts = line.chomp.split("\t")
158
+ case parts[0]
159
+ when 'A'
158
160
  # A path
159
161
  {
160
162
  :status => :modified,
161
- :path => Regexp.last_match(1)
163
+ :path => parts[1],
162
164
  }
163
- when /^C(?:\d*)\s+(\S+)\s+(\S+)/
165
+ when /^C(?:\d*)/
164
166
  # C<numbers> path1 path2
165
167
  {
166
168
  :status => :modified,
167
- :path => Regexp.last_match(2)
169
+ :path => parts[2],
168
170
  }
169
- when /^D\s+(\S+)$/
171
+ when 'D'
170
172
  # D path
171
173
  {
172
174
  :status => :deleted,
173
- :path => Regexp.last_match(1)
175
+ :path => parts[1],
174
176
  }
175
- when /^M(?:\d*)\s+(\S+)$/
177
+ when /^M(?:\d*)/
176
178
  # M<numbers> path
177
179
  {
178
180
  :status => :modified,
179
- :path => Regexp.last_match(1)
181
+ :path => parts[1],
180
182
  }
181
- when /^R(?:\d*)\s+(\S+)\s+(\S+)/
183
+ when /^R(?:\d*)/
182
184
  # R<numbers> path1 path2
183
185
  [
184
186
  {
185
187
  :status => :deleted,
186
- :path => Regexp.last_match(1)
188
+ :path => parts[1],
187
189
  },
188
190
  {
189
191
  :status => :modified,
190
- :path => Regexp.last_match(2)
191
- }
192
+ :path => parts[2],
193
+ },
192
194
  ]
193
- when /^T\s+(\S+)$/
195
+ when 'T'
194
196
  # T path
195
197
  [
196
198
  {
197
199
  :status => :deleted,
198
- :path => Regexp.last_match(1)
200
+ :path => parts[1],
199
201
  },
200
202
  {
201
203
  :status => :modified,
202
- :path => Regexp.last_match(1)
203
- }
204
+ :path => parts[1],
205
+ },
204
206
  ]
205
207
  else
206
- fail 'No match'
208
+ fail 'Failed to parse repo diff line.'
207
209
  end
208
210
  end.flatten.map do |x|
209
211
  {
210
212
  :status => x[:status],
211
- :path => x[:path].sub("#{@repo_path}/", '')
213
+ :path => x[:path].sub("#{@repo_path}/", ''),
212
214
  }
213
215
  end
214
216
  # rubocop:enable MultilineBlockChain
@@ -50,10 +50,10 @@ module BetweenMeals
50
50
  stdout = @cmd.status(start_ref, end_ref).stdout
51
51
  begin
52
52
  parse_status(stdout).compact
53
- rescue => e
53
+ rescue StandardError => e
54
54
  # We've seen some weird non-reproducible failures here
55
55
  @logger.error(
56
- 'Something went wrong. Please please report this output.'
56
+ 'Something went wrong. Please report this output.',
57
57
  )
58
58
  @logger.error(e)
59
59
  stdout.lines.each do |line|
@@ -65,9 +65,9 @@ module BetweenMeals
65
65
 
66
66
  def update
67
67
  @cmd.pull.stdout
68
- rescue
68
+ rescue StandardError => e
69
69
  @logger.error('Something went wrong with hg!')
70
- @logger.error(cmd.stdout)
70
+ @logger.error(e)
71
71
  raise
72
72
  end
73
73
 
@@ -83,7 +83,7 @@ module BetweenMeals
83
83
  :time => Time.parse(@cmd.log('date|isodate', 'master').stdout),
84
84
  :rev => @cmd.log('node', 'master').stdout,
85
85
  }]
86
- rescue
86
+ rescue StandardError
87
87
  [{
88
88
  :time => nil,
89
89
  :rev => nil,
@@ -103,7 +103,7 @@ module BetweenMeals
103
103
 
104
104
  def last_msg
105
105
  @cmd.log('desc').stdout
106
- rescue
106
+ rescue StandardError
107
107
  nil
108
108
  end
109
109
 
@@ -115,13 +115,13 @@ module BetweenMeals
115
115
 
116
116
  def email
117
117
  username[2]
118
- rescue
118
+ rescue StandardError
119
119
  nil
120
120
  end
121
121
 
122
122
  def name
123
123
  username[1]
124
- rescue
124
+ rescue StandardError
125
125
  nil
126
126
  end
127
127
 
@@ -143,7 +143,7 @@ module BetweenMeals
143
143
  def valid_ref?(ref)
144
144
  @cmd.rev(ref)
145
145
  return true
146
- rescue
146
+ rescue StandardError
147
147
  raise Changeset::ReferenceError
148
148
  end
149
149
 
@@ -165,49 +165,48 @@ module BetweenMeals
165
165
  # I = ignored
166
166
  # = origin of the previous file (with --copies)
167
167
 
168
- # rubocop:disable MultilineBlockChain
169
168
  changes.lines.map do |line|
170
- case line
171
- when /^A (\S+)$/
169
+ parts = line.chomp.split(nil, 2)
170
+ case parts[0]
171
+ when 'A'
172
172
  {
173
173
  :status => :added,
174
- :path => Regexp.last_match(1)
174
+ :path => parts[1],
175
175
  }
176
- when /^C (\S+)$/
176
+ when 'C'
177
177
  {
178
178
  :status => :clean,
179
- :path => Regexp.last_match(1)
179
+ :path => parts[1],
180
180
  }
181
- when /^R (\S+)$/
181
+ when 'R'
182
182
  {
183
183
  :status => :deleted,
184
- :path => Regexp.last_match(1)
184
+ :path => parts[1],
185
185
  }
186
- when /^M (\S+)$/
186
+ when 'M'
187
187
  {
188
188
  :status => :modified,
189
- :path => Regexp.last_match(1)
189
+ :path => parts[1],
190
190
  }
191
- when /^! (\S+)$/
191
+ when '!'
192
192
  {
193
193
  :status => :missing,
194
- :path => Regexp.last_match(1)
194
+ :path => parts[1],
195
195
  }
196
- when /^\? (\S+)$/
196
+ when '?'
197
197
  {
198
198
  :status => :untracked,
199
- :path => Regexp.last_match(1)
199
+ :path => parts[1],
200
200
  }
201
- when /^I (\S+)$/
201
+ when 'I'
202
202
  {
203
203
  :status => :ignored,
204
- :path => Regexp.last_match(1)
204
+ :path => parts[1],
205
205
  }
206
206
  else
207
- fail 'No match'
207
+ fail 'Failed to parse repo diff line.'
208
208
  end
209
209
  end
210
- # rubocop:enable MultilineBlockChain
211
210
  end
212
211
  end
213
212
  end
@@ -50,7 +50,7 @@ module BetweenMeals
50
50
  begin
51
51
  f.write(msg)
52
52
  f.flush
53
- cmd("commit --amend -l #{f.path}")
53
+ cmd("commit --amend --exclude '**' -l #{f.path}")
54
54
  ensure
55
55
  f.close
56
56
  f.unlink
@@ -64,9 +64,9 @@ module BetweenMeals
64
64
 
65
65
  begin
66
66
  parse_status(changes).compact
67
- rescue => e
67
+ rescue StandardError => e
68
68
  @logger.error(
69
- 'Something went wrong. Please please report this output.'
69
+ 'Something went wrong. Please report this output.',
70
70
  )
71
71
  @logger.error(e)
72
72
  stdout.lines.each do |line|
@@ -88,12 +88,11 @@ module BetweenMeals
88
88
  end
89
89
  end
90
90
 
91
- def upstream?
92
- end
91
+ def upstream?; end
93
92
 
94
93
  def valid_ref?(ref)
95
94
  @cmd.info_r(ref, @repo_path)
96
- rescue
95
+ rescue StandardError
97
96
  raise Changeset::ReferenceError
98
97
  end
99
98
 
@@ -103,13 +102,13 @@ module BetweenMeals
103
102
  # http://svnbook.red-bean.com/en/1.0/re26.html
104
103
  changes.lines.map do |line|
105
104
  case line
106
- when (/^([\w ])\w?\s+(\S+)$/)
105
+ when /^([\w ])\w?\s+(.+)$/
107
106
  {
108
107
  :status => Regexp.last_match(1) == 'D' ? :deleted : :modified,
109
108
  :path => Regexp.last_match(2).sub("#{@repo_path}/", ''),
110
109
  }
111
110
  else
112
- fail 'No match'
111
+ fail 'Failed to parse repo diff line.'
113
112
  end
114
113
  end
115
114
  end
@@ -15,13 +15,15 @@
15
15
  # limitations under the License.
16
16
 
17
17
  require 'colorize'
18
+ require 'net/http'
19
+ require 'openssl'
18
20
  require 'socket'
19
21
  require 'timeout'
20
22
 
21
23
  module BetweenMeals
22
24
  # A set of simple utility functions used throughout BetweenMeals
23
25
  #
24
- # Feel freeo to use... note that if you pass in a logger once
26
+ # Feel free to use... note that if you pass in a logger once
25
27
  # you don't need to again, but be safe and always pass one in. :)
26
28
 
27
29
  # Util classes need class vars :)
@@ -36,28 +38,29 @@ module BetweenMeals
36
38
  info("Executed in #{format('%.2f', Time.now - t0)}s")
37
39
  end
38
40
 
39
- def exec!(command, logger = nil)
41
+ def exec!(command, logger = nil, stream = nil)
40
42
  @@logger = logger if logger
41
- c = execute(command)
43
+ c = execute(command, stream)
42
44
  c.error!
43
45
  return c.status.exitstatus, c.stdout
44
46
  end
45
47
 
46
- def exec(command, logger = nil)
48
+ def exec(command, logger = nil, stream = nil)
47
49
  @@logger = logger if logger
48
- c = execute(command)
50
+
51
+ c = execute(command, stream)
49
52
  return c.status.exitstatus, c.stdout
50
53
  end
51
54
 
52
55
  private
53
56
 
54
57
  def info(msg)
55
- @@logger.info(msg) if @@logger
58
+ @@logger&.info(msg)
56
59
  end
57
60
 
58
- def execute(command)
61
+ def execute(command, stream)
59
62
  info("Running: #{command}")
60
- c = Mixlib::ShellOut.new(command)
63
+ c = Mixlib::ShellOut.new(command, :live_stream => stream)
61
64
  c.run_command
62
65
  c.stdout.lines.each do |line|
63
66
  info("STDOUT: #{line.strip}")
@@ -69,20 +72,43 @@ module BetweenMeals
69
72
  end
70
73
 
71
74
  def port_open?(port)
72
- begin
73
- Timeout.timeout(1) do
74
- begin
75
- s = TCPSocket.new('localhost', port)
76
- s.close
77
- return true
78
- rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
79
- return false
75
+ ips = Socket.ip_address_list
76
+ ips.map!(&:ip_address)
77
+ ips.each do |ip|
78
+ begin
79
+ Timeout.timeout(1) do
80
+ begin
81
+ s = TCPSocket.new(ip, port)
82
+ s.close
83
+ return true
84
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
85
+ next
86
+ end
87
+ end
88
+ rescue Timeout::Error
89
+ next
90
+ end
91
+ end
92
+ return false
93
+ end
94
+
95
+ def chef_zero_running?(port, use_ssl)
96
+ Timeout.timeout(1) do
97
+ begin
98
+ http = Net::HTTP.new('localhost', port)
99
+ if use_ssl
100
+ http.use_ssl = true
101
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
80
102
  end
103
+ res = http.get('/')
104
+ return res['Server'] == 'chef-zero'
105
+ rescue StandardError
106
+ return false
81
107
  end
82
- rescue Timeout::Error
83
- return false
84
108
  end
109
+ rescue Timeout::Error
85
110
  return false
86
111
  end
87
112
  end
88
113
  end
114
+ # rubocop:enable ClassVars
metadata CHANGED
@@ -1,208 +1,175 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: between_meals
3
- version: !ruby/object:Gem::Version
4
- hash: 19
5
- prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 6
10
- version: 0.0.6
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.11
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Phil Dibowitz
14
8
  - Marcin Sawicki
15
9
  autorequire:
16
10
  bindir: bin
17
11
  cert_chain: []
18
-
19
- date: 2015-11-26 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2020-05-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: colorize
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
27
18
  - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
33
21
  type: :runtime
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: json
37
22
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
41
25
  - - ">="
42
- - !ruby/object:Gem::Version
43
- hash: 3
44
- segments:
45
- - 0
46
- version: "0"
47
- type: :runtime
48
- version_requirements: *id002
49
- - !ruby/object:Gem::Dependency
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
50
29
  name: mixlib-shellout
51
- prerelease: false
52
- requirement: &id003 !ruby/object:Gem::Requirement
53
- none: false
54
- requirements:
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
55
32
  - - ">="
56
- - !ruby/object:Gem::Version
57
- hash: 3
58
- segments:
59
- - 0
60
- version: "0"
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
61
35
  type: :runtime
62
- version_requirements: *id003
63
- - !ruby/object:Gem::Dependency
64
- name: rugged
65
36
  prerelease: false
66
- requirement: &id004 !ruby/object:Gem::Requirement
67
- none: false
68
- requirements:
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rugged
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
69
46
  - - ">="
70
- - !ruby/object:Gem::Version
71
- hash: 3
72
- segments:
73
- - 0
74
- version: "0"
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
75
49
  type: :runtime
76
- version_requirements: *id004
77
- - !ruby/object:Gem::Dependency
78
- name: rspec-core
79
50
  prerelease: false
80
- requirement: &id005 !ruby/object:Gem::Requirement
81
- none: false
82
- requirements:
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec-core
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
83
60
  - - ">="
84
- - !ruby/object:Gem::Version
85
- hash: 3
86
- segments:
87
- - 0
88
- version: "0"
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
89
63
  type: :development
90
- version_requirements: *id005
91
- - !ruby/object:Gem::Dependency
92
- name: rspec-expectations
93
64
  prerelease: false
94
- requirement: &id006 !ruby/object:Gem::Requirement
95
- none: false
96
- requirements:
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec-expectations
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
97
74
  - - ">="
98
- - !ruby/object:Gem::Version
99
- hash: 3
100
- segments:
101
- - 0
102
- version: "0"
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
103
77
  type: :development
104
- version_requirements: *id006
105
- - !ruby/object:Gem::Dependency
106
- name: rspec-mocks
107
78
  prerelease: false
108
- requirement: &id007 !ruby/object:Gem::Requirement
109
- none: false
110
- requirements:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec-mocks
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
111
88
  - - ">="
112
- - !ruby/object:Gem::Version
113
- hash: 3
114
- segments:
115
- - 0
116
- version: "0"
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
117
91
  type: :development
118
- version_requirements: *id007
119
- - !ruby/object:Gem::Dependency
120
- name: rubocop
121
92
  prerelease: false
122
- requirement: &id008 !ruby/object:Gem::Requirement
123
- none: false
124
- requirements:
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
125
95
  - - ">="
126
- - !ruby/object:Gem::Version
127
- hash: 3
128
- segments:
129
- - 0
130
- version: "0"
131
- type: :development
132
- version_requirements: *id008
133
- - !ruby/object:Gem::Dependency
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
134
99
  name: simplecov
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
135
106
  prerelease: false
136
- requirement: &id009 !ruby/object:Gem::Requirement
137
- none: false
138
- requirements:
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
139
109
  - - ">="
140
- - !ruby/object:Gem::Version
141
- hash: 3
142
- segments:
143
- - 0
144
- version: "0"
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rubocop
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '='
117
+ - !ruby/object:Gem::Version
118
+ version: 0.49.1
145
119
  type: :development
146
- version_requirements: *id009
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '='
124
+ - !ruby/object:Gem::Version
125
+ version: 0.49.1
147
126
  description: Library for calculation Chef differences between revisions
148
127
  email:
149
128
  executables: []
150
-
151
129
  extensions: []
152
-
153
- extra_rdoc_files:
130
+ extra_rdoc_files:
154
131
  - README.md
155
132
  - LICENSE
156
- files:
157
- - README.md
133
+ files:
158
134
  - LICENSE
159
- - lib/between_meals/knife.rb
160
- - lib/between_meals/cmd.rb
161
- - lib/between_meals/util.rb
162
- - lib/between_meals/repo.rb
163
- - lib/between_meals/changeset.rb
135
+ - README.md
164
136
  - lib/between_meals/changes/change.rb
165
- - lib/between_meals/changes/role.rb
166
137
  - lib/between_meals/changes/cookbook.rb
167
138
  - lib/between_meals/changes/databag.rb
168
- - lib/between_meals/repo/svn/cmd.rb
169
- - lib/between_meals/repo/hg/cmd.rb
170
- - lib/between_meals/repo/git/cmd.rb
171
- - lib/between_meals/repo/svn.rb
139
+ - lib/between_meals/changes/role.rb
140
+ - lib/between_meals/changeset.rb
141
+ - lib/between_meals/cmd.rb
142
+ - lib/between_meals/knife.rb
143
+ - lib/between_meals/repo.rb
172
144
  - lib/between_meals/repo/git.rb
145
+ - lib/between_meals/repo/git/cmd.rb
173
146
  - lib/between_meals/repo/hg.rb
147
+ - lib/between_meals/repo/hg/cmd.rb
148
+ - lib/between_meals/repo/svn.rb
149
+ - lib/between_meals/repo/svn/cmd.rb
150
+ - lib/between_meals/util.rb
174
151
  homepage: https://github.com/facebook/between-meals
175
- licenses:
176
- - Apache
152
+ licenses:
153
+ - Apache-2.0
154
+ metadata: {}
177
155
  post_install_message:
178
156
  rdoc_options: []
179
-
180
- require_paths:
157
+ require_paths:
181
158
  - lib
182
- required_ruby_version: !ruby/object:Gem::Requirement
183
- none: false
184
- requirements:
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
185
161
  - - ">="
186
- - !ruby/object:Gem::Version
187
- hash: 3
188
- segments:
189
- - 0
190
- version: "0"
191
- required_rubygems_version: !ruby/object:Gem::Requirement
192
- none: false
193
- requirements:
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
194
166
  - - ">="
195
- - !ruby/object:Gem::Version
196
- hash: 3
197
- segments:
198
- - 0
199
- version: "0"
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
200
169
  requirements: []
201
-
202
170
  rubyforge_project:
203
- rubygems_version: 1.8.5
171
+ rubygems_version: 2.7.6.2
204
172
  signing_key:
205
- specification_version: 3
173
+ specification_version: 4
206
174
  summary: Between Meals
207
175
  test_files: []
208
-