-
Notifications
You must be signed in to change notification settings - Fork 1.4k
SE-0318 Package creation #3514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SE-0318 Package creation #3514
Conversation
throw InternalError("Could not get the current working directory") | ||
} | ||
|
||
if localFileSystem.exists(cwd.appending(RelativePath(url))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when passing in a path it should be an absolute path, not relative to the working directory.
|
||
try localFileSystem.copy(from: currentTemplateLocation, to: templateDirectory) | ||
} else { | ||
let templatePath = configPath.appending(components: "templates", "new-package", String(url.split(separator: "/").last!)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
url parsing in fragile
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Foundation has URLComponents
for this.
} | ||
} | ||
|
||
internal var useNewBehaviour: Mode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useNewBehaviour -> createPackageMode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this var should be be in an extension to InitPackage rather than "free floating" to better encapsulate the logic
} | ||
} | ||
|
||
internal enum Mode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mode -> CreatePackageMode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function should be be in an extension to InitPackage rather than "free floating" to better encapsulate the logic
@@ -966,3 +1051,207 @@ fileprivate func logPackageChanges(changes: [(PackageReference, Workspace.Packag | |||
} | |||
stream.flush() | |||
} | |||
|
|||
internal struct PackageTemplate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this type still required? iirc this was for JSON parsing
case legacy | ||
} | ||
|
||
internal func getSwiftPMDefaultTemplate(type: InitPackage.PackageType, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function should be be in an extension to InitPackage rather than "free floating" to better encapsulate the logic
} | ||
} | ||
|
||
fileprivate func makePackage(fileSystem: FileSystem, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function should be be in an extension to InitPackage rather than "free floating" to better encapsulate the logic
try initPackage.writePackageStructure() | ||
} | ||
|
||
fileprivate func copyTemplate(fileSystem: FileSystem, sourcePath: AbsolutePath, destinationPath: AbsolutePath, name: String) throws { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function should be be in an extension to InitPackage rather than "free floating" to better encapsulate the logic
} | ||
} | ||
|
||
fileprivate enum MakePackageMode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this enum should be be in an extension to InitPackage rather than "free floating" to better encapsulate the logic
internal func getSwiftPMDefaultTemplate(type: InitPackage.PackageType, | ||
sources: RelativePath = .init("./Sources"), | ||
tests: RelativePath? = nil, | ||
createSubDirectoryForModule: Bool = false) -> PackageTemplate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can now return InitPackage.PackageTemplate since we dont need the other type now that we are not parsing JSON
let templateHomeDirectory = configPath.appending(components: "templates", "new-package") | ||
|
||
var foundTemplate = false | ||
var templateToUse = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make templateToUse optional and then you can get rid of foundTemplate
name = packageName ?? cwd.basename | ||
destinationPath = cwd | ||
case .create: | ||
name = packageName! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not safe! you should guard to make sure its set
print("Copying \($0)") | ||
try copyTemplate(fileSystem: fileSystem, sourcePath: templateHomeDirectory.appending(components: templateToUse, $0), destinationPath: destinationPath, name: name) | ||
} | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if returning here, then the else branch is not required and you can move the let packageTemplate down
print(message) | ||
} | ||
try initPackage.writePackageStructure() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I read this correctly, I dont think this follow the logic defined in the evolution proposal.
I suggest restructuring the code in the following way:
- separate
makePackage
into 2 functions, one for the "legacy behavior" (e.g.makePackageLegacy
) and one for the "new" one (e.g.makePackageNew
). - from the Init command, call
makePackageLegacy
when mode == .legacy andmakePackageNew
when mode == .new - from the Create command, we can always call
makePackageNew
since its only available when mode == .new - initPackage.writePackageStructure should wither take a mode argument, or also be split into legacy/new since per the design its supposed to work a bit differently in legacy vs. new mode (e.g. not create certain files)
// Recursively copy the template package | ||
// Currently only replaces the string literal "$NAME" | ||
if fileSystem.isDirectory(sourcePath) { | ||
if let fileName = sourcePath.pathString.split(separator: "/").last { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this fileName or directory name?
renamed = renamed.replacingOccurrences(of: "___NAME_AS_C99___", with: name.spm_mangledToC99ExtendedIdentifier()) | ||
|
||
if let fileName = sourcePath.pathString.split(separator: "/").last { | ||
if !fileSystem.exists(destinationPath.appending(component: String(fileName))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like you can move this condition up so not to do anything if the file already exists
Sources/Workspace/InitPackage.swift
Outdated
@@ -241,7 +274,7 @@ public final class InitPackage { | |||
# \(pkgname) | |||
|
|||
A description of this package. | |||
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove redundant space
Tests/WorkspaceTests/InitTests.swift
Outdated
@@ -13,6 +13,7 @@ import SPMTestSupport | |||
import TSCBasic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ideally none of these test have to change
|
||
func testCreateNoNameArgument() throws { | ||
try XCTSkipIf(useNewBehaviour == .legacy) | ||
fixture(name: "Miscellaneous") { prefix in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the fixture needed here?
Package.swift
Outdated
@@ -273,7 +273,7 @@ let package = Package( | |||
dependencies: ["swift-build", "swift-package", "swift-test", "swift-run", "Commands", "Workspace", "SPMTestSupport"]), | |||
.testTarget( | |||
name: "WorkspaceTests", | |||
dependencies: ["Workspace", "SPMTestSupport"]), | |||
dependencies: ["Workspace", "SPMTestSupport", "Commands"]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this likely points to some leaky abstraction - we should not need to bring Commands into workspace tests
if useNewBehaviour == .new { | ||
subCommands.insert(Create.self, at: 6) | ||
subCommands.insert(AddTemplate.self, at: 7) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
Tests/WorkspaceTests/InitTests.swift
Outdated
@@ -13,6 +13,7 @@ import SPMTestSupport | |||
import TSCBasic | |||
import PackageModel | |||
import Workspace | |||
@testable import Commands |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see above, this likely point to some leaky abstraction and should not be needed
|
||
public init() {} | ||
|
||
public static var _errorLabel: String { "error" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a requirement of swift-argument-parser
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do need the constructor, but _errorLabel
isn't needed.
From the swift-argument-parser
documentation _errorLabel
is used to insert the label at the beginning of an error message.
/// The label to use for "Error: ..." messages from this type. (experimental)
public static var _errorLabel: String { get }
] | ||
|
||
if InitPackage.createPackageMode == .new { | ||
subCommands.insert(Create.self, at: 6) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to derive these indices from looking up Init.self
in the array? If not, it would be good to have a comment up in that array, since it's very easy otherwise to add a subcommand without realizing that this hardcoded index has to be updated.
Tests/WorkspaceTests/InitTests.swift
Outdated
@@ -266,10 +266,15 @@ class InitTests: XCTestCase { | |||
try localFileSystem.removeFileTree(packageRoot) | |||
try localFileSystem.createDirectory(packageRoot) | |||
|
|||
let packageTemplate = InitPackage.PackageTemplate(sourcesDirectory: RelativePath("./Sources"), | |||
testsDirectory: RelativePath("./Tests"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not assume that the path separator is /
. You should use the join
method to generate the relative paths.
Might have hit limitation of json, would be nice to have support for multiline strings
Needed because the default directory structure has been simplified
- Moved to transforming dir - Tests are now skipped depending on flag
- Restored InitTests.swift - add-template is less fragile - extension instead of free floating
testPlatforms() was removed because the refactoring also removes InitPackage.InitPackageOptions() It wasn't possible from a user to access, it's dead code and only used by this test.
- Fixed some typos - add-template is now more robust when determining if we have a path or web url - rough implementation of update-template
-C needed to come first
The funny name is just a folder that is space separated
@swift-ci please smoke test |
|
||
struct AddTemplate: SwiftCommand { | ||
static let configuration = CommandConfiguration( | ||
abstract: "Donwloads/moves a template into the default template directory") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
abstract: "Donwloads/moves a template into the default template directory") | |
abstract: "Downloads/moves a template into the default template directory") |
@OptionGroup(_hiddenFromHelp: true) | ||
var swiftOptions: SwiftToolOptions | ||
|
||
@Argument(help: "URL to template (absolute path to template works too)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Argument(help: "URL to template (absolute path to template works too)") | |
@Argument(help: "URL or absolute path of template") |
Closing because we are exploring a different approach (evolution proposal was sent back). |
swiftlang/swift-evolution#1349
swift package create <packageName>
Makes new packages while also handling the ceremony of making the package's directory first.Defaults to executable package
swift package add-template <url>
Facilitates adding new templates from gitTemplates are generic Swift package directories that are transformed when making a new packages based off of a template
Directory structure is simplified from:
To: