Skip to content

Commit 02f91fc

Browse files
author
luke
committed
Merging symlinks back into files. Symlinks still exist but with a warning about deprecation. Fixes puppetlabs#93. Also the first time I have run any tests on OS X, so there are some bug fixes related to that.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1000 980ebf18-57e1-0310-9a29-db15c13687c0
1 parent b336e7e commit 02f91fc

File tree

9 files changed

+304
-53
lines changed

9 files changed

+304
-53
lines changed

lib/puppet/type/pfile.rb

+61-3
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ def handleignore(children)
218218
return children unless self[:ignore]
219219
self[:ignore].each { |ignore|
220220
ignored = []
221-
Dir.glob(File.join(self[:path],ignore), File::FNM_DOTMATCH) { |match|
222-
ignored.push(File.basename(match))
221+
Dir.glob(File.join(self[:path],ignore), File::FNM_DOTMATCH) {
222+
|match| ignored.push(File.basename(match))
223223
}
224224
children = children - ignored
225225
}
@@ -229,7 +229,6 @@ def handleignore(children)
229229
def initialize(hash)
230230
# clean out as many references to any file paths as possible
231231
# this was the source of many, many bugs
232-
233232
@arghash = self.argclean(hash)
234233
@arghash.delete(self.class.namevar)
235234

@@ -409,11 +408,70 @@ def recurse
409408
end
410409

411410
self.localrecurse(recurse)
411+
if @states.include?(:ensure) and @states[:ensure].should =~ /^#{File::SEPARATOR}/
412+
self.linkrecurse(recurse)
413+
end
412414
if @states.include?(:source)
413415
self.sourcerecurse(recurse)
414416
end
415417
end
416418

419+
# Build a recursive map of a link source
420+
def linkrecurse(recurse)
421+
target = @states[:ensure].should
422+
423+
method = :lstat
424+
if self[:links] == :follow
425+
method = :stat
426+
end
427+
428+
targetstat = nil
429+
unless FileTest.exist?(target)
430+
#self.info "%s does not exist; not recursing" %
431+
# target
432+
return
433+
end
434+
# Now stat our target
435+
targetstat = File.send(method, target)
436+
unless targetstat.ftype == "directory"
437+
#self.info "%s is not a directory; not recursing" %
438+
# target
439+
return
440+
end
441+
442+
unless FileTest.readable? target
443+
self.notice "Cannot manage %s: permission denied" % self.name
444+
return
445+
end
446+
447+
children = Dir.entries(target).reject { |d| d =~ /^\.+$/ }
448+
449+
#Get rid of ignored children
450+
if @parameters.include?(:ignore)
451+
children = handleignore(children)
452+
end
453+
454+
added = []
455+
children.each do |file|
456+
longname = File.join(@states[:ensure].should, file)
457+
458+
# Files know to create directories when recursion
459+
# is enabled and we're making links
460+
args = {
461+
:recurse => recurse,
462+
:ensure => longname
463+
}
464+
465+
if child = self.newchild(file, true, args)
466+
unless @children.include?(child)
467+
self.push child
468+
added.push file
469+
end
470+
end
471+
end
472+
end
473+
474+
# Build up a recursive map of what's around right now
417475
def localrecurse(recurse)
418476
unless FileTest.exist?(self[:path]) and self.stat.directory?
419477
#self.info "%s is not a directory; not recursing" %

lib/puppet/type/pfile/ensure.rb

+66-23
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,32 @@ module Puppet
33
require 'etc'
44
desc "Whether to create files that don't currently exist.
55
Possible values are *absent*, *present* (equivalent to *file*),
6-
**file**/*directory*. Specifying 'absent' will delete the file,
6+
*file*, and *directory*. Specifying 'absent' will delete the file,
77
although currently this will not recursively delete directories.
8+
9+
Anything other than those values will be considered to be a symlink.
10+
For instance, the following text creates a link::
11+
12+
# Useful on solaris
13+
file { \"/etc/inetd.conf\":
14+
ensure => \"/etc/inet/inetd.conf\"
15+
}
816
9-
This is the only element with an *ensure* state that does not have
10-
a default value."
17+
You can make relative links:
18+
19+
# Useful on solaris
20+
file { \"/etc/inetd.conf\":
21+
ensure => \"inet/inetd.conf\"
22+
}
23+
24+
If you need to make a relative link to a file named the same
25+
as one of the valid values, you must prefix it with ``./`` or
26+
something similar.
27+
28+
You can also make recursive symlinks, which will create a
29+
directory structure that maps to the target directory,
30+
with directories corresponding to each directory
31+
and links corresponding to each file."
1132

1233
# Most 'ensure' states have a default, but with files we, um, don't.
1334
nodefault
@@ -52,6 +73,41 @@ module Puppet
5273
return :directory_created
5374
end
5475

76+
# Symlinks. We pretty much have to match just about anything,
77+
# in order to match relative links. Somewhat ugly, but eh, it
78+
# works.
79+
newvalue(/./) do
80+
Dir.chdir(File.dirname(@parent[:path])) do
81+
target = self.should
82+
unless FileTest.exists?(target)
83+
self.debug "Not linking to non-existent '%s'" % target
84+
nil # Grrr, can't return
85+
else
86+
if FileTest.directory?(target) and @parent[:recurse]
87+
# If we're pointing to a directory and recursion is
88+
# enabled, then make a directory instead of a link.
89+
self.set_directory
90+
else
91+
Puppet::Util.asuser(@parent.asuser()) do
92+
mode = @parent.should(:mode)
93+
if mode
94+
Puppet::Util.withumask(000) do
95+
File.symlink(self.should, @parent[:path])
96+
end
97+
else
98+
File.symlink(self.should, @parent[:path])
99+
end
100+
end
101+
102+
# We can't use "return" here because we're in an anonymous
103+
# block.
104+
:link_created
105+
end
106+
end
107+
end
108+
end
109+
110+
# Check that we can actually create anything
55111
def check
56112
basedir = File.dirname(@parent[:path])
57113

@@ -68,34 +124,21 @@ def check
68124

69125
def retrieve
70126
if stat = @parent.stat(false)
71-
@is = stat.ftype.intern
127+
# If we're a link, set the 'is' value to the destination
128+
# of the link
129+
if stat.ftype == "link"
130+
@is = File.readlink(@parent[:path])
131+
else
132+
@is = stat.ftype.intern
133+
end
72134
else
73135
if self.should == :false
74136
@is = :false
75137
else
76138
@is = :absent
77139
end
78140
end
79-
80-
#self.debug "'exists' state is %s" % self.is
81141
end
82-
83-
84-
# We can mostly rely on the superclass method, but we want other states
85-
# to take precedence over 'ensure' if they are present.
86-
# def sync
87-
# # XXX This is a bad idea, because it almost guarantees bugs if we
88-
# # introduce more states to manage content, but anything else is just
89-
# # about as bad.
90-
# event = nil
91-
# #if state = @parent.state(:source) or state = @parent.state(:content)
92-
# # event = state.sync
93-
# #else
94-
# event = super
95-
# @parent.setchecksum
96-
# #end
97-
# return event
98-
# end
99142
end
100143
end
101144

lib/puppet/type/state.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ def set
7373
[value, self.class.name, detail]
7474
end
7575
elsif ary = self.class.match?(value)
76-
event = ary[1].call(value)
76+
# FIXME It'd be better here to define a method, so that
77+
# the blocks could return values.
78+
event = self.instance_eval(&ary[1])
7779
else
7880
self.fail "%s is not a valid value for %s" %
7981
[value, self.class.name]

lib/puppet/type/symlink.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ def sync
122122
@stat = nil
123123
@target = @parent.state(:ensure).should
124124

125-
self.setparent()
125+
self.setparent(@target)
126126
end
127127

128-
def setparent
128+
def setparent(value)
129129
# we want to remove our state, because we're creating children
130130
# to do the links
131131
if FileTest.exist?(@target)

lib/puppet/type/user.rb

+23-19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,27 @@ module Puppet
1919

2020
newstate(:ensure, @parentstate) do
2121
newvalue(:present) do
22+
# Verify that they have provided everything necessary, if we
23+
# are trying to manage the user
24+
if @parent.managed?
25+
@parent.class.states.each { |state|
26+
next if stateobj = @parent.state(state.name)
27+
next if state.name == :ensure
28+
29+
unless state.autogen? or state.isoptional?
30+
if state.method_defined?(:autogen)
31+
@parent[state.name] = :auto
32+
else
33+
@parent.fail "Users require a value for %s" %
34+
state.name
35+
end
36+
end
37+
}
38+
39+
#if @states.empty?
40+
# @parent[:comment] = @parent[:name]
41+
#end
42+
end
2243
self.syncname(:present)
2344
end
2445

@@ -307,25 +328,8 @@ def initialize(hash)
307328
@userinfo = nil
308329
super
309330

310-
# Verify that they have provided everything necessary, if we
311-
# are trying to manage the user
312-
if self.managed?
313-
self.class.states.each { |state|
314-
next if @states.include?(state.name)
315-
next if state.name == :ensure
316-
317-
unless state.autogen? or state.isoptional?
318-
if state.method_defined?(:autogen)
319-
self[state.name] = :auto
320-
else
321-
self.fail "Users require a value for %s" % state.name
322-
end
323-
end
324-
}
325-
326-
if @states.empty?
327-
self[:comment] = self[:name]
328-
end
331+
unless defined? @states
332+
raise "wtf?"
329333
end
330334
end
331335

0 commit comments

Comments
 (0)