mxcl / swift-sh

Easily script with third-party Swift dependencies.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Some package import do not work with Swift 5.2

Frizlab opened this issue · comments

This is new in Swift 5.2, I think the Package.swift needs to be generated differently.

With this script,

#!/usr/bin/swift sh
import Crypto // apple/swift-crypto ~> 1.0.1

we get the following error

error: manifest parse error: unknown package 'Crypto' in dependencies of target 'my_awesome_script'; if the package is named differently from the product, either use '.product(name: "Crypto", package: <package-name>)' to specify the package name or give the package the 'Crypto' name using '.package(name: "Crypto", ...)'

Can you provide the generated Package.swift, it'll be in ~/Library/Develop/swift-sh.cache.

Sure! There it is

// swift-tools-version:5.2
import PackageDescription

let pkg = Package(name: "hash_htpasswd_user_pass")

pkg.products = [
    .executable(name: "hash_htpasswd_user_pass", targets: ["hash_htpasswd_user_pass"])
]
pkg.dependencies = [
    .package(url: "https://github.com/apple/swift-crypto.git", .upToNextMajor(from: "1.0.1")),
    .package(url: "https://github.com/kareman/SwiftShell.git", .upToNextMajor(from: "5.0.1"))
]
pkg.targets = [
    .target(name: "hash_htpasswd_user_pass", dependencies: ["Crypto", "SwiftShell"], path: ".", sources: ["main.swift"])
]

#if swift(>=5) && os(macOS)
pkg.platforms = [
   .macOS(.v10_15)
]
#endif

I've manually changed the swift-tools-version back to 5.1 for now. That appears to fix things.

I too have a script failing since upgrading Xcode to 11.4.x, it does import ArgumentParser // apple/swift-argument-parser. I dove a little deeper into SPM to see what was up.

My script fails like (linefeeds added to error message for clarity):

Fetching https://github.com/apple/swift-argument-parser.git
Cloning https://github.com/apple/swift-argument-parser.git
Resolving https://github.com/apple/swift-argument-parser.git at 0.0.5
'rename' /Users/myself/Library/Developer/swift-sh.cache/e44e2e32219f152e07016f3bdb92d57f:
    error: dependency 'ArgumentParser' in target 'rename' requires explicit declaration;
    reference the package in the target dependency with
    '.product(name: "ArgumentParser", package: "swift-argument-parser")'

The generated Package.swift:

// swift-tools-version:5.2
import PackageDescription

let pkg = Package(name: "rename")

pkg.products = [
	.executable(name: "rename", targets: ["rename"])
]
pkg.dependencies = [
	.package(url: "https://github.com/apple/swift-argument-parser.git", Version(0,0,0)...Version(1_000_000,0,0)),
]
pkg.targets = [
	.target(name: "rename", dependencies: ["ArgumentParser"], path: ".", sources: ["main.swift"])
]

#if swift(>=5) && os(macOS)
pkg.platforms = [
   .macOS(.v10_15)
]
#endif

I tried changing Package.swift manually and running again (which I'm happy was possible), changing the .package call to what the error message described, but this didn't work.

/Users/myself/Library/Developer/swift-sh.cache/e44e2e32219f152e07016f3bdb92d57f: error: manifest parse error(s):
/Users/myself/Library/Developer/swift-sh.cache/e44e2e32219f152e07016f3bdb92d57f/Package.swift:11:6: error: type 'Array<Package.Dependency>.ArrayLiteralElement' (aka 'Package.Dependency') has no member 'product'
	.product(name: "ArgumentParser", url: "https://github.com/apple/swift-argument-parser.git", Version(0,0,0)...Version(1_000_000,0,0)),
	~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: 1 <(/usr/bin/swift build -Xswiftc -suppress-warnings)

I found SR-12075 which seems to be all about the change to the error message, which mentions ”SwiftPM should tell me that I need to specify name: "SwiftSyntax" in the declaration of the dependency”, however looking at the Package.Dependency documentation and exported swift interface, I cannot find a variants of static func product(...) with a name parameter.

In fact, in the swift interface all those static functions are preceded by @available(_PackageDescription, obsoleted: 5.2), which looks fishy:

@available(_PackageDescription, obsoleted: 5.2)
public static func package(url: String, from version: PackageDescription.Version) -> PackageDescription.Package.Dependency

@available(_PackageDescription, obsoleted: 5.2)
public static func package(url: String, _ requirement: PackageDescription.Package.Dependency.Requirement) -> PackageDescription.Package.Dependency

@available(_PackageDescription, obsoleted: 5.2)
public static func package(url: String, _ range: Range<PackageDescription.Version>) -> PackageDescription.Package.Dependency

@available(_PackageDescription, obsoleted: 5.2)
public static func package(url: String, _ range: ClosedRange<PackageDescription.Version>) -> PackageDescription.Package.Dependency

@available(_PackageDescription, obsoleted: 5.2)
public static func package(path: String) -> PackageDescription.Package.Dependency

Is .package(..) now canonically defined elsewhere for 5.2 with different signatures adding a name: parameter, the above static functions remaining as-is for backwards compatibility? I cannot find such new declarations. Or is this just broken in Swift 5.2 Package Manager, with the new error message thanks to SR-12075 merely aspirational?

AFAICT, you changed the wrong thing. You should change dependencies: ["ArgumentParser"] (in the .target of the pkg.targets assignment) to dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")] and it should work.

D'oh! Indeed that works, thanks.

I'm having the same issue with SwiftProtobuf.

#!/usr/bin/swift sh

import Foundation
import SwiftProtobuf // apple/swift-protobuf ~> 1.8.0

Getting error

error: dependency 'SwiftProtobuf' in target 'main' requires explicit declaration; provide the name of the package dependency with '.package(name: "SwiftProtobuf", url: "https://github.com/apple/swift-protobuf.git", from: "1.8.0")'

There's no option to add such .package to dependencies.

It is interesting that if I do swift sh eject and then swift build in the newly created folder, it works. Same Package.swift that swift-sh generated in ~/Library/Developer/swift-sh-cache

There's a difference actually, swift sh eject used // swift-tools-version:4.2

Fixed with 1.18.0

This still is broken in some cases. For example when using

import Path // mxcl/Path.swift ~> 1.0.1

The error is:

error: unknown package 'Path' in dependencies of target 'makeModule'

The package name should be "Path.swift" instead of "Path" in the generated Package.swift

// swift-tools-version:5.2
import PackageDescription

let pkg = Package(name: "makeModule")

pkg.products = [
    .executable(name: "makeModule", targets: ["makeModule"])
]
pkg.dependencies = [
    .package(url: "https://github.com/kylef/Commander.git", .upToNextMajor(from: "0.9.1")),
    .package(url: "https://github.com/wlisac/Environment.git", .upToNextMajor(from: "0.11.1")),
    .package(url: "https://github.com/mxcl/Path.swift.git", .upToNextMajor(from: "1.0.1")),
    .package(url: "https://github.com/JohnSundell/ShellOut.git", .upToNextMajor(from: "2.0.0"))
]
pkg.targets = [
    .target(name: "makeModule", dependencies: [.product(name: "Commander", package: "Commander"), .product(name: "Environment", package: "Environment"), .product(name: "Path", package: "Path"), .product(name: "ShellOut", package: "ShellOut")], path: ".", sources: ["main.swift"])
]

#if swift(>=5) && os(macOS)
pkg.platforms = [
   .macOS(.v10_15)
]
#endif

Thanks for the report, would you mind creating a ticket?