Skip to content

Commit a9e72ad

Browse files
authored
Add Snippet support with SwiftBuild (#9089)
Snippets are treated as executable targets with the native build system. This change updates the PIF Builder to support snippet, giving Snippet support with the Swift Build build system. Depends on: swiftlang/swift-build#775 Depends on: #9115 Fixes: #9040 issue: rdar://158630024 issue: rdar://147705448
1 parent ec2a626 commit a9e72ad

File tree

23 files changed

+1947
-571
lines changed

23 files changed

+1947
-571
lines changed

Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Package.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ let package = Package(
88
name: "PluginScriptProduct",
99
targets: [
1010
"PluginScriptTarget"
11-
]
11+
],
12+
),
13+
.library(
14+
name: "MyLib",
15+
targets: [
16+
"MyLib",
17+
],
1218
),
1319
],
1420
targets: [
@@ -17,9 +23,10 @@ let package = Package(
1723
capability: .command(
1824
intent: .custom(
1925
verb: "do-something",
20-
description: "Do something"
21-
)
22-
)
26+
description: "Do something",
27+
),
28+
),
2329
),
30+
.target(name: "MyLib"),
2431
]
2532
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
3+
4+
@main
5+
struct foo {
6+
static func main() {
7+
print("hello, snippets. File: \(#file)")
8+
}
9+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import MyLib
2+
3+
libraryCall()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print("hello, snippets. File: \(#file)")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print("hello, snippets! File: \(#file)")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public func libraryCall() {
2+
print("From library")
3+
print("hello, snippets. File: \(#file)")
4+
}

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ let package = Package(
534534
.target(
535535
name: "SwiftBuildSupport",
536536
dependencies: [
537+
"Build",
537538
"SPMBuildCore",
538539
"PackageGraph",
539540
],

Sources/Basics/FileSystem/InMemoryFileSystem.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,24 @@ public final class InMemoryFileSystem: FileSystem {
226226
}
227227

228228
/// Virtualized current working directory.
229+
private var _currentWorkingDirectory: TSCBasic.AbsolutePath = try! .init(validating: "/")
230+
229231
public var currentWorkingDirectory: TSCBasic.AbsolutePath? {
230-
return try? .init(validating: "/")
232+
return _currentWorkingDirectory
231233
}
232234

233235
public func changeCurrentWorkingDirectory(to path: TSCBasic.AbsolutePath) throws {
234-
throw FileSystemError(.unsupported, path)
236+
return try lock.withLock {
237+
// Verify the path exists and is a directory
238+
guard let node = try getNode(path) else {
239+
throw FileSystemError(.noEntry, path)
240+
}
241+
242+
guard case .directory = node.contents else {
243+
throw FileSystemError(.notDirectory, path)
244+
}
245+
_currentWorkingDirectory = path
246+
}
235247
}
236248

237249
public var homeDirectory: TSCBasic.AbsolutePath {

Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,34 @@ import struct TSCBasic.ByteString
3434
@available(*, deprecated, renamed: "SwiftModuleBuildDescription")
3535
public typealias SwiftTargetBuildDescription = SwiftModuleBuildDescription
3636

37+
// looking into the file content to see if it is using the @main annotation
38+
// this is not bullet-proof since theoretically the file can contain the @main string for other reasons
39+
// but it is the closest to accurate we can do at this point
40+
package func containsAtMain(fileSystem: FileSystem, path: AbsolutePath) throws -> Bool {
41+
let content: String = try fileSystem.readFileContents(path)
42+
let lines = content.split(whereSeparator: { $0.isNewline }).map { $0.trimmingCharacters(in: .whitespaces) }
43+
44+
var multilineComment = false
45+
for line in lines {
46+
if line.hasPrefix("//") {
47+
continue
48+
}
49+
if line.hasPrefix("/*") {
50+
multilineComment = true
51+
}
52+
if line.hasSuffix("*/") {
53+
multilineComment = false
54+
}
55+
if multilineComment {
56+
continue
57+
}
58+
if line.hasPrefix("@main") {
59+
return true
60+
}
61+
}
62+
return false
63+
}
64+
3765
/// Build description for a Swift module.
3866
public final class SwiftModuleBuildDescription {
3967
/// The package this target belongs to.
@@ -216,40 +244,12 @@ public final class SwiftModuleBuildDescription {
216244
return false
217245
}
218246
// looking into the file content to see if it is using the @main annotation which requires parse-as-library
219-
return (try? self.containsAtMain(fileSystem: self.fileSystem, path: self.sources[0])) ?? false
247+
return (try? containsAtMain(fileSystem: self.fileSystem, path: self.sources[0])) ?? false
220248
default:
221249
return false
222250
}
223251
}
224252

225-
// looking into the file content to see if it is using the @main annotation
226-
// this is not bullet-proof since theoretically the file can contain the @main string for other reasons
227-
// but it is the closest to accurate we can do at this point
228-
func containsAtMain(fileSystem: FileSystem, path: AbsolutePath) throws -> Bool {
229-
let content: String = try self.fileSystem.readFileContents(path)
230-
let lines = content.split(whereSeparator: { $0.isNewline }).map { $0.trimmingCharacters(in: .whitespaces) }
231-
232-
var multilineComment = false
233-
for line in lines {
234-
if line.hasPrefix("//") {
235-
continue
236-
}
237-
if line.hasPrefix("/*") {
238-
multilineComment = true
239-
}
240-
if line.hasSuffix("*/") {
241-
multilineComment = false
242-
}
243-
if multilineComment {
244-
continue
245-
}
246-
if line.hasPrefix("@main") {
247-
return true
248-
}
249-
}
250-
return false
251-
}
252-
253253
/// The filesystem to operate on.
254254
let fileSystem: FileSystem
255255

Sources/Commands/PackageCommands/CompletionCommand.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,18 @@ extension SwiftPackageCommand {
7979
case .listExecutables:
8080
let graph = try await swiftCommandState.loadPackageGraph()
8181
let package = graph.rootPackages[graph.rootPackages.startIndex].underlying
82-
let executables = package.products.filter { $0.type == .executable }
82+
let executables = package.products.filter { $0.type == .executable }.sorted()
8383
for executable in executables {
8484
print(executable.name)
8585
}
8686
case .listSnippets:
8787
let graph = try await swiftCommandState.loadPackageGraph()
8888
let package = graph.rootPackages[graph.rootPackages.startIndex].underlying
89-
let executables = package.modules.filter { $0.type == .snippet }
89+
let executables = package.modules.filter { $0.type == .snippet }.sorted()
9090
for executable in executables {
9191
print(executable.name)
9292
}
9393
}
9494
}
9595
}
96-
}
96+
}

0 commit comments

Comments
 (0)