berktacular 0.1.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 +15 -0
- data/bin/berktacular +155 -0
- data/lib/berktacular.rb +45 -0
- data/lib/berktacular/berksfile.rb +199 -0
- data/lib/berktacular/cookbook.rb +115 -0
- data/lib/berktacular/version.rb +4 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NzNiYWFhMGQ4YTY3ZTM5Zjg3Y2E1MDRjYjA2MWY2Yzg5OTk2MWIwNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZjI0MmRhODJmYmM1YWVmNjNiYjE4YTY5Y2EzMGVhNDQwNDkyODBjNg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YjI2ZWIyZGFmZjgxYWY1ZDEzYjZlMDlmYzk4NjRkNDNiMTk1MTMzODc0ZDU2
|
10
|
+
NTgzODU1NmM1Y2JjNTk1ZmI3YTc4ODhkMThjNWQ0NWNjZmMxNDFkMDZhM2Qy
|
11
|
+
OTFkZGRmMzRmYTYzZTk4MWE3NDE1OWY0ODViYzdjYmQ3N2QyNDg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODcxYmUwODZlZjNkM2M0YjkxZmIwMDkxYTJhNmI0ZDMyYWUxM2VhYWI0ZDg3
|
14
|
+
YzcyNTcwMjBmOWEwYjAwY2VmY2Y5YzA4MmIyN2ViNjBiZTRkYTRlN2I1NWIw
|
15
|
+
MWQwNGE3YmMxZGVhMGUwNTRkZGExN2QzNzdkZmIyOTI2ZjA2MDQ=
|
data/bin/berktacular
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'berktacular'
|
6
|
+
|
7
|
+
env_file = nil
|
8
|
+
check = false
|
9
|
+
upgrade = false
|
10
|
+
gtoken_path = File.join(ENV['HOME'], '.github-token')
|
11
|
+
github_token= nil
|
12
|
+
printit = false
|
13
|
+
berksfile = nil
|
14
|
+
new_envfile = nil
|
15
|
+
preserve = false
|
16
|
+
verify = nil
|
17
|
+
upload = false
|
18
|
+
berks_conf = nil
|
19
|
+
knife_conf = nil
|
20
|
+
workdir = nil
|
21
|
+
verbose = false
|
22
|
+
|
23
|
+
options = OptionParser.new do |opts|
|
24
|
+
opts.banner = "Read environment json file and spit out a berksfile"
|
25
|
+
opts.on("-e ENV.json", "--environment ENV.json", String, "Path to the environment file to use. Required.") do |f|
|
26
|
+
env_file = f
|
27
|
+
end
|
28
|
+
opts.on("-c", "--check", "Check for updates and print what they would be") do |c|
|
29
|
+
check = true
|
30
|
+
end
|
31
|
+
opts.on("-u", "--upgrade", "Auto-upgrade cookbooks that support it") do |u|
|
32
|
+
upgrade = true
|
33
|
+
end
|
34
|
+
opts.on("-p", "--print", "Print the berksfile to stdout") do |p|
|
35
|
+
printit = true
|
36
|
+
end
|
37
|
+
opts.on("-b PATH", "--berksfile PATH", String, "Write the berksfile to PATH.") do |b|
|
38
|
+
berksfile = b
|
39
|
+
end
|
40
|
+
opts.on("-n PATH", "--new-envfile PATH", String, "Write a new (updated) env file to PATH.") do |n|
|
41
|
+
new_envfile = n
|
42
|
+
end
|
43
|
+
opts.on("--[no-]verify", "Install cookbooks to WORKDIR and confirm that all dependancies are met") do |v|
|
44
|
+
verify = v
|
45
|
+
end
|
46
|
+
opts.on("--upload", "Upload the cookbooks and updated env file to the chef-server") do
|
47
|
+
upload = true
|
48
|
+
end
|
49
|
+
opts.on("--berksconfig BERKS_CONF", "The berkshelf config file to use. Defaults to ~/.chef/<env_name>-berkshelf.json") do |k|
|
50
|
+
berks_conf = k
|
51
|
+
end
|
52
|
+
opts.on("--knifeconfig KNIFE_CONF", "The knife config file to use. Defaults to ~/.chef/<env_name>-knife.rb") do |k|
|
53
|
+
knife_conf = k
|
54
|
+
end
|
55
|
+
opts.on("--github-token-file FILE", String, "Path to the github token to use") do |g|
|
56
|
+
gtoken_path = g
|
57
|
+
end
|
58
|
+
opts.on("-g TOKEN", "--github-token TOKEN", String, "The github token to use, not the path. This will show up in ps output") do |t|
|
59
|
+
github_token = t
|
60
|
+
end
|
61
|
+
opts.on("-w PATH","--workdir PATH", String, "The working directory to use, it will be created if need be.",
|
62
|
+
"The working directory is used to test the cookbook install.",
|
63
|
+
"Using this option prevents berktacular from deleting the workdir when done.",
|
64
|
+
"Using a tmpfs filesystem is recommended (used by default)",
|
65
|
+
"Default is a tmpdir somewhere (probably /tmp or /dev/shm)") do |w|
|
66
|
+
workdir = w
|
67
|
+
preserve = true
|
68
|
+
end
|
69
|
+
opts.on("-v", "--verbose", "Turn on verbose output" ) do
|
70
|
+
verbose = true
|
71
|
+
end
|
72
|
+
opts.on_tail("-h", "--help", "Print this help message" ) do
|
73
|
+
puts opts
|
74
|
+
exit 0
|
75
|
+
end
|
76
|
+
begin
|
77
|
+
opts.parse!
|
78
|
+
rescue OptionParser::ParseError, OptionParser::MissingArgument
|
79
|
+
warn opts
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
# Enable verify by default if uploading, unless the user has surpressed it.
|
84
|
+
verify ||= upload
|
85
|
+
|
86
|
+
require 'json'
|
87
|
+
require 'solve'
|
88
|
+
|
89
|
+
unless env_file && File.exist?(env_file)
|
90
|
+
warn "No env file found at: '#{env_file}'"
|
91
|
+
warn options
|
92
|
+
exit 2
|
93
|
+
end
|
94
|
+
|
95
|
+
my_env = JSON.parse( File.read( env_file ) )
|
96
|
+
|
97
|
+
unless github_token
|
98
|
+
if File.exists? gtoken_path
|
99
|
+
github_token = IO.read(gtoken_path).strip
|
100
|
+
elsif upgrade || check
|
101
|
+
warn "No github token, cannot continue"
|
102
|
+
warn options
|
103
|
+
exit 3
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
if upload
|
108
|
+
berks_conf ||= "#{File.join(ENV['HOME'], File.basename(env_file, ".json") + "-berkshelf.json" )}"
|
109
|
+
unless File.exists? berks_conf
|
110
|
+
warn "The berkshelf config file could not be found at '#{berks_conf}'"
|
111
|
+
warn options
|
112
|
+
exit 4
|
113
|
+
end
|
114
|
+
knife_conf ||= "#{File.join(ENV['HOME'], File.basename(env_file, ".json") + "-knife.rb" )}"
|
115
|
+
unless File.exists? knife_conf
|
116
|
+
warn "The knife config file could not be found at '#{knife_conf}'"
|
117
|
+
warn options
|
118
|
+
exit 5
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Create a new berksfile
|
123
|
+
puts "Checking updates, this can take some time..." if check || upgrade
|
124
|
+
b = Berktacular::Berksfile.new(my_env, upgrade: upgrade, github_token: github_token, verbose: verbose)
|
125
|
+
b.check_updates if check
|
126
|
+
puts "#{b}" if printit
|
127
|
+
if berksfile
|
128
|
+
FileUtils.mkdir_p( File.dirname(berksfile) )
|
129
|
+
File.write(berksfile, b)
|
130
|
+
end
|
131
|
+
if new_envfile
|
132
|
+
FileUtils.mkdir_p( File.dirname(new_envfile))
|
133
|
+
File.write(new_envfile, JSON.pretty_generate(b.env_file))
|
134
|
+
end
|
135
|
+
|
136
|
+
if verify
|
137
|
+
unless b.verify(workdir)
|
138
|
+
puts "Berksfile verification failed"
|
139
|
+
b.missing_deps.each do |name, msg|
|
140
|
+
puts "#{name}\n\t#{msg}"
|
141
|
+
end
|
142
|
+
exit 10
|
143
|
+
end
|
144
|
+
puts "Berksfile Verified"
|
145
|
+
end
|
146
|
+
|
147
|
+
if upload
|
148
|
+
unless b.upload(knife_conf, workdir)
|
149
|
+
puts "Upload failed!"
|
150
|
+
exit 11
|
151
|
+
end
|
152
|
+
puts "Cookbooks and new environment file have been uploaded to the server"
|
153
|
+
end
|
154
|
+
|
155
|
+
b.clean unless preserve
|
data/lib/berktacular.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'berktacular/version'
|
5
|
+
|
6
|
+
# This module contains classes that allow for generating Berksfiles from chef environment files.
|
7
|
+
module Berktacular
|
8
|
+
|
9
|
+
# @param h [Object] does a deep copy of whatever is passed in.
|
10
|
+
# @return [Object] a deep copy of the passed in object.
|
11
|
+
def self.deep_copy(h)
|
12
|
+
Marshal.load(Marshal.dump(h))
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [String] a command to run.
|
16
|
+
# @return [True] or raise on failure.
|
17
|
+
def self.run_command(cmd)
|
18
|
+
puts "Running command: #{cmd}"
|
19
|
+
unless system(cmd)
|
20
|
+
raise "Command failed with exit code #{$?.exitstatus}: #{cmd}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String] the best tmpdir to use for this machine. Prefers /dev/shm if available.
|
25
|
+
def self.best_temp_dir
|
26
|
+
require 'tempfile'
|
27
|
+
tmp = if File.directory?("/dev/shm") && File.writable?("/dev/shm")
|
28
|
+
'/dev/shm'
|
29
|
+
else
|
30
|
+
'/tmp'
|
31
|
+
end
|
32
|
+
pat = [
|
33
|
+
Time.now().strftime('%Y_%m_%d-%H.%M.%S_'),
|
34
|
+
'_berktacular'
|
35
|
+
]
|
36
|
+
Dir.mktmpdir(pat, tmp)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Matches the numric version information from a tag.
|
40
|
+
VERSION_RE = Regexp.new(/\d+(?:\.\d+)*/)
|
41
|
+
|
42
|
+
autoload :Cookbook, 'berktacular/cookbook'
|
43
|
+
autoload :Berksfile, 'berktacular/berksfile'
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
module Berktacular
|
2
|
+
|
3
|
+
# This class represents a Berksfile
|
4
|
+
|
5
|
+
class Berksfile
|
6
|
+
|
7
|
+
# @!attribute [r] name
|
8
|
+
# @return [String] the name of the environment.
|
9
|
+
# @!attribute [r] description
|
10
|
+
# @return [String] a description of the enviroment.
|
11
|
+
# @!attribute [r] installed
|
12
|
+
# @return [Hash] a hash of installed cookbook directories.
|
13
|
+
# @!attribute [r] missing_deps
|
14
|
+
# @return [Hash] a hash of cookbooks missing dependencies after calling verify.
|
15
|
+
attr_reader :name, :description, :installed, :missing_deps
|
16
|
+
|
17
|
+
# Creates a new Berksfile from a chef environment file.
|
18
|
+
#
|
19
|
+
# @param environment [Hash] a parsed JSON chef environment config.
|
20
|
+
# @option opts [String] :github_token (nil) the github token to use.
|
21
|
+
# @option opts [True,False] :upgrade (False) whether or not to check for upgraded cookbooks.
|
22
|
+
# @option opts [True,False] :verbose (False) be more verbose.
|
23
|
+
def initialize( environment, opts = {})
|
24
|
+
@env_hash = environment # Save the whole thing so we can emit an updated version if needed.
|
25
|
+
@name = environment['name'] || nil
|
26
|
+
@description = environment['description'] || nil
|
27
|
+
@cookbook_versions = environment['cookbook_versions'] || {}
|
28
|
+
@cookbook_locations = environment['cookbook_locations'] || {}
|
29
|
+
@opts = {
|
30
|
+
:upgrade => opts.has_key?(:upgrade) ? opts[:upgrade] : false,
|
31
|
+
:github_token => opts.has_key?(:github_token) ? opts[:github_token] : nil,
|
32
|
+
:verbose => opts.has_key?(:verbose) ? opts[:verbose] : false
|
33
|
+
}
|
34
|
+
@installed = {}
|
35
|
+
# only connect once, pass the client to each cookbook. and only if needed
|
36
|
+
connect_to_git if @opts[:upgrade]
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Hash] representation of the env_file.
|
40
|
+
def env_file
|
41
|
+
if @opts[:upgrade]
|
42
|
+
cookbooks.each do |book|
|
43
|
+
@env_hash['cookbook_versions'][book.name] = book.version_specifier
|
44
|
+
end
|
45
|
+
end
|
46
|
+
@env_hash
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [String] representation of the env_file in pretty json.
|
50
|
+
def env_file_json
|
51
|
+
if @opts[:upgrade]
|
52
|
+
cookbooks.each do |book|
|
53
|
+
@env_hash['cookbook_versions'][book.name] = book.version_specifier
|
54
|
+
end
|
55
|
+
end
|
56
|
+
JSON.pretty_generate(@env_hash)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param workdir [String] the directory in which to install. If nil, Berktacular.best_temp_dir is used.
|
60
|
+
# @return [String] the directory path where the cookbooks were installed.
|
61
|
+
def install(workdir = nil)
|
62
|
+
if workdir
|
63
|
+
FileUtils.mkdir_p(workdir)
|
64
|
+
else
|
65
|
+
workdir = Berktacular.best_temp_dir
|
66
|
+
end
|
67
|
+
unless @installed[workdir]
|
68
|
+
# remove the Berksfile.lock if it exists (it shouldn't).
|
69
|
+
berksfile = File.join(workdir, "Berksfile")
|
70
|
+
lck = berksfile + ".lock"
|
71
|
+
FileUtils.rm(lck) if File.exists? lck
|
72
|
+
File.write(berksfile, self)
|
73
|
+
Berktacular.run_command("berks install --berksfile #{berksfile} --path #{workdir}")
|
74
|
+
@installed[workdir] = {berksfile: berksfile, lck: lck}
|
75
|
+
end
|
76
|
+
workdir
|
77
|
+
end
|
78
|
+
|
79
|
+
# @params workdir [String] the directory in which to install. If nill, Berktacular.best_temp_dir is used.
|
80
|
+
# @return [True,False] the status of the verify.
|
81
|
+
def verify(workdir = nil)
|
82
|
+
require 'ridley'
|
83
|
+
@missing_deps = {}
|
84
|
+
workdir = install(workdir)
|
85
|
+
versions = {}
|
86
|
+
dependencies = {}
|
87
|
+
Dir["#{workdir}/*"].each do |cookbook_dir|
|
88
|
+
next unless File.directory?(cookbook_dir)
|
89
|
+
metadata_path = File.join(cookbook_dir, 'metadata.rb')
|
90
|
+
metadata = Ridley::Chef::Cookbook::Metadata.from_file(metadata_path)
|
91
|
+
cookbook_name = metadata.name
|
92
|
+
name_from_path = File.basename(cookbook_dir)
|
93
|
+
unless cookbook_name == name_from_path
|
94
|
+
if cookbook_name.empty?
|
95
|
+
puts "Cookbook #{name_from_path} has no name specified in metadata.rb"
|
96
|
+
cookbook_name = name_from_path
|
97
|
+
else
|
98
|
+
warn "Cookbook name from metadata.rb does not match the directory name!",
|
99
|
+
"metadata.rb: '#{cookbook_name}'",
|
100
|
+
"cookbook directory name: '#{name_from_path}'"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
versions[cookbook_name] = metadata.version
|
104
|
+
dependencies[cookbook_name] = metadata.dependencies
|
105
|
+
end
|
106
|
+
errors = false
|
107
|
+
dependencies.each do |name, deps|
|
108
|
+
deps.each do |dep_name, constraint|
|
109
|
+
actual_version = versions[dep_name]
|
110
|
+
if !actual_version
|
111
|
+
@missing_deps[name] = "#{name}-#{versions[name]} depends on #{dep_name} which was not installed!"
|
112
|
+
warn @missing_deps[name]
|
113
|
+
errors = true
|
114
|
+
elsif !Solve::Constraint.new(constraint).satisfies?(actual_version)
|
115
|
+
@missing_deps[name] = "#{name}-#{versions[name]} depends on #{dep_name} #{constraint} but #{dep_name} is #{actual_version}!"
|
116
|
+
warn @missing_deps[name]
|
117
|
+
errors = true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
!errors
|
122
|
+
end
|
123
|
+
|
124
|
+
# @param berks_conf [String] path to the berkshelf config file to use.
|
125
|
+
# @param knife_conf [String] path to the knife config file to use.
|
126
|
+
# @param workdir [String] Path to use as the working directory.
|
127
|
+
# @default Berktacular.best_temp_dir
|
128
|
+
# @return [True] or raise on error.
|
129
|
+
def upload(berks_conf, knife_conf, workdir=nil)
|
130
|
+
raise "No berks config, required for upload" unless berks_conf && File.exists?(berks_conf)
|
131
|
+
raise "No knife config, required for upload" unless knife_conf && File.exists?(knife_conf)
|
132
|
+
workdir = install(workdir)
|
133
|
+
new_env_file = File.write(File.join(workdir, @name + ".rb"), env_file_json )
|
134
|
+
Berktacular.run_command("berks upload --berksfile #{@installed[workdir][:berksfile]} --c #{berks_conf}")
|
135
|
+
Berktacular.run_command("knife environment from file #{new_env_file} -c #{knife_conf}")
|
136
|
+
end
|
137
|
+
|
138
|
+
# param workdir [String,nil] the workdir to remove. If nil, remove all installed working directories.
|
139
|
+
def clean(workdir = nil)
|
140
|
+
if workdir
|
141
|
+
Fileutils.rm_r(workdir)
|
142
|
+
@installed.delete(workdir)
|
143
|
+
else
|
144
|
+
# clean them all
|
145
|
+
@installed.keys.each { |d| FileUtils.rm_r(d) }
|
146
|
+
@installed = {}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# @param [IO] where to write the data.
|
151
|
+
def print_berksfile( io = STDOUT )
|
152
|
+
io.puts to_s
|
153
|
+
end
|
154
|
+
|
155
|
+
# @return [String] the berksfile as a String object
|
156
|
+
def to_s
|
157
|
+
str = ''
|
158
|
+
str << "# Name: '#{@name}'\n" if @name
|
159
|
+
str << "# Description: #{@description}\n\n" if @description
|
160
|
+
str << "# This file is auto-generated, changes will be overwritten\n"
|
161
|
+
str << "# Modify the .json environment file and regenerate this Berksfile to make changes.\n\n"
|
162
|
+
|
163
|
+
str << "site :opscode\n\n"
|
164
|
+
cookbooks.each { |l| str << l.to_s << "\n" }
|
165
|
+
str
|
166
|
+
end
|
167
|
+
|
168
|
+
# @return [Array] a list of Cookbook objects for this environment.
|
169
|
+
def cookbooks
|
170
|
+
@cookbooks ||= @cookbook_versions.sort.map do |book, version|
|
171
|
+
Cookbook.new(book, version, @cookbook_locations[book], @opts )
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# print out the cookbooks that have newer version available on github.
|
176
|
+
def check_updates
|
177
|
+
connect_to_git
|
178
|
+
cookbooks.each do |b|
|
179
|
+
candidates = b.check_updates
|
180
|
+
next unless candidates.any?
|
181
|
+
puts "Cookbook: #{b.name} (auto upgrade: #{b.auto_upgrade ? 'enabled' : 'disabled'})",
|
182
|
+
"\tCurrent:#{b.version_number}",
|
183
|
+
"\tUpdates: #{candidates.join(", ")}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
# connect to github using the token in @opts[:github_token].
|
190
|
+
# @return [Octokit::Client] a connected github client.
|
191
|
+
def connect_to_git
|
192
|
+
raise "No token given, can't connect to git" unless @opts[:github_token]
|
193
|
+
puts "Connecting to git with supplied github_token" if @opts[:verbose]
|
194
|
+
require 'octokit'
|
195
|
+
@opts[:git_client] ||= Octokit::Client.new(access_token: @opts[:github_token])
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Berktacular
|
2
|
+
|
3
|
+
# This class represents a cookbook entry form a Berksfile
|
4
|
+
|
5
|
+
class Cookbook
|
6
|
+
|
7
|
+
# @!attribute [r] name
|
8
|
+
# @return [String] the name of the cookbook.
|
9
|
+
# @!attribute [r] version_number
|
10
|
+
# @return [String] the exact version of the cookbook.
|
11
|
+
# @!attribute [r] auto_upgrade
|
12
|
+
# @return [True, False] whether or now this cookbook can autoupgrade.
|
13
|
+
# @!attribute [r] config
|
14
|
+
# @return [Hash, nil] the cookbook_location hash associated with this cookbook or nil
|
15
|
+
attr_reader :name, :version_number, :auto_upgrade, :config
|
16
|
+
|
17
|
+
# Creates a new cookbook entry for a Berksfile.
|
18
|
+
#
|
19
|
+
# @param name [String] the name of the cookbook to use.
|
20
|
+
# @param version_spec [String] the exact version number as in a chef environment file. eg. '= 1.2.3'
|
21
|
+
# @param config [Hash,nil] the cookbook_location hash to for this cookbook. Optional.
|
22
|
+
# @option opts [Octokit::Client] :git_client (nil) the github client to use.
|
23
|
+
# @option opts [True,False] :upgrade (False) whether or not to check for updates. auto_upgrade must also be enbaled for the updated entry to be used.
|
24
|
+
# @option opts [True,False] :verbose (False) be more vervose.
|
25
|
+
def initialize( name, version_spec, config = nil, opts = {} )
|
26
|
+
@name = name || raise( "Missing cookbook name" )
|
27
|
+
@version_spec = version_spec || raise( "Missing cookbook version" )
|
28
|
+
@version_number = VERSION_RE.match( version_spec )[0]
|
29
|
+
@version_solved = Solve::Version.new(@version_number)
|
30
|
+
@auto_upgrade = config && config['auto_upgrade'] || false
|
31
|
+
@versions = config && config['versions'] || {}
|
32
|
+
@config = config ? config.reject{ |k,v| k == 'auto_upgrade' || k == 'versions' } : nil
|
33
|
+
@upgrade = opts.has_key?(:upgrade) ? opts[:upgrade] : false
|
34
|
+
@git_client = opts.has_key?(:git_client) ? opts[:git_client].dup : nil
|
35
|
+
@verbose = opts.has_key?(:verbose) ? opts[:verbose] : false
|
36
|
+
check_updates if @auto_upgrade && @upgrade
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String] the exact version of the cookbook
|
40
|
+
def version_specifier
|
41
|
+
"= #{(@auto_upgrade && @upgrade && check_updates.any?) ? check_updates.first : @version_number }"
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [String] the latest available version number of the cookbook
|
45
|
+
def latest_version
|
46
|
+
check_updates.any? ? check_updates.first : @version_number
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [String] a Berksfile line for this cookbook
|
50
|
+
def to_s
|
51
|
+
line
|
52
|
+
end
|
53
|
+
|
54
|
+
# param upgrade [True,False] ('@upgrade') whether or not to force the lastest version when @auto_update is enabled
|
55
|
+
# @return [String] a Berksfile line for this cookbook
|
56
|
+
def line(upgrade = @upgrade)
|
57
|
+
"cookbook \"#{@name}\", #{generate_conf_line(upgrade, @config )}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Array] a list of available cookbook version newer then we started with, with most recent first
|
61
|
+
def check_updates
|
62
|
+
@candidates ||= if @config && @config['github']
|
63
|
+
get_tags_from_github
|
64
|
+
else
|
65
|
+
[]
|
66
|
+
end.select do |tag|
|
67
|
+
next if @config.has_key?('rel') && ! /^#{@name}-[v\d]/.match(tag)
|
68
|
+
m = VERSION_RE.match(tag)
|
69
|
+
next unless m
|
70
|
+
v = m[0]
|
71
|
+
begin
|
72
|
+
t = Solve::Version.new(v)
|
73
|
+
rescue Solve::Errors::InvalidVersionFormat
|
74
|
+
next
|
75
|
+
end
|
76
|
+
t > @version_solved
|
77
|
+
end.sort.reverse
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# @param upgrade [True,False] use updated cookbook version if @auto_update is also true.
|
83
|
+
# @param config [Hash] the cookbook_locations hash associated with this cookbook.
|
84
|
+
# @return [String] the config line for this cookbook, everything after the cookbook name.
|
85
|
+
def generate_conf_line(upgrade, config)
|
86
|
+
ver = (upgrade && @candidates && @candiates.first) || @version_number
|
87
|
+
line = []
|
88
|
+
if config
|
89
|
+
if config.has_key?('github')
|
90
|
+
line << "github: \"#{config['github']}\""
|
91
|
+
line << "rel: \"#{config['rel']}\"" if config.has_key?('rel')
|
92
|
+
line << 'protocol: :ssh'
|
93
|
+
end
|
94
|
+
if @versions.has_key?(ver)
|
95
|
+
line << "ref: \"#{@versions[ver]['ref']}\""
|
96
|
+
else
|
97
|
+
if !@config.has_key?('tag')
|
98
|
+
line << "tag: \"#{ver}\""
|
99
|
+
else
|
100
|
+
line << "tag: \"#{@config['tag']}\""
|
101
|
+
end
|
102
|
+
end
|
103
|
+
else
|
104
|
+
line << " \"#{ver}\""
|
105
|
+
end
|
106
|
+
line.join(", ").gsub('%{version}', ver)
|
107
|
+
end
|
108
|
+
|
109
|
+
# return [Array] a list of tags from the github repository of this cookbook.
|
110
|
+
def get_tags_from_github
|
111
|
+
@git_client.repo(@config['github']).rels[:tags].get.data.map { |obj| obj.name }
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: berktacular
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Harvey-Smith
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: solve
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.8.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.8'
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.8.2
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: ridley
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.5'
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.5.3
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ~>
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.5'
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.5.3
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: octokit
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '3.0'
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 3.0.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.0'
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 3.0.0
|
73
|
+
description: Generates a Berksfile from JSON style Chef environment files. Also support
|
74
|
+
extension to environment file with 'cookbook_locations'. Verifies the Berksfile
|
75
|
+
is consistent (all dependencies met) and will upload updated cookbooks and env files
|
76
|
+
to a chef server.
|
77
|
+
email:
|
78
|
+
- jeff@clearstorydata.com
|
79
|
+
executables:
|
80
|
+
- berktacular
|
81
|
+
extensions: []
|
82
|
+
extra_rdoc_files: []
|
83
|
+
files:
|
84
|
+
- bin/berktacular
|
85
|
+
- lib/berktacular.rb
|
86
|
+
- lib/berktacular/berksfile.rb
|
87
|
+
- lib/berktacular/cookbook.rb
|
88
|
+
- lib/berktacular/version.rb
|
89
|
+
homepage: https://rubygems.org/gems/berktacular
|
90
|
+
licenses:
|
91
|
+
- Apache License, Version 2.0
|
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: '1.9'
|
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.2.2
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: Parse chef env files, generates a Berksfile and verifies it.
|
113
|
+
test_files: []
|
114
|
+
has_rdoc:
|