From 2d9f1be61a0e379b51e3c9eca7d531e1605faeae Mon Sep 17 00:00:00 2001 From: Nikita Bobko Date: Mon, 23 Sep 2024 21:36:19 +0200 Subject: [PATCH] install-from-sources.sh: install as AeroSpace-Dev.app If we didn't separate those builds, macOS would re-request accessibility permission when users switch between "-Dev" and GitHub builds. "-Dev" builds and GitHub builds differ only in the application name and App Bundle ID. Related: https://github.com/nikitabobko/AeroSpace/issues/530 --- .github/workflows/build.yml | 12 ++- AeroSpace.xcodeproj/project.pbxproj | 81 +++++++++++++++++- build-release.sh | 83 +++++++++++-------- dev-docs/development.md | 16 +++- ...-sources.sh => install-dev-from-sources.sh | 4 +- project.yml | 16 +++- script/build-brew-cask.sh | 29 ++++--- script/publish-release.sh | 40 +++++++-- 8 files changed, 216 insertions(+), 65 deletions(-) rename install-from-sources.sh => install-dev-from-sources.sh (87%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d45d1de..0e4469d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,10 +33,16 @@ jobs: # "-" means "Sign to run locally". There is no aerospace-codesign-certificate in GH Actions # build-release.sh takes too much time to complete in macos-13. # Running build-release.sh only in macos-14, cuts the build time twice in GH Actions. - - name: ./build-release.sh on macos-14 + - name: ./build-release.sh --configuration Dev on macos-14 run: | sw_vers -productVersion if sw_vers -productVersion | grep -q "^14"; then - ./build-release.sh --codesign-identity - - ./install-from-sources.sh --dont-rebuild + ./build-release.sh --configuration Dev --codesign-identity - + ./install-dev-from-sources.sh --dont-rebuild + fi + - name: ./build-release.sh --configuration Release on macos-14 + run: | + sw_vers -productVersion + if sw_vers -productVersion | grep -q "^14"; then + ./build-release.sh --configuration Release --codesign-identity - fi diff --git a/AeroSpace.xcodeproj/project.pbxproj b/AeroSpace.xcodeproj/project.pbxproj index b5afe1c9..2cb97c33 100644 --- a/AeroSpace.xcodeproj/project.pbxproj +++ b/AeroSpace.xcodeproj/project.pbxproj @@ -243,13 +243,90 @@ ); MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = "0.0.0-SNAPSHOT"; - PRODUCT_BUNDLE_IDENTIFIER = bobko.debug.aerospace; + PRODUCT_BUNDLE_IDENTIFIER = bobko.aerospace.debug; PRODUCT_NAME = "AeroSpace-Debug"; SDKROOT = macosx; SWIFT_VERSION = 5.9; }; name = Debug; }; + 6BDAA670FB7E7B16FDEB09CB /* Dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + }; + name = Dev; + }; + 9264D9CD4E2A7E31EB00947C /* Dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = resources/AeroSpace.entitlements; + CODE_SIGN_IDENTITY = "aerospace-codesign-certificate"; + COMBINE_HIDPI_IMAGES = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_LSUIElement = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = "0.0.0-SNAPSHOT"; + PRODUCT_BUNDLE_IDENTIFIER = bobko.aerospace.dev; + PRODUCT_NAME = "AeroSpace-Dev"; + SDKROOT = macosx; + SWIFT_VERSION = 5.9; + }; + name = Dev; + }; A991F90908318BCD1655E904 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -334,6 +411,7 @@ isa = XCConfigurationList; buildConfigurations = ( 31B702864571F51814E4F12C /* Debug */, + 9264D9CD4E2A7E31EB00947C /* Dev */, D1D1A9E07F0AB40E14CAC0F6 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -343,6 +421,7 @@ isa = XCConfigurationList; buildConfigurations = ( 175127AAF914899705FABF12 /* Debug */, + 6BDAA670FB7E7B16FDEB09CB /* Dev */, A991F90908318BCD1655E904 /* Release */, ); defaultConfigurationIsVisible = 0; diff --git a/build-release.sh b/build-release.sh index ca7535a9..c1fed914 100755 --- a/build-release.sh +++ b/build-release.sh @@ -4,14 +4,30 @@ source ./script/setup.sh build_version="0.0.0-SNAPSHOT" codesign_identity="aerospace-codesign-certificate" +configuration="Release" while [[ $# -gt 0 ]]; do case $1 in - --build-version) build_version="$2"; shift 2 ;; - --codesign-identity) codesign_identity="$2"; shift 2 ;; - *) echo "Unknown option $1"; exit 1 ;; + --build-version) build_version="$2"; shift 2;; + --codesign-identity) codesign_identity="$2"; shift 2;; + --configuration) configuration="$2"; shift 2;; + *) echo "Unknown option $1" > /dev/stderr; exit 1 ;; esac done +case $configuration in + Release) + aerospace_dot_app='AeroSpace.app' + aerospace_dot_app_bin='AeroSpace' + cask_name='aerospace' + ;; + Dev) + aerospace_dot_app='AeroSpace-Dev.app' + aerospace_dot_app_bin='AeroSpace-Dev' + cask_name='aerospace-dev' + ;; + *) echo "Unknown configuration: $configuration" > /dev/stderr; exit 1;; +esac + generate-git-hash() { cat > Sources/Common/gitHashGenerated.swift < /dev/null; then + if ! strings "$1" | grep --fixed-string "$hash" > /dev/null; then echo "$1 doesn't contain $hash" exit 1 fi } -check-universal-binary .release/AeroSpace.app/Contents/MacOS/AeroSpace +check-universal-binary .release/$aerospace_dot_app/Contents/MacOS/$aerospace_dot_app_bin check-universal-binary .release/aerospace -check-contains-hash .release/AeroSpace.app/Contents/MacOS/AeroSpace +check-contains-hash .release/$aerospace_dot_app/Contents/MacOS/$aerospace_dot_app_bin check-contains-hash .release/aerospace -codesign -v .release/AeroSpace.app +codesign -v .release/$aerospace_dot_app codesign -v .release/aerospace ############ ### PACK ### ############ -mkdir -p .release/AeroSpace-v$build_version/manpage && cp .man/*.1 .release/AeroSpace-v$build_version/manpage -cp -r ./legal .release/AeroSpace-v$build_version/legal -cp -r .shell-completion .release/AeroSpace-v$build_version/shell-completion +mkdir -p ".release/AeroSpace-v$build_version/manpage" && cp .man/*.1 ".release/AeroSpace-v$build_version/manpage" +cp -r ./legal ".release/AeroSpace-v$build_version/legal" +cp -r .shell-completion ".release/AeroSpace-v$build_version/shell-completion" cd .release - mkdir -p AeroSpace-v$build_version/bin && cp -r aerospace AeroSpace-v$build_version/bin - cp -r AeroSpace.app AeroSpace-v$build_version - zip -r AeroSpace-v$build_version.zip AeroSpace-v$build_version + mkdir -p "AeroSpace-v$build_version/bin" && cp -r aerospace "AeroSpace-v$build_version/bin" + cp -r $aerospace_dot_app "AeroSpace-v$build_version" + zip -r "AeroSpace-v$build_version.zip" "AeroSpace-v$build_version" cd - ################# ### Brew Cask ### ################# ./script/build-brew-cask.sh \ - --zip-uri .release/AeroSpace-v$build_version.zip \ - --cask-name aerospace-dev \ - --build-version $build_version \ - --conflicts-with-casks aerospace + --cask-name "$cask_name" \ + --zip-uri ".release/AeroSpace-v$build_version.zip" \ + --build-version "$build_version" diff --git a/dev-docs/development.md b/dev-docs/development.md index 592c6912..72266618 100644 --- a/dev-docs/development.md +++ b/dev-docs/development.md @@ -9,6 +9,10 @@ Feel free to report GitHub issues if something doesn't work for you If you struggle to build AeroSpace locally, you can also refer to [builds in GitHub Actions](https://github.com/nikitabobko/AeroSpace/actions?query=branch%3Amain) +## Definitions + +**SPM.** Swift package manager and Swift build tool. In other words, `swift` CLI tool + ## 1. Install dependencies 1. Install Xcode from App Store https://apps.apple.com/us/app/xcode/id497799835 @@ -36,7 +40,7 @@ If you only plan to build the debug version of AeroSpace, you can run it from th ## 3. Entry point scripts **Debug build** -- `build-debug.sh` - Build debug build to `.debug` dir. +- `build-debug.sh` - Build debug build to `.debug` dir by using SPM. (Xcode is not involved) - `run-tests.sh` - Run tests. - `run-debug.sh` - Run AeroSpace.app debug build. - `run-cli.sh` - Run `aerospace` in CLI. Arguments are forwarded to `aerospace` binary. @@ -50,8 +54,14 @@ If you only plan to build the debug version of AeroSpace, you can run it from th > Debug build uses `~/.aerospace-debug.toml` instead of `~/.aerospace.toml` **Release build** -- `build-release.sh` - Build release build to `.release` dir. -- `install-from-sources.sh` - Build from sources and install release build to `aerospace-dev` brew cask +- `build-release.sh` - Build release build to `.release` dir by using Xcode. +- `install-dev-from-sources.sh` - Build `AeroSpace-Dev.app` release build from sources and install it as `aerospace-dev` brew cask. + Suffix "-Dev" is used to distinguish self-build **release** builds from **release** builds published to GitHub. + Builds published to GitHub are signed by Nikita Bobko's private certificate. + "-Dev" builds are signed by your local `aerospace-codesign-certificate`. + If we didn't separate those builds, macOS would re-request accessibility permission when users switch between "-Dev" and GitHub builds. + "-Dev" builds and GitHub builds differ only in the application name and App Bundle ID. + If you want to build the release without "-Dev" suffix, you can use `./build-release.sh --configuration Release`, but be aware of the mentioned problem. ## IDE diff --git a/install-from-sources.sh b/install-dev-from-sources.sh similarity index 87% rename from install-from-sources.sh rename to install-dev-from-sources.sh index 2e4abc1f..4c7a3e8b 100755 --- a/install-from-sources.sh +++ b/install-dev-from-sources.sh @@ -11,13 +11,11 @@ while [[ $# -gt 0 ]]; do done if test $rebuild == 1; then - ./build-release.sh + ./build-release.sh --configuration Dev fi brew list aerospace-dev > /dev/null 2>&1 && brew uninstall aerospace-dev brew list aerospace > /dev/null 2>&1 && brew uninstall aerospace -rm -rf /Applications/AeroSpace.app -rm -rf ~/Applications/AeroSpace.app # Override HOMEBREW_CACHE. Otherwise, homebrew refuses to "redownload" the snapshot file # Maybe there is a better way, I don't know diff --git a/project.yml b/project.yml index c27191e8..943f33db 100644 --- a/project.yml +++ b/project.yml @@ -7,6 +7,11 @@ packages: AeroSpacePackage: path: . +configs: + Debug: debug + Release: release + Dev: release + targets: AeroSpace: type: application @@ -31,12 +36,17 @@ targets: INFOPLIST_KEY_LSUIElement: YES CODE_SIGN_IDENTITY: ${XCODEGEN_AEROSPACE_CODE_SIGN_IDENTITY} configs: - debug: + Debug: PRODUCT_NAME: AeroSpace-Debug - PRODUCT_BUNDLE_IDENTIFIER: bobko.debug.aerospace - release: + PRODUCT_BUNDLE_IDENTIFIER: bobko.aerospace.debug + Release: PRODUCT_NAME: AeroSpace PRODUCT_BUNDLE_IDENTIFIER: bobko.aerospace + # Dev builds have different identifier because they are signed by user's certificate. + # Release builds are signed by Nikita Bobko's certificate + Dev: + PRODUCT_NAME: AeroSpace-Dev + PRODUCT_BUNDLE_IDENTIFIER: bobko.aerospace.dev entitlements: path: resources/AeroSpace.entitlements properties: diff --git a/script/build-brew-cask.sh b/script/build-brew-cask.sh index baedd902..85b1b331 100755 --- a/script/build-brew-cask.sh +++ b/script/build-brew-cask.sh @@ -4,16 +4,12 @@ source ./script/setup.sh zip_uri='' # mandatory cask_name='' # mandatory -conflicts_with_casks='' build_version="0.0.0-SNAPSHOT" -out_dir='.release' while [[ $# -gt 0 ]]; do case $1 in --build-version) build_version="$2"; shift 2 ;; --zip-uri) zip_uri="$2"; shift 2 ;; - --out-dir) out_dir="$2"; shift 2 ;; --cask-name) cask_name="$2"; shift 2 ;; - --conflicts-with-casks) conflicts_with_casks="$2"; shift 2 ;; *) echo "Unknown arg $1"; exit 1 ;; esac done @@ -21,6 +17,18 @@ done if test -z "$zip_uri"; then echo "--zip-uri is mandatory" > /dev/stderr; exit 1; fi if test -z "$cask_name"; then echo "--cask-name is mandatory" > /dev/stderr; exit 1; fi +case $cask_name in + aerospace) + aerospace_dot_app="AeroSpace.app" + conflicts_with_casks=" conflicts_with cask: 'aerospace-dev'" + ;; + aerospace-dev) + aerospace_dot_app="AeroSpace-Dev.app" + conflicts_with_casks=" conflicts_with cask: 'aerospace'" + ;; + *) echo "The only allowed cask names are 'aerospace' or 'aerospace-dev'" > /dev/stderr; exit 1;; +esac + zip_file='' if test -f "$zip_uri"; then zip_file=$zip_uri @@ -34,9 +42,6 @@ else fi sha=$(shasum -a 256 "$zip_file" | awk '{print $1}') -if ! test -z "$conflicts_with_casks"; then - conflicts_with_casks=" conflicts_with cask: '$conflicts_with_casks'" -fi cask_version='' zip_root_dir='' @@ -53,9 +58,9 @@ manpages=$(unzip -l "$zip_file" | \ grep --only-matching 'manpage/aerospace-.*' | \ while read -r it; do echo " manpage \"$zip_root_dir/$it\""; done) -rm -f "$out_dir/$cask_name.rb" || true -mkdir -p "$out_dir" -cat > "$out_dir/$cask_name.rb" < ".release/$cask_name.rb" < /dev/stderr exit 1 fi +if ! test -d "$cask_git_repo_path"; then + echo "--cask-git-repo-path is a mandatory flag that must point to existing directory" > /dev/stderr + exit 1 +fi + +if ! test -d "$site_git_repo_path"; then + echo "--site-git-repo-path is a mandatory flag that must point to existing directory" > /dev/stderr + exit 1 +fi + ./run-tests.sh -./build-release.sh --build-version "$build_version" +./build-release.sh --build-version "$build_version" --configuration Release -git tag -a v$build_version -m "v$build_version" && git push git@github.com:nikitabobko/AeroSpace.git v$build_version +git tag -a "v$build_version" -m "v$build_version" && git push git@github.com:nikitabobko/AeroSpace.git "v$build_version" link="https://github.com/nikitabobko/AeroSpace/releases/new?tag=v$build_version" open "$link" || { echo "$link"; exit 1; } sleep 1 -open -R ./.release/AeroSpace-v$build_version.zip +open -R "./.release/AeroSpace-v$build_version.zip" + +echo "Please upload .zip to GitHub release and hit Enter" +read -r + +./script/build-brew-cask.sh \ + --cask-name aerospace \ + --zip-uri "https://github.com/nikitabobko/AeroSpace/releases/download/v$build_version/AeroSpace-v$build_version.zip" \ + --build-version "$build_version" + +eval "$cask_git_repo_path/pin.sh" +cp .release/aerospace.rb "$cask_git_repo_path/Casks/aerospace.rb" + +rm -rf "${site_git_repo_path:?}/*" # https://www.shellcheck.net/wiki/SC2115 +cp .site/* "$site_git_repo_path"