puppet 6.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/Gemfile.lock +20 -20
- data/Guardfile.example +76 -0
- data/LICENSE +189 -4
- data/README.md +3 -3
- data/Rakefile +5 -2
- data/ext/solaris/smf/svc-puppetd +8 -1
- data/ext/solaris/smf/svc-puppetmasterd +8 -1
- data/lib/puppet/application/apply.rb +100 -59
- data/lib/puppet/application/cert.rb +4 -114
- data/lib/puppet/application/device.rb +48 -32
- data/lib/puppet/application/script.rb +1 -1
- data/lib/puppet/application/ssl.rb +135 -51
- data/lib/puppet/application.rb +5 -0
- data/lib/puppet/configurer.rb +2 -3
- data/lib/puppet/defaults.rb +33 -49
- data/lib/puppet/etc.rb +20 -0
- data/lib/puppet/face/config.rb +3 -3
- data/lib/puppet/face/key.rb +1 -1
- data/lib/puppet/face/node/clean.rb +0 -1
- data/lib/puppet/feature/base.rb +1 -1
- data/lib/puppet/file_bucket/dipper.rb +1 -1
- data/lib/puppet/file_serving/fileset.rb +1 -1
- data/lib/puppet/functions/abs.rb +1 -1
- data/lib/puppet/functions/new.rb +1 -1
- data/lib/puppet/module/task.rb +29 -38
- data/lib/puppet/pal/catalog_compiler.rb +96 -0
- data/lib/puppet/pal/compiler.rb +221 -0
- data/lib/puppet/pal/function_signature.rb +52 -0
- data/lib/puppet/pal/json_catalog_encoder.rb +67 -0
- data/lib/puppet/pal/pal_api.rb +15 -0
- data/lib/puppet/pal/pal_impl.rb +523 -0
- data/lib/puppet/pal/plan_signature.rb +71 -0
- data/lib/puppet/pal/script_compiler.rb +71 -0
- data/lib/puppet/pal/task_signature.rb +58 -0
- data/lib/puppet/parser/catalog_compiler.rb +24 -0
- data/lib/puppet/parser/compiler.rb +3 -1
- data/lib/puppet/parser/functions/generate.rb +7 -6
- data/lib/puppet/plugins/configuration.rb +5 -1
- data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +3 -1
- data/lib/puppet/pops/evaluator/deferred_resolver.rb +3 -0
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -1
- data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -3
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +2 -2
- data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +19 -10
- data/lib/puppet/pops/loader/task_instantiator.rb +13 -70
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
- data/lib/puppet/pops/parser/lexer2.rb +1 -1
- data/lib/puppet/pops/pcore.rb +10 -33
- data/lib/puppet/pops/serialization/to_data_converter.rb +9 -1
- data/lib/puppet/pops/serialization.rb +1 -0
- data/lib/puppet/pops/types/p_timespan_type.rb +2 -2
- data/lib/puppet/pops/types/string_converter.rb +18 -4
- data/lib/puppet/pops/validation/checker4_0.rb +17 -2
- data/lib/puppet/provider/exec.rb +59 -57
- data/lib/puppet/provider/group/aix.rb +18 -2
- data/lib/puppet/provider/group/windows_adsi.rb +7 -3
- data/lib/puppet/provider/nameservice.rb +1 -25
- data/lib/puppet/provider/package/dnf.rb +2 -0
- data/lib/puppet/provider/package/pkgng.rb +37 -21
- data/lib/puppet/provider/package/portage.rb +2 -2
- data/lib/puppet/provider/package/windows/exe_package.rb +16 -10
- data/lib/puppet/provider/package/windows/msi_package.rb +8 -0
- data/lib/puppet/provider/package/windows/package.rb +9 -1
- data/lib/puppet/provider/package/windows.rb +2 -2
- data/lib/puppet/provider/package/yum.rb +1 -1
- data/lib/puppet/provider/parsedfile.rb +25 -4
- data/lib/puppet/provider/service/launchd.rb +19 -3
- data/lib/puppet/provider/service/smf.rb +54 -0
- data/lib/puppet/provider/service/systemd.rb +19 -0
- data/lib/puppet/provider/service/upstart.rb +1 -0
- data/lib/puppet/provider/service/windows.rb +22 -5
- data/lib/puppet/provider/user/aix.rb +48 -2
- data/lib/puppet/provider/user/useradd.rb +2 -10
- data/lib/puppet/provider/user/windows_adsi.rb +9 -1
- data/lib/puppet/resource/catalog.rb +1 -5
- data/lib/puppet/resource.rb +3 -1
- data/lib/puppet/ssl/host.rb +26 -16
- data/lib/puppet/syntax_checkers/epp.rb +34 -0
- data/lib/puppet/syntax_checkers/pp.rb +34 -0
- data/lib/puppet/transaction/event_manager.rb +13 -1
- data/lib/puppet/transaction/persistence.rb +1 -1
- data/lib/puppet/transaction/resource_harness.rb +3 -1
- data/lib/puppet/type/group.rb +29 -1
- data/lib/puppet/type/package.rb +5 -1
- data/lib/puppet/type/resources.rb +12 -2
- data/lib/puppet/type/schedule.rb +7 -0
- data/lib/puppet/type/service.rb +12 -0
- data/lib/puppet/type/user.rb +5 -2
- data/lib/puppet/type.rb +6 -0
- data/lib/puppet/util/command_line.rb +2 -3
- data/lib/puppet/util/execution.rb +15 -1
- data/lib/puppet/util/filetype.rb +56 -8
- data/lib/puppet/util/log/destinations.rb +3 -2
- data/lib/puppet/util/logging.rb +3 -2
- data/lib/puppet/util/posix.rb +15 -0
- data/lib/puppet/util/selinux.rb +1 -1
- data/lib/puppet/util/storage.rb +12 -0
- data/lib/puppet/util/windows/adsi.rb +79 -2
- data/lib/puppet/util/windows/api_types.rb +1 -1
- data/lib/puppet/util/windows/process.rb +23 -3
- data/lib/puppet/util/windows/registry.rb +29 -5
- data/lib/puppet/util/windows/security.rb +14 -0
- data/lib/puppet/util/windows/service.rb +294 -74
- data/lib/puppet/util/windows/user.rb +3 -5
- data/lib/puppet/util.rb +7 -3
- data/lib/puppet/version.rb +1 -1
- data/lib/puppet.rb +1 -0
- data/lib/puppet_pal.rb +5 -1099
- data/locales/ja/puppet.po +952 -986
- data/locales/puppet.pot +592 -347
- data/man/man5/puppet.conf.5 +26 -31
- data/man/man8/puppet-agent.8 +1 -1
- data/man/man8/puppet-apply.8 +1 -1
- data/man/man8/puppet-catalog.8 +1 -1
- data/man/man8/puppet-config.8 +4 -4
- data/man/man8/puppet-describe.8 +1 -1
- data/man/man8/puppet-device.8 +23 -19
- data/man/man8/puppet-doc.8 +1 -1
- data/man/man8/puppet-epp.8 +1 -1
- data/man/man8/puppet-facts.8 +1 -1
- data/man/man8/puppet-filebucket.8 +1 -1
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +1 -1
- data/man/man8/puppet-key.8 +2 -2
- data/man/man8/puppet-lookup.8 +1 -1
- data/man/man8/puppet-man.8 +1 -1
- data/man/man8/puppet-module.8 +1 -1
- data/man/man8/puppet-node.8 +1 -1
- data/man/man8/puppet-parser.8 +1 -1
- data/man/man8/puppet-plugin.8 +1 -1
- data/man/man8/puppet-report.8 +1 -1
- data/man/man8/puppet-resource.8 +1 -1
- data/man/man8/puppet-script.8 +1 -1
- data/man/man8/puppet-ssl.8 +26 -3
- data/man/man8/puppet-status.8 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load.rb +11 -0
- data/spec/fixtures/unit/provider/package/pkgng/pkg.query +7 -1
- data/spec/fixtures/unit/provider/package/pkgng/pkg.query.zsh +1 -0
- data/spec/fixtures/unit/provider/service/smf/svcs_fmri.out +6 -0
- data/spec/fixtures/unit/provider/service/smf/svcs_multiple_fmris.out +13 -0
- data/spec/integration/application/apply_spec.rb +4 -1
- data/spec/integration/parser/collection_spec.rb +4 -8
- data/spec/integration/provider/service/windows_spec.rb +5 -5
- data/spec/integration/ssl/key_spec.rb +0 -4
- data/spec/integration/transaction_spec.rb +559 -0
- data/spec/integration/type/file_spec.rb +6 -6
- data/spec/integration/util/windows/registry_spec.rb +39 -0
- data/spec/integration/util/windows/security_spec.rb +10 -7
- data/spec/integration/util/windows/user_spec.rb +37 -17
- data/spec/lib/puppet/test_ca.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/agent_spec.rb +2 -2
- data/spec/unit/application/apply_spec.rb +55 -2
- data/spec/unit/application/device_spec.rb +10 -7
- data/spec/unit/application/face_base_spec.rb +1 -1
- data/spec/unit/application/lookup_spec.rb +2 -1
- data/spec/unit/application/ssl_spec.rb +178 -109
- data/spec/unit/application_spec.rb +29 -11
- data/spec/unit/configurer/downloader_spec.rb +1 -1
- data/spec/unit/configurer_spec.rb +16 -5
- data/spec/unit/etc_spec.rb +25 -0
- data/spec/unit/face/node_spec.rb +1 -3
- data/spec/unit/face/parser_spec.rb +15 -0
- data/spec/unit/file_serving/fileset_spec.rb +11 -11
- data/spec/unit/functions/logging_spec.rb +10 -3
- data/spec/unit/indirector/catalog/json_spec.rb +9 -3
- data/spec/unit/indirector/yaml_spec.rb +1 -1
- data/spec/unit/network/http/connection_spec.rb +2 -2
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +36 -0
- data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +22 -4
- data/spec/unit/pops/loaders/loader_spec.rb +9 -17
- data/spec/unit/pops/loaders/loaders_spec.rb +48 -0
- data/spec/unit/pops/loaders/module_loaders_spec.rb +7 -7
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
- data/spec/unit/pops/serialization/to_from_hr_spec.rb +9 -0
- data/spec/unit/pops/types/p_timespan_type_spec.rb +22 -0
- data/spec/unit/pops/types/p_timestamp_type_spec.rb +19 -0
- data/spec/unit/pops/types/string_converter_spec.rb +25 -1
- data/spec/unit/pops/types/task_spec.rb +42 -116
- data/spec/unit/pops/validator/validator_spec.rb +24 -10
- data/spec/unit/provider/exec/posix_spec.rb +24 -0
- data/spec/unit/provider/group/aix_spec.rb +20 -6
- data/spec/unit/provider/group/ldap_spec.rb +22 -25
- data/spec/unit/provider/group/pw_spec.rb +7 -10
- data/spec/unit/provider/group/windows_adsi_spec.rb +42 -33
- data/spec/unit/provider/nameservice/directoryservice_spec.rb +97 -103
- data/spec/unit/provider/package/aix_spec.rb +5 -8
- data/spec/unit/provider/package/apt_spec.rb +3 -6
- data/spec/unit/provider/package/dnf_spec.rb +38 -25
- data/spec/unit/provider/package/dpkg_spec.rb +18 -21
- data/spec/unit/provider/package/freebsd_spec.rb +4 -7
- data/spec/unit/provider/package/gem_spec.rb +41 -41
- data/spec/unit/provider/package/hpux_spec.rb +7 -10
- data/spec/unit/provider/package/macports_spec.rb +13 -15
- data/spec/unit/provider/package/nim_spec.rb +3 -10
- data/spec/unit/provider/package/openbsd_spec.rb +14 -17
- data/spec/unit/provider/package/pip3_spec.rb +3 -6
- data/spec/unit/provider/package/pip_spec.rb +45 -49
- data/spec/unit/provider/package/pkgin_spec.rb +13 -18
- data/spec/unit/provider/package/pkgng_spec.rb +32 -27
- data/spec/unit/provider/package/puppet_gem_spec.rb +6 -9
- data/spec/unit/provider/package/tdnf_spec.rb +9 -12
- data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
- data/spec/unit/provider/package/windows_spec.rb +4 -4
- data/spec/unit/provider/package/yum_spec.rb +30 -16
- data/spec/unit/provider/package/zypper_spec.rb +17 -19
- data/spec/unit/provider/service/bsd_spec.rb +7 -9
- data/spec/unit/provider/service/daemontools_spec.rb +12 -16
- data/spec/unit/provider/service/debian_spec.rb +6 -10
- data/spec/unit/provider/service/freebsd_spec.rb +2 -2
- data/spec/unit/provider/service/launchd_spec.rb +19 -0
- data/spec/unit/provider/service/openbsd_spec.rb +13 -17
- data/spec/unit/provider/service/rcng_spec.rb +2 -4
- data/spec/unit/provider/service/redhat_spec.rb +12 -11
- data/spec/unit/provider/service/runit_spec.rb +7 -14
- data/spec/unit/provider/service/smf_spec.rb +77 -13
- data/spec/unit/provider/service/src_spec.rb +11 -16
- data/spec/unit/provider/service/systemd_spec.rb +39 -1
- data/spec/unit/provider/service/windows_spec.rb +39 -7
- data/spec/unit/provider/user/aix_spec.rb +43 -2
- data/spec/unit/provider/user/hpux_spec.rb +3 -5
- data/spec/unit/provider/user/ldap_spec.rb +29 -32
- data/spec/unit/provider/user/pw_spec.rb +10 -13
- data/spec/unit/provider/user/useradd_spec.rb +2 -2
- data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
- data/spec/unit/puppet_pal_2pec.rb +6 -6
- data/spec/unit/puppet_pal_catalog_spec.rb +58 -0
- data/spec/unit/resource/catalog_spec.rb +2 -2
- data/spec/unit/resource_spec.rb +31 -0
- data/spec/unit/ssl/host_spec.rb +22 -1
- data/spec/unit/ssl/key_spec.rb +2 -4
- data/spec/unit/task_spec.rb +50 -5
- data/spec/unit/transaction/event_manager_spec.rb +12 -1
- data/spec/unit/transaction/persistence_spec.rb +4 -4
- data/spec/unit/transaction/resource_harness_spec.rb +18 -0
- data/spec/unit/type/group_spec.rb +11 -3
- data/spec/unit/type/resources_spec.rb +18 -0
- data/spec/unit/type/service_spec.rb +27 -1
- data/spec/unit/util/execution_spec.rb +77 -0
- data/spec/unit/util/filetype_spec.rb +13 -5
- data/spec/unit/util/log/destinations_spec.rb +10 -0
- data/spec/unit/util/logging_spec.rb +58 -41
- data/spec/unit/util/monkey_patches_spec.rb +18 -5
- data/spec/unit/util/posix_spec.rb +28 -0
- data/spec/unit/util/selinux_spec.rb +4 -0
- data/spec/unit/util/storage_spec.rb +107 -0
- data/spec/unit/util/suidmanager_spec.rb +1 -3
- data/spec/unit/util/windows/adsi_spec.rb +95 -0
- data/spec/unit/util/windows/service_spec.rb +377 -131
- metadata +24 -11
- data/ext/autotest/Rakefile +0 -8
- data/ext/autotest/config +0 -43
- data/ext/autotest/readme.rst +0 -16
- data/spec/fixtures/unit/provider/package/pkgng/pkg.info +0 -7
- data/spec/fixtures/unit/provider/package/pkgng/pkg.query_absent +0 -1
- data/spec/watchr.rb +0 -137
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Puppet
|
|
2
|
+
module Pal
|
|
3
|
+
# A TaskSignature is returned from `task_signature`. Its purpose is to answer questions about the task's parameters
|
|
4
|
+
# and if it can be run/called with a hash of named parameters.
|
|
5
|
+
#
|
|
6
|
+
class TaskSignature
|
|
7
|
+
def initialize(task)
|
|
8
|
+
@task = task
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Returns whether or not the given arguments are acceptable when running the task.
|
|
12
|
+
# In addition to returning the boolean outcome, if a block is given, it is called with a string of formatted
|
|
13
|
+
# error messages that describes the difference between what was given and what is expected. The error message may
|
|
14
|
+
# have multiple lines of text, and each line is indented one space.
|
|
15
|
+
#
|
|
16
|
+
# @param args_hash [Hash] a hash mapping parameter names to argument values
|
|
17
|
+
# @yieldparam [String] a formatted error message if a type mismatch occurs that explains the mismatch
|
|
18
|
+
# @return [Boolean] if the given arguments are acceptable when running the task
|
|
19
|
+
#
|
|
20
|
+
def runnable_with?(args_hash)
|
|
21
|
+
params = @task.parameters
|
|
22
|
+
params_type = if params.nil?
|
|
23
|
+
T_GENERIC_TASK_HASH
|
|
24
|
+
else
|
|
25
|
+
Puppet::Pops::Types::TypeFactory.struct(params)
|
|
26
|
+
end
|
|
27
|
+
return true if params_type.instance?(args_hash)
|
|
28
|
+
|
|
29
|
+
if block_given?
|
|
30
|
+
tm = Puppet::Pops::Types::TypeMismatchDescriber.singleton
|
|
31
|
+
error = if params.nil?
|
|
32
|
+
tm.describe_mismatch('', params_type, Puppet::Pops::Types::TypeCalculator.infer_set(args_hash))
|
|
33
|
+
else
|
|
34
|
+
tm.describe_struct_signature(params_type, args_hash).flatten.map {|e| e.format }.join("\n")
|
|
35
|
+
end
|
|
36
|
+
yield "Task #{@task.name}:\n#{error}"
|
|
37
|
+
end
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Returns the Task instance as a hash
|
|
42
|
+
#
|
|
43
|
+
# @return [Hash{String=>Object}] the hash representation of the task
|
|
44
|
+
def task_hash
|
|
45
|
+
@task._pcore_init_hash
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns the Task instance which can be further explored. It contains all meta-data defined for
|
|
49
|
+
# the task such as the description, parameters, output, etc.
|
|
50
|
+
#
|
|
51
|
+
# @return [Puppet::Pops::Types::PuppetObject] An instance of a dynamically created Task class
|
|
52
|
+
def task
|
|
53
|
+
@task
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -29,4 +29,28 @@ class Puppet::Parser::CatalogCompiler < Puppet::Parser::Compiler
|
|
|
29
29
|
raise Puppet::Error, message, detail.backtrace
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Evaluates all added constructs, and validates the resulting catalog.
|
|
33
|
+
# This can be called whenever a series of evaluation of puppet code strings
|
|
34
|
+
# have reached a stable state (essentially that there are no relationships to
|
|
35
|
+
# non-existing resources).
|
|
36
|
+
#
|
|
37
|
+
# Raises an error if validation fails.
|
|
38
|
+
#
|
|
39
|
+
def compile_additions
|
|
40
|
+
evaluate_additions
|
|
41
|
+
validate
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Evaluates added constructs that are lazily evaluated until all of them have been evaluated.
|
|
45
|
+
#
|
|
46
|
+
def evaluate_additions
|
|
47
|
+
evaluate_generators
|
|
48
|
+
finish
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Validates the current state of the catalog.
|
|
52
|
+
# Does not cause evaluation of lazy constructs.
|
|
53
|
+
def validate
|
|
54
|
+
validate_catalog(CatalogValidator::FINAL)
|
|
55
|
+
end
|
|
32
56
|
end
|
|
@@ -577,6 +577,7 @@ class Puppet::Parser::Compiler
|
|
|
577
577
|
end
|
|
578
578
|
end
|
|
579
579
|
end
|
|
580
|
+
protected :evaluate_generators
|
|
580
581
|
|
|
581
582
|
# Find and evaluate our main object, if possible.
|
|
582
583
|
def evaluate_main
|
|
@@ -641,6 +642,7 @@ class Puppet::Parser::Compiler
|
|
|
641
642
|
|
|
642
643
|
add_resource_metaparams
|
|
643
644
|
end
|
|
645
|
+
protected :finish
|
|
644
646
|
|
|
645
647
|
def add_resource_metaparams
|
|
646
648
|
unless main = catalog.resource(:class, :main)
|
|
@@ -780,8 +782,8 @@ class Puppet::Parser::Compiler
|
|
|
780
782
|
settings_resource = Puppet::Parser::Resource.new('class', SETTINGS, :scope => @topscope)
|
|
781
783
|
|
|
782
784
|
@catalog.add_resource(settings_resource)
|
|
783
|
-
|
|
784
785
|
settings_type.evaluate_code(settings_resource)
|
|
786
|
+
settings_resource.instance_variable_set(:@evaluated, true) # Prevents settings from being reevaluated
|
|
785
787
|
|
|
786
788
|
scope = @topscope.class_scope(settings_type)
|
|
787
789
|
scope.merge_settings(environment.name)
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# Runs an external command and returns the results
|
|
2
2
|
Puppet::Parser::Functions::newfunction(:generate, :arity => -2, :type => :rvalue,
|
|
3
3
|
:doc => "Calls an external command on the Puppet master and returns
|
|
4
|
-
the results of the command.
|
|
5
|
-
arguments.
|
|
4
|
+
the results of the command. Any arguments are passed to the external command as
|
|
5
|
+
arguments. If the generator does not exit with return code of 0,
|
|
6
6
|
the generator is considered to have failed and a parse error is
|
|
7
|
-
thrown.
|
|
8
|
-
and periods in them.
|
|
7
|
+
thrown. Generators can only have file separators, alphanumerics, dashes,
|
|
8
|
+
and periods in them. This function will attempt to protect you from
|
|
9
9
|
malicious generator calls (e.g., those with '..' in them), but it can
|
|
10
|
-
never be entirely safe.
|
|
10
|
+
never be entirely safe. No subshell is used to execute
|
|
11
11
|
generators, so all shell metacharacters are passed directly to
|
|
12
|
-
the generator
|
|
12
|
+
the generator, and all metacharacters are returned by the function.
|
|
13
|
+
Consider cleaning white space from any string generated.") do |args|
|
|
13
14
|
|
|
14
15
|
#TRANSLATORS "fully qualified" refers to a fully qualified file system path
|
|
15
16
|
raise Puppet::ParseError, _("Generators must be fully qualified") unless Puppet::Util.absolute_path?(args[0])
|
|
@@ -10,6 +10,8 @@ module Puppet::Plugins
|
|
|
10
10
|
require 'puppet/plugins/syntax_checkers'
|
|
11
11
|
require 'puppet/syntax_checkers/base64'
|
|
12
12
|
require 'puppet/syntax_checkers/json'
|
|
13
|
+
require 'puppet/syntax_checkers/pp'
|
|
14
|
+
require 'puppet/syntax_checkers/epp'
|
|
13
15
|
|
|
14
16
|
def self.load_plugins
|
|
15
17
|
# Register extensions
|
|
@@ -17,7 +19,9 @@ module Puppet::Plugins
|
|
|
17
19
|
{
|
|
18
20
|
SyntaxCheckers::SYNTAX_CHECKERS_KEY => {
|
|
19
21
|
'json' => Puppet::SyntaxCheckers::Json.new,
|
|
20
|
-
'base64' => Puppet::SyntaxCheckers::Base64.new
|
|
22
|
+
'base64' => Puppet::SyntaxCheckers::Base64.new,
|
|
23
|
+
'pp' => Puppet::SyntaxCheckers::PP.new,
|
|
24
|
+
'epp' => Puppet::SyntaxCheckers::EPP.new
|
|
21
25
|
}
|
|
22
26
|
}
|
|
23
27
|
end
|
|
@@ -51,7 +51,9 @@ class Puppet::Pops::Evaluator::Collectors::AbstractCollector
|
|
|
51
51
|
|
|
52
52
|
objects.each do |res|
|
|
53
53
|
unless @collected.include?(res.ref)
|
|
54
|
-
|
|
54
|
+
t = res.type
|
|
55
|
+
t = Puppet::Pops::Evaluator::Runtime3ResourceSupport.find_resource_type(scope, t)
|
|
56
|
+
newres = Puppet::Parser::Resource.new(t, res.title, @overrides)
|
|
55
57
|
scope.compiler.add_override(newres)
|
|
56
58
|
end
|
|
57
59
|
end
|
|
@@ -96,6 +96,9 @@ class DeferredResolver
|
|
|
96
96
|
elsif x.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive)
|
|
97
97
|
# rewrap in a new Sensitive after resolving any nested deferred values
|
|
98
98
|
Puppet::Pops::Types::PSensitiveType::Sensitive.new(resolve(x.unwrap))
|
|
99
|
+
elsif x.is_a?(Puppet::Pops::Types::PBinaryType::Binary)
|
|
100
|
+
# use the ASCII-8BIT string that it wraps
|
|
101
|
+
x.binary_buffer
|
|
99
102
|
else
|
|
100
103
|
x
|
|
101
104
|
end
|
|
@@ -1028,8 +1028,12 @@ class EvaluatorImpl
|
|
|
1028
1028
|
|
|
1029
1029
|
# Evaluates Puppet DSL Heredoc
|
|
1030
1030
|
def eval_HeredocExpression o, scope
|
|
1031
|
+
expr = o.text_expr.expr # Always a SublocatedExpression with an expression
|
|
1031
1032
|
result = evaluate(o.text_expr, scope)
|
|
1032
|
-
|
|
1033
|
+
unless expr.is_a?(Model::LiteralString)
|
|
1034
|
+
# When expr is a LiteralString, validation has already validated this
|
|
1035
|
+
assert_external_syntax(scope, result, o.syntax, o.text_expr)
|
|
1036
|
+
end
|
|
1033
1037
|
result
|
|
1034
1038
|
end
|
|
1035
1039
|
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
#
|
|
4
4
|
require 'puppet/plugins/syntax_checkers'
|
|
5
5
|
module Puppet::Pops::Evaluator::ExternalSyntaxSupport
|
|
6
|
-
def assert_external_syntax(
|
|
6
|
+
def assert_external_syntax(_, result, syntax, reference_expr)
|
|
7
7
|
# ignore 'unspecified syntax'
|
|
8
8
|
return if syntax.nil? || syntax == ''
|
|
9
9
|
|
|
10
|
-
checker = checker_for_syntax(
|
|
10
|
+
checker = checker_for_syntax(nil, syntax)
|
|
11
11
|
# ignore syntax with no matching checker
|
|
12
12
|
return unless checker
|
|
13
13
|
|
|
@@ -26,7 +26,7 @@ module Puppet::Pops::Evaluator::ExternalSyntaxSupport
|
|
|
26
26
|
# Finds the most significant checker for the given syntax (most significant is to the right).
|
|
27
27
|
# Returns nil if there is no registered checker.
|
|
28
28
|
#
|
|
29
|
-
def checker_for_syntax(
|
|
29
|
+
def checker_for_syntax(_, syntax)
|
|
30
30
|
checkers_hash = Puppet.lookup(:plugins)[Puppet::Plugins::SyntaxCheckers::SYNTAX_CHECKERS_KEY]
|
|
31
31
|
checkers_hash[lookup_keys_for_syntax(syntax).find {|x| checkers_hash[x] }]
|
|
32
32
|
end
|
|
@@ -105,8 +105,8 @@ class Runtime3Converter
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
def convert_Symbol(o, scope, undef_value)
|
|
108
|
-
o == :undef
|
|
109
|
-
|
|
108
|
+
return o unless o == :undef
|
|
109
|
+
!@inner ? undef_value : nil
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
def convert_PAnyType(o, scope, undef_value)
|
|
@@ -20,17 +20,26 @@ class Puppet::Pops::Loader::RubyLegacyFunctionInstantiator
|
|
|
20
20
|
loader_for_function = loader.private_loader
|
|
21
21
|
here = get_binding(loader_for_function)
|
|
22
22
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
|
|
23
|
+
# Avoid reloading the function if already loaded via one of the APIs that trigger 3x function loading
|
|
24
|
+
# Check if function is already loaded the 3x way (and obviously not the 4x way since we would not be here in the
|
|
25
|
+
# first place.
|
|
26
|
+
environment = Puppet.lookup(:current_environment)
|
|
27
|
+
func_info = Puppet::Parser::Functions.environment_module(environment).get_function_info(typed_name.name.to_sym)
|
|
28
|
+
if func_info.nil?
|
|
29
|
+
# This will to do the 3x loading and define the "function_<name>" and "real_function_<name>" methods
|
|
30
|
+
# in the anonymous module used to hold function definitions.
|
|
31
|
+
#
|
|
32
|
+
func_info = eval(ruby_code_string, here, source_ref, 1)
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
# Validate what was loaded
|
|
35
|
+
unless func_info.is_a?(Hash)
|
|
36
|
+
# TRANSLATORS - the word 'newfunction' shoud not be translated as it is a method name.
|
|
37
|
+
raise ArgumentError, _("Illegal legacy function definition! The code loaded from %{source_ref} did not return the result of calling 'newfunction'. Got '%{klass}'") % { source_ref: source_ref, klass: func_info.class }
|
|
38
|
+
end
|
|
39
|
+
unless func_info[:name] == "function_#{typed_name.name()}"
|
|
40
|
+
raise ArgumentError, _("The code loaded from %{source_ref} produced mis-matched name, expected 'function_%{type_name}', got '%{created_name}'") % {
|
|
41
|
+
source_ref: source_ref, type_name: typed_name.name, created_name: func_info[:name] }
|
|
42
|
+
end
|
|
34
43
|
end
|
|
35
44
|
|
|
36
45
|
created = Puppet::Functions::Function3x.create_function(typed_name.name(), func_info, loader_for_function)
|
|
@@ -1,58 +1,9 @@
|
|
|
1
1
|
# The TypeDefinitionInstantiator instantiates a type alias or a type definition
|
|
2
2
|
#
|
|
3
|
+
require 'puppet/module/task'
|
|
3
4
|
module Puppet::Pops
|
|
4
5
|
module Loader
|
|
5
6
|
class TaskInstantiator
|
|
6
|
-
def self.load_metadata(loader, metadata)
|
|
7
|
-
if metadata.nil?
|
|
8
|
-
EMPTY_HASH
|
|
9
|
-
else
|
|
10
|
-
json_text = loader.get_contents(metadata)
|
|
11
|
-
begin
|
|
12
|
-
Puppet::Util::Json.load(json_text).freeze || EMPTY_HASH
|
|
13
|
-
rescue Puppet::Util::Json::ParseError => ex
|
|
14
|
-
raise Puppet::ParseError.new(ex.message, metadata)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.validate_implementations(typed_name, directory, metadata, executables)
|
|
20
|
-
name = typed_name.name
|
|
21
|
-
basename = typed_name.name_parts[1] || 'init'
|
|
22
|
-
# If 'implementations' is defined, it needs to mention at least one
|
|
23
|
-
# implementation, and everything it mentions must exist.
|
|
24
|
-
if metadata.key?('implementations')
|
|
25
|
-
if metadata['implementations'].is_a?(Array)
|
|
26
|
-
metadata['implementations'].map do |impl|
|
|
27
|
-
path = executables.find { |real_impl| File.basename(real_impl) == impl['name'] }
|
|
28
|
-
if path
|
|
29
|
-
{ "name" => impl['name'], "requirements" => impl.fetch('requirements', []), "path" => path }
|
|
30
|
-
else
|
|
31
|
-
raise ArgumentError, _("Task metadata for task %{name} specifies missing implementation %{implementation}") %
|
|
32
|
-
{ name: name, implementation: impl['name'] }
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
else
|
|
36
|
-
# If 'implementations' is the wrong type, we just pass it through and
|
|
37
|
-
# let the task type definition reject it.
|
|
38
|
-
metadata['implementations']
|
|
39
|
-
end
|
|
40
|
-
# If implementations isn't defined, then we use executables matching the
|
|
41
|
-
# task name, and only one may exist.
|
|
42
|
-
else
|
|
43
|
-
implementations = executables.select { |impl| File.basename(impl, '.*') == basename }
|
|
44
|
-
if implementations.empty?
|
|
45
|
-
raise ArgumentError, _('No source besides task metadata was found in directory %{directory} for task %{name}') %
|
|
46
|
-
{ name: name, directory: directory }
|
|
47
|
-
elsif implementations.length > 1
|
|
48
|
-
raise ArgumentError, _("Multiple executables were found in directory %{directory} for task %{name}; define 'implementations' in metadata to differentiate between them") %
|
|
49
|
-
{ name: name, directory: implementations[0] }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
[{ "name" => File.basename(implementations.first), "path" => implementations.first, "requirements" => [] }]
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
7
|
def self.create(loader, typed_name, source_refs)
|
|
57
8
|
name = typed_name.name
|
|
58
9
|
basename = typed_name.name_parts[1] || 'init'
|
|
@@ -60,31 +11,16 @@ class TaskInstantiator
|
|
|
60
11
|
metadata_files, executables = source_refs.partition { |source_ref| source_ref.end_with?('.json') }
|
|
61
12
|
metadata_file = metadata_files.find { |source_ref| File.basename(source_ref, '.json') == basename }
|
|
62
13
|
|
|
63
|
-
metadata =
|
|
14
|
+
metadata = Puppet::Module::Task.read_metadata(metadata_file) || {}
|
|
64
15
|
|
|
65
|
-
|
|
16
|
+
files = Puppet::Module::Task.find_files(name, dirname, metadata, executables)
|
|
66
17
|
|
|
67
|
-
|
|
68
|
-
'name' => name,
|
|
69
|
-
'implementations' => implementation_metadata
|
|
70
|
-
}
|
|
18
|
+
task = { 'name' => name, 'metadata' => metadata, 'files' => files }
|
|
71
19
|
|
|
72
20
|
begin
|
|
73
|
-
|
|
74
|
-
if %w[parameters output].include?(key)
|
|
75
|
-
ps = {}
|
|
76
|
-
value.each_pair do |k, v|
|
|
77
|
-
pd = v.dup
|
|
78
|
-
t = v['type']
|
|
79
|
-
pd['type'] = t.nil? ? Types::TypeFactory.data : Types::TypeParser.singleton.parse(t)
|
|
80
|
-
ps[k] = pd
|
|
81
|
-
end
|
|
82
|
-
value = ps
|
|
83
|
-
end
|
|
84
|
-
arguments[key] = value unless arguments.key?(key)
|
|
85
|
-
end
|
|
21
|
+
task['parameters'] = convert_types(metadata['parameters'])
|
|
86
22
|
|
|
87
|
-
Types::TypeFactory.task.from_hash(
|
|
23
|
+
Types::TypeFactory.task.from_hash(task)
|
|
88
24
|
rescue Types::TypeAssertionError => ex
|
|
89
25
|
# Not strictly a parser error but from the users perspective, the file content didn't parse properly. The
|
|
90
26
|
# ParserError also conveys file info (even though line is unknown)
|
|
@@ -92,6 +28,13 @@ class TaskInstantiator
|
|
|
92
28
|
raise Puppet::ParseError.new(msg, metadata_file)
|
|
93
29
|
end
|
|
94
30
|
end
|
|
31
|
+
|
|
32
|
+
def self.convert_types(args)
|
|
33
|
+
args.each_with_object({}) do |(k, v), hsh|
|
|
34
|
+
hsh[k] = v['type'].nil? ? Types::TypeFactory.data : Types::TypeParser.singleton.parse(v['type'])
|
|
35
|
+
end if args
|
|
36
|
+
end
|
|
37
|
+
private_class_method :convert_types
|
|
95
38
|
end
|
|
96
39
|
end
|
|
97
40
|
end
|
|
@@ -98,8 +98,7 @@ module HeredocSupport
|
|
|
98
98
|
|
|
99
99
|
# Use a new lexer instance configured with a sub-locator to enable correct positioning
|
|
100
100
|
sublexer = self.class.new()
|
|
101
|
-
locator = Locator::SubLocator.
|
|
102
|
-
locator.file, heredoc_line, heredoc_offset, leading.length())
|
|
101
|
+
locator = Locator::SubLocator.new(locator, heredoc_line, heredoc_offset, leading.length())
|
|
103
102
|
|
|
104
103
|
# Emit a token that provides the grammar with location information about the lines on which the heredoc
|
|
105
104
|
# content is based.
|
|
@@ -189,7 +189,7 @@ class Lexer2
|
|
|
189
189
|
',' => lambda { emit(TOKEN_COMMA, @scanner.pos) },
|
|
190
190
|
'[' => lambda do
|
|
191
191
|
before = @scanner.pos
|
|
192
|
-
if (before == 0 ||
|
|
192
|
+
if (before == 0 || locator.string[locator.char_offset(before)-1,1] =~ /[[:blank:]\r\n]+/)
|
|
193
193
|
emit(TOKEN_LISTSTART, before)
|
|
194
194
|
else
|
|
195
195
|
emit(TOKEN_LBRACK, before)
|
data/lib/puppet/pops/pcore.rb
CHANGED
|
@@ -39,39 +39,16 @@ module Pcore
|
|
|
39
39
|
# Fully qualified name of the task
|
|
40
40
|
name => { type => Pattern[/\\A[a-z][a-z0-9_]*(?:::[a-z][a-z0-9_]*)*\\z/] },
|
|
41
41
|
|
|
42
|
-
# List of
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
parameters => {
|
|
53
|
-
type => Optional[Hash[
|
|
54
|
-
Pattern[/\\A[a-z][a-z0-9_]*\\z/],
|
|
55
|
-
Struct[
|
|
56
|
-
Optional[description] => String,
|
|
57
|
-
Optional[sensitive] => Boolean,
|
|
58
|
-
type => Type]]],
|
|
59
|
-
value => undef
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
# Type, description, and sensitive property of each output
|
|
63
|
-
output => {
|
|
64
|
-
type => Optional[Hash[
|
|
65
|
-
Pattern[/\\A[a-z][a-z0-9_]*\\z/],
|
|
66
|
-
Struct[
|
|
67
|
-
Optional[description] => String,
|
|
68
|
-
Optional[sensitive] => Boolean,
|
|
69
|
-
type => Type]]],
|
|
70
|
-
value => undef
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
supports_noop => { type => Boolean, value => false },
|
|
74
|
-
input_method => { type => Optional[String] },
|
|
42
|
+
# List of file references referenced by metadata and their paths on disk.
|
|
43
|
+
# If there are no implementations listed in metadata, the first file is always
|
|
44
|
+
# the task executable.
|
|
45
|
+
files => { type => Array[Struct[name => String, path => String]] },
|
|
46
|
+
|
|
47
|
+
# Task metadata
|
|
48
|
+
metadata => { type => Hash[String, Any] },
|
|
49
|
+
|
|
50
|
+
# Map parameter names to their parsed data type
|
|
51
|
+
parameters => { type => Optional[Hash[Pattern[/\\A[a-z][a-z0-9_]*\\z/], Type]], value => undef },
|
|
75
52
|
}
|
|
76
53
|
}
|
|
77
54
|
PUPPET
|
|
@@ -70,7 +70,15 @@ module Serialization
|
|
|
70
70
|
|
|
71
71
|
def to_data(value)
|
|
72
72
|
if value.nil? || Types::PScalarDataType::DEFAULT.instance?(value)
|
|
73
|
-
value
|
|
73
|
+
if @rich_data && value.is_a?(String) && value.encoding == Encoding::ASCII_8BIT
|
|
74
|
+
# Transform the binary string to rich Binary
|
|
75
|
+
{
|
|
76
|
+
PCORE_TYPE_KEY => PCORE_TYPE_BINARY,
|
|
77
|
+
PCORE_VALUE_KEY => Puppet::Pops::Types::PBinaryType::Binary.from_binary_string(value).to_s
|
|
78
|
+
}
|
|
79
|
+
else
|
|
80
|
+
value
|
|
81
|
+
end
|
|
74
82
|
elsif :default == value
|
|
75
83
|
if @rich_data
|
|
76
84
|
{ PCORE_TYPE_KEY => PCORE_TYPE_DEFAULT }
|
|
@@ -65,9 +65,9 @@ module Types
|
|
|
65
65
|
when String
|
|
66
66
|
impl_class.parse(arg)
|
|
67
67
|
when Integer
|
|
68
|
-
|
|
68
|
+
impl_class.new(arg * Time::NSECS_PER_SEC)
|
|
69
69
|
when Float
|
|
70
|
-
|
|
70
|
+
impl_class.new(arg * Time::NSECS_PER_SEC)
|
|
71
71
|
else
|
|
72
72
|
raise ArgumentError, "Unable to create a #{impl_class.name} from a #{arg.class.name}" unless arg.nil? || arg == :default
|
|
73
73
|
nil
|
|
@@ -484,8 +484,17 @@ class StringConverter
|
|
|
484
484
|
|
|
485
485
|
value_type = TypeCalculator.infer_set(value)
|
|
486
486
|
if string_formats.is_a?(String)
|
|
487
|
-
#
|
|
488
|
-
|
|
487
|
+
# For Array and Hash, the format is given as a Hash where 'format' key is the format for the collection itself
|
|
488
|
+
if Puppet::Pops::Types::PArrayType::DEFAULT.assignable?(value_type)
|
|
489
|
+
# add the format given for the exact type
|
|
490
|
+
string_formats = { Puppet::Pops::Types::PArrayType::DEFAULT => {'format' => string_formats }}
|
|
491
|
+
elsif Puppet::Pops::Types::PHashType::DEFAULT.assignable?(value_type)
|
|
492
|
+
# add the format given for the exact type
|
|
493
|
+
string_formats = { Puppet::Pops::Types::PHashType::DEFAULT => {'format' => string_formats }}
|
|
494
|
+
else
|
|
495
|
+
# add the format given for the exact type
|
|
496
|
+
string_formats = { value_type => string_formats }
|
|
497
|
+
end
|
|
489
498
|
end
|
|
490
499
|
|
|
491
500
|
case string_formats
|
|
@@ -804,7 +813,7 @@ class StringConverter
|
|
|
804
813
|
Kernel.format(f.orig_fmt, val)
|
|
805
814
|
|
|
806
815
|
when :p
|
|
807
|
-
apply_string_flags(f, puppet_quote(val))
|
|
816
|
+
apply_string_flags(f, puppet_quote(val, f.alt?))
|
|
808
817
|
|
|
809
818
|
when :c
|
|
810
819
|
c_val = val.capitalize
|
|
@@ -836,10 +845,15 @@ class StringConverter
|
|
|
836
845
|
# strings will be quoted using double quotes.
|
|
837
846
|
#
|
|
838
847
|
# @param [String] str the string that should be formatted
|
|
848
|
+
# @param [Boolean] enforce_double_quotes if true the result will be double quoted (even if single quotes would be possible)
|
|
839
849
|
# @return [String] the formatted string
|
|
840
850
|
#
|
|
841
851
|
# @api public
|
|
842
|
-
def puppet_quote(str)
|
|
852
|
+
def puppet_quote(str, enforce_double_quotes = false)
|
|
853
|
+
if enforce_double_quotes
|
|
854
|
+
return puppet_double_quote(str)
|
|
855
|
+
end
|
|
856
|
+
|
|
843
857
|
# Assume that the string can be single quoted
|
|
844
858
|
bld = '\''
|
|
845
859
|
bld.force_encoding(str.encoding)
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
require 'puppet/pops/evaluator/external_syntax_support'
|
|
2
|
+
|
|
1
3
|
module Puppet::Pops
|
|
2
4
|
module Validation
|
|
5
|
+
|
|
3
6
|
# A Validator validates a model.
|
|
4
7
|
#
|
|
5
8
|
# Validation is performed on each model element in isolation. Each method should validate the model element's state
|
|
@@ -12,6 +15,8 @@ module Validation
|
|
|
12
15
|
# This is however mostly valuable when validating model to model transformations, and is therefore T.B.D
|
|
13
16
|
#
|
|
14
17
|
class Checker4_0 < Evaluator::LiteralEvaluator
|
|
18
|
+
include Puppet::Pops::Evaluator::ExternalSyntaxSupport
|
|
19
|
+
|
|
15
20
|
attr_reader :acceptor
|
|
16
21
|
attr_reader :migration_checker
|
|
17
22
|
|
|
@@ -324,6 +329,14 @@ class Checker4_0 < Evaluator::LiteralEvaluator
|
|
|
324
329
|
end
|
|
325
330
|
end
|
|
326
331
|
|
|
332
|
+
def check_HeredocExpression(o)
|
|
333
|
+
# Only check static text in heredoc
|
|
334
|
+
expr = o.text_expr.expr # Always a SublocatedExpression with an expression
|
|
335
|
+
if expr.is_a?(Model::LiteralString)
|
|
336
|
+
assert_external_syntax(nil, expr.value, o.syntax, o.text_expr)
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
327
340
|
def check_MethodCallExpression(o)
|
|
328
341
|
unless o.functor_expr.is_a? Model::QualifiedName
|
|
329
342
|
acceptor.accept(Issues::ILLEGAL_EXPRESSION, o.functor_expr, :feature => 'function name', :container => o)
|
|
@@ -559,6 +572,8 @@ class Checker4_0 < Evaluator::LiteralEvaluator
|
|
|
559
572
|
return if namespace_for_file(file) == NO_NAMESPACE
|
|
560
573
|
|
|
561
574
|
body = prog.body
|
|
575
|
+
return if prog.body.is_a?(Model::Nop) #Ignore empty or comment-only files
|
|
576
|
+
|
|
562
577
|
if(body.is_a?(Model::BlockExpression))
|
|
563
578
|
body.statements.each { |s| acceptor.accept(Issues::ILLEGAL_TOP_CONSTRUCT_LOCATION, s) unless valid_top_construct?(s) }
|
|
564
579
|
else
|
|
@@ -623,9 +638,9 @@ class Checker4_0 < Evaluator::LiteralEvaluator
|
|
|
623
638
|
|
|
624
639
|
def is_parent_dir_of(parent_dir, child_dir)
|
|
625
640
|
parent_dir_path = Pathname.new(parent_dir)
|
|
626
|
-
clean_parent = parent_dir_path.cleanpath
|
|
641
|
+
clean_parent = parent_dir_path.cleanpath.to_s + File::SEPARATOR
|
|
627
642
|
|
|
628
|
-
return child_dir.to_s.start_with?(clean_parent
|
|
643
|
+
return child_dir.to_s.start_with?(clean_parent)
|
|
629
644
|
end
|
|
630
645
|
|
|
631
646
|
def dir_to_names(relative_path)
|