def fromFile(cls, filename, classPrefix, includeRestorationIDs=False):
        res = cls(lib.bareFilename(filename), classPrefix)

        root = ElementTree.parse(fn)

        segueIds = getAttrsForAllNodesWithAttr(root, 'identifier', 'segue')
        res._addIds(segueIds, cls.SEGUE)

        # This seems to be limited to view controllers, but we can't specify a tag, as different
        # UIViewController subclasses have different tags (e.g. nav controllers).
        viewControllerIds = getAttrsForAllNodesWithAttr(
            root, 'storyboardIdentifier')
        res._addIds(viewControllerIds, cls.VIEW_CONTROLLER)

        reuseIds = getAttrsForAllNodesWithAttr(root, 'reuseIdentifier')
        res._addIds(reuseIds, cls.REUSE)

        if includeRestorationIDs:
            restorationIds = getAttrsForAllNodesWithAttr(
                root, 'restorationIdentifier')
            restorationIds.extend(
                getRestorationIDsForVCsUsingStoryboardIDs(root))
            res._addIds(restorationIds, cls.RESTORATION)

        return res
Example #2
0
def getIconFilenames(dir):
    # We want the processed Info.plist in the .app, not the one in the project.
    # Xcode consolidates asset catalog info into that plist, so it's a reliable
    # source for the names of icon files, regardless of how they got to be that way.
    packagedInfoPlist, _ = lib.loadPlist(os.path.join(dir, "Info.plist"))
    iPhoneIcons = packagedInfoPlist.valueForKeyPath_("CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles") or []
    iPadIcons = packagedInfoPlist.valueForKeyPath_("CFBundleIcons~ipad.CFBundlePrimaryIcon.CFBundleIconFiles") or []

    allIconNames = set(itertools.chain(iPhoneIcons, iPadIcons))

    resSuffixes = ["", "@2x", "@3x"]
    devSuffixes = ["", "~ipad"]

    fns = [
        os.path.join(dir, fn + res + dev + ".png") for fn in allIconNames for res in resSuffixes for dev in devSuffixes
    ]

    return filter(os.path.exists, fns)
Example #3
0
    def _addId(self, id_, type_):
        targetDict = None
        suffixes = [ 'ID', 'Id', 'Identifier' ]

        if type_ == self.SEGUE:
            targetDict = self.segues
            suffixes.append('Segue')
        elif type_ == self.VIEW_CONTROLLER:
            targetDict = self.viewControllers
            suffixes.extend(['ViewController', 'Controller', 'VC'])
        elif type_ == self.REUSE:
            targetDict = self.reusables
            suffixes.append('Reuse')
        elif type_ == self.RESTORATION:
            targetDict = self.restorables
            suffixes.append('Restoration')

        variableName = lib.variableNameForString(id_, self._defaultPrefixes, suffixes)
        targetDict[variableName] = id_
Example #4
0
def headerAndImpContentsForCatalog(catalogDir, classPrefix):
    imageNames = imageNamesInCatalog(catalogDir)
    if not imageNames:
        return ([], [])

    className = classNameForCatalog(catalogDir, classPrefix)

    hLines = ['@interface {}: NSObject\n'.format(className)]
    mLines = ['@implementation {}\n'.format(className)]

    for imageName in imageNames:
        identifier = lib.variableNameForString(imageName)
        hLines.append('+(UIImage *)' + identifier + ';')
        mLines.append('+(UIImage *)' + identifier + ' { return [UIImage imageNamed:@"' + imageName + '"]; }')

    hLines.append('\n@end')
    mLines.append('\n@end')

    return ('\n'.join(hLines), '\n'.join(mLines))
    def _addId(self, id_, type_):
        targetDict = None
        suffixes = ['ID', 'Id', 'Identifier']

        if type_ == self.SEGUE:
            targetDict = self.segues
            suffixes.append('Segue')
        elif type_ == self.VIEW_CONTROLLER:
            targetDict = self.viewControllers
            suffixes.extend(['ViewController', 'Controller', 'VC'])
        elif type_ == self.REUSE:
            targetDict = self.reusables
            suffixes.append('Reuse')
        elif type_ == self.RESTORATION:
            targetDict = self.restorables
            suffixes.append('Restoration')

        variableName = lib.variableNameForString(id_, self._defaultPrefixes,
                                                 suffixes)
        targetDict[variableName] = id_
Example #6
0
def getIconFilenames(dir):
    # We want the processed Info.plist in the .app, not the one in the project.
    # Xcode consolidates asset catalog info into that plist, so it's a reliable
    # source for the names of icon files, regardless of how they got to be that way.
    packagedInfoPlist, _ = lib.loadPlist(os.path.join(dir, "Info.plist"))
    iPhoneIcons = packagedInfoPlist.valueForKeyPath_("CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles") or []
    iPadIcons = packagedInfoPlist.valueForKeyPath_("CFBundleIcons~ipad.CFBundlePrimaryIcon.CFBundleIconFiles") or []

    fns = []
    fns.extend([fn + ".png" for fn in iPhoneIcons])
    fns.extend([fn + "@2x.png" for fn in iPhoneIcons])
    fns.extend([fn + "@3x.png" for fn in iPhoneIcons])  # IT'S HAPPENING
    fns.extend([fn + "~ipad.png" for fn in iPadIcons])
    fns.extend([fn + "@2x~ipad.png" for fn in iPadIcons])
    fns.extend([fn + "@3x~ipad.png" for fn in iPadIcons])
    fns = [os.path.join(dir, fn) for fn in fns]

    fns = filter(os.path.exists, fns)

    return fns
Example #7
0
    def __init__(self, storyboardName, classPrefix):
        self.name = storyboardName
        self.classPrefix = classPrefix
        self.segues = {}
        self.viewControllers = {}
        self.reusables = {}
        self.restorables = {}

        self._defaultPrefixes = [ classPrefix, storyboardName, 'Storyboard' ]
        if storyboardName.endswith('Storyboard'):
            self._defaultPrefixes.append(storyboardName[:-10])

        self.className = lib.variableNameForString(storyboardName, [ classPrefix ], [ 'Storyboard' ], lower = False)
        self._defaultPrefixes.append(self.className)

        if classPrefix:
            self.className = classPrefix + self.className
            self._defaultPrefixes.append(self.className)

        self.className += 'StoryboardIDs'
Example #8
0
def getIconFilenames(dir):
    # We want the processed Info.plist in the .app, not the one in the project.
    # Xcode consolidates asset catalog info into that plist, so it's a reliable
    # source for the names of icon files, regardless of how they got to be that way.
    packagedInfoPlist, _ = lib.loadPlist(os.path.join(dir, 'Info.plist'))
    iPhoneIcons = packagedInfoPlist.valueForKeyPath_(
        'CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles') or []
    iPadIcons = packagedInfoPlist.valueForKeyPath_(
        'CFBundleIcons~ipad.CFBundlePrimaryIcon.CFBundleIconFiles') or []

    allIconNames = set(itertools.chain(iPhoneIcons, iPadIcons))

    resSuffixes = ['', '@2x', '@3x']
    devSuffixes = ['', '~ipad']

    fns = [
        os.path.join(dir, fn + res + dev + '.png') for fn in allIconNames
        for res in resSuffixes for dev in devSuffixes
    ]

    return filter(os.path.exists, fns)
Example #9
0
    def fromFile(cls, filename, classPrefix, includeRestorationIDs = False):
        res = cls(lib.bareFilename(filename), classPrefix)

        root = ElementTree.parse(fn)

        segueIds = getAttrsForAllNodesWithAttr(root, 'identifier', 'segue')
        res._addIds(segueIds, cls.SEGUE)

        # This seems to be limited to view controllers, but we can't specify a tag, as different
        # UIViewController subclasses have different tags (e.g. nav controllers).
        viewControllerIds = getAttrsForAllNodesWithAttr(root, 'storyboardIdentifier')
        res._addIds(viewControllerIds, cls.VIEW_CONTROLLER)

        reuseIds = getAttrsForAllNodesWithAttr(root, 'reuseIdentifier')
        res._addIds(reuseIds, cls.REUSE)

        if includeRestorationIDs:
            restorationIds = getAttrsForAllNodesWithAttr(root, 'restorationIdentifier')
            restorationIds.extend(getRestorationIDsForVCsUsingStoryboardIDs(root))
            res._addIds(restorationIds, cls.RESTORATION)

        return res
    def __init__(self, storyboardName, classPrefix):
        self.name = storyboardName
        self.classPrefix = classPrefix
        self.segues = {}
        self.viewControllers = {}
        self.reusables = {}
        self.restorables = {}

        self._defaultPrefixes = [classPrefix, storyboardName, 'Storyboard']
        if storyboardName.endswith('Storyboard'):
            self._defaultPrefixes.append(storyboardName[:-10])

        self.className = lib.variableNameForString(storyboardName,
                                                   [classPrefix],
                                                   ['Storyboard'],
                                                   lower=False)
        self._defaultPrefixes.append(self.className)

        if classPrefix:
            self.className = classPrefix + self.className
            self._defaultPrefixes.append(self.className)

        self.className += 'StoryboardIDs'
