yonaskolb / XcodeGen

A Swift command line tool for generating your Xcode project
MIT License
7.03k stars 818 forks source link

Enhancement: copyFiles buildPhase using Products #985

Open aerobounce opened 3 years ago

aerobounce commented 3 years ago

First thing first, let me show you concept:

Note that this is just a concept and is not a valid syntax

targets:
    Sample Application:
        type: application
        platform: macOS
        sources:
              target: Helper
              optional: true
              buildPhase:
                  copyFiles:
                      destination: wrapper
                      subpath: $(CONTENTS_FOLDER_PATH)/Library/LoginItems
    Helper:
        type: application
        platform: macOS

Back to xcodegen, if I'm correct, this is not possible as of v2.18.0 (Please correct me if I'm missing something). The above is just an example to explain the usefulness if it's possible. And this is not specific to the LoginItem thing, there may be other cases that can use this approach, I guess. Thus, "copyFiles buildPhase using Products". (I'm not sure if sources is the suitable location to put them, this is just a concept)

What do you think?

jsorge commented 3 years ago

I'd love to do something similar in my app where I want to have a helper CLI embedded in my app package, I'm just not sure how to do it yet. If this is possible with XcodeGen as it is today I'd love to learn it. To my mind having this be in the sources object feels really weird because it's not part of the sources of my target. I was looking more for a specific copyFiles object separate from the sources object.

FelixLisczyk commented 3 years ago

I would like to reference files from the product directory in my build phases as well. 👍

My current workaround for login items contains a post-build shell script, but there is probably a better solution.

LOGIN_ITEMS_DIR="$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Contents/Library/LoginItems"
rm -rf "$LOGIN_ITEMS_DIR"
mkdir -p "$LOGIN_ITEMS_DIR"
cp -a "$BUILT_PRODUCTS_DIR/Helper.app" "$LOGIN_ITEMS_DIR"
aerobounce commented 3 years ago

I'm using post-script to workaround this too.

However I've been thinking that I've had mischosen the repo to open this issue as XcodeGen relies on tuist/XcodeProj to parse project files. Did some research before and if I remember correctly, XcodeProj doesn't support treating a product as a file to use it to like, very this issue's situation.

jsorge commented 3 years ago

I've gotten this working by doing 2 things: 1) add embed: false to the app's dependency on the CLI, and 2) this build phase:

    postBuildScripts:
      - script: "ditto \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\""
        name: Copy CLI Helper
        inputFiles:
          - ${BUILT_PRODUCTS_DIR}/bindlewriter
        outputFiles:
          - ${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/Contents/Helpers/bindlewriter

Where in this case bindlewriter is the name of the CLI product that's being embedded inside of my app's bundle at Contents/Helpers. It's helpful for me when I run into situations like this to write the script in my generated project and then copy it in to the right spot in my manifest.

aerobounce commented 3 years ago

That's elegant! I like it. What I've reached in the end is far more verbose:

    dependencies: # This assures you the app will be copied into Resources dir
      - target: TARGET NAME OF THE HELPER APP

    postBuildScripts:
      - script: |
          set -Ceux
          HELPER_PRODUCT_NAME="TARGET NAME OF THE HELPER APP"
          CONTENTS_PATH="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}"
          RESOURCES_DIR="${CONTENTS_PATH}/Resources"
          LOGIN_ITEMS_DIR="${CONTENTS_PATH}/Library/LoginItems"
          ORIGIN_HELPER_PATH="${RESOURCES_DIR}/${HELPER_PRODUCT_NAME}.app"

          [[ -d $LOGIN_ITEMS_DIR ]] && rm -rfv "$LOGIN_ITEMS_DIR"
          mkdir -p "$LOGIN_ITEMS_DIR"
          mv -v "$ORIGIN_HELPER_PATH" "$LOGIN_ITEMS_DIR"

          [[ $(ls -A "$RESOURCES_DIR") ]] || rm -rfv "${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources"
        name: Move Helper.app to LoginItems

Then, create two main targets: One with the dependency and the script above, and the other without any dependency (for debugging). The benefit of this is you don't have to manually build helper app because it is a dependency.

jsorge commented 3 years ago

Yeah I really just mimicked how XcodeGen does other copy files stages and adopted that for my own need! :joy:

imWildCat commented 1 year ago

Hope this helps the future:

dependencies:
  - target: LanchAtLoginHelper
    embed: true
    codeSign: false
    copy:
      destination: wrapper
      subpath: Contents/Library/LoginItems