Class: PuppetFixtures::Fixtures

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet_fixtures.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source_dir: Dir.pwd, max_thread_limit: 10) ⇒ Fixtures

Returns a new instance of Fixtures.



42
43
44
45
# File 'lib/puppet_fixtures.rb', line 42

def initialize(source_dir: Dir.pwd, max_thread_limit: 10)
  @source_dir = source_dir
  @max_thread_limit = max_thread_limit
end

Instance Attribute Details

#source_dirObject (readonly)

Returns the value of attribute source_dir.



40
41
42
# File 'lib/puppet_fixtures.rb', line 40

def source_dir
  @source_dir
end

Instance Method Details

#cleanObject



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/puppet_fixtures.rb', line 261

def clean
  repositories.each_value do |opts|
    target = opts[:target]
    logger.debug("Removing repository #{target}")
    FileUtils.rm_rf(target)
  end

  forge_modules.each_value do |opts|
    target = opts[:target]
    logger.debug("Removing forge module #{target}")
    FileUtils.rm_rf(target)
  end

  symlinks.each_value do |symlink|
    logger.debug("Removing symlink #{symlink}")
    symlink.remove
  end
end

#downloadObject



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/puppet_fixtures.rb', line 204

def download
  logger.debug("Downloading to #{module_target_dir}")
  FileUtils.mkdir_p(module_target_dir)

  if symlinks.empty?
    logger.debug('No symlinks to create')
  else
    symlinks.each_value do |symlink|
      logger.info("Creating symlink #{symlink}")
      symlink.create
    end
  end

  queue = Queue.new

  repositories.each do |remote, opts|
    queue << [:repository, remote, opts]
  end
  forge_modules.each do |remote, opts|
    queue << [:forge, remote, opts]
  end

  if queue.empty?
    logger.debug('Nothing to download')
    return
  end

  instance = self

  thread_count = [@max_thread_limit, queue.size].min
  logger.debug("Download queue size: #{queue.size}; using #{thread_count} threads")

  threads = Array.new(thread_count) do |_i|
    Thread.new do
      loop do
        begin
          type, remote, opts = queue.pop(true)
        rescue ThreadError
          break # Queue is empty
        end
        case type
        when :repository
          instance.download_repository(remote, **opts)
        when :forge
          instance.download_module(remote, **opts)
        end
      end
    end
  end

  begin
    threads.map(&:join)
  rescue Interrupt
    # pass
  end
end

#download_module(remote, ref:, target:, flags:) ⇒ Boolean

Returns true if the module was downloaded, false otherwise

Parameters:

  • remote (String)

    the remote url or namespace/name of the module to download

Returns:

  • (Boolean)

    returns true if the module was downloaded, false otherwise



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/puppet_fixtures.rb', line 170

def download_module(remote, ref:, target:, flags:)
  if File.directory?(target)
    if !ref || ref.empty?
      logger.debug("Module #{target} already up to date")
      return false
    end

    begin
      version = PuppetFixtures::Metadata.new(File.join(target, 'metadata.json')).version
    rescue ArgumentError
      logger.warn "Unable to detect module version for #{target}; updating"
    else
      if ref == version
        logger.debug("Module #{target} already up to date (#{ref})")
        return false
      else
        logger.debug("Module #{target} version #{version} != #{ref}; updating")
      end
    end
  end

  command = %w[puppet module install]
  command << '--version' << ref if ref
  command += flags if flags
  command += ['--ignore-dependencies', '--force', '--target-dir', module_target_dir, remote]

  Dir.mktmpdir do |working_dir|
    command += ['--module_working_dir', working_dir]
    raise "Failed to install module #{remote} to #{module_target_dir}" unless run_command(command)
  end

  true
end

#download_repository(remote, target:, scm:, subdir:, ref:, branch:, flags:) ⇒ Boolean

Returns true if the module was downloaded successfully, false otherwise

Parameters:

  • remote (String)

    The remote url or namespace/name of the module to download

  • scm (String)

    The SCM to use

Returns:

  • (Boolean)

    Returns true if the module was downloaded successfully, false otherwise



154
155
156
157
# File 'lib/puppet_fixtures.rb', line 154

