r10k 0.0.9 → 1.0.0rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/bin/r10k +1 -1
  2. data/lib/r10k.rb +0 -4
  3. data/lib/r10k/cli.rb +9 -5
  4. data/lib/r10k/cli/deploy.rb +108 -0
  5. data/lib/r10k/cli/environment.rb +5 -1
  6. data/lib/r10k/cli/environment/deploy.rb +6 -28
  7. data/lib/r10k/cli/environment/list.rb +6 -10
  8. data/lib/r10k/cli/environment/stale.rb +6 -16
  9. data/lib/r10k/cli/module.rb +5 -1
  10. data/lib/r10k/cli/module/deploy.rb +5 -32
  11. data/lib/r10k/cli/module/list.rb +6 -27
  12. data/lib/r10k/cli/puppetfile.rb +76 -0
  13. data/lib/r10k/cli/synchronize.rb +8 -24
  14. data/lib/r10k/cli/version.rb +22 -0
  15. data/lib/r10k/deployment.rb +55 -26
  16. data/lib/r10k/deployment/config.rb +69 -0
  17. data/lib/r10k/{config → deployment/config}/loader.rb +9 -5
  18. data/lib/r10k/deployment/environment.rb +88 -0
  19. data/lib/r10k/deployment/source.rb +79 -0
  20. data/lib/r10k/errors.rb +3 -5
  21. data/lib/r10k/execution.rb +43 -0
  22. data/lib/r10k/git/cache.rb +131 -0
  23. data/lib/r10k/git/errors.rb +34 -0
  24. data/lib/r10k/git/repository.rb +74 -0
  25. data/lib/r10k/git/working_dir.rb +142 -0
  26. data/lib/r10k/logging.rb +6 -2
  27. data/lib/r10k/module.rb +10 -13
  28. data/lib/r10k/module/forge.rb +35 -22
  29. data/lib/r10k/module/git.rb +18 -8
  30. data/lib/r10k/puppetfile.rb +107 -0
  31. data/lib/r10k/task.rb +13 -0
  32. data/lib/r10k/task/deployment.rb +151 -0
  33. data/lib/r10k/task/environment.rb +29 -0
  34. data/lib/r10k/task/module.rb +18 -0
  35. data/lib/r10k/task/puppetfile.rb +99 -0
  36. data/lib/r10k/task_runner.rb +72 -0
  37. data/lib/r10k/util/purgeable.rb +50 -0
  38. data/lib/r10k/version.rb +1 -1
  39. data/spec/unit/deployment/environment_spec.rb +19 -0
  40. data/spec/unit/git/cache_spec.rb +37 -0
  41. data/spec/unit/git/working_dir_spec.rb +15 -0
  42. data/spec/unit/module/forge_spec.rb +95 -0
  43. data/spec/unit/module_spec.rb +29 -0
  44. metadata +79 -44
  45. data/lib/r10k/action.rb +0 -7
  46. data/lib/r10k/action/environment.rb +0 -74
  47. data/lib/r10k/action/module.rb +0 -36
  48. data/lib/r10k/cli/cache.rb +0 -32
  49. data/lib/r10k/config.rb +0 -46
  50. data/lib/r10k/deployment/environment_collection.rb +0 -75
  51. data/lib/r10k/librarian.rb +0 -31
  52. data/lib/r10k/librarian/dsl.rb +0 -20
  53. data/lib/r10k/root.rb +0 -98
  54. data/lib/r10k/synchro/git.rb +0 -226
@@ -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'
@@ -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
@@ -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