puppet_fixtures 0.1.0
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 +7 -0
- data/bin/puppet-fixtures +59 -0
- data/lib/puppet_fixtures/tasks.rb +15 -0
- data/lib/puppet_fixtures.rb +576 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0b6246620641ff6d3570c494428f46def8a857befdda5bcca94ada409f363e76
|
4
|
+
data.tar.gz: bafb926914441b2118e2a72cfd3ce2108073576c76f6e7e16dc6edacd1585414
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a8fff928c60d024ffff15ef613e2eafbea0c00c51d64057c820b3b2500793c0b24bd72da3ca6e169e4c45868db34b2cc60db4cca47eec8dc77edc3d0cfc2e46b
|
7
|
+
data.tar.gz: e8a69aee563e805b5f17f24b567b40492cb4760b80b7ee988e466c87fb0d013cba74b167f3319f124b33798414ed13717cc96364188412a59a896f9e89499c80
|
data/bin/puppet-fixtures
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require 'puppet_fixtures'
|
7
|
+
|
8
|
+
COMMANDS = ['clean', 'install', 'show']
|
9
|
+
|
10
|
+
command = ARGV[0]
|
11
|
+
unless COMMANDS.include?(command)
|
12
|
+
$stderr.puts "Usage: #{$0} #{COMMANDS.join('|')}"
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
fixtures = PuppetFixtures::Fixtures.new
|
17
|
+
|
18
|
+
case command
|
19
|
+
when 'clean'
|
20
|
+
fixtures.clean
|
21
|
+
when 'install'
|
22
|
+
fixtures.download
|
23
|
+
when 'show'
|
24
|
+
if (path = fixtures.fixture_path)
|
25
|
+
puts "Parsing #{fixtures.fixture_path}"
|
26
|
+
|
27
|
+
if fixtures.symlinks.any?
|
28
|
+
puts
|
29
|
+
puts "Symlinks"
|
30
|
+
fixtures.symlinks.each do |_target, symlink|
|
31
|
+
puts " #{symlink}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if fixtures.forge_modules.any?
|
36
|
+
puts
|
37
|
+
puts "Forge modules"
|
38
|
+
fixtures.forge_modules.each do |mod, opts|
|
39
|
+
dir = Pathname.new(opts[:target]).relative_path_from(fixtures.module_target_dir)
|
40
|
+
description = mod
|
41
|
+
description += " #{opts[:ref]}"
|
42
|
+
puts " #{dir} => #{description}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
if fixtures.repositories.any?
|
47
|
+
puts
|
48
|
+
puts "Repositories"
|
49
|
+
fixtures.repositories.each do |repository, opts|
|
50
|
+
dir = Pathname.new(opts[:target]).relative_path_from(fixtures.module_target_dir)
|
51
|
+
description = ["#{opts[:scm]}+#{repository}", opts[:ref]]
|
52
|
+
description << "branch #{opts[:branch]}" if opts[:branch]
|
53
|
+
puts " #{dir} => #{description.compact.join(' ')}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
else
|
57
|
+
$stderr.puts "No fixture file found"
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative '../puppet_fixtures'
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
namespace :fixtures do
|
6
|
+
desc 'Create the fixtures directory'
|
7
|
+
task :prep do
|
8
|
+
PuppetFixtures.new.download(max_thread_limit: ENV.fetch('MAX_FIXTURE_THREAD_COUNT', 10).to_i)
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Clean up the fixtures directory'
|
12
|
+
task :clean do
|
13
|
+
PuppetFixtures.new.clean
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,576 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'open3'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
# PuppetFixtures is a mechanism to download Puppet fixtures.
|
8
|
+
#
|
9
|
+
# These fixtures can be symlinks, repositories (git or Mercurial) or forge
|
10
|
+
# modules.
|
11
|
+
module PuppetFixtures
|
12
|
+
# @return [Boolean]
|
13
|
+
# true if the os is a windows system
|
14
|
+
def self.windows?
|
15
|
+
# Ruby only sets File::ALT_SEPARATOR on Windows and Rubys standard library
|
16
|
+
# uses this to check for Windows
|
17
|
+
!!File::ALT_SEPARATOR
|
18
|
+
end
|
19
|
+
|
20
|
+
class Fixtures
|
21
|
+
attr_reader :source_dir
|
22
|
+
|
23
|
+
def initialize(source_dir: Dir.pwd, max_thread_limit: 10)
|
24
|
+
@source_dir = source_dir
|
25
|
+
@max_thread_limit = max_thread_limit
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Hash]
|
29
|
+
# A hash of all the fixture repositories
|
30
|
+
# @example
|
31
|
+
# {
|
32
|
+
# "puppetlabs-stdlib"=>{
|
33
|
+
# "target"=>"https://gitlab.com/puppetlabs/puppet-stdlib.git",
|
34
|
+
# "ref"=>nil,
|
35
|
+
# "branch"=>"main",
|
36
|
+
# "scm"=>nil,
|
37
|
+
# }
|
38
|
+
# }
|
39
|
+
def repositories
|
40
|
+
@repositories ||= fixtures['repositories']
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Hash]
|
44
|
+
# A hash of all the fixture forge modules
|
45
|
+
# @example
|
46
|
+
# {
|
47
|
+
# "puppetlabs-stdlib"=>{
|
48
|
+
# "target"=>"spec/fixtures/modules/stdlib",
|
49
|
+
# "ref"=>nil,
|
50
|
+
# "branch"=>nil,
|
51
|
+
# "scm"=>nil,
|
52
|
+
# "flags"=>"--module_repository=https://myforge.example.com/",
|
53
|
+
# "subdir"=>nil,
|
54
|
+
# }
|
55
|
+
# }
|
56
|
+
def forge_modules
|
57
|
+
@forge_modules ||= fixtures['forge_modules']
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Hash[String, Symlink]]
|
61
|
+
# A hash of symlinks specified in the fixtures file
|
62
|
+
def symlinks
|
63
|
+
@symlinks ||= fixtures['symlinks']
|
64
|
+
end
|
65
|
+
|
66
|
+
def fixtures
|
67
|
+
@fixtures ||= begin
|
68
|
+
categories = read_fixtures_file['fixtures']
|
69
|
+
|
70
|
+
categories['symlinks'] ||= begin
|
71
|
+
metadata = PuppetFixtures::Metadata.new(File.join(source_dir, 'metadata.json'))
|
72
|
+
{ metadata.name.split('-').last => source_dir }
|
73
|
+
rescue ArgumentError
|
74
|
+
{}
|
75
|
+
end
|
76
|
+
categories['forge_modules'] ||= {}
|
77
|
+
categories['repositories'] ||= {}
|
78
|
+
|
79
|
+
defaults = { 'target' => module_target_dir }
|
80
|
+
|
81
|
+
['symlinks', 'forge_modules', 'repositories'].to_h do |category|
|
82
|
+
# load defaults from the `.fixtures.yml` `defaults` section
|
83
|
+
# for the requested category and merge them into my defaults
|
84
|
+
if (category_defaults = categories.dig('defaults', category))
|
85
|
+
category_defaults = defaults.merge(category_defaults)
|
86
|
+
else
|
87
|
+
category_defaults = defaults
|
88
|
+
end
|
89
|
+
|
90
|
+
entries = categories[category].to_h do |fixture, opts|
|
91
|
+
# convert a simple string fixture to a hash, by
|
92
|
+
# using the string fixture as the `repo` option of the hash.
|
93
|
+
if opts.instance_of?(String)
|
94
|
+
opts = { 'repo' => opts }
|
95
|
+
end
|
96
|
+
# there should be a warning or something if it's not a hash...
|
97
|
+
next unless opts.instance_of?(Hash)
|
98
|
+
|
99
|
+
# merge our options into the defaults to get the
|
100
|
+
# final option list
|
101
|
+
opts = category_defaults.merge(opts)
|
102
|
+
|
103
|
+
next unless include_repo?(opts['puppet_version'])
|
104
|
+
|
105
|
+
entry = validate_fixture_hash!(
|
106
|
+
target: File.join(opts['target'], fixture),
|
107
|
+
ref: opts['ref'] || opts['tag'],
|
108
|
+
branch: opts['branch'],
|
109
|
+
scm: opts.fetch('scm', 'git'),
|
110
|
+
flags: opts['flags'],
|
111
|
+
subdir: opts['subdir'],
|
112
|
+
)
|
113
|
+
|
114
|
+
case category
|
115
|
+
when 'forge_modules'
|
116
|
+
entry.delete(:scm)
|
117
|
+
entry.delete(:branch)
|
118
|
+
entry.delete(:subdir)
|
119
|
+
when 'symlinks'
|
120
|
+
entry = PuppetFixtures::Symlink.new(link: entry[:target], target: opts['repo'])
|
121
|
+
end
|
122
|
+
|
123
|
+
[opts['repo'], entry]
|
124
|
+
end
|
125
|
+
|
126
|
+
[category, entries]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# @param [String] remote
|
132
|
+
# The remote url or namespace/name of the module to download
|
133
|
+
# @param [String] scm
|
134
|
+
# The SCM to use
|
135
|
+
# @return [Boolean]
|
136
|
+
# Returns true if the module was downloaded successfully, false otherwise
|
137
|
+
def download_repository(remote, target:, scm:, subdir:, ref:, branch:, flags:)
|
138
|
+
repository = PuppetFixtures::Repository.factory(scm: scm, remote: remote, target: target, branch: branch, ref: ref)
|
139
|
+
repository.download(flags, subdir)
|
140
|
+
end
|
141
|
+
|
142
|
+
# @return [String]
|
143
|
+
# the spec/fixtures/modules directory in the module root folder
|
144
|
+
def module_target_dir
|
145
|
+
# TODO: relative to source_dir?
|
146
|
+
@module_target_dir ||= File.expand_path(File.join('spec', 'fixtures', 'modules'))
|
147
|
+
end
|
148
|
+
|
149
|
+
# @param [String] remote
|
150
|
+
# the remote url or namespace/name of the module to download
|
151
|
+
# @return [Boolean]
|
152
|
+
# returns true if the module was downloaded, false otherwise
|
153
|
+
def download_module(remote, ref:, target:, flags:)
|
154
|
+
if File.directory?(target)
|
155
|
+
if !ref || ref.empty?
|
156
|
+
logger.debug("Module #{target} already up to date")
|
157
|
+
return false
|
158
|
+
end
|
159
|
+
|
160
|
+
begin
|
161
|
+
version = PuppetFixtures::Metadata.new(File.join(target, 'metadata.json')).version
|
162
|
+
rescue ArgumentError
|
163
|
+
logger.warn "Unable to detect module version for #{target}; updating"
|
164
|
+
else
|
165
|
+
if ref == version
|
166
|
+
logger.debug("Module #{target} already up to date (#{ref})")
|
167
|
+
return false
|
168
|
+
else
|
169
|
+
logger.debug("Module #{target} version #{version} != #{ref}; updating")
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
command = ['puppet', 'module', 'install']
|
175
|
+
command << '--version' << ref if ref
|
176
|
+
command += flags if flags
|
177
|
+
command += ['--ignore-dependencies', '--force', '--target-dir', module_target_dir, remote]
|
178
|
+
|
179
|
+
unless run_command(command)
|
180
|
+
raise "Failed to install module #{remote} to #{module_target_dir}"
|
181
|
+
end
|
182
|
+
|
183
|
+
true
|
184
|
+
end
|
185
|
+
|
186
|
+
def download
|
187
|
+
logger.debug("Downloading to #{module_target_dir}")
|
188
|
+
FileUtils.mkdir_p(module_target_dir)
|
189
|
+
|
190
|
+
if symlinks.empty?
|
191
|
+
logger.debug('No symlinks to create')
|
192
|
+
else
|
193
|
+
symlinks.each_value do |symlink|
|
194
|
+
logger.info("Creating symlink #{symlink}")
|
195
|
+
symlink.create
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
queue = Queue.new
|
200
|
+
|
201
|
+
repositories.each do |remote, opts|
|
202
|
+
queue << [:repository, remote, opts]
|
203
|
+
end
|
204
|
+
forge_modules.each do |remote, opts|
|
205
|
+
queue << [:forge, remote, opts]
|
206
|
+
end
|
207
|
+
|
208
|
+
if queue.empty?
|
209
|
+
logger.debug('Nothing to download')
|
210
|
+
return
|
211
|
+
end
|
212
|
+
|
213
|
+
instance = self
|
214
|
+
|
215
|
+
thread_count = [@max_thread_limit, queue.size].min
|
216
|
+
logger.debug("Download queue size: #{queue.size}; using #{thread_count} threads")
|
217
|
+
|
218
|
+
threads = thread_count.times.map do |i|
|
219
|
+
Thread.new do
|
220
|
+
type, remote, opts = queue.pop(true)
|
221
|
+
case type
|
222
|
+
when :repository
|
223
|
+
instance.download_repository(remote, **opts)
|
224
|
+
when :forge
|
225
|
+
instance.download_module(remote, **opts)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
begin
|
231
|
+
threads.map(&:join)
|
232
|
+
rescue Interrupt
|
233
|
+
# pass
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def clean
|
238
|
+
repositories.each_value do |opts|
|
239
|
+
target = opts[:target]
|
240
|
+
logger.debug("Removing repository #{target}")
|
241
|
+
FileUtils.rm_rf(target)
|
242
|
+
end
|
243
|
+
|
244
|
+
forge_modules.each_value do |opts|
|
245
|
+
target = opts[:target]
|
246
|
+
logger.debug("Removing forge module #{target}")
|
247
|
+
FileUtils.rm_rf(target)
|
248
|
+
end
|
249
|
+
|
250
|
+
symlinks.each_value do |symlink|
|
251
|
+
logger.debug("Removing symlink #{symlink}")
|
252
|
+
symlink.remove
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def fixture_path
|
257
|
+
if ENV['FIXTURES_YML']
|
258
|
+
ENV['FIXTURES_YML']
|
259
|
+
elsif File.exist?('.fixtures.yml')
|
260
|
+
'.fixtures.yml'
|
261
|
+
elsif File.exist?('.fixtures.yaml')
|
262
|
+
'.fixtures.yaml'
|
263
|
+
else
|
264
|
+
nil
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
private
|
269
|
+
|
270
|
+
def include_repo?(version_range)
|
271
|
+
return true unless version_range
|
272
|
+
|
273
|
+
require 'semantic_puppet'
|
274
|
+
|
275
|
+
puppet_spec = Gem::Specification.find_by_name('puppet')
|
276
|
+
puppet_version = SemanticPuppet::Version.parse(puppet_spec.version.to_s)
|
277
|
+
|
278
|
+
constraint = SemanticPuppet::VersionRange.parse(version_range)
|
279
|
+
constraint.include?(puppet_version)
|
280
|
+
end
|
281
|
+
|
282
|
+
def git_remote_url(target)
|
283
|
+
output, status = Open3.capture2e('git', '--git-dir', File.join(target, '.git'), 'ls-remote', '--get-url', 'origin')
|
284
|
+
status.success? ? output.strip : nil
|
285
|
+
end
|
286
|
+
|
287
|
+
# creates a logger so we can log events with certain levels
|
288
|
+
def logger
|
289
|
+
@logger ||= begin
|
290
|
+
require 'logger'
|
291
|
+
Logger.new($stderr, level: ENV['ENABLE_LOGGER'] ? Logger::DEBUG : Logger::INFO)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def read_fixtures_file
|
296
|
+
fixtures_yaml = fixture_path
|
297
|
+
|
298
|
+
fixtures = nil
|
299
|
+
if fixtures_yaml
|
300
|
+
begin
|
301
|
+
fixtures = YAML.load_file(fixtures_yaml)
|
302
|
+
rescue Errno::ENOENT
|
303
|
+
raise "Fixtures file not found: '#{fixtures_yaml}'"
|
304
|
+
rescue Psych::SyntaxError => e
|
305
|
+
raise "Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
fixtures ||= { 'fixtures' => {} }
|
309
|
+
|
310
|
+
unless fixtures.include?('fixtures')
|
311
|
+
# File is non-empty, but does not specify fixtures
|
312
|
+
raise("No 'fixtures' entries found in '#{fixtures_yaml}'; required")
|
313
|
+
end
|
314
|
+
|
315
|
+
fixtures
|
316
|
+
end
|
317
|
+
|
318
|
+
def validate_fixture_hash!(**hash)
|
319
|
+
if hash[:flags].is_a?(String)
|
320
|
+
require 'shellwords'
|
321
|
+
hash[:flags] = Shellwords.split(hash[:flags])
|
322
|
+
end
|
323
|
+
|
324
|
+
if hash['scm'] == 'git' && hash['ref'].include?('/')
|
325
|
+
# Forward slashes in the ref aren't allowed. And is probably a branch name.
|
326
|
+
raise ArgumentError, "The ref for #{hash['target']} is invalid (Contains a forward slash). If this is a branch name, please use the 'branch' setting instead."
|
327
|
+
end
|
328
|
+
|
329
|
+
hash
|
330
|
+
end
|
331
|
+
|
332
|
+
# @param [Array[String]] command
|
333
|
+
def run_command(command, chdir: nil)
|
334
|
+
logger.debug do
|
335
|
+
require 'shellwords'
|
336
|
+
if chdir
|
337
|
+
"Calling command #{Shellwords.join(command)} in #{chdir}"
|
338
|
+
else
|
339
|
+
"Calling command #{Shellwords.join(command)}"
|
340
|
+
end
|
341
|
+
end
|
342
|
+
if chdir
|
343
|
+
system(*command, chdir: chdir)
|
344
|
+
else
|
345
|
+
system(*command)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
class Metadata
|
351
|
+
def initialize(path)
|
352
|
+
raise ArgumentError unless File.file?(path) && File.readable?(path)
|
353
|
+
|
354
|
+
@metadata = JSON.parse(File.read(path))
|
355
|
+
rescue JSON::ParserError => e
|
356
|
+
raise ArgumentError, "Failed to read module metadata at #{path}: #{e}"
|
357
|
+
end
|
358
|
+
|
359
|
+
# @return [String[1]] The module name
|
360
|
+
def name
|
361
|
+
n = @metadata['name']
|
362
|
+
raise ArgumentError "No module name found" if !n || n.empty?
|
363
|
+
|
364
|
+
n
|
365
|
+
end
|
366
|
+
|
367
|
+
# @return [String[1]] The module version
|
368
|
+
def version
|
369
|
+
v = @metadata['version']
|
370
|
+
raise ArgumentError "No module name found" if !v || v.empty?
|
371
|
+
|
372
|
+
v
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
class Symlink
|
377
|
+
# @param target [String]
|
378
|
+
# the target directory
|
379
|
+
# @param link [String]
|
380
|
+
# the name of the link you wish to create
|
381
|
+
def initialize(target:, link:)
|
382
|
+
@target = target
|
383
|
+
@link = link
|
384
|
+
end
|
385
|
+
|
386
|
+
# Create a junction on Windows or otherwise a symlink
|
387
|
+
# works on windows and linux
|
388
|
+
def create
|
389
|
+
return if File.symlink?(@link)
|
390
|
+
|
391
|
+
if PuppetFixtures.windows?
|
392
|
+
begin
|
393
|
+
require 'win32/dir'
|
394
|
+
rescue LoadError
|
395
|
+
end
|
396
|
+
target = File.join(File.dirname(@link), @target) unless Pathname.new(@target).absolute?
|
397
|
+
if Dir.respond_to?(:create_junction)
|
398
|
+
Dir.create_junction(@link, target)
|
399
|
+
else
|
400
|
+
warn 'win32-dir gem not installed, falling back to executing mklink directly'
|
401
|
+
# TODO: use run_command
|
402
|
+
system("call mklink /J \"#{@link.tr('/', '\\')}\" \"#{target.tr('/', '\\')}\"")
|
403
|
+
end
|
404
|
+
else
|
405
|
+
FileUtils.ln_sf(@target, @link)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def remove
|
410
|
+
FileUtils.rm_f(@link)
|
411
|
+
end
|
412
|
+
|
413
|
+
def to_s
|
414
|
+
# TODO: relative?
|
415
|
+
"#{@link} => #{@target}"
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
module Repository
|
420
|
+
def self.factory(scm:, remote:, target:, branch:, ref:)
|
421
|
+
cls = case scm
|
422
|
+
when 'git'
|
423
|
+
Repository::Git
|
424
|
+
when 'hg'
|
425
|
+
Repository::Mercurial
|
426
|
+
else
|
427
|
+
raise ArgumentError, "Unfortunately #{scm} is not supported yet"
|
428
|
+
end
|
429
|
+
cls.new(remote: remote, target: target, branch: branch, ref: ref)
|
430
|
+
end
|
431
|
+
|
432
|
+
class Base
|
433
|
+
def initialize(remote:, target:, branch:, ref:)
|
434
|
+
@remote = remote
|
435
|
+
@target = target
|
436
|
+
@ref = ref
|
437
|
+
@branch = branch
|
438
|
+
end
|
439
|
+
|
440
|
+
def download(flags = nil, subdir = nil)
|
441
|
+
can_update = false
|
442
|
+
if File.directory?(@target)
|
443
|
+
if remote_url_changed?
|
444
|
+
warn "Remote for #{@target} has changed, recloning repository"
|
445
|
+
FileUtils.rm_rf(@target)
|
446
|
+
else
|
447
|
+
can_update = true
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
if can_update
|
452
|
+
update
|
453
|
+
else
|
454
|
+
clone(flags)
|
455
|
+
unless File.exist?(@target)
|
456
|
+
raise "Failed to clone repository #{@remote} into #{@target}"
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
revision
|
461
|
+
remove_subdirectory(subdir) if subdir
|
462
|
+
end
|
463
|
+
|
464
|
+
protected
|
465
|
+
|
466
|
+
def remove_subdirectory(subdir)
|
467
|
+
Dir.mktmpdir do |tmpdir|
|
468
|
+
FileUtils.mv(Dir.glob(File.join(@target, subdir, "{.[^\.]*,*}")), tmpdir)
|
469
|
+
FileUtils.rm_rf(File.join(@target, subdir))
|
470
|
+
FileUtils.mv(Dir.glob(File.join(tmpdir, "{.[^\.]*,*}")), @target.to_s)
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
def run_command(command, chdir: nil)
|
475
|
+
# TODO: duplicated
|
476
|
+
logger.debug do
|
477
|
+
require 'shellwords'
|
478
|
+
if chdir
|
479
|
+
"Calling command #{Shellwords.join(command)} in #{chdir}"
|
480
|
+
else
|
481
|
+
"Calling command #{Shellwords.join(command)}"
|
482
|
+
end
|
483
|
+
end
|
484
|
+
if chdir
|
485
|
+
system(*command, chdir: chdir)
|
486
|
+
else
|
487
|
+
system(*command)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def logger
|
492
|
+
# TODO: duplicated
|
493
|
+
@logger ||= begin
|
494
|
+
require 'logger'
|
495
|
+
# TODO: progname?
|
496
|
+
Logger.new($stderr, level: ENV['ENABLE_LOGGER'] ? Logger::DEBUG : Logger::INFO)
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
class Git < Base
|
502
|
+
def clone(flags = nil)
|
503
|
+
command = ['git', 'clone']
|
504
|
+
command.push('--depth', '1') unless @ref
|
505
|
+
command.push('-b', @branch) if @branch
|
506
|
+
command.push(flags) if flags
|
507
|
+
command.push(@remote, @target)
|
508
|
+
|
509
|
+
run_command(command)
|
510
|
+
end
|
511
|
+
|
512
|
+
def update
|
513
|
+
# TODO: should this pull?
|
514
|
+
command = ['git', 'fetch']
|
515
|
+
command.push('--unshallow') if shallow_git_repo?
|
516
|
+
|
517
|
+
run_command(command, chdir: @target)
|
518
|
+
end
|
519
|
+
|
520
|
+
def revision
|
521
|
+
return true unless @ref
|
522
|
+
|
523
|
+
command = ['git', 'reset', '--hard', @ref]
|
524
|
+
result = run_command(command, chdir: @target)
|
525
|
+
raise "Invalid ref #{ref} for #{@target}" unless result
|
526
|
+
|
527
|
+
result
|
528
|
+
end
|
529
|
+
|
530
|
+
def remote_url_changed?(remote = 'origin')
|
531
|
+
remote_url(remote) != @remote
|
532
|
+
end
|
533
|
+
|
534
|
+
private
|
535
|
+
|
536
|
+
def remote_url(remote = 'origin')
|
537
|
+
output, status = Open3.capture2e('git', '--git-dir', File.join(@target, '.git'), 'ls-remote', '--get-url', remote)
|
538
|
+
status.success? ? output.strip : nil
|
539
|
+
end
|
540
|
+
|
541
|
+
def shallow_git_repo?
|
542
|
+
File.file?(File.join(@target, '.git', 'shallow'))
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
class Mercurial < Base
|
547
|
+
def clone(flags = nil)
|
548
|
+
command = ['hg', 'clone']
|
549
|
+
command.push('-b', @branch) if @branch
|
550
|
+
command.push(flags) if flags
|
551
|
+
command.push(@remote, @target)
|
552
|
+
|
553
|
+
run_command(command)
|
554
|
+
end
|
555
|
+
|
556
|
+
def update
|
557
|
+
run_command(['hg', 'pull'])
|
558
|
+
end
|
559
|
+
|
560
|
+
def revision
|
561
|
+
return true unless @ref
|
562
|
+
|
563
|
+
command = ['hg', 'update', '--clean', '-r', @ref]
|
564
|
+
result = run_command(command, chdir: @target)
|
565
|
+
raise "Invalid ref #{ref} for #{@target}" unless result
|
566
|
+
|
567
|
+
result
|
568
|
+
end
|
569
|
+
|
570
|
+
def remote_url_changed?
|
571
|
+
# Not implemented
|
572
|
+
false
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: puppet_fixtures
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ewoud Kohl van Wijngaarden
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: rake
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '13.0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '13.0'
|
26
|
+
description: |
|
27
|
+
Originally part of puppetlabs_spec_helper, but with a significant
|
28
|
+
refactoring to make it available standalone.
|
29
|
+
executables:
|
30
|
+
- puppet-fixtures
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- bin/puppet-fixtures
|
35
|
+
- lib/puppet_fixtures.rb
|
36
|
+
- lib/puppet_fixtures/tasks.rb
|
37
|
+
homepage: https://github.com/voxpupuli/puppet_fixtures
|
38
|
+
licenses:
|
39
|
+
- GPL-2.0-only
|
40
|
+
metadata:
|
41
|
+
source_code_uri: https://github.com/voxpupuli/puppet_fixtures
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.7'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '4'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubygems_version: 3.6.7
|
60
|
+
specification_version: 4
|
61
|
+
summary: Set up fixtures for Puppet testing
|
62
|
+
test_files: []
|