Class: Bolt::ModuleInstaller::Puppetfile

Inherits:
Object
  • Object
show all
Defined in:
lib/bolt/module_installer/puppetfile.rb,
lib/bolt/module_installer/puppetfile/module.rb,
lib/bolt/module_installer/puppetfile/git_module.rb,
lib/bolt/module_installer/puppetfile/forge_module.rb

Defined Under Namespace

Classes: ForgeModule, GitModule, Module

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(modules = []) ⇒ Puppetfile

Returns a new instance of Puppetfile.



15
16
17
# File 'lib/bolt/module_installer/puppetfile.rb', line 15

def initialize(modules = [])
  @modules = modules
end

Instance Attribute Details

#modulesObject (readonly)

Returns the value of attribute modules.



13
14
15
# File 'lib/bolt/module_installer/puppetfile.rb', line 13

def modules
  @modules
end

Class Method Details

.parse(path, skip_unsupported_modules: false) ⇒ Object

Loads a Puppetfile and parses its modules.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/bolt/module_installer/puppetfile.rb', line 21

def self.parse(path, skip_unsupported_modules: false)
  require 'puppetfile-resolver'

  return new unless path.exist?

  begin
    parsed = ::PuppetfileResolver::Puppetfile::Parser::R10KEval.parse(File.read(path))
  rescue StandardError => e
    raise Bolt::Error.new(
      "Unable to parse Puppetfile #{path}: #{e.message}",
      'bolt/puppetfile-parsing'
    )
  end

  unless parsed.valid?
    raise Bolt::ValidationError, <<~MSG
      Unable to parse Puppetfile #{path}:
      #{parsed.validation_errors.join("\n\n")}.
      This Puppetfile might not be managed by Bolt.
    MSG
  end

  modules = parsed.modules.each_with_object([]) do |mod, acc|
    case mod.module_type
    when :forge
      acc << ForgeModule.new(
        mod.title,
        mod.version.is_a?(String) ? mod.version[1..-1] : nil
      )
    when :git
      acc << GitModule.new(
        mod.name,
        mod.remote,
        mod.ref || mod.commit || mod.tag
      )
    else
      unless skip_unsupported_modules
        raise Bolt::ValidationError,
              "Cannot parse Puppetfile at #{path}, module '#{mod.title}' is not a "\
              "Puppet Forge or Git module."
      end
    end
  end

  new(modules)
end

Instance Method Details

#assert_satisfies(specs) ⇒ Object

Asserts that the Puppetfile satisfies the given specifications.



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
# File 'lib/bolt/module_installer/puppetfile.rb', line 93

def assert_satisfies(specs)
  unsatisfied_specs = specs.specs.reject do |spec|
    @modules.any? do |mod|
      spec.satisfied_by?(mod)
    end
  end

  versionless_mods = @modules.select { |mod| mod.is_a?(ForgeModule) && mod.version.nil? }
  command = Bolt::Util.windows? ? 'Install-BoltModule -Force' : 'bolt module install --force'

  if unsatisfied_specs.any?
    message = <<~MESSAGE.chomp
      Puppetfile does not include modules that satisfy the following specifications:

      #{unsatisfied_specs.map(&:to_hash).to_yaml.lines.drop(1).join.chomp}
      
      This Puppetfile might not be managed by Bolt. To forcibly overwrite the
      Puppetfile, run '#{command}'.
    MESSAGE

    raise Bolt::Error.new(message, 'bolt/missing-module-specs')
  end

  if versionless_mods.any?
    message = <<~MESSAGE.chomp
      Puppetfile includes Forge modules without a version requirement:
      
      #{versionless_mods.map(&:to_spec).join.chomp}
      
      This Puppetfile might not be managed by Bolt. To forcibly overwrite the
      Puppetfile, run '#{command}'.
    MESSAGE

    raise Bolt::Error.new(message, 'bolt/missing-module-version-specs')
  end
end

#write(path, moduledir = nil) ⇒ Object

Writes a Puppetfile that includes specifications for each of the modules.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/bolt/module_installer/puppetfile.rb', line 71

def write(path, moduledir = nil)
  File.open(path, 'w') do |file|
    if moduledir
      file.puts "# This Puppetfile is managed by Bolt. Do not edit."
      file.puts "# For more information, see https://pup.pt/bolt-modules"
      file.puts
      file.puts "# The following directive installs modules to the managed moduledir."
      file.puts "moduledir '#{moduledir.basename}'"
      file.puts
    end

    @modules.each { |mod| file.puts mod.to_spec }
  end
rescue SystemCallError => e
  raise Bolt::FileError.new(
    "#{e.message}: unable to write Puppetfile.",
    path
  )
end