diff --git a/functions/dir_clean.pp b/functions/dir_clean.pp new file mode 100644 index 0000000..b87d5aa --- /dev/null +++ b/functions/dir_clean.pp @@ -0,0 +1,20 @@ +# @summary Take a path and normalise it to its Unix form. +# Instead of having to deal with the different separators between Unix and Windows this +# function instead formats Windows paths a equivalent Unix like path. +# +# @param dir The path to clean +# @return Stdlib::Unixpath The cleaned path +# @example clean Unix paths to return `/tmp/test/libs` (i.e. noop) +# extlib::dir_clean('/tmp/test/libs') +# @example Clean Windows paths to return `/c/test/libs` +# extlib::dir_clean('c:\\'test\\libs') +# +# $dir is defined as a Variant to support cleaning 'c:' which is not a valid +# Stdlib::Absolutepath +function extlib::dir_clean(Variant[Stdlib::Absolutepath, Pattern[/\A[a-zA-Z]:\z/]] $dir) >> Stdlib::Unixpath { + $dir ? { + Stdlib::Windowspath => $dir.regsubst('^([a-zA-Z]):', '/\\1').regsubst('\\\\', '/', 'G'), + Pattern[/\A[a-z]:\z/] => $dir.regsubst('^([a-zA-Z]):', '/\\1'), + default => $dir, + } +} diff --git a/functions/dir_split.pp b/functions/dir_split.pp index b8598b2..c74fe35 100644 --- a/functions/dir_split.pp +++ b/functions/dir_split.pp @@ -1,26 +1,19 @@ # @summary Splits the given directory or directories into individual paths. # # Use this function when you need to split a absolute path into multiple absolute paths # that all descend from the given path. # # @param dirs [Variant[Stdlib::Absolutepath, Array[Stdlib::Absolutepath]]] - either an absolute path or a array of absolute paths. # @return [Array[String]] - an array of absolute paths after being cut into individual paths. # @example calling the function # extlib::dir_split('/opt/puppetlabs') => ['/opt', '/opt/puppetlabs'] -function extlib::dir_split(Variant[Stdlib::Absolutepath, Array[Stdlib::Absolutepath]] *$values) >> Array[String] { - $dirs = $values.flatten.unique - $sep = extlib::file_separator() - - $dirs_array = $dirs.map | Stdlib::Absolutepath $dir | { - $dir.split(shell_escape($sep)).reduce([]) |Array $acc, $value | { - $counter = $acc.length - 1 - $acc_value = ($acc[$counter] =~ Undef) ? { true => '', false => $acc[$counter] } - unless empty($value) { - $acc + extlib::path_join([$acc_value, $value]) - } else { - $acc +function extlib::dir_split(Variant[Stdlib::Absolutepath, Array[Stdlib::Absolutepath]] *$dirs) >> Array[String] { + [$dirs].flatten.unique.map | Stdlib::Absolutepath $dir | { + extlib::dir_clean($dir).split('/').reduce([]) |Array $memo, $value | { + empty($value) ? { + true => $memo, + default => $memo + "${memo[-1]}/${value}", } } - } - $dirs_array.flatten.unique + }.flatten.unique } diff --git a/functions/path_join.pp b/functions/path_join.pp index 7513de2..80c6c8d 100644 --- a/functions/path_join.pp +++ b/functions/path_join.pp @@ -1,30 +1,19 @@ -# @summary Take one or more paths and join them together using the os specific separator. -# Because in how windows uses a different separator this function -# will format a windows path into a equilivent unix like path. This type of unix like -# path will work on windows. +# @summary Take one or more paths and join them together +# This function will format a windows paths into equivalent unix like paths. +# This type of unix like path should work on windows. # # @param dirs Joins two or more directories by file separator. # @return [Stdlib::Absolutepath] The joined path # @example Joining Unix paths to return `/tmp/test/libs` # extlib::path_join(['/tmp', 'test', 'libs']) # @example Joining Windows paths to return `/c/test/libs` # extlib::path_join(['c:', 'test', 'libs']) -function extlib::path_join(Variant[String, Array[String]] *$values) >> Stdlib::Absolutepath { - $unix_sep = '/' - $sep_regex = /\/|\\/ - $dirs = $values.flatten - $first_value = $dirs[0] - # when first value is absolute path, append all other elements - # by breaking the path into pieces first, then joining - if $first_value =~ Stdlib::Absolutepath { - $fixed_dirs = $first_value.split($sep_regex) + $dirs.delete($first_value) - } else { - $fixed_dirs = $dirs - } - $no_empty_dirs = $fixed_dirs.filter |$dir| { !empty($dir) } - $dirs_without_sep = $no_empty_dirs.map |String $dir | { - # remove : and file separator - $dir.regsubst($sep_regex, '').regsubst(':', '') - } - join([$unix_sep,$dirs_without_sep.join($unix_sep)]) +function extlib::path_join(Variant[String, Array[String]] *$dirs) >> Stdlib::Absolutepath { + [$dirs].flatten.map |$index, $dir| { + $index ? { + # only allow paths in the first element (should we enforce this more strictly?) + 0 => extlib::dir_clean($dir), + default => $dir, + } + }.join('/') } diff --git a/spec/functions/extlib/dir_clean_spec.rb b/spec/functions/extlib/dir_clean_spec.rb new file mode 100644 index 0000000..fc800f6 --- /dev/null +++ b/spec/functions/extlib/dir_clean_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe 'extlib::dir_clean' do + describe 'check functions' do + let(:dirs) do + { + 'c:' => '/c', + 'c:\windows\puppetlabs\puppet\embedded\gems' => '/c/windows/puppetlabs/puppet/embedded/gems', + '/opt/puppetlabs/puppet/embedded/bin/gems' => '/opt/puppetlabs/puppet/embedded/bin/gems', + } + end + it 'valid dirs' do + dirs.each_pair do |input, output| + is_expected.to run.with_params(input).and_return(output) + end + end + end +end