Skip to content

Commit

Permalink
Merge pull request #1093 from pol-piella/master
Browse files Browse the repository at this point in the history
📦 Adds support for Swift Package plugin command
  • Loading branch information
polpielladev authored Sep 14, 2022
2 parents 13eccd4 + a6846cc commit 9846370
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 1.8.3
- Update StencilSwiftKit to fix SPM resolving issue when building as a Command Plugin [#1023](https://github.com/krzysztofzablocki/Sourcery/issues/1023)
- Adds new `--cacheBasePath` option to `SourceryExecutable` to allow for plugins setting a default cache [#1093](https://github.com/krzysztofzablocki/Sourcery/pull/1093)

## 1.8.2
## New Features
Expand Down
27 changes: 20 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.5
// swift-tools-version:5.6

import PackageDescription
import Foundation
Expand All @@ -17,16 +17,16 @@ let package = Package(
.library(name: "SourceryJS", targets: ["SourceryJS"]),
.library(name: "SourcerySwift", targets: ["SourcerySwift"]),
.library(name: "SourceryFramework", targets: ["SourceryFramework"]),
.plugin(name: "SourceryCommandPlugin", targets: ["SourceryCommandPlugin"])
],
dependencies: [
.package(url: "https://github.com/jpsim/Yams.git", from: "4.0.6"),
.package(url: "https://github.com/kylef/Commander.git", .exact("0.9.1")),
.package(url: "https://github.com/kylef/Commander.git", exact: "0.9.1"),
// PathKit needs to be exact to avoid a SwiftPM bug where dependency resolution takes a very long time.
.package(url: "https://github.com/kylef/PathKit.git", .exact("1.0.1")),
.package(url: "https://github.com/StencilProject/Stencil.git", .upToNextMajor(from: "0.14.0")),
.package(url: "https://github.com/SwiftGen/StencilSwiftKit.git", .exact("2.10.1")),
.package(url: "https://github.com/tuist/XcodeProj.git", .exact("8.3.1")),
.package(url: "https://github.com/apple/swift-syntax.git", .exact("0.50600.1")),
.package(url: "https://github.com/kylef/PathKit.git", exact: "1.0.1"),
.package(url: "https://github.com/SwiftGen/StencilSwiftKit.git", exact: "2.10.1"),
.package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.3.1"),
.package(url: "https://github.com/apple/swift-syntax.git", exact: "0.50600.1"),
.package(url: "https://github.com/Quick/Quick.git", from: "3.0.0"),
.package(url: "https://github.com/Quick/Nimble.git", from: "9.0.0")
],
Expand Down Expand Up @@ -231,6 +231,19 @@ let package = Package(
name: "lib_InternalSwiftSyntaxParser",
url: "https://github.com/keith/StaticInternalSwiftSyntaxParser/releases/download/5.6/lib_InternalSwiftSyntaxParser.xcframework.zip",
checksum: "88d748f76ec45880a8250438bd68e5d6ba716c8042f520998a438db87083ae9d"
),
.plugin(
name: "SourceryCommandPlugin",
capability: .command(
intent: .custom(
verb: "sourcery-command",
description: "Sourcery command plugin for code generation"
),
permissions: [
.writeToPackageDirectory(reason: "Need permission to write generated files to package directory")
]
),
dependencies: ["SourceryExecutable"]
)
]
)
74 changes: 74 additions & 0 deletions Plugins/SourceryCommandPlugin/SourceryCommandPlugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import PackagePlugin
import Foundation

@main
struct SourceryCommandPlugin {
private func run(_ sourcery: String, withConfig configFilePath: String, cacheBasePath: String) throws {
let sourceryURL = URL(fileURLWithPath: sourcery)

let process = Process()
process.executableURL = sourceryURL
process.arguments = [
"--config",
configFilePath,
"--cacheBasePath",
cacheBasePath
]

try process.run()
process.waitUntilExit()

let gracefulExit = process.terminationReason == .exit && process.terminationStatus == 0
if !gracefulExit {
throw "🛑 The plugin execution failed with reason: \(process.terminationReason.rawValue) and status: \(process.terminationStatus) "
}
}
}

// MARK: - CommandPlugin

extension SourceryCommandPlugin: CommandPlugin {
func performCommand(context: PluginContext, arguments: [String]) async throws {
// Run one per target
for target in context.package.targets {
let configFilePath = target.directory.appending(subpath: ".sourcery.yml").string
let sourcery = try context.tool(named: "SourceryExecutable").path.string

guard FileManager.default.fileExists(atPath: configFilePath) else {
Diagnostics.warning("⚠️ Could not find `.sourcery.yml` for the given target")
return
}

try run(sourcery, withConfig: configFilePath, cacheBasePath: context.pluginWorkDirectory.string)
}
}
}

// MARK: - XcodeProjectPlugin

#if canImport(XcodeProjectPlugin)
import XcodeProjectPlugin

