#!/usr/bin/env python3 # vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=python: # Copyright (C) 2013-2016 Ivan Drucker # Copyright (C) 2017 T. Joseph Carter # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # If interested, please see the file HISTORY.md for information about both the # technical and licensing decisions that have gone into the rewriting of cppo. """cppo: Copy/catalog files from a ProDOS/DOS 3.3/ShrinkIt image/archive. copy all files: cppo [options] imagefile target_directory copy one file : cppo [options] imagefile /extract/path target_path catalog image : cppo -cat [options] imagefile options: -shk: ShrinkIt archive as source (also auto-enabled by filename). -ad : Netatalk-compatible AppleDouble metadata files and resource forks. -e : Nulib2-compatible filenames with type/auxtype and resource forks. -uc : Copy GS/OS mixed case filenames as uppercase. -pro: Adapt DOS 3.3 names to ProDOS and remove addr/len from file data. /extract/path examples: /FULL/PRODOS/PATH (ProDOS image source) "MY FILENAME" (DOS 3.3 image source) Dir:SubDir:FileName (ShrinkIt archive source) + after a file name indicates a GS/OS or Mac OS extended (forked) file. Wildcard matching (*) is not supported and images are not validated. ShrinkIt support requires Nulib2. cppo requires Python 3.5+.""" import sys import os import blocksfree.legacy import blocksfree.logging as logging LOG = logging.LOG def usage(exitcode=1): """Print script usage and exit "gracefully" Args: exitcode: The shell return value (1 is appropriate for errors) """ print(sys.modules[__name__].__doc__) sys.exit(exitcode) #pylint: disable=too-many-branches,too-many-statements def main() -> None: """provide the legacy cppo CLI interface""" # Setup logging handler = logging.StreamHandler(sys.stdout) formatter = logging.Formatter('{message}', style='{') handler.setFormatter(formatter) LOG.logger.addHandler(handler) LOG.setLevel(logging.DEBUG) g = blocksfree.legacy.g #pylint: disable=invalid-name args = sys.argv while True: if len(args) == 1: usage() # End of flags elif args[1][0] != '-': break # [UNDOCUMENTED] suppress afpsync message elif args[1] == '-s': g.afpsync_msg = False args = args[1:] # [UNDOCUMENTED] extract files in place elif args[1] == '-n': g.extract_in_place = True args = args[1:] # Extract GS/OS mixed case filenames as uppercase elif args[1] == '-uc': g.casefold_upper = True args = args[1:] # Create netatalk-compatible AppleDouble resource forks and type data elif args[1] == '-ad': g.use_appledouble = True g.prodos_names = True args = args[1:] # Source file is ShrinkIt format (may be implied by extension) elif args[1] == '-shk': g.src_shk = True args = args[1:] # Adapt DOS 3.3 files to ProDOS format elif args[1] == '-pro': g.prodos_names = True args = args[1:] # Extract filenames using nulib2 conventsions for type/fork info elif args[1] == '-e': g.use_extended = True g.prodos_names = True args = args[1:] # Catalog image rather than extract it elif args[1] == '-cat': g.catalog_only = True args = args[1:] else: usage() if g.use_appledouble and g.use_extended: usage() if g.catalog_only: if len(args) != 2: usage() else: if len(args) not in (3, 4): usage() g.image_file = args[1] if len(args) == 4: g.extract_file = args[2] if g.extract_file: target_path = args[3] if os.path.isdir(target_path): g.target_dir = target_path elif len(target_path.rsplit("/", 1)) > 1: g.target_dir, g.target_name = target_path.rsplit("/", 1) if not os.path.isdir(g.target_dir): LOG.critical("Directory {} not found.".format(g.target_dir)) sys.exit(2) else: if not g.catalog_only: g.target_dir = args[2] if not os.path.isdir(g.target_dir): LOG.critical("Directory {} not found.".format(g.target_dir)) sys.exit(2) blocksfree.legacy.run_cppo() #pylint: enable=too-many-branches,too-many-statements if __name__ == '__main__': main()