vagrant-parallels 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/Gemfile +3 -2
- data/Rakefile +9 -11
- data/debug.log +27547 -117
- data/lib/vagrant-parallels/action/match_mac_address.rb +10 -3
- data/lib/vagrant-parallels/driver/prl_ctl.rb +16 -1
- data/lib/vagrant-parallels/version.rb +1 -1
- data/locales/en.yml +4 -1
- data/tasks/bundler.rake +3 -0
- data/tasks/test.rake +12 -0
- data/test/support/isolated_environment.rb +46 -0
- data/test/support/tempdir.rb +43 -0
- data/test/unit/base.rb +27 -0
- data/test/unit/driver/prl_ctl_test.rb +138 -0
- data/test/unit/support/shared/parallels_context.rb +30 -0
- data/vagrant-parallels.gemspec +1 -3
- metadata +13 -40
- data/.ruby-gemset +0 -1
- data/spec/vagrant-parallels/setup_spec.rb +0 -7
@@ -9,9 +9,16 @@ module VagrantPlugins
|
|
9
9
|
def call(env)
|
10
10
|
raise Vagrant::Errors::VMBaseMacNotSpecified if !env[:machine].config.vm.base_mac
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
env[:machine].
|
12
|
+
env[:ui].info I18n.t("vagrant_parallels.actions.vm.match_mac.matching")
|
13
|
+
|
14
|
+
base_mac = env[:machine].config.vm.base_mac
|
15
|
+
# Generate new base mac if the specified address is already in use
|
16
|
+
if env[:machine].provider.driver.mac_in_use?(base_mac)
|
17
|
+
env[:ui].info I18n.t("vagrant_parallels.actions.vm.match_mac.generate")
|
18
|
+
env[:machine].provider.driver.set_mac_address('auto')
|
19
|
+
else
|
20
|
+
env[:machine].provider.driver.set_mac_address(base_mac)
|
21
|
+
end
|
15
22
|
|
16
23
|
@app.call(env)
|
17
24
|
end
|
@@ -40,6 +40,7 @@ module VagrantPlugins
|
|
40
40
|
|
41
41
|
def compact(uuid=nil)
|
42
42
|
uuid ||= @uuid
|
43
|
+
# TODO: VM can have more than one hdd!
|
43
44
|
path_to_hdd = read_settings(uuid).fetch("Hardware", {}).fetch("hdd0", {}).fetch("image", nil)
|
44
45
|
raw('prl_disk_tool', 'compact', '--hdd', path_to_hdd) do |type, data|
|
45
46
|
lines = data.split("\r")
|
@@ -80,7 +81,9 @@ module VagrantPlugins
|
|
80
81
|
end
|
81
82
|
|
82
83
|
def clear_shared_folders
|
83
|
-
read_settings.fetch("Host Shared Folders", {}).keys
|
84
|
+
shf = read_settings.fetch("Host Shared Folders", {}).keys
|
85
|
+
shf.delete("enabled")
|
86
|
+
shf.each do |folder|
|
84
87
|
execute("set", @uuid, "--shf-host-del", folder)
|
85
88
|
end
|
86
89
|
end
|
@@ -214,6 +217,18 @@ module VagrantPlugins
|
|
214
217
|
end
|
215
218
|
end
|
216
219
|
|
220
|
+
|
221
|
+
def mac_in_use?(mac)
|
222
|
+
all_macs_in_use = []
|
223
|
+
read_all_info.each do |vm|
|
224
|
+
all_macs_in_use << vm.fetch('Hardware', {}).fetch('net0',{}).fetch('mac', '')
|
225
|
+
end
|
226
|
+
|
227
|
+
valid_mac = mac.upcase.tr('^A-F0-9', '')
|
228
|
+
|
229
|
+
all_macs_in_use.include?(valid_mac)
|
230
|
+
end
|
231
|
+
|
217
232
|
# Returns a hash of all UUIDs assigned to VMs and templates currently
|
218
233
|
# known by Parallels. Keys are 'name' values
|
219
234
|
#
|
data/locales/en.yml
CHANGED
@@ -890,7 +890,10 @@ en:
|
|
890
890
|
The VM import failed! Try running `prlctl import` on the box file
|
891
891
|
manually for more verbose error output.
|
892
892
|
match_mac:
|
893
|
-
|
893
|
+
generate: |-
|
894
|
+
The specified base MAC is already in use. Generating a new unique MAC
|
895
|
+
address for Shared network...
|
896
|
+
matching: Matching MAC address for Shared network...
|
894
897
|
no_base_mac: |-
|
895
898
|
No base MAC address was specified. This is required for the NAT networking
|
896
899
|
to work properly (and hence port forwarding, SSH, etc.). Specifying this
|
data/tasks/bundler.rake
ADDED
data/tasks/test.rake
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
namespace :test do
|
5
|
+
RSpec::Core::RakeTask.new(:unit) do |t|
|
6
|
+
t.pattern = "test/unit/**/*_test.rb"
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:acceptance) do |t|
|
10
|
+
t.pattern = "test/acceptance/**/*_test.rb"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
require "log4r"
|
5
|
+
|
6
|
+
require "support/tempdir"
|
7
|
+
|
8
|
+
# This class manages an isolated environment for Vagrant to
|
9
|
+
# run in. It creates a temporary directory to act as the
|
10
|
+
# working directory as well as sets a custom home directory.
|
11
|
+
#
|
12
|
+
# This class also provides various helpers to create Vagrantfiles,
|
13
|
+
# boxes, etc.
|
14
|
+
class IsolatedEnvironment
|
15
|
+
attr_reader :homedir
|
16
|
+
attr_reader :workdir
|
17
|
+
|
18
|
+
# Initializes an isolated environment. You can pass in some
|
19
|
+
# options here to configure runing custom applications in place
|
20
|
+
# of others as well as specifying environmental variables.
|
21
|
+
#
|
22
|
+
# @param [Hash] apps A mapping of application name (such as "vagrant")
|
23
|
+
# to an alternate full path to the binary to run.
|
24
|
+
# @param [Hash] env Additional environmental variables to inject
|
25
|
+
# into the execution environments.
|
26
|
+
def initialize
|
27
|
+
@logger = Log4r::Logger.new("test::isolated_environment")
|
28
|
+
|
29
|
+
# Create a temporary directory for our work
|
30
|
+
@tempdir = Tempdir.new("vagrant")
|
31
|
+
@logger.info("Initialize isolated environment: #{@tempdir.path}")
|
32
|
+
|
33
|
+
# Setup the home and working directories
|
34
|
+
@homedir = Pathname.new(File.join(@tempdir.path, "home"))
|
35
|
+
@workdir = Pathname.new(File.join(@tempdir.path, "work"))
|
36
|
+
|
37
|
+
@homedir.mkdir
|
38
|
+
@workdir.mkdir
|
39
|
+
end
|
40
|
+
|
41
|
+
# This closes the environment by cleaning it up.
|
42
|
+
def close
|
43
|
+
@logger.info("Removing isolated environment: #{@tempdir.path}")
|
44
|
+
FileUtils.rm_rf(@tempdir.path)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
# This class provides an easy way of creating a temporary
|
5
|
+
# directory and having it removed when the application exits.
|
6
|
+
class Tempdir
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
def initialize(basename="vagrant")
|
10
|
+
@path = nil
|
11
|
+
|
12
|
+
# Loop and attempt to create a temporary directory until
|
13
|
+
# it succeeds.
|
14
|
+
while @path.nil?
|
15
|
+
file = Tempfile.new(basename)
|
16
|
+
@path = file.path
|
17
|
+
file.unlink
|
18
|
+
|
19
|
+
begin
|
20
|
+
Dir.mkdir(@path)
|
21
|
+
rescue
|
22
|
+
@path = nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Setup a finalizer to delete the directory. This is the same way
|
27
|
+
# that Tempfile and friends do this...
|
28
|
+
@cleanup_proc = lambda do
|
29
|
+
FileUtils.rm_rf(@path) if File.directory?(@path)
|
30
|
+
end
|
31
|
+
|
32
|
+
ObjectSpace.define_finalizer(self, @cleanup_proc)
|
33
|
+
end
|
34
|
+
|
35
|
+
# This deletes the temporary directory.
|
36
|
+
def unlink
|
37
|
+
# Delete the directory
|
38
|
+
@cleanup_proc.call
|
39
|
+
|
40
|
+
# Undefine the finalizer since we're all cleaned up
|
41
|
+
ObjectSpace.undefine_finalizer(self)
|
42
|
+
end
|
43
|
+
end
|
data/test/unit/base.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rspec/autorun"
|
3
|
+
|
4
|
+
# Require Vagrant itself so we can reference the proper
|
5
|
+
# classes to test.
|
6
|
+
require "vagrant"
|
7
|
+
require 'vagrant-parallels'
|
8
|
+
|
9
|
+
# Add the test directory to the load path
|
10
|
+
$:.unshift File.expand_path("../../", __FILE__)
|
11
|
+
|
12
|
+
# Load in helpers
|
13
|
+
require "support/tempdir"
|
14
|
+
require "unit/support/shared/parallels_context"
|
15
|
+
|
16
|
+
# Do not buffer output
|
17
|
+
$stdout.sync = true
|
18
|
+
$stderr.sync = true
|
19
|
+
|
20
|
+
# Configure RSpec
|
21
|
+
RSpec.configure do |c|
|
22
|
+
c.expect_with :rspec, :stdlib
|
23
|
+
end
|
24
|
+
|
25
|
+
# Configure VAGRANT_CWD so that the tests never find an actual
|
26
|
+
# Vagrantfile anywhere, or at least this minimizes those chances.
|
27
|
+
ENV["VAGRANT_CWD"] = Tempdir.new.path
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require_relative "../base"
|
2
|
+
|
3
|
+
describe VagrantPlugins::Parallels::Driver::PrlCtl do
|
4
|
+
include_context "parallels"
|
5
|
+
|
6
|
+
subject { VagrantPlugins::Parallels::Driver::PrlCtl.new(uuid) }
|
7
|
+
|
8
|
+
describe "compact" do
|
9
|
+
it "compacts the VM disk images" do
|
10
|
+
pending "Should have possibility to compact more than one hdd"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "create_host_only_network" do
|
15
|
+
it "creates host-only NIC"
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "export" do
|
19
|
+
tpl_name = "new_template_name"
|
20
|
+
tpl_uuid = "12345-hfgs-3456-hste"
|
21
|
+
|
22
|
+
it "exports VM to template" do
|
23
|
+
subject.stub(:read_settings).with(tpl_name).
|
24
|
+
and_return({"ID" => tpl_uuid})
|
25
|
+
|
26
|
+
subprocess.should_receive(:execute).
|
27
|
+
with("prlctl", "clone", uuid, "--name", an_instance_of(String), "--template", "--dst",
|
28
|
+
an_instance_of(String), an_instance_of(Hash)).
|
29
|
+
and_return(subprocess_result(stdout: "The VM has been successfully cloned"))
|
30
|
+
subject.export("/path/to/template", tpl_name).should == tpl_uuid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "clear_shared_folders" do
|
35
|
+
shf_hash = {"enabled" => true, "shf_name_1" => {}, "shf_name_2" => {}}
|
36
|
+
it "deletes every shared folder assigned to the VM" do
|
37
|
+
subject.stub(:read_settings).and_return({"Host Shared Folders" => shf_hash})
|
38
|
+
|
39
|
+
subprocess.should_receive(:execute).exactly(2).times.
|
40
|
+
with("prlctl", "set", uuid, "--shf-host-del", an_instance_of(String), an_instance_of(Hash)).
|
41
|
+
and_return(subprocess_result(stdout: "Shared folder deleted"))
|
42
|
+
subject.clear_shared_folders
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "halt" do
|
47
|
+
it "stops the VM" do
|
48
|
+
subprocess.should_receive(:execute).
|
49
|
+
with("prlctl", "stop", uuid, an_instance_of(Hash)).
|
50
|
+
and_return(subprocess_result(stdout: "VM has been halted gracefully"))
|
51
|
+
subject.halt
|
52
|
+
end
|
53
|
+
|
54
|
+
it "stops the VM force" do
|
55
|
+
subprocess.should_receive(:execute).
|
56
|
+
with("prlctl", "stop", uuid, "--kill", an_instance_of(Hash)).
|
57
|
+
and_return(subprocess_result(stdout: "VM has been halted forcibly"))
|
58
|
+
subject.halt(force=true)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "mac_in_use?" do
|
63
|
+
vm_1 = {
|
64
|
+
'Hardware' => {
|
65
|
+
'net0' => {'mac' => '001C42BB5901'},
|
66
|
+
'net1' => {'mac' => '001C42BB5902'},
|
67
|
+
}
|
68
|
+
}
|
69
|
+
vm_2 = {
|
70
|
+
'Hardware' => {
|
71
|
+
'net0' => {'mac' => '001C42BB5903'},
|
72
|
+
'net1' => {'mac' => '001C42BB5904'},
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
it "checks the MAC address is already in use" do
|
77
|
+
subject.stub(:read_all_info).and_return([vm_1, vm_2])
|
78
|
+
|
79
|
+
subject.mac_in_use?('00:1c:42:bb:59:01').should be_true
|
80
|
+
subject.mac_in_use?('00:1c:42:bb:59:02').should be_false
|
81
|
+
subject.mac_in_use?('00:1c:42:bb:59:03').should be_true
|
82
|
+
subject.mac_in_use?('00:1c:42:bb:59:04').should be_false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "set_mac_address" do
|
87
|
+
it "sets base MAC address to the Shared network adapter" do
|
88
|
+
subprocess.should_receive(:execute).exactly(2).times.
|
89
|
+
with("prlctl", "set", uuid, '--device-set', 'net0', '--type', 'shared', '--mac',
|
90
|
+
an_instance_of(String), an_instance_of(Hash)).
|
91
|
+
and_return(subprocess_result(stdout: "Settings applied"))
|
92
|
+
|
93
|
+
subject.set_mac_address('001C42DD5902')
|
94
|
+
subject.set_mac_address('auto')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "start" do
|
99
|
+
it "starts the VM" do
|
100
|
+
subprocess.should_receive(:execute).
|
101
|
+
with("prlctl", "start", uuid, an_instance_of(Hash)).
|
102
|
+
and_return(subprocess_result(stdout: "VM started"))
|
103
|
+
subject.start
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "suspend" do
|
108
|
+
it "suspends the VM" do
|
109
|
+
subprocess.should_receive(:execute).
|
110
|
+
with("prlctl", "suspend", uuid, an_instance_of(Hash)).
|
111
|
+
and_return(subprocess_result(stdout: "VM suspended"))
|
112
|
+
subject.suspend
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "unregister" do
|
117
|
+
it "suspends the VM" do
|
118
|
+
subprocess.should_receive(:execute).
|
119
|
+
with("prlctl", "unregister", an_instance_of(String), an_instance_of(Hash)).
|
120
|
+
and_return(subprocess_result(stdout: "Specified VM unregistered"))
|
121
|
+
subject.unregister("template_or_vm_uuid")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "version" do
|
126
|
+
it "parses the version from output" do
|
127
|
+
subject.version.should match(/(#{parallels_version}[\d\.]+)/)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "rises ParallelsInstallIncomplete exception when output is invalid" do
|
131
|
+
subprocess.should_receive(:execute).
|
132
|
+
with("prlctl", "--version", an_instance_of(Hash)).
|
133
|
+
and_return(subprocess_result(stdout: "Some incorrect value has been returned!"))
|
134
|
+
expect { subject.version }.
|
135
|
+
to raise_error(VagrantPlugins::Parallels::Errors::ParallelsInstallIncomplete)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
shared_context "parallels" do
|
2
|
+
let(:parallels_context) { true }
|
3
|
+
let(:uuid) { "9876-dcba-8765-hgfe" }
|
4
|
+
let(:parallels_version) { "9" }
|
5
|
+
let(:subprocess) { double("Vagrant::Util::Subprocess") }
|
6
|
+
|
7
|
+
# this is a helper that returns a duck type suitable from a system command
|
8
|
+
# execution; allows setting exit_code, stdout, and stderr in stubs.
|
9
|
+
def subprocess_result(options={})
|
10
|
+
defaults = {exit_code: 0, stdout: "", stderr: ""}
|
11
|
+
double("subprocess_result", defaults.merge(options))
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
# we don't want unit tests to ever run commands on the system; so we wire
|
16
|
+
# in a double to ensure any unexpected messages raise exceptions
|
17
|
+
stub_const("Vagrant::Util::Subprocess", subprocess)
|
18
|
+
|
19
|
+
# drivers will blow up on instantiation if they cannot determine the
|
20
|
+
# Parallels Desktop version, so wire this stub in automatically
|
21
|
+
subprocess.stub(:execute).
|
22
|
+
with("prlctl", "--version", an_instance_of(Hash)).
|
23
|
+
and_return(subprocess_result(stdout: "prlctl version #{parallels_version}.23456.987654"))
|
24
|
+
|
25
|
+
# drivers also call vm_exists? during init;
|
26
|
+
subprocess.stub(:execute).
|
27
|
+
with("prlctl", "list", kind_of(String), "--info", "--json", kind_of(Hash)).
|
28
|
+
and_return(subprocess_result(exit_code: 0))
|
29
|
+
end
|
30
|
+
end
|
data/vagrant-parallels.gemspec
CHANGED
@@ -18,9 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
|
19
19
|
spec.add_development_dependency "bundler", "~> 1.3"
|
20
20
|
spec.add_development_dependency "rake"
|
21
|
-
spec.add_development_dependency "rspec
|
22
|
-
spec.add_development_dependency "rspec-expectations", "~> 2.12.1"
|
23
|
-
spec.add_development_dependency "rspec-mocks", "~> 2.12.1"
|
21
|
+
spec.add_development_dependency "rspec", "~> 2.14.0"
|
24
22
|
|
25
23
|
# The following block of code determines the files that should be included
|
26
24
|
# in the gem. It does this by reading all the files in the directory where
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-parallels
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-12-
|
12
|
+
date: 2013-12-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -44,13 +44,13 @@ dependencies:
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name: rspec
|
47
|
+
name: rspec
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
51
|
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 2.
|
53
|
+
version: 2.14.0
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,39 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: rspec-expectations
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ~>
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: 2.12.1
|
70
|
-
type: :development
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ~>
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: 2.12.1
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: rspec-mocks
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
|
-
requirements:
|
83
|
-
- - ~>
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
version: 2.12.1
|
86
|
-
type: :development
|
87
|
-
prerelease: false
|
88
|
-
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
|
-
requirements:
|
91
|
-
- - ~>
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version: 2.12.1
|
61
|
+
version: 2.14.0
|
94
62
|
description: Enables Vagrant to manage Parallels machines.
|
95
63
|
email:
|
96
64
|
- yshahin@gmail.com
|
@@ -148,10 +116,15 @@ files:
|
|
148
116
|
- locales/en.yml
|
149
117
|
- Rakefile
|
150
118
|
- README.md
|
151
|
-
-
|
119
|
+
- tasks/bundler.rake
|
120
|
+
- tasks/test.rake
|
121
|
+
- test/support/isolated_environment.rb
|
122
|
+
- test/support/tempdir.rb
|
123
|
+
- test/unit/base.rb
|
124
|
+
- test/unit/driver/prl_ctl_test.rb
|
125
|
+
- test/unit/support/shared/parallels_context.rb
|
152
126
|
- vagrant-parallels.gemspec
|
153
127
|
- .gitignore
|
154
|
-
- .ruby-gemset
|
155
128
|
- .travis.yml
|
156
129
|
homepage: http://github.com/yshahin/vagrant-parallels
|
157
130
|
licenses:
|
@@ -168,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
168
141
|
version: '0'
|
169
142
|
segments:
|
170
143
|
- 0
|
171
|
-
hash:
|
144
|
+
hash: 1018017984449213160
|
172
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
146
|
none: false
|
174
147
|
requirements:
|