Add wildcard arguments to rfx

This commit is contained in:
Elliot Nunn 2020-01-10 20:20:17 +08:00
parent 4dab2dfd14
commit 30e91e860d
1 changed files with 58 additions and 18 deletions

76
bin/rfx
View File

@ -3,6 +3,7 @@
import macresources
import sys
import tempfile
import os
from os import path
import re
import subprocess
@ -11,16 +12,17 @@ import textwrap
if len(sys.argv) < 2 or sys.argv[1].startswith('-'):
sys.exit(textwrap.dedent('''
usage: rfx command [arg[//type/id] ...]
usage: rfx command [arg | arg// | arg//type | arg//type/id ...]
Shell command wrapper for accessing resources inside a Rez textfile
Resources specified as filename.rdump//type/id are converted to tempfiles before
the command is run, and back to resources after the command returns.
the command is run, and back to resources after the command returns. Truncated
// arguments are wildcards.
examples:
rfx mv Doc.rdump//STR/0 Doc.rdump//STR/1
rfx cp App.rdump//PICT/2000 2000.pict
rfx cp App.rdump//PICT allpictures/
rfx rm System.rdump//vers/2
''').strip())
@ -109,28 +111,66 @@ def rez_delete_resource(the_path, the_type, the_id):
del the_file[start:stop]
def escape_ostype(ostype):
escaped = ''
for char in ostype:
if ord('A') <= char <= ord('Z') or ord('a') <= char <= ord('z'):
escaped += chr(char)
else:
escaped += '_%02X' % char
return escaped
with tempfile.TemporaryDirectory() as backup_tmp_dir:
new_argv = [sys.argv[1]]
to_retrieve = []
for i, arg in enumerate(sys.argv[2:], 1):
m = re.match(r'(.*[^/])//([^/]{1,4})/(-?\d+)$'.replace('/', re.escape(path.sep)), arg)
m = re.match(r'(.*[^/])//(?:([^/]{1,4})(?:/(-?\d+)?)?)?$'.replace('/', re.escape(path.sep)), arg)
if m:
res_spec = (m.group(1), m.group(2).encode('mac_roman').ljust(4)[:4], int(m.group(3)))
tmp_file = path.join(backup_tmp_dir, str(i))
to_retrieve.append((tmp_file, res_spec))
res_data = rez_get_resource(*res_spec)
if res_data is not None:
with open(tmp_file, 'wb') as f:
f.write(res_data)
new_argv.append(tmp_file)
else:
if not m:
# Do not expand this argument
new_argv.append(arg)
else:
# Expand arg into 1+ fake-resource tempfiles. This is a (filename, type, id) list.
res_specs = []
res_file = m.group(1)
res_type = m.group(2).encode('mac_roman').ljust(4)[:4] if m.group(2) else None
res_id = int(m.group(3)) if m.group(3) else None
if res_type is None:
# File// = every resource
for found_res in macresources.parse_rez_code(get_cached_file(res_file)):
res_specs.append((res_file, found_res.type, found_res.id))
elif res_id is None:
# File//Type/ = resources of type (can omit trailing slash)
for found_res in macresources.parse_rez_code(get_cached_file(res_file)):
if found_res.type == res_type:
res_specs.append((res_file, res_type, found_res.id))
else:
# File//Type/ID = 1 resource
res_specs.append((res_file, res_type, res_id))
if not res_specs:
# Failed to expand so leave unchanged
new_argv.append(arg)
else:
# Expand!
tmp_subdir = path.join(backup_tmp_dir, str(i))
os.mkdir(tmp_subdir)
for res_spec in res_specs:
res_file, res_type, res_id = res_spec
tmp_file = path.join(tmp_subdir, '%s.%d' % (escape_ostype(res_type), res_id))
to_retrieve.append((tmp_file, res_spec))
res_data = rez_get_resource(*res_spec)
if res_data is not None:
with open(tmp_file, 'wb') as f:
f.write(res_data)
new_argv.append(tmp_file)
result = subprocess.run(new_argv)