A new home for scripts/applets
EditPythonPrefs - Edit the preferences file (sys.path, python home)
PackLibDir - Convert a sys.path directory to a resource file
RunLibScript - import a module and run as __main__
mkapplet - Create a python applet
The resource files belonging to these should also be stored here, somehow..
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()
+