Commits

Anonymous committed b353ea3

Comitted an almost working Panther/Xcode templates.

  • Participants
  • Parent commits bb06e0f

Comments (0)

Files changed (5)

File pyobjc/Xcode/Project Templates/00README.txt

+========================
+Python Project Templates
+========================
+
+:Author: Bill Bumgarner
+:Contact: bbum@codefab.com
+
+To use the project templates, simply copy (or link) them into the Project
+Templates directory used by Project Builder.  The project templates are also
+included in the PyObjC installer package.
+
+.. contents::
+
+Notes
+-----
+
+- In all cases that involve loading frameworks or bundles, all of the classes
+  in that framework or bundle can be made available by using the
+  ``loadBundle()`` function in the ``objc`` module::
+
+    objc.loadBundle("MyFramework", globals(), bundle_path="/path/to/MyFramework.framework")
+
+  This has the effect of importing all of the classes in the bundle or
+  framework into the current python scope's globals.  For all intents and
+  purposes, it is similar to::
+
+    from Foundation import *
+
+- There is risk that the pyobjc modules compiled for one version of python
+  will not work with another.  Where this may be a problem is if the a
+  standalone application is packaged with the pyobjc modules compiled
+  against, say, the Fink or Framework builds of Python, but is then executed
+  using the Apple supplied python binary.
+
+ - The *Project Templates* directory includes a **clean.py** script that
+   removes noise files from the project templates.   When working on project
+   templates, it is recommended that this script be invoked before creating a
+   test project from one of the templates.   For example, the presence of
+   user specific project builder settings will cause any projects created
+   from a template to be incorrect.
+    
+Cocoa-Python Templates
+----------------------
+
+The Cocoa-Python templates all create various different kinds of Cocoa
+application projects.   Some of the resulting projects are incompatible with
+Apple's build of Python[#].  Be sure and pick the correct project type for your
+needs.
+
+Cocoa-Python Application
+------------------------
+
+A project created from this template is designed to implement standalone,
+pure-Python, applications that are compatible with Apple's build of Python as
+well as all other builds of python that support PyObjC.
+
+When building the 'install' target, the resulting application wrapper will
+included the PyObjC module and can be launched on any stock OS X 10.2 system
+without requiring PyObjC to be preinstalled.
+
+Cocoa-Python-ObjC Application
+-----------------------------
+
+A project created from this template includes an embedded framework project
+into which all compiled code can be placed.  Upon launch, the application
+automatically dynamically loads the embedded framework containing the
+compiled code.
+
+Each Framework's Resources directory is automatically added to sys.path.
+
+.. Cocoa-Python Application (Embedded Interpreter)
+   -----------------------------------------------
+
+.. This project template uses an embedded Python interpreter.  As such,
+   Objective-C classes can be freely mixed into the project along with Python
+   classes.   However, because it uses an embedded interpreter, this project
+   must be built and run after some version of Python is installed that can
+   support an embedded interpreter.  Alternatively, an application based on this
+   template must include a build of Python within its app wrapper.
+
+.. This type of project is not compatible with Apple's build of Python.
+
+Cocoa-Python Document-based Application
+---------------------------------------
+
+This template works like the `Cocoa-Python Application`_ template in that it
+is compatible with the Apple build of Python.   It creates an application
+that uses Cocoa's Multiple Document Architecture in the same fashion as the
+default Cocoa Document-based Application supplied with Project Builder.
+
+Cocoa-Python-ObjC Document-based Application
+-----------------------------
+
+A project created from this template includes an embedded framework project
+into which all compiled code can be placed.  Upon launch, the application
+automatically dynamically loads the embedded framework containing the
+compiled code. It is based on the `Cocoa-Python Document-based Application`_
+template.  It creates an application that uses Cocoa's Multiple Document 
+Architecture in the same fashion as the default Cocoa Document-based 
+Application supplied with Project Builder.
+
+Each Framework's Resources directory is automatically added to sys.path.
+
+.. Cocoa-Python Document-based Application (Embedded Interpreter)
+   --------------------------------------------------------------
+
+.. This template works like the `Cocoa-Python Application (Embedded
+   Interpreter)`_ template in that it is incompatible with the Apple build of
+   Python.   It creates an application that uses Cocoa's Multiple Document
+   Architecture in the same fashion as the default Cocoa Document-based
+   Application supplied with Project Builder.
+
+.. [#] Apple's build of python lacks a shared or static library to which an
+       application can be linked.  As such, it is impossible to embed the
+       Python interpreter into an application.  Because of this, it is
+       impossible to directly link compiled objective-c directly into an
+       application project.  Hence, the "Apple Python compatible" projects are
+       labeled as 100% pure Python.  Since bundles and frameworks can be
+       loaded into such applications, it is still possible to use compiled
+       classes.

File pyobjc/Xcode/Project Templates/Cocoa-Python Application/CocoaApp.xcode/TemplateInfo.plist

+{
+	FilesToRename = {
+		"AppDelegate.py" = "�PROJECTNAMEASIDENTIFIER�AppDelegate.py";
+		"CocoaApp_Prefix.pch" = "�PROJECTNAMEASIDENTIFIER�_Prefix.pch";
+	};
+	FilesToMacroExpand = (
+		"English.lproj/InfoPlist.strings",
+		"main-embedded-interpreter.m",
+		"__main__.py",
+		"Info.plist",
+		"�PROJECTNAMEASIDENTIFIER�AppDelegate.py",
+		"English.lproj/MainMenu.nib/keyedobjects.nib",
+		"English.lproj/MainMenu.nib/classes.nib",
+		"English.lproj/MainMenu.nib/info.nib",
+		"�PROJECTNAMEASIDENTIFIER�_Prefix.pch"
+	);
+
+	Description = "This project builds a Cocoa-based application written in Python.  The project is compatible with the Python that ships with OS X, but can be used with Fink, Framework, or manual builds of Python (if pyobjc has been installed correctly within the desired build).  Upon building the 'install' target, the resulting application should contain everything necessary to run the application on any 10.2 system without first requiring the installation of PyObjC.";
+}

File pyobjc/Xcode/Project Templates/Cocoa-Python Application/CocoaApp.xcode/project.pbxproj

+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 39;
+	objects = {
+		080E96DDFE201D6D7F000001 = {
+			children = (
+				F60DD8BD0358A22201C8ED3C,
+			);
+			isa = PBXGroup;
+			name = Classes;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		089C165CFE840E0CC02AAC07 = {
+			children = (
+				089C165DFE840E0CC02AAC07,
+			);
+			isa = PBXVariantGroup;
+			name = InfoPlist.strings;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		089C165DFE840E0CC02AAC07 = {
+			expectedFileType = text.plist.strings;
+			fileEncoding = 10;
+			isa = PBXFileReference;
+			name = English;
+			path = English.lproj/InfoPlist.strings;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+//080
+//081
+//082
+//083
+//084
+//100
+//101
+//102
+//103
+//104
+		1058C7A1FEA54F0111CA2CBB = {
+			expectedFileType = wrapper.framework;
+			fallbackIsa = PBXFileReference;
+			isa = PBXFrameworkReference;
+			name = Cocoa.framework;
+			path = /System/Library/Frameworks/Cocoa.framework;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+//100
+//101
+//102
+//103
+//104
+//190
+//191
+//192
+//193
+//194
+		19C28FACFE9D520D11CA2CBB = {
+			children = (
+				1BFB80A804CEE27800DEF731,
+			);
+			isa = PBXGroup;
+			name = Products;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+//190
+//191
+//192
+//193
+//194
+//1B0
+//1B1
+//1B2
+//1B3
+//1B4
+		1BFB7DBF04CEE17C00DEF731 = {
+			expectedFileType = sourcecode.c.objc;
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			path = "main-embedded-interpreter.m";
+			refType = 2;
+			sourceTree = SOURCE_ROOT;
+		};
+		1BFB7DD504CEE24900DEF731 = {
+			expectedFileType = wrapper.framework;
+			isa = PBXFileReference;
+			name = Python.framework;
+			path = /System/Library/Frameworks/Python.framework;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		1BFB7F6D04CEE27700DEF731 = {
+			buildPhases = (
+				1BFB7F6E04CEE27700DEF731,
+				1BFB7F6F04CEE27700DEF731,
+				1BFB801004CEE27700DEF731,
+				1BFB801204CEE27700DEF731,
+				77A8F17D04D6B2470033F030,
+			);
+			buildRules = (
+			);
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_ENABLE_TRIGRAPHS = NO;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "«PROJECTNAMEASIDENTIFIER»_Prefix.pch";
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+				GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+				GCC_WARN_UNKNOWN_PRAGMAS = NO;
+				HEADER_SEARCH_PATHS = "";
+				INFOPLIST_FILE = Info.plist;
+				INSTALL_PATH = "$(HOME)/Applications";
+				LIBRARY_SEARCH_PATHS = "";
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				PRODUCT_NAME = "«PROJECTNAME»";
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+				WRAPPER_EXTENSION = app;
+			};
+			dependencies = (
+			);
+			isa = PBXNativeTarget;
+			name = "«PROJECTNAME»";
+			productInstallPath = "$(HOME)/Applications";
+			productName = "«PROJECTNAME»";
+			productReference = 1BFB80A804CEE27800DEF731;
+			productType = "com.apple.product-type.application";
+		};
+		1BFB7F6E04CEE27700DEF731 = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			isa = PBXHeadersBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		1BFB7F6F04CEE27700DEF731 = {
+			buildActionMask = 2147483647;
+			files = (
+				1BFB7F7004CEE27700DEF731,
+				1BFB7F7104CEE27700DEF731,
+				1BFB7F7204CEE27700DEF731,
+				1BFB7F7304CEE27700DEF731,
+				777C19C904D6B9D800FBF432,
+				77A9B0E204D6BD1E00EC1630,
+			);
+			isa = PBXResourcesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		1BFB7F7004CEE27700DEF731 = {
+			fileRef = 29B97318FDCFA39411CA2CEA;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		1BFB7F7104CEE27700DEF731 = {
+			fileRef = 089C165CFE840E0CC02AAC07;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		1BFB7F7204CEE27700DEF731 = {
+			fileRef = F60DD8BC0358A22201C8ED3C;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		1BFB7F7304CEE27700DEF731 = {
+			fileRef = F60DD8BD0358A22201C8ED3C;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		1BFB801004CEE27700DEF731 = {
+			buildActionMask = 2147483647;
+			files = (
+				1BFB801104CEE27700DEF731,
+			);
+			isa = PBXSourcesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		1BFB801104CEE27700DEF731 = {
+			fileRef = 1BFB7DBF04CEE17C00DEF731;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		1BFB801204CEE27700DEF731 = {
+			buildActionMask = 2147483647;
+			files = (
+				1BFB801304CEE27700DEF731,
+				1BFB80F904CEE38B00DEF731,
+				1BFB801404CEE27700DEF731,
+			);
+			isa = PBXFrameworksBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		1BFB801304CEE27700DEF731 = {
+			fileRef = 29B97325FDCFA39411CA2CEA;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		1BFB801404CEE27700DEF731 = {
+			fileRef = 1BFB7DD504CEE24900DEF731;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		1BFB80A804CEE27800DEF731 = {
+			expectedFileType = wrapper.application;
+			includeInIndex = 0;
+			isa = PBXFileReference;
+			path = "«PROJECTNAME».app";
+			refType = 3;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		1BFB80F904CEE38B00DEF731 = {
+			fileRef = 1058C7A1FEA54F0111CA2CBB;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+//1B0
+//1B1
+//1B2
+//1B3
+//1B4
+//290
+//291
+//292
+//293
+//294
+		29B97313FDCFA39411CA2CEA = {
+			buildSettings = {
+			};
+			buildStyles = (
+				4A9504CCFFE6A4B311CA0CBA,
+				4A9504CDFFE6A4B311CA0CBA,
+			);
+			hasScannedForEncodings = 1;
+			isa = PBXProject;
+			mainGroup = 29B97314FDCFA39411CA2CEA;
+			projectDirPath = "";
+			targets = (
+				1BFB7F6D04CEE27700DEF731,
+			);
+		};
+		29B97314FDCFA39411CA2CEA = {
+			children = (
+				080E96DDFE201D6D7F000001,
+				29B97315FDCFA39411CA2CEA,
+				29B97317FDCFA39411CA2CEA,
+				29B97323FDCFA39411CA2CEA,
+				19C28FACFE9D520D11CA2CBB,
+			);
+			isa = PBXGroup;
+			name = "«PROJECTNAMEASXML»";
+			path = "";
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		29B97315FDCFA39411CA2CEA = {
+			children = (
+				F60DD8BC0358A22201C8ED3C,
+				1BFB7DBF04CEE17C00DEF731,
+				777C19C804D6B9D800FBF432,
+				77A9B0E104D6BD1E00EC1630,
+			);
+			isa = PBXGroup;
+			name = "Other Sources";
+			path = "";
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		29B97317FDCFA39411CA2CEA = {
+			children = (
+				29B97318FDCFA39411CA2CEA,
+				089C165CFE840E0CC02AAC07,
+			);
+			isa = PBXGroup;
+			name = Resources;
+			path = "";
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		29B97318FDCFA39411CA2CEA = {
+			children = (
+				29B97319FDCFA39411CA2CEA,
+			);
+			isa = PBXVariantGroup;
+			name = MainMenu.nib;
+			path = "";
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		29B97319FDCFA39411CA2CEA = {
+			expectedFileType = wrapper.nib;
+			isa = PBXFileReference;
+			name = English;
+			path = English.lproj/MainMenu.nib;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		29B97323FDCFA39411CA2CEA = {
+			children = (
+				29B97324FDCFA39411CA2CEA,
+				1058C7A1FEA54F0111CA2CBB,
+				29B97325FDCFA39411CA2CEA,
+				1BFB7DD504CEE24900DEF731,
+				77A8EFE904D6B2200033F030,
+			);
+			isa = PBXGroup;
+			name = "Frameworks & Modules";
+			path = "";
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		29B97324FDCFA39411CA2CEA = {
+			expectedFileType = wrapper.framework;
+			fallbackIsa = PBXFileReference;
+			isa = PBXFrameworkReference;
+			name = AppKit.framework;
+			path = /System/Library/Frameworks/AppKit.framework;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		29B97325FDCFA39411CA2CEA = {
+			expectedFileType = wrapper.framework;
+			fallbackIsa = PBXFileReference;
+			isa = PBXFrameworkReference;
+			name = Foundation.framework;
+			path = /System/Library/Frameworks/Foundation.framework;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+//290
+//291
+//292
+//293
+//294
+//4A0
+//4A1
+//4A2
+//4A3
+//4A4
+		4A9504CCFFE6A4B311CA0CBA = {
+			buildRules = (
+			);
+			buildSettings = {
+				COPY_PHASE_STRIP = NO;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				OPTIMIZATION_CFLAGS = "-O0";
+				ZERO_LINK = YES;
+			};
+			isa = PBXBuildStyle;
+			name = Development;
+		};
+		4A9504CDFFE6A4B311CA0CBA = {
+			buildRules = (
+			);
+			buildSettings = {
+				COPY_PHASE_STRIP = YES;
+				DEPLOYMENT_LOCATION = YES;
+				DEPLOYMENT_POSTPROCESSING = YES;
+				GCC_ENABLE_FIX_AND_CONTINUE = NO;
+				ZERO_LINK = NO;
+			};
+			isa = PBXBuildStyle;
+			name = Deployment;
+		};
+//4A0
+//4A1
+//4A2
+//4A3
+//4A4
+//770
+//771
+//772
+//773
+//774
+		777C19C804D6B9D800FBF432 = {
+			expectedFileType = sourcecode.c.h;
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			path = "«PROJECTNAMEASIDENTIFIER»_Prefix.pch";
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		777C19C904D6B9D800FBF432 = {
+			fileRef = 777C19C804D6B9D800FBF432;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		77A8EF4A04D6B2180033F030 = {
+			expectedFileType = folder;
+			isa = PBXFileReference;
+			name = AppKit;
+			path = /Library/Python/2.3/PyObjC/AppKit;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		77A8EF6204D6B2180033F030 = {
+			expectedFileType = "compiled.mach-o.bundle";
+			isa = PBXFileReference;
+			name = autoGIL.so;
+			path = /Library/Python/2.3/PyObjC/autoGIL.so;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		77A8EF6304D6B2180033F030 = {
+			expectedFileType = folder;
+			isa = PBXFileReference;
+			name = Foundation;
+			path = /Library/Python/2.3/PyObjC/Foundation;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		77A8EF9804D6B2180033F030 = {
+			expectedFileType = folder;
+			isa = PBXFileReference;
+			name = objc;
+			path = /Library/Python/2.3/PyObjC/objc;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		77A8EFC804D6B2180033F030 = {
+			expectedFileType = folder;
+			isa = PBXFileReference;
+			name = PyObjCTools;
+			path = /Library/Python/2.3/PyObjC/PyObjCTools;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		77A8EFE904D6B2200033F030 = {
+			children = (
+				77A8EF4A04D6B2180033F030,
+				77A8EF6204D6B2180033F030,
+				77A8EF6304D6B2180033F030,
+				77A8EF9804D6B2180033F030,
+				77A8EFC804D6B2180033F030,
+			);
+			isa = PBXGroup;
+			name = PyObjC;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		77A8F17D04D6B2470033F030 = {
+			buildActionMask = 8;
+			dstPath = "";
+			dstSubfolderSpec = 7;
+			files = (
+				77A8F1E004D6B2750033F030,
+				77A8F1E104D6B2750033F030,
+				77A8F1E204D6B2750033F030,
+				77A8F1E304D6B2750033F030,
+				77A8F1E404D6B2750033F030,
+			);
+			isa = PBXCopyFilesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+		77A8F1E004D6B2750033F030 = {
+			fileRef = 77A8EF4A04D6B2180033F030;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		77A8F1E104D6B2750033F030 = {
+			fileRef = 77A8EF6204D6B2180033F030;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		77A8F1E204D6B2750033F030 = {
+			fileRef = 77A8EF6304D6B2180033F030;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		77A8F1E304D6B2750033F030 = {
+			fileRef = 77A8EF9804D6B2180033F030;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		77A8F1E404D6B2750033F030 = {
+			fileRef = 77A8EFC804D6B2180033F030;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		77A9B0E104D6BD1E00EC1630 = {
+			expectedFileType = text.plist;
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			path = Info.plist;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		77A9B0E204D6BD1E00EC1630 = {
+			fileRef = 77A9B0E104D6BD1E00EC1630;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+//770
+//771
+//772
+//773
+//774
+//F60
+//F61
+//F62
+//F63
+//F64
+		F60DD8BC0358A22201C8ED3C = {
+			expectedFileType = text.script.python;
+			fallbackIsa = PBXFileReference;
+			fileEncoding = 30;
+			isa = PBXExecutableFileReference;
+			path = __main__.py;
+			refType = 2;
+			sourceTree = SOURCE_ROOT;
+		};
+		F60DD8BD0358A22201C8ED3C = {
+			expectedFileType = text.script.python;
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			path = "«PROJECTNAMEASIDENTIFIER»AppDelegate.py";
+			refType = 2;
+			sourceTree = SOURCE_ROOT;
+		};
+	};
+	rootObject = 29B97313FDCFA39411CA2CEA;
+}

File pyobjc/Xcode/Project Templates/Cocoa-Python Application/English.lproj/InfoPlist.strings

Binary file added.

File pyobjc/Xcode/clean.py

+#!/usr/bin/env python
+
+import sys
+import os
+import re
+import shutil
+
+import getopt
+
+## usage
+def usage(msg=None, exitCode=1):
+    if msg:
+        print "Error:", msg
+    print """
+clean.py [-hvkrw] <source> <dest>
+    
+Copies tree of templates or projects from <source> to <dest>.  Before copying,
+cleans up <source> by removing various bits of garbage.   After copying,
+transforms <dest> by replacing strings with their Xcode template counterparts.
+
+The -r flag can be used to reverse the project;  turning an Xcode template into
+a working project.
+
+Options:
+    -h/--help              show usage
+    -v/--verbose           verbose
+    -k/--kill-destination  erase <dest> (no warning)
+    -r/--reverse           reverse transformation (template -> editable project)
+    -w/--working           try to make destination into a working project
+    """
+    sys.exit(exitCode)
+
+## settings
+verbose = False
+killDest = False
+doReverse = False
+makeWorking = False
+
+## process options
+try:
+    opts, args = getopt.getopt(sys.argv[1:], "hvkrw", ["help", "verbose", "kill-destination", "reverse", "working"])
+except getopt.GetoptError, details:
+    usage(details, 2)
+
+if len(args) != 2:
+    usage(None, 2)
+
+for opt, value in opts:
+    if opt in ['-h', '--help']:
+        usage(None, 1)
+    if opt in ['-v', '--verbose']:
+        verbose = True
+        continue
+    if opt in ['-k', '--kill-destination']:
+        killDest = True
+        continue
+    if opt in ['-r', '--reverse']:
+        doReverse = True
+        continue
+    if opt in ['-w', '--working']:
+        makeWorking = True
+        continue
+
+## define functions used in script
+def killNasties(irrelevant, dirName, names):
+    for aName in names:
+        if len(filter(lambda expr, aName=aName: expr.match(aName), nastyFileExprs)):
+            path = os.path.join(dirName, aName)
+            if verbose:
+                print "Removing '%s'..." % path
+            if os.path.isdir(path):
+		shutil.rmtree(path)
+            else:
+                os.remove(path)
+
+def doSubstitutions(irrelevant, dirName, names):
+    for aName in names:
+        didPch = False
+        path = os.path.join(dirName, aName)
+        if os.path.isdir(path): continue
+        if aName in specialFiles:
+            specialFiles[aName](path)
+            continue
+        extension = os.path.splitext(path)[1]
+        if extension in utf16Extensions:
+            doFileSubstitution(path, utf16Substitutions)
+        elif extension in utf8Extensions:
+            doFileSubstitution(path, utf8Substitutions)
+        elif extension in asciiExtensions:
+            doFileSubstitution(path, asciiSubstitutions)
+        else:
+            sys.stderr.write("*WARN* Skipping unknown file with uknown type: %s\n" % path)
+        if makeWorking and (extension in [".pch"]):
+            if verbose:
+                print 'Making working copy of %s...' % path
+            tail = aName.split("_", 1)[1]
+            targetFile = os.path.join(dirName, "xcPROJECTNAMExc_%s" % tail)
+            inFile = file(path, "r")
+            data = inFile.read()
+            inFile.close()
+            if extension in [".pch"]: # C type file
+                message = "\n\n// WARNING\n// This file is copied from %s.  Keep the two in sync.\n// --- file resumes after here ---\n" % aName
+            outFile = file(targetFile, "w")
+            outFile.write(message)
+            outFile.write(data)
+            outFile.flush()
+            outFile.close()
+
+def doFileSubstitution(aFile, subs):
+    if verbose:
+        print 'Processing %s....' % aFile
+    inFile = file(aFile, "r")
+    data = inFile.read()
+    inFile.close()
+    for originalString, targetString in subs:
+        data = data.replace(originalString, targetString)
+    outFile = file(aFile, "w")
+    outFile.write(data)
+    outFile.flush()
+    outFile.close()
+
+def doTemplateInfo(aFile):
+    if not doReverse:
+        doFileSubstitution(aFile, utf8Substitutions)
+
+## define per-file behaviors
+specialFiles = {
+    "TemplateInfo.plist" : doTemplateInfo
+    }
+
+utf8Extensions = ['.plist', '.pbxproj', '.nib', '.xib']
+asciiExtensions = ['.m', '.h', '.c', '.pch', '.rtf', '.java', '.applescript', '.dependency']
+utf16Extensions = ['.strings']
+
+## define character mappings
+asciiSimpleSurrounds = [('xc', 'xc')]
+asciiSurrounds = [('\xc7', '\xc8')]
+
+utf8SimpleSurrounds = asciiSimpleSurrounds
+utf8Surrounds = [('\xc2\xab', '\xc2\xbb')]
+
+utf16SimpleSurrounds = [('\x00x\x00c', '\x00x\x00c')]
+utf16Surrounds = [('\x00\xab', '\x00\xbb')]
+
+## substitution strings
+substitutionStrings = [
+    'PROJECTNAME',
+    'FULLUSERNAME',
+    'DATE',
+    'YEAR',
+    'PROJECTNAMEASIDENTIFIER',
+    'PROJECTNAMEASXML',
+    'ORGANIZATIONNAME'
+    ]
+
+utf16SubstitutionStrings = ["".join(['\x00%s' % c for c in aString]) for aString in substitutionStrings]
+
+utf16Substitutions = None
+utf8Substitutions = None
+asciiSubstitutions = None
+
+## build substitution tables based on options
+if doReverse:
+    asciiSubstitutions = [("%s%s%s" % (surround[0], aString, surround[1]),
+                            "%s%s%s" % (simpleSurround[0], aString, simpleSurround[1]))
+                         for aString in substitutionStrings
+                         for surround in asciiSurrounds
+                         for simpleSurround in asciiSimpleSurrounds]
+    utf8Substitutions = [("%s%s%s" % (surround[0], aString, surround[1]),
+                          "%s%s%s" % (simpleSurround[0], aString, simpleSurround[1]))
+                         for aString in substitutionStrings
+                         for surround in utf8Surrounds
+                         for simpleSurround in utf8SimpleSurrounds]
+    utf16Substitutions = [("%s%s%s" % (surround[0], aString, surround[1]),
+                          "%s%s%s" % (simpleSurround[0], aString, simpleSurround[1]))
+                         for aString in utf16SubstitutionStrings
+                         for surround in utf16Surrounds
+                         for simpleSurround in utf16SimpleSurrounds]
+else:
+    asciiSubstitutions = [("%s%s%s" % (simpleSurround[0], aString, simpleSurround[1]),
+                            "%s%s%s" % (surround[0], aString, surround[1]))
+                         for aString in substitutionStrings
+                         for surround in asciiSurrounds
+                         for simpleSurround in asciiSimpleSurrounds]
+    utf8Substitutions = [("%s%s%s" % (simpleSurround[0], aString, simpleSurround[1]),
+                          "%s%s%s" % (surround[0], aString, surround[1]))
+                         for aString in substitutionStrings
+                         for surround in utf8Surrounds
+                         for simpleSurround in utf8SimpleSurrounds]
+    utf16Substitutions = [("%s%s%s" % (simpleSurround[0], aString, simpleSurround[1]),
+                          "%s%s%s" % (surround[0], aString, surround[1]))
+                         for aString in utf16SubstitutionStrings
+                         for surround in utf16Surrounds
+                         for simpleSurround in utf16SimpleSurrounds]
+
+## processing starts here
+source = os.path.normpath(args[0])
+dest = os.path.normpath(args[1])
+
+if os.path.exists(dest):
+    if killDest:
+        if verbose:
+            print "Removing '%s'..." % dest
+        shutil.rmtree(dest)
+    else:
+        usage("Destination already exists.  -k to destroy or use different destination.")
+
+if verbose:
+    print "Creating destination '%s'...." % dest
+try:
+    head, tail = os.path.split(dest)
+    if not os.path.isdir(head):
+        os.makedirs(dest)
+except OSError, errno:
+    usage(errno)
+
+nastyFileExprs = [re.compile(expr) for expr in ['^.DS_Store$', '.*~.*$', '.*.pbxuser$']]
+
+os.path.walk(source, killNasties, None)
+
+if verbose:
+    print "Copying from '%s' to '%s'...." % (source, dest)
+shutil.copytree(source, dest)
+
+os.path.walk(dest, doSubstitutions, None)