def imageNamesInCatalog(catalogDir):
    imagesetDirs = glob(os.path.join(catalogDir, '*.imageset'))
    return [lib.bareFilename(d) for d in imagesetDirs]
    imp = warning
    imp += '#import "' + outputBasename + '.h"\n\n'
    imp += '\n\n'.join(lines[1])

    headerFn = os.path.join(outputDir, outputBasename + '.h')
    impFn = os.path.join(outputDir, outputBasename + '.m')

    with open(headerFn, 'w') as f:
        f.write(header.encode('utf-8'))

    with open(impFn, 'w') as f:
        f.write(imp.encode('utf-8'))

if __name__ == '__main__':
    outBasename = 'AssetCatalogIdentifiers'
    prefix = lib.classPrefix

    projectDir = os.path.join(lib.getEnv('SRCROOT'), lib.getEnv('PROJECT_NAME'))

    catalogDirs = list(lib.recursiveGlob(projectDir, '*.xcassets', includeDirs = True))
    lines = ([], [])
    for catalogDir in catalogDirs:
        hString, mString = headerAndImpContentsForCatalog(catalogDir, prefix)
        if hString:
            lines[0].append(hString)
            lines[1].append(mString)

    outDir = os.path.join(projectDir, 'Other-Sources', 'Generated')
    assembleAndOutput(lines, outDir, outBasename)

    print 'Generated {}.h and .m for image assets in the following catalog(s): {}'.format(outBasename, ', '.join([os.path.basename(d) for d in catalogDirs]))
Example #13
0
    headerFn = os.path.join(outputDir, outputBasename + '.h')
    impFn = os.path.join(outputDir, outputBasename + '.m')

    with open(headerFn, 'w') as f:
        f.write(header.encode('utf-8'))

    with open(impFn, 'w') as f:
        f.write(imp.encode('utf-8'))


if __name__ == '__main__':
    outBasename = 'StoryboardIdentifiers'
    prefix = lib.classPrefix
    needRestorationIDs = 'NEED_RESTORATION_IDS' in os.environ

    projectDir = os.path.join(lib.getEnv('SRCROOT'), lib.getEnv('PROJECT_NAME'))

    inputFiles = list(lib.recursiveGlob(projectDir, '*.storyboard'))

    lines = ([], [])
    for fn in inputFiles:
        idList = IDList.fromFile(fn, prefix, needRestorationIDs)
        hString, mString = idList.headerAndImpContents()
        if hString:
            lines[0].append('#pragma mark ' + idList.name)
            lines[0].append(hString)

            lines[1].append('#pragma mark ' + idList.name)
            lines[1].append(mString)

    outDir = os.path.join(projectDir, 'Other-Sources', 'Generated')
Example #14
0
from __future__ import print_function, unicode_literals
import AmaroLib as lib
from sys import exit
from glob import glob
import os.path
from shutil import rmtree

# Don't run in continuous integration or if we're not a build for release
if lib.inContinuousIntegration or not lib.isDistributionOrAdHocBuildForDevice:
    print('Not removing localizations; this is an internal build')
    exit(0)

# The project object has a knownRegions property that is an array of 
# locale strings (e.g. "Base", "en") that were set up in Xcode.
knownRegions = lib.getProjectKeypath('knownRegions')

if not knownRegions:
    lib.warn('The project is reporting that there are no known localizations in your project.\nPlease report this at {}'.format(lib.REPORT_URL))
    exit(0)

print('Keeping localizations for regions: ' + ', '.join(knownRegions))

regionsAndFoldersToDelete = []
lprojFolders = glob(os.path.join(lib.getEnv('CODESIGNING_FOLDER_PATH'), '*.lproj'))
for lprojFolder in lprojFolders:
    region = lib.bareFilename(lprojFolder)
    if not region in knownRegions:
        regionsAndFoldersToDelete.append((region, lprojFolder))

