Skip to content

Commit

Permalink
Printer rotation command (#174)
Browse files Browse the repository at this point in the history
* Parsing for mod printer

* Implemented mod-printer functionality

* Test and bugfix mod-printer

* Update mod-printer with more modern Python functions

* Change mod-printer to subparsers

* Add list_printers mod-printer base function

* Add list subcommand to mod-printer

* Minor mod-printer doc fix

* Fix mod-printer formatting, general verbosity
  • Loading branch information
Boomaa23 authored and Justin Zhang committed Mar 12, 2022
1 parent 39e403b commit 6bb978f
Showing 1 changed file with 111 additions and 0 deletions.
111 changes: 111 additions & 0 deletions staff/lab/mod-printer
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env python3
"""Remove or add printers to/from CUPS classes."""
import argparse
import re
import subprocess
import sys


def modify_printer(args):
"""Perform internal call to CUPS CLI to modify class(es)."""
# Determine which CUPS classes are available
lpstat_proc = subprocess.run(['lpstat', '-p'], check=True,
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
lpstat_out = lpstat_proc.stdout.decode('utf-8').strip().split('\n')

# Parse lpstat output for printer class names
# Output is of the form: printer <printername> is idle. <etc>
cups_classes = [re.search(r'printer (\S*) is', classname).group(1) for classname in lpstat_out]

if args.verbose:
print('Found CUPS classes: %s' % cups_classes)

# Override with specified classname if provided and valid
if args.classname:
if args.classname in cups_classes:
cups_classes = [args.classname]
if args.verbose:
print('Overriding CUPS classes with parameter: %s' % args.classname)
else:
print('ERROR: Specified class %s could not be found in available classes %s'
% (args.classname, cups_classes))
return 1

# Perform pre-call logging and input processing
printer = args.printer.lower()
if args.verbose:
print('Printer to perform action on: %s' % printer)
action_flag = '-r' if args.action == 'remove' else '-c'
if args.verbose:
print('Action to be performed (and flag): %s (%s)' % (args.action, action_flag))

# Call lpadmin command to perform addition/removal
for classname in cups_classes:
action_cmd = ['lpadmin', '-p', printer + '-' + classname, action_flag, classname]
subprocess.run(action_cmd, check=True)
action_out = 'added to' if args.action == 'add' else 'removed from'
print('Printer %s was successfully %s %s' % (printer, action_out, classname))


def list_printers(args):
"""Perform internal call to CUPS CLI to list printer status(es) (and potentially jobs)."""
# Initialize base lpstat command
lpstat_cmd = ['lpstat', '-c']

# Add on to lpstat command with arguments
if args.classname:
lpstat_cmd.append(args.classname)
if args.jobs:
lpstat_cmd.append('-o')

if args.verbose:
print('Calling %s to list printer status' % lpstat_cmd)

# Call lpstat - prints members of the class and can
# be configured to include jobs as well. No way to
# check for printers not in classes.
lpstat_proc = subprocess.run(lpstat_cmd, check=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)

# Parse output to fit printer arg, or send directly to stdout
status_msgs = lpstat_proc.stdout.decode('utf-8')
if args.printer:
for line in status_msgs.split('\n'):
if args.printer in line or 'members of class' in line:
print(line)
else:
print(status_msgs, end='')


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-v', '--verbose', '--debug',
action='store_true',
help='output more verbose logging to stdout'
)
parser.add_argument('-c', '--classname', help='modify/list only a specific class')

subparsers = parser.add_subparsers(dest='action', help='action to perform', required=True)

add_parser = subparsers.add_parser('add', help='add a printer')
add_parser.add_argument('printer', help='name of printer to add')

remove_parser = subparsers.add_parser('remove', help='remove a printer')
remove_parser.add_argument('printer', help='name of printer to remove')

list_parser = subparsers.add_parser('list', help='list printer statuses')
list_parser.add_argument('-p', '--printer', help='list only this named printer')
list_parser.add_argument('-j', '--jobs',
action='store_true', help='include print jobs')

args = parser.parse_args()
if args.action == 'add' or args.action == 'remove':
return modify_printer(args)
elif args.action == 'list':
return list_printers(args)
else:
print('ERROR: Invalid action passed %s' % args.action)
return 1


if __name__ == '__main__':
sys.exit(main())

0 comments on commit 6bb978f

Please sign in to comment.