jfahrenkrug
(Johannes Fahrenkrug)
1
Dear esteemed gentlepeople,
I have a Swift Package with a test target. The test target needs to include a folder as a resource while preserving its folder structure. I have symlinked that folder because it lives in an npm package and contains many large-ish files that are shared with other test suites in other programming languages.
So my structure looks like this:
- Package.swift
- node_modules/some-package/Files
- Swift/Tests/Files (which is a symlink to "../../node_modules/some-package/Files")
My Package.swift:
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
import Foundation
let package = Package(
name: "MyGreatProject",
platforms: [.iOS(.v15), .macOS(.v13)],
products: [
.library(
name: "MyGreatProject",
targets: ["MyGreatProject"]),
],
targets: [
.target(
name: "MyGreatProject",
path: "Swift/Sources"
),
.testTarget(
name: "MyGreatProjectTests",
dependencies: [
"MyGreatProject",
],
path: "Swift/Tests",
resources: [
// symlinked from node_modules/some-package/Files to Swift/Tests/Files
.copy("Files"),
]
)
]
)
When I open this Swift package in Xcode, I can run the tests and everything works. The symlinked "Files" folder is copied to [Derived Data]/some extra folders/MyGreatProject_MyGreatProjectTests.bundle/Contents/Resources/Files.
However, when I run swift test from the command line, the symlink itself is copied, not its recursive contents. So it creates a symlink named "Files" in .build/arm64-apple-macosx/debug/MyGreatProject_MyGreatProjectTests.bundle which points to "../../node_modules/some-package/Files", which is an invalid path from that location.
Is this a bug? If not, is there a way I can solve this so it works both in Xcode and when running swift test from the command line? Thank you so much!
NeoNacho
(Boris Buegling)
2
I would basically always consider it a bug if Xcode and CLI SwiftPM behave differently in a substantial way like this.
For this particular one, it isn't actually clear to me what we would consider the correct behavior. SE-0271 doesn't seem to talk about symbolic links at all, so I don't think anyone has ever really thought about it. The Xcode behavior seems generally more useful to me though, it could see the possibility of wanting to copy a symlink, but it seems rare. There's also the question what should happen if there's a symlink somewhere inside the copied folder structure that points outside of the target.
I don't have any suggestions for a workaround, unfortunately.
jfahrenkrug
(Johannes Fahrenkrug)
3
@NeoNacho Thank you for your feedback. I agree that this feels like a bug. Good questions about how symlinks should be treated: Since we are talking about copying resources, I would argue that following the top-level symlink would make the most sense. If one of its subdirectories also contains a symlink, it would just be copied as-is. Basically I'd expect the same behavior as cp -r origin_symlink_folder destination_folder: That results in a new folder named destination_folder being created containing the contents of the target of origin_symlink_folder symlink.
I worked around my issue by defining a postinstall script in my package.json that actually copies the folders from the npm package to Swift/Tests/Files.