if regionsAndFoldersToDelete:
#!/usr/bin/env python2.7

# This script increments the build number (CFBundleVersion in the Info.plist)
# on Ad-Hoc or Distribution builds that target real devices.
# In the context of Amaro, that means an archive build of any scheme, or any
# non-simulator build of the AppStore scheme.

# This script should be run as a build phase before the "Copy Bundle Resources"
# phase. It has no input or output files.

from __future__ import print_function, unicode_literals
import AmaroLib as lib
from sys import exit

# Bail unless we're a build for something that's going to be released
if not lib.isDistributionOrAdHocBuildForDevice:
    print('Not incrementing build number; this is an internal build')
    exit(0)

buildNumber = lib.buildNumber
try:
    buildNumber = int(buildNumber)
except ValueError, e:
    lib.warn('Unable to parse your build number ("{}") as an integer. Not incrementing it!'.format(buildNumber))
    exit(0)

lib.infoPlist['CFBundleVersionKey'] = str(buildNumber + 1)
lib.writePlist(lib.infoPlistFilename, lib.infoPlist, lib.infoPlistFormat)
def classNameForCatalog(catalogDir, classPrefix):
    name = lib.bareFilename(catalogDir)
    return classPrefix + lib.variableNameForString(name, [classPrefix], ['AssetCatalog', 'Catalog'], lower = False) + 'Catalog'
    headerFn = os.path.join(outputDir, outputBasename + '.h')
    impFn = os.path.join(outputDir, outputBasename + '.m')

    with open(headerFn, 'w') as f:
        f.write(header.encode('utf-8'))

    with open(impFn, 'w') as f:
        f.write(imp.encode('utf-8'))


if __name__ == '__main__':
    outBasename = 'StoryboardIdentifiers'
    prefix = lib.classPrefix
    needRestorationIDs = 'NEED_RESTORATION_IDS' in os.environ

    projectDir = os.path.join(lib.getEnv('SRCROOT'),
                              lib.getEnv('PROJECT_NAME'))

    inputFiles = list(lib.recursiveGlob(projectDir, '*.storyboard'))

    lines = ([], [])
    for fn in inputFiles:
        idList = IDList.fromFile(fn, prefix, needRestorationIDs)
        hString, mString = idList.headerAndImpContents()
        if hString:
            lines[0].append('#pragma mark ' + idList.name)
            lines[0].append(hString)

            lines[1].append('#pragma mark ' + idList.name)
            lines[1].append(mString)
Example #18
0
#!/usr/bin/env python2.7

# This script increments the build number (CFBundleVersion in the Info.plist)
# on Ad-Hoc or Distribution builds that target real devices.
# In the context of Amaro, that means an archive build of any scheme, or any
# non-simulator build of the AppStore scheme.

# This script should be run as a build phase before the "Copy Bundle Resources"
# phase. It has no input or output files.

from __future__ import print_function, unicode_literals
import AmaroLib as lib
from sys import exit
import subprocess

# Bail unless we're a build for something that's going to be released
if not lib.isDistributionOrAdHocBuildForDevice:
    print('Not incrementing build number; this is an internal build')
    exit(0)

newBuildNumber = subprocess.check_output(["./bin/buildNo.sh",], shell=True).strip()
print("build number: %s" % newBuildNumber)

lib.infoPlist['CFBundleVersion'] = newBuildNumber
lib.writePlist(lib.infoPlistFilename, lib.infoPlist, lib.infoPlistFormat)
Example #19
0
# This script increments the build number (CFBundleVersion in the Info.plist)
# on Ad-Hoc or Distribution builds that target real devices.
# In the context of Amaro, that means an archive build of any scheme, or any
# non-simulator build of the AppStore scheme.

# This script should be run as a build phase before the "Copy Bundle Resources"
# phase. It has no input or output files.

from __future__ import print_function, unicode_literals
import AmaroLib as lib
from sys import exit

# Bail unless we're a build for something that's going to be released
if not lib.isDistributionOrAdHocBuildForDevice:
    print('Not incrementing build number; this is an internal build')
    exit(0)

buildNumber = lib.buildNumber
try:
    buildNumber = int(buildNumber)
except ValueError, e:
    lib.warn(
        'Unable to parse your build number ("{}") as an integer. Not incrementing it!'
        .format(buildNumber))
    exit(0)

