Skip to content

Commit f1f8520

Browse files
committed
implemented runscript plugin
1 parent 4489813 commit f1f8520

File tree

10 files changed

+311
-30
lines changed

10 files changed

+311
-30
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ DerivedData/
77
.swiftpm/config/registries.json
88
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
99
.netrc
10+
11+
run-script-bin.artifactbundle
12+
run-script-bin.artifactbundle.zip

Package.resolved

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
// swift-tools-version: 5.7
2-
// The swift-tools-version declares the minimum version of Swift required to build this package.
32

43
import PackageDescription
54

65
let package = Package(
76
name: "RunScriptPlugin",
87
products: [
9-
// Products define the executables and libraries a package produces, and make them visible to other packages.
10-
.library(
8+
.plugin(
119
name: "RunScriptPlugin",
12-
targets: ["RunScriptPlugin"]),
10+
targets: ["RunScriptPlugin"]
11+
),
12+
.executable(
13+
name: "run-script",
14+
targets: ["run-script"]
15+
)
1316
],
1417
dependencies: [
15-
// Dependencies declare other packages that this package depends on.
16-
// .package(url: /* package url */, from: "1.0.0"),
18+
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1")
1719
],
1820
targets: [
19-
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
20-
// Targets can depend on other targets in this package, and on products in packages this package depends on.
21-
.target(
21+
.executableTarget(
22+
name: "run-script",
23+
dependencies: [
24+
.product(name: "Yams", package: "Yams")
25+
]
26+
),
27+
.binaryTarget(name: "run-script-bin", path: "./run-script-bin.artifactbundle.zip"),
28+
.plugin(
2229
name: "RunScriptPlugin",
23-
dependencies: []),
24-
.testTarget(
25-
name: "RunScriptPluginTests",
26-
dependencies: ["RunScriptPlugin"]),
30+
capability: .buildTool(),
31+
dependencies: [
32+
"run-script-bin"
33+
]
34+
)
2735
]
2836
)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//
2+
// plugin.swift
3+
//
4+
//
5+
// Created by p-x9 on 2023/02/04.
6+
//
7+
//
8+
9+
import Foundation
10+
import PackagePlugin
11+
12+
@main
13+
struct RunScriptPlugin: BuildToolPlugin {
14+
func createBuildCommands(context: PackagePlugin.PluginContext, target: PackagePlugin.Target) async throws -> [PackagePlugin.Command] {
15+
createBuildCommands(
16+
packageDirectory: context.package.directory,
17+
workingDirectory: context.pluginWorkDirectory,
18+
tool: try context.tool(named: "run-script-bin")
19+
)
20+
}
21+
22+
private func createBuildCommands(
23+
packageDirectory: Path,
24+
workingDirectory: Path,
25+
tool: PluginContext.Tool
26+
) -> [Command] {
27+
guard let configuration = packageDirectory.firstConfigurationFileInParentDirectories() else {
28+
return []
29+
}
30+
31+
let arguments = [configuration.string]
32+
33+
return [
34+
.prebuildCommand(
35+
displayName: "RunScriptPlugin(PreBuild)",
36+
executable: tool.path,
37+
arguments: arguments + ["1"],
38+
outputFilesDirectory: workingDirectory
39+
),
40+
.buildCommand(
41+
displayName: "RunScriptPlugin(Build)",
42+
executable: tool.path,
43+
arguments: arguments + ["0"]
44+
)
45+
]
46+
}
47+
}
48+
49+
#if canImport(XcodeProjectPlugin)
50+
import XcodeProjectPlugin
51+
52+
extension RunScriptPlugin: XcodeBuildToolPlugin {
53+
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
54+
return createBuildCommands(
55+
packageDirectory: context.xcodeProject.directory,
56+
workingDirectory: context.pluginWorkDirectory,
57+
tool: try context.tool(named: "run-script-bin")
58+
)
59+
}
60+
}
61+
#endif
62+
63+
// ref: https://github.com/realm/SwiftLint/blob/main/Plugins/SwiftLintPlugin/Path%2BHelpers.swift
64+
extension Path {
65+
func firstConfigurationFileInParentDirectories() -> Path? {
66+
let defaultConfigurationFileName = ".runscript.yml"
67+
let proposedDirectory = sequence(
68+
first: self,
69+
next: { path in
70+
guard path.stem.count > 1 else {
71+
// Check we're not at the root of this filesystem, as `removingLastComponent()`
72+
// will continually return the root from itself.
73+
return nil
74+
}
75+
76+
return path.removingLastComponent()
77+
}
78+
).first { path in
79+
let potentialConfigurationFile = path.appending(subpath: defaultConfigurationFileName)
80+
return potentialConfigurationFile.isAccessible()
81+
}
82+
return proposedDirectory?.appending(subpath: defaultConfigurationFileName)
83+
}
84+
85+
/// Safe way to check if the file is accessible from within the current process sandbox.
86+
private func isAccessible() -> Bool {
87+
let result = string.withCString { pointer in
88+
access(pointer, R_OK)
89+
}
90+
91+
return result == 0
92+
}
93+
}
94+

Sources/RunScriptPlugin/RunScriptPlugin.swift

Lines changed: 0 additions & 6 deletions
This file was deleted.

