lib/pdk/module/templatedir.rb in pdk-akerl-1.9.1.1 vs lib/pdk/module/templatedir.rb in pdk-akerl-1.14.0.1
- old
+ new
@@ -1,25 +1,19 @@
-require 'yaml'
-require 'deep_merge'
-require 'pdk/util'
-require 'pdk/util/git'
-require 'pdk/cli/errors'
-require 'pdk/template_file'
-
module PDK
module Module
class TemplateDir
attr_accessor :module_metadata
+ attr_reader :uri
# Initialises the TemplateDir object with the path or URL to the template
# and the block of code to run to be run while the template is available.
#
# The template directory is only guaranteed to be available on disk
# within the scope of the block passed to this method.
#
- # @param path_or_url [String] The path to a directory to use as the
- # template or a URL to a git repository.
+ # @param uri [PDK::Util::TemplateURI] The path to a directory to use as the
+ # template or a URI to a git repository.
# @param module_metadata [Hash] A Hash containing the module metadata.
# Defaults to an empty Hash.
# @yieldparam self [PDK::Module::TemplateDir] The initialised object with
# the template available on disk.
#
@@ -35,21 +29,39 @@
# @raise [ArgumentError] If no block is given to this method.
# @raise [PDK::CLI::FatalError] (see #clone_repo)
# @raise [ArgumentError] (see #validate_module_template!)
#
# @api public
- def initialize(path_or_url, module_metadata = {}, init = false)
+ def initialize(uri, module_metadata = {}, init = false)
+ require 'pdk/analytics'
+ require 'pdk/util/template_uri'
+ require 'pdk/util/git'
+
unless block_given?
raise ArgumentError, _('%{class_name} must be initialized with a block.') % { class_name: self.class.name }
end
+ unless uri.is_a? PDK::Util::TemplateURI
+ raise ArgumentError, _('PDK::Module::TemplateDir.new must be initialized with a PDK::Util::TemplateURI, got a %{uri_type}') % { uri_type: uri.class }
+ end
- if PDK::Util::Git.repo?(path_or_url)
- @path = self.class.clone_template_repo(path_or_url)
- @repo = path_or_url
+ if PDK::Util::Git.repo?(uri.git_remote)
+ # This is either a bare local repo or a remote. either way it needs cloning.
+ @path = clone_template_repo(uri)
+ temp_dir_clone = true
else
- @path = path_or_url
+ # if it is a local path & non-bare repo then we can use it directly.
+ # Still have to check the branch.
+ @path = uri.shell_path
+ # We don't do a checkout of local-path repos. There are lots of edge
+ # cases or user un-expectations.
+ if PDK::Util::Git.work_tree?(@path)
+ PDK.logger.warn _("Repository '%{repo}' has a work-tree; skipping git reset.") % {
+ repo: @path,
+ }
+ end
end
+ @uri = uri
@init = init
@moduleroot_dir = File.join(@path, 'moduleroot')
@moduleroot_init = File.join(@path, 'moduleroot_init')
@dirs = [@moduleroot_dir]
@@ -58,15 +70,19 @@
validate_module_template!
@module_metadata = module_metadata
+ template_type = uri.default? ? 'default' : 'custom'
+ PDK.analytics.event('TemplateDir', 'initialize', label: template_type)
+
yield self
ensure
# If we cloned a git repo to get the template, remove the clone once
# we're done with it.
- if @repo
+ if temp_dir_clone
+ require 'fileutils'
FileUtils.remove_dir(@path)
end
end
# Retrieve identifying metadata for the template.
@@ -76,20 +92,17 @@
#
# @return [Hash{String => String}] A hash of identifying metadata.
#
# @api public
def metadata
- result = {
- 'pdk-version' => PDK::Util::Version.version_string,
- }
+ require 'pdk/util/version'
- result['template-url'] = @repo ? @repo : @path
-
- ref_result = PDK::Util::Git.git('--git-dir', File.join(@path, '.git'), 'describe', '--all', '--long', '--always')
- result['template-ref'] = ref_result[:stdout].strip if ref_result[:exit_code].zero?
-
- result
+ {
+ 'pdk-version' => PDK::Util::Version.version_string,
+ 'template-url' => uri.metadata_format,
+ 'template-ref' => cache_template_ref(@path),
+ }
end
# Loop through the files in the template, yielding each rendered file to
# the supplied block.
#
@@ -102,29 +115,36 @@
#
# @return [void]
#
# @api public
def render
+ require 'pdk/template_file'
+
PDK::Module::TemplateDir.files_in_template(@dirs).each do |template_file, template_loc|
template_file = template_file.to_s
PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
dest_path = template_file.sub(%r{\.erb\Z}, '')
config = config_for(dest_path)
- dest_status = :manage
+ dest_status = if template_loc.start_with?(@moduleroot_init)
+ :init
+ else
+ :manage
+ end
+
if config['unmanaged']
dest_status = :unmanage
elsif config['delete']
dest_status = :delete
else
begin
dest_content = PDK::TemplateFile.new(File.join(template_loc, template_file), configs: config, template_dir: self).render
- rescue => e
+ rescue => error
error_msg = _(
"Failed to render template '%{template}'\n" \
'%{exception}: %{message}',
- ) % { template: template_file, exception: e.class, message: e.message }
+ ) % { template: template_file, exception: error.class, message: error.message }
raise PDK::CLI::FatalError, error_msg
end
end
yield dest_path, dest_content, dest_status
@@ -145,17 +165,19 @@
#
# @api public
def object_template_for(object_type)
object_path = File.join(@object_dir, "#{object_type}.erb")
type_path = File.join(@object_dir, "#{object_type}_type.erb")
+ device_path = File.join(@object_dir, "#{object_type}_device.erb")
spec_path = File.join(@object_dir, "#{object_type}_spec.erb")
type_spec_path = File.join(@object_dir, "#{object_type}_type_spec.erb")
if File.file?(object_path) && File.readable?(object_path)
result = { object: object_path }
result[:type] = type_path if File.file?(type_path) && File.readable?(type_path)
result[:spec] = spec_path if File.file?(spec_path) && File.readable?(spec_path)
+ result[:device] = device_path if File.file?(device_path) && File.readable?(device_path)
result[:type_spec] = type_spec_path if File.file?(type_spec_path) && File.readable?(type_spec_path)
result
else
nil
end
@@ -185,10 +207,12 @@
#
# @api private
def validate_module_template!
# rubocop:disable Style/GuardClause
unless File.directory?(@path)
+ require 'pdk/util'
+
if PDK::Util.package_install? && File.fnmatch?(File.join(PDK::Util.package_cachedir, '*'), @path)
raise ArgumentError, _('The built-in template has substantially changed. Please run "pdk convert" on your module to continue.')
else
raise ArgumentError, _("The specified template '%{path}' is not a directory.") % { path: @path }
end
@@ -201,10 +225,11 @@
unless File.directory?(@moduleroot_init)
# rubocop:disable Metrics/LineLength
raise ArgumentError, _("The template at '%{path}' does not contain a 'moduleroot_init/' directory, which indicates you are using an older style of template. Before continuing please use the --template-url flag when running the pdk new commands to pass a new style template.") % { path: @path }
# rubocop:enable Metrics/LineLength Style/GuardClause
end
+ # rubocop:enable Style/GuardClause
end
# Get a list of template files in the template directory.
#
# @return [Hash{String=>String}] A hash of key file names and
@@ -237,24 +262,42 @@
# @return [Hash] The data that will be available to the template via the
# `@configs` instance variable.
#
# @api private
def config_for(dest_path, sync_config_path = nil)
+ require 'pdk/util'
+ require 'pdk/analytics'
+
module_root = PDK::Util.module_root
sync_config_path ||= File.join(module_root, '.sync.yml') unless module_root.nil?
config_path = File.join(@path, 'config_defaults.yml')
if @config.nil?
+ require 'deep_merge'
conf_defaults = read_config(config_path)
- sync_config = read_config(sync_config_path) unless sync_config_path.nil?
+ @sync_config = read_config(sync_config_path) unless sync_config_path.nil?
@config = conf_defaults
- @config.deep_merge!(sync_config, knockout_prefix: '---') unless sync_config.nil?
+ @config.deep_merge!(@sync_config, knockout_prefix: '---') unless @sync_config.nil?
end
file_config = @config.fetch(:global, {})
file_config['module_metadata'] = @module_metadata
file_config.merge!(@config.fetch(dest_path, {})) unless dest_path.nil?
- file_config.merge!(@config)
+ file_config.merge!(@config).tap do |c|
+ if uri.default?
+ file_value = if c['unmanaged']
+ 'unmanaged'
+ elsif c['delete']
+ 'deleted'
+ elsif @sync_config && @sync_config.key?(dest_path)
+ 'customized'
+ else
+ 'default'
+ end
+
+ PDK.analytics.event('TemplateDir', 'file', label: dest_path, value: file_value)
+ end
+ end
end
# Generates a hash of data from a given yaml file location.
#
# @param loc [String] The path of the yaml config file.
@@ -265,10 +308,12 @@
# @return [Hash] The data that has been read in from the given yaml file.
#
# @api private
def read_config(loc)
if File.file?(loc) && File.readable?(loc)
+ require 'yaml'
+
begin
YAML.safe_load(File.read(loc), [], [], true)
rescue Psych::SyntaxError => e
PDK.logger.warn _("'%{file}' is not a valid YAML file: %{problem} %{context} at line %{line} column %{column}") % {
file: loc,
@@ -288,34 +333,57 @@
#
# @raise [PDK::CLI::FatalError] If unable to clone the given origin_repo into a tempdir.
# @raise [PDK::CLI::FatalError] If reset HEAD of the cloned repo to desired ref.
#
# @api private
- def self.clone_template_repo(origin_repo)
+ def clone_template_repo(uri)
# @todo When switching this over to using rugged, cache the cloned
# template repo in `%AppData%` or `$XDG_CACHE_DIR` and update before
# use.
+ require 'pdk/util'
+ require 'pdk/util/git'
+
temp_dir = PDK::Util.make_tmpdir_name('pdk-templates')
- git_ref = (origin_repo == PDK::Util.default_template_url) ? PDK::Util.default_template_ref : 'origin/master'
+ origin_repo = uri.git_remote
+ git_ref = uri.git_ref
clone_result = PDK::Util::Git.git('clone', origin_repo, temp_dir)
if clone_result[:exit_code].zero?
- Dir.chdir(temp_dir) do
- reset_result = PDK::Util::Git.git('reset', '--hard', git_ref)
- unless reset_result[:exit_code].zero?
- PDK.logger.error reset_result[:stdout]
- PDK.logger.error reset_result[:stderr]
- raise PDK::CLI::FatalError, _("Unable to set HEAD of git repository at '%{repo}' to ref:'%{ref}'.") % { repo: temp_dir, ref: git_ref }
- end
- end
+ checkout_template_ref(temp_dir, git_ref)
else
PDK.logger.error clone_result[:stdout]
PDK.logger.error clone_result[:stderr]
raise PDK::CLI::FatalError, _("Unable to clone git repository at '%{repo}' into '%{dest}'.") % { repo: origin_repo, dest: temp_dir }
end
PDK::Util.canonical_path(temp_dir)
+ end
+
+ # @api private
+ def checkout_template_ref(path, ref)
+ require 'pdk/util/git'
+
+ if PDK::Util::Git.work_dir_clean?(path)
+ Dir.chdir(path) do
+ full_ref = PDK::Util::Git.ls_remote(path, ref)
+ cache_template_ref(path, full_ref)
+ reset_result = PDK::Util::Git.git('reset', '--hard', full_ref)
+ return if reset_result[:exit_code].zero?
+
+ PDK.logger.error reset_result[:stdout]
+ PDK.logger.error reset_result[:stderr]
+ raise PDK::CLI::FatalError, _("Unable to checkout '%{ref}' of git repository at '%{path}'.") % { ref: ref, path: path }
+ end
+ else
+ PDK.logger.warn _("Uncommitted changes found when attempting to checkout '%{ref}' of git repository at '%{path}'; skipping git reset.") % { ref: ref, path: path }
+ end
+ end
+
+ def cache_template_ref(path, ref = nil)
+ require 'pdk/util/git'
+
+ @template_ref ||= PDK::Util::Git.describe(File.join(path, '.git'), ref)
end
end
end
end