#!/usr/bin/env python __version__ = '0.1' import sys import os import re import shutil import codecs import tempfile from optparse import OptionParser, Option, OptionValueError import logging from logging import error, info, debug import site site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'source-deps')) import subprocess import utf16reader utf16reader.install() def deletePath(path): info("Removing '%s'...", path) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) ## define functions used in script NASTYFILEEXPR = re.compile(r'|'.join([ r'(?:%s)' % (_exp,) for _exp in [ r'^\.svn$', r'^CVS$', r'^\.DS_Store$', r'~.*$', r'\.pbxuser$', r'^build$', r'\.mode[0-9]$' ] ])) def killNasties(dirName, aName, options): if NASTYFILEEXPR.search(aName) is None: return path = os.path.join(dirName, aName) deletePath(path) ## define per-file behaviors def maybenib(encoding): def maybenib(fn): if file(fn).read(11) == 'typedstream': info("Convert %s to a text nib file if you need substitution", fn) return None return encoding(fn) return maybenib def maybeutf(encoding=None): def maybeutf(fn): header = file(fn).read(4) if header.startswith(codecs.BOM_UTF8): return 'utf_8' elif header.startswith(codecs.BOM_UTF16_BE): return 'utf_16_be' elif header.startswith(codecs.BOM_UTF16_LE): return 'utf_16_le' # some hacks to guess BOM-less UTF-16 text elif header[0::2] == '\x00\x00' and header[1::2] != '\x00\x00': return 'utf_16_be' elif header[1::2] == '\x00\x00' and header[0::2] != '\x00\x00': return 'utf_16_le' # anything else is undetermined, can't match # utf-8 against Copies tree of templates or projects from to . Before copying, it cleans up by removing various bits of garbage. After copying, it transforms by replacing strings with their Xcode template counterparts. The reverse flag can be used to reverse this process; turning an Xcode template into a working project.""" parser = OptionParser(USAGE, version=__version__) def store_true(*args, **kwargs): kwargs['action'] = 'store_true' kwargs['default'] = False parser.add_option(*args, **kwargs) store_true('-v', '--verbose', dest='verbose', help='verbose') store_true('-k', '--kill-dest', dest='killDest', help='erase (no warning)') store_true('-r', '--reverse', dest='doReverse', help='reverse transformation (template -> editable project)') store_true('-w', '--working', dest='makeWorking', help='try to make destination into a working project') store_true('-n', '--nib', dest='rewriteNibFiles', help='rewrite NIB files to 10.2 text-only format') return parser def simplePathWalker(walkdir, fn, arg=None): def _simplePathWalker(arg, dirname, fnames): for name in fnames: fn(dirname, name, arg) os.path.walk(walkdir, _simplePathWalker, arg) def main(): parser = build_parser() options, args = parser.parse_args() if not args: parser.print_help() return if len(args) != 2: parser.error("Must specify both a source and destination") return if options.verbose: hdlr = logging.StreamHandler() fmt = logging.Formatter('%(message)s') hdlr.setFormatter(fmt) logger = logging.getLogger() logger.addHandler(hdlr) logger.setLevel(logging.INFO) else: logging.basicConfig() source, dest = map(os.path.normpath, args) if source == dest: parser.error("Source and destination may not be the same.") return if os.path.exists(dest): if options.killDest: deletePath(dest) else: parser.error("Destination already exists. -k to destroy or use different destination.") return info("Copying from '%s' to '%s'....", source, dest) shutil.copytree(source, dest) simplePathWalker(dest, killNasties, options) simplePathWalker(dest, doSubstitutions, options) if __name__ == '__main__': main()