Skip to content

Commit 1ec044b

Browse files
committed
bundle presets and textures in the app resources, add mac build script
1 parent 9755a5f commit 1ec044b

File tree

2 files changed

+181
-20
lines changed

2 files changed

+181
-20
lines changed

rel.sh

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
#######################################
6+
# Variables
7+
#######################################
8+
APP_NAME="projectm_sdl"
9+
BUNDLE_ID="projectM"
10+
DEVELOPER_ID="Developer ID Application: Mischa Spiegelmock (5926VBQM6Y)"
11+
TEAM_ID="5926VBQM6Y"
12+
KEYCHAIN_PROFILE="projectm"
13+
14+
BUILD_DIR="target"
15+
OUTPUT_DIR="${PWD}/dist"
16+
17+
# Paths for universal binary
18+
UNIVERSAL_BINARY="${OUTPUT_DIR}/${APP_NAME}"
19+
20+
# .app bundle paths
21+
APP_BUNDLE_NAME="${APP_NAME}.app"
22+
APP_BUNDLE_PATH="${OUTPUT_DIR}/${APP_BUNDLE_NAME}"
23+
APP_EXECUTABLE_PATH="${APP_BUNDLE_PATH}/Contents/MacOS"
24+
INFO_PLIST_PATH="${APP_BUNDLE_PATH}/Contents/Info.plist"
25+
RESOURCES_PATH="${APP_BUNDLE_PATH}/Contents/Resources"
26+
27+
# Zip paths
28+
PRE_NOTARIZATION_ZIP="${OUTPUT_DIR}/${APP_NAME}-pre-notarization.zip"
29+
FINAL_ZIP="${OUTPUT_DIR}/${APP_NAME}.zip"
30+
31+
#######################################
32+
# 1) Build Rust Binaries (x86_64 + arm64)
33+
#######################################
34+
echo "==> Building for x86_64"
35+
cargo build --release --target x86_64-apple-darwin
36+
37+
echo "==> Building for arm64"
38+
cargo build --release --target aarch64-apple-darwin
39+
40+
#######################################
41+
# 2) Create Universal Binary
42+
#######################################
43+
mkdir -p "${OUTPUT_DIR}"
44+
echo "==> Creating universal binary"
45+
lipo -create -output "${UNIVERSAL_BINARY}" \
46+
"${BUILD_DIR}/x86_64-apple-darwin/release/${APP_NAME}" \
47+
"${BUILD_DIR}/aarch64-apple-darwin/release/${APP_NAME}"
48+
49+
#######################################
50+
# 3) Create .app Bundle Structure
51+
#######################################
52+
echo "==> Creating .app bundle structure"
53+
rm -rf "${APP_BUNDLE_PATH}" || true
54+
mkdir -p "${APP_EXECUTABLE_PATH}"
55+
mkdir -p "${RESOURCES_PATH}"
56+
57+
# Move the universal binary into MacOS/
58+
mv "${UNIVERSAL_BINARY}" "${APP_EXECUTABLE_PATH}/${APP_NAME}"
59+
60+
#######################################
61+
# 4) Create Info.plist
62+
#######################################
63+
cat > "${INFO_PLIST_PATH}" <<EOL
64+
<?xml version="1.0" encoding="UTF-8"?>
65+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
66+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
67+
<plist version="1.0">
68+
<dict>
69+
<key>CFBundleName</key>
70+
<string>${APP_NAME}</string>
71+
<key>CFBundleIdentifier</key>
72+
<string>${BUNDLE_ID}</string>
73+
<key>CFBundleVersion</key>
74+
<string>1.0</string>
75+
<key>CFBundleExecutable</key>
76+
<string>${APP_NAME}</string>
77+
<key>CFBundlePackageType</key>
78+
<string>APPL</string>
79+
<key>LSMinimumSystemVersion</key>
80+
<string>10.12</string>
81+
</dict>
82+
</plist>
83+
EOL
84+
85+
#######################################
86+
# 5) Clone and Copy Presets/Textures
87+
#######################################
88+
echo "==> Cloning preset repositories"
89+
TEMP_DIR="$(mktemp -d)"
90+
pushd "$TEMP_DIR" >/dev/null
91+
92+
# cream-of-the-crop
93+
git clone [email protected]:projectM-visualizer/presets-cream-of-the-crop.git
94+
mkdir -p "${RESOURCES_PATH}/presets"
95+
cp -R presets-cream-of-the-crop/"." "${RESOURCES_PATH}/presets/"
96+
97+
# milkdrop-texture-pack
98+
git clone [email protected]:projectM-visualizer/presets-milkdrop-texture-pack.git
99+
mkdir -p "${RESOURCES_PATH}/textures"
100+
cp -R presets-milkdrop-texture-pack/textures/"." "${RESOURCES_PATH}/textures/"
101+
102+
popd >/dev/null
103+
rm -rf "$TEMP_DIR"
104+
105+
#######################################
106+
# 6) Sign the .app Bundle
107+
#######################################
108+
echo "==> Signing the .app with hardened runtime"
109+
codesign --deep --verbose --force --options runtime \
110+
--sign "${DEVELOPER_ID}" "${APP_BUNDLE_PATH}"
111+
112+
#######################################
113+
# 7) Zip the Signed .app for Notarization
114+
#######################################
115+
echo "==> Creating zip for notarization"
116+
rm -f "${PRE_NOTARIZATION_ZIP}"
117+
ditto -c -k --sequesterRsrc --keepParent \
118+
"${APP_BUNDLE_PATH}" \
119+
"${PRE_NOTARIZATION_ZIP}"
120+
121+
#######################################
122+
# 8) Submit the Zip File for Notarization
123+
#######################################
124+
echo "==> Submitting for notarization"
125+
xcrun notarytool submit "${PRE_NOTARIZATION_ZIP}" \
126+
--keychain-profile "${KEYCHAIN_PROFILE}" \
127+
--team-id "${TEAM_ID}" \
128+
--wait
129+
130+
#######################################
131+
# 9) Staple the Now-Notarized .app
132+
#######################################
133+
echo "==> Stapling notarization ticket to .app"
134+
xcrun stapler staple "${APP_BUNDLE_PATH}"
135+
136+
#######################################
137+
# 10) (Optional) Create Final Zip with Stapled .app
138+
#######################################
139+
echo "==> Creating final zip of stapled .app"
140+
rm -f "${FINAL_ZIP}"
141+
ditto -c -k --sequesterRsrc --keepParent \
142+
"${APP_BUNDLE_PATH}" \
143+
"${FINAL_ZIP}"
144+
145+
#######################################
146+
# 11) Verify with Gatekeeper
147+
#######################################
148+
echo "==> Verifying with spctl"
149+
spctl --assess --verbose=4 "${APP_BUNDLE_PATH}"
150+
151+
echo "✅ Build, sign, notarize, staple, and package completed successfully!"

