forked from nmcspadden/PrinterGenerator
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathAirPrint_Generator_Outset.py
214 lines (191 loc) · 10.3 KB
/
AirPrint_Generator_Outset.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/local/munki/munki-python
# AirPrint_Generator_Outset
# Version 1.1
# Updated 3/17/22
from __future__ import absolute_import, print_function
import argparse
import csv
import os
import re
import sys
try:
from plistlib import load as load_plist # Python 3
from plistlib import dump as dump_plist
except ImportError:
from plistlib import readPlist as load_plist # Python 2
from plistlib import writePlist as dump_plist
def getOptionsString(optionList):
# optionList should be a list item
optionsString = ''
for option in optionList:
if option == optionList[-1]:
optionsString += "\"%s\":\"%s\"" % (str(option.split('=')[0]), str(option.split('=')[1]))
else:
optionsString += "\"%s\":\"%s\"" % (str(option.split('=')[0]), str(option.split('=')[1])) + ', '
return optionsString
parser = argparse.ArgumentParser(description='Generate a Munki nopkg-style pkginfo for printer installation.')
parser.add_argument('--printername', help='Name of printer queue. May not contain spaces, tabs, # or /. Required.')
parser.add_argument('--address', help='IP or DNS address of printer. Defaults to ipp:// which should be used for AirPrint. Required.')
parser.add_argument('--location', help='Location name for printer. Optional. Defaults to printername.')
parser.add_argument('--displayname', help='Display name for printer (and Munki pkginfo). Optional. Defaults to printername.')
parser.add_argument('--desc', help='Description for Munki pkginfo only. Optional.')
parser.add_argument('--requires', help='Required packages in form of space-delimited \'CanonDriver1 CanonDriver2\'. Optional.')
parser.add_argument('--options', nargs='*', dest='options', help='Printer options in form of space-delimited \'Option1=Key Option2=Key Option3=Key\', etc. Optional.')
parser.add_argument('--version', help='Version number of Munki pkginfo. Optional. Defaults to 1.0.', default='1.0')
parser.add_argument('--icon', help='Specifies an existing icon in the Munki repo to display for the printer in Managed Software Center. Optional.')
parser.add_argument('--csv', help='Path to CSV file containing printer info. If CSV is provided, all other options are ignored.')
args = parser.parse_args()
pwd = os.path.dirname(os.path.realpath(__file__))
f = open(os.path.join(pwd, 'AirPrinter-Template-Outset.plist'), 'rb')
templatePlist = load_plist(f)
f.close()
if args.csv:
# A CSV was found, use that for all data.
with open(args.csv, mode='r') as infile:
reader = csv.reader(infile)
next(reader, None) # skip the header row
for row in reader:
newPlist = dict(templatePlist)
# each row contains 10 elements:
# Printer name, location, display name, address, driver, description, options, version, requires, icon
# options in the form of "Option=Value Option2=Value Option3=Value"
# requires in the form of "package1 package2" Note: the space seperator
theOptionString = ''
if row[6] != "":
theOptionString = getOptionsString(row[6].split(" "))
# First, change the plist keys in the pkginfo itself
newPlist['display_name'] = row[2]
newPlist['description'] = row[5]
newPlist['name'] = "Printer_" + str(row[0]) # set to printer name
# Check for an icon
if row[9] != "":
newPlist['icon_name'] = row[9]
# Check for a version number
if row[7] != "":
# Assume the user specified a version number
version = row[7]
else:
# Use the default version of 1.0
version = "1.0"
newPlist['version'] = version
# Check for a protocol listed in the address
if '://' in row[3]:
# Assume the user passed in a full address and protocol
address = row[3]
else:
# Assume the user wants to use the default, ipp://
address = 'ipp://' + row[3]
# Set the path to the programmatically generated PPD
driver = '/tmp/%s.ppd' % row[0]
# Now change the variables in the installcheck_script
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("PRINTERNAME", row[0])
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("OPTIONS", theOptionString)
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("LOCATION", row[1].replace('"', ''))
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("DISPLAY_NAME", row[2].replace('"', ''))
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("ADDRESS", address)
# Now change the variables in the preinstall_script
newPlist['preinstall_script'] = newPlist['preinstall_script'].replace("PRINTERNAME", row[0])
newPlist['preinstall_script'] = newPlist['preinstall_script'].replace("ADDRESS", address)
# Now change the variables in the postinstall_script
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("PRINTERNAME", row[0])
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("LOCATION", row[1].replace('"', ''))
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("DISPLAY_NAME", row[2].replace('"', ''))
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("ADDRESS", address)
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("DRIVER", driver)
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("OPTIONS", theOptionString)
# Now change the one variable in the uninstall_script
newPlist['uninstall_script'] = newPlist['uninstall_script'].replace("PRINTERNAME", row[0])
# Add required packages if passed in the csv
if row[8] != "":
newPlist['requires'] = row[8].split(' ')
# Write out the file
newFileName = "Printer-" + row[0] + "-" + version + ".pkginfo"
f = open(newFileName, 'wb')
dump_plist(newPlist, f)
f.close()
else:
if not args.printername:
print(os.path.basename(sys.argv[0]) + ': error: argument --printername is required', file=sys.stderr)
parser.print_usage()
sys.exit(1)
#if not args.driver:
# print(os.path.basename(sys.argv[0]) + ': error: argument --driver is required', file=sys.stderr)
# parser.print_usage()
# sys.exit(1)
if not args.address:
print(os.path.basename(sys.argv[0]) + ': error: argument --address is required', file=sys.stderr)
parser.print_usage()
sys.exit(1)
if re.search(r"[\s#/]", args.printername):
# printernames can't contain spaces, tabs, # or /. See lpadmin manpage for details.
print("ERROR: Printernames can't contain spaces, tabs, # or /.", file=sys.stderr)
sys.exit(1)
if args.desc:
description = args.desc
else:
description = ""
if args.displayname:
displayName = args.displayname
else:
displayName = str(args.printername)
if args.location:
location = args.location
else:
location = args.printername
if args.version:
version = str(args.version)
else:
version = "1.0"
if args.requires:
requires = args.requires
else:
requires = ""
if args.icon:
icon = args.icon
else:
icon = ""
if args.options:
optionsString = str(args.options[0]).split(' ')
optionsString = getOptionsString(optionsString)
else:
optionsString = ''
# Set the path to the automatically created PPD
driver = '/tmp/%s.ppd' % args.printername
if '://' in args.address:
# Assume the user passed in a full address and protocol
address = args.address
else:
# Assume the user wants to use the default, ipp://
address = 'ipp://' + args.address
newPlist = dict(templatePlist)
# root pkginfo variable replacement
newPlist['description'] = description
newPlist['display_name'] = displayName
newPlist['name'] = "Printer_" + args.printername
newPlist['version'] = version
newPlist['icon_name'] = icon
# installcheck_script variable replacement
newPlist['installcheck_script'] = templatePlist['installcheck_script'].replace("PRINTERNAME", args.printername)
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("ADDRESS", address)
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("DISPLAY_NAME", displayName)
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("LOCATION", location.replace('"', ''))
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("OPTIONS", optionsString)
# preinstall_script variable replacment
newPlist['preinstall_script'] = templatePlist['preinstall_script'].replace("PRINTERNAME", args.printername)
newPlist['preinstall_script'] = newPlist['preinstall_script'].replace("ADDRESS", address)
# postinstall_script variable replacement
newPlist['postinstall_script'] = templatePlist['postinstall_script'].replace("PRINTERNAME", args.printername)
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("ADDRESS", address)
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("DISPLAY_NAME", displayName)
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("LOCATION", location.replace('"', ''))
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("DRIVER", driver)
newPlist['postinstall_script'] = newPlist['postinstall_script'].replace("OPTIONS", optionsString)
# uninstall_script variable replacement
newPlist['uninstall_script'] = templatePlist['uninstall_script'].replace("PRINTERNAME", args.printername)
# required packages
if requires != "":
newPlist['requires'] = [r.replace('\\', '') for r in re.split(r"(?<!\\)\s", requires)]
newFileName = "Printer-" + str(args.printername) + "-%s.pkginfo" % str(version)
f = open(newFileName, 'wb')
dump_plist(newPlist, f)
f.close()