Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Swift Package Manager #186

Merged
merged 46 commits into from
Sep 23, 2021
Merged

Conversation

bjhomer
Copy link
Contributor

@bjhomer bjhomer commented Jul 27, 2021

This PR adds support for Swift Package Manager!

Don't be scared off by the huge number of changes. The majority of the deletions are removing the old .xcodeproj package that is no longer needed, and the majority of the additions are in the new Package.swift file that describes the package structure.

A few highlights to help guide you through this PR:

Source compatibility

This should be fully source-compatible with anyone using Tracks via Cocoapods. (Please check me on that, though!) And switching an existing project over to SPM from Cocoapods should be as simple as adding the SPM dependency and removing the Cocoapod. No code changes should be required.

Organizational changes

When built under SPM, the single "AutomatticTracks" library has now been split into multiple separate modules that implement the various pieces of functionality

  • AutomatticTracksEvents for reporting events
  • AutomatticExperiments for running A/B tests using ExPlat
  • AutomatticRemoteLogging for uploading app logs and crash logs
  • AutomatticCrashLoggingUI for displaying crash logs in a SwiftUI view
  • AutomatticTracks imports all of the above

There are also a couple other modules that just implement shared code: AutomatticTracksModel and AutomatticTracksModelObjC. These aren't very useful on their own, but it seemed useful to pull out the common code.

If you're using the library via Cocoapods, we still just expose import AutomatticTracks as before, so there should be no source changes needed there.

Directory structure

The directory structure has also changed. SPM really wants all files of a single target to belong to a single directory. Because SPM can't have Swift and ObjC code in the same target, I had to make some changes anyway, and since I was doing so, I decided to bring them more in line with what SPM would usually produce. Here's a rough overview of the changes:

  • Before:
    Screen Shot 2021-07-27 at 9 16 50 AM
  • After:
    Screen Shot 2021-07-27 at 9 17 12 AM

Most of those loose files have just been deleted, as they were unnecessary.

Other changes of note.

  • The README has been updated to explain how to install using SPM.
  • The "Reachability" dependency has been removed. It was using deprecated technology, which is now implemented using nw_path_monitor.
  • I've commented inline on other changes, where relevant.

bjhomer added 27 commits July 9, 2021 14:25
This is OCMock 3.8.1, downloaded from ocmock.org and built into an xcframework using the following command:

```bash
xcodebuild -create-xcframework
  -framework OCMock/iOS/OCMock.framework
  -framework OCMock/Mac/OCMock.framework
  -output OCMock.xcframework
```

We were previously pulling in OCMock using Cocoapods, but we are migrating from that to Swift Package Manager. However, OCMock uses unsafe flags in its SPM package manifest, and Xcode 12.5 does not allow dependencies on a package with unsafe flags in its manifest. (Xcode 13 does, so long as you pin to a particular commit, but as of this writing Xcode 13 is still in beta.)
Because tests don't run on iOS devices, our OCMock xcframework doesn't include a slice for physical devices. That means that the tests fail to compile if you're building them for an iOS device destination. But we don't need that anyway, because Xcode already prevents the tests from running in that case.
Cocoapods have been removed from the demo app.
…pdate it.

This preserves backward-compatibility with everyone already using Tracks.
This prevents us from needing an entirely separate module for just one ObjC file.
Calling it "AutomatticTracksiOS" felt wrong, since it also works on Mac.
@bjhomer bjhomer force-pushed the bjhomer/swift-package-manager branch 3 times, most recently from 7fc51a0 to 4415eab Compare July 27, 2021 17:04
@bjhomer
Copy link
Contributor Author

bjhomer commented Aug 10, 2021

Okay, I think this is ready to review again.

@jkmassel jkmassel force-pushed the bjhomer/swift-package-manager branch 2 times, most recently from 5ca6ba1 to 1689f40 Compare August 13, 2021 23:40
@jkmassel jkmassel force-pushed the bjhomer/swift-package-manager branch from 1689f40 to a4e96d9 Compare August 13, 2021 23:48
@jkmassel jkmassel force-pushed the bjhomer/swift-package-manager branch from e9025cc to 65bad60 Compare August 26, 2021 22:20
@jkmassel jkmassel force-pushed the bjhomer/swift-package-manager branch from 74fa9da to b8f8af4 Compare August 26, 2021 22:43
@jkmassel
Copy link
Contributor

@mokagio – tagging you for review in this, because I had to replace the work done in #147 – even with the test target sandboxed, the tests ask for access to the user's Documents directory.

After this change, the Tracks DB will always live in the Application Support directory – whether inside the container, or inside ~/Library/Application Support – thus never triggering this prompt.

The downside is that we'll lose some tracks events in the transition, but it shouldn't be very many, we should only need to do it once, and it'll only be on macOS.

@jkmassel jkmassel requested a review from mokagio August 26, 2021 22:44
Copy link
Contributor

@mokagio mokagio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for doing all this great work @bjhomer. Impressive.

A question for @jkmassel: this PR updates both CircleCI and Buildkite. Is it intentional? Are we waiting to remove CircleCI in a dedicated PR?

The tests now run on a sandboxed app. Ideally, I would like to test this in a non-sandboxed app before approving, but I'm running out of time today. Besides, the only client that is not sandboxed is AutoProxxy, on which we are not planning to do any change soon (which is unfortunate, but we have bigger fishes to fry 🤷 ) It might be cool to add a new build configuration for the macOS demo app, to which we could add a different entitlement file which doesn't use sandboxing. But doesn't have to happen here 👍


Also, this is happening on my local copy:

2021-09-13 14-50-01 2021-09-13 14_51_35

🙃

Is it just me? I'm approving this under the assumption that it's just me.


There's a few questions in which I could have checked the result myself. I wanted to do so, but between my Xcode being stuck in that resolve packages loop and GitHub refusing to scrolling somehow, I'm choosing the lazy route and simply leaving the questions for you to answer. Sorry about that 😞

// target that _only_ builds that one dependency.
// We ignore any failures when building this target.
// Then we go on to build the actual product, which
// builds correctly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a radar for this? Do you happen to have tested it on Xcode 13?

Copy link
Contributor Author

@bjhomer bjhomer Sep 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it works fine on Xcode 13. When I originally put up this PR, Xcode 13 was still a few months out so I was shooting for compatibility with Xcode 12. But since the final Xcode 13 build is likely to be coming out this week, we may be able to just drop this altogether. (On the other hand, this workaround doesn't cause any problems in Xcode 13 either.)

It is mentioned as fixed in the Xcode 13 b3 release notes:

Fixed an issue where resolution of packages with binary dependencies failed to extract the binary archive. (77011310) (FB9085487)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent! Thank you for the update 🙇

In my experience in Automattic Apps Division so far, we haven't been jumping onto the latest Xcode version as soon as released because of the various projects and CI setups. So, I'd lean towards shipping with this and drop it later on.

README.md Outdated Show resolved Hide resolved
Sources/AutomatticTracks/AllExports.swift Outdated Show resolved Hide resolved
Sources/AutomatticTracks/AutomatticTracks.h Outdated Show resolved Hide resolved
Sources/Event Logging/TracksEventService.h Outdated Show resolved Hide resolved
Sources/Remote Logging/RemoteLoggingExports.swift Outdated Show resolved Hide resolved
Comment on lines 1 to 7
//
// File.swift
//
//
// Created by BJ Homer on 7/27/21.
//

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of replacing this with a few lines explaining why we need this workaround here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on how soon we're willing to support Xcode 13 in CI builds, we may be able to just remove this workaround altogether. But if we need to support Xcode 12 in CI builds for a while, then yeah, a comment here would make sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not likely to ship Xcode 13 CI support until about the time macOS Monterey ships (typically most of the bugs are worked out by then). That may change if there are critical features we need from XC13.

}