Sources/run-script/Config.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// Config.swift
3+
//
4+
//
5+
// Created by p-x9 on 2023/02/04.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
struct Config: Codable {
12+
let prebuild: [Script]?
13+
let build: [Script]?
14+
}
15+
16+
struct Script: Codable {
17+
let name: String?
18+
19+
let launchPath: String?
20+
21+
let path: String?
22+
let script: String?
23+
}

Sources/run-script/main.swift

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// main.swift
3+
//
4+
//
5+
// Created by p-x9 on 2023/02/04.
6+
//
7+
//
8+
9+
import Foundation
10+
import Yams
11+
12+
#if os(macOS)
13+
enum CommandError: LocalizedError {
14+
case invalidArguments
15+
}
16+
17+
func run() throws {
18+
let arguments = ProcessInfo().arguments
19+
20+
guard arguments.count == 3 else {
21+
throw CommandError.invalidArguments
22+
}
23+
24+
let configFilePath = arguments[1]
25+
let configFileURL = URL(fileURLWithPath: configFilePath)
26+
27+
let isPrebuild: Bool = arguments[2] == "1"
28+
29+
let fileManager = FileManager.default
30+
let decoder = YAMLDecoder()
31+
32+
guard fileManager.fileExists(atPath: configFilePath) else {
33+
return
34+
}
35+
36+
let data = try Data(contentsOf: configFileURL)
37+
let config = try decoder.decode(Config.self, from: data)
38+
39+
let directory = configFileURL.deletingLastPathComponent().path
40+
FileManager.default.changeCurrentDirectoryPath(directory)
41+
42+
let scripts = isPrebuild ? config.prebuild : config.build
43+
try scripts?.forEach {
44+
try run($0)
45+
}
46+
}
47+
48+
func run(_ script: Script) throws {
49+
let process = Process()
50+
51+
process.launchPath = "/bin/sh"
52+
53+
if let path = script.path {
54+
process.arguments = [path]
55+
} else if let script = script.script {
56+
process.arguments = ["-c", script]
57+
}
58+
59+
process.launch()
60+
process.waitUntilExit()
61+
}
62+
63+
do {
64+
try run()
65+
exit(0)
66+
} catch {
67+
exit(1)
68+
}
69+
#endif

Tests/RunScriptPluginTests/RunScriptPluginTests.swift

Lines changed: 0 additions & 11 deletions
This file was deleted.

scripts/create_artifactbundle.sh

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env bash
2+
3+
# example
4+
#
5+
# - version
6+
# scripts/create_artifactbundle.sh 1.0.0
7+
#
8+
# - version with artifactbundle name
9+
# scripts/create_artifactbundle.sh 1.0.0 run-script-bin
10+
11+
set -Ceu
12+
13+
VERSION_STRING=$1
14+
15+
PRODUCT_NAME="run-script"
16+
NAME=$PRODUCT_NAME
17+
18+
if (( $# > 1 )); then
19+
NAME=$2
20+
fi
21+
22+
ARTIFACT_BUNDLE_NAME="${NAME}.artifactbundle"
23+
ARTIFACT_BUNDLE_BIN_PATH="${ARTIFACT_BUNDLE_NAME}/${NAME}/bin"
24+
25+
INFO_TEMPLATE="./scripts/info.json.template"
26+
27+
show_checksum() {
28+
CHECKSUM=$(swift package compute-checksum ./${ARTIFACT_BUNDLE_NAME}.zip)
29+
echo "checksum:"
30+
echo ${CHECKSUM}
31+
}
32+
33+
create_artifact_bundle() {
34+
mkdir -p "${ARTIFACT_BUNDLE_BIN_PATH}"
35+
36+
sed "s/__VERSION__/${VERSION_STRING}/g; s/__NAME__/${NAME}/g" ${INFO_TEMPLATE} > "${ARTIFACT_BUNDLE_NAME}/info.json"
37+
38+
cp -f ".build/apple/Products/Release/${PRODUCT_NAME}" "${ARTIFACT_BUNDLE_BIN_PATH}"
39+
# cp -f LICENSE "${ARTIFACT_BUNDLE_NAME}"
40+
41+
mv "${ARTIFACT_BUNDLE_BIN_PATH}/${PRODUCT_NAME}" "${ARTIFACT_BUNDLE_BIN_PATH}/${NAME}"
42+
}
43+
44+
zip_artifact_bundle() {
45+
zip -yr - "${ARTIFACT_BUNDLE_NAME}" > "./${ARTIFACT_BUNDLE_NAME}.zip"
46+
}
47+
48+
build_target() {
49+
swift build -c release --product $PRODUCT_NAME --arch arm64 --arch x86_64
50+
}
51+
52+
clear_outputs() {
53+
rm -rf $ARTIFACT_BUNDLE_NAME
54+
rm -f "${ARTIFACT_BUNDLE_NAME}.zip"
55+
}
56+
57+
58+
clear_outputs
59+
60+
if [ "$1" = "--clear" ]; then
61+
exit
62+
fi
63+
64+
build_target
65+
create_artifact_bundle
66+
zip_artifact_bundle
67+
68+
show_checksum
69+

scripts/info.json.template

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"schemaVersion": "1.0",
3+
"artifacts": {
4+
"__NAME__": {
5+
"version": "__VERSION__",
6+
"type": "executable",
7+
"variants": [
8+
{
9+
"path": "__NAME__/bin/__NAME__",
10+
"supportedTriples": [
11+
"x86_64-apple-macosx",
12+
"arm64-apple-macosx"
13+
]
14+
}
15+
]
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)