puppet 4.10.4 → 4.10.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/lib/puppet/application/lookup.rb +2 -2
- data/lib/puppet/configurer/fact_handler.rb +1 -1
- data/lib/puppet/face/epp.rb +26 -24
- data/lib/puppet/file_serving/metadata.rb +2 -2
- data/lib/puppet/forge.rb +5 -3
- data/lib/puppet/forge/cache.rb +1 -0
- data/lib/puppet/forge/repository.rb +2 -1
- data/lib/puppet/indirector/catalog/compiler.rb +4 -3
- data/lib/puppet/indirector/request.rb +9 -8
- data/lib/puppet/module.rb +30 -0
- data/lib/puppet/network/http/rack/rest.rb +2 -1
- data/lib/puppet/parser/compiler.rb +4 -0
- data/lib/puppet/parser/functions/assert_type.rb +1 -1
- data/lib/puppet/parser/functions/binary_file.rb +1 -1
- data/lib/puppet/parser/functions/break.rb +1 -1
- data/lib/puppet/parser/functions/defined.rb +1 -1
- data/lib/puppet/parser/functions/dig.rb +1 -1
- data/lib/puppet/parser/functions/each.rb +1 -1
- data/lib/puppet/parser/functions/epp.rb +1 -1
- data/lib/puppet/parser/functions/filter.rb +1 -1
- data/lib/puppet/parser/functions/find_file.rb +1 -1
- data/lib/puppet/parser/functions/inline_epp.rb +1 -1
- data/lib/puppet/parser/functions/lest.rb +1 -1
- data/lib/puppet/parser/functions/map.rb +1 -1
- data/lib/puppet/parser/functions/match.rb +1 -1
- data/lib/puppet/parser/functions/new.rb +1 -1
- data/lib/puppet/parser/functions/next.rb +1 -1
- data/lib/puppet/parser/functions/reduce.rb +1 -1
- data/lib/puppet/parser/functions/return.rb +1 -1
- data/lib/puppet/parser/functions/reverse_each.rb +1 -1
- data/lib/puppet/parser/functions/slice.rb +1 -1
- data/lib/puppet/parser/functions/step.rb +1 -1
- data/lib/puppet/parser/functions/strftime.rb +1 -1
- data/lib/puppet/parser/functions/then.rb +1 -1
- data/lib/puppet/parser/functions/type.rb +1 -1
- data/lib/puppet/parser/functions/with.rb +1 -1
- data/lib/puppet/pops/evaluator/collector_transformer.rb +2 -2
- data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +2 -2
- data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +2 -2
- data/lib/puppet/pops/merge_strategy.rb +1 -1
- data/lib/puppet/provider/nameservice.rb +4 -2
- data/lib/puppet/reports/http.rb +4 -2
- data/lib/puppet/resource/capability_finder.rb +1 -1
- data/lib/puppet/type/file/source.rb +9 -3
- data/lib/puppet/util.rb +122 -2
- data/lib/puppet/util/execution.rb +1 -1
- data/lib/puppet/util/rdoc/generators/puppet_generator.rb +1 -1
- data/lib/puppet/version.rb +1 -1
- data/locales/puppet.pot +12 -4
- data/spec/integration/application/apply_spec.rb +10 -0
- data/spec/integration/type/file_spec.rb +29 -0
- data/spec/integration/util/execution_spec.rb +8 -0
- data/spec/unit/application/lookup_spec.rb +1 -1
- data/spec/unit/configurer/fact_handler_spec.rb +30 -8
- data/spec/unit/face/epp_face_spec.rb +9 -0
- data/spec/unit/file_serving/metadata_spec.rb +21 -0
- data/spec/unit/forge/forge_spec.rb +112 -0
- data/spec/unit/forge/repository_spec.rb +4 -4
- data/spec/unit/functions/lookup_spec.rb +26 -0
- data/spec/unit/indirector/catalog/compiler_spec.rb +1 -1
- data/spec/unit/indirector/file_bucket_file/file_spec.rb +3 -3
- data/spec/unit/indirector/request_spec.rb +16 -1
- data/spec/unit/module_spec.rb +29 -0
- data/spec/unit/network/http/api/indirected_routes_spec.rb +3 -3
- data/spec/unit/network/http/rack/rest_spec.rb +3 -3
- data/spec/unit/type/file_spec.rb +46 -0
- data/spec/unit/util_spec.rb +230 -1
- data/tasks/parallel.rake +12 -7
- metadata +184 -194
@@ -42,10 +42,10 @@ class CollectorTransformer
|
|
42
42
|
|
43
43
|
case o.query
|
44
44
|
when Model::VirtualQuery
|
45
|
-
newcoll = Collectors::CatalogCollector.new(scope, resource_type
|
45
|
+
newcoll = Collectors::CatalogCollector.new(scope, resource_type, code, overrides)
|
46
46
|
when Model::ExportedQuery
|
47
47
|
match = match_unless_nop(o.query, scope)
|
48
|
-
newcoll = Collectors::ExportedCollector.new(scope, resource_type
|
48
|
+
newcoll = Collectors::ExportedCollector.new(scope, resource_type, match, code, overrides)
|
49
49
|
end
|
50
50
|
|
51
51
|
scope.compiler.add_collection(newcoll)
|
@@ -3,14 +3,14 @@ class Puppet::Pops::Evaluator::Collectors::CatalogCollector < Puppet::Pops::Eval
|
|
3
3
|
# Creates a CatalogCollector using the AbstractCollector's
|
4
4
|
# constructor to set the scope and overrides
|
5
5
|
#
|
6
|
-
# param [
|
6
|
+
# param [Puppet::CompilableResourceType] type the resource type to be collected
|
7
7
|
# param [Proc] query the query which defines which resources to match
|
8
8
|
def initialize(scope, type, query, overrides = nil)
|
9
9
|
super(scope, overrides)
|
10
10
|
|
11
11
|
@query = query
|
12
12
|
|
13
|
-
@type = Puppet::Resource.new(type,
|
13
|
+
@type = Puppet::Resource.new(type, 'whatever').type
|
14
14
|
end
|
15
15
|
|
16
16
|
# Collects virtual resources based off a collection in a manifest
|
@@ -3,7 +3,7 @@ class Puppet::Pops::Evaluator::Collectors::ExportedCollector < Puppet::Pops::Eva
|
|
3
3
|
# Creates an ExportedCollector using the AbstractCollector's
|
4
4
|
# constructor to set the scope and overrides
|
5
5
|
#
|
6
|
-
# param [
|
6
|
+
# param [Puppet::CompilableResourceType] type the resource type to be collected
|
7
7
|
# param [Array] equery an array representation of the query (exported query)
|
8
8
|
# param [Proc] cquery a proc representation of the query (catalog query)
|
9
9
|
def initialize(scope, type, equery, cquery, overrides = nil)
|
@@ -12,7 +12,7 @@ class Puppet::Pops::Evaluator::Collectors::ExportedCollector < Puppet::Pops::Eva
|
|
12
12
|
@equery = equery
|
13
13
|
@cquery = cquery
|
14
14
|
|
15
|
-
@type = Puppet::Resource.new(type,
|
15
|
+
@type = Puppet::Resource.new(type, 'whatever').type
|
16
16
|
end
|
17
17
|
|
18
18
|
# Ensures that storeconfigs is present before calling AbstractCollector's
|
@@ -375,7 +375,7 @@ module Puppet::Pops
|
|
375
375
|
'knockout_prefix=>Optional[String],'\
|
376
376
|
'merge_debug=>Optional[Boolean],'\
|
377
377
|
'merge_hash_arrays=>Optional[Boolean],'\
|
378
|
-
'
|
378
|
+
'sort_merged_arrays=>Optional[Boolean],'\
|
379
379
|
'}]')
|
380
380
|
end
|
381
381
|
|
@@ -24,11 +24,13 @@ class Puppet::Provider::NameService < Puppet::Provider
|
|
24
24
|
|
25
25
|
def instances
|
26
26
|
objects = []
|
27
|
-
Puppet::Etc.send("set#{section}ent")
|
28
27
|
begin
|
29
|
-
|
28
|
+
method = Puppet::Etc.method(:"get#{section}ent")
|
29
|
+
while ent = method.call
|
30
30
|
objects << new(:name => ent.name, :canonical_name => ent.canonical_name, :ensure => :present)
|
31
31
|
end
|
32
|
+
ensure
|
33
|
+
Puppet::Etc.send("end#{section}ent")
|
32
34
|
end
|
33
35
|
objects
|
34
36
|
end
|
data/lib/puppet/reports/http.rb
CHANGED
@@ -6,8 +6,10 @@ Puppet::Reports.register_report(:http) do
|
|
6
6
|
|
7
7
|
desc <<-DESC
|
8
8
|
Send reports via HTTP or HTTPS. This report processor submits reports as
|
9
|
-
POST requests to the address in the `reporturl` setting.
|
10
|
-
|
9
|
+
POST requests to the address in the `reporturl` setting. When a HTTPS URL
|
10
|
+
is used, the remote server must present a certificate issued by the Puppet
|
11
|
+
CA or the connection will fail validation. The body of each POST request
|
12
|
+
is the YAML dump of a Puppet::Transaction::Report object, and the
|
11
13
|
Content-Type is set as `application/x-yaml`.
|
12
14
|
DESC
|
13
15
|
|
@@ -87,7 +87,7 @@ module Puppet::Resource::CapabilityFinder
|
|
87
87
|
Puppet::Util::Puppetdb.query_puppetdb(["from", "resources", query])
|
88
88
|
# For PuppetDB < 4, use the old internal method action()
|
89
89
|
else
|
90
|
-
url = "/pdb/query/v4/resource?query=#{
|
90
|
+
url = "/pdb/query/v4/resource?query=#{Puppet::Util.uri_query_encode(query.to_json)}"
|
91
91
|
response = Puppet::Util::Puppetdb::Http.action(url) do |conn, uri|
|
92
92
|
conn.get(uri, { 'Accept' => 'application/json'})
|
93
93
|
end
|
@@ -70,7 +70,7 @@ module Puppet
|
|
70
70
|
next if Puppet::Util.absolute_path?(source)
|
71
71
|
|
72
72
|
begin
|
73
|
-
uri = URI.parse(
|
73
|
+
uri = URI.parse(Puppet::Util.uri_encode(source))
|
74
74
|
rescue => detail
|
75
75
|
self.fail Puppet::Error, "Could not understand source #{source}: #{detail}", detail
|
76
76
|
end
|
@@ -91,7 +91,13 @@ module Puppet
|
|
91
91
|
source = self.class.normalize(source)
|
92
92
|
|
93
93
|
if Puppet::Util.absolute_path?(source)
|
94
|
-
|
94
|
+
# CGI.unescape will butcher properly escaped URIs
|
95
|
+
uri_string = Puppet::Util.path_to_uri(source).to_s
|
96
|
+
# Ruby 1.9.3 and earlier have a URI bug in URI
|
97
|
+
# to_s returns an ASCII string despite UTF-8 fragments
|
98
|
+
# since its escaped its safe to universally call encode
|
99
|
+
# URI.unescape always returns strings in the original encoding
|
100
|
+
URI.unescape(uri_string.encode(Encoding::UTF_8))
|
95
101
|
else
|
96
102
|
source
|
97
103
|
end
|
@@ -219,7 +225,7 @@ module Puppet
|
|
219
225
|
end
|
220
226
|
|
221
227
|
def uri
|
222
|
-
@uri ||= URI.parse(
|
228
|
+
@uri ||= URI.parse(Puppet::Util.uri_encode(metadata.source))
|
223
229
|
end
|
224
230
|
|
225
231
|
def write(file)
|
data/lib/puppet/util.rb
CHANGED
@@ -321,7 +321,12 @@ module Util
|
|
321
321
|
end
|
322
322
|
end
|
323
323
|
|
324
|
-
|
324
|
+
# have to split *after* any relevant escaping
|
325
|
+
params[:path], params[:query] = uri_encode(path).split('?')
|
326
|
+
search_for_fragment = params[:query] ? :query : :path
|
327
|
+
if params[search_for_fragment].include?('#')
|
328
|
+
params[search_for_fragment], _, params[:fragment] = params[search_for_fragment].rpartition('#')
|
329
|
+
end
|
325
330
|
|
326
331
|
begin
|
327
332
|
URI::Generic.build(params)
|
@@ -335,7 +340,9 @@ module Util
|
|
335
340
|
def uri_to_path(uri)
|
336
341
|
return unless uri.is_a?(URI)
|
337
342
|
|
338
|
-
|
343
|
+
# CGI.unescape doesn't handle space rules properly in uri paths
|
344
|
+
# URI.unescape does, but returns strings in their original encoding
|
345
|
+
path = URI.unescape(uri.path.encode(Encoding::UTF_8))
|
339
346
|
|
340
347
|
if Puppet.features.microsoft_windows? and uri.scheme == 'file'
|
341
348
|
if uri.host
|
@@ -349,6 +356,119 @@ module Util
|
|
349
356
|
end
|
350
357
|
module_function :uri_to_path
|
351
358
|
|
359
|
+
private
|
360
|
+
|
361
|
+
RFC_3986_URI_REGEX = /^(?<scheme>([^:\/?#]+):)?(?<authority>\/\/([^\/?#]*))?(?<path>[^?#]*)(\?(?<query>[^#]*))?(#(?<fragment>.*))?$/
|
362
|
+
|
363
|
+
public
|
364
|
+
|
365
|
+
# Percent-encodes a URI query parameter per RFC3986 - https://tools.ietf.org/html/rfc3986
|
366
|
+
#
|
367
|
+
# The output will correctly round-trip through URI.unescape
|
368
|
+
#
|
369
|
+
# @param [String query_string] A URI query parameter that may contain reserved
|
370
|
+
# characters that must be percent encoded for the key or value to be
|
371
|
+
# properly decoded as part of a larger query string:
|
372
|
+
#
|
373
|
+
# query
|
374
|
+
# encodes as : query
|
375
|
+
#
|
376
|
+
# query_with_special=chars like&and * and# plus+this
|
377
|
+
# encodes as:
|
378
|
+
# query_with_special%3Dchars%20like%26and%20%2A%20and%23%20plus%2Bthis
|
379
|
+
#
|
380
|
+
# Note: Also usable by fragments, but not suitable for paths
|
381
|
+
#
|
382
|
+
# @return [String] a new string containing an encoded query string per the
|
383
|
+
# rules of RFC3986.
|
384
|
+
#
|
385
|
+
# In particular,
|
386
|
+
# query will encode + as %2B and space as %20
|
387
|
+
def uri_query_encode(query_string)
|
388
|
+
return nil if query_string.nil?
|
389
|
+
|
390
|
+
# query can encode space to %20 OR +
|
391
|
+
# + MUST be encoded as %2B
|
392
|
+
# in RFC3968 both query and fragment are defined as:
|
393
|
+
# = *( pchar / "/" / "?" )
|
394
|
+
# CGI.escape turns space into + which is the most backward compatible
|
395
|
+
# however it doesn't roundtrip through URI.unescape which prefers %20
|
396
|
+
CGI.escape(query_string).gsub('+', '%20')
|
397
|
+
end
|
398
|
+
module_function :uri_query_encode
|
399
|
+
|
400
|
+
# Percent-encodes a URI string per RFC3986 - https://tools.ietf.org/html/rfc3986
|
401
|
+
#
|
402
|
+
# Properly handles escaping rules for paths, query strings and fragments
|
403
|
+
# independently
|
404
|
+
#
|
405
|
+
# The output is safe to pass to URI.parse or URI::Generic.build and will
|
406
|
+
# correctly round-trip through URI.unescape
|
407
|
+
#
|
408
|
+
# @param [String path] A URI string that may be in the form of:
|
409
|
+
#
|
410
|
+
# http://foo.com/bar?query
|
411
|
+
# file://tmp/foo bar
|
412
|
+
# //foo.com/bar?query
|
413
|
+
# /bar?query
|
414
|
+
# bar?query
|
415
|
+
# bar
|
416
|
+
# .
|
417
|
+
# C:\Windows\Temp
|
418
|
+
#
|
419
|
+
# Note that with no specified scheme, authority or query parameter delimiter
|
420
|
+
# ? that a naked string will be treated as a path.
|
421
|
+
#
|
422
|
+
# Note that if query parameters need to contain data such as & or =
|
423
|
+
# that this method should not be used, as there is no way to differentiate
|
424
|
+
# query parameter data from query delimiters when multiple parameters
|
425
|
+
# are specified
|
426
|
+
#
|
427
|
+
# @param [Hash{Symbol=>String} opts] Options to alter encoding
|
428
|
+
# @option opts [Array<Symbol>] :allow_fragment defaults to false. When false
|
429
|
+
# will treat # as part of a path or query and not a fragment delimiter
|
430
|
+
#
|
431
|
+
# @return [String] a new string containing appropriate portions of the URI
|
432
|
+
# encoded per the rules of RFC3986.
|
433
|
+
# In particular,
|
434
|
+
# path will not encode +, but will encode space as %20
|
435
|
+
# query will encode + as %2B and space as %20
|
436
|
+
# fragment behaves like query
|
437
|
+
def uri_encode(path, opts = { :allow_fragment => false })
|
438
|
+
raise ArgumentError.new('path may not be nil') if path.nil?
|
439
|
+
|
440
|
+
# ensure string starts as UTF-8 for the sake of Ruby 1.9.3
|
441
|
+
encoded = ''.encode!(Encoding::UTF_8)
|
442
|
+
|
443
|
+
# parse uri into named matches, then reassemble properly encoded
|
444
|
+
parts = path.match(RFC_3986_URI_REGEX)
|
445
|
+
|
446
|
+
encoded += parts[:scheme] unless parts[:scheme].nil?
|
447
|
+
encoded += parts[:authority] unless parts[:authority].nil?
|
448
|
+
|
449
|
+
# path requires space to be encoded as %20 (NEVER +)
|
450
|
+
# + should be left unencoded
|
451
|
+
# URI::parse and URI::Generic.build don't like paths encoded with CGI.escape
|
452
|
+
# URI.escape does not change / to %2F and : to %3A like CGI.escape
|
453
|
+
encoded += URI.escape(parts[:path]) unless parts[:path].nil?
|
454
|
+
|
455
|
+
# each query parameter
|
456
|
+
if !parts[:query].nil?
|
457
|
+
query_string = parts[:query].split('&').map do |pair|
|
458
|
+
# can optionally be separated by an =
|
459
|
+
pair.split('=').map do |v|
|
460
|
+
uri_query_encode(v)
|
461
|
+
end.join('=')
|
462
|
+
end.join('&')
|
463
|
+
encoded += '?' + query_string
|
464
|
+
end
|
465
|
+
|
466
|
+
encoded += ((opts[:allow_fragment] ? '#' : '%23') + uri_query_encode(parts[:fragment])) unless parts[:fragment].nil?
|
467
|
+
|
468
|
+
encoded
|
469
|
+
end
|
470
|
+
module_function :uri_encode
|
471
|
+
|
352
472
|
def safe_posix_fork(stdin=$stdin, stdout=$stdout, stderr=$stderr, &block)
|
353
473
|
child_pid = Kernel.fork do
|
354
474
|
$stdin.reopen(stdin)
|
@@ -383,7 +383,7 @@ module Generators
|
|
383
383
|
resources.each do |r|
|
384
384
|
res << {
|
385
385
|
"name" => CGI.escapeHTML(r.name),
|
386
|
-
"aref" =>
|
386
|
+
"aref" => Puppet::Util.uri_encode(path_prefix)+"\#"+Puppet::Util.uri_query_encode(r.aref)
|
387
387
|
}
|
388
388
|
end
|
389
389
|
res
|
data/lib/puppet/version.rb
CHANGED
data/locales/puppet.pot
CHANGED
@@ -6,11 +6,11 @@
|
|
6
6
|
#, fuzzy
|
7
7
|
msgid ""
|
8
8
|
msgstr ""
|
9
|
-
"Project-Id-Version: Puppet automation framework
|
9
|
+
"Project-Id-Version: Puppet automation framework 5.0.0-48-gd9d2edc\n"
|
10
10
|
"\n"
|
11
11
|
"Report-Msgid-Bugs-To: https://tickets.puppetlabs.com\n"
|
12
|
-
"POT-Creation-Date: 2017-
|
13
|
-
"PO-Revision-Date: 2017-
|
12
|
+
"POT-Creation-Date: 2017-07-14 21:19+0000\n"
|
13
|
+
"PO-Revision-Date: 2017-07-14 21:19+0000\n"
|
14
14
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
15
15
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
16
16
|
"Language: \n"
|
@@ -122,6 +122,14 @@ msgstr ""
|
|
122
122
|
msgid "Existing backup does not match its expected sum, %{sum}. Overwriting corrupted backup."
|
123
123
|
msgstr ""
|
124
124
|
|
125
|
+
#: ../lib/puppet/module.rb:77
|
126
|
+
msgid "GettextSetup initialization for %{module_name} failed with: %{error_message}"
|
127
|
+
msgstr ""
|
128
|
+
|
129
|
+
#: ../lib/puppet/module.rb:80
|
130
|
+
msgid "GettextSetup is not available, skipping GettextSetup initialization for %{module_name}."
|
131
|
+
msgstr ""
|
132
|
+
|
125
133
|
#: ../lib/puppet/pops/lookup/environment_data_provider.rb:20
|
126
134
|
msgid "hiera.yaml version 3 found at the environment root was ignored"
|
127
135
|
msgstr ""
|
@@ -130,7 +138,7 @@ msgstr ""
|
|
130
138
|
msgid "hiera.yaml version 3 found at module root was ignored"
|
131
139
|
msgstr ""
|
132
140
|
|
133
|
-
#: ../lib/puppet/provider/nameservice.rb:
|
141
|
+
#: ../lib/puppet/provider/nameservice.rb:58
|
134
142
|
msgid "listbyname is deprecated and will be removed in a future release of Puppet. Please use `self.instances` to obtain a list of users."
|
135
143
|
msgstr ""
|
136
144
|
|
@@ -131,6 +131,16 @@ end
|
|
131
131
|
expect(notices).to include('false')
|
132
132
|
expect(notices).not_to include('the Puppet::Type says hello')
|
133
133
|
end
|
134
|
+
|
135
|
+
it 'does not load the ruby type when when referenced from collector during compile' do
|
136
|
+
notices = eval_and_collect_notices("@applytest { 'applytest was here': }\nApplytest<| title == 'applytest was here' |>", node)
|
137
|
+
expect(notices).not_to include('the Puppet::Type says hello')
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'does not load the ruby type when when referenced from exported collector during compile' do
|
141
|
+
notices = eval_and_collect_notices("@@applytest { 'applytest was here': }\nApplytest<<| |>>", node)
|
142
|
+
expect(notices).not_to include('the Puppet::Type says hello')
|
143
|
+
end
|
134
144
|
end
|
135
145
|
end
|
136
146
|
|
@@ -1074,6 +1074,35 @@ describe Puppet::Type.type(:file), :uses_checksums => true do
|
|
1074
1074
|
expect(File.read(dest)).to eq("foo")
|
1075
1075
|
end
|
1076
1076
|
|
1077
|
+
it "should maintain source URIs as UTF-8 with Unicode characters in their names and be able to copy such files" do
|
1078
|
+
# different UTF-8 widths
|
1079
|
+
# 1-byte A
|
1080
|
+
# 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191
|
1081
|
+
# 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160
|
1082
|
+
# 4-byte <U+070E> - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142
|
1083
|
+
mixed_utf8 = "A\u06FF\u16A0\u{2070E}" # Aۿᚠ<U+070E>
|
1084
|
+
|
1085
|
+
dest = tmpfile("destwith #{mixed_utf8}")
|
1086
|
+
source = tmpfile_with_contents("filewith #{mixed_utf8}", "foo")
|
1087
|
+
catalog.add_resource described_class.new(:path => dest, :source => source)
|
1088
|
+
|
1089
|
+
catalog.apply
|
1090
|
+
|
1091
|
+
# find the resource and verify
|
1092
|
+
resource = catalog.resources.first { |r| r.title == "File[#{dest}]" }
|
1093
|
+
uri_path = resource.parameters[:source].uri.path
|
1094
|
+
|
1095
|
+
# note that Windows file:// style URIs get an extra / in front of c:/ like /c:/
|
1096
|
+
source_prefix = Puppet.features.microsoft_windows? ? '/' : ''
|
1097
|
+
|
1098
|
+
# the URI can be round-tripped through unescape
|
1099
|
+
expect(URI.unescape(uri_path)).to eq(source_prefix + source)
|
1100
|
+
# and is properly UTF-8
|
1101
|
+
expect(uri_path.encoding).to eq (Encoding::UTF_8)
|
1102
|
+
|
1103
|
+
expect(File.read(dest)).to eq('foo')
|
1104
|
+
end
|
1105
|
+
|
1077
1106
|
it "should be able to copy individual files even if recurse has been specified" do
|
1078
1107
|
source = tmpfile_with_contents("source", "foo")
|
1079
1108
|
dest = tmpfile("dest")
|