4
4
5
5
module PuppetlabsSpecHelper ; end
6
6
module PuppetlabsSpecHelper ::Tasks ; end
7
+
7
8
module PuppetlabsSpecHelper ::Tasks ::FixtureHelpers
8
9
# This is a helper for the self-symlink entry of fixtures.yml
9
10
def source_dir
10
11
Dir . pwd
11
12
end
12
13
14
+ # @return [String] - the name of current module
13
15
def module_name
14
16
raise ArgumentError unless File . file? ( 'metadata.json' ) && File . readable? ( 'metadata.json' )
15
17
@@ -23,18 +25,39 @@ def module_name
23
25
File . basename ( Dir . pwd ) . split ( '-' ) . last
24
26
end
25
27
26
- # cache the repositories and return a hash object
28
+ # @return [Hash] - returns a hash of all the fixture repositories
29
+ # @example
30
+ # {"puppetlabs-stdlib"=>{"target"=>"https://gitlab.com/puppetlabs/puppet-stdlib.git",
31
+ # "ref"=>nil, "branch"=>"master", "scm"=>nil,
32
+ # }}
27
33
def repositories
28
- unless @repositories
29
- @repositories = fixtures ( 'repositories' )
30
- end
31
- @repositories
34
+ @repositories ||= fixtures ( 'repositories' ) || { }
32
35
end
33
36
37
+ # @return [Hash] - returns a hash of all the fixture forge modules
38
+ # @example
39
+ # {"puppetlabs-stdlib"=>{"target"=>"spec/fixtures/modules/stdlib",
40
+ # "ref"=>nil, "branch"=>nil, "scm"=>nil,
41
+ # "flags"=>"--module_repository=https://myforge.example.com/", "subdir"=>nil}}
42
+ def forge_modules
43
+ @forge_modules ||= fixtures ( 'forge_modules' ) || { }
44
+ end
45
+
46
+ # @return [Hash] - a hash of symlinks specified in the fixtures file
47
+ def symlinks
48
+ @symlinks ||= fixtures ( 'symlinks' ) || { }
49
+ end
50
+
51
+ # @return [Hash] - returns a hash with the module name and the source directory
34
52
def auto_symlink
35
53
{ module_name => '#{source_dir}' }
36
54
end
37
55
56
+ # @return [Boolean] - true if the os is a windows system
57
+ def windows?
58
+ !!File ::ALT_SEPARATOR
59
+ end
60
+
38
61
def fixtures ( category )
39
62
fixtures_yaml = if ENV [ 'FIXTURES_YML' ]
40
63
ENV [ 'FIXTURES_YML' ]
@@ -77,7 +100,6 @@ def fixtures(category)
77
100
78
101
result = { }
79
102
if fixtures . include? ( category ) && !fixtures [ category ] . nil?
80
-
81
103
defaults = { 'target' => 'spec/fixtures/modules' }
82
104
83
105
# load defaults from the `.fixtures.yml` `defaults` section
@@ -235,6 +257,7 @@ def module_working_directory
235
257
# returns the current thread count that is currently active
236
258
# a status of false or nil means the thread completed
237
259
# so when anything else we count that as a active thread
260
+ # @return [Integer] - current thread count
238
261
def current_thread_count ( items )
239
262
active_threads = items . find_all do |_item , opts |
240
263
if opts [ :thread ]
@@ -247,79 +270,46 @@ def current_thread_count(items)
247
270
active_threads . count
248
271
end
249
272
250
- # returns the max_thread_count
251
- # because we may want to limit ssh or https connections
273
+ # @summary Set a limit on the amount threads used, defaults to 10
274
+ # MAX_FIXTURE_THREAD_COUNT can be used to set this limit
275
+ # @return [Integer] - returns the max_thread_count
252
276
def max_thread_limit
253
- unless @max_thread_limit
254
- # the default thread count is 10 but can be
255
- # raised by using environment variable MAX_FIXTURE_THREAD_COUNT
256
- @max_thread_limit = if ENV [ 'MAX_FIXTURE_THREAD_COUNT' ] . to_i > 0
257
- ENV [ 'MAX_FIXTURE_THREAD_COUNT' ] . to_i
258
- else
259
- 10 # the default
260
- end
261
- end
262
- @max_thread_limit
277
+ @max_thread_limit ||= ( ENV [ 'MAX_FIXTURE_THREAD_COUNT' ] || 10 ) . to_i
263
278
end
264
- end
265
- include PuppetlabsSpecHelper ::Tasks ::FixtureHelpers
266
279
267
- desc 'Create the fixtures directory'
268
- task :spec_prep do
269
- # Ruby only sets File::ALT_SEPARATOR on Windows and Rubys standard library
270
- # uses this to check for Windows
271
- is_windows = !!File ::ALT_SEPARATOR
272
- if is_windows
273
- begin
274
- require 'win32/dir'
275
- rescue LoadError
276
- $stderr. puts 'win32-dir gem not installed, falling back to executing mklink directly'
277
- end
278
- end
279
-
280
- # git has a race condition creating that directory, that would lead to aborted clone operations
281
- FileUtils . mkdir_p ( 'spec/fixtures/modules' )
282
-
283
- repositories . each do |remote , opts |
284
- scm = 'git'
285
- target = opts [ 'target' ]
286
- subdir = opts [ 'subdir' ]
287
- ref = opts [ 'ref' ]
288
- scm = opts [ 'scm' ] if opts [ 'scm' ]
289
- branch = opts [ 'branch' ] if opts [ 'branch' ]
290
- flags = opts [ 'flags' ]
291
- # get the current active threads that are alive
292
- count = current_thread_count ( repositories )
293
- if count < max_thread_limit
294
- logger . debug "New Thread started for #{ remote } "
295
- # start up a new thread and store it in the opts hash
296
- opts [ :thread ] = Thread . new do
297
- if valid_repo? ( scm , target , remote )
298
- update_repo ( scm , target )
299
- else
300
- clone_repo ( scm , remote , target , subdir , ref , branch , flags )
280
+ # @param items [Hash] - a hash of either repositories or forge modules
281
+ # @param [Block] - the method you wish to use to download the item
282
+ def download_items ( items )
283
+ items . each do |remote , opts |
284
+ # get the current active threads that are alive
285
+ count = current_thread_count ( items )
286
+ if count < max_thread_limit
287
+ logger . debug "New Thread started for #{ remote } "
288
+ # start up a new thread and store it in the opts hash
289
+ opts [ :thread ] = Thread . new do
290
+ yield ( remote , opts )
301
291
end
302
- revision ( scm , target , ref ) if ref
303
- remove_subdirectory ( target , subdir ) if subdir
292
+ else
293
+ # the last thread started should be the longest wait
294
+ item , item_opts = items . find_all { |_i , o | o . key? ( :thread ) } . last
295
+ logger . debug "Waiting on #{ item } "
296
+ item_opts [ :thread ] . join # wait for the thread to finish
297
+ # now that we waited lets try again
298
+ redo
304
299
end
305
- else
306
- # the last thread started should be the longest wait
307
- item , item_opts = repositories . find_all { |_i , o | o . key? ( :thread ) } . last
308
- logger . debug "Waiting on #{ item } "
309
- item_opts [ :thread ] . join # wait for the thread to finish
310
- # now that we waited lets try again
311
- redo
312
300
end
301
+ # wait for all the threads to finish
302
+ items . each { |_remote , opts | opts [ :thread ] . join }
313
303
end
314
304
315
- # wait for all the threads to finish
316
- repositories . each { | _remote , opts | opts [ :thread ] . join }
317
-
318
- fixtures ( 'symlinks' ) . each do | target , link |
305
+ # @param target [String] - the target directory
306
+ # @param link [String] - the name of the link you wish to create
307
+ # works on windows and linux
308
+ def setup_symlink ( target , link )
319
309
link = link [ 'target' ]
320
- next if File . symlink? ( link )
310
+ return if File . symlink? ( link )
321
311
logger . info ( "Creating symlink from #{ link } to #{ target } " )
322
- if is_windows
312
+ if windows?
323
313
target = File . join ( File . dirname ( link ) , target ) unless Pathname . new ( target ) . absolute?
324
314
if Dir . respond_to? ( :create_junction )
325
315
Dir . create_junction ( link , target )
@@ -331,7 +321,35 @@ def max_thread_limit
331
321
end
332
322
end
333
323
334
- fixtures ( 'forge_modules' ) . each do |remote , opts |
324
+ # @return [Boolean] - returns true if the module was downloaded successfully, false otherwise
325
+ # @param [String] - the remote url or namespace/name of the module to download
326
+ # @param [Hash] - list of options such as version, branch, ref
327
+ def download_repository ( remote , opts )
328
+ scm = 'git'
329
+ target = opts [ 'target' ]
330
+ subdir = opts [ 'subdir' ]
331
+ ref = opts [ 'ref' ]
332
+ scm = opts [ 'scm' ] if opts [ 'scm' ]
333
+ branch = opts [ 'branch' ] if opts [ 'branch' ]
334
+ flags = opts [ 'flags' ]
335
+ if valid_repo? ( scm , target , remote )
336
+ update_repo ( scm , target )
337
+ else
338
+ clone_repo ( scm , remote , target , subdir , ref , branch , flags )
339
+ end
340
+ revision ( scm , target , ref ) if ref
341
+ remove_subdirectory ( target , subdir ) if subdir
342
+ end
343
+
344
+ # @return [String] - the spec/fixtures/modules directory in the module root folder
345
+ def module_target_dir
346
+ @module_target_dir ||= File . expand_path ( 'spec/fixtures/modules' )
347
+ end
348
+
349
+ # @return [Boolean] - returns true if the module was downloaded successfully, false otherwise
350
+ # @param [String] - the remote url or namespace/name of the module to download
351
+ # @param [Hash] - list of options such as version
352
+ def download_module ( remote , opts )
335
353
ref = ''
336
354
flags = ''
337
355
if opts . instance_of? ( String )
@@ -342,34 +360,60 @@ def max_thread_limit
342
360
flags = " #{ opts [ 'flags' ] } " if opts [ 'flags' ]
343
361
end
344
362
345
- next if File . directory? ( target )
363
+ return false if File . directory? ( target )
364
+
365
+ # The PMT cannot handle multi threaded runs due to cache directory collisons
366
+ # so we randomize the directory instead.
367
+ # Does working_dir even need to be passed?
368
+ Dir . mktmpdir do |working_dir |
369
+ command = 'puppet module install' + ref + flags + ' --ignore-dependencies' \
370
+ ' --force' \
371
+ " --module_working_dir \" #{ working_dir } \" " \
372
+ " --target-dir \" #{ module_target_dir } \" \" #{ remote } \" "
346
373
347
- working_dir = module_working_directory
348
- target_dir = File . expand_path ( 'spec/fixtures/modules' )
374
+ unless system ( command )
375
+ raise "Failed to install module #{ remote } to #{ module_target_dir } "
376
+ end
377
+ end
378
+ $CHILD_STATUS. success?
379
+ end
380
+ end
349
381
350
- command = 'puppet module install' + ref + flags + \
351
- ' --ignore-dependencies' \
352
- ' --force' \
353
- " --module_working_dir \" #{ working_dir } \" " \
354
- " --target-dir \" #{ target_dir } \" \" #{ remote } \" "
382
+ include PuppetlabsSpecHelper ::Tasks ::FixtureHelpers
355
383
356
- unless system ( command )
357
- raise "Failed to install module #{ remote } to #{ target_dir } "
384
+ desc 'Create the fixtures directory'
385
+ task :spec_prep do
386
+ # Ruby only sets File::ALT_SEPARATOR on Windows and Rubys standard library
387
+ # uses this to check for Windows
388
+ if windows?
389
+ begin
390
+ require 'win32/dir'
391
+ rescue LoadError
392
+ $stderr. puts 'win32-dir gem not installed, falling back to executing mklink directly'
358
393
end
359
394
end
360
395
396
+ # git has a race condition creating that directory, that would lead to aborted clone operations
397
+ FileUtils . mkdir_p ( 'spec/fixtures/modules' )
398
+
399
+ symlinks . each { |target , link | setup_symlink ( target , link ) }
400
+
401
+ download_items ( repositories ) { |remote , opts | download_repository ( remote , opts ) }
402
+
403
+ download_items ( forge_modules ) { |remote , opts | download_module ( remote , opts ) }
404
+
361
405
FileUtils . mkdir_p ( 'spec/fixtures/manifests' )
362
406
FileUtils . touch ( 'spec/fixtures/manifests/site.pp' )
363
407
end
364
408
365
409
desc 'Clean up the fixtures directory'
366
410
task :spec_clean do
367
- fixtures ( ' repositories' ) . each do |_remote , opts |
411
+ repositories . each do |_remote , opts |
368
412
target = opts [ 'target' ]
369
413
FileUtils . rm_rf ( target )
370
414
end
371
415
372
- fixtures ( ' forge_modules' ) . each do |_remote , opts |
416
+ forge_modules . each do |_remote , opts |
373
417
target = opts [ 'target' ]
374
418
FileUtils . rm_rf ( target )
375
419
end
0 commit comments