src/app/config.rs

+30-20
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,40 @@ pub struct Config {
2323
pub preset_duration: Option<f64>,
2424
}
2525

26+
#[cfg(target_os = "macos")]
27+
fn default_resource_dir() -> std::path::PathBuf {
28+
// current_exe() => /Path/To/projectm_sdl.app/Contents/MacOS/projectm_sdl
29+
let exe_path = std::env::current_exe().unwrap();
30+
// Jump up two levels to Contents/, then into Resources
31+
exe_path
32+
.parent() // MacOS
33+
.unwrap()
34+
.parent() // Contents
35+
.unwrap()
36+
.join("Resources")
37+
}
38+
39+
#[cfg(not(target_os = "macos"))]
40+
fn default_resource_dir() -> std::path::PathBuf {
41+
// On Linux, Windows, etc., do as you wish
42+
"/usr/local/share/projectM".into()
43+
}
44+
2645
impl Default for Config {
2746
fn default() -> Self {
28-
// get paths to presets and textures
29-
// TODO: get from config file or env
30-
//
31-
// use /usr/local/share/projectM if it exists, otherwise use local paths
32-
let resource_dir = "/usr/local/share/projectM";
33-
let dir_exists = Path::new(&resource_dir).exists();
34-
let preset_path = if dir_exists && false {
35-
String::from(resource_dir) + "/presets"
36-
} else {
37-
// just test presets
38-
"./presets".to_owned()
39-
};
40-
let texture_path = if dir_exists {
41-
String::from(resource_dir) + "/textures"
42-
} else {
43-
// doesn't exist
44-
"./textures".to_owned()
45-
};
47+
#[cfg(target_os = "macos")]
48+
let resource_dir = default_resource_dir(); // points to .app/Contents/Resources
49+
50+
#[cfg(not(target_os = "macos"))]
51+
let resource_dir = std::path::PathBuf::from("/usr/local/share/projectM");
52+
53+
// Construct paths
54+
let presets_path = resource_dir.join("presets");
55+
let textures_path = resource_dir.join("textures");
4656

4757
Self {
48-
preset_path: Path::new(&preset_path).exists().then(|| preset_path),
49-
texture_path: Path::new(&texture_path).exists().then(|| texture_path),
58+
preset_path: presets_path.exists().then(|| presets_path.to_string_lossy().to_string()),
59+
texture_path: textures_path.exists().then(|| textures_path.to_string_lossy().to_string()),
5060
frame_rate: Some(60),
5161
beat_sensitivity: Some(1.0),
5262
preset_duration: Some(10.0),

0 commit comments

Comments
 (0)