├── Examples
├── Annotated Configuration.json
└── Example Configuration.json
├── License.txt
├── README.md
├── XCAssetPacker Tests
├── Complication Rules.json
├── Info.plist
├── Skip Circles Rules.json
├── Watch
│ ├── Image Generation.xcodeproj
│ │ └── project.pbxproj
│ ├── Source
│ │ ├── App Icon.sketch
│ │ ├── Bed-38.png
│ │ ├── Bed-42.png
│ │ ├── ColorComplicationIndicator-38.png
│ │ ├── ColorComplicationIndicator-42.png
│ │ ├── Complication Rules.json
│ │ ├── GrayscaleComplicationIndicator-38.png
│ │ ├── GrayscaleComplicationIndicator-42.png
│ │ ├── Icons.sketch
│ │ ├── Moon-38.png
│ │ ├── Moon-42.png
│ │ ├── ReminderSelected-38.png
│ │ ├── ReminderSelected-42.png
│ │ ├── ReminderUnselected-38.png
│ │ ├── ReminderUnselected-42.png
│ │ ├── Sun-38.png
│ │ ├── Sun-42.png
│ │ ├── Watch App Icon.png
│ │ ├── Watch App Notification Icon-38.png
│ │ ├── Watch App Notification Icon-42.png
│ │ ├── Watch App Rules.json
│ │ ├── Watch App Short Look Icon-38.png
│ │ └── Watch App Short Look Icon-42.png
│ ├── Watch
│ │ └── Images
│ │ │ ├── CircularSmallCircle
│ │ │ ├── CircularSmallCircle0-38.png
│ │ │ ├── CircularSmallCircle0-42.png
│ │ │ ├── CircularSmallCircle1-38.png
│ │ │ ├── CircularSmallCircle1-42.png
│ │ │ ├── CircularSmallCircle2-38.png
│ │ │ └── CircularSmallCircle2-42.png
│ │ │ ├── ComplicationPreview
│ │ │ ├── ComplicationPreview0-38.png
│ │ │ ├── ComplicationPreview0-42.png
│ │ │ ├── ComplicationPreview1-38.png
│ │ │ └── ComplicationPreview1-42.png
│ │ │ ├── ModularSmallCircle
│ │ │ ├── ModularSmallCircle0-38.png
│ │ │ ├── ModularSmallCircle0-42.png
│ │ │ ├── ModularSmallCircle1-38.png
│ │ │ ├── ModularSmallCircle1-42.png
│ │ │ ├── ModularSmallCircle2-38.png
│ │ │ ├── ModularSmallCircle2-42.png
│ │ │ ├── ModularSmallCircle3-38.png
│ │ │ ├── ModularSmallCircle3-42.png
│ │ │ ├── ModularSmallCircle4-38.png
│ │ │ └── ModularSmallCircle4-42.png
│ │ │ ├── SleepDuration
│ │ │ ├── SleepDuration0-38.png
│ │ │ ├── SleepDuration0-42.png
│ │ │ ├── SleepDuration1-38.png
│ │ │ ├── SleepDuration1-42.png
│ │ │ ├── SleepDuration2-38.png
│ │ │ ├── SleepDuration2-42.png
│ │ │ ├── SleepDuration3-38.png
│ │ │ ├── SleepDuration3-42.png
│ │ │ ├── SleepDuration4-38.png
│ │ │ └── SleepDuration4-42.png
│ │ │ ├── UtilitarianExtraLargeCircle
│ │ │ ├── UtilitarianExtraLargeCircle0-38.png
│ │ │ └── UtilitarianExtraLargeCircle0-42.png
│ │ │ └── WakeTime
│ │ │ ├── WakeTime0.png
│ │ │ ├── WakeTime1.png
│ │ │ ├── WakeTime10.png
│ │ │ ├── WakeTime11.png
│ │ │ ├── WakeTime12.png
│ │ │ ├── WakeTime13.png
│ │ │ ├── WakeTime14.png
│ │ │ ├── WakeTime15.png
│ │ │ ├── WakeTime16.png
│ │ │ ├── WakeTime17.png
│ │ │ ├── WakeTime18.png
│ │ │ ├── WakeTime19.png
│ │ │ ├── WakeTime2.png
│ │ │ ├── WakeTime20.png
│ │ │ ├── WakeTime21.png
│ │ │ ├── WakeTime22.png
│ │ │ ├── WakeTime23.png
│ │ │ ├── WakeTime24.png
│ │ │ ├── WakeTime25.png
│ │ │ ├── WakeTime26.png
│ │ │ ├── WakeTime27.png
│ │ │ ├── WakeTime28.png
│ │ │ ├── WakeTime29.png
│ │ │ ├── WakeTime3.png
│ │ │ ├── WakeTime30.png
│ │ │ ├── WakeTime31.png
│ │ │ ├── WakeTime32.png
│ │ │ ├── WakeTime33.png
│ │ │ ├── WakeTime34.png
│ │ │ ├── WakeTime35.png
│ │ │ ├── WakeTime36.png
│ │ │ ├── WakeTime37.png
│ │ │ ├── WakeTime38.png
│ │ │ ├── WakeTime39.png
│ │ │ ├── WakeTime4.png
│ │ │ ├── WakeTime40.png
│ │ │ ├── WakeTime41.png
│ │ │ ├── WakeTime42.png
│ │ │ ├── WakeTime43.png
│ │ │ ├── WakeTime44.png
│ │ │ ├── WakeTime45.png
│ │ │ ├── WakeTime46.png
│ │ │ ├── WakeTime47.png
│ │ │ ├── WakeTime48.png
│ │ │ ├── WakeTime49.png
│ │ │ ├── WakeTime5.png
│ │ │ ├── WakeTime50.png
│ │ │ ├── WakeTime51.png
│ │ │ ├── WakeTime52.png
│ │ │ ├── WakeTime6.png
│ │ │ ├── WakeTime7.png
│ │ │ ├── WakeTime8.png
│ │ │ └── WakeTime9.png
│ └── generate.sh
└── XCAssetPacker_Tests.swift
├── XCAssetPacker.xcodeproj
└── project.pbxproj
└── XCAssetPacker
├── AssetCatalogGenerator+Creation.swift
├── AssetCatalogGenerator.swift
├── CommandLine
├── .gitignore
├── .travis.yml
├── CommandLineKit.xcodeproj
│ ├── project.pbxproj
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── CommandLine.xcscheme
├── CommandLineKit
│ ├── CommandLine.swift
│ ├── Info.plist
│ ├── Option.swift
│ └── StringExtensions.swift
├── LICENSE
├── Package.swift
├── README.md
├── Tests
│ ├── CommandLineKitTests
│ │ ├── CommandLineTests.swift
│ │ ├── Info.plist
│ │ └── StringExtensionTests.swift
│ └── LinuxMain.swift
└── install-linux-swift.sh
├── Constants.swift
├── DeviceIdiom.swift
├── Extensions.swift
├── ImageProperties.swift
├── SwiftGeneration.swift
└── main.swift
/Examples/Annotated Configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | /* Skip images */
3 | "skip-images" : {
4 | "patterns" : ["Watch App .*", "Bed.*"]
5 | },
6 |
7 |
8 | /* Set which images to include. Defaults to ["png"] */
9 | "valid-image-extensions" : ["png", "jpeg", "jpg", "tiff"],
10 |
11 | // Set the base rendering options
12 | "base" : {
13 | "template-rendering-intent" : "template"
14 | },
15 |
16 | /* Apply properties based on the target device */
17 | "devices" : [
18 | {
19 | "device-type" : "watch",
20 | "properties" : {
21 | "template-rendering-intent" : "template"
22 | }
23 | }
24 | ],
25 |
26 | /* By default images following the AppIcon-{size}.png naming convention
27 | will be treated as prerendered app icons and won't be exposed to Swift */
28 | "app-icon" : {
29 | "pattern" : "Custom App Icon Name.*",
30 | "prerendered" : false /* Defaults to true */
31 | },
32 |
33 | /* Apply custom sets of properties to images matched by the given patterns */
34 | "custom" : [
35 | {
36 | "patterns" : [".*Preview.*", "SleepDuration.*", "WakeTime.*"],
37 | "properties" : {
38 | "template-rendering-intent" : "original"
39 | }
40 | }
41 | ]
42 | }
--------------------------------------------------------------------------------
/Examples/Example Configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "skip-images" : {
3 | "patterns" : ["Watch App .*", "Bed.*"]
4 | },
5 |
6 | "valid-image-extensions" : ["png", "jpeg", "jpg", "tiff"],
7 |
8 | "base" : {
9 | "template-rendering-intent" : "template"
10 | },
11 |
12 | "devices" : [
13 | {
14 | "device-type" : "watch",
15 | "properties" : {
16 | "template-rendering-intent" : "template"
17 | }
18 | }
19 | ],
20 |
21 | "app-icon" : {
22 | "pattern" : "Custom App Icon Name.*",
23 | "prerendered" : false
24 | },
25 |
26 | "custom" : [
27 | {
28 | "patterns" : [".*Preview.*", "SleepDuration.*", "WakeTime.*"],
29 | "properties" : {
30 | "template-rendering-intent" : "original"
31 | }
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 | # XCAssetPacker
2 | Copyright (c) 2016 Inquisitive Software. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 |
17 | # CommandLine.swift
18 | Copyright (c) 2014 Ben Gollmer.
19 |
20 | Licensed under the Apache License, Version 2.0 (the "License");
21 | you may not use this file except in compliance with the License.
22 | You may obtain a copy of the License at
23 |
24 | http://www.apache.org/licenses/LICENSE-2.0
25 |
26 | Unless required by applicable law or agreed to in writing, software
27 | distributed under the License is distributed on an "AS IS" BASIS,
28 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 | See the License for the specific language governing permissions and
30 | limitations under the License.
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # XCAssetPacker
2 | XCAssetPacker is a command line tool to create an Xcode `.xcasset` package from a folder of images.
3 |
4 | ## Installation
5 | The easiest way to get up and running is to use homebrew: `brew install inquisitiveSoft/tools/XCAssetPacker`
6 |
7 | Alternatively, it's very easy to download and build from source using Xcode. All dependencies are included directly in the project.
8 |
9 | ## Usage
10 | I recommend calling `xcassetpacker` with the `--force` flag and treating the .xcassets and Swift output file as purely machine-generated.
11 |
12 | ```
13 | xcassetpacker
14 | --input "Images/Source"
15 | --output "Resources/App.xcassets"
16 | --config "Images/Source/Main App Images Configuration.json"
17 | --swift "Code/Images.swift"
18 | --force
19 | ```
20 |
21 | ### Command Line Options
22 | `-i`, `--input`: Path to the input folder.
23 | `-c`, `--config`: The location of a json configuration file. If none is specified then uses sensible defaults.
24 | `-o`, `--output`: Path to the output file or folder. If a folder is given then an Assets.xcassets package will be created inside it.
25 | `--swift`: Path to the output swift file or folder. If a folder is given then an Images.swift package will be created inside it.
26 | `-f`, `--force`: Overwrite any existing .xcassets package or Swift file.
27 | `-h`, `--help`: Prints a help message.
28 |
29 | You can set the target for generated Swift using: `--iOS`, `--mac` or `--watch`. By default it will generate iOS code.
30 |
31 | ## Image Naming Conventions
32 | There are a number of image naming conventions which will be auto-detected.
33 |
34 | - Scale is determined using a trailing `@1x`, `@2x` or `@3x`.
35 |
36 | - Image type will also be detected using the following suffixes:
37 |
38 | | Suffix | Detected Image Type |
39 | | ------ | ---------- |
40 | | -38 | Image targeting the smaller Apple Watch |
41 | | -42 | Image targeting the larger Apple Watch |
42 | | -20 | Notification icon |
43 | | -29 | Settings icon |
44 | | -40 | Spotlight icon |
45 | | -60 | iPhone App icon |
46 | | -76 | iPad App icon |
47 | | -83.5 | iPad Pro App icon |
48 |
49 | - In addition `AppIcon` is recognized as a standard icon name. App icons are stored slightly differently internally and will be marked as `prerendered` by default. For example an image named `AppIcon-40@3x.png` would be detected as the spotlight icon for the Plus sized iPhone.
50 |
51 | ### Configuration.json
52 | XCAssetPacker has sensible defaults, so you can get started straight away, but you can also configure it using a JSON file. The most common uses are for filtering which images are included, and to set image properties such as target device or rendering intent of images.
53 |
54 | ---
55 |
56 | Skip images that match the given regex `patterns`:
57 |
58 | ```
59 | "skip-images" : {
60 | "patterns" : ["Watch App .*", "Bed.*"]
61 | }
62 | ```
63 |
64 | ---
65 | Determine which images to include. Defaults to `png` only:
66 |
67 | ```
68 | "valid-image-extensions" : ["png", "jpeg", "jpg", "tiff"]
69 | ```
70 |
71 | ---
72 | Apply a dictionary of properties to every image:
73 |
74 | ```
75 | "base" : {
76 | "template-rendering-intent" : "template"
77 | }
78 | ```
79 |
80 | ---
81 | Apply properties based on the target device:
82 |
83 | ```
84 | "devices" : [
85 | {
86 | "device-type" : "watch",
87 | "properties" : {
88 | "template-rendering-intent" : "template"
89 | }
90 | }
91 | ]
92 | ```
93 |
94 | ---
95 | By default, images following the `AppIcon-{size}.png` naming convention
96 | will be treated as prerendered app icons and won't be exposed to Swift, or you can customize the app-icon properties:
97 | ```
98 | "app-icon" : {
99 | "pattern" : "Custom App Icon Name.*",
100 | "prerendered" : false /* Defaults to true */
101 | }
102 | ```
103 |
104 | ---
105 | Apply a dictionary of properties to images matched by the given patterns:
106 | ```
107 | "custom" : [
108 | {
109 | "patterns" : [".*Preview.*", "SleepDuration.*", "WakeTime.*"],
110 | "properties" : {
111 | "template-rendering-intent" : "original"
112 | }
113 | }
114 | ]
115 | ```
116 |
117 | ---
118 | `template-rendering-intent` is a property that iOS uses to determine whether an image has a tintColor applied. Valid properties are `rendering` (tinted) or `original` (not-tinted). Not supplying a value is equivalent to the 'Default' option in Xcode's UI.
119 |
120 | A good starting point might be the [Example Configuration.json](Examples/Example%20Configuration.json).
121 |
122 | ## Credits
123 | Uses Ben Gollmer's nifty [CommandLine framework](https://github.com/jatoben/CommandLine) for parsing CLI input.
124 |
125 | ## License
126 | Open sourced under the Apache Version 2.0 License.
127 |
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Complication Rules.json:
--------------------------------------------------------------------------------
1 | {
2 | "base" : {
3 | "template-rendering-intent" : "template"
4 | },
5 | "devices" : [
6 | {
7 | "device-type" : "watch",
8 | "properties" : {
9 | "template-rendering-intent" : "template"
10 | }
11 | }
12 | ],
13 | "custom" : [
14 | {
15 | "patterns" : [".*Preview.*", "SleepDuration.*", "WakeTime.*"],
16 | "properties" : {
17 | "template-rendering-intent" : "original"
18 | }
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Skip Circles Rules.json:
--------------------------------------------------------------------------------
1 | {
2 | "base" : {
3 | "template-rendering-intent" : "template"
4 | },
5 | "devices" : [
6 | {
7 | "device-type" : "watch",
8 | "properties" : {
9 | "template-rendering-intent" : "template"
10 | }
11 | }
12 | ],
13 | "custom" : [
14 | {
15 | "patterns" : [".*Preview.*", "SleepDuration.*", "WakeTime.*"],
16 | "properties" : {
17 | "template-rendering-intent" : "original"
18 | }
19 | }
20 | ],
21 | "skip-images" : {
22 | "patterns" : [".*Circle"]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Image Generation.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXAggregateTarget section */
10 | 4A66849B1DEB3E1600BEE075 /* Generate Images */ = {
11 | isa = PBXAggregateTarget;
12 | buildConfigurationList = 4A66849C1DEB3E1600BEE075 /* Build configuration list for PBXAggregateTarget "Generate Images" */;
13 | buildPhases = (
14 | 4A6684A31DEB3E2000BEE075 /* ShellScript */,
15 | );
16 | dependencies = (
17 | 4A6684A01DEB3E1C00BEE075 /* PBXTargetDependency */,
18 | );
19 | name = "Generate Images";
20 | productName = "Generate Images";
21 | };
22 | /* End PBXAggregateTarget section */
23 |
24 | /* Begin PBXBuildFile section */
25 | 4A0656D91DF8FC9E000073E0 /* Blank.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0656D81DF8FC9E000073E0 /* Blank.swift */; };
26 | 4A7023F21DF4A83C00F04BD0 /* CommandLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7023EF1DF4A83C00F04BD0 /* CommandLine.swift */; };
27 | 4A7023F31DF4A83C00F04BD0 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7023F01DF4A83C00F04BD0 /* Option.swift */; };
28 | 4A7023F41DF4A83C00F04BD0 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7023F11DF4A83C00F04BD0 /* StringExtensions.swift */; };
29 | 4AE3F5A41DE6744A003B192E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE3F59A1DE67087003B192E /* main.swift */; };
30 | 4AE3F5A51DE6744A003B192E /* ImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE3F5991DE67087003B192E /* ImageGenerator.swift */; };
31 | 4AE3F5A61DE6744A003B192E /* Maths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE3F59B1DE67087003B192E /* Maths.swift */; };
32 | 4AE3F5A71DE6744A003B192E /* Circle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE3F59C1DE67087003B192E /* Circle.swift */; };
33 | 4AE3F5BE1DE73FE4003B192E /* SleepDuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE3F5BD1DE73FE4003B192E /* SleepDuration.swift */; };
34 | 4AE3F5C01DE74A8F003B192E /* WakeTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE3F5BF1DE74A8F003B192E /* WakeTime.swift */; };
35 | /* End PBXBuildFile section */
36 |
37 | /* Begin PBXContainerItemProxy section */
38 | 4A66849F1DEB3E1C00BEE075 /* PBXContainerItemProxy */ = {
39 | isa = PBXContainerItemProxy;
40 | containerPortal = 4AE3F5211DE60EB4003B192E /* Project object */;
41 | proxyType = 1;
42 | remoteGlobalIDString = 4AE3F5281DE60EB4003B192E;
43 | remoteInfo = ImageGeneration;
44 | };
45 | /* End PBXContainerItemProxy section */
46 |
47 | /* Begin PBXCopyFilesBuildPhase section */
48 | 4AE3F5271DE60EB4003B192E /* CopyFiles */ = {
49 | isa = PBXCopyFilesBuildPhase;
50 | buildActionMask = 2147483647;
51 | dstPath = /usr/share/man/man1/;
52 | dstSubfolderSpec = 0;
53 | files = (
54 | );
55 | runOnlyForDeploymentPostprocessing = 1;
56 | };
57 | /* End PBXCopyFilesBuildPhase section */
58 |
59 | /* Begin PBXFileReference section */
60 | 4A0656D81DF8FC9E000073E0 /* Blank.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Blank.swift; path = ImageGeneration/Blank.swift; sourceTree = SOURCE_ROOT; };
61 | 4A7023EF1DF4A83C00F04BD0 /* CommandLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CommandLine.swift; path = CommandLine/CommandLineKit/CommandLine.swift; sourceTree = SOURCE_ROOT; };
62 | 4A7023F01DF4A83C00F04BD0 /* Option.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Option.swift; path = CommandLine/CommandLineKit/Option.swift; sourceTree = SOURCE_ROOT; };
63 | 4A7023F11DF4A83C00F04BD0 /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringExtensions.swift; path = CommandLine/CommandLineKit/StringExtensions.swift; sourceTree = SOURCE_ROOT; };
64 | 4AE3F5291DE60EB4003B192E /* ImageGeneration */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ImageGeneration; sourceTree = BUILT_PRODUCTS_DIR; };
65 | 4AE3F5991DE67087003B192E /* ImageGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageGenerator.swift; path = ImageGeneration/ImageGenerator.swift; sourceTree = SOURCE_ROOT; };
66 | 4AE3F59A1DE67087003B192E /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ImageGeneration/main.swift; sourceTree = SOURCE_ROOT; };
67 | 4AE3F59B1DE67087003B192E /* Maths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Maths.swift; path = ImageGeneration/Maths.swift; sourceTree = SOURCE_ROOT; };
68 | 4AE3F59C1DE67087003B192E /* Circle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Circle.swift; path = ImageGeneration/Circle.swift; sourceTree = SOURCE_ROOT; };
69 | 4AE3F5BD1DE73FE4003B192E /* SleepDuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SleepDuration.swift; path = ImageGeneration/SleepDuration.swift; sourceTree = SOURCE_ROOT; };
70 | 4AE3F5BF1DE74A8F003B192E /* WakeTime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WakeTime.swift; path = ImageGeneration/WakeTime.swift; sourceTree = SOURCE_ROOT; };
71 | /* End PBXFileReference section */
72 |
73 | /* Begin PBXFrameworksBuildPhase section */
74 | 4AE3F5261DE60EB4003B192E /* Frameworks */ = {
75 | isa = PBXFrameworksBuildPhase;
76 | buildActionMask = 2147483647;
77 | files = (
78 | );
79 | runOnlyForDeploymentPostprocessing = 0;
80 | };
81 | /* End PBXFrameworksBuildPhase section */
82 |
83 | /* Begin PBXGroup section */
84 | 4AE3F5201DE60EB4003B192E = {
85 | isa = PBXGroup;
86 | children = (
87 | 4AE3F52B1DE60EB4003B192E /* ImageGeneration */,
88 | 4AE3F54A1DE66424003B192E /* CommandLIne */,
89 | 4AE3F52A1DE60EB4003B192E /* Products */,
90 | );
91 | sourceTree = "";
92 | };
93 | 4AE3F52A1DE60EB4003B192E /* Products */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 4AE3F5291DE60EB4003B192E /* ImageGeneration */,
97 | );
98 | name = Products;
99 | sourceTree = "";
100 | };
101 | 4AE3F52B1DE60EB4003B192E /* ImageGeneration */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 4AE3F59A1DE67087003B192E /* main.swift */,
105 | 4AE3F5991DE67087003B192E /* ImageGenerator.swift */,
106 | 4AE3F59B1DE67087003B192E /* Maths.swift */,
107 | 4AE3F5BC1DE73FB8003B192E /* App Images */,
108 | 4AE3F5B91DE674F1003B192E /* Complications */,
109 | );
110 | name = ImageGeneration;
111 | path = "Image Generation";
112 | sourceTree = "";
113 | };
114 | 4AE3F54A1DE66424003B192E /* CommandLIne */ = {
115 | isa = PBXGroup;
116 | children = (
117 | 4A7023EF1DF4A83C00F04BD0 /* CommandLine.swift */,
118 | 4A7023F01DF4A83C00F04BD0 /* Option.swift */,
119 | 4A7023F11DF4A83C00F04BD0 /* StringExtensions.swift */,
120 | );
121 | name = CommandLIne;
122 | path = XCAssetPacker;
123 | sourceTree = "";
124 | };
125 | 4AE3F5B91DE674F1003B192E /* Complications */ = {
126 | isa = PBXGroup;
127 | children = (
128 | 4AE3F59C1DE67087003B192E /* Circle.swift */,
129 | 4A0656D81DF8FC9E000073E0 /* Blank.swift */,
130 | );
131 | name = Complications;
132 | sourceTree = "";
133 | };
134 | 4AE3F5BC1DE73FB8003B192E /* App Images */ = {
135 | isa = PBXGroup;
136 | children = (
137 | 4AE3F5BD1DE73FE4003B192E /* SleepDuration.swift */,
138 | 4AE3F5BF1DE74A8F003B192E /* WakeTime.swift */,
139 | );
140 | name = "App Images";
141 | sourceTree = "";
142 | };
143 | /* End PBXGroup section */
144 |
145 | /* Begin PBXNativeTarget section */
146 | 4AE3F5281DE60EB4003B192E /* ImageGeneration */ = {
147 | isa = PBXNativeTarget;
148 | buildConfigurationList = 4AE3F5301DE60EB4003B192E /* Build configuration list for PBXNativeTarget "ImageGeneration" */;
149 | buildPhases = (
150 | 4AE3F5251DE60EB4003B192E /* Sources */,
151 | 4AE3F5261DE60EB4003B192E /* Frameworks */,
152 | 4AE3F5271DE60EB4003B192E /* CopyFiles */,
153 | );
154 | buildRules = (
155 | );
156 | dependencies = (
157 | );
158 | name = ImageGeneration;
159 | productName = "Image Generation";
160 | productReference = 4AE3F5291DE60EB4003B192E /* ImageGeneration */;
161 | productType = "com.apple.product-type.tool";
162 | };
163 | /* End PBXNativeTarget section */
164 |
165 | /* Begin PBXProject section */
166 | 4AE3F5211DE60EB4003B192E /* Project object */ = {
167 | isa = PBXProject;
168 | attributes = {
169 | LastSwiftUpdateCheck = 0810;
170 | LastUpgradeCheck = 0810;
171 | ORGANIZATIONNAME = "Inquisitive Software";
172 | TargetAttributes = {
173 | 4A66849B1DEB3E1600BEE075 = {
174 | CreatedOnToolsVersion = 8.1;
175 | DevelopmentTeam = D92MT22EX5;
176 | ProvisioningStyle = Automatic;
177 | };
178 | 4AE3F5281DE60EB4003B192E = {
179 | CreatedOnToolsVersion = 8.1;
180 | DevelopmentTeam = D92MT22EX5;
181 | LastSwiftMigration = 0810;
182 | ProvisioningStyle = Automatic;
183 | };
184 | };
185 | };
186 | buildConfigurationList = 4AE3F5241DE60EB4003B192E /* Build configuration list for PBXProject "Image Generation" */;
187 | compatibilityVersion = "Xcode 3.2";
188 | developmentRegion = English;
189 | hasScannedForEncodings = 0;
190 | knownRegions = (
191 | en,
192 | );
193 | mainGroup = 4AE3F5201DE60EB4003B192E;
194 | productRefGroup = 4AE3F52A1DE60EB4003B192E /* Products */;
195 | projectDirPath = "";
196 | projectRoot = "";
197 | targets = (
198 | 4AE3F5281DE60EB4003B192E /* ImageGeneration */,
199 | 4A66849B1DEB3E1600BEE075 /* Generate Images */,
200 | );
201 | };
202 | /* End PBXProject section */
203 |
204 | /* Begin PBXShellScriptBuildPhase section */
205 | 4A6684A31DEB3E2000BEE075 /* ShellScript */ = {
206 | isa = PBXShellScriptBuildPhase;
207 | buildActionMask = 2147483647;
208 | files = (
209 | );
210 | inputPaths = (
211 | );
212 | outputPaths = (
213 | );
214 | runOnlyForDeploymentPostprocessing = 0;
215 | shellPath = /bin/sh;
216 | shellScript = "\"${PROJECT_DIR}/generate.sh\"";
217 | };
218 | /* End PBXShellScriptBuildPhase section */
219 |
220 | /* Begin PBXSourcesBuildPhase section */
221 | 4AE3F5251DE60EB4003B192E /* Sources */ = {
222 | isa = PBXSourcesBuildPhase;
223 | buildActionMask = 2147483647;
224 | files = (
225 | 4A7023F31DF4A83C00F04BD0 /* Option.swift in Sources */,
226 | 4AE3F5A61DE6744A003B192E /* Maths.swift in Sources */,
227 | 4AE3F5A51DE6744A003B192E /* ImageGenerator.swift in Sources */,
228 | 4A7023F41DF4A83C00F04BD0 /* StringExtensions.swift in Sources */,
229 | 4AE3F5C01DE74A8F003B192E /* WakeTime.swift in Sources */,
230 | 4AE3F5A71DE6744A003B192E /* Circle.swift in Sources */,
231 | 4AE3F5BE1DE73FE4003B192E /* SleepDuration.swift in Sources */,
232 | 4A7023F21DF4A83C00F04BD0 /* CommandLine.swift in Sources */,
233 | 4A0656D91DF8FC9E000073E0 /* Blank.swift in Sources */,
234 | 4AE3F5A41DE6744A003B192E /* main.swift in Sources */,
235 | );
236 | runOnlyForDeploymentPostprocessing = 0;
237 | };
238 | /* End PBXSourcesBuildPhase section */
239 |
240 | /* Begin PBXTargetDependency section */
241 | 4A6684A01DEB3E1C00BEE075 /* PBXTargetDependency */ = {
242 | isa = PBXTargetDependency;
243 | target = 4AE3F5281DE60EB4003B192E /* ImageGeneration */;
244 | targetProxy = 4A66849F1DEB3E1C00BEE075 /* PBXContainerItemProxy */;
245 | };
246 | /* End PBXTargetDependency section */
247 |
248 | /* Begin XCBuildConfiguration section */
249 | 4A66849D1DEB3E1600BEE075 /* Debug */ = {
250 | isa = XCBuildConfiguration;
251 | buildSettings = {
252 | DEVELOPMENT_TEAM = D92MT22EX5;
253 | PRODUCT_NAME = "$(TARGET_NAME)";
254 | };
255 | name = Debug;
256 | };
257 | 4A66849E1DEB3E1600BEE075 /* Release */ = {
258 | isa = XCBuildConfiguration;
259 | buildSettings = {
260 | DEVELOPMENT_TEAM = D92MT22EX5;
261 | PRODUCT_NAME = "$(TARGET_NAME)";
262 | };
263 | name = Release;
264 | };
265 | 4AE3F52E1DE60EB4003B192E /* Debug */ = {
266 | isa = XCBuildConfiguration;
267 | buildSettings = {
268 | ALWAYS_SEARCH_USER_PATHS = NO;
269 | CLANG_ANALYZER_NONNULL = YES;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
271 | CLANG_CXX_LIBRARY = "libc++";
272 | CLANG_ENABLE_MODULES = YES;
273 | CLANG_ENABLE_OBJC_ARC = YES;
274 | CLANG_WARN_BOOL_CONVERSION = YES;
275 | CLANG_WARN_CONSTANT_CONVERSION = YES;
276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
277 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
278 | CLANG_WARN_EMPTY_BODY = YES;
279 | CLANG_WARN_ENUM_CONVERSION = YES;
280 | CLANG_WARN_INFINITE_RECURSION = YES;
281 | CLANG_WARN_INT_CONVERSION = YES;
282 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
283 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
284 | CLANG_WARN_UNREACHABLE_CODE = YES;
285 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
286 | CODE_SIGN_IDENTITY = "-";
287 | CONFIGURATION_BUILD_DIR = $PROJECT_DIR/build;
288 | COPY_PHASE_STRIP = NO;
289 | DEBUG_INFORMATION_FORMAT = dwarf;
290 | ENABLE_STRICT_OBJC_MSGSEND = YES;
291 | ENABLE_TESTABILITY = YES;
292 | GCC_C_LANGUAGE_STANDARD = gnu99;
293 | GCC_DYNAMIC_NO_PIC = NO;
294 | GCC_NO_COMMON_BLOCKS = YES;
295 | GCC_OPTIMIZATION_LEVEL = 0;
296 | GCC_PREPROCESSOR_DEFINITIONS = (
297 | "DEBUG=1",
298 | "$(inherited)",
299 | );
300 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
301 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
302 | GCC_WARN_UNDECLARED_SELECTOR = YES;
303 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
304 | GCC_WARN_UNUSED_FUNCTION = YES;
305 | GCC_WARN_UNUSED_VARIABLE = YES;
306 | MACOSX_DEPLOYMENT_TARGET = 10.11;
307 | MTL_ENABLE_DEBUG_INFO = YES;
308 | ONLY_ACTIVE_ARCH = YES;
309 | SDKROOT = macosx;
310 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
311 | SWIFT_VERSION = 3.0.1;
312 | };
313 | name = Debug;
314 | };
315 | 4AE3F52F1DE60EB4003B192E /* Release */ = {
316 | isa = XCBuildConfiguration;
317 | buildSettings = {
318 | ALWAYS_SEARCH_USER_PATHS = NO;
319 | CLANG_ANALYZER_NONNULL = YES;
320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
321 | CLANG_CXX_LIBRARY = "libc++";
322 | CLANG_ENABLE_MODULES = YES;
323 | CLANG_ENABLE_OBJC_ARC = YES;
324 | CLANG_WARN_BOOL_CONVERSION = YES;
325 | CLANG_WARN_CONSTANT_CONVERSION = YES;
326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
327 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
328 | CLANG_WARN_EMPTY_BODY = YES;
329 | CLANG_WARN_ENUM_CONVERSION = YES;
330 | CLANG_WARN_INFINITE_RECURSION = YES;
331 | CLANG_WARN_INT_CONVERSION = YES;
332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
333 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
334 | CLANG_WARN_UNREACHABLE_CODE = YES;
335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
336 | CODE_SIGN_IDENTITY = "-";
337 | CONFIGURATION_BUILD_DIR = $PROJECT_DIR/build;
338 | COPY_PHASE_STRIP = NO;
339 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
340 | ENABLE_NS_ASSERTIONS = NO;
341 | ENABLE_STRICT_OBJC_MSGSEND = YES;
342 | GCC_C_LANGUAGE_STANDARD = gnu99;
343 | GCC_NO_COMMON_BLOCKS = YES;
344 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
345 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
346 | GCC_WARN_UNDECLARED_SELECTOR = YES;
347 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
348 | GCC_WARN_UNUSED_FUNCTION = YES;
349 | GCC_WARN_UNUSED_VARIABLE = YES;
350 | MACOSX_DEPLOYMENT_TARGET = 10.11;
351 | MTL_ENABLE_DEBUG_INFO = NO;
352 | SDKROOT = macosx;
353 | SWIFT_VERSION = 3.0.1;
354 | };
355 | name = Release;
356 | };
357 | 4AE3F5311DE60EB4003B192E /* Debug */ = {
358 | isa = XCBuildConfiguration;
359 | buildSettings = {
360 | CLANG_ENABLE_MODULES = YES;
361 | DEVELOPMENT_TEAM = D92MT22EX5;
362 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
363 | PRODUCT_NAME = "$(TARGET_NAME)";
364 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
365 | SWIFT_VERSION = 3.0.1;
366 | };
367 | name = Debug;
368 | };
369 | 4AE3F5321DE60EB4003B192E /* Release */ = {
370 | isa = XCBuildConfiguration;
371 | buildSettings = {
372 | CLANG_ENABLE_MODULES = YES;
373 | DEVELOPMENT_TEAM = D92MT22EX5;
374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
375 | PRODUCT_NAME = "$(TARGET_NAME)";
376 | SWIFT_VERSION = 3.0.1;
377 | };
378 | name = Release;
379 | };
380 | /* End XCBuildConfiguration section */
381 |
382 | /* Begin XCConfigurationList section */
383 | 4A66849C1DEB3E1600BEE075 /* Build configuration list for PBXAggregateTarget "Generate Images" */ = {
384 | isa = XCConfigurationList;
385 | buildConfigurations = (
386 | 4A66849D1DEB3E1600BEE075 /* Debug */,
387 | 4A66849E1DEB3E1600BEE075 /* Release */,
388 | );
389 | defaultConfigurationIsVisible = 0;
390 | defaultConfigurationName = Release;
391 | };
392 | 4AE3F5241DE60EB4003B192E /* Build configuration list for PBXProject "Image Generation" */ = {
393 | isa = XCConfigurationList;
394 | buildConfigurations = (
395 | 4AE3F52E1DE60EB4003B192E /* Debug */,
396 | 4AE3F52F1DE60EB4003B192E /* Release */,
397 | );
398 | defaultConfigurationIsVisible = 0;
399 | defaultConfigurationName = Release;
400 | };
401 | 4AE3F5301DE60EB4003B192E /* Build configuration list for PBXNativeTarget "ImageGeneration" */ = {
402 | isa = XCConfigurationList;
403 | buildConfigurations = (
404 | 4AE3F5311DE60EB4003B192E /* Debug */,
405 | 4AE3F5321DE60EB4003B192E /* Release */,
406 | );
407 | defaultConfigurationIsVisible = 0;
408 | defaultConfigurationName = Release;
409 | };
410 | /* End XCConfigurationList section */
411 | };
412 | rootObject = 4AE3F5211DE60EB4003B192E /* Project object */;
413 | }
414 |
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/App Icon.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/App Icon.sketch
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Bed-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Bed-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Bed-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Bed-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/ColorComplicationIndicator-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/ColorComplicationIndicator-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/ColorComplicationIndicator-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/ColorComplicationIndicator-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Complication Rules.json:
--------------------------------------------------------------------------------
1 | {
2 | "base" : {
3 | "template-rendering-intent" : "template"
4 | },
5 | "devices" : [
6 | {
7 | "device-type" : "watch",
8 | "properties" : {
9 | "template-rendering-intent" : "template"
10 | }
11 | }
12 | ],
13 | "custom" : [
14 | {
15 | "patterns" : [".*Preview.*", "SleepDuration.*", "WakeTime.*"],
16 | "properties" : {
17 | "template-rendering-intent" : "original"
18 | }
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/GrayscaleComplicationIndicator-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/GrayscaleComplicationIndicator-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/GrayscaleComplicationIndicator-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/GrayscaleComplicationIndicator-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Icons.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Icons.sketch
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Moon-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Moon-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Moon-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Moon-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/ReminderSelected-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/ReminderSelected-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/ReminderSelected-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/ReminderSelected-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/ReminderUnselected-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/ReminderUnselected-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/ReminderUnselected-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/ReminderUnselected-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Sun-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Sun-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Sun-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Sun-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Watch App Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Watch App Icon.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Watch App Notification Icon-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Watch App Notification Icon-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Watch App Notification Icon-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Watch App Notification Icon-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Watch App Rules.json:
--------------------------------------------------------------------------------
1 | {
2 | "skip-images" : {
3 | "patterns" : ["Watch App .*", "Bed.*"]
4 | },
5 | "base" : {
6 | "template-rendering-intent" : "original"
7 | }
8 | }
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Watch App Short Look Icon-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Watch App Short Look Icon-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Source/Watch App Short Look Icon-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Source/Watch App Short Look Icon-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle0-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle0-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle0-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle0-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle1-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle1-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle1-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle1-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle2-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle2-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle2-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/CircularSmallCircle/CircularSmallCircle2-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview0-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview0-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview0-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview0-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview1-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview1-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview1-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ComplicationPreview/ComplicationPreview1-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle0-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle0-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle0-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle0-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle1-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle1-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle1-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle1-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle2-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle2-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle2-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle2-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle3-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle3-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle3-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle3-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle4-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle4-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle4-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/ModularSmallCircle/ModularSmallCircle4-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration0-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration0-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration0-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration0-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration1-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration1-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration1-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration1-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration2-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration2-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration2-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration2-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration3-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration3-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration3-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration3-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration4-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration4-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration4-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/SleepDuration/SleepDuration4-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/UtilitarianExtraLargeCircle/UtilitarianExtraLargeCircle0-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/UtilitarianExtraLargeCircle/UtilitarianExtraLargeCircle0-38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/UtilitarianExtraLargeCircle/UtilitarianExtraLargeCircle0-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/UtilitarianExtraLargeCircle/UtilitarianExtraLargeCircle0-42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime0.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime1.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime10.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime11.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime12.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime13.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime14.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime15.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime16.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime17.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime18.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime19.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime2.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime20.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime21.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime22.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime23.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime24.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime25.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime26.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime27.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime27.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime28.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime29.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime3.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime30.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime31.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime32.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime33.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime34.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime34.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime35.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime35.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime36.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime37.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime38.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime39.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime39.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime4.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime40.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime41.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime41.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime42.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime43.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime43.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime44.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime45.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime45.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime46.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime47.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime47.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime48.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime49.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime49.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime5.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime50.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime51.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime51.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime52.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime52.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime6.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime7.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime8.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inquisitiveSoft/XCAssetPacker/05d4864effaeaa576318f44cf57683dfcb607ecb/XCAssetPacker Tests/Watch/Watch/Images/WakeTime/WakeTime9.png
--------------------------------------------------------------------------------
/XCAssetPacker Tests/Watch/generate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Create the .xcassets package for generated complications
4 | XCAssetPacker --input "Generated/Images" --config "../Source/Complication Rules.json" --output "Generated/Complications.xcassets" -f
5 |
6 | # Create the .xcassets package for static images
7 | XCAssetPacker --input "Source" --config "../Source/Watch App Rules.json" --output "Generated/Watch App.xcassets" -f
8 |
--------------------------------------------------------------------------------
/XCAssetPacker Tests/XCAssetPacker_Tests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XCAssetPacker_Tests.swift
3 | // XCAssetPacker Tests
4 | //
5 | // Created by Harry Jordan on 17/04/2017.
6 | // Copyright © 2017 Inquisitive Software. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 |
12 | class XCAssetPacker_Tests: XCTestCase {
13 |
14 |
15 | func testWatchNoConstraints() {
16 | validateAssetCatalog(directory: "Watch") { (assetCatalog, log) in
17 | XCTAssertEqual(log.numberOfImages, 85, "Expect to find 85 test images")
18 | }
19 | }
20 |
21 |
22 | func testWatchSkipImagesContainingTheWordCircle() {
23 | validateAssetCatalog(directory: "Watch", configurationFileName: "Skip Circles Rules") { (assetCatalog, log) in
24 | XCTAssertEqual(log.numberOfImages, 67, "Expect to find 67 test images")
25 | }
26 | }
27 |
28 |
29 | func testSwiftGeneration() {
30 | validateAssetCatalog(directory: "Watch", swift: .watch) { (assetCatalog, log) in
31 | XCTAssertEqual(log.numberOfImages, 85, "Expect to find 85 test images")
32 | }
33 | }
34 |
35 |
36 | func validateAssetCatalog(directory: String, configurationFileName: String? = nil, swift swiftTarget: SwiftTarget? = nil, expectations: (AssetCatalogGenerator, AssetCatalogLog) -> Void) {
37 | do {
38 | let bundle = Bundle(for: XCAssetPacker_Tests.self)
39 | let watchURL = bundle.url(forResource: directory, withExtension: nil, subdirectory: nil)!
40 | let destinationURL = watchURL.deletingLastPathComponent()
41 | let swiftDestinationURL: URL?
42 | let target: SwiftTarget
43 |
44 | if let swiftTarget = swiftTarget {
45 | swiftDestinationURL = destinationURL.appendingPathComponent("\(swiftTarget.libraryName).swift")
46 | target = swiftTarget
47 | } else {
48 | swiftDestinationURL = nil
49 | target = .iOS
50 | }
51 |
52 | let configuration: [String: Any]
53 | if let configurationFileName = configurationFileName {
54 | configuration = try self.configuration(forFileName: configurationFileName, inBundle: bundle)
55 | XCTAssert(!configuration.isEmpty, "Couldn't load configuration for name: \(configurationFileName)")
56 | } else {
57 | configuration = [:]
58 | }
59 |
60 | let assetCatalog = try AssetCatalogGenerator(from: watchURL, to: destinationURL, swift: swiftDestinationURL, target: target, overwrite: true, configuration: configuration)
61 | let log = try assetCatalog.applyChanges(logLevel: .detailed, dryRun: true)
62 |
63 | expectations(assetCatalog, log)
64 | } catch let error as AssetCatalogError {
65 | switch error {
66 | case .ioError(let decription):
67 | XCTFail(decription)
68 | }
69 | } catch let error {
70 | XCTFail(String(describing: error))
71 | }
72 | }
73 |
74 |
75 | func configuration(forFileName jsonFileName: String, inBundle bundle: Bundle) throws -> [String: Any] {
76 | guard let configurationFileURL = bundle.url(forResource: jsonFileName, withExtension: "json", subdirectory: nil) else {
77 | throw AssetCatalogError.ioError("Ivli")
78 | }
79 |
80 |
81 | let data = try Data(contentsOf: configurationFileURL)
82 | let json = try JSONSerialization.jsonObject(with: data, options: [])
83 |
84 | if let configurationJSON = json as? [String: Any] {
85 | return configurationJSON
86 | } else {
87 | throw AssetCatalogError.ioError("Invalid json")
88 | }
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/XCAssetPacker.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4A07727C1DF9634A0068A929 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A07727B1DF9634A0068A929 /* Extensions.swift */; };
11 | 4A07727E1DF963C70068A929 /* ImageProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A07727D1DF963C70068A929 /* ImageProperties.swift */; };
12 | 4A0772821DF9731B0068A929 /* CommandLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A07727F1DF9731B0068A929 /* CommandLine.swift */; };
13 | 4A0772831DF9731B0068A929 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0772801DF9731B0068A929 /* Option.swift */; };
14 | 4A0772841DF9731B0068A929 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0772811DF9731B0068A929 /* StringExtensions.swift */; };
15 | 4A56D14B1DE5B573000B40D8 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A56D14A1DE5B573000B40D8 /* main.swift */; };
16 | 4A56D1591DE5BA85000B40D8 /* AssetCatalogGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A56D1581DE5BA85000B40D8 /* AssetCatalogGenerator.swift */; };
17 | 4A5F178F1EA3EDE8007C37DE /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A5F178E1EA3EDE8007C37DE /* Constants.swift */; };
18 | 4AD71E741EA4899500016A1A /* SwiftGeneration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AD71E731EA4899500016A1A /* SwiftGeneration.swift */; };
19 | 4AD71E7F1EA4CCBA00016A1A /* XCAssetPacker_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AD71E7E1EA4CCBA00016A1A /* XCAssetPacker_Tests.swift */; };
20 | 4AD71E841EA4CD0800016A1A /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A5F178E1EA3EDE8007C37DE /* Constants.swift */; };
21 | 4AD71E851EA4CD0800016A1A /* AssetCatalogGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A56D1581DE5BA85000B40D8 /* AssetCatalogGenerator.swift */; };
22 | 4AD71E861EA4CD0800016A1A /* ImageProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A07727D1DF963C70068A929 /* ImageProperties.swift */; };
23 | 4AD71E871EA4CD0800016A1A /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A07727B1DF9634A0068A929 /* Extensions.swift */; };
24 | 4AD71E881EA4CD0800016A1A /* SwiftGeneration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AD71E731EA4899500016A1A /* SwiftGeneration.swift */; };
25 | 4AD71E8A1EA4CD0800016A1A /* CommandLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A07727F1DF9731B0068A929 /* CommandLine.swift */; };
26 | 4AD71E8B1EA4CD0800016A1A /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0772801DF9731B0068A929 /* Option.swift */; };
27 | 4AD71E8C1EA4CD0800016A1A /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0772811DF9731B0068A929 /* StringExtensions.swift */; };
28 | 4AD71E8E1EA4CDAE00016A1A /* Watch in Resources */ = {isa = PBXBuildFile; fileRef = 4AD71E8D1EA4CDAE00016A1A /* Watch */; };
29 | 4AD71E901EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AD71E8F1EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift */; };
30 | 4AD71E911EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AD71E8F1EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift */; };
31 | 4AD71E951EA4DD2700016A1A /* Complication Rules.json in Resources */ = {isa = PBXBuildFile; fileRef = 4AD71E941EA4DD2700016A1A /* Complication Rules.json */; };
32 | 4AD71E971EA4EEEC00016A1A /* Skip Circles Rules.json in Resources */ = {isa = PBXBuildFile; fileRef = 4AD71E961EA4EEEC00016A1A /* Skip Circles Rules.json */; };
33 | 4AFFC5911F5D8E35000FDCFD /* DeviceIdiom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AFFC5901F5D8E35000FDCFD /* DeviceIdiom.swift */; };
34 | 4AFFC5931F5D8E83000FDCFD /* DeviceIdiom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AFFC5921F5D8E83000FDCFD /* DeviceIdiom.swift */; };
35 | /* End PBXBuildFile section */
36 |
37 | /* Begin PBXCopyFilesBuildPhase section */
38 | 4A56D1451DE5B573000B40D8 /* CopyFiles */ = {
39 | isa = PBXCopyFilesBuildPhase;
40 | buildActionMask = 2147483647;
41 | dstPath = /usr/share/man/man1/;
42 | dstSubfolderSpec = 0;
43 | files = (
44 | );
45 | runOnlyForDeploymentPostprocessing = 1;
46 | };
47 | /* End PBXCopyFilesBuildPhase section */
48 |
49 | /* Begin PBXFileReference section */
50 | 4A07727B1DF9634A0068A929 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; };
51 | 4A07727D1DF963C70068A929 /* ImageProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageProperties.swift; sourceTree = ""; };
52 | 4A07727F1DF9731B0068A929 /* CommandLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CommandLine.swift; path = CommandLine/CommandLineKit/CommandLine.swift; sourceTree = ""; };
53 | 4A0772801DF9731B0068A929 /* Option.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Option.swift; path = CommandLine/CommandLineKit/Option.swift; sourceTree = ""; };
54 | 4A0772811DF9731B0068A929 /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringExtensions.swift; path = CommandLine/CommandLineKit/StringExtensions.swift; sourceTree = ""; };
55 | 4A56D1471DE5B573000B40D8 /* xcassetpacker */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xcassetpacker; sourceTree = BUILT_PRODUCTS_DIR; };
56 | 4A56D14A1DE5B573000B40D8 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
57 | 4A56D1581DE5BA85000B40D8 /* AssetCatalogGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetCatalogGenerator.swift; sourceTree = ""; };
58 | 4A5F178E1EA3EDE8007C37DE /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; };
59 | 4AD71E731EA4899500016A1A /* SwiftGeneration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftGeneration.swift; sourceTree = ""; };
60 | 4AD71E7C1EA4CCBA00016A1A /* XCAssetPacker Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "XCAssetPacker Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
61 | 4AD71E7E1EA4CCBA00016A1A /* XCAssetPacker_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCAssetPacker_Tests.swift; sourceTree = ""; };
62 | 4AD71E801EA4CCBA00016A1A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | 4AD71E8D1EA4CDAE00016A1A /* Watch */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Watch; path = Watch/Watch; sourceTree = ""; };
64 | 4AD71E8F1EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AssetCatalogGenerator+Creation.swift"; sourceTree = ""; };
65 | 4AD71E941EA4DD2700016A1A /* Complication Rules.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Complication Rules.json"; sourceTree = ""; };
66 | 4AD71E961EA4EEEC00016A1A /* Skip Circles Rules.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Skip Circles Rules.json"; sourceTree = ""; };
67 | 4AFFC5901F5D8E35000FDCFD /* DeviceIdiom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceIdiom.swift; sourceTree = ""; };
68 | 4AFFC5921F5D8E83000FDCFD /* DeviceIdiom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeviceIdiom.swift; path = XCAssetPacker/DeviceIdiom.swift; sourceTree = ""; };
69 | /* End PBXFileReference section */
70 |
71 | /* Begin PBXFrameworksBuildPhase section */
72 | 4A56D1441DE5B573000B40D8 /* Frameworks */ = {
73 | isa = PBXFrameworksBuildPhase;
74 | buildActionMask = 2147483647;
75 | files = (
76 | );
77 | runOnlyForDeploymentPostprocessing = 0;
78 | };
79 | 4AD71E791EA4CCBA00016A1A /* Frameworks */ = {
80 | isa = PBXFrameworksBuildPhase;
81 | buildActionMask = 2147483647;
82 | files = (
83 | );
84 | runOnlyForDeploymentPostprocessing = 0;
85 | };
86 | /* End PBXFrameworksBuildPhase section */
87 |
88 | /* Begin PBXGroup section */
89 | 4A56D13E1DE5B573000B40D8 = {
90 | isa = PBXGroup;
91 | children = (
92 | 4AFFC5921F5D8E83000FDCFD /* DeviceIdiom.swift */,
93 | 4A56D1491DE5B573000B40D8 /* XCAssetPacker */,
94 | 4A56D1571DE5B5AB000B40D8 /* CommandLine */,
95 | 4AD71E7D1EA4CCBA00016A1A /* XCAssetPacker Tests */,
96 | 4A56D1481DE5B573000B40D8 /* Products */,
97 | );
98 | sourceTree = "";
99 | };
100 | 4A56D1481DE5B573000B40D8 /* Products */ = {
101 | isa = PBXGroup;
102 | children = (
103 | 4A56D1471DE5B573000B40D8 /* xcassetpacker */,
104 | 4AD71E7C1EA4CCBA00016A1A /* XCAssetPacker Tests.xctest */,
105 | );
106 | name = Products;
107 | sourceTree = "";
108 | };
109 | 4A56D1491DE5B573000B40D8 /* XCAssetPacker */ = {
110 | isa = PBXGroup;
111 | children = (
112 | 4A56D14A1DE5B573000B40D8 /* main.swift */,
113 | 4A5F178E1EA3EDE8007C37DE /* Constants.swift */,
114 | 4AD71E8F1EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift */,
115 | 4A56D1581DE5BA85000B40D8 /* AssetCatalogGenerator.swift */,
116 | 4A07727D1DF963C70068A929 /* ImageProperties.swift */,
117 | 4AFFC5901F5D8E35000FDCFD /* DeviceIdiom.swift */,
118 | 4A07727B1DF9634A0068A929 /* Extensions.swift */,
119 | 4AD71E731EA4899500016A1A /* SwiftGeneration.swift */,
120 | );
121 | path = XCAssetPacker;
122 | sourceTree = "";
123 | };
124 | 4A56D1571DE5B5AB000B40D8 /* CommandLine */ = {
125 | isa = PBXGroup;
126 | children = (
127 | 4A07727F1DF9731B0068A929 /* CommandLine.swift */,
128 | 4A0772801DF9731B0068A929 /* Option.swift */,
129 | 4A0772811DF9731B0068A929 /* StringExtensions.swift */,
130 | );
131 | name = CommandLine;
132 | path = XCAssetPacker;
133 | sourceTree = "";
134 | };
135 | 4AD71E7D1EA4CCBA00016A1A /* XCAssetPacker Tests */ = {
136 | isa = PBXGroup;
137 | children = (
138 | 4AD71E7E1EA4CCBA00016A1A /* XCAssetPacker_Tests.swift */,
139 | 4AD71E941EA4DD2700016A1A /* Complication Rules.json */,
140 | 4AD71E961EA4EEEC00016A1A /* Skip Circles Rules.json */,
141 | 4AD71E8D1EA4CDAE00016A1A /* Watch */,
142 | 4AD71E801EA4CCBA00016A1A /* Info.plist */,
143 | );
144 | path = "XCAssetPacker Tests";
145 | sourceTree = "";
146 | };
147 | /* End PBXGroup section */
148 |
149 | /* Begin PBXNativeTarget section */
150 | 4A56D1461DE5B573000B40D8 /* xcassetpacker */ = {
151 | isa = PBXNativeTarget;
152 | buildConfigurationList = 4A56D14E1DE5B573000B40D8 /* Build configuration list for PBXNativeTarget "xcassetpacker" */;
153 | buildPhases = (
154 | 4A56D1431DE5B573000B40D8 /* Sources */,
155 | 4A56D1441DE5B573000B40D8 /* Frameworks */,
156 | 4A56D1451DE5B573000B40D8 /* CopyFiles */,
157 | );
158 | buildRules = (
159 | );
160 | dependencies = (
161 | );
162 | name = xcassetpacker;
163 | productName = XCAssetPacker;
164 | productReference = 4A56D1471DE5B573000B40D8 /* xcassetpacker */;
165 | productType = "com.apple.product-type.tool";
166 | };
167 | 4AD71E7B1EA4CCBA00016A1A /* XCAssetPacker Tests */ = {
168 | isa = PBXNativeTarget;
169 | buildConfigurationList = 4AD71E811EA4CCBA00016A1A /* Build configuration list for PBXNativeTarget "XCAssetPacker Tests" */;
170 | buildPhases = (
171 | 4AD71E781EA4CCBA00016A1A /* Sources */,
172 | 4AD71E791EA4CCBA00016A1A /* Frameworks */,
173 | 4AD71E7A1EA4CCBA00016A1A /* Resources */,
174 | );
175 | buildRules = (
176 | );
177 | dependencies = (
178 | );
179 | name = "XCAssetPacker Tests";
180 | productName = "XCAssetPacker Tests";
181 | productReference = 4AD71E7C1EA4CCBA00016A1A /* XCAssetPacker Tests.xctest */;
182 | productType = "com.apple.product-type.bundle.unit-test";
183 | };
184 | /* End PBXNativeTarget section */
185 |
186 | /* Begin PBXProject section */
187 | 4A56D13F1DE5B573000B40D8 /* Project object */ = {
188 | isa = PBXProject;
189 | attributes = {
190 | LastSwiftUpdateCheck = 0830;
191 | LastUpgradeCheck = 0830;
192 | ORGANIZATIONNAME = "Inquisitive Software";
193 | TargetAttributes = {
194 | 4A56D1461DE5B573000B40D8 = {
195 | CreatedOnToolsVersion = 8.1;
196 | DevelopmentTeam = D92MT22EX5;
197 | LastSwiftMigration = 0900;
198 | ProvisioningStyle = Automatic;
199 | };
200 | 4AD71E7B1EA4CCBA00016A1A = {
201 | CreatedOnToolsVersion = 8.3.1;
202 | DevelopmentTeam = D92MT22EX5;
203 | LastSwiftMigration = 0900;
204 | ProvisioningStyle = Automatic;
205 | };
206 | };
207 | };
208 | buildConfigurationList = 4A56D1421DE5B573000B40D8 /* Build configuration list for PBXProject "XCAssetPacker" */;
209 | compatibilityVersion = "Xcode 3.2";
210 | developmentRegion = English;
211 | hasScannedForEncodings = 0;
212 | knownRegions = (
213 | en,
214 | );
215 | mainGroup = 4A56D13E1DE5B573000B40D8;
216 | productRefGroup = 4A56D1481DE5B573000B40D8 /* Products */;
217 | projectDirPath = "";
218 | projectRoot = "";
219 | targets = (
220 | 4A56D1461DE5B573000B40D8 /* xcassetpacker */,
221 | 4AD71E7B1EA4CCBA00016A1A /* XCAssetPacker Tests */,
222 | );
223 | };
224 | /* End PBXProject section */
225 |
226 | /* Begin PBXResourcesBuildPhase section */
227 | 4AD71E7A1EA4CCBA00016A1A /* Resources */ = {
228 | isa = PBXResourcesBuildPhase;
229 | buildActionMask = 2147483647;
230 | files = (
231 | 4AD71E971EA4EEEC00016A1A /* Skip Circles Rules.json in Resources */,
232 | 4AD71E951EA4DD2700016A1A /* Complication Rules.json in Resources */,
233 | 4AD71E8E1EA4CDAE00016A1A /* Watch in Resources */,
234 | );
235 | runOnlyForDeploymentPostprocessing = 0;
236 | };
237 | /* End PBXResourcesBuildPhase section */
238 |
239 | /* Begin PBXSourcesBuildPhase section */
240 | 4A56D1431DE5B573000B40D8 /* Sources */ = {
241 | isa = PBXSourcesBuildPhase;
242 | buildActionMask = 2147483647;
243 | files = (
244 | 4A0772821DF9731B0068A929 /* CommandLine.swift in Sources */,
245 | 4AFFC5911F5D8E35000FDCFD /* DeviceIdiom.swift in Sources */,
246 | 4A5F178F1EA3EDE8007C37DE /* Constants.swift in Sources */,
247 | 4A07727C1DF9634A0068A929 /* Extensions.swift in Sources */,
248 | 4A07727E1DF963C70068A929 /* ImageProperties.swift in Sources */,
249 | 4A0772841DF9731B0068A929 /* StringExtensions.swift in Sources */,
250 | 4A56D1591DE5BA85000B40D8 /* AssetCatalogGenerator.swift in Sources */,
251 | 4A0772831DF9731B0068A929 /* Option.swift in Sources */,
252 | 4A56D14B1DE5B573000B40D8 /* main.swift in Sources */,
253 | 4AD71E741EA4899500016A1A /* SwiftGeneration.swift in Sources */,
254 | 4AD71E901EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift in Sources */,
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | 4AD71E781EA4CCBA00016A1A /* Sources */ = {
259 | isa = PBXSourcesBuildPhase;
260 | buildActionMask = 2147483647;
261 | files = (
262 | 4AD71E7F1EA4CCBA00016A1A /* XCAssetPacker_Tests.swift in Sources */,
263 | 4AD71E841EA4CD0800016A1A /* Constants.swift in Sources */,
264 | 4AD71E851EA4CD0800016A1A /* AssetCatalogGenerator.swift in Sources */,
265 | 4AD71E861EA4CD0800016A1A /* ImageProperties.swift in Sources */,
266 | 4AD71E871EA4CD0800016A1A /* Extensions.swift in Sources */,
267 | 4AD71E881EA4CD0800016A1A /* SwiftGeneration.swift in Sources */,
268 | 4AD71E8A1EA4CD0800016A1A /* CommandLine.swift in Sources */,
269 | 4AFFC5931F5D8E83000FDCFD /* DeviceIdiom.swift in Sources */,
270 | 4AD71E8B1EA4CD0800016A1A /* Option.swift in Sources */,
271 | 4AD71E8C1EA4CD0800016A1A /* StringExtensions.swift in Sources */,
272 | 4AD71E911EA4D13400016A1A /* AssetCatalogGenerator+Creation.swift in Sources */,
273 | );
274 | runOnlyForDeploymentPostprocessing = 0;
275 | };
276 | /* End PBXSourcesBuildPhase section */
277 |
278 | /* Begin XCBuildConfiguration section */
279 | 4A56D14C1DE5B573000B40D8 /* Debug */ = {
280 | isa = XCBuildConfiguration;
281 | buildSettings = {
282 | ALWAYS_SEARCH_USER_PATHS = NO;
283 | CLANG_ANALYZER_NONNULL = YES;
284 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
285 | CLANG_CXX_LIBRARY = "libc++";
286 | CLANG_ENABLE_MODULES = YES;
287 | CLANG_ENABLE_OBJC_ARC = YES;
288 | CLANG_WARN_BOOL_CONVERSION = YES;
289 | CLANG_WARN_CONSTANT_CONVERSION = YES;
290 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
291 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
292 | CLANG_WARN_EMPTY_BODY = YES;
293 | CLANG_WARN_ENUM_CONVERSION = YES;
294 | CLANG_WARN_INFINITE_RECURSION = YES;
295 | CLANG_WARN_INT_CONVERSION = YES;
296 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
297 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
298 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
299 | CLANG_WARN_UNREACHABLE_CODE = YES;
300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
301 | CODE_SIGN_IDENTITY = "-";
302 | COPY_PHASE_STRIP = NO;
303 | DEBUG_INFORMATION_FORMAT = dwarf;
304 | ENABLE_STRICT_OBJC_MSGSEND = YES;
305 | ENABLE_TESTABILITY = YES;
306 | GCC_C_LANGUAGE_STANDARD = gnu99;
307 | GCC_DYNAMIC_NO_PIC = NO;
308 | GCC_NO_COMMON_BLOCKS = YES;
309 | GCC_OPTIMIZATION_LEVEL = 0;
310 | GCC_PREPROCESSOR_DEFINITIONS = (
311 | "DEBUG=1",
312 | "$(inherited)",
313 | );
314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
316 | GCC_WARN_UNDECLARED_SELECTOR = YES;
317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
318 | GCC_WARN_UNUSED_FUNCTION = YES;
319 | GCC_WARN_UNUSED_VARIABLE = YES;
320 | MACOSX_DEPLOYMENT_TARGET = 10.11;
321 | MTL_ENABLE_DEBUG_INFO = YES;
322 | ONLY_ACTIVE_ARCH = YES;
323 | SDKROOT = macosx;
324 | SWIFT_INSTALL_OBJC_HEADER = NO;
325 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
326 | };
327 | name = Debug;
328 | };
329 | 4A56D14D1DE5B573000B40D8 /* Release */ = {
330 | isa = XCBuildConfiguration;
331 | buildSettings = {
332 | ALWAYS_SEARCH_USER_PATHS = NO;
333 | CLANG_ANALYZER_NONNULL = YES;
334 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
335 | CLANG_CXX_LIBRARY = "libc++";
336 | CLANG_ENABLE_MODULES = YES;
337 | CLANG_ENABLE_OBJC_ARC = YES;
338 | CLANG_WARN_BOOL_CONVERSION = YES;
339 | CLANG_WARN_CONSTANT_CONVERSION = YES;
340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
341 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
342 | CLANG_WARN_EMPTY_BODY = YES;
343 | CLANG_WARN_ENUM_CONVERSION = YES;
344 | CLANG_WARN_INFINITE_RECURSION = YES;
345 | CLANG_WARN_INT_CONVERSION = YES;
346 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
347 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
348 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
349 | CLANG_WARN_UNREACHABLE_CODE = YES;
350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
351 | CODE_SIGN_IDENTITY = "-";
352 | COPY_PHASE_STRIP = NO;
353 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
354 | ENABLE_NS_ASSERTIONS = NO;
355 | ENABLE_STRICT_OBJC_MSGSEND = YES;
356 | GCC_C_LANGUAGE_STANDARD = gnu99;
357 | GCC_NO_COMMON_BLOCKS = YES;
358 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
359 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
360 | GCC_WARN_UNDECLARED_SELECTOR = YES;
361 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
362 | GCC_WARN_UNUSED_FUNCTION = YES;
363 | GCC_WARN_UNUSED_VARIABLE = YES;
364 | MACOSX_DEPLOYMENT_TARGET = 10.11;
365 | MTL_ENABLE_DEBUG_INFO = NO;
366 | SDKROOT = macosx;
367 | SWIFT_INSTALL_OBJC_HEADER = NO;
368 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
369 | };
370 | name = Release;
371 | };
372 | 4A56D14F1DE5B573000B40D8 /* Debug */ = {
373 | isa = XCBuildConfiguration;
374 | buildSettings = {
375 | DEVELOPMENT_TEAM = D92MT22EX5;
376 | PRODUCT_NAME = "$(TARGET_NAME)";
377 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
378 | SWIFT_VERSION = 4.0;
379 | };
380 | name = Debug;
381 | };
382 | 4A56D1501DE5B573000B40D8 /* Release */ = {
383 | isa = XCBuildConfiguration;
384 | buildSettings = {
385 | DEVELOPMENT_TEAM = D92MT22EX5;
386 | PRODUCT_NAME = "$(TARGET_NAME)";
387 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
388 | SWIFT_VERSION = 4.0;
389 | };
390 | name = Release;
391 | };
392 | 4AD71E821EA4CCBA00016A1A /* Debug */ = {
393 | isa = XCBuildConfiguration;
394 | buildSettings = {
395 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
396 | COMBINE_HIDPI_IMAGES = YES;
397 | DEVELOPMENT_TEAM = D92MT22EX5;
398 | INFOPLIST_FILE = "XCAssetPacker Tests/Info.plist";
399 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
400 | MACOSX_DEPLOYMENT_TARGET = 10.12;
401 | PRODUCT_BUNDLE_IDENTIFIER = "com.inquisitiveSoftware.XCAssetPacker-Tests";
402 | PRODUCT_NAME = "$(TARGET_NAME)";
403 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
404 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
405 | SWIFT_VERSION = 4.0;
406 | };
407 | name = Debug;
408 | };
409 | 4AD71E831EA4CCBA00016A1A /* Release */ = {
410 | isa = XCBuildConfiguration;
411 | buildSettings = {
412 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
413 | COMBINE_HIDPI_IMAGES = YES;
414 | DEVELOPMENT_TEAM = D92MT22EX5;
415 | INFOPLIST_FILE = "XCAssetPacker Tests/Info.plist";
416 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
417 | MACOSX_DEPLOYMENT_TARGET = 10.12;
418 | PRODUCT_BUNDLE_IDENTIFIER = "com.inquisitiveSoftware.XCAssetPacker-Tests";
419 | PRODUCT_NAME = "$(TARGET_NAME)";
420 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
421 | SWIFT_VERSION = 4.0;
422 | };
423 | name = Release;
424 | };
425 | /* End XCBuildConfiguration section */
426 |
427 | /* Begin XCConfigurationList section */
428 | 4A56D1421DE5B573000B40D8 /* Build configuration list for PBXProject "XCAssetPacker" */ = {
429 | isa = XCConfigurationList;
430 | buildConfigurations = (
431 | 4A56D14C1DE5B573000B40D8 /* Debug */,
432 | 4A56D14D1DE5B573000B40D8 /* Release */,
433 | );
434 | defaultConfigurationIsVisible = 0;
435 | defaultConfigurationName = Release;
436 | };
437 | 4A56D14E1DE5B573000B40D8 /* Build configuration list for PBXNativeTarget "xcassetpacker" */ = {
438 | isa = XCConfigurationList;
439 | buildConfigurations = (
440 | 4A56D14F1DE5B573000B40D8 /* Debug */,
441 | 4A56D1501DE5B573000B40D8 /* Release */,
442 | );
443 | defaultConfigurationIsVisible = 0;
444 | defaultConfigurationName = Release;
445 | };
446 | 4AD71E811EA4CCBA00016A1A /* Build configuration list for PBXNativeTarget "XCAssetPacker Tests" */ = {
447 | isa = XCConfigurationList;
448 | buildConfigurations = (
449 | 4AD71E821EA4CCBA00016A1A /* Debug */,
450 | 4AD71E831EA4CCBA00016A1A /* Release */,
451 | );
452 | defaultConfigurationIsVisible = 0;
453 | defaultConfigurationName = Release;
454 | };
455 | /* End XCConfigurationList section */
456 | };
457 | rootObject = 4A56D13F1DE5B573000B40D8 /* Project object */;
458 | }
459 |
--------------------------------------------------------------------------------
/XCAssetPacker/AssetCatalogGenerator+Creation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AssetCatalog.swift
3 | // XCAssetPacker
4 | //
5 | // Created by Harry Jordan on 17/04/2017.
6 | // Copyright © 2017 Inquisitive Software. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 |
12 |
13 | extension AssetCatalogGenerator {
14 |
15 | convenience init(from sourceDirectoryURL: URL, to destinationDirectoryURL: URL, swift swiftDestinationURL: URL?, target: SwiftTarget, overwrite shouldOverwrite: Bool, configuration: [String: Any]) throws {
16 | let fileManager = FileManager()
17 |
18 | guard let fileEnumerator = fileManager.enumerator(at: sourceDirectoryURL, includingPropertiesForKeys: [.isRegularFileKey], options: [], errorHandler: nil) else {
19 | print()
20 | throw AssetCatalogError.ioError("Can't create file enumerator for \(sourceDirectoryURL)")
21 | }
22 |
23 |
24 | // Validate the destination url
25 | var isDirectory: ObjCBool = false
26 | var destinationURL = destinationDirectoryURL
27 |
28 | if fileManager.fileExists(atPath: destinationURL.path, isDirectory: &isDirectory),
29 | isDirectory.boolValue,
30 | destinationURL.pathExtension != FileExtension.assetPackage.rawValue {
31 | destinationURL = destinationURL.appendingPathComponent("Assets.\(FileExtension.assetPackage.rawValue)")
32 | }
33 |
34 |
35 | // Validate the Swift output url
36 | var swiftFileURL: URL? = swiftDestinationURL
37 |
38 | if let swiftDestinationURL = swiftDestinationURL,
39 | fileManager.fileExists(atPath: swiftDestinationURL.path, isDirectory: &isDirectory),
40 | isDirectory.boolValue,
41 | swiftDestinationURL.pathExtension != FileExtension.swift.rawValue {
42 | swiftFileURL = swiftDestinationURL.appendingPathComponent("Images.\(FileExtension.swift)")
43 | }
44 |
45 | self.init(at: destinationURL, swift: swiftFileURL, target: target, shouldOverwrite: shouldOverwrite, configuration: configuration)
46 |
47 |
48 | // Limit to a set of image extensions
49 | let validImageExtensions: [String]
50 |
51 | if let imageExtensions = configuration.value(for: .validImageExtensions) as? [String], !imageExtensions.isEmpty {
52 | validImageExtensions = imageExtensions.map { $0.lowercased() }
53 | } else {
54 | validImageExtensions = ["png"]
55 | }
56 |
57 |
58 | // Enumarate images
59 | while let file = fileEnumerator.nextObject() {
60 | if let fileURL = file as? URL, let resourceValues = try? fileURL.resourceValues(forKeys: [.isRegularFileKey]) {
61 | if validImageExtensions.contains(fileURL.pathExtension.lowercased()), let isRegularFile = resourceValues.isRegularFile, isRegularFile {
62 | self.addImageAsset(from: fileURL, inDirectory: sourceDirectoryURL)
63 | } else if fileURL.pathExtension == FileExtension.assetPackage.rawValue {
64 | // Don't search within existing .xcasset packages
65 | fileEnumerator.skipDescendants()
66 | }
67 | }
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/XCAssetPacker/AssetCatalogGenerator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AssetCatalogGenerator.swift
3 | // XCAssetPacker
4 | //
5 | // Created by Harry Jordan on 23/11/2016.
6 | // Copyright © 2016 Inquisitive Software. All rights reserved.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | import Foundation
22 |
23 |
24 | enum AssetCatalogError: Error {
25 | case ioError(String)
26 | }
27 |
28 |
29 | enum AssetCatalogLogLevel {
30 | // Fast only adds up the number of images included
31 | case fast
32 |
33 | // Detailed populates the images and imageProperties arrays
34 | case detailed
35 | }
36 |
37 |
38 |
39 | struct AssetCatalogLog {
40 |
41 | init(logLevel: AssetCatalogLogLevel, images: [[String: Any]]) {
42 | self.logLevel = logLevel
43 | numberOfImages = images.count
44 |
45 | if logLevel == .detailed {
46 | self.images = images
47 | }
48 | }
49 |
50 | let logLevel: AssetCatalogLogLevel
51 | var numberOfImages: Int
52 | var images: [[String: Any]] = []
53 | var code: String?
54 |
55 | mutating func append(_ otherResult: AssetCatalogLog) {
56 | numberOfImages += otherResult.numberOfImages
57 |
58 | if logLevel == .detailed {
59 | images.append(contentsOf: otherResult.images)
60 | }
61 | }
62 |
63 | }
64 |
65 |
66 | class Node {
67 | let name: String
68 | var sourceURL: URL?
69 | var properties: ImageProperties?
70 | let parent: Node?
71 | var children: [Node] = []
72 | var isImageSet = false
73 | var isAppIcon = false
74 |
75 | init(sourceURL: URL? = nil, name: String, parent: Node?) {
76 | self.sourceURL = sourceURL
77 | self.name = name
78 | self.parent = parent
79 | }
80 |
81 |
82 | func childNode(named childName: String) -> Node {
83 | for child in children {
84 | if child.name.compare(childName, options: [.caseInsensitive]) == .orderedSame {
85 | return child
86 | }
87 | }
88 |
89 | let newNode = Node(name: childName, parent: self)
90 | children.append(newNode)
91 |
92 | return newNode
93 | }
94 |
95 |
96 | var isDirectory: Bool {
97 | return sourceURL == nil
98 | }
99 |
100 |
101 | var pathComponents: [String] {
102 | var currentNode: Node? = self
103 | var pathComponents: [String] = []
104 |
105 | while let node = currentNode, node.parent != nil {
106 | pathComponents.append(node.name)
107 | currentNode = node.parent
108 | }
109 |
110 | return pathComponents.reversed()
111 | }
112 |
113 |
114 | func printTree(depth: Int = 0) {
115 | let depthPadding = (0...depth).reduce("") { (existing, _) -> String in
116 | return existing + " "
117 | }
118 |
119 | print(depthPadding + "- \(name)")
120 | let childDepth = depth + 1
121 |
122 | for child in children {
123 | child.printTree(depth: childDepth)
124 | }
125 | }
126 |
127 | }
128 |
129 |
130 | class AssetCatalogGenerator {
131 | let destinationURL: URL
132 | let swiftFileURL: URL?
133 | let swiftTarget: SwiftTarget
134 | let shouldOverwrite: Bool
135 | let baseIdiom: DeviceIdiom?
136 | let rootNode: Node
137 |
138 | let numberOfRootPathComponents: Int
139 | let configuration: [String: Any]
140 |
141 | let fileManager = FileManager()
142 |
143 |
144 | init(at destinationURL: URL, swift: URL?, target: SwiftTarget, shouldOverwrite: Bool, configuration: [String: Any]) {
145 | self.destinationURL = destinationURL
146 | self.rootNode = Node(name: destinationURL.lastPathComponent, parent: nil)
147 | self.numberOfRootPathComponents = destinationURL.pathComponents.count
148 |
149 | self.swiftFileURL = swift
150 | self.swiftTarget = target
151 |
152 | self.shouldOverwrite = shouldOverwrite
153 | self.configuration = configuration
154 |
155 | if let base = configuration.value(for: .base) as? [String: Any],
156 | let idiom = base.value(for: .idiom) as? String {
157 | baseIdiom = DeviceIdiom(idiom)
158 | } else {
159 | baseIdiom = nil
160 | }
161 | }
162 |
163 |
164 | // MARK: Construct a tree of source images
165 |
166 | func addImageAsset(from sourceURL: URL, inDirectory sourceDirectoryURL: URL) {
167 | let numberOfPathComponents = sourceDirectoryURL.pathComponents.count
168 | let fileName = sourceURL.lastPathComponent
169 | var isAppIcon = false
170 |
171 | if let include = configuration.value(for: .includeImages) as? [String: Any],
172 | let patternsToRequire = include.value(for: .multiplePatterns) as? [String],
173 | !fileName.isMatchedBy(patternsToRequire) {
174 | return
175 | }
176 |
177 | if let skip = configuration.value(for: .skipImages) as? [String: Any],
178 | let patternsToSkip = skip.value(for: .multiplePatterns) as? [String],
179 | fileName.isMatchedBy(patternsToSkip) {
180 | return
181 | }
182 |
183 | if let appIcon = configuration.value(for: .appIcon) as? [String: Any],
184 | let appIconPattern = appIcon.value(for: .pattern) as? String {
185 | isAppIcon = fileName.isMatchedBy(appIconPattern)
186 | } else {
187 | isAppIcon = fileName.isMatchedBy(FileName.appIcon.rawValue)
188 | }
189 |
190 | let imageProperties = ImageProperties(from: fileName, isAppIcon: isAppIcon, configuration: configuration)
191 |
192 | let groupFileExtension: FileExtension = isAppIcon ? .appIconSet : .imageSet
193 | let generalizedImageSetName = (imageProperties.name as NSString).appendingPathExtension(groupFileExtension.rawValue)!
194 |
195 | var pathComponents = sourceURL.pathComponents.suffix(from: numberOfPathComponents)
196 |
197 | // Create an asset with a generalized name stripped of the -38, -42 or @2x etc. prefixes
198 | _ = pathComponents.popLast()
199 | pathComponents.append(generalizedImageSetName)
200 |
201 | var currentNode = rootNode
202 |
203 | for pathComponent in pathComponents {
204 | currentNode = currentNode.childNode(named: pathComponent)
205 | }
206 |
207 | currentNode.isImageSet = true
208 | currentNode.isAppIcon = isAppIcon
209 |
210 | let imageNode = currentNode.childNode(named: fileName)
211 | imageNode.properties = imageProperties
212 | imageNode.sourceURL = sourceURL
213 | }
214 |
215 |
216 | // MARK: Outputing the .xcasset package
217 |
218 | @discardableResult func applyChanges(logLevel: AssetCatalogLogLevel = .fast, dryRun: Bool = false) throws -> AssetCatalogLog {
219 | // Overwrite an existing .xcasset package if the --force argument is supplied
220 | if shouldOverwrite {
221 | if fileManager.fileExists(atPath: destinationURL.path) {
222 | try fileManager.removeItem(at: destinationURL)
223 | }
224 | } else {
225 | // Otherwise bail if an existing .xcasset package or swift file exist
226 | let destinationExists = fileManager.fileExists(atPath: destinationURL.path)
227 |
228 | if destinationExists {
229 | throw AssetCatalogError.ioError("An asset collection already exists at: \(destinationURL)")
230 | }
231 |
232 | if let swiftFileURL = swiftFileURL {
233 | let swiftFileExists = fileManager.fileExists(atPath: swiftFileURL.path)
234 |
235 | if(swiftFileExists) {
236 | throw AssetCatalogError.ioError("An swift file already exists at: \(swiftFileURL)")
237 | }
238 | }
239 | }
240 |
241 |
242 | // Generate Swift code
243 | let generatedCode: String?
244 |
245 | if let swiftFileURL = swiftFileURL {
246 | let code = try swiftCode(forTarget: swiftTarget, rootNode: rootNode)
247 | try code.write(to: swiftFileURL, atomically: true, encoding: .utf8)
248 | generatedCode = code
249 | } else {
250 | generatedCode = nil
251 | }
252 |
253 | // Create the folder structure, the metadata and copy the images across
254 | var result = try applyChanges(forNode: rootNode, dryRun: dryRun, logLevel: logLevel)
255 | result.code = generatedCode
256 |
257 | return result
258 | }
259 |
260 |
261 | func applyChanges(forNode node: Node, dryRun: Bool, logLevel: AssetCatalogLogLevel) throws -> AssetCatalogLog {
262 | // Create a Contents.json for each directory
263 | var images: [[String : Any]] = []
264 | var copies: [(from: URL, to: URL)] = []
265 | var imageProperties: [ImageProperties] = []
266 |
267 | for child in node.children where !child.isDirectory {
268 | if let sourceURL = child.sourceURL, let properties = child.properties {
269 | imageProperties.append(properties)
270 |
271 | let imageFileName = sourceURL.lastPathComponent
272 | let assetDestinationURL = destinationURL.appending(pathComponents: node.pathComponents).appendingPathComponent(imageFileName)
273 |
274 | // Xcode 9 seperates Notification, Settings and Spotlight images for iPhone and iPad
275 | // if no base idiom is supplied then add both images
276 | //
277 | // This is rather messy, so would ideally be tidied up
278 | switch properties.type {
279 | case .notification, .settings, .spotlight:
280 | if let idiom = baseIdiom {
281 | images.append(imageDictionary(for: imageFileName, properties: properties, customIdiom: idiom.idiomString))
282 | } else {
283 | let targetIdioms: [DeviceIdiom] = [.iPhone, .iPad]
284 |
285 | for targetIdiom in targetIdioms {
286 | images.append(imageDictionary(for: imageFileName, properties: properties, customIdiom: targetIdiom.idiomString))
287 | }
288 | }
289 |
290 | default:
291 | images.append(imageDictionary(for: imageFileName, properties: properties))
292 | }
293 |
294 | copies.append((sourceURL, assetDestinationURL))
295 | }
296 | }
297 |
298 |
299 | var contents = contentsDictionaryFor(node: node, imageProperties: imageProperties)
300 |
301 | if !images.isEmpty {
302 | contents[Configuration.images.rawValue] = images
303 | }
304 |
305 | if !dryRun {
306 | // Create the destination folder
307 | let folderURL = destinationURL.appending(pathComponents: node.pathComponents)
308 | try fileManager.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
309 |
310 | // Save the Contents.json
311 | try write(contents, to: folderURL, fileName: FileName.contents.rawValue)
312 |
313 | // Perform copies
314 | for (sourceURL, destinationURL) in copies {
315 | try fileManager.copyItem(at: sourceURL, to: destinationURL)
316 | }
317 | }
318 |
319 | // Apply recursively for each child directory
320 | var result = AssetCatalogLog(logLevel: logLevel, images: images)
321 |
322 | for child in node.children where child.isDirectory {
323 | let childResult = try applyChanges(forNode: child, dryRun: dryRun, logLevel: logLevel)
324 | result.append(childResult)
325 | }
326 |
327 | return result
328 | }
329 |
330 |
331 | func write(_ json: [String: Any], to url: URL, fileName: String) throws {
332 | let destinationURL = url.appendingPathComponent(fileName)
333 |
334 | let jsonData = try JSONSerialization.data(withJSONObject: json, options: [])
335 | try jsonData.write(to: destinationURL)
336 | }
337 |
338 |
339 | // MARK: Generate json for each component within the .xcassets package
340 |
341 |
342 | func imageDictionary(for imageName: String, properties: ImageProperties, customIdiom: String? = nil) -> [String: Any] {
343 | var imageDictionary: [String: Any] = [:]
344 | imageDictionary[Configuration.filename.rawValue] = imageName
345 |
346 | if let idiom = customIdiom {
347 | imageDictionary[Configuration.idiom.rawValue] = idiom
348 | } else if let idiom = properties.idiom {
349 | imageDictionary[Configuration.idiom.rawValue] = idiom
350 | }
351 |
352 | if let scale = properties.scaleString {
353 | imageDictionary[Configuration.scale.rawValue] = scale
354 | }
355 |
356 | if let size = properties.type.sizeString {
357 | imageDictionary[Configuration.size.rawValue] = size
358 | }
359 |
360 | if let screenWidth = properties.type.screenWidth {
361 | imageDictionary[Configuration.screenWidth.rawValue] = screenWidth
362 | }
363 |
364 | if let prerendered = properties.prerendered {
365 | imageDictionary[Configuration.prerendered.rawValue] = prerendered
366 | }
367 |
368 | return imageDictionary
369 | }
370 |
371 |
372 | func contentsDictionaryFor(node: Node, imageProperties: [ImageProperties]) -> [String: Any] {
373 | var contents = (configuration.value(for: .info) as? [String: Any]) ?? [
374 | "info" : [
375 | "version" : 1,
376 | "author" : "xcode"
377 | ]
378 | ]
379 |
380 | var combinedProperties: [String: Any] = [:]
381 |
382 | if let baseProperties = configuration.value(for: .base) as? [String: Any] {
383 | for (key, value) in baseProperties {
384 | combinedProperties[key] = value
385 | }
386 | }
387 |
388 |
389 | if let devices = configuration.value(for: .devices) as? [[String: Any]] {
390 | for device in devices {
391 | // Test that the device type matches the image format
392 | if let deviceType = device.value(for: .deviceType) as? String,
393 | deviceType == imageProperties.first?.type.deviceType,
394 | let properties = device.value(for: .properties) as? [String: Any] {
395 | for (key, value) in properties {
396 | combinedProperties[key] = value
397 | }
398 | }
399 | }
400 | }
401 |
402 |
403 | if let customProperties = configuration.value(for: .custom) as? [[String: Any]] {
404 | for customProperty in customProperties {
405 | if let patterns = customProperty.value(for: .multiplePatterns) as? [String],
406 | node.name.isMatchedBy(patterns),
407 | let properties = customProperty.value(for: .properties) as? [String: Any] {
408 |
409 | for (key, value) in properties {
410 | combinedProperties[key] = value
411 | }
412 | }
413 | }
414 | }
415 |
416 | if !combinedProperties.isEmpty {
417 | contents[Configuration.properties.rawValue] = combinedProperties
418 | }
419 |
420 | return contents
421 | }
422 |
423 | }
424 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | .build/
5 | *.pbxuser
6 | !default.pbxuser
7 | *.mode1v3
8 | !default.mode1v3
9 | *.mode2v3
10 | !default.mode2v3
11 | *.perspectivev3
12 | !default.perspectivev3
13 | xcuserdata
14 | *.xccheckout
15 | *.moved-aside
16 | DerivedData
17 | *.hmap
18 | *.ipa
19 | *.xcuserstate
20 |
21 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/.travis.yml:
--------------------------------------------------------------------------------
1 | matrix:
2 | include:
3 | - os: osx
4 | language: objective-c # this is a lie
5 | xcode_project: CommandLine.xcodeproj
6 | xcode_scheme: CommandLine
7 | script: xcodebuild -scheme CommandLine test
8 | osx_image: xcode8.2
9 | - os: linux
10 | sudo: required
11 | dist: trusty
12 | before_install:
13 | - sudo apt-get install -y clang libicu-dev
14 | - sudo locale-gen sv_SE.UTF-8 # for alternate-locale tests
15 | - ./install-linux-swift.sh
16 | - export PATH="/swift/usr/bin:${PATH}"
17 | script:
18 | - swift build -v
19 | - swift test
20 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/CommandLineKit.xcodeproj/xcshareddata/xcschemes/CommandLine.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
98 |
104 |
105 |
106 |
107 |
109 |
110 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/CommandLineKit/CommandLine.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * CommandLine.swift
3 | * Copyright (c) 2014 Ben Gollmer.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import Foundation
19 | /* Required for setlocale(3) */
20 | #if os(OSX)
21 | import Darwin
22 | #elseif os(Linux)
23 | import Glibc
24 | #endif
25 |
26 | let shortOptionPrefix = "-"
27 | let longOptionPrefix = "--"
28 |
29 | /* Stop parsing arguments when an ArgumentStopper (--) is detected. This is a GNU getopt
30 | * convention; cf. https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html
31 | */
32 | let argumentStopper = "--"
33 |
34 | /* Allow arguments to be attached to flags when separated by this character.
35 | * --flag=argument is equivalent to --flag argument
36 | */
37 | let argumentAttacher: Character = "="
38 |
39 | /* An output stream to stderr; used by CommandLine.printUsage(). */
40 | private struct StderrOutputStream: TextOutputStream {
41 | static let stream = StderrOutputStream()
42 | func write(_ s: String) {
43 | fputs(s, stderr)
44 | }
45 | }
46 |
47 | /**
48 | * The CommandLine class implements a command-line interface for your app.
49 | *
50 | * To use it, define one or more Options (see Option.swift) and add them to your
51 | * CommandLine object, then invoke `parse()`. Each Option object will be populated with
52 | * the value given by the user.
53 | *
54 | * If any required options are missing or if an invalid value is found, `parse()` will throw
55 | * a `ParseError`. You can then call `printUsage()` to output an automatically-generated usage
56 | * message.
57 | */
58 | public class CommandLine {
59 | private var _arguments: [String]
60 | private var _options: [Option] = [Option]()
61 | private var _maxFlagDescriptionWidth: Int = 0
62 | private var _usedFlags: Set {
63 | var usedFlags = Set(minimumCapacity: _options.count * 2)
64 |
65 | for option in _options {
66 | for case let flag? in [option.shortFlag, option.longFlag] {
67 | usedFlags.insert(flag)
68 | }
69 | }
70 |
71 | return usedFlags
72 | }
73 |
74 | /**
75 | * After calling `parse()`, this property will contain any values that weren't captured
76 | * by an Option. For example:
77 | *
78 | * ```
79 | * let cli = CommandLine()
80 | * let fileType = StringOption(shortFlag: "t", longFlag: "type", required: true, helpMessage: "Type of file")
81 | *
82 | * do {
83 | * try cli.parse()
84 | * print("File type is \(type), files are \(cli.unparsedArguments)")
85 | * catch {
86 | * cli.printUsage(error)
87 | * exit(EX_USAGE)
88 | * }
89 | *
90 | * ---
91 | *
92 | * $ ./readfiles --type=pdf ~/file1.pdf ~/file2.pdf
93 | * File type is pdf, files are ["~/file1.pdf", "~/file2.pdf"]
94 | * ```
95 | */
96 | public private(set) var unparsedArguments: [String] = [String]()
97 |
98 | /**
99 | * If supplied, this function will be called when printing usage messages.
100 | *
101 | * You can use the `defaultFormat` function to get the normally-formatted
102 | * output, either before or after modifying the provided string. For example:
103 | *
104 | * ```
105 | * let cli = CommandLine()
106 | * cli.formatOutput = { str, type in
107 | * switch(type) {
108 | * case .Error:
109 | * // Make errors shouty
110 | * return defaultFormat(str.uppercaseString, type: type)
111 | * case .OptionHelp:
112 | * // Don't use the default indenting
113 | * return ">> \(s)\n"
114 | * default:
115 | * return defaultFormat(str, type: type)
116 | * }
117 | * }
118 | * ```
119 | *
120 | * - note: Newlines are not appended to the result of this function. If you don't use
121 | * `defaultFormat()`, be sure to add them before returning.
122 | */
123 | public var formatOutput: ((String, OutputType) -> String)?
124 |
125 | /**
126 | * The maximum width of all options' `flagDescription` properties; provided for use by
127 | * output formatters.
128 | *
129 | * - seealso: `defaultFormat`, `formatOutput`
130 | */
131 | public var maxFlagDescriptionWidth: Int {
132 | if _maxFlagDescriptionWidth == 0 {
133 | _maxFlagDescriptionWidth = _options.map { $0.flagDescription.characters.count }.sorted().first ?? 0
134 | }
135 |
136 | return _maxFlagDescriptionWidth
137 | }
138 |
139 | /**
140 | * The type of output being supplied to an output formatter.
141 | *
142 | * - seealso: `formatOutput`
143 | */
144 | public enum OutputType {
145 | /** About text: `Usage: command-example [options]` and the like */
146 | case about
147 |
148 | /** An error message: `Missing required option --extract` */
149 | case error
150 |
151 | /** An Option's `flagDescription`: `-h, --help:` */
152 | case optionFlag
153 |
154 | /** An Option's help message */
155 | case optionHelp
156 | }
157 |
158 | /** A ParseError is thrown if the `parse()` method fails. */
159 | public enum ParseError: Error, CustomStringConvertible {
160 | /** Thrown if an unrecognized argument is passed to `parse()` in strict mode */
161 | case invalidArgument(String)
162 |
163 | /** Thrown if the value for an Option is invalid (e.g. a string is passed to an IntOption) */
164 | case invalidValueForOption(Option, [String])
165 |
166 | /** Thrown if an Option with required: true is missing */
167 | case missingRequiredOptions([Option])
168 |
169 | public var description: String {
170 | switch self {
171 | case let .invalidArgument(arg):
172 | return "Invalid argument: \(arg)"
173 | case let .invalidValueForOption(opt, vals):
174 | let vs = vals.joined(separator: ", ")
175 | return "Invalid value(s) for option \(opt.flagDescription): \(vs)"
176 | case let .missingRequiredOptions(opts):
177 | return "Missing required options: \(opts.map { return $0.flagDescription })"
178 | }
179 | }
180 | }
181 |
182 | /**
183 | * Initializes a CommandLine object.
184 | *
185 | * - parameter arguments: Arguments to parse. If omitted, the arguments passed to the app
186 | * on the command line will automatically be used.
187 | *
188 | * - returns: An initalized CommandLine object.
189 | */
190 | public init(arguments: [String] = Swift.CommandLine.arguments) {
191 | self._arguments = arguments
192 |
193 | /* Initialize locale settings from the environment */
194 | setlocale(LC_ALL, "")
195 | }
196 |
197 | /* Returns all argument values from flagIndex to the next flag or the end of the argument array. */
198 | private func _getFlagValues(_ flagIndex: Int, _ attachedArg: String? = nil) -> [String] {
199 | var args: [String] = [String]()
200 | var skipFlagChecks = false
201 |
202 | if let a = attachedArg {
203 | args.append(a)
204 | }
205 |
206 | for i in flagIndex + 1 ..< _arguments.count {
207 | if !skipFlagChecks {
208 | if _arguments[i] == argumentStopper {
209 | skipFlagChecks = true
210 | continue
211 | }
212 |
213 | if _arguments[i].hasPrefix(shortOptionPrefix) && Int(_arguments[i]) == nil &&
214 | _arguments[i].toDouble() == nil {
215 | break
216 | }
217 | }
218 |
219 | args.append(_arguments[i])
220 | }
221 |
222 | return args
223 | }
224 |
225 | /**
226 | * Adds an Option to the command line.
227 | *
228 | * - parameter option: The option to add.
229 | */
230 | public func addOption(_ option: Option) {
231 | let uf = _usedFlags
232 | for case let flag? in [option.shortFlag, option.longFlag] {
233 | assert(!uf.contains(flag), "Flag '\(flag)' already in use")
234 | }
235 |
236 | _options.append(option)
237 | _maxFlagDescriptionWidth = 0
238 | }
239 |
240 | /**
241 | * Adds one or more Options to the command line.
242 | *
243 | * - parameter options: An array containing the options to add.
244 | */
245 | public func addOptions(_ options: [Option]) {
246 | for o in options {
247 | addOption(o)
248 | }
249 | }
250 |
251 | /**
252 | * Adds one or more Options to the command line.
253 | *
254 | * - parameter options: The options to add.
255 | */
256 | public func addOptions(_ options: Option...) {
257 | for o in options {
258 | addOption(o)
259 | }
260 | }
261 |
262 | /**
263 | * Sets the command line Options. Any existing options will be overwritten.
264 | *
265 | * - parameter options: An array containing the options to set.
266 | */
267 | public func setOptions(_ options: [Option]) {
268 | _options = [Option]()
269 | addOptions(options)
270 | }
271 |
272 | /**
273 | * Sets the command line Options. Any existing options will be overwritten.
274 | *
275 | * - parameter options: The options to set.
276 | */
277 | public func setOptions(_ options: Option...) {
278 | _options = [Option]()
279 | addOptions(options)
280 | }
281 |
282 | /**
283 | * Parses command-line arguments into their matching Option values.
284 | *
285 | * - parameter strict: Fail if any unrecognized flags are present (default: false).
286 | *
287 | * - throws: A `ParseError` if argument parsing fails:
288 | * - `.InvalidArgument` if an unrecognized flag is present and `strict` is true
289 | * - `.InvalidValueForOption` if the value supplied to an option is not valid (for
290 | * example, a string is supplied for an IntOption)
291 | * - `.MissingRequiredOptions` if a required option isn't present
292 | */
293 | public func parse(strict: Bool = false) throws {
294 | var strays = _arguments
295 |
296 | /* Nuke executable name */
297 | strays[0] = ""
298 |
299 | let argumentsEnumerator = _arguments.enumerated()
300 | for (idx, arg) in argumentsEnumerator {
301 | if arg == argumentStopper {
302 | break
303 | }
304 |
305 | if !arg.hasPrefix(shortOptionPrefix) {
306 | continue
307 | }
308 |
309 | let skipChars = arg.hasPrefix(longOptionPrefix) ?
310 | longOptionPrefix.characters.count : shortOptionPrefix.characters.count
311 | let flagWithArg = arg[arg.index(arg.startIndex, offsetBy: skipChars)..
348 | */
349 | let vals = (i == flagLength - 1) ? self._getFlagValues(idx, attachedArg) : [String]()
350 | guard option.setValue(vals) else {
351 | throw ParseError.invalidValueForOption(option, vals)
352 | }
353 |
354 | var claimedIdx = idx + option.claimedValues
355 | if attachedArg != nil { claimedIdx -= 1 }
356 | for i in idx...claimedIdx {
357 | strays[i] = ""
358 | }
359 |
360 | flagMatched = true
361 | break
362 | }
363 | }
364 | }
365 |
366 | /* Invalid flag */
367 | guard !strict || flagMatched else {
368 | throw ParseError.invalidArgument(arg)
369 | }
370 | }
371 |
372 | /* Check to see if any required options were not matched */
373 | let missingOptions = _options.filter { $0.required && !$0.wasSet }
374 | guard missingOptions.count == 0 else {
375 | throw ParseError.missingRequiredOptions(missingOptions)
376 | }
377 |
378 | unparsedArguments = strays.filter { $0 != "" }
379 | }
380 |
381 | /**
382 | * Provides the default formatting of `printUsage()` output.
383 | *
384 | * - parameter s: The string to format.
385 | * - parameter type: Type of output.
386 | *
387 | * - returns: The formatted string.
388 | * - seealso: `formatOutput`
389 | */
390 | public func defaultFormat(s: String, type: OutputType) -> String {
391 | switch type {
392 | case .about:
393 | return "\(s)\n"
394 | case .error:
395 | return "\(s)\n\n"
396 | case .optionFlag:
397 | return " \(s.padded(toWidth: maxFlagDescriptionWidth)):\n"
398 | case .optionHelp:
399 | return " \(s)\n"
400 | }
401 | }
402 |
403 | /* printUsage() is generic for OutputStreamType because the Swift compiler crashes
404 | * on inout protocol function parameters in Xcode 7 beta 1 (rdar://21372694).
405 | */
406 |
407 | /**
408 | * Prints a usage message.
409 | *
410 | * - parameter to: An OutputStreamType to write the error message to.
411 | */
412 | public func printUsage(_ to: inout TargetStream) {
413 | /* Nil coalescing operator (??) doesn't work on closures :( */
414 | let format = formatOutput != nil ? formatOutput! : defaultFormat
415 |
416 | let name = _arguments[0]
417 | print(format("Usage: \(name) [options]", .about), terminator: "", to: &to)
418 |
419 | for opt in _options {
420 | print(format(opt.flagDescription, .optionFlag), terminator: "", to: &to)
421 | print(format(opt.helpMessage, .optionHelp), terminator: "", to: &to)
422 | }
423 | }
424 |
425 | /**
426 | * Prints a usage message.
427 | *
428 | * - parameter error: An error thrown from `parse()`. A description of the error
429 | * (e.g. "Missing required option --extract") will be printed before the usage message.
430 | * - parameter to: An OutputStreamType to write the error message to.
431 | */
432 | public func printUsage(_ error: Error, to: inout TargetStream) {
433 | let format = formatOutput != nil ? formatOutput! : defaultFormat
434 | print(format("\(error)", .error), terminator: "", to: &to)
435 | printUsage(&to)
436 | }
437 |
438 | /**
439 | * Prints a usage message.
440 | *
441 | * - parameter error: An error thrown from `parse()`. A description of the error
442 | * (e.g. "Missing required option --extract") will be printed before the usage message.
443 | */
444 | public func printUsage(_ error: Error) {
445 | var out = StderrOutputStream.stream
446 | printUsage(error, to: &out)
447 | }
448 |
449 | /**
450 | * Prints a usage message.
451 | */
452 | public func printUsage() {
453 | var out = StderrOutputStream.stream
454 | printUsage(&out)
455 | }
456 | }
457 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/CommandLineKit/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSHumanReadableCopyright
24 | Copyright © 2014 Ben Gollmer. Licensed under the Apache License, Version 2.0.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/CommandLineKit/Option.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Option.swift
3 | * Copyright (c) 2014 Ben Gollmer.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | /**
19 | * The base class for a command-line option.
20 | */
21 | public class Option {
22 | public let shortFlag: String?
23 | public let longFlag: String?
24 | public let required: Bool
25 | public let helpMessage: String
26 |
27 | /** True if the option was set when parsing command-line arguments */
28 | public var wasSet: Bool {
29 | return false
30 | }
31 |
32 | public var claimedValues: Int { return 0 }
33 |
34 | public var flagDescription: String {
35 | switch (shortFlag, longFlag) {
36 | case let (sf?, lf?):
37 | return "\(shortOptionPrefix)\(sf), \(longOptionPrefix)\(lf)"
38 | case (nil, let lf?):
39 | return "\(longOptionPrefix)\(lf)"
40 | case (let sf?, nil):
41 | return "\(shortOptionPrefix)\(sf)"
42 | default:
43 | return ""
44 | }
45 | }
46 |
47 | internal init(_ shortFlag: String?, _ longFlag: String?, _ required: Bool, _ helpMessage: String) {
48 | if let sf = shortFlag {
49 | assert(sf.characters.count == 1, "Short flag must be a single character")
50 | assert(Int(sf) == nil && sf.toDouble() == nil, "Short flag cannot be a numeric value")
51 | }
52 |
53 | if let lf = longFlag {
54 | assert(Int(lf) == nil && lf.toDouble() == nil, "Long flag cannot be a numeric value")
55 | }
56 |
57 | self.shortFlag = shortFlag
58 | self.longFlag = longFlag
59 | self.helpMessage = helpMessage
60 | self.required = required
61 | }
62 |
63 | /* The optional casts in these initalizers force them to call the private initializer. Without
64 | * the casts, they recursively call themselves.
65 | */
66 |
67 | /** Initializes a new Option that has both long and short flags. */
68 | public convenience init(shortFlag: String, longFlag: String, required: Bool = false, helpMessage: String) {
69 | self.init(shortFlag as String?, longFlag, required, helpMessage)
70 | }
71 |
72 | /** Initializes a new Option that has only a short flag. */
73 | public convenience init(shortFlag: String, required: Bool = false, helpMessage: String) {
74 | self.init(shortFlag as String?, nil, required, helpMessage)
75 | }
76 |
77 | /** Initializes a new Option that has only a long flag. */
78 | public convenience init(longFlag: String, required: Bool = false, helpMessage: String) {
79 | self.init(nil, longFlag as String?, required, helpMessage)
80 | }
81 |
82 | func flagMatch(_ flag: String) -> Bool {
83 | return flag == shortFlag || flag == longFlag
84 | }
85 |
86 | func setValue(_ values: [String]) -> Bool {
87 | return false
88 | }
89 | }
90 |
91 | /**
92 | * A boolean option. The presence of either the short or long flag will set the value to true;
93 | * absence of the flag(s) is equivalent to false.
94 | */
95 | public class BoolOption: Option {
96 | private var _value: Bool = false
97 |
98 | public var value: Bool {
99 | return _value
100 | }
101 |
102 | override public var wasSet: Bool {
103 | return _value
104 | }
105 |
106 | override func setValue(_ values: [String]) -> Bool {
107 | _value = true
108 | return true
109 | }
110 | }
111 |
112 | /** An option that accepts a positive or negative integer value. */
113 | public class IntOption: Option {
114 | private var _value: Int?
115 |
116 | public var value: Int? {
117 | return _value
118 | }
119 |
120 | override public var wasSet: Bool {
121 | return _value != nil
122 | }
123 |
124 | override public var claimedValues: Int {
125 | return _value != nil ? 1 : 0
126 | }
127 |
128 | override func setValue(_ values: [String]) -> Bool {
129 | if values.count == 0 {
130 | return false
131 | }
132 |
133 | if let val = Int(values[0]) {
134 | _value = val
135 | return true
136 | }
137 |
138 | return false
139 | }
140 | }
141 |
142 | /**
143 | * An option that represents an integer counter. Each time the short or long flag is found
144 | * on the command-line, the counter will be incremented.
145 | */
146 | public class CounterOption: Option {
147 | private var _value: Int = 0
148 |
149 | public var value: Int {
150 | return _value
151 | }
152 |
153 | override public var wasSet: Bool {
154 | return _value > 0
155 | }
156 |
157 | public func reset() {
158 | _value = 0
159 | }
160 |
161 | override func setValue(_ values: [String]) -> Bool {
162 | _value += 1
163 | return true
164 | }
165 | }
166 |
167 | /** An option that accepts a positive or negative floating-point value. */
168 | public class DoubleOption: Option {
169 | private var _value: Double?
170 |
171 | public var value: Double? {
172 | return _value
173 | }
174 |
175 | override public var wasSet: Bool {
176 | return _value != nil
177 | }
178 |
179 | override public var claimedValues: Int {
180 | return _value != nil ? 1 : 0
181 | }
182 |
183 | override func setValue(_ values: [String]) -> Bool {
184 | if values.count == 0 {
185 | return false
186 | }
187 |
188 | if let val = values[0].toDouble() {
189 | _value = val
190 | return true
191 | }
192 |
193 | return false
194 | }
195 | }
196 |
197 | /** An option that accepts a string value. */
198 | public class StringOption: Option {
199 | private var _value: String? = nil
200 |
201 | public var value: String? {
202 | return _value
203 | }
204 |
205 | override public var wasSet: Bool {
206 | return _value != nil
207 | }
208 |
209 | override public var claimedValues: Int {
210 | return _value != nil ? 1 : 0
211 | }
212 |
213 | override func setValue(_ values: [String]) -> Bool {
214 | if values.count == 0 {
215 | return false
216 | }
217 |
218 | _value = values[0]
219 | return true
220 | }
221 | }
222 |
223 | /** An option that accepts one or more string values. */
224 | public class MultiStringOption: Option {
225 | private var _value: [String]?
226 |
227 | public var value: [String]? {
228 | return _value
229 | }
230 |
231 | override public var wasSet: Bool {
232 | return _value != nil
233 | }
234 |
235 | override public var claimedValues: Int {
236 | if let v = _value {
237 | return v.count
238 | }
239 |
240 | return 0
241 | }
242 |
243 | override func setValue(_ values: [String]) -> Bool {
244 | if values.count == 0 {
245 | return false
246 | }
247 |
248 | _value = values
249 | return true
250 | }
251 | }
252 |
253 | /** An option that represents an enum value. */
254 | public class EnumOption: Option where T.RawValue == String {
255 | private var _value: T?
256 | public var value: T? {
257 | return _value
258 | }
259 |
260 | override public var wasSet: Bool {
261 | return _value != nil
262 | }
263 |
264 | override public var claimedValues: Int {
265 | return _value != nil ? 1 : 0
266 | }
267 |
268 | /* Re-defining the intializers is necessary to make the Swift 2 compiler happy, as
269 | * of Xcode 7 beta 2.
270 | */
271 |
272 | internal override init(_ shortFlag: String?, _ longFlag: String?, _ required: Bool, _ helpMessage: String) {
273 | super.init(shortFlag, longFlag, required, helpMessage)
274 | }
275 |
276 | /** Initializes a new Option that has both long and short flags. */
277 | public convenience init(shortFlag: String, longFlag: String, required: Bool = false, helpMessage: String) {
278 | self.init(shortFlag as String?, longFlag, required, helpMessage)
279 | }
280 |
281 | /** Initializes a new Option that has only a short flag. */
282 | public convenience init(shortFlag: String, required: Bool = false, helpMessage: String) {
283 | self.init(shortFlag as String?, nil, required, helpMessage)
284 | }
285 |
286 | /** Initializes a new Option that has only a long flag. */
287 | public convenience init(longFlag: String, required: Bool = false, helpMessage: String) {
288 | self.init(nil, longFlag as String?, required, helpMessage)
289 | }
290 |
291 | override func setValue(_ values: [String]) -> Bool {
292 | if values.count == 0 {
293 | return false
294 | }
295 |
296 | if let v = T(rawValue: values[0]) {
297 | _value = v
298 | return true
299 | }
300 |
301 | return false
302 | }
303 |
304 | }
305 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/CommandLineKit/StringExtensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * StringExtensions.swift
3 | * Copyright (c) 2014 Ben Gollmer.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | /* Required for localeconv(3) */
19 | #if os(OSX)
20 | import Darwin
21 | #elseif os(Linux)
22 | import Glibc
23 | #endif
24 |
25 | internal extension String {
26 | /* Retrieves locale-specified decimal separator from the environment
27 | * using localeconv(3).
28 | */
29 | private func _localDecimalPoint() -> Character {
30 | let locale = localeconv()
31 | if locale != nil {
32 | if let decimalPoint = locale?.pointee.decimal_point {
33 | return Character(UnicodeScalar(UInt32(decimalPoint.pointee))!)
34 | }
35 | }
36 |
37 | return "."
38 | }
39 |
40 | /**
41 | * Attempts to parse the string value into a Double.
42 | *
43 | * - returns: A Double if the string can be parsed, nil otherwise.
44 | */
45 | func toDouble() -> Double? {
46 | var characteristic: String = "0"
47 | var mantissa: String = "0"
48 | var inMantissa: Bool = false
49 | var isNegative: Bool = false
50 | let decimalPoint = self._localDecimalPoint()
51 |
52 | let charactersEnumerator = self.characters.enumerated()
53 | for (i, c) in charactersEnumerator {
54 | if i == 0 && c == "-" {
55 | isNegative = true
56 | continue
57 | }
58 |
59 | if c == decimalPoint {
60 | inMantissa = true
61 | continue
62 | }
63 |
64 | if Int(String(c)) != nil {
65 | if !inMantissa {
66 | characteristic.append(c)
67 | } else {
68 | mantissa.append(c)
69 | }
70 | } else {
71 | /* Non-numeric character found, bail */
72 | return nil
73 | }
74 | }
75 |
76 | let doubleCharacteristic = Double(Int(characteristic)!)
77 | return (doubleCharacteristic +
78 | Double(Int(mantissa)!) / pow(Double(10), Double(mantissa.characters.count - 1))) *
79 | (isNegative ? -1 : 1)
80 | }
81 |
82 | /**
83 | * Splits a string into an array of string components.
84 | *
85 | * - parameter by: The character to split on.
86 | * - parameter maxSplits: The maximum number of splits to perform. If 0, all possible splits are made.
87 | *
88 | * - returns: An array of string components.
89 | */
90 | func split(by: Character, maxSplits: Int = 0) -> [String] {
91 | var s = [String]()
92 | var numSplits = 0
93 |
94 | var curIdx = self.startIndex
95 | for i in self.characters.indices {
96 | let c = self[i]
97 | if c == by && (maxSplits == 0 || numSplits < maxSplits) {
98 | s.append(String(self[curIdx.. String {
120 | var s = self
121 | var currentLength = self.characters.count
122 |
123 | while currentLength < width {
124 | s.append(padChar)
125 | currentLength += 1
126 | }
127 |
128 | return s
129 | }
130 |
131 | /**
132 | * Wraps a string to the specified width.
133 | *
134 | * This just does simple greedy word-packing, it doesn't go full Knuth-Plass.
135 | * If a single word is longer than the line width, it will be placed (unsplit)
136 | * on a line by itself.
137 | *
138 | * - parameter atWidth: The maximum length of a line.
139 | * - parameter wrapBy: The line break character to use.
140 | * - parameter splitBy: The character to use when splitting the string into words.
141 | *
142 | * - returns: A new string, wrapped at the given width.
143 | */
144 | func wrapped(atWidth width: Int, wrapBy: Character = "\n", splitBy: Character = " ") -> String {
145 | var s = ""
146 | var currentLineWidth = 0
147 |
148 | for word in self.split(by: splitBy) {
149 | let wordLength = word.characters.count
150 |
151 | if currentLineWidth + wordLength + 1 > width {
152 | /* Word length is greater than line length, can't wrap */
153 | if wordLength >= width {
154 | s += word
155 | }
156 |
157 | s.append(wrapBy)
158 | currentLineWidth = 0
159 | }
160 |
161 | currentLineWidth += wordLength + 1
162 | s += word
163 | s.append(splitBy)
164 | }
165 |
166 | return s
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/Package.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Package.swift
3 | * Copyright (c) 2015 Ben Gollmer.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import PackageDescription
19 |
20 | let package = Package(name: "CommandLine")
21 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/README.md:
--------------------------------------------------------------------------------
1 | # CommandLineKit [](https://travis-ci.org/jatoben/CommandLine)
2 |
3 | A pure Swift library for creating command-line interfaces.
4 |
5 | *Note: CommandLineKit `master` requires Xcode 8 / Swift 3.0. If you're using older versions of Swift, please check out the [earlier releases](https://github.com/jatoben/CommandLine/releases).*
6 |
7 | ## Usage
8 |
9 | CommandLine aims to have a simple and self-explanatory API.
10 |
11 | ```swift
12 | import CommandLineKit
13 |
14 | let cli = CommandLineKit.CommandLine()
15 |
16 | let filePath = StringOption(shortFlag: "f", longFlag: "file", required: true,
17 | helpMessage: "Path to the output file.")
18 | let compress = BoolOption(shortFlag: "c", longFlag: "compress",
19 | helpMessage: "Use data compression.")
20 | let help = BoolOption(shortFlag: "h", longFlag: "help",
21 | helpMessage: "Prints a help message.")
22 | let verbosity = CounterOption(shortFlag: "v", longFlag: "verbose",
23 | helpMessage: "Print verbose messages. Specify multiple times to increase verbosity.")
24 |
25 | cli.addOptions(filePath, compress, help, verbosity)
26 |
27 | do {
28 | try cli.parse()
29 | } catch {
30 | cli.printUsage(error)
31 | exit(EX_USAGE)
32 | }
33 |
34 | print("File path is \(filePath.value!)")
35 | print("Compress is \(compress.value)")
36 | print("Verbosity is \(verbosity.value)")
37 | ```
38 |
39 | See `Option.swift` for additional Option types.
40 |
41 | To use CommandLineKit in your project, add it to your workspace, then add CommandLineKit.framework to the __Build Phases / Link Binary With Libraries__ setting of your target.
42 |
43 | If you are building a command-line tool and need to embed this and other frameworks to it, follow the steps in http://colemancda.github.io/programming/2015/02/12/embedded-swift-frameworks-osx-command-line-tools/ to link Swift frameworks to your command-line tool.
44 |
45 | If you are building a standalone command-line tool, you'll need to add the CommandLineKit source files directly to your target, because Xcode [can't yet build static libraries that contain Swift code](https://github.com/ksm/SwiftInFlux#static-libraries).
46 |
47 |
48 | ## Features
49 |
50 | ### Automatically generated usage messages
51 |
52 | ```
53 | Usage: example [options]
54 | -f, --file:
55 | Path to the output file.
56 | -c, --compress:
57 | Use data compression.
58 | -h, --help:
59 | Prints a help message.
60 | -v, --verbose:
61 | Print verbose messages. Specify multiple times to increase verbosity.
62 | ```
63 |
64 | You can fully customize the usage message by supplying a `formatOutput` function. For example, [Rainbow](https://github.com/onevcat/Rainbow) provides a handy way to generate colorized output:
65 |
66 | ```swift
67 | import Rainbow
68 |
69 | cli.formatOutput = { s, type in
70 | var str: String
71 | switch(type) {
72 | case .Error:
73 | str = s.red.bold
74 | case .OptionFlag:
75 | str = s.green.underline
76 | case .OptionHelp:
77 | str = s.blue
78 | default:
79 | str = s
80 | }
81 |
82 | return cli.defaultFormat(str, type: type)
83 | }
84 | ```
85 |
86 | 
87 |
88 | ### Supports all common flag styles
89 |
90 | These command-lines are equivalent:
91 |
92 | ```bash
93 | $ ./example -c -v -f /path/to/file
94 | $ ./example -cvf /path/to/file
95 | $ ./example -c --verbose --file /path/to/file
96 | $ ./example -cv --file /path/to/file
97 | $ ./example --compress -v --file=/path/to/file
98 | ```
99 |
100 | Option processing can be stopped with '--', [as in getopt(3)](https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html).
101 |
102 | ### Intelligent handling of negative int & float arguments
103 |
104 | This will pass negative 42 to the int option, and negative 3.1419 to the float option:
105 |
106 | ```bash
107 | $ ./example2 -i -42 --float -3.1419
108 | ```
109 |
110 | ### Locale-aware float parsing
111 |
112 | Floats will be handled correctly when in a locale that uses an alternate decimal point character:
113 |
114 | ```bash
115 | $ LC_NUMERIC=sv_SE.UTF-8 ./example2 --float 3,1419
116 | ```
117 |
118 | ### Type-safe Enum options
119 |
120 | ```swift
121 | enum Operation: String {
122 | case create = "c"
123 | case extract = "x"
124 | case list = "l"
125 | case verify = "v"
126 | }
127 |
128 | let cli = CommandLineKit.CommandLine()
129 | let op = EnumOption(shortFlag: "o", longFlag: "operation", required: true,
130 | helpMessage: "File operation - c for create, x for extract, l for list, or v for verify.")
131 | cli.setOptions(op)
132 |
133 | do {
134 | try cli.parse()
135 | } catch {
136 | cli.printUsage(error)
137 | exit(EX_USAGE)
138 | }
139 |
140 | switch op.value {
141 | case Operation.Create:
142 | // Create file
143 |
144 | case Operation.Extract:
145 | // Extract file
146 |
147 | // Remainder of cases
148 | }
149 | ```
150 |
151 | Note: Enums must be initalizable from a String value.
152 |
153 | ### Fully emoji-compliant
154 |
155 | ```bash
156 | $ ./example3 -👍 --👻
157 | ```
158 |
159 | *(please don't actually do this)*
160 |
161 | License
162 | -------
163 | Copyright (c) 2014 Ben Gollmer.
164 |
165 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
166 |
167 | http://www.apache.org/licenses/LICENSE-2.0
168 |
169 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
170 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/Tests/CommandLineKitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | NSHumanReadableCopyright
24 | Copyright © 2014 Ben Gollmer. Licensed under the Apache License, Version 2.0.
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/Tests/CommandLineKitTests/StringExtensionTests.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * StringExtensionTests.swift
3 | * Copyright (c) 2014 Ben Gollmer.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import XCTest
19 | @testable import CommandLineKit
20 | #if os(OSX)
21 | import Darwin
22 | #elseif os(Linux)
23 | import Glibc
24 | #endif
25 |
26 | class StringExtensionTests: XCTestCase {
27 | static var allTests : [(String, (StringExtensionTests) -> () throws -> Void)] {
28 | return [
29 | ("testToDouble", testToDouble),
30 | ("testSplit", testSplit),
31 | ("testPadded", testPadded),
32 | ("testWrapped", testWrapped),
33 | ]
34 | }
35 |
36 | override func setUp() {
37 | /* set locale to "C" to start with '.' as the decimal separator */
38 | setlocale(LC_ALL, "C")
39 | }
40 |
41 | func testToDouble() {
42 | /* Regular ol' double */
43 | let a = "3.14159".toDouble()
44 | XCTAssertEqual(a, 3.14159, "Failed to parse pi as double")
45 |
46 | let b = "-98.23".toDouble()
47 | XCTAssertEqual(b, -98.23, "Failed to parse negative double")
48 |
49 | /* Ints should be parsable as doubles */
50 | let c = "5".toDouble()
51 | XCTAssertEqual(c, 5, "Failed to parse int as double")
52 |
53 | let d = "-2099".toDouble()
54 | XCTAssertEqual(d, -2099, "Failed to parse negative int as double")
55 |
56 |
57 | /* Zero handling */
58 | let e = "0.0".toDouble()
59 | XCTAssertEqual(e, 0, "Failed to parse zero double")
60 |
61 | let f = "0".toDouble()
62 | XCTAssertEqual(f, 0, "Failed to parse zero int as double")
63 |
64 | let g = "0.0000000000000000".toDouble()
65 | XCTAssertEqual(g, 0, "Failed to parse very long zero double")
66 |
67 | let h = "-0.0".toDouble()
68 | XCTAssertEqual(h, 0, "Failed to parse negative zero double")
69 |
70 | let i = "-0".toDouble()
71 | XCTAssertEqual(i, 0, "Failed to parse negative zero int as double")
72 |
73 | let j = "-0.000000000000000".toDouble()
74 | XCTAssertEqual(j, 0, "Failed to parse very long negative zero double")
75 |
76 |
77 | /* Various extraneous chars */
78 | let k = "+42.3".toDouble()
79 | XCTAssertNil(k, "Parsed double with extraneous +")
80 |
81 | let l = " 827.2".toDouble()
82 | XCTAssertNil(l, "Parsed double with extraneous space")
83 |
84 | let m = "283_3".toDouble()
85 | XCTAssertNil(m, "Parsed double with extraneous _")
86 |
87 | let n = "💩".toDouble()
88 | XCTAssertNil(n, "Parsed poo")
89 |
90 | /* Locale handling */
91 | setlocale(LC_NUMERIC, "sv_SE.UTF-8")
92 |
93 | let o = "888,8".toDouble()
94 | XCTAssertEqual(o!, 888.8, "Failed to parse double in alternate locale")
95 |
96 | let p = "888.8".toDouble()
97 | XCTAssertNil(p, "Parsed double in alternate locale with wrong decimal point")
98 |
99 | /* Set locale back so as not to perturb any other tests */
100 | setlocale(LC_NUMERIC, "")
101 | }
102 |
103 | func testSplit() {
104 | let a = "1,2,3".split(by: ",")
105 | XCTAssertEqual(a.count, 3, "Failed to split into correct number of components")
106 |
107 | let b = "123".split(by: ",")
108 | XCTAssertEqual(b.count, 1, "Failed to split when separator not found")
109 |
110 | let c = "".split(by: ",")
111 | XCTAssertEqual(c.count, 0, "Splitting empty string should return empty array")
112 |
113 | let e = "a-b-c-d".split(by: "-", maxSplits: 2)
114 | XCTAssertEqual(e.count, 3, "Failed to limit splits")
115 | XCTAssertEqual(e[0], "a", "Invalid value for split 1")
116 | XCTAssertEqual(e[1], "b", "Invalid value for split 2")
117 | XCTAssertEqual(e[2], "c-d", "Invalid value for last split")
118 | }
119 |
120 | func testPadded() {
121 | let a = "this is a test"
122 |
123 | XCTAssertEqual(a.padded(toWidth: 80).characters.count,
124 | 80, "Failed to pad to correct width")
125 | XCTAssertEqual(a.padded(toWidth: 5).characters.count,
126 | a.characters.count, "Bad padding when pad width is less than string width")
127 | XCTAssertEqual(a.padded(toWidth: -2).characters.count,
128 | a.characters.count, "Bad padding with negative pad width")
129 |
130 | let b = a.padded(toWidth: 80)
131 | let lastBCharIndex = b.index(before: b.endIndex)
132 | XCTAssertEqual(b[lastBCharIndex], " " as Character, "Failed to pad with default character")
133 |
134 | let c = a.padded(toWidth: 80, with: "+")
135 | let lastCCharIndex = c.index(before: b.endIndex)
136 | XCTAssertEqual(c[lastCCharIndex], "+" as Character, "Failed to pad with specified character")
137 | }
138 |
139 | func testWrapped() {
140 | let lipsum = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
141 | for line in lipsum.wrapped(atWidth: 80).split(by: "\n") {
142 | XCTAssertLessThanOrEqual(line.characters.count, 80, "Failed to wrap long line: \(line)")
143 | }
144 |
145 | /* Words longer than the wrap width should not be split */
146 | let longWords = "Lorem ipsum consectetur adipisicing eiusmod tempor incididunt"
147 | let lines = longWords.wrapped(atWidth: 3).split(by: "\n")
148 | XCTAssertEqual(lines.count, 8, "Failed to wrap long words")
149 | for line in lines {
150 | XCTAssertGreaterThan(line.characters.count, 3, "Bad long word wrapping on line: \(line)")
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * LinuxMain.swift
3 | * Copyright (c) 2015 Ben Gollmer.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import XCTest
19 | @testable import CommandLineKitTests
20 |
21 | XCTMain([testCase(CommandLineTests.allTests), testCase(StringExtensionTests.allTests)])
22 |
--------------------------------------------------------------------------------
/XCAssetPacker/CommandLine/install-linux-swift.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -ev
3 | SWIFT_SNAPSHOT="swift-3.0.1-RELEASE"
4 | XCTEST_SNAPSHOT="swift-3.0.1-RELEASE"
5 |
6 | echo "Installing ${SWIFT_SNAPSHOT}..."
7 | if [ ! -f "${SWIFT_SNAPSHOT}-ubuntu14.04.tar.gz" ]; then
8 | curl -s -L -O "https://swift.org/builds/$(echo $SWIFT_SNAPSHOT | tr A-Z a-z)/ubuntu1404/${SWIFT_SNAPSHOT}/${SWIFT_SNAPSHOT}-ubuntu14.04.tar.gz"
9 | fi
10 |
11 | tar -zxf "${SWIFT_SNAPSHOT}-ubuntu14.04.tar.gz"
12 | sudo rm -rf /swift
13 | sudo mv "${SWIFT_SNAPSHOT}-ubuntu14.04" /swift
14 |
15 | # Force the use of the gold linker
16 | # See https://bugs.swift.org/browse/SR-1023 and https://github.com/apple/swift/pull/2609
17 | sudo rm /usr/bin/ld
18 | sudo ln -s /usr/bin/ld.gold /usr/bin/ld
19 |
20 | echo "Installing XCTest..."
21 | if [ ! -f "${XCTEST_SNAPSHOT}.tar.gz" ]; then
22 | curl -s -L -O "https://github.com/apple/swift-corelibs-xctest/archive/${XCTEST_SNAPSHOT}.tar.gz"
23 | fi
24 | tar -zxvf "${XCTEST_SNAPSHOT}.tar.gz"
25 | cd "swift-corelibs-xctest-${XCTEST_SNAPSHOT}"
26 | sudo ./build_script.py --swiftc="/swift/usr/bin/swiftc" --build-dir="/tmp/XCTest_build" --foundation-build-dir="/swift/usr/lib/swift/linux" --library-install-path="/swift/usr/lib/swift/linux" --module-install-path="/swift/usr/lib/swift/linux/x86_64"
27 | cd ..
28 | rm -rf "swift-corelibs-xctest-${XCTEST_SNAPSHOT}"
29 |
--------------------------------------------------------------------------------
/XCAssetPacker/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // XCAssetPacker
4 | //
5 | // Created by Harry Jordan on 16/04/2017.
6 | // Copyright © 2017 Inquisitive Software. All rights reserved.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | import Foundation
22 |
23 |
24 | enum Configuration: String {
25 | case appIcon = "app-icon"
26 | case pattern = "pattern"
27 | case multiplePatterns = "patterns"
28 | case includeImages = "include-images"
29 | case skipImages = "skip-images"
30 | case images = "images"
31 | case filename = "filename"
32 | case idiom = "idiom"
33 | case scale = "scale"
34 | case size = "size"
35 | case screenWidth = "screen-width"
36 | case prerendered = "pre-rendered"
37 | case info = "info"
38 | case base = "base"
39 | case devices = "devices"
40 | case deviceType = "device-type"
41 | case properties = "properties"
42 | case custom = "custom"
43 | case universal = "universal"
44 | case validImageExtensions = "valid-image-extensions"
45 | }
46 |
47 |
48 | enum FileExtension: String {
49 | case imageSet = "imageset"
50 | case appIconSet = "appiconset"
51 | case json = "json"
52 | case assetPackage = "xcassets"
53 | case swift = "swift"
54 | }
55 |
56 |
57 | enum FileName: String {
58 | case appIcon = "AppIcon"
59 | case contents = "Contents.json"
60 | }
61 |
62 |
63 | enum ImageScales: String {
64 | case appIcon = "AppIcon"
65 | case contents = "Contents.json"
66 | }
67 |
68 |
69 | extension Dictionary where Key == String {
70 |
71 | func value(for key: Configuration) -> Value? {
72 | return self[key.rawValue]
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/XCAssetPacker/DeviceIdiom.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DeviceIdiom.swift
3 | // XCAssetPacker
4 | //
5 | // Created by Harry Jordan on 04/09/2017.
6 | // Copyright © 2017 Inquisitive Software. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 |
12 | public enum DeviceIdiom: String {
13 | case watch, iPhone, iPad, iOSMarketing
14 |
15 | static var all: [DeviceIdiom] = [watch, iPhone, iPad, iOSMarketing]
16 |
17 |
18 | init?(_ idiomString: String) {
19 | let idiom = DeviceIdiom.all.first(where: {
20 | $0.idiomString.caseInsensitiveCompare(idiomString) == .orderedSame
21 | })
22 |
23 | if let idiom = idiom {
24 | self = idiom
25 | } else {
26 | return nil
27 | }
28 | }
29 |
30 |
31 | var idiomString: String {
32 | // Keys used for xcasset properties
33 | switch self {
34 | case .watch:
35 | return "watch"
36 |
37 | case .iPhone:
38 | return "iphone"
39 |
40 | case .iPad:
41 | return "ipad"
42 |
43 | case .iOSMarketing:
44 | return "ios-marketing"
45 | }
46 | }
47 |
48 |
49 | var configurationKey: String {
50 | // Keys used to match strings in the configuration .json
51 | return self.rawValue
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/XCAssetPacker/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // XCAssetPacker
4 | //
5 | // Created by Harry Jordan on 23/11/2016.
6 | // Copyright © 2016 Inquisitive Software. All rights reserved.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | import Foundation
22 |
23 |
24 | extension String {
25 |
26 | func isMatchedBy(_ patterns: [String]) -> Bool {
27 | for pattern in patterns {
28 | if isMatchedBy(pattern) {
29 | return true
30 | }
31 | }
32 |
33 | return false
34 | }
35 |
36 |
37 | func isMatchedBy(_ pattern: String) -> Bool {
38 | if let regex = try? NSRegularExpression(pattern: pattern, options: [.caseInsensitive]) {
39 | return regex.numberOfMatches(in: self, options: [], range: self.asNSRange) > 0
40 | }
41 |
42 | return false
43 | }
44 |
45 |
46 | var asNSRange: NSRange {
47 | return NSRange(location: 0, length: (self as NSString).length)
48 | }
49 |
50 | }
51 |
52 |
53 | extension URL {
54 |
55 | func appending(pathComponents: [String]) -> URL {
56 | var url = self
57 |
58 | for pathComponent in pathComponents {
59 | url = url.appendingPathComponent(pathComponent)
60 | }
61 |
62 | return url
63 | }
64 |
65 | }
66 |
67 |
68 | // The MIT License (MIT)
69 | //
70 | // Copyright (c) 2014 Ankur Patel
71 | //
72 | // Permission is hereby granted, free of charge, to any person obtaining a copy
73 | // of this software and associated documentation files (the "Software"), to deal
74 | // in the Software without restriction, including without limitation the rights
75 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
76 | // copies of the Software, and to permit persons to whom the Software is
77 | // furnished to do so, subject to the following conditions:
78 | //
79 | // The above copyright notice and this permission notice shall be included in all
80 | // copies or substantial portions of the Software.
81 | //
82 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
83 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
84 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
85 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
86 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
87 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
88 | // SOFTWARE.
89 | //
90 | // https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift
91 |
92 |
93 | extension Dictionary {
94 |
95 | mutating func merge(dict: [K: V]) {
96 | for (k, v) in dict {
97 | self.updateValue(v as! Value, forKey: k as! Key)
98 | }
99 | }
100 |
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/XCAssetPacker/ImageProperties.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageProperties.swift
3 | // XCAssetPacker
4 | //
5 | // Created by Harry Jordan on 23/11/2016.
6 | // Copyright © 2016 Inquisitive Software. All rights reserved.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | import Foundation
22 |
23 |
24 | struct ImageProperties {
25 | let name: String
26 | let type: ImageType
27 | let scale: ImageScale
28 | let prerendered: Bool?
29 | let configuration: [String: Any]
30 |
31 |
32 | init(from fileName: String, isAppIcon: Bool, configuration: [String: Any]) {
33 | let sourceImageName = (fileName as NSString).deletingPathExtension
34 |
35 | var adaptedName: String = sourceImageName
36 | var type: ImageType = .universal
37 | var scale: ImageScale = .universal
38 |
39 | // Look for an image scale e.g. @2x or @3x
40 | if let match = ImageProperties.scaleRegularExpression.firstMatch(in: adaptedName, range: adaptedName.asNSRange), match.numberOfRanges >= 2 {
41 | let rangeOfDigits = match.range(at: 1)
42 | let digitString = (adaptedName as NSString).substring(with: rangeOfDigits)
43 |
44 | if let scaleNumber = Int(digitString) {
45 | adaptedName = (sourceImageName as NSString).substring(to: match.range.location)
46 | scale = .scale(scaleNumber)
47 | }
48 | }
49 |
50 | // Parse standardized image extensions
51 | for (suffix, detectedImageType) in ImageProperties.typesForSuffixes {
52 | if let range = adaptedName.range(of: suffix, options: [.anchored, .backwards]) {
53 | type = detectedImageType
54 | adaptedName = sourceImageName.substring(to: range.lowerBound)
55 | break
56 | }
57 | }
58 |
59 | if isAppIcon {
60 | if let appIcon = configuration.value(for: .appIcon) as? [String: Any],
61 | let prerendered = appIcon.value(for: .prerendered) as? Bool {
62 | self.prerendered = prerendered
63 | } else {
64 | // Default to prerendered
65 | self.prerendered = true
66 | }
67 | } else {
68 | self.prerendered = nil
69 | }
70 |
71 | self.name = adaptedName
72 | self.type = type
73 | self.scale = scale
74 | self.configuration = configuration
75 | }
76 |
77 |
78 | static var scaleRegularExpression: NSRegularExpression = {
79 | let regularExpression = try! NSRegularExpression(pattern: "@(\\d)[xX]$", options: [])
80 | return regularExpression
81 | }()
82 |
83 |
84 | static var typesForSuffixes: [(String, ImageType)] {
85 | return ImageType.all.flatMap { (type) in
86 | if let suffix = type.suffix {
87 | return (suffix, type)
88 | } else {
89 | return nil
90 | }
91 | }
92 | }
93 |
94 |
95 | var scaleString: String? {
96 | switch type {
97 | case .watch, .watch38, .watch42:
98 | return "2x"
99 |
100 | default:
101 | if let scaleString = scale.scaleString {
102 | // See if the scale is identifiable from the filename
103 | return scaleString
104 | } else if let base = configuration.value(for: .base) as? [String: Any],
105 | let scaleString = base.value(for: .scale) as? String {
106 | // Look for a base scale in the configuration file
107 | return scaleString
108 | } else {
109 | // Otherwise default to 1x
110 | return "1x"
111 | }
112 | }
113 | }
114 |
115 |
116 | var idiom: String? {
117 | if let idiom = type.idiom {
118 | return idiom
119 | }
120 |
121 | if let base = configuration.value(for: .base) as? [String: Any],
122 | let idiomString = base.value(for: .idiom) as? String,
123 | let deviceIdiom = DeviceIdiom(idiomString) {
124 | return deviceIdiom.idiomString
125 | }
126 |
127 | return Configuration.universal.rawValue
128 | }
129 |
130 | }
131 |
132 |
133 | enum ImageType {
134 | case watch, watch38, watch42, universal, notification, settings, spotlight, iPhoneAppIcon, iPadAppIcon, iPadProAppIcon, iTunesPreview
135 |
136 |
137 | static var all: [ImageType] {
138 | return [watch, watch38, watch42, universal, notification, settings, spotlight, iPhoneAppIcon, iPadAppIcon, iPadProAppIcon, iTunesPreview]
139 | }
140 |
141 |
142 | var idiom: String? {
143 | let idiom: DeviceIdiom?
144 |
145 | switch self {
146 | case .watch, .watch38, .watch42:
147 | idiom = .watch
148 |
149 | case .iPhoneAppIcon:
150 | idiom = .iPhone
151 |
152 | case .iPadAppIcon, .iPadProAppIcon:
153 | idiom = .iPad
154 |
155 | case .iTunesPreview:
156 | idiom = .iOSMarketing
157 |
158 | default:
159 | idiom = nil
160 | }
161 |
162 | return idiom?.idiomString
163 | }
164 |
165 |
166 | var screenWidth: String? {
167 | switch self {
168 | case .watch:
169 | return nil
170 |
171 | case .watch38:
172 | return "<=145"
173 |
174 | case .watch42:
175 | return ">145"
176 |
177 | default:
178 | return nil
179 | }
180 | }
181 |
182 |
183 | var deviceType: String {
184 | // Used for matching with the configuration file
185 | switch self {
186 | case .watch, .watch38, .watch42:
187 | return DeviceIdiom.watch.configurationKey
188 |
189 | case .iPhoneAppIcon:
190 | return DeviceIdiom.iPhone.configurationKey
191 |
192 | case .iPadAppIcon, .iPadProAppIcon:
193 | return DeviceIdiom.iPad.configurationKey
194 |
195 | default:
196 | return "universal"
197 | }
198 | }
199 |
200 |
201 | var suffix: String? {
202 | switch self {
203 | // Watch types
204 | case .watch:
205 | return nil
206 |
207 | case .watch42:
208 | return "-42"
209 |
210 | case .watch38:
211 | return "-38"
212 |
213 | case .notification:
214 | return "-20"
215 |
216 | case .settings:
217 | return "-29"
218 |
219 | case .spotlight:
220 | return "-40"
221 |
222 | case .iPhoneAppIcon:
223 | return "-60"
224 |
225 | case .iPadAppIcon:
226 | return "-76"
227 |
228 | case .iPadProAppIcon:
229 | return "-83.5"
230 |
231 | case .iTunesPreview:
232 | return "-1024"
233 |
234 | case .universal:
235 | return nil
236 | }
237 | }
238 |
239 |
240 | var sizeString: String? {
241 | switch self {
242 | case .notification:
243 | return "20x20"
244 |
245 | case .settings:
246 | return "29x29"
247 |
248 | case .spotlight:
249 | return "40x40"
250 |
251 | case .iPhoneAppIcon:
252 | return "60x60"
253 |
254 | case .iPadAppIcon:
255 | return "76x76"
256 |
257 | case .iPadProAppIcon:
258 | return "83.5x83.5"
259 |
260 | case .iTunesPreview:
261 | return "1024x1024"
262 |
263 | default:
264 | return nil
265 | }
266 | }
267 |
268 | }
269 |
270 |
271 | enum ImageScale {
272 | case scale(Int), universal
273 |
274 | var scaleString: String? {
275 | switch self {
276 | case .scale(let scale):
277 | return "\(scale)x"
278 |
279 | case .universal:
280 | return nil
281 | }
282 | }
283 | }
284 |
285 |
--------------------------------------------------------------------------------
/XCAssetPacker/SwiftGeneration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftGeneration.swift
3 | // XCAssetPacker
4 | //
5 | // Created by Harry Jordan on 23/11/2016.
6 | // Copyright © 2016 Inquisitive Software. All rights reserved.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | import Foundation
22 |
23 |
24 | enum SwiftGenerationError: Error {
25 | case duplicateProperty(name: String, originalFileName: String)
26 | }
27 |
28 |
29 |
30 | enum SwiftTarget {
31 | case cocoa, iOS, watch
32 |
33 | var libraryName: String {
34 | switch self {
35 | case .cocoa:
36 | return "Cocoa"
37 |
38 | case .iOS:
39 | return "UIKit"
40 |
41 | case .watch:
42 | return "ClockKit"
43 | }
44 | }
45 |
46 | var imageClassName: String {
47 | switch self {
48 | case .cocoa:
49 | return "NSImage"
50 |
51 | case .iOS, .watch:
52 | return "UIImage"
53 | }
54 | }
55 |
56 | }
57 |
58 |
59 | extension AssetCatalogGenerator {
60 |
61 | func swiftCode(forTarget target: SwiftTarget, rootNode node: Node) throws -> String {
62 | let result = try generateSwiftCode(forTarget: target, node: node, depth: 0)
63 |
64 | return header(forTarget: target) + result.code
65 | }
66 |
67 |
68 | func generateSwiftCode(forTarget target: SwiftTarget, node: Node, depth: Int) throws -> (code: String, propertyNames: [String]) {
69 | // Code Indents
70 | let topLevel = String(repeating: " ", count: depth)
71 | let firstIndent = String(repeating: " ", count: depth + 1)
72 | let secondIndent = String(repeating: " ", count: depth + 2)
73 |
74 | // Group name
75 | let structName: String
76 | let groupPropertyName: String?
77 |
78 | if depth == 0 {
79 | structName = "ImageAssetCatalog"
80 | groupPropertyName = nil
81 | } else {
82 | structName = "ImageAssetCatalog" + node.name
83 |
84 | let groupName = node.name.llamaCase()
85 | groupPropertyName = groupName
86 | }
87 |
88 | var generatedCode = ""
89 | var propertyNames: [String] = []
90 |
91 | if let groupPropertyName = groupPropertyName {
92 | // Add a var to the struct to accesss the images in this group
93 | generatedCode += topLevel + "var \(groupPropertyName) = \(structName)()\n"
94 | }
95 |
96 | generatedCode += topLevel + "struct \(structName) {\n"
97 |
98 | if depth == 0 {
99 | generatedCode += firstIndent + "private func image(named name: String) -> \(target.imageClassName) {\n" +
100 | secondIndent + "// Force unwrapping here as it seems reasonable to assume the image exists\n" +
101 | secondIndent + "// since the .xcassets package was generated in tandem with this code\n" +
102 | secondIndent + "return \(target.imageClassName)(named: name)!\n" +
103 | firstIndent + "}\n\n"
104 | }
105 |
106 | // Sort using the numeric option, so that numbered image sets appear in a logical order
107 | let childNodes = node.children.sorted(by: { (firstNode, secondNode) -> Bool in
108 | let firstProperty = firstNode.swiftPropertyName(withinGroup: groupPropertyName)
109 | let secondProperty = secondNode.swiftPropertyName(withinGroup: groupPropertyName)
110 |
111 | let comparison = firstProperty.compare(secondProperty, options: [.caseInsensitive, .numeric, .widthInsensitive, .forcedOrdering], locale: Locale.current)
112 | return comparison == .orderedAscending
113 | })
114 |
115 | for child in childNodes where child.isDirectory && child.isImageSet && !child.isAppIcon {
116 | let propertyName = child.swiftPropertyName(withinGroup: groupPropertyName)
117 |
118 | if propertyNames.contains(propertyName) {
119 | throw SwiftGenerationError.duplicateProperty(name: propertyName, originalFileName: child.name)
120 | } else {
121 | propertyNames.append(propertyName)
122 |
123 | generatedCode += firstIndent + "var \(propertyName): \(target.imageClassName) { return image(named: \"\(child.swiftCatalogName)\") }\n"
124 | }
125 | }
126 |
127 | for child in node.children where child.isDirectory && !child.isImageSet && !child.isAppIcon {
128 | let result = try self.generateSwiftCode(forTarget: target, node: child, depth: depth + 1)
129 | generatedCode += result.code
130 |
131 | propertyNames.append(contentsOf: result.propertyNames)
132 | }
133 |
134 | generatedCode += topLevel + "}\n\n"
135 |
136 | return (generatedCode, propertyNames)
137 | }
138 |
139 |
140 | func header(forTarget target: SwiftTarget) -> String {
141 | let dateFormatter = DateFormatter()
142 | dateFormatter.dateFormat = "YYYY-MM-dd"
143 |
144 | let dateString = dateFormatter.string(from: Date())
145 |
146 | let header = "// *********************************************************\n" +
147 | "// *********************************************************\n" +
148 | "// ***\n" +
149 | "// *** DO NOT EDIT\n" +
150 | "// *** This file is machine-generated by XCAssetPacker\n" +
151 | "// *** and is intended to be overwritten regularly\n" +
152 | "// ***\n" +
153 | "// *** Last updated: \(dateString)\n" +
154 | "// ***\n" +
155 | "// *********************************************************\n" +
156 | "// *********************************************************\n\n" +
157 | "import \(target.libraryName)\n\n" +
158 | "extension \(target.imageClassName) {\n" +
159 | " static let assets = ImageAssetCatalog()\n" +
160 | " static let r = ImageAssetCatalog()\n" +
161 | "}\n\n"
162 |
163 | return header
164 | }
165 |
166 | }
167 |
168 |
169 | extension Node {
170 |
171 | func swiftPropertyName(withinGroup groupName: String?) -> String {
172 | var name = swiftCatalogName
173 |
174 | if let groupName = groupName,
175 | let matchingRange = name.range(of: groupName, options: [.anchored, .caseInsensitive]) {
176 | let uniqueSubstring = name.substring(from: matchingRange.upperBound)
177 | name = uniqueSubstring
178 | }
179 |
180 | name = name.llamaCase()
181 |
182 | // Append a prefix as digits aren't allowed as the fist character of a variable
183 | if let firstCharacter = name.unicodeScalars.first, CharacterSet.decimalDigits.contains(firstCharacter) {
184 | let prefix = "i"
185 | name = prefix + name
186 | }
187 |
188 | return name
189 | }
190 |
191 |
192 | var swiftCatalogName: String {
193 | return (name as NSString).deletingPathExtension
194 | }
195 |
196 | }
197 |
198 |
199 | extension String {
200 | // Adapted from: https://gist.github.com/AmitaiB/bbfcba3a21411ee6d3f972320bcd1ecd
201 |
202 | func llamaCase() -> String {
203 | //
204 | var adaptedText: String = ""
205 | var isFirstLetter = true
206 |
207 | self.enumerateSubstrings(in: startIndex.. String in
146 | return combined + "/" + pathComponent
147 | }
148 |
149 | print("Created assets package \(lastPathComponents) containing \(log.numberOfImages) images")
150 | exit(EXIT_SUCCESS)
151 | } catch let error as AssetCatalogError {
152 | switch error {
153 | case .ioError(let description):
154 | print(description)
155 | exit(EX_IOERR)
156 | }
157 | } catch let error as SwiftGenerationError {
158 | switch error {
159 | case .duplicateProperty(let name, originalFileName: let originalFileName):
160 | print("Conflicting property '\(name)' for \(originalFileName)")
161 | print("Images need to have distinct llama case representations")
162 | exit(EX_IOERR)
163 | }
164 | } catch let error {
165 | print("Unexpected error: \(String(describing: error))")
166 | exit(EX_IOERR)
167 | }
168 |
--------------------------------------------------------------------------------