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

Sometimes SPM seems to duplicate checked out files #5589

Closed
hassila opened this issue Jun 14, 2022 · 5 comments
Closed

Sometimes SPM seems to duplicate checked out files #5589

hassila opened this issue Jun 14, 2022 · 5 comments
Assignees

Comments

@hassila
Copy link

hassila commented Jun 14, 2022

Description

As outlined in https://forums.swift.org/t/docc-gets-duplicated-file-checked-out/57742/2 :

We see a weird behaviour with the docc plugin and wonder if anyone else have run in to it or have any hints - quite often we'll get duplicate checkout of docc plugin source files (see below) which leads to a broken build as there are multiple source files with the same content (suffixed "2", "3", ...) removing the .build directory will give a perfectly clean compilation. In this case I had a clean build, ran tests with TSAN and then triggered the problem.

hassila@max ~/D/G/swift-storage (main) [1]> swift test
Compiling plugin Swift-DocC...
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/SwiftDocCConvert 3.swift:13:14: error: invalid redeclaration of 'SwiftDocCConvert'
@main struct SwiftDocCConvert: CommandPlugin {
             ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/SwiftDocCConvert.swift:13:14: note: 'SwiftDocCConvert' previously declared here
@main struct SwiftDocCConvert: CommandPlugin {
             ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/SwiftDocCConvert 3.swift:16:37: error: ambiguous use of 'doccExecutable'
        let doccExecutableURL = try context.doccExecutable
                                    ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/PluginContext+doccExecutableURL 2.swift:19:9: note: found this candidate
    var doccExecutable: URL {
        ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/PluginContext+doccExecutableURL 3.swift:19:9: note: found this candidate
    var doccExecutable: URL {
        ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/PluginContext+doccExecutableURL.swift:19:9: note: found this candidate
    var doccExecutable: URL {
        ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/SwiftDocCConvert 3.swift:19:36: error: ambiguous use of 'extractSpecifiedTargets(in:)'
        let specifiedTargets = try argumentExtractor.extractSpecifiedTargets(in: context.package)
                                   ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/ArgumentExtractor+extractSpecifiedTargets 3.swift:51:19: note: found this candidate
    mutating func extractSpecifiedTargets(in package: Package) throws -> [SwiftSourceModuleTarget] {
                  ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/ArgumentExtractor+extractSpecifiedTargets.swift:51:19: note: found this candidate
    mutating func extractSpecifiedTargets(in package: Package) throws -> [SwiftSourceModuleTarget] {
                  ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/SwiftDocCConvert 3.swift:23:48: error: ambiguous use of 'allDocumentableTargets'
            swiftSourceModuleTargets = context.package.allDocumentableTargets
                                               ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/PackageExtensions 3.swift:73:9: note: found this candidate
    var allDocumentableTargets: [SwiftSourceModuleTarget] {
        ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/PackageExtensions.swift:73:9: note: found this candidate
    var allDocumentableTargets: [SwiftSourceModuleTarget] {
        ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/SwiftDocCConvert 3.swift:29:19: error: ambiguous use of 'packageDoesNotContainSwiftSourceModuleTargets'
            throw ArgumentParsingError.packageDoesNotContainSwiftSourceModuleTargets
                  ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/ArgumentExtractor+extractSpecifiedTargets 3.swift:16:10: note: found this candidate
    case packageDoesNotContainSwiftSourceModuleTargets
         ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SharedPackagePluginExtensions/ArgumentExtractor+extractSpecifiedTargets.swift:16:10: note: found this candidate
    case packageDoesNotContainSwiftSourceModuleTargets
         ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/SwiftDocCConvert 3.swift:35:31: error: ambiguous use of 'init(_:)'
        let parsedArguments = ParsedArguments(argumentExtractor.remainingArguments)
                              ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SwiftDocCPluginUtilities/ParsedArguments 3.swift:154:12: note: found this candidate
    public init(_ arguments: [String]) {
           ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SwiftDocCPluginUtilities/ParsedArguments.swift:154:12: note: found this candidate
    public init(_ arguments: [String]) {
           ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SwiftDocCPluginUtilities/HelpInformation 3.swift:37:50: error: 'PluginAction' is ambiguous for type lookup in this context
    public static func forAction(_ pluginAction: PluginAction, doccExecutableURL: URL) throws -> String {
                                                 ^~~~~~~~~~~~
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SwiftDocCPluginUtilities/PluginAction 2.swift:10:13: note: found this candidate
public enum PluginAction: String {
            ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SwiftDocCPluginUtilities/PluginAction 3.swift:10:13: note: found this candidate
public enum PluginAction: String {
            ^
/Users/hassila/Documents/GitHub/swift-storage/.build/checkouts/swift-docc-plugin/Plugins/Swift-DocC Convert/Symbolic Links/SwiftDocCPluginUtilities/PluginAction.swift:10:13: note: found this candidate
.......

Haven't used any other SPM plugins so can't say if it's an issue with SPM, with the DocC plugin or with our environment (we are simply using GitHub and checking out from there).

In this specific example the package manifest is fairly minimal:

// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "swift-storage",
    platforms: [
        .macOS(.v12),
    ],
    products: [
        .library(
            name: "Storage",
            targets: ["Storage"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-lmdb", branch: "main"),
        .package(url: "https://github.com/apple/swift-argument-parser", .upToNextMajor(from: "1.1.0")),
        .package(url: "https://github.com/apple/swift-log", .upToNextMajor(from: "1.0.0")),
        .package(url: "https://github.com/apple/swift-system", .upToNextMajor(from: "1.0.0")),
        .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
    ],
    targets: [
        .target(
            name: "Storage",
            dependencies: [
                .product(name: "CLMDB", package: "swift-lmdb"),
                .product(name: "Logging", package: "swift-log"),
                .product(name: "SystemPackage", package: "swift-system"),
            ]
        ),
        .executableTarget(
            name: "StorageExecutable",
            dependencies: [
                .product(name: "ArgumentParser", package: "swift-argument-parser"),
                .product(name: "Logging", package: "swift-log"),
                .product(name: "SystemPackage", package: "swift-system"),
                "Storage",
            ]
        ),
        .testTarget(
            name: "StorageTests",
            dependencies: ["Storage",
                           .product(name: "Logging", package: "swift-log")]
        ),
    ]
)

Expected behavior

Only get a single copy of each source file checked out which should change properly when e.g. switching branches.

Actual behavior

I sometimes get double-checked or triple-checked out files as outlined in the description, doing rm -rf .build and rebuilding fixes the issue, but it is tedious for larger projects.

Steps to reproduce

Unfortunately not reproducible at will yet, will update if I figure out what triggers the issue.

Swift Package Manager version/commit hash

Swift 5.6.1

Swift & OS version (output of swift --version && uname -a)

Darwin max.local 21.5.0 Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:37 PDT 2022; root:xnu-8020.121.3~4/RELEASE_ARM64_T6000 arm64

swift-driver version: 1.45.2 Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)
Target: arm64-apple-macosx12.0
@abertelrud
Copy link
Contributor

The plugin machinery takes the source files in the Plugins subdirectory as inputs, but never writes there. So I suspect that there's some issue here with the checkout. The point about TSAN is interesting — I don't know if that could write any files to the source directory, but I'd be surprised if it did. Have you only seen this with TSAN?

The " 2" suffix thing looks like the kind of thing you'd get if you duplicated a file in Finder, which is also suspicious. The error itself makes perfect sense if there are three copies of the source files inside that directory, so the question is how they got there.

If there are any steps to reproduce this reliably, please do add them (as you noted you will). This is baffling.

@hassila
Copy link
Author

hassila commented Jun 16, 2022

Hej @abertelrud - very long time, nice to see you here! (I've changed surname, but Research & Trade + GradientKit should jog your memory if needed ;-)

I can't say its only with TSAN, it was just what I worked with the last few weeks so unclear if that is the root cause - my best guess is that its related to branch switching, but as mentioned I'll definitely try to nail down root use pattern that triggers and will update the case.

You are absolutely right about the suffix, sometimes it also gets a " 3" etc, the compilation issues I get is simply due to the same files being there in multiple copies - it looks basically as someone went into the Finder and did 'duplicate' on all files (which I definitely did not...).

@abertelrud
Copy link
Contributor

abertelrud commented Jun 27, 2022

Hej Jocke! Long time indeed! Great to hear from you! Yes, I remember well, though I would not have guessed immediately that it was you, because of the different surname. Yes GradientKit was forever ago. Maybe it's time to make a second version of that, now as a package! :)

This is a really odd one — as far as I know there is nothing in SwiftPM that would add that suffix as tiebreaker. I suppose it's possible Foundation does that in some way on Darwin, but it's still odd (and we shell out to git to do the checkout, so Foundation shouldn't be involved). You're sure that there isn't any macOS tool (such as Hazel) or Finder Actions at work here? It's a long-shot and I'm sure you would have remembered, but I've seen stranger things.

I still have not been able to reproduce this, but I also suspect that it's actually orthogonal to plugins. If you find any hints of what might cause it, that would be very interesting indeed.

@hassila
Copy link
Author

hassila commented Jun 27, 2022

No other macOS tools in play really - got a fairly clean new setup with minimal cruft. Haven’t been reproducing it lately but haven’t used tsan either so that’s my current best guess - I’ll update with details when I get it reproduced again for sure when nailing it down - it happened quite often a few weeks ago so seems likely it’s something that will be possible to reproduce eventually. Stay tuned.

@hassila
Copy link
Author

hassila commented Aug 9, 2022

Ok, after having this reproducible often before I can now classify it as a Heisenbug, will close this now and reopen if I manage to reproduce again. Perhaps related to asan/tsan as I was using them a lot when reproducing it, but haven't worked with them lately, but will revert with more precise information if I encounter it again. Thanks.

@hassila hassila closed this as completed Aug 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants