Merge tuist-embed into tuist (#80)

* Remove tuist-embed target

* Merge tuist-embed into tuist
This commit is contained in:
Pedro Piñera Buendía 2018-07-25 18:23:58 -04:00 committed by GitHub
parent 8e10558ee7
commit 01c9078575
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 130 additions and 117 deletions

View File

@ -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"]),

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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",

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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))
}
}
}

View File

@ -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!)")

View File

@ -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]

View File

@ -1,4 +0,0 @@
import Foundation
import TuistKit
FrameworkEmbedder().embed()

View File

@ -17,7 +17,6 @@ final class BuildCopierTests: XCTestCase {
func test_files() {
XCTAssertEqual(BuildCopier.files, [
"tuist",
"tuist-embed",
"ProjectDescription.swiftmodule",
"ProjectDescription.swiftdoc",
"libProjectDescription.dylib",

View File

@ -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 {

View File

@ -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"])