1+ #!/usr/bin/env python
2+ # -*- coding: utf-8 -*-
3+ from __future__ import absolute_import , division , print_function , unicode_literals
4+
5+ import sys , os , io , argparse
6+
7+ try :
8+ import pycatfile as P # core must provide *_neo functions
9+ except Exception as e :
10+ sys .stderr .write ("Failed to import core module 'pycatfile': %s\n " % (e ,))
11+ sys .exit (2 )
12+
13+
14+ def _expand_combined_short_opts (argv ):
15+ out = [argv [0 ]]
16+ i = 1
17+ while i < len (argv ):
18+ a = argv [i ]
19+ if a .startswith ("--" ) or not (a .startswith ("-" ) and len (a ) > 2 ):
20+ out .append (a ); i += 1 ; continue
21+ for ch in a [1 :]:
22+ out .append ("-" + ch )
23+ i += 1
24+ return out
25+
26+
27+ def main ():
28+ argv = _expand_combined_short_opts (sys .argv )
29+
30+ p = argparse .ArgumentParser (
31+ description = "PyNeoFile CLI (uses pycatfile core)" )
32+ g = p .add_mutually_exclusive_group (required = True )
33+ g .add_argument ("-l" , "--list" , action = "store_true" , help = "List archive" )
34+ g .add_argument ("-e" , "--extract" , action = "store_true" , help = "Extract archive" )
35+ g .add_argument ("-c" , "--create" , action = "store_true" , help = "Create archive from path" )
36+ g .add_argument ("-r" , "--repack" , action = "store_true" , help = "Repack (recompress) an archive" )
37+ g .add_argument ("-E" , "--empty" , action = "store_true" , help = "Create an empty archive" )
38+
39+ p .add_argument ("-i" , "--input" , help = "Input file/path" , nargs = "*" )
40+ p .add_argument ("-o" , "--output" , help = "Output file/dir (or '-' for stdout)" )
41+ p .add_argument ("-d" , "--verbose" , action = "store_true" , help = "Verbose/detailed listing" )
42+ p .add_argument ("-P" , "--compression" , default = "auto" , help = "Compression algo (auto, none, zlib, gzip, bz2, lzma)" )
43+ p .add_argument ("-L" , "--level" , type = int , default = None , help = "Compression level/preset" )
44+ p .add_argument ("--checksum" , default = "crc32" , help = "Checksum type for header/content/json (default: crc32)" )
45+
46+ args = p .parse_args (argv [1 :])
47+
48+ src = None
49+ if args .input :
50+ if isinstance (args .input , list ) and len (args .input ) == 1 :
51+ src = args .input [0 ]
52+ elif isinstance (args .input , list ) and len (args .input ) > 1 :
53+ src = args .input [0 ]
54+ else :
55+ src = args .input
56+
57+ if args .empty :
58+ dst = args .output or "-"
59+ blob_or_true = P .make_empty_file_neo (dst , fmttype = "auto" , checksumtype = args .checksum , encoding = "UTF-8" , returnfp = False )
60+ if dst in (None , "-" ):
61+ data = blob_or_true if isinstance (blob_or_true , (bytes , bytearray )) else b""
62+ if hasattr (sys .stdout , "buffer" ):
63+ sys .stdout .buffer .write (data )
64+ else :
65+ sys .stdout .write (data .decode ("latin1" ))
66+ return 0
67+
68+ if args .list :
69+ if not src :
70+ p .error ("list requires -i <archive>" )
71+ P .archivefilelistfiles_neo (src , advanced = args .verbose , include_dirs = True )
72+ return 0
73+
74+ if args .extract :
75+ if not src :
76+ p .error ("extract requires -i <archive>" )
77+ outdir = args .output or "."
78+ ok = P .unpack_neo (src , outdir , skipchecksum = False , uncompress = True )
79+ return 0 if ok else 1
80+
81+ if args .create :
82+ if not src :
83+ p .error ("create requires -i <path>" )
84+ if args .verbose :
85+ walkroot = src
86+ if os .path .isdir (walkroot ):
87+ print (walkroot )
88+ for root , dirs , files in os .walk (walkroot ):
89+ relroot = root if root .startswith ("./" ) else "./" + root .replace ("\\ " , "/" )
90+ if root != walkroot :
91+ print (relroot )
92+ for name in sorted (files ):
93+ path = os .path .join (root , name ).replace ("\\ " , "/" )
94+ if not path .startswith ("./" ):
95+ path = "./" + path
96+ print (path )
97+ else :
98+ path = src if src .startswith ("./" ) else "./" + src
99+ print (path )
100+
101+ outpath = args .output or "-"
102+ ok = P .pack_neo (src , outpath , checksumtypes = (args .checksum ,args .checksum ,args .checksum ,args .checksum ),
103+ encoding = "UTF-8" , compression = args .compression , compression_level = args .level )
104+ if outpath in (None , "-" ) and isinstance (ok , (bytes , bytearray )):
105+ if hasattr (sys .stdout , "buffer" ):
106+ sys .stdout .buffer .write (ok )
107+ else :
108+ sys .stdout .write (ok .decode ("latin1" ))
109+ return 0
110+ return 0 if ok else 1
111+
112+ if args .repack :
113+ if not src :
114+ p .error ("repack requires -i <archive>" )
115+ outpath = args .output or "-"
116+ ok = P .repack_neo (src , outpath , checksumtypes = (args .checksum ,args .checksum ,args .checksum ,args .checksum ),
117+ compression = args .compression , compression_level = args .level )
118+ if outpath in (None , "-" ) and isinstance (ok , (bytes , bytearray )):
119+ if hasattr (sys .stdout , "buffer" ):
120+ sys .stdout .buffer .write (ok )
121+ else :
122+ sys .stdout .write (ok .decode ("latin1" ))
123+ return 0
124+ return 0 if ok else 1
125+
126+ return 0
127+
128+
129+ if __name__ == "__main__" :
130+ sys .exit (main ())
0 commit comments