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

Add support for Copy Files build phase #345

Merged
merged 4 commits into from
Jul 31, 2018

Conversation

brentleyjones
Copy link
Collaborator

Related to #344, this allows manually setting up Copy Files build phases.

case .none: return nil
}
}
}

public struct CopyFiles: Equatable, Hashable {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thinking about this, maybe this should be called CopyFilesBuildPhaseSettings. I know it's longer, but I think it makes it clear what it's for.

- `none` - Will not be added to any build phases
- [ ] **copyFiles**: **[Copy Files](#copy-files)** - Options for the Copy Files build phase. If specified the `buildPhase` needs to be `copyFiles` or unspecified (in which case it will default to `copyFiles`).
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Instead of this I could make it so when you specify copyFiles for buildPhase you have to do it as an object:

- buildPhase:
    type: copyFiles
    destination: productsDirectory
    subpath: include/$(PRODUCT_NAME)

This might complicate it too much though, which is why I went the route I did.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also, I believe the way people will specify this is just by using the copyFiles object and not specifying a buildPhase manually.

@@ -74,6 +74,10 @@ extension Project {
if !source.optional && !sourcePath.exists {
errors.append(.invalidTargetSource(target: target.name, source: sourcePath.string))
}

if let buildPhase = source.buildPhase, buildPhase != .copyFiles, source.copyFiles != nil {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I need this to also pick up the case when build phase is copyFiles but a copyFiles section doesn't exist.

@@ -12,6 +12,7 @@ public struct TargetSource: Equatable {
public var type: SourceType?
public var optional: Bool
public var buildPhase: BuildPhase?
public var copyFiles: CopyFiles?
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Instead of adding another field, I’m going to make BuildPhase have an associated value. It makes my follow up PR easier as well as cleaning up the paths that don’t care about copyFiles.

Copy link
Collaborator

@toshi0383 toshi0383 left a comment

Choose a reason for hiding this comment

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

Great!

@brentleyjones
Copy link
Collaborator Author

I'll update CHANGELOG.md soon. I keep forgetting about that step.

@brentleyjones
Copy link
Collaborator Author

@yonaskolb Not sure on the protocol here. Is this fine for me to merge?

@yonaskolb
Copy link
Owner

There were just a couple of comments I wanted to make. Just on the road at the moment, but will get to them all tomorrow 😀👍

dstSubfolderSpec: copyFiles.destination.destination,
files: buildPhaseFiles
)
let copyFilesBuildPhase = createObject(id: target.name, buildPhase)
Copy link
Owner

Choose a reason for hiding this comment

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

Can the id include string copy files similar to the other PBXCopyFilesBuildPhases. That makes the resulting UUID handle clashes for when there is more than one PBXCopyFilesBuildPhase

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I’ll adjust 🙂.

case none
// Not currently exposed as selectable options, but here to translate to PBXCopyFilesBuildPhase completely
case frameworks
Copy link
Owner

Choose a reason for hiding this comment

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

Do we need these in here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, since this type is now used where xcproj ones were before, to allow defaulting to work correctly (see the modulemap PR for an example).


public var buildPhase: xcproj.BuildPhase? {
switch self {
case .sources: return .sources
case .headers: return .headers
case .resources: return .resources
case .copyFiles(_): return .copyFiles
Copy link
Owner

Choose a reason for hiding this comment

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

nitpick: we don't need the (_). This would probably get removed by make format_code anyway, so not really an issue

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I did it without and got an error. I’ll try again.

guard case let .copyFiles(copyFilesSettings)? = sourceFile.buildPhase else { continue }
var sourceFilesForCopyFiles = sourceFilesByCopyFiles[copyFilesSettings] ?? []
sourceFilesForCopyFiles.append(sourceFile)
sourceFilesByCopyFiles[copyFilesSettings] = sourceFilesForCopyFiles
Copy link
Owner

Choose a reason for hiding this comment

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

You can use Swift 4's new dictionary accessors:

sourceFilesByCopyFiles[copyFilesSettings, default: []].append(sourceFile)

if let string = string {
chosenString = string
} else if copyFilesSettings != nil {
chosenString = "copyFiles"
Copy link
Owner

Choose a reason for hiding this comment

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

The downside of this is that if they have a TargetSource with mixed files, there's no way to just specify the settings for the ones that will be in copyFiles by default, because if you do that everything will be moved to the copyFiles build phase.
I would be ok with keeping the copyFiles struct out of the enum like you had it before. The validation error could then be thrown in the generator when searching through the files and finding any copyFiles build phase SourceFiles (like modulemap) and it not having a copyFiles settings.

Are there other sorts of files you would want to add to copyFiles, or is it just modulemap?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Header files in the case of static libraries.

Let me think about your downside comment. When I had it different before it would default the whole sources to the copy files build phase, and the way I see you recommending it is that if it were determined to need to be copied it should use these settings. Right now I’m treating it exactly like all the other build phases and if specified they override any default logic. This phase just happens to require additional configuration options.

@@ -279,10 +281,31 @@ targets:
- "-Wextra"
- path: MyOtherTargetSource3
compilerFlags: "-Werror -Wextra"
- path: ModuleMaps
copyFiles:
Copy link
Owner

Choose a reason for hiding this comment

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

indentation

@brentleyjones brentleyjones force-pushed the modulemap branch 2 times, most recently from 68b1cb4 to 0bb4dd5 Compare July 23, 2018 13:24
@brentleyjones
Copy link
Collaborator Author

@yonaskolb I adressed all your feedback, expect for
#345 (comment). With that I changed the structure so copyFiles is simply an object specified for buildPhase. It's only special in the sense that it has additional required fields to be specified. It behaves the same as all the other build phases, if you specify it you mean it for all of the files (so use excludes or be specific). Defaults will be handled by #346 and a PR I plan on making soon for static library headers.

@yonaskolb
Copy link
Owner

Cool, I'll take a look later 😄👍
In the future if a PR has been reviewed could you add new commits instead of rebasing? It makes it easier to see the changes since reviewing. We always have the option of squashing on merge if there are lots of commits

@brentleyjones
Copy link
Collaborator Author

Will do! I'll add commits next time (I rebased a couple other PRs, sorry, I won't in the future).

@yonaskolb
Copy link
Owner

Also I should clarify. It's ok to rebase off the target branch to get new changes, but I meant not amending or squashing new commits 👍

@brentleyjones
Copy link
Collaborator Author

@yonaskolb Rebased and ready to go.

- `sharedSupport`
- `plugins`
- [x] **subpath**: **String** - The path inside of the destination to copy the files.
- [x] **subpath**: **String** - The path inside of the destination to copy the files.
Copy link
Owner

Choose a reason for hiding this comment

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

duplicate line

case none
// Not currently exposed as selectable options, but used internally
case frameworks
Copy link
Owner

Choose a reason for hiding this comment

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

indenting

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@yonaskolb I’m not sure what you are referring to here. Do you want a newline before the comment, the comment to be indented differently, or something else?

Copy link
Owner

Choose a reason for hiding this comment

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

Hmm, it's not showing up now. I swear case frameworks looked indented differently before

let copyFilesBuildPhase = createObject(
id: "copy files" + copyFiles.destination.rawValue + copyFiles.subpath + target.name,
PBXCopyFilesBuildPhase(
dstPath: copyFiles.subpath,
Copy link
Owner

Choose a reason for hiding this comment

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

I guess you've tested if a the default subpath of "" is valid, as opposed to nil? As the value is optional in PBXCopyFilesBuildPhase. Just trying to minimise diffs when projects are opened in Xcode

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I’ll reaffirm.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The default is "". If you don't specify it, it won't exist, which is still valid, but to match what Xcode does naturally it's "" specified. Xcode won't change when opening either way.

Copy link
Owner

Choose a reason for hiding this comment

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

👍
Sometimes Xcode won't change the project on open, but if something else changes (like reordering some files is an easy way to test), then it will rewrite things in it's preferred way


public init(jsonDictionary: JSONDictionary) throws {
destination = try jsonDictionary.json(atKeyPath: "destination")
subpath = jsonDictionary.json(atKeyPath: "subpath") ?? ""
Copy link
Owner

Choose a reason for hiding this comment

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

Would the default be nil?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll adjust the docs to say it's optional. We should still default it to "" though to match Xcode behavior (there isn't a way to make it not "" by using just Xcode).

@@ -5,6 +5,7 @@ public enum SpecParsingError: Error, CustomStringConvertible {
case unknownTargetPlatform(String)
case invalidDependency([String: Any])
case unknownSourceBuildPhase(String)
case invalidSourceCopyFilesPhase
Copy link
Owner

Choose a reason for hiding this comment

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

This might get unwieldy if we add more build phase enum options. Can we just used the existing unknownSourceBuildPhase but renamed to invalidSourceBuildPhase along with the error. Then the string can be copyFiles must be a dictionary

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep. I’ll adjust.

Consolidate `.unknownSourceBuildPhase` and `.invalidSourceCopyFilesPhase` into one.
@brentleyjones
Copy link
Collaborator Author

@yonaskolb All feedback addressed besides for the indentation one (I left a question). This is G2G 😄.

@@ -260,21 +260,33 @@ A source can be provided via a string (the path) or an object of the form:
- `sources` - Compile Sources phase
- `resources` - Copy Bundle Resources phase
- `headers` - Headers Phase
- `none` - Will not be added to any build phases
Copy link
Owner

Choose a reason for hiding this comment

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

Has none been removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No. I’m not sure how that happened. I’ll fix it.

case "headers": self = .headers
case "resources": self = .resources
case "copyFiles":
throw SpecParsingError.invalidSourceBuildPhase("copyFiles must specify directory")
Copy link
Owner

@yonaskolb yonaskolb Jul 31, 2018

Choose a reason for hiding this comment

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

Should this be copyFiles must specify a \"destination\" and optional \"subpath\"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, that's more descriptive.

throw SpecParsingError.invalidSourceBuildPhase("copyFiles must specify directory")
case "none": self = .none
default:
throw SpecParsingError.invalidSourceBuildPhase("Unknown build phase \(string.quoted)")
Copy link
Owner

Choose a reason for hiding this comment

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

I guess this can just be the string

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

👍

@yonaskolb
Copy link
Owner

Feel free to merge

@brentleyjones brentleyjones merged commit 717c899 into yonaskolb:master Jul 31, 2018
@brentleyjones brentleyjones deleted the modulemap branch July 31, 2018 13:02
@yonaskolb
Copy link
Owner

Nice work @brentleyjones! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants