Skip to content

Commit

Permalink
- Added basic support for vendor PPD options. PPD options can be spec…
Browse files Browse the repository at this point in the history
…ified using the `ppd_options` property, and are specific to the queue you are defining.

- Updated README to reflect the new ppd_options property.
  • Loading branch information
mosen committed Sep 14, 2012
1 parent 05e4ad4 commit 429feb3
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 18 deletions.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -71,7 +71,8 @@ An example using almost every possible parameter:
# list of installed drivers.
enabled => true, # Enabled by default
shared => false, # Disabled by default
options => { media => 'A4' }, # Hash of options ( name => value ), highly depends on the printer.
options => { media => 'A4' }, # Hash of options ( name => value ), these are non vendor specific options.
ppd_options => { 'HPOption_Duplexer' => 'False' }, # Hash of vendor PPD options
}

- The easiest way to find out a list of valid options for any single printer is to install that printer locally, and
Expand Down
65 changes: 49 additions & 16 deletions lib/puppet/provider/printer/cups.rb
Expand Up @@ -76,6 +76,7 @@ def self.prefetch(resources)

printer[:ensure] = :present
printer[:options] = self.printer_options(name, resource)
printer[:ppd_options] = self.ppd_options(name, resource)
printer[:provider] = :cups
printer[:uri] = prefetched_uris[printer[:name]] if prefetched_uris.key?(printer[:name])

Expand Down Expand Up @@ -132,7 +133,8 @@ def self.printers_long
end


# Retrieve options explicitly specified by the type definition.
# I only retrieve options that are specified in the type definition, which avoids resetting all options at once.
# queue options are space separated, and come in pairs separated by equals(=)
def self.printer_options(destination, resource)
options = {}

Expand All @@ -147,6 +149,27 @@ def self.printer_options(destination, resource)
options
end

# vendor PPD options are formatted differently:
# ShortName/Long Name: *Selected NotSelectedValue
def self.ppd_options(destination, resource)
ppdopts = {}

return ppdopts unless resource[:ppd_options].kind_of? Hash

lpoptions('-d', destination, '-l').each_line do |line|
keyvalues = line.split(':')
key = /^([^\/]*)/.match(keyvalues[0]).captures[0]

next unless resource[:ppd_options].key? key

selected_value = /\s\*([^\s]*)\s/.match(keyvalues[1]).captures[0]

ppdopts[key] = selected_value
end

ppdopts
end

def self.printer_uris
begin
uris = {}
Expand Down Expand Up @@ -186,20 +209,21 @@ def flush
lpadmin "-x", name
when :present
# Regardless of whether the printer is being added or modified, the `lpadmin -p` command is used.
# Sometimes, in the case of `-E` or `-o` parameters, lpadmin seems to do nothing under some circumstances.
# For this reason, I'm running cupsenable/reject and lpoptions to ensure those values match what we expect.

# BUG: flush should never be called if only the model or PPD parameters differ, because lpstat can't tell
# what the actual value is.

params = Array.new # lpadmin parameters
options = Array.new # lpoptions parameters
vendor_options = Array.new # ppd options

# Handle most parameters via string substitution
Cups_Options.keys.each do |k|
params.unshift Cups_Options[k] % @resource[k] if @resource[k]
end



options.push '-o printer-is-shared=true' if @property_hash[:shared] === :true

if @property_hash[:options].is_a? Hash
Expand All @@ -214,6 +238,12 @@ def flush
end
end

if @property_hash[:ppd_options].is_a? Hash
@property_hash[:ppd_options].each_pair do |k, v|
vendor_options.push "-o %s=%s" % [k, v]
end
end

begin
# -E means different things when it comes before or after -p, see man page for explanation.
if @property_hash[:enabled] === :true and @property_hash[:accept] === :true
Expand All @@ -226,20 +256,23 @@ def flush
lpoptions "-p", name, options
end

# -E option covers enable & accept both true, and allows us to skip the other utilities.
#unless @property_hash[:enabled] === :true and @property_hash[:accept] === :true
if @property_hash[:enabled] === :true
cupsenable name
else
cupsdisable name
end
unless vendor_options.empty?
lpoptions "-p", name, vendor_options
end

if @property_hash[:accept] === :true
cupsaccept name
else
cupsreject name
end
#end
# Normally, the -E option would let us skip cupsenable/accept.
# But the behaviour seems unpredictable when the queue already exists.
if @property_hash[:enabled] === :true
cupsenable name
else
cupsdisable name
end

if @property_hash[:accept] === :true
cupsaccept name
else
cupsreject name
end
rescue Exception => e
# If an option turns out to be invalid, CUPS will normally add the printer anyway.
# Normally, the printer should not even be created, so we delete it again to make things consistent.
Expand Down
12 changes: 11 additions & 1 deletion lib/puppet/type/printer.rb
Expand Up @@ -59,13 +59,23 @@
end

newproperty(:options) do
desc "Sets a list of PPD options for the printer"
desc "Sets a list of options for the printer"

validate do |value|
raise ArgumentError, "invalid value supplied for printer options" unless value.is_a? Hash
end
end

newproperty(:ppd_options) do
desc "Sets a list of PPD (vendor specific) options for the printer.
Use lpoptions -p destination -l to get a list of valid vendor PPD options for that queue."

validate do |value|
raise ArgumentError, "invalid value supplied for printer PPD options" unless value.is_a? Hash
end
end

# Allow a printer resource without explicitly specifying a file resource for the PPD.
autorequire(:file) do
self[:ppd] if self[:ppd]
Expand Down

0 comments on commit 429feb3

Please sign in to comment.