r10k 0.0.9 → 1.0.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/r10k +1 -1
- data/lib/r10k.rb +0 -4
- data/lib/r10k/cli.rb +9 -5
- data/lib/r10k/cli/deploy.rb +108 -0
- data/lib/r10k/cli/environment.rb +5 -1
- data/lib/r10k/cli/environment/deploy.rb +6 -28
- data/lib/r10k/cli/environment/list.rb +6 -10
- data/lib/r10k/cli/environment/stale.rb +6 -16
- data/lib/r10k/cli/module.rb +5 -1
- data/lib/r10k/cli/module/deploy.rb +5 -32
- data/lib/r10k/cli/module/list.rb +6 -27
- data/lib/r10k/cli/puppetfile.rb +76 -0
- data/lib/r10k/cli/synchronize.rb +8 -24
- data/lib/r10k/cli/version.rb +22 -0
- data/lib/r10k/deployment.rb +55 -26
- data/lib/r10k/deployment/config.rb +69 -0
- data/lib/r10k/{config → deployment/config}/loader.rb +9 -5
- data/lib/r10k/deployment/environment.rb +88 -0
- data/lib/r10k/deployment/source.rb +79 -0
- data/lib/r10k/errors.rb +3 -5
- data/lib/r10k/execution.rb +43 -0
- data/lib/r10k/git/cache.rb +131 -0
- data/lib/r10k/git/errors.rb +34 -0
- data/lib/r10k/git/repository.rb +74 -0
- data/lib/r10k/git/working_dir.rb +142 -0
- data/lib/r10k/logging.rb +6 -2
- data/lib/r10k/module.rb +10 -13
- data/lib/r10k/module/forge.rb +35 -22
- data/lib/r10k/module/git.rb +18 -8
- data/lib/r10k/puppetfile.rb +107 -0
- data/lib/r10k/task.rb +13 -0
- data/lib/r10k/task/deployment.rb +151 -0
- data/lib/r10k/task/environment.rb +29 -0
- data/lib/r10k/task/module.rb +18 -0
- data/lib/r10k/task/puppetfile.rb +99 -0
- data/lib/r10k/task_runner.rb +72 -0
- data/lib/r10k/util/purgeable.rb +50 -0
- data/lib/r10k/version.rb +1 -1
- data/spec/unit/deployment/environment_spec.rb +19 -0
- data/spec/unit/git/cache_spec.rb +37 -0
- data/spec/unit/git/working_dir_spec.rb +15 -0
- data/spec/unit/module/forge_spec.rb +95 -0
- data/spec/unit/module_spec.rb +29 -0
- metadata +79 -44
- data/lib/r10k/action.rb +0 -7
- data/lib/r10k/action/environment.rb +0 -74
- data/lib/r10k/action/module.rb +0 -36
- data/lib/r10k/cli/cache.rb +0 -32
- data/lib/r10k/config.rb +0 -46
- data/lib/r10k/deployment/environment_collection.rb +0 -75
- data/lib/r10k/librarian.rb +0 -31
- data/lib/r10k/librarian/dsl.rb +0 -20
- data/lib/r10k/root.rb +0 -98
- data/lib/r10k/synchro/git.rb +0 -226
data/lib/r10k/librarian.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'r10k'
|
2
|
-
require 'r10k/module'
|
3
|
-
|
4
|
-
class R10K::Librarian
|
5
|
-
|
6
|
-
attr_reader :forge
|
7
|
-
|
8
|
-
def initialize(puppetfile)
|
9
|
-
@puppetfile = puppetfile
|
10
|
-
@modules = []
|
11
|
-
@forge = 'forge.puppetlabs.com'
|
12
|
-
end
|
13
|
-
|
14
|
-
def load
|
15
|
-
dsl = R10K::Librarian::DSL.new(self)
|
16
|
-
dsl.instance_eval(File.read(@puppetfile), @puppetfile)
|
17
|
-
|
18
|
-
@modules
|
19
|
-
end
|
20
|
-
|
21
|
-
# This method only exists because people tried being excessively clever.
|
22
|
-
def set_forge(forge)
|
23
|
-
@forge = forge
|
24
|
-
end
|
25
|
-
|
26
|
-
def add_module(name, args)
|
27
|
-
@modules << [name, args]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
require 'r10k/librarian/dsl'
|
data/lib/r10k/librarian/dsl.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'r10k/librarian'
|
2
|
-
|
3
|
-
class R10K::Librarian::DSL
|
4
|
-
|
5
|
-
def initialize(librarian)
|
6
|
-
@librarian = librarian
|
7
|
-
end
|
8
|
-
|
9
|
-
def mod(name, args = [])
|
10
|
-
@librarian.add_module(name, args)
|
11
|
-
end
|
12
|
-
|
13
|
-
def forge(location)
|
14
|
-
@librarian.set_forge(location)
|
15
|
-
end
|
16
|
-
|
17
|
-
def method_missing(method, *args)
|
18
|
-
raise NoMethodError, "unrecognized declaration '#{method}'"
|
19
|
-
end
|
20
|
-
end
|
data/lib/r10k/root.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'r10k'
|
2
|
-
require 'r10k/module'
|
3
|
-
require 'r10k/synchro/git'
|
4
|
-
require 'r10k/logging'
|
5
|
-
|
6
|
-
class R10K::Root
|
7
|
-
|
8
|
-
include R10K::Logging
|
9
|
-
|
10
|
-
# @!attribute [r] name
|
11
|
-
# The directory name of this root
|
12
|
-
attr_reader :name
|
13
|
-
|
14
|
-
# @!attribute [r] basedir
|
15
|
-
# The basedir to clone the root into
|
16
|
-
attr_reader :basedir
|
17
|
-
|
18
|
-
# @!attribute [r] remote
|
19
|
-
# The location of the remote git repository
|
20
|
-
attr_reader :remote
|
21
|
-
|
22
|
-
# @!attribute [r] ref
|
23
|
-
# The git ref to instantiate into the basedir
|
24
|
-
attr_reader :ref
|
25
|
-
|
26
|
-
def initialize(hash)
|
27
|
-
parse_initialize_hash(hash)
|
28
|
-
end
|
29
|
-
|
30
|
-
def sync!(options = {})
|
31
|
-
synchro = R10K::Synchro::Git.new(@remote)
|
32
|
-
recursive_needed = !(synchro.cloned?(full_path))
|
33
|
-
synchro.sync(full_path, @ref, options)
|
34
|
-
|
35
|
-
sync_modules!(options) if recursive_needed
|
36
|
-
end
|
37
|
-
|
38
|
-
def sync_modules!(options = {})
|
39
|
-
modules.each do |mod|
|
40
|
-
mod.sync!(options)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def modules
|
45
|
-
librarian = R10K::Librarian.new("#{full_path}/Puppetfile")
|
46
|
-
|
47
|
-
module_data = librarian.load
|
48
|
-
|
49
|
-
@modules = module_data.map do |mod|
|
50
|
-
name = mod[0]
|
51
|
-
args = mod[1]
|
52
|
-
R10K::Module.new(name, "#{full_path}/modules", args)
|
53
|
-
end
|
54
|
-
rescue Errno::ENOENT
|
55
|
-
logger.warn "#{self}: #{full_path} does not exist, cannot enumerate modules."
|
56
|
-
[]
|
57
|
-
end
|
58
|
-
|
59
|
-
def full_path
|
60
|
-
@full_path ||= File.expand_path(File.join @basedir, @name)
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def parse_initialize_hash(hash)
|
66
|
-
if hash['name']
|
67
|
-
@name = hash.delete('name')
|
68
|
-
elsif hash['ref']
|
69
|
-
@name = hash['ref']
|
70
|
-
else
|
71
|
-
raise "Unable to resolve directory name from options #{hash.inspect}"
|
72
|
-
end
|
73
|
-
|
74
|
-
# XXX This could be metaprogrammed, but it seems like the road to madness.
|
75
|
-
|
76
|
-
if hash['basedir']
|
77
|
-
@basedir = hash.delete('basedir')
|
78
|
-
else
|
79
|
-
raise "'basedir' is a required value for #{self.class}.new"
|
80
|
-
end
|
81
|
-
|
82
|
-
if hash['remote']
|
83
|
-
@remote = hash.delete('remote')
|
84
|
-
else
|
85
|
-
raise "'remote' is a required value for #{self.class}.new"
|
86
|
-
end
|
87
|
-
|
88
|
-
if hash['ref']
|
89
|
-
@ref = hash.delete('ref')
|
90
|
-
else
|
91
|
-
raise "'ref' is a required value for #{self.class}.new"
|
92
|
-
end
|
93
|
-
|
94
|
-
unless hash.empty?
|
95
|
-
raise "#{self.class}.new only expects keys ['name', 'basedir', 'remote', 'ref'], got #{hash.keys.inspect}"
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
data/lib/r10k/synchro/git.rb
DELETED
@@ -1,226 +0,0 @@
|
|
1
|
-
require 'r10k'
|
2
|
-
require 'r10k/errors'
|
3
|
-
require 'r10k/logging'
|
4
|
-
|
5
|
-
require 'systemu'
|
6
|
-
require 'fileutils'
|
7
|
-
|
8
|
-
module R10K::Synchro; end
|
9
|
-
|
10
|
-
class R10K::Synchro::Git
|
11
|
-
# Define a thingy that can synchronize git repositories.
|
12
|
-
#
|
13
|
-
# This class is built to be a general purpose mechanism for syncing and
|
14
|
-
# caching git repositories.
|
15
|
-
#
|
16
|
-
# Class instances are memoized based on the git remote path. This way if a
|
17
|
-
# single git repository is instantiated multiple times, the object cache
|
18
|
-
# will only be updated once.
|
19
|
-
|
20
|
-
class << self
|
21
|
-
attr_accessor :cache_root
|
22
|
-
|
23
|
-
# @return [Hash<R10K::Synchro::Git>] A hash of memoized class instances
|
24
|
-
def synchros
|
25
|
-
@synchros ||= {}
|
26
|
-
end
|
27
|
-
|
28
|
-
# Memoize class instances and return existing instances.
|
29
|
-
#
|
30
|
-
# This allows objects to mark themselves as cached to prevent unnecessary
|
31
|
-
# cache refreshes.
|
32
|
-
#
|
33
|
-
# @param [String] remote A git remote URL
|
34
|
-
# @return [R10K::Synchro::Git]
|
35
|
-
def new(remote)
|
36
|
-
unless synchros[remote]
|
37
|
-
obj = self.allocate
|
38
|
-
obj.send(:initialize, remote)
|
39
|
-
synchros[remote] = obj
|
40
|
-
end
|
41
|
-
synchros[remote]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
include R10K::Logging
|
46
|
-
|
47
|
-
attr_reader :remote
|
48
|
-
|
49
|
-
# Instantiates a new git synchro and optionally prepares for caching
|
50
|
-
#
|
51
|
-
# @param [String] remote A git remote URL
|
52
|
-
def initialize(remote)
|
53
|
-
@remote = remote
|
54
|
-
|
55
|
-
if self.class.cache_root
|
56
|
-
@cache_path = File.join(self.class.cache_root, @remote.gsub(/[^@\w\.-]/, '-'))
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Synchronize the local git repository.
|
61
|
-
#
|
62
|
-
# @param [String] path The destination path for the files
|
63
|
-
# @param [String] ref The git ref to instantiate at the destination path
|
64
|
-
def sync(path, ref, options = {:update_cache => true})
|
65
|
-
path = File.expand_path(path)
|
66
|
-
cache if options[:update_cache]
|
67
|
-
|
68
|
-
if self.cloned?(path)
|
69
|
-
fetch(path)
|
70
|
-
else
|
71
|
-
clone(path)
|
72
|
-
end
|
73
|
-
reset(path, ref)
|
74
|
-
end
|
75
|
-
|
76
|
-
# @return [TrueClass] if the git repository is cached
|
77
|
-
def cached?
|
78
|
-
@cache_path and File.directory? @cache_path
|
79
|
-
end
|
80
|
-
|
81
|
-
# Determine if repo has been cloned into a specific dir
|
82
|
-
#
|
83
|
-
# @param [String] dirname The directory to check
|
84
|
-
#
|
85
|
-
# @return [true, false] If the repo has already been cloned
|
86
|
-
def cloned?(directory)
|
87
|
-
File.directory?(File.join(directory, '.git'))
|
88
|
-
end
|
89
|
-
|
90
|
-
# Update the git object cache repository if it hasn't been done
|
91
|
-
#
|
92
|
-
# @return [true, nil] If the cache was actually updated
|
93
|
-
def cache
|
94
|
-
unless @cached
|
95
|
-
cache!
|
96
|
-
@cached = true
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Force a cache refresh
|
101
|
-
def cache!
|
102
|
-
if cached?
|
103
|
-
logger.debug "Updating existing cache at #{@cache_path}"
|
104
|
-
git "fetch --prune", :git_dir => @cache_path
|
105
|
-
else
|
106
|
-
logger.debug "No cache for #{@remote.inspect}, forcing cache build"
|
107
|
-
cache_root = self.class.cache_root
|
108
|
-
FileUtils.mkdir_p cache_root unless File.exist? cache_root
|
109
|
-
git "clone --mirror #{@remote} #{@cache_path}"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# Retrieve a list of cached branches for the git repo associated with this
|
114
|
-
# object.
|
115
|
-
#
|
116
|
-
# @return [Array<String>] A list of all cached remote branches
|
117
|
-
def branches(options = {:update_cache => false})
|
118
|
-
cache if (options[:update_cache] or not cached?)
|
119
|
-
output = git "branch", :git_dir => @cache_path
|
120
|
-
output.split("\n").map { |str| str[2..-1] }
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
# Perform a non-bare clone of a git repository.
|
126
|
-
#
|
127
|
-
# If a cachedir is available and the repo is already cached, it will be
|
128
|
-
# used as an object reference to speed up the clone.
|
129
|
-
#
|
130
|
-
# @param [String] path The directory to create the repo working directory
|
131
|
-
def clone(path)
|
132
|
-
if cached?
|
133
|
-
git "clone --reference #{@cache_path} #{@remote} #{path}"
|
134
|
-
git "remote add cache #{@cache_path}", :path => path
|
135
|
-
else
|
136
|
-
FileUtils.mkdir_p path unless File.directory? path
|
137
|
-
git "clone #{@remote} #{path}"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def fetch(path)
|
142
|
-
if cached?
|
143
|
-
git "fetch --prune cache", :path => path
|
144
|
-
else
|
145
|
-
git "fetch --prune origin", :path => path
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
# Reset a git repo with a working directory to a specific ref
|
150
|
-
#
|
151
|
-
# @param [String] path The path to the working directory of the git repo
|
152
|
-
# @param [String] ref The git reference to reset to.
|
153
|
-
def reset(path, ref)
|
154
|
-
commit = resolve_commit(ref)
|
155
|
-
|
156
|
-
begin
|
157
|
-
git "reset --hard #{commit}", :path => path
|
158
|
-
rescue R10K::ExecutionFailure => e
|
159
|
-
logger.error "Unable to locate commit object #{commit} in git repo #{path}"
|
160
|
-
raise
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
# Resolve a ref to a commit hash
|
165
|
-
#
|
166
|
-
# @param [String] ref
|
167
|
-
#
|
168
|
-
# @return [String] The dereferenced hash of `ref`
|
169
|
-
def resolve_commit(ref)
|
170
|
-
commit = git "rev-parse #{ref}^{commit}", :git_dir => @cache_path
|
171
|
-
commit.chomp
|
172
|
-
rescue R10K::ExecutionFailure => e
|
173
|
-
logger.error "Could not resolve ref #{ref.inspect} for git cache #{@cache_path}"
|
174
|
-
raise
|
175
|
-
end
|
176
|
-
|
177
|
-
# Wrap git commands
|
178
|
-
#
|
179
|
-
# @param [String] command_line_args The arguments for the git prompt
|
180
|
-
# @param [Hash] opts
|
181
|
-
#
|
182
|
-
# @option opts [String] :git_dir
|
183
|
-
# @option opts [String] :work_tree
|
184
|
-
# @option opts [String] :work_tree
|
185
|
-
#
|
186
|
-
# @return [String] The git command output
|
187
|
-
def git(command_line_args, opts = {})
|
188
|
-
args = %w{git}
|
189
|
-
|
190
|
-
log_event = "git #{command_line_args}"
|
191
|
-
log_event << ", args: #{opts.inspect}" unless opts.empty?
|
192
|
-
|
193
|
-
|
194
|
-
if opts[:path]
|
195
|
-
args << "--git-dir #{opts[:path]}/.git"
|
196
|
-
args << "--work-tree #{opts[:path]}"
|
197
|
-
else
|
198
|
-
if opts[:git_dir]
|
199
|
-
args << "--git-dir #{opts[:git_dir]}"
|
200
|
-
end
|
201
|
-
if opts[:work_tree]
|
202
|
-
args << "--work-tree #{opts[:work_tree]}"
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
logger.debug1 "Execute: '#{log_event}'"
|
207
|
-
|
208
|
-
args << command_line_args
|
209
|
-
cmd = args.join(' ')
|
210
|
-
|
211
|
-
status, stdout, stderr = systemu(cmd)
|
212
|
-
|
213
|
-
logger.debug2 "[#{log_event}] STDOUT: #{stdout.chomp}" unless stdout.empty?
|
214
|
-
logger.debug2 "[#{log_event}] STDERR: #{stderr.chomp}" unless stderr.empty?
|
215
|
-
|
216
|
-
unless status == 0
|
217
|
-
msg = "#{cmd.inspect} returned with non-zero exit value #{status.exitstatus}"
|
218
|
-
e = R10K::ExecutionFailure.new(msg)
|
219
|
-
e.exit_code = status
|
220
|
-
e.stdout = stdout
|
221
|
-
e.stderr = stderr
|
222
|
-
raise e
|
223
|
-
end
|
224
|
-
stdout
|
225
|
-
end
|
226
|
-
end
|