-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild
More file actions
executable file
·756 lines (695 loc) · 32.2 KB
/
Copy pathbuild
File metadata and controls
executable file
·756 lines (695 loc) · 32.2 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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
#!/bin/bash
#---- project parameters
project_name=MarkNote
project_version=0.1.5
main_class=Main
JARS=
JFX_VERSION=25
vendor_name="SNAPGAMES"
author_name="Frédéric Delorme<contact.snapgames@gmail.com>"
#
#--- DO NOT CHANGE THE FOLLOWING LINES ---
#
SRC=./src
LIBS=./libs
TARGET=./target
BUILD=${TARGET}/build
CLASSES=${TARGET}/classes
RESOURCES=${SRC}/main/resources
SOURCE_ENCODING="UTF-8"
SOURCE_VERSION="25"
JARS=libs/
JFX_PATH="libs"
JFX_MODULES="javafx.base,javafx.graphics,javafx.controls,javafx.fxml,javafx.media,javafx.web"
COMPILATION_OPTS="-Xlint:unchecked -Xlint:deprecation -parameters"
JAR_OPTS="-Xmx512m"
RUN_OPT="--module-path ${JFX_PATH} --add-modules ${JFX_MODULES}"
# add your test execution commands here
TEST_CLASSES=${TARGET}/test-classes
TEST_RESOURCES=${SRC}/test/resources
LIB_TEST=$LIBS/junit-platform-console-standalone-6.0.1.jar
# detect OS type to set the classpath separator and JavaFX platform suffix
if [[ "$OSTYPE" == "linux"* ]]; then
FS=":"
JFX_OS_SUFFIX="linux"
elif [[ "$OSTYPE" == "darwin"* ]]; then
FS=":"
JFX_OS_SUFFIX="mac"
else
FS=";"
JFX_OS_SUFFIX="win"
fi
# define colors
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
NC='\033[0m'
#---- process buid
GIT_COMMIT_ID=$(git rev-parse HEAD)
JAVA_BUILD=$(java --version | head -1 | cut -f2 -d' ')
# Prepare Build
rm -vrf target/
find $SRC/main/java $RESOURCES -name "*.java"
mkdir -vp ${TARGET}/{classes,build/libs,jfx-libs}
# Prepare platform-specific JavaFX libs for compilation
echo "Preparing JavaFX libs for ${JFX_OS_SUFFIX}..."
# Copy common libs (platform-independent JavaFX jars + flexmark)
cp ${LIBS}/common/*.jar ${TARGET}/jfx-libs/
# Copy platform-specific JavaFX jars (native bindings)
cp ${LIBS}/${JFX_OS_SUFFIX}/*.jar ${TARGET}/jfx-libs/ 2>/dev/null || true
# Compile sources using platform-specific libs
JFX_COMPILE_PATH="${TARGET}/jfx-libs"
javac ${COMPILATION_OPTS} --module-path ${JFX_COMPILE_PATH} --add-modules ${JFX_MODULES} -cp "${JFX_COMPILE_PATH}/*" $(find $SRC/main/java $RESOURCES -name "*.java") -d ${CLASSES}
# create MANIFEST file
cp -vr $RESOURCES/* $CLASSES
echo "done."
echo ---
echo "build jar..."
for app in ${main_class}
do
mkdir -p $TARGET/META-INF
echo ">> for ${project_name}.$app..."
echo """
Manifest-Version: ${project_name}
Main-Class: ${app}
Class-Path: ${JARS}
Created-By: ${JAVA_BUILD}
Implementation-Title: ${project_name}
Implementation-Version: ${project_version}-build_${GIT_COMMIT_ID:0:12}
Implementation-Vendor: ${vendor_name}
Implementation-Author: ${author_name}
""" >>target/META-INF/MANIFEST.MF
# jar cvfe target/build/${project_name}-$app-${project_version}.jar $app -C target/classes .
# Copy libs into build (use pre-prepared platform-specific libs)
mkdir -p ${BUILD}/libs
cp -v ${TARGET}/jfx-libs/*.jar ${BUILD}/libs/
jar cvfe target/build/${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar $app -C target/classes .
echo "done."
# create run script
echo "create run script ${BUILD}/${project_name}.sh ..."
rm -f ${BUILD}/${project_name}.sh
cat > ${BUILD}/${project_name}.sh << 'LAUNCH_EOF'
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Convert MSYS/Cygwin paths to Windows paths if needed
if command -v cygpath &> /dev/null; then
SCRIPT_DIR="$(cygpath -w "$SCRIPT_DIR")"
fi
if [[ "$OSTYPE" == "linux"* ]] || [[ "$OSTYPE" == "darwin"* ]]; then
FS=":"
else
FS=";"
fi
LAUNCH_EOF
echo "java -Djava.net.preferIPv6Addresses=true --module-path \"\${SCRIPT_DIR}/libs\" --add-modules ${JFX_MODULES} -cp \"\${SCRIPT_DIR}/${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar\${FS}\${SCRIPT_DIR}/libs/*\" $app \"\$@\"" >> ${BUILD}/${project_name}.sh
chmod +x ${BUILD}/${project_name}.sh
done
echo "done."
# Run tests
if( [ "$1" == "test" ] ); then
echo "Run tests..."
echo -e "|_ ${BLUE}6. Execute tests${NC}..."
echo "> from : ${SRC}/test"
echo "> to : ${TARGET}/test-classes"
mkdir -p ${TARGET}/test-classes
echo "copy test resources"
cp -r ./$RESOURCES/* $TEST_CLASSES
echo "compile test classes"
#list test sources (compile test sources only, using already-compiled main classes)
find ${SRC}/test -name '*.java' >${TARGET}/test-sources.lst
javac -encoding $SOURCE_ENCODING $COMPILATION_OPTS -cp ".${FS}$LIB_TEST${FS}${CLASSES}" -d $TEST_CLASSES @${TARGET}/test-sources.lst
echo "execute tests through JUnit"
java $JAR_OPTS -cp "${LIB_TEST}${FS}${CLASSES}${FS}${TEST_CLASSES}${FS}." org.junit.platform.console.ConsoleLauncher execute --scan-class-path
echo -e " |_ ${GREEN}done$NC"
echo "- execute tests through JUnit ${SRC}/test." >>${TARGET}/build.log
fi
if( [ "$1" == "run" ] ); then
echo "Run the generated JAR(s)..."
for app in ${main_class}
do
# echo ">> run JAR ${project_name}-$app-${project_version}.jar ..."
echo ">> run JAR ${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar ..."
shift 1
# java $RUN_OPT -jar ${TARGET}/build/${project_name}-$app-${project_version}.jar $@
java -Djava.net.preferIPv6Addresses=true --module-path "${TARGET}/build/libs" --add-modules ${JFX_MODULES} -cp "${TARGET}/build/${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar${FS}${TARGET}/build/libs/*" $app $@
echo "done."
done
fi
# ─── Helper: package for a given target platform ────────────────────────────
# Usage: do_package_for_os <linux|mac|win>
# Bundles the pre-built JAR + platform JavaFX libs + OS-specific launcher and
# installer. A minimal JRE is embedded via jlink only when TARGET_OS matches
# the current host OS; cross-platform packages ship without an embedded JRE
# (the target machine needs a compatible Java runtime).
do_package_for_os() {
local TARGET_OS="$1"
local HOST_OS="${JFX_OS_SUFFIX}"
local DIST_DIR="${TARGET}/dist/${project_name}-${project_version}-${TARGET_OS}-${GIT_COMMIT_ID:0:12}"
local JRE_DIR="${DIST_DIR}/jre"
# Clean and create distribution directory
rm -rf "${DIST_DIR}"
mkdir -p "${DIST_DIR}"
# ── Build artifacts ──────────────────────────────────────────────────────
echo "Copying build artifacts..."
cp "${BUILD}/${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar" "${DIST_DIR}/"
mkdir -p "${DIST_DIR}/libs"
# Copy common (platform-independent) libs first
if [[ -d "libs/common" ]] && ls libs/common/*.jar &>/dev/null 2>&1; then
cp libs/common/*.jar "${DIST_DIR}/libs/"
echo " Copied common libs from libs/common/"
fi
# Copy platform-specific JavaFX libs
if [[ -d "libs/${TARGET_OS}" ]] && ls libs/${TARGET_OS}/*.jar &>/dev/null 2>&1; then
cp libs/${TARGET_OS}/*.jar "${DIST_DIR}/libs/"
echo " Using platform JavaFX libs from libs/${TARGET_OS}/"
else
cp ${BUILD}/libs/*.jar "${DIST_DIR}/libs/"
echo -e " ${YELLOW}Warning: no libs/${TARGET_OS}/ found – using current-build libs.${NC}"
fi
# ── Minimal JRE (jlink, host platform only) ──────────────────────────────
JRE_MODULES="java.base,java.desktop,java.logging,java.xml,java.net.http,java.scripting,jdk.xml.dom,java.sql,java.naming,java.prefs,jdk.unsupported,jdk.jsobject"
if [[ "$TARGET_OS" == "$HOST_OS" ]]; then
echo "Creating minimal JRE with jlink..."
jlink --module-path "${TARGET}/jfx-libs" \
--add-modules ${JRE_MODULES} \
--output "${JRE_DIR}" \
--strip-debug \
--compress zip-6 \
--no-header-files \
--no-man-pages
echo "JRE created: $(du -sh ${JRE_DIR} | cut -f1)"
else
echo -e " ${YELLOW}Skipping jlink for ${TARGET_OS} (requires a ${TARGET_OS} JDK on this host).${NC}"
echo -e " ${YELLOW}The package will require a compatible JRE installed on the target system.${NC}"
fi
# ── Launcher script ──────────────────────────────────────────────────────
echo "Creating launcher script..."
if [[ "$TARGET_OS" == "win" ]]; then
if [[ -d "${JRE_DIR}" ]]; then
cat > "${DIST_DIR}/${project_name}.bat" << WINLAUNCHER_JRE
@echo off
setlocal
set SCRIPT_DIR=%~dp0
set JRE_PATH=%SCRIPT_DIR%jre\\bin\\java.exe
"%JRE_PATH%" --module-path "%SCRIPT_DIR%libs" --add-modules ${JFX_MODULES} -cp "%SCRIPT_DIR%${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar;%SCRIPT_DIR%libs\\*" ${main_class} %*
endlocal
WINLAUNCHER_JRE
else
cat > "${DIST_DIR}/${project_name}.bat" << WINLAUNCHER_NOJRE
@echo off
setlocal
set SCRIPT_DIR=%~dp0
java -Djava.net.preferIPv6Addresses=true --module-path "%SCRIPT_DIR%libs" --add-modules ${JFX_MODULES} -cp "%SCRIPT_DIR%${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar;%SCRIPT_DIR%libs\\*" ${main_class} %*
endlocal
WINLAUNCHER_NOJRE
fi
else
if [[ -d "${JRE_DIR}" ]]; then
cat > "${DIST_DIR}/${project_name}.sh" << 'UNIXLAUNCHER_JRE_START'
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
JRE_PATH="${SCRIPT_DIR}/jre/bin/java"
UNIXLAUNCHER_JRE_START
echo "\"\${JRE_PATH}\" --module-path \"\${SCRIPT_DIR}/libs\" --add-modules ${JFX_MODULES} -cp \"\${SCRIPT_DIR}/${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar:\${SCRIPT_DIR}/libs/*\" ${main_class} \"\$@\"" >> "${DIST_DIR}/${project_name}.sh"
else
cat > "${DIST_DIR}/${project_name}.sh" << 'UNIXLAUNCHER_NOJRE_START'
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
UNIXLAUNCHER_NOJRE_START
echo "java -Djava.net.preferIPv6Addresses=true --module-path \"\${SCRIPT_DIR}/libs\" --add-modules ${JFX_MODULES} -cp \"\${SCRIPT_DIR}/${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar:\${SCRIPT_DIR}/libs/*\" ${main_class} \"\$@\"" >> "${DIST_DIR}/${project_name}.sh"
fi
chmod +x "${DIST_DIR}/${project_name}.sh"
fi
# ── Application icons ────────────────────────────────────────────────────
echo "Copying application icons..."
mkdir -p "${DIST_DIR}/icons"
cp ${SRC}/main/resources/images/icons/marknote.svg "${DIST_DIR}/icons/" 2>/dev/null || true
cp ${SRC}/main/resources/images/icons/marknote.ico "${DIST_DIR}/icons/" 2>/dev/null || true
cp ${SRC}/main/resources/images/icons/marknote-128.png "${DIST_DIR}/icons/" 2>/dev/null || true
cp ${SRC}/main/resources/images/icons/marknote-64.png "${DIST_DIR}/icons/" 2>/dev/null || true
cp ${SRC}/main/resources/images/icons/marknote-32.png "${DIST_DIR}/icons/" 2>/dev/null || true
cp ${SRC}/main/resources/images/icons/marknote-16.png "${DIST_DIR}/icons/" 2>/dev/null || true
# ── OS-specific installer ────────────────────────────────────────────────
echo "Generating installer script for ${TARGET_OS}..."
if [[ "$TARGET_OS" == "linux" ]]; then
#----- Linux installer: install to ~/.local and create desktop shortcut -----
cat > "${DIST_DIR}/install.sh" << 'LINUX_INSTALL_EOF'
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
APP_NAME="MarkNote"
LINUX_INSTALL_EOF
echo "APP_VERSION=\"${project_version}\"" >> "${DIST_DIR}/install.sh"
cat >> "${DIST_DIR}/install.sh" << 'LINUX_INSTALL_EOF2'
INSTALL_DIR="${HOME}/.local/share/${APP_NAME}"
BIN_DIR="${HOME}/.local/bin"
DESKTOP_DIR="${HOME}/.local/share/applications"
ICON_DIR="${HOME}/.local/share/icons/hicolor"
echo "========================================="
echo " ${APP_NAME} ${APP_VERSION} - Installer"
echo "========================================="
echo ""
echo "This will install ${APP_NAME} to:"
echo " ${INSTALL_DIR}"
echo ""
# ── Check for a previous installation ──────────────────────────────────────
if [[ -d "${INSTALL_DIR}" ]]; then
PREV_JAR=$(ls "${INSTALL_DIR}"/*.jar 2>/dev/null | head -1)
if [[ -n "${PREV_JAR}" ]]; then
PREV_VERSION=$(basename "${PREV_JAR}" | sed 's/${APP_NAME}-\(.*\)\.jar/\1/')
echo " WARNING: A previous version (${PREV_VERSION}) is already installed."
else
echo " WARNING: A previous installation was found in ${INSTALL_DIR}."
fi
echo ""
read -p "Uninstall the previous version before installing? [Y/n] " do_uninstall
if [[ ! "$do_uninstall" =~ ^[Nn] ]]; then
echo "Removing previous installation..."
rm -rf "${INSTALL_DIR}"
rm -f "${BIN_DIR}/marknote"
rm -f "${DESKTOP_DIR}/marknote.desktop"
rm -f "${HOME}/Desktop/marknote.desktop"
echo "Previous version removed."
echo ""
fi
fi
# ────────────────────────────────────────────────────────────────────────────
read -p "Continue? [Y/n] " confirm
if [[ "$confirm" =~ ^[Nn] ]]; then
echo "Installation cancelled."
exit 0
fi
# Create installation directory
echo "Installing ${APP_NAME}..."
mkdir -p "${INSTALL_DIR}"
mkdir -p "${BIN_DIR}"
mkdir -p "${DESKTOP_DIR}"
# Copy application files
cp -r "${SCRIPT_DIR}"/*.jar "${INSTALL_DIR}/"
cp -r "${SCRIPT_DIR}/libs" "${INSTALL_DIR}/"
if [[ -d "${SCRIPT_DIR}/jre" ]]; then cp -r "${SCRIPT_DIR}/jre" "${INSTALL_DIR}/"; fi
cp -r "${SCRIPT_DIR}/icons" "${INSTALL_DIR}/"
cp "${SCRIPT_DIR}/${APP_NAME}.sh" "${INSTALL_DIR}/"
chmod +x "${INSTALL_DIR}/${APP_NAME}.sh"
# Install icons at standard sizes
for size in 16 32 64 128; do
icon_file="${INSTALL_DIR}/icons/marknote-${size}.png"
if [[ -f "${icon_file}" ]]; then
mkdir -p "${ICON_DIR}/${size}x${size}/apps"
cp "${icon_file}" "${ICON_DIR}/${size}x${size}/apps/marknote.png"
fi
done
# Install SVG icon
if [[ -f "${INSTALL_DIR}/icons/marknote.svg" ]]; then
mkdir -p "${ICON_DIR}/scalable/apps"
cp "${INSTALL_DIR}/icons/marknote.svg" "${ICON_DIR}/scalable/apps/marknote.svg"
fi
# Create symlink in ~/.local/bin
ln -sf "${INSTALL_DIR}/${APP_NAME}.sh" "${BIN_DIR}/marknote"
# Create .desktop file for application menu
cat > "${DESKTOP_DIR}/marknote.desktop" << DESKTOP_EOF
[Desktop Entry]
Type=Application
Name=${APP_NAME}
Comment=Markdown Note Editor
Exec=${INSTALL_DIR}/${APP_NAME}.sh %F
Icon=${INSTALL_DIR}/icons/marknote.svg
Terminal=false
Categories=Utility;TextEditor;
MimeType=text/markdown;text/x-markdown;text/plain;
StartupWMClass=MarkNote
DESKTOP_EOF
# Create desktop shortcut
DESKTOP_SHORTCUT="${HOME}/Desktop/marknote.desktop"
if [[ -d "${HOME}/Desktop" ]]; then
cp "${DESKTOP_DIR}/marknote.desktop" "${DESKTOP_SHORTCUT}"
chmod +x "${DESKTOP_SHORTCUT}"
# Mark as trusted on GNOME-based desktops
if command -v gio &> /dev/null; then
gio set "${DESKTOP_SHORTCUT}" metadata::trusted true 2>/dev/null || true
fi
echo "Desktop shortcut created."
fi
# Update icon cache if available
if command -v gtk-update-icon-cache &> /dev/null; then
gtk-update-icon-cache -f -t "${ICON_DIR}" 2>/dev/null || true
fi
# Update desktop database if available
if command -v update-desktop-database &> /dev/null; then
update-desktop-database "${DESKTOP_DIR}" 2>/dev/null || true
fi
echo ""
echo "========================================="
echo " ${APP_NAME} installed successfully!"
echo "========================================="
echo ""
echo " Location : ${INSTALL_DIR}"
echo " Command : marknote (if ~/.local/bin is in PATH)"
echo " Shortcut : Desktop & Application Menu"
echo ""
echo "To uninstall, run:"
echo " rm -rf ${INSTALL_DIR}"
echo " rm -f ${BIN_DIR}/marknote"
echo " rm -f ${DESKTOP_DIR}/marknote.desktop"
echo " rm -f ${DESKTOP_SHORTCUT}"
LINUX_INSTALL_EOF2
chmod +x "${DIST_DIR}/install.sh"
echo -e " ${GREEN}Linux installer created.${NC}"
elif [[ "$TARGET_OS" == "win" ]]; then
#----- Windows installer: install to %LOCALAPPDATA% (no admin required) -----
cat > "${DIST_DIR}/install.bat" << 'WIN_INSTALL_EOF'
@echo off
setlocal EnableDelayedExpansion
set APP_NAME=MarkNote
WIN_INSTALL_EOF
echo "set APP_VERSION=${project_version}" >> "${DIST_DIR}/install.bat"
cat >> "${DIST_DIR}/install.bat" << 'WIN_INSTALL_EOF2'
set INSTALL_DIR=%LOCALAPPDATA%\%APP_NAME%
set SCRIPT_DIR=%~dp0
set START_MENU=%APPDATA%\Microsoft\Windows\Start Menu\Programs
echo =========================================
echo %APP_NAME% %APP_VERSION% - Installer
echo =========================================
echo.
echo This will install %APP_NAME% to:
echo %INSTALL_DIR%
echo.
rem ── Check for a previous installation ──────────────────────────────────────
if exist "%INSTALL_DIR%" (
set PREV_VERSION=unknown
for %%f in ("%INSTALL_DIR%\%APP_NAME%-*.jar") do (
set "JARFILE=%%~nf"
set "PREV_VERSION=!JARFILE:%APP_NAME%-=!"
)
echo WARNING: A previous installation was detected: !PREV_VERSION!
echo.
set /p DO_UNINSTALL="Uninstall the previous version before installing? [Y/n] "
if /i not "!DO_UNINSTALL!"=="n" (
echo Removing previous installation...
rmdir /S /Q "%INSTALL_DIR%"
if exist "%USERPROFILE%\Desktop\%APP_NAME%.lnk" del /Q "%USERPROFILE%\Desktop\%APP_NAME%.lnk"
if exist "%START_MENU%\%APP_NAME%.lnk" del /Q "%START_MENU%\%APP_NAME%.lnk"
echo Previous version removed.
echo.
)
)
rem ─────────────────────────────────────────────────────────────────────────────
set /p CONFIRM="Continue? [Y/n] "
if /i "%CONFIRM%"=="n" (
echo Installation cancelled.
exit /b 0
)
echo Installing %APP_NAME%...
:: Create installation directory
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
if not exist "%INSTALL_DIR%\libs" mkdir "%INSTALL_DIR%\libs"
if not exist "%INSTALL_DIR%\icons" mkdir "%INSTALL_DIR%\icons"
:: Copy application files
xcopy /Y /Q "%SCRIPT_DIR%*.jar" "%INSTALL_DIR%\"
xcopy /Y /Q /E "%SCRIPT_DIR%libs\*" "%INSTALL_DIR%\libs\"
if exist "%SCRIPT_DIR%jre" xcopy /Y /Q /E /I "%SCRIPT_DIR%jre" "%INSTALL_DIR%\jre"
xcopy /Y /Q /E "%SCRIPT_DIR%icons\*" "%INSTALL_DIR%\icons\"
copy /Y "%SCRIPT_DIR%%APP_NAME%.bat" "%INSTALL_DIR%\"
:: Create Desktop shortcut using PowerShell
echo Creating Desktop shortcut...
powershell -NoProfile -Command "$ws = New-Object -ComObject WScript.Shell; $sc = $ws.CreateShortcut([System.IO.Path]::Combine([Environment]::GetFolderPath('Desktop'), '%APP_NAME%.lnk')); $sc.TargetPath = '%INSTALL_DIR%\%APP_NAME%.bat'; $sc.WorkingDirectory = '%INSTALL_DIR%'; $sc.IconLocation = '%INSTALL_DIR%\icons\marknote.ico'; $sc.Description = 'MarkNote - Markdown Note Editor'; $sc.Save()"
:: Create Start Menu shortcut
echo Creating Start Menu shortcut...
powershell -NoProfile -Command "$ws = New-Object -ComObject WScript.Shell; $sc = $ws.CreateShortcut('%START_MENU%\%APP_NAME%.lnk'); $sc.TargetPath = '%INSTALL_DIR%\%APP_NAME%.bat'; $sc.WorkingDirectory = '%INSTALL_DIR%'; $sc.IconLocation = '%INSTALL_DIR%\icons\marknote.ico'; $sc.Description = 'MarkNote - Markdown Note Editor'; $sc.Save()"
echo.
echo =========================================
echo %APP_NAME% installed successfully!
echo =========================================
echo.
echo Location : %INSTALL_DIR%
echo Shortcuts: Desktop ^& Start Menu
echo.
echo To uninstall, delete:
echo %INSTALL_DIR%
echo Desktop shortcut: %APP_NAME%.lnk
echo Start Menu: %START_MENU%\%APP_NAME%.lnk
echo.
pause
WIN_INSTALL_EOF2
echo -e " ${GREEN}Windows installer created.${NC}"
elif [[ "$TARGET_OS" == "mac" ]]; then
if [[ "$TARGET_OS" == "$HOST_OS" ]] && command -v jpackage &>/dev/null; then
# ── Native macOS DMG via jpackage ─────────────────────────────────
echo "Creating macOS DMG with jpackage..."
# Input directory: main JAR + non-JavaFX libs only.
# JavaFX modules are bundled into the app image via --module-path / --add-modules.
local JPACKAGE_INPUT="${TARGET}/jpackage-input"
rm -rf "${JPACKAGE_INPUT}"
mkdir -p "${JPACKAGE_INPUT}"
cp "${BUILD}/${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar" "${JPACKAGE_INPUT}/"
if [[ -d "libs/common" ]] && ls libs/common/*.jar &>/dev/null 2>&1; then
cp libs/common/*.jar "${JPACKAGE_INPUT}/" 2>/dev/null || true
echo " Copied common libs into jpackage input."
fi
# Icon resolution: prefer .icns, convert from PNG with sips+iconutil if needed
local ICON_ICNS="${SRC}/main/resources/images/icons/marknote.icns"
local ICON_PNG="${SRC}/main/resources/images/icons/marknote-128.png"
local JPACKAGE_ICON_OPT=()
local ICON_TMPDIR=""
if [[ -f "${ICON_ICNS}" ]]; then
JPACKAGE_ICON_OPT=(--icon "${ICON_ICNS}")
elif [[ -f "${ICON_PNG}" ]] && command -v sips &>/dev/null && command -v iconutil &>/dev/null; then
echo " Converting PNG icon to .icns..."
ICON_TMPDIR=$(mktemp -d)
local ICONSET_DIR="${ICON_TMPDIR}/marknote.iconset"
mkdir -p "${ICONSET_DIR}"
for sz in 16 32 64 128 256 512; do
sips -z ${sz} ${sz} "${ICON_PNG}" --out "${ICONSET_DIR}/icon_${sz}x${sz}.png" 2>/dev/null || true
done
for sz in 16 32 128 256; do
local dbl=$(( sz * 2 ))
sips -z ${dbl} ${dbl} "${ICON_PNG}" --out "${ICONSET_DIR}/icon_${sz}x${sz}@2x.png" 2>/dev/null || true
done
local GENERATED_ICNS="${ICON_TMPDIR}/marknote.icns"
iconutil -c icns "${ICONSET_DIR}" -o "${GENERATED_ICNS}" 2>/dev/null || true
[[ -f "${GENERATED_ICNS}" ]] && JPACKAGE_ICON_OPT=(--icon "${GENERATED_ICNS}")
fi
mkdir -p "${TARGET}/dist"
jpackage \
--type dmg \
--name "${project_name}" \
--app-version "${project_version}" \
--vendor "${vendor_name}" \
--description "Markdown Note Editor" \
--input "${JPACKAGE_INPUT}" \
--main-jar "${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar" \
--main-class "${main_class}" \
--module-path "${TARGET}/jfx-libs" \
--add-modules "${JFX_MODULES}" \
--java-options "-Djava.net.preferIPv6Addresses=true" \
--dest "${TARGET}/dist" \
--mac-package-identifier "com.snapgames.marknote" \
--mac-package-name "${project_name}" \
"${JPACKAGE_ICON_OPT[@]}"
[[ -n "${ICON_TMPDIR}" ]] && rm -rf "${ICON_TMPDIR}"
local DMG_FILE
DMG_FILE=$(ls "${TARGET}/dist/${project_name}"*.dmg 2>/dev/null | head -1)
if [[ -f "${DMG_FILE}" ]]; then
echo -e "${GREEN}macOS DMG created: ${DMG_FILE}${NC}"
echo "Package size: $(du -sh "${DMG_FILE}" | cut -f1)"
else
echo -e "${YELLOW}Warning: DMG not found – check ${TARGET}/dist/${NC}"
ls -lh "${TARGET}/dist/" 2>/dev/null || true
fi
echo "done."
return 0
fi
# ── Fallback: .app bundle + install.sh ────────────────────────────────
if [[ "$HOST_OS" != "mac" ]]; then
echo -e " ${YELLOW}Cross-platform build: jpackage DMG requires a macOS host – falling back to .app bundle + install.sh.${NC}"
else
echo -e " ${YELLOW}jpackage not found in PATH – falling back to .app bundle + install.sh.${NC}"
fi
#----- macOS installer: create .app bundle in ~/Applications -----
cat > "${DIST_DIR}/install.sh" << 'MAC_INSTALL_EOF'
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
APP_NAME="MarkNote"
MAC_INSTALL_EOF
# Inject build-time values
echo "APP_VERSION=\"${project_version}\"" >> "${DIST_DIR}/install.sh"
echo "JAR_NAME=\"${project_name}-${project_version}-${GIT_COMMIT_ID:0:12}.jar\"" >> "${DIST_DIR}/install.sh"
echo "JFX_MODULES=\"${JFX_MODULES}\"" >> "${DIST_DIR}/install.sh"
echo "MAIN_CLASS=\"${main_class}\"" >> "${DIST_DIR}/install.sh"
cat >> "${DIST_DIR}/install.sh" << 'MAC_INSTALL_EOF2'
APP_BUNDLE="${HOME}/Applications/${APP_NAME}.app"
echo "========================================="
echo " ${APP_NAME} ${APP_VERSION} - Installer"
echo "========================================="
echo ""
echo "This will install ${APP_NAME} as an application bundle to:"
echo " ${APP_BUNDLE}"
echo ""
# ── Check for a previous installation ──────────────────────────────────────
if [[ -d "${APP_BUNDLE}" ]]; then
PLIST="${APP_BUNDLE}/Contents/Info.plist"
if [[ -f "${PLIST}" ]]; then
PREV_VERSION=$(grep -A1 'CFBundleShortVersionString' "${PLIST}" \
| grep '<string>' | sed 's/.*<string>\(.*\)<\/string>/\1/' | tr -d '[:space:]')
echo " WARNING: A previous version (${PREV_VERSION}) is already installed."
else
echo " WARNING: A previous installation was found at ${APP_BUNDLE}."
fi
echo ""
read -p "Remove the previous version before installing? [Y/n] " do_uninstall
if [[ ! "$do_uninstall" =~ ^[Nn] ]]; then
echo "Removing previous installation..."
rm -rf "${APP_BUNDLE}"
echo "Previous version removed."
echo ""
fi
fi
# ────────────────────────────────────────────────────────────────────────────
read -p "Continue? [Y/n] " confirm
if [[ "$confirm" =~ ^[Nn] ]]; then
echo "Installation cancelled."
exit 0
fi
echo "Installing ${APP_NAME}..."
# Create .app bundle structure
mkdir -p "${APP_BUNDLE}/Contents/MacOS"
mkdir -p "${APP_BUNDLE}/Contents/Resources"
# Copy application files into Resources
cp -r "${SCRIPT_DIR}"/*.jar "${APP_BUNDLE}/Contents/Resources/"
cp -r "${SCRIPT_DIR}/libs" "${APP_BUNDLE}/Contents/Resources/"
if [[ -d "${SCRIPT_DIR}/jre" ]]; then cp -r "${SCRIPT_DIR}/jre" "${APP_BUNDLE}/Contents/Resources/"; fi
# Convert PNG icon to .icns if possible, otherwise use PNG
ICON_SRC="${SCRIPT_DIR}/icons/marknote-128.png"
ICNS_FILE="${APP_BUNDLE}/Contents/Resources/marknote.icns"
if command -v sips &> /dev/null && command -v iconutil &> /dev/null; then
echo "Creating macOS icon..."
ICONSET_DIR=$(mktemp -d)/marknote.iconset
mkdir -p "${ICONSET_DIR}"
for size in 16 32 64 128 256 512; do
sips -z ${size} ${size} "${ICON_SRC}" --out "${ICONSET_DIR}/icon_${size}x${size}.png" 2>/dev/null || true
done
for size in 16 32 128 256; do
double=$((size * 2))
sips -z ${double} ${double} "${ICON_SRC}" --out "${ICONSET_DIR}/icon_${size}x${size}@2x.png" 2>/dev/null || true
done
iconutil -c icns "${ICONSET_DIR}" -o "${ICNS_FILE}" 2>/dev/null || true
rm -rf "$(dirname "${ICONSET_DIR}")"
fi
if [[ ! -f "${ICNS_FILE}" ]]; then
cp "${ICON_SRC}" "${APP_BUNDLE}/Contents/Resources/marknote.png"
fi
# Create Info.plist
cat > "${APP_BUNDLE}/Contents/Info.plist" << PLIST_EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>${APP_NAME}</string>
<key>CFBundleDisplayName</key>
<string>${APP_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.snapgames.marknote</string>
<key>CFBundleVersion</key>
<string>${APP_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${APP_VERSION}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleExecutable</key>
<string>MarkNote</string>
<key>CFBundleIconFile</key>
<string>marknote</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>md</string>
<string>markdown</string>
<string>txt</string>
</array>
<key>CFBundleTypeName</key>
<string>Markdown Document</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
</dict>
</array>
</dict>
</plist>
PLIST_EOF
# Create launcher executable in MacOS/
JRE_EXEC="${SCRIPT_DIR}/jre/bin/java"
if [[ ! -f "${JRE_EXEC}" ]]; then JRE_EXEC="java"; fi
cat > "${APP_BUNDLE}/Contents/MacOS/${APP_NAME}" << MACOS_LAUNCHER_EOF
#!/bin/bash
CONTENTS_DIR="\$(cd "\$(dirname "\$0")/.." && pwd)"
RESOURCES="\${CONTENTS_DIR}/Resources"
JRE_PATH="${JRE_EXEC}"
"\${JRE_PATH}" --module-path "\${RESOURCES}/libs" --add-modules ${JFX_MODULES} -cp "\${RESOURCES}/${JAR_NAME}:\${RESOURCES}/libs/*" ${MAIN_CLASS} "\$@"
MACOS_LAUNCHER_EOF
chmod +x "${APP_BUNDLE}/Contents/MacOS/${APP_NAME}"
echo ""
echo "========================================="
echo " ${APP_NAME} installed successfully!"
echo "========================================="
echo ""
echo " Location: ${APP_BUNDLE}"
echo " Launch : Open from ~/Applications or Spotlight"
echo ""
echo "To uninstall, run:"
echo " rm -rf ${APP_BUNDLE}"
MAC_INSTALL_EOF2
chmod +x "${DIST_DIR}/install.sh"
echo -e " ${GREEN}macOS installer created.${NC}"
fi
# ── ZIP archive ──────────────────────────────────────────────────────────
echo "Creating ZIP archive..."
local PACKAGE_NAME="${project_name}-${project_version}-${TARGET_OS}-${GIT_COMMIT_ID:0:12}.zip"
cd "${TARGET}/dist"
zip -r "../${PACKAGE_NAME}" "${project_name}-${project_version}-${TARGET_OS}-${GIT_COMMIT_ID:0:12}"
cd - > /dev/null
echo -e "${GREEN}Package created: ${TARGET}/${PACKAGE_NAME}${NC}"
echo "Package size: $(du -sh ${TARGET}/${PACKAGE_NAME} | cut -f1)"
echo "done."
}
if( [ "$1" == "package" ] ); then
echo "Creating distribution package..."
# Clean dist directory before packaging
rm -rf "${TARGET}/dist"
do_package_for_os "${JFX_OS_SUFFIX}"
fi
if( [ "$1" == "package-all" ] ); then
echo "Creating distribution packages for all platforms (linux, mac, win)..."
echo "(Note: an embedded JRE is bundled only for the current host platform: ${JFX_OS_SUFFIX})"
echo ""
# Clean dist directory once before all platforms
rm -rf "${TARGET}/dist"
mkdir -p "${TARGET}/dist"
FAILED_PLATFORMS=()
for OS_TARGET in linux mac win; do
echo "────────────────────────────────────────────────"
echo -e "${BLUE}>>> Packaging for ${OS_TARGET}...${NC}"
echo "────────────────────────────────────────────────"
if do_package_for_os "${OS_TARGET}"; then
echo -e "${GREEN}<<< ${OS_TARGET} package done.${NC}"
else
echo -e "${RED}<<< ${OS_TARGET} package FAILED.${NC}"
FAILED_PLATFORMS+=("${OS_TARGET}")
fi
echo ""
done
echo "════════════════════════════════════════════════"
echo -e "${GREEN}package-all complete.${NC}"
echo "Packages in ${TARGET}/:"
ls -lh "${TARGET}"/*.zip 2>/dev/null || echo " (no zip files found)"
if [[ ${#FAILED_PLATFORMS[@]} -gt 0 ]]; then
echo -e "${RED}Failed platforms: ${FAILED_PLATFORMS[*]}${NC}"
fi
echo "════════════════════════════════════════════════"
fi