diff options
Diffstat (limited to 'Mac/scripts')
-rw-r--r-- | Mac/scripts/BuildApplet.py | 260 | ||||
-rw-r--r-- | Mac/scripts/EditPythonPrefs.py | 168 | ||||
-rw-r--r-- | Mac/scripts/PackLibDir.py | 93 | ||||
-rw-r--r-- | Mac/scripts/RunLibScript.py | 108 |
4 files changed, 629 insertions, 0 deletions
diff --git a/Mac/scripts/BuildApplet.py b/Mac/scripts/BuildApplet.py new file mode 100644 index 0000000..cf90901 --- /dev/null +++ b/Mac/scripts/BuildApplet.py @@ -0,0 +1,260 @@ +"""Create an applet from a Python script. + +This puts up a dialog asking for a Python source file ('TEXT'). +The output is a file with the same name but its ".py" suffix dropped. +It is created by copying an applet template and then adding a 'PYC ' +resource named __main__ containing the compiled, marshalled script. +""" + +import sys +sys.stdout = sys.stderr + +import string +import os +import marshal +import imp +import macfs +import MacOS +from Res import * + +# .pyc file (and 'PYC ' resource magic number) +MAGIC = imp.get_magic() + +# Template file (searched on sys.path) +TEMPLATE = "PythonApplet" + +# Specification of our resource +RESTYPE = 'PYC ' +RESNAME = '__main__' + +# A resource with this name sets the "owner" (creator) of the destination +OWNERNAME = "owner resource" + +# OpenResFile mode parameters +READ = 1 +WRITE = 2 + +def main(): + + # Find the template + # (there's no point in proceeding if we can't find it) + + for p in sys.path: + template = os.path.join(p, TEMPLATE) + try: + tmpl = open(template, "rb") + tmpl.close() + break + except IOError: + continue + else: + die("Template %s not found" % `template`) + return + + # Convert to full pathname + template = macfs.FSSpec(template).as_pathname() + + # Ask for source text if not specified in sys.argv[1:] + + if not sys.argv[1:]: + srcfss, ok = macfs.StandardGetFile('TEXT') + if not ok: + return + filename = srcfss.as_pathname() + tp, tf = os.path.split(filename) + if tf[-3:] == '.py': + tf = tf[:-3] + else: + tf = tf + '.applet' + dstfss, ok = macfs.StandardPutFile('Save application as:', tf) + if not ok: return + process(template, filename, dstfss.as_pathname()) + else: + + # Loop over all files to be processed + for filename in sys.argv[1:]: + process(template, filename, '') + +undefs = ('Atmp', '????', ' ', '\0\0\0\0', 'BINA') + +def process(template, filename, output): + + print "Processing", `filename`, "..." + + # Read the source and compile it + # (there's no point overwriting the destination if it has a syntax error) + + fp = open(filename) + text = fp.read() + fp.close() + try: + code = compile(text, filename, "exec") + except (SyntaxError, EOFError): + die("Syntax error in script %s" % `filename`) + return + + # Set the destination file name + + if string.lower(filename[-3:]) == ".py": + destname = filename[:-3] + rsrcname = destname + '.rsrc' + else: + destname = filename + ".applet" + rsrcname = filename + '.rsrc' + + if output: + destname = output + # Copy the data from the template (creating the file as well) + + tmpl = open(template, "rb") + dest = open(destname, "wb") + data = tmpl.read() + if data: + dest.write(data) + dest.close() + tmpl.close() + + # Copy the creator of the template to the destination + # unless it already got one. Set type to APPL + + tctor, ttype = MacOS.GetCreatorAndType(template) + ctor, type = MacOS.GetCreatorAndType(destname) + if type in undefs: type = 'APPL' + if ctor in undefs: ctor = tctor + + # Open the output resource fork + + try: + output = FSpOpenResFile(destname, WRITE) + except MacOS.Error: + print "Creating resource fork..." + CreateResFile(destname) + output = FSpOpenResFile(destname, WRITE) + + # Copy the resources from the template + + input = FSpOpenResFile(template, READ) + newctor = copyres(input, output) + CloseResFile(input) + if newctor: ctor = newctor + + # Copy the resources from the target specific resource template, if any + + try: + input = FSpOpenResFile(rsrcname, READ) + except MacOS.Error: + pass + else: + newctor = copyres(input, output) + CloseResFile(input) + if newctor: ctor = newctor + + # Now set the creator and type of the destination + + MacOS.SetCreatorAndType(destname, ctor, type) + + # Make sure we're manipulating the output resource file now + + UseResFile(output) + + # Delete any existing 'PYC 'resource named __main__ + + try: + res = Get1NamedResource(RESTYPE, RESNAME) + res.RemoveResource() + except Error: + pass + + # Create the raw data for the resource from the code object + + data = marshal.dumps(code) + del code + data = (MAGIC + '\0\0\0\0') + data + + # Create the resource and write it + + id = 0 + while id < 128: + id = Unique1ID(RESTYPE) + res = Resource(data) + res.AddResource(RESTYPE, id, RESNAME) + res.WriteResource() + res.ReleaseResource() + + # Close the output file + + CloseResFile(output) + + # Give positive feedback + + message("Applet %s created." % `destname`) + + +# Copy resources between two resource file descriptors. +# Exception: don't copy a __main__ resource. +# If a resource's name is "owner resource", its type is returned +# (so the caller can use it to set the destination's creator) + +def copyres(input, output): + ctor = None + UseResFile(input) + ntypes = Count1Types() + for itype in range(1, 1+ntypes): + type = Get1IndType(itype) + nresources = Count1Resources(type) + for ires in range(1, 1+nresources): + res = Get1IndResource(type, ires) + id, type, name = res.GetResInfo() + lcname = string.lower(name) + if (type, lcname) == (RESTYPE, RESNAME): + continue # Don't copy __main__ from template + if lcname == OWNERNAME: ctor = type + size = res.size + attrs = res.GetResAttrs() + print id, type, name, size, hex(attrs) + res.LoadResource() + res.DetachResource() + UseResFile(output) + try: + res2 = Get1Resource(type, id) + except MacOS.Error: + res2 = None + if res2: + print "Overwriting..." + res2.RemoveResource() + res.AddResource(type, id, name) + res.WriteResource() + attrs = attrs | res.GetResAttrs() + print "New attrs =", hex(attrs) + res.SetResAttrs(attrs) + UseResFile(input) + return ctor + + +# Show a message and exit + +def die(str): + message(str) + sys.exit(1) + + +# Show a message + +def message(str, id = 256): + from Dlg import * + d = GetNewDialog(id, -1) + if not d: + print "Error:", `str` + print "DLOG id =", id, "not found." + return + tp, h, rect = d.GetDialogItem(2) + SetDialogItemText(h, str) + while 1: + n = ModalDialog(None) + if n == 1: break + del d + + +if __name__ == '__main__': + main() + diff --git a/Mac/scripts/EditPythonPrefs.py b/Mac/scripts/EditPythonPrefs.py new file mode 100644 index 0000000..3e14ff3 --- /dev/null +++ b/Mac/scripts/EditPythonPrefs.py @@ -0,0 +1,168 @@ +"""Edit the Python Preferences file.""" +import addpack +addpack.addpack('Tools') +addpack.addpack('bgen') +addpack.addpack('evt') + +from Dlg import * +from Events import * +from Res import * +import string +import struct +import macfs +import MacOS +import os +import sys +import Res # For Res.Error + +# resource IDs in our own resources (dialogs, etc) +MESSAGE_ID = 256 + +DIALOG_ID = 131 +TEXT_ITEM = 1 +OK_ITEM = 2 +CANCEL_ITEM = 3 +REVERT_ITEM = 4 +DIR_ITEM = 5 + +# Resource IDs in the preferences file +PATH_STRINGS_ID = 128 +DIRECTORY_ID = 128 + +WRITE = 2 +smAllScripts = -3 +kOnSystemDisk = 0x8000 + +def restolist(data): + """Convert STR# resource data to a list of strings""" + if not data: + return [] + num, = struct.unpack('h', data[:2]) + data = data[2:] + rv = [] + for i in range(num): + strlen = ord(data[0]) + if strlen < 0: strlen = strlen + 256 + str = data[1:strlen+1] + data = data[strlen+1:] + rv.append(str) + return rv + +def listtores(list): + """Convert a list of strings to STR# resource data""" + rv = struct.pack('h', len(list)) + for str in list: + rv = rv + chr(len(str)) + str + return rv + +def message(str = "Hello, world!", id = MESSAGE_ID): + """Show a simple alert with a text message""" + d = GetNewDialog(id, -1) + print 'd=', d + tp, h, rect = d.GetDialogItem(2) + SetDialogItemText(h, str) + while 1: + n = ModalDialog(None) + if n == 1: break + +def interact(list, pythondir): + """Let the user interact with the dialog""" + opythondir = pythondir + try: + # Try to go to the "correct" dir for GetDirectory + os.chdir(pythondir.as_pathname()) + except os.error: + pass + d = GetNewDialog(DIALOG_ID, -1) + tp, h, rect = d.GetDialogItem(1) + SetDialogItemText(h, string.joinfields(list, '\r')) + while 1: + n = ModalDialog(None) + if n == OK_ITEM: + break + if n == CANCEL_ITEM: + return None + if n == REVERT_ITEM: + return [], pythondir + if n == DIR_ITEM: + fss, ok = macfs.GetDirectory() + if ok: + pythondir = fss + tmp = string.splitfields(GetDialogItemText(h), '\r') + rv = [] + for i in tmp: + if i: + rv.append(i) + return rv, pythondir + +def main(): + try: + h = OpenResFile('EditPythonPrefs.rsrc') + except Res.Error: + pass # Assume we already have acces to our own resource + + # Find the preferences folder and our prefs file, create if needed. + vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0) + preff_fss = macfs.FSSpec((vrefnum, dirid, 'Python Preferences')) + try: + preff_handle = FSpOpenResFile(preff_fss, WRITE) + except Res.Error: + # Create it + message('No preferences file, creating one...') + FSpCreateResFile(preff_fss, 'PYTH', 'pref', smAllScripts) + preff_handle = FSpOpenResFile(preff_fss, WRITE) + + # Load the path and directory resources + try: + sr = GetResource('STR#', PATH_STRINGS_ID) + except (MacOS.Error, Res.Error): + message('Cannot find any sys.path resource! (Old python?)') + sys.exit(0) + d = sr.data + l = restolist(d) + + try: + dr = GetResource('alis', DIRECTORY_ID) + fss, fss_changed = macfs.RawAlias(dr.data).Resolve() + except (MacOS.Error, Res.Error): + dr = None + fss = macfs.FSSpec(os.getcwd()) + fss_changed = 1 + + # Let the user play away + result = interact(l, fss) + + # See what we have to update, and how + if result == None: + sys.exit(0) + + pathlist, nfss = result + if nfss != fss: + fss_changed = 1 + + if fss_changed or pathlist != l: + if fss_changed: + alias = nfss.NewAlias() + if dr: + dr.data = alias.data + dr.ChangedResource() + else: + dr = Resource(alias.data) + dr.AddResource('alis', DIRECTORY_ID, '') + + if pathlist != l: + if pathlist == []: + if sr.HomeResFile() == preff_handle: + sr.RemoveResource() + elif sr.HomeResFile() == preff_handle: + sr.data = listtores(pathlist) + sr.ChangedResource() + else: + sr = Resource(listtores(pathlist)) + sr.AddResource('STR#', PATH_STRINGS_ID, '') + + CloseResFile(preff_handle) + +if __name__ == '__main__': + print # Stupid, to init toolboxes... + main() diff --git a/Mac/scripts/PackLibDir.py b/Mac/scripts/PackLibDir.py new file mode 100644 index 0000000..cdda87d --- /dev/null +++ b/Mac/scripts/PackLibDir.py @@ -0,0 +1,93 @@ +# +# Turn a pyc file into a resource file containing it in 'PYC ' resource form +import addpack +addpack.addpack('Tools') +addpack.addpack('bgen') +addpack.addpack('res') +from Res import * +import Res +from Resources import * +import os +import macfs +import sys + +READ = 1 +WRITE = 2 +smAllScripts = -3 + +error = 'mkpycresourcefile.error' + +def Pstring(str): + if len(str) > 255: + raise ValueError, 'String too large' + return chr(len(str))+str + +def createoutput(dst): + """Create output file. Return handle and first id to use.""" + + + FSpCreateResFile(dst, 'PYTH', 'rsrc', smAllScripts) + output = FSpOpenResFile(dst, WRITE) + UseResFile(output) + num = 128 + return output, num + +def writemodule(name, id, data): + """Write pyc code to a PYC resource with given name and id.""" + # XXXX Check that it doesn't exist + res = Resource(data) + res.AddResource('PYC ', id, name) + res.WriteResource() + res.ReleaseResource() + +def mkpycresourcefile(src, dst): + """Copy pyc file/dir src to resource file dst.""" + + if not os.path.isdir(src) and src[-4:] <> '.pyc': + raise error, 'I can only handle .pyc files or directories' + handle, oid = createoutput(dst) + if os.path.isdir(src): + id = handlesubdir(handle, oid, src) + else: + id = handleonepycfile(handle, oid, src) + print 'Wrote',id-oid,'PYC resources to', dst + CloseResFile(handle) + +def handleonepycfile(handle, id, file): + """Copy one pyc file to the open resource file""" + d, name = os.path.split(file) + name = name[:-4] + print ' module', name + writemodule(name, id, open(file, 'rb').read()) + return id+1 + +def handlesubdir(handle, id, srcdir): + """Recursively scan a directory for pyc files and copy to resources""" + print 'Directory', srcdir + src = os.listdir(srcdir) + for file in src: + file = os.path.join(srcdir, file) + if os.path.isdir(file): + id = handlesubdir(handle, id, file) + elif file[-4:] == '.pyc': + id = handleonepycfile(handle, id, file) + return id + + +if __name__ == '__main__': + args = sys.argv[1:] + if not args: + ifss, ok = macfs.StandardGetFile('PYC ') + if ok: + args = [ifss.as_pathname()] + else: + ifss, ok = macfs.GetDirectory() + if not ok: + sys.exit(0) + args = [ifss.as_pathname()] + for ifn in args: + ofss, ok = macfs.StandardPutFile('Output for '+os.path.split(ifn)[1]) + if not ok: + sys.exit(0) + mkpycresourcefile(ifn, ofss.as_pathname()) + sys.exit(1) # So we can see something... diff --git a/Mac/scripts/RunLibScript.py b/Mac/scripts/RunLibScript.py new file mode 100644 index 0000000..36787d9 --- /dev/null +++ b/Mac/scripts/RunLibScript.py @@ -0,0 +1,108 @@ +"""Import a module while pretending its name is __main__. This +can be used to run scripts from the PackedLib resource file while pretending +they have been double-clicked.""" + +import imp +import sys +import os +import string +import Dlg +import macfs + +DIALOG_ID = 140 +OK = 1 +CANCEL = 2 +SCRIPTNAME=3 +ARGV=4 +STDIN_CONS=5 +STDIN_FILE=6 +STDOUT_CONS=7 +STDOUT_FILE=8 +WORKING_DIR=9 +PAUSE=10 + +def import_as_main(name): + fp, path, (suffix, mode, type) = imp.find_module(name) + if type == imp.PY_SOURCE: + imp.load_source('__main__', path) + elif type == imp.PY_COMPILED: + imp.load_compiled('__main__', path) + elif type == imp.PY_RESOURCE: + imp.load_resource('__main__', path) + +def interact(): + d = Dlg.GetNewDialog(DIALOG_ID, -1) + wdir = stdin = stdout = None + pause = 0 + + tp, in_c_h, rect = d.GetDialogItem(STDIN_CONS) + tp, in_f_h, rect = d.GetDialogItem(STDIN_FILE) + tp, out_c_h, rect = d.GetDialogItem(STDOUT_CONS) + tp, out_f_h, rect = d.GetDialogItem(STDOUT_FILE) + tp, pause_h, rect = d.GetDialogItem(PAUSE) + in_c_h = in_c_h.as_Control() + in_f_h = in_f_h.as_Control() + out_c_h = out_c_h.as_Control() + out_f_h = out_f_h.as_Control() + pause_h = pause_h.as_Control() + + while 1: + in_c_h.SetControlValue(not stdin) + in_f_h.SetControlValue(not not stdin) + out_c_h.SetControlValue(not stdout) + out_f_h.SetControlValue(not not stdout) + pause_h.SetControlValue(pause) + + n = Dlg.ModalDialog(None) + if n == OK: + break + elif n == CANCEL: + sys.exit(0) + elif n == STDIN_CONS: + stdin = None + elif n == STDIN_FILE: + fss, ok = macfs.StandardGetFile('TEXT') + if ok: + stdin = fss + elif n == STDOUT_FILE: + fss, ok = macfs.StandardPutFile('stdout:') + if ok: + stdout = fss + elif n == WORKING_DIR: + fss, ok = macfs.GetDirectory() + if ok: + wdir = fss + elif n == PAUSE: + pause = (not pause) + + tp, h, rect = d.GetDialogItem(SCRIPTNAME) + name = Dlg.GetDialogItemText(h) + tp, h, rect = d.GetDialogItem(ARGV) + argv = Dlg.GetDialogItemText(h) + return name, argv, stdin, stdout, wdir, pause + +def main(): + curdir = os.getcwd() + import Res + Res.OpenResFile('RunLibScript.rsrc') + name, argv, stdin, stdout, wdir, pause = interact() + if not name: + sys.exit(0) + sys.argv = [name] + string.split(argv) + if stdin: + sys.stdin = open(stdin.as_pathname()) + if stdout: + sys.stdout = open(stdout.as_pathname(), 'w') + if wdir: + os.chdir(wdir.as_pathname()) + else: + os.chdir(curdir) + + import_as_main(name) + + if pause: + sys.exit(1) + +if __name__ == '__main__': + main() + |