berkshelf 0.4.0.rc4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/.gitignore +2 -0
  2. data/Guardfile +6 -3
  3. data/features/default_locations.feature +122 -0
  4. data/features/install.feature +20 -4
  5. data/features/lockfile.feature +1 -6
  6. data/features/update.feature +2 -3
  7. data/generator_files/Berksfile.erb +2 -0
  8. data/generator_files/gitignore.erb +6 -0
  9. data/lib/berkshelf.rb +6 -10
  10. data/lib/berkshelf/berksfile.rb +203 -14
  11. data/lib/berkshelf/cached_cookbook.rb +5 -1
  12. data/lib/berkshelf/cli.rb +4 -0
  13. data/lib/berkshelf/cookbook_source.rb +49 -91
  14. data/lib/berkshelf/cookbook_store.rb +2 -0
  15. data/lib/berkshelf/downloader.rb +71 -51
  16. data/lib/berkshelf/errors.rb +7 -3
  17. data/lib/berkshelf/formatters.rb +6 -6
  18. data/lib/berkshelf/location.rb +171 -0
  19. data/lib/berkshelf/locations/chef_api_location.rb +252 -0
  20. data/lib/berkshelf/locations/git_location.rb +76 -0
  21. data/lib/berkshelf/locations/path_location.rb +38 -0
  22. data/lib/berkshelf/locations/site_location.rb +150 -0
  23. data/lib/berkshelf/lockfile.rb +2 -2
  24. data/lib/berkshelf/resolver.rb +12 -15
  25. data/lib/berkshelf/uploader.rb +2 -9
  26. data/lib/berkshelf/version.rb +1 -1
  27. data/spec/fixtures/lockfile_spec/without_lock/.gitkeep +0 -0
  28. data/spec/support/chef_api.rb +7 -1
  29. data/spec/unit/berkshelf/berksfile_spec.rb +157 -12
  30. data/spec/unit/berkshelf/cached_cookbook_spec.rb +19 -0
  31. data/spec/unit/berkshelf/cookbook_generator_spec.rb +1 -0
  32. data/spec/unit/berkshelf/cookbook_source_spec.rb +25 -35
  33. data/spec/unit/berkshelf/cookbook_store_spec.rb +3 -3
  34. data/spec/unit/berkshelf/downloader_spec.rb +171 -43
  35. data/spec/unit/berkshelf/formatters_spec.rb +13 -16
  36. data/spec/unit/berkshelf/{cookbook_source/location_spec.rb → location_spec.rb} +10 -10
  37. data/spec/unit/berkshelf/{cookbook_source → locations}/chef_api_location_spec.rb +4 -4
  38. data/spec/unit/berkshelf/{cookbook_source → locations}/git_location_spec.rb +8 -8
  39. data/spec/unit/berkshelf/{cookbook_source → locations}/path_location_spec.rb +5 -5
  40. data/spec/unit/berkshelf/{cookbook_source → locations}/site_location_spec.rb +17 -3
  41. data/spec/unit/berkshelf/lockfile_spec.rb +26 -17
  42. data/spec/unit/berkshelf/resolver_spec.rb +6 -5
  43. data/spec/unit/berkshelf/uploader_spec.rb +6 -4
  44. metadata +27 -31
  45. data/lib/berkshelf/cookbook_source/chef_api_location.rb +0 -256
  46. data/lib/berkshelf/cookbook_source/git_location.rb +0 -78
  47. data/lib/berkshelf/cookbook_source/location.rb +0 -167
  48. data/lib/berkshelf/cookbook_source/path_location.rb +0 -40
  49. data/lib/berkshelf/cookbook_source/site_location.rb +0 -149
  50. data/lib/berkshelf/dsl.rb +0 -45
  51. data/lib/berkshelf/tx_result.rb +0 -12
  52. data/lib/berkshelf/tx_result_set.rb +0 -37
  53. data/spec/fixtures/lockfile_spec/without_lock/Berksfile.lock +0 -5
  54. data/spec/unit/berkshelf/dsl_spec.rb +0 -42
  55. data/spec/unit/berkshelf/tx_result_set_spec.rb +0 -77
  56. data/spec/unit/berkshelf/tx_result_spec.rb +0 -21
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Berkshelf
4
- describe CookbookSource::PathLocation do
4
+ describe PathLocation do
5
5
  let(:complacent_constraint) { double('comp-vconstraint', satisfies?: true) }
