puppet 6.0.3-x86-mingw32 → 6.0.4-x86-mingw32
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 +4 -4
- data/Gemfile.lock +3 -3
- data/Rakefile +2 -1
- data/lib/puppet/face/config.rb +1 -1
- data/lib/puppet/file_bucket/dipper.rb +1 -1
- data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +3 -2
- data/lib/puppet/provider/group/aix.rb +31 -1
- data/lib/puppet/provider/group/pw.rb +8 -4
- data/lib/puppet/provider/group/windows_adsi.rb +4 -3
- data/lib/puppet/provider/nameservice/directoryservice.rb +3 -5
- data/lib/puppet/provider/package/dnf.rb +1 -0
- data/lib/puppet/type/group.rb +41 -57
- data/lib/puppet/util/filetype.rb +21 -5
- data/lib/puppet/util/log/destinations.rb +3 -2
- data/lib/puppet/util/windows/adsi.rb +0 -2
- data/lib/puppet/version.rb +1 -1
- data/locales/puppet.pot +28 -39
- data/man/man5/puppet.conf.5 +1 -1
- data/man/man8/puppet-config.8 +1 -1
- data/man/man8/puppet.8 +1 -1
- 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/integration/util/windows/adsi_spec.rb +1 -2
- data/spec/unit/pops/loaders/loaders_spec.rb +18 -0
- data/spec/unit/provider/group/aix_spec.rb +33 -0
- data/spec/unit/provider/group/pw_spec.rb +6 -0
- data/spec/unit/provider/group/windows_adsi_spec.rb +33 -23
- data/spec/unit/provider/nameservice/directoryservice_spec.rb +2 -2
- data/spec/unit/provider/package/dnf_spec.rb +14 -0
- data/spec/unit/type/group_spec.rb +18 -108
- data/spec/unit/util/log/destinations_spec.rb +10 -0
- data/spec/unit/util/suidmanager_spec.rb +1 -3
- data/spec/unit/util/windows/adsi_spec.rb +5 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d14104edfa498be3127e28b0c869c7d8a7bcb2501a39a18b4ac9365236ddf540
|
4
|
+
data.tar.gz: 5b9080742fd9bcb8af6d942231066603736ab0383040eb2462e9bed78d67905f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1909a8ac26bd45d1966e8b40ce576ed1c3778440d0097f87298ae9858fbb0cee3df5796de3c1b6d401142e367208b83db42df79e7d65aca51f90cb51b50d1704
|
7
|
+
data.tar.gz: f5c740bf06a557810a97d7caa1170864bf26a03f80e8b4120b1b03fd752b4985ad77698afc1c001fb3033552bc9238e3c0f2408b6f9a15183df778e952beec0b
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
puppet (6.0.
|
4
|
+
puppet (6.0.4)
|
5
5
|
CFPropertyList (~> 2.2)
|
6
6
|
facter (>= 2.0.1, < 4)
|
7
7
|
fast_gettext (~> 1.1.2)
|
@@ -47,7 +47,7 @@ GEM
|
|
47
47
|
memory_profiler (0.9.12)
|
48
48
|
metaclass (0.0.4)
|
49
49
|
method_source (0.9.0)
|
50
|
-
minitar (0.
|
50
|
+
minitar (0.7)
|
51
51
|
mocha (1.5.0)
|
52
52
|
metaclass (~> 0.0.1)
|
53
53
|
msgpack (1.2.4)
|
@@ -64,7 +64,7 @@ GEM
|
|
64
64
|
coderay (~> 1.1.0)
|
65
65
|
method_source (~> 0.9.0)
|
66
66
|
public_suffix (3.0.3)
|
67
|
-
puppet-resource_api (1.6.
|
67
|
+
puppet-resource_api (1.6.2)
|
68
68
|
hocon (>= 1.0)
|
69
69
|
puppetserver-ca (1.1.1)
|
70
70
|
facter (>= 2.0.1, < 4)
|
data/Rakefile
CHANGED
@@ -71,7 +71,7 @@ task(:commits) do
|
|
71
71
|
%x{git log --no-merges --pretty=%s #{commit_range}}.each_line do |commit_summary|
|
72
72
|
# This regex tests for the currently supported commit summary tokens: maint, doc, packaging, or pup-<number>.
|
73
73
|
# The exception tries to explain it in more full.
|
74
|
-
if /^\((maint|doc|docs|packaging|pup-\d+)\)|revert/i.match(commit_summary).nil?
|
74
|
+
if /^\((maint|doc|docs|packaging|l10n|pup-\d+)\)|revert/i.match(commit_summary).nil?
|
75
75
|
raise "\n\n\n\tThis commit summary didn't match CONTRIBUTING.md guidelines:\n" \
|
76
76
|
"\n\t\t#{commit_summary}\n" \
|
77
77
|
"\tThe commit summary (i.e. the first line of the commit message) should start with one of:\n" \
|
@@ -80,6 +80,7 @@ task(:commits) do
|
|
80
80
|
"\t\t(docs)(DOCUMENT-<digits>)\n" \
|
81
81
|
"\t\t(maint)\n" \
|
82
82
|
"\t\t(packaging)\n" \
|
83
|
+
"\t\t(L10n)\n" \
|
83
84
|
"\n\tThis test for the commit summary is case-insensitive.\n\n\n"
|
84
85
|
else
|
85
86
|
puts "#{commit_summary}"
|
data/lib/puppet/face/config.rb
CHANGED
@@ -210,7 +210,7 @@ https://puppet.com/docs/puppet/latest/configuration.html#environment
|
|
210
210
|
|
211
211
|
action(:delete) do
|
212
212
|
summary _("Delete a Puppet setting.")
|
213
|
-
arguments _("
|
213
|
+
arguments _("<setting>")
|
214
214
|
#TRANSLATORS 'main' is a specific section name and should not be translated
|
215
215
|
description "Deletes a setting from the specified section. (The default is the section 'main')."
|
216
216
|
notes <<-'EOT'
|
@@ -33,10 +33,11 @@ class Puppet::Pops::Loader::RubyLegacyFunctionInstantiator
|
|
33
33
|
|
34
34
|
# Validate what was loaded
|
35
35
|
unless func_info.is_a?(Hash)
|
36
|
-
|
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 }
|
37
38
|
end
|
38
39
|
unless func_info[:name] == "function_#{typed_name.name()}"
|
39
|
-
raise ArgumentError, _("The code loaded from %{source_ref} produced mis-matched name, expected 'function_%{type_name}', got %{created_name}") % {
|
40
|
+
raise ArgumentError, _("The code loaded from %{source_ref} produced mis-matched name, expected 'function_%{type_name}', got '%{created_name}'") % {
|
40
41
|
source_ref: source_ref, type_name: typed_name.name, created_name: func_info[:name] }
|
41
42
|
end
|
42
43
|
end
|
@@ -53,10 +53,30 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
|
|
53
53
|
|
54
54
|
group_hash
|
55
55
|
end
|
56
|
+
|
57
|
+
# Define some Puppet Property => AIX Attribute (and vice versa)
|
58
|
+
# conversion functions here. This is so we can unit test them.
|
59
|
+
|
60
|
+
def members_to_users(provider, members)
|
61
|
+
members = members.split(',') if members.is_a?(String)
|
62
|
+
unless provider.resource[:auth_membership]
|
63
|
+
current_members = provider.members
|
64
|
+
current_members = [] if current_members == :absent
|
65
|
+
members = (members + current_members).uniq
|
66
|
+
end
|
67
|
+
|
68
|
+
members.join(',')
|
69
|
+
end
|
70
|
+
|
71
|
+
def users_to_members(users)
|
72
|
+
users.split(',')
|
73
|
+
end
|
56
74
|
end
|
57
75
|
|
58
76
|
mapping puppet_property: :members,
|
59
|
-
aix_attribute: :users
|
77
|
+
aix_attribute: :users,
|
78
|
+
property_to_attribute: method(:members_to_users),
|
79
|
+
attribute_to_property: method(:users_to_members)
|
60
80
|
|
61
81
|
numeric_mapping puppet_property: :gid,
|
62
82
|
aix_attribute: :id
|
@@ -65,4 +85,14 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
|
|
65
85
|
# the resource methods (property getters + setters for our mapped
|
66
86
|
# properties + a getter for the attributes property).
|
67
87
|
mk_resource_methods
|
88
|
+
|
89
|
+
# We could add this to the top-level members property since the
|
90
|
+
# implementation is not platform-specific; however, it is best
|
91
|
+
# to do it this way so that we do not accidentally break something.
|
92
|
+
# This is ok for now, since we do plan on moving this and the
|
93
|
+
# auth_membership management over to the property class in a future
|
94
|
+
# Puppet release.
|
95
|
+
def members_insync?(current, should)
|
96
|
+
current.sort == @resource.parameter(:members).actual_should(current, should)
|
97
|
+
end
|
68
98
|
end
|
@@ -9,10 +9,7 @@ Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService:
|
|
9
9
|
defaultfor :operatingsystem => [:freebsd, :dragonfly]
|
10
10
|
confine :operatingsystem => [:freebsd, :dragonfly]
|
11
11
|
|
12
|
-
options :members,
|
13
|
-
:flag => "-M",
|
14
|
-
:method => :mem,
|
15
|
-
:unmunge => proc { |members| members.join(',') }
|
12
|
+
options :members, :flag => "-M", :method => :mem
|
16
13
|
|
17
14
|
verify :gid, _("GID must be an integer") do |value|
|
18
15
|
value.is_a? Integer
|
@@ -29,6 +26,9 @@ Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService:
|
|
29
26
|
|
30
27
|
if members = @resource.should(:members)
|
31
28
|
unless members == :absent
|
29
|
+
if members.is_a?(Array)
|
30
|
+
members = members.join(",")
|
31
|
+
end
|
32
32
|
cmd << "-M" << members
|
33
33
|
end
|
34
34
|
end
|
@@ -39,6 +39,10 @@ Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService:
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def modifycmd(param, value)
|
42
|
+
# members may be an array, need a comma separated list
|
43
|
+
if param == :members and value.is_a?(Array)
|
44
|
+
value = value.join(",")
|
45
|
+
end
|
42
46
|
super(param, value)
|
43
47
|
end
|
44
48
|
end
|
@@ -22,9 +22,10 @@ Puppet::Type.type(:group).provide :windows_adsi do
|
|
22
22
|
|
23
23
|
# Cannot use munge of the group property to canonicalize @should
|
24
24
|
# since the default array_matching comparison is not commutative
|
25
|
+
|
25
26
|
# dupes automatically weeded out when hashes built
|
26
|
-
current_members = Puppet::Util::Windows::ADSI::
|
27
|
-
specified_members = Puppet::Util::Windows::ADSI::
|
27
|
+
current_members = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current)
|
28
|
+
specified_members = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should)
|
28
29
|
|
29
30
|
current_sids = current_members.keys.to_a
|
30
31
|
specified_sids = specified_members.keys.to_a
|
@@ -65,7 +66,7 @@ Puppet::Type.type(:group).provide :windows_adsi do
|
|
65
66
|
end
|
66
67
|
|
67
68
|
def members
|
68
|
-
@members ||= Puppet::Util::Windows::ADSI::
|
69
|
+
@members ||= Puppet::Util::Windows::ADSI::Group.name_sid_hash(group.members)
|
69
70
|
@members.keys
|
70
71
|
end
|
71
72
|
|
@@ -116,7 +116,7 @@ class Puppet::Provider::NameService::DirectoryService < Puppet::Provider::NameSe
|
|
116
116
|
ds_value = input_hash[key]
|
117
117
|
case ds_to_ns_attribute_map[ds_attribute]
|
118
118
|
when :members
|
119
|
-
ds_value = ds_value
|
119
|
+
ds_value = ds_value # only members uses arrays so far
|
120
120
|
when :gid, :uid
|
121
121
|
# OS X stores objects like uid/gid as strings.
|
122
122
|
# Try casting to an integer for these cases to be
|
@@ -344,10 +344,8 @@ class Puppet::Provider::NameService::DirectoryService < Puppet::Provider::NameSe
|
|
344
344
|
|
345
345
|
def set(param, value)
|
346
346
|
self.class.validate(param, value)
|
347
|
+
current_members = @property_value_cache_hash[:members]
|
347
348
|
if param == :members
|
348
|
-
current_members = @property_value_cache_hash[:members].split(',')
|
349
|
-
value = value.split(',')
|
350
|
-
|
351
349
|
# If we are meant to be authoritative for the group membership
|
352
350
|
# then remove all existing members who haven't been specified
|
353
351
|
# in the manifest.
|
@@ -411,7 +409,7 @@ class Puppet::Provider::NameService::DirectoryService < Puppet::Provider::NameSe
|
|
411
409
|
end
|
412
410
|
if value != "" and not value.nil?
|
413
411
|
if property == :members
|
414
|
-
add_members(nil, value
|
412
|
+
add_members(nil, value)
|
415
413
|
else
|
416
414
|
exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
|
417
415
|
exec_arg_vector << ns_to_ds_attribute_map[property.intern]
|
@@ -30,6 +30,7 @@ Puppet::Type.type(:package).provide :dnf, :parent => :yum do
|
|
30
30
|
|
31
31
|
defaultfor :operatingsystem => :fedora
|
32
32
|
notdefaultfor :operatingsystem => :fedora, :operatingsystemmajrelease => (19..21).to_a
|
33
|
+
defaultfor :osfamily => :redhat, :operatingsystemmajrelease => ["8"]
|
33
34
|
|
34
35
|
def self.update_command
|
35
36
|
# In DNF, update is deprecated for upgrade
|
data/lib/puppet/type/group.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'etc'
|
2
2
|
require 'facter'
|
3
3
|
require 'puppet/property/keyvalue'
|
4
|
-
require 'puppet/property/list'
|
5
4
|
require 'puppet/parameter/boolean'
|
6
5
|
|
7
6
|
module Puppet
|
@@ -82,84 +81,69 @@ module Puppet
|
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
85
|
-
newproperty(:members, :
|
84
|
+
newproperty(:members, :array_matching => :all, :required_features => :manages_members) do
|
86
85
|
desc "The members of the group. For platforms or directory services where group
|
87
86
|
membership is stored in the group objects, not the users. This parameter's
|
88
87
|
behavior can be configured with `auth_membership`."
|
89
88
|
|
90
|
-
|
91
|
-
|
92
|
-
raise ArgumentError, _("The members property must be specified as either an array of strings, or as a single string consisting of a comma-separated list of members")
|
93
|
-
end
|
94
|
-
|
95
|
-
if value.is_a?(Integer) || value =~ /^\d+$/
|
96
|
-
raise ArgumentError, _("User names must be provided, not UID numbers.")
|
97
|
-
end
|
89
|
+
def change_to_s(currentvalue, newvalue)
|
90
|
+
newvalue = actual_should(currentvalue, newvalue)
|
98
91
|
|
99
|
-
if
|
100
|
-
|
101
|
-
|
92
|
+
currentvalue = currentvalue.join(",") if currentvalue != :absent
|
93
|
+
newvalue = newvalue.join(",")
|
94
|
+
super(currentvalue, newvalue)
|
95
|
+
end
|
102
96
|
|
103
|
-
|
104
|
-
|
97
|
+
def insync?(current)
|
98
|
+
if provider.respond_to?(:members_insync?)
|
99
|
+
return provider.members_insync?(current, @should)
|
105
100
|
end
|
106
|
-
end
|
107
101
|
|
108
|
-
|
109
|
-
@resource[:auth_membership]
|
102
|
+
super(current)
|
110
103
|
end
|
111
104
|
|
112
|
-
def
|
113
|
-
newvalue = newvalue.split(",") if newvalue != :absent
|
114
|
-
|
105
|
+
def is_to_s(currentvalue)
|
115
106
|
if provider.respond_to?(:members_to_s)
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
107
|
+
currentvalue = '' if currentvalue.nil?
|
108
|
+
currentvalue = currentvalue.is_a?(Array) ? currentvalue : currentvalue.split(',')
|
109
|
+
|
110
|
+
return provider.members_to_s(currentvalue)
|
120
111
|
end
|
121
112
|
|
122
|
-
super(currentvalue
|
113
|
+
super(currentvalue)
|
123
114
|
end
|
124
115
|
|
125
|
-
|
126
|
-
|
127
|
-
if provider.respond_to?(:members_to_s)
|
128
|
-
# Windows ADSI members returns SIDs, but retrieve needs names
|
129
|
-
# must return qualified names for SIDs for "is" value and puppet resource
|
130
|
-
return provider.members_to_s(provider.members).split(',')
|
131
|
-
end
|
132
|
-
|
133
|
-
super
|
116
|
+
def should_to_s(newvalue)
|
117
|
+
is_to_s(actual_should(retrieve, newvalue))
|
134
118
|
end
|
135
119
|
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
def should=(values)
|
148
|
-
super(values)
|
149
|
-
|
150
|
-
if @should.length == 1 && @should.first.include?(delimiter)
|
151
|
-
@should = @should.first.split(delimiter)
|
120
|
+
# Calculates the actual should value given the current and
|
121
|
+
# new values. This is only used in should_to_s and change_to_s
|
122
|
+
# to fix the change notification issue reported in PUP-6542.
|
123
|
+
def actual_should(currentvalue, newvalue)
|
124
|
+
currentvalue = munge_members_value(currentvalue)
|
125
|
+
newvalue = munge_members_value(newvalue)
|
126
|
+
|
127
|
+
if @resource[:auth_membership]
|
128
|
+
newvalue.uniq.sort
|
129
|
+
else
|
130
|
+
(currentvalue + newvalue).uniq.sort
|
152
131
|
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Useful helper to handle the possible property value types that we can
|
135
|
+
# both pass-in and return. It munges the value into an array
|
136
|
+
def munge_members_value(value)
|
137
|
+
return [] if value == :absent
|
138
|
+
return value.split(',') if value.is_a?(String)
|
153
139
|
|
154
|
-
|
140
|
+
value
|
155
141
|
end
|
156
142
|
|
157
|
-
|
158
|
-
if provider.respond_to?(:
|
159
|
-
return provider.
|
143
|
+
validate do |value|
|
144
|
+
if provider.respond_to?(:member_valid?)
|
145
|
+
return provider.member_valid?(value)
|
160
146
|
end
|
161
|
-
|
162
|
-
super(current)
|
163
147
|
end
|
164
148
|
end
|
165
149
|
|
data/lib/puppet/util/filetype.rb
CHANGED
@@ -166,6 +166,12 @@ class Puppet::Util::FileType
|
|
166
166
|
end
|
167
167
|
|
168
168
|
# Handle Linux-style cron tabs.
|
169
|
+
#
|
170
|
+
# TODO: We can possibly eliminate the "-u <username>" option in cmdbase
|
171
|
+
# by just running crontab under <username>'s uid (like we do for suntab
|
172
|
+
# and aixtab). It may be worth investigating this alternative
|
173
|
+
# implementation in the future. This way, we can refactor all three of
|
174
|
+
# our cron file types into a common crontab file type.
|
169
175
|
newfiletype(:crontab) do
|
170
176
|
def initialize(user)
|
171
177
|
self.path = user
|
@@ -185,16 +191,26 @@ class Puppet::Util::FileType
|
|
185
191
|
|
186
192
|
# Read a specific @path's cron tab.
|
187
193
|
def read
|
188
|
-
|
194
|
+
Puppet::Util::Execution.execute("#{cmdbase} -l", failonfail: true, combine: true)
|
195
|
+
rescue => detail
|
196
|
+
case detail.to_s
|
197
|
+
when /no crontab for/
|
198
|
+
return ""
|
199
|
+
when /are not allowed to/
|
200
|
+
raise FileReadError, _("User %{path} not authorized to use cron") % { path: @path }, detail.backtrace
|
201
|
+
else
|
202
|
+
raise FileReadError, _("Could not read crontab for %{path}: %{detail}") % { path: @path, detail: detail }, detail.backtrace
|
203
|
+
end
|
189
204
|
end
|
190
205
|
|
191
206
|
# Remove a specific @path's cron tab.
|
192
207
|
def remove
|
208
|
+
cmd = "#{cmdbase} -r"
|
193
209
|
if %w{Darwin FreeBSD DragonFly}.include?(Facter.value("operatingsystem"))
|
194
|
-
|
195
|
-
else
|
196
|
-
%x{#{cmdbase} -r 2>/dev/null}
|
210
|
+
cmd = "/bin/echo yes | #{cmd}"
|
197
211
|
end
|
212
|
+
|
213
|
+
Puppet::Util::Execution.execute(cmd, failonfail: true, combine: true)
|
198
214
|
end
|
199
215
|
|
200
216
|
# Overwrite a specific @path's cron tab; must be passed the @path name
|
@@ -270,7 +286,7 @@ class Puppet::Util::FileType
|
|
270
286
|
Puppet::Util::Execution.execute(%w{crontab -l}, cronargs)
|
271
287
|
rescue => detail
|
272
288
|
case detail.to_s
|
273
|
-
when /
|
289
|
+
when /open.*in.*directory/
|
274
290
|
return ""
|
275
291
|
when /You are not authorized to use the cron command/
|
276
292
|
raise FileReadError, _("User %{path} not authorized to use cron") % { path: @path }, detail.backtrace
|
@@ -77,9 +77,10 @@ Puppet::Util::Log.newdesttype :file do
|
|
77
77
|
|
78
78
|
# create the log file, if it doesn't already exist
|
79
79
|
need_array_start = false
|
80
|
+
file_exists = File.exists?(path)
|
80
81
|
if @json == 1
|
81
82
|
need_array_start = true
|
82
|
-
if
|
83
|
+
if file_exists
|
83
84
|
sz = File.size(path)
|
84
85
|
need_array_start = sz == 0
|
85
86
|
|
@@ -93,7 +94,7 @@ Puppet::Util::Log.newdesttype :file do
|
|
93
94
|
file.puts('[') if need_array_start
|
94
95
|
|
95
96
|
# Give ownership to the user and group puppet will run as
|
96
|
-
if Puppet.features.root? && !Puppet::Util::Platform.windows?
|
97
|
+
if Puppet.features.root? && !Puppet::Util::Platform.windows? && !file_exists
|
97
98
|
begin
|
98
99
|
FileUtils.chown(Puppet[:user], Puppet[:group], path)
|
99
100
|
rescue ArgumentError, Errno::EPERM
|
@@ -547,8 +547,6 @@ module Puppet::Util::Windows::ADSI
|
|
547
547
|
def set_members(desired_members, inclusive = true)
|
548
548
|
return if desired_members.nil?
|
549
549
|
|
550
|
-
desired_members = desired_members.split(',').map(&:strip)
|
551
|
-
|
552
550
|
current_hash = Hash[ self.member_sids.map { |sid| [sid.sid, sid] } ]
|
553
551
|
desired_hash = self.class.name_sid_hash(desired_members)
|
554
552
|
|