-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add implementation of tool to generate LibraryVersion
- Loading branch information
1 parent
7b401ff
commit 9b598bc
Showing
5 changed files
with
170 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"pins" : [ | ||
{ | ||
"identity" : "swift-syntax", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-syntax.git", | ||
"state" : { | ||
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", | ||
"version" : "509.1.1" | ||
} | ||
} | ||
], | ||
"version" : 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,24 @@ | ||
// swift-tools-version: 5.9 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "GitVersionPlugin", | ||
platforms: [ | ||
.macOS(.v13), | ||
], | ||
products: [ | ||
// Products can be used to vend plugins, making them visible to other packages. | ||
.plugin( | ||
name: "GitVersionPlugin", | ||
targets: ["GitVersionPlugin"]), | ||
.plugin(name: "GitVersionPlugin", targets: ["GitVersionPlugin"]), | ||
], | ||
dependencies: [ | ||
.package(url: "https://github.com/apple/swift-syntax.git", exact: "509.1.1"), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package, defining a module or a test suite. | ||
// Targets can depend on other targets in this package and products from dependencies. | ||
.plugin( | ||
name: "GitVersionPlugin", | ||
capability: .buildTool() | ||
), | ||
.plugin(name: "GitVersionPlugin", capability: .buildTool(), dependencies: [ | ||
.target(name: "GitStatus"), | ||
]), | ||
.executableTarget(name: "GitStatus", dependencies: [ | ||
.product(name: "SwiftSyntax", package: "swift-syntax"), | ||
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), | ||
]), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,10 @@ | ||
# GitVersionPlugin | ||
|
||
A SwiftPM plugin that codegens a version number, as read by Git, for use in tooling | ||
|
||
Split from [Apple's swift-testing repo](https://github.com/apple/swift-testing/blob/7f39433a0a78ccc92b541597c542b70f68de75e6/Sources/GitStatus/main.swift) and Xcode plugin added to the interface. | ||
|
||
The version is determined from: | ||
- If the repository is sitting at a tag with no uncommitted changes, use the tag. | ||
- Otherwise, use the commit hash (with a "there are changes" marker if needed.) | ||
- Finally, fall back to nil if nothing else is available. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// | ||
// This file was sourced from: | ||
// https://github.com/apple/swift-testing/blob/7f39433a0a78ccc92b541597c542b70f68de75e6/Sources/GitStatus/main.swift | ||
// | ||
// Copyright (c) 2023 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// See https://swift.org/LICENSE.txt for license information | ||
// | ||
|
||
import Foundation | ||
import SwiftSyntax | ||
import SwiftSyntaxBuilder | ||
|
||
// Resolve arguments to the tool. | ||
let repoPath = CommandLine.arguments[1] | ||
let generatedSourceURL = URL(fileURLWithPath: CommandLine.arguments[2], isDirectory: false) | ||
|
||
/// Run the `git` tool and process the output it writes to standard output. | ||
/// | ||
/// - Parameters: | ||
/// - arguments: The arguments to pass to `git`. | ||
/// - maxOutputCount: The maximum amount of output to read and return. | ||
/// | ||
/// - Returns: A string containing the `git` command's output, up to | ||
/// `maxOutputCount` UTF-8-encoded bytes, or `nil` if the command failed or | ||
/// the output could not be read. | ||
func _runGit(passing arguments: String..., readingUpToCount maxOutputCount: Int) -> String? { | ||
#if os(macOS) || os(Linux) || os(Windows) | ||
let path: String | ||
var arguments = ["-C", repoPath] + arguments | ||
#if os(Windows) | ||
path = "C:\\Program Files\\Git\\cmd\\git.exe" | ||
#else | ||
path = "/usr/bin/env" | ||
arguments = CollectionOfOne("git") + arguments | ||
#endif | ||
|
||
let process = Process() | ||
process.executableURL = URL(fileURLWithPath: path, isDirectory: false) | ||
process.arguments = arguments | ||
|
||
let stdoutPipe = Pipe() | ||
process.standardOutput = stdoutPipe | ||
process.standardError = nil | ||
do { | ||
try process.run() | ||
} catch { | ||
return nil | ||
} | ||
defer { | ||
process.terminate() | ||
} | ||
guard let output = try? stdoutPipe.fileHandleForReading.read(upToCount: maxOutputCount) else { | ||
return nil | ||
} | ||
return String(data: output, encoding: .utf8) | ||
#else | ||
return nil | ||
#endif | ||
} | ||
|
||
// The current Git tag, if available. | ||
let currentGitTag = _runGit(passing: "describe", "--exact-match", "--tags", readingUpToCount: 40)? | ||
.split(whereSeparator: \.isNewline) | ||
.first | ||
.map(String.init) | ||
|
||
// The current Git commit hash, if available. | ||
let currentGitCommitHash = _runGit(passing: "rev-parse", "HEAD", readingUpToCount: 40)? | ||
.split(whereSeparator: \.isNewline) | ||
.first | ||
.map(String.init) | ||
|
||
// Whether or not the Git repository has uncommitted changes, if available. | ||
let gitHasUncommittedChanges = _runGit(passing: "status", "-s", readingUpToCount: 1) | ||
.map { !$0.isEmpty } ?? false | ||
|
||
// Figure out what value to emit for the version: | ||
// - If the repository is sitting at a tag with no uncommitted changes, use the tag. | ||
// - Otherwise, use the commit hash (with a "there are changes" marker if needed.) | ||
// - Finally, fall back to nil if nothing else is available. | ||
let sourceCode: DeclSyntax = if !gitHasUncommittedChanges, let currentGitTag { | ||
""" | ||
var _toolVersion: String? { | ||
\(literal: currentGitTag) | ||
} | ||
""" | ||
} else if let currentGitCommitHash { | ||
if gitHasUncommittedChanges { | ||
""" | ||
var _toolVersion: String? { | ||
\(literal: currentGitCommitHash) + " (modified)" | ||
} | ||
""" | ||
} else { | ||
""" | ||
var _toolVersion: String? { | ||
\(literal: currentGitCommitHash) | ||
} | ||
""" | ||
} | ||
} else { | ||
""" | ||
var _toolVersion: String? { | ||
nil | ||
} | ||
""" | ||
} | ||
|
||
// Write the generated Swift file to the specified destination path. | ||
try String(describing: sourceCode).write(to: generatedSourceURL, atomically: false, encoding: .utf8) |