berksfiler 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b5fc16d987ad8571285a55ce408be5c849f1d7f8
4
+ data.tar.gz: 775080806b8f17f710de8ea60955eb6a3e0f6ed5
5
+ SHA512:
6
+ metadata.gz: ba41c26dcd94480ee7ecbd50a129ff0305fe2d838298933e2bcb8d1150f771e7a74e771cafec8df86bf920ef91608b16a7213e52f0c41a6a03725f5179b3b30c
7
+ data.tar.gz: 6665555a9551a940a623d3336bfaa7964cf04ad76234f15d7d057d622022658c8a3f8fe603be9e46ada49461485049b7dc66b992cb67de4bb7ff16920ea1b38a
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ cache:
3
+ - bundler
4
+ install:
5
+ - bundle install
6
+ rvm:
7
+ - 2.1.6
8
+ - 2.2.2
9
+ script:
10
+ - bundle exec rake test
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in berksfiler.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Matt Greensmith and Cozy Services Ltd.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # Berksfiler
2
+
3
+ [![Build Status](https://travis-ci.org/mgreensmith/berksfiler.svg)](https://travis-ci.org/mgreensmith/berksfiler)
4
+
5
+ Berksfiler programatically generates [Berkshelf](http://berkshelf.com/) Berksfiles for your [Chef](https://www.chef.io/) cookbooks.
6
+
7
+ ## Overview
8
+
9
+ This tool is designed to help people who have monolithic cookbook repositories generate Berksfiles for their cookbooks. Keeping Berksfiles up to date can be a demanding task, especially when they reference a number of other local cookbooks.
10
+
11
+ Berksfiler can iterate through a `/cookbooks` directory and generate a Berksfile for each cookbook in that directory (with configurable exclusions), or it can generate Berksfiles for individual cookbooks.
12
+
13
+ It runs `knife deps` to determine the full dependency tree for a cookbook. It then generates a Berksfile that includes all local cookbook dependencies, as well as any cookbooks with manually-specified options or sources.
14
+
15
+ You can configure Berksfiler to include specific cookbook dependencies in every Berksfile. This is useful for cookbook dependencies that are used for local development (eg. `chef-solo-seach`) but are not appropriate to include in the metadata of your cookbooks.
16
+
17
+ ## Requirements
18
+
19
+ - A working `knife` toolchain
20
+
21
+ ## Installation
22
+
23
+ $ gem install berksfiler
24
+
25
+ ## Configuration
26
+
27
+ Berksfiler expects a `.berksfiler.yml` in your working directory (the root of your chef repository).
28
+
29
+ Heres an example of a config file with all available options:
30
+
31
+ ```yaml
32
+ ---
33
+ # A relative or absolute path to the location of your cookbooks directory.
34
+ cookbooks_root: cookbooks
35
+
36
+ # An array of cookbooks to include in every Berksfile
37
+ # even if cookbook metadata doesn't specify them
38
+ common_cookbooks:
39
+ - chef-solo-search
40
+
41
+ # An array of local cookbooks for which we should not attempt
42
+ # to overwrite the existing Berksfile. Useful for 3rd party
43
+ # or vendored cookbooks for which we don't want to overwrite
44
+ # an existing Berksfile.
45
+ excluded_cookbooks:
46
+ - jenkins
47
+
48
+ # An array of hashes that specify options for cookbooks.
49
+ # All array elements must have string keys 'name' and 'options'.
50
+ # Options will be appended verbatim to the `cookbook` line
51
+ # in the Berksfile for the named cookbook.
52
+ cookbook_options:
53
+ -
54
+ name: artifact
55
+ options: "git: 'git://github.com/CozyCo/artifact-cookbook.git'"
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ```
61
+ Usage: berksfiler [options]
62
+ -b, --books COOKBOOK,COOKBOOK Cookbooks for which to generate Berksfiles
63
+ -c, --config-file FILE Path to config file
64
+ -h, --help Displays Help
65
+ ```
66
+
67
+ Running `berksfiler` without the `--books` option will cause Berksfiler to generate
68
+ new Berksfiles for all cookbooks in the configured `cookbooks_root` directory,
69
+ except for any cookbooks specified in the `excluded_cookbooks` config option.
70
+
71
+ Berksfiler should be run from the root of your Chef repository.
72
+
73
+ ## Example
74
+
75
+ Given:
76
+
77
+ 1. In the cookbook tree:
78
+ ```
79
+ /cookbooks
80
+ /foo
81
+ /bar
82
+ /baz
83
+ ```
84
+
85
+ 2. if `/cookbooks/foo/metadata.rb` contains the following dependencies:
86
+ ```
87
+ depends 'artifact'
88
+ depends 'bar'
89
+ depends 'baz'
90
+ depends 'some_public_cookbook'
91
+ depends 'some_other_public_cookbook'
92
+ ```
93
+
94
+ 3. And using the example config file displayed above, running
95
+ ```
96
+ $ berksfiler -b foo
97
+ ```
98
+
99
+ would create or update the file `/cookbooks/foo/Berksfile` with the following content:
100
+ ```
101
+ # Autogenerated by Berksfiler, do not edit
102
+
103
+ source 'https://supermarket.chef.io'
104
+ metadata
105
+
106
+ # Common dependencies for all Berksfiles
107
+ cookbook 'chef-solo-search'
108
+
109
+ # Dependencies of this cookbook
110
+ cookbook 'artifact', git: 'git://github.com/CozyCo/artifact-cookbook.git'
111
+ cookbook 'bar', path: '../bar'
112
+ cookbook 'baz', path: '../baz'
113
+ ```
114
+
115
+ ## Copyright
116
+
117
+ Copyright (c) 2014-2015 Matt Greensmith and Cozy Services Ltd. See [LICENSE.txt](LICENSE.txt) for
118
+ further details.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ task default: %w(test)
4
+
5
+ task :test do
6
+ sh 'rubocop'
7
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'berksfiler/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'berksfiler'
8
+ spec.version = Berksfiler::VERSION
9
+ spec.authors = ['Matt Greensmith']
10
+ spec.email = ['matt@mttgreensmith.net']
11
+ spec.summary = 'Programatically generate Berksfiles for Chef cookbooks.'
12
+ spec.description = spec.summary
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.name
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'configurability'
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.6'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rubocop'
25
+ end
data/bin/berksfiler ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'pathname'
5
+ require 'berksfiler'
6
+
7
+ options = { cookbooks: [], config_file: nil }
8
+
9
+ OptionParser.new do |opts|
10
+ opts.banner = 'Usage: berksfiler [options]'
11
+ opts.on('-b', '--books COOKBOOK,COOKBOOK',
12
+ 'Cookbooks for which to generate Berksfiles') do |cookbooks|
13
+ options[:cookbooks] = cookbooks.split(',').map(&:strip)
14
+ end
15
+
16
+ opts.on('-c', '--config-file FILE', 'Path to config file') do |cfile|
17
+ options[:config_file] = cfile
18
+ end
19
+
20
+ opts.on('-h', '--help', 'Displays Help') do
21
+ puts opts
22
+ exit
23
+ end
24
+ end.parse!
25
+
26
+ Berksfiler.load_config(options[:config_file])
27
+
28
+ if options[:cookbooks].empty?
29
+ Berksfiler.run
30
+ else
31
+ options[:cookbooks].each do |cb|
32
+ Berksfiler.emplace_berksfile(cb)
33
+ end
34
+ end
data/lib/berksfiler.rb ADDED
@@ -0,0 +1,78 @@
1
+ require 'pathname'
2
+ require 'configurability'
3
+
4
+ require 'berksfiler/formatter'
5
+ require 'berksfiler/generator'
6
+
7
+ # Berksfiler programmatically generates Berksfiles with correct dependencies
8
+ module Berksfiler
9
+ CONFIG_FILE = Pathname('.berksfiler.yml').expand_path
10
+
11
+ EXCLUDED_DIRS_REGEX = /^\./ # reject . and .. when globbing the cookbooks dir
12
+
13
+ CONFIG_DEFAULTS = {
14
+ cookbooks_root: 'cookbooks',
15
+ common_cookbooks: [],
16
+ excluded_cookbooks: [],
17
+ cookbook_options: []
18
+ }
19
+
20
+ def self::cookbooks_root
21
+ Pathname(config.cookbooks_root).expand_path
22
+ end
23
+
24
+ def self::cookbook_options
25
+ config.cookbook_options
26
+ end
27
+
28
+ def self::common_cookbooks
29
+ config.common_cookbooks
30
+ end
31
+
32
+ def self::excluded_cookbooks
33
+ config.excluded_cookbooks
34
+ end
35
+
36
+ ### Get the loaded config (a Configurability::Config object)
37
+ def self::config
38
+ Configurability.loaded_config
39
+ end
40
+
41
+ ### Load the specified +config_file+ and install the config
42
+ def self::load_config(config_file = nil)
43
+ config_file ||= CONFIG_FILE
44
+ config = Configurability::Config.load(config_file, CONFIG_DEFAULTS)
45
+ config.install
46
+ end
47
+
48
+ # returns an array of all local cookbooks
49
+ # (basically a directory listing of the cookbook_root)
50
+ def self::local_cookbooks
51
+ @local_cookbooks ||= Dir.entries(cookbooks_root).reject do |dir|
52
+ dir =~ EXCLUDED_DIRS_REGEX
53
+ end
54
+ end
55
+
56
+ # returns an array of all cookbooks that have non-default options
57
+ def self::specific_cookbooks
58
+ local_cookbooks + cookbook_options.map { |cb| cb['name'] }
59
+ end
60
+
61
+ # Generate a berksfile and place it in a +cookbook+
62
+ def self::emplace_berksfile(cookbook)
63
+ puts "Generating Berksfile for local cookbook '#{cookbook}'"
64
+ content = Generator.generate_berksfile(cookbook)
65
+ open(File.join(cookbooks_root, cookbook, 'Berksfile'), 'w') do |f|
66
+ f << content
67
+ end
68
+ end
69
+
70
+ # for all local cookbooks, excluding `excluded_cookbooks`, calculate all
71
+ # dependencies and programmatically generate a Berksfile for that cookbook
72
+ # which takes into account the correct sources for all dependencies.
73
+ def self::run
74
+ local_cookbooks - excluded_cookbooks.each do |cb|
75
+ emplace_berksfile(cb)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,63 @@
1
+ module Berksfiler
2
+ # Methods for formatting data to be emplaced in a Berksfile
3
+ class Formatter
4
+ # generate the correct Berksfile line for any cookbook
5
+ def self::cookbook_line(cookbook)
6
+ if special_cookbook_lines.key?(cookbook)
7
+ special_cookbook_lines[cookbook]
8
+ else
9
+ "cookbook '#{cookbook}'\n"
10
+ end
11
+ end
12
+
13
+ # generate a hash of 'name' => '[formatted Berksfile line]' for all local
14
+ # cookbooks and cookbooks that have specified options
15
+ def self::special_cookbook_lines
16
+ return @special_cookbook_lines if @special_cookbook_lines
17
+
18
+ @special_cookbook_lines = {}
19
+
20
+ # local cookbooks are discovered from coobooks_root, and are string names
21
+ Berksfiler.local_cookbooks.map do |cb|
22
+ @special_cookbook_lines[cb] = "cookbook '#{cb}', path: '../#{cb}'\n"
23
+ end
24
+
25
+ # cookbooks with options are provided as a hash
26
+ # with name: and options: keys
27
+ Berksfiler.cookbook_options.each do |cb|
28
+ @special_cookbook_lines[cb['name']] =
29
+ "cookbook '#{cb['name']}', #{cb['options']}\n"
30
+ end
31
+ @special_cookbook_lines
32
+ end
33
+
34
+ #### DISPLAY HELPERS
35
+
36
+ # given a 2-dimensional array +lists+, return an array of the maximum
37
+ # length of the content for each index of the inner arrays
38
+ def self::array_maxes(lists)
39
+ lists.reduce([]) do |maxes, list| # rubocop:disable Style/EachWithObject
40
+ list.each_with_index do |value, index|
41
+ maxes[index] = [(maxes[index] || 0), value.to_s.length].max
42
+ end
43
+ maxes
44
+ end
45
+ end
46
+
47
+ # given a 2-dimensional array +lists+, right-pad each array member based on
48
+ # the maximum length of array members at that inner array index
49
+ # returns an array of formatted lines
50
+ def self::aligned_print(lists)
51
+ out = []
52
+ maxes = array_maxes(lists)
53
+ lists.each do |list|
54
+ line = ''
55
+ list.each_with_index do |value, index|
56
+ line << "#{value.to_s.ljust(maxes[index])} "
57
+ end
58
+ out << line.strip
59
+ end
60
+ out
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,63 @@
1
+ module Berksfiler
2
+ # Methods for generating a Berksfile
3
+ class Generator
4
+ BERKSFILE_FRONTMATTER = <<-END.gsub(/^ {6}/, '')
5
+ # Autogenerated by Berksfiler, do not edit
6
+
7
+ source 'https://supermarket.chef.io'
8
+ metadata
9
+
10
+ END
11
+
12
+ # returns an array of all cookbook dependencies for a
13
+ # given cookbook by running `knife deps`
14
+ def self::get_deps(cookbook)
15
+ # ["cookbooks/foo", "cookbooks/bar"]
16
+ raw_deps = `knife deps cookbooks/#{cookbook} --remote`.split("\n")
17
+ # ["foo", "bar"]
18
+ raw_deps.map { |cb| cb.split('/')[1].strip }
19
+ end
20
+
21
+ # returns an array of cookbook dependencies for a given cookbook,
22
+ # limited to cookbooks which are are local or have specific options
23
+ def self::get_local_deps(cookbook)
24
+ all_deps = get_deps(cookbook)
25
+ specific_cookbooks = Berksfiler.specific_cookbooks.reject do |cb|
26
+ cb == cookbook
27
+ end # don't include self
28
+ all_deps.select { |cb| specific_cookbooks.include?(cb) }
29
+ end
30
+
31
+ # generate a full berksfile for a cookbook, including all dependencies
32
+ # with their correct sources. Excludes community cookbooks unless they
33
+ # are specified in `common_cookbooks`, because the metadata` directive
34
+ # handles these includes.
35
+ def self::generate_berksfile(cookbook)
36
+ content = '' << BERKSFILE_FRONTMATTER
37
+ content << generate_common_berksfile_section
38
+
39
+ cookbooks = get_local_deps(cookbook).map do |cb|
40
+ Formatter.cookbook_line(cb).split(' ')
41
+ end
42
+ unless cookbooks.empty?
43
+ content << "\n# Dependencies of this cookbook\n"
44
+ content << Formatter.aligned_print(cookbooks.sort).join("\n") << "\n"
45
+ end
46
+ content
47
+ end
48
+
49
+ # generate the 'common dependencies' section of a Berksfile
50
+ def self::generate_common_berksfile_section
51
+ content = ''
52
+ common_cookbooks = Berksfiler.common_cookbooks.map do |cb|
53
+ Formatter.cookbook_line(cb).split(' ')
54
+ end
55
+ unless common_cookbooks.empty?
56
+ content << "# Common dependencies for all Berksfiles\n"
57
+ content << Formatter.aligned_print(common_cookbooks.sort).join("\n")
58
+ content << "\n"
59
+ end
60
+ content
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,4 @@
1
+ # Berksfiler programmatically generates Berksfiles with correct dependencies
2
+ module Berksfiler
3
+ VERSION = '0.0.1'
4
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: berksfiler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matt Greensmith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: configurability
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Programatically generate Berksfiles for Chef cookbooks.
70
+ email:
71
+ - matt@mttgreensmith.net
72
+ executables:
73
+ - berksfiler
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - berksfiler.gemspec
84
+ - bin/berksfiler
85
+ - lib/berksfiler.rb
86
+ - lib/berksfiler/formatter.rb
87
+ - lib/berksfiler/generator.rb
88
+ - lib/berksfiler/version.rb
89
+ homepage: ''
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.5
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Programatically generate Berksfiles for Chef cookbooks.
113
+ test_files: []