def download_repository(remote, target:, scm:, subdir:, ref:, branch:, flags:)
  repository = PuppetFixtures::Repository.factory(scm: scm, remote: remote, target: target, branch: branch, ref: ref)
  repository.download(flags, subdir)
end

#fixture_pathObject



280
281
282
283
284
285
286
287
288
# File 'lib/puppet_fixtures.rb', line 280

def fixture_path
  if ENV['FIXTURES_YML']
    ENV['FIXTURES_YML']
  elsif File.exist?('.fixtures.yml')
    '.fixtures.yml'
  elsif File.exist?('.fixtures.yaml')
    '.fixtures.yaml'
  end
end

#fixturesObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/puppet_fixtures.rb', line 85

def fixtures
  @fixtures ||= begin
    categories = read_fixtures_file['fixtures']

    categories['symlinks'] ||= begin
       = PuppetFixtures::Metadata.new(File.join(source_dir, 'metadata.json'))
      { .name.split('-').last => source_dir }
    rescue ArgumentError
      {}
    end
    categories['forge_modules'] ||= {}
    categories['repositories'] ||= {}

    defaults = { 'target' => module_target_dir }

    %w[symlinks forge_modules repositories].to_h do |category|
      # load defaults from the `.fixtures.yml` `defaults` section
      # for the requested category and merge them into my defaults
      category_defaults = if (category_defaults = categories.dig('defaults', category))
                            defaults.merge(category_defaults)
                          else
                            defaults
                          end

      entries = categories[category].to_h do |fixture, opts|
        # convert a simple string fixture to a hash, by
        # using the string fixture as the `repo` option of the hash.
        opts = { 'repo' => opts } if opts.instance_of?(String)
        # there should be a warning or something if it's not a hash...
        next unless opts.instance_of?(Hash)

        # merge our options into the defaults to get the
        # final option list
        opts = category_defaults.merge(opts)

        next unless include_repo?(opts['puppet_version'])

        entry = validate_fixture_hash!(
          target: File.join(opts['target'], fixture),
          ref: opts['ref'] || opts['tag'],
          branch: opts['branch'],
          scm: opts.fetch('scm', 'git'),
          flags: opts['flags'],
          subdir: opts['subdir'],
        )

        case category
        when 'forge_modules'
          entry.delete(:scm)
          entry.delete(:branch)
          entry.delete(:subdir)
        when 'symlinks'
          entry = PuppetFixtures::Symlink.new(link: entry[:target], target: opts['repo'])
        end

        [opts['repo'], entry]
      end

      [category, entries]
    end
  end
end

#forge_modulesHash

Returns A hash of all the fixture forge modules.

Examples:

{
  "puppetlabs-stdlib"=>{
    "target"=>"spec/fixtures/modules/stdlib",
    "ref"=>nil,
    "branch"=>nil,
    "scm"=>nil,
    "flags"=>"--module_repository=https://myforge.example.com/",
    "subdir"=>nil,
  }
}

Returns:

  • (Hash)

    A hash of all the fixture forge modules



75
76
77
# File 'lib/puppet_fixtures.rb', line 75

def forge_modules
  @forge_modules ||= fixtures['forge_modules']
end

#module_target_dirString

Returns the spec/fixtures/modules directory in the module root folder.

Returns:

  • (String)

    the spec/fixtures/modules directory in the module root folder



161
162
163
164
# File 'lib/puppet_fixtures.rb', line 161

def module_target_dir
  # TODO: relative to source_dir?
  @module_target_dir ||= File.expand_path(File.join('spec', 'fixtures', 'modules'))
end

#repositoriesHash

Returns A hash of all the fixture repositories.

Examples:

{
  "puppetlabs-stdlib"=>{
    "repo"=>"https://gitlab.com/puppetlabs/puppet-stdlib.git",
    "ref"=>nil,
    "branch"=>"main",
    "scm"=>nil,
  }
}

Returns:

  • (Hash)

    A hash of all the fixture repositories



58
59
60
# File 'lib/puppet_fixtures.rb', line 58

def repositories
  @repositories ||= fixtures['repositories']
end

Returns A hash of symlinks specified in the fixtures file.

Returns:

  • (Hash[String, Symlink])

    A hash of symlinks specified in the fixtures file



81
82
83
# File 'lib/puppet_fixtures.rb', line 81

def symlinks
  @symlinks ||= fixtures['symlinks']
end