override func tearDown() {
mockDataProvider.reset()
UserDefaults.standard.removeObject(forKey: "force-crash-logging")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: we could extract the "force-crash-logging" string in an instance private let to prevent typos in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'll do that.

Comment on lines +80 to +82
#if SWIFT_PACKAGE
// When building for SPM, there is no active application for the tests.
XCTAssertEqual("unavailable", event?.tags?["app.state"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the answer either, but I would guess it's an SPM thing, something to do with Linux compatibility maybe? When running the tests for a package with swift test, for example, the Simulator doesn't load. Also, in the template projects, tests are simply files in a folder, there's no mention of an application in the Package.swift or in the project Xcode generates to work on the package. 🤔

<key>IDEDidComputeMac32BitWarning</key>
<key>com.apple.security.app-sandbox</key>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the .plist structure, Git considers this a rename, but it's actually two actions:

  • Add a .entitlements for the Mac demo app to enable sandboxing
  • Remove the IDEWorkspaceChecks.plist file

I wonder why the checks file was removed 🤔 Is this something you did intentionally, or something Xcode automated away?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checks file was removed when I removed the entire .xcworkspace file. It's no longer needed, since Package.swift now serves as the project structure. You can see the commit where it was removed here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package.swift now serves as the project structure

I assume to open the project in this configuration you either open Package.swift or the entire project folder with Xcode. Right?

In such a case, how do you run the demo app from the Package version of the project in Xcode? 🤔 I tried adding a new scheme for it, but couldn't find a way.

image

The only way I found was to open the xcodeproj in the TracksDemo folder. When I do that, Xcode regenerates the IDE checks file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yep. Opening the .xcodeproj file directly is the expected way to run the demo project; the Package.swift file doesn't reference it at all. (Which makes sense, because users of the library don't need to know about it.)

If you want to just open the library code, you can double-click on the Package.swift file, and it will open the whole Swift Package structure in Xcode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't object to checking in the IDEChecks file for the demo project, though.

@bjhomer
Copy link
Contributor Author

bjhomer commented Sep 13, 2021

@mokagio

Is it just me? I'm approving this under the assumption that it's just me.

I am not seeing that repeated package resolution thing, either in Xcode 12.5 or in Xcode 13 betas. So either it's just you, or maybe you're using a different version of Xcode than the ones I've tested on.

@mokagio
Copy link
Contributor

mokagio commented Sep 14, 2021

Thank you for taking the time to address my suggestions @bjhomer and for answering my questions 🙇 .

So either it's just you, or maybe you're using a different version of Xcode than the ones I've tested on.

I get that behavior both on 12.5.1 and 13 beta 4 😞 It's not the first time SPM-related stuff behaves weird on my Mac, I'll file it in that same bucked for now.

@mokagio
Copy link
Contributor

mokagio commented Sep 14, 2021

Something I noticed while doing some experiments around the IDEWorkspaceChecks.plist file (see this comment) is that, with both Xcode 12.5.1 and 13 beta 4, when I open the project the .swiftpm folder is generated.

I'm pretty sure that's the expected behavior, or, at least, is what I've seen in other projects that depend on Package.swift.

The UX around that folder is a bit unclear, but we should at least ignored .swiftpm/xcode. Some references:

The above as well is all based on how I open the code within Xcode: by opening the entire folder with open -a Xcode .. Maybe I'm just not opening it the right way? 🤔

@bjhomer
Copy link
Contributor Author

bjhomer commented Sep 14, 2021

I've added .swiftpm/xcode to the gitignore, and I've committed the IDEWorkspaceChecks plist file.

I'm on Xcode 13 b5 instead of b4, so it's possible the SPM looping behavior is related to that… but I wouldn't put my hopes on that.

@jkmassel jkmassel self-requested a review September 14, 2021 16:50
Copy link
Contributor

@jkmassel jkmassel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the fact that Gio is good with this, I'm onboard to merge it at any time now 🙂

@bjhomer
Copy link
Contributor Author

bjhomer commented Sep 23, 2021

Great, I'm gonna merge it!

@bjhomer bjhomer merged commit d923cb3 into develop Sep 23, 2021
@bjhomer bjhomer deleted the bjhomer/swift-package-manager branch September 23, 2021 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants