cppo-ng/cppo

165 lines
4.6 KiB
Python
Executable File

#!/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()