Merge tuist-embed into tuist (#80)
* Remove tuist-embed target * Merge tuist-embed into tuist
This commit is contained in:
parent
8e10558ee7
commit
01c9078575
|
@ -6,7 +6,6 @@ let package = Package(
|
|||
name: "tuist",
|
||||
products: [
|
||||
.executable(name: "tuist", targets: ["tuist"]),
|
||||
.executable(name: "tuist-embed", targets: ["tuist-embed"]),
|
||||
.executable(name: "tuistenv", targets: ["tuistenv"]),
|
||||
.library(name: "ProjectDescription",
|
||||
type: .dynamic,
|
||||
|
@ -36,9 +35,6 @@ let package = Package(
|
|||
.target(
|
||||
name: "tuist",
|
||||
dependencies: ["TuistKit"]),
|
||||
.target(
|
||||
name: "tuist-embed",
|
||||
dependencies: ["TuistKit"]),
|
||||
.target(
|
||||
name: "TuistEnvKit",
|
||||
dependencies: ["Utility", "TuistCore"]),
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
import Utility
|
||||
|
||||
/// Protocol that defines a command line command.
|
||||
public protocol Command {
|
||||
/// Command name. This name is used from the command line to call the command.
|
||||
static var command: String { get }
|
||||
|
||||
/// Command overview. It's used to show more details about your command from the command line.
|
||||
static var overview: String { get }
|
||||
|
||||
/// Initializes the command with the argument parser.
|
||||
///
|
||||
/// - Parameter parser: argument parser.
|
||||
init(parser: ArgumentParser)
|
||||
|
||||
/// Runs the command with the given arguments.
|
||||
///
|
||||
/// - Parameter arguments: arguments.
|
||||
/// - Throws: an error if the command execution fails.
|
||||
func run(with arguments: ArgumentParser.Result) throws
|
||||
}
|
||||
|
||||
public protocol HiddenCommand {
|
||||
static var command: String { get }
|
||||
init()
|
||||
func run(arguments: [String]) throws
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import Foundation
|
||||
import TuistCore
|
||||
import Utility
|
||||
|
||||
public final class MockHiddenCommand: HiddenCommand {
|
||||
public static var command: String = "hidden"
|
||||
public var runStub: (([String]) throws -> Void)? = { _ in }
|
||||
public var runCallCount: UInt = 0
|
||||
|
||||
public init() {}
|
||||
|
||||
public func run(arguments: [String]) throws {
|
||||
runCallCount += 1
|
||||
try runStub?(arguments)
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@ class BuildCopier: BuildCopying {
|
|||
/// Files that should be copied (if they exist).
|
||||
static let files: [String] = [
|
||||
"tuist",
|
||||
"tuist-embed",
|
||||
// Project description
|
||||
"ProjectDescription.swiftmodule",
|
||||
"ProjectDescription.swiftdoc",
|
||||
|
|
|
@ -9,6 +9,7 @@ public final class CommandRegistry {
|
|||
|
||||
let parser: ArgumentParser
|
||||
var commands: [Command] = []
|
||||
var hiddenCommands: [String: HiddenCommand] = [:]
|
||||
private let commandCheck: CommandChecking
|
||||
private let errorHandler: ErrorHandling
|
||||
private let processArguments: () -> [String]
|
||||
|
@ -24,6 +25,7 @@ public final class CommandRegistry {
|
|||
register(command: DumpCommand.self)
|
||||
register(command: VersionCommand.self)
|
||||
register(command: CreateIssueCommand.self)
|
||||
register(hiddenCommand: EmbedCommand.self)
|
||||
}
|
||||
|
||||
init(commandCheck: CommandChecking,
|
||||
|
@ -33,8 +35,7 @@ public final class CommandRegistry {
|
|||
self.errorHandler = errorHandler
|
||||
parser = ArgumentParser(commandName: "tuist",
|
||||
usage: "<command> <options>",
|
||||
overview: "Generate, build and test your Xcode projects.",
|
||||
seeAlso: "http://docs.xcodepm.com/")
|
||||
overview: "Generate, build and test your Xcode projects.")
|
||||
self.processArguments = processArguments
|
||||
}
|
||||
|
||||
|
@ -48,12 +49,20 @@ public final class CommandRegistry {
|
|||
commands.append(command.init(parser: parser))
|
||||
}
|
||||
|
||||
func register(hiddenCommand command: HiddenCommand.Type) {
|
||||
hiddenCommands[command.command] = command.init()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
public func run() {
|
||||
do {
|
||||
let parsedArguments = try parse()
|
||||
try process(arguments: parsedArguments)
|
||||
if let hiddenCommand = hiddenCommand() {
|
||||
try hiddenCommand.run(arguments: Array(processArguments().dropFirst(2)))
|
||||
} else {
|
||||
let parsedArguments = try parse()
|
||||
try process(arguments: parsedArguments)
|
||||
}
|
||||
} catch let error as FatalError {
|
||||
errorHandler.fatal(error: error)
|
||||
} catch {
|
||||
|
@ -68,6 +77,12 @@ public final class CommandRegistry {
|
|||
return try parser.parse(arguments)
|
||||
}
|
||||
|
||||
fileprivate func hiddenCommand() -> HiddenCommand? {
|
||||
let arguments = Array(processArguments().dropFirst())
|
||||
guard let commandName = arguments.first else { return nil }
|
||||
return hiddenCommands[commandName]
|
||||
}
|
||||
|
||||
fileprivate func process(arguments: ArgumentParser.Result) throws {
|
||||
guard let subparser = arguments.subparser(parser),
|
||||
let command = commands.first(where: { type(of: $0).command == subparser }) else {
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import Basic
|
||||
import Foundation
|
||||
import TuistCore
|
||||
import Utility
|
||||
|
||||
enum EmbedCommandError: FatalError {
|
||||
case missingFrameworkPath
|
||||
|
||||
var type: ErrorType {
|
||||
switch self {
|
||||
case .missingFrameworkPath:
|
||||
return .bug
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .missingFrameworkPath:
|
||||
return "The path to the framework is missing."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class EmbedCommand: HiddenCommand {
|
||||
|
||||
// MARK: - HiddenCommand
|
||||
|
||||
static var command: String = "embed"
|
||||
|
||||
// MARK: - Attributes
|
||||
|
||||
private let embedder: FrameworkEmbedding
|
||||
private let parser: ArgumentParser
|
||||
private let fileHandler: FileHandling
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
convenience init() {
|
||||
self.init(embedder: FrameworkEmbedder(),
|
||||
parser: ArgumentParser(usage: "embed", overview: ""),
|
||||
fileHandler: FileHandler())
|
||||
}
|
||||
|
||||
init(embedder: FrameworkEmbedding,
|
||||
parser: ArgumentParser,
|
||||
fileHandler: FileHandling) {
|
||||
self.embedder = embedder
|
||||
self.parser = parser
|
||||
self.fileHandler = fileHandler
|
||||
}
|
||||
|
||||
func run(arguments: [String]) throws {
|
||||
guard let pathString = arguments.first else {
|
||||
throw EmbedCommandError.missingFrameworkPath
|
||||
}
|
||||
let path = AbsolutePath(pathString, relativeTo: fileHandler.currentPath)
|
||||
try embedder.embed(path: path)
|
||||
}
|
||||
}
|
|
@ -5,24 +5,32 @@ import Basic
|
|||
import Foundation
|
||||
import TuistCore
|
||||
|
||||
public class FrameworkEmbedder {
|
||||
protocol FrameworkEmbedding: AnyObject {
|
||||
func embed(path: AbsolutePath) throws
|
||||
}
|
||||
|
||||
final class FrameworkEmbedder: FrameworkEmbedding {
|
||||
|
||||
// MARK: - Attributes
|
||||
|
||||
private let fileHandler: FileHandling
|
||||
private let errorHandler: ErrorHandling
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public convenience init() {
|
||||
self.init(fileHandler: FileHandler(),
|
||||
errorHandler: ErrorHandler())
|
||||
self.init(fileHandler: FileHandler())
|
||||
}
|
||||
|
||||
init(fileHandler: FileHandling,
|
||||
errorHandler: ErrorHandling) {
|
||||
init(fileHandler: FileHandling) {
|
||||
self.fileHandler = fileHandler
|
||||
self.errorHandler = errorHandler
|
||||
}
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
func embed(path _: AbsolutePath) throws {
|
||||
let environment = XcodeBuild.Environment()!
|
||||
try embed(frameworkPath: RelativePath(CommandLine.arguments[1]),
|
||||
environment: environment)
|
||||
}
|
||||
|
||||
func embed(frameworkPath: RelativePath,
|
||||
|
@ -115,18 +123,4 @@ public class FrameworkEmbedder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
public func embed() {
|
||||
do {
|
||||
let environment = XcodeBuild.Environment()!
|
||||
try embed(frameworkPath: RelativePath(CommandLine.arguments[1]),
|
||||
environment: environment)
|
||||
} catch let error as FatalError {
|
||||
errorHandler.fatal(error: error)
|
||||
} catch {
|
||||
errorHandler.fatal(error: UnhandledError(error: error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ final class LinkGenerator: LinkGenerating {
|
|||
/// - pbxTarget: Xcode target.
|
||||
/// - objects: Xcode project objects.
|
||||
/// - fileElements: project file elements.
|
||||
/// - resourceLocator: resource locator used to get the path to the "tuist-embed" util.
|
||||
/// - resourceLocator: resource locator used to get the path to the "tuist" util.
|
||||
/// - sourceRootPath: path to the folder where the Xcode project is generated.
|
||||
func generateEmbedPhase(dependencies: [DependencyReference],
|
||||
pbxTarget: PBXTarget,
|
||||
|
@ -144,12 +144,12 @@ final class LinkGenerator: LinkGenerating {
|
|||
pbxTarget.buildPhasesReferences.append(embedPhaseReference)
|
||||
|
||||
var script: [String] = []
|
||||
let embedPath = try resourceLocator.embedPath()
|
||||
let cliPath = try resourceLocator.cliPath()
|
||||
|
||||
try dependencies.forEach { dependency in
|
||||
if case let DependencyReference.absolute(path) = dependency {
|
||||
let relativePath = "$(SRCROOT)/\(path.relative(to: sourceRootPath).asString)"
|
||||
script.append("\(embedPath.asString) \(path.relative(to: sourceRootPath).asString)")
|
||||
script.append("\(cliPath.asString) embed \(path.relative(to: sourceRootPath).asString)")
|
||||
precompiledEmbedPhase.inputPaths.append(relativePath)
|
||||
precompiledEmbedPhase.outputPaths.append("$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/\(path.components.last!)")
|
||||
|
||||
|
|
|
@ -2,36 +2,14 @@ import Basic
|
|||
import Foundation
|
||||
import TuistCore
|
||||
|
||||
/// Util to locate resources such es the ProjectDescription.framework or the tuist cli binary.
|
||||
protocol ResourceLocating: AnyObject {
|
||||
/// Returns the ProjectDescription.framework path.
|
||||
///
|
||||
/// - Parameter context: context.
|
||||
/// - Returns: ProjectDescription.framework path.
|
||||
/// - Throws: an error if the framework cannot be found.
|
||||
func projectDescription() throws -> AbsolutePath
|
||||
|
||||
/// Returns the CLI path.
|
||||
///
|
||||
/// - Parameter context: context.
|
||||
/// - Returns: path to the tuist CLI.
|
||||
/// - Throws: an error if the CLI cannot be found.
|
||||
func cliPath() throws -> AbsolutePath
|
||||
|
||||
/// Returns the embed util path.
|
||||
///
|
||||
/// - Returns: path to the embed util.
|
||||
/// - Throws: an error if embed cannot be found.
|
||||
func embedPath() throws -> AbsolutePath
|
||||
}
|
||||
|
||||
/// Resource locating error.
|
||||
///
|
||||
/// - notFound: thrown then the resource cannot be found.
|
||||
enum ResourceLocatingError: FatalError {
|
||||
case notFound(String)
|
||||
|
||||
/// Error description.
|
||||
var description: String {
|
||||
switch self {
|
||||
case let .notFound(name):
|
||||
|
@ -39,7 +17,6 @@ enum ResourceLocatingError: FatalError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Error type.
|
||||
var type: ErrorType {
|
||||
switch self {
|
||||
default:
|
||||
|
@ -47,12 +24,6 @@ enum ResourceLocatingError: FatalError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Compares two ResourceLocatingError instances.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - lhs: first instance to be compared.
|
||||
/// - rhs: second instance to be compared.
|
||||
/// - Returns: true if the two instances are the same.
|
||||
static func == (lhs: ResourceLocatingError, rhs: ResourceLocatingError) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case let (.notFound(lhsPath), .notFound(rhsPath)):
|
||||
|
@ -61,30 +32,27 @@ enum ResourceLocatingError: FatalError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resource locator.
|
||||
final class ResourceLocator: ResourceLocating {
|
||||
/// File handler.
|
||||
private let fileHandler: FileHandling
|
||||
|
||||
/// Initializes the locator with its attributes.
|
||||
///
|
||||
/// - Parameter fileHandler: file handler.
|
||||
// MARK: - Init
|
||||
|
||||
init(fileHandler: FileHandling = FileHandler()) {
|
||||
self.fileHandler = fileHandler
|
||||
}
|
||||
|
||||
/// Returns the ProjectDescription.framework path.
|
||||
///
|
||||
/// - Returns: ProjectDescription.framework path.
|
||||
/// - Throws: an error if the framework cannot be found.
|
||||
// MARK: - ResourceLocating
|
||||
|
||||
func projectDescription() throws -> AbsolutePath {
|
||||
return try frameworkPath("ProjectDescription")
|
||||
}
|
||||
|
||||
/// Returns the path of the framework/module with the given name.
|
||||
///
|
||||
/// - Parameter name: name of the framework
|
||||
/// - Returns: path if the framework exists.
|
||||
func cliPath() throws -> AbsolutePath {
|
||||
return try toolPath("tuist")
|
||||
}
|
||||
|
||||
// MARK: - Fileprivate
|
||||
|
||||
fileprivate func frameworkPath(_ name: String) throws -> AbsolutePath {
|
||||
let frameworkNames = ["\(name).framework", "lib\(name).dylib"]
|
||||
let bundlePath = AbsolutePath(Bundle(for: GraphManifestLoader.self).bundleURL.path)
|
||||
|
@ -98,29 +66,6 @@ final class ResourceLocator: ResourceLocating {
|
|||
return frameworkPath
|
||||
}
|
||||
|
||||
/// Returns the CLI path.
|
||||
///
|
||||
/// - Returns: path to the tuist CLI.
|
||||
/// - Throws: an error if the CLI cannot be found.
|
||||
func cliPath() throws -> AbsolutePath {
|
||||
return try toolPath("tuist")
|
||||
}
|
||||
|
||||
/// Returns the embed util path.
|
||||
///
|
||||
/// - Returns: path to the embed util.
|
||||
/// - Throws: an error if embed cannot be found.
|
||||
func embedPath() throws -> AbsolutePath {
|
||||
return try toolPath("tuist-embed")
|
||||
}
|
||||
|
||||
/// Returns the path to the tool with the given name.
|
||||
/// Command line tools are bundled in the shared support directory of the application bundle.
|
||||
/// If the project is executed from Xcode, the tool will be in the built products directory instead.
|
||||
///
|
||||
/// - Parameter name: name of the tool.
|
||||
/// - Returns: the path to the tool if it could be found.
|
||||
/// - Throws: an error if the tool couldn't be found.
|
||||
fileprivate func toolPath(_ name: String) throws -> AbsolutePath {
|
||||
let bundlePath = AbsolutePath(Bundle(for: GraphManifestLoader.self).bundleURL.path)
|
||||
let paths = [bundlePath, bundlePath.parentDirectory]
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
import Foundation
|
||||
import TuistKit
|
||||
|
||||
FrameworkEmbedder().embed()
|
|
@ -17,7 +17,6 @@ final class BuildCopierTests: XCTestCase {
|
|||
func test_files() {
|
||||
XCTAssertEqual(BuildCopier.files, [
|
||||
"tuist",
|
||||
"tuist-embed",
|
||||
"ProjectDescription.swiftmodule",
|
||||
"ProjectDescription.swiftdoc",
|
||||
"libProjectDescription.dylib",
|
||||
|
|
|
@ -18,6 +18,7 @@ final class CommandRegistryTests: XCTestCase {
|
|||
processArguments: { ["tuist", type(of: self.command).command] })
|
||||
command = MockCommand(parser: subject.parser)
|
||||
subject.register(command: MockCommand.self)
|
||||
subject.register(hiddenCommand: MockHiddenCommand.self)
|
||||
}
|
||||
|
||||
func test_run_reportsFatalErrors() throws {
|
||||
|
|
|
@ -47,7 +47,7 @@ final class LinkGeneratorErrorTests: XCTestCase {
|
|||
|
||||
let scriptBuildPhase: PBXShellScriptBuildPhase? = try pbxTarget.buildPhasesReferences.first?.object()
|
||||
XCTAssertEqual(scriptBuildPhase?.name, "Embed Precompiled Frameworks")
|
||||
XCTAssertEqual(scriptBuildPhase?.shellScript, "/embed test.framework")
|
||||
XCTAssertEqual(scriptBuildPhase?.shellScript, "/ embed test.framework")
|
||||
XCTAssertEqual(scriptBuildPhase?.inputPaths, ["$(SRCROOT)/test.framework"])
|
||||
XCTAssertEqual(scriptBuildPhase?.outputPaths, ["$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/test.framework"])
|
||||
|
||||
|
|
Loading…
Reference in New Issue