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

TSCBasic: support case insensitivity for environment #447

Merged
merged 1 commit into from
Dec 19, 2023

Conversation

compnerd
Copy link
Member

Windows is case insensitive for the environment control block, which we did not honour. This causes issues when Swift is used with programs which are incorrectly cased (e.g. emacs). Introduce an explicit wrapper type for Windows to make the lookup case insensitive, canonicalising the name to lowercase. This allows us to treat Path and PATH identically (along with any other environment variable and case matching) which respects the Windows behaviour. Additionally, migrate away from the POSIX variants which do not handle the case properly to the Windows version which does.

Fixes: #446

@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

@swift-ci please test

@MaxDesiatov
Copy link
Contributor

@swift-ci test

@compnerd
Copy link
Member Author

This will need a complementary change in swift-driver, I'll whip that up in a bit.

@MaxDesiatov
Copy link
Contributor

It may break SwiftPM and/or SourceKit-LSP too, that's why deprecation of the old API and introducing a new one may be preferable.

@compnerd
Copy link
Member Author

Sure, the deprecation is something to consider, but this is a problem for Windows and needs to propagate.

@compnerd
Copy link
Member Author

compnerd commented Dec 8, 2023

@swift-ci please test

@compnerd
Copy link
Member Author

compnerd commented Dec 9, 2023

@swift-ci please test Linux platform

@compnerd compnerd force-pushed the insensitive branch 2 times, most recently from e78f87f to fdfb719 Compare December 9, 2023 18:42
@compnerd
Copy link
Member Author

compnerd commented Dec 9, 2023

@MaxDesiatov I'm no longer convinced that trying to do this is valuable and we should just expose this in all its nuance to all users. We will end up having to rebuild the full Dictionary interface otherwise. Either way, the constraints that are needed on the public interfaces are such that we need to make CaseInsensitiveString public in any case, so there is no true value in trying to convert this to a custom data structure.

Sources/TSCBasic/Process.swift Outdated Show resolved Hide resolved
@MaxDesiatov
Copy link
Contributor

MaxDesiatov commented Dec 12, 2023

One more request here: this needs test cases to specify and verify all of the new API surface, since the original bug report doesn't provide self-contained reproducible test cases. Hence my confusion about desired behaviour in a different version of the change.

@compnerd
Copy link
Member Author

I don't know about tests that would be useful here - this is providing the API surface that is necessary to build the dependencies - I don't think that this makes sense to provide tests for unless we just give up on the type representation and just force people to spell out the dictionary type.

@MaxDesiatov
Copy link
Contributor

We have to verify that the new API surface works well in the first place. Tests codify a specification for the behavior and the API shape.

For example, if you want to preserve string case sensitivity internally while allowing case insensitive lookup at the same time, as you mentioned in the other PR, tests should verify that this property holds, and will also guarantee that it doesn't regress in the future.


/// Invalidate the cached env.
public static func invalidateEnv() {
_vars = ProcessInfo.processInfo.environment
_vars = ProcessEnvironmentBlock(uniqueKeysWithValues: ProcessInfo.processInfo.environment.map { (CaseInsensitiveString($0.key), $0.value) })
Copy link
Contributor

Choose a reason for hiding this comment

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

This has to be _block to avoid the deprecation, doesn't it? Also the line is too long, so needs formatting adjustments

Suggested change
_vars = ProcessEnvironmentBlock(uniqueKeysWithValues: ProcessInfo.processInfo.environment.map { (CaseInsensitiveString($0.key), $0.value) })
_block = ProcessEnvironmentBlock(
uniqueKeysWithValues: ProcessInfo.processInfo.environment.map {
(CaseInsensitiveString($0.key), $0.value)
}
)

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think it does, I don't see any deprecation warnings. Note that I left the backing store named _vars. I can change it to _block if you prefer.

}
}
#else
public typealias ProcessEnvironmentBlock = [String:String]
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm unsure if this is a good name, since AFAIU this is specific to Windows NT. Is there something more generic we could use instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

We already have a mixture of env and environment, I think that this is a reasonable alternative.

@compnerd compnerd force-pushed the insensitive branch 3 times, most recently from 1978ba3 to f57674f Compare December 19, 2023 15:15
@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd compnerd force-pushed the insensitive branch 2 times, most recently from d988b94 to 90fd114 Compare December 19, 2023 18:53
@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd compnerd enabled auto-merge (rebase) December 19, 2023 18:54
Copy link
Contributor

@MaxDesiatov MaxDesiatov left a comment

Choose a reason for hiding this comment

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

This LGTM now, thank you for iterating on this 👍

Windows is case insensitive for the environment control block, which we
did not honour. This causes issues when Swift is used with programs
which are incorrectly cased (e.g. emacs). Introduce an explicit wrapper
type for Windows to make the lookup case insensitive, canonicalising the
name to lowercase. This allows us to treat Path and PATH identically
(along with any other environment variable and case matching) which
respects the Windows behaviour. Additionally, migrate away from the
POSIX variants which do not handle the case properly to the Windows
version which does.

The introduced type `ProcessEnvironmentBlock` is just a typealias,
allowing access to the dictionary itself which is important to preserve
the behaviour for the clients.  The `CaseInsensitiveString` is a case
insensitive, case preserving string representation that allows us to
recreate the environment on Windows as the environment is case
insensitive, so it should not be possible to have conflicts when reading
the Process Environment Block from the Process Execution Block.

This is a partial resolution to environment variable handling as the
tools need subsequent changes to adopt the new API.

Fixes: swiftlang#446

Co-authored-by: Max Desiatov <[email protected]>
@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

@swift-ci please test Windows platform

1 similar comment
@compnerd
Copy link
Member Author

@swift-ci please test Windows platform

@compnerd compnerd merged commit 0583d26 into swiftlang:main Dec 19, 2023
3 checks passed
@compnerd compnerd deleted the insensitive branch December 19, 2023 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

case sensitivity of Path environment variable on windows
2 participants