Skip to content

Commit 487cbb0

Browse files
committed
Merge branch 'main' into matt/runtimeDownload
2 parents dc5a8b0 + 5b18a90 commit 487cbb0

37 files changed

Lines changed: 661 additions & 65 deletions

.github/workflows/appcast.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ jobs:
99
runs-on: ubuntu-latest
1010
steps:
1111
- name: Checkout 🛎
12-
uses: actions/checkout@v3
12+
uses: actions/checkout@v4
1313
with:
14-
# If you're using actions/checkout@v3 you must set persist-credentials to false in most cases for the deployment to work correctly.
14+
# If you're using actions/checkout@v4 you must set persist-credentials to false in most cases for the deployment to work correctly.
1515
persist-credentials: false
1616

1717
- name: Cache 📦
18-
uses: actions/cache@v3.3.1
18+
uses: actions/cache@v3.3.2
1919
with:
2020
path: AppCast/vendor/bundle
2121
key: ${{ runner.os }}-gems-v1.0-${{ hashFiles('AppCast/Gemfile') }}
2222
restore-keys: |
2323
${{ runner.os }}-gems-
2424
2525
- name: Setup Ruby, JRuby and TruffleRuby
26-
uses: ruby/setup-ruby@v1.144.2
26+
uses: ruby/setup-ruby@v1.161.0
2727
with:
2828
ruby-version: '2.7'
2929

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ on:
88

99
jobs:
1010
test:
11-
runs-on: macos-12
11+
runs-on: macos-13
1212
steps:
13-
- uses: actions/checkout@v3
13+
- uses: actions/checkout@v4
1414
- name: Run tests
1515
env:
16-
DEVELOPER_DIR: /Applications/Xcode_13.2.1.app
16+
DEVELOPER_DIR: /Applications/Xcode_15.0.1.app
1717
run: xcodebuild test -scheme Xcodes

README.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ The easiest way to install and switch between multiple versions of Xcode.
44

55
_If you're looking for a command-line version of Xcodes.app, try [`xcodes`](https://github.com/XcodesOrg/xcodes)._
66