newBuildNumber = str(buildNumber + 1)
lib.infoPlist['CFBundleVersion'] = newBuildNumber
print('Incrementing build number to {}'.format(newBuildNumber))

lib.writePlist(lib.infoPlistFilename, lib.infoPlist, lib.infoPlistFormat)
Example #20
0
def classNameForCatalog(catalogDir, classPrefix):
    name = lib.bareFilename(catalogDir)
    return classPrefix + lib.variableNameForString(name, [classPrefix],
                                                   ['AssetCatalog', 'Catalog'],
                                                   lower=False) + 'Catalog'
Example #21
0
def imageNamesInCatalog(catalogDir):
    imagesetDirs = glob(os.path.join(catalogDir, '*.imageset'))
    return [lib.bareFilename(d) for d in imagesetDirs]
Example #22
0
    headerFn = os.path.join(outputDir, outputBasename + '.h')
    impFn = os.path.join(outputDir, outputBasename + '.m')

    with open(headerFn, 'w') as f:
        f.write(header.encode('utf-8'))

    with open(impFn, 'w') as f:
        f.write(imp.encode('utf-8'))


if __name__ == '__main__':
    outBasename = 'AssetCatalogIdentifiers'
    prefix = lib.classPrefix

    projectDir = os.path.join(lib.getEnv('SRCROOT'),
                              lib.getEnv('PROJECT_NAME'))

    catalogDirs = list(
        lib.recursiveGlob(projectDir, '*.xcassets', includeDirs=True))
    lines = ([], [])
    for catalogDir in catalogDirs:
        hString, mString = headerAndImpContentsForCatalog(catalogDir, prefix)
        if hString:
            lines[0].append(hString)
            lines[1].append(mString)

    outDir = os.path.join(projectDir, 'Other-Sources', 'Generated')
    assembleAndOutput(lines, outDir, outBasename)

    print(
Example #23
0
def getIconFilenames(dir):
    # We want the processed Info.plist in the .app, not the one in the project.
    # Xcode consolidates asset catalog info into that plist, so it's a reliable
    # source for the names of icon files, regardless of how they got to be that way.
    packagedInfoPlist, _ = lib.loadPlist(os.path.join(dir, 'Info.plist'))
    iPhoneIcons = packagedInfoPlist.valueForKeyPath_('CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles') or []
    iPadIcons = packagedInfoPlist.valueForKeyPath_('CFBundleIcons~ipad.CFBundlePrimaryIcon.CFBundleIconFiles') or []

    allIconNames = set(itertools.chain(iPhoneIcons, iPadIcons))

    resSuffixes = ['', '@2x', '@3x']
    devSuffixes = ['', '~ipad']

    fns = [os.path.join(dir, fn + res + dev + '.png')
            for fn in allIconNames
            for res in resSuffixes
            for dev in devSuffixes]

    return filter(os.path.exists, fns)


if __name__ == '__main__':
    sourceDir = lib.getEnv('CODESIGNING_FOLDER_PATH')

    iconFns = getIconFilenames(sourceDir)

    for fn in iconFns:
        badgeFile(fn, sourceDir, lib.targetingStaging, lib.version, lib.buildNumber)

    print('Badged the following icon files: ' + ', '.join([os.path.basename(fn) for fn in iconFns]))
Example #24
0
    packagedInfoPlist, _ = lib.loadPlist(os.path.join(dir, 'Info.plist'))
    iPhoneIcons = packagedInfoPlist.valueForKeyPath_(
        'CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles') or []
    iPadIcons = packagedInfoPlist.valueForKeyPath_(
        'CFBundleIcons~ipad.CFBundlePrimaryIcon.CFBundleIconFiles') or []

    allIconNames = set(itertools.chain(iPhoneIcons, iPadIcons))

    resSuffixes = ['', '@2x', '@3x']
    devSuffixes = ['', '~ipad']

    fns = [
        os.path.join(dir, fn + res + dev + '.png') for fn in allIconNames
        for res in resSuffixes for dev in devSuffixes
    ]

    return filter(os.path.exists, fns)


if __name__ == '__main__':
    sourceDir = lib.getEnv('CODESIGNING_FOLDER_PATH')

    iconFns = getIconFilenames(sourceDir)

    for fn in iconFns:
        badgeFile(fn, sourceDir, lib.targetingStaging, lib.version,
                  lib.buildNumber)

    print('Badged the following icon files: ' +
          ', '.join([os.path.basename(fn) for fn in iconFns]))