Skip to content

Xcode generation tests #198

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

Merged
merged 2 commits into from
Mar 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions Sources/Xcodeproj/generate().swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,33 @@ import POSIX
Generates an xcodeproj at the specified path.
- Returns: the path to the generated project
*/
public func generate(path path: String, package: Package, modules: [SwiftModule], products: [Product]) throws -> String {
public func generate(dstdir dstdir: String, projectName: String, srcroot: String, modules: [SwiftModule], products: [Product]) throws -> String {

/// If a specific *.xcodeproj path is already passed in, use that.
/// Otherwise treat the path as the desired enclosing folder for
/// the .xcodeproj folder.
let rootdir = path.hasSuffix(".xcodeproj") ? path : Path.join(path, "\(package.name).xcodeproj")
try mkdir(rootdir)

let schemedir = try mkdir(rootdir, "xcshareddata/xcschemes")
let xcodeprojName = "\(projectName).xcodeproj"
let xcodeprojPath = try mkdir(dstdir, xcodeprojName)
let schemesDirectory = try mkdir(xcodeprojPath, "xcshareddata/xcschemes")
let schemeName = "\(projectName).xcscheme"

////// the pbxproj file describes the project and its targets
try open(rootdir, "project.pbxproj") { fwrite in
pbxproj(projectPath: path, package: package, modules: modules, products: products, printer: fwrite)
try open(xcodeprojPath, "project.pbxproj") { fwrite in
pbxproj(srcroot: srcroot, projectRoot: dstdir, modules: modules, products: products, printer: fwrite)
}

////// the scheme acts like an aggregate target for all our targets
/// it has all tests associated so CMD+U works
try open(schemedir, "\(package.name).xcscheme") { fwrite in
xcscheme(packageName: package.name, modules: modules, printer: fwrite)
try open(schemesDirectory, schemeName) { fwrite in
xcscheme(container: xcodeprojName, modules: modules, printer: fwrite)
}

////// we generate this file to ensure our main scheme is listed
/// before any inferred schemes Xcode may autocreate
try open(schemedir, "xcschememanagement.plist") { fwrite in
try open(schemesDirectory, "xcschememanagement.plist") { fwrite in
fwrite("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
fwrite("<plist version=\"1.0\">")
fwrite("<dict>")
fwrite(" <key>SchemeUserState</key>")
fwrite(" <dict>")
fwrite(" <key>\(package.name).xcscheme</key>")
fwrite(" <key>\(schemeName)</key>")
fwrite(" <dict></dict>")
fwrite(" </dict>")
fwrite(" <key>SuppressBuildableAutocreation</key>")
Expand All @@ -54,7 +51,7 @@ public func generate(path path: String, package: Package, modules: [SwiftModule]
fwrite("</plist>")
}

return rootdir
return xcodeprojPath
}


Expand Down
6 changes: 2 additions & 4 deletions Sources/Xcodeproj/pbxproj().swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
import PackageType
import Utility

public func pbxproj(projectPath projectPath: String, package: Package, modules: [SwiftModule], products _: [Product], printer print: (String) -> Void) {

let srcroot = projectPath
public func pbxproj(srcroot srcroot: String, projectRoot: String, modules: [SwiftModule], products _: [Product], printer print: (String) -> Void) {
let nontests = modules.filter{ !($0 is TestModule) }
let tests = modules.filter{ $0 is TestModule }

Expand Down Expand Up @@ -60,7 +58,7 @@ public func pbxproj(projectPath projectPath: String, package: Package, modules:
print(" \(module.groupReference) = {")
print(" isa = PBXGroup;")
print(" name = \(module.name);")
print(" path = '\(Path(module.sources.root).relative(to: srcroot))';")
print(" path = '\(Path(module.sources.root).relative(to: projectRoot))';")
print(" sourceTree = '<group>';")
print(" children = (" + fileRefs(forModuleSources: module, srcroot: srcroot).map{$0.0}.joined(separator: ", ") + ");")
print(" };")
Expand Down
6 changes: 3 additions & 3 deletions Sources/Xcodeproj/xcscheme().swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import PackageType

func xcscheme(packageName packageName: String, modules: [SwiftModule], printer print: (String) -> Void) {
func xcscheme(container container: String, modules: [SwiftModule], printer print: (String) -> Void) {
print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
print("<Scheme LastUpgradeVersion = \"9999\" version = \"1.3\">")
print(" <BuildAction parallelizeBuildables = \"YES\" buildImplicitDependencies = \"YES\">")
Expand All @@ -26,7 +26,7 @@ func xcscheme(packageName packageName: String, modules: [SwiftModule], printer p
print(" BlueprintIdentifier = \"\(module.blueprintIdentifier)\"")
print(" BuildableName = \"\(module.buildableName)\"")
print(" BlueprintName = \"\(module.blueprintName)\"")
print(" ReferencedContainer = \"container:\(packageName).xcodeproj\">")
print(" ReferencedContainer = \"container:\(container)\">")
print(" </BuildableReference>")
print(" </BuildActionEntry>")
}
Expand All @@ -48,7 +48,7 @@ func xcscheme(packageName packageName: String, modules: [SwiftModule], printer p
print(" BlueprintIdentifier = \"\(module.blueprintIdentifier)\"")
print(" BuildableName = \"\(module.buildableName)\"")
print(" BlueprintName = \"\(module.blueprintName)\"")
print(" ReferencedContainer = \"container:\(packageName).xcodeproj\">")
print(" ReferencedContainer = \"container:\(container)\">")
print(" </BuildableReference>")
print(" </TestableReference>")
}
Expand Down
24 changes: 21 additions & 3 deletions Sources/swift-build/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,27 @@ do {
let (modules, products) = try transmute(packages, rootdir: dirs.root)
let swiftModules = modules.flatMap{ $0 as? SwiftModule }

let path = try Xcodeproj.generate(path: outpath ?? dirs.root, package: packages.last!, modules: swiftModules, products: products)

print("generated:", path.prettied)
let projectName: String
let dstdir: String
let packageName = packages.last!.name //FIXME coincidental dependency on order

switch outpath {
case let outpath? where outpath.hasSuffix(".xcodeproj"):
// if user specified path ending with .xcodeproj, generate that
"\(packageName).xcodeproj"
projectName = String(outpath.basename.characters.dropLast(10))
dstdir = outpath.parentDirectory
case let outpath?:
dstdir = outpath
projectName = packageName
case _:
dstdir = dirs.root
projectName = packageName
}

let outpath = try Xcodeproj.generate(dstdir: dstdir, projectName: projectName, srcroot: dirs.root, modules: swiftModules, products: products)

print("generated:", outpath.prettied)
}

} catch {
Expand Down
67 changes: 67 additions & 0 deletions Tests/Xcodeproj/TestGeneration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
This source file is part of the Swift.org open source project

Copyright 2015 - 2016 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import func POSIX.mkdtemp
import PackageType
import Xcodeproj
import Utility
import XCTest


// copy pasta
func mktmpdir(file: StaticString = #file, line: UInt = #line, @noescape body: (String) throws -> Void) {
do {
try POSIX.mkdtemp("spm-tests") { dir in
defer { _ = try? rmtree(dir) }
try body(dir)
}
} catch {
XCTFail("\(error)", file: file, line: line)
}
}

func XCTAssertDirectoryExists(paths: String..., file: StaticString = #file, line: UInt = #line) {
let path = Path.join(paths)
if !path.isDirectory {
XCTFail("Expected directory doesn’t exist: \(path)", file: file, line: line)
}
}


#if os(OSX)
class TestGeneration: XCTestCase {

/// --> this comment is here <--

func testXcodeBuildCanParseIt() {
mktmpdir { dstdir in
func dummy() -> [SwiftModule] {
return [SwiftModule(name: "DummyModuleName", sources: Sources(paths: [], root: dstdir))]
}

let projectName = "DummyProjectName"
let srcroot = dstdir
let modules = dummy()
let products: [Product] = []

let outpath = try Xcodeproj.generate(dstdir: dstdir, projectName: projectName, srcroot: srcroot, modules: modules, products: products)

XCTAssertDirectoryExists(outpath)
XCTAssertEqual(outpath, Path.join(dstdir, "\(projectName).xcodeproj"))

let output = try popen(["xcodebuild", "-list", "-project", outpath])

let expectedOutput = "Information about project \"DummyProjectName\":\n Targets:\n DummyModuleName\n\n Build Configurations:\n Debug\n\n If no build configuration is specified and -scheme is not passed then \"Debug\" is used.\n\n Schemes:\n DummyProjectName\n"

XCTAssertEqual(output, expectedOutput)
}
}
}
#endif