Fixing header paths including folders and non-header files (#356)
Resolves https://github.com/tuist/tuist/issues/352 - Specifying a permissive glob pattern (e.g. `Headers/**`) for headers would incorrectly include all files and folders as headers - Limiting the paths to header files resolves this issue - Adding Objective-C classes to test out headers within the fixtures Test Plan: - Verify unit tests pass via `swift build` - Verify acceptance tests pass via `bundle exec rake features` - Manually generate `fixtures/ios_app_with_frameworks` via `tuist generate` - Verify `Framework2` has the appropriate public, private & project headers set
This commit is contained in:
parent
d7e7c2f9f5
commit
47118ec48f
|
@ -21,6 +21,7 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
|
|||
- Updating init template to avoid warnings https://github.com/tuist/tuist/pull/339 by @kwridan
|
||||
- Fixing generation failures due to asset catalog & `**/*.png` glob patterns handling https://github.com/tuist/tuist/pull/346 by @kwridan
|
||||
- Supporting bundle target dependencies that reside in different projects (in `TuistGenerator`) https://github.com/tuist/tuist/pull/348 by @kwridan
|
||||
- Fixing header paths including folders and non-header files https://github.com/tuist/tuist/pull/356 by @kwridan
|
||||
|
||||
## 0.14.0
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import XcodeProj
|
|||
|
||||
/// Headers
|
||||
public class Headers: Equatable {
|
||||
public static let extensions = Xcode.headersExtensions
|
||||
|
||||
// MARK: - Attributes
|
||||
|
||||
public let `public`: [AbsolutePath]
|
||||
|
|
|
@ -156,7 +156,7 @@ extension TuistGenerator.Project {
|
|||
}
|
||||
|
||||
let schemes = manifest.schemes.map { TuistGenerator.Scheme.from(manifest: $0) }
|
||||
|
||||
|
||||
let additionalFiles = manifest.additionalFiles.flatMap {
|
||||
TuistGenerator.FileElement.from(manifest: $0,
|
||||
path: path,
|
||||
|
@ -296,11 +296,22 @@ extension TuistGenerator.CoreDataModel {
|
|||
|
||||
extension TuistGenerator.Headers {
|
||||
static func from(manifest: ProjectDescription.Headers, path: AbsolutePath, fileHandler: FileHandling) -> TuistGenerator.Headers {
|
||||
let `public` = manifest.public.map { fileHandler.glob(path, glob: $0) } ?? []
|
||||
let `private` = manifest.private.map { fileHandler.glob(path, glob: $0) } ?? []
|
||||
let project = manifest.project.map { fileHandler.glob(path, glob: $0) } ?? []
|
||||
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) } ?? []
|
||||
return Headers(public: `public`, private: `private`, project: project)
|
||||
}
|
||||
|
||||
private static func headerFiles(path: AbsolutePath,
|
||||
glob: String,
|
||||
fileHandler: FileHandling) -> [AbsolutePath] {
|
||||
return fileHandler.glob(path, glob: glob).filter {
|
||||
if let `extension` = $0.extension, Headers.extensions.contains(".\(`extension`)") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TuistGenerator.Dependency {
|
||||
|
|
|
@ -348,34 +348,45 @@ class GeneratorModelLoaderTest: XCTestCase {
|
|||
|
||||
func test_headers() throws {
|
||||
// Given
|
||||
let publicPath = path.appending(component: "public")
|
||||
try fileHandler.createFolder(publicPath)
|
||||
try fileHandler.touch(publicPath.appending(component: "a.h"))
|
||||
try fileHandler.touch(publicPath.appending(component: "b.h"))
|
||||
try fileHandler.createFiles([
|
||||
"Sources/public/A1.h",
|
||||
"Sources/public/A1.m",
|
||||
"Sources/public/A2.h",
|
||||
"Sources/public/A2.m",
|
||||
|
||||
let projectPath = path.appending(component: "project")
|
||||
try fileHandler.createFolder(projectPath)
|
||||
try fileHandler.touch(projectPath.appending(component: "c.h"))
|
||||
"Sources/private/B1.h",
|
||||
"Sources/private/B1.m",
|
||||
"Sources/private/B2.h",
|
||||
"Sources/private/B2.m",
|
||||
|
||||
let privatePath = path.appending(component: "private")
|
||||
try fileHandler.createFolder(privatePath)
|
||||
"Sources/project/C1.h",
|
||||
"Sources/project/C1.m",
|
||||
"Sources/project/C2.h",
|
||||
"Sources/project/C2.m",
|
||||
])
|
||||
|
||||
let manifest = HeadersManifest(public: "public/*.h", private: "private/*.h", project: "project/*.h")
|
||||
let manifest = HeadersManifest(public: "Sources/public/**",
|
||||
private: "Sources/private/**",
|
||||
project: "Sources/project/**")
|
||||
|
||||
// When
|
||||
let model = TuistGenerator.Headers.from(manifest: manifest, path: path, fileHandler: fileHandler)
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(model.public, [
|
||||
publicPath.appending(component: "a.h"),
|
||||
publicPath.appending(component: "b.h"),
|
||||
])
|
||||
"Sources/public/A1.h",
|
||||
"Sources/public/A2.h",
|
||||
].map { fileHandler.currentPath.appending(RelativePath($0)) })
|
||||
|
||||
XCTAssertEqual(model.private, [
|
||||
"Sources/private/B1.h",
|
||||
"Sources/private/B2.h",
|
||||
].map { fileHandler.currentPath.appending(RelativePath($0)) })
|
||||
|
||||
XCTAssertEqual(model.project, [
|
||||
projectPath.appending(component: "c.h"),
|
||||
])
|
||||
|
||||
XCTAssertEqual(model.private, [])
|
||||
"Sources/project/C1.h",
|
||||
"Sources/project/C2.h",
|
||||
].map { fileHandler.currentPath.appending(RelativePath($0)) })
|
||||
}
|
||||
|
||||
func test_coreDataModel() throws {
|
||||
|
|
|
@ -114,9 +114,9 @@ Each target in the list of project targets can be initialized with the following
|
|||
- **[String]:** A list of files or list of glob patterns _(e.g. `["Sources/**"]`)_
|
||||
- **Resources (optional):** List of [FileElement](#FileElement)s to include in the resource build phase.
|
||||
- **Headers (optional):** Target headers. It accepts a `Header` type that is initialized with the following attributes:
|
||||
- **Public:** Relative path to the folder that contains the public headers.
|
||||
- **Private:** Relative path to the folder that contains the private headers.
|
||||
- **Project:** Relative path to the folder that contains the project headers.
|
||||
- **Public:** Relative path or glob pattern to the public headers _(e.g. `Sources/Public/**`)_
|
||||
- **Private:** Relative path or glob pattern to the private headers _(e.g. `Sources/Private/**`)_
|
||||
- **Project:** Relative path or glob pattern to the project headers _(e.g. `Sources/Project/**`)_
|
||||
- **Entitlements (optional):** Relative path to the entitlements file.
|
||||
- **Actions (optional):** Target actions allow defining extra script build phases. It's an array of `TargetAction` objects that that can be of type `pre` and `post`:
|
||||
- **pre:** Executed before the target-specific build phases.
|
||||
|
|
|
@ -9,11 +9,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
func applicationDidFinishLaunching(_: UIApplication) {
|
||||
let framework1 = Framework1File()
|
||||
let framework2 = Framework2File()
|
||||
let framework2Objc = MyPublicClass()
|
||||
|
||||
print(hello())
|
||||
print("AppDelegate -> \(framework1.hello())")
|
||||
print("AppDelegate -> \(framework1.helloFromFramework2())")
|
||||
print("AppDelegate -> \(framework2.hello())")
|
||||
print("AppDelegate -> \(framework2Objc.hello())")
|
||||
}
|
||||
|
||||
func hello() -> String {
|
||||
|
|
|
@ -8,6 +8,9 @@ let project = Project(name: "Framework2",
|
|||
bundleId: "io.tuist.Framework2",
|
||||
infoPlist: "Config/Framework2-Info.plist",
|
||||
sources: "Sources/**",
|
||||
headers: Headers(public: "Sources/Public/**",
|
||||
private: "Sources/Private/**",
|
||||
project: "Sources/Project/**"),
|
||||
dependencies: []),
|
||||
|
||||
Target(name: "Framework2Tests",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MyPrivateClass : NSObject
|
||||
|
||||
- (NSString *)hello;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#import "MyPrivateClass.h"
|
||||
|
||||
@implementation MyPrivateClass
|
||||
|
||||
- (NSString *)hello
|
||||
{
|
||||
return @"MyPrivateClass.hello";
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MyProjectClass : NSObject
|
||||
|
||||
- (NSString *)hello;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#import "MyProjectClass.h"
|
||||
|
||||
@implementation MyProjectClass
|
||||
|
||||
- (NSString *)hello
|
||||
{
|
||||
return @"MyProjectClass.hello";
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
#import <Framework2/MyPublicClass.h>
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MyPublicClass : NSObject
|
||||
|
||||
- (NSString *)hello;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#import "MyPublicClass.h"
|
||||
|
||||
@implementation MyPublicClass
|
||||
|
||||
- (NSString *)hello
|
||||
{
|
||||
return @"MyPublicClass.hello";
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,10 @@
|
|||
import XCTest
|
||||
@testable import Framework2
|
||||
|
||||
class MyPublicClassTests: XCTestCase {
|
||||
func testHello() {
|
||||
let sut = MyPublicClass()
|
||||
|
||||
XCTAssertEqual("MyPublicClass.hello", sut.hello())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue