Skip to content
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

Support Multiple Header Paths #459

Merged
merged 10 commits into from
Jul 25, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
- Support for executing Tuist by running `swift project ...` https://github.com/tuist/tuist/pull/447 by @pepibumur.
- New manifest model, `TuistConfig`, to easily configure Tuist's functionalities https://github.com/tuist/tuist/pull/446 by @pepibumur.
- Adding ability to re-generate individual projects https://github.com/tuist/tuist/pull/457 by @kwridan
- Support multiple header paths https://github.com/tuist/tuist/pull/459 by @adamkhazi

### Fixed

Expand Down
25 changes: 25 additions & 0 deletions Sources/ProjectDescription/FileList.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Foundation

public final class FileList: Codable {
/// List glob patterns.
public let globs: [String]

/// Initializes the files list with the glob patterns.
///
/// - Parameter globs: Glob patterns.
public init(globs: [String]) {
self.globs = globs
}
}

extension FileList: ExpressibleByStringLiteral {
public convenience init(stringLiteral value: String) {
self.init(globs: [value])
}
}

extension FileList: ExpressibleByArrayLiteral {
public convenience init(arrayLiteral elements: String...) {
self.init(globs: elements)
}
}
14 changes: 7 additions & 7 deletions Sources/ProjectDescription/Headers.swift
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import Foundation

/// Headers
public class Headers: Codable {
public final class Headers: Codable {
/// Relative path to public headers.
public let `public`: String?
public let `public`: FileList?

/// Relative path to private headers.
public let `private`: String?
public let `private`: FileList?

/// Relative path to project headers.
public let project: String?
public let project: FileList?

public init(public: String? = nil,
private: String? = nil,
project: String? = nil) {
public init(public: FileList? = nil,
private: FileList? = nil,
project: FileList? = nil) {
self.public = `public`
self.private = `private`
self.project = project
Expand Down
6 changes: 2 additions & 4 deletions Sources/ProjectDescription/SourceFilesList.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// MARK: - FileList

public typealias FileList = SourceFilesList

/// A model to refer to source files that supports passing compiler flags.
public final class SourceFileGlob: ExpressibleByStringLiteral, Codable {
/// Relative glob pattern.
Expand Down Expand Up @@ -59,13 +57,13 @@ public final class SourceFilesList: Codable {
}

/// Support file as single string
extension FileList: ExpressibleByStringLiteral {
extension SourceFilesList: ExpressibleByStringLiteral {
public convenience init(stringLiteral value: String) {
self.init(globs: [value])
}
}

extension FileList: ExpressibleByArrayLiteral {
extension SourceFilesList: ExpressibleByArrayLiteral {
public convenience init(arrayLiteral elements: SourceFileGlob...) {
self.init(globs: elements)
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/ProjectDescription/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class Target: Codable {
public let dependencies: [TargetDependency]

/// Relative paths to the sources directory.
public let sources: FileList?
public let sources: SourceFilesList?

/// Relative paths to the resources directory.
public let resources: [FileElement]?
Expand Down Expand Up @@ -91,7 +91,7 @@ public class Target: Codable {
productName: String? = nil,
bundleId: String,
infoPlist: InfoPlist,
sources: FileList? = nil,
sources: SourceFilesList? = nil,
resources: [FileElement]? = nil,
headers: Headers? = nil,
entitlements: String? = nil,
Expand Down
15 changes: 12 additions & 3 deletions Sources/TuistKit/Generator/GeneratorModelLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,18 @@ extension TuistGenerator.CoreDataModel {

extension TuistGenerator.Headers {
static func from(manifest: ProjectDescription.Headers, path: AbsolutePath, fileHandler: FileHandling) -> TuistGenerator.Headers {
let `public` = manifest.public.map { headerFiles(path: path, glob: $0, fileHandler: fileHandler) } ?? []
let `private` = manifest.private.map { headerFiles(path: path, glob: $0, fileHandler: fileHandler) } ?? []
let project = manifest.project.map { headerFiles(path: path, glob: $0, fileHandler: fileHandler) } ?? []
let `public` = manifest.public?.globs.flatMap {
headerFiles(path: path, glob: $0, fileHandler: fileHandler)
} ?? []

let `private` = manifest.private?.globs.flatMap {
headerFiles(path: path, glob: $0, fileHandler: fileHandler)
} ?? []

let project = manifest.project?.globs.flatMap {
headerFiles(path: path, glob: $0, fileHandler: fileHandler)
} ?? []

return Headers(public: `public`, private: `private`, project: project)
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/ProjectDescriptionTests/HeadersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ final class HeadersTests: XCTestCase {
func test_toJSON() {
let subject = Headers(public: "public", private: "private", project: "project")

XCTAssertCodableEqualToJson(subject, "{\"private\": \"private\", \"project\": \"project\", \"public\": \"public\"}")
XCTAssertCodableEqualToJson(subject, "{\"public\":{\"globs\":[\"public\"]},\"private\":{\"globs\":[\"private\"]},\"project\":{\"globs\":[\"project\"]}}")
}
}
20 changes: 10 additions & 10 deletions Tests/ProjectDescriptionTests/TargetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ final class TargetTests: XCTestCase {
let expected = """
{
"headers": {
"public": "public\\/*",
"private": "private\\/*",
"project": "project\\/*"
"public": { "globs": ["public\\/*"] },
"private": { "globs": ["private\\/*"] },
"project": { "globs": ["project\\/*"] }
},
"bundle_id": "bundle_id",
"core_data_models": [
Expand Down Expand Up @@ -133,11 +133,11 @@ final class TargetTests: XCTestCase {
productName: "product_name",
bundleId: "bundle_id",
infoPlist: "info.plist",
sources: FileList(globs: ["sources/*"]),
sources: SourceFilesList(globs: ["sources/*"]),
resources: ["resources/*"],
headers: Headers(public: "public/*",
private: "private/*",
project: "project/*"),
headers: Headers(public: ["public/*"],
private: ["private/*"],
project: ["project/*"]),
entitlements: "entitlement",
actions: [
TargetAction.post(path: "path", arguments: ["arg"], name: "name"),
Expand All @@ -159,9 +159,9 @@ final class TargetTests: XCTestCase {
let expected = """
{
"headers": {
"public": "public\\/*",
"private": "private\\/*",
"project": "project\\/*"
"public": { "globs": ["public\\/*"] },
"private": { "globs": ["private\\/*"] },
"project": { "globs": ["project\\/*"] }
},
"bundle_id": "bundle_id",
"core_data_models": [
Expand Down
72 changes: 72 additions & 0 deletions Tests/TuistKitTests/Generator/GeneratorModelLoaderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,78 @@ class GeneratorModelLoaderTest: XCTestCase {
].map { fileHandler.currentPath.appending(RelativePath($0)) })
}

func test_headersArray() throws {
// Given
try fileHandler.createFiles([
"Sources/public/A/A1.h",
"Sources/public/A/A1.m",
"Sources/public/B/B1.h",
"Sources/public/B/B1.m",

"Sources/private/C/C1.h",
"Sources/private/C/C1.m",
"Sources/private/D/D1.h",
"Sources/private/D/D1.m",

"Sources/project/E/E1.h",
"Sources/project/E/E1.m",
"Sources/project/F/F1.h",
"Sources/project/F/F1.m",
])

let manifest = HeadersManifest(public: ["Sources/public/A/*.h", "Sources/public/B/*.h"],
private: ["Sources/private/C/*.h", "Sources/private/D/*.h"],
project: ["Sources/project/E/*.h", "Sources/project/F/*.h"])

// When
let model = TuistGenerator.Headers.from(manifest: manifest, path: path, fileHandler: fileHandler)

// Then
XCTAssertEqual(model.public, [
"Sources/public/A/A1.h",
"Sources/public/B/B1.h",
].map { fileHandler.currentPath.appending(RelativePath($0)) })

XCTAssertEqual(model.private, [
"Sources/private/C/C1.h",
"Sources/private/D/D1.h",
].map { fileHandler.currentPath.appending(RelativePath($0)) })

XCTAssertEqual(model.project, [
"Sources/project/E/E1.h",
"Sources/project/F/F1.h",
].map { fileHandler.currentPath.appending(RelativePath($0)) })
}

func test_headersStringAndArrayMix() throws {
// Given
try fileHandler.createFiles([
"Sources/public/A/A1.h",
"Sources/public/A/A1.m",

"Sources/project/C/C1.h",
"Sources/project/C/C1.m",
"Sources/project/D/D1.h",
"Sources/project/D/D1.m",
])

let manifest = HeadersManifest(public: "Sources/public/A/*.h",
project: ["Sources/project/C/*.h", "Sources/project/D/*.h"])

// When
let model = TuistGenerator.Headers.from(manifest: manifest, path: path, fileHandler: fileHandler)

// Then
XCTAssertEqual(model.public, [
"Sources/public/A/A1.h",
].map { fileHandler.currentPath.appending(RelativePath($0)) })

XCTAssertEqual(model.project, [
"Sources/project/C/C1.h",
"Sources/project/D/D1.h",
].map { fileHandler.currentPath.appending(RelativePath($0)) })
}

func test_coreDataModel() throws {
// Given
try fileHandler.touch(path.appending(component: "model.xcdatamodeld"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ extension Target {
productName: String? = nil,
bundleId: String = "com.some.bundle.id",
infoPlist: InfoPlist = .file(path: "Info.plist"),
sources: FileList = "Sources/**",
sources: SourceFilesList = "Sources/**",
resources: [FileElement] = "Resources/**",
headers: Headers? = nil,
entitlements: String? = "app.entitlements",
Expand Down
3 changes: 3 additions & 0 deletions docs/usage/1-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ let project = Project(name: "MyApp",
infoPlist: "Info.plist",
sources: ["Sources/**"],
resources: ["Resources/**"],
headers: Headers(public: ["Sources/public/A/**", "Sources/public/B/**"],
private: "Sources/private/**",
project: ["Sources/project/A/**", "Sources/project/B/**"]),
dependencies: [
/* Target dependencies can be defined here */
/* .framework(path: "framework") */
Expand Down
27 changes: 23 additions & 4 deletions docs/usage/project.swift.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ let project = Project(name: "MyProject",
resources: [
"Resources/**",
.folderReference(path: "Stubs")
],
],
headers: Headers(public: ["Sources/public/A/**", "Sources/public/B/**"],
private: "Sources/private/**",
project: ["Sources/project/A/**", "Sources/project/B/**"]),
dependencies: [
.project(target: "Framework1", path: "../Framework1"),
.project(target: "Framework2", path: "../Framework2")
Expand Down Expand Up @@ -304,27 +307,43 @@ It represents the target headers:
{
name: 'Public',
description: 'Relative glob pattern that points to the public headers',
type: 'String',
type: 'FileList',
optional: true,
default: 'nil',
},
{
name: 'Private',
description: 'Relative glob pattern that points to the private headers',
type: 'String',
type: 'FileList',
optional: true,
default: 'nil',
},
{
name: 'Project',
description: 'Relative glob pattern that points to the project headers',
type: 'String',
type: 'FileList',
optional: true,
default: 'nil',
},
]}
/>

## File List

It represents a list of glob patterns that refer to files:

<PropertiesTable
props={[
{
name: 'Globs',
description: 'Glob pattern to the files.',
type: '[String]',
optional: false,
default: '',
}
]}
/>

## Core Data Model

The `CoreDataModel` type represents a Core Data model:
Expand Down
13 changes: 13 additions & 0 deletions features/generate.feature
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ Feature: Generate a new project using Tuist
Then I should be able to build the scheme Framework1
Then the product 'Framework1.framework' with destination 'Debug-iphoneos' contains the Info.plist key 'Test'

Scenario: The project is an iOS application with headers (ios_app_with_headers)
Given that tuist is available
And I have a working directory
Then I copy the fixture ios_app_with_headers into the working directory
Then tuist generates the project
Then I should be able to build the scheme App
Then I should be able to test the scheme AppTests
Then I should be able to build the scheme Framework1-iOS
Then I should be able to build the scheme Framework1-macOS
Then I should be able to test the scheme Framework1Tests
Then I should be able to build the scheme MainApp_Manifest
Then I should be able to build the scheme Framework1_Manifest

Scenario: The project is a directory without valid manifest file (invalid_workspace_manifest_name)
Given that tuist is available
And I have a working directory
Expand Down
43 changes: 43 additions & 0 deletions fixtures/ios_app_with_headers/App/Config/App-Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright Tuist©. All rights reserved.</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>