Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ group(:packaging) do
gem 'vanagon', *location_for(ENV['VANAGON_LOCATION'] || 'https://github.com/openvoxproject/vanagon#main')
end
gem 'artifactory'
gem 'json', '< 3'
gem 'json', '< 4'
gem 'octokit'
end

Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/face/epp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ def dump_parse(source, filename, options, show_filename = true)
pn = Puppet::Pops::Model::PNTransformer.transform(parse_result)
case fmt
when 'json'
options[:pretty] ? JSON.pretty_unparse(pn.to_data) : JSON.dump(pn.to_data)
options[:pretty] ? JSON.pretty_generate(pn.to_data) : JSON.dump(pn.to_data)
else
pn.format(options[:pretty] ? Puppet::Pops::PN::Indent.new(' ') : nil, output)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/face/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def dump_parse(source, filename, options, show_filename = true)
pn = Puppet::Pops::Model::PNTransformer.transform(parse_result)
case fmt
when 'json'
options[:pretty] ? JSON.pretty_unparse(pn.to_data) : JSON.dump(pn.to_data)
options[:pretty] ? JSON.pretty_generate(pn.to_data) : JSON.dump(pn.to_data)
else
pn.format(options[:pretty] ? Puppet::Pops::PN::Indent.new(' ') : nil, output)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/pal/json_catalog_encoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def encode_resource(type, title)
r = possibly_filtered_catalog.resource(type, title)
return nil if r.nil?

r.to_data_hash.to_json(:pretty => pretty)
Puppet::Util::Json.dump(r.to_data_hash, :pretty => pretty)
end

# Applies a filter for virtual resources and returns filtered catalog
Expand Down
18 changes: 15 additions & 3 deletions lib/puppet/util/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ def self.build(original_exception, data)

require 'json'

# Generator options equivalent to the `JSON::PRETTY_STATE_PROTOTYPE`
# that json 2.x provided and json 3 removed.
PRETTY_OPTIONS = { :indent => ' ', :space => ' ', :object_nl => "\n", :array_nl => "\n" }.freeze

# Generator options that json 3 rejects as unknown. `quirks_mode` has been
# a no-op since json 2.0, when quirks mode became the only mode.
OBSOLETE_DUMP_OPTIONS = [:quirks_mode].freeze

# Load the content from a file as JSON if
# contents are in valid format. This method does not
# raise error but returns `nil` when invalid file is
Expand All @@ -41,16 +49,20 @@ def self.load_file(filename, options = {})
def self.load(string, options = {})
string = string.read if string.respond_to?(:read)

options = options.dup
options[:symbolize_names] = true if options.delete(:symbolize_keys)
::JSON.parse(string, options)
# json 3 only accepts parser options as keyword arguments
::JSON.parse(string, **options)
rescue JSON::ParserError => e
raise Puppet::Util::Json::ParseError.build(e, string)
end

def self.dump(object, options = {})
# Options is a state when we're being called recursively
if !options.is_a?(JSON::State) && options.delete(:pretty)
options.merge!(::JSON::PRETTY_STATE_PROTOTYPE.to_h)
unless options.is_a?(JSON::State)
options = options.dup
OBSOLETE_DUMP_OPTIONS.each { |key| options.delete(key) }
options.merge!(PRETTY_OPTIONS) if options.delete(:pretty)
end
object.to_json(options)
end
Expand Down
5 changes: 5 additions & 0 deletions spec/lib/matchers/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ def initialize(schema)
end

def matches?(json)
# Parse here rather than letting json-schema do it, since json-schema
# (as of 6.2.1) still calls JSON.parse with a positional options hash,
# which json 3 rejects.
json = Puppet::Util::Json.load(json) if json.is_a?(String)

