r10k 0.0.9 → 1.0.0rc1

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.
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