extension SourceryCommandPlugin: XcodeCommandPlugin {
func performCommand(context: XcodePluginContext, arguments: [String]) throws {
for target in context.xcodeProject.targets {
guard let configFilePath = target
.inputFiles
.filter({ $0.path.lastComponent == ".sourcery.yml" })
.first?
.path
.string else {
Diagnostics.warning("⚠️ Could not find `.sourcery.yml` in Xcode's input file list")
return
}
let sourcery = try context.tool(named: "SourceryExecutable").path.string

try run(sourcery, withConfig: configFilePath, cacheBasePath: context.pluginWorkDirectory.string)
}
}
}
#endif

extension String: LocalizedError {
public var errorDescription: String? { return self }
}
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,21 @@ You can also watch this quick getting started and intro to mocking video by Insi

Run `xcodebuild -scheme sourcery -destination generic/platform=macOS -archivePath sourcery.xcarchive archive` and export the binary from the archive.

- _SPM (for plugin use only)_
Add the package dependency to your `Package.swift` manifest from version `1.8.3`.

```
.package(url: "https://github.com/krzysztofzablocki/Sourcery.git", from: "1.8.3")
```

## Documentation

Full documentation for the latest release is available [here](http://merowing.info/Sourcery/).

## Usage

### Running the executable

Sourcery is a command line tool; you can either run it manually or in a custom build phase using the following command:

```
Expand All @@ -134,6 +143,32 @@ $ ./bin/sourcery --sources <sources path> --templates <templates path> --output

> Note: this command differs depending on how you installed Sourcery (see [Installing](#installing))
### Swift Package command

Sourcery can now be used as a Swift package command plugin. In order to do this, the package must be added as a dependency to your Swift package or Xcode project (see [Installing](#installing) above).

To provide a configuration for the plugin to use, place a `.sourcery.yml` file at the root of the target's directory (in the sources folder rather than the root of the package).

#### Running from the command line

To verify the plugin can be found by SwiftPM, use:

```
$ swift package plugin --list
```

To run the code generator, you need to allow changes to the project with the `--allow-writing-to-package-directory` flag:

```
$ swift package --allow-writing-to-package-directory sourcery-command
```

#### Running in Xcode

Inside a project/package that uses this command plugin, right-click the project and select "SourceryCommand" from the "SourceryPlugins" menu group.

> ⚠️ Note that this is only available from Xcode 14 onwards.
### Command line options

- `--sources` - Path to a source swift files or directories. You can provide multiple paths using multiple `--sources` option.
Expand All @@ -149,6 +184,7 @@ $ ./bin/sourcery --sources <sources path> --templates <templates path> --output
- `--prune` [default: false] - Prune empty generated files
- `--version` - Display the current version of Sourcery
- `--help` - Display help information
- `--cacheBasePath` - Base path to the cache directory. Can be overriden by the config file.

### Configuration file

Expand Down
11 changes: 7 additions & 4 deletions SourceryExecutable/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ func runCLI() {
or should be passed one by one (e.g. --args arg1=value --args arg2). Arguments are accessible in templates \
via `argument.<name>`. To pass in string you should use escaped quotes (\\").
"""),
Option<Path>("ejsPath", default: "", description: "Path to EJS file for JavaScript templates.")
) { watcherEnabled, disableCache, verboseLogging, logAST, logBenchmark, parseDocumentation, quiet, prune, serialParse, sources, excludeSources, templates, excludeTemplates, output, configPaths, forceParse, args, ejsPath in
Option<Path>("ejsPath", default: "", description: "Path to EJS file for JavaScript templates."),
Option<Path>("cacheBasePath", default: "", description: "Base path to Sourcery's cache directory")
) { watcherEnabled, disableCache, verboseLogging, logAST, logBenchmark, parseDocumentation, quiet, prune, serialParse, sources, excludeSources, templates, excludeTemplates, output, configPaths, forceParse, args, ejsPath, cacheBasePath in
do {
switch (quiet, verboseLogging) {
case (true, _):
Expand Down Expand Up @@ -140,7 +141,7 @@ func runCLI() {
sources: Paths(include: sources, exclude: excludeSources) ,
templates: Paths(include: templates, exclude: excludeTemplates),
output: output.string.isEmpty ? "." : output,
cacheBasePath: Path.defaultBaseCachePath,
cacheBasePath: cacheBasePath.string.isEmpty ? Path.defaultBaseCachePath : cacheBasePath,
forceParse: forceParse,
parseDocumentation: parseDocumentation,
args: arguments
Expand Down Expand Up @@ -187,11 +188,13 @@ func runCLI() {

let keepAlive = try configurations.flatMap { configuration -> [FolderWatcher.Local] in
configuration.validate()

let shouldUseCacheBasePathArg = configuration.cacheBasePath == Path.defaultBaseCachePath && !cacheBasePath.string.isEmpty

let sourcery = Sourcery(verbose: verboseLogging,
watcherEnabled: watcherEnabled,
cacheDisabled: disableCache,
cacheBasePath: configuration.cacheBasePath,
cacheBasePath: shouldUseCacheBasePathArg ? cacheBasePath : configuration.cacheBasePath,
prune: prune,
serialParse: serialParse,
arguments: configuration.args)
Expand Down

0 comments on commit 9846370

Please sign in to comment.