172 Commits
Author SHA1 Message Date
Josh Abernathy 37cd028730 Merge pull request #172 from Squirrel/truncate-logs
Truncate logs
2016-06-03 12:43:44 -04:00
joshaber cc8993e6e7 Bump up the max length. 2016-06-03 09:55:05 -04:00
joshaber a0b35f490b Revert "Move back to the beginning of the file before writing."
This reverts commit ed0614d8cf.
2016-06-02 12:32:29 -04:00
joshaber ed0614d8cf Move back to the beginning of the file before writing. 2016-06-02 12:31:03 -04:00
joshaber ea70eb937a Truncate log files. 2016-06-02 12:27:21 -04:00
joshaber b5ecff7e03 Use the log paths instead of constructing them manually. 2016-06-02 12:27:11 -04:00
joshaber 8589cbedbb Expose the log paths. 2016-06-02 12:27:02 -04:00
Josh Abernathy edc604bfec Merge pull request #171 from Squirrel/stop-redownloading
Conditionally download updates.
2016-06-02 10:13:22 -04:00
Keith Duncan 8995e0faeb Merge pull request #169 from Squirrel/use-cache
Use the Caches directory instead of Application Support.
2016-06-02 16:07:17 +02:00
joshaber 67a68bef8c 🍩 need this change 2016-06-01 14:26:06 -04:00
joshaber 7c4b43d2d1 Conditionally download the update. 2016-06-01 14:20:04 -04:00
Josh Abernathy 694f96abec More words.
Fixes #120.
2016-06-01 13:49:01 -04:00
joshaber 369854b103 Update specs 2016-06-01 13:12:24 -04:00
joshaber 104ebb9442 s/an/a 2016-06-01 12:59:49 -04:00
joshaber e1f56bfdc6 Use the Caches directory instead of Application Support. 2016-06-01 12:55:24 -04:00
Keith Duncan 4a50411246 Merge pull request #165 from adam-lynch/patch-1
README: removing trailing comma from JSON format
2016-02-22 10:06:24 +11:00
Adam Lynch fc3ce8158c README: removing trailing comma from JSON format 2016-02-21 22:54:01 +00:00
Josh Abernathy 6e1e11809e Merge pull request #156 from Squirrel/dates
Fix parsing of ISO 8601 dates
2015-11-09 13:25:16 -05:00
Matt Diephouse 9d67b82d5c Use the correct day specifier
`DD` is day of year; `dd` is day of month.
2015-11-09 12:58:40 -05:00
Matt Diephouse 09a3b74f93 Test the dates are correct 2015-11-09 12:57:41 -05:00
Matt Diephouse c108f4aac4 Merge pull request #154 from Squirrel/fix-ci
Fix CI
2015-10-26 17:43:39 -04:00
joshaber 0ac595efd9 I am dissappoint, Travis 2015-10-26 17:25:51 -04:00
joshaber ce1b59c1cf Revert "Smore random sleeps"
This reverts commit 2dea99045d.
2015-10-26 17:17:55 -04:00
joshaber f7438e91b3 Revert "More sleeping!"
This reverts commit 656d2cdd29.
2015-10-26 17:17:46 -04:00
joshaber 656d2cdd29 More sleeping! 2015-10-26 17:08:03 -04:00
joshaber d8a244dd1a Try Xcode 7.1 for funsies. 2015-10-26 16:58:21 -04:00
joshaber 2dea99045d Smore random sleeps 2015-10-26 16:56:28 -04:00
joshaber 483eb38d73 Resource rules were deprecated. 2015-10-26 16:55:30 -04:00
joshaber 475c50a8e3 🔥 mdeep-codesign
It hasn’t been needed for a while.
2015-10-26 16:51:37 -04:00
joshaber 4384ccb485 I dunno let's try waiting. 2015-10-26 16:46:29 -04:00
joshaber 4b4bb7c87c Stop tailing 2015-10-26 16:36:46 -04:00
joshaber cd6ccb9c7b Try just one test. 2015-10-26 16:27:11 -04:00
joshaber 0c91d7fe9c Don't use async anymore. 2015-10-26 16:27:06 -04:00
joshaber 0d8fe0f642 LOL 2015-10-26 16:13:15 -04:00
joshaber b6f4e70731 Try an async. 2015-10-26 16:09:25 -04:00
joshaber efd944e337 Revert "can u not"
This reverts commit 5bfd32eeae.
2015-10-26 16:02:03 -04:00
joshaber cc86db04e2 Standardize on our longer timeout. 2015-10-26 16:01:45 -04:00
joshaber c9ce161632 Up the timeout. 2015-10-26 14:08:08 -04:00
joshaber f924fc3023 Make sure we don't use automatic termination. 2015-10-26 13:58:19 -04:00
joshaber 5bfd32eeae can u not 2015-10-26 13:26:54 -04:00
joshaber 7c365d304f Ugh spelling. 2015-10-26 13:06:31 -04:00
joshaber a6a782aefb Bigger timeout? 2015-10-26 12:59:31 -04:00
joshaber aa72c42c3b Setup some certs. 2015-10-26 12:21:33 -04:00
joshaber bee2be5dfb Revert "🔥 Deep code sign."
This reverts commit d0c932a90d.
2015-10-26 11:58:05 -04:00
joshaber 9bcc86be72 Update Travis again. 2015-10-26 11:42:43 -04:00
joshaber d0c932a90d 🔥 Deep code sign.
It’s been unnecessary for a while now, afaik. /cc @keithduncan
2015-10-26 11:41:40 -04:00
joshaber 4a0aa59d25 We really don't care about app extensions. 2015-10-26 11:40:49 -04:00
joshaber 70a838c834 Use Travis. 2015-10-23 16:52:54 -04:00
joshaber 19dc11c735 Fix the tests. 2015-10-23 16:52:50 -04:00
Matt Diephouse 87e854e8d4 Merge pull request #153 from Squirrel/xcode-7
Xcode 7 support
2015-10-23 10:45:12 -04:00
joshaber 5640bbe863 --regret 2015-10-23 09:49:49 -04:00
joshaber 843ee9fa22 Revert "Update all our references to RAC files."
This reverts commit 0026cef7bf.
2015-10-23 09:44:20 -04:00
joshaber 95ce084ddd Revert "Go with the swift2 branch of RAC."
This reverts commit 2cc8a7d4ab.
2015-10-23 09:44:12 -04:00
joshaber ed92f6aad2 Revert "Bleh."
This reverts commit 56f52ccfe4.
2015-10-23 09:44:02 -04:00
joshaber 56f52ccfe4 Bleh. 2015-10-22 17:19:17 -04:00
joshaber 2cc8a7d4ab Go with the swift2 branch of RAC. 2015-10-22 17:07:23 -04:00
joshaber 0026cef7bf Update all our references to RAC files. 2015-10-22 17:03:34 -04:00
joshaber f0fee4a4e8 ++RAC submodule 2015-10-22 16:41:45 -04:00
joshaber 1898bbde62 ++more things 2015-10-22 16:40:20 -04:00
joshaber 031a7cd850 ++everything 2015-10-22 16:31:59 -04:00
joshaber 27f7777ba5 Hi Xcode 7. 2015-10-22 16:17:57 -04:00
Matt Diephouse 8caa2fa200 Merge pull request #152 from Squirrel/fix-pruning
Fix pruning
2015-09-22 10:40:54 -05:00
joshaber 2fe45e940f Just use a method. 2015-09-22 00:21:23 +01:00
joshaber e50720470c Don't replay, that's crazy.
If we replay, then we don’t ever prune after the first subscription. We
just keep replaying the previous results.

Fixes https://github.com/atom/atom/issues/7061.
2015-09-21 00:17:11 +01:00
joshaber cebf4a85d6 Failing test. 2015-09-21 00:14:25 +01:00
joshaber 5f96d1e565 Allow tests to specify the number of update requests. 2015-09-21 00:14:08 +01:00
joshaber 1f3e0ccbe5 Verify that we have updates. 2015-09-21 00:10:30 +01:00
Keith Duncan 6252f3dbda Merge pull request #149 from Squirrel/renames
Renames
2015-06-29 17:09:59 +10:00
joshaber 1e71daa4f7 Merge branch 'renames-rebase' into renames
Conflicts:
	Squirrel/SQRLInstaller.m
2015-06-23 15:32:15 -04:00
joshaber 8eb2517d6b Do the rename first. 2015-06-23 15:30:58 -04:00
joshaber 46e044726f Do the rename first. 2015-06-23 14:10:39 -04:00
joshaber b30ee65933 Be more explicit. 2015-06-22 11:41:32 -04:00
joshaber ae89c0a1f6 Be more explicit. 2015-06-22 11:24:24 -04:00
joshaber 54f765b19e Naming and docs. 2015-06-19 15:30:33 -04:00
joshaber d8a1185c6b Let the abort use the old request. 2015-06-19 15:30:27 -04:00
joshaber dbf430683f Fix the tests. 2015-06-19 15:30:21 -04:00
joshaber d0634fc8e6 Naming and docs. 2015-06-19 13:48:31 -04:00
joshaber 178648f373 Let the abort use the old request. 2015-06-19 12:47:03 -04:00
joshaber 3a4428cfb3 Fix the tests. 2015-06-19 12:35:28 -04:00
joshaber dab5bf2892 Merge branch 'renames-rebase' into renames
Conflicts:
	Squirrel/SQRLInstaller.m
