berkshelf 3.0.0.beta4 → 3.0.0.beta5
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +6 -0
- data/README.md +3 -0
- data/berkshelf-complete.sh +10 -3
- data/berkshelf.gemspec +12 -11
- data/features/berksfile.feature +0 -2
- data/features/commands/apply.feature +0 -1
- data/features/commands/contingent.feature +0 -3
- data/features/commands/cookbook.feature +0 -3
- data/features/commands/init.feature +0 -2
- data/features/commands/install.feature +42 -35
- data/features/commands/list.feature +0 -3
- data/features/commands/outdated.feature +0 -4
- data/features/commands/package.feature +2 -39
- data/features/commands/shelf/list.feature +0 -2
- data/features/commands/shelf/show.feature +0 -5
- data/features/commands/shelf/uninstall.feature +0 -5
- data/features/commands/show.feature +0 -3
- data/features/commands/update.feature +0 -3
- data/features/commands/upload.feature +0 -13
- data/features/commands/vendor.feature +0 -5
- data/features/community_site.feature +0 -2
- data/features/config.feature +0 -6
- data/features/json_formatter.feature +0 -5
- data/features/licenses.feature +0 -5
- data/features/lockfile.feature +0 -20
- data/features/step_definitions/chef_server_steps.rb +8 -2
- data/generator_files/Gemfile.erb +2 -2
- data/lib/berkshelf.rb +0 -4
- data/lib/berkshelf/berksfile.rb +21 -51
- data/lib/berkshelf/cli.rb +26 -15
- data/lib/berkshelf/config.rb +4 -0
- data/lib/berkshelf/cookbook_generator.rb +1 -1
- data/lib/berkshelf/cookbook_store.rb +8 -0
- data/lib/berkshelf/core_ext/file.rb +2 -2
- data/lib/berkshelf/core_ext/pathname.rb +5 -7
- data/lib/berkshelf/dependency.rb +8 -1
- data/lib/berkshelf/downloader.rb +37 -0
- data/lib/berkshelf/errors.rb +1 -0
- data/lib/berkshelf/formatters.rb +1 -0
- data/lib/berkshelf/formatters/human_readable.rb +23 -9
- data/lib/berkshelf/formatters/json.rb +7 -9
- data/lib/berkshelf/git.rb +0 -1
- data/lib/berkshelf/init_generator.rb +1 -1
- data/lib/berkshelf/installer.rb +43 -19
- data/lib/berkshelf/location.rb +8 -13
- data/lib/berkshelf/locations/git_location.rb +12 -19
- data/lib/berkshelf/locations/mercurial_location.rb +5 -18
- data/lib/berkshelf/locations/path_location.rb +7 -0
- data/lib/berkshelf/lockfile.rb +5 -1
- data/lib/berkshelf/packager.rb +73 -0
- data/lib/berkshelf/resolver.rb +7 -5
- data/lib/berkshelf/resolver/graph.rb +7 -0
- data/lib/berkshelf/source.rb +22 -2
- data/lib/berkshelf/ui.rb +0 -2
- data/lib/berkshelf/version.rb +1 -1
- data/spec/support/git.rb +1 -0
- data/spec/support/mercurial.rb +37 -36
- data/spec/unit/berkshelf/berksfile_spec.rb +2 -34
- data/spec/unit/berkshelf/cli_spec.rb +3 -2
- data/spec/unit/berkshelf/config_spec.rb +3 -3
- data/spec/unit/berkshelf/core_ext/pathname_spec.rb +46 -0
- data/spec/unit/berkshelf/dependency_spec.rb +3 -3
- data/spec/unit/berkshelf/formatters_spec.rb +4 -4
- data/spec/unit/berkshelf/git_spec.rb +8 -8
- data/spec/unit/berkshelf/installer_spec.rb +2 -2
- data/spec/unit/berkshelf/locations/git_location_spec.rb +2 -8
- data/spec/unit/berkshelf/locations/mercurial_location_spec.rb +4 -23
- data/spec/unit/berkshelf/lockfile_spec.rb +1 -1
- data/spec/unit/berkshelf/mercurial_spec.rb +6 -7
- data/spec/unit/berkshelf/packager_spec.rb +39 -0
- data/spec/unit/berkshelf/ui_spec.rb +2 -2
- data/spec/unit/berkshelf_spec.rb +2 -2
- metadata +37 -24
- data/lib/berkshelf/api_client.rb +0 -65
- data/lib/berkshelf/api_client/remote_cookbook.rb +0 -55
- data/spec/unit/berkshelf/api_client/remote_cookbook_spec.rb +0 -23
- data/spec/unit/berkshelf/api_client_spec.rb +0 -57
data/lib/berkshelf/lockfile.rb
CHANGED
@@ -99,7 +99,9 @@ module Berkshelf
|
|
99
99
|
options[:path] &&= File.expand_path(options[:path], File.dirname(filepath))
|
100
100
|
|
101
101
|
begin
|
102
|
-
|
102
|
+
dependency = Berkshelf::Dependency.new(berksfile, name.to_s, options)
|
103
|
+
next if dependency.location && !dependency.location.valid?
|
104
|
+
add(dependency)
|
103
105
|
rescue Berkshelf::CookbookNotFound
|
104
106
|
# It's possible that a source is locked that contains a path location, and
|
105
107
|
# that path location was renamed or no longer exists. When loading the
|
@@ -123,6 +125,7 @@ module Berkshelf
|
|
123
125
|
#
|
124
126
|
# @param [String, Berkshelf::Dependency] dependency
|
125
127
|
# the cookbook dependency/name to find
|
128
|
+
#
|
126
129
|
# @return [Berkshelf::Dependency, nil]
|
127
130
|
# the cookbook dependency from this lockfile or nil if one was not found
|
128
131
|
def find(dependency)
|
@@ -133,6 +136,7 @@ module Berkshelf
|
|
133
136
|
#
|
134
137
|
# @param [String, Berkshelf::Dependency] dependency
|
135
138
|
# the cookbook dependency/name to determine existence of
|
139
|
+
#
|
136
140
|
# @return [Boolean]
|
137
141
|
# true if the dependency exists, false otherwise
|
138
142
|
def has_dependency?(dependency)
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'archive/tar/minitar'
|
2
|
+
require 'zlib'
|
3
|
+
|
4
|
+
module Berkshelf
|
5
|
+
# A class for archiving and compressing directory containing one or more cookbooks.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
# Archiving a path containing the cookbooks:
|
9
|
+
# * "/path/to/cookbooks/my_face"
|
10
|
+
# * "/path/to/cookbooks/nginx"
|
11
|
+
#
|
12
|
+
# irb> source = "/path/to/cookbooks"
|
13
|
+
# irb> packager = Berkshelf::Packager.new("some/path/cookbooks.tar.gz")
|
14
|
+
# irb> packager.run(source) #=> "some/path/cookbooks.tar.gz"
|
15
|
+
class Packager
|
16
|
+
class << self
|
17
|
+
def validate_destination(path)
|
18
|
+
path = path.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [String]
|
23
|
+
attr_reader :out_file
|
24
|
+
|
25
|
+
# @param [#to_s] out_file
|
26
|
+
# path to write the archive to
|
27
|
+
def initialize(out_file)
|
28
|
+
@out_file = out_file.to_s
|
29
|
+
@out_dir, @filename = File.split(@out_file)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Archive the contents of given path
|
33
|
+
#
|
34
|
+
# @param [#to_s] source
|
35
|
+
# the filepath to archive the contents of
|
36
|
+
#
|
37
|
+
# @raise [PackageError]
|
38
|
+
# if an error is encountered while writing the out_file
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
# path to the generated archive
|
42
|
+
def run(source)
|
43
|
+
Dir.chdir(source.to_s) do |dir|
|
44
|
+
tgz = Zlib::GzipWriter.new(File.open(out_file, "wb"))
|
45
|
+
Archive::Tar::Minitar.pack(".", tgz)
|
46
|
+
end
|
47
|
+
|
48
|
+
out_file
|
49
|
+
rescue SystemCallError => ex
|
50
|
+
raise PackageError, ex
|
51
|
+
end
|
52
|
+
|
53
|
+
# Validate that running the packager would be successful. Returns nil if would be
|
54
|
+
# successful and raises an error if would not.
|
55
|
+
#
|
56
|
+
# @raise [PackageError]
|
57
|
+
# if running the packager would absolutely not result in a success
|
58
|
+
#
|
59
|
+
# @return [nil]
|
60
|
+
def validate!
|
61
|
+
raise PackageError, "Path is not a directory: #{out_dir}" unless File.directory?(out_dir)
|
62
|
+
raise PackageError, "Directory is not writable: #{out_dir}" unless File.writable?(out_dir)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# @return [String]
|
68
|
+
attr_reader :out_dir
|
69
|
+
|
70
|
+
# @return [String]
|
71
|
+
attr_reader :filename
|
72
|
+
end
|
73
|
+
end
|
data/lib/berkshelf/resolver.rb
CHANGED
@@ -41,11 +41,13 @@ module Berkshelf
|
|
41
41
|
demands.push(demand)
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
# Add dependencies of a locally cached cookbook which will take precedence over anything
|
45
|
+
# found in the universe.
|
46
|
+
#
|
47
|
+
# @param [Berkshelf::CachedCookbook] cookbook
|
48
|
+
#
|
49
|
+
# @return [Hash]
|
50
|
+
def add_explicit_dependencies(cookbook)
|
49
51
|
graph.populate_local(cookbook)
|
50
52
|
end
|
51
53
|
|
@@ -10,6 +10,11 @@ module Berkshelf
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
# Add dependencies of a locally cached cookbook to the graph
|
14
|
+
#
|
15
|
+
# @param [Berkshelf::CachedCookbook] cookbook
|
16
|
+
#
|
17
|
+
# @return [Hash]
|
13
18
|
def populate_local(cookbook)
|
14
19
|
name = cookbook.cookbook_name
|
15
20
|
version = cookbook.version
|
@@ -23,6 +28,8 @@ module Berkshelf
|
|
23
28
|
# @param [Array<Berkshelf::Source>, Berkshelf::Source] sources
|
24
29
|
def populate(sources)
|
25
30
|
universe(sources).each do |cookbook|
|
31
|
+
next if has_artifact?(cookbook.name, cookbook.version)
|
32
|
+
|
26
33
|
artifacts(cookbook.name, cookbook.version)
|
27
34
|
|
28
35
|
cookbook.dependencies.each do |dependency, constraint|
|
data/lib/berkshelf/source.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'berkshelf/api-client'
|
2
|
+
|
1
3
|
module Berkshelf
|
2
4
|
class Source
|
3
5
|
include Comparable
|
@@ -9,11 +11,29 @@ module Berkshelf
|
|
9
11
|
def initialize(uri)
|
10
12
|
@uri = SourceURI.parse(uri)
|
11
13
|
@api_client = APIClient.new(uri)
|
14
|
+
@universe = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Forcefully obtain the universe from the API endpoint and assign it to {#universe}. This
|
18
|
+
# will reload the value of {#universe} even if it has been loaded before.
|
19
|
+
#
|
20
|
+
# @return [Array<APIClient::RemoteCookbook>]
|
21
|
+
def build_universe
|
22
|
+
@universe = api_client.universe
|
23
|
+
rescue => ex
|
24
|
+
@universe = Array.new
|
25
|
+
raise ex
|
12
26
|
end
|
13
27
|
|
14
|
-
#
|
28
|
+
# Return the universe from the API endpoint.
|
29
|
+
#
|
30
|
+
# This is lazily loaded so the universe will be retrieved from the API endpoint on the first
|
31
|
+
# call and cached for future calls. Send the {#build_universe} message if you want to reload
|
32
|
+
# the cached universe.
|
33
|
+
#
|
34
|
+
# @return [Array<APIClient::RemoteCookbook>]
|
15
35
|
def universe
|
16
|
-
@universe
|
36
|
+
@universe || build_universe
|
17
37
|
end
|
18
38
|
|
19
39
|
# @param [String] name
|
data/lib/berkshelf/ui.rb
CHANGED
data/lib/berkshelf/version.rb
CHANGED
data/spec/support/git.rb
CHANGED
data/spec/support/mercurial.rb
CHANGED
@@ -77,46 +77,47 @@ module Berkshelf
|
|
77
77
|
end
|
78
78
|
|
79
79
|
private
|
80
|
-
# The path to store the local git clones.
|
81
|
-
#
|
82
|
-
# @return [Pathname]
|
83
|
-
def clones
|
84
|
-
ensure_and_return(tmp_path.join('clones'))
|
85
|
-
end
|
86
80
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
81
|
+
# The path to store the local git clones.
|
82
|
+
#
|
83
|
+
# @return [Pathname]
|
84
|
+
def clones
|
85
|
+
ensure_and_return(tmp_path.join('clones'))
|
86
|
+
end
|
93
87
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
def generate_mercurial_cookbook(name, options = {})
|
101
|
-
options = {
|
102
|
-
skip_vagrant: true,
|
103
|
-
skip_test_kitchen: true,
|
104
|
-
force: true,
|
105
|
-
}.merge(options)
|
88
|
+
# The path to store the git remotes.
|
89
|
+
#
|
90
|
+
# @return [Pathname]
|
91
|
+
def remotes
|
92
|
+
ensure_and_return(tmp_path.join('remotes'))
|
93
|
+
end
|
106
94
|
|
107
|
-
|
108
|
-
|
95
|
+
# Generate a cookbook by the given name.
|
96
|
+
#
|
97
|
+
# @param [#to_s] name
|
98
|
+
# the name of the cookbook to create
|
99
|
+
# @param [Hash] options
|
100
|
+
# the list ooptions to pass to the generator
|
101
|
+
def generate_mercurial_cookbook(name, options = {})
|
102
|
+
options = {
|
103
|
+
skip_vagrant: true,
|
104
|
+
skip_test_kitchen: true,
|
105
|
+
force: true,
|
106
|
+
}.merge(options)
|
109
107
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
return Pathname
|
119
|
-
|
108
|
+
Berkshelf::Cli.new.invoke(:cookbook, [name.to_s], options)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Make sure the given path exists and return the path
|
112
|
+
#
|
113
|
+
# @param [#to_s] path
|
114
|
+
# the path to create and return
|
115
|
+
#
|
116
|
+
# @return [Pathname]
|
117
|
+
def ensure_and_return(path)
|
118
|
+
FileUtils.mkdir(path) unless File.exist?(path)
|
119
|
+
return Pathname.new(path).expand_path
|
120
|
+
end
|
120
121
|
end
|
121
122
|
end
|
122
123
|
end
|
@@ -313,7 +313,7 @@ describe Berkshelf::Berksfile do
|
|
313
313
|
end
|
314
314
|
|
315
315
|
context "when given the :git option" do
|
316
|
-
let(:options) { { git: "git@github.com:
|
316
|
+
let(:options) { { git: "git@github.com:berkshelf/berkshelf.git" } }
|
317
317
|
|
318
318
|
it "has a GitLocation location" do
|
319
319
|
expect(dependency.location).to be_a(Berkshelf::GitLocation)
|
@@ -321,7 +321,7 @@ describe Berkshelf::Berksfile do
|
|
321
321
|
end
|
322
322
|
|
323
323
|
context "when given the :github option" do
|
324
|
-
let(:options) { { github: "
|
324
|
+
let(:options) { { github: "berkshelf/berkshelf" } }
|
325
325
|
|
326
326
|
it "has a GithubLocation location" do
|
327
327
|
expect(dependency.location).to be_a(Berkshelf::GithubLocation)
|
@@ -512,38 +512,6 @@ describe Berkshelf::Berksfile do
|
|
512
512
|
end
|
513
513
|
end
|
514
514
|
|
515
|
-
describe '#package' do
|
516
|
-
context 'when the dependency does not exist' do
|
517
|
-
it 'raises a CookbookNotFound exception' do
|
518
|
-
expect {
|
519
|
-
subject.package('non-existent', output: Dir.tmpdir)
|
520
|
-
}.to raise_error(Berkshelf::CookbookNotFound)
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
context 'when the dependency exists' do
|
525
|
-
let(:dependency) { double('dependency') }
|
526
|
-
let(:cached) { double('cached', path: '/foo/bar', cookbook_name: 'cookbook') }
|
527
|
-
let(:options) { { output: Dir.tmpdir } }
|
528
|
-
|
529
|
-
before do
|
530
|
-
FileUtils.stub(:cp_r)
|
531
|
-
FileUtils.stub(:mkdir_p)
|
532
|
-
subject.stub(:find).with('non-existent').and_return(dependency)
|
533
|
-
subject.stub(:install).with(options).and_return([ cached ])
|
534
|
-
end
|
535
|
-
|
536
|
-
it 'resolves the dependencies' do
|
537
|
-
subject.should_receive(:install).with(options)
|
538
|
-
subject.package('non-existent', options)
|
539
|
-
end
|
540
|
-
|
541
|
-
it 'returns the output path' do
|
542
|
-
expect(subject.package('non-existent', options)).to eq(File.join(Dir.tmpdir, 'non-existent.tar.gz'))
|
543
|
-
end
|
544
|
-
end
|
545
|
-
end
|
546
|
-
|
547
515
|
describe "#remove_dependency" do
|
548
516
|
let(:dependency) { "nginx" }
|
549
517
|
before { subject.add_dependency(dependency) }
|
@@ -4,12 +4,13 @@ describe Berkshelf::Cli do
|
|
4
4
|
let(:subject) { described_class.new }
|
5
5
|
let(:berksfile) { double('Berksfile') }
|
6
6
|
let(:cookbooks) { ['mysql'] }
|
7
|
+
|
7
8
|
describe '#upload' do
|
8
9
|
it 'calls to upload with params if passed in cli' do
|
9
10
|
Berkshelf::Berksfile.should_receive(:from_file).and_return(berksfile)
|
10
|
-
berksfile.should_receive(:upload).with(include(:
|
11
|
+
berksfile.should_receive(:upload).with(include(skip_syntax_check: true, freeze: false, cookbooks: cookbooks))
|
11
12
|
subject.options[:skip_syntax_check] = true
|
12
|
-
subject.options[:no_freeze]
|
13
|
+
subject.options[:no_freeze] = true
|
13
14
|
subject.upload('mysql')
|
14
15
|
end
|
15
16
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Berkshelf::Config do
|
4
|
-
describe '
|
4
|
+
describe '::file' do
|
5
5
|
context 'when the file does not exist' do
|
6
6
|
before { File.stub(:exists?).and_return(false) }
|
7
7
|
|
@@ -11,13 +11,13 @@ describe Berkshelf::Config do
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
describe '
|
14
|
+
describe '::instance' do
|
15
15
|
it 'should be a Berkshelf::Config' do
|
16
16
|
expect(Berkshelf::Config.instance).to be_an_instance_of(Berkshelf::Config)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
describe '
|
20
|
+
describe '::path' do
|
21
21
|
it 'is a string' do
|
22
22
|
expect(Berkshelf::Config.path).to be_a(String)
|
23
23
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Pathname do
|
4
|
+
describe "#cookbook?" do
|
5
|
+
let(:cookbook_path) { tmp_path }
|
6
|
+
let(:metadata_rb) { tmp_path.join("metadata.rb") }
|
7
|
+
let(:metadata_json) { tmp_path.join("metadata.json") }
|
8
|
+
|
9
|
+
subject { Pathname.new(cookbook_path) }
|
10
|
+
|
11
|
+
context "when the path contains a metadata.json file" do
|
12
|
+
before { FileUtils.touch(metadata_json) }
|
13
|
+
its(:cookbook?) { should be_true }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when the path contains a metadata.rb file" do
|
17
|
+
before { FileUtils.touch(metadata_rb) }
|
18
|
+
its(:cookbook?) { should be_true }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when the path does not contain a metadata.json or metadata.rb file" do
|
22
|
+
before { FileUtils.rm_f(metadata_rb) && FileUtils.rm_f(metadata_json) }
|
23
|
+
its(:cookbook?) { should be_false }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#cookbook_root" do
|
28
|
+
let(:root_path) { fixtures_path.join("cookbooks", "example_cookbook") }
|
29
|
+
let(:cookbook_path) { root_path }
|
30
|
+
subject { Pathname.new(cookbook_path) }
|
31
|
+
|
32
|
+
context "when in the root of a cookbook" do
|
33
|
+
its(:cookbook_root) { should eql(root_path) }
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when in the structure of a cookbook" do
|
37
|
+
let(:cookbook_path) { root_path.join("recipes") }
|
38
|
+
its(:cookbook_root) { should eql(root_path) }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when not within the structure of a cookbook" do
|
42
|
+
let(:cookbook_path) { "/" }
|
43
|
+
its(:cookbook_root) { should be_nil }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|