JSON::Validator.validate!(JSON_META_SCHEMA, @schema)
JSON::Validator.validate!(@schema, json)
end
Expand Down
5 changes: 2 additions & 3 deletions spec/unit/pops/loaders/loaders_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,6 @@ class tstt {
"name": "example/%1$s",
"version": "0.0.2",
"source": "git@github.com/example/example-%1$s.git",
"dependencies": [],
"author": "Bob the Builder",
"license": "Apache-2.0"%2$s
}
Expand Down Expand Up @@ -732,7 +731,7 @@ class tstt {
'y.pp' => 'type C::D::Y = Integer'
}
},
'metadata.json' => sprintf(metadata_json, 'c', '')
'metadata.json' => sprintf(metadata_json, 'c', ', "dependencies": []')
},
'd' => {
'types' => {
Expand All @@ -746,7 +745,7 @@ class tstt {
}]
PUPPET
},
'metadata.json' => sprintf(metadata_json, 'd', '')
'metadata.json' => sprintf(metadata_json, 'd', ', "dependencies": []')
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions spec/unit/puppet_pal_catalog_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
c.with_json_encoding() {|encoder| encoder.encode_resource('notify', 'test') }
}
end
expect(result).to match(/"message":"yay"/)
expect(result).to match(/"message": ?"yay"/)
end

it 'encodes values as rich data when needed' do
Expand All @@ -218,7 +218,7 @@
c.with_json_encoding(pretty: true) {|encoder| encoder.encode_resource('notify', 'test') }
}
end
expect(result).to match(/"__ptype":"Regexp"/)
expect(result).to match(/"__ptype": ?"Regexp"/)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/unit/resource/catalog_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ class {'multi_param_class':
@catalog.add_resource(two)

# TODO this should really guarantee sort order
expect(JSON.parse(@catalog.to_json,:create_additions => false)['resources'].sort).to eq(["one_resource", "two_resource"].sort)
expect(JSON.parse(@catalog.to_json)['resources'].sort).to eq(["one_resource", "two_resource"].sort)
end

it "should convert its edges to a JSON-encoded array and store it as the 'edges' data" do
Expand All @@ -1101,7 +1101,7 @@ class {'multi_param_class':
expect(@catalog.edges_between(one, two )[0]).to receive(:to_data_hash).and_return("one_two_json")
expect(@catalog.edges_between(two, three)[0]).to receive(:to_data_hash).and_return("two_three_json")

expect(JSON.parse(@catalog.to_json,:create_additions => false)['edges'].sort).to eq(%w{one_two_json two_three_json}.sort)
expect(JSON.parse(@catalog.to_json)['edges'].sort).to eq(%w{one_two_json two_three_json}.sort)
end
end

Expand Down
65 changes: 65 additions & 0 deletions spec/unit/util/json_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,71 @@
}
JSON
end

it 'passes options to the parser' do
expect(Puppet::Util::Json.load('{"a": 1}', symbolize_names: true)).to eq(a: 1)
end

it 'translates symbolize_keys to symbolize_names' do
expect(Puppet::Util::Json.load('{"a": 1}', symbolize_keys: true)).to eq(a: 1)
end

it 'does not modify the options it is given' do
options = { symbolize_keys: true }
Puppet::Util::Json.load('{"a": 1}', options)

expect(options).to eq(symbolize_keys: true)
end

it 'loads from an IO' do
expect(Puppet::Util::Json.load(StringIO.new('{"a": 1}'))).to eq('a' => 1)
end
end

context "#dump" do
let(:data) { { 'a' => [1, { 'b' => nil }] } }

it 'dumps compact JSON by default' do
expect(Puppet::Util::Json.dump(data)).to eq('{"a":[1,{"b":null}]}')
end

it 'pretty prints when pretty is set' do
expect(Puppet::Util::Json.dump(data, pretty: true)).to eq(<<~JSON.chomp)
{
"a": [
1,
{
"b": null
}
]
}
JSON
end

it 'dumps a scalar' do
expect(Puppet::Util::Json.dump(42, pretty: true)).to eq('42')
end

it 'ignores the obsolete quirks_mode option' do
expect(Puppet::Util::Json.dump(data, pretty: true, quirks_mode: true)).to eq(JSON.pretty_generate(data))
end

it 'passes generator options through' do
expect(Puppet::Util::Json.dump(data, space: ' ')).to eq('{"a": [1,{"b": null}]}')
end

it 'accepts a JSON::State when called recursively' do
state = JSON::State.new(indent: ' ', object_nl: "\n")

expect(Puppet::Util::Json.dump(data, state)).to eq(data.to_json(state))
end

it 'does not modify the options it is given' do
options = { pretty: true, quirks_mode: true }
Puppet::Util::Json.dump(data, options)

expect(options).to eq(pretty: true, quirks_mode: true)
end
end

context "load_file_if_valid" do
Expand Down
Loading