Class: PDK::Module::Build

Inherits:
Object
  • Object
show all
Defined in:
lib/pdk/module/build.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Build

Returns a new instance of Build.



18
19
20
21
# File 'lib/pdk/module/build.rb', line 18

def initialize(options = {})
  @module_dir = File.expand_path(options[:module_dir] || Dir.pwd)
  @target_dir = File.expand_path(options[:'target-dir'] || File.join(module_dir, 'pkg'))
end

Instance Attribute Details

#module_dirObject (readonly)

Returns the value of attribute module_dir.



15
16
17
# File 'lib/pdk/module/build.rb', line 15

def module_dir
  @module_dir
end

#target_dirObject (readonly)

Returns the value of attribute target_dir.



16
17
18
# File 'lib/pdk/module/build.rb', line 16

def target_dir
  @target_dir
end

Class Method Details

.invoke(options = {}) ⇒ Object



11
12
13
# File 'lib/pdk/module/build.rb', line 11

def self.invoke(options = {})
  new(options).build
end

Instance Method Details

#buildString

Build a module package from a module directory.

Returns:

  • (String)

    The path to the built package file.



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/pdk/module/build.rb', line 39

def build
  cleanup_module
  create_build_dir

  stage_module_in_build_dir
  build_package

  package_file
ensure
  cleanup_build_dir
end

#build_dirObject

Return the path to the temporary build directory, which will be placed inside the target directory and match the release name (see #release_name).



65
66
67
# File 'lib/pdk/module/build.rb', line 65

def build_dir
  @build_dir ||= File.join(target_dir, release_name)
end

#build_packageObject

Creates a gzip compressed tarball of the build directory.

If the destination package already exists, it will be removed before creating the new tarball.

Returns:

  • nil.



172
173
174
175
176
177
178
179
180
# File 'lib/pdk/module/build.rb', line 172

def build_package
  FileUtils.rm_f(package_file)

  Dir.chdir(target_dir) do
    Zlib::GzipWriter.open(package_file) do |package_fd|
      Minitar.pack(release_name, package_fd)
    end
  end
end

#cleanup_build_dirObject

Remove the temporary build directory and all its contents from disk.

Returns:

  • nil.



82
83
84
# File 'lib/pdk/module/build.rb', line 82

def cleanup_build_dir
  FileUtils.rm_rf(build_dir, secure: true)
end

#cleanup_moduleObject

Clean up any files created during use of the PDK that shouldn’t be part of the built module (e.g. test fixtures).

Returns:

  • nil



90
91
92
93
94
95
# File 'lib/pdk/module/build.rb', line 90

def cleanup_module
  PDK::Util::Bundler.ensure_bundle!
  PDK::Util::Bundler.ensure_binstubs!('rake')

  PDK::Test::Unit.tear_down
end

#create_build_dirObject

Create a temporary build directory where the files to be included in the package will be staged before building the tarball.

If the directory already exists, remove it first.



73
74
75
76
77
# File 'lib/pdk/module/build.rb', line 73

def create_build_dir
  cleanup_build_dir

  FileUtils.mkdir_p(build_dir)
end

#ignore_fileString

Select the most appropriate ignore file in the module directory.

In order of preference, we first try ‘.pdkignore`, then `.pmtignore` and finally `.gitignore`.

Returns:

  • (String)

    The path to the file containing the patterns of file paths to ignore.



189
190
191
192
193
194
195
# File 'lib/pdk/module/build.rb', line 189

def ignore_file
  @ignore_file ||= [
    File.join(module_dir, '.pdkignore'),
    File.join(module_dir, '.pmtignore'),
    File.join(module_dir, '.gitignore'),
  ].find { |file| File.file?(file) && File.readable?(file) }
end

#ignored_filesPathSpec

Instantiate a new PathSpec class and populate it with the pattern(s) of files to be ignored.

Returns:

  • (PathSpec)

    The populated ignore path matcher.



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/pdk/module/build.rb', line 201

def ignored_files
  @ignored_files ||=
    begin
      ignored = if ignore_file.nil?
                  PathSpec.new
                else
                  fd = File.open(ignore_file, 'rb:UTF-8')
                  data = fd.read
                  fd.close

                  PathSpec.new(data)
                end

      if File.realdirpath(target_dir).start_with?(File.realdirpath(module_dir))
        ignored = ignored.add("\/#{File.basename(target_dir)}\/")
      end

      ignored
    end
end

#ignored_path?(path) ⇒ Boolean

Check if the given path matches one of the patterns listed in the ignore file.

Parameters:

  • path (String)

    The path to be checked.

Returns:

  • (Boolean)

    true if the path matches and should be ignored.



144
145
146
147
148
# File 'lib/pdk/module/build.rb', line 144

def ignored_path?(path)
  path = path.to_s + '/' if File.directory?(path)

  !ignored_files.match_paths([path], module_dir).empty?
end

#metadataHash{String => Object}

Read and parse the values from metadata.json for the module that is being built.

Returns:

  • (Hash{String => Object})

    The hash of metadata values.



27
28
29
# File 'lib/pdk/module/build.rb', line 27

def 
  @metadata ||= PDK::Module::Metadata.from_file(File.join(module_dir, 'metadata.json')).data
end

#module_pdk_compatible?Boolean

Check if the module is PDK Compatible. If not, then prompt the user if they want to run PDK Convert.

Returns:

  • (Boolean)


59
60
61
# File 'lib/pdk/module/build.rb', line 59

def module_pdk_compatible?
  ['pdk-version', 'template-url'].any? { |key| .key?(key) }
end

#package_already_exists?Boolean

Verify if there is an existing package in the target directory and prompts the user if they want to overwrite it.

Returns:

  • (Boolean)


53
54
55
# File 'lib/pdk/module/build.rb', line 53

def package_already_exists?
  File.exist? package_file
end

#package_fileObject

Return the path where the built package file will be written to.



32
33
34
# File 'lib/pdk/module/build.rb', line 32

def package_file
  @package_file ||= File.join(target_dir, "#{release_name}.tar.gz")
end

#release_nameString

Combine the module name and version into a Forge-compatible dash separated string.

Returns:

  • (String)

    The module name and version, joined by a dash.



101
102
103
104
105
106
# File 'lib/pdk/module/build.rb', line 101

def release_name
  @release_name ||= [
    ['name'],
    ['version'],
  ].join('-')
end

#stage_module_in_build_dirObject

Iterate through all the files and directories in the module and stage them into the temporary build directory (unless ignored).

Returns:

  • nil



112
113
114
115
116
117
118
# File 'lib/pdk/module/build.rb', line 112

def stage_module_in_build_dir
  Find.find(module_dir) do |path|
    next if path == module_dir

    ignored_path?(path) ? Find.prune : stage_path(path)
  end
end

#stage_path(path) ⇒ Object

Stage a file or directory from the module into the build directory.

Parameters:

  • path (String)

    The path to the file or directory.

Returns:

  • nil.



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/pdk/module/build.rb', line 125

def stage_path(path)
  relative_path = Pathname.new(path).relative_path_from(Pathname.new(module_dir))
  dest_path = File.join(build_dir, relative_path)

  if File.directory?(path)
    FileUtils.mkdir_p(dest_path, mode: File.stat(path).mode)
  elsif File.symlink?(path)
    warn_symlink(path)
  else
    FileUtils.cp(path, dest_path, preserve: true)
  end
end

Warn the user about a symlink that would have been included in the built package.

Parameters:

  • path (String)

    The relative or absolute path to the symlink.

Returns:

  • nil.



156
157
158
159
160
161
162
163
164
# File 'lib/pdk/module/build.rb', line 156

def warn_symlink(path)
  symlink_path = Pathname.new(path)
  module_path = Pathname.new(module_dir)

  PDK.logger.warn _('Symlinks in modules are not supported and will not be included in the package. Please investigate symlink %{from} -> %{to}.') % {
    from: symlink_path.relative_path_from(module_path),
    to:   symlink_path.realpath.relative_path_from(module_path),
  }
end