6
6
  let(:path) { fixtures_path.join("cookbooks", "example_cookbook").to_s }
7
- subject { CookbookSource::PathLocation.new("nginx", complacent_constraint, path: path) }
7
+ subject { PathLocation.new("nginx", complacent_constraint, path: path) }
8
8
 
9
9
  describe "#download" do
10
10
  it "returns an instance of CachedCookbook" do
@@ -18,7 +18,7 @@ module Berkshelf
18
18
  end
19
19
 
20
20
  context "given a path that does not exist" do
21
- subject { CookbookSource::PathLocation.new("doesnot_exist", complacent_constraint, path: tmp_path.join("doesntexist_noway")) }
21
+ subject { PathLocation.new("doesnot_exist", complacent_constraint, path: tmp_path.join("doesntexist_noway")) }
22
22
 
23
23
  it "raises a CookbookNotFound error" do
24
24
  lambda {
@@ -28,7 +28,7 @@ module Berkshelf
28
28
  end
29
29
 
30
30
  context "given a path that does not contain a cookbook" do
31
- subject { CookbookSource::PathLocation.new("doesnot_exist", complacent_constraint, path: fixtures_path) }
31
+ subject { PathLocation.new("doesnot_exist", complacent_constraint, path: fixtures_path) }
32
32
 
33
33
  it "raises a CookbookNotFound error" do
34
34
  lambda {
@@ -38,7 +38,7 @@ module Berkshelf
38
38
  end
39
39
 
40
40
  context "given the content at path does not satisfy the version constraint" do
41
- subject { CookbookSource::PathLocation.new("nginx", double('constraint', satisfies?: false), path: path) }
41
+ subject { PathLocation.new("nginx", double('constraint', satisfies?: false), path: path) }
42
42
 
43
43
  it "raises a ConstraintNotSatisfied error" do
44
44
  lambda {
@@ -1,9 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Berkshelf
4
- describe CookbookSource::SiteLocation do
4
+ describe SiteLocation do
5
+ describe "ClassMethods" do
6
+ subject { SiteLocation }
7
+
8
+ describe "::initialize" do
9
+ context "given the symbol :opscode for the value of URI" do
10
+ it "creates a SiteLocation with a URI equal to the default Opscode Community Site API" do
11
+ result = subject.new("nginx", double('constraint'), site: :opscode)
12
+
13
+ result.api_uri.should eql(Location::OPSCODE_COMMUNITY_API)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
5
19
  let(:complacent_constraint) { double('comp-vconstraint', satisfies?: true) }
6
- subject { CookbookSource::SiteLocation.new("nginx", complacent_constraint) }
20
+ subject { SiteLocation.new("nginx", complacent_constraint) }
7
21
 
8
22
  describe "#download" do
9
23
  before(:each) do
@@ -44,7 +58,7 @@ module Berkshelf
44
58
 
45
59
  context "given an explicit :site location key" do
46
60
  subject do
47
- CookbookSource::SiteLocation.new("nginx",
61
+ SiteLocation.new("nginx",
48
62
  complacent_constraint,
49
63
  site: "http://cookbooks.opscode.com/api/v1/cookbooks"
50
64
  )
@@ -1,25 +1,34 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Berkshelf::Lockfile do
4
- describe "without a lockfile in place already" do
5
- before do
6
- @old_dir = Dir.pwd
7
- Dir.chdir fixtures_path.join("lockfile_spec", "without_lock")
8
- end
3
+ module Berkshelf
4
+ describe Lockfile do
5
+ let(:downloader) { Downloader.new(Berkshelf.cookbook_store) }
6
+
7
+ describe "without a lockfile in place already" do
8
+ before(:all) do
9
+ @old_dir = Dir.pwd
10
+ Dir.chdir fixtures_path.join("lockfile_spec", "without_lock")
11
+ end
12
+
13
+ after(:all) do
14
+ FileUtils.rm(fixtures_path.join("lockfile_spec", "without_lock", "Berksfile.lock"))
15
+ Dir.chdir(@old_dir)
16
+ end
9
17
 
10
- it "should be able to write a Berksfile.lock from a list of cookbooks" do
11
- resolver = Berkshelf::Resolver.new(Berkshelf.downloader, Berkshelf::CookbookSource.new('nginx', '= 0.101.0'))
12
- resolver.resolve
18
+ it "should be able to write a Berksfile.lock from a list of cookbooks" do
19
+ resolver = Resolver.new(downloader, sources: CookbookSource.new('nginx', constraint: '= 0.101.0'))
20
+ resolver.resolve
13
21
 
14
- Berkshelf::Lockfile.new(resolver.sources).write
22
+ Lockfile.new(resolver.sources).write
15
23
 
16
- File.read('Berksfile.lock').split(/\r?\n/).sort.should == [
17
- "cookbook 'bluepill', :locked_version => '1.0.6'",
18
- "cookbook 'build-essential', :locked_version => '1.1.0'",
19
- "cookbook 'nginx', :locked_version => '0.101.0'",
20
- "cookbook 'ohai', :locked_version => '1.0.2'",
21
- "cookbook 'runit', :locked_version => '0.15.0'"
22
- ]
24
+ File.read('Berksfile.lock').split(/\r?\n/).sort.should == [
25
+ "cookbook 'bluepill', :locked_version => '1.0.4'",
26
+ "cookbook 'build-essential', :locked_version => '1.0.2'",
27
+ "cookbook 'nginx', :locked_version => '0.101.0'",
28
+ "cookbook 'ohai', :locked_version => '1.0.2'",
29
+ "cookbook 'runit', :locked_version => '0.15.0'"
30
+ ]
31
+ end
23
32
  end
24
33
  end
25
34
  end
@@ -36,16 +36,16 @@ module Berkshelf
36
36
  subject { Resolver }
37
37
 
38
38
  describe "::initialize" do
39
- let(:downloader) { Berkshelf.downloader }
39
+ let(:downloader) { Downloader.new(Berkshelf.cookbook_store) }
40
40
 
41
41
  it "adds the specified sources to the sources hash" do
42
- resolver = subject.new(downloader, source)
42
+ resolver = subject.new(downloader, sources: source)
43
43
 
44
44
  resolver.should have_source(source.name)
45
45
  end
46
46
 
47
47
  it "adds the dependencies of the source as sources" do
48
- resolver = subject.new(downloader, source)
48
+ resolver = subject.new(downloader, sources: source)
49
49
 
50
50
  resolver.should have_source("nginx")
51
51
  resolver.should have_source("artifact")
@@ -54,7 +54,7 @@ module Berkshelf
54
54
  context "given an array of sources" do
55
55
  it "adds each source to the sources hash" do
56
56
  sources = [source]
57
- resolver = subject.new(downloader, sources)
57
+ resolver = subject.new(downloader, sources: sources)
58
58
 
59
59
  resolver.should have_source(sources[0].name)
60
60
  end
@@ -62,7 +62,8 @@ module Berkshelf
62
62
  end
63
63
  end
64
64
 
65
- subject { Resolver.new(Berkshelf.downloader) }
65
+ let(:downloader) { Downloader.new(Berkshelf.cookbook_store) }
66
+ subject { Resolver.new(downloader) }
66
67
 
67
68
  describe "#add_source" do
68
69
  let(:package_version) { double('package-version', dependencies: Array.new) }
@@ -20,16 +20,18 @@ module Berkshelf
20
20
  subject.should_receive(:save_cookbook)
21
21
  end
22
22
 
23
- it "returns a successful TXResult" do
24
- subject.upload(cookbook).should be_success
23
+ it "returns true" do
24
+ subject.upload(cookbook).should be_true
25
25
  end
26
26
  end
27
27
 
28
28
  context "when cookbook is not valid" do
29
29
  before(:each) { cookbook.should_receive(:validate!).and_raise(CookbookSyntaxError) }
30
30
 
31
- it "returns a failed TXResult" do
32
- subject.upload(cookbook).should be_failed
31
+ it "raises a CookbookSyntaxError error" do
32
+ lambda {
33
+ subject.upload(cookbook)
34
+ }.should raise_error(CookbookSyntaxError)
33
35
  end
34
36
  end
35
37
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: berkshelf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.rc4
5
- prerelease: 6
4
+ version: 0.4.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Josiah Kiehl
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-08-21 00:00:00.000000000 Z
15
+ date: 2012-09-11 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: solve
@@ -371,6 +371,7 @@ files:
371
371
  - berkshelf.gemspec
372
372
  - bin/berks
373
373
  - features/cookbook_command.feature
374
+ - features/default_locations.feature
374
375
  - features/init_command.feature
375
376
  - features/install.feature
376
377
  - features/json_formatter.feature
@@ -405,11 +406,6 @@ files:
405
406
  - lib/berkshelf/cli.rb
406
407
  - lib/berkshelf/cookbook_generator.rb
407
408
  - lib/berkshelf/cookbook_source.rb
408
- - lib/berkshelf/cookbook_source/chef_api_location.rb
409
- - lib/berkshelf/cookbook_source/git_location.rb
410
- - lib/berkshelf/cookbook_source/location.rb
411
- - lib/berkshelf/cookbook_source/path_location.rb
412
- - lib/berkshelf/cookbook_source/site_location.rb
413
409
  - lib/berkshelf/cookbook_store.rb
414
410
  - lib/berkshelf/core_ext.rb
415
411
  - lib/berkshelf/core_ext/file.rb
@@ -418,18 +414,20 @@ files:
418
414
  - lib/berkshelf/core_ext/pathname.rb
419
415
  - lib/berkshelf/core_ext/string.rb
420
416
  - lib/berkshelf/downloader.rb
421
- - lib/berkshelf/dsl.rb
422
417
  - lib/berkshelf/errors.rb
423
418
  - lib/berkshelf/formatters.rb
424
419
  - lib/berkshelf/formatters/human_readable.rb
425
420
  - lib/berkshelf/formatters/json.rb
426
421
  - lib/berkshelf/git.rb
427
422
  - lib/berkshelf/init_generator.rb
423
+ - lib/berkshelf/location.rb
424
+ - lib/berkshelf/locations/chef_api_location.rb
425
+ - lib/berkshelf/locations/git_location.rb
426
+ - lib/berkshelf/locations/path_location.rb
427
+ - lib/berkshelf/locations/site_location.rb
428
428
  - lib/berkshelf/lockfile.rb
429
429
  - lib/berkshelf/resolver.rb
430
430
  - lib/berkshelf/thor.rb
431
- - lib/berkshelf/tx_result.rb
432
- - lib/berkshelf/tx_result_set.rb
433
431
  - lib/berkshelf/uploader.rb
434
432
  - lib/berkshelf/version.rb
435
433
  - spec/fixtures/Berksfile
@@ -456,7 +454,7 @@ files:
456
454
  - spec/fixtures/cookbooks/nginx-0.100.5/templates/default/nginx.pill.erb
457
455
  - spec/fixtures/cookbooks/nginx-0.100.5/templates/default/plugins/nginx.rb.erb
458
456
  - spec/fixtures/lockfile_spec/with_lock/Berksfile
459
- - spec/fixtures/lockfile_spec/without_lock/Berksfile.lock
457
+ - spec/fixtures/lockfile_spec/without_lock/.gitkeep
460
458
  - spec/fixtures/reset.pem
461
459
  - spec/knife.rb.sample
462
460
  - spec/spec_helper.rb
@@ -467,23 +465,20 @@ files:
467
465
  - spec/unit/berkshelf/berksfile_spec.rb
468
466
  - spec/unit/berkshelf/cached_cookbook_spec.rb
469
467
  - spec/unit/berkshelf/cookbook_generator_spec.rb
470
- - spec/unit/berkshelf/cookbook_source/chef_api_location_spec.rb
471
- - spec/unit/berkshelf/cookbook_source/git_location_spec.rb
472
- - spec/unit/berkshelf/cookbook_source/location_spec.rb
473
- - spec/unit/berkshelf/cookbook_source/path_location_spec.rb
474
- - spec/unit/berkshelf/cookbook_source/site_location_spec.rb
475
468
  - spec/unit/berkshelf/cookbook_source_spec.rb
476
469
  - spec/unit/berkshelf/cookbook_store_spec.rb
477
470
  - spec/unit/berkshelf/core_ext/fileutils_spec.rb
478
471
  - spec/unit/berkshelf/downloader_spec.rb
479
- - spec/unit/berkshelf/dsl_spec.rb
480
472
  - spec/unit/berkshelf/formatters_spec.rb
481
473
  - spec/unit/berkshelf/git_spec.rb
482
474
  - spec/unit/berkshelf/init_generator_spec.rb
475
+ - spec/unit/berkshelf/location_spec.rb
476
+ - spec/unit/berkshelf/locations/chef_api_location_spec.rb
477
+ - spec/unit/berkshelf/locations/git_location_spec.rb
478
+ - spec/unit/berkshelf/locations/path_location_spec.rb
479
+ - spec/unit/berkshelf/locations/site_location_spec.rb
483
480
  - spec/unit/berkshelf/lockfile_spec.rb
484
481
  - spec/unit/berkshelf/resolver_spec.rb
485
- - spec/unit/berkshelf/tx_result_set_spec.rb
486
- - spec/unit/berkshelf/tx_result_spec.rb
487
482
  - spec/unit/berkshelf/uploader_spec.rb
488
483
  - spec/unit/berkshelf_spec.rb
489
484
  homepage: https://github.com/RiotGames/berkshelf
@@ -501,9 +496,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
501
496
  required_rubygems_version: !ruby/object:Gem::Requirement
502
497
  none: false
503
498
  requirements:
504
- - - ! '>'
499
+ - - ! '>='
505
500
  - !ruby/object:Gem::Version
506
- version: 1.3.1
501
+ version: '0'
502
+ segments:
503
+ - 0
504
+ hash: -718551766010983641
507
505
  requirements: []
508
506
  rubyforge_project:
509
507
  rubygems_version: 1.8.23
@@ -512,6 +510,7 @@ specification_version: 3
512
510
  summary: Manages a Cookbook's, or an Application's, Cookbook dependencies
513
511
  test_files:
514
512
  - features/cookbook_command.feature
513
+ - features/default_locations.feature
515
514
  - features/init_command.feature
516
515
  - features/install.feature
517
516
  - features/json_formatter.feature
@@ -549,7 +548,7 @@ test_files:
549
548
  - spec/fixtures/cookbooks/nginx-0.100.5/templates/default/nginx.pill.erb
550
549
  - spec/fixtures/cookbooks/nginx-0.100.5/templates/default/plugins/nginx.rb.erb
551
550
  - spec/fixtures/lockfile_spec/with_lock/Berksfile
552
- - spec/fixtures/lockfile_spec/without_lock/Berksfile.lock
551
+ - spec/fixtures/lockfile_spec/without_lock/.gitkeep
553
552
  - spec/fixtures/reset.pem
554
553
  - spec/knife.rb.sample
555
554
  - spec/spec_helper.rb
@@ -560,23 +559,20 @@ test_files:
560
559
  - spec/unit/berkshelf/berksfile_spec.rb
561
560
  - spec/unit/berkshelf/cached_cookbook_spec.rb
562
561
  - spec/unit/berkshelf/cookbook_generator_spec.rb
563
- - spec/unit/berkshelf/cookbook_source/chef_api_location_spec.rb
564
- - spec/unit/berkshelf/cookbook_source/git_location_spec.rb
565
- - spec/unit/berkshelf/cookbook_source/location_spec.rb
566
- - spec/unit/berkshelf/cookbook_source/path_location_spec.rb
567
- - spec/unit/berkshelf/cookbook_source/site_location_spec.rb
568
562
  - spec/unit/berkshelf/cookbook_source_spec.rb
569
563
  - spec/unit/berkshelf/cookbook_store_spec.rb
570
564
  - spec/unit/berkshelf/core_ext/fileutils_spec.rb
571
565
  - spec/unit/berkshelf/downloader_spec.rb
572
- - spec/unit/berkshelf/dsl_spec.rb
573
566
  - spec/unit/berkshelf/formatters_spec.rb
574
567
  - spec/unit/berkshelf/git_spec.rb
575
568
  - spec/unit/berkshelf/init_generator_spec.rb
569
+ - spec/unit/berkshelf/location_spec.rb
570
+ - spec/unit/berkshelf/locations/chef_api_location_spec.rb
571
+ - spec/unit/berkshelf/locations/git_location_spec.rb
572
+ - spec/unit/berkshelf/locations/path_location_spec.rb
573
+ - spec/unit/berkshelf/locations/site_location_spec.rb
576
574
  - spec/unit/berkshelf/lockfile_spec.rb
577
575
  - spec/unit/berkshelf/resolver_spec.rb
578
- - spec/unit/berkshelf/tx_result_set_spec.rb
579
- - spec/unit/berkshelf/tx_result_spec.rb
580
576
  - spec/unit/berkshelf/uploader_spec.rb
581
577
  - spec/unit/berkshelf_spec.rb
582
578
  has_rdoc:
@@ -1,256 +0,0 @@
1
- require 'uri'
2
-
3
- module Berkshelf
4
- class CookbookSource
5
- # @author Jamie Winsor <jamie@vialstudios.com>
6
- class ChefAPILocation
7
- class << self
8
- # @param [String] node_name
9
- #
10
- # @return [Boolean]
11
- def validate_node_name(node_name)
12
- node_name.is_a?(String) && !node_name.empty?
13
- end
14
-
15
- # @raise [InvalidChefAPILocation]
16
- #
17
- # @see validate_node_name
18
- def validate_node_name!(node_name)
19
- unless validate_node_name(node_name)
20
- raise InvalidChefAPILocation
21
- end
22
-
23
- true
24
- end
25
-
26
- # @param [String] client_key
27
- #
28
- # @return [Boolean]
29
- def validate_client_key(client_key)
30
- File.exists?(client_key)
31
- end
32
-
33
- # @raise [InvalidChefAPILocation]
34
- #
35
- # @see validate_client_key
36
- def validate_client_key!(client_key)
37
- unless validate_client_key(client_key)
38
- raise InvalidChefAPILocation
39
- end
40
-
41
- true
42
- end
43
-
44
- # @param [String] uri
45
- #
46
- # @return [Boolean]
47
- def validate_uri(uri)
48
- uri =~ URI.regexp(['http', 'https'])
49
- end
50
-
51
- # @raise [InvalidChefAPILocation] if the given object is not a String containing a
52
- # valid Chef API URI
53
- #
54
- # @see validate_uri
55
- def validate_uri!(uri)
56
- unless validate_uri(uri)
57
- raise InvalidChefAPILocation, "'#{uri}' is not a valid Chef API URI."
58
- end
59
-
60
- true
61
- end
62
- end
63
-
64
- include Location
65
-
66
- location_key :chef_api
67
- valid_options :node_name, :client_key
68
-
69
- attr_reader :uri
70
- attr_reader :node_name
71
- attr_reader :client_key
72
-
73
- # @param [#to_s] name
74
- # @param [Solve::Constraint] version_constraint
75
- # @param [Hash] options
76
- #
77
- # @option options [String, Symbol] :chef_api
78
- # a URL to a Chef API. Alternatively the symbol :knife can be provided
79
- # which will instantiate this location with the values found in your
80
- # knife configuration.
81
- # @option options [String] :node_name
82
- # the name of the client to use to communicate with the Chef API.
83
- # Default: Chef::Config[:node_name]
84
- # @option options [String] :client_key
85
- # the filepath to the authentication key for the client
86
- # Default: Chef::Config[:client_key]
87
- def initialize(name, version_constraint, options = {})
88
- @name = name
89
- @version_constraint = version_constraint
90
- @downloaded_status = false
91
-
92
- validate_options!(options)
93
-
94
- if options[:chef_api] == :knife
95
- begin
96
- Berkshelf.load_config
97
- rescue KnifeConfigNotFound => e
98
- raise KnifeConfigNotFound, "A Knife config is required when ':knife' is given for the value of a 'chef_api' location. #{e}"
99
- end
100
- @node_name = Chef::Config[:node_name]
101
- @client_key = Chef::Config[:client_key]
102
- @uri = Chef::Config[:chef_server_url]
103
- else
104
- @node_name = options[:node_name]
105
- @client_key = options[:client_key]
106
- @uri = options[:chef_api]
107
- end
108
-
109
- @rest = Chef::REST.new(uri, node_name, client_key)
110
- end
111
-
112
- # @param [#to_s] destination
113
- #
114
- # @return [Berkshelf::CachedCookbook]
115
- def download(destination)
116
- version, uri = target_version
117
- cookbook = rest.get_rest(uri)
118
-
119
- scratch = download_files(cookbook.manifest)
120
-
121
- cb_path = File.join(destination, "#{name}-#{version}")
122
- FileUtils.mv(scratch, cb_path, force: true)
123
-
124
- cached = CachedCookbook.from_store_path(cb_path)
125
- validate_cached(cached)
126
-
127
- set_downloaded_status(true)
128
- cached
129
- end
130
-
131
- # Returns a hash representing the cookbook versions on at a Chef API for location's cookbook.
132
- # The keys are version strings and the values are URLs to download the cookbook version.
133
- #
134
- # @example
135
- # {
136
- # "0.101.2" => "https://api.opscode.com/organizations/vialstudios/cookbooks/nginx/0.101.2",
137
- # "0.101.5" => "https://api.opscode.com/organizations/vialstudios/cookbooks/nginx/0.101.5"
138
- # }
139
- #
140
- # @return [Hash]
141
- def versions
142
- {}.tap do |versions|
143
- rest.get_rest("cookbooks/#{name}").each do |name, data|
144
- data["versions"].each do |version_info|
145
- versions[version_info["version"]] = version_info["url"]
146
- end
147
- end
148
- end
149
- rescue Net::HTTPServerException => e
150
- if e.response.code == "404"
151
- raise CookbookNotFound, "Cookbook '#{name}' not found at chef_api: '#{uri}'"
152
- else
153
- raise
154
- end
155
- end
156
-
157
- # Returns an array where the first element is a string representing the latest version of
158
- # the Cookbook and the second element is the download URL for that version.
159
- #
160
- # @example
161
- # [ "0.101.2" => "https://api.opscode.com/organizations/vialstudios/cookbooks/nginx/0.101.2" ]
162
- #
163
- # @return [Array]
164
- def latest_version
165
- graph = Solve::Graph.new
166
- versions.each do |version, url|
167
- graph.artifacts(name, version)
168
- end
169
- graph.demands(name, ">= 0.0.0")
170
-
171
- version = Solve.it!(graph)[name]
172
-
173
- [ version, versions[version] ]
174
- end
175
-
176
- def to_s
177
- "chef_api: '#{uri}'"
178
- end
179
-
180
- private
181
-
182
- attr_reader :rest
183
-
184
- # Returns an array containing the version and download URL for the cookbook version that
185
- # should be downloaded for this location.
186
- #
187
- # @example
188
- # [ "0.101.2" => "https://api.opscode.com/organizations/vialstudios/cookbooks/nginx/0.101.2" ]
189
- #
190
- # @return [Array]
191
- def target_version
192
- if version_constraint
193
- solution = self.class.solve_for_constraint(version_constraint, versions)
194
-
195
- unless solution
196
- raise NoSolution, "No cookbook version of '#{name}' found at #{self} that would satisfy constraint (#{version_constraint})."
197
- end
198
-
199
- solution
200
- else
201
- latest_version
202
- end
203
- end
204
-
205
- # Download all of the files in the given manifest to the given destination. If no destination
206
- # is provided a temporary directory will be created and the files will be downloaded to there.
207
- #
208
- # @note
209
- # the manifest Hash is the same manifest that you get by sending the manifest message to
210
- # an instance of Chef::CookbookVersion.
211
- #
212
- # @param [Hash] manifest
213
- # @param [String] destination
214
- #
215
- # @return [String]
216
- # the path to the directory containing the files
217
- def download_files(manifest, destination = Dir.mktmpdir)
218
- Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
219
- next unless manifest.has_key?(segment)
220
- manifest[segment].each do |segment_file|
221
- dest = File.join(destination, segment_file['path'].gsub('/', File::SEPARATOR))
222
- FileUtils.mkdir_p(File.dirname(dest))
223
- rest.sign_on_redirect = false
224
- tempfile = rest.get_rest(segment_file['url'], true)
225
- FileUtils.mv(tempfile.path, dest)
226
- end
227
- end
228
-
229
- destination
230
- end
231
-
232
- # Validates the options hash given to the constructor.
233
- #
234
- # @param [Hash] options
235
- #
236
- # @raise [InvalidChefAPILocation] if any of the options are missing or their values do not
237
- # pass validation
238
- def validate_options!(options)
239
- if options[:chef_api] == :knife
240
- return true
241
- end
242
-
243
- missing_options = [:node_name, :client_key] - options.keys
244
-
245
- unless missing_options.empty?
246
- missing_options.collect! { |opt| "'#{opt}'" }
247
- raise InvalidChefAPILocation, "Source '#{name}' is a 'chef_api' location with a URL for it's value but is missing options: #{missing_options.join(', ')}."
248
- end
249
-
250
- self.class.validate_node_name!(options[:node_name])
251
- self.class.validate_client_key!(options[:client_key])
252
- self.class.validate_uri!(options[:chef_api])
253
- end
254
- end
255
- end
256
- end