Permalink
Browse files

Added - osx package utilities from scribus

  • Loading branch information...
1 parent a4ffb48 commit 2e419a873c26b15638120ff760fcffb27e829a43 Pierre Marchand committed Jul 16, 2010
@@ -0,0 +1,215 @@
+import os
+import re
+import shutil
+
+
+def findFramework(path, name = None):
+ "find the framework folder for FW name"
+ if path == "" or path == "@executable_path" or path == "/":
+ return None
+ elif name == None:
+ return findFramework(os.path.dirname(path),
+ os.path.basename(path))
+ elif os.path.basename(path) == name + ".framework":
+ return path
+ elif len(os.path.dirname(path)) >= len(path):
+ print "MachO.findFramework: Oops '" + path + "', '" + name + "'"
+ return None
+ else:
+ return findFramework(os.path.dirname(path), name)
+
+
+
+def stripPrefix(prefix, path):
+ "Returns the relative path r such that os.path.join(prefix, r) == path"
+ prefix = os.path.normpath(prefix)
+ prefixLen = len(prefix)
+ path = os.path.normpath(path)
+ if path[0 : prefixLen] == prefix:
+ if path[prefixLen] == os.sep:
+ return path[prefixLen+1 : ]
+ else:
+ return path[prefixLen : ]
+ else:
+ return path
+
+
+class Executable:
+ "Represents an Mach-O executable."
+
+ def __init__(self, path, kind):
+ self.Location = path
+ self.Kind = kind
+
+
+ def __repr__(self):
+ return self.Location + " (" + self.Kind + ")"
+
+
+ def getDependencies(self):
+ "Return a list of MachO.Fixes describing the dependencies."
+ "Uses otool -L"
+ f = os.popen("otool -L " + self.Location, "r")
+ result = []
+ pat = re.compile("\s*([^(]*)\s\((.+)\)")
+ for line in f:
+ m = pat.match(line)
+ if m != None:
+ result.append(Fix(m.group(1), m.group(2)))
+ status = f.close()
+ return result
+
+ def applyFixes(self, changes, log):
+ "Uses install_name_tool to change the links to dependencies."
+ "changes is a dictionary mapping links (as strings) to Fixes."
+ args = ""
+ for dep in self.getDependencies():
+ if dep.Link in changes:
+ args = args + changes[dep.Link].getChange()
+ log.append(">> " + "install_name_tool " + args + self.Location)
+ if len(args) > 0:
+ os.system("install_name_tool " + args + self.Location)
+ pat = re.compile("(library)|(universal binary)")
+ if pat.search(self.Kind):
+ relName = os.path.basename(self.Location) # FIXME: rel to fw
+ log.append(">> " + "install_name_tool -id " + relName +
+ " " + self.Location)
+ os.system("install_name_tool -id " + relName +
+ " " + self.Location)
+
+
+def findExecutables(bundleDir):
+ "Return a list of MachO.Executables found in bundleDir"
+ result = []
+ pat = re.compile("Mach-O (.+)")
+ for root, dirs, files in os.walk(bundleDir):
+ for n in files:
+ p = os.path.join(root, n)
+ f = os.popen("file -b " + p, "r")
+ m = pat.match(f.readline())
+ if m != None:
+ result.append(Executable(p, m.group(1)))
+ print "found " + m.group(1) + ": " + n
+ f.close()
+ return result
+
+
+
+class Fix:
+ "Represents a fix for a library link."
+
+ def __init__(self, dependency, versionString="?"):
+ self.Link = dependency
+ self.Location = dependency
+ self.NewLink = dependency
+ self.NewLocation = dependency
+ self.versionString = versionString # not used yet
+ self.fwPath = None
+ self.relPath = None
+
+ def __repr__(self):
+ return (self.Link + " (" + self.versionString + ")")
+
+ def isAbsolute(self):
+ return os.path.isabs(self.Link)
+
+ def isBundleRelative(self):
+ return self.Link[0:17] == "@executable_path/"
+
+ def isSystem(self):
+ return (self.Location[0:8] == "/usr/lib" # also matches libexec
+ or self.Location[0:8] == "/usr/X11" # also matches X11R6
+ or self.Location[0:8] == "/System/")
+
+ def getChange(self):
+ "Returns argument for install_name_tool."
+ if self.Link == self.NewLink:
+ return ""
+ else:
+ return "-change " + self.Link + " " + self.NewLink + " "
+
+ def findLocation(self, exePath=None):
+ if self.isBundleRelative():
+ if exePath != None:
+ self.Location = os.path.normpath(
+ os.path.join(exePath, self.Link[17:]))
+ else:
+ self.Location = self.Link[17:]
+ else:
+ self.Location = self.Link
+
+ # check if done
+ if (os.path.isabs(self.Location) and
+ os.path.isfile(self.Location)):
+ self.NewLocation = self.Location
+ return True
+
+ # search for frameworks in /System/Library and /Library
+ fwPath = findFramework(self.Location)
+ if fwPath:
+ fwdir = os.path.dirname(fwPath)
+ self.relPath = stripPrefix(fwdir, self.Location)
+ for d in ["/Library/Frameworks",
+ "/System/Library/Frameworks"]:
+ if os.path.isfile(os.path.join(d, self.relPath)):
+# self.Location = os.path.join(d, self.relPath)
+ self.Location = os.path.join(d, self.relPath)
+ self.NewLocation = self.Location
+ self.fwPath = os.path.join(d, os.path.basename(fwPath))
+ self.relPath = stripPrefix(self.fwPath, self.Location)
+ return True
+
+ # ok, try libs
+ lib = os.path.basename(self.Location)
+ self.relPath = None
+ for d in ["/usr/local/lib", "/opt/local/lib",
+ "/usr/lib", "/opt/lib"]:
+ if os.path.isfile(os.path.join(d, lib)):
+ self.Location = os.path.join(d, lib)
+ self.NewLocation = self.Location
+ return True
+
+ # not found
+ return False
+
+
+ def moveLibrary(self, destBundlePath, stripFW, log):
+ "Copies the library or fw to destBundlePath."
+ "Also sets NewLink and NewLocation properties"
+ "Returns a list of copied executables"
+
+ # dont do this if we are already inside the bundle:
+ if stripPrefix(destBundlePath, self.Location) != self.Location:
+ log.append("-- ignoring " + self.Location)
+ return []
+
+ if self.relPath != None and not stripFW:
+ # copy framework
+ newFwPath = os.path.join(destBundlePath,
+ "Contents/Frameworks",
+ os.path.basename(self.fwPath))
+ log.append(">> " + self.fwPath + " ===> " + newFwPath)
+ if (os.path.exists(destBundlePath) and
+ not os.path.exists(newFwPath)):
+ shutil.copytree(self.fwPath, newFwPath, True)
+ self.NewLocation = os.path.join(newFwPath, self.relPath)
+ self.NewLink = ("@executable_path/"
+ + os.path.join("../Frameworks",
+ os.path.basename(self.fwPath),
+ self.relPath))
+ return findExecutables(newFwPath)
+ else:
+ # copy lib to bundle.app/Contents/Frameworks/
+ self.NewLocation = os.path.join(destBundlePath,
+ "Contents/Frameworks",
+ os.path.basename(self.Location))
+ self.NewLink = ("@executable_path/"
+ + os.path.join("../Frameworks",
+ os.path.basename(self.Location)))
+ log.append(">> " + self.Location + " ---> " + self.NewLocation)
+ if (os.path.exists(destBundlePath) and
+ not os.path.exists(self.NewLocation)):
+ shutil.copy(self.Location, self.NewLocation)
+ return [Executable(self.NewLocation, "lib")]
+
+
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+import os
+import sys
+import osxtools
+
+def usage():
+ print """
+ Usage: ingest.py bundle [-x lib] [-s fw]
+
+ Copies all dependent libraries and frameworks into the app bundle.
+ System libraries (/usr/lib*, /System/Library) are not copied.
+ Fixes the dependencies in all executabels contained in bundle.
+
+ bundle: the path to the *.app bundle
+ -x lib: dont move lib into the bundle.
+ -s fw: only move the referenced libarry file from framework fw
+ into the bundle, not the complete framework
+ """
+
+
+if len(sys.argv) <= 1 or sys.argv[1] == "-?" :
+ usage()
+ sys.exit(0)
+
+
+
+exceptions = []
+strippedfws = []
+bundle = None
+
+argp = 1
+
+while argp < len(sys.argv) :
+ if sys.argv[argp] == '-x' :
+ exceptions.append(sys.argv[argp + 1])
+ argp = argp + 2
+ elif sys.argv[argp][0:2] == '-x' :
+ exceptions.append(sys.argv[argp][2:])
+ argp = argp + 1
+ elif sys.argv[argp] == '-s' :
+ strippedfws.append(sys.argv[argp + 1])
+ argp = argp + 2
+ elif sys.argv[argp][0:2] == '-s' :
+ strippedfws.append(sys.argv[argp][2:])
+ argp = argp + 1
+ elif sys.argv[argp][0:1] == '-' :
+ print "Error: unknown option: " + sys.argv[argp]
+ usage()
+ sys.exit(1)
+ elif bundle == None:
+ bundle = sys.argv[argp]
+ argp = argp + 1
+ else:
+ print "Error: more than one bundle path specified!"
+ usage()
+ sys.exit(1)
+
+if bundle == None:
+ print "Error: no bundle path specified!"
+ usage()
+ sys.exit(1)
+
+if not os.path.isabs(bundle):
+ bundle = os.path.join(os.getenv("PWD"), bundle)
+
+if not os.path.isdir(bundle):
+ print "Error: '" + bundle + "' is no bundle path!"
+ usage()
+ sys.exit(1)
+
+osxtools.ingest(bundle, exceptions, strippedfws)
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+
+import os
+import sys
+import shutil
+import osxtools
+
+def usage():
+ print """
+ Usage: mkappbundle.py bundle [-b binary] [-i infofile|-v version]
+
+ Creates the directory structure for an application bundle.
+ If binary is given, it will be used as the binaries executable,
+ otherwise the binary will just be an empty shell.
+
+ bundle: the path to the *.app bundle
+ -b binary: copy lib into the bundle.
+ -i infofile: use "ver" as the version instead of the standard 'A'
+ """
+
+
+if len(sys.argv) <= 1 or sys.argv[1] == "-?" :
+ usage()
+ sys.exit(0)
+
+
+
+infofile = None
+binfile = None
+bundle = None
+
+argp = 1
+
+while argp < len(sys.argv) :
+ if sys.argv[argp] == '-b' :
+ binfile = (sys.argv[argp + 1])
+ argp = argp + 2
+ elif sys.argv[argp][0:2] == '-b' :
+ binfile = (sys.argv[argp][2:])
+ argp = argp + 1
+ elif sys.argv[argp] == '-i' :
+ infofile = (sys.argv[argp + 1])
+ argp = argp + 2
+ elif sys.argv[argp][0:2] == '-i' :
+ infofile = (sys.argv[argp][2:])
+ argp = argp + 1
+ elif sys.argv[argp][0:1] == '-' :
+ print "Error: unknown option: " + sys.argv[argp]
+ usage()
+ sys.exit(1)
+ elif bundle == None:
+ bundle = sys.argv[argp]
+ argp = argp + 1
+ else:
+ print "Error: more than one bundle path specified!"
+ usage()
+ sys.exit(1)
+
+if bundle == None:
+ print "Error: no bundle path specified!"
+ usage()
+ sys.exit(1)
+
+if not os.path.isabs(bundle):
+ bundle = os.path.join(os.getenv("PWD"), bundle)
+
+if bundle[-4 : ] != ".app":
+ bundle = bundle + ".app"
+appName = os.path.basename(bundle)[0: -4]
+
+if not os.path.exists(bundle):
+ os.makedirs(bundle, 0755)
+elif not os.path.isdir(bundle):
+ print "Error: '" + bundle + "' is no bundle path!"
+ usage()
+ sys.exit(1)
+
+binPath = os.path.join(bundle, "Contents/MacOS")
+
+if not os.path.exists(binPath):
+ os.makedirs(binPath, 0755)
+
+if binfile != None:
+ shutil.copy(binfile, os.path.join(binPath, appName))
+
+shutil.copy(infofile, os.path.join(bundle, "Contents/Info.plist")
+
Oops, something went wrong.

0 comments on commit 2e419a8

Please sign in to comment.