nicklockwood / SwiftFormat

A command-line tool and Xcode Extension for formatting Swift code
MIT License
7.87k stars 637 forks source link

error: Failed to write file <File Location> #1549

Open NoamEfergan opened 12 months ago

NoamEfergan commented 12 months ago

I'm trying to run SwiftFormat whenever my SPM package builds (when it's not embedded in an app. when it is, it's just a build phase) To do so i've got the following:

// MARK: - CodeFormatPlugin
enum CodeFormatPlugin {
  static let name = "CodeFormatPlugin"

  static var plugin: Product {
    .plugin(name: name, targets: [name])
  }

  static var pluginTarget: Target {
    .plugin(name: name,
            capability: .buildTool(),
            dependencies: ["klswiftformat"])
  }

  static var swiftformatBinaryTarget: Target {
    .binaryTarget(name: "klswiftformat",
                  url: "https://github.com/nicklockwood/SwiftFormat/releases/download/0.52.2/swiftformat.artifactbundle.zip",
                  checksum: "af5f0d8854bc88ffd1120cb65782c24f6794c3fdbb01fdc68cd0115473c3cfa0")
  }
}

and in my Package.swift file:

...
 products: [
                        CodeFormatPlugin.plugin,
...
                      targets: [
                        CodeFormatPlugin.swiftformatBinaryTarget,
                        CodeFormatPlugin.pluginTarget,

The actual file looks like this:

import Foundation
import PackagePlugin

// MARK: - CodeFormatPlugin
@main
struct CodeFormatPlugin {}

// MARK: BuildToolPlugin
extension CodeFormatPlugin: BuildToolPlugin {
  func createBuildCommands(context: PackagePlugin.PluginContext,
                           target: PackagePlugin.Target) async throws -> [PackagePlugin.Command] {
    // We don't want this to run on the CI, since it creates errors.
    guard ProcessInfo.processInfo.environment["CIRCLECI"] == nil else {
      return []
    }
    guard let _ = target as? SourceModuleTarget else {
      return []
    }
    let tool = try context.tool(named: "swiftformat")
    let output = context.pluginWorkDirectory
    let packageDir = context.package.directory.string
    return [
      .prebuildCommand(displayName: "CodeFormatPlugin: Run swiftformat at: \(packageDir)",
                       executable: tool.path,
                       arguments: [
                         packageDir
                       ],
                       outputFilesDirectory: output)
    ]
  }
}

Any idea what i might be doing wrong?

nicklockwood commented 12 months ago

Have you disabled script sandboxing?

NOTE (2): If you are using Xcode 15 or later, make sure that the ENABLE_USER_SCRIPT_SANDBOXING (aka "User Script Sandboxing") option is set to NO, otherwise SwiftFormat won't be able to run correctly.

NoamEfergan commented 12 months ago

i have on the main app, but on the package i can't (or at least don't know where?)

nicklockwood commented 12 months ago

Yeah, I'm not sure either I'm afraid. It's not a use-case I've tried myself.

NoamEfergan commented 12 months ago

if i find a fix i'll post it here, maybe even (if i'm lucky!) i'll contribute!

NoamEfergan commented 11 months ago

Just to confirm, to fix was found on my side, and there seems to be no way to have the tool run on a package from the package

giginet commented 10 months ago

I hit the same situation.

@NoamKitman Do you mean it's impossible to write files from Command/Build Plugins?

giginet commented 10 months ago

How about using --allow-writing-to-directory . instead of --allow-writing-to-package-directory?

I tried passing this option, it seems to work fine. Please try this.

NoamEfergan commented 10 months ago

@giginet passing that where ? the only one i can see is writeToPackageDirectory. or do you pass it in as pre build thing from Xcode iteself?

image
giginet commented 10 months ago

You can pass the option with CLI arguments.

$ swift package plugin --allow-writing-to-directory . your_plugin

See swift package plugin --help for details.

giginet commented 10 months ago

I tried this as a command plugin. But your question is for Build Tools plugins. So it may not help you.

NoamEfergan commented 10 months ago

hmm yeah my issue is that i wanted it to run on the project every time i build. thanks for the attempt to help thought!