Skip to content

Commit 79d64b3

Browse files
plemarquanddnadobaheckj
authored
Use @main instead of top level code when initializing executable (#8371)
### Motivation: Since `@main` is the general purpose way of marking the entry point to executables, use it over top level code when generating an executable template. ### Modifications: Update the template output when the specified `--type` is executable. ### Result: The template is now: ```swift @main struct MyProject { static func main() { print("Hello, world!") } } ``` This patch reverts #6197 and partially reverts #6144 --------- Co-authored-by: David Nadoba <[email protected]> Co-authored-by: Joseph Heck <[email protected]>
1 parent b175dd8 commit 79d64b3

File tree

3 files changed

+42
-23
lines changed

3 files changed

+42
-23
lines changed

Sources/Workspace/InitPackage.swift

+18-20
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ public final class InitPackage {
239239
// Products define the executables and libraries a package produces, making them visible to other packages.
240240
.library(
241241
name: "\(pkgname)",
242-
targets: ["\(pkgname)"]),
242+
targets: ["\(pkgname)"]
243+
),
243244
]
244245
""")
245246
} else if packageType == .buildToolPlugin || packageType == .commandPlugin {
@@ -248,7 +249,8 @@ public final class InitPackage {
248249
// Products can be used to vend plugins, making them visible to other packages.
249250
.plugin(
250251
name: "\(pkgname)",
251-
targets: ["\(pkgname)"]),
252+
targets: ["\(pkgname)"]
253+
),
252254
]
253255
""")
254256
} else if packageType == .macro {
@@ -299,7 +301,8 @@ public final class InitPackage {
299301
if packageType == .executable {
300302
param += """
301303
.executableTarget(
302-
name: "\(pkgname)"),
304+
name: "\(pkgname)"
305+
),
303306
]
304307
"""
305308
} else if packageType == .tool {
@@ -394,7 +397,8 @@ public final class InitPackage {
394397

395398
param += """
396399
.target(
397-
name: "\(pkgname)"),
400+
name: "\(pkgname)"
401+
),
398402
\(testTarget)
399403
]
400404
"""
@@ -570,21 +574,12 @@ public final class InitPackage {
570574
progressReporter?("Creating \(sources.relative(to: destinationPath))")
571575
try makeDirectories(sources)
572576

573-
let moduleDir: AbsolutePath
574-
switch packageType {
575-
case .executable, .tool:
576-
moduleDir = sources
577-
default:
578-
moduleDir = sources.appending("\(pkgname)")
579-
}
577+
let moduleDir = sources.appending("\(pkgname)")
580578
try makeDirectories(moduleDir)
581579

582-
let sourceFileName: String
583-
if packageType == .executable {
584-
sourceFileName = "main.swift"
585-
} else {
586-
sourceFileName = "\(typeName).swift"
587-
}
580+
// If we're creating an executable we can't have both a @main declaration and a main.swift file.
581+
// Handle the edge case of a user creating a project called "main" by give the generated file a different name.
582+
let sourceFileName = ((packageType == .executable || packageType == .tool) && typeName == "main") ? "MainEntrypoint.swift" : "\(typeName).swift"
588583
let sourceFile = try AbsolutePath(validating: sourceFileName, relativeTo: moduleDir)
589584

590585
let content: String
@@ -600,7 +595,12 @@ public final class InitPackage {
600595
// The Swift Programming Language
601596
// https://docs.swift.org/swift-book
602597
603-
print("Hello, world!")
598+
@main
599+
struct \(typeName) {
600+
static func main() {
601+
print("Hello, world!")
602+
}
603+
}
604604
605605
"""
606606
case .tool:
@@ -686,7 +686,6 @@ public final class InitPackage {
686686
}
687687
content += "@testable import \(moduleName)\n"
688688

689-
690689
if options.supportedTestingLibraries.contains(.swiftTesting) {
691690
content += """
692691
@@ -750,7 +749,6 @@ public final class InitPackage {
750749
751750
"""##
752751

753-
754752
// XCTest is only added if it was explicitly asked for, so add tests
755753
// for it *and* Testing if it is enabled.
756754

Tests/CommandsTests/PackageCommandTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ class PackageCommandTestCase: CommandsBuildProviderTestCase {
840840
XCTAssertMatch(contents, .prefix("// swift-tools-version:\(version < .v5_4 ? "" : " ")\(versionSpecifier)\n"))
841841

842842
XCTAssertFileExists(manifest)
843-
XCTAssertEqual(try fs.getDirectoryContents(path.appending("Sources")), ["main.swift"])
843+
XCTAssertEqual(try fs.getDirectoryContents(path.appending("Sources").appending(("Foo"))), ["Foo.swift"])
844844
}
845845
}
846846

@@ -871,7 +871,7 @@ class PackageCommandTestCase: CommandsBuildProviderTestCase {
871871
XCTAssertMatch(contents, .prefix("// swift-tools-version:\(version < .v5_4 ? "" : " ")\(versionSpecifier)\n"))
872872

873873
XCTAssertFileExists(manifest)
874-
XCTAssertEqual(try fs.getDirectoryContents(path.appending("Sources")), ["main.swift"])
874+
XCTAssertEqual(try fs.getDirectoryContents(path.appending("Sources").appending("CustomName")), ["CustomName.swift"])
875875
}
876876
}
877877

Tests/WorkspaceTests/InitTests.swift

+22-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ final class InitTests: XCTestCase {
8585
let versionSpecifier = "\(version.major).\(version.minor)"
8686
XCTAssertMatch(manifestContents, .prefix("// swift-tools-version:\(version < .v5_4 ? "" : " ")\(versionSpecifier)\n"))
8787

88-
XCTAssertEqual(try fs.getDirectoryContents(path.appending("Sources")), ["main.swift"])
88+
XCTAssertEqual(try fs.getDirectoryContents(path.appending("Sources").appending("Foo")), ["Foo.swift"])
8989
await XCTAssertBuilds(path)
9090
let triple = try UserToolchain.default.targetTriple
9191
let binPath = path.appending(components: ".build", triple.platformBuildPathComponent, "debug")
@@ -98,6 +98,27 @@ final class InitTests: XCTestCase {
9898
}
9999
}
100100

101+
func testInitPackageExecutableCalledMain() async throws {
102+
try await testWithTemporaryDirectory { tmpPath in
103+
let fs = localFileSystem
104+
let path = tmpPath.appending("main")
105+
let name = path.basename
106+
try fs.createDirectory(path)
107+
108+
// Create the package
109+
let initPackage = try InitPackage(
110+
name: name,
111+
packageType: .executable,
112+
destinationPath: path,
113+
fileSystem: localFileSystem
114+
)
115+
try initPackage.writePackageStructure()
116+
117+
XCTAssertEqual(try fs.getDirectoryContents(path.appending("Sources").appending("main")), ["MainEntrypoint.swift"])
118+
await XCTAssertBuilds(path)
119+
}
120+
}
121+
101122
func testInitPackageLibraryWithXCTestOnly() async throws {
102123
try await testWithTemporaryDirectory { tmpPath in
103124
let fs = localFileSystem

0 commit comments

Comments
 (0)