2015-06-19 12:31:46 -04:00
joshaber e3aa7a6767 Only rename if needed. 2015-06-19 12:21:42 -04:00
joshaber 0c8394f6f4 Rename after moving. 2015-06-19 12:08:55 -04:00
joshaber 6779322eea Deliver an updated request. 2015-06-19 11:00:07 -04:00
joshaber 5d8ffc9070 Use -installItemToURL:fromURL:. 2015-06-18 16:23:51 -04:00
joshaber 72345d4c18 Serialize whether we're allowed to rename. 2015-06-18 15:58:55 -04:00
joshaber 52a6dc2fd2 More logging. 2015-06-18 15:28:13 -04:00
joshaber 5b05c23877 Only do the dance when installing. 2015-06-18 15:18:47 -04:00
joshaber 81c0841201 Logging. 2015-06-18 14:33:09 -04:00
joshaber 747e183b98 Check the bundle ID at our new destination. 2015-06-18 14:10:03 -04:00
joshaber 62a39671fc Early exits. 2015-06-18 14:09:57 -04:00
joshaber 3be9c89f49 Use the source's name as the new name. 2015-06-18 14:09:52 -04:00
joshaber ceb4f34827 RAC em up. 2015-06-18 14:09:46 -04:00
joshaber 22e785a637 Try the dumb guy route first. 2015-06-18 14:09:41 -04:00
joshaber 221519e3ad Check the bundle ID at our new destination. 2015-06-18 13:58:38 -04:00
joshaber 7faed9ec18 Early exits. 2015-06-18 13:58:29 -04:00
joshaber c74ecf9c07 Use the source's name as the new name. 2015-06-18 13:47:47 -04:00
joshaber 04233f8f7c RAC em up. 2015-06-18 13:34:27 -04:00
joshaber 378e3891bf Try the dumb guy route first. 2015-06-18 12:27:59 -04:00
Justin Spahr-Summers 9e040347f5 Merge pull request #145 from Squirrel/xcode6.3
Upgrade dependencies for Xcode 6.3
2015-04-09 16:06:29 -07:00
Justin Spahr-Summers c99ce7dfbb Upgrade dependencies for Xcode 6.3 2015-04-09 14:59:58 -07:00
Justin Spahr-Summers 6b017d5d3f Fix call to superclass method that doesn't exist
Not sure how this ever worked.
2015-04-09 14:56:04 -07:00
Justin Spahr-Summers b1f4ecf615 Merge pull request #143 from Squirrel/quote-paths-when-signing
Quote the paths passed to otool.
2015-02-12 12:15:42 -08:00
Rob Rix fd29bc392f Quote the paths passed to otool.
We pass in a path which could contain spaces, so we need to quote it.
2015-02-12 10:02:32 -05:00
Justin Spahr-Summers 61b5ceb1cb Merge pull request #142 from Squirrel/pacify-xcode
Pacify Xcode
2015-01-16 13:50:10 -08:00
joshaber 38a8914b55 OK Computer 2015-01-16 15:06:06 -05:00
joshaber ede35f29d8 ++xcconfigs 2015-01-16 15:05:50 -05:00
Justin Spahr-Summers 7e8abd13c4 Merge pull request #141 from Squirrel/keithduncan-patch-1
Separate the update available and install instructions
2015-01-15 12:21:37 -08:00
Keith Duncan d776817d8d More tweaks 2015-01-15 12:18:34 -08:00
Keith Duncan 82d79b65c3 Tweak wording 2015-01-15 11:40:26 -08:00
Keith Duncan 8cf49c6fef Separate the update available and install instructions 2015-01-14 14:32:40 -08:00
Justin Spahr-Summers caba5b81af Merge pull request #140 from Squirrel/sign-shipit
Let Xcode code sign ShipIt.
2015-01-10 10:01:34 -08:00
joshaber 98efd568df Let Xcode code sign ShipIt. 2015-01-09 17:58:31 -08:00
Rob Rix 0e729b3725 Merge pull request #139 from Squirrel/carthage-0.5
Migrate to Carthage 0.5
2014-12-30 02:07:23 -05:00
Justin Spahr-Summers 190ac7a2b0 Bump Cartfile 2014-12-29 21:13:42 -08:00
Justin Spahr-Summers 7e91d04b28 Use a Cartfile.private, loosen version constraints 2014-12-29 16:25:54 -08:00
Justin Spahr-Summers c43df8037b Update to Carthage 0.5 directory structure 2014-12-29 16:24:28 -08:00
Matt Diephouse 5471b65a4a Merge pull request #136 from Squirrel/bump-rac
Bump Carthage dependencies
2014-12-08 13:36:12 -05:00
Justin Spahr-Summers 37d3b3f802 Add extobjc header paths to Squirrel target 2014-12-08 10:26:24 -08:00
Justin Spahr-Summers bd9abf504d Bump Carthage dependencies (particularly RAC)
Hopefully resolves #118.
2014-12-08 10:17:14 -08:00
Keith Duncan f415391772 Merge pull request #135 from Squirrel/skip-cstemp
Don’t attempt to sign .cstemp files
2014-12-05 21:12:14 +00:00
Rob Rix c29fee075d Delete .cstemp files just prior to codesigning. 2014-12-05 14:40:21 -05:00
Rob Rix bcd5433733 Revert "Don’t attempt to sign .cstemp files"
This reverts commit c0df5b1d57.
2014-12-05 14:36:14 -05:00
Rob Rix c0df5b1d57 Don’t attempt to sign .cstemp files 2014-12-03 11:12:14 -05:00
Justin Spahr-Summers f61a35ab42 Merge pull request #133 from Squirrel/cartfile
Use Carthage for managing submodules
2014-11-21 15:39:03 -08:00
Justin Spahr-Summers 0575de80c6 Use Carthage for managing submodules 2014-11-21 15:36:02 -08:00
Josh Abernathy 2a60c9c0f3 Merge pull request #132 from Squirrel/xcode6
Xcode 6.1 support
2014-11-07 14:45:51 -05:00
Justin Spahr-Summers d9fe18f95e Actually wait for the backup to be restored :( 2014-11-07 11:33:38 -08:00
Justin Spahr-Summers c7ea0aedb8 Always create the directory for test log files 2014-11-07 11:19:36 -08:00
Justin Spahr-Summers f340c9cb41 Remove deprecated Debug key for launchd.plist 2014-11-07 11:09:22 -08:00
Justin Spahr-Summers 8babde1e71 Fix ShipIt job label for tests 2014-11-07 11:09:06 -08:00
Justin Spahr-Summers e5685ac806 ++RAC 2014-11-06 13:46:14 -08:00
Justin Spahr-Summers 7597115f53 Xcode lulz 2014-11-06 13:44:33 -08:00
Justin Spahr-Summers 8a4a52fb2c For “long delay” test, wait longer than the delay 2014-11-05 12:03:28 -08:00
Justin Spahr-Summers 775afe32c9 Move away from afterEach for expectations
The ordering between multiple afterEach blocks isn’t guaranteed, so
just run any expectations inline.
2014-11-05 12:01:42 -08:00
Justin Spahr-Summers c4d487ea41 Fix test bundle lookup
We can’t use self.class, because this is being defined in a category on
QuickSpec.
2014-11-05 11:53:17 -08:00
Justin Spahr-Summers 23d4e3e3ce Take ownership of the installed bundle itself too 2014-11-05 11:31:56 -08:00
Justin Spahr-Summers 3e6d0bf55c Fix compilation error in QuickSpec+SQRLFixtures 2014-11-04 16:10:19 -08:00
Justin Spahr-Summers 446ebb4501 ++RAC for Quick 2014-11-04 16:09:01 -08:00
Justin Spahr-Summers 656f742bee Migrate to new QuickConfiguration style 2014-11-04 15:45:02 -08:00
Justin Spahr-Summers f91f53c545 ++Quick 2014-11-04 15:18:23 -08:00
Justin Spahr-Summers 4a8004be83 Use undocumented withTimeout() instead of sleeping 2014-10-29 12:00:38 -07:00
Justin Spahr-Summers 970343b9ee Increase timeouts for test app termination 2014-10-28 16:04:13 -07:00
Justin Spahr-Summers 70dc382f8d Fix missing symbols, bundle ID failures, etc. 2014-10-28 15:56:43 -07:00
Justin Spahr-Summers c53a20d4de Finish upgrading to Nimble matcher syntax 2014-10-28 15:25:52 -07:00
Justin Spahr-Summers 3a462922f4 Refactor SQRLTestCase into a QuickSpec category 2014-10-28 13:35:45 -07:00
Justin Spahr-Summers 38840a492e Restore some imports I erroneously removed 2014-10-28 13:22:46 -07:00
Justin Spahr-Summers 70ace5c15b WIP migrate to Quick and Nimble spec formats 2014-10-28 13:10:27 -07:00
Justin Spahr-Summers 6ef1b62d44 Find libextobjc files in RAC for testing 2014-10-28 13:04:03 -07:00
Justin Spahr-Summers 3b9e8e6243 The Test config trolls again 2014-10-28 12:59:38 -07:00
Justin Spahr-Summers 21ffa5a45a Import Nimble and Quick errrrrywhere 2014-10-28 12:48:26 -07:00
Justin Spahr-Summers 55e4c5c42e Add Quick and Nimble to test target 2014-10-28 12:45:47 -07:00
Justin Spahr-Summers 38cd714fd2 Manually import/link everything ShipIt depends on
These have to be statically built into the ShipIt, since (by contrast)
dynamic frameworks could disappear out from under it during the update
process.
2014-10-28 12:42:22 -07:00
Justin Spahr-Summers dd69adc9ff Bump deployment target of tests 2014-10-28 12:30:50 -07:00
Justin Spahr-Summers cb07313ca7 Fix compilation of Squirrel source files 2014-10-28 12:30:44 -07:00
Justin Spahr-Summers ef930ca242 Update to jspahrsummers/objc-build-scripts@a54782 2014-10-28 12:29:02 -07:00
Justin Spahr-Summers f30b68945c Just generally fix a bunch of things in the project 2014-10-28 12:27:44 -07:00
Justin Spahr-Summers 31c0abff54 Fix RAC reference, 🔥 Specta and Expecta 2014-10-28 12:15:24 -07:00
Justin Spahr-Summers 4ca24da5ea ++MTL, ++RAC 2014-10-28 12:12:59 -07:00
Justin Spahr-Summers 43a7614322 Merge branch 'master' into xcode6 2014-10-28 12:12:30 -07:00
Keith Duncan 453b8697f9 Merge pull request #130 from Squirrel/timestamp-none
Don't use a timestamp for non-release builds
2014-09-06 06:55:36 +02:00
Matt Diephouse 693d513354 Add a timestamp argument instead 2014-09-05 14:57:45 -04:00
Matt Diephouse 9488a4cd12 Don't use a timestamp for release builds 2014-09-04 13:40:40 -04:00
Josh Abernathy a9ea214d11 Merge pull request #129 from Squirrel/resolve-top-level-symlinks
Resolve the top level symlink
2014-09-02 17:07:12 +02:00
Keith Duncan 6d91340ffa Resolve the top level symlink
When archiving uninstalled products component paths are a symlink to another dir.
2014-09-02 17:03:58 +02:00
Alan Rogers e8851b59bc Merge pull request #128 from robb/patch-1
Update Mantle link
2014-09-02 23:36:02 +10:00
Robert Böhnke 9539744417 Update Mantle link 2014-09-02 14:10:11 +02:00
Keith Duncan 19b011bee5 Merge pull request #127 from Squirrel/update-deep-codesign
🔥 Resource rules 🔥
2014-09-02 10:24:20 +02:00
joshaber 6ca74dc2c7 🔥 Resource rules 🔥 2014-09-02 10:20:47 +02:00
Justin Spahr-Summers cb2d4ecfd2 Merge pull request #126 from robb/patch-1
Fix anchor in README
2014-08-28 10:43:47 -07:00
Robert Böhnke 81c8b56e52 Fix anchor in README 2014-08-28 19:33:28 +02:00
Justin Spahr-Summers c245afac29 Don't automatically build unit tests 2014-07-16 11:39:57 -07:00
Justin Spahr-Summers 106e95b41f ++MTL and ++RAC 2014-07-16 11:39:56 -07:00
68 changed files with 1303 additions and 1115 deletions
+19 -6
View File
@@ -1,9 +1,22 @@
[submodule "External/ReactiveCocoa"]
path = External/ReactiveCocoa
url = https://github.com/ReactiveCocoa/ReactiveCocoa.git
[submodule "External/Mantle"]
path = External/Mantle
url = https://github.com/MantleFramework/Mantle.git
[submodule "External/OHHTTPStubs"]
path = External/OHHTTPStubs
url = https://github.com/github/OHHTTPStubs
[submodule "Carthage.checkout/Nimble"]
path = Carthage/Checkouts/Nimble
url = https://github.com/Quick/Nimble.git
[submodule "Carthage.checkout/ReactiveCocoa"]
path = Carthage/Checkouts/ReactiveCocoa
url = https://github.com/ReactiveCocoa/ReactiveCocoa.git
[submodule "Carthage.checkout/Quick"]
path = Carthage/Checkouts/Quick
url = https://github.com/Quick/Quick.git
[submodule "Carthage.checkout/xcconfigs"]
path = Carthage/Checkouts/xcconfigs
url = https://github.com/jspahrsummers/xcconfigs.git
[submodule "Carthage.checkout/Mantle"]
path = Carthage/Checkouts/Mantle
url = https://github.com/Mantle/Mantle.git
[submodule "Carthage/Checkouts/Nimble"]
url = https://github.com/Quick/Nimble.git
[submodule "Carthage/Checkouts/Quick"]
url = https://github.com/Quick/Quick.git
+12
View File
@@ -0,0 +1,12 @@
osx_image: xcode7.1
language: objective-c
before_install:
- brew update
- brew outdated xctool || brew upgrade xctool
install: script/bootstrap
script: script/cibuild
notifications:
email: false
env:
global:
secure: L4C3hHzXc/sgL35dIz3kjqIzPWnXCHsFOgbOcz0f249zlnegeKHQdChm4HUDtfrbmKLMYQCIvVfcgPeLaHkCSeHqXUihXLT2LglK+0GX3MBbFzde9x1uln2O68hH1tTmBg2O2i4Dtc4D3e+2tVv3XmhQDZt0znIVO6n9YgevDqw=
+2
View File
@@ -0,0 +1,2 @@
github "Mantle/Mantle" ~> 1.5.3
github "ReactiveCocoa/ReactiveCocoa" ~> 2.4.3
+3
View File
@@ -0,0 +1,3 @@
github "jspahrsummers/xcconfigs" >= 0.7.1
github "Quick/Quick" ~> 0.7
github "Quick/Nimble" ~> 2.0
+5
View File
@@ -0,0 +1,5 @@
github "Mantle/Mantle" "1.5.6"
github "Quick/Nimble" "v2.0.0"
github "Quick/Quick" "v0.7.0"
github "ReactiveCocoa/ReactiveCocoa" "v2.5"
github "jspahrsummers/xcconfigs" "0.8.1"
Vendored Submodule
+1
Vendored Submodule
+1
Vendored Submodule
+1
-1
Submodule External/Mantle deleted from fe3a65987b
+15 -8
View File
@@ -6,6 +6,7 @@ and transparent as updates to a website**.
Instead of publishing a feed of versions from which your app must select,
Squirrel updates to the version your server tells it to. This allows you to
intelligently update your clients based on the request you give to Squirrel.
The server can remotely drive behaviors like rolling back or phased rollouts.
Your request can include authentication details, custom headers or a request
body so that your server has the context it needs in order to supply the most
@@ -39,7 +40,7 @@ If you’re developing Squirrel on its own, then use `Squirrel.xcworkspace`.
# Dependencies
Squirrel depends on [ReactiveCocoa](http://github.com/ReactiveCocoa/ReactiveCocoa)
and [Mantle](https://github.com/MantleFramework/Mantle).
and [Mantle](https://github.com/Mantle/Mantle).
If your application is already using ReactiveCocoa, ensure it is using the same
version as Squirrel.
@@ -113,12 +114,18 @@ To know when an update is ready to be installed, you can subscribe to the
}];
```
If you've been notified of an available update, and don't want to wait for it to
be installed automatically, you can terminate the app to begin the installation
process immediately.
## Installing Updates
If you want to install a downloaded update and automatically relaunch afterward,
`SQRLUpdater` can do that:
While downloaded updates are automatically installed when your application
terminates, if don't want to wait you can manually terminate the app to begin
the installation process immediately.
Once an [update available notification](#update-available-notifications) has
been received, you may want to present an interface informing the user about
the update and offering the ability to install and relaunch.
To explicitly install a downloaded update and automatically relaunch afterward,
subscribe to the `relaunchToInstallUpdate` signal on `SQRLUpdater`:
```objc
[[self.updater relaunchToInstallUpdate] subscribeError:^(NSError *error) {
@@ -152,7 +159,7 @@ to the update request provided:
"url": "http://mycompany.com/myapp/releases/myrelease",
"name": "My Release Name",
"notes": "Theses are some release notes innit",
"pub_date": "2013-09-18T12:29:53+01:00",
"pub_date": "2013-09-18T12:29:53+01:00"
}
```
@@ -169,4 +176,4 @@ appropriate format.
Squirrel does not provide any GUI components for presenting updates. If you want
to indicate updates to the user, make sure to [listen for downloaded
updates](#update-notifications).
updates](#update-available-notifications).
+378 -141
View File
@@ -8,13 +8,11 @@
/* Begin PBXBuildFile section */
533076EB17EB688300BDCCE0 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D097B9BC17BB4777006C3FEB /* IOKit.framework */; };
534FF35B17D8E8B90020A51A /* unused-helper in Copy LoginItems */ = {isa = PBXBuildFile; fileRef = D0B1DDCB17B487D90059C355 /* unused-helper */; };
534FF35B17D8E8B90020A51A /* unused-helper in Copy LoginItems */ = {isa = PBXBuildFile; fileRef = D0B1DDCB17B487D90059C355 /* unused-helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
534FF36117D8E90A0020A51A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F60CA7EA179FC4F60069F69A /* Foundation.framework */; };
534FF36717D8E90A0020A51A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 534FF36517D8E90A0020A51A /* InfoPlist.strings */; };
534FF36A17D8E90A0020A51A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 534FF36917D8E90A0020A51A /* main.m */; };
534FF37317D8E9370020A51A /* com.github.Squirrel.TestApplication.TestService.xpc in Copy XPCServices */ = {isa = PBXBuildFile; fileRef = 534FF36017D8E90A0020A51A /* com.github.Squirrel.TestApplication.TestService.xpc */; };
53710D7417D8F59700A992DE /* SQRLDeepCodesignSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 53710D7317D8F59700A992DE /* SQRLDeepCodesignSpec.m */; };
53710D8417D8F5CB00A992DE /* deep-codesign in Resources */ = {isa = PBXBuildFile; fileRef = 53710D7F17D8F5C300A992DE /* deep-codesign */; };
534FF37317D8E9370020A51A /* com.github.Squirrel.TestApplication.TestService.xpc in Copy XPCServices */ = {isa = PBXBuildFile; fileRef = 534FF36017D8E90A0020A51A /* com.github.Squirrel.TestApplication.TestService.xpc */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
5371815F18A29DC8005ED798 /* TestAppConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 5371815E18A29DC8005ED798 /* TestAppConstants.m */; };
5371816018A29DC8005ED798 /* TestAppConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 5371815E18A29DC8005ED798 /* TestAppConstants.m */; };
5374DCC6187AD0D8006B7056 /* SQRLAuthorization.h in Headers */ = {isa = PBXBuildFile; fileRef = 5374DCC4187AD0D8006B7056 /* SQRLAuthorization.h */; };
@@ -27,9 +25,8 @@
5397A69D187DF8610014A477 /* SQRLInstallerOwnedBundle.m in Sources */ = {isa = PBXBuildFile; fileRef = 5397A5EB187DA2570014A477 /* SQRLInstallerOwnedBundle.m */; };
53AACF4B17E9CA0500B41027 /* SQRLUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = 53AACF4917E9CA0500B41027 /* SQRLUpdate.h */; settings = {ATTRIBUTES = (Public, ); }; };
53AACF4C17E9CA0500B41027 /* SQRLUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53AACF4A17E9CA0500B41027 /* SQRLUpdate.m */; };
BE312944196B999300F1A675 /* SQRLTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = BE312943196B999300F1A675 /* SQRLTestHelper.m */; };
BE31BEA0196B74A900376A76 /* libSpecta-OSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BE31BE9F196B74A900376A76 /* libSpecta-OSX.a */; };
BE31BEA1196B74B000376A76 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0366C1C17B18FEE0086ED44 /* XCTest.framework */; };
88CA21971BD980FC006693B7 /* MTLEXTRuntimeExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 88CA21941BD980FC006693B7 /* MTLEXTRuntimeExtensions.m */; };
88CA21981BD980FC006693B7 /* MTLEXTScope.m in Sources */ = {isa = PBXBuildFile; fileRef = 88CA21961BD980FC006693B7 /* MTLEXTScope.m */; };
D000218F17BACEFF0050109A /* SQRLZipArchiver.m in Sources */ = {isa = PBXBuildFile; fileRef = D000218D17BACEFF0050109A /* SQRLZipArchiver.m */; };
D000219717BAD34D0050109A /* TestApplication.app.zip in Resources */ = {isa = PBXBuildFile; fileRef = D000219617BAD34D0050109A /* TestApplication.app.zip */; };
D000219917BAD35C0050109A /* SQRLZipArchiverSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D000219817BAD35C0050109A /* SQRLZipArchiverSpec.m */; };
@@ -40,7 +37,7 @@
D014ABBA17B97403007D79D0 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D014ABB917B97403007D79D0 /* ServiceManagement.framework */; };
D014AC0517B97885007D79D0 /* ShipIt-main.m in Sources */ = {isa = PBXBuildFile; fileRef = D014AC0417B97885007D79D0 /* ShipIt-main.m */; };
D014AC1117B9789C007D79D0 /* SQRLInstaller.m in Sources */ = {isa = PBXBuildFile; fileRef = D014AC1017B9789C007D79D0 /* SQRLInstaller.m */; };
D014AC1817B97945007D79D0 /* ShipIt in Copy ShipIt */ = {isa = PBXBuildFile; fileRef = D014AC0117B97885007D79D0 /* ShipIt */; };
D014AC1817B97945007D79D0 /* ShipIt in Copy ShipIt */ = {isa = PBXBuildFile; fileRef = D014AC0117B97885007D79D0 /* ShipIt */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D014AC1917B979A8007D79D0 /* SQRLCodeSignature.m in Sources */ = {isa = PBXBuildFile; fileRef = F6F2ED8217A33C4900F4D220 /* SQRLCodeSignature.m */; };
D014AC1A17B979AA007D79D0 /* NSError+SQRLVerbosityExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0EDBE9B17B0C68E0058BC3C /* NSError+SQRLVerbosityExtensions.m */; };
D014AC1D17B979B7007D79D0 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6EB217F179D0E4D001108CF /* Security.framework */; };
@@ -58,6 +55,7 @@
D06B58B518032B1500656D97 /* RACSignal+SQRLTransactionExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D06B58B318032B1500656D97 /* RACSignal+SQRLTransactionExtensions.m */; };
D06B58B618032B1500656D97 /* RACSignal+SQRLTransactionExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D06B58B318032B1500656D97 /* RACSignal+SQRLTransactionExtensions.m */; };
D06B58D118035B5A00656D97 /* SQRLTerminationListenerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D06B58D018035B5A00656D97 /* SQRLTerminationListenerSpec.m */; };
D06F7B101AD72DD30009A3BC /* RACKVOProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = D06F7B0F1AD72DD30009A3BC /* RACKVOProxy.m */; };
D08D4E0D17B451500012B22D /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C22BDA179CC00E00158214 /* Cocoa.framework */; };
D08D4E1317B451500012B22D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D08D4E1117B451500012B22D /* InfoPlist.strings */; };
D08D4E1517B451500012B22D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D08D4E1417B451500012B22D /* main.m */; };
@@ -65,7 +63,7 @@
D08D4E1C17B451500012B22D /* TestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D08D4E1B17B451500012B22D /* TestAppDelegate.m */; };
D08D4E2117B451500012B22D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D08D4E2017B451500012B22D /* Images.xcassets */; };
D08D4E4717B451E50012B22D /* Squirrel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C22BD7179CC00E00158214 /* Squirrel.framework */; };
D08D4E4917B451F20012B22D /* Squirrel.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D0C22BD7179CC00E00158214 /* Squirrel.framework */; };
D08D4E4917B451F20012B22D /* Squirrel.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D0C22BD7179CC00E00158214 /* Squirrel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D08D4E4A17B451FD0012B22D /* TestApplication.app in Resources */ = {isa = PBXBuildFile; fileRef = D08D4E0C17B451500012B22D /* TestApplication.app */; };
D093682417FF732200BA0EAE /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D014ABB917B97403007D79D0 /* ServiceManagement.framework */; };
D0964B3817F2E01500D88BF7 /* SQRLDownloadedUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = D0964B3617F2E01500D88BF7 /* SQRLDownloadedUpdate.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -74,37 +72,91 @@
D0964B3D17F2E20B00D88BF7 /* NSBundle+SQRLVersionExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0964B3B17F2E20B00D88BF7 /* NSBundle+SQRLVersionExtensions.m */; };
D0964B3E17F2E20B00D88BF7 /* NSBundle+SQRLVersionExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0964B3B17F2E20B00D88BF7 /* NSBundle+SQRLVersionExtensions.m */; };
D097B9BD17BB4777006C3FEB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D097B9BC17BB4777006C3FEB /* IOKit.framework */; };
D09C66291A00520B007D7ED0 /* NSArray+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66281A00520B007D7ED0 /* NSArray+RACSequenceAdditions.m */; };
D09C662C1A005226007D7ED0 /* NSObject+RACKVOWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C662A1A005226007D7ED0 /* NSObject+RACKVOWrapper.m */; };
D09C662D1A005226007D7ED0 /* NSObject+RACPropertySubscribing.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C662B1A005226007D7ED0 /* NSObject+RACPropertySubscribing.m */; };
D09C66351A00535B007D7ED0 /* RACKVOTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66341A00535B007D7ED0 /* RACKVOTrampoline.m */; };
D09C66381A00537A007D7ED0 /* NSObject+RACDeallocating.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66361A00537A007D7ED0 /* NSObject+RACDeallocating.m */; };
D09C66391A00537A007D7ED0 /* NSObject+RACDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66371A00537A007D7ED0 /* NSObject+RACDescription.m */; };
D09C663B1A00538D007D7ED0 /* RACObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C663A1A00538D007D7ED0 /* RACObjCRuntime.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
D09C663D1A0053C6007D7ED0 /* NSString+RACKeyPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C663C1A0053C6007D7ED0 /* NSString+RACKeyPathUtilities.m */; };
D09C663F1A005433007D7ED0 /* NSEnumerator+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C663E1A005433007D7ED0 /* NSEnumerator+RACSequenceAdditions.m */; };
D09C66411A005592007D7ED0 /* MTLModel+NSCoding.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66401A005592007D7ED0 /* MTLModel+NSCoding.m */; };
D09C66461A0055E6007D7ED0 /* NSArray+MTLManipulationAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66421A0055E6007D7ED0 /* NSArray+MTLManipulationAdditions.m */; };
D09C66471A0055E6007D7ED0 /* NSDictionary+MTLManipulationAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66431A0055E6007D7ED0 /* NSDictionary+MTLManipulationAdditions.m */; };
D09C66481A0055E6007D7ED0 /* NSError+MTLModelException.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66441A0055E6007D7ED0 /* NSError+MTLModelException.m */; };
D09C66491A0055E6007D7ED0 /* NSObject+MTLComparisonAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C66451A0055E6007D7ED0 /* NSObject+MTLComparisonAdditions.m */; };
D09C664B1A0055F3007D7ED0 /* NSValueTransformer+MTLInversionAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D09C664A1A0055F3007D7ED0 /* NSValueTransformer+MTLInversionAdditions.m */; };
D09D244117B595470001FAF8 /* SQRLInstallerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D09D244017B595470001FAF8 /* SQRLInstallerSpec.m */; };
D09D244A17B59AB30001FAF8 /* TestApplication 2.1.app in Resources */ = {isa = PBXBuildFile; fileRef = D09D244917B59AB30001FAF8 /* TestApplication 2.1.app */; };
D0A6D2BC17B9FA9E00B2C3DF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6EB217F179D0E4D001108CF /* Security.framework */; };
D0B1DDCE17B487FB0059C355 /* unused-helper in Copy Executables */ = {isa = PBXBuildFile; fileRef = D0B1DDCB17B487D90059C355 /* unused-helper */; };
D0AFE33B1A00282C00C6048F /* MTLJSONAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3381A00282C00C6048F /* MTLJSONAdapter.m */; };
D0AFE33C1A00282C00C6048F /* MTLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3391A00282C00C6048F /* MTLModel.m */; };
D0AFE33D1A00282C00C6048F /* MTLValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE33A1A00282C00C6048F /* MTLValueTransformer.m */; };
D0AFE3431A00285000C6048F /* MTLReflection.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3411A00285000C6048F /* MTLReflection.m */; };
D0AFE3441A00285000C6048F /* NSValueTransformer+MTLPredefinedTransformerAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3421A00285000C6048F /* NSValueTransformer+MTLPredefinedTransformerAdditions.m */; };
D0AFE34A1A00287100C6048F /* RACCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3451A00287100C6048F /* RACCommand.m */; };
D0AFE34B1A00287100C6048F /* RACDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3461A00287100C6048F /* RACDisposable.m */; };
D0AFE34C1A00287100C6048F /* RACScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3471A00287100C6048F /* RACScheduler.m */; };
D0AFE34D1A00287100C6048F /* RACSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3481A00287100C6048F /* RACSignal.m */; };
D0AFE34E1A00287100C6048F /* RACSignal+Operations.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3491A00287100C6048F /* RACSignal+Operations.m */; };
D0AFE3651A0028A400C6048F /* RACBlockTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE34F1A0028A400C6048F /* RACBlockTrampoline.m */; };
D0AFE3661A0028A400C6048F /* RACCompoundDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3501A0028A400C6048F /* RACCompoundDisposable.m */; };
D0AFE3671A0028A400C6048F /* RACDynamicSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3511A0028A400C6048F /* RACDynamicSignal.m */; };
D0AFE3681A0028A400C6048F /* RACEmptySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3521A0028A400C6048F /* RACEmptySequence.m */; };
D0AFE3691A0028A400C6048F /* RACEmptySignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3531A0028A400C6048F /* RACEmptySignal.m */; };
D0AFE36A1A0028A400C6048F /* RACErrorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3541A0028A400C6048F /* RACErrorSignal.m */; };
D0AFE36B1A0028A400C6048F /* RACEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3551A0028A400C6048F /* RACEvent.m */; };
D0AFE36C1A0028A400C6048F /* RACGroupedSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3561A0028A400C6048F /* RACGroupedSignal.m */; };
D0AFE36D1A0028A400C6048F /* RACImmediateScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3571A0028A400C6048F /* RACImmediateScheduler.m */; };
D0AFE36E1A0028A400C6048F /* RACMulticastConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3581A0028A400C6048F /* RACMulticastConnection.m */; };
D0AFE36F1A0028A400C6048F /* RACReplaySubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3591A0028A400C6048F /* RACReplaySubject.m */; };
D0AFE3701A0028A400C6048F /* RACReturnSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE35A1A0028A400C6048F /* RACReturnSignal.m */; };
D0AFE3711A0028A400C6048F /* RACScopedDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE35B1A0028A400C6048F /* RACScopedDisposable.m */; };
D0AFE3721A0028A400C6048F /* RACSerialDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE35C1A0028A400C6048F /* RACSerialDisposable.m */; };
D0AFE3731A0028A400C6048F /* RACSignalSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE35D1A0028A400C6048F /* RACSignalSequence.m */; };
D0AFE3741A0028A400C6048F /* RACStream.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE35E1A0028A400C6048F /* RACStream.m */; };
D0AFE3751A0028A400C6048F /* RACSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE35F1A0028A400C6048F /* RACSubject.m */; };
D0AFE3761A0028A400C6048F /* RACSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3601A0028A400C6048F /* RACSubscriber.m */; };
D0AFE3771A0028A400C6048F /* RACSubscriptionScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3611A0028A400C6048F /* RACSubscriptionScheduler.m */; };
D0AFE3781A0028A400C6048F /* RACTargetQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3621A0028A400C6048F /* RACTargetQueueScheduler.m */; };
D0AFE3791A0028A400C6048F /* RACTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3631A0028A400C6048F /* RACTuple.m */; };
D0AFE37A1A0028A400C6048F /* RACUnit.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3641A0028A400C6048F /* RACUnit.m */; };
D0AFE37C1A0028B000C6048F /* RACCompoundDisposableProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE37B1A0028B000C6048F /* RACCompoundDisposableProvider.d */; };
D0AFE3811A0028CC00C6048F /* RACPassthroughSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE37D1A0028CC00C6048F /* RACPassthroughSubscriber.m */; };
D0AFE3821A0028CC00C6048F /* RACQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE37E1A0028CC00C6048F /* RACQueueScheduler.m */; };
D0AFE3831A0028CC00C6048F /* RACSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE37F1A0028CC00C6048F /* RACSequence.m */; };
D0AFE3841A0028CC00C6048F /* RACTupleSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3801A0028CC00C6048F /* RACTupleSequence.m */; };
D0AFE3861A0028D500C6048F /* RACSignalProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3851A0028D500C6048F /* RACSignalProvider.d */; };
D0AFE38B1A0028EC00C6048F /* RACArraySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3871A0028EC00C6048F /* RACArraySequence.m */; };
D0AFE38C1A0028EC00C6048F /* RACDynamicSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3881A0028EC00C6048F /* RACDynamicSequence.m */; };
D0AFE38D1A0028EC00C6048F /* RACEagerSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE3891A0028EC00C6048F /* RACEagerSequence.m */; };
D0AFE38E1A0028EC00C6048F /* RACUnarySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE38A1A0028EC00C6048F /* RACUnarySequence.m */; };
D0AFE3901A00294100C6048F /* SwiftSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AFE38F1A00294100C6048F /* SwiftSpec.swift */; };
D0AFE3931A00297500C6048F /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0AFE3921A00297500C6048F /* Quick.framework */; };
D0AFE3951A0029A700C6048F /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0AFE3941A0029A700C6048F /* Nimble.framework */; };
D0B1DDCE17B487FB0059C355 /* unused-helper in Copy Executables */ = {isa = PBXBuildFile; fileRef = D0B1DDCB17B487D90059C355 /* unused-helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D0C22BDB179CC00E00158214 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C22BDA179CC00E00158214 /* Cocoa.framework */; };
D0C22BE5179CC00E00158214 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0C22BE3179CC00E00158214 /* InfoPlist.strings */; };
D0C22BF2179CC00E00158214 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C22BDA179CC00E00158214 /* Cocoa.framework */; };
D0C22BF5179CC00E00158214 /* Squirrel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C22BD7179CC00E00158214 /* Squirrel.framework */; };
D0C22BFB179CC00E00158214 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0C22BF9179CC00E00158214 /* InfoPlist.strings */; };
D0C22C4C179CC15100158214 /* SQRLUpdater.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C22C4A179CC15100158214 /* SQRLUpdater.h */; settings = {ATTRIBUTES = (Public, ); }; };
D0C22C4D179CC15100158214 /* SQRLUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C22C4B179CC15100158214 /* SQRLUpdater.m */; };
D0C22C50179CC18C00158214 /* SQRLUpdaterSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C22C4F179CC18C00158214 /* SQRLUpdaterSpec.m */; };
D0C22C52179CC23900158214 /* Squirrel.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C22BE7179CC00E00158214 /* Squirrel.h */; settings = {ATTRIBUTES = (Public, ); }; };
D0D2B6261804E903000EA901 /* SQRLDirectoryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D2B6241804E903000EA901 /* SQRLDirectoryManager.m */; };
D0D2B6271804E903000EA901 /* SQRLDirectoryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D2B6241804E903000EA901 /* SQRLDirectoryManager.m */; };
D0D97E4517B58FC400301C72 /* ResourceRules.plist in Resources */ = {isa = PBXBuildFile; fileRef = D0D97E4417B58FC400301C72 /* ResourceRules.plist */; };
D0EDBE9D17B0C68E0058BC3C /* NSError+SQRLVerbosityExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0EDBE9B17B0C68E0058BC3C /* NSError+SQRLVerbosityExtensions.m */; };
D0EDBEDD17B0DB3E0058BC3C /* SQRLTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = D0EDBEDC17B0DB3E0058BC3C /* SQRLTestCase.m */; };
D0EDBEDD17B0DB3E0058BC3C /* QuickSpec+SQRLFixtures.m in Sources */ = {isa = PBXBuildFile; fileRef = D0EDBEDC17B0DB3E0058BC3C /* QuickSpec+SQRLFixtures.m */; };
D0EDBEE117B0E3650058BC3C /* SQRLCodeSignatureSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D0EDBEE017B0E3650058BC3C /* SQRLCodeSignatureSpec.m */; };
D45F1A9218E46F2E005CE515 /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909A18E46DFE00786EFE /* ReactiveCocoa.framework */; };
D45F1A9318E46F2E005CE515 /* Mantle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909818E46DE900786EFE /* Mantle.framework */; };
D45F1A9418E47055005CE515 /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909A18E46DFE00786EFE /* ReactiveCocoa.framework */; };
D45F1A9518E47055005CE515 /* Mantle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909818E46DE900786EFE /* Mantle.framework */; };
D4ACA4F618DB9CCB00EBD899 /* libExpecta.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ACA4F518DB9CCB00EBD899 /* libExpecta.a */; };
D4ACA50118DB9F3F00EBD899 /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ACA50018DB9F3F00EBD899 /* OHHTTPStubs.framework */; };
D4C4909918E46DE900786EFE /* Mantle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909818E46DE900786EFE /* Mantle.framework */; };
D4C4909B18E46DFE00786EFE /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909A18E46DFE00786EFE /* ReactiveCocoa.framework */; };
D4C4909E18E46E1000786EFE /* ReactiveCocoa.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909A18E46DFE00786EFE /* ReactiveCocoa.framework */; };
D4C4909F18E46E1000786EFE /* Mantle.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909818E46DE900786EFE /* Mantle.framework */; };
D4C490A118E46E8200786EFE /* libMantle-Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C490A018E46E8200786EFE /* libMantle-Mac.a */; };
D4C490A318E46E8800786EFE /* libReactiveCocoa-Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C490A218E46E8800786EFE /* libReactiveCocoa-Mac.a */; };
D4C4909E18E46E1000786EFE /* ReactiveCocoa.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909A18E46DFE00786EFE /* ReactiveCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D4C4909F18E46E1000786EFE /* Mantle.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4C4909818E46DE900786EFE /* Mantle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
F6EB2162179CFD93001108CF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6EB2161179CFD93001108CF /* SystemConfiguration.framework */; };
F6EB2180179D0E4D001108CF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6EB217F179D0E4D001108CF /* Security.framework */; };
F6F2ED8417A33C4900F4D220 /* SQRLCodeSignature.m in Sources */ = {isa = PBXBuildFile; fileRef = F6F2ED8217A33C4900F4D220 /* SQRLCodeSignature.m */; };
@@ -214,10 +266,8 @@
534FF36617D8E90A0020A51A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
534FF36817D8E90A0020A51A /* TestService-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TestService-Prefix.pch"; sourceTree = "<group>"; };
534FF36917D8E90A0020A51A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
53710D7317D8F59700A992DE /* SQRLDeepCodesignSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLDeepCodesignSpec.m; sourceTree = "<group>"; };
53710D7D17D8F5C300A992DE /* bootstrap */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = bootstrap; sourceTree = "<group>"; };
53710D7E17D8F5C300A992DE /* cibuild */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = cibuild; sourceTree = "<group>"; };
53710D7F17D8F5C300A992DE /* deep-codesign */ = {isa = PBXFileReference; lastKnownFileType = text; path = "deep-codesign"; sourceTree = "<group>"; };
53710D8017D8F5C300A992DE /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.md; sourceTree = "<group>"; };
53710D8117D8F5C300A992DE /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.md; sourceTree = "<group>"; };
53710D8217D8F5C300A992DE /* targets.awk */ = {isa = PBXFileReference; lastKnownFileType = text; path = targets.awk; sourceTree = "<group>"; };
@@ -234,9 +284,12 @@
5397A69C187DF6490014A477 /* SQRLInstaller+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SQRLInstaller+Private.h"; sourceTree = "<group>"; };
53AACF4917E9CA0500B41027 /* SQRLUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQRLUpdate.h; sourceTree = "<group>"; };
53AACF4A17E9CA0500B41027 /* SQRLUpdate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLUpdate.m; sourceTree = "<group>"; };
BE312942196B999300F1A675 /* SQRLTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQRLTestHelper.h; sourceTree = "<group>"; };
BE312943196B999300F1A675 /* SQRLTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLTestHelper.m; sourceTree = "<group>"; };
BE31BE9F196B74A900376A76 /* libSpecta-OSX.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libSpecta-OSX.a"; path = "External/ReactiveCocoa/external/specta/build/Debug/libSpecta-OSX.a"; sourceTree = "<group>"; };
88CA21911BD980FC006693B7 /* metamacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = metamacros.h; path = Carthage/Checkouts/Mantle/Mantle/extobjc/metamacros.h; sourceTree = SOURCE_ROOT; };
88CA21921BD980FC006693B7 /* MTLEXTKeyPathCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTLEXTKeyPathCoding.h; path = Carthage/Checkouts/Mantle/Mantle/extobjc/MTLEXTKeyPathCoding.h; sourceTree = SOURCE_ROOT; };
88CA21931BD980FC006693B7 /* MTLEXTRuntimeExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTLEXTRuntimeExtensions.h; path = Carthage/Checkouts/Mantle/Mantle/extobjc/MTLEXTRuntimeExtensions.h; sourceTree = SOURCE_ROOT; };
88CA21941BD980FC006693B7 /* MTLEXTRuntimeExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTLEXTRuntimeExtensions.m; path = Carthage/Checkouts/Mantle/Mantle/extobjc/MTLEXTRuntimeExtensions.m; sourceTree = SOURCE_ROOT; };
88CA21951BD980FC006693B7 /* MTLEXTScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTLEXTScope.h; path = Carthage/Checkouts/Mantle/Mantle/extobjc/MTLEXTScope.h; sourceTree = SOURCE_ROOT; };
88CA21961BD980FC006693B7 /* MTLEXTScope.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTLEXTScope.m; path = Carthage/Checkouts/Mantle/Mantle/extobjc/MTLEXTScope.m; sourceTree = SOURCE_ROOT; };
D000218C17BACEFF0050109A /* SQRLZipArchiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQRLZipArchiver.h; sourceTree = "<group>"; };
D000218D17BACEFF0050109A /* SQRLZipArchiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLZipArchiver.m; sourceTree = "<group>"; };
D000219617BAD34D0050109A /* TestApplication.app.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = TestApplication.app.zip; sourceTree = "<group>"; };
@@ -254,7 +307,6 @@
D0366C0017B18FEE0086ED44 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
D0366C0117B18FEE0086ED44 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
D0366C0217B18FEE0086ED44 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D0366C1C17B18FEE0086ED44 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
D03BE98C17B6174500458593 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
D043F77017FF40C90012F996 /* SQRLTerminationListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQRLTerminationListener.h; sourceTree = "<group>"; };
D043F77117FF40C90012F996 /* SQRLTerminationListener.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLTerminationListener.m; sourceTree = "<group>"; };
@@ -265,6 +317,7 @@
D06B58B218032B1500656D97 /* RACSignal+SQRLTransactionExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACSignal+SQRLTransactionExtensions.h"; sourceTree = "<group>"; };
D06B58B318032B1500656D97 /* RACSignal+SQRLTransactionExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RACSignal+SQRLTransactionExtensions.m"; sourceTree = "<group>"; };
D06B58D018035B5A00656D97 /* SQRLTerminationListenerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLTerminationListenerSpec.m; sourceTree = "<group>"; };
D06F7B0F1AD72DD30009A3BC /* RACKVOProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACKVOProxy.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACKVOProxy.m; sourceTree = SOURCE_ROOT; };
D08D4E0C17B451500012B22D /* TestApplication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApplication.app; sourceTree = BUILT_PRODUCTS_DIR; };
D08D4E1017B451500012B22D /* TestApplication-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TestApplication-Info.plist"; sourceTree = "<group>"; };
D08D4E1217B451500012B22D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -279,18 +332,77 @@
D0964B3A17F2E20B00D88BF7 /* NSBundle+SQRLVersionExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+SQRLVersionExtensions.h"; sourceTree = "<group>"; };
D0964B3B17F2E20B00D88BF7 /* NSBundle+SQRLVersionExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+SQRLVersionExtensions.m"; sourceTree = "<group>"; };
D097B9BC17BB4777006C3FEB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
D09C66281A00520B007D7ED0 /* NSArray+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+RACSequenceAdditions.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/NSArray+RACSequenceAdditions.m"; sourceTree = SOURCE_ROOT; };
D09C662A1A005226007D7ED0 /* NSObject+RACKVOWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSObject+RACKVOWrapper.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/NSObject+RACKVOWrapper.m"; sourceTree = SOURCE_ROOT; };
D09C662B1A005226007D7ED0 /* NSObject+RACPropertySubscribing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSObject+RACPropertySubscribing.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/NSObject+RACPropertySubscribing.m"; sourceTree = SOURCE_ROOT; };
D09C66341A00535B007D7ED0 /* RACKVOTrampoline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACKVOTrampoline.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACKVOTrampoline.m; sourceTree = SOURCE_ROOT; };
D09C66361A00537A007D7ED0 /* NSObject+RACDeallocating.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSObject+RACDeallocating.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/NSObject+RACDeallocating.m"; sourceTree = SOURCE_ROOT; };
D09C66371A00537A007D7ED0 /* NSObject+RACDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSObject+RACDescription.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/NSObject+RACDescription.m"; sourceTree = SOURCE_ROOT; };
D09C663A1A00538D007D7ED0 /* RACObjCRuntime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACObjCRuntime.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACObjCRuntime.m; sourceTree = SOURCE_ROOT; };
D09C663C1A0053C6007D7ED0 /* NSString+RACKeyPathUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+RACKeyPathUtilities.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/NSString+RACKeyPathUtilities.m"; sourceTree = SOURCE_ROOT; };
D09C663E1A005433007D7ED0 /* NSEnumerator+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSEnumerator+RACSequenceAdditions.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/NSEnumerator+RACSequenceAdditions.m"; sourceTree = SOURCE_ROOT; };
D09C66401A005592007D7ED0 /* MTLModel+NSCoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "MTLModel+NSCoding.m"; path = "Carthage/Checkouts/Mantle/Mantle/MTLModel+NSCoding.m"; sourceTree = SOURCE_ROOT; };
D09C66421A0055E6007D7ED0 /* NSArray+MTLManipulationAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+MTLManipulationAdditions.m"; path = "Carthage/Checkouts/Mantle/Mantle/NSArray+MTLManipulationAdditions.m"; sourceTree = SOURCE_ROOT; };
D09C66431A0055E6007D7ED0 /* NSDictionary+MTLManipulationAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+MTLManipulationAdditions.m"; path = "Carthage/Checkouts/Mantle/Mantle/NSDictionary+MTLManipulationAdditions.m"; sourceTree = SOURCE_ROOT; };
D09C66441A0055E6007D7ED0 /* NSError+MTLModelException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSError+MTLModelException.m"; path = "Carthage/Checkouts/Mantle/Mantle/NSError+MTLModelException.m"; sourceTree = SOURCE_ROOT; };
D09C66451A0055E6007D7ED0 /* NSObject+MTLComparisonAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSObject+MTLComparisonAdditions.m"; path = "Carthage/Checkouts/Mantle/Mantle/NSObject+MTLComparisonAdditions.m"; sourceTree = SOURCE_ROOT; };
D09C664A1A0055F3007D7ED0 /* NSValueTransformer+MTLInversionAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSValueTransformer+MTLInversionAdditions.m"; path = "Carthage/Checkouts/Mantle/Mantle/NSValueTransformer+MTLInversionAdditions.m"; sourceTree = SOURCE_ROOT; };
D09D244017B595470001FAF8 /* SQRLInstallerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLInstallerSpec.m; sourceTree = "<group>"; };
D09D244917B59AB30001FAF8 /* TestApplication 2.1.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = "TestApplication 2.1.app"; sourceTree = "<group>"; };
D0AFE3351A00236E00C6048F /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = "<group>"; };
D0AFE3361A00237400C6048F /* iOS-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "iOS-Framework.xcconfig"; sourceTree = "<group>"; };
D0AFE3381A00282C00C6048F /* MTLJSONAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTLJSONAdapter.m; path = Carthage/Checkouts/Mantle/Mantle/MTLJSONAdapter.m; sourceTree = SOURCE_ROOT; };
D0AFE3391A00282C00C6048F /* MTLModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTLModel.m; path = Carthage/Checkouts/Mantle/Mantle/MTLModel.m; sourceTree = SOURCE_ROOT; };
D0AFE33A1A00282C00C6048F /* MTLValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTLValueTransformer.m; path = Carthage/Checkouts/Mantle/Mantle/MTLValueTransformer.m; sourceTree = SOURCE_ROOT; };
D0AFE3411A00285000C6048F /* MTLReflection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTLReflection.m; path = Carthage/Checkouts/Mantle/Mantle/MTLReflection.m; sourceTree = SOURCE_ROOT; };
D0AFE3421A00285000C6048F /* NSValueTransformer+MTLPredefinedTransformerAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSValueTransformer+MTLPredefinedTransformerAdditions.m"; path = "Carthage/Checkouts/Mantle/Mantle/NSValueTransformer+MTLPredefinedTransformerAdditions.m"; sourceTree = SOURCE_ROOT; };
D0AFE3451A00287100C6048F /* RACCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACCommand.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACCommand.m; sourceTree = SOURCE_ROOT; };
D0AFE3461A00287100C6048F /* RACDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACDisposable.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACDisposable.m; sourceTree = SOURCE_ROOT; };
D0AFE3471A00287100C6048F /* RACScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACScheduler.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACScheduler.m; sourceTree = SOURCE_ROOT; };
D0AFE3481A00287100C6048F /* RACSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACSignal.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSignal.m; sourceTree = SOURCE_ROOT; };
D0AFE3491A00287100C6048F /* RACSignal+Operations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RACSignal+Operations.m"; path = "Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSignal+Operations.m"; sourceTree = SOURCE_ROOT; };
D0AFE34F1A0028A400C6048F /* RACBlockTrampoline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACBlockTrampoline.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACBlockTrampoline.m; sourceTree = SOURCE_ROOT; };
D0AFE3501A0028A400C6048F /* RACCompoundDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACCompoundDisposable.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposable.m; sourceTree = SOURCE_ROOT; };
D0AFE3511A0028A400C6048F /* RACDynamicSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACDynamicSignal.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACDynamicSignal.m; sourceTree = SOURCE_ROOT; };
D0AFE3521A0028A400C6048F /* RACEmptySequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACEmptySequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACEmptySequence.m; sourceTree = SOURCE_ROOT; };
D0AFE3531A0028A400C6048F /* RACEmptySignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACEmptySignal.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACEmptySignal.m; sourceTree = SOURCE_ROOT; };
D0AFE3541A0028A400C6048F /* RACErrorSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACErrorSignal.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACErrorSignal.m; sourceTree = SOURCE_ROOT; };
D0AFE3551A0028A400C6048F /* RACEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACEvent.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACEvent.m; sourceTree = SOURCE_ROOT; };
D0AFE3561A0028A400C6048F /* RACGroupedSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACGroupedSignal.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACGroupedSignal.m; sourceTree = SOURCE_ROOT; };
D0AFE3571A0028A400C6048F /* RACImmediateScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACImmediateScheduler.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACImmediateScheduler.m; sourceTree = SOURCE_ROOT; };
D0AFE3581A0028A400C6048F /* RACMulticastConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACMulticastConnection.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACMulticastConnection.m; sourceTree = SOURCE_ROOT; };
D0AFE3591A0028A400C6048F /* RACReplaySubject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACReplaySubject.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACReplaySubject.m; sourceTree = SOURCE_ROOT; };
D0AFE35A1A0028A400C6048F /* RACReturnSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACReturnSignal.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACReturnSignal.m; sourceTree = SOURCE_ROOT; };
D0AFE35B1A0028A400C6048F /* RACScopedDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACScopedDisposable.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACScopedDisposable.m; sourceTree = SOURCE_ROOT; };
D0AFE35C1A0028A400C6048F /* RACSerialDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACSerialDisposable.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSerialDisposable.m; sourceTree = SOURCE_ROOT; };
D0AFE35D1A0028A400C6048F /* RACSignalSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACSignalSequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSignalSequence.m; sourceTree = SOURCE_ROOT; };
D0AFE35E1A0028A400C6048F /* RACStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACStream.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACStream.m; sourceTree = SOURCE_ROOT; };
D0AFE35F1A0028A400C6048F /* RACSubject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACSubject.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSubject.m; sourceTree = SOURCE_ROOT; };
D0AFE3601A0028A400C6048F /* RACSubscriber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACSubscriber.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSubscriber.m; sourceTree = SOURCE_ROOT; };
D0AFE3611A0028A400C6048F /* RACSubscriptionScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACSubscriptionScheduler.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSubscriptionScheduler.m; sourceTree = SOURCE_ROOT; };
D0AFE3621A0028A400C6048F /* RACTargetQueueScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACTargetQueueScheduler.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACTargetQueueScheduler.m; sourceTree = SOURCE_ROOT; };
D0AFE3631A0028A400C6048F /* RACTuple.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACTuple.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACTuple.m; sourceTree = SOURCE_ROOT; };
D0AFE3641A0028A400C6048F /* RACUnit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACUnit.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACUnit.m; sourceTree = SOURCE_ROOT; };
D0AFE37B1A0028B000C6048F /* RACCompoundDisposableProvider.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = RACCompoundDisposableProvider.d; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposableProvider.d; sourceTree = SOURCE_ROOT; };
D0AFE37D1A0028CC00C6048F /* RACPassthroughSubscriber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACPassthroughSubscriber.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACPassthroughSubscriber.m; sourceTree = SOURCE_ROOT; };
D0AFE37E1A0028CC00C6048F /* RACQueueScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACQueueScheduler.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACQueueScheduler.m; sourceTree = SOURCE_ROOT; };
D0AFE37F1A0028CC00C6048F /* RACSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACSequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSequence.m; sourceTree = SOURCE_ROOT; };
D0AFE3801A0028CC00C6048F /* RACTupleSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACTupleSequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACTupleSequence.m; sourceTree = SOURCE_ROOT; };
D0AFE3851A0028D500C6048F /* RACSignalProvider.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = RACSignalProvider.d; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACSignalProvider.d; sourceTree = SOURCE_ROOT; };
D0AFE3871A0028EC00C6048F /* RACArraySequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACArraySequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACArraySequence.m; sourceTree = SOURCE_ROOT; };
D0AFE3881A0028EC00C6048F /* RACDynamicSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACDynamicSequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACDynamicSequence.m; sourceTree = SOURCE_ROOT; };
D0AFE3891A0028EC00C6048F /* RACEagerSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACEagerSequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACEagerSequence.m; sourceTree = SOURCE_ROOT; };
D0AFE38A1A0028EC00C6048F /* RACUnarySequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RACUnarySequence.m; path = Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/RACUnarySequence.m; sourceTree = SOURCE_ROOT; };
D0AFE38F1A00294100C6048F /* SwiftSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSpec.swift; sourceTree = "<group>"; };
D0AFE3921A00297500C6048F /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Quick.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D0AFE3941A0029A700C6048F /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D0B1DDCB17B487D90059C355 /* unused-helper */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = "unused-helper"; sourceTree = "<group>"; };
D0C22BD7179CC00E00158214 /* Squirrel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Squirrel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D0C22BDA179CC00E00158214 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
D0C22BE2179CC00E00158214 /* Squirrel-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Squirrel-Info.plist"; sourceTree = "<group>"; };
D0C22BE4179CC00E00158214 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D0C22BE6179CC00E00158214 /* Squirrel-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Squirrel-Prefix.pch"; sourceTree = "<group>"; };
D0C22BE7179CC00E00158214 /* Squirrel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Squirrel.h; sourceTree = "<group>"; };
D0C22BEF179CC00E00158214 /* SquirrelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SquirrelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D0C22BF8179CC00E00158214 /* SquirrelTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SquirrelTests-Info.plist"; sourceTree = "<group>"; };
D0C22BFA179CC00E00158214 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D0C22C09179CC02E00158214 /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = "<group>"; };
D0C22C0B179CC02E00158214 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
D0C22C0C179CC02E00158214 /* Profile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Profile.xcconfig; sourceTree = "<group>"; };
@@ -310,22 +422,16 @@
D0C22C4A179CC15100158214 /* SQRLUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQRLUpdater.h; sourceTree = "<group>"; };
D0C22C4B179CC15100158214 /* SQRLUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLUpdater.m; sourceTree = "<group>"; };
D0C22C4F179CC18C00158214 /* SQRLUpdaterSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLUpdaterSpec.m; sourceTree = "<group>"; };
D0C22C51179CC1A200158214 /* SquirrelTests-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SquirrelTests-Prefix.pch"; sourceTree = "<group>"; };
D0D2B6231804E903000EA901 /* SQRLDirectoryManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQRLDirectoryManager.h; sourceTree = "<group>"; };
D0D2B6241804E903000EA901 /* SQRLDirectoryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLDirectoryManager.m; sourceTree = "<group>"; };
D0D97E4417B58FC400301C72 /* ResourceRules.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ResourceRules.plist; sourceTree = "<group>"; };
D0EDBE9A17B0C68E0058BC3C /* NSError+SQRLVerbosityExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSError+SQRLVerbosityExtensions.h"; path = "Squirrel/NSError+SQRLVerbosityExtensions.h"; sourceTree = SOURCE_ROOT; };
D0EDBE9B17B0C68E0058BC3C /* NSError+SQRLVerbosityExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSError+SQRLVerbosityExtensions.m"; path = "Squirrel/NSError+SQRLVerbosityExtensions.m"; sourceTree = SOURCE_ROOT; };
D0EDBEDB17B0DB3E0058BC3C /* SQRLTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQRLTestCase.h; sourceTree = "<group>"; };
D0EDBEDC17B0DB3E0058BC3C /* SQRLTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLTestCase.m; sourceTree = "<group>"; };
D0EDBEDB17B0DB3E0058BC3C /* QuickSpec+SQRLFixtures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "QuickSpec+SQRLFixtures.h"; sourceTree = "<group>"; };
D0EDBEDC17B0DB3E0058BC3C /* QuickSpec+SQRLFixtures.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "QuickSpec+SQRLFixtures.m"; sourceTree = "<group>"; };
D0EDBEE017B0E3650058BC3C /* SQRLCodeSignatureSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQRLCodeSignatureSpec.m; sourceTree = "<group>"; };
D4ACA4F518DB9CCB00EBD899 /* libExpecta.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libExpecta.a; path = External/ReactiveCocoa/external/expecta/build/Debug/libExpecta.a; sourceTree = "<group>"; };
D4ACA4F718DB9CCE00EBD899 /* libSpecta.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSpecta.a; path = External/ReactiveCocoa/external/specta/build/Debug/libSpecta.a; sourceTree = "<group>"; };
D4ACA50018DB9F3F00EBD899 /* OHHTTPStubs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OHHTTPStubs.framework; path = External/OHHTTPStubs/OHHTTPStubs/build/Debug/OHHTTPStubs.framework; sourceTree = "<group>"; };
D4C4909818E46DE900786EFE /* Mantle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mantle.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4C4909A18E46DFE00786EFE /* ReactiveCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ReactiveCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4C490A018E46E8200786EFE /* libMantle-Mac.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libMantle-Mac.a"; sourceTree = BUILT_PRODUCTS_DIR; };
D4C490A218E46E8800786EFE /* libReactiveCocoa-Mac.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libReactiveCocoa-Mac.a"; sourceTree = BUILT_PRODUCTS_DIR; };
F60CA7EA179FC4F60069F69A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
F65A915F17A71AA5005A4666 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
F6EB2161179CFD93001108CF /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
@@ -351,8 +457,6 @@
D014AC1F17B979C4007D79D0 /* Cocoa.framework in Frameworks */,
D014AC1D17B979B7007D79D0 /* Security.framework in Frameworks */,
D014AC1E17B979BD007D79D0 /* ServiceManagement.framework in Frameworks */,
D4C490A118E46E8200786EFE /* libMantle-Mac.a in Frameworks */,
D4C490A318E46E8800786EFE /* libReactiveCocoa-Mac.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -385,13 +489,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D0AFE3931A00297500C6048F /* Quick.framework in Frameworks */,
D4ACA50118DB9F3F00EBD899 /* OHHTTPStubs.framework in Frameworks */,
D093682417FF732200BA0EAE /* ServiceManagement.framework in Frameworks */,
BE31BEA1196B74B000376A76 /* XCTest.framework in Frameworks */,
BE31BEA0196B74A900376A76 /* libSpecta-OSX.a in Frameworks */,
D4ACA4F618DB9CCB00EBD899 /* libExpecta.a in Frameworks */,
D061E40317FD581C00CC134A /* IOKit.framework in Frameworks */,
D0C22BF2179CC00E00158214 /* Cocoa.framework in Frameworks */,
D0AFE3951A0029A700C6048F /* Nimble.framework in Frameworks */,
D0A6D2BC17B9FA9E00B2C3DF /* Security.framework in Frameworks */,
D0C22BF5179CC00E00158214 /* Squirrel.framework in Frameworks */,
D45F1A9218E46F2E005CE515 /* ReactiveCocoa.framework in Frameworks */,
@@ -427,7 +530,6 @@
children = (
53710D7D17D8F5C300A992DE /* bootstrap */,
53710D7E17D8F5C300A992DE /* cibuild */,
53710D7F17D8F5C300A992DE /* deep-codesign */,
53710D8017D8F5C300A992DE /* LICENSE.md */,
53710D8117D8F5C300A992DE /* README.md */,
53710D8217D8F5C300A992DE /* targets.awk */,
@@ -466,6 +568,7 @@
D043F77117FF40C90012F996 /* SQRLTerminationListener.m */,
5397A5EA187DA2570014A477 /* SQRLInstallerOwnedBundle.h */,
5397A5EB187DA2570014A477 /* SQRLInstallerOwnedBundle.m */,
D0AFE3371A00282000C6048F /* Static Dependencies */,
);
name = ShipIt;
path = Squirrel;
@@ -518,7 +621,6 @@
D08D4E0F17B451500012B22D /* Supporting Files */ = {
isa = PBXGroup;
children = (
D0D97E4417B58FC400301C72 /* ResourceRules.plist */,
D0B1DDCB17B487D90059C355 /* unused-helper */,
D08D4E1017B451500012B22D /* TestApplication-Info.plist */,
D08D4E1117B451500012B22D /* InfoPlist.strings */,
@@ -581,6 +683,77 @@
name = "Code Signing";
sourceTree = "<group>";
};
D0AFE3371A00282000C6048F /* Static Dependencies */ = {
isa = PBXGroup;
children = (
88CA21911BD980FC006693B7 /* metamacros.h */,
88CA21921BD980FC006693B7 /* MTLEXTKeyPathCoding.h */,
88CA21931BD980FC006693B7 /* MTLEXTRuntimeExtensions.h */,
88CA21941BD980FC006693B7 /* MTLEXTRuntimeExtensions.m */,
88CA21951BD980FC006693B7 /* MTLEXTScope.h */,
88CA21961BD980FC006693B7 /* MTLEXTScope.m */,
D0AFE3381A00282C00C6048F /* MTLJSONAdapter.m */,
D0AFE3391A00282C00C6048F /* MTLModel.m */,
D09C66401A005592007D7ED0 /* MTLModel+NSCoding.m */,
D0AFE3411A00285000C6048F /* MTLReflection.m */,
D0AFE33A1A00282C00C6048F /* MTLValueTransformer.m */,
D09C66421A0055E6007D7ED0 /* NSArray+MTLManipulationAdditions.m */,
D09C66281A00520B007D7ED0 /* NSArray+RACSequenceAdditions.m */,
D09C66431A0055E6007D7ED0 /* NSDictionary+MTLManipulationAdditions.m */,
D09C663E1A005433007D7ED0 /* NSEnumerator+RACSequenceAdditions.m */,
D09C66441A0055E6007D7ED0 /* NSError+MTLModelException.m */,
D09C664A1A0055F3007D7ED0 /* NSValueTransformer+MTLInversionAdditions.m */,
D09C66451A0055E6007D7ED0 /* NSObject+MTLComparisonAdditions.m */,
D09C66361A00537A007D7ED0 /* NSObject+RACDeallocating.m */,
D09C66371A00537A007D7ED0 /* NSObject+RACDescription.m */,
D09C662A1A005226007D7ED0 /* NSObject+RACKVOWrapper.m */,
D09C662B1A005226007D7ED0 /* NSObject+RACPropertySubscribing.m */,
D09C663C1A0053C6007D7ED0 /* NSString+RACKeyPathUtilities.m */,
D0AFE3421A00285000C6048F /* NSValueTransformer+MTLPredefinedTransformerAdditions.m */,
D0AFE3871A0028EC00C6048F /* RACArraySequence.m */,
D0AFE34F1A0028A400C6048F /* RACBlockTrampoline.m */,
D0AFE3451A00287100C6048F /* RACCommand.m */,
D0AFE3501A0028A400C6048F /* RACCompoundDisposable.m */,
D0AFE37B1A0028B000C6048F /* RACCompoundDisposableProvider.d */,
D0AFE3461A00287100C6048F /* RACDisposable.m */,
D0AFE3881A0028EC00C6048F /* RACDynamicSequence.m */,
D0AFE3511A0028A400C6048F /* RACDynamicSignal.m */,
D0AFE3891A0028EC00C6048F /* RACEagerSequence.m */,
D0AFE3521A0028A400C6048F /* RACEmptySequence.m */,
D0AFE3531A0028A400C6048F /* RACEmptySignal.m */,
D0AFE3541A0028A400C6048F /* RACErrorSignal.m */,
D0AFE3551A0028A400C6048F /* RACEvent.m */,
D0AFE3561A0028A400C6048F /* RACGroupedSignal.m */,
D0AFE3571A0028A400C6048F /* RACImmediateScheduler.m */,
D06F7B0F1AD72DD30009A3BC /* RACKVOProxy.m */,
D09C66341A00535B007D7ED0 /* RACKVOTrampoline.m */,
D0AFE3581A0028A400C6048F /* RACMulticastConnection.m */,
D09C663A1A00538D007D7ED0 /* RACObjCRuntime.m */,
D0AFE37D1A0028CC00C6048F /* RACPassthroughSubscriber.m */,
D0AFE37E1A0028CC00C6048F /* RACQueueScheduler.m */,
D0AFE3591A0028A400C6048F /* RACReplaySubject.m */,
D0AFE35A1A0028A400C6048F /* RACReturnSignal.m */,
D0AFE3471A00287100C6048F /* RACScheduler.m */,
D0AFE35B1A0028A400C6048F /* RACScopedDisposable.m */,
D0AFE37F1A0028CC00C6048F /* RACSequence.m */,
D0AFE35C1A0028A400C6048F /* RACSerialDisposable.m */,
D0AFE3481A00287100C6048F /* RACSignal.m */,
D0AFE3491A00287100C6048F /* RACSignal+Operations.m */,
D0AFE3851A0028D500C6048F /* RACSignalProvider.d */,
D0AFE35D1A0028A400C6048F /* RACSignalSequence.m */,
D0AFE35E1A0028A400C6048F /* RACStream.m */,
D0AFE35F1A0028A400C6048F /* RACSubject.m */,
D0AFE3601A0028A400C6048F /* RACSubscriber.m */,
D0AFE3611A0028A400C6048F /* RACSubscriptionScheduler.m */,
D0AFE3621A0028A400C6048F /* RACTargetQueueScheduler.m */,
D0AFE3631A0028A400C6048F /* RACTuple.m */,
D0AFE3801A0028CC00C6048F /* RACTupleSequence.m */,
D0AFE38A1A0028EC00C6048F /* RACUnarySequence.m */,
D0AFE3641A0028A400C6048F /* RACUnit.m */,
);
name = "Static Dependencies";
sourceTree = "<group>";
};
D0C22BCD179CC00E00158214 = {
isa = PBXGroup;
children = (
@@ -612,13 +785,10 @@
D0C22BD9179CC00E00158214 /* Frameworks */ = {
isa = PBXGroup;
children = (
BE31BE9F196B74A900376A76 /* libSpecta-OSX.a */,
D0AFE3941A0029A700C6048F /* Nimble.framework */,
D0AFE3921A00297500C6048F /* Quick.framework */,
D4C4909A18E46DFE00786EFE /* ReactiveCocoa.framework */,
D4C4909818E46DE900786EFE /* Mantle.framework */,
D4C490A218E46E8800786EFE /* libReactiveCocoa-Mac.a */,
D4C490A018E46E8200786EFE /* libMantle-Mac.a */,
D4ACA4F518DB9CCB00EBD899 /* libExpecta.a */,
D4ACA4F718DB9CCE00EBD899 /* libSpecta.a */,
D4ACA50018DB9F3F00EBD899 /* OHHTTPStubs.framework */,
D097B9BC17BB4777006C3FEB /* IOKit.framework */,
D014ABB917B97403007D79D0 /* ServiceManagement.framework */,
@@ -627,7 +797,6 @@
F6EB217F179D0E4D001108CF /* Security.framework */,
F6EB2161179CFD93001108CF /* SystemConfiguration.framework */,
F60CA7EA179FC4F60069F69A /* Foundation.framework */,
D0366C1C17B18FEE0086ED44 /* XCTest.framework */,
D0366BFF17B18FEE0086ED44 /* Other Frameworks */,
);
name = Frameworks;
@@ -648,8 +817,6 @@
isa = PBXGroup;
children = (
D0C22BE2179CC00E00158214 /* Squirrel-Info.plist */,
D0C22BE3179CC00E00158214 /* InfoPlist.strings */,
D0C22BE6179CC00E00158214 /* Squirrel-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -666,13 +833,14 @@
D0C22BF7179CC00E00158214 /* Supporting Files */ = {
isa = PBXGroup;
children = (
D0EDBEDB17B0DB3E0058BC3C /* QuickSpec+SQRLFixtures.h */,
D0EDBEDC17B0DB3E0058BC3C /* QuickSpec+SQRLFixtures.m */,
D0AFE38F1A00294100C6048F /* SwiftSpec.swift */,
D049059E180558B7004E683E /* SQRLTestUpdate.h */,
D049059F180558B7004E683E /* SQRLTestUpdate.m */,
D000219617BAD34D0050109A /* TestApplication.app.zip */,
D09D244917B59AB30001FAF8 /* TestApplication 2.1.app */,
D0C22BF8179CC00E00158214 /* SquirrelTests-Info.plist */,
D0C22BF9179CC00E00158214 /* InfoPlist.strings */,
D0C22C51179CC1A200158214 /* SquirrelTests-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -686,7 +854,7 @@
D0C22C1C179CC02E00158214 /* README.md */,
);
name = Configuration;
path = External/ReactiveCocoa/external/xcconfigs;
path = Carthage/Checkouts/xcconfigs;
sourceTree = "<group>";
};
D0C22C08179CC02E00158214 /* Base */ = {
@@ -714,6 +882,7 @@
isa = PBXGroup;
children = (
D0C22C10179CC02E00158214 /* Application.xcconfig */,
D0AFE3351A00236E00C6048F /* Framework.xcconfig */,
D0C22C11179CC02E00158214 /* StaticLibrary.xcconfig */,
);
path = Targets;
@@ -724,6 +893,7 @@
children = (
D0C22C13179CC02E00158214 /* iOS-Application.xcconfig */,
D0C22C14179CC02E00158214 /* iOS-Base.xcconfig */,
D0AFE3361A00237400C6048F /* iOS-Framework.xcconfig */,
D0C22C15179CC02E00158214 /* iOS-StaticLibrary.xcconfig */,
);
path = iOS;
@@ -756,15 +926,10 @@
children = (
D00F5B8D17E82DE6009A4818 /* NSProcessInfoExtensionsSpec.m */,
D0EDBEE017B0E3650058BC3C /* SQRLCodeSignatureSpec.m */,
53710D7317D8F59700A992DE /* SQRLDeepCodesignSpec.m */,
D049059A180554BA004E683E /* SQRLDirectoryManagerSpec.m */,
D09D244017B595470001FAF8 /* SQRLInstallerSpec.m */,
D049059C18055671004E683E /* SQRLShipItRequestSpec.m */,
D06B58D018035B5A00656D97 /* SQRLTerminationListenerSpec.m */,
D0EDBEDB17B0DB3E0058BC3C /* SQRLTestCase.h */,
D0EDBEDC17B0DB3E0058BC3C /* SQRLTestCase.m */,
BE312942196B999300F1A675 /* SQRLTestHelper.h */,
BE312943196B999300F1A675 /* SQRLTestHelper.m */,
D0C22C4F179CC18C00158214 /* SQRLUpdaterSpec.m */,
5395C0E217E9D013001648E8 /* SQRLUpdateSpec.m */,
D000219817BAD35C0050109A /* SQRLZipArchiverSpec.m */,
@@ -908,7 +1073,8 @@
isa = PBXProject;
attributes = {
CLASSPREFIX = SQRL;
LastUpgradeCheck = 0510;
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0710;
ORGANIZATIONNAME = GitHub;
};
buildConfigurationList = D0C22BD1179CC00E00158214 /* Build configuration list for PBXProject "Squirrel" */;
@@ -949,7 +1115,6 @@
D08D4E1317B451500012B22D /* InfoPlist.strings in Resources */,
D08D4E2117B451500012B22D /* Images.xcassets in Resources */,
D08D4E1917B451500012B22D /* Credits.rtf in Resources */,
D0D97E4517B58FC400301C72 /* ResourceRules.plist in Resources */,
D03BE98D17B6174500458593 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -958,7 +1123,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D0C22BE5179CC00E00158214 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -966,11 +1130,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D0C22BFB179CC00E00158214 /* InfoPlist.strings in Resources */,
D08D4E4A17B451FD0012B22D /* TestApplication.app in Resources */,
D09D244A17B59AB30001FAF8 /* TestApplication 2.1.app in Resources */,
D000219717BAD34D0050109A /* TestApplication.app.zip in Resources */,
53710D8417D8F5CB00A992DE /* deep-codesign in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -989,16 +1151,76 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D0AFE36F1A0028A400C6048F /* RACReplaySubject.m in Sources */,
D0AFE3681A0028A400C6048F /* RACEmptySequence.m in Sources */,
D09C663F1A005433007D7ED0 /* NSEnumerator+RACSequenceAdditions.m in Sources */,
D09C66471A0055E6007D7ED0 /* NSDictionary+MTLManipulationAdditions.m in Sources */,
D0AFE34C1A00287100C6048F /* RACScheduler.m in Sources */,
D014AC1117B9789C007D79D0 /* SQRLInstaller.m in Sources */,
D043F77217FF40C90012F996 /* SQRLTerminationListener.m in Sources */,
D09C66481A0055E6007D7ED0 /* NSError+MTLModelException.m in Sources */,
D0AFE3781A0028A400C6048F /* RACTargetQueueScheduler.m in Sources */,
D0AFE3651A0028A400C6048F /* RACBlockTrampoline.m in Sources */,
D0AFE3711A0028A400C6048F /* RACScopedDisposable.m in Sources */,
D0AFE3661A0028A400C6048F /* RACCompoundDisposable.m in Sources */,
D0AFE37C1A0028B000C6048F /* RACCompoundDisposableProvider.d in Sources */,
D0AFE3441A00285000C6048F /* NSValueTransformer+MTLPredefinedTransformerAdditions.m in Sources */,
D0AFE38B1A0028EC00C6048F /* RACArraySequence.m in Sources */,
D06F7B101AD72DD30009A3BC /* RACKVOProxy.m in Sources */,
D0AFE3751A0028A400C6048F /* RACSubject.m in Sources */,
D014AC0517B97885007D79D0 /* ShipIt-main.m in Sources */,
D0AFE3431A00285000C6048F /* MTLReflection.m in Sources */,
D0AFE3741A0028A400C6048F /* RACStream.m in Sources */,
D0AFE38D1A0028EC00C6048F /* RACEagerSequence.m in Sources */,
D0AFE37A1A0028A400C6048F /* RACUnit.m in Sources */,
D0AFE34D1A00287100C6048F /* RACSignal.m in Sources */,
D09C663B1A00538D007D7ED0 /* RACObjCRuntime.m in Sources */,
D014AC1917B979A8007D79D0 /* SQRLCodeSignature.m in Sources */,
D0AFE34A1A00287100C6048F /* RACCommand.m in Sources */,
D09C66381A00537A007D7ED0 /* NSObject+RACDeallocating.m in Sources */,
5397A5D0187D92810014A477 /* SQRLShipItRequest.m in Sources */,
D09C66461A0055E6007D7ED0 /* NSArray+MTLManipulationAdditions.m in Sources */,
D06B58B618032B1500656D97 /* RACSignal+SQRLTransactionExtensions.m in Sources */,
D0AFE33D1A00282C00C6048F /* MTLValueTransformer.m in Sources */,
D0AFE3841A0028CC00C6048F /* RACTupleSequence.m in Sources */,
5397A5EC187DA2570014A477 /* SQRLInstallerOwnedBundle.m in Sources */,
D014AC1A17B979AA007D79D0 /* NSError+SQRLVerbosityExtensions.m in Sources */,
D09C66411A005592007D7ED0 /* MTLModel+NSCoding.m in Sources */,
D09C664B1A0055F3007D7ED0 /* NSValueTransformer+MTLInversionAdditions.m in Sources */,
D0AFE36E1A0028A400C6048F /* RACMulticastConnection.m in Sources */,
D0AFE34E1A00287100C6048F /* RACSignal+Operations.m in Sources */,
D09C66491A0055E6007D7ED0 /* NSObject+MTLComparisonAdditions.m in Sources */,
D0AFE38C1A0028EC00C6048F /* RACDynamicSequence.m in Sources */,
D09C662C1A005226007D7ED0 /* NSObject+RACKVOWrapper.m in Sources */,
D0AFE3821A0028CC00C6048F /* RACQueueScheduler.m in Sources */,
D0AFE3771A0028A400C6048F /* RACSubscriptionScheduler.m in Sources */,
D0AFE38E1A0028EC00C6048F /* RACUnarySequence.m in Sources */,
D0AFE33B1A00282C00C6048F /* MTLJSONAdapter.m in Sources */,
D09C66351A00535B007D7ED0 /* RACKVOTrampoline.m in Sources */,
88CA21981BD980FC006693B7 /* MTLEXTScope.m in Sources */,
D0AFE3691A0028A400C6048F /* RACEmptySignal.m in Sources */,
D09C66391A00537A007D7ED0 /* NSObject+RACDescription.m in Sources */,
D0D2B6271804E903000EA901 /* SQRLDirectoryManager.m in Sources */,
D0AFE36D1A0028A400C6048F /* RACImmediateScheduler.m in Sources */,
D0AFE36A1A0028A400C6048F /* RACErrorSignal.m in Sources */,
D0AFE3791A0028A400C6048F /* RACTuple.m in Sources */,
D0AFE3811A0028CC00C6048F /* RACPassthroughSubscriber.m in Sources */,
D0AFE3721A0028A400C6048F /* RACSerialDisposable.m in Sources */,
D0964B3E17F2E20B00D88BF7 /* NSBundle+SQRLVersionExtensions.m in Sources */,
D0AFE36C1A0028A400C6048F /* RACGroupedSignal.m in Sources */,
D0AFE34B1A00287100C6048F /* RACDisposable.m in Sources */,
D0AFE3731A0028A400C6048F /* RACSignalSequence.m in Sources */,
88CA21971BD980FC006693B7 /* MTLEXTRuntimeExtensions.m in Sources */,
D09C662D1A005226007D7ED0 /* NSObject+RACPropertySubscribing.m in Sources */,
D0AFE3861A0028D500C6048F /* RACSignalProvider.d in Sources */,
D0AFE36B1A0028A400C6048F /* RACEvent.m in Sources */,
D0AFE3831A0028CC00C6048F /* RACSequence.m in Sources */,
D0AFE3671A0028A400C6048F /* RACDynamicSignal.m in Sources */,
D0AFE3761A0028A400C6048F /* RACSubscriber.m in Sources */,
D0AFE33C1A00282C00C6048F /* MTLModel.m in Sources */,
D09C66291A00520B007D7ED0 /* NSArray+RACSequenceAdditions.m in Sources */,
D09C663D1A0053C6007D7ED0 /* NSString+RACKeyPathUtilities.m in Sources */,
D0AFE3701A0028A400C6048F /* RACReturnSignal.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1042,15 +1264,14 @@
D043F77E17FF43640012F996 /* SQRLTerminationListener.m in Sources */,
D09D244117B595470001FAF8 /* SQRLInstallerSpec.m in Sources */,
D0C22C50179CC18C00158214 /* SQRLUpdaterSpec.m in Sources */,
D0EDBEDD17B0DB3E0058BC3C /* SQRLTestCase.m in Sources */,
D0EDBEDD17B0DB3E0058BC3C /* QuickSpec+SQRLFixtures.m in Sources */,
D0AFE3901A00294100C6048F /* SwiftSpec.swift in Sources */,
D06B58D118035B5A00656D97 /* SQRLTerminationListenerSpec.m in Sources */,
5371815F18A29DC8005ED798 /* TestAppConstants.m in Sources */,
D0EDBEE117B0E3650058BC3C /* SQRLCodeSignatureSpec.m in Sources */,
53710D7417D8F59700A992DE /* SQRLDeepCodesignSpec.m in Sources */,
D00F5B8E17E82DE6009A4818 /* NSProcessInfoExtensionsSpec.m in Sources */,
D049059B180554BA004E683E /* SQRLDirectoryManagerSpec.m in Sources */,
5397A69D187DF8610014A477 /* SQRLInstallerOwnedBundle.m in Sources */,
BE312944196B999300F1A675 /* SQRLTestHelper.m in Sources */,
D061E40217FD580D00CC134A /* SQRLInstaller.m in Sources */,
D04905A0180558B7004E683E /* SQRLTestUpdate.m in Sources */,
D049059D18055671004E683E /* SQRLShipItRequestSpec.m in Sources */,
@@ -1112,22 +1333,6 @@
name = Credits.rtf;
sourceTree = "<group>";
};
D0C22BE3179CC00E00158214 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
D0C22BE4179CC00E00158214 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
D0C22BF9179CC00E00158214 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
D0C22BFA179CC00E00158214 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
@@ -1138,6 +1343,7 @@
GCC_PREFIX_HEADER = "TestService/TestService-Prefix.pch";
INFOPLIST_FILE = "TestService/TestService-Info.plist";
MACH_O_TYPE = mh_execute;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_NAME}";
PRODUCT_NAME = "com.github.Squirrel.TestApplication.$(TARGET_NAME:rfc1034identifier)";
WRAPPER_EXTENSION = xpc;
};
@@ -1150,6 +1356,7 @@
GCC_PREFIX_HEADER = "TestService/TestService-Prefix.pch";
INFOPLIST_FILE = "TestService/TestService-Info.plist";
MACH_O_TYPE = mh_execute;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_NAME}";
PRODUCT_NAME = "com.github.Squirrel.TestApplication.$(TARGET_NAME:rfc1034identifier)";
WRAPPER_EXTENSION = xpc;
};
@@ -1162,6 +1369,7 @@
GCC_PREFIX_HEADER = "TestService/TestService-Prefix.pch";
INFOPLIST_FILE = "TestService/TestService-Info.plist";
MACH_O_TYPE = mh_execute;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_NAME}";
PRODUCT_NAME = "com.github.Squirrel.TestApplication.$(TARGET_NAME:rfc1034identifier)";
WRAPPER_EXTENSION = xpc;
};
@@ -1174,6 +1382,7 @@
GCC_PREFIX_HEADER = "TestService/TestService-Prefix.pch";
INFOPLIST_FILE = "TestService/TestService-Info.plist";
MACH_O_TYPE = mh_execute;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_NAME}";
PRODUCT_NAME = "com.github.Squirrel.TestApplication.$(TARGET_NAME:rfc1034identifier)";
WRAPPER_EXTENSION = xpc;
};
@@ -1183,11 +1392,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C17179CC02E00158214 /* Mac-Application.xcconfig */;
buildSettings = {
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"mtl_copyPropertyAttributes=rac_copyPropertyAttributes",
"mtl_propertyAttributes=rac_propertyAttributes",
);
HEADER_SEARCH_PATHS = (
"\"$(BUILT_PRODUCTS_DIR)/include/\"",
"\"$(OBJROOT)/UninstalledProducts/include/\"",
"$(inherited)",
Carthage/Checkouts/Mantle,
"Carthage/Checkouts/ReactiveCocoa/**",
);
OTHER_LDFLAGS = "-all_load";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@@ -1197,11 +1411,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C17179CC02E00158214 /* Mac-Application.xcconfig */;
buildSettings = {
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"mtl_copyPropertyAttributes=rac_copyPropertyAttributes",
"mtl_propertyAttributes=rac_propertyAttributes",
);
HEADER_SEARCH_PATHS = (
"\"$(BUILT_PRODUCTS_DIR)/include/\"",
"\"$(OBJROOT)/UninstalledProducts/include/\"",
"$(inherited)",
Carthage/Checkouts/Mantle,
"Carthage/Checkouts/ReactiveCocoa/**",
);
OTHER_LDFLAGS = "-all_load";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@@ -1211,11 +1430,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C17179CC02E00158214 /* Mac-Application.xcconfig */;
buildSettings = {
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"mtl_copyPropertyAttributes=rac_copyPropertyAttributes",
"mtl_propertyAttributes=rac_propertyAttributes",
);
HEADER_SEARCH_PATHS = (
"\"$(BUILT_PRODUCTS_DIR)/include/\"",
"\"$(OBJROOT)/UninstalledProducts/include/\"",
"$(inherited)",
Carthage/Checkouts/Mantle,
"Carthage/Checkouts/ReactiveCocoa/**",
);
OTHER_LDFLAGS = "-all_load";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@@ -1225,11 +1449,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C17179CC02E00158214 /* Mac-Application.xcconfig */;
buildSettings = {
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"mtl_copyPropertyAttributes=rac_copyPropertyAttributes",
"mtl_propertyAttributes=rac_propertyAttributes",
);
HEADER_SEARCH_PATHS = (
"\"$(BUILT_PRODUCTS_DIR)/include/\"",
"\"$(OBJROOT)/UninstalledProducts/include/\"",
"$(inherited)",
Carthage/Checkouts/Mantle,
"Carthage/Checkouts/ReactiveCocoa/**",
);
OTHER_LDFLAGS = "-all_load";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@@ -1241,10 +1470,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_RESOURCE_RULES_PATH = TestApplication/ResourceRules.plist;
GCC_PREFIX_HEADER = "TestApplication/TestApplication-Prefix.pch";
INFOPLIST_FILE = "TestApplication/TestApplication-Info.plist";
OTHER_CODE_SIGN_FLAGS = "--timestamp=none";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.Squirrel.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
VALIDATE_PRODUCT = YES;
WRAPPER_EXTENSION = app;
@@ -1257,10 +1486,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_RESOURCE_RULES_PATH = TestApplication/ResourceRules.plist;
GCC_PREFIX_HEADER = "TestApplication/TestApplication-Prefix.pch";
INFOPLIST_FILE = "TestApplication/TestApplication-Info.plist";
OTHER_CODE_SIGN_FLAGS = "--timestamp=none";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.Squirrel.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
VALIDATE_PRODUCT = YES;
WRAPPER_EXTENSION = app;
@@ -1273,10 +1502,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_RESOURCE_RULES_PATH = TestApplication/ResourceRules.plist;
GCC_PREFIX_HEADER = "TestApplication/TestApplication-Prefix.pch";
INFOPLIST_FILE = "TestApplication/TestApplication-Info.plist";
OTHER_CODE_SIGN_FLAGS = "--timestamp=none";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.Squirrel.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
VALIDATE_PRODUCT = YES;
WRAPPER_EXTENSION = app;
@@ -1289,10 +1518,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_RESOURCE_RULES_PATH = TestApplication/ResourceRules.plist;
GCC_PREFIX_HEADER = "TestApplication/TestApplication-Prefix.pch";
INFOPLIST_FILE = "TestApplication/TestApplication-Info.plist";
OTHER_CODE_SIGN_FLAGS = "--timestamp=none";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.Squirrel.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
VALIDATE_PRODUCT = YES;
WRAPPER_EXTENSION = app;
@@ -1303,11 +1532,10 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C0B179CC02E00158214 /* Debug.xcconfig */;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PREFIX_HEADER = "Squirrel/Squirrel-Prefix.pch";
MACOSX_DEPLOYMENT_TARGET = 10.7;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
@@ -1316,12 +1544,8 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C0D179CC02E00158214 /* Release.xcconfig */;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PREFIX_HEADER = "Squirrel/Squirrel-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
MACOSX_DEPLOYMENT_TARGET = 10.7;
GCC_NO_COMMON_BLOCKS = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx;
};
name = Release;
@@ -1330,11 +1554,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C1A179CC02E00158214 /* Mac-Framework.xcconfig */;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
HEADER_SEARCH_PATHS = (
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "Squirrel/Squirrel-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
WRAPPER_EXTENSION = framework;
};
name = Debug;
@@ -1343,11 +1572,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C1A179CC02E00158214 /* Mac-Framework.xcconfig */;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
HEADER_SEARCH_PATHS = (
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "Squirrel/Squirrel-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
WRAPPER_EXTENSION = framework;
};
name = Release;
@@ -1360,13 +1594,13 @@
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PREFIX_HEADER = "SquirrelTests/SquirrelTests-Prefix.pch";
HEADER_SEARCH_PATHS = (
External/ReactiveCocoa/external/specta/src,
"External/ReactiveCocoa/external/expecta/src/**",
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "SquirrelTests/SquirrelTests-Info.plist";
OTHER_LDFLAGS = "-all_load";
MACOSX_DEPLOYMENT_TARGET = 10.9;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -1379,13 +1613,13 @@
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PREFIX_HEADER = "SquirrelTests/SquirrelTests-Prefix.pch";
HEADER_SEARCH_PATHS = (
External/ReactiveCocoa/external/specta/src,
"External/ReactiveCocoa/external/expecta/src/**",
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "SquirrelTests/SquirrelTests-Info.plist";
OTHER_LDFLAGS = "-all_load";
MACOSX_DEPLOYMENT_TARGET = 10.9;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@@ -1394,12 +1628,8 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C0C179CC02E00158214 /* Profile.xcconfig */;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PREFIX_HEADER = "Squirrel/Squirrel-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
MACOSX_DEPLOYMENT_TARGET = 10.7;
GCC_NO_COMMON_BLOCKS = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx;
};
name = Profile;
@@ -1408,11 +1638,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C1A179CC02E00158214 /* Mac-Framework.xcconfig */;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
HEADER_SEARCH_PATHS = (
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "Squirrel/Squirrel-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
WRAPPER_EXTENSION = framework;
};
name = Profile;
@@ -1425,13 +1660,13 @@
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PREFIX_HEADER = "SquirrelTests/SquirrelTests-Prefix.pch";
HEADER_SEARCH_PATHS = (
External/ReactiveCocoa/external/specta/src,
"External/ReactiveCocoa/external/expecta/src/**",
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "SquirrelTests/SquirrelTests-Info.plist";
OTHER_LDFLAGS = "-all_load";
MACOSX_DEPLOYMENT_TARGET = 10.9;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
@@ -1440,11 +1675,8 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C0E179CC02E00158214 /* Test.xcconfig */;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PREFIX_HEADER = "Squirrel/Squirrel-Prefix.pch";
MACOSX_DEPLOYMENT_TARGET = 10.7;
GCC_NO_COMMON_BLOCKS = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx;
};
name = Test;
@@ -1453,11 +1685,16 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D0C22C1A179CC02E00158214 /* Mac-Framework.xcconfig */;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
HEADER_SEARCH_PATHS = (
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "Squirrel/Squirrel-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
WRAPPER_EXTENSION = framework;
};
name = Test;
@@ -1470,13 +1707,13 @@
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PREFIX_HEADER = "SquirrelTests/SquirrelTests-Prefix.pch";
HEADER_SEARCH_PATHS = (
External/ReactiveCocoa/external/specta/src,
"External/ReactiveCocoa/external/expecta/src/**",
"$(inherited)",
Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/extobjc,
);
INFOPLIST_FILE = "SquirrelTests/SquirrelTests-Info.plist";
OTHER_LDFLAGS = "-all_load";
MACOSX_DEPLOYMENT_TARGET = 10.9;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0510"
version = "1.3">
LastUpgradeVersion = "0710"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
@@ -22,10 +22,10 @@
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0C22BEE179CC00E00158214"
@@ -37,10 +37,10 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Test">
shouldUseLaunchSchemeArgsEnv = "NO">
<Testables>
<TestableReference
skipped = "NO">
@@ -53,16 +53,45 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0C22BD6179CC00E00158214"
BuildableName = "Squirrel.framework"
BlueprintName = "Squirrel"
ReferencedContainer = "container:Squirrel.xcodeproj">
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key = "FORCE_APP_IDENTIFIER"
value = "com.github.Squirrel.SquirrelTests"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugXPCServices = "NO"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0C22BD6179CC00E00158214"
BuildableName = "Squirrel.framework"
BlueprintName = "Squirrel"
ReferencedContainer = "container:Squirrel.xcodeproj">
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key = "SQRLUpdateFromURL"
@@ -74,11 +103,20 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Profile"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0C22BD6179CC00E00158214"
BuildableName = "Squirrel.framework"
BlueprintName = "Squirrel"
ReferencedContainer = "container:Squirrel.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0510"
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -23,10 +23,10 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Test">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
@@ -38,17 +38,21 @@
ReferencedContainer = "container:Squirrel.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D08D4E0B17B451500012B22D"
@@ -61,12 +65,13 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D08D4E0B17B451500012B22D"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0510"
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -23,30 +23,42 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Test">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D014AC0017B97885007D79D0"
BuildableName = "ShipIt"
BlueprintName = "ShipIt"
ReferencedContainer = "container:Squirrel.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
+8 -8
View File
@@ -5,18 +5,18 @@
location = "group:Squirrel.xcodeproj">
</FileRef>
<FileRef
location = "group:External/Mantle/Mantle.xcodeproj">
location = "group:Carthage/Checkouts/Mantle/Mantle.xcodeproj">
</FileRef>
<FileRef
location = "group:External/ReactiveCocoa/ReactiveCocoaFramework/ReactiveCocoa.xcodeproj">
</FileRef>
<FileRef
location = "group:External/ReactiveCocoa/external/specta/Specta.xcodeproj">
</FileRef>
<FileRef
location = "group:External/ReactiveCocoa/external/expecta/Expecta.xcodeproj">
location = "group:Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa.xcodeproj">
</FileRef>
<FileRef
location = "group:External/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj">
</FileRef>
<FileRef
location = "group:Carthage/Checkouts/Quick/Quick.xcodeproj">
</FileRef>
<FileRef
location = "group:Carthage/Checkouts/Nimble/Nimble.xcodeproj">
</FileRef>
</Workspace>
@@ -14,4 +14,7 @@
// Info.plist, or nil if the key is not present.
@property (nonatomic, copy, readonly) NSString *sqrl_bundleVersion;
/// The value of the `kCFBundleExecutableKey` key.
@property (nonatomic, copy, readonly) NSString *sqrl_executableName;
@end
@@ -14,4 +14,8 @@
return [self objectForInfoDictionaryKey:(id)kCFBundleVersionKey];
}
- (NSString *)sqrl_executableName {
return [self objectForInfoDictionaryKey:(id)kCFBundleExecutableKey];
}
@end
@@ -6,7 +6,7 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <ReactiveCocoa/RACSignal.h>
@interface RACSignal (SQRLTransactionExtensions)
@@ -7,6 +7,8 @@
//
#import "RACSignal+SQRLTransactionExtensions.h"
#import <ReactiveCocoa/RACDisposable.h>
#import <IOKit/pwr_mgt/IOPMLib.h>
// How long before power assertions time out.
+5 -2
View File
@@ -7,8 +7,11 @@
//
#import "SQRLCodeSignature.h"
#import <ReactiveCocoa/EXTScope.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "EXTKeyPathCoding.h"
#import "EXTScope.h"
#import <ReactiveCocoa/RACSignal+Operations.h>
#import <ReactiveCocoa/RACSubscriber.h>
#import <Security/Security.h>
NSString * const SQRLCodeSignatureErrorDomain = @"SQRLCodeSignatureErrorDomain";
+13 -3
View File
@@ -6,7 +6,7 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
@class RACSignal;
@@ -29,14 +29,24 @@
// on-disk locations for. This must not be nil.
- (instancetype)initWithApplicationIdentifier:(NSString *)appIdentifier;
// Finds or creates an Application Support folder.
// Finds or creates a storage folder.
//
// Returns a signal which synchronously sends a URL then completes, or errors.
- (RACSignal *)applicationSupportURL;
- (RACSignal *)storageURL;
// Determines where archived `SQRLShipItState` should be saved.
//
// Returns a signal which synchronously sends a URL then completes, or errors.
- (RACSignal *)shipItStateURL;
// Determines where ShipIt's stdout log should be saved.
//
// Returns a signal which synchronously sends a URL then completes, or errors.
- (RACSignal *)shipItStdoutURL;
// Determines where ShipIt's stderr log should be saved.
//
// Returns a signal which synchronously sends a URL then completes, or errors.
- (RACSignal *)shipItStderrURL;
@end
+25 -6
View File
@@ -7,7 +7,8 @@
//
#import "SQRLDirectoryManager.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <ReactiveCocoa/RACSignal+Operations.h>
@implementation SQRLDirectoryManager
@@ -23,7 +24,7 @@
// Should only fallback to when running under otest, where
// NSBundle.mainBundle doesn't return useful data.
if (identifier == nil) {
identifier = NSRunningApplication.currentApplication.localizedName;
identifier = NSProcessInfo.processInfo.environment[@"FORCE_APP_IDENTIFIER"];
}
NSAssert(identifier != nil, @"Could not automatically determine the current application's identifier");
@@ -46,11 +47,11 @@
#pragma mark Folder URLs
- (RACSignal *)applicationSupportURL {
- (RACSignal *)storageURL {
return [[RACSignal
defer:^{
NSError *error = nil;
NSURL *folderURL = [NSFileManager.defaultManager URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
NSURL *folderURL = [NSFileManager.defaultManager URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
if (folderURL == nil) {
return [RACSignal error:error];
}
@@ -62,18 +63,36 @@
return [RACSignal return:folderURL];
}]
setNameWithFormat:@"%@ -applicationSupportURL", self];
setNameWithFormat:@"%@ -storageURL", self];
}
- (RACSignal *)shipItStateURL {
return [[[self
applicationSupportURL]
storageURL]
map:^(NSURL *folderURL) {
return [folderURL URLByAppendingPathComponent:@"ShipItState.plist"];
}]
setNameWithFormat:@"%@ -shipItStateURL", self];
}
- (RACSignal *)shipItStdoutURL {
return [[[self
storageURL]
map:^(NSURL *folderURL) {
return [folderURL URLByAppendingPathComponent:@"ShipIt_stdout.log"];
}]
setNameWithFormat:@"%@ -shipItStdoutURL", self];
}
- (RACSignal *)shipItStderrURL {
return [[[self
storageURL]
map:^(NSURL *folderURL) {
return [folderURL URLByAppendingPathComponent:@"ShipIt_stderr.log"];
}]
setNameWithFormat:@"%@ -shipItStderrURL", self];
}
#pragma mark NSObject
- (NSString *)description {
+2 -2
View File
@@ -40,9 +40,9 @@
#pragma mark MTLJSONSerializing
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return [super.JSONKeyPathsByPropertyKey mtl_dictionaryByAddingEntriesFromDictionary:@{
return @{
@keypath(SQRLDownloadedUpdate.new, bundleURL): NSNull.null
}];
};
}
@end
+83 -22
View File
@@ -7,6 +7,17 @@
//
#import "SQRLInstaller.h"
#import <libkern/OSAtomic.h>
#import "EXTScope.h"
#import <ReactiveCocoa/NSEnumerator+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSObject+RACPropertySubscribing.h>
#import <ReactiveCocoa/RACCommand.h>
#import <ReactiveCocoa/RACSequence.h>
#import <ReactiveCocoa/RACSignal+Operations.h>
#import <ReactiveCocoa/RACSubscriber.h>
#import <sys/xattr.h>
#import "NSBundle+SQRLVersionExtensions.h"
#import "NSError+SQRLVerbosityExtensions.h"
#import "RACSignal+SQRLTransactionExtensions.h"
@@ -14,10 +25,6 @@
#import "SQRLDirectoryManager.h"
#import "SQRLShipItRequest.h"
#import "SQRLTerminationListener.h"
#import <libkern/OSAtomic.h>
#import <ReactiveCocoa/EXTScope.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <sys/xattr.h>
#import "SQRLInstallerOwnedBundle.h"
NSString * const SQRLInstallerErrorDomain = @"SQRLInstallerErrorDomain";
@@ -165,7 +172,7 @@ NSString * const SQRLInstallerOwnedBundleKey = @"SQRLInstallerOwnedBundle";
return [self abortInstall];
}];
return self;
}
@@ -255,27 +262,49 @@ NSString * const SQRLInstallerOwnedBundleKey = @"SQRLInstallerOwnedBundle";
setNameWithFormat:@"%@ -acquireTargetBundleURLForRequest: %@", self, request];
}
- (RACSignal *)renameIfNeeded:(SQRLShipItRequest *)request updateBundleURL:(NSURL *)updateBundleURL {
if (!request.useUpdateBundleName) return [RACSignal return:request];
return [[self
renamedTargetIfNeededWithTargetURL:request.targetBundleURL sourceURL:updateBundleURL]
flattenMap:^(NSURL *newTargetURL) {
if ([newTargetURL isEqual:request.targetBundleURL]) return [RACSignal return:request];
SQRLShipItRequest *updatedRequest = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:request.updateBundleURL targetBundleURL:newTargetURL bundleIdentifier:request.bundleIdentifier launchAfterInstallation:request.launchAfterInstallation useUpdateBundleName:request.useUpdateBundleName];
return [[self
installItemToURL:newTargetURL fromURL:request.targetBundleURL]
concat:[RACSignal return:updatedRequest]];
}];
}
- (RACSignal *)installRequest:(SQRLShipItRequest *)request {
NSParameterAssert(request != nil);
return [[[[self
prepareAndValidateUpdateBundleURLForRequest:request]
flattenMap:^(NSURL *updateBundleURL) {
return [[[[[[[self
acquireTargetBundleURLForRequest:request]
concat:[self installItemToURL:request.targetBundleURL fromURL:updateBundleURL]]
concat:[RACSignal return:request.updateBundleURL]]
concat:[RACSignal return:updateBundleURL]]
concat:[RACSignal defer:^{
return [RACSignal return:self.ownedBundle.temporaryURL];
}]]
flattenMap:^(NSURL *location) {
return [[[self
deleteOwnedBundleAtURL:location]
doError:^(NSError *error) {
NSLog(@"Couldn't remove owned bundle at location %@, error %@", location, error.sqrl_verboseDescription);
return [[[[self
renameIfNeeded:request updateBundleURL:updateBundleURL]
flattenMap:^(SQRLShipItRequest *request) {
return [[self acquireTargetBundleURLForRequest:request] concat:[RACSignal return:request]];
}]
flattenMap:^(SQRLShipItRequest *request) {
return [[[[[[self
installItemToURL:request.targetBundleURL fromURL:updateBundleURL]
concat:[RACSignal return:request.updateBundleURL]]
concat:[RACSignal return:updateBundleURL]]
concat:[RACSignal defer:^{
return [RACSignal return:self.ownedBundle.temporaryURL];
}]]
flattenMap:^(NSURL *location) {
return [[[self
deleteOwnedBundleAtURL:location]
doError:^(NSError *error) {
NSLog(@"Couldn't remove owned bundle at location %@, error %@", location, error.sqrl_verboseDescription);
}]
catchTo:[RACSignal empty]];
}]
catchTo:[RACSignal empty]];
concat:[RACSignal return:request]];
}]
doCompleted:^{
self.ownedBundle = nil;
@@ -406,6 +435,36 @@ NSString * const SQRLInstallerOwnedBundleKey = @"SQRLInstallerOwnedBundle";
#pragma mark Installation
/// Check if the target should be renamed and provide the renamed URL.
///
/// targetURL - The URL for the target. Cannot be nil.
/// sourceURL - The URL for the source. Cannot be nil.
///
/// Returns a signal which will send the URL for the renamed target. If a rename
/// isn't needed then it will send `targetURL`.
- (RACSignal *)renamedTargetIfNeededWithTargetURL:(NSURL *)targetURL sourceURL:(NSURL *)sourceURL {
return [RACSignal defer:^{
NSBundle *sourceBundle = [NSBundle bundleWithURL:sourceURL];
NSString *targetExecutableName = targetURL.lastPathComponent.stringByDeletingPathExtension;
NSString *sourceExecutableName = sourceBundle.sqrl_executableName;
// If they're already the same then we're good.
if ([targetExecutableName isEqual:sourceExecutableName]) {
return [RACSignal return:targetURL];
}
NSString *newAppName = [sourceExecutableName stringByAppendingPathExtension:@"app"];
NSURL *newTargetURL = [targetURL.URLByDeletingLastPathComponent URLByAppendingPathComponent:newAppName];
// If there's already something there then don't rename to it.
if ([NSFileManager.defaultManager fileExistsAtPath:newTargetURL.path]) {
return [RACSignal return:targetURL];
}
return [RACSignal return:newTargetURL];
}];
}
- (RACSignal *)installItemToURL:(NSURL *)targetURL fromURL:(NSURL *)sourceURL {
NSParameterAssert(targetURL != nil);
NSParameterAssert(sourceURL != nil);
@@ -418,7 +477,7 @@ NSString * const SQRLInstallerOwnedBundleKey = @"SQRLInstallerOwnedBundle";
} else {
int code = errno;
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
const char *desc = strerror(code);
if (desc != NULL) userInfo[NSLocalizedDescriptionKey] = @(desc);
@@ -470,7 +529,7 @@ NSString * const SQRLInstallerOwnedBundleKey = @"SQRLInstallerOwnedBundle";
// file to begin with.
if (code != ENOATTR) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
const char *desc = strerror(code);
if (desc != NULL) userInfo[NSLocalizedDescriptionKey] = @(desc);
@@ -526,7 +585,9 @@ NSString * const SQRLInstallerOwnedBundleKey = @"SQRLInstallerOwnedBundle";
return NO;
}];
return [enumerator.rac_sequence.signal subscribe:subscriber];
return [[enumerator.rac_sequence.signal
startWith:directoryURL]
subscribe:subscriber];
}]
flattenMap:^(NSURL *itemURL) {
return [[[self
+1 -1
View File
@@ -8,7 +8,7 @@
#import "SQRLInstallerOwnedBundle.h"
#import <ReactiveCocoa/EXTKeyPathCoding.h>
#import "EXTKeyPathCoding.h"
@implementation SQRLInstallerOwnedBundle
+5 -10
View File
@@ -22,8 +22,7 @@ const NSInteger SQRLShipItLauncherErrorCouldNotStartService = 1;
@implementation SQRLShipItLauncher
+ (NSString *)shipItJobLabel {
NSString *currentAppIdentifier = NSBundle.mainBundle.bundleIdentifier ?: [NSString stringWithFormat:@"%@:%d", NSProcessInfo.processInfo.processName, NSProcessInfo.processInfo.processIdentifier];
return [currentAppIdentifier stringByAppendingString:@".ShipIt"];
return [SQRLDirectoryManager.currentApplicationManager.applicationIdentifier stringByAppendingString:@".ShipIt"];
}
+ (RACSignal *)shipItJobDictionary {
@@ -32,9 +31,9 @@ const NSInteger SQRLShipItLauncherErrorCouldNotStartService = 1;
return [[[RACSignal
defer:^{
SQRLDirectoryManager *directoryManager = [[SQRLDirectoryManager alloc] initWithApplicationIdentifier:jobLabel];
return [directoryManager applicationSupportURL];
return [RACSignal zip:@[ [directoryManager shipItStdoutURL], [directoryManager shipItStderrURL] ]];
}]
map:^(NSURL *appSupportURL) {
reduceEach:^(NSURL *stdoutURL, NSURL *stderrURL) {
NSBundle *squirrelBundle = [NSBundle bundleForClass:self.class];
NSAssert(squirrelBundle != nil, @"Could not open Squirrel.framework bundle");
@@ -58,13 +57,9 @@ const NSInteger SQRLShipItLauncherErrorCouldNotStartService = 1;
[arguments addObject:jobLabel];
jobDict[@(LAUNCH_JOBKEY_PROGRAMARGUMENTS)] = arguments;
jobDict[@(LAUNCH_JOBKEY_STANDARDOUTPATH)] = [appSupportURL URLByAppendingPathComponent:@"ShipIt_stdout.log"].path;
jobDict[@(LAUNCH_JOBKEY_STANDARDERRORPATH)] = [appSupportURL URLByAppendingPathComponent:@"ShipIt_stderr.log"].path;
jobDict[@(LAUNCH_JOBKEY_STANDARDOUTPATH)] = stdoutURL.path;
jobDict[@(LAUNCH_JOBKEY_STANDARDERRORPATH)] = stderrURL.path;
#if DEBUG
jobDict[@(LAUNCH_JOBKEY_DEBUG)] = @YES;
#endif
return jobDict;
}]
setNameWithFormat:@"+shipItJobDictionary"];
+5 -1
View File
@@ -73,10 +73,11 @@ extern NSString * const SQRLShipItRequestPropertyErrorKey;
// installing. Can be nil.
// launchAfterInstallation - Whether the updated application should be launched
// after installation.
// useUpdateBundleName - Should the target use the update bundle's name?
//
// Returns a request which can be written to disk for ShipIt to read and
// perform.
- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation;
- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation useUpdateBundleName:(BOOL)useUpdateBundleName;
// The URL to the downloaded update's app bundle.
@property (nonatomic, copy, readonly) NSURL *updateBundleURL;
@@ -93,4 +94,7 @@ extern NSString * const SQRLShipItRequestPropertyErrorKey;
// Whether to launch the application after an update is successfully installed.
@property (nonatomic, assign, readonly) BOOL launchAfterInstallation;
// Whether the app should use the update bundle's name.
@property (nonatomic, assign, readonly) BOOL useUpdateBundleName;
@end
+4 -2
View File
@@ -8,7 +8,8 @@
#import "SQRLShipItRequest.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "EXTKeyPathCoding.h"
#import <ReactiveCocoa/RACSignal+Operations.h>
NSString * const SQRLShipItRequestErrorDomain = @"SQRLShipItRequestErrorDomain";
@@ -46,12 +47,13 @@ NSString * const SQRLShipItRequestPropertyErrorKey = @"SQRLShipItRequestProperty
return self;
}
- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation {
- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation useUpdateBundleName:(BOOL)useUpdateBundleName {
return [self initWithDictionary:@{
@keypath(self.updateBundleURL): updateBundleURL,
@keypath(self.targetBundleURL): targetBundleURL,
@keypath(self.bundleIdentifier): bundleIdentifier ?: NSNull.null,
@keypath(self.launchAfterInstallation): @(launchAfterInstallation),
@keypath(self.useUpdateBundleName): @(useUpdateBundleName),
} error:NULL];
}
+1 -1
View File
@@ -6,7 +6,7 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
@class RACSignal;
+8 -2
View File
@@ -7,7 +7,14 @@
//
#import "SQRLTerminationListener.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "EXTKeyPathCoding.h"
#import <ReactiveCocoa/NSArray+RACSequenceAdditions.h>
#import <ReactiveCocoa/RACDisposable.h>
#import <ReactiveCocoa/RACScheduler.h>
#import <ReactiveCocoa/RACSequence.h>
#import <ReactiveCocoa/RACSignal+Operations.h>
#import <ReactiveCocoa/RACSubscriber.h>
@interface SQRLTerminationListener ()
@@ -74,7 +81,6 @@
dispatch_resume(source);
return [RACDisposable disposableWithBlock:^{
dispatch_source_cancel(source);
dispatch_release(source);
}];
}]
setNameWithFormat:@"%@ -waitForTerminationOfProcessIdentifier: %i", self, (int)processIdentifier];
+1 -1
View File
@@ -74,7 +74,7 @@ NSString * const SQRLUpdateJSONPublicationDateKey = @"pub_date";
+ (NSValueTransformer *)releaseDateJSONTransformer {
// ISO 8601 Time Zone with ':'
NSString * const ISO8601DateFormat = @"yyyy'-'MM'-'DD'T'HH':'mm':'ssZZZZZ";
NSString * const ISO8601DateFormat = @"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ";
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^ NSDate * (NSString *dateString) {
if (![dateString isKindOfClass:NSString.class]) return nil;
+3
View File
@@ -6,6 +6,9 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
// Represents the current state of the updater.
//
// SQRLUpdaterStateIdle - Doing absolutely diddly squat.
+104 -48
View File
@@ -40,6 +40,10 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
@property (atomic, readwrite) SQRLUpdaterState state;
/// The etag of the currently downloaded update, nil if no update has been
/// downloaded.
@property (atomic, copy) NSString *etag;
// The code signature for the running application, used to check updates before
// sending them to ShipIt.
@property (nonatomic, strong, readonly) SQRLCodeSignature *signature;
@@ -49,16 +53,6 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
// Sends completed or error.
@property (nonatomic, strong, readonly) RACSignal *shipItLauncher;
// Lazily removes outdated temporary directories (used for previous updates)
// upon first subscription.
//
// Pruning directories while an update is pending or in progress will result in
// undefined behavior.
//
// Sends each removed directory then completes, or errors, on an unspecified
// thread.
@property (nonatomic, strong, readonly) RACSignal *prunedUpdateDirectories;
// Parses an update model from downloaded data.
//
// data - JSON data representing an update manifest. This must not be nil.
@@ -169,33 +163,6 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
BOOL updatesDisabled = (getenv("DISABLE_UPDATE_CHECK") != NULL);
@weakify(self);
_prunedUpdateDirectories = [[[[RACSignal
defer:^{
SQRLDirectoryManager *directoryManager = [[SQRLDirectoryManager alloc] initWithApplicationIdentifier:SQRLShipItLauncher.shipItJobLabel];
return [directoryManager applicationSupportURL];
}]
flattenMap:^(NSURL *appSupportURL) {
NSFileManager *manager = [[NSFileManager alloc] init];
NSDirectoryEnumerator *enumerator = [manager enumeratorAtURL:appSupportURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:^(NSURL *URL, NSError *error) {
NSLog(@"Error enumerating item %@ within directory %@: %@", URL, appSupportURL, error);
return YES;
}];
return [[enumerator.rac_sequence.signal
filter:^(NSURL *enumeratedURL) {
NSString *name = enumeratedURL.lastPathComponent;
return [name hasPrefix:SQRLUpdaterUniqueTemporaryDirectoryPrefix];
}]
doNext:^(NSURL *directoryURL) {
NSError *error = nil;
if (![manager removeItemAtURL:directoryURL error:&error]) {
NSLog(@"Error removing old update directory at %@: %@", directoryURL, error.sqrl_verboseDescription);
}
}];
}]
replayLazily]
setNameWithFormat:@"%@ -prunedUpdateDirectories", self];
_checkForUpdatesCommand = [[RACCommand alloc] initWithEnabled:[RACSignal return:@(!updatesDisabled)] signalBlock:^(id _) {
@strongify(self);
NSParameterAssert(self.updateRequest != nil);
@@ -204,12 +171,8 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
NSMutableURLRequest *request = [self.updateRequest mutableCopy];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
// Prune old updates before the first update check.
return [[[[[[[[self.prunedUpdateDirectories
catch:^(NSError *error) {
NSLog(@"Error pruning old updates: %@", error);
return [RACSignal empty];
}]
return [[[[[[[[self
performHousekeeping]
then:^{
self.state = SQRLUpdaterStateCheckingForUpdate;
@@ -365,12 +328,20 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
NSURL *zipDownloadURL = update.updateURL;
NSMutableURLRequest *zipDownloadRequest = [NSMutableURLRequest requestWithURL:zipDownloadURL];
[zipDownloadRequest setValue:@"application/zip" forHTTPHeaderField:@"Accept"];
if (self.etag != nil) {
[zipDownloadRequest setValue:self.etag forHTTPHeaderField:@"If-None-Match"];
}
return [[[[NSURLConnection
rac_sendAsynchronousRequest:zipDownloadRequest]
reduceEach:^(NSURLResponse *response, NSData *bodyData) {
if ([response isKindOfClass:NSHTTPURLResponse.class]) {
NSHTTPURLResponse *httpResponse = (id)response;
if (httpResponse.statusCode == 304 /* Not Modified */) {
return [RACSignal empty];
}
if (!(httpResponse.statusCode >= 200 && httpResponse.statusCode <= 299)) {
NSDictionary *errorInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"Update download failed", nil),
@@ -380,6 +351,8 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
NSError *error = [NSError errorWithDomain:SQRLUpdaterErrorDomain code:SQRLUpdaterErrorInvalidServerResponse userInfo:errorInfo];
return [RACSignal error:error];
}
self.etag = httpResponse.allHeaderFields[@"ETag"];
}
return [RACSignal return:bodyData];
@@ -421,10 +394,10 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
return [[[RACSignal
defer:^{
SQRLDirectoryManager *directoryManager = [[SQRLDirectoryManager alloc] initWithApplicationIdentifier:SQRLShipItLauncher.shipItJobLabel];
return [directoryManager applicationSupportURL];
return [directoryManager storageURL];
}]
flattenMap:^(NSURL *appSupportURL) {
NSURL *updateDirectoryTemplate = [appSupportURL URLByAppendingPathComponent:[SQRLUpdaterUniqueTemporaryDirectoryPrefix stringByAppendingString:@"XXXXXXX"]];
flattenMap:^(NSURL *storageURL) {
NSURL *updateDirectoryTemplate = [storageURL URLByAppendingPathComponent:[SQRLUpdaterUniqueTemporaryDirectoryPrefix stringByAppendingString:@"XXXXXXX"]];
char *updateDirectoryCString = strdup(updateDirectoryTemplate.path.fileSystemRepresentation);
@onExit {
free(updateDirectoryCString);
@@ -502,6 +475,84 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
setNameWithFormat:@"%@ -shipItStateURL", self];
}
- (RACSignal *)performHousekeeping {
return [[RACSignal
merge:@[ [self pruneUpdateDirectories], [self truncateLogs] ]]
catch:^(NSError *error) {
NSLog(@"Error doing housekeeping: %@", error);
return [RACSignal empty];
}];
}
/// Lazily removes outdated temporary directories (used for previous updates)
/// upon subscription.
///
/// Pruning directories while an update is pending or in progress will result in
/// undefined behavior.
///
/// Sends each removed directory then completes, or errors, on an unspecified
/// thread.
- (RACSignal *)pruneUpdateDirectories {
return [[[RACSignal
defer:^{
SQRLDirectoryManager *directoryManager = [[SQRLDirectoryManager alloc] initWithApplicationIdentifier:SQRLShipItLauncher.shipItJobLabel];
return [directoryManager storageURL];
}]
flattenMap:^(NSURL *storageURL) {
NSFileManager *manager = [[NSFileManager alloc] init];
NSDirectoryEnumerator *enumerator = [manager enumeratorAtURL:storageURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:^(NSURL *URL, NSError *error) {
NSLog(@"Error enumerating item %@ within directory %@: %@", URL, storageURL, error);
return YES;
}];
return [[enumerator.rac_sequence.signal
filter:^(NSURL *enumeratedURL) {
NSString *name = enumeratedURL.lastPathComponent;
return [name hasPrefix:SQRLUpdaterUniqueTemporaryDirectoryPrefix];
}]
doNext:^(NSURL *directoryURL) {
NSError *error = nil;
if (![manager removeItemAtURL:directoryURL error:&error]) {
NSLog(@"Error removing old update directory at %@: %@", directoryURL, error.sqrl_verboseDescription);
}
}];
}]
setNameWithFormat:@"%@ -prunedUpdateDirectories", self];
}
// Like truncation, but backwards.
- (RACSignal *)backwardTruncateFile:(NSURL *)fileURL {
return [RACSignal defer:^{
static const NSInteger MAX_LENGTH = 1024 * 1024 * 8;
NSError *error;
NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:fileURL error:&error];
if (handle == nil) return [RACSignal error:error];
unsigned long long fileLength = [handle seekToEndOfFile];
if (fileLength <= MAX_LENGTH) return [RACSignal empty];
[handle seekToFileOffset:fileLength - MAX_LENGTH];
NSData *mostRecentData = [handle readDataToEndOfFile];
[handle truncateFileAtOffset:0];
[handle writeData:mostRecentData];
return [RACSignal empty];
}];
}
- (RACSignal *)truncateLogs {
return [[RACSignal
defer:^{
SQRLDirectoryManager *directoryManager = [[SQRLDirectoryManager alloc] initWithApplicationIdentifier:SQRLShipItLauncher.shipItJobLabel];
return [RACSignal zip:@[ [directoryManager shipItStdoutURL], [directoryManager shipItStderrURL] ]];
}]
reduceEach:^(NSURL *stdoutURL, NSURL *stderrURL) {
return [RACSignal merge:@[ [self backwardTruncateFile:stdoutURL], [self backwardTruncateFile:stderrURL] ]];
}];
}
#pragma mark Installing Updates
- (RACSignal *)verifyAndPrepareUpdate:(SQRLUpdate *)update fromBundle:(NSBundle *)updateBundle {
@@ -528,7 +579,12 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
return [[[[RACSignal
defer:^{
NSRunningApplication *currentApplication = NSRunningApplication.currentApplication;
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:update.bundle.bundleURL targetBundleURL:currentApplication.bundleURL bundleIdentifier:currentApplication.bundleIdentifier launchAfterInstallation:NO];
NSBundle *appBundle = [NSBundle bundleWithURL:currentApplication.bundleURL];
// Only use the update bundle's name if the user hasn't renamed the
// app themselves.
BOOL useUpdateBundleName = [appBundle.sqrl_executableName isEqual:currentApplication.bundleURL.lastPathComponent.stringByDeletingPathExtension];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:update.bundle.bundleURL targetBundleURL:currentApplication.bundleURL bundleIdentifier:currentApplication.bundleIdentifier launchAfterInstallation:NO useUpdateBundleName:useUpdateBundleName];
return [request writeUsingURL:self.shipItStateURL];
}]
then:^{
@@ -542,7 +598,7 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
return [[[[[[[[SQRLShipItRequest
readUsingURL:self.shipItStateURL]
map:^(SQRLShipItRequest *request) {
return [[SQRLShipItRequest alloc] initWithUpdateBundleURL:request.updateBundleURL targetBundleURL:request.targetBundleURL bundleIdentifier:request.bundleIdentifier launchAfterInstallation:YES];
return [[SQRLShipItRequest alloc] initWithUpdateBundleURL:request.updateBundleURL targetBundleURL:request.targetBundleURL bundleIdentifier:request.bundleIdentifier launchAfterInstallation:YES useUpdateBundleName:request.useUpdateBundleName];
}]
flattenMap:^(SQRLShipItRequest *request) {
return [[request
+12 -7
View File
@@ -7,8 +7,12 @@
//
#import <Foundation/Foundation.h>
#import <ReactiveCocoa/EXTScope.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "EXTScope.h"
#import <ReactiveCocoa/RACCommand.h>
#import <ReactiveCocoa/RACSignal+Operations.h>
#import <ReactiveCocoa/RACScheduler.h>
#import "NSError+SQRLVerbosityExtensions.h"
#import "RACSignal+SQRLTransactionExtensions.h"
#import "SQRLDirectoryManager.h"
@@ -71,7 +75,7 @@ static void installRequest(RACSignal *readRequestSignal, SQRLDirectoryManager *d
RACSignal *action;
if (attempt > SQRLShipItMaximumInstallationAttempts) {
action = [[[installer.abortInstallationCommand
action = [[[[installer.abortInstallationCommand
execute:request]
initially:^{
NSLog(@"Too many attempts to install, aborting update");
@@ -82,7 +86,8 @@ static void installRequest(RACSignal *readRequestSignal, SQRLDirectoryManager *d
// Exit successfully so launchd doesn't restart us
// again.
return [RACSignal empty];
}];
}]
concat:[RACSignal return:request]];
} else {
action = [[[[installer.installUpdateCommand
execute:request]
@@ -110,15 +115,15 @@ static void installRequest(RACSignal *readRequestSignal, SQRLDirectoryManager *d
// Launch regardless of whether installation succeeds or fails.
action = [[action
deliverOn:RACScheduler.mainThreadScheduler]
finally:^{
NSURL *bundleURL = request.targetBundleURL;
doNext:^(SQRLShipItRequest *finalRequest) {
NSURL *bundleURL = finalRequest.targetBundleURL;
if (bundleURL == nil) {
NSLog(@"Missing target bundle URL, cannot launch application");
return;
}
NSError *error;
if (![NSWorkspace.sharedWorkspace launchApplicationAtURL:bundleURL options:NSWorkspaceLaunchDefault configuration:nil error:&error]) {
if (![NSWorkspace.sharedWorkspace launchApplicationAtURL:bundleURL options:NSWorkspaceLaunchDefault configuration:@{} error:&error]) {
NSLog(@"Could not launch application at %@: %@", bundleURL, error);
return;
}
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.github.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
-8
View File
@@ -1,8 +0,0 @@
//
// Prefix header for all source files of the 'Squirrel' target in the 'Squirrel' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#import <SystemConfiguration/SystemConfiguration.h>
#endif
+8
View File
@@ -6,6 +6,14 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for Squirrel.
FOUNDATION_EXPORT double SquirrelVersionNumber;
//! Project version string for Squirrel.
FOUNDATION_EXPORT const unsigned char SquirrelVersionString[];
#import <Squirrel/NSBundle+SQRLVersionExtensions.h>
#import <Squirrel/NSProcessInfo+SQRLVersionExtensions.h>
#import <Squirrel/SQRLDownloadedUpdate.h>
-2
View File
@@ -1,2 +0,0 @@
/* Localized versions of Info.plist keys */
+12 -7
View File
@@ -6,30 +6,35 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
SpecBegin(NSProcessInfoExtensions)
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
QuickSpecBegin(NSProcessInfoExtensions)
describe(@"-sqrl_operatingSystemShortVersionString", ^{
__block NSString *versionString;
beforeEach(^{
versionString = NSProcessInfo.processInfo.sqrl_operatingSystemShortVersionString;
expect(versionString).notTo.beNil();
expect(versionString).notTo(beNil());
});
it(@"should follow major.minor.patch format", ^{
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]+(\\.[0-9]+)*$" options:0 error:&error];
expect(regex).notTo.beNil();
expect(error).to.beNil();
expect(regex).notTo(beNil());
expect(error).to(beNil());
NSRange fullRange = NSMakeRange(0, versionString.length);
NSRange matchRange = [regex rangeOfFirstMatchInString:versionString options:0 range:fullRange];
expect(NSEqualRanges(matchRange, fullRange)).to.beTruthy();
expect(@(NSEqualRanges(matchRange, fullRange))).to(beTruthy());
});
it(@"should be numerically comparable", ^{
expect([@"10.6.9" compare:versionString options:NSNumericSearch]).to.equal(NSOrderedAscending);
expect(@([@"10.6.9" compare:versionString options:NSNumericSearch])).to(equal(@(NSOrderedAscending)));
});
});
SpecEnd
QuickSpecEnd
@@ -1,11 +1,19 @@
//
// SQRLTestCase.h
// QuickSpec+SQRLFixtures.h
// Squirrel
//
// Created by Justin Spahr-Summers on 2013-08-06.
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
/// See https://github.com/Squirrel/Squirrel.Mac/pull/154#issuecomment-151287744
#define SKIP_IF_RUNNING_ON_TRAVIS if (self.runningOnTravis) return;
// The short version string for the `testApplicationBundle`.
extern NSString * const SQRLTestApplicationOriginalShortVersionString;
@@ -16,11 +24,15 @@ extern NSString * const SQRLTestApplicationUpdatedShortVersionString;
// The Info.plist key associated with a bundle's short version string.
extern NSString * const SQRLBundleShortVersionStringKey;
/// The longer timeout we should use for things that take a long time. This is
/// especially needed on slower machines (e.g., Travis CI).
extern const NSTimeInterval SQRLLongTimeout;
@class SQRLCodeSignature;
@class SQRLDirectoryManager;
@class SQRLShipItRequest;
@interface SQRLTestCase : SPTXCTestCase
@interface QuickSpec (SQRLFixtures)
// A URL to a temporary directory tests can use.
//
@@ -49,6 +61,9 @@ extern NSString * const SQRLBundleShortVersionStringKey;
// A directory manager for finding URLs that apply to ShipIt.
@property (nonatomic, strong, readonly) SQRLDirectoryManager *shipItDirectoryManager;
/// Are the tests currently being run on Travis?
@property (nonatomic, readonly, assign, getter = isRunningOnTravis) BOOL runningOnTravis;
// Launches a new copy of TestApplication.app from the `testApplicationBundle`.
//
// Invoking this method multiple times will result in multiple running instances
@@ -1,20 +1,20 @@
//
// SQRLTestCase.m
// QuickSpec+SQRLFixtures.m
// Squirrel
//
// Created by Justin Spahr-Summers on 2013-08-06.
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import "SQRLTestCase.h"
#import "QuickSpec+SQRLFixtures.h"
#import "SQRLCodeSignature.h"
#import "SQRLDirectoryManager.h"
#import "SQRLInstaller.h"
#import "SQRLShipItLauncher.h"
#import "SQRLShipItRequest.h"
#import "SQRLTestHelper.h"
#import <ServiceManagement/ServiceManagement.h>
#import <objc/runtime.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
@@ -23,6 +23,8 @@ NSString * const SQRLTestApplicationOriginalShortVersionString = @"1.0";
NSString * const SQRLTestApplicationUpdatedShortVersionString = @"2.1";
NSString * const SQRLBundleShortVersionStringKey = @"CFBundleShortVersionString";
const NSTimeInterval SQRLLongTimeout = 20;
static void SQRLKillAllTestApplications(void) {
// Forcibly kill all copies of the TestApplication that may be running.
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.github.Squirrel.TestApplication"];
@@ -43,40 +45,25 @@ static void SQRLSignalHandler(int sig) {
abort();
}
@interface SQRLTestCase ()
static NSBundle *SQRLTestBundle(void) {
return [NSBundle bundleWithIdentifier:@"com.github.SquirrelTests"];
}
// An array of dispatch_block_t values, for performing cleanup after the current
// example finishes.
//
// This array will be emptied between each example.
@property (nonatomic, strong, readonly) NSMutableArray *exampleCleanupBlocks;
static NSMutableArray *cleanupBlocks = nil;
// The URL to the temporary directory which contains `temporaryDirectoryURL` and
// all copied test data.
@property (nonatomic, copy, readonly) NSURL *baseTemporaryDirectoryURL;
static NSURL *baseTemporaryDirectoryURL = nil;
// Returns an _unlaunched_ task that will follow log files at the given paths,
// then pipe that output through this process.
+ (NSTask *)tailTaskWithPaths:(RACSequence *)paths;
QuickConfigurationBegin(Fixtures)
@end
@implementation SQRLTestCase
#pragma mark Properties
@synthesize baseTemporaryDirectoryURL = _baseTemporaryDirectoryURL;
#pragma mark Lifecycle
+ (void)load {
+ (void)configure:(Configuration *)configuration {
NSURL *appSupportURL = [NSFileManager.defaultManager URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
NSAssert(appSupportURL != nil, @"Could not find Application Support folder");
NSArray *folders = @[
@"com.github.Squirrel.TestApplication.ShipIt",
@"otest.ShipIt",
@"otest-x86_64.ShipIt",
@"com.github.Squirrel.SquirrelTests.ShipIt",
];
RACSequence *URLs = [folders.rac_sequence flattenMap:^(NSString *folder) {
@@ -87,79 +74,69 @@ static void SQRLSignalHandler(int sig) {
].rac_sequence;
}];
for (NSURL *URL in URLs) {
[[NSData data] writeToURL:URL atomically:YES];
}
[configuration beforeSuite:^{
signal(SIGILL, &SQRLSignalHandler);
NSSetUncaughtExceptionHandler(&SQRLUncaughtExceptionHandler);
RACSequence *paths = [URLs map:^(NSURL *URL) {
return URL.path;
cleanupBlocks = [NSMutableArray array];
for (NSURL *URL in URLs) {
[NSFileManager.defaultManager createDirectoryAtURL:URL.URLByDeletingLastPathComponent withIntermediateDirectories:YES attributes:nil error:NULL];
if (![[NSData data] writeToURL:URL atomically:YES]) {
NSLog(@"Could not touch log file at %@", URL);
}
}
}];
NSTask *readShipIt = [self tailTaskWithPaths:paths];
[readShipIt launch];
// We want to run any enqueued cleanup blocks after _and before_ each spec,
// in case beforeSuites (for example) use the fixtures.
void (^runCleanupBlocks)(void) = ^{
// Enumerate backwards, so later resources are cleaned up first.
for (dispatch_block_t block in cleanupBlocks.reverseObjectEnumerator) {
block();
}
NSAssert([readShipIt isRunning], @"Could not start task %@", readShipIt);
atexit_b(^{
[readShipIt terminate];
});
}
- (void)setUp {
[super setUp];
signal(SIGILL, &SQRLSignalHandler);
NSSetUncaughtExceptionHandler(&SQRLUncaughtExceptionHandler);
Expecta.asynchronousTestTimeout = 3;
}
- (void)tearDown {
[super tearDown];
SQRLKillAllTestApplications();
}
- (void)addCleanupBlock:(dispatch_block_t)block {
[SQRLTestHelper addCleanupBlock:block];
}
#pragma mark Logging
+ (NSTask *)tailTaskWithPaths:(RACSequence *)paths {
NSPipe *outputPipe = [NSPipe pipe];
NSFileHandle *outputHandle = outputPipe.fileHandleForReading;
outputHandle.readabilityHandler = ^(NSFileHandle *handle) {
NSString *output = [[NSString alloc] initWithData:handle.availableData encoding:NSUTF8StringEncoding];
NSLog(@"\n%@", output);
[cleanupBlocks removeAllObjects];
};
NSTask *task = [[NSTask alloc] init];
task.launchPath = @"/usr/bin/tail";
task.standardOutput = outputPipe;
task.arguments = [[paths startWith:@"-f"] array];
return task;
[configuration beforeEach:^{
runCleanupBlocks();
}];
[configuration afterEach:^{
runCleanupBlocks();
SQRLKillAllTestApplications();
}];
}
QuickConfigurationEnd
@implementation QuickSpec (SQRLFixtures)
#pragma mark Lifecycle
- (void)addCleanupBlock:(dispatch_block_t)block {
[cleanupBlocks addObject:[block copy]];
}
#pragma mark Temporary Directory
- (NSURL *)baseTemporaryDirectoryURL {
if (_baseTemporaryDirectoryURL == nil) {
if (baseTemporaryDirectoryURL == nil) {
NSURL *globalTemporaryDirectory = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
_baseTemporaryDirectoryURL = [[globalTemporaryDirectory URLByAppendingPathComponent:@"com.github.SquirrelTests"] URLByAppendingPathComponent:[NSProcessInfo.processInfo globallyUniqueString]];
baseTemporaryDirectoryURL = [[globalTemporaryDirectory URLByAppendingPathComponent:@"com.github.SquirrelTests"] URLByAppendingPathComponent:[NSProcessInfo.processInfo globallyUniqueString]];
NSError *error = nil;
BOOL success = [NSFileManager.defaultManager createDirectoryAtURL:_baseTemporaryDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error];
XCTAssertTrue(success, @"Couldn't create temporary directory at %@: %@", _baseTemporaryDirectoryURL, error);
BOOL success = [NSFileManager.defaultManager createDirectoryAtURL:baseTemporaryDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error];
XCTAssertTrue(success, @"Couldn't create temporary directory at %@: %@", baseTemporaryDirectoryURL, error);
[self addCleanupBlock:^{
[NSFileManager.defaultManager removeItemAtURL:_baseTemporaryDirectoryURL error:NULL];
_baseTemporaryDirectoryURL = nil;
[NSFileManager.defaultManager removeItemAtURL:baseTemporaryDirectoryURL error:NULL];
baseTemporaryDirectoryURL = nil;
}];
}
return _baseTemporaryDirectoryURL;
return baseTemporaryDirectoryURL;
}
- (NSURL *)temporaryDirectoryURL {
@@ -177,7 +154,7 @@ static void SQRLSignalHandler(int sig) {
- (NSURL *)testApplicationURL {
NSURL *fixtureURL = [self.temporaryDirectoryURL URLByAppendingPathComponent:@"TestApplication.app" isDirectory:YES];
if (![NSFileManager.defaultManager fileExistsAtPath:fixtureURL.path]) {
NSURL *bundleURL = [[NSBundle bundleForClass:self.class] URLForResource:@"TestApplication" withExtension:@"app"];
NSURL *bundleURL = [SQRLTestBundle() URLForResource:@"TestApplication" withExtension:@"app"];
XCTAssertNotNil(bundleURL, @"Couldn't find TestApplication.app in test bundle");
NSError *error = nil;
@@ -186,15 +163,6 @@ static void SQRLSignalHandler(int sig) {
NSURL *testAppLog = [fixtureURL.URLByDeletingLastPathComponent URLByAppendingPathComponent:@"TestApplication.log"];
[[NSData data] writeToURL:testAppLog atomically:YES];
NSTask *readTestApp = [self.class tailTaskWithPaths:[RACSequence return:testAppLog.path]];
[readTestApp launch];
XCTAssertTrue([readTestApp isRunning], @"Could not start task %@ to read %@", readTestApp, testAppLog);
[self addCleanupBlock:^{
[readTestApp terminate];
}];
}
return fixtureURL;
@@ -204,7 +172,7 @@ static void SQRLSignalHandler(int sig) {
NSURL *fixtureURL = self.testApplicationURL;
NSBundle *bundle = [NSBundle bundleWithURL:fixtureURL];
XCTAssertNotNil(bundle, @"Couldn't open bundle at %@", fixtureURL);
return bundle;
}
@@ -243,7 +211,7 @@ static void SQRLSignalHandler(int sig) {
}
- (NSURL *)createTestApplicationUpdate {
NSURL *originalURL = [[NSBundle bundleForClass:self.class] URLForResource:@"TestApplication 2.1" withExtension:@"app"];
NSURL *originalURL = [SQRLTestBundle() URLForResource:@"TestApplication 2.1" withExtension:@"app"];
XCTAssertNotNil(originalURL, @"Couldn't find TestApplication update in test bundle");
NSError *error = nil;
@@ -262,7 +230,7 @@ static void SQRLSignalHandler(int sig) {
}
- (id)performWithTestApplicationRequirement:(id (^)(SecRequirementRef requirement))block {
NSURL *bundleURL = [[NSBundle bundleForClass:self.class] URLForResource:@"TestApplication" withExtension:@"app"];
NSURL *bundleURL = [SQRLTestBundle() URLForResource:@"TestApplication" withExtension:@"app"];
XCTAssertNotNil(bundleURL, @"Couldn't find TestApplication.app in test bundle");
SecStaticCodeRef staticCode = NULL;
@@ -285,7 +253,7 @@ static void SQRLSignalHandler(int sig) {
}
- (SQRLCodeSignature *)testApplicationSignature {
NSURL *bundleURL = [[NSBundle bundleForClass:self.class] URLForResource:@"TestApplication" withExtension:@"app"];
NSURL *bundleURL = [SQRLTestBundle() URLForResource:@"TestApplication" withExtension:@"app"];
XCTAssertNotNil(bundleURL, @"Couldn't find TestApplication.app in test bundle");
NSError *error = nil;
@@ -305,11 +273,11 @@ static void SQRLSignalHandler(int sig) {
- (void)installWithRequest:(SQRLShipItRequest *)request remote:(BOOL)remote {
if (remote) {
expect([[request writeUsingURL:self.shipItDirectoryManager.shipItStateURL] waitUntilCompleted:NULL]).to.beTruthy();
expect(@([[request writeUsingURL:self.shipItDirectoryManager.shipItStateURL] waitUntilCompleted:NULL])).to(beTruthy());
__block NSError *error = nil;
expect([[SQRLShipItLauncher launchPrivileged:NO] waitUntilCompleted:&error]).to.beTruthy();
expect(error).to.beNil();
expect(@([[SQRLShipItLauncher launchPrivileged:NO] waitUntilCompleted:&error])).to(beTruthy());
expect(error).to(beNil());
[self addCleanupBlock:^{
// Remove ShipIt's launchd job so it doesn't relaunch itself.
@@ -317,19 +285,19 @@ static void SQRLSignalHandler(int sig) {
NSError *lookupError;
NSURL *stateURL = [[self.shipItDirectoryManager shipItStateURL] firstOrDefault:nil success:NULL error:&lookupError];
expect(stateURL).notTo.beNil();
expect(lookupError).to.beNil();
expect(stateURL).notTo(beNil());
expect(lookupError).to(beNil());
[NSFileManager.defaultManager removeItemAtURL:stateURL error:NULL];
}];
} else {
SQRLInstaller *installer = [[SQRLInstaller alloc] initWithApplicationIdentifier:self.shipItDirectoryManager.applicationIdentifier];
expect(installer).notTo.beNil();
expect(installer).notTo(beNil());
NSError *installedError = nil;
BOOL installed = [[installer.installUpdateCommand execute:request] asynchronouslyWaitUntilCompleted:&installedError];
expect(installed).to.beTruthy();
expect(installedError).to.beNil();
expect(@(installed)).to(beTruthy());
expect(installedError).to(beNil());
}
}
@@ -344,20 +312,24 @@ static void SQRLSignalHandler(int sig) {
createInvocation = [NSString stringWithFormat:@"hdiutil create '%@' -fs 'HFS+' -volname '%@' -format UDSP -size 10m -srcfolder '%@' -quiet", destinationURL.path, name, directoryURL.path];
}
expect(system(createInvocation.UTF8String)).to.equal(0);
expect(@(system(createInvocation.UTF8String))).to(equal(@0));
NSString *mountInvocation = [NSString stringWithFormat:@"hdiutil attach '%@.sparseimage' -noverify -noautofsck -readwrite -quiet", destinationURL.path];
expect(system(mountInvocation.UTF8String)).to.equal(0);
expect(@(system(mountInvocation.UTF8String))).to(equal(@0));
NSString *path = [NSString stringWithFormat:@"/Volumes/%@", name];
[self addCleanupBlock:^{
NSString *detachInvocation = [NSString stringWithFormat:@"hdiutil detach '%@' -force -quiet", path];
expect(system(detachInvocation.UTF8String)).to.equal(0);
expect(@(system(detachInvocation.UTF8String))).to(equal(@0));
}];
return [NSURL fileURLWithPath:path isDirectory:YES];
}
- (BOOL)isRunningOnTravis {
return NSProcessInfo.processInfo.environment[@"TRAVIS"] != nil;
}
@end
#pragma clang diagnostic pop
+63 -56
View File
@@ -6,9 +6,16 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
#import "SQRLCodeSignature.h"
SpecBegin(SQRLCodeSignature)
#import "QuickSpec+SQRLFixtures.h"
QuickSpecBegin(SQRLCodeSignatureSpec)
__block NSBundle *bundle;
__block void (^corruptURL)(NSURL *URL);
@@ -17,26 +24,26 @@ beforeEach(^{
bundle = self.testApplicationBundle;
corruptURL = ^(NSURL *URL) {
expect([@"this bundle is corrupted, yo" writeToURL:bundle.executableURL atomically:YES encoding:NSUTF8StringEncoding error:NULL]).to.beTruthy();
expect(@([@"this bundle is corrupted, yo" writeToURL:bundle.executableURL atomically:YES encoding:NSUTF8StringEncoding error:NULL])).to(beTruthy());
};
});
it(@"should verify a valid bundle", ^{
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
});
it(@"should fail to verify with different code signing requirements", ^{
NSError *error = nil;
SQRLCodeSignature *signature = [SQRLCodeSignature currentApplicationSignature:&error];
expect(signature).notTo.beNil();
expect(error).to.beNil();
expect(signature).notTo(beNil());
expect(error).to(beNil());
BOOL success = [[signature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(error).notTo.beNil();
expect(@(success)).to(beFalsy());
expect(error).notTo(beNil());
});
describe(@"code signature changes", ^{
@@ -47,15 +54,15 @@ describe(@"code signature changes", ^{
});
it(@"should fail to verify a bundle with a missing code signature", ^{
expect([NSFileManager.defaultManager removeItemAtURL:codeSignatureURL error:NULL]).to.beTruthy();
expect(@([NSFileManager.defaultManager removeItemAtURL:codeSignatureURL error:NULL])).to(beTruthy());
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
it(@"should fail to verify a bundle with a corrupt code signature", ^{
@@ -63,25 +70,25 @@ describe(@"code signature changes", ^{
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
});
describe(@"main executable changes", ^{
it(@"should fail to verify a bundle with a missing executable", ^{
expect([NSFileManager.defaultManager removeItemAtURL:bundle.executableURL error:NULL]).to.beTruthy();
expect(@([NSFileManager.defaultManager removeItemAtURL:bundle.executableURL error:NULL])).to(beTruthy());
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorCouldNotCreateStaticCode);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorCouldNotCreateStaticCode)));
});
it(@"should fail to verify a bundle with a corrupt executable", ^{
@@ -89,11 +96,11 @@ describe(@"main executable changes", ^{
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
});
@@ -102,19 +109,19 @@ describe(@"helper executable changes", ^{
beforeEach(^{
helperURL = [bundle URLForAuxiliaryExecutable:@"unused-helper"];
expect(helperURL).notTo.beNil();
expect(helperURL).notTo(beNil());
});
it(@"should fail to verify a bundle with a missing helper", ^{
expect([NSFileManager.defaultManager removeItemAtURL:helperURL error:NULL]).to.beTruthy();
expect(@([NSFileManager.defaultManager removeItemAtURL:helperURL error:NULL])).to(beTruthy());
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
it(@"should fail to verify a bundle with a corrupt helper", ^{
@@ -122,11 +129,11 @@ describe(@"helper executable changes", ^{
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
});
@@ -135,19 +142,19 @@ describe(@"resource changes", ^{
beforeEach(^{
resourceURL = [bundle URLForResource:@"MainMenu" withExtension:@"nib"];
expect(resourceURL).notTo.beNil();
expect(resourceURL).notTo(beNil());
});
it(@"should fail to verify a bundle with a missing resource", ^{
expect([NSFileManager.defaultManager removeItemAtURL:resourceURL error:NULL]).to.beTruthy();
expect(@([NSFileManager.defaultManager removeItemAtURL:resourceURL error:NULL])).to(beTruthy());
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
it(@"should fail to verify a bundle with a corrupt resource", ^{
@@ -155,11 +162,11 @@ describe(@"resource changes", ^{
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
});
@@ -171,15 +178,15 @@ describe(@"framework changes", ^{
});
it(@"should fail to verify a bundle with a missing framework", ^{
expect([NSFileManager.defaultManager removeItemAtURL:frameworkURL error:NULL]).to.beTruthy();
expect(@([NSFileManager.defaultManager removeItemAtURL:frameworkURL error:NULL])).to(beTruthy());
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
it(@"should fail to verify a bundle with a corrupt framework", ^{
@@ -187,12 +194,12 @@ describe(@"framework changes", ^{
NSError *error = nil;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:bundle.bundleURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLCodeSignatureErrorDomain);
expect(error.code).to.equal(SQRLCodeSignatureErrorDidNotPass);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLCodeSignatureErrorDomain));
expect(@(error.code)).to(equal(@(SQRLCodeSignatureErrorDidNotPass)));
});
});
SpecEnd
QuickSpecEnd
-119
View File
@@ -1,119 +0,0 @@
//
// SQRLDeepCodesignSpec.m
// Squirrel
//
// Created by Keith Duncan on 2013-09-05.
// Copyright (c) 2013 GitHub. All rights reserved.
//
SpecBegin(SQRLDeepCodesign)
NSMutableDictionary * (^environmentSuitableForChildProcess)(void) = ^ {
// Remove environment variables that configure the Obj-C runtime
// Specifically OBJC_DISABLE_GC so that child processes aren't forced to
// adopt the GC preference of the test suite
NSMutableDictionary *environment = [NSProcessInfo.processInfo.environment mutableCopy];
NSSet *objcEnvironmentVariables = [environment keysOfEntriesPassingTest:^(NSString *variable, id obj, BOOL *stop) {
return [variable hasPrefix:@"OBJC"];
}];
[environment removeObjectsForKeys:objcEnvironmentVariables.allObjects];
return environment;
};
NSTask * (^codesignTaskWithArguments)(NSArray *) = ^ (NSArray *arguments) {
NSTask *task = [[NSTask alloc] init];
task.launchPath = @"/usr/bin/xcrun";
task.arguments = [@[ @"codesign" ] arrayByAddingObjectsFromArray:arguments];
task.environment = environmentSuitableForChildProcess();
return task;
};
void (^resignTestApplicationPreserveEverythingButTheRequirements)(void) = ^{
NSURL *testApplicationLocation = self.testApplicationURL;
NSTask *resignCodesignTask = codesignTaskWithArguments(@[
@"--sign", @"-",
@"--force",
@"--verbose=4",
@"--preserve-metadata=identifier,entitlements,resource-rules",
testApplicationLocation.path,
]);
[resignCodesignTask launch];
[resignCodesignTask waitUntilExit];
expect(resignCodesignTask.terminationStatus).to.equal(0);
};
void (^deepCodesignTestApplication)(void) = ^{
NSURL *testApplicationLocation = self.testApplicationURL;
NSBundle *testsBundle = [NSBundle bundleForClass:self.class];
NSURL *deepCodesignLocation = [testsBundle URLForResource:@"deep-codesign" withExtension:nil];
NSNumber *executable = nil;
NSError *executableError = nil;
BOOL getExecutable = [deepCodesignLocation getResourceValue:&executable forKey:NSURLIsExecutableKey error:&executableError];
expect(getExecutable).to.beTruthy();
expect(executable.boolValue).to.beTruthy();
expect(executableError).to.beNil();
NSTask *deepCodesignTask = [[NSTask alloc] init];
deepCodesignTask.launchPath = deepCodesignLocation.path;
deepCodesignTask.standardError = [NSPipe pipe];
deepCodesignTask.standardOutput = [NSPipe pipe];
NSMutableDictionary *environment = environmentSuitableForChildProcess();
[environment addEntriesFromDictionary:@{
@"CODE_SIGN_IDENTITY": @"-",
@"CONFIGURATION_BUILD_DIR": testApplicationLocation.URLByDeletingLastPathComponent.path,
@"FULL_PRODUCT_NAME": testApplicationLocation.lastPathComponent,
}];
deepCodesignTask.environment = environment;
[deepCodesignTask launch];
[deepCodesignTask waitUntilExit];
expect(deepCodesignTask.terminationStatus).to.equal(0);
/*
By signing test application's contents, which are covered by test
application's ResourceRules it's signature becomes invalid. Usually,
Xcode would sign the application after deep-codesign has run so the
signature would include the _signed_ child resources which are covered
by test application's ResourceRules
test application is already signed, so we need to manually resign it
deep-codesign preserves the requirements, we can't use it to resign the
root target, the new signing identity wouldn't verify against the
original designated requirement
*/
resignTestApplicationPreserveEverythingButTheRequirements();
};
BOOL (^deepVerify)(void) = ^ BOOL {
NSTask *deepVerifyTask = codesignTaskWithArguments(@[
@"--deep-verify",
@"--verbose=4",
self.testApplicationURL.path
]);
[deepVerifyTask launch];
[deepVerifyTask waitUntilExit];
return deepVerifyTask.terminationStatus == 0;
};
it(@"should deep sign the test application", ^{
deepCodesignTestApplication();
});
xit(@"should deep verify after signing", ^{
expect(deepVerify()).to.beFalsy();
deepCodesignTestApplication();
expect(deepVerify()).to.beTruthy();
});
SpecEnd
+19 -14
View File
@@ -6,39 +6,44 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
#import "SQRLDirectoryManager.h"
SpecBegin(SQRLDirectoryManager)
QuickSpecBegin(SQRLDirectoryManagerSpec)
__block NSString *otestIdentifier;
beforeEach(^{
otestIdentifier = NSRunningApplication.currentApplication.localizedName;
expect(otestIdentifier).notTo.beNil();
otestIdentifier = NSProcessInfo.processInfo.environment[@"FORCE_APP_IDENTIFIER"];
expect(otestIdentifier).notTo(beNil());
});
it(@"should initialize", ^{
SQRLDirectoryManager *manager = [[SQRLDirectoryManager alloc] initWithApplicationIdentifier:otestIdentifier];
expect(manager).notTo.beNil();
expect(manager).notTo(beNil());
});
it(@"should create a manager for the current app", ^{
SQRLDirectoryManager *manager = SQRLDirectoryManager.currentApplicationManager;
expect(manager).notTo.beNil();
expect(manager).to.equal([[SQRLDirectoryManager alloc] initWithApplicationIdentifier:otestIdentifier]);
expect(manager).notTo(beNil());
expect(manager).to(equal([[SQRLDirectoryManager alloc] initWithApplicationIdentifier:otestIdentifier]));
});
it(@"should send an Application Support URL", ^{
SQRLDirectoryManager *manager = SQRLDirectoryManager.currentApplicationManager;
NSError *error = nil;
NSURL *appSupportURL = [[manager applicationSupportURL] firstOrDefault:nil success:NULL error:&error];
expect(appSupportURL).notTo.beNil();
expect(error).to.beNil();
NSURL *appSupportURL = [[manager storageURL] firstOrDefault:nil success:NULL error:&error];
expect(appSupportURL).notTo(beNil());
expect(error).to(beNil());
__block BOOL directory = NO;
expect([NSFileManager.defaultManager fileExistsAtPath:appSupportURL.path isDirectory:&directory]).to.beTruthy();
expect(directory).to.beTruthy();
expect(@([NSFileManager.defaultManager fileExistsAtPath:appSupportURL.path isDirectory:&directory])).to(beTruthy());
expect(@(directory)).to(beTruthy());
});
it(@"should send a ShipIt state URL", ^{
@@ -46,8 +51,8 @@ it(@"should send a ShipIt state URL", ^{
NSError *error = nil;
NSURL *stateURL = [[manager shipItStateURL] firstOrDefault:nil success:NULL error:&error];
expect(stateURL).notTo.beNil();
expect(error).to.beNil();
expect(stateURL).notTo(beNil());
expect(error).to(beNil());
});
SpecEnd
QuickSpecEnd
+68 -58
View File
@@ -6,24 +6,29 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
#import "SQRLCodeSignature.h"
#import "SQRLDirectoryManager.h"
#import "SQRLInstaller.h"
#import "SQRLInstaller+Private.h"
#import "SQRLShipItLauncher.h"
#import "SQRLShipItRequest.h"
#import "SQRLInstallerOwnedBundle.h"
#import "SQRLShipItRequest.h"
SpecBegin(SQRLInstaller)
#import "QuickSpec+SQRLFixtures.h"
QuickSpecBegin(SQRLInstallerSpec)
mode_t (^modeOfURL)(NSURL *) = ^ mode_t (NSURL *fileURL) {
NSFileSecurity *fileSecurity = nil;
BOOL success = [fileURL getResourceValue:&fileSecurity forKey:NSURLFileSecurityKey error:NULL];
expect(success).to.beTruthy();
expect(fileSecurity).notTo.beNil();
expect(@(success)).to(beTruthy());
expect(fileSecurity).notTo(beNil());
__block mode_t mode;
expect(CFFileSecurityGetMode((__bridge CFFileSecurityRef)fileSecurity, &mode)).to.beTruthy();
expect(@(CFFileSecurityGetMode((__bridge CFFileSecurityRef)fileSecurity, &mode))).to(beTruthy());
return mode & (S_IRWXU | S_IRWXG | S_IRWXO);
};
@@ -35,75 +40,71 @@ beforeEach(^{
});
it(@"should install an update using ShipIt", ^{
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});
it(@"should install an update in process", ^{
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
[self installWithRequest:request remote:NO];
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});
it(@"should install an update and relaunch", ^{
NSString *bundleIdentifier = @"com.github.Squirrel.TestApplication";
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundleIdentifier];
expect(apps.count).to.equal(0);
expect(@(apps.count)).to(equal(@0));
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:YES];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:YES useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect([NSRunningApplication runningApplicationsWithBundleIdentifier:bundleIdentifier].count).will.equal(1);
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
expect(@([NSRunningApplication runningApplicationsWithBundleIdentifier:bundleIdentifier].count)).toEventually(equal(@1));
});
it(@"should install an update from another volume", ^{
NSURL *diskImageURL = [self createAndMountDiskImageNamed:@"TestApplication 2.1" fromDirectory:updateURL.URLByDeletingLastPathComponent];
updateURL = [diskImageURL URLByAppendingPathComponent:updateURL.lastPathComponent];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});
it(@"should install an update to another volume", ^{
NSURL *diskImageURL = [self createAndMountDiskImageNamed:@"TestApplication" fromDirectory:self.testApplicationURL.URLByDeletingLastPathComponent];
NSURL *targetURL = [diskImageURL URLByAppendingPathComponent:self.testApplicationURL.lastPathComponent];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
NSURL *plistURL = [targetURL URLByAppendingPathComponent:@"Contents/Info.plist"];
expect([NSDictionary dictionaryWithContentsOfURL:plistURL][SQRLBundleShortVersionStringKey]).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect([NSDictionary dictionaryWithContentsOfURL:plistURL][SQRLBundleShortVersionStringKey]).withTimeout(SQRLLongTimeout).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});
describe(@"with backup restoration", ^{
__block NSURL *targetURL;
__block SQRLShipItRequest *request;
beforeEach(^{
targetURL = self.testApplicationURL;
request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO];
NSURL *copiedTargetURL = [self.temporaryDirectoryURL URLByAppendingPathComponent:@"TestApplication Target.app"];
expect([NSFileManager.defaultManager moveItemAtURL:targetURL toURL:copiedTargetURL error:NULL]).to.beTruthy();
expect(@([NSFileManager.defaultManager moveItemAtURL:targetURL toURL:copiedTargetURL error:NULL])).to(beTruthy());
SQRLCodeSignature *codeSignature = self.testApplicationSignature;
SQRLInstallerOwnedBundle *ownedBundle = [[SQRLInstallerOwnedBundle alloc] initWithOriginalURL:targetURL temporaryURL:copiedTargetURL codeSignature:codeSignature];
NSData *ownedBundleArchive = [NSKeyedArchiver archivedDataWithRootObject:ownedBundle];
expect(ownedBundleArchive).notTo.beNil();
expect(ownedBundleArchive).notTo(beNil());
// Set up ShipIt's preferences like it paused in the middle of an
// installation.
@@ -113,56 +114,71 @@ describe(@"with backup restoration", ^{
CFPreferencesSetValue((__bridge CFStringRef)SQRLInstallerOwnedBundleKey, (__bridge CFDataRef)ownedBundleArchive, (__bridge CFStringRef)applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
BOOL synchronized = CFPreferencesSynchronize((__bridge CFStringRef)applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
expect(synchronized).to.beTruthy();
});
afterEach(^{
__block NSError *error;
expect([[self.testApplicationSignature verifyBundleAtURL:targetURL] waitUntilCompleted:&error]).will.beTruthy();
expect(error).to.beNil();
expect(self.testApplicationBundleVersion).to.equal(SQRLTestApplicationOriginalShortVersionString);
expect(@(synchronized)).to(beTruthy());
});
it(@"should not install an update after too many attempts", ^{
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
__block NSError *error;
expect(@([[self.testApplicationSignature verifyBundleAtURL:targetURL] waitUntilCompleted:&error])).toEventually(beTruthy());
expect(error).to(beNil());
expect(self.testApplicationBundleVersion).to(equal(SQRLTestApplicationOriginalShortVersionString));
});
it(@"should relaunch even after failing to install an update", ^{
request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:YES];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:YES useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
expect([NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.github.Squirrel.TestApplication"].count).will.equal(1);
expect(@([NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.github.Squirrel.TestApplication"].count)).toEventually(equal(@1));
__block NSError *error;
expect(@([[self.testApplicationSignature verifyBundleAtURL:targetURL] waitUntilCompleted:&error])).to(beTruthy());
expect(error).to(beNil());
expect(self.testApplicationBundleVersion).to(equal(SQRLTestApplicationOriginalShortVersionString));
});
});
it(@"should disallow writing the updated application except by the owner", ^{
NSString *command = [NSString stringWithFormat:@"chmod -R 0777 '%@'", updateURL.path];
expect(system(command.UTF8String)).to.equal(0);
expect(@(system(command.UTF8String))).to(equal(@0));
expect(modeOfURL(updateURL)).to.equal(0777);
expect(modeOfURL([updateURL URLByAppendingPathComponent:@"Contents/MacOS/TestApplication"])).to.equal(0777);
expect(@(modeOfURL(updateURL))).to(equal(@0777));
expect(@(modeOfURL([updateURL URLByAppendingPathComponent:@"Contents/MacOS/TestApplication"]))).to(equal(@0777));
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
expect(modeOfURL(self.testApplicationURL)).to.equal(0755);
expect(modeOfURL([self.testApplicationURL URLByAppendingPathComponent:@"Contents/MacOS/TestApplication"])).to.equal(0755);
expect(@(modeOfURL(self.testApplicationURL))).to(equal(@0755));
expect(@(modeOfURL([self.testApplicationURL URLByAppendingPathComponent:@"Contents/MacOS/TestApplication"]))).to(equal(@0755));
});
describe(@"signal handling", ^{
__block NSURL *targetURL;
void (^verifyUpdate)(void) = ^{
// Wait up to the launchd throttle interval, then verify that ShipIt
// relaunched and finished installing the update.
expect(self.testApplicationBundleVersion).withTimeout(SQRLLongTimeout).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
NSError *error;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:targetURL] waitUntilCompleted:&error];
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
};
beforeEach(^{
// Copied so that we don't recreate the TestApplication bundle by
// accessing the property.
targetURL = self.testApplicationURL;
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
[self installWithRequest:request remote:YES];
@@ -172,32 +188,24 @@ describe(@"signal handling", ^{
[NSThread sleepForTimeInterval:delay];
});
afterEach(^{
// Wait up to the launchd throttle interval, then verify that ShipIt
// relaunched and finished installing the update.
Expecta.asynchronousTestTimeout = 5;
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
NSError *error;
BOOL success = [[self.testApplicationSignature verifyBundleAtURL:targetURL] waitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
});
it(@"should handle SIGHUP", ^{
system("killall -HUP ShipIt");
verifyUpdate();
});
it(@"should handle SIGTERM", ^{
system("killall -TERM ShipIt");
verifyUpdate();
});
it(@"should handle SIGINT", ^{
system("killall -INT ShipIt");
verifyUpdate();
});
it(@"should handle SIGQUIT", ^{
system("killall -QUIT ShipIt");
verifyUpdate();
});
it(@"should handle SIGKILL", ^{
@@ -213,7 +221,9 @@ describe(@"signal handling", ^{
NSTimeInterval delay = 2 + (arc4random_uniform(100) / 1000.0);
[NSThread sleepForTimeInterval:delay];
}
verifyUpdate();
});
});
SpecEnd
QuickSpecEnd
+32 -25
View File
@@ -6,10 +6,17 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
#import "SQRLDirectoryManager.h"
#import "SQRLShipItRequest.h"
SpecBegin(SQRLShipItRequest)
#import "QuickSpec+SQRLFixtures.h"
QuickSpecBegin(SQRLShipItRequestSpec)
__block SQRLDirectoryManager *directoryManager;
__block SQRLShipItRequest *request;
@@ -18,46 +25,46 @@ beforeEach(^{
directoryManager = SQRLDirectoryManager.currentApplicationManager;
NSURL *updateURL = [self createTestApplicationUpdate];
request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
expect(request).notTo.beNil();
request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO useUpdateBundleName:NO];
expect(request).notTo(beNil());
expect(request.targetBundleURL).to.equal(self.testApplicationURL);
expect(request.updateBundleURL).to.equal(updateURL);
expect(request.bundleIdentifier).to.beNil();
expect(request.launchAfterInstallation).to.beFalsy();
expect(request.targetBundleURL).to(equal(self.testApplicationURL));
expect(request.updateBundleURL).to(equal(updateURL));
expect(request.bundleIdentifier).to(beNil());
expect(@(request.launchAfterInstallation)).to(beFalsy());
});
afterEach(^{
NSURL *stateURL = [[directoryManager shipItStateURL] first];
expect(stateURL).notTo.beNil();
expect(stateURL).notTo(beNil());
[NSFileManager.defaultManager removeItemAtURL:stateURL error:NULL];
});
it(@"should copy", ^{
SQRLShipItRequest *requestCopy = [request copy];
expect(requestCopy).to.equal(request);
expect(requestCopy).notTo.beIdenticalTo(request);
expect(requestCopy).to(equal(request));
expect(requestCopy).notTo(beIdenticalTo(request));
});
it(@"should fail to read state when no file exists yet", ^{
NSError *error;
BOOL success = [[SQRLShipItRequest readUsingURL:directoryManager.shipItStateURL] waitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(error).notTo.beNil();
expect(@(success)).to(beFalsy());
expect(error).notTo(beNil());
});
it(@"should write and read state to disk", ^{
NSError *error;
BOOL success = [[request writeUsingURL:directoryManager.shipItStateURL] waitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
SQRLShipItRequest *readRequest = [[SQRLShipItRequest readUsingURL:directoryManager.shipItStateURL] firstOrDefault:nil success:&success error:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
expect(readRequest).to.equal(request);
expect(readRequest).to(equal(request));
});
it(@"should fail gracefully with archives encoding a different class", ^{
@@ -65,15 +72,15 @@ it(@"should fail gracefully with archives encoding a different class", ^{
NSError *error;
BOOL write = [[NSKeyedArchiver archivedDataWithRootObject:@"rogue object"] writeToURL:archiveLocation atomically:YES];
expect(write).to.beTruthy();
expect(error).to.beNil();
expect(@(write)).to(beTruthy());
expect(error).to(beNil());
BOOL success = NO;
SQRLShipItRequest *request = [[SQRLShipItRequest readUsingURL:[RACSignal return:archiveLocation]] firstOrDefault:nil success:&success error:&error];
expect(request).to.beNil();
expect(success).to.beFalsy();
expect(error.domain).to.equal(SQRLShipItRequestErrorDomain);
expect(error.code).to.equal(SQRLShipItRequestErrorUnarchiving);
expect(request).to(beNil());
expect(@(success)).to(beFalsy());
expect(error.domain).to(equal(SQRLShipItRequestErrorDomain));
expect(@(error.code)).to(equal(@(SQRLShipItRequestErrorUnarchiving)));
});
SpecEnd
QuickSpecEnd
+24 -13
View File
@@ -6,15 +6,22 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
#import "SQRLTerminationListener.h"
SpecBegin(SQRLTerminationListener)
#import "QuickSpec+SQRLFixtures.h"
QuickSpecBegin(SQRLTerminationListenerSpec)
__block SQRLTerminationListener *listener;
beforeEach(^{
listener = [[SQRLTerminationListener alloc] initWithURL:self.testApplicationURL bundleIdentifier:self.testApplicationBundle.bundleIdentifier];
expect(listener).notTo.beNil();
expect(listener).notTo(beNil());
});
it(@"should complete immediately when the app is not running", ^{
@@ -23,10 +30,12 @@ it(@"should complete immediately when the app is not running", ^{
completed = YES;
}];
expect(completed).to.beTruthy();
expect(@(completed)).to(beTruthy());
});
it(@"should wait until one instance terminates", ^{
SKIP_IF_RUNNING_ON_TRAVIS
NSRunningApplication *app = [self launchTestApplicationWithEnvironment:nil];
__block NSRunningApplication *observedApp = nil;
@@ -37,15 +46,17 @@ it(@"should wait until one instance terminates", ^{
completed = YES;
}];
expect(observedApp).will.equal(app);
expect(completed).to.beFalsy();
expect(observedApp).toEventually(equal(app));
expect(@(completed)).to(beFalsy());
[app forceTerminate];
expect(app.terminated).will.beTruthy();
expect(completed).will.beTruthy();
expect(@(app.terminated)).toEventually(beTruthy());
expect(@(completed)).toEventually(beTruthy());
});
it(@"should wait until multiple instances terminate", ^{
SKIP_IF_RUNNING_ON_TRAVIS
NSRunningApplication *app1 = [self launchTestApplicationWithEnvironment:nil];
NSRunningApplication *app2 = [self launchTestApplicationWithEnvironment:nil];
@@ -54,15 +65,15 @@ it(@"should wait until multiple instances terminate", ^{
completed = YES;
}];
expect(completed).to.beFalsy();
expect(@(completed)).to(beFalsy());
[app1 forceTerminate];
expect(app1.terminated).will.beTruthy();
expect(completed).to.beFalsy();
expect(@(app1.terminated)).toEventually(beTruthy());
expect(@(completed)).to(beFalsy());
[app2 forceTerminate];
expect(app2.terminated).will.beTruthy();
expect(completed).will.beTruthy();
expect(@(app2.terminated)).toEventually(beTruthy());
expect(@(completed)).toEventually(beTruthy());
});
SpecEnd
QuickSpecEnd
-17
View File
@@ -1,17 +0,0 @@
//
// SQRLTestHelper.h
// Squirrel
//
// Created by Matt Diephouse on 7/7/14.
// Copyright (c) 2014 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
/// A test helper class that will run cleanup blocks after each test finishes.
@interface SQRLTestHelper : NSObject
/// Adds a cleanup block that will run after the next test completes.
+ (void)addCleanupBlock:(dispatch_block_t)block;
@end
-42
View File
@@ -1,42 +0,0 @@
//
// SQRLTestHelper.m
// Squirrel
//
// Created by Matt Diephouse on 7/7/14.
// Copyright (c) 2014 GitHub. All rights reserved.
//
#import "SQRLTestHelper.h"
#import <objc/runtime.h>
@implementation SQRLTestHelper
#pragma mark - Specta Methods
+ (void)afterEach {
// Enumerate backwards, so later resources are cleaned up first.
for (dispatch_block_t block in self.cleanupBlocks.reverseObjectEnumerator) {
block();
}
[self.cleanupBlocks removeAllObjects];
}
#pragma mark - Public Methods
+ (void)addCleanupBlock:(dispatch_block_t)block {
[self.cleanupBlocks addObject:[block copy]];
}
#pragma mark - Private Methods
+ (NSMutableArray *)cleanupBlocks {
NSMutableArray *blocks = objc_getAssociatedObject(self, "sqrl_cleanupBlocks");
if (blocks == nil) {
blocks = [NSMutableArray array];
objc_setAssociatedObject(self, "sqrl_cleanupBlocks", blocks, OBJC_ASSOCIATION_RETAIN);
}
return blocks;
}
@end
+19 -14
View File
@@ -6,22 +6,27 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
SpecBegin(SQRLUpdate)
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
QuickSpecBegin(SQRLUpdateSpec)
it(@"should return nil when initialised without a url", ^{
NSError *error = nil;
SQRLUpdate *update = [[SQRLUpdate alloc] initWithDictionary:@{} error:&error];
expect(update).to.beNil();
expect(error.domain).to.equal(NSCocoaErrorDomain);
expect(error.code).to.equal(NSKeyValueValidationError);
expect(update).to(beNil());
expect(error.domain).to(equal(NSCocoaErrorDomain));
expect(@(error.code)).to(equal(@(NSKeyValueValidationError)));
});
it(@"should return nil when initialised with a url not in URL syntax", ^{
NSError *error = nil;
SQRLUpdate *update = [[SQRLUpdate alloc] initWithDictionary:@{ @"updateURL": [NSURL URLWithString:@"test"] } error:&error];
expect(update).to.beNil();
expect(error.domain).to.equal(NSCocoaErrorDomain);
expect(error.code).to.equal(NSKeyValueValidationError);
expect(update).to(beNil());
expect(error.domain).to(equal(NSCocoaErrorDomain));
expect(@(error.code)).to(equal(@(NSKeyValueValidationError)));
});
it(@"should validate release name and notes", ^{
@@ -32,20 +37,20 @@ it(@"should validate release name and notes", ^{
@"releaseNotes": [[NSObject alloc] init]
} error:NULL];
expect(update).notTo.beNil();
expect(update.updateURL).to.equal(updateURL);
expect(update.releaseName).to.beNil();
expect(update.releaseNotes).to.beNil();
expect(update).notTo(beNil());
expect(update.updateURL).to(equal(updateURL));
expect(update.releaseName).to(beNil());
expect(update.releaseNotes).to(beNil());
});
it(@"should parse Central style dates", ^{
SQRLUpdate *update = [MTLJSONAdapter modelOfClass:SQRLUpdate.class fromJSONDictionary:@{ @"url": @"http://example.com/update", @"pub_date": @"Tue Sep 17 10:24:27 -0700 2013" } error:NULL];
expect(update.releaseDate).notTo.beNil();
expect(update.releaseDate).to(equal([NSDate dateWithTimeIntervalSince1970:1379438667]));
});
it(@"should parse ISO 8601 dates", ^{
SQRLUpdate *update = [MTLJSONAdapter modelOfClass:SQRLUpdate.class fromJSONDictionary:@{ @"url": @"http://example.com/update", @"pub_date": @"2013-09-18T13:17:07+01:00" } error:NULL];
expect(update.releaseDate).notTo.beNil();
expect(update.releaseDate).to(equal([NSDate dateWithTimeIntervalSince1970:1379506627]));
});
SpecEnd
QuickSpecEnd
+66 -47
View File
@@ -6,38 +6,44 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
#import "SQRLDirectoryManager.h"
#import "SQRLZipArchiver.h"
#import "SQRLTestUpdate.h"
#import "OHHTTPStubs/OHHTTPStubs.h"
#import "QuickSpec+SQRLFixtures.h"
#import "SQRLTestUpdate.h"
#import "TestAppConstants.h"
SpecBegin(SQRLUpdater)
QuickSpecBegin(SQRLUpdaterSpec)
__block NSURL *JSONURL;
void (^writeUpdate)(SQRLUpdate *) = ^(SQRLUpdate *update) {
NSDictionary *updateInfo = [MTLJSONAdapter JSONDictionaryFromModel:update];
expect(updateInfo).notTo.beNil();
expect(updateInfo).notTo(beNil());
NSError *error = nil;
NSData *JSON = [NSJSONSerialization dataWithJSONObject:updateInfo options:NSJSONWritingPrettyPrinted error:&error];
expect(JSON).notTo.beNil();
expect(error).to.beNil();
expect(JSON).notTo(beNil());
expect(error).to(beNil());
BOOL success = [JSON writeToURL:JSONURL options:NSDataWritingAtomic error:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
};
NSURL * (^zipUpdate)(NSURL *) = ^(NSURL *updateURL) {
NSURL *zipFolderURL = [NSFileManager.defaultManager URLForDirectory:NSItemReplacementDirectory inDomain:NSUserDomainMask appropriateForURL:self.temporaryDirectoryURL create:YES error:NULL];
expect(zipFolderURL).notTo.beNil();
expect(zipFolderURL).notTo(beNil());
NSURL *zippedUpdateURL = [[zipFolderURL URLByAppendingPathComponent:updateURL.lastPathComponent] URLByAppendingPathExtension:@"zip"];
BOOL success = [[SQRLZipArchiver createZipArchiveAtURL:zippedUpdateURL fromDirectoryAtURL:updateURL] asynchronouslyWaitUntilCompleted:NULL];
expect(success).to.beTruthy();
expect(@(success)).to(beTruthy());
return zippedUpdateURL;
};
@@ -55,30 +61,34 @@ beforeEach(^{
describe(@"updating", ^{
__block NSURL *updateURL;
beforeEach(^{
updateURL = [self createTestApplicationUpdate];
});
it(@"should use the application's bundled version of Squirrel and update in-place", ^{
SKIP_IF_RUNNING_ON_TRAVIS
NSError *error = nil;
SQRLTestUpdate *update = [SQRLTestUpdate modelWithDictionary:@{
@"updateURL": zipUpdate(updateURL),
@"final": @YES
} error:&error];
expect(update).notTo.beNil();
expect(error).to.beNil();
expect(update).notTo(beNil());
expect(error).to(beNil());
writeUpdate(update);
NSRunningApplication *app = launchWithEnvironment(nil);
expect(app.terminated).will.beTruthy();
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect(@(app.terminated)).withTimeout(SQRLLongTimeout).toEventually(beTruthy());
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});
it(@"should not install a corrupt update", ^{
SKIP_IF_RUNNING_ON_TRAVIS
NSURL *codeSignatureURL = [updateURL URLByAppendingPathComponent:@"Contents/_CodeSignature"];
expect([NSFileManager.defaultManager removeItemAtURL:codeSignatureURL error:NULL]).to.beTruthy();
expect(@([NSFileManager.defaultManager removeItemAtURL:codeSignatureURL error:NULL])).to(beTruthy());
SQRLTestUpdate *update = [SQRLTestUpdate modelWithDictionary:@{
@"updateURL": zipUpdate(updateURL),
@@ -88,14 +98,16 @@ describe(@"updating", ^{
writeUpdate(update);
NSRunningApplication *app = launchWithEnvironment(nil);
expect(app.terminated).will.beTruthy();
expect(@(app.terminated)).withTimeout(SQRLLongTimeout).toEventually(beTruthy());
// Give the update some time to finish installing.
[NSThread sleepForTimeInterval:0.2];
expect(self.testApplicationBundleVersion).to.equal(SQRLTestApplicationOriginalShortVersionString);
expect(self.testApplicationBundleVersion).to(equal(SQRLTestApplicationOriginalShortVersionString));
});
it(@"should update to the most recently enqueued job", ^{
SKIP_IF_RUNNING_ON_TRAVIS
SQRLTestUpdate *update = [SQRLTestUpdate modelWithDictionary:@{
@"updateURL": zipUpdate(self.testApplicationURL)
} error:NULL];
@@ -119,11 +131,13 @@ describe(@"updating", ^{
writeUpdate(update);
expect(app.terminated).will.beTruthy();
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect(@(app.terminated)).withTimeout(SQRLLongTimeout).toEventually(beTruthy());
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});
it(@"should use the application's bundled version of Squirrel and update in-place after a significant delay", ^{
SKIP_IF_RUNNING_ON_TRAVIS
SQRLTestUpdate *update = [SQRLTestUpdate modelWithDictionary:@{
@"updateURL": zipUpdate(updateURL),
@"final": @YES
@@ -131,24 +145,22 @@ describe(@"updating", ^{
writeUpdate(update);
NSTimeInterval delay = 30;
NSTimeInterval delay = 15;
NSRunningApplication *app = launchWithEnvironment(@{ @"SQRLUpdateDelay": [NSString stringWithFormat:@"%f", delay] });
Expecta.asynchronousTestTimeout = delay + 3;
expect(app.terminated).will.beTruthy();
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
expect(@(app.terminated)).withTimeout(delay + SQRLLongTimeout).toEventually(beTruthy());
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});
describe(@"cleaning up", ^{
__block NSURL *appSupportURL;
__block RACSignal *updateDirectoryURLs;
beforeEach(^{
SQRLDirectoryManager *directoryManager = [[SQRLDirectoryManager alloc] initWithApplicationIdentifier:@"com.github.Squirrel.TestApplication.ShipIt"];
appSupportURL = [[directoryManager applicationSupportURL] first];
expect(appSupportURL).notTo.beNil();
appSupportURL = [[directoryManager storageURL] first];
expect(appSupportURL).notTo(beNil());
updateDirectoryURLs = [[RACSignal
defer:^{
@@ -163,22 +175,25 @@ describe(@"updating", ^{
});
it(@"should remove downloaded archives after updating", ^{
SKIP_IF_RUNNING_ON_TRAVIS
NSError *error = nil;
SQRLTestUpdate *update = [SQRLTestUpdate modelWithDictionary:@{
@"updateURL": zipUpdate(updateURL),
@"final": @YES
} error:&error];
expect(update).notTo.beNil();
expect(error).to.beNil();
expect(update).notTo(beNil());
expect(error).to(beNil());
writeUpdate(update);
NSRunningApplication *app = launchWithEnvironment(nil);
expect(app.terminated).will.beTruthy();
expect(self.testApplicationBundleVersion).will.equal(SQRLTestApplicationUpdatedShortVersionString);
NSRunningApplication *app = launchWithEnvironment(@{ @"SQRLUpdateRequestCount": @2 });
expect([updateDirectoryURLs toArray]).toEventuallyNot(equal(@[]));
expect(@(app.terminated)).withTimeout(SQRLLongTimeout).toEventually(beTruthy());
expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
expect([updateDirectoryURLs toArray]).will.equal(@[]);
expect([updateDirectoryURLs toArray]).toEventually(equal(@[]));
});
});
});
@@ -187,7 +202,7 @@ describe(@"response handling", ^{
__block NSURLRequest *localRequest = nil;
__block SQRLUpdater *updater = nil;
before(^{
beforeEach(^{
localRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"fake://host/path"]];
updater = [[SQRLUpdater alloc] initWithUpdateRequest:localRequest];
});
@@ -204,9 +219,9 @@ describe(@"response handling", ^{
NSError *error = nil;
BOOL result = [[updater.checkForUpdatesCommand execute:nil] asynchronouslyWaitUntilCompleted:&error];
expect(result).to.beFalsy();
expect(error.domain).to.equal(SQRLUpdaterErrorDomain);
expect(error.code).to.equal(SQRLUpdaterErrorInvalidServerResponse);
expect(@(result)).to(beFalsy());
expect(error.domain).to(equal(SQRLUpdaterErrorDomain));
expect(@(error.code)).to(equal(@(SQRLUpdaterErrorInvalidServerResponse)));
});
it(@"should return an error for non JSON data", ^{
@@ -221,9 +236,9 @@ describe(@"response handling", ^{
NSError *error = nil;
BOOL result = [[updater.checkForUpdatesCommand execute:nil] asynchronouslyWaitUntilCompleted:&error];
expect(result).to.beFalsy();
expect(error.domain).to.equal(SQRLUpdaterErrorDomain);
expect(error.code).to.equal(SQRLUpdaterErrorInvalidServerBody);
expect(@(result)).to(beFalsy());
expect(error.domain).to(equal(SQRLUpdaterErrorDomain));
expect(@(error.code)).to(equal(@(SQRLUpdaterErrorInvalidServerBody)));
});
});
@@ -238,6 +253,8 @@ static RACSignal * (^stateNotificationListener)(void) = ^ {
describe(@"state", ^{
it(@"should transition through idle, checking and idle, when there is no update", ^{
SKIP_IF_RUNNING_ON_TRAVIS
NSMutableArray *states = [NSMutableArray array];
[stateNotificationListener() subscribeNext:^(NSNumber *state) {
[states addObject:state];
@@ -250,12 +267,14 @@ describe(@"state", ^{
@(SQRLUpdaterStateCheckingForUpdate),
@(SQRLUpdaterStateIdle),
];
expect(states).will.equal(expectedStates);
expect(states).toEventually(equal(expectedStates));
expect(testApplication.terminated).will.beTruthy();
expect(@(testApplication.terminated)).withTimeout(SQRLLongTimeout).toEventually(beTruthy());
});
it(@"should transition through idle, checking, downloading and awaiting relaunch, when there is an update", ^{
SKIP_IF_RUNNING_ON_TRAVIS
NSMutableArray *states = [NSMutableArray array];
[stateNotificationListener() subscribeNext:^(NSNumber *state) {
[states addObject:state];
@@ -266,8 +285,8 @@ describe(@"state", ^{
@"updateURL": zipUpdate([self createTestApplicationUpdate]),
@"final": @YES,
} error:&error];
expect(update).notTo.beNil();
expect(error).to.beNil();
expect(update).notTo(beNil());
expect(error).to(beNil());
writeUpdate(update);
@@ -279,10 +298,10 @@ describe(@"state", ^{
@(SQRLUpdaterStateDownloadingUpdate),
@(SQRLUpdaterStateAwaitingRelaunch),
];
expect(states).will.equal(expectedStates);
expect(states).withTimeout(SQRLLongTimeout).toEventually(equal(expectedStates));
expect(testApplication.terminated).will.beTruthy();
expect(@(testApplication.terminated)).withTimeout(SQRLLongTimeout).toEventually(beTruthy());
});
});
SpecEnd
QuickSpecEnd
+26 -20
View File
@@ -6,38 +6,44 @@
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <Quick/Quick.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <Squirrel/Squirrel.h>
#import "QuickSpec+SQRLFixtures.h"
#import "SQRLCodeSignature.h"
#import "SQRLZipArchiver.h"
SpecBegin(SQRLZipArchiver)
QuickSpecBegin(SQRLZipArchiverSpec)
it(@"should extract a zip archive created by the Finder", ^{
NSURL *zipURL = [[NSBundle bundleForClass:self.class] URLForResource:@"TestApplication.app" withExtension:@"zip"];
NSError *error = nil;
BOOL success = [[SQRLZipArchiver unzipArchiveAtURL:zipURL intoDirectoryAtURL:self.temporaryDirectoryURL] asynchronouslyWaitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
NSURL *extractedAppURL = [self.temporaryDirectoryURL URLByAppendingPathComponent:@"TestApplication 2.1.app"];
expect([NSFileManager.defaultManager fileExistsAtPath:extractedAppURL.path]).to.beTruthy();
expect(@([NSFileManager.defaultManager fileExistsAtPath:extractedAppURL.path])).to(beTruthy());
success = [[self.testApplicationSignature verifyBundleAtURL:extractedAppURL] waitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
});
it(@"should fail to extract a nonexistent zip archive", ^{
NSError *error = nil;
BOOL success = [[SQRLZipArchiver unzipArchiveAtURL:[self.temporaryDirectoryURL URLByAppendingPathComponent:@"foo.zip"] intoDirectoryAtURL:self.temporaryDirectoryURL] asynchronouslyWaitUntilCompleted:&error];
expect(success).to.beFalsy();
expect(@(success)).to(beFalsy());
NSLog(@"%@", error);
expect(error).notTo.beNil();
expect(error.domain).to.equal(SQRLZipArchiverErrorDomain);
expect(error.code).to.equal(SQRLZipArchiverShellTaskFailed);
expect(error.userInfo[SQRLZipArchiverExitCodeErrorKey]).notTo.equal(0);
expect(error).notTo(beNil());
expect(error.domain).to(equal(SQRLZipArchiverErrorDomain));
expect(@(error.code)).to(equal(@(SQRLZipArchiverShellTaskFailed)));
expect(error.userInfo[SQRLZipArchiverExitCodeErrorKey]).notTo(equal(0));
});
it(@"should create a zip archive readable by itself", ^{
@@ -45,21 +51,21 @@ it(@"should create a zip archive readable by itself", ^{
NSError *error = nil;
BOOL success = [[SQRLZipArchiver createZipArchiveAtURL:zipURL fromDirectoryAtURL:self.testApplicationURL] asynchronouslyWaitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
expect([NSFileManager.defaultManager fileExistsAtPath:zipURL.path]).to.beTruthy();
expect(@([NSFileManager.defaultManager fileExistsAtPath:zipURL.path])).to(beTruthy());
success = [[SQRLZipArchiver unzipArchiveAtURL:zipURL intoDirectoryAtURL:self.temporaryDirectoryURL] asynchronouslyWaitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
NSURL *extractedAppURL = [self.temporaryDirectoryURL URLByAppendingPathComponent:@"TestApplication.app"];
expect([NSFileManager.defaultManager fileExistsAtPath:extractedAppURL.path]).to.beTruthy();
expect(@([NSFileManager.defaultManager fileExistsAtPath:extractedAppURL.path])).to(beTruthy());
success = [[self.testApplicationSignature verifyBundleAtURL:extractedAppURL] waitUntilCompleted:&error];
expect(success).to.beTruthy();
expect(error).to.beNil();
expect(@(success)).to(beTruthy());
expect(error).to(beNil());
});
SpecEnd
QuickSpecEnd
+1 -1
View File
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.github.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
-28
View File
@@ -1,28 +0,0 @@
//
// SquirrelTests-Prefix.pch
// Squirrel
//
// Created by Justin Spahr-Summers on 2013-07-21.
// Copyright (c) 2013 GitHub. All rights reserved.
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#import <XCTest/XCTest.h>
#import <Mantle/Mantle.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <ReactiveCocoa/EXTScope.h>
#import <Squirrel/Squirrel.h>
#define SPT_SUBCLASS SQRLTestCase
#import "Specta.h"
#define EXP_SHORTHAND
#import "Expecta.h"
// Expecta #defines startWith as beginWith, which messes up -startWith: :-(
#undef startWith
#import "SQRLTestCase.h"
#endif
+19
View File
@@ -0,0 +1,19 @@
//
// SwiftSpec.swift
// ReactiveCocoa
//
// Created by Justin Spahr-Summers on 2014-10-14.
// Copyright (c) 2014 GitHub. All rights reserved.
//
import Foundation
import Nimble
import Quick
// Without this, the Swift stdlib won't be linked into the test target (even if
// “Embedded Content Contains Swift Code” is enabled).
class SwiftSpec: QuickSpec {
override func spec() {
expect(true).to(beTruthy())
}
}
-2
View File
@@ -1,2 +0,0 @@
/* Localized versions of Info.plist keys */
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>rules</key>
<dict>
<key>.*</key>
<true/>
</dict>
</dict>
</plist>
+4 -1
View File
@@ -72,6 +72,9 @@
__block NSUInteger updateCheckCount = 1;
NSInteger updateRequestCount = [NSProcessInfo.processInfo.environment[@"SQRLUpdateRequestCount"] integerValue];
if (updateRequestCount < 1) updateRequestCount = 1;
[[[[[[[[[[RACSignal
defer:^{
NSLog(@"***** UPDATE CHECK %lu *****", (unsigned long)updateCheckCount);
@@ -90,7 +93,7 @@
return testUpdate.final;
}]
take:1]
take:updateRequestCount]
doNext:^(id _) {
NSLog(@"***** READY TO INSTALL UPDATE *****");
}]
+3 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.github.Squirrel.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -30,5 +30,7 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticTermination</key>
<false/>
</dict>
</plist>
+1 -1
View File
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_NAME}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
+9 -2
View File
@@ -10,7 +10,7 @@ config ()
{
# A whitespace-separated list of executables that must be present and locatable.
: ${REQUIRED_TOOLS="xctool"}
export REQUIRED_TOOLS
}
@@ -28,7 +28,14 @@ main ()
check_deps
fi
local submodules=$(git submodule status 2>/dev/null)
local submodules=$(git submodule status)
local result=$?
if [ "$result" -ne "0" ]
then
exit $result
fi
if [ -n "$submodules" ]
then
echo "*** Updating submodules..."
BIN
View File
Binary file not shown.
+26 -19
View File
@@ -41,30 +41,26 @@ config ()
# Individual names can be quoted to avoid word splitting.
: ${SCHEMES:=Squirrel}
# A source-able file with information about the Keychain, containing our
# code-signing certificate.
: ${KEYCHAIN_INFO:=/var/lib/jenkins/config/xcodekeychain}
export XCWORKSPACE
export XCODEPROJ
export BOOTSTRAP
export XCTOOL_OPTIONS
export SCHEMES
export KEYCHAIN_INFO
}
##
## Code Signing
##
unlock_keychain ()
setup_keychain ()
{
if [ -e "$KEYCHAIN_INFO" ]
then
# Unlock the keychain so the certificates it contains can be used for building.
. "$KEYCHAIN_INFO"
security unlock-keychain -p "$XCODE_KEYCHAIN_PASSWORD" "$XCODE_KEYCHAIN"
fi
KEY_CHAIN=build.keychain
security create-keychain -p travis $KEY_CHAIN
security default-keychain -s $KEY_CHAIN
security unlock-keychain -p travis $KEY_CHAIN
security set-keychain-settings -t 3600 -u $KEY_CHAIN
security import script/certs.p12 -k build.keychain -P $KEY_PASSWORD -T /usr/bin/codesign
}
##
@@ -74,7 +70,7 @@ unlock_keychain ()
main ()
{
config
unlock_keychain
setup_keychain
if [ -f "$BOOTSTRAP" ]
then
@@ -140,18 +136,29 @@ build_scheme ()
local awkstatus=$?
if [ "$awkstatus" -eq "1" ]
then
# SDK not found, try for iphonesimulator.
sdkflag="-sdk iphonesimulator"
# Determine whether the unit tests will run with iphonesimulator
run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build
awkstatus=$?
if [ "$awkstatus" -ne "0" ]
then
# Unit tests will not run on iphonesimulator.
sdkflag=""
fi
fi
if [ "$awkstatus" -ne "0" ]
then
# Unit tests aren't supported.
action=build
fi
if [ "$awkstatus" -eq "1" ]
then
# Build for iOS.
sdkflag="-sdk iphonesimulator"
fi
run_xctool $sdkflag -scheme "$scheme" $action
}
-199
View File
@@ -1,199 +0,0 @@
#!/usr/bin/env ruby
def exit_error(description)
puts "{ \"error\": \"#{description}\" }"
exit 1
end
module Targets
class Object
def self.match(path)
!File.symlink?(path)
end
attr_reader :path
def initialize(path)
@path = path
end
def search_directories
[]
end
end
class Bundle < Object
def self.match(path)
return false unless super
return false unless match = File.extname(path).match(/\.(.+)/)
return match[1] == extension
end
def contents_directories
[ "Contents" ]
end
def suffix_directories
[
"Frameworks",
"SharedFrameworks",
"XPCServices",
"PlugIns",
"Support",
"SharedSupport",
File.join("Library", "LoginItems"),
File.join("Library", "LaunchServices"),
]
end
def search_directories
contents_directories.product(suffix_directories).map do |combination|
File.join(*combination)
end
end
end
class VersionedBundle < Bundle
def contents_directories
contents_directories = []
versions_directory = File.join(@path, "Versions")
Dir.foreach(versions_directory) do |current_version|
next if current_version.start_with?('.')
full_path = File.join(versions_directory, current_version)
next if File.symlink?(full_path)
contents_directories << File.join("Versions", current_version)
end
contents_directories
end
end
class App < Bundle
def self.extension
"app"
end
end
class Framework < VersionedBundle
def self.extension
"framework"
end
end
class XPCService < Bundle
def self.extension
"xpc"
end
end
class Tool < Object
def self.match(path)
return false unless super
return false unless File.executable?(path)
# Look for an __TEXT,__info_plist section
# This contains the CFBundleIdentifier necessary for signing
`otool -l #{path}` =~ /__info_plist/
end
end
def self.all_targets
[ App, Framework, XPCService, Tool ]
end
end
module Codesign
class Task
def self.sign(target, identity)
codesign_with_arguments([ "--sign", identity, "--force", "--preserve-metadata=identifier,entitlements,resource-rules,requirements", "--verbose", target.path ])
end
protected
def self.codesign_with_arguments(arguments)
$stdout.flush
pid = fork
if pid.nil?
exec("/usr/bin/xcrun", *([ "codesign" ].concat(arguments)))
else
Process.wait(pid)
exit_error("codesign failed") unless $?.exitstatus == 0
end
end
end
end
codesign_identity = ENV['CODE_SIGN_IDENTITY']
unless codesign_identity
exit_error("No codesign identity provided")
end
build_dir = ENV['CONFIGURATION_BUILD_DIR']
product_name = ENV['FULL_PRODUCT_NAME']
unless build_dir && product_name
exit_error("Path to built product not provided")
end
input_path = File.join(build_dir, product_name)
unless File.exists?(input_path)
exit_error("Built product doesn't exist at path provided")
end
targets = [ ]
def match_path(path)
Targets.all_targets.each do |target|
return target.new(path) if target.match(path)
end
nil
end
root_target = match_path input_path
if root_target.nil?
exit_error("Built product is not a known file structure, cannot deep codesign")
end
# Recursion base case can't use build_dir because there can be >1 product
paths_to_search = root_target.search_directories.map do |current_dir|
File.join(root_target.path, current_dir)
end
while paths_to_search.size > 0
new_search_paths = []
paths_to_search.each do |search_path|
next unless File.directory?(search_path)
Dir.foreach(search_path) do |current_directory_entry|
next if current_directory_entry.start_with?(".")
target = match_path(File.join(search_path, current_directory_entry))
next if target.nil?
targets << target
new_search_paths << target.search_directories.map do |current_search_directory|
File.join(target.path, current_search_directory)
end
end
end
paths_to_search = new_search_paths.flatten
end
puts "Signing these targets:"
puts "="*22
print "\n"
# Sort into nested-most first, outer targets might include inner targets
# in their ResourceRules
targets = targets.sort_by do |target|
target.path.size
end
targets.reverse!
targets.each do |target|
puts "=> #{target.path}"
Codesign::Task.sign(target, codesign_identity)
end
+1 -3
View File
@@ -2,10 +2,8 @@ BEGIN {
FS = "\n";
}
/Targets:/ {
/Schemes:/ {
while (getline && $0 != "") {
if ($0 ~ /Test/) continue;
sub(/^ +/, "");
print "'" $0 "'";
}