编写 Swift 脚本是简单的
$ cat <<EOF > script
#!/usr/bin/swift
print("Hi!")
EOF
$ chmod u+x script
$ ./script
Hi!
遗憾的是,要使用第三方依赖,我们必须将脚本迁移到 Swift 包并使用 swift build
,当我们只想快速编写一个脚本时,这是一个相对繁重的解决方案。swift-sh
为我们提供了两全其美的方案
$ cat <<EOF > script
#!/usr/bin/swift sh
import PromiseKit // @mxcl ~> 6.5
print(Promise.value("Hi!"))
EOF
$ chmod u+x script
$ ./script
Promise("Hi!")
如果还不清楚,swift-sh
会读取 import
后面的注释,并使用此信息来获取您的依赖项。
让我们看一个例子:如果您有一个名为 foo.swift
的单个文件,并且您想导入 mxcl/PromiseKit
#!/usr/bin/swift sh
import Foundation
import PromiseKit // @mxcl ~> 6.5
firstly {
after(.seconds(2))
}.then {
after(.milliseconds(500))
}.done {
print("notice: two and a half seconds elapsed")
exit(0)
}
RunLoop.main.run()
您可以使用以下命令运行它
$ swift sh foo.swift
或者为了使其更具“脚本”特性,首先使其可执行
$ chmod u+x foo.swift
$ mv foo.swift foo # optional step!
然后直接运行它
$ ./foo
如果您的公司依赖 swift-sh
,请考虑赞助该项目。否则我很难证明维护它的合理性。
brew install swift-sh
或者您可以使用 swift build
手动构建。
安装结果是一个名为 swift-sh
的单个可执行文件,当您键入 swift sh
时,swift
可执行文件将调用它(前提是它在您的 PATH
中)。
我们积极支持 Linux 和 Mac,并将尽快支持 Windows。
在脚本的第一行添加 shebang:#!/usr/bin/swift sh
。
您的依赖项通过您的 import
行确定
#!/usr/bin/swift sh
import AppUpdater // @mxcl
// ^^ https://github.com/mxcl/AppUpdater, latest version
import PromiseKit // @mxcl ~> 6.5
// ^^ mxcl/PromiseKit, version 6.5.0 or higher up to but not including 7.0.0 or higher
import Chalk // @mxcl == 0.3.1
// ^^ mxcl/Chalk, only version 0.3.1
import LegibleError // @mxcl == b4de8c12
// ^^ mxcl/LegibleError, the precise commit `b4de8c12`
import Path // mxcl/Path.swift ~> 0.16
// ^^ for when the module-name and repo-name are not identical
import BumbleButt // https://example.com/bb.git ~> 9
// ^^ non-GitHub URLs are fine
import CommonTaDa // git@github.com:mxcl/tada.git ~> 1
// ^^ ssh URLs are fine
import TaDa // ssh://git@github.com:mxcl/tada.git ~> 1
// ^^ this style of ssh URL is also fine
import Foo // ./my/project
import Bar // ../my/other/project
import Baz // ~/my/other/other/project
import Fuz // /I/have/many/projects
// ^^ local dependencies must expose library products in their `Package.swift`
// careful: `foo/bar` will be treated as a GitHub dependency; prefix with `./`
// local dependencies do *not* need to be versioned
import Floibles // @mxcl ~> 1.0.0-alpha.1
import Bloibles // @mxcl == 1.0.0-alpha.1
// ^^ alphas/betas will only be fetched if you specify them explicitly like so
// this is per Semantic Versioning guidelines
swift-sh
读取您的 imports 后面的注释并获取请求的 SwiftPM 依赖项。
对于传递依赖项,无需添加注释规范。
以下命令将生成一个 Xcode 项目(不在工作目录中,我们将其保存在缓存目录之外)并打开它,编辑内容将保存到您的脚本文件。
$ swift sh edit ./myScript
简单的脚本可以快速变成更大的项目,这些项目将受益于成为您使用 SwiftPM 构建的包。为了帮助您迁移项目,我们提供了 swift sh eject
,例如
$ swift sh eject foo.swift
在 ./Foo
中创建一个 Swift 包,从现在开始在 Foo
目录中使用 swift build
。您的脚本现在是 ./Foo/Sources/main.swift
。
如果您想让使用 CI 的人员可以使用脚本;请使用 stdin
brew install mxcl/made/swift-sh
swift sh <(curl http://example.com/yourscript) arg1 arg2
swift sh
在 swift-sh 缓存目录 † 下的目录中创建一个带有依赖项的 Swift Package.swift
包管理器项目,构建可执行文件,然后通过 swift run
执行它。仅当脚本文件比可执行文件更新时,才(重新)构建脚本。
† 使用(FreeDesktop)环境变量 XDG_CACHE_HOME 指定缓存父目录。如果未指定,在 macOS 上 swif-sh
使用 $HOME/Library/Developer/swift-sh.cache
,否则使用 $HOME/.cache/swift-sh
。
swfit-sh
v2 需要 Swift 5.1。我们不得不放弃对 Swift v4.2 的支持,因为维护起来太棘手了。
swift-sh
使用活动工具版本(即:xcode-select
)或 Linux 上 PATH
中的第一个 Swift。它为其将使用该工具版本进行 swift build
的包编写清单。因此,Xcode 11.0 使用 Swift 5.1 构建。依赖项使用它们声明支持的 Swift 版本构建,前提是活动工具链可以做到这一点(例如,Xcode 11.0 支持 Swift 4.2 及更高版本)
要在您的脚本本身中声明对特定 Swift 版本的支持,请使用 #if swift
或 #if compiler
指令。
错误:无法调用子命令:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-sh
如果您通过 Google 搜索来到这里,说明您有一个使用此工具的脚本,如果您现在安装 swift-sh
,您将能够运行您的脚本
brew install mxcl/made/swift-sh
或者查看上面的安装说明。