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

Follow-up / Making Scipio environment-configurable #154

Merged
merged 10 commits into from
Nov 18, 2024

Conversation

dmhts
Copy link
Contributor

@dmhts dmhts commented Oct 30, 2024

This PR is a follow-up built on #140, where Runner became more environment-aware. This follow-up addresses two additional issues:

Issue 1:

It fixes an issue where the environment dictionary was not properly passed through to UserToolchain.

Issue 2:

It introduces a non-caching implementation of the SwiftSDK.sdkPlatformFrameworkPaths(environment:) function (which basically copies the original function without the path-caching part). The original function, although environment-aware, caches the resolved platform path unconditionally on the first call in a private static property, with no way to reset the cache later. For Scipio to be fully environment-configurable, especially when the environment may change multiple times within a single run (e.g., when Scipio is used with multiple toolchains), each environment (associated with a specific toolchain) requires a unique platform path, e.g.:

- /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform
- /Applications/Xcode-15.4.app/Contents/Developer/Platforms/MacOSX.platform
- /Applications/Xcode-16.1.app/Contents/Developer/Platforms/MacOSX.platform"

Therefore, to enable greater flexibility, a non-caching implementation of the original function has been introduced.

@giginet As always, looking forward to your comments and questions.

@dmhts dmhts changed the title Follow-up / Making environment configurable Follow-up / Making Scipio environment-configurable Oct 30, 2024

/// A non-caching environment-aware implementation of `SwiftSDK.sdkPlatformFrameworkPaths`
/// Returns `macosx` sdk platform framework path.
func nonCachingSDKPlatformFrameworkPaths() async throws -> (fwk: AbsolutePath, lib: AbsolutePath) {
Copy link
Contributor Author

@dmhts dmhts Oct 30, 2024

Choose a reason for hiding this comment

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

As I mentioned in the PR description, this is just a copy of the existing function without the path-caching part.

Copy link
Owner

Choose a reason for hiding this comment

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

Could you note this context in the comment?

Copy link
Owner

Choose a reason for hiding this comment

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

Please avoid abbreviations frameworkPath, libPath

Copy link
Owner

Choose a reason for hiding this comment

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

I prefer to add a verb to the name. This method executes external commands, so it's not better to name it like a getter.

How about renaming like resolveSDKPlatformFrameworkPaths?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please avoid abbreviations frameworkPath, libPath

Sorry, I just copied Apple's implementation one-to-one. Of course, it makes sense. Done.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How about renaming like resolveSDKPlatformFrameworkPaths?

Yes, I also like it. Done.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you note this context in the comment?

/// A non-caching environment-aware implementation of SwiftSDK.sdkPlatformFrameworkPaths

I believe it's already in the comment above, or did you mean something else?

Copy link
Owner

@giginet giginet left a comment

Choose a reason for hiding this comment

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

Its concept looks good. However, it's better to tweak the interface of adding the method even if you just moved the existing implementation.


/// A non-caching environment-aware implementation of `SwiftSDK.sdkPlatformFrameworkPaths`
/// Returns `macosx` sdk platform framework path.
func nonCachingSDKPlatformFrameworkPaths() async throws -> (fwk: AbsolutePath, lib: AbsolutePath) {
Copy link
Owner

Choose a reason for hiding this comment

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

Could you note this context in the comment?


/// A non-caching environment-aware implementation of `SwiftSDK.sdkPlatformFrameworkPaths`
/// Returns `macosx` sdk platform framework path.
func nonCachingSDKPlatformFrameworkPaths() async throws -> (fwk: AbsolutePath, lib: AbsolutePath) {
Copy link
Owner

Choose a reason for hiding this comment

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

Please avoid abbreviations frameworkPath, libPath


/// A non-caching environment-aware implementation of `SwiftSDK.sdkPlatformFrameworkPaths`
/// Returns `macosx` sdk platform framework path.
func nonCachingSDKPlatformFrameworkPaths() async throws -> (fwk: AbsolutePath, lib: AbsolutePath) {
Copy link
Owner

Choose a reason for hiding this comment

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

I prefer to add a verb to the name. This method executes external commands, so it's not better to name it like a getter.

How about renaming like resolveSDKPlatformFrameworkPaths?

import struct Basics.AbsolutePath
@_spi(SwiftPMInternal) import struct Basics.Environment

public typealias ToolchainEnvironment = [String: String]
Copy link
Contributor Author

@dmhts dmhts Nov 13, 2024

Choose a reason for hiding this comment

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

@giginet I've extracted all the ToolchainEnvironment-related logic into a separate file and introduced a type alias for improved semantics. Does that work for you?

Comment on lines 77 to 83
self.toolchain = try UserToolchain(
swiftSDK: try .hostSwiftSDK(
toolchainEnvironment?.toolchainBinPath,
environment: toolchainEnvironment.asSwiftPMEnvironment
),
environment: toolchainEnvironment.asSwiftPMEnvironment
)
Copy link
Contributor Author

@dmhts dmhts Nov 13, 2024

Choose a reason for hiding this comment

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

Sorry for the belated response. I'm back as of today!

We’re almost finished with our Scipio-powered tool, and during final testing, we discovered another environment-related issue (hopefully the last one!).

There’s a bug in SwiftPM where Environment isn’t passed down to the shell-executing function here. Fortunately, it’s possible to work around this by supplying a custom binDir (pointing to the bin dir of the current toolchain in our case) a few lines above.

I’m planning to file another fix for this in SwiftPM soon (I've already merged these two, and have one currently open). Although it’s not a critical issue, resolving it would allow a cleaner setup by removing the need to specify a custom bin path.

Apologies for including this change in the current PR, but I believe it’s closely related to its focus, and it’s purely additive, leaving existing behavior unaffected.

As mentioned, this appears to be the last environment-related enhancement needed to enable Scipio for multi-toolchain use. 🎉

@dmhts
Copy link
Contributor Author

dmhts commented Nov 13, 2024

@giginet is it the CI issue?

@ikesyo
Copy link
Collaborator

ikesyo commented Nov 18, 2024

The CI failure is related to actions/runner-images#10703

Copy link
Owner

@giginet giginet left a comment

Choose a reason for hiding this comment

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

Almost great. I'll modify the small points on this PR and I'll merge this

@@ -0,0 +1,19 @@
import XCTest
Copy link
Owner

Choose a reason for hiding this comment

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

You can use @Testing for new tests 😄

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 haven't noticed you already used it in the other tests. No problem, I'll do it next time 👍

}
}

extension ToolchainEnvironment? {
Copy link
Owner

@giginet giginet Nov 18, 2024

Choose a reason for hiding this comment

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

It's confusing to extend to Optional.
.current is injected on the callee side, but I prefer to inject on the caller side explicitly.

Copy link
Contributor Author

@dmhts dmhts Nov 18, 2024

Choose a reason for hiding this comment

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

The idea is to shift all the boilerplate from the calling site to the extension. Sure, we can use map or flatMap at the calling site, but then it would be like this:

try UserToolchain(
    swiftSDK: try .hostSwiftSDK(
        toolchainEnvironment?.toolchainBinPath,
        environment: toolchainEnvironment.flatMap { Environment($0) } ?? Environment.current
    ),
    environment: toolchainEnvironment.flatMap { Environment($0) } ?? Environment.current
)

versus with the optional extension:

try UserToolchain(
    swiftSDK: try .hostSwiftSDK(
        toolchainEnvironment?.toolchainBinPath,
        environment: toolchainEnvironment.asSwiftPMEnvironment
    ),
    environment: toolchainEnvironment.asSwiftPMEnvironment
)

Additionally, in the first case, we would also need to use this clunky import: @_spi(SwiftPMInternal) import struct Basics.Environment every time Environment is referenced.

or did you mean something else?

Copy link
Owner

Choose a reason for hiding this comment

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

Thank you for the comment. I haven't considered _spi.

I already tweaked my changes, but I'll revert this commit. 260baa5

Sorry for the modification!

Copy link
Contributor Author

@dmhts dmhts Nov 18, 2024

Choose a reason for hiding this comment

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

@giginet I see what you mean! Looks good to me 👍

Update: yeah, it doesn't solve the issue with the import.

Copy link
Owner

Choose a reason for hiding this comment

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

Oops, I already reverted the commit 😓

If you think it's good, I'll apply the commit again and merge this. Thank you!

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 was mistaken, the import was not needed in your case. Yeah, feel free to apply it again. As a benefit of your approach - it's more obvious that the variable is optional at the calling site.

@giginet
Copy link
Owner

giginet commented Nov 18, 2024

Sorry, I tweaked your patch. I'll merge this 🚀

@giginet giginet merged commit 8bab62a into giginet:main Nov 18, 2024
2 checks passed
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.

3 participants