13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

XcodeGenを導入してハマったこと

Last updated at Posted at 2019-01-10

何かあったら追記していくかも

ブランチを切り替える際にファイルが追加/削除されていてもプロジェクトに反映されない

まあproject.pbxが管理されないので当然である(
とはいえgit checkoutを走らせる度に毎回XcodeGenとpod install走らせるのめんどい

そこでGit hooksなる仕組みを発見したのでこれを使うことにしました

.git/hooks/post-checkout
#!/bin/sh

# エラーになった時点で終了
set -e

echo "Post Checkout"
/usr/local/bin/mint run xcodegen
/usr/local/bin/pod install

これでgit checkoutの度に自動でプロジェクト構成を更新してくれるようになりました。

ちなみになぜmintpodをフルパスで書いてるかって言うと、GUIツールでブランチを切り替える時にPATHがターミナル実行時と違うために、/usr/local/binがPATHとして認識されなかったためです。
(SourceTreeも使うのでその度にエラー吐かれて鬱陶しい)

$ gout
Switched to branch 'hoge'
Post Checkout
🌱  XcodeGen 2.1.0 already installed
🌱  Running xcodegen 2.1.0...
(中略)
Analyzing dependencies
Downloading dependencies
(中略)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 11 dependencies from the Podfile and 14 total pods installed.

2020/02/13 追記

本当に毎回走られると流石に鬱陶しくなってくるので、git checkout時にcheckout前後の差分に応じて走らせるようにしてみました。

post-checkout
#!/bin/zsh

# エラーになった時点で終了
set -e

# GUIツール対策
PATH=$HOME/.rbenv/shims:/usr/local/bin:$PATH

PREV_COMMIT=$1
POST_COMMIT=$2

DIFF=$(git diff $PREV_COMMIT..$POST_COMMIT --name-status --diff-filter=ADR | grep -e project.yml -e .swift)
if [[ $DIFF != "" ]]; then
    while read line
    do
        echo "$line"
    done <<END
    $DIFF
END
    mint run xcodegen
    pod install
fi

CI上でR.swift等の自動生成系がコケる

project.pbxが(ry

最初のアプローチ
ビルドスクリプト自体は
*project.yml*
project.yml
    preBuildScripts:
      - name: Lint
        script: |
                if which swiftlint >/dev/null; then
                swiftlint
                else
                echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
                fi
      - name: BuildConfig.swift
        script: |
                if [ "${CONFIGURATION}" = 'Release' ]; then
                ENVIRONMENT='production'
                else
                ENVIRONMENT='staging'
                fi
                ${PODS_ROOT}/BuildConfig.swift/buildconfigswift -o ${SRCROOT}/Libs/BuildConfig_swift -e $ENVIRONMENT ${SRCROOT}/Resources/Config
        inputFiles:
          - $(TEMP_DIR)/buildconfigswift-lastrun
        outputFiles:
          - $(SRCROOT)/Libs/BuildConfig_swift/BuildConfig.generated.swift
          - $(SRCROOT)/Libs/BuildConfig_swift/BuildConfig.plist
      - name: R.swift
        script: ${PODS_ROOT}/R.swift/rswift generate ${SRCROOT}/Libs/R_swift/R.generated.swift
        inputFiles:
          - $(TEMP_DIR)/rswift-lastrun
        outputFiles:
          - $(SRCROOT)/Libs/R_swift/R.generated.swift
で定義していたので、

outputFilesに合わせて初期化用のlaneを作り、そこで自動生成ファイルを先に作るようにしました

Fastfile
  desc "Initialize project"
  lane :init_project do
    lib_dir = 'Libs'
    sh("cd .. && mkdir -p #{lib_dir}/R_swift #{lib_dir}/BuildConfig_swift && touch #{lib_dir}/R_swift/R.generated.swift #{lib_dir}/BuildConfig_swift/BuildConfig.generated.swift #{lib_dir}/BuildConfig_swift/BuildConfig.plist")

    carthage(
      cache_builds: true,
      platform: 'iOS'
    )
    sh("cd .. && mint run xcodegen")
    cocoapods(repo_update: false)
  end

これでCI上でも自動生成系のファイルがXcodeGenの実行よりも先に生成されるのでproject.pbxprojに取り込まれるようになりました。

また、新しいメンバーが入ってきた際の開発環境構築でも同じ問題に遭遇するので、fastlaneに疎い人でも構築しやすいようにMakefileを用意しました

Makefile
init:
    bundle install --quiet
    bundle exec fastlane init_project

2019/5/15追記

@yosshi4486さんからブログ記事を紹介してもらいました。
project.ymlで完結できるのでこちらの方が良さそうですね😃
最終的にsourcesに以下のように追加することで解決しました。

project.yml
- path: Libs/R_swift/R.generated.swift
  optional: true
  createIntermediateGroups: true
- path: Libs/BuildConfig_swift/BuildConfig.generated.swift
  optional: true
  createIntermediateGroups: true
- path: Libs/BuildConfig_swift/BuildConfig.plist
  optional: true
  createIntermediateGroups: true

createIntermediateGroupsをtrueにしないとLibsグループで括ってくれないので注意。

Swift Package Manager使いたいけどPackage.lockがgitで管理できない

XcodeGenを導入したての時、多くの人(主語デカ)は.gitignoreにこのように書くのではないでしょうか

.gitignore
*.xcodeproj/*

今まではこれでも問題なかったのですが、Swift Package Managerを使おうとすると話が変わってきます。
Xcode11からiOS/macOSプロジェクトでもSwift Package Managerが使えるようになりましたが、依存性を解決した結果を格納するPackage.resolvedファイルは

○○.xcodeproj
├ project.pbxproj
├ project.xcworkspace
│ ├ contents.xcworkspacedata
│ ├ xcshareddata
│ │ ├ IDEWorkspaceChecks.plist
│ │ └ swiftpm
│ │   └ Package.resolved ← ココにいます。
│ └ xcuserdata
│   └ {username}.xcuserdatad
│     └ UserInterfaceState.xcuserstate
├ xcshareddata
│ ├ xcdebugger
│ └ xcschemes
└ xcuserdata
  └ {username}.xcuserdatad
    ├ xcdebugger
    │ └ Breakpoints_v2.xcbkptlist
    └ xcschemes
    └ xcschememanagement.plist

先に書いた.gitignoreの書き方だと、これらが丸ごとgit管理されなくなります。
そこで、Package.resolvedだけgit管理するためにこのように追記してみます。

.gitignore
*.xcodeproj/*
!*.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

一見これで良さそうに見えますが、この状態で実際にPackage.resolvedをgit addしようとすると以下のように怒られます

$ git add ○○.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
The following paths are ignored by one of your .gitignore files:
○○.xcodeproj/project.xcworkspace
Use -f if you really want to add them.

Package.resolved自体を無視対象から外そうとしても、その上の階層のフォルダが無視されてしまっているためにその下にいるPackage.resolvedまで見てくれないようです。

エラー文言に言われた通りgit add -fで追加してもいいんですがその後間違ってgit rmとかしたら面倒なことになりそうなので、どうにかしてPackage.resolvedを無視対象から外したいところ。

解決策

愚直に途中のフォルダを無視対象から外してそのフォルダ内のファイルを無視するような記述をする必要があります。
最終的には以下のようになります。

.gitignore
*.xcodeproj/*
!*.xcodeproj/project.xcworkspace/
*.xcodeproj/project.xcworkspace/*
!*.xcodeproj/project.xcworkspace/xcshareddata/
*.xcodeproj/project.xcworkspace/xcshareddata/*
!*.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/
*.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/*
!*.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

参考

13
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?