berkshelf 0.1.5 → 0.2.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.
@@ -0,0 +1,43 @@
1
+ # Berkshelf
2
+
3
+ Manage a Cookbook or an Application's Cookbook dependencies
4
+
5
+ ## Installation
6
+
7
+ $ gem install berkshelf
8
+
9
+ ## Usage
10
+
11
+ See [berkshelf.com](http://berkshelf.com) for up-to-date usage instructions.
12
+
13
+ # Contributing
14
+
15
+ ## Running tests
16
+
17
+ ### Install prerequisites
18
+
19
+ Install the latest version of {Bundler}[http://gembundler.com]
20
+
21
+ $ gem install bundler
22
+
23
+ Clone the project
24
+
25
+ $ git clone git://github.com/RiotGames/berkshelf.git
26
+
27
+ and run:
28
+
29
+ $ cd berkshelf
30
+ $ bundle install
31
+
32
+ Bundler will install all gems and their dependencies required for testing and developing.
33
+
34
+ ### Running unit (RSpec) and acceptance (Cucumber) tests
35
+
36
+ $ bundle exec guard start
37
+
38
+ # Authors and Contributors
39
+
40
+ * Josiah Kiehl (<josiah@skirmisher.net>)
41
+ * Jamie Winsor (<jamie@vialstudios.com>)
42
+ * Erik Hollensbe (<erik@hollensbe.org>)
43
+ * Michael Ivey (<ivey@gweezlebur.com>)
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.add_runtime_dependency 'minitar'
22
22
  s.add_runtime_dependency 'thor', '~> 0.15.2'
23
23
 
24
+ s.add_development_dependency 'redcarpet'
24
25
  s.add_development_dependency 'cucumber'
25
26
  s.add_development_dependency 'vcr'
26
27
  s.add_development_dependency 'webmock'
@@ -53,3 +53,20 @@ Feature: install cookbooks from a Berksfile
53
53
  Cookbook 'doesntexist' not found at site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
54
54
  """
55
55
  And the CLI should exit with the status code for error "DownloadFailure"
56
+
57
+ @wip
58
+ Scenario: running install command with the --shims flag to create a directory of shims
59
+ Given I write to "Berksfile" with:
60
+ """
61
+ cookbook "mysql", "1.2.4"
62
+ """
63
+ When I run the install command with flags:
64
+ | --shims |
65
+ Then the following directories should exist:
66
+ | cookbooks |
67
+ | cookbooks/mysql |
68
+ And the output should contain:
69
+ """
70
+ Shims written to:
71
+ """
72
+ And the exit status should be 0
@@ -39,7 +39,11 @@ When /^I run the init command with no value for the target$/ do
39
39
  end
40
40
 
41
41
  When /^I run the install command$/ do
42
- run_simple(unescape("knife berks install"), false)
42
+ run_simple(unescape("knife berks install"), true)
43
+ end
44
+
45
+ When /^I run the install command with flags:$/ do |flags|
46
+ run_simple(unescape("knife berks install #{flags.raw.join(" ")}"), true)
43
47
  end
44
48
 
45
49
  When /^I run the update command$/ do
@@ -119,9 +119,16 @@ module Berkshelf
119
119
  # @option options [Symbol, Array] :without
120
120
  # Group(s) to exclude which will cause any sources marked as a member of the
121
121
  # group to not be installed
122
+ # @option options [String, Pathname] :shims
123
+ # Path to a directory of shims each pointing to a Cookbook Version that is
124
+ # part of the dependency solution. Each shim is a hard link on disk.
122
125
  def install(options = {})
123
126
  resolver = Resolver.new(Berkshelf.downloader, sources(exclude: options[:without]))
124
- resolver.resolve
127
+ solution = resolver.resolve
128
+ if options[:shims]
129
+ write_shims(options[:shims], solution)
130
+ Berkshelf.ui.info "Shims written to: '#{options[:shims]}'"
131
+ end
125
132
  write_lockfile(resolver.sources) unless lockfile_present?
126
133
  end
127
134
 
@@ -152,6 +159,26 @@ module Berkshelf
152
159
  end
153
160
  end
154
161
 
162
+ # Write a collection of hard links to the given path representing the given
163
+ # CachedCookbooks. Useful for getting Cookbooks in a single location for
164
+ # consumption by Vagrant, or another tool that expect this structure.
165
+ #
166
+ # @example
167
+ # Given the path: '/Users/reset/code/pvpnet/cookbooks'
168
+ # And a CachedCookbook: 'nginx' verison '0.100.5' at '/Users/reset/.berkshelf/nginx-0.100.5'
169
+ #
170
+ # A hardlink will be created at: '/Users/reset/code/pvpnet/cookbooks/nginx'
171
+ #
172
+ # @param [Pathname, String] path
173
+ # @param [Array<Berkshelf::CachedCookbook>] cached_cookbooks
174
+ def write_shims(path, cached_cookbooks)
175
+ FileUtils.mkdir_p(path)
176
+ cached_cookbooks.each do |cached_cookbook|
177
+ destination = File.join(path, cached_cookbook.cookbook_name)
178
+ FileUtils.ln_r(cached_cookbook.path, destination, force: true)
179
+ end
180
+ end
181
+
155
182
  private
156
183
 
157
184
  def lockfile_present?
@@ -40,7 +40,7 @@ module Berkshelf
40
40
 
41
41
  def to_s
42
42
  s = "git: '#{uri}'"
43
- s << " with branch '#{branch}" if branch
43
+ s << " with branch '#{branch}'" if branch
44
44
  s
45
45
  end
46
46
 
@@ -0,0 +1,80 @@
1
+ module FileUtils
2
+ # @note taken from proposed FileUtils feature:
3
+ # @note {http://redmine.ruby-lang.org/issues/show/4189}
4
+ # @note {https://github.com/ruby/ruby/pull/4}
5
+ #
6
+ # Options: noop verbose dereference_root force
7
+ #
8
+ # Hard link +src+ to +dest+. If +src+ is a directory, this method links
9
+ # all its contents recursively. If +dest+ is a directory, links
10
+ # +src+ to +dest/src+.
11
+ #
12
+ # +src+ can be a list of files.
13
+ #
14
+ # # Installing ruby library "mylib" under the site_ruby
15
+ # FileUtils.rm_r site_ruby + '/mylib', :force
16
+ # FileUtils.ln_r 'lib/', site_ruby + '/mylib'
17
+ #
18
+ # # Examples of copying several files to target directory.
19
+ # FileUtils.ln_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
20
+ # FileUtils.ln_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true
21
+ #
22
+ # # If you want to copy all contents of a directory instead of the
23
+ # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
24
+ # # use following code.
25
+ # FileUtils.ln_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest,
26
+ # # but this doesn't.
27
+ def ln_r(src, dest, options = {})
28
+ fu_check_options options, OPT_TABLE['ln_r']
29
+ fu_output_message "ln -r#{options[:force] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
30
+ return if options[:noop]
31
+ options = options.dup
32
+ options[:dereference_root] = true unless options.key?(:dereference_root)
33
+ fu_each_src_dest(src, dest) do |s, d|
34
+ link_entry s, d, options[:dereference_root], options[:force]
35
+ end
36
+ end
37
+ module_function :ln_r
38
+
39
+ OPT_TABLE['ln_r'] = [:noop, :verbose, :dereference_root, :force]
40
+
41
+ #
42
+ # Hard links a file system entry +src+ to +dest+.
43
+ # If +src+ is a directory, this method links its contents recursively.
44
+ #
45
+ # Both of +src+ and +dest+ must be a path name.
46
+ # +src+ must exist, +dest+ must not exist.
47
+ #
48
+ # If +dereference_root+ is true, this method dereference tree root.
49
+ #
50
+ # If +force+ is true, this method removes each destination file before copy.
51
+ #
52
+ def link_entry(src, dest, dereference_root = false, force = false)
53
+ Entry_.new(src, nil, dereference_root).traverse do |ent|
54
+ destent = Entry_.new(dest, ent.rel, false)
55
+ File.unlink destent.path if force && File.file?(destent.path)
56
+ ent.link destent.path
57
+ end
58
+ end
59
+ module_function :link_entry
60
+
61
+ private
62
+
63
+ class Entry_ #:nodoc:
64
+ def link(dest)
65
+ case
66
+ when directory?
67
+ if !File.exist?(dest) and descendant_diretory?(dest, path)
68
+ raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest]
69
+ end
70
+ begin
71
+ Dir.mkdir dest
72
+ rescue
73
+ raise unless File.directory?(dest)
74
+ end
75
+ else
76
+ File.link path(), dest
77
+ end
78
+ end
79
+ end
80
+ end
@@ -22,7 +22,7 @@ module Berkshelf
22
22
  type: :boolean,
23
23
  desc: "Freeze the uploaded cookbooks so that they cannot be overwritten.",
24
24
  default: false
25
- desc "upload", "shit"
25
+ desc "upload", "Upload the sources defined in your Berksfile and their dependencies to a Chef Server."
26
26
  def upload
27
27
  begin
28
28
  Chef::Config.from_file(File.expand_path(options[:config]))
@@ -1,3 +1,3 @@
1
1
  module Berkshelf
2
- VERSION = "0.1.5"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -8,20 +8,35 @@ module Berkshelf
8
8
 
9
9
  banner "knife berks install (options)"
10
10
 
11
+ option :shims,
12
+ short: "-s",
13
+ long: "--shims",
14
+ description: "Create a directory of shims pointing to Cookbook Versions.",
15
+ boolean: true
11
16
  option :without,
12
- :short => "-W WITHOUT",
13
- :long => "--without WITHOUT",
14
- :description => "Exclude cookbooks that are in these groups",
15
- :proc => lambda { |w| w.split(",") },
16
- :default => Array.new
17
-
17
+ short: "-W WITHOUT",
18
+ long: "--without WITHOUT",
19
+ description: "Exclude cookbooks that are in these groups",
20
+ proc: lambda { |w| w.split(",") },
21
+ default: Array.new
18
22
  def run
19
23
  ::Berkshelf.ui = ui
24
+ # JW TODO: replace knife with Thor bin. Opt parsing here isn't my favorite.
25
+ if config[:shims]
26
+ config[:shims] = shims_path
27
+ end
28
+
20
29
  cookbook_file = ::Berkshelf::Berksfile.from_file(File.join(Dir.pwd, Berkshelf::DEFAULT_FILENAME))
21
30
  cookbook_file.install(config)
22
31
  rescue BerkshelfError => e
23
32
  Berkshelf.ui.fatal e
24
33
  exit e.status_code
25
34
  end
35
+
36
+ private
37
+
38
+ def shims_path
39
+ File.join(Dir.pwd, "cookbooks")
40
+ end
26
41
  end
27
42
  end
@@ -155,6 +155,44 @@ EOF
155
155
  subject.install
156
156
  end
157
157
  end
158
+
159
+ context "when given a value for :shims pointing to a valid path"do
160
+ let(:cached_one) { double('cached_one', cookbook_name: 'nginx', path: fixtures_path.join("cookbooks", "nginx-0.100.5")) }
161
+ let(:cached_two) { double('cached_two', cookbook_name: 'example_cookbook', path: fixtures_path.join("cookbooks", "example_cookbook-0.5.0")) }
162
+ let(:shims_path) { tmp_path.join("cookbook_shims") }
163
+
164
+ before(:each) do
165
+ resolver.stub(:resolve).and_return([cached_one, cached_two])
166
+ end
167
+
168
+ it "sends a message to write_shims with the given directory and the resolver's solution" do
169
+ subject.should_receive(:write_shims).with(shims_path, [cached_one, cached_two])
170
+ subject.install(shims: shims_path)
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "#write_shims" do
176
+ let(:cached_one) { double('cached_one', cookbook_name: 'nginx', path: fixtures_path.join("cookbooks", "nginx-0.100.5")) }
177
+ let(:cached_two) { double('cached_two', cookbook_name: 'example_cookbook', path: fixtures_path.join("cookbooks", "example_cookbook-0.5.0")) }
178
+ let(:shims_path) { tmp_path.join("cookbook_shims") }
179
+
180
+ before(:each) { subject.write_shims(shims_path, [cached_one, cached_two]) }
181
+
182
+ it "writes a directory at the given path" do
183
+ shims_path.should exist
184
+ shims_path.should be_directory
185
+ end
186
+
187
+ it "writes a symlink of the name of each source within the given directory" do
188
+ linked_path_one = shims_path.join(cached_one.cookbook_name)
189
+ linked_path_two = shims_path.join(cached_two.cookbook_name)
190
+
191
+ linked_path_one.should exist
192
+ linked_path_one.should be_cookbook
193
+ linked_path_two.should exist
194
+ linked_path_two.should be_cookbook
195
+ end
158
196
  end
159
197
  end
160
198
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: berkshelf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-06-23 00:00:00.000000000 Z
15
+ date: 2012-06-24 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: dep_selector
@@ -78,6 +78,22 @@ dependencies:
78
78
  - - ~>
79
79
  - !ruby/object:Gem::Version
80
80
  version: 0.15.2
81
+ - !ruby/object:Gem::Dependency
82
+ name: redcarpet
83
+ requirement: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
81
97
  - !ruby/object:Gem::Dependency
82
98
  name: cucumber
83
99
  requirement: !ruby/object:Gem::Requirement
@@ -333,7 +349,7 @@ files:
333
349
  - Gemfile
334
350
  - Guardfile
335
351
  - LICENSE
336
- - README.rdoc
352
+ - README.md
337
353
  - Thorfile
338
354
  - berkshelf.gemspec
339
355
  - features/config.sample.yml
@@ -358,6 +374,7 @@ files:
358
374
  - lib/berkshelf/cookbook_store.rb
359
375
  - lib/berkshelf/core_ext.rb
360
376
  - lib/berkshelf/core_ext/file.rb
377
+ - lib/berkshelf/core_ext/fileutils.rb
361
378
  - lib/berkshelf/core_ext/kernel.rb
362
379
  - lib/berkshelf/core_ext/pathname.rb
363
380
  - lib/berkshelf/downloader.rb
@@ -405,13 +422,13 @@ files:
405
422
  - spec/support/chef_api.rb
406
423
  - spec/support/matchers/file_system_matchers.rb
407
424
  - spec/support/matchers/filepath_matchers.rb
425
+ - spec/unit/berkshelf/berksfile_spec.rb
408
426
  - spec/unit/berkshelf/cached_cookbook_spec.rb
409
427
  - spec/unit/berkshelf/cookbook_source/git_location_spec.rb
410
428
  - spec/unit/berkshelf/cookbook_source/path_location_spec.rb
411
429
  - spec/unit/berkshelf/cookbook_source/site_location_spec.rb
412
430
  - spec/unit/berkshelf/cookbook_source_spec.rb
413
431
  - spec/unit/berkshelf/cookbook_store_spec.rb
414
- - spec/unit/berkshelf/cookbookfile_spec.rb
415
432
  - spec/unit/berkshelf/downloader_spec.rb
416
433
  - spec/unit/berkshelf/dsl_spec.rb
417
434
  - spec/unit/berkshelf/git_spec.rb
@@ -442,7 +459,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
442
459
  version: '0'
443
460
  segments:
444
461
  - 0
445
- hash: 4586386475461844469
462
+ hash: -3927630543327707547
446
463
  requirements: []
447
464
  rubyforge_project:
448
465
  rubygems_version: 1.8.23
@@ -489,13 +506,13 @@ test_files:
489
506
  - spec/support/chef_api.rb
490
507
  - spec/support/matchers/file_system_matchers.rb
491
508
  - spec/support/matchers/filepath_matchers.rb
509
+ - spec/unit/berkshelf/berksfile_spec.rb
492
510
  - spec/unit/berkshelf/cached_cookbook_spec.rb
493
511
  - spec/unit/berkshelf/cookbook_source/git_location_spec.rb
494
512
  - spec/unit/berkshelf/cookbook_source/path_location_spec.rb
495
513
  - spec/unit/berkshelf/cookbook_source/site_location_spec.rb
496
514
  - spec/unit/berkshelf/cookbook_source_spec.rb
497
515
  - spec/unit/berkshelf/cookbook_store_spec.rb
498
- - spec/unit/berkshelf/cookbookfile_spec.rb
499
516
  - spec/unit/berkshelf/downloader_spec.rb
500
517
  - spec/unit/berkshelf/dsl_spec.rb
501
518
  - spec/unit/berkshelf/git_spec.rb
@@ -1,102 +0,0 @@
1
- = Berkshelf
2
-
3
- Manages a Cookbook's, or an Application's, Cookbook dependencies
4
-
5
- == Getting Started
6
-
7
- === Install
8
-
9
- $ gem install berkshelf
10
-
11
- === Use
12
-
13
- ==== Berksfile
14
-
15
- Dependencies are managed via a `Berksfile` in the directory where you want the cookbooks to be installed. The Berksfile, like Bundler's Gemfile, contains which cookbooks are needed and, optionally, where to find them:
16
-
17
- cookbook 'memcached'
18
- cookbook 'nginx'
19
- cookbook 'my_app', path: '/path/to/cookbook'
20
- cookbook 'mysql', git: 'git://github.com/opscode-cookbooks/mysql.git'
21
-
22
- ==== CLI
23
-
24
- The CLI consists of 2 commands: install, update
25
-
26
- $ knife berks (install|update) [(--without|-W) group_to_exclude]
27
-
28
- [install] Installs the from the Berksfile.lock, or Berksfile if the the lockfile does not exist.
29
-
30
- [update] Skips the lockfile and installs fresh
31
-
32
- [init] Prepares a local path to have it's Cookbook dependencies managed by Berkshelf. If the target path is a Cookbook itself, additional Berkshelf support files will be generated to get you started.
33
-
34
- == The Berksfile
35
-
36
- Cookbooks are defined as dependencies by declaring them in the `Berksfile`
37
-
38
- cookbook 'nginx'
39
-
40
- Cookbooks without additional options are assumed to come from the Opscode Community site at the latest available version: http://community.opscode.com/cookbooks
41
-
42
- Options available include:
43
-
44
- version constraint
45
-
46
- cookbook "nginx", "= 0.101.2" # precisely 0.101.2
47
- cookbook "mysql", "< 1.2.4" # less than and not including 1.2.4
48
- cookbook "openssl", "~> 1.0.0" # greater than 1.0.0, and up to but not including 1.1.0
49
-
50
- git
51
-
52
- # ref can be a branch name, tag, or commit hash. If ref is not provided, HEAD is used.
53
- cookbook "mysql", git: "https://github.com/opscode-cookbooks/mysql.git", ref: "<any git ref>"
54
-
55
- path
56
-
57
- # knife berks will look in /path/to/location/of/my_application for the cookbook
58
- cookbook "my_application", path: "/path/to/location/of"
59
-
60
- === Groups
61
-
62
- Groups can be defined via blocks or inline as an option:
63
-
64
- group :solo do
65
- cookbook 'base'
66
- end
67
-
68
- cookbook 'base', :group => 'solo'
69
-
70
- When using install or update, groups can be excluded with the --without GROUP_NAME or -W GROUP_NAME flags.
71
-
72
- = Contributing
73
-
74
- == Running tests
75
-
76
- === Install prerequisites
77
-
78
- Install the latest version of {Bundler}[http://gembundler.com]
79
-
80
- $ gem install bundler
81
-
82
- Clone the project
83
-
84
- $ git clone git://github.com/RiotGames/berkshelf.git
85
-
86
- and run:
87
-
88
- $ cd berkshelf
89
- $ bundle install
90
-
91
- Bundler will install all gems and their dependencies required for testing and developing.
92
-
93
- === Running unit (RSpec) and acceptance (Cucumber) tests
94
-
95
- $ bundle exec guard start
96
-
97
- = Authors and Contributors
98
-
99
- * Josiah Kiehl (<josiah@skirmisher.net>)
100
- * Jamie Winsor (<jamie@vialstudios.com>)
101
- * Erik Hollensbe (<erik@hollensbe.org>)
102
- * Michael Ivey (<ivey@gweezlebur.com>)