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

Adding support for resource folder references #318

Merged
merged 8 commits into from
Apr 8, 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 @@ -8,6 +8,7 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
### Added

- Adding support for project additional files https://github.com/tuist/tuist/pull/314 by @kwridan
- Adding support for resource folder references https://github.com/tuist/tuist/pull/318 by @kwridan

### Removed
### Fixed
Expand Down
16 changes: 16 additions & 0 deletions Sources/ProjectDescription/FileElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,19 @@ extension FileElement: ExpressibleByStringLiteral {
self = .glob(pattern: value)
}
}

extension Array: ExpressibleByUnicodeScalarLiteral where Element == FileElement {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘

public typealias UnicodeScalarLiteralType = String
}

extension Array: ExpressibleByExtendedGraphemeClusterLiteral where Element == FileElement {
public typealias ExtendedGraphemeClusterLiteralType = String
}

extension Array: ExpressibleByStringLiteral where Element == FileElement {
public typealias StringLiteralType = String

public init(stringLiteral value: String) {
self = [.glob(pattern: value)]
}
}
4 changes: 2 additions & 2 deletions Sources/ProjectDescription/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class Target: Codable {
public let sources: FileList?

/// Relative paths to the resources directory.
public let resources: FileList?
public let resources: [FileElement]?

/// Headers.
public let headers: Headers?
Expand Down Expand Up @@ -85,7 +85,7 @@ public class Target: Codable {
bundleId: String,
infoPlist: String,
sources: FileList? = nil,
resources: FileList? = nil,
resources: [FileElement]? = nil,
headers: Headers? = nil,
entitlements: String? = nil,
actions: [TargetAction] = [],
Expand Down
20 changes: 20 additions & 0 deletions Sources/TuistCoreTesting/Utils/MockFileHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,23 @@ public final class MockFileHandler: FileHandling {
return fileHandler.isFolder(path)
}
}

extension MockFileHandler {
@discardableResult
func createFiles(_ files: [String]) throws -> [AbsolutePath] {
let paths = files.map { currentPath.appending(RelativePath($0)) }
try paths.forEach {
try touch($0)
}
return paths
}

@discardableResult
func createFolders(_ folders: [String]) throws -> [AbsolutePath] {
let paths = folders.map { currentPath.appending(RelativePath($0)) }
try paths.forEach {
try createFolder($0)
}
return paths
}
}
2 changes: 1 addition & 1 deletion Sources/TuistGenerator/Generator/BuildPhaseGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ final class BuildPhaseGenerator: BuildPhaseGenerating {
fileElements: fileElements,
pbxproj: pbxproj)

try generateResourcesBuildPhase(files: target.resources,
try generateResourcesBuildPhase(files: target.resources.map(\.path),
coreDataModels: target.coreDataModels,
pbxTarget: pbxTarget,
fileElements: fileElements,
Expand Down
21 changes: 13 additions & 8 deletions Sources/TuistGenerator/Generator/ProjectFileElements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,7 @@ class ProjectFileElements {
var files = Set<GroupFileElement>()
var products = Set<String>()
project.targets.forEach { target in
let targetFilePaths = targetFiles(target: target)
let targetFileElements = targetFilePaths.map {
GroupFileElement(path: $0, group: target.filesGroup)
}
files.formUnion(targetFileElements)
files.formUnion(targetFiles(target: target))
products.formUnion(targetProducts(target: target))
}
let projectFileElements = projectFiles(project: project)
Expand Down Expand Up @@ -123,10 +119,9 @@ class ProjectFileElements {
return products
}

func targetFiles(target: Target) -> Set<AbsolutePath> {
func targetFiles(target: Target) -> Set<GroupFileElement> {
var files = Set<AbsolutePath>()
files.formUnion(target.sources)
files.formUnion(target.resources)
files.formUnion(target.coreDataModels.map { $0.path })
files.formUnion(target.coreDataModels.flatMap { $0.versions })

Expand All @@ -152,7 +147,17 @@ class ProjectFileElements {
if let releaseConfigFile = target.settings?.release?.xcconfig {
files.insert(releaseConfigFile)
}
return files

// Elements
var elements = Set<GroupFileElement>()
elements.formUnion(files.map { GroupFileElement(path: $0, group: target.filesGroup) })
elements.formUnion(target.resources.map {
GroupFileElement(path: $0.path,
group: target.filesGroup,
isReference: $0.isReference)
})

return elements
}

func generate(files: [GroupFileElement],
Expand Down
2 changes: 1 addition & 1 deletion Sources/TuistGenerator/Linter/TargetLinter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class TargetLinter: TargetLinting {
private func lintCopiedFiles(target: Target) -> [LintingIssue] {
var issues: [LintingIssue] = []

let files = target.resources
let files = target.resources.map(\.path)
let infoPlists = files.filter { $0.asString.contains("Info.plist") }
let entitlements = files.filter { $0.asString.contains(".entitlements") }

Expand Down
24 changes: 10 additions & 14 deletions Sources/TuistGenerator/Models/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class Target: Equatable {
public let settings: Settings?
public let dependencies: [Dependency]
public let sources: [AbsolutePath]
public let resources: [AbsolutePath]
public let resources: [FileElement]
public let headers: Headers?
public let coreDataModels: [CoreDataModel]
public let actions: [TargetAction]
Expand All @@ -39,7 +39,7 @@ public class Target: Equatable {
entitlements: AbsolutePath? = nil,
settings: Settings? = nil,
sources: [AbsolutePath] = [],
resources: [AbsolutePath] = [],
resources: [FileElement] = [],
headers: Headers? = nil,
coreDataModels: [CoreDataModel] = [],
actions: [TargetAction] = [],
Expand Down Expand Up @@ -90,18 +90,14 @@ public class Target: Equatable {
}
}

public static func resources(projectPath: AbsolutePath, resources: [String], fileHandler: FileHandling) throws -> [AbsolutePath] {
return resources.flatMap { source in
projectPath.glob(source).filter { path in
if !fileHandler.isFolder(path) {
return true
// We filter out folders that are not Xcode supported bundles such as .app or .framework.
} else if let `extension` = path.extension, Target.validFolderExtensions.contains(`extension`) {
return true
} else {
return false
}
}
public static func isResource(path: AbsolutePath, fileHandler: FileHandling) -> Bool {
if !fileHandler.isFolder(path) {
return true
// We filter out folders that are not Xcode supported bundles such as .app or .framework.
} else if let `extension` = path.extension, Target.validFolderExtensions.contains(`extension`) {
return true
} else {
return false
}
}

Expand Down
29 changes: 25 additions & 4 deletions Sources/TuistKit/Generator/GeneratorModelLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ extension TuistGenerator.FileElement {
static func from(manifest: ProjectDescription.FileElement,
path: AbsolutePath,
fileHandler: FileHandling,
printer: Printing) -> [TuistGenerator.FileElement] {
printer: Printing,
includeFiles: @escaping (AbsolutePath) -> Bool = { _ in true }) -> [TuistGenerator.FileElement] {
func globFiles(_ string: String) -> [AbsolutePath] {
let files = fileHandler.glob(path, glob: string)
.filter(includeFiles)

if files.isEmpty {
printer.print(warning: "No files found at: \(string)")
Expand Down Expand Up @@ -146,7 +148,12 @@ extension TuistGenerator.Project {
printer: Printing) throws -> TuistGenerator.Project {
let name = manifest.name
let settings = manifest.settings.map { TuistGenerator.Settings.from(manifest: $0, path: path) }
let targets = try manifest.targets.map { try TuistGenerator.Target.from(manifest: $0, path: path, fileHandler: fileHandler) }
let targets = try manifest.targets.map {
try TuistGenerator.Target.from(manifest: $0,
path: path,
fileHandler: fileHandler,
printer: printer)
}

let additionalFiles = manifest.additionalFiles.flatMap {
TuistGenerator.FileElement.from(manifest: $0,
Expand Down Expand Up @@ -174,7 +181,10 @@ extension TuistGenerator.Project {
}

extension TuistGenerator.Target {
static func from(manifest: ProjectDescription.Target, path: AbsolutePath, fileHandler: FileHandling) throws -> TuistGenerator.Target {
static func from(manifest: ProjectDescription.Target,
path: AbsolutePath,
fileHandler: FileHandling,
printer: Printing) throws -> TuistGenerator.Target {
let name = manifest.name
let platform = try TuistGenerator.Platform.from(manifest: manifest.platform)
let product = TuistGenerator.Product.from(manifest: manifest.product)
Expand All @@ -188,7 +198,18 @@ extension TuistGenerator.Target {
let settings = manifest.settings.map { TuistGenerator.Settings.from(manifest: $0, path: path) }

let sources = try TuistGenerator.Target.sources(projectPath: path, sources: manifest.sources?.globs ?? [], fileHandler: fileHandler)
let resources = try TuistGenerator.Target.resources(projectPath: path, resources: manifest.resources?.globs ?? [], fileHandler: fileHandler)

let resourceFilter = { (path: AbsolutePath) -> Bool in
TuistGenerator.Target.isResource(path: path, fileHandler: fileHandler)
}
let resources = (manifest.resources ?? []).flatMap {
TuistGenerator.FileElement.from(manifest: $0,
path: path,
fileHandler: fileHandler,
printer: printer,
includeFiles: resourceFilter)
}

let headers = manifest.headers.map { TuistGenerator.Headers.from(manifest: $0, path: path, fileHandler: fileHandler) }

let coreDataModels = try manifest.coreDataModels.map {
Expand Down
6 changes: 3 additions & 3 deletions Tests/ProjectDescriptionTests/TargetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class TargetTests: XCTestCase {
coreDataModels: [CoreDataModel("pat", currentVersion: "version")],
environment: ["a": "b"])

let expected = "{\"bundle_id\": \"bundle_id\", \"core_data_models\": [{\"current_version\": \"version\", \"path\": \"pat\"}], \"dependencies\": [{\"path\": \"path\", \"type\": \"framework\"}, {\"path\": \"path\", \"public_headers\": \"public\", \"swift_module_map\": \"module\", \"type\": \"library\"}, {\"path\": \"path\", \"target\": \"target\", \"type\": \"project\"}, {\"name\": \"name\", \"type\": \"target\"}], \"entitlements\": \"entitlement\", \"headers\": {\"private\": \"private/*\", \"project\": \"project/*\", \"public\": \"public/*\"}, \"info_plist\": \"info.plist\", \"name\": \"name\", \"platform\": \"ios\", \"product\": \"app\", \"resources\": {\"globs\": [\"resources/*\"]}, \"settings\": {\"base\": {\"a\": \"b\"}, \"debug\": {\"settings\": {\"a\": \"b\"}, \"xcconfig\": \"config\"}, \"release\": {\"settings\": {\"a\": \"b\"}, \"xcconfig\": \"config\"}}, \"sources\": {\"globs\": [\"sources/*\"]}, \"actions\": [ { \"path\": \"path\", \"arguments\": [\"arg\"], \"name\": \"name\", \"order\": \"post\"}], \"environment\": {\"a\": \"b\"}}"
let expected = "{\"headers\":{\"public\":\"public\\/*\",\"private\":\"private\\/*\",\"project\":\"project\\/*\"},\"bundle_id\":\"bundle_id\",\"core_data_models\":[{\"path\":\"pat\",\"current_version\":\"version\"}],\"actions\":[{\"arguments\":[\"arg\"],\"path\":\"path\",\"order\":\"post\",\"name\":\"name\"}],\"product\":\"app\",\"sources\":{\"globs\":[\"sources\\/*\"]},\"settings\":{\"base\":{\"a\":\"b\"},\"debug\":{\"xcconfig\":\"config\",\"settings\":{\"a\":\"b\"}},\"release\":{\"xcconfig\":\"config\",\"settings\":{\"a\":\"b\"}}},\"resources\":[{\"type\":\"glob\",\"pattern\":\"resources\\/*\"}],\"platform\":\"ios\",\"entitlements\":\"entitlement\",\"info_plist\":\"info.plist\",\"dependencies\":[{\"type\":\"framework\",\"path\":\"path\"},{\"path\":\"path\",\"public_headers\":\"public\",\"swift_module_map\":\"module\",\"type\":\"library\"},{\"type\":\"project\",\"target\":\"target\",\"path\":\"path\"},{\"type\":\"target\",\"name\":\"name\"}],\"environment\":{\"a\":\"b\"},\"name\":\"name\"}"
assertCodableEqualToJson(subject, expected)
}

Expand All @@ -43,7 +43,7 @@ final class TargetTests: XCTestCase {
bundleId: "bundle_id",
infoPlist: "info.plist",
sources: FileList(globs: ["sources/*"]),
resources: FileList(globs: ["resources/*"]),
resources: ["resources/*"],
headers: Headers(public: "public/*",
private: "private/*",
project: "project/*"),
Expand All @@ -65,7 +65,7 @@ final class TargetTests: XCTestCase {
coreDataModels: [CoreDataModel("pat", currentVersion: "version")],
environment: ["a": "b"])

let expected = "{\"bundle_id\": \"bundle_id\", \"core_data_models\": [{\"current_version\": \"version\", \"path\": \"pat\"}], \"dependencies\": [{\"path\": \"path\", \"type\": \"framework\"}, {\"path\": \"path\", \"public_headers\": \"public\", \"swift_module_map\": \"module\", \"type\": \"library\"}, {\"path\": \"path\", \"target\": \"target\", \"type\": \"project\"}, {\"name\": \"name\", \"type\": \"target\"}], \"entitlements\": \"entitlement\", \"headers\": {\"private\": \"private/*\", \"project\": \"project/*\", \"public\": \"public/*\"}, \"info_plist\": \"info.plist\", \"name\": \"name\", \"platform\": \"ios\", \"product\": \"app\", \"resources\": {\"globs\": [\"resources/*\"]}, \"settings\": {\"base\": {\"a\": \"b\"}, \"debug\": {\"settings\": {\"a\": \"b\"}, \"xcconfig\": \"config\"}, \"release\": {\"settings\": {\"a\": \"b\"}, \"xcconfig\": \"config\"}}, \"sources\": {\"globs\": [\"sources/*\"]}, \"actions\": [ { \"path\": \"path\", \"arguments\": [\"arg\"], \"name\": \"name\", \"order\": \"post\"}], \"environment\": {\"a\": \"b\"}}"
let expected = "{\"headers\":{\"public\":\"public\\/*\",\"private\":\"private\\/*\",\"project\":\"project\\/*\"},\"bundle_id\":\"bundle_id\",\"core_data_models\":[{\"path\":\"pat\",\"current_version\":\"version\"}],\"actions\":[{\"arguments\":[\"arg\"],\"path\":\"path\",\"order\":\"post\",\"name\":\"name\"}],\"product\":\"app\",\"sources\":{\"globs\":[\"sources\\/*\"]},\"settings\":{\"base\":{\"a\":\"b\"},\"debug\":{\"xcconfig\":\"config\",\"settings\":{\"a\":\"b\"}},\"release\":{\"xcconfig\":\"config\",\"settings\":{\"a\":\"b\"}}},\"resources\":[{\"type\":\"glob\",\"pattern\":\"resources\\/*\"}],\"platform\":\"ios\",\"entitlements\":\"entitlement\",\"info_plist\":\"info.plist\",\"dependencies\":[{\"type\":\"framework\",\"path\":\"path\"},{\"path\":\"path\",\"public_headers\":\"public\",\"swift_module_map\":\"module\",\"type\":\"library\"},{\"type\":\"project\",\"target\":\"target\",\"path\":\"path\"},{\"type\":\"target\",\"name\":\"name\"}],\"environment\":{\"a\":\"b\"},\"name\":\"name\"}"
assertCodableEqualToJson(subject, expected)
}
}
39 changes: 22 additions & 17 deletions Tests/TuistGeneratorTests/Generator/ProjectFileElementsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import XCTest
@testable import TuistGenerator

final class ProjectFileElementsTests: XCTestCase {
typealias FileElement = ProjectFileElements.GroupFileElement
typealias GroupFileElement = ProjectFileElements.GroupFileElement

var subject: ProjectFileElements!
var fileHandler: MockFileHandler!
Expand Down Expand Up @@ -36,10 +36,10 @@ final class ProjectFileElementsTests: XCTestCase {

// Then
XCTAssertTrue(files.isSuperset(of: [
FileElement(path: "/project/debug.xcconfig", group: project.filesGroup),
FileElement(path: "/project/release.xcconfig", group: project.filesGroup),
FileElement(path: "/path/to/file", group: project.filesGroup),
FileElement(path: "/path/to/folder", group: project.filesGroup, isReference: true),
GroupFileElement(path: "/project/debug.xcconfig", group: project.filesGroup),
GroupFileElement(path: "/project/release.xcconfig", group: project.filesGroup),
GroupFileElement(path: "/path/to/file", group: project.filesGroup),
GroupFileElement(path: "/path/to/folder", group: project.filesGroup, isReference: true),
]))
}

Expand All @@ -63,7 +63,10 @@ final class ProjectFileElementsTests: XCTestCase {
entitlements: AbsolutePath("/project/app.entitlements"),
settings: settings,
sources: [AbsolutePath("/project/file.swift")],
resources: [AbsolutePath("/project/image.png")],
resources: [
.file(path: AbsolutePath("/project/image.png")),
.folderReference(path: AbsolutePath("/project/reference")),
],
coreDataModels: [CoreDataModel(path: AbsolutePath("/project/model.xcdatamodeld"),
versions: [AbsolutePath("/project/model.xcdatamodeld/1.xcdatamodel")],
currentVersion: "1")],
Expand All @@ -73,16 +76,18 @@ final class ProjectFileElementsTests: XCTestCase {
dependencies: [])

let files = subject.targetFiles(target: target)

XCTAssertTrue(files.contains(AbsolutePath("/project/debug.xcconfig")))
XCTAssertTrue(files.contains(AbsolutePath("/project/release.xcconfig")))
XCTAssertTrue(files.contains(AbsolutePath("/project/file.swift")))
XCTAssertTrue(files.contains(AbsolutePath("/project/image.png")))
XCTAssertTrue(files.contains(AbsolutePath("/project/public.h")))
XCTAssertTrue(files.contains(AbsolutePath("/project/project.h")))
XCTAssertTrue(files.contains(AbsolutePath("/project/private.h")))
XCTAssertTrue(files.contains(AbsolutePath("/project/model.xcdatamodeld/1.xcdatamodel")))
XCTAssertTrue(files.contains(AbsolutePath("/project/model.xcdatamodeld")))
XCTAssertTrue(files.isSuperset(of: [
GroupFileElement(path: "/project/debug.xcconfig", group: target.filesGroup),
GroupFileElement(path: "/project/release.xcconfig", group: target.filesGroup),
GroupFileElement(path: "/project/file.swift", group: target.filesGroup),
GroupFileElement(path: "/project/image.png", group: target.filesGroup),
GroupFileElement(path: "/project/reference", group: target.filesGroup, isReference: true),
GroupFileElement(path: "/project/public.h", group: target.filesGroup),
GroupFileElement(path: "/project/project.h", group: target.filesGroup),
GroupFileElement(path: "/project/private.h", group: target.filesGroup),
GroupFileElement(path: "/project/model.xcdatamodeld/1.xcdatamodel", group: target.filesGroup),
GroupFileElement(path: "/project/model.xcdatamodeld", group: target.filesGroup),
]))
}

func test_generateProduct() {
Expand Down Expand Up @@ -190,7 +195,7 @@ final class ProjectFileElementsTests: XCTestCase {
// Given
let pbxproj = PBXProj()
let path = AbsolutePath("/a/b/c/file.swift")
let fileElement = FileElement(path: path, group: .group(name: "SomeGroup"))
let fileElement = GroupFileElement(path: path, group: .group(name: "SomeGroup"))
let project = Project.test(filesGroup: .group(name: "SomeGroup"))
let sourceRootPath = AbsolutePath("/a/project/")
let groups = ProjectGroups.generate(project: project,
Expand Down