berkshelf 5.2.0 → 8.0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +19 -47
- data/Rakefile +14 -4
- data/berkshelf.gemspec +61 -40
- data/bin/berks +2 -2
- data/lib/berkshelf/api-client.rb +1 -0
- data/lib/berkshelf/api_client/chef_server_connection.rb +29 -0
- data/lib/berkshelf/api_client/connection.rb +57 -0
- data/lib/berkshelf/api_client/errors.rb +10 -0
- data/lib/berkshelf/api_client/remote_cookbook.rb +56 -0
- data/lib/berkshelf/api_client/version.rb +5 -0
- data/lib/berkshelf/api_client.rb +24 -0
- data/lib/berkshelf/berksfile.rb +149 -122
- data/lib/berkshelf/cached_cookbook.rb +127 -24
- data/lib/berkshelf/chef_config_compat.rb +51 -0
- data/lib/berkshelf/chef_repo_universe.rb +47 -0
- data/lib/berkshelf/cli.rb +143 -174
- data/lib/berkshelf/commands/shelf.rb +20 -19
- data/lib/berkshelf/community_rest.rb +59 -94
- data/lib/berkshelf/config.rb +97 -127
- data/lib/berkshelf/cookbook_store.rb +7 -6
- data/lib/berkshelf/core_ext/file.rb +1 -1
- data/lib/berkshelf/core_ext/file_utils.rb +4 -4
- data/lib/berkshelf/core_ext.rb +1 -1
- data/lib/berkshelf/dependency.rb +25 -32
- data/lib/berkshelf/downloader.rb +66 -39
- data/lib/berkshelf/errors.rb +23 -17
- data/lib/berkshelf/file_syncer.rb +24 -47
- data/lib/berkshelf/formatters/human.rb +7 -5
- data/lib/berkshelf/formatters/json.rb +6 -6
- data/lib/berkshelf/installer.rb +120 -111
- data/lib/berkshelf/location.rb +14 -14
- data/lib/berkshelf/locations/base.rb +1 -1
- data/lib/berkshelf/locations/git.rb +16 -24
- data/lib/berkshelf/locations/github.rb +2 -2
- data/lib/berkshelf/locations/path.rb +2 -2
- data/lib/berkshelf/lockfile.rb +326 -328
- data/lib/berkshelf/logger.rb +64 -1
- data/lib/berkshelf/mixin/git.rb +6 -5
- data/lib/berkshelf/packager.rb +44 -10
- data/lib/berkshelf/resolver/graph.rb +1 -1
- data/lib/berkshelf/resolver.rb +4 -4
- data/lib/berkshelf/ridley_compat.rb +109 -0
- data/lib/berkshelf/shell.rb +2 -1
- data/lib/berkshelf/shell_out.rb +18 -0
- data/lib/berkshelf/source.rb +77 -33
- data/lib/berkshelf/source_uri.rb +4 -4
- data/lib/berkshelf/ssl_policies.rb +38 -0
- data/lib/berkshelf/thor.rb +1 -1
- data/lib/berkshelf/thor_ext/hash_with_indifferent_access.rb +1 -1
- data/lib/berkshelf/thor_ext.rb +1 -1
- data/lib/berkshelf/uploader.rb +106 -70
- data/lib/berkshelf/validator.rb +13 -5
- data/lib/berkshelf/version.rb +1 -1
- data/lib/berkshelf/visualizer.rb +16 -11
- data/lib/berkshelf.rb +106 -81
- data/spec/config/knife.rb +4 -4
- data/spec/data/trusted_certs/example.crt +22 -0
- data/spec/fixtures/Berksfile +3 -3
- data/spec/fixtures/complex-cookbook-path/cookbooks/app/metadata.rb +2 -0
- data/spec/fixtures/complex-cookbook-path/cookbooks/jenkins/metadata.rb +2 -0
- data/spec/fixtures/complex-cookbook-path/cookbooks/jenkins-config/metadata.rb +4 -0
- data/spec/fixtures/cookbook-path/jenkins-config/metadata.rb +3 -3
- data/spec/fixtures/cookbook-path-uploader/apt-2.3.6/metadata.rb +2 -0
- data/spec/fixtures/cookbook-path-uploader/build-essential-1.4.2/metadata.rb +2 -0
- data/spec/fixtures/cookbook-path-uploader/jenkins-2.0.3/metadata.rb +5 -0
- data/spec/fixtures/cookbook-path-uploader/jenkins-config-0.1.0/metadata.rb +4 -0
- data/spec/fixtures/cookbook-path-uploader/runit-1.5.8/metadata.rb +5 -0
- data/spec/fixtures/cookbook-path-uploader/yum-3.0.6/metadata.rb +2 -0
- data/spec/fixtures/cookbook-path-uploader/yum-epel-0.2.0/metadata.rb +3 -0
- data/spec/fixtures/cookbook-store/jenkins-2.0.3/metadata.rb +5 -5
- data/spec/fixtures/cookbook-store/jenkins-2.0.4/metadata.rb +4 -4
- data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +3 -3
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +3 -3
- data/spec/spec_helper.rb +56 -64
- data/spec/support/chef_api.rb +15 -16
- data/spec/support/chef_server.rb +71 -69
- data/spec/support/git.rb +59 -58
- data/spec/support/kitchen.rb +0 -14
- data/spec/support/matchers/file_system_matchers.rb +4 -5
- data/spec/support/matchers/filepath_matchers.rb +2 -2
- data/spec/support/path_helpers.rb +17 -17
- data/spec/support/shared_examples/formatter.rb +1 -1
- data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/attributes/default.rb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/files/default/file.h +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/metadata.rb +2 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/recipes/default.rb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/templates/default/template.erb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/attributes/default.rb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/files/default/file.h +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/metadata.rb +2 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/recipes/default.rb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/templates/default/template.erb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/attributes/default.rb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/files/default/file.h +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/metadata.rb +2 -0
- data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/recipes/default.rb +0 -0
- data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/templates/default/template.erb +0 -0
- data/spec/unit/berkshelf/berksfile_spec.rb +84 -105
- data/spec/unit/berkshelf/berkshelf/api_client/chef_server_connection_spec.rb +65 -0
- data/spec/unit/berkshelf/berkshelf/api_client/connection_spec.rb +157 -0
- data/spec/unit/berkshelf/berkshelf/api_client/remote_cookbook_spec.rb +23 -0
- data/spec/unit/berkshelf/berkshelf/api_client_spec.rb +9 -0
- data/spec/unit/berkshelf/cached_cookbook_spec.rb +45 -47
- data/spec/unit/berkshelf/chef_repo_universe_spec.rb +37 -0
- data/spec/unit/berkshelf/cli_spec.rb +7 -8
- data/spec/unit/berkshelf/community_rest_spec.rb +82 -90
- data/spec/unit/berkshelf/config_spec.rb +51 -22
- data/spec/unit/berkshelf/cookbook_store_spec.rb +41 -41
- data/spec/unit/berkshelf/core_ext/file_utils_spec.rb +7 -8
- data/spec/unit/berkshelf/core_ext/pathname_spec.rb +1 -1
- data/spec/unit/berkshelf/dependency_spec.rb +48 -48
- data/spec/unit/berkshelf/downloader_spec.rb +191 -34
- data/spec/unit/berkshelf/errors_spec.rb +3 -3
- data/spec/unit/berkshelf/file_syncer_spec.rb +87 -87
- data/spec/unit/berkshelf/formatters/base_spec.rb +23 -23
- data/spec/unit/berkshelf/formatters/human_spec.rb +2 -2
- data/spec/unit/berkshelf/formatters/json_spec.rb +2 -2
- data/spec/unit/berkshelf/formatters/null_spec.rb +3 -3
- data/spec/unit/berkshelf/installer_spec.rb +8 -8
- data/spec/unit/berkshelf/location_spec.rb +11 -11
- data/spec/unit/berkshelf/locations/base_spec.rb +35 -36
- data/spec/unit/berkshelf/locations/git_spec.rb +90 -93
- data/spec/unit/berkshelf/locations/path_spec.rb +40 -41
- data/spec/unit/berkshelf/lockfile_parser_spec.rb +71 -71
- data/spec/unit/berkshelf/lockfile_spec.rb +205 -211
- data/spec/unit/berkshelf/logger_spec.rb +3 -3
- data/spec/unit/berkshelf/mixin/logging_spec.rb +5 -5
- data/spec/unit/berkshelf/packager_spec.rb +2 -2
- data/spec/unit/berkshelf/resolver/graph_spec.rb +10 -8
- data/spec/unit/berkshelf/resolver_spec.rb +17 -17
- data/spec/unit/berkshelf/ridley_compat_spec.rb +16 -0
- data/spec/unit/berkshelf/shell_spec.rb +34 -34
- data/spec/unit/berkshelf/source_spec.rb +186 -20
- data/spec/unit/berkshelf/source_uri_spec.rb +1 -1
- data/spec/unit/berkshelf/ssl_policies_spec.rb +86 -0
- data/spec/unit/berkshelf/uploader_spec.rb +146 -64
- data/spec/unit/berkshelf/validator_spec.rb +23 -16
- data/spec/unit/berkshelf/visualizer_spec.rb +24 -15
- data/spec/unit/berkshelf_spec.rb +18 -18
- metadata +138 -289
- data/.gitignore +0 -29
- data/.travis.yml +0 -64
- data/CHANGELOG.legacy.md +0 -307
- data/CHANGELOG.md +0 -1358
- data/CONTRIBUTING.md +0 -64
- data/Gemfile.lock +0 -399
- data/Guardfile +0 -23
- data/PLUGINS.md +0 -25
- data/README.md +0 -70
- data/Thorfile +0 -61
- data/appveyor.yml +0 -31
- data/docs/berkshelf_for_newcomers.md +0 -65
- data/features/berksfile.feature +0 -46
- data/features/commands/apply.feature +0 -41
- data/features/commands/contingent.feature +0 -48
- data/features/commands/cookbook.feature +0 -35
- data/features/commands/info.feature +0 -99
- data/features/commands/init.feature +0 -27
- data/features/commands/install.feature +0 -636
- data/features/commands/list.feature +0 -78
- data/features/commands/outdated.feature +0 -130
- data/features/commands/package.feature +0 -17
- data/features/commands/search.feature +0 -17
- data/features/commands/shelf/list.feature +0 -32
- data/features/commands/shelf/show.feature +0 -143
- data/features/commands/shelf/uninstall.feature +0 -96
- data/features/commands/show.feature +0 -83
- data/features/commands/update.feature +0 -142
- data/features/commands/upload.feature +0 -426
- data/features/commands/vendor.feature +0 -111
- data/features/commands/verify.feature +0 -29
- data/features/commands/viz.feature +0 -66
- data/features/community_site.feature +0 -37
- data/features/config.feature +0 -111
- data/features/help.feature +0 -11
- data/features/json_formatter.feature +0 -161
- data/features/lifecycle.feature +0 -378
- data/features/lockfile.feature +0 -378
- data/features/step_definitions/berksfile_steps.rb +0 -39
- data/features/step_definitions/chef/config_steps.rb +0 -12
- data/features/step_definitions/chef_server_steps.rb +0 -60
- data/features/step_definitions/cli_steps.rb +0 -18
- data/features/step_definitions/config_steps.rb +0 -46
- data/features/step_definitions/environment_steps.rb +0 -7
- data/features/step_definitions/filesystem_steps.rb +0 -269
- data/features/step_definitions/gem_steps.rb +0 -13
- data/features/step_definitions/json_steps.rb +0 -23
- data/features/step_definitions/utility_steps.rb +0 -11
- data/features/support/aruba.rb +0 -12
- data/features/support/env.rb +0 -82
- data/generator_files/Berksfile.erb +0 -11
- data/generator_files/CHANGELOG.md.erb +0 -3
- data/generator_files/Gemfile.erb +0 -8
- data/generator_files/README.md.erb +0 -42
- data/generator_files/Thorfile.erb +0 -11
- data/generator_files/Vagrantfile.erb +0 -117
- data/generator_files/chefignore +0 -94
- data/generator_files/default_recipe.erb +0 -6
- data/generator_files/default_test.rb.erb +0 -11
- data/generator_files/gitignore.erb +0 -23
- data/generator_files/helpers.rb.erb +0 -7
- data/generator_files/licenses/apachev2.erb +0 -13
- data/generator_files/licenses/gplv2.erb +0 -15
- data/generator_files/licenses/gplv3.erb +0 -14
- data/generator_files/licenses/mit.erb +0 -20
- data/generator_files/licenses/reserved.erb +0 -3
- data/generator_files/metadata.rb.erb +0 -11
- data/lib/berkshelf/base_generator.rb +0 -43
- data/lib/berkshelf/commands/test_command.rb +0 -13
- data/lib/berkshelf/cookbook_generator.rb +0 -133
- data/lib/berkshelf/init_generator.rb +0 -195
- data/spec/fixtures/cookbooks/example_cookbook/.gitignore +0 -2
- data/spec/fixtures/cookbooks/example_cookbook/.kitchen.yml +0 -26
- data/spec/unit/berkshelf/cookbook_generator_spec.rb +0 -110
- data/spec/unit/berkshelf/init_generator_spec.rb +0 -263
data/lib/berkshelf/lockfile.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative "dependency"
|
2
|
+
require "chef/environment"
|
2
3
|
|
3
4
|
module Berkshelf
|
4
5
|
class Lockfile
|
@@ -24,10 +25,10 @@ module Berkshelf
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
DEFAULT_FILENAME =
|
28
|
+
DEFAULT_FILENAME = "Berksfile.lock".freeze
|
28
29
|
|
29
|
-
DEPENDENCIES =
|
30
|
-
GRAPH =
|
30
|
+
DEPENDENCIES = "DEPENDENCIES".freeze
|
31
|
+
GRAPH = "GRAPH".freeze
|
31
32
|
|
32
33
|
include Berkshelf::Mixin::Logging
|
33
34
|
|
@@ -57,7 +58,7 @@ module Berkshelf
|
|
57
58
|
@dependencies = {}
|
58
59
|
@graph = Graph.new(self)
|
59
60
|
|
60
|
-
parse if File.
|
61
|
+
parse if File.exist?(@filepath)
|
61
62
|
end
|
62
63
|
|
63
64
|
# Parse the lockfile.
|
@@ -75,7 +76,7 @@ module Berkshelf
|
|
75
76
|
# @return [Boolean]
|
76
77
|
# true if this lockfile exists on the disk, false otherwise
|
77
78
|
def present?
|
78
|
-
File.
|
79
|
+
File.exist?(filepath) && !File.read(filepath).strip.empty?
|
79
80
|
end
|
80
81
|
|
81
82
|
# Determine if we can "trust" this lockfile. A lockfile is trustworthy if:
|
@@ -94,7 +95,7 @@ module Berkshelf
|
|
94
95
|
# @return [Boolean]
|
95
96
|
# true if this lockfile is trusted, false otherwise
|
96
97
|
def trusted?
|
97
|
-
Berkshelf.log.info
|
98
|
+
Berkshelf.log.info "Checking if lockfile is trusted"
|
98
99
|
|
99
100
|
checked = {}
|
100
101
|
|
@@ -113,7 +114,7 @@ module Berkshelf
|
|
113
114
|
return false
|
114
115
|
end
|
115
116
|
|
116
|
-
if cookbook = locked.cached_cookbook
|
117
|
+
if ( cookbook = locked.cached_cookbook )
|
117
118
|
Berkshelf.log.debug " Detected there is a cached cookbook"
|
118
119
|
|
119
120
|
unless (cookbook.dependencies.keys - graphed.dependencies.keys).empty?
|
@@ -154,7 +155,7 @@ module Berkshelf
|
|
154
155
|
#
|
155
156
|
# @return [Boolean]
|
156
157
|
def satisfies_transitive?(graph_item, checked, level = 0)
|
157
|
-
indent =
|
158
|
+
indent = " " * (level + 2)
|
158
159
|
|
159
160
|
Berkshelf.log.debug "#{indent}Checking transitive dependencies for #{graph_item}"
|
160
161
|
|
@@ -203,20 +204,23 @@ module Berkshelf
|
|
203
204
|
# if you are locking cookbooks with an invalid or not-specified client
|
204
205
|
# configuration
|
205
206
|
def apply(name, options = {})
|
206
|
-
locks = graph.locks.inject({}) do |hash, (
|
207
|
-
|
208
|
-
|
207
|
+
locks = graph.locks.inject({}) do |hash, (dep_name, dependency)|
|
208
|
+
hash[dep_name] = "= #{dependency.locked_version}"
|
209
|
+
hash
|
209
210
|
end
|
210
211
|
|
211
212
|
if options[:envfile]
|
212
213
|
update_environment_file(options[:envfile], locks) if options[:envfile]
|
213
214
|
else
|
214
215
|
Berkshelf.ridley_connection(options) do |connection|
|
215
|
-
environment =
|
216
|
-
|
217
|
-
|
216
|
+
environment =
|
217
|
+
begin
|
218
|
+
Chef::Environment.from_hash(connection.get("environments/#{name}"))
|
219
|
+
rescue Berkshelf::APIClient::ServiceNotFound
|
220
|
+
raise EnvironmentNotFound.new(name)
|
221
|
+
end
|
218
222
|
|
219
|
-
environment.cookbook_versions
|
223
|
+
environment.cookbook_versions locks
|
220
224
|
environment.save unless options[:envfile]
|
221
225
|
end
|
222
226
|
end
|
@@ -224,7 +228,7 @@ module Berkshelf
|
|
224
228
|
|
225
229
|
# @return [Array<CachedCookbook>]
|
226
230
|
def cached
|
227
|
-
graph.locks.values.collect
|
231
|
+
graph.locks.values.collect(&:cached_cookbook)
|
228
232
|
end
|
229
233
|
|
230
234
|
# The list of dependencies constrained in this lockfile.
|
@@ -297,7 +301,7 @@ module Berkshelf
|
|
297
301
|
unless locked.installed?
|
298
302
|
name = locked.name
|
299
303
|
version = locked.locked_version || locked.version_constraint
|
300
|
-
raise CookbookNotFound.new(name, version,
|
304
|
+
raise CookbookNotFound.new(name, version, "in the cookbook store")
|
301
305
|
end
|
302
306
|
|
303
307
|
locked.cached_cookbook
|
@@ -314,17 +318,17 @@ module Berkshelf
|
|
314
318
|
# @raise [EnvironmentFileNotFound]
|
315
319
|
# If environment file doesn't exist
|
316
320
|
def update_environment_file(environment_file, locks)
|
317
|
-
unless File.
|
321
|
+
unless File.exist?(environment_file)
|
318
322
|
raise EnvironmentFileNotFound.new(environment_file)
|
319
323
|
end
|
320
324
|
|
321
325
|
json_environment = JSON.parse(File.read(environment_file))
|
322
326
|
|
323
|
-
json_environment[
|
327
|
+
json_environment["cookbook_versions"] = locks
|
324
328
|
|
325
329
|
json = JSON.pretty_generate(json_environment)
|
326
330
|
|
327
|
-
File.open(environment_file,
|
331
|
+
File.open(environment_file, "w") { |f| f.puts(json) }
|
328
332
|
|
329
333
|
Berkshelf.log.info "Updated environment file #{environment_file}"
|
330
334
|
end
|
@@ -395,7 +399,6 @@ module Berkshelf
|
|
395
399
|
end
|
396
400
|
Berkshelf.log.debug ""
|
397
401
|
|
398
|
-
|
399
402
|
# Unlock any locked dependencies that are no longer in the Berksfile
|
400
403
|
Berkshelf.log.debug "Unlocking dependencies no longer in the Berksfile"
|
401
404
|
|
@@ -432,7 +435,7 @@ module Berkshelf
|
|
432
435
|
# constraints are satisfied by it.
|
433
436
|
dependency.locked_version = graphed.version
|
434
437
|
|
435
|
-
if cookbook = dependency.cached_cookbook
|
438
|
+
if ( cookbook = dependency.cached_cookbook )
|
436
439
|
Berkshelf.log.debug " Cached cookbook exists"
|
437
440
|
Berkshelf.log.debug " Updating cookbook dependencies if required"
|
438
441
|
graphed.set_dependencies(cookbook.dependencies)
|
@@ -441,11 +444,11 @@ module Berkshelf
|
|
441
444
|
|
442
445
|
# Iteratively remove orphan dependencies
|
443
446
|
orphans = true
|
444
|
-
while orphans
|
447
|
+
while orphans
|
445
448
|
orphans = false
|
446
449
|
graph.each do |cookbook|
|
447
450
|
name = cookbook.name
|
448
|
-
unless dependency?(name)
|
451
|
+
unless dependency?(name) || graph.dependency?(name)
|
449
452
|
Berkshelf.log.debug "#{cookbook} identified as orphan; removing it"
|
450
453
|
unlock(name)
|
451
454
|
orphans = true
|
@@ -461,7 +464,6 @@ module Berkshelf
|
|
461
464
|
Berkshelf.log.debug ""
|
462
465
|
end
|
463
466
|
|
464
|
-
|
465
467
|
# Write the contents of the current statue of the lockfile to disk. This
|
466
468
|
# method uses an atomic file write. A temporary file is created, written,
|
467
469
|
# and then copied over the existing one. This ensures any partial updates
|
@@ -473,7 +475,7 @@ module Berkshelf
|
|
473
475
|
def save
|
474
476
|
return false if dependencies.empty?
|
475
477
|
|
476
|
-
tempfile = Tempfile.new([
|
478
|
+
tempfile = Tempfile.new(["Berksfile", ".lock"])
|
477
479
|
|
478
480
|
tempfile.write(to_lock)
|
479
481
|
|
@@ -509,359 +511,355 @@ module Berkshelf
|
|
509
511
|
"#<Berkshelf::Lockfile #{Pathname.new(filepath).basename}, dependencies: #{dependencies.inspect}>"
|
510
512
|
end
|
511
513
|
|
512
|
-
|
514
|
+
# The class responsible for parsing the lockfile and turning it into a
|
515
|
+
# useful data structure.
|
516
|
+
class LockfileParser
|
517
|
+
NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'.freeze
|
518
|
+
DEPENDENCY_PATTERN = /^ {2}#{NAME_VERSION}$/.freeze
|
519
|
+
DEPENDENCIES_PATTERN = /^ {4}#{NAME_VERSION}$/.freeze
|
520
|
+
OPTION_PATTERN = /^ {4}(.+)\: (.+)/.freeze
|
513
521
|
|
514
|
-
#
|
515
|
-
#
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
522
|
+
# Create a new lockfile parser.
|
523
|
+
#
|
524
|
+
# @param [Lockfile]
|
525
|
+
def initialize(lockfile)
|
526
|
+
@lockfile = lockfile
|
527
|
+
@berksfile = lockfile.berksfile
|
528
|
+
end
|
521
529
|
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
@berksfile = lockfile.berksfile
|
528
|
-
end
|
530
|
+
# Parse the lockfile contents, adding the correct things to the lockfile.
|
531
|
+
#
|
532
|
+
# @return [true]
|
533
|
+
def run
|
534
|
+
@parsed_dependencies = {}
|
529
535
|
|
530
|
-
|
531
|
-
#
|
532
|
-
# @return [true]
|
533
|
-
def run
|
534
|
-
@parsed_dependencies = {}
|
536
|
+
contents = File.read(@lockfile.filepath)
|
535
537
|
|
536
|
-
|
538
|
+
if contents.strip.empty?
|
539
|
+
Berkshelf.formatter.warn "Your lockfile at '#{@lockfile.filepath}' " \
|
540
|
+
"is empty. I am going to parse it anyway, but there is a chance " \
|
541
|
+
"that a larger problem is at play. If you manually edited your " \
|
542
|
+
"lockfile, you may have corrupted it."
|
543
|
+
end
|
537
544
|
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
545
|
+
if contents.strip[0] == "{"
|
546
|
+
Berkshelf.formatter.warn "It looks like you are using an older " \
|
547
|
+
"version of the lockfile. Attempting to convert..."
|
548
|
+
|
549
|
+
dependencies = "#{Lockfile::DEPENDENCIES}\n"
|
550
|
+
graph = "#{Lockfile::GRAPH}\n"
|
551
|
+
|
552
|
+
begin
|
553
|
+
hash = JSON.parse(contents)
|
554
|
+
rescue JSON::ParserError
|
555
|
+
Berkshelf.formatter.warn "Could not convert lockfile! This is a " \
|
556
|
+
"problem. You see, previous versions of the lockfile were " \
|
557
|
+
"actually a lie. It lied to you about your version locks, and we " \
|
558
|
+
"are really sorry about that.\n\n" \
|
559
|
+
"Here's the good news - we fixed it!\n\n" \
|
560
|
+
"Here's the bad news - you probably should not trust your old " \
|
561
|
+
"lockfile. You should manually delete your old lockfile and " \
|
562
|
+
"re-run the installer."
|
543
563
|
end
|
544
564
|
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
graph = "#{Lockfile::GRAPH}\n"
|
551
|
-
|
552
|
-
begin
|
553
|
-
hash = JSON.parse(contents)
|
554
|
-
rescue JSON::ParserError
|
555
|
-
Berkshelf.formatter.warn "Could not convert lockfile! This is a " \
|
556
|
-
"problem. You see, previous versions of the lockfile were " \
|
557
|
-
"actually a lie. It lied to you about your version locks, and we " \
|
558
|
-
"are really sorry about that.\n\n" \
|
559
|
-
"Here's the good news - we fixed it!\n\n" \
|
560
|
-
"Here's the bad news - you probably should not trust your old " \
|
561
|
-
"lockfile. You should manually delete your old lockfile and " \
|
562
|
-
"re-run the installer."
|
563
|
-
end
|
564
|
-
|
565
|
-
hash['dependencies'] && hash['dependencies'].sort .each do |name, info|
|
566
|
-
dependencies << " #{name} (>= 0.0.0)\n"
|
567
|
-
info.each do |key, value|
|
568
|
-
unless key == 'locked_version'
|
569
|
-
dependencies << " #{key}: #{value}\n"
|
570
|
-
end
|
565
|
+
hash["dependencies"] && hash["dependencies"].sort .each do |name, info|
|
566
|
+
dependencies << " #{name} (>= 0.0.0)\n"
|
567
|
+
info.each do |key, value|
|
568
|
+
unless key == "locked_version"
|
569
|
+
dependencies << " #{key}: #{value}\n"
|
571
570
|
end
|
572
|
-
|
573
|
-
graph << " #{name} (#{info['locked_version']})\n"
|
574
571
|
end
|
575
572
|
|
576
|
-
|
577
|
-
end
|
578
|
-
|
579
|
-
contents.split(/(?:\r?\n)+/).each do |line|
|
580
|
-
if line == Lockfile::DEPENDENCIES
|
581
|
-
@state = :dependency
|
582
|
-
elsif line == Lockfile::GRAPH
|
583
|
-
@state = :graph
|
584
|
-
else
|
585
|
-
send("parse_#{@state}", line)
|
586
|
-
end
|
573
|
+
graph << " #{name} (#{info["locked_version"]})\n"
|
587
574
|
end
|
588
575
|
|
589
|
-
|
590
|
-
|
591
|
-
options[:locked_version] = graph_item.version if graph_item
|
576
|
+
contents = "#{dependencies}\n#{graph}"
|
577
|
+
end
|
592
578
|
|
593
|
-
|
594
|
-
|
579
|
+
contents.split(/(?:\r?\n)+/).each do |line|
|
580
|
+
if line == Lockfile::DEPENDENCIES
|
581
|
+
@state = :dependency
|
582
|
+
elsif line == Lockfile::GRAPH
|
583
|
+
@state = :graph
|
584
|
+
else
|
585
|
+
send("parse_#{@state}", line)
|
595
586
|
end
|
596
|
-
|
597
|
-
true
|
598
587
|
end
|
599
588
|
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
#
|
604
|
-
# @param [String] line
|
605
|
-
def parse_dependency(line)
|
606
|
-
if line =~ DEPENDENCY_PATTERN
|
607
|
-
name, version = $1, $2
|
608
|
-
|
609
|
-
@parsed_dependencies[name] ||= {}
|
610
|
-
@parsed_dependencies[name][:constraint] = version if version
|
611
|
-
@current_dependency = @parsed_dependencies[name]
|
612
|
-
elsif line =~ OPTION_PATTERN
|
613
|
-
key, value = $1, $2
|
614
|
-
@current_dependency[key.to_sym] = value
|
615
|
-
end
|
616
|
-
end
|
589
|
+
@parsed_dependencies.each do |name, options|
|
590
|
+
graph_item = @lockfile.graph.find(name)
|
591
|
+
options[:locked_version] = graph_item.version if graph_item
|
617
592
|
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
name, version = $1, $2
|
624
|
-
|
625
|
-
@lockfile.graph.find(name) || @lockfile.graph.add(name, version)
|
626
|
-
@current_lock = name
|
627
|
-
elsif line =~ DEPENDENCIES_PATTERN
|
628
|
-
name, constraint = $1, $2
|
629
|
-
@lockfile.graph.find(@current_lock).add_dependency(name, constraint)
|
630
|
-
end
|
631
|
-
end
|
593
|
+
dependency = Dependency.new(@berksfile, name, options)
|
594
|
+
@lockfile.add(dependency)
|
595
|
+
end
|
596
|
+
|
597
|
+
true
|
632
598
|
end
|
633
599
|
|
634
|
-
|
635
|
-
class Graph
|
636
|
-
include Enumerable
|
600
|
+
private
|
637
601
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
@
|
648
|
-
|
649
|
-
|
602
|
+
# Parse a dependency line.
|
603
|
+
#
|
604
|
+
# @param [String] line
|
605
|
+
def parse_dependency(line)
|
606
|
+
if line =~ DEPENDENCY_PATTERN
|
607
|
+
name, version = $1, $2
|
608
|
+
|
609
|
+
@parsed_dependencies[name] ||= {}
|
610
|
+
@parsed_dependencies[name][:constraint] = version if version
|
611
|
+
@current_dependency = @parsed_dependencies[name]
|
612
|
+
elsif line =~ OPTION_PATTERN
|
613
|
+
key, value = $1, $2
|
614
|
+
@current_dependency[key.to_sym] = value
|
650
615
|
end
|
616
|
+
end
|
651
617
|
|
652
|
-
|
653
|
-
|
654
|
-
|
618
|
+
# Parse a graph line.
|
619
|
+
#
|
620
|
+
# @param [String] line
|
621
|
+
def parse_graph(line)
|
622
|
+
if line =~ DEPENDENCY_PATTERN
|
623
|
+
name, version = $1, $2
|
624
|
+
|
625
|
+
@lockfile.graph.find(name) || @lockfile.graph.add(name, version)
|
626
|
+
@current_lock = name
|
627
|
+
elsif line =~ DEPENDENCIES_PATTERN
|
628
|
+
name, constraint = $1, $2
|
629
|
+
@lockfile.graph.find(@current_lock).add_dependency(name, constraint)
|
655
630
|
end
|
631
|
+
end
|
632
|
+
end
|
656
633
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
#
|
661
|
-
# @return [Hash<String, Dependency>]
|
662
|
-
# a key-value hash where the key is the name of the cookbook and the
|
663
|
-
# value is the locked dependency
|
664
|
-
def locks
|
665
|
-
@graph.sort.inject({}) do |hash, (name, item)|
|
666
|
-
dependency = @lockfile.find(name) ||
|
667
|
-
@berksfile && @berksfile.find(name) ||
|
668
|
-
Dependency.new(@berksfile, name)
|
669
|
-
|
670
|
-
# We need to make a copy of the dependency, or else we could be
|
671
|
-
# modifying an existing object that other processes depend on!
|
672
|
-
dependency = dependency.dup
|
673
|
-
dependency.locked_version = item.version unless dependency.locked_version
|
674
|
-
|
675
|
-
hash[item.name] = dependency
|
676
|
-
hash
|
677
|
-
end
|
678
|
-
end
|
634
|
+
# The class representing an internal graph.
|
635
|
+
class Graph
|
636
|
+
include Enumerable
|
679
637
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
638
|
+
# Create a new Lockfile graph.
|
639
|
+
#
|
640
|
+
# Some clarifying terminology:
|
641
|
+
#
|
642
|
+
# yum-epel (0.2.0) <- lock
|
643
|
+
# yum (~> 3.0) <- dependency
|
644
|
+
#
|
645
|
+
# @return [Graph]
|
646
|
+
def initialize(lockfile)
|
647
|
+
@lockfile = lockfile
|
648
|
+
@berksfile = lockfile.berksfile
|
649
|
+
@graph = {}
|
650
|
+
end
|
690
651
|
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
652
|
+
# @yield [Hash<String]
|
653
|
+
def each(&block)
|
654
|
+
@graph.values.each(&block)
|
655
|
+
end
|
656
|
+
|
657
|
+
# The list of locks for this graph. Dependencies are retrieved from the
|
658
|
+
# lockfile, then the Berksfile, and finally a new dependency object is
|
659
|
+
# created if none of those exist.
|
660
|
+
#
|
661
|
+
# @return [Hash<String, Dependency>]
|
662
|
+
# a key-value hash where the key is the name of the cookbook and the
|
663
|
+
# value is the locked dependency
|
664
|
+
def locks
|
665
|
+
@graph.sort.inject({}) do |hash, (name, item)|
|
666
|
+
dependency = @lockfile.find(name) ||
|
667
|
+
@berksfile && @berksfile.find(name) ||
|
668
|
+
Dependency.new(@berksfile, name)
|
669
|
+
|
670
|
+
# We need to make a copy of the dependency, or else we could be
|
671
|
+
# modifying an existing object that other processes depend on!
|
672
|
+
dependency = dependency.dup
|
673
|
+
dependency.locked_version = item.version unless dependency.locked_version
|
674
|
+
|
675
|
+
hash[item.name] = dependency
|
676
|
+
hash
|
699
677
|
end
|
700
|
-
|
678
|
+
end
|
701
679
|
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
680
|
+
# Find a given dependency in the graph.
|
681
|
+
#
|
682
|
+
# @param [Dependency, String]
|
683
|
+
# the name/dependency to find
|
684
|
+
#
|
685
|
+
# @return [GraphItem, nil]
|
686
|
+
# the item for the name
|
687
|
+
def find(dependency)
|
688
|
+
@graph[Dependency.name(dependency)]
|
689
|
+
end
|
690
|
+
|
691
|
+
# Find if the given lock exists?
|
692
|
+
#
|
693
|
+
# @param [Dependency, String]
|
694
|
+
# the name/dependency to find
|
695
|
+
#
|
696
|
+
# @return [true, false]
|
697
|
+
def lock?(dependency)
|
698
|
+
!find(dependency).nil?
|
699
|
+
end
|
700
|
+
alias_method :has_lock?, :lock?
|
701
|
+
|
702
|
+
# Determine if this graph contains the given dependency. This method is
|
703
|
+
# used by the lockfile when adding or removing dependencies to see if a
|
704
|
+
# dependency can be safely removed.
|
705
|
+
#
|
706
|
+
# @param [Dependency, String] dependency
|
707
|
+
# the name/dependency to find
|
708
|
+
#
|
709
|
+
# @option options [String, Array<String>] :ignore
|
710
|
+
# the list of dependencies to ignore
|
711
|
+
def dependency?(dependency, options = {})
|
712
|
+
name = Dependency.name(dependency)
|
713
|
+
ignore = Hash[*Array(options[:ignore]).map { |i| [i, true] }.flatten]
|
714
714
|
|
715
|
-
|
716
|
-
|
715
|
+
@graph.values.each do |item|
|
716
|
+
next if ignore[item.name]
|
717
717
|
|
718
|
-
|
719
|
-
|
720
|
-
end
|
718
|
+
if item.dependencies.key?(name)
|
719
|
+
return true
|
721
720
|
end
|
722
|
-
|
723
|
-
false
|
724
721
|
end
|
725
|
-
alias_method :has_dependency?, :dependency?
|
726
722
|
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
# the name of the cookbook
|
731
|
-
# @param [#to_s] version
|
732
|
-
# the version of the lock
|
733
|
-
#
|
734
|
-
# @return [GraphItem]
|
735
|
-
def add(name, version)
|
736
|
-
@graph[name.to_s] = GraphItem.new(name, version)
|
737
|
-
end
|
723
|
+
false
|
724
|
+
end
|
725
|
+
alias_method :has_dependency?, :dependency?
|
738
726
|
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
727
|
+
# Add each a new {GraphItem} to the graph.
|
728
|
+
#
|
729
|
+
# @param [#to_s] name
|
730
|
+
# the name of the cookbook
|
731
|
+
# @param [#to_s] version
|
732
|
+
# the version of the lock
|
733
|
+
#
|
734
|
+
# @return [GraphItem]
|
735
|
+
def add(name, version)
|
736
|
+
@graph[name.to_s] = GraphItem.new(name, version)
|
737
|
+
end
|
749
738
|
|
750
|
-
|
751
|
-
|
752
|
-
|
739
|
+
# Recursively remove any dependencies from the graph unless they exist as
|
740
|
+
# top-level dependencies or nested dependencies.
|
741
|
+
#
|
742
|
+
# @param [Dependency, String] dependency
|
743
|
+
# the name/dependency to remove
|
744
|
+
#
|
745
|
+
# @option options [String, Array<String>] :ignore
|
746
|
+
# the list of dependencies to ignore
|
747
|
+
def remove(dependency, options = {})
|
748
|
+
name = Dependency.name(dependency)
|
753
749
|
|
754
|
-
|
755
|
-
|
756
|
-
|
750
|
+
if @lockfile.dependency?(name)
|
751
|
+
return
|
752
|
+
end
|
757
753
|
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
754
|
+
if dependency?(name, options)
|
755
|
+
return
|
756
|
+
end
|
757
|
+
|
758
|
+
# Grab the nested dependencies for this particular entry so we can
|
759
|
+
# recurse and try to remove them from the graph.
|
760
|
+
locked = @graph[name]
|
761
|
+
nested_dependencies = locked && locked.dependencies.keys || []
|
762
762
|
|
763
|
-
|
764
|
-
|
763
|
+
# Now delete the entry
|
764
|
+
@graph.delete(name)
|
765
|
+
|
766
|
+
# Recursively try to delete the remaining dependencies for this item
|
767
|
+
nested_dependencies.each(&method(:remove))
|
768
|
+
end
|
765
769
|
|
766
|
-
|
767
|
-
|
770
|
+
# Update the graph with the given cookbooks. This method destroys the
|
771
|
+
# existing dependency graph with this new result!
|
772
|
+
#
|
773
|
+
# @param [Array<CachedCookbook>]
|
774
|
+
# the list of cookbooks to populate the graph with
|
775
|
+
def update(cookbooks)
|
776
|
+
@graph = {}
|
777
|
+
|
778
|
+
cookbooks.each do |cookbook|
|
779
|
+
@graph[cookbook.cookbook_name.to_s] = GraphItem.new(
|
780
|
+
cookbook.cookbook_name,
|
781
|
+
cookbook.version,
|
782
|
+
cookbook.dependencies
|
783
|
+
)
|
768
784
|
end
|
785
|
+
end
|
769
786
|
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
787
|
+
# Write the contents of the graph to the lockfile format.
|
788
|
+
#
|
789
|
+
# The resulting format looks like:
|
790
|
+
#
|
791
|
+
# GRAPH
|
792
|
+
# apache2 (1.8.14)
|
793
|
+
# yum-epel (0.2.0)
|
794
|
+
# yum (~> 3.0)
|
795
|
+
#
|
796
|
+
# @example lockfile.graph.to_lock #=> "GRAPH\n apache2 (1.18.14)\n..."
|
797
|
+
#
|
798
|
+
# @return [String]
|
799
|
+
#
|
800
|
+
def to_lock
|
801
|
+
out = "#{Lockfile::GRAPH}\n"
|
802
|
+
@graph.sort.each do |name, item|
|
803
|
+
out << " #{name} (#{item.version})\n"
|
804
|
+
|
805
|
+
unless item.dependencies.empty?
|
806
|
+
item.dependencies.sort.each do |dep_name, constraint|
|
807
|
+
out << " #{dep_name} (#{constraint})\n"
|
808
|
+
end
|
784
809
|
end
|
785
810
|
end
|
786
811
|
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
#
|
793
|
-
# yum-epel (0.2.0)
|
794
|
-
# yum (~> 3.0)
|
795
|
-
#
|
796
|
-
# @example lockfile.graph.to_lock #=> "GRAPH\n apache2 (1.18.14)\n..."
|
812
|
+
out
|
813
|
+
end
|
814
|
+
|
815
|
+
# A single item inside the graph.
|
816
|
+
class GraphItem
|
817
|
+
# The name of the cookbook that corresponds to this graph item.
|
797
818
|
#
|
798
819
|
# @return [String]
|
820
|
+
# the name of the cookbook
|
821
|
+
attr_reader :name
|
822
|
+
|
823
|
+
# The locked version for this graph item.
|
799
824
|
#
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
out << " #{name} (#{item.version})\n"
|
804
|
-
|
805
|
-
unless item.dependencies.empty?
|
806
|
-
item.dependencies.sort.each do |name, constraint|
|
807
|
-
out << " #{name} (#{constraint})\n"
|
808
|
-
end
|
809
|
-
end
|
810
|
-
end
|
825
|
+
# @return [String]
|
826
|
+
# the locked version of the graph item (as a string)
|
827
|
+
attr_reader :version
|
811
828
|
|
812
|
-
|
829
|
+
# The list of dependencies and their constraints.
|
830
|
+
#
|
831
|
+
# @return [Hash<String, String>]
|
832
|
+
# the list of dependencies for this graph item, where the key
|
833
|
+
# corresponds to the name of the dependency and the value is the
|
834
|
+
# version constraint.
|
835
|
+
attr_reader :dependencies
|
836
|
+
|
837
|
+
# Create a new graph item.
|
838
|
+
def initialize(name, version, dependencies = {})
|
839
|
+
@name = name.to_s
|
840
|
+
@version = version.to_s
|
841
|
+
@dependencies = dependencies
|
813
842
|
end
|
814
843
|
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
# The locked version for this graph item.
|
826
|
-
#
|
827
|
-
# @return [String]
|
828
|
-
# the locked version of the graph item (as a string)
|
829
|
-
attr_reader :version
|
830
|
-
|
831
|
-
# The list of dependencies and their constraints.
|
832
|
-
#
|
833
|
-
# @return [Hash<String, String>]
|
834
|
-
# the list of dependencies for this graph item, where the key
|
835
|
-
# corresponds to the name of the dependency and the value is the
|
836
|
-
# version constraint.
|
837
|
-
attr_reader :dependencies
|
838
|
-
|
839
|
-
# Create a new graph item.
|
840
|
-
def initialize(name, version, dependencies = {})
|
841
|
-
@name = name.to_s
|
842
|
-
@version = version.to_s
|
843
|
-
@dependencies = dependencies
|
844
|
-
end
|
845
|
-
|
846
|
-
# Add a new dependency to the list.
|
847
|
-
#
|
848
|
-
# @param [#to_s] name
|
849
|
-
# the name to use
|
850
|
-
# @param [#to_s] constraint
|
851
|
-
# the version constraint to use
|
852
|
-
def add_dependency(name, constraint)
|
853
|
-
@dependencies[name.to_s] = constraint.to_s
|
854
|
-
end
|
844
|
+
# Add a new dependency to the list.
|
845
|
+
#
|
846
|
+
# @param [#to_s] name
|
847
|
+
# the name to use
|
848
|
+
# @param [#to_s] constraint
|
849
|
+
# the version constraint to use
|
850
|
+
def add_dependency(name, constraint)
|
851
|
+
@dependencies[name.to_s] = constraint.to_s
|
852
|
+
end
|
855
853
|
|
856
|
-
|
857
|
-
|
858
|
-
|
854
|
+
def set_dependencies(dependencies)
|
855
|
+
@dependencies = dependencies.to_hash
|
856
|
+
end
|
859
857
|
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
end
|
858
|
+
# @private
|
859
|
+
def to_s
|
860
|
+
"#{name} (#{version})"
|
861
|
+
end
|
865
862
|
end
|
863
|
+
end
|
866
864
|
end
|
867
865
|
end
|