-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
288 lines (264 loc) · 13.4 KB
/
Copy pathMakefile
File metadata and controls
288 lines (264 loc) · 13.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# Makefile — fuse-for-macos-arm64
#
# Overridable variables:
# CODE_SIGN_IDENTITY Optional explicit signing identity. If unset, the
# Makefile resolves a matching Developer ID Application
# certificate from the keychain using DEVELOPMENT_TEAM.
# Defaults to '-' (ad-hoc) when no local signing config
# is present.
# DEVELOPMENT_TEAM 10-character Apple Team ID. Not used for ad-hoc.
# Required for notarization.
# NOTARYTOOL_PROFILE Keychain profile name for notarytool.
# One-time setup:
# xcrun notarytool store-credentials fuse-notarize \
# --apple-id YOUR_DEV_APPLE_ID \
# --team-id YOUR_TEAM_ID \
# --password YOUR_APP_SPECIFIC_PASSWORD
LOCAL_SIGNING_XCCONFIG = fusepb/LocalSigning.xcconfig
ifeq ($(origin CODE_SIGN_IDENTITY), undefined)
LOCAL_CODE_SIGN_IDENTITY := $(shell if [ -f "$(LOCAL_SIGNING_XCCONFIG)" ]; then sed -n 's/^CODE_SIGN_IDENTITY[[:space:]]*=[[:space:]]*//p' "$(LOCAL_SIGNING_XCCONFIG)" | sed -n '1p'; fi)
else
LOCAL_CODE_SIGN_IDENTITY :=
endif
ifeq ($(origin DEVELOPMENT_TEAM), undefined)
EFFECTIVE_DEVELOPMENT_TEAM := $(shell if [ -f "$(LOCAL_SIGNING_XCCONFIG)" ]; then sed -n 's/^DEVELOPMENT_TEAM[[:space:]]*=[[:space:]]*//p' "$(LOCAL_SIGNING_XCCONFIG)" | sed -n '1p'; fi)
else
EFFECTIVE_DEVELOPMENT_TEAM := $(DEVELOPMENT_TEAM)
endif
ifeq ($(origin CODE_SIGN_IDENTITY), undefined)
ifeq ($(strip $(EFFECTIVE_DEVELOPMENT_TEAM)),)
EFFECTIVE_CODE_SIGN_IDENTITY := -
else
EFFECTIVE_CODE_SIGN_IDENTITY := $(shell security find-identity -v -p codesigning 2>/dev/null | sed -n 's/.*"\(Developer ID Application: .* ($(EFFECTIVE_DEVELOPMENT_TEAM))\)"/\1/p' | sed -n '1p')
ifeq ($(strip $(EFFECTIVE_CODE_SIGN_IDENTITY)),)
EFFECTIVE_CODE_SIGN_IDENTITY := $(if $(strip $(LOCAL_CODE_SIGN_IDENTITY)),$(LOCAL_CODE_SIGN_IDENTITY),Developer ID Application)
endif
endif
else
EFFECTIVE_CODE_SIGN_IDENTITY := $(CODE_SIGN_IDENTITY)
endif
NOTARYTOOL_PROFILE ?= fuse-notarize
NOTARY_POLL_INTERVAL ?= 60
FUSE_APP = fusepb/build/Deployment/Fuse.app
FUSE_DSYM = fusepb/build/Deployment/Fuse.app.dSYM
XCODEPROJ = fusepb/Fuse.xcodeproj
XCODE_BUILD_ROOT = $(CURDIR)/fusepb/build
FUSE_REPO_ROOT = $(CURDIR)
FUSE_SCRIPTS_ROOT = $(FUSE_REPO_ROOT)/fusepb/scripts
FUSE_DEPS_ROOT = $(FUSE_REPO_ROOT)/fusepb/deps
FUSE_THIRD_PARTY_ROOT = $(FUSE_DEPS_ROOT)/third_party
NOTARIZE_ZIP = Fuse-notarize.zip
DIST_ZIP = Fuse.zip
DIST_DIR = Fuse for macOS
DIST_STAGE = .dist-stage
DIST_SKELETON_DIR = fusepb/release_skeleton/$(DIST_DIR)
DIST_STAGE_DIR = $(DIST_STAGE)/$(DIST_DIR)
NOTARY_SUBMISSION_ID_FILE = .notary-submission-id
NOTARY_LOG_FILE = .notary-log.json
ifeq ($(EFFECTIVE_CODE_SIGN_IDENTITY),-)
CODESIGN_TIMESTAMP =
else
CODESIGN_TIMESTAMP = --timestamp
endif
FUSE_CODESIGN_TIMESTAMP =
.PHONY: fuse archive adhoc test test-only notarize notarize-submit notarize-status notarize-log notarize-wait notarize-staple notarize-reset dist list-teams clean
## Run the Quick Look unit test suite (FuseQuickLookTests scheme).
## Requires a macOS host with Xcode and the fuse submodule checked out.
test:
xcodebuild -project $(XCODEPROJ) -scheme FuseQuickLookTests -configuration Development \
-destination 'platform=macOS' \
SYMROOT='$(XCODE_BUILD_ROOT)' OBJROOT='$(XCODE_BUILD_ROOT)' \
FUSE_REPO_ROOT='$(FUSE_REPO_ROOT)' \
FUSE_SCRIPTS_ROOT='$(FUSE_SCRIPTS_ROOT)' \
FUSE_DEPS_ROOT='$(FUSE_DEPS_ROOT)' \
FUSE_THIRD_PARTY_ROOT='$(FUSE_THIRD_PARTY_ROOT)' \
test
## Run a single Quick Look unit test by class and method name.
## Usage: make test-only TEST=ClassName/test_method_name
## Example:
## make test-only TEST=FuseQuickLookImageTests/test_scr_file_produces_bitmap_image
test-only:
@[ -n "$(TEST)" ] || { echo "error: TEST not specified. Example: make test-only TEST=FuseQuickLookImageTests/test_scr_file_produces_bitmap_image"; exit 1; }
xcodebuild -project $(XCODEPROJ) -scheme FuseQuickLookTests -configuration Development \
-destination 'platform=macOS' \
SYMROOT='$(XCODE_BUILD_ROOT)' OBJROOT='$(XCODE_BUILD_ROOT)' \
FUSE_REPO_ROOT='$(FUSE_REPO_ROOT)' \
FUSE_SCRIPTS_ROOT='$(FUSE_SCRIPTS_ROOT)' \
FUSE_DEPS_ROOT='$(FUSE_DEPS_ROOT)' \
FUSE_THIRD_PARTY_ROOT='$(FUSE_THIRD_PARTY_ROOT)' \
-only-testing:"FuseQuickLookTests/$(TEST)" \
test
## Build Fuse.app (Deployment configuration).
## This single Xcode build now also builds the shared staged dependencies plus
## the embedded Quick Look and Spotlight plugin targets.
##
## After xcodebuild, embedded bundled components are re-signed explicitly and
## Fuse.app is then re-signed to seal the corrected nested-code hashes.
fuse:
$(MAKE) -C fusepb
@echo "Running Xcode app build"
xcodebuild -project $(XCODEPROJ) -scheme Fuse -configuration Deployment \
-destination 'platform=macOS' \
SYMROOT='$(XCODE_BUILD_ROOT)' OBJROOT='$(XCODE_BUILD_ROOT)' \
FUSE_REPO_ROOT='$(FUSE_REPO_ROOT)' \
FUSE_SCRIPTS_ROOT='$(FUSE_SCRIPTS_ROOT)' \
FUSE_DEPS_ROOT='$(FUSE_DEPS_ROOT)' \
FUSE_THIRD_PARTY_ROOT='$(FUSE_THIRD_PARTY_ROOT)' \
CODE_SIGN_IDENTITY="$(EFFECTIVE_CODE_SIGN_IDENTITY)" \
DEVELOPMENT_TEAM="$(EFFECTIVE_DEVELOPMENT_TEAM)"
@echo "Re-signing Spotlight importer"
codesign --sign "$(EFFECTIVE_CODE_SIGN_IDENTITY)" --force --options runtime $(FUSE_CODESIGN_TIMESTAMP) \
"$(FUSE_APP)/Contents/Library/Spotlight/FuseImporter.mdimporter"
@echo "Re-signing Quick Look extensions"
codesign --sign "$(EFFECTIVE_CODE_SIGN_IDENTITY)" --force --options runtime $(FUSE_CODESIGN_TIMESTAMP) \
--entitlements "fusepb/FuseQuickLookExtension.entitlements" \
"$(FUSE_APP)/Contents/PlugIns/FuseThumbnailExtension.appex"
codesign --sign "$(EFFECTIVE_CODE_SIGN_IDENTITY)" --force --options runtime $(FUSE_CODESIGN_TIMESTAMP) \
--entitlements "fusepb/FuseQuickLookExtension.entitlements" \
"$(FUSE_APP)/Contents/PlugIns/FusePreviewExtension.appex"
@echo "Re-signing app bundle"
codesign --sign "$(EFFECTIVE_CODE_SIGN_IDENTITY)" --force --options runtime $(FUSE_CODESIGN_TIMESTAMP) \
--entitlements "fusepb/Fuse.entitlements" "$(FUSE_APP)"
@echo "Fuse build complete"
## Build an Xcode archive (.xcarchive) — useful for manual export workflows.
archive:
xcodebuild archive \
-project $(XCODEPROJ) \
-scheme Fuse \
-destination 'platform=macOS' \
SYMROOT='$(XCODE_BUILD_ROOT)' OBJROOT='$(XCODE_BUILD_ROOT)' \
-configuration Deployment \
-archivePath fusepb/build/Fuse.xcarchive \
FUSE_REPO_ROOT='$(FUSE_REPO_ROOT)' \
FUSE_SCRIPTS_ROOT='$(FUSE_SCRIPTS_ROOT)' \
FUSE_DEPS_ROOT='$(FUSE_DEPS_ROOT)' \
FUSE_THIRD_PARTY_ROOT='$(FUSE_THIRD_PARTY_ROOT)' \
CODE_SIGN_IDENTITY="$(EFFECTIVE_CODE_SIGN_IDENTITY)" \
DEVELOPMENT_TEAM="$(EFFECTIVE_DEVELOPMENT_TEAM)"
## Ad-hoc sign Fuse.app and package it as Fuse-adhoc.zip for local testing.
## The resulting zip is NOT suitable for distribution — Gatekeeper will reject
## it on other machines. Use 'make notarize && make dist' for that (Phase 2).
adhoc: fuse
rm -f Fuse-adhoc.zip
ditto -c -k --keepParent "$(FUSE_APP)" Fuse-adhoc.zip
@echo "Ad-hoc build packaged as Fuse-adhoc.zip"
## Submit, wait for, and staple a notarization request.
## Use the subtargets below to resume or inspect long-running submissions.
notarize:
$(MAKE) notarize-submit
$(MAKE) notarize-wait
$(MAKE) notarize-staple
## Submit Fuse.app for notarization and store the submission ID locally.
notarize-submit: fuse
@if [ "$(EFFECTIVE_CODE_SIGN_IDENTITY)" = "-" ]; then \
echo "ERROR: notarize requires a Developer ID Application identity." ; \
echo " Set it in $(LOCAL_SIGNING_XCCONFIG) or re-run with CODE_SIGN_IDENTITY='Developer ID Application: Your Name (TEAMID)'" ; \
false ; \
fi
rm -f $(NOTARIZE_ZIP)
rm -f $(NOTARY_LOG_FILE)
ditto -c -k --keepParent "$(FUSE_APP)" $(NOTARIZE_ZIP)
@submission_json=`xcrun notarytool submit $(NOTARIZE_ZIP) --keychain-profile "$(NOTARYTOOL_PROFILE)" --output-format json` ; \
submission_id=`printf '%s\n' "$$submission_json" | /usr/bin/python3 -c 'import json, sys; print( json.load( sys.stdin )["id"] )'` ; \
status=`printf '%s\n' "$$submission_json" | /usr/bin/python3 -c 'import json, sys; print( json.load( sys.stdin ).get( "status", "Submitted" ) )'` ; \
printf '%s\n' "$$submission_id" > "$(NOTARY_SUBMISSION_ID_FILE)" ; \
echo "Submitted notarization $$submission_id ($$status)" ; \
echo "Check progress with 'make notarize-status' or wait with 'make notarize-wait'."
rm -f $(NOTARIZE_ZIP)
## Show status for the current notarization submission.
notarize-status:
@if [ ! -f "$(NOTARY_SUBMISSION_ID_FILE)" ]; then \
echo "ERROR: no notarization submission ID found." ; \
echo " Run 'make notarize-submit' first." ; \
false ; \
fi
@submission_id=`tr -d '\n' < "$(NOTARY_SUBMISSION_ID_FILE)"` ; \
info_json=`xcrun notarytool info "$$submission_id" --keychain-profile "$(NOTARYTOOL_PROFILE)" --output-format json` ; \
printf '%s\n' "$$info_json" | /usr/bin/python3 -c 'import json, sys; info = json.load( sys.stdin ); print( "Submission ID: {}".format( info.get( "id", "unknown" ) ) ); print( "Status: {}".format( info.get( "status", "unknown" ) ) ); summary = info.get( "statusSummary" ); print( "Summary: {}".format( summary ) ) if summary else None; issues = info.get( "issues" ); print( "Issues: {}".format( len( issues ) ) ) if issues else None'
## Fetch the notarization log for the current submission.
notarize-log:
@if [ ! -f "$(NOTARY_SUBMISSION_ID_FILE)" ]; then \
echo "ERROR: no notarization submission ID found." ; \
echo " Run 'make notarize-submit' first." ; \
false ; \
fi
@submission_id=`tr -d '\n' < "$(NOTARY_SUBMISSION_ID_FILE)"` ; \
xcrun notarytool log "$$submission_id" "$(NOTARY_LOG_FILE)" --keychain-profile "$(NOTARYTOOL_PROFILE)" ; \
echo "Saved notarization log to $(NOTARY_LOG_FILE)"
## Poll the current notarization submission until Apple finishes processing it.
notarize-wait:
@if [ ! -f "$(NOTARY_SUBMISSION_ID_FILE)" ]; then \
echo "ERROR: no notarization submission ID found." ; \
echo " Run 'make notarize-submit' first." ; \
false ; \
fi
@submission_id=`tr -d '\n' < "$(NOTARY_SUBMISSION_ID_FILE)"` ; \
start_time=`date +%s` ; \
while :; do \
info_json=`xcrun notarytool info "$$submission_id" --keychain-profile "$(NOTARYTOOL_PROFILE)" --output-format json` ; \
status=`printf '%s\n' "$$info_json" | /usr/bin/python3 -c 'import json, sys; print( json.load( sys.stdin ).get( "status", "unknown" ) )'` ; \
summary=`printf '%s\n' "$$info_json" | /usr/bin/python3 -c 'import json, sys; print( json.load( sys.stdin ).get( "statusSummary", "" ) )'` ; \
elapsed=$$(( $$(date +%s) - $$start_time )) ; \
echo "Notarization $$submission_id: $$status after $${elapsed}s" ; \
if [ -n "$$summary" ]; then echo " $$summary" ; fi ; \
case "$$status" in \
Accepted) \
break ;; \
Invalid|Rejected) \
echo "Notarization failed; fetching log..." ; \
xcrun notarytool log "$$submission_id" "$(NOTARY_LOG_FILE)" --keychain-profile "$(NOTARYTOOL_PROFILE)" || true ; \
echo "See $(NOTARY_LOG_FILE) for details." ; \
false ;; \
In\ Progress) \
echo "Still processing on Apple's servers. You can stop waiting and later run 'make notarize-status' or 'make notarize-log'." ; \
sleep $(NOTARY_POLL_INTERVAL) ;; \
*) \
echo "Unexpected notarization status: $$status" ; \
sleep $(NOTARY_POLL_INTERVAL) ;; \
esac ; \
done
## Staple Fuse.app after the current submission has been accepted.
notarize-staple:
@if [ ! -f "$(NOTARY_SUBMISSION_ID_FILE)" ]; then \
echo "ERROR: no notarization submission ID found." ; \
echo " Run 'make notarize-submit' first." ; \
false ; \
fi
@submission_id=`tr -d '\n' < "$(NOTARY_SUBMISSION_ID_FILE)"` ; \
status=`xcrun notarytool info "$$submission_id" --keychain-profile "$(NOTARYTOOL_PROFILE)" --output-format json | /usr/bin/python3 -c 'import json, sys; print( json.load( sys.stdin ).get( "status", "unknown" ) )'` ; \
if [ "$$status" != "Accepted" ]; then \
echo "ERROR: submission $$submission_id is $$status, not Accepted." ; \
echo " Run 'make notarize-status' or 'make notarize-log' for details." ; \
false ; \
fi
xcrun stapler staple "$(FUSE_APP)"
## Clear local notarization state files.
notarize-reset:
rm -f $(NOTARIZE_ZIP) $(NOTARY_SUBMISSION_ID_FILE) $(NOTARY_LOG_FILE)
## Create the distributable Fuse.zip from a notarized app.
## The final zip contains the staged "Fuse for macOS" folder layout.
dist: notarize
rm -f $(DIST_ZIP)
rm -rf $(DIST_STAGE)
mkdir -p "$(DIST_STAGE)"
ditto --norsrc "$(DIST_SKELETON_DIR)" "$(DIST_STAGE_DIR)"
rm -rf "$(DIST_STAGE_DIR)/Fuse.app"
ditto --norsrc "$(FUSE_APP)" "$(DIST_STAGE_DIR)/Fuse.app"
mkdir -p "$(DIST_STAGE_DIR)/Debug Symbols"
rm -rf "$(DIST_STAGE_DIR)/Debug Symbols/Fuse.app.dSYM"
ditto --norsrc "$(FUSE_DSYM)" "$(DIST_STAGE_DIR)/Debug Symbols/Fuse.app.dSYM"
python3 -c 'import os, pathlib; root = pathlib.Path("$(DIST_STAGE_DIR)"); [p.unlink() for p in root.rglob("*") if p.name == ".DS_Store" or p.name.startswith("._")]'
cd "$(DIST_STAGE)" && COPYFILE_DISABLE=1 zip -q -r -X "$(CURDIR)/$(DIST_ZIP)" "$(DIST_DIR)"
rm -rf $(DIST_STAGE)
@echo "Notarized build packaged as $(DIST_ZIP)"
## List available signing identities in the keychain.
list-teams:
security find-identity -v -p codesigning
## Clean the fuse build products.
clean:
$(MAKE) -C fusepb clean
xcodebuild -project $(XCODEPROJ) -configuration Deployment clean
rm -f Fuse-adhoc.zip
rm -f $(NOTARIZE_ZIP) $(DIST_ZIP)
rm -rf $(DIST_STAGE)
$(MAKE) notarize-reset