7-
![CI](https://github.com/XcodesOrg/Xcodes.app/workflows/CI/badge.svg)
7+
![CI](https://github.com/XcodesOrg/XcodesApp/workflows/CI/badge.svg)
88

99
![](screenshot_light.png#gh-light-mode-only)
1010
![](screenshot_dark.png#gh-dark-mode-only)
1111

12-
### :tada: Announcment
12+
### :tada: Announcement
1313

1414
XcodesApp is now part of the `XcodesOrg` - [read more here](nextstep.md)
1515

@@ -25,14 +25,14 @@ XcodesApp is now part of the `XcodesOrg` - [read more here](nextstep.md)
2525

2626
## Experiments
2727

28-
- Thanks to the wonderful work of [https://github.com/saagarjha/unxip](https://github.com/saagarjha/unxip), turn on the experiment to increase your unxipping time by up to 70%! More can be found on his repo, but bugs, high memory may occur if used.
28+
- Thanks to the wonderful work of [https://github.com/saagarjha/unxip](https://github.com/saagarjha/unxip), turn on the experiment to increase your unxipping time by up to 70%! More can be found on his repo, but bugs, high memory may occur if used.
2929

30-
![](experiment_light.jpg#gh-light-mode-only)
31-
![](experiment_dark.jpg#gh-dark-mode-only)
30+
![](experiment_light.png#gh-light-mode-only)
31+
![](experiment_dark.png#gh-dark-mode-only)
3232

3333
## Localization
3434

35-
Xcodes supports localization in several languages.
35+
Xcodes supports localization in several languages.
3636

3737
The following languages are supported because of the following community users!
3838

@@ -45,22 +45,23 @@ The following languages are supported because of the following community users!
4545
|Finnish 🇫🇮 |[@marcusziade](https://github.com/marcusziade)|Chinese-Traditional 🇹🇼|[@itszero](https://github.com/itszero)|
4646
|Ukranian 🇺🇦 |[@gelosi](https://github.com/gelosi)|Japanese 🇯🇵|[@tatsuz0u](https://github.com/tatsuz0u)|
4747
|German 🇩🇪|[@drct](https://github.com/drct)|Dutch 🇳🇱|[@jfversluis](https://github/com/jfversluis)|
48-
|Brazilian Portuguese 🇧🇷|[@brunomunizaf](https://github.com/brunomunizaf)||
48+
|Brazilian Portuguese 🇧🇷|[@brunomunizaf](https://github.com/brunomunizaf)|Polish 🇵🇱|[@jakex7](https://github.com/jakex7)|
49+
|Catalan|[@ferranabello](https://github.com/ferranabello)|
4950

50-
Want to add more languages? Simply create a PR with the updated strings file.
51+
Want to add more languages? Simply create a PR with the updated strings file.
5152
## Installation
5253

5354
Xcodes.app runs on macOS Big Sur 11.0 or later.
5455

55-
### Homebrew Cask
56+
### Install with Homebrew
57+
58+
Developer ID-signed and notarized release builds are available on Homebrew. These don't require Xcode to already be installed in order to use.
5659

5760
```sh
5861
brew install --cask xcodes
59-
60-
# These are Developer ID-signed and notarized release builds and don't require Xcode to already be installed in order to use.
6162
```
6263

63-
### Download a release
64+
### Manually install
6465

6566
1. Download the latest version [here](https://github.com/XcodesOrg/XcodesApp/releases/latest) using the **Xcodes.zip** asset. These are Developer ID-signed and notarized release builds and don't require Xcode to already be installed in order to use.
6667
2. Move the unzipped `Xcodes.app` to your `/Applications` directory
@@ -79,7 +80,7 @@ You'll need macOS 12 Big Sur and Xcode 13 in order to build and run Xcodes.app.
7980
# combine for universal binary
8081
lipo -create -output unxip unxip_intel unxip_m1
8182
# check it
82-
lipo -archs unxip
83+
lipo -archs unxip
8384
```
8485

8586
Notable design decisions are recorded in [DECISIONS.md](./DECISIONS.md). The Apple authentication flow is described in [Apple.paw](./Apple.paw), which will allow you to play with the API endpoints that are involved using the [Paw](https://paw.cloud) app.

Xcodes.xcodeproj/project.pbxproj

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 52;
6+
objectVersion = 54;
77
objects = {
88

99
/* Begin PBXBuildFile section */
@@ -100,6 +100,7 @@
100100
CAFE4AB425B7D3AF0064FE51 /* AdvancedPreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFE4AB325B7D3AF0064FE51 /* AdvancedPreferencePane.swift */; };
101101
CAFE4ABC25B7D54B0064FE51 /* UpdatesPreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFE4ABB25B7D54B0064FE51 /* UpdatesPreferencePane.swift */; };
102102
CAFFFED8259CDA5000903F81 /* XcodeListViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */; };
103+
E689540325BE8C64000EBCEA /* DockProgress in Frameworks */ = {isa = PBXBuildFile; productRef = E689540225BE8C64000EBCEA /* DockProgress */; };
103104
E81D7EA02805250100A205FC /* Collection+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81D7E9F2805250100A205FC /* Collection+.swift */; };
104105
E872EE4E2808D4F100D3DD8B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E872EE502808D4F100D3DD8B /* Localizable.strings */; };
105106
E87AB3C52939B65E00D72F43 /* Hardware.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87AB3C42939B65E00D72F43 /* Hardware.swift */; };
@@ -175,6 +176,7 @@
175176

176177
/* Begin PBXFileReference section */
177178
15FAD1652811D15600B63259 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = "<group>"; };
179+
23703D6E29EBF63500DFA346 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
178180
25E2FA26284769A00014A318 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
179181
327DF109286ABE6B00D694D5 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
180182
36741BFC291E4FDB00A85AAE /* DownloadPreferencePane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadPreferencePane.swift; sourceTree = "<group>"; };
@@ -185,6 +187,7 @@
185187
53CBAB2B263DCC9100410495 /* XcodesAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodesAlert.swift; sourceTree = "<group>"; };
186188
58F743C02810A34900EEC0F3 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
187189
5AA8A6102877EDAD009ECDB0 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
190+
5C3927ED28E4B486007B5119 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
188191
63EAA4EA259944450046AB8F /* ProgressButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressButton.swift; sourceTree = "<group>"; };
189192
6CA3A090282EBE72005A6E35 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
190193
7CBF284E28606D2C001AA66B /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -330,6 +333,7 @@
330333
E8F81FC4282D8A17006CBD0F /* Sparkle in Frameworks */,
331334
CABFA9E42592F08E00380FEE /* Version in Frameworks */,
332335
CABFA9FD2592F13300380FEE /* LegibleError in Frameworks */,
336+
E689540325BE8C64000EBCEA /* DockProgress in Frameworks */,
333337
CA9FF86D25951C6E00E47BAF /* XCModel in Frameworks */,
334338
CABFA9F82592F0F900380FEE /* KeychainAccess in Frameworks */,
335339
CAA858CD25A3D8BC00ACF8C0 /* ErrorHandling in Frameworks */,
@@ -672,6 +676,7 @@
672676
CA9FF86C25951C6E00E47BAF /* XCModel */,
673677
CAA858CC25A3D8BC00ACF8C0 /* ErrorHandling */,
674678
E8F81FC3282D8A17006CBD0F /* Sparkle */,
679+
E689540225BE8C64000EBCEA /* DockProgress */,
675680
E8FD5726291EE4AC001E004C /* AsyncNetworkService */,
676681
E8C0EB19291EF43E0081528A /* XcodesKit */,
677682
E8F44A1D296B4CD7002D6592 /* Path */,
@@ -743,8 +748,10 @@
743748
de,
744749
uk,
745750
fi,
751+
ca,
746752
"pt-BR",
747753
nl,
754+
pl,
748755
);
749756
mainGroup = CAD2E7952449574E00113D76;
750757
packageReferences = (
@@ -756,6 +763,7 @@
756763
CAA858CB25A3D8BC00ACF8C0 /* XCRemoteSwiftPackageReference "ErrorHandling" */,
757764
CAC28186259EE27200B8AB0B /* XCRemoteSwiftPackageReference "CombineExpectations" */,
758765
E8F81FC2282D8A17006CBD0F /* XCRemoteSwiftPackageReference "Sparkle" */,
766+
E689540125BE8C64000EBCEA /* XCRemoteSwiftPackageReference "DockProgress" */,
759767
E8FD5725291EE4AC001E004C /* XCRemoteSwiftPackageReference "AsyncHTTPNetworkService" */,
760768
E8F44A1C296B4CD7002D6592 /* XCRemoteSwiftPackageReference "Path" */,
761769
);
@@ -963,8 +971,10 @@
963971
A0187D39285792D1002F46F9 /* de */,
964972
7CBF284E28606D2C001AA66B /* uk */,
965973
5AA8A6102877EDAD009ECDB0 /* fi */,
974+
5C3927ED28E4B486007B5119 /* ca */,
966975
327DF109286ABE6B00D694D5 /* pt-BR */,
967976
E2AFDCCA28F024D000864ADD /* nl */,
977+
23703D6E29EBF63500DFA346 /* pl */,
968978
);
969979
name = Localizable.strings;
970980
sourceTree = "<group>";
@@ -1090,7 +1100,7 @@
10901100
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
10911101
CODE_SIGN_STYLE = Automatic;
10921102
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
1093-
DEVELOPMENT_TEAM = PBH8V487HB;
1103+
DEVELOPMENT_TEAM = ZU6GR6B2FY;
10941104
ENABLE_HARDENED_RUNTIME = YES;
10951105
INFOPLIST_FILE = "$(SRCROOT)/$(TARGET_NAME)/Info.plist";
10961106
MARKETING_VERSION = 1.0.3;
@@ -1140,7 +1150,7 @@
11401150
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
11411151
CODE_SIGN_STYLE = Automatic;
11421152
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
1143-
DEVELOPMENT_TEAM = PBH8V487HB;
1153+
DEVELOPMENT_TEAM = ZU6GR6B2FY;
11441154
ENABLE_HARDENED_RUNTIME = YES;
11451155
INFOPLIST_FILE = "$(SRCROOT)/$(TARGET_NAME)/Info.plist";
11461156
MARKETING_VERSION = 1.0.3;
@@ -1332,7 +1342,7 @@
13321342
BUNDLE_LOADER = "$(TEST_HOST)";
13331343
CODE_SIGN_STYLE = Automatic;
13341344
COMBINE_HIDPI_IMAGES = YES;
1335-
DEVELOPMENT_TEAM = PBH8V487HB;
1345+
DEVELOPMENT_TEAM = ZU6GR6B2FY;
13361346
INFOPLIST_FILE = XcodesTests/Info.plist;
13371347
LD_RUNPATH_SEARCH_PATHS = (
13381348
"$(inherited)",
@@ -1353,7 +1363,7 @@
13531363
BUNDLE_LOADER = "$(TEST_HOST)";
13541364
CODE_SIGN_STYLE = Automatic;
13551365
COMBINE_HIDPI_IMAGES = YES;
1356-
DEVELOPMENT_TEAM = PBH8V487HB;
1366+
DEVELOPMENT_TEAM = ZU6GR6B2FY;
13571367
INFOPLIST_FILE = XcodesTests/Info.plist;
13581368
LD_RUNPATH_SEARCH_PATHS = (
13591369
"$(inherited)",
@@ -1417,6 +1427,8 @@
14171427
isa = XCRemoteSwiftPackageReference;
14181428
repositoryURL = "https://github.com/xcodereleases/data";
14191429
requirement = {
1430+
kind = revision;
1431+
revision = a43ad89e536d7a3da525fcc23fb182c37b756ecc;
14201432
branch = main;
14211433
kind = branch;
14221434
};
@@ -1469,6 +1481,14 @@
14691481
minimumVersion = 0.6.0;
14701482
};
14711483
};
1484+
E689540125BE8C64000EBCEA /* XCRemoteSwiftPackageReference "DockProgress" */ = {
1485+
isa = XCRemoteSwiftPackageReference;
1486+
repositoryURL = "https://github.com/sindresorhus/DockProgress";
1487+
requirement = {
1488+
kind = upToNextMinorVersion;
1489+
minimumVersion = 3.2.0;
1490+
};
1491+
};
14721492
E8F44A1C296B4CD7002D6592 /* XCRemoteSwiftPackageReference "Path" */ = {
14731493
isa = XCRemoteSwiftPackageReference;
14741494
repositoryURL = "https://github.com/mxcl/Path.swift";
@@ -1535,6 +1555,11 @@
15351555
package = CAC28186259EE27200B8AB0B /* XCRemoteSwiftPackageReference "CombineExpectations" */;
15361556
productName = CombineExpectations;
15371557
};
1558+
E689540225BE8C64000EBCEA /* DockProgress */ = {
1559+
isa = XCSwiftPackageProductDependency;
1560+
package = E689540125BE8C64000EBCEA /* XCRemoteSwiftPackageReference "DockProgress" */;
1561+
productName = DockProgress;
1562+
};
15381563
E8C0EB19291EF43E0081528A /* XcodesKit */ = {
15391564
isa = XCSwiftPackageProductDependency;
15401565
productName = XcodesKit;

Xcodes.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Xcodes/Backend/AppState+Install.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import AppleAPI
55
import Version
66
import LegibleError
77
import os.log
8+
import DockProgress
89
import XcodesKit
910

1011
/// Downloads and installs Xcodes
@@ -44,6 +45,8 @@ extension AppState {
4445

4546
Logger.appState.info("Using \(downloader) downloader")
4647

48+
setupDockProgress()
49+
4750
return validateSession()
4851
.flatMap { _ in
4952
self.getXcodeArchive(installationType, downloader: downloader)
@@ -52,6 +55,8 @@ extension AppState {
5255
self.installArchivedXcode(xcode, at: url)
5356
}
5457
.catch { error -> AnyPublisher<InstalledXcode, Swift.Error> in
58+
self.resetDockProgressTracking()
59+
5560
switch error {
5661
case InstallationError.damagedXIP(let damagedXIPURL):
5762
guard attemptNumber < 1 else { return Fail(error: error).eraseToAnyPublisher() }
@@ -100,6 +105,7 @@ extension AppState {
100105
self.downloadOrUseExistingArchive(for: availableXcode, downloader: downloader, progressChanged: { [unowned self] progress in
101106
DispatchQueue.main.async {
102107
self.setInstallationStep(of: availableXcode.version, to: .downloading(progress: progress))
108+
self.overallProgress.addChild(progress, withPendingUnitCount: AppState.totalProgressUnits - AppState.unxipProgressWeight)
103109
}
104110
})
105111
.map { return (availableXcode, $0) }
@@ -152,6 +158,7 @@ extension AppState {
152158
cookies
153159
)
154160
progressChanged(progress)
161+
155162
return publisher
156163
.map { _ in destination.url }
157164
.eraseToAnyPublisher()
@@ -166,6 +173,7 @@ extension AppState {
166173
to: destination.url,
167174
resumingWith: resumeData ?? persistedResumeData)
168175
progressChanged(progress)
176+
169177
return publisher
170178
.map { $0.saveLocation }
171179
.eraseToAnyPublisher()
@@ -177,6 +185,9 @@ extension AppState {
177185
}
178186

179187
public func installArchivedXcode(_ availableXcode: AvailableXcode, at archiveURL: URL) -> AnyPublisher<InstalledXcode, Error> {
188+
unxipProgress.completedUnitCount = 0
189+
overallProgress.addChild(unxipProgress, withPendingUnitCount: AppState.unxipProgressWeight)
190+
180191
do {
181192
let destinationURL = Path.installDirectory.join("Xcode-\(availableXcode.version.descriptionWithoutBuildMetadata).app").url
182193
switch archiveURL.pathExtension {
@@ -416,6 +427,9 @@ extension AppState {
416427
}
417428
self.presentedAlert = .privilegedHelper
418429
}
430+
431+
unxipProgress.completedUnitCount = AppState.totalProgressUnits
432+
resetDockProgressTracking()
419433

420434
return helperInstallConsentSubject
421435
.flatMap {
@@ -456,6 +470,24 @@ extension AppState {
456470
.eraseToAnyPublisher()
457471
}
458472

473+
// MARK: - Dock Progress Tracking
474+
475+
private func setupDockProgress() {
476+
DockProgress.progressInstance = nil
477+
DockProgress.style = .bar
478+
479+
let progress = Progress(totalUnitCount: AppState.totalProgressUnits)
480+
progress.kind = .file
481+
progress.fileOperationKind = .downloading
482+
overallProgress = progress
483+
484+
DockProgress.progressInstance = overallProgress
485+
}
486+
487+
func resetDockProgressTracking() {
488+
DockProgress.progress = 1 // Only way to completely remove overlay with DockProgress is setting progress to complete
489+
}
490+
459491
// MARK: -
460492

461493
func setInstallationStep(of version: Version, to step: InstallationStep) {

0 commit comments

Comments
 (0)