mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2026-07-01 19:06:58 +03:00
Compare commits
106 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdfdf2eef1 | ||
|
|
bbfa5a5ed1 | ||
|
|
43dc330e55 | ||
|
|
0c962dff59 | ||
|
|
ca0dd583ba | ||
|
|
7bb686c85b | ||
|
|
f8d3d8399d | ||
|
|
9cb2a3ab2d | ||
|
|
072c495ec6 | ||
|
|
335941fb46 | ||
|
|
ebeff36da5 | ||
|
|
1d29f63bec | ||
|
|
87dc1bb6a6 | ||
|
|
a85720b8d6 | ||
|
|
4c28a94de1 | ||
|
|
344ae87f25 | ||
|
|
577999bd35 | ||
|
|
887db29f35 | ||
|
|
7865b8128e | ||
|
|
a58f125535 | ||
|
|
d1a05d312d | ||
|
|
bbf21e5824 | ||
|
|
73b4223b61 | ||
|
|
686e0b7b18 | ||
|
|
189878e7e3 | ||
|
|
af74d5f410 | ||
|
|
cdfd0b1002 | ||
|
|
9791c306dc | ||
|
|
e7e9265c40 | ||
|
|
e0c323a190 | ||
|
|
a914747416 | ||
|
|
d453240a94 | ||
|
|
4c4017d7ca | ||
|
|
2a4c4ed8ea | ||
|
|
947fbf7d64 | ||
|
|
1c94a3e3e5 | ||
|
|
eefeb5799d | ||
|
|
6c6a4625ab | ||
|
|
6d2a96f6a7 | ||
|
|
ea9029d7b6 | ||
|
|
76602391f4 | ||
|
|
509f8c7307 | ||
|
|
984daa450b | ||
|
|
04e1a97d59 | ||
|
|
1dce1360bd | ||
|
|
87d5b96760 | ||
|
|
7f074ca7b9 | ||
|
|
c0394c52b7 | ||
|
|
53bc20f13f | ||
|
|
40af3cf3d2 | ||
|
|
3977918c5b | ||
|
|
484d90899f | ||
|
|
0f5eb03839 | ||
|
|
d21cda1880 | ||
|
|
52a321b93b | ||
|
|
dd8dec8be8 | ||
|
|
23d6f8aaed | ||
|
|
d105d76f2a | ||
|
|
698a838b56 | ||
|
|
1129b4160c | ||
|
|
63a6f823fd | ||
|
|
db32b2ad99 | ||
|
|
c3cf5d31da | ||
|
|
1e696328bb | ||
|
|
1d9c97803a | ||
|
|
3d55236fdf | ||
|
|
42190819ae | ||
|
|
130714a9ab | ||
|
|
bf57d77075 | ||
|
|
98fe035442 | ||
|
|
8e4994590b | ||
|
|
0722dba820 | ||
|
|
9560447c92 | ||
|
|
4d89512ca1 | ||
|
|
42a6bd1151 | ||
|
|
f06505b138 | ||
|
|
d854087089 | ||
|
|
31031ec923 | ||
|
|
5f06517b62 | ||
|
|
dde5fc47d3 | ||
|
|
76d5f632dc | ||
|
|
27c6596bcb | ||
|
|
e2f5fb27a6 | ||
|
|
98819a0d02 | ||
|
|
2dde2c4bec | ||
|
|
008d69e5e5 | ||
|
|
a839258c07 | ||
|
|
89041531e1 | ||
|
|
729cec5f45 | ||
|
|
80d675d2e6 | ||
|
|
fb7d19941f | ||
|
|
877ab62c2f | ||
|
|
b983ae0fb0 | ||
|
|
85422427b9 | ||
|
|
51a71d0471 | ||
|
|
25eaa4eba6 | ||
|
|
6da14d66bb | ||
|
|
199c5497d3 | ||
|
|
740db2db02 | ||
|
|
577f8074e1 | ||
|
|
c5e7bb90c5 | ||
|
|
1cf91fa5d9 | ||
|
|
3bf4fbf8f4 | ||
|
|
ff97affa72 | ||
|
|
e8c9722a53 | ||
|
|
9a810dfa6e |
1151 changed files with 26954 additions and 52303 deletions
|
|
@ -5,7 +5,6 @@ AllowShortIfStatementsOnASingleLine: false
|
||||||
ColumnLimit: 140
|
ColumnLimit: 140
|
||||||
---
|
---
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
AccessModifierOffset: -1
|
|
||||||
AlignConsecutiveMacros: None
|
AlignConsecutiveMacros: None
|
||||||
AlignConsecutiveAssignments: None
|
AlignConsecutiveAssignments: None
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
|
|
@ -16,4 +15,3 @@ BraceWrapping:
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeComma
|
||||||
Cpp11BracedListStyle: false
|
Cpp11BracedListStyle: false
|
||||||
QualifierAlignment: Left
|
|
||||||
|
|
|
||||||
33
.clang-tidy
33
.clang-tidy
|
|
@ -1,32 +1,5 @@
|
||||||
FormatStyle: file
|
|
||||||
|
|
||||||
Checks:
|
Checks:
|
||||||
"bugprone-*,clang-analyzer-*,cppcoreguidelines-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,
|
- modernize-use-using
|
||||||
-*-magic-numbers,
|
- readability-avoid-const-params-in-decls
|
||||||
-*-non-private-member-variables-in-classes,
|
|
||||||
-*-special-member-functions,
|
|
||||||
-bugprone-easily-swappable-parameters,
|
|
||||||
-cppcoreguidelines-owning-memory,
|
|
||||||
-cppcoreguidelines-pro-type-static-cast-downcast,
|
|
||||||
-modernize-use-nodiscard,
|
|
||||||
-modernize-use-trailing-return-type,
|
|
||||||
-portability-avoid-pragma-once,
|
|
||||||
-readability-avoid-unconditional-preprocessor-if,
|
|
||||||
-readability-function-cognitive-complexity,
|
|
||||||
-readability-identifier-length,
|
|
||||||
-readability-redundant-access-specifiers"
|
|
||||||
|
|
||||||
CheckOptions:
|
SystemHeaders: false
|
||||||
misc-include-cleaner.MissingIncludes: false
|
|
||||||
readability-identifier-naming.DefaultCase: "camelBack"
|
|
||||||
readability-identifier-naming.NamespaceCase: "CamelCase"
|
|
||||||
readability-identifier-naming.ClassCase: "CamelCase"
|
|
||||||
readability-identifier-naming.ClassConstantCase: "CamelCase"
|
|
||||||
readability-identifier-naming.EnumCase: "CamelCase"
|
|
||||||
readability-identifier-naming.EnumConstantCase: "CamelCase"
|
|
||||||
readability-identifier-naming.MacroDefinitionCase: "UPPER_CASE"
|
|
||||||
readability-identifier-naming.ClassMemberPrefix: "m_"
|
|
||||||
readability-identifier-naming.StaticConstantPrefix: "s_"
|
|
||||||
readability-identifier-naming.StaticVariablePrefix: "s_"
|
|
||||||
readability-identifier-naming.GlobalConstantPrefix: "g_"
|
|
||||||
readability-implicit-bool-conversion.AllowPointerConditions: true
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,8 @@
|
||||||
# EditorConfig specs and documentation: https://EditorConfig.org
|
# EditorConfig specs and documentation: https://EditorConfig.org
|
||||||
|
|
||||||
# top-most EditorConfig file
|
# top-most EditorConfig file
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
# C++ Code Style settings
|
||||||
indent_style = space
|
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
|
||||||
indent_size = 4
|
cpp_generate_documentation_comments = doxygen_slash_star
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.{yml,nix}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# C++ Code Style settings
|
|
||||||
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
|
|
||||||
cpp_generate_documentation_comments = doxygen_slash_star
|
|
||||||
|
|
||||||
[CMakeLists.txt]
|
|
||||||
ij_continuation_indent_size = 4
|
|
||||||
|
|
|
||||||
2
.envrc
2
.envrc
|
|
@ -1,2 +1,2 @@
|
||||||
use nix
|
use flake
|
||||||
watch_file nix/*.nix
|
watch_file nix/*.nix
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,3 @@ bbb3b3e6f6e3c0f95873f22e6d0a4aaf350f49d9
|
||||||
|
|
||||||
# (nix) alejandra -> nixfmt
|
# (nix) alejandra -> nixfmt
|
||||||
4c81d8c53d09196426568c4a31a4e752ed05397a
|
4c81d8c53d09196426568c4a31a4e752ed05397a
|
||||||
|
|
||||||
# reformat codebase
|
|
||||||
1d468ac35ad88d8c77cc83f25e3704d9bd7df01b
|
|
||||||
|
|
||||||
# format a part of codebase
|
|
||||||
5c8481a118c8fefbfe901001d7828eaf6866eac4
|
|
||||||
|
|
|
||||||
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: File a bug report
|
description: File a bug report
|
||||||
labels: ["bug: unconfirmed", "status: needs triage"]
|
labels: [bug]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
@ -23,14 +23,14 @@ body:
|
||||||
- macOS
|
- macOS
|
||||||
- Linux
|
- Linux
|
||||||
- Other
|
- Other
|
||||||
- type: input
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Version of Prism Launcher
|
label: Version of Prism Launcher
|
||||||
description: The version of Prism Launcher used in the bug report.
|
description: The version of Prism Launcher used in the bug report.
|
||||||
placeholder: Prism Launcher 5.0
|
placeholder: Prism Launcher 5.0
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Version of Qt
|
label: Version of Qt
|
||||||
description: The version of Qt used in the bug report. You can find it in Help -> About Prism Launcher -> About Qt.
|
description: The version of Qt used in the bug report. You can find it in Help -> About Prism Launcher -> About Qt.
|
||||||
|
|
|
||||||
6
.github/ISSUE_TEMPLATE/rfc.yml
vendored
6
.github/ISSUE_TEMPLATE/rfc.yml
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst
|
# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst
|
||||||
name: Request for Comment (RFC)
|
name: Request for Comment (RFC)
|
||||||
description: Propose a larger change and start a discussion.
|
description: Propose a larger change and start a discussion.
|
||||||
labels: ["type: enhancement", "status: needs discussion", "status: needs triage"]
|
labels: [rfc]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
@ -44,8 +44,8 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Unresolved Questions
|
label: Unresolved Questions
|
||||||
description: |
|
description: |
|
||||||
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
|
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
|
||||||
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
|
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
|
||||||
If your RFC is mostly unresolved questions and not too much substance, it may not be ready.
|
If your RFC is mostly unresolved questions and not too much substance, it may not be ready.
|
||||||
placeholder: Do a lot of users care about the cat?
|
placeholder: Do a lot of users care about the cat?
|
||||||
validations:
|
validations:
|
||||||
|
|
|
||||||
2
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
2
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
name: Suggestion
|
name: Suggestion
|
||||||
description: Make a suggestion
|
description: Make a suggestion
|
||||||
labels: ["type: enhancement", "status: needs triage"]
|
labels: [enhancement]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
||||||
153
.github/actions/package/linux/action.yml
vendored
153
.github/actions/package/linux/action.yml
vendored
|
|
@ -1,153 +0,0 @@
|
||||||
name: Package for Linux
|
|
||||||
description: Create Linux packages for Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: Launcher version
|
|
||||||
required: true
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
artifact-name:
|
|
||||||
description: Name of the uploaded artifact
|
|
||||||
required: true
|
|
||||||
default: Linux
|
|
||||||
qt-version:
|
|
||||||
description: Version of Qt to use
|
|
||||||
required: true
|
|
||||||
gpg-private-key:
|
|
||||||
description: Private key for AppImage signing
|
|
||||||
required: false
|
|
||||||
gpg-private-key-id:
|
|
||||||
description: ID for the gpg-private-key, to select the signing key
|
|
||||||
required: false
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Cleanup Qt installation on Linux
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/printsupport
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/sqldrivers
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/help
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/designer
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/qmltooling
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/qmlls
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/qmllint
|
|
||||||
rm -rf "$QT_PLUGIN_PATH"/platformthemes/libqgtk3.so
|
|
||||||
|
|
||||||
- name: Setup build variables
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# Fixup architecture naming for AppImages
|
|
||||||
dpkg_arch="$(dpkg-architecture -q DEB_HOST_ARCH_CPU)"
|
|
||||||
case "$dpkg_arch" in
|
|
||||||
"amd64")
|
|
||||||
APPIMAGE_ARCH="x86_64"
|
|
||||||
;;
|
|
||||||
"arm64")
|
|
||||||
APPIMAGE_ARCH="aarch64"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "# 🚨 The Debian architecture \"$deb_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
echo "APPIMAGE_ARCH=$APPIMAGE_ARCH" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
# Used for the file paths of libraries
|
|
||||||
echo "DEB_HOST_MULTIARCH=$(dpkg-architecture -q DEB_HOST_MULTIARCH)" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Package AppImage
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
VERSION: ${{ github.ref_type == 'tag' && github.ref_name || inputs.version }}
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_APPIMAGE_DIR: install-appdir
|
|
||||||
|
|
||||||
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}
|
|
||||||
|
|
||||||
if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then
|
|
||||||
echo "$GPG_PRIVATE_KEY" > privkey.asc
|
|
||||||
gpg --import privkey.asc
|
|
||||||
gpg --export --armor ${{ inputs.gpg-private-key-id }} > pubkey.asc
|
|
||||||
else
|
|
||||||
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
|
|
||||||
fi
|
|
||||||
|
|
||||||
sharun lib4bin \
|
|
||||||
--hard-links \
|
|
||||||
--with-hooks \
|
|
||||||
--dst-dir "$INSTALL_APPIMAGE_DIR" \
|
|
||||||
"$INSTALL_APPIMAGE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so
|
|
||||||
|
|
||||||
cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/bin/
|
|
||||||
# FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work!
|
|
||||||
find "$INSTALL_APPIMAGE_DIR" -name '*gamemode*' -exec rm {} +
|
|
||||||
|
|
||||||
#disable OpenGL and Vulkan launcher features until https://github.com/VHSgunzo/sharun/issues/35
|
|
||||||
echo "PRISMLAUNCHER_DISABLE_GLVULKAN=1" >> "$INSTALL_APPIMAGE_DIR"/.env
|
|
||||||
#makes the launcher use portals for file picking
|
|
||||||
echo "QT_QPA_PLATFORMTHEME=xdgdesktopportal" >> "$INSTALL_APPIMAGE_DIR"/.env
|
|
||||||
ln -s org.prismlauncher.PrismLauncher.metainfo.xml "$INSTALL_APPIMAGE_DIR"/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml
|
|
||||||
ln -s share/applications/org.prismlauncher.PrismLauncher.desktop "$INSTALL_APPIMAGE_DIR"
|
|
||||||
ln -s share/icons/hicolor/256x256/apps/org.prismlauncher.PrismLauncher.png "$INSTALL_APPIMAGE_DIR"
|
|
||||||
mv "$INSTALL_APPIMAGE_DIR"/{sharun,AppRun}
|
|
||||||
ls -la "$INSTALL_APPIMAGE_DIR"
|
|
||||||
|
|
||||||
if [[ "${{ github.ref_type }}" == "tag" ]]; then
|
|
||||||
APPIMAGE_DEST="PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage"
|
|
||||||
else
|
|
||||||
APPIMAGE_DEST="PrismLauncher-Linux-$VERSION-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkappimage \
|
|
||||||
--updateinformation "gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage.zsync" \
|
|
||||||
"$INSTALL_APPIMAGE_DIR" \
|
|
||||||
"$APPIMAGE_DEST"
|
|
||||||
|
|
||||||
- name: Package portable tarball
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
|
|
||||||
INSTALL_PORTABLE_DIR: install-portable
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
|
||||||
|
|
||||||
sharun lib4bin \
|
|
||||||
--with-hooks \
|
|
||||||
--hard-links \
|
|
||||||
--dst-dir "$INSTALL_PORTABLE_DIR" \
|
|
||||||
"$INSTALL_PORTABLE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so
|
|
||||||
|
|
||||||
# FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work!
|
|
||||||
find "$INSTALL_PORTABLE_DIR" -name '*gamemode*' -exec rm {} +
|
|
||||||
|
|
||||||
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f -o -type l); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
|
||||||
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
|
||||||
tar -czf ../PrismLauncher-portable.tar.gz *
|
|
||||||
|
|
||||||
- name: Upload binary tarball
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Qt6-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: PrismLauncher-portable.tar.gz
|
|
||||||
|
|
||||||
- name: Upload AppImage
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage
|
|
||||||
path: PrismLauncher-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage
|
|
||||||
|
|
||||||
- name: Upload AppImage Zsync
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync
|
|
||||||
path: PrismLauncher-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage.zsync
|
|
||||||
147
.github/actions/package/macos/action.yml
vendored
147
.github/actions/package/macos/action.yml
vendored
|
|
@ -1,147 +0,0 @@
|
||||||
name: Package for macOS
|
|
||||||
description: Create a macOS package for Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: Launcher version
|
|
||||||
required: true
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
artifact-name:
|
|
||||||
description: Name of the uploaded artifact
|
|
||||||
required: true
|
|
||||||
default: macOS
|
|
||||||
apple-codesign-cert:
|
|
||||||
description: Certificate for signing macOS builds
|
|
||||||
required: false
|
|
||||||
apple-codesign-password:
|
|
||||||
description: Password for signing macOS builds
|
|
||||||
required: false
|
|
||||||
apple-codesign-id:
|
|
||||||
description: Certificate ID for signing macOS builds
|
|
||||||
required: false
|
|
||||||
apple-notarize-apple-id:
|
|
||||||
description: Apple ID used for notarizing macOS builds
|
|
||||||
required: false
|
|
||||||
apple-notarize-team-id:
|
|
||||||
description: Team ID used for notarizing macOS builds
|
|
||||||
required: false
|
|
||||||
apple-notarize-password:
|
|
||||||
description: Password used for notarizing macOS builds
|
|
||||||
required: false
|
|
||||||
sparkle-ed25519-key:
|
|
||||||
description: Private key for signing Sparkle updates
|
|
||||||
required: false
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Fetch codesign certificate
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo '${{ inputs.apple-codesign-cert }}' | base64 --decode > codesign.p12
|
|
||||||
if [ -n '${{ inputs.apple-codesign-id }}' ]; then
|
|
||||||
security create-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain
|
|
||||||
security default-keychain -s build.keychain
|
|
||||||
security unlock-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain
|
|
||||||
security import codesign.p12 -k build.keychain -P '${{ inputs.apple-codesign-password }}' -T /usr/bin/codesign
|
|
||||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ inputs.apple-codesign-password }}' build.keychain
|
|
||||||
else
|
|
||||||
echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Package
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }}
|
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
|
||||||
|
|
||||||
if [ -n '${{ inputs.apple-codesign-id }}' ]; then
|
|
||||||
APPLE_CODESIGN_ID='${{ inputs.apple-codesign-id }}'
|
|
||||||
ENTITLEMENTS_FILE='../program_info/App.entitlements'
|
|
||||||
else
|
|
||||||
APPLE_CODESIGN_ID='-'
|
|
||||||
ENTITLEMENTS_FILE='../program_info/AdhocSignedApp.entitlements'
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "$ENTITLEMENTS_FILE" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
|
||||||
mv "PrismLauncher.app" "Prism Launcher.app"
|
|
||||||
|
|
||||||
- name: Notarize
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
|
|
||||||
if [ -n '${{ inputs.apple-notarize-password }}' ]; then
|
|
||||||
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
|
||||||
xcrun notarytool submit ../PrismLauncher.zip \
|
|
||||||
--wait --progress \
|
|
||||||
--apple-id '${{ inputs.apple-notarize-apple-id }}' \
|
|
||||||
--team-id '${{ inputs.apple-notarize-team-id }}' \
|
|
||||||
--password '${{ inputs.apple-notarize-password }}'
|
|
||||||
|
|
||||||
xcrun stapler staple "Prism Launcher.app"
|
|
||||||
else
|
|
||||||
echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY
|
|
||||||
fi
|
|
||||||
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
|
||||||
|
|
||||||
- name: Create DMG
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
|
|
||||||
mkdir -p src
|
|
||||||
cp -R "Prism Launcher.app" src/
|
|
||||||
|
|
||||||
ln -s /Applications src/
|
|
||||||
|
|
||||||
hdiutil create \
|
|
||||||
-volname "Prism Launcher ${{ inputs.version }}" \
|
|
||||||
-srcfolder src \
|
|
||||||
-ov -format ULMO \
|
|
||||||
"../PrismLauncher.dmg"
|
|
||||||
|
|
||||||
- name: Make Sparkle signature
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ '${{ inputs.sparkle-ed25519-key }}' != '' ]; then
|
|
||||||
echo '${{ inputs.sparkle-ed25519-key }}' > ed25519-priv.pem
|
|
||||||
signature_zip=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
|
||||||
signature_dmg=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.dmg -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
|
||||||
rm ed25519-priv.pem
|
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
|
||||||
### Artifact Information :information_source:
|
|
||||||
- :memo: Sparkle Signature (ed25519): \`$signature_zip\` (ZIP)
|
|
||||||
- :memo: Sparkle Signature (ed25519): \`$signature_dmg\` (DMG)
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
|
||||||
### Artifact Information :information_source:
|
|
||||||
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload binary tarball
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: PrismLauncher.zip
|
|
||||||
|
|
||||||
- name: Upload disk image
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}.dmg
|
|
||||||
path: PrismLauncher.dmg
|
|
||||||
186
.github/actions/package/windows/action.yml
vendored
186
.github/actions/package/windows/action.yml
vendored
|
|
@ -1,186 +0,0 @@
|
||||||
name: Package for Windows
|
|
||||||
description: Create a Windows package for Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: Launcher version
|
|
||||||
required: true
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
artifact-name:
|
|
||||||
description: Name of the uploaded artifact
|
|
||||||
required: true
|
|
||||||
msystem:
|
|
||||||
description: MSYS2 subsystem to use
|
|
||||||
required: false
|
|
||||||
azure-client-id:
|
|
||||||
description: Client ID for the Azure Signer Application
|
|
||||||
required: true
|
|
||||||
azure-tenant-id:
|
|
||||||
description: Tenant ID for the Azure Signer Application
|
|
||||||
required: true
|
|
||||||
azure-subscription-id:
|
|
||||||
description: Subscription ID for the Azure Signer Application
|
|
||||||
required: true
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Package (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' }}
|
|
||||||
shell: msys2 {0}
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }}
|
|
||||||
touch ${{ env.INSTALL_DIR }}/manifest.txt
|
|
||||||
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt
|
|
||||||
|
|
||||||
- name: Package (MSVC)
|
|
||||||
if: ${{ inputs.msystem == '' }}
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }}
|
|
||||||
|
|
||||||
cd ${{ github.workspace }}
|
|
||||||
|
|
||||||
Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
|
||||||
|
|
||||||
- name: Emit warning for unsigned builds
|
|
||||||
if: ${{ env.CI_HAS_ACCESS_TO_AZURE == '' || inputs.azure-client-id == '' }}
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
|
||||||
|
|
||||||
- name: Login to Azure
|
|
||||||
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
|
|
||||||
uses: azure/login@v3
|
|
||||||
with:
|
|
||||||
client-id: ${{ inputs.azure-client-id }}
|
|
||||||
tenant-id: ${{ inputs.azure-tenant-id }}
|
|
||||||
subscription-id: ${{ inputs.azure-subscription-id }}
|
|
||||||
|
|
||||||
- name: Sign executables
|
|
||||||
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
|
|
||||||
uses: azure/artifact-signing-action@v2
|
|
||||||
with:
|
|
||||||
endpoint: https://eus.codesigning.azure.net/
|
|
||||||
trusted-signing-account-name: PrismLauncher
|
|
||||||
certificate-profile-name: PrismLauncher
|
|
||||||
files-folder: ${{ github.workspace }}\install\
|
|
||||||
files-folder-filter: dll,exe
|
|
||||||
files-folder-recurse: true
|
|
||||||
files-folder-depth: 2
|
|
||||||
# recommended in https://github.com/Azure/artifact-signing-action#timestamping-1
|
|
||||||
timestamp-rfc3161: 'http://timestamp.acs.microsoft.com'
|
|
||||||
timestamp-digest: 'SHA256'
|
|
||||||
# TODO(@getchoo): Is this all really needed???
|
|
||||||
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
|
|
||||||
exclude-environment-credential: true
|
|
||||||
exclude-workload-identity-credential: true
|
|
||||||
exclude-managed-identity-credential: true
|
|
||||||
exclude-shared-token-cache-credential: true
|
|
||||||
exclude-visual-studio-credential: true
|
|
||||||
exclude-visual-studio-code-credential: true
|
|
||||||
exclude-azure-cli-credential: false
|
|
||||||
exclude-azure-powershell-credential: true
|
|
||||||
exclude-azure-developer-cli-credential: true
|
|
||||||
exclude-interactive-browser-credential: true
|
|
||||||
|
|
||||||
- name: Package (MinGW, portable)
|
|
||||||
if: ${{ inputs.msystem != '' }}
|
|
||||||
shell: msys2 {0}
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
INSTALL_PORTABLE_DIR: install-portable
|
|
||||||
run: |
|
|
||||||
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
|
||||||
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
|
||||||
|
|
||||||
- name: Package (MSVC, portable)
|
|
||||||
if: ${{ inputs.msystem == '' }}
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
INSTALL_PORTABLE_DIR: install-portable
|
|
||||||
run: |
|
|
||||||
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
|
||||||
|
|
||||||
Get-ChildItem ${{ env.INSTALL_PORTABLE_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_PORTABLE_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
|
||||||
|
|
||||||
- name: Package (installer)
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
|
|
||||||
NSCURL_VERSION: "v24.9.26.122"
|
|
||||||
NSCURL_SHA256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
|
|
||||||
run: |
|
|
||||||
New-Item -Name NSISPlugins -ItemType Directory
|
|
||||||
Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/"${{ env.NSCURL_VERSION }}"/NScurl.zip -OutFile NSISPlugins\NScurl.zip
|
|
||||||
$nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash
|
|
||||||
if ( $nscurl_hash -ne "${{ env.nscurl_sha256 }}") {
|
|
||||||
echo "::error:: NSCurl.zip sha256 mismatch"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl
|
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
|
||||||
|
|
||||||
- name: Sign installer
|
|
||||||
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
|
|
||||||
uses: azure/artifact-signing-action@v2
|
|
||||||
with:
|
|
||||||
endpoint: https://eus.codesigning.azure.net/
|
|
||||||
trusted-signing-account-name: PrismLauncher
|
|
||||||
certificate-profile-name: PrismLauncher
|
|
||||||
|
|
||||||
files: |
|
|
||||||
${{ github.workspace }}\PrismLauncher-Setup.exe
|
|
||||||
|
|
||||||
# recommended in https://github.com/Azure/artifact-signing-action#timestamping-1
|
|
||||||
timestamp-rfc3161: 'http://timestamp.acs.microsoft.com'
|
|
||||||
timestamp-digest: 'SHA256'
|
|
||||||
# TODO(@getchoo): Is this all really needed???
|
|
||||||
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
|
|
||||||
exclude-environment-credential: true
|
|
||||||
exclude-workload-identity-credential: true
|
|
||||||
exclude-managed-identity-credential: true
|
|
||||||
exclude-shared-token-cache-credential: true
|
|
||||||
exclude-visual-studio-credential: true
|
|
||||||
exclude-visual-studio-code-credential: true
|
|
||||||
exclude-azure-cli-credential: false
|
|
||||||
exclude-azure-powershell-credential: true
|
|
||||||
exclude-azure-developer-cli-credential: true
|
|
||||||
exclude-interactive-browser-credential: true
|
|
||||||
|
|
||||||
- name: Upload binary zip
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: install/**
|
|
||||||
|
|
||||||
- name: Upload portable zip
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: install-portable/**
|
|
||||||
|
|
||||||
- name: Upload installer
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Setup-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: PrismLauncher-Setup.exe
|
|
||||||
81
.github/actions/setup-dependencies/action.yml
vendored
81
.github/actions/setup-dependencies/action.yml
vendored
|
|
@ -1,81 +0,0 @@
|
||||||
name: Setup Dependencies
|
|
||||||
description: Install and setup dependencies for building Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
artifact-name:
|
|
||||||
description: Name of the uploaded artifact
|
|
||||||
required: true
|
|
||||||
msystem:
|
|
||||||
description: MSYS2 subsystem to use
|
|
||||||
required: false
|
|
||||||
vcvars-arch:
|
|
||||||
description: Visual Studio architecture to use
|
|
||||||
required: false
|
|
||||||
qt-architecture:
|
|
||||||
description: Qt architecture
|
|
||||||
required: false
|
|
||||||
qt-version:
|
|
||||||
description: Version of Qt to use
|
|
||||||
required: true
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
build-type:
|
|
||||||
description: Type of build used
|
|
||||||
value: ${{ inputs.build-type }}
|
|
||||||
qt-version:
|
|
||||||
description: Version of Qt used
|
|
||||||
value: ${{ inputs.qt-version }}
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Setup Linux dependencies
|
|
||||||
if: ${{ runner.os == 'Linux' }}
|
|
||||||
uses: ./.github/actions/setup-dependencies/linux
|
|
||||||
|
|
||||||
- name: Setup macOS dependencies
|
|
||||||
if: ${{ runner.os == 'macOS' }}
|
|
||||||
uses: ./.github/actions/setup-dependencies/macos
|
|
||||||
with:
|
|
||||||
build-type: ${{ inputs.build-type }}
|
|
||||||
|
|
||||||
- name: Setup Windows dependencies
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
uses: ./.github/actions/setup-dependencies/windows
|
|
||||||
with:
|
|
||||||
build-type: ${{ inputs.build-type }}
|
|
||||||
msystem: ${{ inputs.msystem }}
|
|
||||||
vcvars-arch: ${{ inputs.vcvars-arch }}
|
|
||||||
|
|
||||||
# TODO(@getchoo): Get this working on MSYS2!
|
|
||||||
- name: Setup ccache
|
|
||||||
if: ${{ (runner.os != 'Windows' || inputs.msystem == '') && inputs.build-type == 'Debug' }}
|
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
|
||||||
with:
|
|
||||||
variant: sccache
|
|
||||||
create-symlink: ${{ runner.os != 'Windows' }}
|
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.artifact-name }}-sccache
|
|
||||||
|
|
||||||
- name: Use ccache on debug builds
|
|
||||||
if: ${{ inputs.build-type == 'Debug' }}
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
# Only use ccache on MSYS2
|
|
||||||
CCACHE_VARIANT: ${{ (runner.os == 'Windows' && inputs.msystem != '') && 'ccache' || 'sccache' }}
|
|
||||||
run: |
|
|
||||||
echo "CMAKE_C_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV"
|
|
||||||
echo "CMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Install Qt
|
|
||||||
if: ${{ inputs.msystem == '' }}
|
|
||||||
uses: jurplel/install-qt-action@v4
|
|
||||||
with:
|
|
||||||
aqtversion: "==3.1.*"
|
|
||||||
version: ${{ inputs.qt-version }}
|
|
||||||
modules: qtimageformats qtnetworkauth
|
|
||||||
cache: ${{ inputs.build-type == 'Debug' }}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
name: Setup Linux dependencies
|
|
||||||
description: Install and setup dependencies for building Prism Launcher
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Install host dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y update
|
|
||||||
sudo apt-get -y install \
|
|
||||||
dpkg-dev \
|
|
||||||
ninja-build extra-cmake-modules pkg-config scdoc \
|
|
||||||
cmark gamemode-dev libarchive-dev libcmark-dev libqrencode-dev zlib1g-dev \
|
|
||||||
libxcb-cursor-dev libtomlplusplus-dev
|
|
||||||
|
|
||||||
- name: Setup AppImage tooling
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
run: |
|
|
||||||
# Determinate AppImage architecture to use
|
|
||||||
dpkg_arch="$(dpkg-architecture -q DEB_HOST_ARCH_CPU)"
|
|
||||||
case "$dpkg_arch" in
|
|
||||||
"amd64")
|
|
||||||
APPIMAGE_ARCH="x86_64"
|
|
||||||
;;
|
|
||||||
"arm64")
|
|
||||||
APPIMAGE_ARCH="aarch64"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "# 🚨 The Debian architecture \"$deb_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
gh release download \
|
|
||||||
--repo VHSgunzo/sharun \
|
|
||||||
--pattern "sharun-$APPIMAGE_ARCH-aio" \
|
|
||||||
--output ~/bin/sharun
|
|
||||||
|
|
||||||
# FIXME!: revert this to probonopd/go-appimage once https://github.com/probonopd/go-appimage/pull/377 is merged!
|
|
||||||
gh release download continuous \
|
|
||||||
--repo DioEgizio/go-appimage \
|
|
||||||
--pattern "mkappimage-*-$APPIMAGE_ARCH.AppImage" \
|
|
||||||
--output ~/bin/mkappimage
|
|
||||||
|
|
||||||
gh release download \
|
|
||||||
--repo AppImageCommunity/AppImageUpdate \
|
|
||||||
--pattern "AppImageUpdate-$APPIMAGE_ARCH.AppImage" \
|
|
||||||
--output ~/bin/AppImageUpdate.AppImage
|
|
||||||
chmod +x ~/bin/*
|
|
||||||
echo "$HOME/bin" >> "$GITHUB_PATH"
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
name: Setup macOS dependencies
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Install dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
brew update
|
|
||||||
brew install ninja extra-cmake-modules temurin@17 mono
|
|
||||||
|
|
||||||
- name: Set JAVA_HOME
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "JAVA_HOME=$(/usr/libexec/java_home -v 17)" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Setup vcpkg cache
|
|
||||||
if: ${{ inputs.build-type == 'Debug' }}
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
USERNAME: ${{ github.repository_owner }}
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
|
|
||||||
run: |
|
|
||||||
mono `vcpkg fetch nuget | tail -n 1` \
|
|
||||||
sources add \
|
|
||||||
-Source "$FEED_URL" \
|
|
||||||
-StorePasswordInClearText \
|
|
||||||
-Name GitHubPackages \
|
|
||||||
-UserName "$USERNAME" \
|
|
||||||
-Password "$GITHUB_TOKEN"
|
|
||||||
mono `vcpkg fetch nuget | tail -n 1` \
|
|
||||||
setapikey "$GITHUB_TOKEN" \
|
|
||||||
-Source "$FEED_URL"
|
|
||||||
echo "VCPKG_BINARY_SOURCES=clear;nuget,$FEED_URL,readwrite" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Setup vcpkg environment
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
name: Setup Windows Dependencies
|
|
||||||
description: Install and setup dependencies for building Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
msystem:
|
|
||||||
description: MSYS2 subsystem to use
|
|
||||||
required: false
|
|
||||||
vcvars-arch:
|
|
||||||
description: Visual Studio architecture to use
|
|
||||||
required: true
|
|
||||||
default: amd64
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# NOTE: Installed on MinGW as well for SignTool
|
|
||||||
- name: Enter VS Developer shell
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
|
||||||
with:
|
|
||||||
arch: ${{ inputs.vcvars-arch }}
|
|
||||||
vsversion: 2022
|
|
||||||
|
|
||||||
- name: Setup Java (MSVC)
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
# NOTE(@getchoo): We should probably stay on Zulu.
|
|
||||||
# Temurin doesn't have Java 17 builds for WoA
|
|
||||||
distribution: zulu
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup vcpkg cache (MSVC)
|
|
||||||
if: ${{ inputs.msystem == '' && inputs.build-type == 'Debug' }}
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
USERNAME: ${{ github.repository_owner }}
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
|
|
||||||
run: |
|
|
||||||
.$(vcpkg fetch nuget) `
|
|
||||||
sources add `
|
|
||||||
-Source "$env:FEED_URL" `
|
|
||||||
-StorePasswordInClearText `
|
|
||||||
-Name GitHubPackages `
|
|
||||||
-UserName "$env:USERNAME" `
|
|
||||||
-Password "$env:GITHUB_TOKEN"
|
|
||||||
.$(vcpkg fetch nuget) `
|
|
||||||
setapikey "$env:GITHUB_TOKEN" `
|
|
||||||
-Source "$env:FEED_URL"
|
|
||||||
"VCPKG_BINARY_SOURCES=clear;nuget,$env:FEED_URL,readwrite" | Out-File -Append $env:GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Setup vcpkg environment (MSVC)
|
|
||||||
if: ${{ inputs.msystem == '' }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Setup MSYS2 (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' }}
|
|
||||||
uses: msys2/setup-msys2@v2
|
|
||||||
with:
|
|
||||||
msystem: ${{ inputs.msystem }}
|
|
||||||
update: true
|
|
||||||
install: >-
|
|
||||||
git
|
|
||||||
pacboy: >-
|
|
||||||
toolchain:p
|
|
||||||
ccache:p
|
|
||||||
cmake:p
|
|
||||||
extra-cmake-modules:p
|
|
||||||
ninja:p
|
|
||||||
qt6-base:p
|
|
||||||
qt6-svg:p
|
|
||||||
qt6-imageformats:p
|
|
||||||
qt6-networkauth:p
|
|
||||||
cmark:p
|
|
||||||
qrencode:p
|
|
||||||
tomlplusplus:p
|
|
||||||
libarchive:p
|
|
||||||
|
|
||||||
- name: List pacman packages (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' }}
|
|
||||||
shell: msys2 {0}
|
|
||||||
run: |
|
|
||||||
pacman -Qe
|
|
||||||
|
|
||||||
- name: Retrieve ccache cache (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
|
|
||||||
uses: actions/cache@v5.0.5
|
|
||||||
with:
|
|
||||||
path: '${{ github.workspace }}\.ccache'
|
|
||||||
key: ${{ runner.os }}-mingw-w64-ccache-${{ github.run_id }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-mingw-w64-ccache
|
|
||||||
|
|
||||||
- name: Setup ccache (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
|
|
||||||
shell: msys2 {0}
|
|
||||||
run: |
|
|
||||||
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
|
||||||
ccache --set-config=max_size='500M'
|
|
||||||
ccache --set-config=compression=true
|
|
||||||
ccache -p # Show config
|
|
||||||
9
.github/workflows/backport.yml
vendored
9
.github/workflows/backport.yml
vendored
|
|
@ -8,7 +8,8 @@ on:
|
||||||
# the GitHub repository. This means that it should not evaluate user input in a
|
# the GitHub repository. This means that it should not evaluate user input in a
|
||||||
# way that allows code injection.
|
# way that allows code injection.
|
||||||
|
|
||||||
permissions: {}
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
backport:
|
backport:
|
||||||
|
|
@ -18,13 +19,13 @@ jobs:
|
||||||
actions: write # for korthout/backport-action to create PR with workflow changes
|
actions: write # for korthout/backport-action to create PR with workflow changes
|
||||||
name: Backport Pull Request
|
name: Backport Pull Request
|
||||||
if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
|
if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
- name: Create backport PRs
|
- name: Create backport PRs
|
||||||
uses: korthout/backport-action@v4.5
|
uses: korthout/backport-action@v3.1.0
|
||||||
with:
|
with:
|
||||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||||
pull_description: |-
|
pull_description: |-
|
||||||
|
|
|
||||||
257
.github/workflows/blocked-prs.yml
vendored
257
.github/workflows/blocked-prs.yml
vendored
|
|
@ -1,257 +0,0 @@
|
||||||
name: Blocked/Stacked Pull Requests Automation
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- reopened
|
|
||||||
- edited
|
|
||||||
- synchronize
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
pr_id:
|
|
||||||
description: Local Pull Request number to work on
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
blocked_status:
|
|
||||||
name: Check Blocked Status
|
|
||||||
runs-on: ubuntu-slim
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Generate token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@v3
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
|
||||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Setup From Dispatch Event
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
id: dispatch_event_setup
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
PR_NUMBER: ${{ inputs.pr_id }}
|
|
||||||
run: |
|
|
||||||
# setup env for the rest of the workflow
|
|
||||||
OWNER=$(dirname "${{ github.repository }}")
|
|
||||||
REPO=$(basename "${{ github.repository }}")
|
|
||||||
PR_JSON=$(
|
|
||||||
gh api \
|
|
||||||
-H "Accept: application/vnd.github.raw+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
"/repos/$OWNER/$REPO/pulls/$PR_NUMBER"
|
|
||||||
)
|
|
||||||
echo "PR_JSON=$PR_JSON" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Setup Environment
|
|
||||||
id: env_setup
|
|
||||||
env:
|
|
||||||
EVENT_PR_JSON: ${{ toJSON(github.event.pull_request) }}
|
|
||||||
run: |
|
|
||||||
# setup env for the rest of the workflow
|
|
||||||
PR_JSON=${PR_JSON:-"$EVENT_PR_JSON"}
|
|
||||||
{
|
|
||||||
echo "REPO=$(jq -r '.base.repo.name' <<< "$PR_JSON")"
|
|
||||||
echo "OWNER=$(jq -r '.base.repo.owner.login' <<< "$PR_JSON")"
|
|
||||||
echo "PR_NUMBER=$(jq -r '.number' <<< "$PR_JSON")"
|
|
||||||
echo "JOB_DATA=$(jq -c '
|
|
||||||
{
|
|
||||||
"repo": .base.repo.name,
|
|
||||||
"owner": .base.repo.owner.login,
|
|
||||||
"repoUrl": .base.repo.html_url,
|
|
||||||
"prNumber": .number,
|
|
||||||
"prHeadSha": .head.sha,
|
|
||||||
"prHeadLabel": .head.label,
|
|
||||||
"prBody": (.body // ""),
|
|
||||||
"prLabels": (reduce .labels[].name as $l ([]; . + [$l]))
|
|
||||||
}
|
|
||||||
' <<< "$PR_JSON")"
|
|
||||||
} >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
|
|
||||||
- name: Find Blocked/Stacked PRs in body
|
|
||||||
id: pr_ids
|
|
||||||
run: |
|
|
||||||
prs=$(
|
|
||||||
jq -c '
|
|
||||||
.prBody as $body
|
|
||||||
| (
|
|
||||||
$body |
|
|
||||||
reduce (
|
|
||||||
. | scan("[Bb]locked (?:[Bb]y|[Oo]n):? #([0-9]+)")
|
|
||||||
| map({
|
|
||||||
"type": "Blocked on",
|
|
||||||
"number": ( . | tonumber )
|
|
||||||
})
|
|
||||||
) as $i ([]; . + [$i[]])
|
|
||||||
) as $bprs
|
|
||||||
| (
|
|
||||||
$body |
|
|
||||||
reduce (
|
|
||||||
. | scan("[Ss]tacked [Oo]n:? #([0-9]+)")
|
|
||||||
| map({
|
|
||||||
"type": "Stacked on",
|
|
||||||
"number": ( . | tonumber )
|
|
||||||
})
|
|
||||||
) as $i ([]; . + [$i[]])
|
|
||||||
) as $sprs
|
|
||||||
| ($bprs + $sprs) as $prs
|
|
||||||
| {
|
|
||||||
"blocking": $prs,
|
|
||||||
"numBlocking": ( $prs | length),
|
|
||||||
}
|
|
||||||
' <<< "$JOB_DATA"
|
|
||||||
)
|
|
||||||
echo "prs=$prs" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Collect Blocked PR Data
|
|
||||||
id: blocking_data
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
BLOCKING_PRS: ${{ steps.pr_ids.outputs.prs }}
|
|
||||||
run: |
|
|
||||||
blocked_pr_data=$(
|
|
||||||
while read -r pr_data ; do
|
|
||||||
gh api \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
"/repos/$OWNER/$REPO/pulls/$(jq -r '.number' <<< "$pr_data")" \
|
|
||||||
| jq -c --arg type "$(jq -r '.type' <<< "$pr_data")" \
|
|
||||||
'
|
|
||||||
. | {
|
|
||||||
"type": $type,
|
|
||||||
"number": .number,
|
|
||||||
"merged": .merged,
|
|
||||||
"state": (if .state == "open" then "Open" elif .merged then "Merged" else "Closed" end),
|
|
||||||
"labels": (reduce .labels[].name as $l ([]; . + [$l])),
|
|
||||||
"basePrUrl": .html_url,
|
|
||||||
"baseRepoName": .head.repo.name,
|
|
||||||
"baseRepoOwner": .head.repo.owner.login,
|
|
||||||
"baseRepoUrl": .head.repo.html_url,
|
|
||||||
"baseSha": .head.sha,
|
|
||||||
"baseRefName": .head.ref,
|
|
||||||
}
|
|
||||||
'
|
|
||||||
done < <(jq -c '.blocking[]' <<< "$BLOCKING_PRS") | jq -c -s
|
|
||||||
)
|
|
||||||
{
|
|
||||||
echo "data=$blocked_pr_data";
|
|
||||||
echo "all_merged=$(jq -r 'all(.[] | (.type == "Stacked on" and .merged) or (.type == "Blocked on" and (.state != "Open")); .)' <<< "$blocked_pr_data")";
|
|
||||||
echo "current_blocking=$(jq -c 'map(
|
|
||||||
select(
|
|
||||||
(.type == "Stacked on" and (.merged | not)) or
|
|
||||||
(.type == "Blocked on" and (.state == "Open"))
|
|
||||||
) | .number
|
|
||||||
)' <<< "$blocked_pr_data" )";
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Add 'blocked' Label if Missing
|
|
||||||
id: label_blocked
|
|
||||||
if: "(fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0) && !contains(fromJSON(env.JOB_DATA).prLabels, 'status: blocked') && !fromJSON(steps.blocking_data.outputs.all_merged)"
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
run: |
|
|
||||||
gh -R ${{ github.repository }} issue edit --add-label 'status: blocked' "$PR_NUMBER"
|
|
||||||
|
|
||||||
- name: Remove 'blocked' Label if All Dependencies Are Merged
|
|
||||||
id: unlabel_blocked
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 && fromJSON(steps.blocking_data.outputs.all_merged)
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
run: |
|
|
||||||
gh -R ${{ github.repository }} issue edit --remove-label 'status: blocked' "$PR_NUMBER"
|
|
||||||
|
|
||||||
- name: Apply 'blocking' Label to Unmerged Dependencies
|
|
||||||
id: label_blocking
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
BLOCKING_ISSUES: ${{ steps.blocking_data.outputs.current_blocking }}
|
|
||||||
run: |
|
|
||||||
while read -r pr ; do
|
|
||||||
gh -R ${{ github.repository }} issue edit --add-label 'status: blocking' "$pr" || true
|
|
||||||
done < <(jq -c '.[]' <<< "$BLOCKING_ISSUES")
|
|
||||||
|
|
||||||
- name: Apply Blocking PR Status Check
|
|
||||||
id: blocked_check
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
|
|
||||||
run: |
|
|
||||||
pr_head_sha=$(jq -r '.prHeadSha' <<< "$JOB_DATA")
|
|
||||||
# create commit Status, overwrites previous identical context
|
|
||||||
while read -r pr_data ; do
|
|
||||||
DESC=$(
|
|
||||||
jq -r 'if .type == "Stacked on" then
|
|
||||||
"Stacked PR #" + (.number | tostring) + " is " + (if .merged then "" else "not yet " end) + "merged"
|
|
||||||
else
|
|
||||||
"Blocking PR #" + (.number | tostring) + " is " + (if .state == "Open" then "" else "not yet " end) + "merged or closed"
|
|
||||||
end ' <<< "$pr_data"
|
|
||||||
)
|
|
||||||
gh api \
|
|
||||||
--method POST \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
"/repos/${OWNER}/${REPO}/statuses/${pr_head_sha}" \
|
|
||||||
-f "state=$(jq -r 'if (.type == "Stacked on" and .merged) or (.type == "Blocked on" and (.state != "Open")) then "success" else "failure" end' <<< "$pr_data")" \
|
|
||||||
-f "target_url=$(jq -r '.basePrUrl' <<< "$pr_data" )" \
|
|
||||||
-f "description=$DESC" \
|
|
||||||
-f "context=ci/blocking-pr-check:$(jq '.number' <<< "$pr_data")"
|
|
||||||
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
|
|
||||||
|
|
||||||
- name: Context Comment
|
|
||||||
id: generate-comment
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
|
|
||||||
run: |
|
|
||||||
COMMENT_PATH="$(pwd)/temp_comment_file.txt"
|
|
||||||
echo '<h3>PR Dependencies :pushpin:</h3>' > "$COMMENT_PATH"
|
|
||||||
echo >> "$COMMENT_PATH"
|
|
||||||
pr_head_label=$(jq -r '.prHeadLabel' <<< "$JOB_DATA")
|
|
||||||
while read -r pr_data ; do
|
|
||||||
base_pr=$(jq -r '.number' <<< "$pr_data")
|
|
||||||
base_ref_name=$(jq -r '.baseRefName' <<< "$pr_data")
|
|
||||||
base_repo_owner=$(jq -r '.baseRepoOwner' <<< "$pr_data")
|
|
||||||
base_repo_name=$(jq -r '.baseRepoName' <<< "$pr_data")
|
|
||||||
compare_url="https://github.com/$base_repo_owner/$base_repo_name/compare/$base_ref_name...$pr_head_label"
|
|
||||||
status=$(jq -r '
|
|
||||||
if .type == "Stacked on" then
|
|
||||||
if .merged then ":heavy_check_mark: Merged" else ":x: Not Merged (" + .state + ")" end
|
|
||||||
else
|
|
||||||
if .state != "Open" then ":white_check_mark: " + .state else ":x: Open" end
|
|
||||||
end
|
|
||||||
' <<< "$pr_data")
|
|
||||||
type=$(jq -r '.type' <<< "$pr_data")
|
|
||||||
echo " - $type #$base_pr $status [(compare)]($compare_url)" >> "$COMMENT_PATH"
|
|
||||||
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
|
|
||||||
|
|
||||||
{
|
|
||||||
echo 'body<<EOF';
|
|
||||||
cat "${COMMENT_PATH}";
|
|
||||||
echo 'EOF';
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: 💬 PR Comment
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
COMMENT_BODY: ${{ steps.generate-comment.outputs.body }}
|
|
||||||
run: |
|
|
||||||
gh -R ${{ github.repository }} issue comment "$PR_NUMBER" \
|
|
||||||
--body "$COMMENT_BODY" \
|
|
||||||
--create-if-none \
|
|
||||||
--edit-last
|
|
||||||
|
|
||||||
782
.github/workflows/build.yml
vendored
782
.github/workflows/build.yml
vendored
|
|
@ -1,188 +1,704 @@
|
||||||
name: Build
|
name: Build
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
merge_group:
|
|
||||||
types: [checks_requested]
|
|
||||||
pull_request:
|
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
build-type:
|
build_type:
|
||||||
description: Type of build (Debug or Release)
|
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
|
||||||
type: string
|
type: string
|
||||||
default: Debug
|
default: Debug
|
||||||
environment:
|
is_qt_cached:
|
||||||
description: Deployment environment to run under
|
description: Enable Qt caching or not
|
||||||
type: string
|
type: string
|
||||||
workflow_dispatch:
|
default: true
|
||||||
inputs:
|
secrets:
|
||||||
build-type:
|
SPARKLE_ED25519_KEY:
|
||||||
description: Type of build (Debug or Release)
|
description: Private key for signing Sparkle updates
|
||||||
type: string
|
required: false
|
||||||
default: Debug
|
WINDOWS_CODESIGN_CERT:
|
||||||
|
description: Certificate for signing Windows builds
|
||||||
permissions: {}
|
required: false
|
||||||
|
WINDOWS_CODESIGN_PASSWORD:
|
||||||
|
description: Password for signing Windows builds
|
||||||
|
required: false
|
||||||
|
APPLE_CODESIGN_CERT:
|
||||||
|
description: Certificate for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_CODESIGN_PASSWORD:
|
||||||
|
description: Password for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_CODESIGN_ID:
|
||||||
|
description: Certificate ID for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_APPLE_ID:
|
||||||
|
description: Apple ID used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_TEAM_ID:
|
||||||
|
description: Team ID used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_PASSWORD:
|
||||||
|
description: Password used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
CACHIX_AUTH_TOKEN:
|
||||||
|
description: Private token for authenticating against Cachix cache
|
||||||
|
required: false
|
||||||
|
GPG_PRIVATE_KEY:
|
||||||
|
description: Private key for AppImage signing
|
||||||
|
required: false
|
||||||
|
GPG_PRIVATE_KEY_ID:
|
||||||
|
description: ID for the GPG_PRIVATE_KEY, to select the signing key
|
||||||
|
required: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build (${{ matrix.artifact-name }})
|
|
||||||
|
|
||||||
environment: ${{ inputs.environment || '' }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
# Required for Azure Trusted Signing
|
|
||||||
id-token: write
|
|
||||||
# Required for vcpkg binary cache
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-24.04
|
- os: ubuntu-20.04
|
||||||
artifact-name: Linux
|
qt_ver: 5
|
||||||
cmake-preset: linux
|
qt_host: linux
|
||||||
qt-version: 6.10.2
|
qt_arch: ""
|
||||||
|
qt_version: "5.15.2"
|
||||||
|
qt_modules: "qtnetworkauth"
|
||||||
|
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-20.04
|
||||||
artifact-name: Linux-aarch64
|
qt_ver: 6
|
||||||
cmake-preset: linux
|
qt_host: linux
|
||||||
qt-version: 6.10.2
|
qt_arch: ""
|
||||||
|
qt_version: "6.5.3"
|
||||||
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
artifact-name: Windows-MinGW-w64
|
name: "Windows-MinGW-w64"
|
||||||
cmake-preset: windows_mingw
|
msystem: clang64
|
||||||
msystem: CLANG64
|
vcvars_arch: "amd64_x86"
|
||||||
vcvars-arch: amd64_x86
|
|
||||||
|
|
||||||
- os: windows-11-arm
|
|
||||||
artifact-name: Windows-MinGW-arm64
|
|
||||||
cmake-preset: windows_mingw
|
|
||||||
msystem: CLANGARM64
|
|
||||||
vcvars-arch: arm64
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
artifact-name: Windows-MSVC
|
name: "Windows-MSVC"
|
||||||
cmake-preset: windows_msvc
|
msystem: ""
|
||||||
# TODO(@getchoo): This is the default in setup-dependencies/windows. Why isn't it working?!?!
|
architecture: "x64"
|
||||||
vcvars-arch: amd64
|
vcvars_arch: "amd64"
|
||||||
qt-version: 6.10.2
|
qt_ver: 6
|
||||||
|
qt_host: windows
|
||||||
|
qt_arch: ""
|
||||||
|
qt_version: "6.7.3"
|
||||||
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
nscurl_tag: "v24.9.26.122"
|
||||||
|
nscurl_sha256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
|
||||||
|
|
||||||
- os: windows-11-arm
|
- os: windows-2022
|
||||||
artifact-name: Windows-MSVC-arm64
|
name: "Windows-MSVC-arm64"
|
||||||
cmake-preset: windows_msvc
|
msystem: ""
|
||||||
vcvars-arch: arm64
|
architecture: "arm64"
|
||||||
qt-version: 6.10.2
|
vcvars_arch: "amd64_arm64"
|
||||||
|
qt_ver: 6
|
||||||
|
qt_host: windows
|
||||||
|
qt_arch: "win64_msvc2019_arm64"
|
||||||
|
qt_version: "6.7.3"
|
||||||
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
nscurl_tag: "v24.9.26.122"
|
||||||
|
nscurl_sha256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
|
||||||
|
|
||||||
- os: macos-26
|
- os: macos-14
|
||||||
artifact-name: macOS
|
name: macOS
|
||||||
cmake-preset: macos_universal
|
macosx_deployment_target: 11.0
|
||||||
macosx-deployment-target: 12.0
|
qt_ver: 6
|
||||||
qt-version: 6.9.3
|
qt_host: mac
|
||||||
|
qt_arch: ""
|
||||||
|
qt_version: "6.7.3"
|
||||||
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
|
||||||
|
- os: macos-14
|
||||||
|
name: macOS-Legacy
|
||||||
|
macosx_deployment_target: 10.13
|
||||||
|
qt_ver: 5
|
||||||
|
qt_host: mac
|
||||||
|
qt_version: "5.15.2"
|
||||||
|
qt_modules: "qtnetworkauth"
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: ${{ matrix.msystem != '' && 'msys2 {0}' || 'bash' }}
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
ARTIFACT_NAME: ${{ matrix.artifact-name }}-Qt6
|
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
|
||||||
BUILD_PLATFORM: official
|
INSTALL_DIR: "install"
|
||||||
BUILD_TYPE: ${{ inputs.build-type || 'Debug' }}
|
INSTALL_PORTABLE_DIR: "install-portable"
|
||||||
CMAKE_PRESET: ${{ matrix.cmake-preset }}
|
INSTALL_APPIMAGE_DIR: "install-appdir"
|
||||||
|
BUILD_DIR: "build"
|
||||||
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx-deployment-target }}
|
CCACHE_VAR: ""
|
||||||
|
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
##
|
##
|
||||||
# SETUP
|
# PREPARE
|
||||||
|
##
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
|
|
||||||
|
- name: "Setup MSYS2"
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: ${{ matrix.msystem }}
|
||||||
|
update: true
|
||||||
|
install: >-
|
||||||
|
git
|
||||||
|
mingw-w64-x86_64-binutils
|
||||||
|
pacboy: >-
|
||||||
|
toolchain:p
|
||||||
|
cmake:p
|
||||||
|
extra-cmake-modules:p
|
||||||
|
ninja:p
|
||||||
|
qt6-base:p
|
||||||
|
qt6-svg:p
|
||||||
|
qt6-imageformats:p
|
||||||
|
quazip-qt6:p
|
||||||
|
ccache:p
|
||||||
|
qt6-5compat:p
|
||||||
|
qt6-networkauth:p
|
||||||
|
cmark:p
|
||||||
|
|
||||||
|
- name: Force newer ccache
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == '' && inputs.build_type == 'Debug'
|
||||||
|
run: |
|
||||||
|
choco install ccache --version 4.7.1
|
||||||
|
|
||||||
|
- name: Setup ccache
|
||||||
|
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||||
|
with:
|
||||||
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
||||||
|
|
||||||
|
- name: Retrieve ccache cache (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
|
uses: actions/cache@v4.2.0
|
||||||
|
with:
|
||||||
|
path: '${{ github.workspace }}\.ccache'
|
||||||
|
key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ matrix.os }}-mingw-w64-ccache
|
||||||
|
|
||||||
|
- name: Setup ccache (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
||||||
|
ccache --set-config=max_size='500M'
|
||||||
|
ccache --set-config=compression=true
|
||||||
|
ccache -p # Show config
|
||||||
|
ccache -z # Zero stats
|
||||||
|
|
||||||
|
- name: Use ccache on Debug builds only
|
||||||
|
if: inputs.build_type == 'Debug'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Set short version
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ver_short=`git rev-parse --short HEAD`
|
||||||
|
echo "VERSION=$ver_short" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install Dependencies (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install ninja-build extra-cmake-modules scdoc appstream libxcb-cursor-dev
|
||||||
|
|
||||||
|
- name: Install Dependencies (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
|
brew install ninja extra-cmake-modules
|
||||||
|
|
||||||
|
- name: Install host Qt (Windows MSVC arm64)
|
||||||
|
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
||||||
|
uses: jurplel/install-qt-action@v3
|
||||||
|
with:
|
||||||
|
aqtversion: "==3.1.*"
|
||||||
|
py7zrversion: ">=0.20.2"
|
||||||
|
version: ${{ matrix.qt_version }}
|
||||||
|
host: "windows"
|
||||||
|
target: "desktop"
|
||||||
|
arch: ""
|
||||||
|
modules: ${{ matrix.qt_modules }}
|
||||||
|
cache: ${{ inputs.is_qt_cached }}
|
||||||
|
cache-key-prefix: host-qt-arm64-windows
|
||||||
|
dir: ${{ github.workspace }}\HostQt
|
||||||
|
set-env: false
|
||||||
|
|
||||||
|
- name: Install Qt (macOS, Linux & Windows MSVC)
|
||||||
|
if: matrix.msystem == ''
|
||||||
|
uses: jurplel/install-qt-action@v3
|
||||||
|
with:
|
||||||
|
aqtversion: "==3.1.*"
|
||||||
|
py7zrversion: ">=0.20.2"
|
||||||
|
version: ${{ matrix.qt_version }}
|
||||||
|
target: "desktop"
|
||||||
|
arch: ${{ matrix.qt_arch }}
|
||||||
|
modules: ${{ matrix.qt_modules }}
|
||||||
|
tools: ${{ matrix.qt_tools }}
|
||||||
|
cache: ${{ inputs.is_qt_cached }}
|
||||||
|
|
||||||
|
- name: Install MSVC (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' # We want this for MinGW builds as well, as we need SignTool
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
with:
|
||||||
|
vsversion: 2022
|
||||||
|
arch: ${{ matrix.vcvars_arch }}
|
||||||
|
|
||||||
|
- name: Prepare AppImage (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
run: |
|
||||||
|
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
||||||
|
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
|
||||||
|
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage"
|
||||||
|
|
||||||
|
wget "https://github.com/AppImageCommunity/AppImageUpdate/releases/download/continuous/AppImageUpdate-x86_64.AppImage"
|
||||||
|
|
||||||
|
sudo apt install libopengl0
|
||||||
|
|
||||||
|
- name: Add QT_HOST_PATH var (Windows MSVC arm64)
|
||||||
|
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
||||||
|
run: |
|
||||||
|
echo "QT_HOST_PATH=${{ github.workspace }}\HostQt\Qt\${{ matrix.qt_version }}\msvc2019_64" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup java (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: "temurin"
|
||||||
|
java-version: "17"
|
||||||
|
##
|
||||||
|
# CONFIGURE
|
||||||
##
|
##
|
||||||
|
|
||||||
- name: Checkout
|
- name: Configure CMake (macOS)
|
||||||
uses: actions/checkout@v6
|
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
||||||
with:
|
run: |
|
||||||
submodules: true
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
||||||
|
|
||||||
- name: Setup dependencies
|
- name: Configure CMake (macOS-Legacy)
|
||||||
id: setup-dependencies
|
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
||||||
uses: ./.github/actions/setup-dependencies
|
run: |
|
||||||
with:
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -DCMAKE_OSX_ARCHITECTURES="x86_64" -G Ninja
|
||||||
build-type: ${{ env.BUILD_TYPE }}
|
|
||||||
artifact-name: ${{ matrix.artifact-name }}
|
- name: Configure CMake (Windows MinGW-w64)
|
||||||
msystem: ${{ matrix.msystem }}
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
vcvars-arch: ${{ matrix.vcvars-arch }}
|
shell: msys2 {0}
|
||||||
qt-version: ${{ matrix.qt-version }}
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
|
- name: Configure CMake (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }}
|
||||||
|
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
|
||||||
|
if ("${{ env.CCACHE_VAR }}")
|
||||||
|
{
|
||||||
|
Copy-Item C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/ccache.exe -Destination C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/cl.exe
|
||||||
|
echo "CLToolExe=cl.exe" >> $env:GITHUB_ENV
|
||||||
|
echo "CLToolPath=C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/" >> $env:GITHUB_ENV
|
||||||
|
echo "TrackFileAccess=false" >> $env:GITHUB_ENV
|
||||||
|
}
|
||||||
|
# Needed for ccache, but also speeds up compile
|
||||||
|
echo "UseMultiToolTask=true" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Configure CMake (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
##
|
##
|
||||||
# BUILD
|
# BUILD
|
||||||
##
|
##
|
||||||
|
|
||||||
- name: Configure project
|
- name: Build
|
||||||
|
if: runner.os != 'Windows'
|
||||||
run: |
|
run: |
|
||||||
cmake --preset "$CMAKE_PRESET"
|
cmake --build ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
- name: Run build
|
- name: Build (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake --build --preset "$CMAKE_PRESET" --config "$BUILD_TYPE"
|
cmake --build ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
- name: Run tests
|
- name: Build (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
run: |
|
run: |
|
||||||
ctest --preset "$CMAKE_PRESET" --build-config "$BUILD_TYPE"
|
cmake --build ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
||||||
|
|
||||||
##
|
##
|
||||||
# PACKAGE
|
# TEST
|
||||||
##
|
##
|
||||||
|
|
||||||
- name: Get short version
|
- name: Test
|
||||||
id: short-version
|
if: runner.os != 'Windows'
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
echo "version=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
ctest -E "^example64|example$" --test-dir build --output-on-failure
|
||||||
|
|
||||||
- name: Package (Linux)
|
- name: Test (Windows MinGW-w64)
|
||||||
if: ${{ runner.os == 'Linux' }}
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
uses: ./.github/actions/package/linux
|
shell: msys2 {0}
|
||||||
with:
|
run: |
|
||||||
version: ${{ steps.short-version.outputs.version }}
|
ctest -E "^example64|example$" --test-dir build --output-on-failure
|
||||||
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
|
||||||
artifact-name: ${{ matrix.artifact-name }}
|
|
||||||
qt-version: ${{ steps.setup-dependencies.outputs.qt-version }}
|
|
||||||
|
|
||||||
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
|
- name: Test (Windows MSVC)
|
||||||
gpg-private-key-id: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
if: runner.os == 'Windows' && matrix.msystem == '' && matrix.architecture != 'arm64'
|
||||||
|
run: |
|
||||||
|
ctest -E "^example64|example$" --test-dir build --output-on-failure -C ${{ inputs.build_type }}
|
||||||
|
|
||||||
|
##
|
||||||
|
# PACKAGE BUILDS
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: Fetch codesign certificate (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
echo '${{ secrets.APPLE_CODESIGN_CERT }}' | base64 --decode > codesign.p12
|
||||||
|
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
|
||||||
|
security create-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
security default-keychain -s build.keychain
|
||||||
|
security unlock-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
security import codesign.p12 -k build.keychain -P '${{ secrets.APPLE_CODESIGN_PASSWORD }}' -T /usr/bin/codesign
|
||||||
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
else
|
||||||
|
echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Package (macOS)
|
- name: Package (macOS)
|
||||||
if: ${{ runner.os == 'macOS' }}
|
if: runner.os == 'macOS'
|
||||||
uses: ./.github/actions/package/macos
|
run: |
|
||||||
with:
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
version: ${{ steps.short-version.outputs.version }}
|
|
||||||
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
|
||||||
artifact-name: ${{ matrix.artifact-name }}
|
|
||||||
|
|
||||||
apple-codesign-cert: ${{ secrets.APPLE_CODESIGN_CERT }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
apple-codesign-password: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
|
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
apple-codesign-id: ${{ secrets.APPLE_CODESIGN_ID }}
|
|
||||||
apple-notarize-apple-id: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
|
||||||
apple-notarize-team-id: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
|
||||||
apple-notarize-password: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
|
||||||
sparkle-ed25519-key: ${{ secrets.SPARKLE_ED25519_KEY }}
|
|
||||||
|
|
||||||
- name: Package (Windows)
|
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
|
||||||
if: ${{ runner.os == 'Windows' }}
|
APPLE_CODESIGN_ID='${{ secrets.APPLE_CODESIGN_ID }}'
|
||||||
uses: ./.github/actions/package/windows
|
else
|
||||||
|
APPLE_CODESIGN_ID='-'
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
|
mv "PrismLauncher.app" "Prism Launcher.app"
|
||||||
|
|
||||||
|
- name: Notarize (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
|
||||||
|
if [ -n '${{ secrets.APPLE_NOTARIZE_PASSWORD }}' ]; then
|
||||||
|
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
||||||
|
xcrun notarytool submit ../PrismLauncher.zip \
|
||||||
|
--wait --progress \
|
||||||
|
--apple-id '${{ secrets.APPLE_NOTARIZE_APPLE_ID }}' \
|
||||||
|
--team-id '${{ secrets.APPLE_NOTARIZE_TEAM_ID }}' \
|
||||||
|
--password '${{ secrets.APPLE_NOTARIZE_PASSWORD }}'
|
||||||
|
|
||||||
|
xcrun stapler staple "Prism Launcher.app"
|
||||||
|
else
|
||||||
|
echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
||||||
|
|
||||||
|
- name: Make Sparkle signature (macOS)
|
||||||
|
if: matrix.name == 'macOS'
|
||||||
|
run: |
|
||||||
|
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
||||||
|
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
|
||||||
|
signature=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
||||||
|
rm ed25519-priv.pem
|
||||||
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
|
### Artifact Information :information_source:
|
||||||
|
- :memo: Sparkle Signature (ed25519): \`$signature\`
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
|
### Artifact Information :information_source:
|
||||||
|
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Package (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
touch ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
|
||||||
|
- name: Package (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
|
run: |
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
||||||
|
|
||||||
|
cd ${{ github.workspace }}
|
||||||
|
|
||||||
|
Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
|
||||||
|
- name: Fetch codesign certificate (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
shell: bash # yes, we are not using MSYS2 or PowerShell here
|
||||||
|
run: |
|
||||||
|
echo '${{ secrets.WINDOWS_CODESIGN_CERT }}' | base64 --decode > codesign.pfx
|
||||||
|
|
||||||
|
- name: Sign executable (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
if (Get-Content ./codesign.pfx){
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
# We ship the exact same executable for portable and non-portable editions, so signing just once is fine
|
||||||
|
SignTool sign /fd sha256 /td sha256 /f ../codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com prismlauncher.exe prismlauncher_updater.exe prismlauncher_filelink.exe
|
||||||
|
} else {
|
||||||
|
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Package (Windows MinGW-w64, portable)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||||
|
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
||||||
|
|
||||||
|
- name: Package (Windows MSVC, portable)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
|
run: |
|
||||||
|
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||||
|
|
||||||
|
Get-ChildItem ${{ env.INSTALL_PORTABLE_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_PORTABLE_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
|
||||||
|
- name: Package (Windows, installer)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
if ('${{ matrix.nscurl_tag }}') {
|
||||||
|
New-Item -Name NSISPlugins -ItemType Directory
|
||||||
|
Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/${{ matrix.nscurl_tag }}/NScurl.zip -OutFile NSISPlugins\NScurl.zip
|
||||||
|
$nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash
|
||||||
|
if ( $nscurl_hash -ne "${{ matrix.nscurl_sha256 }}") {
|
||||||
|
echo "::error:: NSCurl.zip sha256 mismatch"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl
|
||||||
|
}
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
||||||
|
|
||||||
|
- name: Sign installer (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
if (Get-Content ./codesign.pfx){
|
||||||
|
SignTool sign /fd sha256 /td sha256 /f codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com PrismLauncher-Setup.exe
|
||||||
|
} else {
|
||||||
|
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Package AppImage (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
shell: bash
|
||||||
env:
|
env:
|
||||||
CI_HAS_ACCESS_TO_AZURE: ${{ vars.CI_HAS_ACCESS_TO_AZURE || '' }}
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
with:
|
run: |
|
||||||
version: ${{ steps.short-version.outputs.version }}
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
||||||
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
|
||||||
artifact-name: ${{ matrix.artifact-name }}
|
|
||||||
msystem: ${{ matrix.msystem }}
|
|
||||||
|
|
||||||
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
mv ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.metainfo.xml ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml
|
||||||
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
export "NO_APPSTREAM=1" # we have to skip appstream checking because appstream on ubuntu 20.04 is outdated
|
||||||
azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
|
||||||
|
export OUTPUT="PrismLauncher-Linux-x86_64.AppImage"
|
||||||
|
|
||||||
|
chmod +x linuxdeploy-*.AppImage
|
||||||
|
|
||||||
|
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib
|
||||||
|
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
||||||
|
|
||||||
|
cp -r ${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
||||||
|
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libOpenGL.so.0* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
||||||
|
|
||||||
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib"
|
||||||
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
chmod +x AppImageUpdate-x86_64.AppImage
|
||||||
|
cp AppImageUpdate-x86_64.AppImage ${{ env.INSTALL_APPIMAGE_DIR }}/usr/bin
|
||||||
|
|
||||||
|
export UPDATE_INFORMATION="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-x86_64.AppImage.zsync"
|
||||||
|
|
||||||
|
if [ '${{ secrets.GPG_PRIVATE_KEY_ID }}' != '' ]; then
|
||||||
|
export SIGN=1
|
||||||
|
export SIGN_KEY=${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
mkdir -p ~/.gnupg/
|
||||||
|
echo "$GPG_PRIVATE_KEY" > ~/.gnupg/private.key
|
||||||
|
gpg --import ~/.gnupg/private.key
|
||||||
|
else
|
||||||
|
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.prismlauncher.PrismLauncher.svg
|
||||||
|
|
||||||
|
mv "PrismLauncher-Linux-x86_64.AppImage" "PrismLauncher-Linux-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||||
|
|
||||||
|
- name: Package (Linux, portable)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_PORTABLE_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -DINSTALL_BUNDLE=full -G Ninja
|
||||||
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --component portable
|
||||||
|
|
||||||
|
mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libffi.so.7 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
mv ${{ env.INSTALL_PORTABLE_DIR }}/bin/*.so* ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
|
||||||
|
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
||||||
|
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
|
tar -czf ../PrismLauncher-portable.tar.gz *
|
||||||
|
|
||||||
|
##
|
||||||
|
# UPLOAD BUILDS
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: Upload binary tarball (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher.zip
|
||||||
|
|
||||||
|
- name: Upload binary zip (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: ${{ env.INSTALL_DIR }}/**
|
||||||
|
|
||||||
|
- name: Upload binary zip (Windows, portable)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
||||||
|
|
||||||
|
- name: Upload installer (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher-Setup.exe
|
||||||
|
|
||||||
|
- name: Upload binary tarball (Linux, portable, Qt 5)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
|
- name: Upload binary tarball (Linux, portable, Qt 6)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
|
- name: Upload AppImage (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
|
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
|
|
||||||
|
- name: Upload AppImage Zsync (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync
|
||||||
|
path: PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
|
|
||||||
|
- name: ccache stats (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
ccache -s
|
||||||
|
|
||||||
|
flatpak:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
|
||||||
|
options: --privileged
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
if: inputs.build_type == 'Debug'
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
|
- name: Set short version
|
||||||
|
shell: bash
|
||||||
|
run: echo "VERSION=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Flatpak (Linux)
|
||||||
|
if: inputs.build_type == 'Debug'
|
||||||
|
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||||
|
with:
|
||||||
|
bundle: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-Flatpak.flatpak
|
||||||
|
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
|
||||||
|
|
||||||
|
nix:
|
||||||
|
name: Nix (${{ matrix.system }})
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
system: x86_64-linux
|
||||||
|
|
||||||
|
- os: macos-13
|
||||||
|
system: x86_64-darwin
|
||||||
|
|
||||||
|
- os: macos-14
|
||||||
|
system: aarch64-darwin
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@v30
|
||||||
|
|
||||||
|
# For PRs
|
||||||
|
- name: Setup Nix Magic Cache
|
||||||
|
uses: DeterminateSystems/magic-nix-cache-action@v8
|
||||||
|
|
||||||
|
# For in-tree builds
|
||||||
|
- name: Setup Cachix
|
||||||
|
uses: cachix/cachix-action@v15
|
||||||
|
with:
|
||||||
|
name: prismlauncher
|
||||||
|
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
|
|
||||||
|
- name: Run flake checks
|
||||||
|
run: |
|
||||||
|
nix flake check --print-build-logs --show-trace
|
||||||
|
|
||||||
|
- name: Build debug package
|
||||||
|
if: ${{ inputs.build_type == 'Debug' }}
|
||||||
|
run: |
|
||||||
|
nix build --print-build-logs .#prismlauncher-debug
|
||||||
|
|
||||||
|
- name: Build release package
|
||||||
|
if: ${{ inputs.build_type != 'Debug' }}
|
||||||
|
run: |
|
||||||
|
nix build --print-build-logs .#prismlauncher
|
||||||
|
|
|
||||||
48
.github/workflows/clang-tidy.yml
vendored
48
.github/workflows/clang-tidy.yml
vendored
|
|
@ -1,48 +0,0 @@
|
||||||
name: Clang-Tidy Code Scanning
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
merge_group:
|
|
||||||
types: [checks_requested]
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
clang-tidy:
|
|
||||||
name: Run Clang-Tidy
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Required for diffing later on
|
|
||||||
submodules: "true"
|
|
||||||
|
|
||||||
- name: Install Nix
|
|
||||||
uses: cachix/install-nix-action@v31
|
|
||||||
|
|
||||||
- name: Run source generators
|
|
||||||
# TODO(@getchoo): Figure out how to make this work with PCH
|
|
||||||
run: |
|
|
||||||
nix develop --command bash -c '
|
|
||||||
cmake -B build -D Launcher_USE_PCH=OFF && cmake --build build --target autogen autorcc
|
|
||||||
'
|
|
||||||
|
|
||||||
# TODO: Use SARIF after https://github.com/psastras/sarif-rs/issues/638 is fixed
|
|
||||||
- name: Run clang-tidy-diff
|
|
||||||
env:
|
|
||||||
BASE_REF: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
|
|
||||||
run: |
|
|
||||||
nix develop --command bash -c '
|
|
||||||
clang-tidy -verify-config && git diff -U0 --no-color "$BASE_REF" | clang-tidy-diff.py -p1 -quiet -only-check-in-db
|
|
||||||
'
|
|
||||||
43
.github/workflows/codeql.yml
vendored
43
.github/workflows/codeql.yml
vendored
|
|
@ -1,52 +1,35 @@
|
||||||
name: "CodeQL Code Scanning"
|
name: "CodeQL Code Scanning"
|
||||||
|
|
||||||
concurrency:
|
on: [ push, pull_request, workflow_dispatch ]
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
merge_group:
|
|
||||||
types: [checks_requested]
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CodeQL:
|
CodeQL:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: "true"
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v4
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
queries: security-and-quality
|
queries: security-and-quality
|
||||||
languages: cpp, java
|
languages: cpp, java
|
||||||
|
|
||||||
- name: Setup dependencies
|
- name: Install Dependencies
|
||||||
uses: ./.github/actions/setup-dependencies
|
run:
|
||||||
with:
|
sudo apt-get -y update
|
||||||
build-type: Debug
|
|
||||||
qt-version: 6.4.3
|
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 libqt5networkauth5-dev
|
||||||
|
|
||||||
- name: Configure and Build
|
- name: Configure and Build
|
||||||
run: |
|
run: |
|
||||||
cmake --preset linux -DLauncher_USE_PCH=OFF
|
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DLauncher_QT_VERSION_MAJOR=5 -G Ninja
|
||||||
cmake --build --preset linux --config Debug
|
|
||||||
|
|
||||||
- name: Run tests
|
cmake --build build
|
||||||
run: |
|
|
||||||
ctest --preset linux --build-config Debug --extra-verbose --output-on-failure
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v4
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|
|
||||||
174
.github/workflows/container.yml
vendored
174
.github/workflows/container.yml
vendored
|
|
@ -1,174 +0,0 @@
|
||||||
name: Development Container
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
merge_group:
|
|
||||||
types: [checks_requested]
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build (${{ matrix.arch }})
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
image-name: ${{ steps.image-name.outputs.image-name }}
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- arch: arm64
|
|
||||||
os: ubuntu-24.04-arm
|
|
||||||
- arch: amd64
|
|
||||||
os: ubuntu-24.04
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set image name
|
|
||||||
id: image-name
|
|
||||||
run: |
|
|
||||||
echo "image-name=${REGISTRY}/${GITHUB_REPOSITORY_OWNER,,}/devcontainer" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Install Podman
|
|
||||||
uses: redhat-actions/podman-install@main
|
|
||||||
# TODO(@getchoo): Always use this when the action properly supports ARM
|
|
||||||
if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }}
|
|
||||||
with:
|
|
||||||
github-token: ${{ github.token }}
|
|
||||||
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Determine metadata for image
|
|
||||||
id: image-metadata
|
|
||||||
uses: docker/metadata-action@v6
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ steps.image-name.outputs.image-name }}
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
tags: |
|
|
||||||
type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }}
|
|
||||||
|
|
||||||
type=sha
|
|
||||||
type=sha,format=long
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=tag
|
|
||||||
|
|
||||||
- name: Build image
|
|
||||||
id: build-image
|
|
||||||
uses: redhat-actions/buildah-build@v2
|
|
||||||
with:
|
|
||||||
containerfiles: |
|
|
||||||
./Containerfile
|
|
||||||
tags: ${{ steps.image-metadata.outputs.tags }}
|
|
||||||
labels: ${{ steps.image-metadata.outputs.labels }}
|
|
||||||
|
|
||||||
- name: Push image
|
|
||||||
id: push-image
|
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
|
||||||
uses: redhat-actions/push-to-registry@v2
|
|
||||||
with:
|
|
||||||
tags: ${{ steps.build-image.outputs.tags }}
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ github.token }}
|
|
||||||
tls-verify: true
|
|
||||||
|
|
||||||
- name: Export image digest
|
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
|
||||||
env:
|
|
||||||
DIGEST: ${{ steps.push-image.outputs.digest }}
|
|
||||||
run: |
|
|
||||||
mkdir -p "$RUNNER_TEMP"/digests
|
|
||||||
touch "$RUNNER_TEMP"/digests/"${DIGEST#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest artifact
|
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: digests-${{ matrix.arch }}
|
|
||||||
path: ${{ runner.temp }}/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
manifest:
|
|
||||||
name: Create manifest
|
|
||||||
|
|
||||||
needs: [ build ]
|
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Download digests
|
|
||||||
uses: actions/download-artifact@v8
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/digests
|
|
||||||
pattern: digests-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Install Podman
|
|
||||||
# TODO(@getchoo): Always use this when the action properly supports ARM
|
|
||||||
if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }}
|
|
||||||
uses: redhat-actions/podman-install@main
|
|
||||||
with:
|
|
||||||
github-token: ${{ github.token }}
|
|
||||||
|
|
||||||
- name: Login to registry
|
|
||||||
uses: redhat-actions/podman-login@v1
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ github.token }}
|
|
||||||
|
|
||||||
- name: Determine metadata for manifest
|
|
||||||
id: manifest-metadata
|
|
||||||
uses: docker/metadata-action@v6
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ needs.build.outputs.image-name }}
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
tags: |
|
|
||||||
type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }}
|
|
||||||
|
|
||||||
type=sha
|
|
||||||
type=sha,format=long
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=tag
|
|
||||||
|
|
||||||
- name: Create manifest list
|
|
||||||
working-directory: ${{ runner.temp }}/digests
|
|
||||||
env:
|
|
||||||
IMAGE_NAME: ${{ needs.build.outputs.image-name }}
|
|
||||||
run: |
|
|
||||||
while read -r tag; do
|
|
||||||
podman manifest create "$tag" \
|
|
||||||
$(printf "$IMAGE_NAME@sha256:%s " *)
|
|
||||||
done <<< "$DOCKER_METADATA_OUTPUT_TAGS"
|
|
||||||
|
|
||||||
- name: Push manifest
|
|
||||||
uses: redhat-actions/push-to-registry@v2
|
|
||||||
with:
|
|
||||||
tags: ${{ steps.manifest-metadata.outputs.tags }}
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ github.token }}
|
|
||||||
tls-verify: true
|
|
||||||
64
.github/workflows/merge-blocking-pr.yml
vendored
64
.github/workflows/merge-blocking-pr.yml
vendored
|
|
@ -1,64 +0,0 @@
|
||||||
name: Merged Blocking Pull Request Automation
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
pr_id:
|
|
||||||
description: Local Pull Request number to work on
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-blocked-status:
|
|
||||||
name: Update Blocked Status
|
|
||||||
runs-on: ubuntu-slim
|
|
||||||
|
|
||||||
# a pr that was a `blocking:<id>` label was merged.
|
|
||||||
# find the open pr's it was blocked by and trigger a refresh of their state
|
|
||||||
if: "${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'status: blocking') }}"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Generate token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@v3
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
|
||||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Gather Dependent PRs
|
|
||||||
id: gather_deps
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }}
|
|
||||||
run: |
|
|
||||||
blocked_prs=$(
|
|
||||||
gh -R ${{ github.repository }} pr list --label 'status: blocked' --json 'number,body' \
|
|
||||||
| jq -c --argjson pr "$PR_NUMBER" '
|
|
||||||
reduce ( .[] | select(
|
|
||||||
.body |
|
|
||||||
scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") |
|
|
||||||
map(tonumber) |
|
|
||||||
any(.[]; . == $pr)
|
|
||||||
)) as $i ([]; . + [$i])
|
|
||||||
'
|
|
||||||
)
|
|
||||||
{
|
|
||||||
echo "deps=$blocked_prs"
|
|
||||||
echo "numdeps=$(jq -r '. | length' <<< "$blocked_prs")"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Trigger Blocked PR Workflows for Dependants
|
|
||||||
if: fromJSON(steps.gather_deps.outputs.numdeps) > 0
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
DEPS: ${{ steps.gather_deps.outputs.deps }}
|
|
||||||
run: |
|
|
||||||
while read -r pr ; do
|
|
||||||
gh -R ${{ github.repository }} workflow run 'blocked-prs.yml' -r "${{ github.ref_name }}" -f pr_id="$pr"
|
|
||||||
done < <(jq -c '.[].number' <<< "$DEPS")
|
|
||||||
|
|
||||||
138
.github/workflows/nix.yml
vendored
138
.github/workflows/nix.yml
vendored
|
|
@ -1,138 +0,0 @@
|
||||||
name: Nix
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "develop"
|
|
||||||
- "release-*"
|
|
||||||
tags:
|
|
||||||
- "*"
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
- "**.md"
|
|
||||||
|
|
||||||
# Build files
|
|
||||||
- "**.nix"
|
|
||||||
- "nix/**"
|
|
||||||
- "flake.lock"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/**"
|
|
||||||
- "cmake/**"
|
|
||||||
- "launcher/**"
|
|
||||||
- "libraries/**"
|
|
||||||
- "program_info/**"
|
|
||||||
- "tests/**"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/nix.yml"
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
- "**.md"
|
|
||||||
|
|
||||||
# Build files
|
|
||||||
- "**.nix"
|
|
||||||
- "nix/**"
|
|
||||||
- "flake.lock"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/**"
|
|
||||||
- "cmake/**"
|
|
||||||
- "launcher/**"
|
|
||||||
- "libraries/**"
|
|
||||||
- "program_info/**"
|
|
||||||
- "tests/**"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/nix.yml"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
env:
|
|
||||||
DEBUG: ${{ github.ref_type != 'tag' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build (${{ matrix.system }})
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
system: x86_64-linux
|
|
||||||
|
|
||||||
- os: ubuntu-22.04-arm
|
|
||||||
system: aarch64-linux
|
|
||||||
|
|
||||||
- os: macos-26
|
|
||||||
system: aarch64-darwin
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Install Nix
|
|
||||||
uses: cachix/install-nix-action@v31
|
|
||||||
|
|
||||||
# For PRs
|
|
||||||
- name: Setup Nix Magic Cache
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
uses: DeterminateSystems/magic-nix-cache-action@v14
|
|
||||||
with:
|
|
||||||
diagnostic-endpoint: ""
|
|
||||||
use-flakehub: false
|
|
||||||
|
|
||||||
# For in-tree builds
|
|
||||||
- name: Setup Cachix
|
|
||||||
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
|
||||||
uses: cachix/cachix-action@v17
|
|
||||||
with:
|
|
||||||
name: prismlauncher
|
|
||||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
|
||||||
|
|
||||||
- name: Run Flake checks
|
|
||||||
run: |
|
|
||||||
nix flake check --print-build-logs --show-trace
|
|
||||||
|
|
||||||
- name: Build debug package
|
|
||||||
if: ${{ env.DEBUG == 'true' }}
|
|
||||||
run: |
|
|
||||||
nix build \
|
|
||||||
--no-link --print-build-logs --print-out-paths \
|
|
||||||
.#prismlauncher-debug >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
|
|
||||||
- name: Build release package
|
|
||||||
if: ${{ env.DEBUG == 'false' }}
|
|
||||||
env:
|
|
||||||
TAG: ${{ github.ref_name }}
|
|
||||||
SYSTEM: ${{ matrix.system }}
|
|
||||||
run: |
|
|
||||||
nix build --no-link --print-out-paths .#prismlauncher \
|
|
||||||
| tee -a "$GITHUB_STEP_SUMMARY" \
|
|
||||||
| xargs cachix pin prismlauncher "$TAG"-"$SYSTEM"
|
|
||||||
43
.github/workflows/trigger_builds.yml
vendored
Normal file
43
.github/workflows/trigger_builds.yml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
name: Build Application
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- "renovate/**"
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
- "**/LICENSE"
|
||||||
|
- "flake.lock"
|
||||||
|
- "packages/**"
|
||||||
|
- ".github/ISSUE_TEMPLATE/**"
|
||||||
|
- ".markdownlint**"
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
- "**/LICENSE"
|
||||||
|
- "flake.lock"
|
||||||
|
- "packages/**"
|
||||||
|
- ".github/ISSUE_TEMPLATE/**"
|
||||||
|
- ".markdownlint**"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_debug:
|
||||||
|
name: Build Debug
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
with:
|
||||||
|
build_type: Debug
|
||||||
|
is_qt_cached: true
|
||||||
|
secrets:
|
||||||
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
|
||||||
|
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
|
||||||
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
|
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
|
@ -5,38 +5,40 @@ on:
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- "*"
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_release:
|
build_release:
|
||||||
name: Build Release
|
name: Build Release
|
||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
# Required for Azure Trusted Signing
|
|
||||||
id-token: write
|
|
||||||
# Required for vcpkg binary cache
|
|
||||||
packages: write
|
|
||||||
with:
|
with:
|
||||||
build-type: Release
|
build_type: Release
|
||||||
environment: Release
|
is_qt_cached: false
|
||||||
secrets: inherit
|
secrets:
|
||||||
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
|
||||||
|
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
|
||||||
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
|
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
|
||||||
create_release:
|
create_release:
|
||||||
needs: build_release
|
needs: build_release
|
||||||
permissions:
|
runs-on: ubuntu-latest
|
||||||
contents: write
|
|
||||||
runs-on: ubuntu-slim
|
|
||||||
outputs:
|
outputs:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: "true"
|
submodules: "true"
|
||||||
path: "PrismLauncher-source"
|
path: "PrismLauncher-source"
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v4
|
||||||
- name: Grab and store version
|
- name: Grab and store version
|
||||||
run: |
|
run: |
|
||||||
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
|
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
|
||||||
|
|
@ -45,13 +47,11 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
|
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
|
||||||
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-Linux-aarch64-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-Linux-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*-x86_64.AppImage PrismLauncher-Linux-x86_64.AppImage
|
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
|
||||||
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-x86_64.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*-aarch64.AppImage PrismLauncher-Linux-aarch64.AppImage
|
mv PrismLauncher-macOS-Legacy*/PrismLauncher.zip PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
||||||
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-aarch64.AppImage.zsync PrismLauncher-Linux-aarch64.AppImage.zsync
|
|
||||||
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
|
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
|
||||||
mv PrismLauncher-macOS*/PrismLauncher.dmg PrismLauncher-macOS-${{ env.VERSION }}.dmg
|
|
||||||
|
|
||||||
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
||||||
|
|
||||||
|
|
@ -81,40 +81,23 @@ jobs:
|
||||||
cd ..
|
cd ..
|
||||||
done
|
done
|
||||||
|
|
||||||
for d in PrismLauncher-Windows-MinGW-arm64*; do
|
|
||||||
cd "${d}" || continue
|
|
||||||
INST="$(echo -n ${d} | grep -o Setup || true)"
|
|
||||||
PORT="$(echo -n ${d} | grep -o Portable || true)"
|
|
||||||
NAME="PrismLauncher-Windows-MinGW-arm64"
|
|
||||||
test -z "${PORT}" || NAME="${NAME}-Portable"
|
|
||||||
test -z "${INST}" || mv PrismLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
|
|
||||||
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
|
|
||||||
cd ..
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: softprops/action-gh-release@v3
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
name: Prism Launcher ${{ env.VERSION }}
|
name: Prism Launcher ${{ env.VERSION }}
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
fail_on_unmatched_files: true
|
|
||||||
files: |
|
files: |
|
||||||
|
PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-x86_64.AppImage
|
PrismLauncher-Linux-x86_64.AppImage
|
||||||
PrismLauncher-Linux-x86_64.AppImage.zsync
|
PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
PrismLauncher-Linux-aarch64.AppImage
|
|
||||||
PrismLauncher-Linux-aarch64.AppImage.zsync
|
|
||||||
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
|
||||||
PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-Windows-MinGW-arm64-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MinGW-arm64-Portable-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MinGW-arm64-Setup-${{ env.VERSION }}.exe
|
|
||||||
PrismLauncher-Windows-MSVC-arm64-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-arm64-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe
|
||||||
|
|
@ -122,5 +105,5 @@ jobs:
|
||||||
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-macOS-${{ env.VERSION }}.zip
|
PrismLauncher-macOS-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-macOS-${{ env.VERSION }}.dmg
|
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
PrismLauncher-${{ env.VERSION }}.tar.gz
|
||||||
25
.github/workflows/update-flake.yml
vendored
25
.github/workflows/update-flake.yml
vendored
|
|
@ -6,30 +6,25 @@ on:
|
||||||
- cron: "0 0 * * 0"
|
- cron: "0 0 * * 0"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions: {}
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-flake:
|
update-flake:
|
||||||
if: github.repository == 'PrismLauncher/PrismLauncher'
|
if: github.repository == 'PrismLauncher/PrismLauncher'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
runs-on: ubuntu-slim
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31
|
- uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
|
||||||
|
|
||||||
- uses: DeterminateSystems/update-flake-lock@v28
|
- uses: DeterminateSystems/update-flake-lock@v24
|
||||||
with:
|
with:
|
||||||
commit-msg: "chore(nix): update lockfile"
|
commit-msg: "chore(nix): update lockfile"
|
||||||
pr-title: "chore(nix): update lockfile"
|
pr-title: "chore(nix): update lockfile"
|
||||||
pr-labels: |
|
pr-labels: |
|
||||||
platform: Linux
|
Linux
|
||||||
area: packaging
|
packaging
|
||||||
complexity: low
|
simple change
|
||||||
priority: low
|
|
||||||
type: robot
|
|
||||||
changelog:omit
|
changelog:omit
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,13 @@
|
||||||
name: Publish
|
name: Publish to WinGet
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [ released ]
|
types: [released]
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
winget:
|
publish:
|
||||||
name: Winget
|
runs-on: windows-latest
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
runs-on: ubuntu-slim
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Publish on Winget
|
- uses: vedantmgoyal2009/winget-releaser@v2
|
||||||
uses: vedantmgoyal2009/winget-releaser@v2
|
|
||||||
with:
|
with:
|
||||||
identifier: PrismLauncher.PrismLauncher
|
identifier: PrismLauncher.PrismLauncher
|
||||||
version: ${{ github.event.release.tag_name }}
|
version: ${{ github.event.release.tag_name }}
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -14,7 +14,6 @@ CMakeLists.txt.user.*
|
||||||
CMakeSettings.json
|
CMakeSettings.json
|
||||||
/CMakeFiles
|
/CMakeFiles
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CMakeUserPresets.json
|
|
||||||
/.project
|
/.project
|
||||||
/.settings
|
/.settings
|
||||||
/.idea
|
/.idea
|
||||||
|
|
@ -22,7 +21,6 @@ CMakeUserPresets.json
|
||||||
/.vs
|
/.vs
|
||||||
cmake-build-*/
|
cmake-build-*/
|
||||||
Debug
|
Debug
|
||||||
compile_commands.json
|
|
||||||
|
|
||||||
# Build dirs
|
# Build dirs
|
||||||
build
|
build
|
||||||
|
|
@ -49,12 +47,8 @@ run/
|
||||||
|
|
||||||
# Nix/NixOS
|
# Nix/NixOS
|
||||||
.direnv/
|
.direnv/
|
||||||
## Used when manually invoking stdenv phases
|
.pre-commit-config.yaml
|
||||||
outputs/
|
|
||||||
## Regular artifacts
|
|
||||||
result
|
result
|
||||||
result-*
|
|
||||||
repl-result-*
|
|
||||||
|
|
||||||
# Flatpak
|
# Flatpak
|
||||||
.flatpak-builder
|
.flatpak-builder
|
||||||
|
|
|
||||||
21
.gitmodules
vendored
21
.gitmodules
vendored
|
|
@ -1,3 +1,24 @@
|
||||||
|
[submodule "libraries/quazip"]
|
||||||
|
path = libraries/quazip
|
||||||
|
url = https://github.com/stachenov/quazip.git
|
||||||
|
[submodule "libraries/tomlplusplus"]
|
||||||
|
path = libraries/tomlplusplus
|
||||||
|
url = https://github.com/marzer/tomlplusplus.git
|
||||||
|
[submodule "libraries/filesystem"]
|
||||||
|
path = libraries/filesystem
|
||||||
|
url = https://github.com/gulrak/filesystem
|
||||||
[submodule "libraries/libnbtplusplus"]
|
[submodule "libraries/libnbtplusplus"]
|
||||||
path = libraries/libnbtplusplus
|
path = libraries/libnbtplusplus
|
||||||
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
||||||
|
[submodule "libraries/zlib"]
|
||||||
|
path = libraries/zlib
|
||||||
|
url = https://github.com/madler/zlib.git
|
||||||
|
[submodule "libraries/extra-cmake-modules"]
|
||||||
|
path = libraries/extra-cmake-modules
|
||||||
|
url = https://github.com/KDE/extra-cmake-modules
|
||||||
|
[submodule "libraries/cmark"]
|
||||||
|
path = libraries/cmark
|
||||||
|
url = https://github.com/commonmark/cmark.git
|
||||||
|
[submodule "flatpak/shared-modules"]
|
||||||
|
path = flatpak/shared-modules
|
||||||
|
url = https://github.com/flathub/shared-modules.git
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
libraries/nbtplusplus
|
libraries/nbtplusplus
|
||||||
|
libraries/quazip
|
||||||
|
|
|
||||||
437
CMakeLists.txt
437
CMakeLists.txt
|
|
@ -1,9 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.25) # Required for features like `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`
|
cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
|
||||||
|
|
||||||
project(Launcher LANGUAGES C CXX)
|
project(Launcher)
|
||||||
if(APPLE)
|
|
||||||
enable_language(OBJC OBJCXX)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
||||||
if(IS_IN_SOURCE_BUILD)
|
if(IS_IN_SOURCE_BUILD)
|
||||||
|
|
@ -13,10 +10,6 @@ endif()
|
||||||
##################################### Set CMake options #####################################
|
##################################### Set CMake options #####################################
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
|
||||||
set(CMAKE_AUTOGEN_ORIGIN_DEPENDS OFF)
|
|
||||||
set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
|
|
||||||
set(CMAKE_GLOBAL_AUTORCC_TARGET ON)
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
|
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
|
||||||
|
|
@ -31,106 +24,101 @@ set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars)
|
||||||
######## Set compiler flags ########
|
######## Set compiler flags ########
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED true)
|
set(CMAKE_CXX_STANDARD_REQUIRED true)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED true)
|
set(CMAKE_C_STANDARD_REQUIRED true)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
|
if(MSVC)
|
||||||
|
# /GS Adds buffer security checks, default on but incuded anyway to mirror gcc's fstack-protector flag
|
||||||
|
# /permissive- specify standards-conforming compiler behavior, also enabled by Qt6, default on with std:c++20
|
||||||
|
# Use /W4 as /Wall includes unnesserey warnings such as added padding to structs
|
||||||
|
set(CMAKE_CXX_FLAGS "/GS /permissive- /W4 ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
add_compile_definitions($<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>)
|
# /EHs Enables stack unwind semantics for standard C++ exceptions to ensure stackframes are unwound
|
||||||
add_compile_definitions(QT_WARN_DEPRECATED_UP_TO=0x060400)
|
# and object deconstructors are called when an exception is caught.
|
||||||
add_compile_definitions(QT_DISABLE_DEPRECATED_UP_TO=0x060400)
|
# without it memory leaks and a warning is printed
|
||||||
|
# /EHc tells the compiler to assume that functions declared as extern "C" never throw a C++ exception
|
||||||
|
# This appears to not always be a defualt compiler option in CMAKE
|
||||||
|
set(CMAKE_CXX_FLAGS "/EHsc ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
# LINK accepts /SUBSYSTEM whics sets if we are a WINDOWS (gui) or a CONSOLE programs
|
||||||
add_compile_options(
|
# This implicitly selects an entrypoint specific to the subsystem selected
|
||||||
# /GS Adds buffer security checks, default on but included anyway to mirror gcc's fstack-protector flag
|
# qtmain/QtEntryPointLib provides the correct entrypoint (wWinMain) for gui programs
|
||||||
"$<$<COMPILE_LANGUAGE:C,CXX>:/GS>"
|
# Additinaly LINK autodetects we use a GUI so we can omit /SUBSYSTEM
|
||||||
|
# This allows tests to still use have console without using seperate linker flags
|
||||||
# /Gw helps reduce binary size
|
# /LTCG allows for linking wholy optimizated programs
|
||||||
# /Gy allows the compiler to package individual functions
|
# /MANIFEST:NO disables generating a manifest file, we instead provide our own
|
||||||
# /guard:cf enables control flow guard
|
# /STACK sets the stack reserve size, ATL's pack list needs 3-4 MiB as of November 2022, provide 8 MiB
|
||||||
"$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:/Gw;/Gy;/guard:cf>"
|
set(CMAKE_EXE_LINKER_FLAGS "/LTCG /MANIFEST:NO /STACK:8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
)
|
|
||||||
|
|
||||||
add_link_options(
|
|
||||||
# /LTCG allows for linking wholy optimizated programs
|
|
||||||
# /MANIFEST:NO disables generating a manifest file, we instead provide our own
|
|
||||||
# /STACK sets the stack reserve size, ATL's pack list needs 3-4 MiB as of November 2022, provide 8 MiB
|
|
||||||
"$<$<COMPILE_LANGUAGE:C,CXX>:/LTCG;/MANIFEST:NO;/STACK:8388608>"
|
|
||||||
)
|
|
||||||
|
|
||||||
# /GL enables whole program optimizations
|
# /GL enables whole program optimizations
|
||||||
# NOTE: With Clang, this is implemented as regular LTO and only used during linking
|
# /Gw helps reduce binary size
|
||||||
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
# /Gy allows the compiler to package individual functions
|
||||||
add_compile_options("$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:/GL>")
|
# /guard:cf enables control flow guard
|
||||||
endif()
|
foreach(lang C CXX)
|
||||||
|
set("CMAKE_${lang}_FLAGS_RELEASE" "/GL /Gw /Gy /guard:cf")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
# See https://github.com/ccache/ccache/issues/1040
|
# See https://github.com/ccache/ccache/issues/1040
|
||||||
# TODO(@getchoo): Is sccache affected by this? Would be nice to use `ProgramDatabase`....
|
# Note, CMake 3.25 replaces this with CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
|
||||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
|
# See https://cmake.org/cmake/help/v3.25/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.html
|
||||||
|
foreach(config DEBUG RELWITHDEBINFO)
|
||||||
|
foreach(lang C CXX)
|
||||||
|
set(flags_var "CMAKE_${lang}_FLAGS_${config}")
|
||||||
|
string(REGEX REPLACE "/Z[Ii]" "/Z7" ${flags_var} "${${flags_var}}")
|
||||||
|
endforeach()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDLL")
|
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDLL")
|
||||||
set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release "")
|
set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release "")
|
||||||
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release "")
|
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release "")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:-fstack-protector-strong;--param=ssp-buffer-size=4>")
|
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
# Avoid re-defining _FORTIFY_SOURCE, as it can cause redefinition errors in setups that use it by default (i.e., package builds)
|
|
||||||
if(NOT (CMAKE_C_FLAGS MATCHES "-D_FORTIFY_SOURCE" OR CMAKE_CXX_FLAGS MATCHES "-D_FORTIFY_SOURCE"))
|
|
||||||
# NOTE: _FORTIFY_SOURCE requires optimizations in most newer versions of glibc
|
|
||||||
add_compile_options("$<$<AND:$<COMPILE_LANGUAGE:C,CXX>,$<CONFIG:Release,RelWithDebInfo>>:-D_FORTIFY_SOURCE=2>")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# ATL's pack list needs more than the default 1 Mib stack on windows
|
# ATL's pack list needs more than the default 1 Mib stack on windows
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
if(WIN32)
|
||||||
add_link_options("$<$<COMPILE_LANGUAGE:C,CXX>:-Wl,--stack,8388608>")
|
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
|
|
||||||
# -ffunction-sections and -fdata-sections help reduce binary size
|
|
||||||
# -mguard=cf enables Control Flow Guard
|
|
||||||
# TODO: Look into -gc-sections to further reduce binary size
|
|
||||||
add_compile_options("$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:-ffunction-sections;-fdata-sections;-mguard=cf>")
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Export compile commands for debug builds if we can (useful in LSPs like clangd)
|
# Fix build with Qt 5.13
|
||||||
# https://cmake.org/cmake/help/v3.31/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
||||||
if(CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR MATCHES "^Ninja")
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(USE_CLANG_TIDY "Enable the use of clang-tidy during compilation" OFF)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
|
||||||
|
|
||||||
if(USE_CLANG_TIDY)
|
# Fix aarch64 build for toml++
|
||||||
find_program(CLANG_TIDY clang-tidy OPTIONAL)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
|
||||||
if(CLANG_TIDY)
|
|
||||||
message(STATUS "Using clang-tidy during compilation")
|
# set CXXFLAGS for build targets
|
||||||
set(CLANG_TIDY_COMMAND "${CLANG_TIDY}" "--config-file=${CMAKE_SOURCE_DIR}/.clang-tidy")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_COMMAND})
|
|
||||||
else()
|
|
||||||
message(WARNING "Unable to find `clang-tidy`. Not using during compilation")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" OFF)
|
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" OFF)
|
||||||
|
|
||||||
# If this is a Debug build turn on address sanitiser
|
# If this is a Debug build turn on address sanitiser
|
||||||
if (DEBUG_ADDRESS_SANITIZER)
|
if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") AND DEBUG_ADDRESS_SANITIZER)
|
||||||
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
||||||
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
set(USE_ASAN_COMPILE_OPTIONS $<AND:$<CONFIG:Debug,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>)
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
# using clang with clang-cl front end
|
||||||
message(STATUS "Using Address Sanitizer compile options for MSVC frontend")
|
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
|
||||||
add_compile_options(
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
||||||
$<${USE_ASAN_COMPILE_OPTIONS}:/fsanitize=address>
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
||||||
$<${USE_ASAN_COMPILE_OPTIONS}:/Oy->
|
else()
|
||||||
)
|
# AppleClang and Clang
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
message(STATUS "Address Sanitizer available on Clang")
|
||||||
message(STATUS "Using Address Sanitizer compile options for GCC/Clang")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
add_compile_options(
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
$<${USE_ASAN_COMPILE_OPTIONS}:-fsanitize=address,undefined>
|
endif()
|
||||||
$<${USE_ASAN_COMPILE_OPTIONS}:-fno-omit-frame-pointer>
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
$<${USE_ASAN_COMPILE_OPTIONS}:-fno-sanitize-recover=null>
|
# GCC
|
||||||
)
|
message(STATUS "Address Sanitizer available on GCC")
|
||||||
link_libraries("asan" "ubsan")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
|
link_libraries("asan")
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
|
message(STATUS "Address Sanitizer available on MSVC")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
|
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -146,9 +134,8 @@ if(ENABLE_LTO)
|
||||||
if(ipo_supported)
|
if(ipo_supported)
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL TRUE)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL TRUE)
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
|
|
||||||
if(CMAKE_BUILD_TYPE)
|
if(CMAKE_BUILD_TYPE)
|
||||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||||
message(STATUS "IPO / LTO enabled")
|
message(STATUS "IPO / LTO enabled")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Not enabling IPO / LTO on debug builds")
|
message(STATUS "Not enabling IPO / LTO on debug builds")
|
||||||
|
|
@ -163,9 +150,20 @@ endif()
|
||||||
|
|
||||||
option(BUILD_TESTING "Build the testing tree." ON)
|
option(BUILD_TESTING "Build the testing tree." ON)
|
||||||
|
|
||||||
find_package(ECM NO_MODULE REQUIRED)
|
find_package(ECM QUIET NO_MODULE)
|
||||||
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
|
if(NOT ECM_FOUND)
|
||||||
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/extra-cmake-modules/CMakeLists.txt")
|
||||||
|
message(STATUS "Using bundled ECM")
|
||||||
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libraries/extra-cmake-modules/modules;${CMAKE_MODULE_PATH}")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR
|
||||||
|
" Could not find ECM\n \n"
|
||||||
|
" Either install ECM using the system package manager or clone submodules\n"
|
||||||
|
" Submodules can be cloned with 'git submodule update --init --recursive'")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
|
||||||
|
endif()
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(ECMAddTests)
|
include(ECMAddTests)
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
|
|
@ -177,19 +175,17 @@ endif()
|
||||||
######## Set URLs ########
|
######## Set URLs ########
|
||||||
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
||||||
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||||
set(Launcher_WIKI_URL "https://prismlauncher.org/wiki/" CACHE STRING "URL that gets opened when the user clicks 'Launcher Help'")
|
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||||
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help in a dialog window")
|
|
||||||
set(Launcher_LOGIN_CALLBACK_URL "https://prismlauncher.org/successful-login" CACHE STRING "URL that gets opened when the user successfully logins.")
|
set(Launcher_LOGIN_CALLBACK_URL "https://prismlauncher.org/successful-login" CACHE STRING "URL that gets opened when the user successfully logins.")
|
||||||
set(Launcher_LEGACY_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for legacy (<=1.5.2) FML Libraries.")
|
set(Launcher_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for FML Libraries.")
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 12)
|
set(Launcher_VERSION_MAJOR 9)
|
||||||
set(Launcher_VERSION_MINOR 0)
|
set(Launcher_VERSION_MINOR 2)
|
||||||
set(Launcher_VERSION_PATCH 0)
|
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}")
|
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
||||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}.0")
|
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
||||||
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},${Launcher_VERSION_PATCH},0")
|
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0")
|
||||||
|
|
||||||
# Build platform.
|
# Build platform.
|
||||||
set(Launcher_BUILD_PLATFORM "unknown" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
|
set(Launcher_BUILD_PLATFORM "unknown" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
|
||||||
|
|
@ -223,10 +219,9 @@ set(Launcher_DISCORD_URL "https://prismlauncher.org/discord" CACHE STRING "URL f
|
||||||
set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL for the subreddit.")
|
set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL for the subreddit.")
|
||||||
|
|
||||||
# Builds
|
# Builds
|
||||||
|
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
|
||||||
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
|
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
|
||||||
|
|
||||||
option(Launcher_USE_PCH "Use precompiled headers where possible" ON)
|
|
||||||
|
|
||||||
# Java downloader
|
# Java downloader
|
||||||
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
||||||
|
|
||||||
|
|
@ -234,7 +229,7 @@ set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
||||||
# differing Linux/BSD/etc distributions. Downstream packagers should be explicitly opt-ing into this
|
# differing Linux/BSD/etc distributions. Downstream packagers should be explicitly opt-ing into this
|
||||||
# feature if they know it will work with their distribution.
|
# feature if they know it will work with their distribution.
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
|
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Java downloader
|
# Java downloader
|
||||||
|
|
@ -289,59 +284,75 @@ set(Launcher_BUILD_TIMESTAMP "${TODAY}")
|
||||||
|
|
||||||
################################ 3rd Party Libs ################################
|
################################ 3rd Party Libs ################################
|
||||||
|
|
||||||
|
# Successive configurations of cmake without cleaning the build dir will cause zlib fallback to fail due to cached values
|
||||||
|
# Record when fallback triggered and skip this find_package
|
||||||
|
if(NOT Launcher_FORCE_BUNDLED_LIBS AND NOT FORCE_BUNDLED_ZLIB)
|
||||||
|
find_package(ZLIB QUIET)
|
||||||
|
endif()
|
||||||
|
if(NOT ZLIB_FOUND)
|
||||||
|
set(FORCE_BUNDLED_ZLIB TRUE CACHE BOOL "")
|
||||||
|
mark_as_advanced(FORCE_BUNDLED_ZLIB)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Find the required Qt parts
|
# Find the required Qt parts
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
include(QtVersionlessBackport)
|
||||||
|
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
set(QT_VERSION_MAJOR 5)
|
||||||
|
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml NetworkAuth)
|
||||||
|
|
||||||
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
|
find_package(QuaZip-Qt5 1.3 QUIET)
|
||||||
|
endif()
|
||||||
|
if (NOT QuaZip-Qt5_FOUND)
|
||||||
|
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
|
||||||
|
set(FORCE_BUNDLED_QUAZIP 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Qt 6 sets these by default. Notably causes Windows APIs to use UNICODE strings.
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
|
||||||
|
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
||||||
set(QT_VERSION_MAJOR 6)
|
set(QT_VERSION_MAJOR 6)
|
||||||
find_package(Qt6 6.4 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml NetworkAuth OpenGL)
|
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth)
|
||||||
find_package(Qt6 COMPONENTS DBus)
|
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
||||||
list(APPEND Launcher_QT_DBUS Qt6::DBus)
|
|
||||||
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
|
find_package(QuaZip-Qt6 1.3 QUIET)
|
||||||
|
endif()
|
||||||
|
if (NOT QuaZip-Qt6_FOUND)
|
||||||
|
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
|
||||||
|
set(FORCE_BUNDLED_QUAZIP 1)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
include(ECMQueryQt)
|
||||||
|
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
|
||||||
|
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
|
||||||
|
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
|
||||||
|
else()
|
||||||
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
|
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
|
||||||
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
|
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
|
||||||
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
|
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(cmark REQUIRED)
|
# NOTE: Qt 6 already sets this by default
|
||||||
|
if (Qt5_POSITION_INDEPENDENT_CODE)
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
pkg_check_modules(gamemode REQUIRED IMPORTED_TARGET gamemode)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Find libqrencode
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
## NOTE(@getchoo): Never use pkg-config with MSVC since the vcpkg port makes our install bundle fail to find the dll
|
# Find toml++
|
||||||
if(MSVC)
|
find_package(tomlplusplus 3.2.0 QUIET)
|
||||||
find_path(LIBQRENCODE_INCLUDE_DIR qrencode.h REQUIRED)
|
|
||||||
find_library(LIBQRENCODE_LIBRARY_RELEASE qrencode REQUIRED)
|
# Find ghc_filesystem
|
||||||
find_library(LIBQRENCODE_LIBRARY_DEBUG qrencoded)
|
find_package(ghc_filesystem QUIET)
|
||||||
set(LIBQRENCODE_LIBRARIES optimized ${LIBQRENCODE_LIBRARY_RELEASE} debug ${LIBQRENCODE_LIBRARY_DEBUG})
|
|
||||||
else()
|
# Find cmark
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(cmark QUIET)
|
||||||
pkg_check_modules(libqrencode REQUIRED IMPORTED_TARGET libqrencode)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Find libarchive through CMake packages, mainly for vcpkg
|
|
||||||
find_package(LibArchive)
|
|
||||||
# CMake packages aren't available in most distributions of libarchive, so fallback to pkg-config
|
|
||||||
if(NOT LibArchive_FOUND)
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
pkg_check_modules(libarchive REQUIRED IMPORTED_TARGET libarchive)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(tomlplusplus 3.2.0)
|
|
||||||
# fallback to pkgconfig, important especially as many distros package toml++ built with meson
|
|
||||||
if(NOT tomlplusplus_FOUND)
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus>=3.2.0)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(ZLIB REQUIRED)
|
|
||||||
|
|
||||||
|
|
||||||
include(ECMQtDeclareLoggingCategory)
|
include(ECMQtDeclareLoggingCategory)
|
||||||
|
|
||||||
####################################### Program Info #######################################
|
####################################### Program Info #######################################
|
||||||
|
|
@ -355,7 +366,7 @@ set(Launcher_ENABLE_UPDATER NO)
|
||||||
set(Launcher_BUILD_UPDATER NO)
|
set(Launcher_BUILD_UPDATER NO)
|
||||||
|
|
||||||
if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL ""))
|
if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL ""))
|
||||||
set(Launcher_BUILD_UPDATER YES)
|
set(Launcher_BUILD_UPDATER YES)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT (UNIX AND APPLE))
|
if(NOT (UNIX AND APPLE))
|
||||||
|
|
@ -371,10 +382,13 @@ if(UNIX AND APPLE)
|
||||||
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
|
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
|
||||||
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
|
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
|
||||||
|
|
||||||
|
# Apps to bundle
|
||||||
|
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app")
|
||||||
|
|
||||||
# Mac bundle settings
|
# Mac bundle settings
|
||||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
|
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
|
||||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "${Launcher_AppID}")
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
|
|
@ -383,63 +397,23 @@ if(UNIX AND APPLE)
|
||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
|
||||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed")
|
||||||
|
|
||||||
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.8.0/Sparkle-2.8.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.6.4/Sparkle-2.6.4.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_SHA256 "fd5681ee92bf238aaac2d08214ceaf0cc8976e452d7f882d80bac1e61581f3b1" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
set(MACOSX_SPARKLE_SHA256 "50612a06038abc931f16011d7903b8326a362c1074dabccb718404ce8e585f0b" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||||
|
|
||||||
|
# directories to look for dependencies
|
||||||
|
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${MACOSX_SPARKLE_DIR})
|
||||||
|
|
||||||
if(NOT MACOSX_SPARKLE_UPDATE_PUBLIC_KEY STREQUAL "" AND NOT MACOSX_SPARKLE_UPDATE_FEED_URL STREQUAL "")
|
if(NOT MACOSX_SPARKLE_UPDATE_PUBLIC_KEY STREQUAL "" AND NOT MACOSX_SPARKLE_UPDATE_FEED_URL STREQUAL "")
|
||||||
set(Launcher_ENABLE_UPDATER YES)
|
set(Launcher_ENABLE_UPDATER YES)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# install as bundle
|
||||||
|
set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies")
|
||||||
|
|
||||||
# Add the icon
|
# Add the icon
|
||||||
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
||||||
|
|
||||||
find_program(ACTOOL_EXE actool DOC "Path to the apple asset catalog compiler")
|
|
||||||
if(ACTOOL_EXE)
|
|
||||||
execute_process(
|
|
||||||
COMMAND xcodebuild -version
|
|
||||||
OUTPUT_VARIABLE XCODE_VERSION_OUTPUT
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
|
|
||||||
string(REGEX MATCH "Xcode ([0-9]+\.[0-9]+)" XCODE_VERSION_MATCH "${XCODE_VERSION_OUTPUT}")
|
|
||||||
if(XCODE_VERSION_MATCH)
|
|
||||||
set(XCODE_VERSION ${CMAKE_MATCH_1})
|
|
||||||
else()
|
|
||||||
set(XCODE_VERSION 0.0)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(XCODE_VERSION VERSION_GREATER_EQUAL 26.0)
|
|
||||||
set(ASSETS_OUT_DIR "${CMAKE_BINARY_DIR}/program_info")
|
|
||||||
set(GENERATED_ASSETS_CAR "${ASSETS_OUT_DIR}/Assets.car")
|
|
||||||
set(ICON_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_Branding_MAC_ICON}")
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT "${GENERATED_ASSETS_CAR}"
|
|
||||||
COMMAND ${ACTOOL_EXE} "${ICON_SOURCE}"
|
|
||||||
--compile "${ASSETS_OUT_DIR}"
|
|
||||||
--output-partial-info-plist /dev/null
|
|
||||||
--app-icon ${Launcher_Name}
|
|
||||||
--enable-on-demand-resources NO
|
|
||||||
--target-device mac
|
|
||||||
--minimum-deployment-target ${CMAKE_OSX_DEPLOYMENT_TARGET}
|
|
||||||
--platform macosx
|
|
||||||
DEPENDS "${ICON_SOURCE}"
|
|
||||||
COMMENT "Compiling asset catalog (${ICON_SOURCE})"
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
add_custom_target(compile_assets ALL DEPENDS "${GENERATED_ASSETS_CAR}")
|
|
||||||
install(FILES "${GENERATED_ASSETS_CAR}" DESTINATION "${RESOURCES_DEST_DIR}")
|
|
||||||
else()
|
|
||||||
message(WARNING "Xcode ${XCODE_VERSION} is too old. Minimum required version is 26.0. Not compiling liquid glass icons.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
else()
|
|
||||||
message(WARNING "actool not found. Cannot compile macOS app icons.\n"
|
|
||||||
"Install Xcode command line tools: 'xcode-select --install'")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
include(KDEInstallDirs)
|
include(KDEInstallDirs)
|
||||||
|
|
||||||
|
|
@ -447,20 +421,30 @@ elseif(UNIX)
|
||||||
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
||||||
set(JARS_DEST_DIR "share/${Launcher_Name}")
|
set(JARS_DEST_DIR "share/${Launcher_Name}")
|
||||||
|
|
||||||
|
# install as bundle with no dependencies included
|
||||||
|
set(INSTALL_BUNDLE "nodeps" CACHE STRING "Use fixup_bundle to bundle dependencies")
|
||||||
|
|
||||||
# Set RPATH
|
# Set RPATH
|
||||||
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
||||||
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${KDE_INSTALL_APPDIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${KDE_INSTALL_APPDIR})
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${KDE_INSTALL_METAINFODIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${KDE_INSTALL_METAINFODIR})
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_PNG_256} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/256x256/apps" RENAME "${Launcher_AppID}.png")
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
|
||||||
|
|
||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
|
||||||
|
|
||||||
set(PLUGIN_DEST_DIR "plugins")
|
if (INSTALL_BUNDLE STREQUAL full)
|
||||||
set(BUNDLE_DEST_DIR ".")
|
set(PLUGIN_DEST_DIR "plugins")
|
||||||
set(RESOURCES_DEST_DIR ".")
|
set(BUNDLE_DEST_DIR ".")
|
||||||
|
set(RESOURCES_DEST_DIR ".")
|
||||||
|
|
||||||
|
# Apps to bundle
|
||||||
|
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${Launcher_APP_BINARY_NAME}")
|
||||||
|
|
||||||
|
# directories to look for dependencies
|
||||||
|
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(Launcher_ManPage)
|
if(Launcher_ManPage)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
||||||
|
|
@ -476,6 +460,15 @@ elseif(WIN32)
|
||||||
set(PLUGIN_DEST_DIR ".")
|
set(PLUGIN_DEST_DIR ".")
|
||||||
set(RESOURCES_DEST_DIR ".")
|
set(RESOURCES_DEST_DIR ".")
|
||||||
set(JARS_DEST_DIR "jars")
|
set(JARS_DEST_DIR "jars")
|
||||||
|
|
||||||
|
# Apps to bundle
|
||||||
|
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.exe")
|
||||||
|
|
||||||
|
# directories to look for dependencies
|
||||||
|
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
|
||||||
|
# install as bundle
|
||||||
|
set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Platform not supported")
|
message(FATAL_ERROR "Platform not supported")
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -492,12 +485,70 @@ option(NBT_USE_ZLIB "Build NBT library with zlib support" OFF)
|
||||||
option(NBT_BUILD_TESTS "Build NBT library tests" OFF) #FIXME: fix unit tests.
|
option(NBT_BUILD_TESTS "Build NBT library tests" OFF) #FIXME: fix unit tests.
|
||||||
add_subdirectory(libraries/libnbtplusplus)
|
add_subdirectory(libraries/libnbtplusplus)
|
||||||
|
|
||||||
|
add_subdirectory(libraries/systeminfo) # system information library
|
||||||
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
|
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
|
||||||
add_subdirectory(libraries/javacheck) # java compatibility checker
|
add_subdirectory(libraries/javacheck) # java compatibility checker
|
||||||
|
if(FORCE_BUNDLED_ZLIB)
|
||||||
|
message(STATUS "Using bundled zlib")
|
||||||
|
|
||||||
|
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Suppress cmake warnings and allow INTERPROCEDURAL_OPTIMIZATION for zlib
|
||||||
|
set(SKIP_INSTALL_ALL ON)
|
||||||
|
add_subdirectory(libraries/zlib EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
# On OS where unistd.h exists, zlib's generated header defines `Z_HAVE_UNISTD_H`, while the included header does not.
|
||||||
|
# We cannot safely undo the rename on those systems, and they generally have packages for zlib anyway.
|
||||||
|
check_include_file(unistd.h NEED_GENERATED_ZCONF)
|
||||||
|
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" AND NOT NEED_GENERATED_ZCONF)
|
||||||
|
# zlib's cmake script renames a file, dirtying the submodule, see https://github.com/madler/zlib/issues/162
|
||||||
|
message(STATUS "Undoing Rename")
|
||||||
|
message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h")
|
||||||
|
file(RENAME "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/libraries/zlib" "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib" CACHE STRING "" FORCE)
|
||||||
|
set_target_properties(zlibstatic PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIR}")
|
||||||
|
add_library(ZLIB::ZLIB ALIAS zlibstatic)
|
||||||
|
set(ZLIB_LIBRARY ZLIB::ZLIB CACHE STRING "zlib library name")
|
||||||
|
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system zlib")
|
||||||
|
endif()
|
||||||
|
if (FORCE_BUNDLED_QUAZIP)
|
||||||
|
message(STATUS "Using bundled QuaZip")
|
||||||
|
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
|
||||||
|
set(QUAZIP_INSTALL 0)
|
||||||
|
add_subdirectory(libraries/quazip) # zip manipulation library
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system QuaZip")
|
||||||
|
endif()
|
||||||
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
||||||
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
||||||
|
if(NOT tomlplusplus_FOUND)
|
||||||
|
message(STATUS "Using bundled tomlplusplus")
|
||||||
|
add_subdirectory(libraries/tomlplusplus) # toml parser
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system tomlplusplus")
|
||||||
|
endif()
|
||||||
|
if(NOT cmark_FOUND)
|
||||||
|
message(STATUS "Using bundled cmark")
|
||||||
|
set(ORIGINAL_BUILD_TESTING ${BUILD_TESTING})
|
||||||
|
set(BUILD_TESTING 0)
|
||||||
|
set(BUILD_SHARED_LIBS 0)
|
||||||
|
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
|
||||||
|
add_library(cmark::cmark ALIAS cmark)
|
||||||
|
set(BUILD_TESTING ${ORIGINAL_BUILD_TESTING})
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system cmark")
|
||||||
|
endif()
|
||||||
|
add_subdirectory(libraries/gamemode)
|
||||||
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
||||||
|
if (NOT ghc_filesystem_FOUND)
|
||||||
|
message(STATUS "Using bundled ghc_filesystem")
|
||||||
|
add_subdirectory(libraries/filesystem) # Implementation of std::filesystem for old C++, for usage in old macOS
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system ghc_filesystem")
|
||||||
|
endif()
|
||||||
add_subdirectory(libraries/qdcss) # css parser
|
add_subdirectory(libraries/qdcss) # css parser
|
||||||
|
|
||||||
############################### Built Artifacts ###############################
|
############################### Built Artifacts ###############################
|
||||||
|
|
|
||||||
|
|
@ -1,222 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
|
||||||
"version": 8,
|
|
||||||
"cmakeMinimumRequired": {
|
|
||||||
"major": 3,
|
|
||||||
"minor": 28
|
|
||||||
},
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "base",
|
|
||||||
"hidden": true,
|
|
||||||
"binaryDir": "build",
|
|
||||||
"installDir": "install",
|
|
||||||
"generator": "Ninja Multi-Config",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "$penv{ARTIFACT_NAME}",
|
|
||||||
"Launcher_BUILD_PLATFORM": "$penv{BUILD_PLATFORM}",
|
|
||||||
"Launcher_ENABLE_JAVA_DOWNLOADER": "ON",
|
|
||||||
"ENABLE_LTO": "ON"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux",
|
|
||||||
"displayName": "Linux",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos",
|
|
||||||
"displayName": "macOS",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Darwin"
|
|
||||||
},
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal",
|
|
||||||
"displayName": "macOS (Universal Binary)",
|
|
||||||
"inherits": [
|
|
||||||
"macos"
|
|
||||||
],
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
|
|
||||||
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
|
|
||||||
"VCPKG_TARGET_TRIPLET": "universal-osx"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw",
|
|
||||||
"displayName": "Windows (MinGW)",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc",
|
|
||||||
"displayName": "Windows (MSVC)",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "linux",
|
|
||||||
"displayName": "Linux",
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
},
|
|
||||||
"configurePreset": "linux"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos",
|
|
||||||
"displayName": "macOS",
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Darwin"
|
|
||||||
},
|
|
||||||
"configurePreset": "macos"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal",
|
|
||||||
"displayName": "macOS (Universal Binary)",
|
|
||||||
"inherits": [
|
|
||||||
"macos"
|
|
||||||
],
|
|
||||||
"configurePreset": "macos_universal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw",
|
|
||||||
"displayName": "Windows (MinGW)",
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"configurePreset": "windows_mingw"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc",
|
|
||||||
"displayName": "Windows (MSVC)",
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"configurePreset": "windows_msvc"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"testPresets": [
|
|
||||||
{
|
|
||||||
"name": "base",
|
|
||||||
"hidden": true,
|
|
||||||
"output": {
|
|
||||||
"outputOnFailure": true,
|
|
||||||
"verbosity": "extra"
|
|
||||||
},
|
|
||||||
"execution": {
|
|
||||||
"noTestsAction": "error"
|
|
||||||
},
|
|
||||||
"filter": {
|
|
||||||
"exclude": {
|
|
||||||
"name": "^example64|example$"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux",
|
|
||||||
"displayName": "Linux",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
},
|
|
||||||
"configurePreset": "linux"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos",
|
|
||||||
"displayName": "macOS",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Darwin"
|
|
||||||
},
|
|
||||||
"configurePreset": "macos"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal",
|
|
||||||
"displayName": "macOS (Universal Binary)",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Darwin"
|
|
||||||
},
|
|
||||||
"configurePreset": "macos_universal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw",
|
|
||||||
"displayName": "Windows (MinGW)",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"configurePreset": "windows_mingw"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc",
|
|
||||||
"displayName": "Windows (MSVC)",
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"configurePreset": "windows_msvc"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
114
CONTRIBUTING.md
114
CONTRIBUTING.md
|
|
@ -1,113 +1,17 @@
|
||||||
# Contributions Guidelines
|
# Contributions Guidelines
|
||||||
|
|
||||||
## Restrictions on Generative AI Usage (AI Policy)
|
## Code formatting
|
||||||
|
|
||||||
> [!NOTE]
|
Try to follow the existing formatting.
|
||||||
> The following is adapted from [matplotlib's contributing guide](https://matplotlib.org/devdocs/devel/contribute.html#generative-ai) and the [Linux Kernel policy guide](https://www.kernel.org/doc./html/next/process/coding-assistants.html)
|
If there is no existing formatting, you may use `clang-format` with our included `.clang-format` configuration.
|
||||||
|
|
||||||
We expect authentic engagement in our community.
|
In general, in order of importance:
|
||||||
|
|
||||||
- Do not post output from Large Language Models or similar generative AI as comments on GitHub or our discord server, as such comments tend to be formulaic and low-quality content.
|
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
||||||
- If you use generative AI tools as an aid in developing code or documentation changes, ensure that you fully understand the proposed changes and can explain why they are the correct approach.
|
- Prefer readability over dogma.
|
||||||
|
- Keep to the existing formatting.
|
||||||
Make sure you have added value based on your personal competency to your contributions.
|
- Indent with 4 space unless it's in a submodule.
|
||||||
Just taking some input, feeding it to an AI and posting the result is not of value to the project.
|
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
||||||
To preserve precious core developer capacity, we reserve the right to rigorously reject seemingly AI generated low-value contributions.
|
|
||||||
|
|
||||||
### Signed-off-by and Developer Certificate of Origin
|
|
||||||
|
|
||||||
AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the Developer Certificate of Origin (DCO). The human submitter is responsible for:
|
|
||||||
|
|
||||||
- Reviewing all AI-generated code
|
|
||||||
- Ensuring compliance with licensing requirements
|
|
||||||
- Adding their own Signed-off-by tag to certify the DCO
|
|
||||||
- Taking full responsibility for the contribution
|
|
||||||
|
|
||||||
See [Signing your work](#signing-your-work) for more information.
|
|
||||||
|
|
||||||
### Attribution
|
|
||||||
|
|
||||||
When AI tools contribute to development, proper attribution helps track the evolving role of AI in the development process. Contributions should include an Assisted-by tag in the commit message with the following format:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]
|
|
||||||
```
|
|
||||||
|
|
||||||
Where:
|
|
||||||
|
|
||||||
- `AGENT_NAME` is the name of the AI tool or framework
|
|
||||||
- `MODEL_VERSION` is the specific model version used
|
|
||||||
- `[TOOL1] [TOOL2]` are optional specialized analysis tools used (e.g., coccinelle, sparse, smatch, clang-tidy)
|
|
||||||
|
|
||||||
Basic development tools (git, gcc, make, editors) should not be listed.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Assisted-by: Claude:claude-3-opus coccinelle sparse
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code style
|
|
||||||
|
|
||||||
All files are formatted with `clang-format` using the configuration in `.clang-format`. Ensure it is run on changed files before committing!
|
|
||||||
|
|
||||||
Please also follow the project's conventions for C++:
|
|
||||||
|
|
||||||
- Class and type names should be formatted as `PascalCase`: `MyClass`.
|
|
||||||
- Private or protected class data members should be formatted as `camelCase` prefixed with `m_`: `m_myCounter`.
|
|
||||||
- Private or protected `static` class data members should be formatted as `camelCase` prefixed with `s_`: `s_instance`.
|
|
||||||
- Public class data members should be formatted as `camelCase` without the prefix: `dateOfBirth`.
|
|
||||||
- Public, private or protected `static const` class data members should be formatted as `SCREAMING_SNAKE_CASE`: `MAX_VALUE`.
|
|
||||||
- Class function members should be formatted as `camelCase` without a prefix: `incrementCounter`.
|
|
||||||
- Global functions and non-`const` global variables should be formatted as `camelCase` without a prefix: `globalData`.
|
|
||||||
- `const` global variables and macros should be formatted as `SCREAMING_SNAKE_CASE`: `LIGHT_GRAY`.
|
|
||||||
- enum constants should be formatted as `PascalCase`: `CamelusBactrianus`
|
|
||||||
- Avoid inventing acronyms or abbreviations especially for a name of multiple words - like `tp` for `texturePack`.
|
|
||||||
- Avoid using `[[nodiscard]]` unless ignoring the return value is likely to cause a bug in cases such as:
|
|
||||||
- A function allocates memory or another resource and the caller needs to clean it up.
|
|
||||||
- A function has side effects and an error status is returned.
|
|
||||||
- A function is likely be mistaken for having side effects.
|
|
||||||
- A plain getter is unlikely to cause confusion and adding `[[nodiscard]]` can create clutter and inconsistency.
|
|
||||||
|
|
||||||
Most of these rules are included in the `.clang-tidy` file, so you can run `clang-tidy` to check for any violations.
|
|
||||||
|
|
||||||
Here is what these conventions with the formatting configuration look like:
|
|
||||||
|
|
||||||
```c++
|
|
||||||
#define AWESOMENESS 10
|
|
||||||
|
|
||||||
constexpr double PI = 3.14159;
|
|
||||||
|
|
||||||
enum class PizzaToppings { HamAndPineapple, OreoAndKetchup };
|
|
||||||
|
|
||||||
struct Person {
|
|
||||||
QString name;
|
|
||||||
QDateTime dateOfBirth;
|
|
||||||
|
|
||||||
long daysOld() const { return dateOfBirth.daysTo(QDateTime::currentDateTime()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class ImportantClass {
|
|
||||||
public:
|
|
||||||
void incrementCounter()
|
|
||||||
{
|
|
||||||
if (m_counter + 1 > MAX_COUNTER_VALUE)
|
|
||||||
throw std::runtime_error("Counter has reached limit!");
|
|
||||||
|
|
||||||
++m_counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
int counter() const { return m_counter; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr int MAX_COUNTER_VALUE = 100;
|
|
||||||
int m_counter;
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportantClass importantClassInstance;
|
|
||||||
```
|
|
||||||
|
|
||||||
If you see any names which do not follow these conventions, it is preferred that you leave them be - renames increase the number of changes therefore make reviewing harder and make your PR more prone to conflicts. However, if you're refactoring a whole class anyway, it's fine.
|
|
||||||
|
|
||||||
## Signing your work
|
## Signing your work
|
||||||
|
|
||||||
|
|
|
||||||
91
COPYING.md
91
COPYING.md
|
|
@ -1,7 +1,7 @@
|
||||||
## Prism Launcher
|
## Prism Launcher
|
||||||
|
|
||||||
Prism Launcher - Minecraft Launcher
|
Prism Launcher - Minecraft Launcher
|
||||||
Copyright (C) 2022-2026 Prism Launcher Contributors
|
Copyright (C) 2022-2024 Prism Launcher Contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -108,7 +108,7 @@
|
||||||
|
|
||||||
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
|
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
|
||||||
|
|
||||||
## Qt 6
|
## Qt 5/6
|
||||||
|
|
||||||
Copyright (C) 2022 The Qt Company Ltd and other contributors.
|
Copyright (C) 2022 The Qt Company Ltd and other contributors.
|
||||||
Contact: https://www.qt.io/licensing
|
Contact: https://www.qt.io/licensing
|
||||||
|
|
@ -212,6 +212,30 @@
|
||||||
This license is copied below, and is also available with a FAQ at:
|
This license is copied below, and is also available with a FAQ at:
|
||||||
http://scripts.sil.org/OFL
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
## Quazip
|
||||||
|
|
||||||
|
Copyright (C) 2005-2021 Sergey A. Tachenov
|
||||||
|
|
||||||
|
The QuaZip library is licensed under the GNU Lesser General Public
|
||||||
|
License V2.1 plus a static linking exception.
|
||||||
|
|
||||||
|
The original ZIP/UNZIP package (MiniZip) is copyrighted by Gilles
|
||||||
|
Vollant and contributors, see quazip/(un)zip.h files for details.
|
||||||
|
Basically it's the zlib license.
|
||||||
|
|
||||||
|
STATIC LINKING EXCEPTION
|
||||||
|
|
||||||
|
The copyright holders give you permission to link this library with
|
||||||
|
independent modules to produce an executable, regardless of the license
|
||||||
|
terms of these independent modules, and to copy and distribute the
|
||||||
|
resulting executable under terms of your choice, provided that you also
|
||||||
|
meet, for each linked independent module, the terms and conditions of
|
||||||
|
the license of that module. An independent module is a module which is
|
||||||
|
not derived from or based on this library. If you modify this library,
|
||||||
|
you must extend this exception to your version of the library.
|
||||||
|
|
||||||
|
See COPYING file for the full LGPL text.
|
||||||
|
|
||||||
## launcher (`libraries/launcher`)
|
## launcher (`libraries/launcher`)
|
||||||
|
|
||||||
PolyMC - Minecraft Launcher
|
PolyMC - Minecraft Launcher
|
||||||
|
|
@ -338,6 +362,28 @@
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
## gulrak/filesystem
|
||||||
|
|
||||||
|
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
## Breeze icons
|
## Breeze icons
|
||||||
|
|
||||||
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
|
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
|
||||||
|
|
@ -379,44 +425,3 @@
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
## libqrencode (`fukuchi/libqrencode`)
|
|
||||||
|
|
||||||
Copyright (C) 2020 libqrencode Authors
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
## vcpkg (`cmake/vcpkg-ports`)
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) Microsoft Corporation
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
||||||
software and associated documentation files (the "Software"), to deal in the Software
|
|
||||||
without restriction, including without limitation the rights to use, copy, modify,
|
|
||||||
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies
|
|
||||||
or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
||||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
ARG DEBIAN_VERSION=stable-slim
|
|
||||||
|
|
||||||
FROM docker.io/library/debian:${DEBIAN_VERSION}
|
|
||||||
|
|
||||||
ARG QT_ABI=gcc_64
|
|
||||||
ARG QT_ARCH=
|
|
||||||
ARG QT_HOST=linux
|
|
||||||
ARG QT_TARGET=desktop
|
|
||||||
ARG QT_VERSION=6.10.2
|
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get --assume-yes upgrade \
|
|
||||||
&& apt-get --assume-yes autopurge
|
|
||||||
|
|
||||||
# Use Adoptium for Java 17
|
|
||||||
RUN apt-get --assume-yes --no-install-recommends install \
|
|
||||||
apt-transport-https ca-certificates curl gpg
|
|
||||||
RUN curl -L https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/trusted.gpg.d/adoptium.gpg
|
|
||||||
RUN echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list
|
|
||||||
RUN apt-get update
|
|
||||||
|
|
||||||
# Install base dependencies
|
|
||||||
RUN apt-get --assume-yes --no-install-recommends install \
|
|
||||||
# Compilers
|
|
||||||
clang lld llvm temurin-17-jdk \
|
|
||||||
# Build system
|
|
||||||
cmake ninja-build extra-cmake-modules pkg-config \
|
|
||||||
# Dependencies
|
|
||||||
cmark gamemode-dev libarchive-dev libcmark-dev libgamemode0 libgl1-mesa-dev libqrencode-dev libtomlplusplus-dev scdoc zlib1g-dev \
|
|
||||||
# Tooling
|
|
||||||
clang-format clang-tidy git
|
|
||||||
|
|
||||||
# Use LLD by default for faster linking
|
|
||||||
ENV CMAKE_LINKER_TYPE=lld
|
|
||||||
|
|
||||||
# Prepare and install Qt
|
|
||||||
## Setup UTF-8 locale (required, apparently)
|
|
||||||
RUN apt-get --assume-yes --no-install-recommends install locales
|
|
||||||
RUN echo "C.UTF-8 UTF-8" > /etc/locale.gen
|
|
||||||
RUN locale-gen
|
|
||||||
ENV LC_ALL=C.UTF-8
|
|
||||||
|
|
||||||
## Some libraries are required for the official binaries
|
|
||||||
RUN apt-get --assume-yes --no-install-recommends install \
|
|
||||||
libglib2.0-0t64 libxkbcommon0 python3-pip
|
|
||||||
|
|
||||||
RUN pip3 install --break-system-packages aqtinstall
|
|
||||||
RUN aqt install-qt \
|
|
||||||
${QT_HOST} ${QT_TARGET} ${QT_VERSION} ${QT_ARCH} \
|
|
||||||
--outputdir /opt/qt \
|
|
||||||
--modules qtimageformats qtnetworkauth
|
|
||||||
|
|
||||||
ENV PATH=/opt/qt/${QT_VERSION}/${QT_ABI}/bin:$PATH
|
|
||||||
ENV QT_PLUGIN_PATH=/opt/qt/${QT_VERSION}/${QT_ABI}/plugins/
|
|
||||||
|
|
||||||
## We don't use these. Nuke them
|
|
||||||
RUN rm -rf \
|
|
||||||
"$QT_PLUGIN_PATH"/designer \
|
|
||||||
"$QT_PLUGIN_PATH"/help \
|
|
||||||
# "$QT_PLUGIN_PATH"/platformthemes/libqgtk3.so \
|
|
||||||
"$QT_PLUGIN_PATH"/printsupport \
|
|
||||||
"$QT_PLUGIN_PATH"/qmllint \
|
|
||||||
"$QT_PLUGIN_PATH"/qmlls \
|
|
||||||
"$QT_PLUGIN_PATH"/qmltooling \
|
|
||||||
"$QT_PLUGIN_PATH"/sqldrivers
|
|
||||||
|
|
||||||
# Setup workspace
|
|
||||||
RUN mkdir /work
|
|
||||||
WORKDIR /work
|
|
||||||
|
|
||||||
ENTRYPOINT ["bash"]
|
|
||||||
CMD ["-i"]
|
|
||||||
25
README.md
25
README.md
|
|
@ -26,14 +26,18 @@ Please understand that these builds are not intended for most users. There may b
|
||||||
|
|
||||||
There are development builds available through:
|
There are development builds available through:
|
||||||
|
|
||||||
- [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) (includes builds from pull requests opened by contributors)
|
- [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) (includes builds from pull requests opened by contribuitors)
|
||||||
- [nightly.link](https://prismlauncher.org/nightly) (this will always point only to the latest version of develop)
|
- [nightly.link](https://nightly.link/PrismLauncher/PrismLauncher/workflows/trigger_builds/develop) (this will always point only to the latest version of develop)
|
||||||
|
|
||||||
These have debug information in the binaries, so their file sizes are relatively larger.
|
These have debug information in the binaries, so their file sizes are relatively larger.
|
||||||
|
|
||||||
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
|
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
|
||||||
|
|
||||||
On Linux, we also offer our own [Flatpak nightly repository](https://github.com/PrismLauncher/flatpak). Most software centers are able to install it by opening [this link](https://flatpak.prismlauncher.org/prismlauncher-nightly.flatpakref).
|
For **Arch**, **Debian**, **Fedora**, **OpenSUSE (Tumbleweed)** and **Gentoo**, respectively, you can use these packages for the latest development versions:
|
||||||
|
|
||||||
|
[](https://aur.archlinux.org/packages/prismlauncher-git) [](https://aur.archlinux.org/packages/prismlauncher-qt5-git) [](https://mpr.makedeb.org/packages/prismlauncher-git)<br />[](https://copr.fedorainfracloud.org/coprs/g3tchoo/prismlauncher/) [](https://build.opensuse.org/project/show/home:getchoo) [](https://packages.gentoo.org/packages/games-action/prismlauncher)
|
||||||
|
|
||||||
|
These packages are also available to all the distributions based on the ones mentioned above.
|
||||||
|
|
||||||
## Community & Support
|
## Community & Support
|
||||||
|
|
||||||
|
|
@ -57,7 +61,12 @@ The translation effort for Prism Launcher is hosted on [Weblate](https://hosted.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
If you want to build Prism Launcher yourself, check the [build instructions](https://prismlauncher.org/wiki/development/build-instructions).
|
If you want to build Prism Launcher yourself, check the build instructions:
|
||||||
|
|
||||||
|
- [Windows](https://prismlauncher.org/wiki/development/build-instructions/windows/)
|
||||||
|
- [Linux](https://prismlauncher.org/wiki/development/build-instructions/linux/)
|
||||||
|
- [MacOS](https://prismlauncher.org/wiki/development/build-instructions/macos/)
|
||||||
|
- [OpenBSD](https://prismlauncher.org/wiki/development/build-instructions/openbsd/)
|
||||||
|
|
||||||
## Sponsors & Partners
|
## Sponsors & Partners
|
||||||
|
|
||||||
|
|
@ -67,13 +76,7 @@ We thank all the wonderful backers over at Open Collective! Support Prism Launch
|
||||||
|
|
||||||
Thanks to JetBrains for providing us a few licenses for all their products, as part of their [Open Source program](https://www.jetbrains.com/opensource/).
|
Thanks to JetBrains for providing us a few licenses for all their products, as part of their [Open Source program](https://www.jetbrains.com/opensource/).
|
||||||
|
|
||||||
<a href="https://jb.gg/OpenSource">
|
[](https://www.jetbrains.com/opensource/)
|
||||||
<picture>
|
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://www.jetbrains.com/company/brand/img/logo_jb_dos_4.svg">
|
|
||||||
<source media="(prefers-color-scheme: light)" srcset="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg">
|
|
||||||
<img alt="JetBrains logo" src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg" width="40%">
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
Thanks to Weblate for hosting our translation efforts.
|
Thanks to Weblate for hosting our translation efforts.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QObject>
|
#include <qstringliteral.h>
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
const Config BuildConfig;
|
const Config BuildConfig;
|
||||||
|
|
||||||
|
|
@ -48,16 +49,15 @@ Config::Config()
|
||||||
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
||||||
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
||||||
LAUNCHER_GIT = "@Launcher_Git@";
|
LAUNCHER_GIT = "@Launcher_Git@";
|
||||||
LAUNCHER_APPID = "@Launcher_AppID@";
|
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
|
||||||
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
||||||
LAUNCHER_ENVNAME = "@Launcher_ENVName@";
|
|
||||||
|
|
||||||
USER_AGENT = "@Launcher_UserAgent@";
|
USER_AGENT = "@Launcher_UserAgent@";
|
||||||
|
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
|
||||||
|
|
||||||
// Version information
|
// Version information
|
||||||
VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
|
VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
|
||||||
VERSION_MINOR = @Launcher_VERSION_MINOR@;
|
VERSION_MINOR = @Launcher_VERSION_MINOR@;
|
||||||
VERSION_PATCH = @Launcher_VERSION_PATCH@;
|
|
||||||
|
|
||||||
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
||||||
BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@";
|
BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@";
|
||||||
|
|
@ -74,13 +74,14 @@ Config::Config()
|
||||||
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
|
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
|
||||||
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
|
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
|
||||||
|
|
||||||
if (!MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty()) {
|
if (!MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty())
|
||||||
|
{
|
||||||
UPDATER_ENABLED = true;
|
UPDATER_ENABLED = true;
|
||||||
} else if (!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) {
|
} else if(!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) {
|
||||||
UPDATER_ENABLED = true;
|
UPDATER_ENABLED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#cmakedefine01 Launcher_ENABLE_JAVA_DOWNLOADER
|
#cmakedefine01 Launcher_ENABLE_JAVA_DOWNLOADER
|
||||||
JAVA_DOWNLOADER_ENABLED = Launcher_ENABLE_JAVA_DOWNLOADER;
|
JAVA_DOWNLOADER_ENABLED = Launcher_ENABLE_JAVA_DOWNLOADER;
|
||||||
|
|
||||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||||
|
|
@ -88,32 +89,39 @@ Config::Config()
|
||||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||||
|
|
||||||
// Assume that builds outside of Git repos are "stable"
|
// Assume that builds outside of Git repos are "stable"
|
||||||
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND") || GIT_TAG == QStringLiteral("GITDIR-NOTFOUND") ||
|
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|
||||||
GIT_REFSPEC == QStringLiteral("") || GIT_TAG == QStringLiteral("GIT-NOTFOUND")) {
|
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND")
|
||||||
|
|| GIT_REFSPEC == QStringLiteral("")
|
||||||
|
|| GIT_TAG == QStringLiteral("GIT-NOTFOUND"))
|
||||||
|
{
|
||||||
GIT_REFSPEC = "refs/heads/stable";
|
GIT_REFSPEC = "refs/heads/stable";
|
||||||
GIT_TAG = versionString();
|
GIT_TAG = versionString();
|
||||||
GIT_COMMIT = "";
|
GIT_COMMIT = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GIT_REFSPEC.startsWith("refs/heads/")) {
|
if (GIT_REFSPEC.startsWith("refs/heads/"))
|
||||||
|
{
|
||||||
VERSION_CHANNEL = GIT_REFSPEC;
|
VERSION_CHANNEL = GIT_REFSPEC;
|
||||||
VERSION_CHANNEL.remove("refs/heads/");
|
VERSION_CHANNEL.remove("refs/heads/");
|
||||||
} else if (!GIT_COMMIT.isEmpty()) {
|
}
|
||||||
|
else if (!GIT_COMMIT.isEmpty())
|
||||||
|
{
|
||||||
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
|
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
VERSION_CHANNEL = "unknown";
|
VERSION_CHANNEL = "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
||||||
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
||||||
WIKI_URL = "@Launcher_WIKI_URL@";
|
|
||||||
HELP_URL = "@Launcher_HELP_URL@";
|
HELP_URL = "@Launcher_HELP_URL@";
|
||||||
LOGIN_CALLBACK_URL = "@Launcher_LOGIN_CALLBACK_URL@";
|
LOGIN_CALLBACK_URL = "@Launcher_LOGIN_CALLBACK_URL@";
|
||||||
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
||||||
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
||||||
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
||||||
META_URL = "@Launcher_META_URL@";
|
META_URL = "@Launcher_META_URL@";
|
||||||
LEGACY_FMLLIBS_BASE_URL = "@Launcher_LEGACY_FMLLIBS_BASE_URL@";
|
FMLLIBS_BASE_URL = "@Launcher_FMLLIBS_BASE_URL@";
|
||||||
|
|
||||||
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
|
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
|
||||||
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
|
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
|
||||||
|
|
@ -128,7 +136,7 @@ Config::Config()
|
||||||
|
|
||||||
QString Config::versionString() const
|
QString Config::versionString() const
|
||||||
{
|
{
|
||||||
return QString("%1.%2.%3").arg(VERSION_MAJOR).arg(VERSION_MINOR).arg(VERSION_PATCH);
|
return QString("%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Config::printableVersionString() const
|
QString Config::printableVersionString() const
|
||||||
|
|
@ -136,7 +144,8 @@ QString Config::printableVersionString() const
|
||||||
QString vstr = versionString();
|
QString vstr = versionString();
|
||||||
|
|
||||||
// If the build is not a main release, append the channel
|
// If the build is not a main release, append the channel
|
||||||
if (VERSION_CHANNEL != "stable" && GIT_TAG != vstr) {
|
if(VERSION_CHANNEL != "stable" && GIT_TAG != vstr)
|
||||||
|
{
|
||||||
vstr += "-" + VERSION_CHANNEL;
|
vstr += "-" + VERSION_CHANNEL;
|
||||||
}
|
}
|
||||||
return vstr;
|
return vstr;
|
||||||
|
|
@ -153,3 +162,4 @@ QString Config::systemID() const
|
||||||
{
|
{
|
||||||
return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR);
|
return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,16 +52,13 @@ class Config {
|
||||||
QString LAUNCHER_DOMAIN;
|
QString LAUNCHER_DOMAIN;
|
||||||
QString LAUNCHER_CONFIGFILE;
|
QString LAUNCHER_CONFIGFILE;
|
||||||
QString LAUNCHER_GIT;
|
QString LAUNCHER_GIT;
|
||||||
QString LAUNCHER_APPID;
|
QString LAUNCHER_DESKTOPFILENAME;
|
||||||
QString LAUNCHER_SVGFILENAME;
|
QString LAUNCHER_SVGFILENAME;
|
||||||
QString LAUNCHER_ENVNAME;
|
|
||||||
|
|
||||||
/// The major version number.
|
/// The major version number.
|
||||||
int VERSION_MAJOR;
|
int VERSION_MAJOR;
|
||||||
/// The minor version number.
|
/// The minor version number.
|
||||||
int VERSION_MINOR;
|
int VERSION_MINOR;
|
||||||
/// The patch version number.
|
|
||||||
int VERSION_PATCH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The version channel
|
* The version channel
|
||||||
|
|
@ -108,6 +105,9 @@ class Config {
|
||||||
/// User-Agent to use.
|
/// User-Agent to use.
|
||||||
QString USER_AGENT;
|
QString USER_AGENT;
|
||||||
|
|
||||||
|
/// User-Agent to use for uncached requests.
|
||||||
|
QString USER_AGENT_UNCACHED;
|
||||||
|
|
||||||
/// The git commit hash of this build
|
/// The git commit hash of this build
|
||||||
QString GIT_COMMIT;
|
QString GIT_COMMIT;
|
||||||
|
|
||||||
|
|
@ -129,12 +129,7 @@ class Config {
|
||||||
QString NEWS_OPEN_URL;
|
QString NEWS_OPEN_URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL that gets opened when the user clicks 'Launcher Help'
|
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help
|
||||||
*/
|
|
||||||
QString WIKI_URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help in a dialog window
|
|
||||||
*/
|
*/
|
||||||
QString HELP_URL;
|
QString HELP_URL;
|
||||||
|
|
||||||
|
|
@ -172,13 +167,13 @@ class Config {
|
||||||
QString DISCORD_URL;
|
QString DISCORD_URL;
|
||||||
QString SUBREDDIT_URL;
|
QString SUBREDDIT_URL;
|
||||||
|
|
||||||
QString DEFAULT_RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
QString RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
||||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||||
QString LEGACY_FMLLIBS_BASE_URL;
|
QString FMLLIBS_BASE_URL;
|
||||||
QString TRANSLATION_FILES_URL;
|
QString TRANSLATION_FILES_URL;
|
||||||
|
|
||||||
QString FTB_API_BASE_URL = "https://api.feed-the-beast.com/v1/modpacks/public";
|
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||||
|
|
||||||
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
|
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
|
||||||
|
|
||||||
|
|
@ -194,10 +189,8 @@ class Config {
|
||||||
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
||||||
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
||||||
QStringList MODRINTH_MRPACK_HOSTS{ "cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com" };
|
QStringList MODRINTH_MRPACK_HOSTS{ "cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com" };
|
||||||
QString MODRINTH_DOWNLOAD_HOST = "cdn.modrinth.com";
|
|
||||||
|
|
||||||
QString FLAME_BASE_URL = "https://api.curseforge.com/v1";
|
QString FLAME_BASE_URL = "https://api.curseforge.com/v1";
|
||||||
QString FLAME_DOWNLOAD_HOST = "edge.forgecdn.net";
|
|
||||||
|
|
||||||
QString versionString() const;
|
QString versionString() const;
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
163
cmake/CompilerWarnings.cmake
Normal file
163
cmake/CompilerWarnings.cmake
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
#
|
||||||
|
# Function to set compiler warnings with reasonable defaults at the project level.
|
||||||
|
# Taken from https://github.com/aminya/project_options/blob/main/src/CompilerWarnings.cmake
|
||||||
|
# under the folowing license:
|
||||||
|
#
|
||||||
|
# MIT License
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022-2100 Amin Yahyaabadi
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
include_guard()
|
||||||
|
|
||||||
|
function(_set_project_warnings_add_target_link_option TARGET OPTIONS)
|
||||||
|
target_link_options(${_project_name} INTERFACE ${OPTIONS})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Set the compiler warnings
|
||||||
|
#
|
||||||
|
# https://clang.llvm.org/docs/DiagnosticsReference.html
|
||||||
|
# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md
|
||||||
|
function(
|
||||||
|
set_project_warnings
|
||||||
|
_project_name
|
||||||
|
MSVC_WARNINGS
|
||||||
|
CLANG_WARNINGS
|
||||||
|
GCC_WARNINGS
|
||||||
|
)
|
||||||
|
if("${MSVC_WARNINGS}" STREQUAL "")
|
||||||
|
set(MSVC_WARNINGS
|
||||||
|
/W4 # Baseline reasonable warnings
|
||||||
|
/w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data
|
||||||
|
/w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
|
||||||
|
/w14263 # 'function': member function does not override any base class virtual member function
|
||||||
|
/w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not
|
||||||
|
# be destructed correctly
|
||||||
|
/w14287 # 'operator': unsigned/negative constant mismatch
|
||||||
|
/we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside
|
||||||
|
# the for-loop scope
|
||||||
|
/w14296 # 'operator': expression is always 'boolean_value'
|
||||||
|
/w14311 # 'variable': pointer truncation from 'type1' to 'type2'
|
||||||
|
/w14545 # expression before comma evaluates to a function which is missing an argument list
|
||||||
|
/w14546 # function call before comma missing argument list
|
||||||
|
/w14547 # 'operator': operator before comma has no effect; expected operator with side-effect
|
||||||
|
/w14549 # 'operator': operator before comma has no effect; did you intend 'operator'?
|
||||||
|
/w14555 # expression has no effect; expected expression with side- effect
|
||||||
|
/w14619 # pragma warning: there is no warning number 'number'
|
||||||
|
/w14640 # Enable warning on thread un-safe static member initialization
|
||||||
|
/w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
|
||||||
|
/w14905 # wide string literal cast to 'LPSTR'
|
||||||
|
/w14906 # string literal cast to 'LPWSTR'
|
||||||
|
/w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
|
||||||
|
/permissive- # standards conformance mode for MSVC compiler.
|
||||||
|
|
||||||
|
/we4062 # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("${CLANG_WARNINGS}" STREQUAL "")
|
||||||
|
set(CLANG_WARNINGS
|
||||||
|
-Wall
|
||||||
|
-Wextra # reasonable and standard
|
||||||
|
-Wshadow # warn the user if a variable declaration shadows one from a parent context
|
||||||
|
-Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps
|
||||||
|
# catch hard to track down memory errors
|
||||||
|
-Wold-style-cast # warn for c-style casts
|
||||||
|
-Wcast-align # warn for potential performance problem casts
|
||||||
|
-Wunused # warn on anything being unused
|
||||||
|
-Woverloaded-virtual # warn if you overload (not override) a virtual function
|
||||||
|
-Wpedantic # warn if non-standard C++ is used
|
||||||
|
-Wconversion # warn on type conversions that may lose data
|
||||||
|
-Wsign-conversion # warn on sign conversions
|
||||||
|
-Wnull-dereference # warn if a null dereference is detected
|
||||||
|
-Wdouble-promotion # warn if float is implicit promoted to double
|
||||||
|
-Wformat=2 # warn on security issues around functions that format output (ie printf)
|
||||||
|
-Wimplicit-fallthrough # warn on statements that fallthrough without an explicit annotation
|
||||||
|
# -Wgnu-zero-variadic-macro-arguments (part of -pedantic) is triggered by every qCDebug() call and therefore results
|
||||||
|
# in a lot of noise. This warning is only notifying us that clang is emulating the GCC behaviour
|
||||||
|
# instead of the exact standard wording so we can safely ignore it
|
||||||
|
-Wno-gnu-zero-variadic-macro-arguments
|
||||||
|
|
||||||
|
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("${GCC_WARNINGS}" STREQUAL "")
|
||||||
|
set(GCC_WARNINGS
|
||||||
|
${CLANG_WARNINGS}
|
||||||
|
-Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist
|
||||||
|
-Wduplicated-cond # warn if if / else chain has duplicated conditions
|
||||||
|
-Wduplicated-branches # warn if if / else branches have duplicated code
|
||||||
|
-Wlogical-op # warn about logical operations being used where bitwise were probably wanted
|
||||||
|
-Wuseless-cast # warn if you perform a cast to the same type
|
||||||
|
|
||||||
|
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(PROJECT_WARNINGS_CXX ${MSVC_WARNINGS})
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
|
||||||
|
set(PROJECT_WARNINGS_CXX ${CLANG_WARNINGS})
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
set(PROJECT_WARNINGS_CXX ${GCC_WARNINGS})
|
||||||
|
else()
|
||||||
|
message(AUTHOR_WARNING "No compiler warnings set for CXX compiler: '${CMAKE_CXX_COMPILER_ID}'")
|
||||||
|
# TODO support Intel compiler
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add C warnings
|
||||||
|
set(PROJECT_WARNINGS_C "${PROJECT_WARNINGS_CXX}")
|
||||||
|
list(
|
||||||
|
REMOVE_ITEM
|
||||||
|
PROJECT_WARNINGS_C
|
||||||
|
-Wnon-virtual-dtor
|
||||||
|
-Wold-style-cast
|
||||||
|
-Woverloaded-virtual
|
||||||
|
-Wuseless-cast
|
||||||
|
-Wextra-semi
|
||||||
|
|
||||||
|
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_options(
|
||||||
|
${_project_name}
|
||||||
|
INTERFACE # C++ warnings
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>
|
||||||
|
# C warnings
|
||||||
|
$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>
|
||||||
|
)
|
||||||
|
|
||||||
|
# If we are using the compiler as a linker driver pass the warnings to it
|
||||||
|
# (most useful when using LTO or warnings as errors)
|
||||||
|
if(CMAKE_CXX_LINK_EXECUTABLE MATCHES "^<CMAKE_CXX_COMPILER>")
|
||||||
|
_set_project_warnings_add_target_link_option(
|
||||||
|
${_project_name} "$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_C_LINK_EXECUTABLE MATCHES "^<CMAKE_C_COMPILER>")
|
||||||
|
_set_project_warnings_add_target_link_option(
|
||||||
|
${_project_name} "$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endfunction()
|
||||||
100
cmake/ECMQueryQt.cmake
Normal file
100
cmake/ECMQueryQt.cmake
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
|
||||||
|
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
|
||||||
|
# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
|
||||||
|
# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
|
||||||
|
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
ECMQueryQt
|
||||||
|
---------------
|
||||||
|
This module can be used to query the installation paths used by Qt.
|
||||||
|
|
||||||
|
For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
|
||||||
|
support to query the paths of a target platform when cross-compiling).
|
||||||
|
|
||||||
|
This module defines the following function:
|
||||||
|
::
|
||||||
|
|
||||||
|
ecm_query_qt(<result_variable> <qt_variable> [TRY])
|
||||||
|
|
||||||
|
Passing ``TRY`` will result in the method not making the build fail if the executable
|
||||||
|
used for querying has not been found, but instead simply print a warning message and
|
||||||
|
return an empty string.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
include(ECMQueryQt)
|
||||||
|
ecm_query_qt(bin_dir QT_INSTALL_BINS)
|
||||||
|
|
||||||
|
If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
|
||||||
|
``/usr/lib64/qt/bin/``).
|
||||||
|
|
||||||
|
Since: 5.93
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
|
||||||
|
include(CheckLanguage)
|
||||||
|
check_language(CXX)
|
||||||
|
if (CMAKE_CXX_COMPILER)
|
||||||
|
# Enable the CXX language to let CMake look for config files in library dirs.
|
||||||
|
# See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
|
||||||
|
enable_language(CXX)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
|
# QUIET to accommodate the TRY option
|
||||||
|
find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
|
||||||
|
if(TARGET Qt5::qmake)
|
||||||
|
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
|
||||||
|
|
||||||
|
set(QUERY_EXECUTABLE ${_qmake_executable_default}
|
||||||
|
CACHE FILEPATH "Location of the Qt5 qmake executable")
|
||||||
|
set(_exec_name_text "Qt5 qmake")
|
||||||
|
set(_cli_option "-query")
|
||||||
|
endif()
|
||||||
|
elseif(QT_MAJOR_VERSION STREQUAL "6")
|
||||||
|
# QUIET to accommodate the TRY option
|
||||||
|
find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
|
||||||
|
if (TARGET Qt6::qtpaths)
|
||||||
|
get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)
|
||||||
|
|
||||||
|
set(QUERY_EXECUTABLE ${_qtpaths_executable}
|
||||||
|
CACHE FILEPATH "Location of the Qt6 qtpaths executable")
|
||||||
|
set(_exec_name_text "Qt6 qtpaths")
|
||||||
|
set(_cli_option "--query")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
function(ecm_query_qt result_variable qt_variable)
|
||||||
|
set(options TRY)
|
||||||
|
set(oneValueArgs)
|
||||||
|
set(multiValueArgs)
|
||||||
|
|
||||||
|
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT QUERY_EXECUTABLE)
|
||||||
|
if(ARGS_TRY)
|
||||||
|
set(${result_variable} "" PARENT_SCOPE)
|
||||||
|
message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
|
||||||
|
return()
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
|
||||||
|
RESULT_VARIABLE return_code
|
||||||
|
OUTPUT_VARIABLE output
|
||||||
|
)
|
||||||
|
if(return_code EQUAL 0)
|
||||||
|
string(STRIP "${output}" output)
|
||||||
|
file(TO_CMAKE_PATH "${output}" output_path)
|
||||||
|
set(${result_variable} "${output_path}" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
message(WARNING "Failed call: ${_command} \"${qt_variable}\"")
|
||||||
|
message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>A Minecraft mod wants to access your microphone.</string>
|
<string>A Minecraft mod wants to access your microphone.</string>
|
||||||
<key>NSDownloadsFolderUsageDescription</key>
|
<key>NSDownloadsFolderUsageDescription</key>
|
||||||
<string>${Launcher_DisplayName} uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where ${Launcher_DisplayName} scans for downloaded mods in Settings or the prompt that appears.</string>
|
<string>Prism uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where Prism scans for downloaded mods in Settings or the prompt that appears.</string>
|
||||||
<key>NSLocalNetworkUsageDescription</key>
|
<key>NSLocalNetworkUsageDescription</key>
|
||||||
<string>Minecraft uses the local network to find and connect to LAN servers.</string>
|
<string>Minecraft uses the local network to find and connect to LAN servers.</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|
@ -21,9 +21,7 @@
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>${Launcher_Name}</string>
|
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||||
<key>CFBundleIconName</key>
|
|
||||||
<string>${Launcher_Name}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
|
@ -44,8 +42,6 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSRequiresCarbon</key>
|
<key>LSRequiresCarbon</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSApplicationCategoryType</key>
|
|
||||||
<string>public.app-category.games</string>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||||
<key>SUPublicEDKey</key>
|
<key>SUPublicEDKey</key>
|
||||||
|
|
@ -61,7 +57,7 @@
|
||||||
<string>mrpack</string>
|
<string>mrpack</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeName</key>
|
<key>CFBundleTypeName</key>
|
||||||
<string>${Launcher_DisplayName} instance</string>
|
<string>Prism Launcher instance</string>
|
||||||
<key>CFBundleTypeOSTypes</key>
|
<key>CFBundleTypeOSTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>TEXT</string>
|
<string>TEXT</string>
|
||||||
|
|
@ -87,11 +83,10 @@
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleURLName</key>
|
<key>CFBundleURLName</key>
|
||||||
<string>${Launcher_Name}</string>
|
<string>Prismlauncher</string>
|
||||||
<key>CFBundleURLSchemes</key>
|
<key>CFBundleURLSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>prismlauncher</string>
|
<string>prismlauncher</string>
|
||||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
|
|
||||||
38
cmake/QtVersionOption.cmake
Normal file
38
cmake/QtVersionOption.cmake
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#.rst:
|
||||||
|
# QtVersionOption
|
||||||
|
# ---------------
|
||||||
|
#
|
||||||
|
# Adds a build option to select the major Qt version if necessary,
|
||||||
|
# that is, if the major Qt version has not yet been determined otherwise
|
||||||
|
# (e.g. by a corresponding find_package() call).
|
||||||
|
#
|
||||||
|
# This module is typically included by other modules requiring knowledge
|
||||||
|
# about the major Qt version.
|
||||||
|
#
|
||||||
|
# ``QT_MAJOR_VERSION`` is defined to either be "5" or "6".
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Since 5.82.0.
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
if (DEFINED QT_MAJOR_VERSION)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (TARGET Qt5::Core)
|
||||||
|
set(QT_MAJOR_VERSION 5)
|
||||||
|
elseif (TARGET Qt6::Core)
|
||||||
|
set(QT_MAJOR_VERSION 6)
|
||||||
|
else()
|
||||||
|
option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
|
||||||
|
|
||||||
|
if (BUILD_WITH_QT6)
|
||||||
|
set(QT_MAJOR_VERSION 6)
|
||||||
|
else()
|
||||||
|
set(QT_MAJOR_VERSION 5)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
97
cmake/QtVersionlessBackport.cmake
Normal file
97
cmake/QtVersionlessBackport.cmake
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#=============================================================================
|
||||||
|
# Copyright 2005-2011 Kitware, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# * Neither the name of Kitware, Inc. nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived
|
||||||
|
# from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#=============================================================================
|
||||||
|
|
||||||
|
# From Qt5CoreMacros.cmake
|
||||||
|
|
||||||
|
function(qt_generate_moc)
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
qt5_generate_moc(${ARGV})
|
||||||
|
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt6_generate_moc(${ARGV})
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(qt_wrap_cpp outfiles)
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
qt5_wrap_cpp("${outfiles}" ${ARGN})
|
||||||
|
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt6_wrap_cpp("${outfiles}" ${ARGN})
|
||||||
|
endif()
|
||||||
|
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(qt_add_binary_resources)
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
qt5_add_binary_resources(${ARGV})
|
||||||
|
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt6_add_binary_resources(${ARGV})
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(qt_add_resources outfiles)
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
qt5_add_resources("${outfiles}" ${ARGN})
|
||||||
|
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt6_add_resources("${outfiles}" ${ARGN})
|
||||||
|
endif()
|
||||||
|
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(qt_add_big_resources outfiles)
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
qt5_add_big_resources(${outfiles} ${ARGN})
|
||||||
|
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt6_add_big_resources(${outfiles} ${ARGN})
|
||||||
|
endif()
|
||||||
|
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(qt_import_plugins)
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
qt5_import_plugins(${ARGV})
|
||||||
|
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt6_import_plugins(${ARGV})
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
# From Qt5WidgetsMacros.cmake
|
||||||
|
|
||||||
|
function(qt_wrap_ui outfiles)
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
qt5_wrap_ui("${outfiles}" ${ARGN})
|
||||||
|
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt6_wrap_ui("${outfiles}" ${ARGN})
|
||||||
|
endif()
|
||||||
|
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
The only difference between this and the upstream vcpkg port is the addition of `universal-osx.patch`. It's very annoying we need to bundle this entire tree to do that.
|
|
||||||
|
|
||||||
-@getchoo
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py
|
|
||||||
index 11a00be5d..89ae490ff 100644
|
|
||||||
--- a/mesonbuild/cmake/toolchain.py
|
|
||||||
+++ b/mesonbuild/cmake/toolchain.py
|
|
||||||
@@ -202,7 +202,7 @@ class CMakeToolchain:
|
|
||||||
@staticmethod
|
|
||||||
def is_cmdline_option(compiler: 'Compiler', arg: str) -> bool:
|
|
||||||
if compiler.get_argument_syntax() == 'msvc':
|
|
||||||
- return arg.startswith('/')
|
|
||||||
+ return arg.startswith(('/','-'))
|
|
||||||
else:
|
|
||||||
if os.path.basename(compiler.get_exe()) == 'zig' and arg in {'ar', 'cc', 'c++', 'dlltool', 'lib', 'ranlib', 'objcopy', 'rc'}:
|
|
||||||
return True
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py
|
|
||||||
index 883a29a..d9a82af 100644
|
|
||||||
--- a/mesonbuild/dependencies/python.py
|
|
||||||
+++ b/mesonbuild/dependencies/python.py
|
|
||||||
@@ -232,8 +232,10 @@ class _PythonDependencyBase(_Base):
|
|
||||||
else:
|
|
||||||
if self.is_freethreaded:
|
|
||||||
libpath = Path('libs') / f'python{vernum}t.lib'
|
|
||||||
+ libpath = Path('libs') / f'..' / f'..' / f'..' / f'lib' / f'python{vernum}t.lib'
|
|
||||||
else:
|
|
||||||
libpath = Path('libs') / f'python{vernum}.lib'
|
|
||||||
+ libpath = Path('libs') / f'..' / f'..' / f'..' / f'lib' / f'python{vernum}.lib'
|
|
||||||
# For a debug build, pyconfig.h may force linking with
|
|
||||||
# pythonX_d.lib (see meson#10776). This cannot be avoided
|
|
||||||
# and won't work unless we also have a debug build of
|
|
||||||
@@ -250,6 +252,8 @@ class _PythonDependencyBase(_Base):
|
|
||||||
vscrt = self.env.coredata.optstore.get_value('b_vscrt')
|
|
||||||
if vscrt in {'mdd', 'mtd', 'from_buildtype', 'static_from_buildtype'}:
|
|
||||||
vscrt_debug = True
|
|
||||||
+ if is_debug_build:
|
|
||||||
+ libpath = Path('libs') / f'..' / f'..' / f'..' / f'debug/lib' / f'python{vernum}_d.lib'
|
|
||||||
if is_debug_build and vscrt_debug and not self.variables.get('Py_DEBUG'):
|
|
||||||
mlog.warning(textwrap.dedent('''\
|
|
||||||
Using a debug build type with MSVC or an MSVC-compatible compiler
|
|
||||||
@@ -350,9 +354,10 @@ class PythonSystemDependency(SystemDependency, _PythonDependencyBase):
|
|
||||||
self.is_found = True
|
|
||||||
|
|
||||||
# compile args
|
|
||||||
+ verdot = self.variables.get('py_version_short')
|
|
||||||
inc_paths = mesonlib.OrderedSet([
|
|
||||||
self.variables.get('INCLUDEPY'),
|
|
||||||
- self.paths.get('include'),
|
|
||||||
+ self.paths.get('include') + f'/../../../include/python${verdot}',
|
|
||||||
self.paths.get('platinclude')])
|
|
||||||
|
|
||||||
self.compile_args += ['-I' + path for path in inc_paths if path]
|
|
||||||
@@ -416,7 +421,7 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice',
|
|
||||||
candidates.append(functools.partial(wrap_in_pythons_pc_dir, pkg_name, env, kwargs, installation))
|
|
||||||
# We only need to check both, if a python install has a LIBPC. It might point to the wrong location,
|
|
||||||
# e.g. relocated / cross compilation, but the presence of LIBPC indicates we should definitely look for something.
|
|
||||||
- if pkg_libdir is not None:
|
|
||||||
+ if True or pkg_libdir is not None:
|
|
||||||
candidates.append(functools.partial(PythonPkgConfigDependency, pkg_name, env, kwargs, installation))
|
|
||||||
else:
|
|
||||||
candidates.append(functools.partial(PkgConfigDependency, 'python3', env, kwargs))
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
From a16ec8b0fb6d7035b669a13edd4d97ff0c307a0b Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Martin=20D=C3=B8rum?= <martid0311@gmail.com>
|
|
||||||
Date: Fri, 2 May 2025 10:56:28 +0200
|
|
||||||
Subject: [PATCH] cpp: fix _LIBCPP_ENABLE_ASSERTIONS warning
|
|
||||||
|
|
||||||
libc++ deprecated _LIBCPP_ENABLE_ASSERTIONS from version 18.
|
|
||||||
However, the libc++ shipped with Apple Clang backported that
|
|
||||||
deprecation in version 17 already,
|
|
||||||
which is the version which Apple currently ships for macOS.
|
|
||||||
This PR changes the _LIBCPP_ENABLE_ASSERTIONS deprecation check
|
|
||||||
to use version ">=17" on Apple Clang.
|
|
||||||
---
|
|
||||||
mesonbuild/compilers/cpp.py | 12 ++++++++++--
|
|
||||||
1 file changed, 10 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
|
|
||||||
index 01b9bb9fa34f..f7dc150e8608 100644
|
|
||||||
--- a/mesonbuild/compilers/cpp.py
|
|
||||||
+++ b/mesonbuild/compilers/cpp.py
|
|
||||||
@@ -311,6 +311,9 @@ def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subpro
|
|
||||||
return libs
|
|
||||||
return []
|
|
||||||
|
|
||||||
+ def is_libcpp_enable_assertions_deprecated(self) -> bool:
|
|
||||||
+ return version_compare(self.version, ">=18")
|
|
||||||
+
|
|
||||||
def get_assert_args(self, disable: bool, env: 'Environment') -> T.List[str]:
|
|
||||||
if disable:
|
|
||||||
return ['-DNDEBUG']
|
|
||||||
@@ -323,7 +326,7 @@ def get_assert_args(self, disable: bool, env: 'Environment') -> T.List[str]:
|
|
||||||
if self.language_stdlib_provider(env) == 'stdc++':
|
|
||||||
return ['-D_GLIBCXX_ASSERTIONS=1']
|
|
||||||
else:
|
|
||||||
- if version_compare(self.version, '>=18'):
|
|
||||||
+ if self.is_libcpp_enable_assertions_deprecated():
|
|
||||||
return ['-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST']
|
|
||||||
elif version_compare(self.version, '>=15'):
|
|
||||||
return ['-D_LIBCPP_ENABLE_ASSERTIONS=1']
|
|
||||||
@@ -343,7 +346,12 @@ class ArmLtdClangCPPCompiler(ClangCPPCompiler):
|
|
||||||
|
|
||||||
|
|
||||||
class AppleClangCPPCompiler(AppleCompilerMixin, AppleCPPStdsMixin, ClangCPPCompiler):
|
|
||||||
- pass
|
|
||||||
+ def is_libcpp_enable_assertions_deprecated(self) -> bool:
|
|
||||||
+ # Upstream libc++ deprecated _LIBCPP_ENABLE_ASSERTIONS
|
|
||||||
+ # in favor of _LIBCPP_HARDENING_MODE from version 18 onwards,
|
|
||||||
+ # but Apple Clang 17's libc++ has back-ported that change.
|
|
||||||
+ # See: https://github.com/mesonbuild/meson/issues/14440
|
|
||||||
+ return version_compare(self.version, ">=17")
|
|
||||||
|
|
||||||
|
|
||||||
class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler):
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/tools/meson")
|
|
||||||
file(INSTALL "${SOURCE_PATH}/meson.py"
|
|
||||||
"${SOURCE_PATH}/mesonbuild"
|
|
||||||
DESTINATION "${CURRENT_PACKAGES_DIR}/tools/meson"
|
|
||||||
)
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
|
|
||||||
--- a/mesonbuild/dependencies/misc.py
|
|
||||||
+++ b/mesonbuild/dependencies/misc.py
|
|
||||||
@@ -593,7 +593,8 @@ iconv_factory = DependencyFactory(
|
|
||||||
|
|
||||||
packages['intl'] = intl_factory = DependencyFactory(
|
|
||||||
'intl',
|
|
||||||
+ [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
|
|
||||||
+ cmake_name='Intl',
|
|
||||||
- [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
|
|
||||||
builtin_class=IntlBuiltinDependency,
|
|
||||||
system_class=IntlSystemDependency,
|
|
||||||
)
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
[binaries]
|
|
||||||
cmake = ['@CMAKE_COMMAND@']
|
|
||||||
ninja = ['@NINJA@']
|
|
||||||
pkg-config = ['@PKGCONFIG@']
|
|
||||||
@MESON_MT@
|
|
||||||
@MESON_AR@
|
|
||||||
@MESON_RC@
|
|
||||||
@MESON_C@
|
|
||||||
@MESON_C_LD@
|
|
||||||
@MESON_CXX@
|
|
||||||
@MESON_CXX_LD@
|
|
||||||
@MESON_OBJC@
|
|
||||||
@MESON_OBJC_LD@
|
|
||||||
@MESON_OBJCPP@
|
|
||||||
@MESON_OBJCPP_LD@
|
|
||||||
@MESON_FC@
|
|
||||||
@MESON_FC_LD@
|
|
||||||
@MESON_WINDRES@
|
|
||||||
@MESON_ADDITIONAL_BINARIES@
|
|
||||||
[properties]
|
|
||||||
cmake_toolchain_file = '@SCRIPTS@/buildsystems/vcpkg.cmake'
|
|
||||||
@MESON_ADDITIONAL_PROPERTIES@
|
|
||||||
[cmake]
|
|
||||||
CMAKE_BUILD_TYPE = '@MESON_CMAKE_BUILD_TYPE@'
|
|
||||||
VCPKG_TARGET_TRIPLET = '@TARGET_TRIPLET@'
|
|
||||||
VCPKG_HOST_TRIPLET = '@_HOST_TRIPLET@'
|
|
||||||
VCPKG_CHAINLOAD_TOOLCHAIN_FILE = '@VCPKG_CHAINLOAD_TOOLCHAIN_FILE@'
|
|
||||||
VCPKG_CRT_LINKAGE = '@VCPKG_CRT_LINKAGE@'
|
|
||||||
_VCPKG_INSTALLED_DIR = '@_VCPKG_INSTALLED_DIR@'
|
|
||||||
@MESON_HOST_MACHINE@
|
|
||||||
@MESON_BUILD_MACHINE@
|
|
||||||
[built-in options]
|
|
||||||
default_library = '@MESON_DEFAULT_LIBRARY@'
|
|
||||||
werror = false
|
|
||||||
@MESON_CFLAGS@
|
|
||||||
@MESON_CXXFLAGS@
|
|
||||||
@MESON_FCFLAGS@
|
|
||||||
@MESON_OBJCFLAGS@
|
|
||||||
@MESON_OBJCPPFLAGS@
|
|
||||||
# b_vscrt
|
|
||||||
@MESON_VSCRT_LINKAGE@
|
|
||||||
# c_winlibs/cpp_winlibs
|
|
||||||
@MESON_WINLIBS@
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
# This port represents a dependency on the Meson build system.
|
|
||||||
# In the future, it is expected that this port acquires and installs Meson.
|
|
||||||
# Currently is used in ports that call vcpkg_find_acquire_program(MESON) in order to force rebuilds.
|
|
||||||
|
|
||||||
set(VCPKG_POLICY_CMAKE_HELPER_PORT enabled)
|
|
||||||
|
|
||||||
set(patches
|
|
||||||
meson-intl.patch
|
|
||||||
adjust-python-dep.patch
|
|
||||||
adjust-args.patch
|
|
||||||
remove-freebsd-pcfile-specialization.patch
|
|
||||||
fix-libcpp-enable-assertions.patch # https://github.com/mesonbuild/meson/pull/14548, Remove in 1.8.3
|
|
||||||
universal-osx.patch # NOTE(@getchoo): THIS IS THE ONLY CHANGE NEEDED FOR PRISM
|
|
||||||
)
|
|
||||||
set(scripts
|
|
||||||
vcpkg-port-config.cmake
|
|
||||||
vcpkg_configure_meson.cmake
|
|
||||||
vcpkg_install_meson.cmake
|
|
||||||
meson.template.in
|
|
||||||
)
|
|
||||||
set(to_hash
|
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/vcpkg.json"
|
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/portfile.cmake"
|
|
||||||
)
|
|
||||||
foreach(file IN LISTS patches scripts)
|
|
||||||
set(filepath "${CMAKE_CURRENT_LIST_DIR}/${file}")
|
|
||||||
list(APPEND to_hash "${filepath}")
|
|
||||||
file(COPY "${filepath}" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
set(meson_path_hash "")
|
|
||||||
foreach(filepath IN LISTS to_hash)
|
|
||||||
file(SHA1 "${filepath}" to_append)
|
|
||||||
string(APPEND meson_path_hash "${to_append}")
|
|
||||||
endforeach()
|
|
||||||
string(SHA512 meson_path_hash "${meson_path_hash}")
|
|
||||||
|
|
||||||
string(SUBSTRING "${meson_path_hash}" 0 6 MESON_SHORT_HASH)
|
|
||||||
list(TRANSFORM patches REPLACE [[^(..*)$]] [["${CMAKE_CURRENT_LIST_DIR}/\0"]])
|
|
||||||
list(JOIN patches "\n " PATCHES)
|
|
||||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-port-config.cmake" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-port-config.cmake" @ONLY)
|
|
||||||
|
|
||||||
vcpkg_install_copyright(FILE_LIST "${VCPKG_ROOT_DIR}/LICENSE.txt")
|
|
||||||
|
|
||||||
include("${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-port-config.cmake")
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
|
|
||||||
index cc0450a52..13501466d 100644
|
|
||||||
--- a/mesonbuild/modules/pkgconfig.py
|
|
||||||
+++ b/mesonbuild/modules/pkgconfig.py
|
|
||||||
@@ -701,16 +701,8 @@ class PkgConfigModule(NewExtensionModule):
|
|
||||||
pcfile = filebase + '.pc'
|
|
||||||
pkgroot = pkgroot_name = kwargs['install_dir'] or default_install_dir
|
|
||||||
if pkgroot is None:
|
|
||||||
- m = state.environment.machines.host
|
|
||||||
- if m.is_freebsd():
|
|
||||||
- pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'))), 'libdata', 'pkgconfig')
|
|
||||||
- pkgroot_name = os.path.join('{prefix}', 'libdata', 'pkgconfig')
|
|
||||||
- elif m.is_haiku():
|
|
||||||
- pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'))), 'develop', 'lib', 'pkgconfig')
|
|
||||||
- pkgroot_name = os.path.join('{prefix}', 'develop', 'lib', 'pkgconfig')
|
|
||||||
- else:
|
|
||||||
- pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('libdir'))), 'pkgconfig')
|
|
||||||
- pkgroot_name = os.path.join('{libdir}', 'pkgconfig')
|
|
||||||
+ pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('libdir'))), 'pkgconfig')
|
|
||||||
+ pkgroot_name = os.path.join('{libdir}', 'pkgconfig')
|
|
||||||
relocatable = state.get_option('pkgconfig.relocatable')
|
|
||||||
self._generate_pkgconfig_file(state, deps, subdirs, name, description, url,
|
|
||||||
version, pcfile, conflicts, variables,
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py
|
|
||||||
index f57957f0b..a72e72a0b 100644
|
|
||||||
--- a/mesonbuild/compilers/detect.py
|
|
||||||
+++ b/mesonbuild/compilers/detect.py
|
|
||||||
@@ -1472,6 +1472,11 @@ def _get_clang_compiler_defines(compiler: T.List[str], lang: str) -> T.Dict[str,
|
|
||||||
"""
|
|
||||||
from .mixins.clang import clang_lang_map
|
|
||||||
|
|
||||||
+ # Filter out `-arch` flags passed to the compiler for Universal Binaries
|
|
||||||
+ # https://github.com/mesonbuild/meson/issues/5290
|
|
||||||
+ # https://github.com/mesonbuild/meson/issues/8206
|
|
||||||
+ compiler = [arg for i, arg in enumerate(compiler) if not (i > 0 and compiler[i - 1] == "-arch") and not arg == "-arch"]
|
|
||||||
+
|
|
||||||
def _try_obtain_compiler_defines(args: T.List[str]) -> str:
|
|
||||||
mlog.debug(f'Running command: {join_args(args)}')
|
|
||||||
p, output, error = Popen_safe(compiler + args, write='', stdin=subprocess.PIPE)
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
include("${CURRENT_HOST_INSTALLED_DIR}/share/vcpkg-cmake-get-vars/vcpkg-port-config.cmake")
|
|
||||||
# Overwrite builtin scripts
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/vcpkg_configure_meson.cmake")
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/vcpkg_install_meson.cmake")
|
|
||||||
|
|
||||||
set(meson_short_hash @MESON_SHORT_HASH@)
|
|
||||||
|
|
||||||
# Setup meson:
|
|
||||||
set(program MESON)
|
|
||||||
set(program_version @VERSION@)
|
|
||||||
set(program_name meson)
|
|
||||||
set(search_names meson meson.py)
|
|
||||||
set(ref "${program_version}")
|
|
||||||
set(path_to_search "${DOWNLOADS}/tools/meson-${program_version}-${meson_short_hash}")
|
|
||||||
set(download_urls "https://github.com/mesonbuild/meson/archive/${ref}.tar.gz")
|
|
||||||
set(download_filename "meson-${ref}.tar.gz")
|
|
||||||
set(download_sha512 bd2e65f0863d9cb974e659ff502d773e937b8a60aaddfd7d81e34cd2c296c8e82bf214d790ac089ba441543059dfc2677ba95ed51f676df9da420859f404a907)
|
|
||||||
|
|
||||||
find_program(SCRIPT_MESON NAMES ${search_names} PATHS "${path_to_search}" NO_DEFAULT_PATH) # NO_DEFAULT_PATH due top patching
|
|
||||||
|
|
||||||
if(NOT SCRIPT_MESON)
|
|
||||||
vcpkg_download_distfile(archive_path
|
|
||||||
URLS ${download_urls}
|
|
||||||
SHA512 "${download_sha512}"
|
|
||||||
FILENAME "${download_filename}"
|
|
||||||
)
|
|
||||||
file(REMOVE_RECURSE "${path_to_search}")
|
|
||||||
file(REMOVE_RECURSE "${path_to_search}-tmp")
|
|
||||||
file(MAKE_DIRECTORY "${path_to_search}-tmp")
|
|
||||||
file(ARCHIVE_EXTRACT INPUT "${archive_path}"
|
|
||||||
DESTINATION "${path_to_search}-tmp"
|
|
||||||
#PATTERNS "**/mesonbuild/*" "**/*.py"
|
|
||||||
)
|
|
||||||
z_vcpkg_apply_patches(
|
|
||||||
SOURCE_PATH "${path_to_search}-tmp/meson-${ref}"
|
|
||||||
PATCHES
|
|
||||||
@PATCHES@
|
|
||||||
)
|
|
||||||
file(MAKE_DIRECTORY "${path_to_search}")
|
|
||||||
file(RENAME "${path_to_search}-tmp/meson-${ref}/meson.py" "${path_to_search}/meson.py")
|
|
||||||
file(RENAME "${path_to_search}-tmp/meson-${ref}/mesonbuild" "${path_to_search}/mesonbuild")
|
|
||||||
file(REMOVE_RECURSE "${path_to_search}-tmp")
|
|
||||||
set(SCRIPT_MESON "${path_to_search}/meson.py")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Check required python version
|
|
||||||
vcpkg_find_acquire_program(PYTHON3)
|
|
||||||
vcpkg_execute_in_download_mode(
|
|
||||||
COMMAND "${PYTHON3}" --version
|
|
||||||
OUTPUT_VARIABLE version_contents
|
|
||||||
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}"
|
|
||||||
)
|
|
||||||
string(REGEX MATCH [[[0-9]+\.[0-9]+\.[0-9]+]] python_ver "${version_contents}")
|
|
||||||
|
|
||||||
set(min_required 3.7)
|
|
||||||
if(python_ver VERSION_LESS "${min_required}")
|
|
||||||
message(FATAL_ERROR "Found Python version '${python_ver} at ${PYTHON3}' is insufficient for meson. meson requires at least version '${min_required}'")
|
|
||||||
else()
|
|
||||||
message(STATUS "Found Python version '${python_ver} at ${PYTHON3}'")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "Using meson: ${SCRIPT_MESON}")
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"name": "vcpkg-tool-meson",
|
|
||||||
"version": "1.8.2",
|
|
||||||
"description": "Meson build system",
|
|
||||||
"homepage": "https://github.com/mesonbuild/meson",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"supports": "native",
|
|
||||||
"dependencies": [
|
|
||||||
"vcpkg-cmake-get-vars"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,480 +0,0 @@
|
||||||
function(z_vcpkg_meson_set_proglist_variables config_type)
|
|
||||||
if(VCPKG_TARGET_IS_WINDOWS)
|
|
||||||
set(proglist MT AR)
|
|
||||||
else()
|
|
||||||
set(proglist AR RANLIB STRIP NM OBJDUMP DLLTOOL MT)
|
|
||||||
endif()
|
|
||||||
foreach(prog IN LISTS proglist)
|
|
||||||
if(VCPKG_DETECTED_CMAKE_${prog})
|
|
||||||
if(meson_${prog})
|
|
||||||
string(TOUPPER "MESON_${meson_${prog}}" var_to_set)
|
|
||||||
set("${var_to_set}" "${meson_${prog}} = ['${VCPKG_DETECTED_CMAKE_${prog}}']" PARENT_SCOPE)
|
|
||||||
elseif(${prog} STREQUAL AR AND VCPKG_COMBINED_STATIC_LINKER_FLAGS_${config_type})
|
|
||||||
# Probably need to move AR somewhere else
|
|
||||||
string(TOLOWER "${prog}" proglower)
|
|
||||||
z_vcpkg_meson_convert_compiler_flags_to_list(ar_flags "${VCPKG_COMBINED_STATIC_LINKER_FLAGS_${config_type}}")
|
|
||||||
list(PREPEND ar_flags "${VCPKG_DETECTED_CMAKE_${prog}}")
|
|
||||||
z_vcpkg_meson_convert_list_to_python_array(ar_flags ${ar_flags})
|
|
||||||
set("MESON_AR" "${proglower} = ${ar_flags}" PARENT_SCOPE)
|
|
||||||
else()
|
|
||||||
string(TOUPPER "MESON_${prog}" var_to_set)
|
|
||||||
string(TOLOWER "${prog}" proglower)
|
|
||||||
set("${var_to_set}" "${proglower} = ['${VCPKG_DETECTED_CMAKE_${prog}}']" PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
set(compilers "${arg_LANGUAGES}")
|
|
||||||
if(VCPKG_TARGET_IS_WINDOWS)
|
|
||||||
list(APPEND compilers RC)
|
|
||||||
endif()
|
|
||||||
set(meson_RC windres)
|
|
||||||
set(meson_Fortran fortran)
|
|
||||||
set(meson_CXX cpp)
|
|
||||||
foreach(prog IN LISTS compilers)
|
|
||||||
if(VCPKG_DETECTED_CMAKE_${prog}_COMPILER)
|
|
||||||
string(TOUPPER "MESON_${prog}" var_to_set)
|
|
||||||
if(meson_${prog})
|
|
||||||
if(VCPKG_COMBINED_${prog}_FLAGS_${config_type})
|
|
||||||
# Need compiler flags in prog vars for sanity check.
|
|
||||||
z_vcpkg_meson_convert_compiler_flags_to_list(${prog}flags "${VCPKG_COMBINED_${prog}_FLAGS_${config_type}}")
|
|
||||||
endif()
|
|
||||||
list(PREPEND ${prog}flags "${VCPKG_DETECTED_CMAKE_${prog}_COMPILER}")
|
|
||||||
list(FILTER ${prog}flags EXCLUDE REGEX "(-|/)nologo") # Breaks compiler detection otherwise
|
|
||||||
z_vcpkg_meson_convert_list_to_python_array(${prog}flags ${${prog}flags})
|
|
||||||
set("${var_to_set}" "${meson_${prog}} = ${${prog}flags}" PARENT_SCOPE)
|
|
||||||
if (DEFINED VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID
|
|
||||||
AND NOT VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID MATCHES "^(GNU|Intel)$"
|
|
||||||
AND VCPKG_DETECTED_CMAKE_LINKER)
|
|
||||||
string(TOUPPER "MESON_${prog}_LD" var_to_set)
|
|
||||||
set(${var_to_set} "${meson_${prog}}_ld = ['${VCPKG_DETECTED_CMAKE_LINKER}']" PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
if(VCPKG_COMBINED_${prog}_FLAGS_${config_type})
|
|
||||||
# Need compiler flags in prog vars for sanity check.
|
|
||||||
z_vcpkg_meson_convert_compiler_flags_to_list(${prog}flags "${VCPKG_COMBINED_${prog}_FLAGS_${config_type}}")
|
|
||||||
endif()
|
|
||||||
list(PREPEND ${prog}flags "${VCPKG_DETECTED_CMAKE_${prog}_COMPILER}")
|
|
||||||
list(FILTER ${prog}flags EXCLUDE REGEX "(-|/)nologo") # Breaks compiler detection otherwise
|
|
||||||
z_vcpkg_meson_convert_list_to_python_array(${prog}flags ${${prog}flags})
|
|
||||||
string(TOLOWER "${prog}" proglower)
|
|
||||||
set("${var_to_set}" "${proglower} = ${${prog}flags}" PARENT_SCOPE)
|
|
||||||
if (DEFINED VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID
|
|
||||||
AND NOT VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID MATCHES "^(GNU|Intel)$"
|
|
||||||
AND VCPKG_DETECTED_CMAKE_LINKER)
|
|
||||||
string(TOUPPER "MESON_${prog}_LD" var_to_set)
|
|
||||||
set(${var_to_set} "${proglower}_ld = ['${VCPKG_DETECTED_CMAKE_LINKER}']" PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(z_vcpkg_meson_convert_compiler_flags_to_list out_var compiler_flags)
|
|
||||||
separate_arguments(cmake_list NATIVE_COMMAND "${compiler_flags}")
|
|
||||||
list(TRANSFORM cmake_list REPLACE ";" [[\\;]])
|
|
||||||
set("${out_var}" "${cmake_list}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(z_vcpkg_meson_convert_list_to_python_array out_var)
|
|
||||||
z_vcpkg_function_arguments(flag_list 1)
|
|
||||||
vcpkg_list(REMOVE_ITEM flag_list "") # remove empty elements if any
|
|
||||||
vcpkg_list(JOIN flag_list "', '" flag_list)
|
|
||||||
set("${out_var}" "['${flag_list}']" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Generates the required compiler properties for meson
|
|
||||||
function(z_vcpkg_meson_set_flags_variables config_type)
|
|
||||||
if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW)
|
|
||||||
set(libpath_flag /LIBPATH:)
|
|
||||||
else()
|
|
||||||
set(libpath_flag -L)
|
|
||||||
endif()
|
|
||||||
if(config_type STREQUAL "DEBUG")
|
|
||||||
set(path_suffix "/debug")
|
|
||||||
else()
|
|
||||||
set(path_suffix "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(includepath "-I${CURRENT_INSTALLED_DIR}/include")
|
|
||||||
set(libpath "${libpath_flag}${CURRENT_INSTALLED_DIR}${path_suffix}/lib")
|
|
||||||
|
|
||||||
foreach(lang IN LISTS arg_LANGUAGES)
|
|
||||||
z_vcpkg_meson_convert_compiler_flags_to_list(${lang}flags "${VCPKG_COMBINED_${lang}_FLAGS_${config_type}}")
|
|
||||||
if(lang MATCHES "^(C|CXX)$")
|
|
||||||
vcpkg_list(APPEND ${lang}flags "${includepath}")
|
|
||||||
endif()
|
|
||||||
z_vcpkg_meson_convert_list_to_python_array(${lang}flags ${${lang}flags})
|
|
||||||
set(lang_mapping "${lang}")
|
|
||||||
if(lang STREQUAL "Fortran")
|
|
||||||
set(lang_mapping "FC")
|
|
||||||
endif()
|
|
||||||
string(TOLOWER "${lang_mapping}" langlower)
|
|
||||||
if(lang STREQUAL "CXX")
|
|
||||||
set(langlower cpp)
|
|
||||||
endif()
|
|
||||||
set(MESON_${lang_mapping}FLAGS "${langlower}_args = ${${lang}flags}\n")
|
|
||||||
set(linker_flags "${VCPKG_COMBINED_SHARED_LINKER_FLAGS_${config_type}}")
|
|
||||||
z_vcpkg_meson_convert_compiler_flags_to_list(linker_flags "${linker_flags}")
|
|
||||||
vcpkg_list(APPEND linker_flags "${libpath}")
|
|
||||||
z_vcpkg_meson_convert_list_to_python_array(linker_flags ${linker_flags})
|
|
||||||
string(APPEND MESON_${lang_mapping}FLAGS "${langlower}_link_args = ${linker_flags}\n")
|
|
||||||
set(MESON_${lang_mapping}FLAGS "${MESON_${lang_mapping}FLAGS}" PARENT_SCOPE)
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(z_vcpkg_get_build_and_host_system build_system host_system is_cross) #https://mesonbuild.com/Cross-compilation.html
|
|
||||||
set(build_unknown FALSE)
|
|
||||||
if(CMAKE_HOST_WIN32)
|
|
||||||
if(DEFINED ENV{PROCESSOR_ARCHITEW6432})
|
|
||||||
set(build_arch $ENV{PROCESSOR_ARCHITEW6432})
|
|
||||||
else()
|
|
||||||
set(build_arch $ENV{PROCESSOR_ARCHITECTURE})
|
|
||||||
endif()
|
|
||||||
if(build_arch MATCHES "(amd|AMD)64")
|
|
||||||
set(build_cpu_fam x86_64)
|
|
||||||
set(build_cpu x86_64)
|
|
||||||
elseif(build_arch MATCHES "(x|X)86")
|
|
||||||
set(build_cpu_fam x86)
|
|
||||||
set(build_cpu i686)
|
|
||||||
elseif(build_arch MATCHES "^(ARM|arm)64$")
|
|
||||||
set(build_cpu_fam aarch64)
|
|
||||||
set(build_cpu armv8)
|
|
||||||
elseif(build_arch MATCHES "^(ARM|arm)$")
|
|
||||||
set(build_cpu_fam arm)
|
|
||||||
set(build_cpu armv7hl)
|
|
||||||
else()
|
|
||||||
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
|
|
||||||
message(WARNING "Unsupported build architecture ${build_arch}! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the build_machine entry!")
|
|
||||||
endif()
|
|
||||||
set(build_unknown TRUE)
|
|
||||||
endif()
|
|
||||||
elseif(CMAKE_HOST_UNIX)
|
|
||||||
# at this stage, CMAKE_HOST_SYSTEM_PROCESSOR is not defined
|
|
||||||
execute_process(
|
|
||||||
COMMAND uname -m
|
|
||||||
OUTPUT_VARIABLE MACHINE
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
COMMAND_ERROR_IS_FATAL ANY)
|
|
||||||
|
|
||||||
# Show real machine architecture to visually understand whether we are in a native Apple Silicon terminal or running under Rosetta emulation
|
|
||||||
debug_message("Machine: ${MACHINE}")
|
|
||||||
|
|
||||||
if(MACHINE MATCHES "arm64|aarch64")
|
|
||||||
set(build_cpu_fam aarch64)
|
|
||||||
set(build_cpu armv8)
|
|
||||||
elseif(MACHINE MATCHES "armv7h?l")
|
|
||||||
set(build_cpu_fam arm)
|
|
||||||
set(build_cpu ${MACHINE})
|
|
||||||
elseif(MACHINE MATCHES "x86_64|amd64")
|
|
||||||
set(build_cpu_fam x86_64)
|
|
||||||
set(build_cpu x86_64)
|
|
||||||
elseif(MACHINE MATCHES "x86|i686")
|
|
||||||
set(build_cpu_fam x86)
|
|
||||||
set(build_cpu i686)
|
|
||||||
elseif(MACHINE MATCHES "i386")
|
|
||||||
set(build_cpu_fam x86)
|
|
||||||
set(build_cpu i386)
|
|
||||||
elseif(MACHINE MATCHES "loongarch64")
|
|
||||||
set(build_cpu_fam loongarch64)
|
|
||||||
set(build_cpu loongarch64)
|
|
||||||
else()
|
|
||||||
# https://github.com/mesonbuild/meson/blob/master/docs/markdown/Reference-tables.md#cpu-families
|
|
||||||
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
|
|
||||||
message(WARNING "Unhandled machine: ${MACHINE}! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the build_machine entry!")
|
|
||||||
endif()
|
|
||||||
set(build_unknown TRUE)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
|
|
||||||
message(WARNING "Failed to detect the build architecture! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the build_machine entry!")
|
|
||||||
endif()
|
|
||||||
set(build_unknown TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(build "[build_machine]\n") # Machine the build is performed on
|
|
||||||
string(APPEND build "endian = 'little'\n")
|
|
||||||
if(CMAKE_HOST_WIN32)
|
|
||||||
string(APPEND build "system = 'windows'\n")
|
|
||||||
elseif(CMAKE_HOST_APPLE)
|
|
||||||
string(APPEND build "system = 'darwin'\n")
|
|
||||||
elseif(CYGWIN)
|
|
||||||
string(APPEND build "system = 'cygwin'\n")
|
|
||||||
elseif(CMAKE_HOST_UNIX)
|
|
||||||
string(APPEND build "system = 'linux'\n")
|
|
||||||
else()
|
|
||||||
set(build_unknown TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(DEFINED build_cpu_fam)
|
|
||||||
string(APPEND build "cpu_family = '${build_cpu_fam}'\n")
|
|
||||||
endif()
|
|
||||||
if(DEFINED build_cpu)
|
|
||||||
string(APPEND build "cpu = '${build_cpu}'")
|
|
||||||
endif()
|
|
||||||
if(NOT build_unknown)
|
|
||||||
set(${build_system} "${build}" PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(host_unkown FALSE)
|
|
||||||
if(VCPKG_TARGET_ARCHITECTURE MATCHES "(amd|AMD|x|X)64")
|
|
||||||
set(host_cpu_fam x86_64)
|
|
||||||
set(host_cpu x86_64)
|
|
||||||
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "(x|X)86")
|
|
||||||
set(host_cpu_fam x86)
|
|
||||||
set(host_cpu i686)
|
|
||||||
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "^(ARM|arm)64$")
|
|
||||||
set(host_cpu_fam aarch64)
|
|
||||||
set(host_cpu armv8)
|
|
||||||
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "^(ARM|arm)$")
|
|
||||||
set(host_cpu_fam arm)
|
|
||||||
set(host_cpu armv7hl)
|
|
||||||
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "loongarch64")
|
|
||||||
set(host_cpu_fam loongarch64)
|
|
||||||
set(host_cpu loongarch64)
|
|
||||||
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "wasm32")
|
|
||||||
set(host_cpu_fam wasm32)
|
|
||||||
set(host_cpu wasm32)
|
|
||||||
else()
|
|
||||||
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
|
|
||||||
message(WARNING "Unsupported target architecture ${VCPKG_TARGET_ARCHITECTURE}! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the host_machine entry!" )
|
|
||||||
endif()
|
|
||||||
set(host_unkown TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(host "[host_machine]\n") # host=target in vcpkg.
|
|
||||||
string(APPEND host "endian = 'little'\n")
|
|
||||||
if(NOT VCPKG_CMAKE_SYSTEM_NAME OR VCPKG_TARGET_IS_MINGW OR VCPKG_TARGET_IS_UWP)
|
|
||||||
set(meson_system_name "windows")
|
|
||||||
else()
|
|
||||||
string(TOLOWER "${VCPKG_CMAKE_SYSTEM_NAME}" meson_system_name)
|
|
||||||
endif()
|
|
||||||
string(APPEND host "system = '${meson_system_name}'\n")
|
|
||||||
string(APPEND host "cpu_family = '${host_cpu_fam}'\n")
|
|
||||||
string(APPEND host "cpu = '${host_cpu}'")
|
|
||||||
if(NOT host_unkown)
|
|
||||||
set(${host_system} "${host}" PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT build_cpu_fam MATCHES "${host_cpu_fam}"
|
|
||||||
OR VCPKG_TARGET_IS_ANDROID OR VCPKG_TARGET_IS_IOS OR VCPKG_TARGET_IS_UWP
|
|
||||||
OR (VCPKG_TARGET_IS_MINGW AND NOT CMAKE_HOST_WIN32))
|
|
||||||
set(${is_cross} TRUE PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(z_vcpkg_meson_setup_extra_windows_variables config_type)
|
|
||||||
## b_vscrt
|
|
||||||
if(VCPKG_CRT_LINKAGE STREQUAL "static")
|
|
||||||
set(crt_type "mt")
|
|
||||||
else()
|
|
||||||
set(crt_type "md")
|
|
||||||
endif()
|
|
||||||
if(config_type STREQUAL "DEBUG")
|
|
||||||
set(crt_type "${crt_type}d")
|
|
||||||
endif()
|
|
||||||
set(MESON_VSCRT_LINKAGE "b_vscrt = '${crt_type}'" PARENT_SCOPE)
|
|
||||||
## winlibs
|
|
||||||
separate_arguments(c_winlibs NATIVE_COMMAND "${VCPKG_DETECTED_CMAKE_C_STANDARD_LIBRARIES}")
|
|
||||||
separate_arguments(cpp_winlibs NATIVE_COMMAND "${VCPKG_DETECTED_CMAKE_CXX_STANDARD_LIBRARIES}")
|
|
||||||
z_vcpkg_meson_convert_list_to_python_array(c_winlibs ${c_winlibs})
|
|
||||||
z_vcpkg_meson_convert_list_to_python_array(cpp_winlibs ${cpp_winlibs})
|
|
||||||
set(MESON_WINLIBS "c_winlibs = ${c_winlibs}\n")
|
|
||||||
string(APPEND MESON_WINLIBS "cpp_winlibs = ${cpp_winlibs}")
|
|
||||||
set(MESON_WINLIBS "${MESON_WINLIBS}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(z_vcpkg_meson_setup_variables config_type)
|
|
||||||
set(meson_var_list VSCRT_LINKAGE WINLIBS MT AR RC C C_LD CXX CXX_LD OBJC OBJC_LD OBJCXX OBJCXX_LD FC FC_LD WINDRES CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS FCFLAGS SHARED_LINKER_FLAGS)
|
|
||||||
foreach(var IN LISTS meson_var_list)
|
|
||||||
set(MESON_${var} "")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(VCPKG_TARGET_IS_WINDOWS)
|
|
||||||
z_vcpkg_meson_setup_extra_windows_variables("${config_type}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
z_vcpkg_meson_set_proglist_variables("${config_type}")
|
|
||||||
z_vcpkg_meson_set_flags_variables("${config_type}")
|
|
||||||
|
|
||||||
foreach(var IN LISTS meson_var_list)
|
|
||||||
set(MESON_${var} "${MESON_${var}}" PARENT_SCOPE)
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(vcpkg_generate_meson_cmd_args)
|
|
||||||
cmake_parse_arguments(PARSE_ARGV 0 arg
|
|
||||||
""
|
|
||||||
"OUTPUT;CONFIG"
|
|
||||||
"OPTIONS;LANGUAGES;ADDITIONAL_BINARIES;ADDITIONAL_PROPERTIES"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT arg_LANGUAGES)
|
|
||||||
set(arg_LANGUAGES C CXX)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
vcpkg_list(JOIN arg_ADDITIONAL_BINARIES "\n" MESON_ADDITIONAL_BINARIES)
|
|
||||||
vcpkg_list(JOIN arg_ADDITIONAL_PROPERTIES "\n" MESON_ADDITIONAL_PROPERTIES)
|
|
||||||
|
|
||||||
set(buildtype "${arg_CONFIG}")
|
|
||||||
|
|
||||||
if(NOT VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
|
|
||||||
z_vcpkg_select_default_vcpkg_chainload_toolchain()
|
|
||||||
endif()
|
|
||||||
vcpkg_list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS "-DVCPKG_LANGUAGES=${arg_LANGUAGES}")
|
|
||||||
vcpkg_cmake_get_vars(cmake_vars_file)
|
|
||||||
debug_message("Including cmake vars from: ${cmake_vars_file}")
|
|
||||||
include("${cmake_vars_file}")
|
|
||||||
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --backend ninja --wrap-mode nodownload -Doptimization=plain)
|
|
||||||
|
|
||||||
z_vcpkg_get_build_and_host_system(MESON_HOST_MACHINE MESON_BUILD_MACHINE IS_CROSS)
|
|
||||||
|
|
||||||
if(arg_CONFIG STREQUAL "DEBUG")
|
|
||||||
set(suffix "dbg")
|
|
||||||
else()
|
|
||||||
string(SUBSTRING "${arg_CONFIG}" 0 3 suffix)
|
|
||||||
string(TOLOWER "${suffix}" suffix)
|
|
||||||
endif()
|
|
||||||
set(meson_input_file_${buildtype} "${CURRENT_BUILDTREES_DIR}/meson-${TARGET_TRIPLET}-${suffix}.log")
|
|
||||||
|
|
||||||
if(IS_CROSS)
|
|
||||||
# VCPKG_CROSSCOMPILING is not used since it regresses a lot of ports in x64-windows-x triplets
|
|
||||||
# For consistency this should proably be changed in the future?
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --native "${SCRIPTS}/buildsystems/meson/none.txt")
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --cross "${meson_input_file_${buildtype}}")
|
|
||||||
else()
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --native "${meson_input_file_${buildtype}}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# User provided cross/native files
|
|
||||||
if(VCPKG_MESON_NATIVE_FILE)
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --native "${VCPKG_MESON_NATIVE_FILE}")
|
|
||||||
endif()
|
|
||||||
if(VCPKG_MESON_NATIVE_FILE_${buildtype})
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --native "${VCPKG_MESON_NATIVE_FILE_${buildtype}}")
|
|
||||||
endif()
|
|
||||||
if(VCPKG_MESON_CROSS_FILE)
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --cross "${VCPKG_MESON_CROSS_FILE}")
|
|
||||||
endif()
|
|
||||||
if(VCPKG_MESON_CROSS_FILE_${buildtype})
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --cross "${VCPKG_MESON_CROSS_FILE_${buildtype}}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --libdir lib) # else meson install into an architecture describing folder
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS --pkgconfig.relocatable)
|
|
||||||
|
|
||||||
if(arg_CONFIG STREQUAL "RELEASE")
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS -Ddebug=false --prefix "${CURRENT_PACKAGES_DIR}")
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS "--pkg-config-path;['${CURRENT_INSTALLED_DIR}/lib/pkgconfig','${CURRENT_INSTALLED_DIR}/share/pkgconfig']")
|
|
||||||
if(VCPKG_TARGET_IS_WINDOWS)
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}','${CURRENT_INSTALLED_DIR}/debug','${CURRENT_INSTALLED_DIR}/share']")
|
|
||||||
else()
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}','${CURRENT_INSTALLED_DIR}/debug']")
|
|
||||||
endif()
|
|
||||||
elseif(arg_CONFIG STREQUAL "DEBUG")
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS -Ddebug=true --prefix "${CURRENT_PACKAGES_DIR}/debug" --includedir ../include)
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS "--pkg-config-path;['${CURRENT_INSTALLED_DIR}/debug/lib/pkgconfig','${CURRENT_INSTALLED_DIR}/share/pkgconfig']")
|
|
||||||
if(VCPKG_TARGET_IS_WINDOWS)
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}/debug','${CURRENT_INSTALLED_DIR}','${CURRENT_INSTALLED_DIR}/share']")
|
|
||||||
else()
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}/debug','${CURRENT_INSTALLED_DIR}']")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "Unknown configuration. Only DEBUG and RELEASE are valid values.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Allow overrides / additional configuration variables from triplets
|
|
||||||
if(DEFINED VCPKG_MESON_CONFIGURE_OPTIONS)
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS ${VCPKG_MESON_CONFIGURE_OPTIONS})
|
|
||||||
endif()
|
|
||||||
if(DEFINED VCPKG_MESON_CONFIGURE_OPTIONS_${buildtype})
|
|
||||||
vcpkg_list(APPEND arg_OPTIONS ${VCPKG_MESON_CONFIGURE_OPTIONS_${buildtype}})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic")
|
|
||||||
set(MESON_DEFAULT_LIBRARY shared)
|
|
||||||
else()
|
|
||||||
set(MESON_DEFAULT_LIBRARY static)
|
|
||||||
endif()
|
|
||||||
set(MESON_CMAKE_BUILD_TYPE "${cmake_build_type_${buildtype}}")
|
|
||||||
z_vcpkg_meson_setup_variables(${buildtype})
|
|
||||||
configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/meson.template.in" "${meson_input_file_${buildtype}}" @ONLY)
|
|
||||||
set("${arg_OUTPUT}" ${arg_OPTIONS} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(vcpkg_configure_meson)
|
|
||||||
# parse parameters such that semicolons in options arguments to COMMAND don't get erased
|
|
||||||
cmake_parse_arguments(PARSE_ARGV 0 arg
|
|
||||||
"NO_PKG_CONFIG"
|
|
||||||
"SOURCE_PATH"
|
|
||||||
"OPTIONS;OPTIONS_DEBUG;OPTIONS_RELEASE;LANGUAGES;ADDITIONAL_BINARIES;ADDITIONAL_NATIVE_BINARIES;ADDITIONAL_CROSS_BINARIES;ADDITIONAL_PROPERTIES"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(DEFINED arg_ADDITIONAL_NATIVE_BINARIES OR DEFINED arg_ADDITIONAL_CROSS_BINARIES)
|
|
||||||
message(WARNING "Options ADDITIONAL_(NATIVE|CROSS)_BINARIES have been deprecated. Only use ADDITIONAL_BINARIES!")
|
|
||||||
endif()
|
|
||||||
vcpkg_list(APPEND arg_ADDITIONAL_BINARIES ${arg_ADDITIONAL_NATIVE_BINARIES} ${arg_ADDITIONAL_CROSS_BINARIES})
|
|
||||||
vcpkg_list(REMOVE_DUPLICATES arg_ADDITIONAL_BINARIES)
|
|
||||||
|
|
||||||
file(REMOVE_RECURSE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel")
|
|
||||||
file(REMOVE_RECURSE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg")
|
|
||||||
|
|
||||||
vcpkg_find_acquire_program(MESON)
|
|
||||||
|
|
||||||
get_filename_component(CMAKE_PATH "${CMAKE_COMMAND}" DIRECTORY)
|
|
||||||
vcpkg_add_to_path("${CMAKE_PATH}") # Make CMake invokeable for Meson
|
|
||||||
|
|
||||||
vcpkg_find_acquire_program(NINJA)
|
|
||||||
|
|
||||||
if(NOT arg_NO_PKG_CONFIG)
|
|
||||||
vcpkg_find_acquire_program(PKGCONFIG)
|
|
||||||
set(ENV{PKG_CONFIG} "${PKGCONFIG}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
vcpkg_find_acquire_program(PYTHON3)
|
|
||||||
get_filename_component(PYTHON3_DIR "${PYTHON3}" DIRECTORY)
|
|
||||||
vcpkg_add_to_path(PREPEND "${PYTHON3_DIR}")
|
|
||||||
|
|
||||||
set(buildtypes "")
|
|
||||||
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
|
|
||||||
set(buildname "DEBUG")
|
|
||||||
set(cmake_build_type_${buildname} "Debug")
|
|
||||||
vcpkg_list(APPEND buildtypes "${buildname}")
|
|
||||||
set(path_suffix_${buildname} "debug/")
|
|
||||||
set(suffix_${buildname} "dbg")
|
|
||||||
endif()
|
|
||||||
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
|
|
||||||
set(buildname "RELEASE")
|
|
||||||
set(cmake_build_type_${buildname} "Release")
|
|
||||||
vcpkg_list(APPEND buildtypes "${buildname}")
|
|
||||||
set(path_suffix_${buildname} "")
|
|
||||||
set(suffix_${buildname} "rel")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# configure build
|
|
||||||
foreach(buildtype IN LISTS buildtypes)
|
|
||||||
message(STATUS "Configuring ${TARGET_TRIPLET}-${suffix_${buildtype}}")
|
|
||||||
file(MAKE_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-${suffix_${buildtype}}")
|
|
||||||
|
|
||||||
vcpkg_generate_meson_cmd_args(
|
|
||||||
OUTPUT cmd_args
|
|
||||||
CONFIG ${buildtype}
|
|
||||||
LANGUAGES ${arg_LANGUAGES}
|
|
||||||
OPTIONS ${arg_OPTIONS} ${arg_OPTIONS_${buildtype}}
|
|
||||||
ADDITIONAL_BINARIES ${arg_ADDITIONAL_BINARIES}
|
|
||||||
ADDITIONAL_PROPERTIES ${arg_ADDITIONAL_PROPERTIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
vcpkg_execute_required_process(
|
|
||||||
COMMAND ${MESON} setup ${cmd_args} ${arg_SOURCE_PATH}
|
|
||||||
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-${suffix_${buildtype}}"
|
|
||||||
LOGNAME config-${TARGET_TRIPLET}-${suffix_${buildtype}}
|
|
||||||
SAVE_LOG_FILES
|
|
||||||
meson-logs/meson-log.txt
|
|
||||||
meson-info/intro-dependencies.json
|
|
||||||
meson-logs/install-log.txt
|
|
||||||
)
|
|
||||||
|
|
||||||
message(STATUS "Configuring ${TARGET_TRIPLET}-${suffix_${buildtype}} done")
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
function(vcpkg_install_meson)
|
|
||||||
cmake_parse_arguments(PARSE_ARGV 0 arg "ADD_BIN_TO_PATH" "" "")
|
|
||||||
|
|
||||||
vcpkg_find_acquire_program(NINJA)
|
|
||||||
unset(ENV{DESTDIR}) # installation directory was already specified with '--prefix' option
|
|
||||||
|
|
||||||
if(VCPKG_TARGET_IS_OSX)
|
|
||||||
vcpkg_backup_env_variables(VARS SDKROOT MACOSX_DEPLOYMENT_TARGET)
|
|
||||||
set(ENV{SDKROOT} "${VCPKG_DETECTED_CMAKE_OSX_SYSROOT}")
|
|
||||||
set(ENV{MACOSX_DEPLOYMENT_TARGET} "${VCPKG_DETECTED_CMAKE_OSX_DEPLOYMENT_TARGET}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
foreach(buildtype IN ITEMS "debug" "release")
|
|
||||||
if(DEFINED VCPKG_BUILD_TYPE AND NOT VCPKG_BUILD_TYPE STREQUAL buildtype)
|
|
||||||
continue()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(buildtype STREQUAL "debug")
|
|
||||||
set(short_buildtype "dbg")
|
|
||||||
else()
|
|
||||||
set(short_buildtype "rel")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "Package ${TARGET_TRIPLET}-${short_buildtype}")
|
|
||||||
if(arg_ADD_BIN_TO_PATH)
|
|
||||||
vcpkg_backup_env_variables(VARS PATH)
|
|
||||||
if(buildtype STREQUAL "debug")
|
|
||||||
vcpkg_add_to_path(PREPEND "${CURRENT_INSTALLED_DIR}/debug/bin")
|
|
||||||
else()
|
|
||||||
vcpkg_add_to_path(PREPEND "${CURRENT_INSTALLED_DIR}/bin")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
vcpkg_execute_required_process(
|
|
||||||
COMMAND "${NINJA}" install -v
|
|
||||||
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-${short_buildtype}"
|
|
||||||
LOGNAME package-${TARGET_TRIPLET}-${short_buildtype}
|
|
||||||
)
|
|
||||||
if(arg_ADD_BIN_TO_PATH)
|
|
||||||
vcpkg_restore_env_variables(VARS PATH)
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
vcpkg_list(SET renamed_libs)
|
|
||||||
if(VCPKG_TARGET_IS_WINDOWS AND VCPKG_LIBRARY_LINKAGE STREQUAL static AND NOT VCPKG_TARGET_IS_MINGW)
|
|
||||||
# Meson names all static libraries lib<name>.a which basically breaks the world
|
|
||||||
file(GLOB_RECURSE gen_libraries "${CURRENT_PACKAGES_DIR}*/**/lib*.a")
|
|
||||||
foreach(gen_library IN LISTS gen_libraries)
|
|
||||||
get_filename_component(libdir "${gen_library}" DIRECTORY)
|
|
||||||
get_filename_component(libname "${gen_library}" NAME)
|
|
||||||
string(REGEX REPLACE ".a$" ".lib" fixed_librawname "${libname}")
|
|
||||||
string(REGEX REPLACE "^lib" "" fixed_librawname "${fixed_librawname}")
|
|
||||||
file(RENAME "${gen_library}" "${libdir}/${fixed_librawname}")
|
|
||||||
# For cmake fixes.
|
|
||||||
string(REGEX REPLACE ".a$" "" origin_librawname "${libname}")
|
|
||||||
string(REGEX REPLACE ".lib$" "" fixed_librawname "${fixed_librawname}")
|
|
||||||
vcpkg_list(APPEND renamed_libs ${fixed_librawname})
|
|
||||||
set(${librawname}_old ${origin_librawname})
|
|
||||||
set(${librawname}_new ${fixed_librawname})
|
|
||||||
endforeach()
|
|
||||||
file(GLOB_RECURSE cmake_files "${CURRENT_PACKAGES_DIR}*/*.cmake")
|
|
||||||
foreach(cmake_file IN LISTS cmake_files)
|
|
||||||
foreach(current_lib IN LISTS renamed_libs)
|
|
||||||
vcpkg_replace_string("${cmake_file}" "${${current_lib}_old}" "${${current_lib}_new}" IGNORE_UNCHANGED)
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(VCPKG_TARGET_IS_OSX)
|
|
||||||
vcpkg_restore_env_variables(VARS SDKROOT MACOSX_DEPLOYMENT_TARGET)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# See https://github.com/microsoft/vcpkg/discussions/19454
|
|
||||||
# NOTE: Try to keep in sync with default arm64-osx definition
|
|
||||||
set(VCPKG_TARGET_ARCHITECTURE x64)
|
|
||||||
set(VCPKG_CRT_LINKAGE dynamic)
|
|
||||||
set(VCPKG_LIBRARY_LINKAGE static)
|
|
||||||
|
|
||||||
set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
|
|
||||||
set(VCPKG_OSX_ARCHITECTURES "arm64;x86_64")
|
|
||||||
13
default.nix
13
default.nix
|
|
@ -1,4 +1,9 @@
|
||||||
(import (fetchTarball {
|
(import (
|
||||||
url = "https://github.com/edolstra/flake-compat/archive/ff81ac966bb2cae68946d5ed5fc4994f96d0ffec.tar.gz";
|
let
|
||||||
sha256 = "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=";
|
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||||
}) { src = ./.; }).defaultNix
|
in
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
|
}
|
||||||
|
) { src = ./.; }).defaultNix
|
||||||
|
|
|
||||||
56
flake.lock
generated
56
flake.lock
generated
|
|
@ -1,13 +1,29 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696426674,
|
||||||
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"libnbtplusplus": {
|
"libnbtplusplus": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1772016279,
|
"lastModified": 1699286814,
|
||||||
"narHash": "sha256-7itkptyjoRcXfGLwg1/jxajetZ3a4mDc66+w4X6yW8s=",
|
"narHash": "sha256-yy0q+bky80LtK1GWzz7qpM+aAGrOqLuewbid8WT1ilk=",
|
||||||
"owner": "PrismLauncher",
|
"owner": "PrismLauncher",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"rev": "687e43031df0dc641984b4256bcca50d5b3f7de3",
|
"rev": "23b955121b8217c1c348a9ed2483167a6f3ff4ad",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -16,22 +32,42 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-filter": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710156097,
|
||||||
|
"narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "nix-filter",
|
||||||
|
"rev": "3342559a24e85fc164b295c3444e8a139924675b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "nix-filter",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778443072,
|
"lastModified": 1729256560,
|
||||||
"narHash": "sha256-rNDJzV2JTV5SUTwv1cgKZYMdyoUYU9/YfegSaUf3QfY=",
|
"narHash": "sha256-/uilDXvCIEs3C9l73JTACm4quuHUsIHcns1c+cHUJwA=",
|
||||||
"rev": "da5ad661ba4e5ef59ba743f0d112cbc30e474f32",
|
"owner": "NixOS",
|
||||||
"type": "tarball",
|
"repo": "nixpkgs",
|
||||||
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre995699.da5ad661ba4e/nixexprs.tar.xz"
|
"rev": "4c2fcb090b1f3e5b47eaa7bd33913b574a11e0a0",
|
||||||
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"owner": "NixOS",
|
||||||
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
"libnbtplusplus": "libnbtplusplus",
|
"libnbtplusplus": "libnbtplusplus",
|
||||||
|
"nix-filter": "nix-filter",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
205
flake.nix
205
flake.nix
|
|
@ -9,12 +9,34 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
libnbtplusplus = {
|
libnbtplusplus = {
|
||||||
url = "github:PrismLauncher/libnbtplusplus";
|
url = "github:PrismLauncher/libnbtplusplus";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nix-filter.url = "github:numtide/nix-filter";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inputs below this are optional and can be removed
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
inputs.prismlauncher = {
|
||||||
|
url = "github:PrismLauncher/PrismLauncher";
|
||||||
|
inputs = {
|
||||||
|
flake-compat.follows = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
|
|
@ -22,8 +44,9 @@
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
libnbtplusplus,
|
libnbtplusplus,
|
||||||
|
nix-filter,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (nixpkgs) lib;
|
inherit (nixpkgs) lib;
|
||||||
|
|
||||||
|
|
@ -35,178 +58,47 @@
|
||||||
forAllSystems = lib.genAttrs systems;
|
forAllSystems = lib.genAttrs systems;
|
||||||
nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
checks = forAllSystems (
|
checks = forAllSystems (
|
||||||
system:
|
system:
|
||||||
|
|
||||||
let
|
let
|
||||||
pkgs = nixpkgsFor.${system};
|
checks' = nixpkgsFor.${system}.callPackage ./nix/checks.nix { inherit self; };
|
||||||
llvm = pkgs.llvmPackages_22;
|
|
||||||
in
|
in
|
||||||
|
lib.filterAttrs (_: lib.isDerivation) checks'
|
||||||
{
|
|
||||||
formatting =
|
|
||||||
pkgs.runCommand "check-formatting"
|
|
||||||
{
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
deadnix
|
|
||||||
llvm.clang-tools
|
|
||||||
markdownlint-cli
|
|
||||||
nixfmt-rfc-style
|
|
||||||
statix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
''
|
|
||||||
cd ${self}
|
|
||||||
|
|
||||||
echo "Running clang-format...."
|
|
||||||
clang-format --dry-run --style='file' --Werror */**.{c,cc,cpp,h,hh,hpp}
|
|
||||||
|
|
||||||
echo "Running deadnix..."
|
|
||||||
deadnix --fail
|
|
||||||
|
|
||||||
echo "Running markdownlint..."
|
|
||||||
markdownlint --dot .
|
|
||||||
|
|
||||||
echo "Running nixfmt..."
|
|
||||||
find -type f -name '*.nix' -exec nixfmt --check {} +
|
|
||||||
|
|
||||||
echo "Running statix"
|
|
||||||
statix check .
|
|
||||||
|
|
||||||
touch $out
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
devShells = forAllSystems (
|
devShells = forAllSystems (
|
||||||
system:
|
system:
|
||||||
|
|
||||||
let
|
let
|
||||||
pkgs = nixpkgsFor.${system};
|
pkgs = nixpkgsFor.${system};
|
||||||
llvm = pkgs.llvmPackages_22;
|
|
||||||
python = pkgs.python3;
|
|
||||||
mkShell = pkgs.mkShell.override { inherit (llvm) stdenv; };
|
|
||||||
|
|
||||||
packages' = self.packages.${system};
|
|
||||||
|
|
||||||
welcomeMessage = ''
|
|
||||||
Welcome to the Prism Launcher repository! 🌈
|
|
||||||
|
|
||||||
We just set some things up for you. To get building, you can run:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cd "$cmakeBuildDir"
|
|
||||||
$ ninjaBuildPhase
|
|
||||||
$ ninjaInstallPhase
|
|
||||||
```
|
|
||||||
|
|
||||||
Feel free to ask any questions in our Discord server or Matrix space:
|
|
||||||
- https://prismlauncher.org/discord
|
|
||||||
- https://matrix.to/#/#prismlauncher:matrix.org
|
|
||||||
|
|
||||||
And thanks for helping out :)
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Re-use our package wrapper to wrap our development environment
|
|
||||||
qt-wrapper-env = packages'.prismlauncher.overrideAttrs (old: {
|
|
||||||
name = "qt-wrapper-env";
|
|
||||||
|
|
||||||
# Required to use script-based makeWrapper below
|
|
||||||
strictDeps = true;
|
|
||||||
|
|
||||||
# We don't need/want the unwrapped Prism package
|
|
||||||
paths = [ ];
|
|
||||||
|
|
||||||
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [
|
|
||||||
# Ensure the wrapper is script based so it can be sourced
|
|
||||||
pkgs.makeWrapper
|
|
||||||
];
|
|
||||||
|
|
||||||
# Inspired by https://discourse.nixos.org/t/python-qt-woes/11808/10
|
|
||||||
buildCommand = ''
|
|
||||||
makeQtWrapper ${lib.getExe pkgs.runtimeShellPackage} "$out"
|
|
||||||
sed -i '/^exec/d' "$out"
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
default = mkShell {
|
default = pkgs.mkShell {
|
||||||
name = "prism-launcher";
|
inputsFrom = [ self.packages.${system}.prismlauncher-unwrapped ];
|
||||||
|
buildInputs = with pkgs; [
|
||||||
inputsFrom = [ packages'.prismlauncher-unwrapped ];
|
ccache
|
||||||
|
ninja
|
||||||
packages = [
|
|
||||||
pkgs.ccache
|
|
||||||
llvm.clang-tools
|
|
||||||
python # NOTE(@getchoo): Required for run-clang-tidy, etc.
|
|
||||||
|
|
||||||
(pkgs.stdenvNoCC.mkDerivation {
|
|
||||||
pname = "clang-tidy-diff";
|
|
||||||
inherit (llvm.clang) version;
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
|
||||||
pkgs.installShellFiles
|
|
||||||
python.pkgs.wrapPython
|
|
||||||
];
|
|
||||||
|
|
||||||
dontUnpack = true;
|
|
||||||
dontConfigure = true;
|
|
||||||
dontBuild = true;
|
|
||||||
|
|
||||||
postInstall = "installBin ${llvm.libclang.python}/share/clang/clang-tidy-diff.py";
|
|
||||||
postFixup = "wrapPythonPrograms";
|
|
||||||
})
|
|
||||||
];
|
];
|
||||||
|
|
||||||
cmakeBuildType = "Debug";
|
|
||||||
cmakeFlags = [ "-GNinja" ] ++ packages'.prismlauncher-unwrapped.cmakeFlags;
|
|
||||||
dontFixCmake = true;
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
echo "Sourcing ${qt-wrapper-env}"
|
|
||||||
source ${qt-wrapper-env}
|
|
||||||
|
|
||||||
git submodule update --init --force
|
|
||||||
|
|
||||||
if [ ! -f compile_commands.json ]; then
|
|
||||||
cmakeConfigurePhase
|
|
||||||
cd ..
|
|
||||||
ln -s "$cmakeBuildDir"/compile_commands.json compile_commands.json
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ${lib.escapeShellArg welcomeMessage}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
|
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
|
||||||
|
|
||||||
overlays.default =
|
overlays.default = final: prev: {
|
||||||
final: prev:
|
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
|
||||||
|
inherit
|
||||||
let
|
libnbtplusplus
|
||||||
llvm = final.llvmPackages_22 or prev.llvmPackages_22;
|
nix-filter
|
||||||
in
|
self
|
||||||
|
;
|
||||||
{
|
|
||||||
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
|
|
||||||
inherit (llvm) stdenv;
|
|
||||||
inherit
|
|
||||||
libnbtplusplus
|
|
||||||
self
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
prismlauncher = final.callPackage ./nix/wrapper.nix { };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
prismlauncher = final.callPackage ./nix/wrapper.nix { };
|
||||||
|
};
|
||||||
|
|
||||||
packages = forAllSystems (
|
packages = forAllSystems (
|
||||||
system:
|
system:
|
||||||
|
|
||||||
let
|
let
|
||||||
pkgs = nixpkgsFor.${system};
|
pkgs = nixpkgsFor.${system};
|
||||||
|
|
||||||
|
|
@ -219,7 +111,6 @@
|
||||||
default = prismPackages.prismlauncher;
|
default = prismPackages.prismlauncher;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
|
|
||||||
# Only output them if they're available on the current system
|
# Only output them if they're available on the current system
|
||||||
lib.filterAttrs (_: lib.meta.availableOn pkgs.stdenv.hostPlatform) packages
|
lib.filterAttrs (_: lib.meta.availableOn pkgs.stdenv.hostPlatform) packages
|
||||||
);
|
);
|
||||||
|
|
@ -227,18 +118,16 @@
|
||||||
# We put these under legacyPackages as they are meant for CI, not end user consumption
|
# We put these under legacyPackages as they are meant for CI, not end user consumption
|
||||||
legacyPackages = forAllSystems (
|
legacyPackages = forAllSystems (
|
||||||
system:
|
system:
|
||||||
|
|
||||||
let
|
let
|
||||||
packages' = self.packages.${system};
|
prismPackages = self.packages.${system};
|
||||||
legacyPackages' = self.legacyPackages.${system};
|
legacyPackages = self.legacyPackages.${system};
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
prismlauncher-debug = packages'.prismlauncher.override {
|
prismlauncher-debug = prismPackages.prismlauncher.override {
|
||||||
prismlauncher-unwrapped = legacyPackages'.prismlauncher-unwrapped-debug;
|
prismlauncher-unwrapped = legacyPackages.prismlauncher-unwrapped-debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
prismlauncher-unwrapped-debug = packages'.prismlauncher-unwrapped.overrideAttrs {
|
prismlauncher-unwrapped-debug = prismPackages.prismlauncher-unwrapped.overrideAttrs {
|
||||||
cmakeBuildType = "Debug";
|
cmakeBuildType = "Debug";
|
||||||
dontStrip = true;
|
dontStrip = true;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
20
flatpak/flite.json
Normal file
20
flatpak/flite.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"name": "flite",
|
||||||
|
"config-opts": [
|
||||||
|
"--enable-shared",
|
||||||
|
"--with-audio=pulseaudio"
|
||||||
|
],
|
||||||
|
"no-parallel-make": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/festvox/flite.git",
|
||||||
|
"tag": "v2.2",
|
||||||
|
"commit": "e9e2e37c329dbe98bfeb27a1828ef9a71fa84f88",
|
||||||
|
"x-checker-data": {
|
||||||
|
"type": "git",
|
||||||
|
"tag-pattern": "^v([\\d.]+)$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
18
flatpak/libdecor.json
Normal file
18
flatpak/libdecor.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "libdecor",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [
|
||||||
|
"-Ddemo=false"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
||||||
|
"commit": "c2bd8ad6fa42c0cb17553ce77ad8a87d1f543b1f"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cleanup": [
|
||||||
|
"/include",
|
||||||
|
"/lib/pkgconfig"
|
||||||
|
]
|
||||||
|
}
|
||||||
151
flatpak/org.prismlauncher.PrismLauncher.yml
Normal file
151
flatpak/org.prismlauncher.PrismLauncher.yml
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
id: org.prismlauncher.PrismLauncher
|
||||||
|
runtime: org.kde.Platform
|
||||||
|
runtime-version: '6.8'
|
||||||
|
sdk: org.kde.Sdk
|
||||||
|
sdk-extensions:
|
||||||
|
- org.freedesktop.Sdk.Extension.openjdk17
|
||||||
|
|
||||||
|
command: prismlauncher
|
||||||
|
finish-args:
|
||||||
|
- --share=ipc
|
||||||
|
- --socket=x11
|
||||||
|
- --socket=wayland
|
||||||
|
- --device=all
|
||||||
|
- --share=network
|
||||||
|
- --socket=pulseaudio
|
||||||
|
# for Discord RPC mods
|
||||||
|
- --filesystem=xdg-run/app/com.discordapp.Discord:create
|
||||||
|
# Mod drag&drop
|
||||||
|
- --filesystem=xdg-download:ro
|
||||||
|
# FTBApp import
|
||||||
|
- --filesystem=~/.ftba:ro
|
||||||
|
# Userspace visibility for manual hugepages configuration
|
||||||
|
# Required for -XX:+UseLargePages
|
||||||
|
- --filesystem=/sys/kernel/mm/hugepages:ro
|
||||||
|
# Userspace visibility for transparent hugepages configuration
|
||||||
|
# Required for -XX:+UseTransparentHugePages
|
||||||
|
- --filesystem=/sys/kernel/mm/transparent_hugepage:ro
|
||||||
|
|
||||||
|
modules:
|
||||||
|
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
||||||
|
- shared-modules/libusb/libusb.json
|
||||||
|
|
||||||
|
# Needed for proper Wayland support
|
||||||
|
- libdecor.json
|
||||||
|
|
||||||
|
# Text to Speech in the game
|
||||||
|
- flite.json
|
||||||
|
|
||||||
|
- name: prismlauncher
|
||||||
|
buildsystem: cmake-ninja
|
||||||
|
builddir: true
|
||||||
|
config-opts:
|
||||||
|
- -DLauncher_BUILD_PLATFORM=flatpak
|
||||||
|
# This allows us to manage and update Java independently of this Flatpak
|
||||||
|
- -DLauncher_ENABLE_JAVA_DOWNLOADER=ON
|
||||||
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
|
build-options:
|
||||||
|
env:
|
||||||
|
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
|
||||||
|
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
|
||||||
|
run-tests: true
|
||||||
|
sources:
|
||||||
|
- type: dir
|
||||||
|
path: ../
|
||||||
|
|
||||||
|
- name: glfw
|
||||||
|
buildsystem: cmake-ninja
|
||||||
|
config-opts:
|
||||||
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
|
- -DBUILD_SHARED_LIBS:BOOL=ON
|
||||||
|
- -DGLFW_BUILD_WAYLAND:BOOL=ON
|
||||||
|
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
||||||
|
sources:
|
||||||
|
- type: git
|
||||||
|
url: https://github.com/glfw/glfw.git
|
||||||
|
commit: 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 # 3.4
|
||||||
|
- type: patch
|
||||||
|
path: patches/0009-Defer-setting-cursor-position-until-the-cursor-is-lo.patch
|
||||||
|
cleanup:
|
||||||
|
- /include
|
||||||
|
- /lib/cmake
|
||||||
|
- /lib/pkgconfig
|
||||||
|
|
||||||
|
- name: xrandr
|
||||||
|
buildsystem: autotools
|
||||||
|
sources:
|
||||||
|
- type: archive
|
||||||
|
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.3.tar.xz
|
||||||
|
sha256: f8dd7566adb74147fab9964680b6bbadee87cf406a7fcff51718a5e6949b841c
|
||||||
|
x-checker-data:
|
||||||
|
type: anitya
|
||||||
|
project-id: 14957
|
||||||
|
stable-only: true
|
||||||
|
url-template: https://xorg.freedesktop.org/archive/individual/app/xrandr-$version.tar.xz
|
||||||
|
cleanup:
|
||||||
|
- /share/man
|
||||||
|
- /bin/xkeystone
|
||||||
|
|
||||||
|
- name: gamemode
|
||||||
|
buildsystem: meson
|
||||||
|
config-opts:
|
||||||
|
- -Dwith-sd-bus-provider=no-daemon
|
||||||
|
- -Dwith-examples=false
|
||||||
|
post-install:
|
||||||
|
# gamemoderun is installed for users who want to use wrapper commands
|
||||||
|
# post-install is running inside the build dir, we need it from the source though
|
||||||
|
- install -Dm755 ../data/gamemoderun -t /app/bin
|
||||||
|
sources:
|
||||||
|
- type: archive
|
||||||
|
dest-filename: gamemode.tar.gz
|
||||||
|
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.2
|
||||||
|
sha256: 2886d4ce543c78bd2a364316d5e7fd59ef06b71de63f896b37c6d3dc97658f60
|
||||||
|
x-checker-data:
|
||||||
|
type: json
|
||||||
|
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
||||||
|
version-query: .tag_name
|
||||||
|
url-query: .tarball_url
|
||||||
|
timestamp-query: .published_at
|
||||||
|
cleanup:
|
||||||
|
- /include
|
||||||
|
- /lib/pkgconfig
|
||||||
|
- /lib/libgamemodeauto.a
|
||||||
|
|
||||||
|
- name: glxinfo
|
||||||
|
buildsystem: meson
|
||||||
|
config-opts:
|
||||||
|
- --bindir=/app/mesa-demos
|
||||||
|
- -Degl=disabled
|
||||||
|
- -Dglut=disabled
|
||||||
|
- -Dosmesa=disabled
|
||||||
|
- -Dvulkan=disabled
|
||||||
|
- -Dwayland=disabled
|
||||||
|
post-install:
|
||||||
|
- mv -v /app/mesa-demos/glxinfo /app/bin
|
||||||
|
sources:
|
||||||
|
- type: archive
|
||||||
|
url: https://archive.mesa3d.org/demos/mesa-demos-9.0.0.tar.xz
|
||||||
|
sha256: 3046a3d26a7b051af7ebdd257a5f23bfeb160cad6ed952329cdff1e9f1ed496b
|
||||||
|
x-checker-data:
|
||||||
|
type: anitya
|
||||||
|
project-id: 16781
|
||||||
|
stable-only: true
|
||||||
|
url-template: https://archive.mesa3d.org/demos/mesa-demos-$version.tar.xz
|
||||||
|
cleanup:
|
||||||
|
- /include
|
||||||
|
- /mesa-demos
|
||||||
|
- /share
|
||||||
|
modules:
|
||||||
|
- shared-modules/glu/glu-9.json
|
||||||
|
|
||||||
|
- name: enhance
|
||||||
|
buildsystem: simple
|
||||||
|
build-commands:
|
||||||
|
- install -Dm755 prime-run /app/bin/prime-run
|
||||||
|
- mv /app/bin/prismlauncher /app/bin/prismrun
|
||||||
|
- install -Dm755 prismlauncher /app/bin/prismlauncher
|
||||||
|
sources:
|
||||||
|
- type: file
|
||||||
|
path: prime-run
|
||||||
|
- type: file
|
||||||
|
path: prismlauncher
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
From 9997ae55a47de469ea26f8437c30b51483abda5f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Dan Klishch <danilklishch@gmail.com>
|
||||||
|
Date: Sat, 30 Sep 2023 23:38:05 -0400
|
||||||
|
Subject: Defer setting cursor position until the cursor is locked
|
||||||
|
|
||||||
|
---
|
||||||
|
src/wl_platform.h | 3 +++
|
||||||
|
src/wl_window.c | 14 ++++++++++++--
|
||||||
|
2 files changed, 15 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/wl_platform.h b/src/wl_platform.h
|
||||||
|
index ca34f66e..cd1f227f 100644
|
||||||
|
--- a/src/wl_platform.h
|
||||||
|
+++ b/src/wl_platform.h
|
||||||
|
@@ -403,6 +403,9 @@ typedef struct _GLFWwindowWayland
|
||||||
|
int scaleSize;
|
||||||
|
int compositorPreferredScale;
|
||||||
|
|
||||||
|
+ double askedCursorPosX, askedCursorPosY;
|
||||||
|
+ GLFWbool didAskForSetCursorPos;
|
||||||
|
+
|
||||||
|
struct zwp_relative_pointer_v1* relativePointer;
|
||||||
|
struct zwp_locked_pointer_v1* lockedPointer;
|
||||||
|
struct zwp_confined_pointer_v1* confinedPointer;
|
||||||
|
diff --git a/src/wl_window.c b/src/wl_window.c
|
||||||
|
index 1de26558..0df16747 100644
|
||||||
|
--- a/src/wl_window.c
|
||||||
|
+++ b/src/wl_window.c
|
||||||
|
@@ -2586,8 +2586,9 @@ void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
|
||||||
|
|
||||||
|
void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
|
||||||
|
{
|
||||||
|
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
|
- "Wayland: The platform does not support setting the cursor position");
|
||||||
|
+ window->wl.didAskForSetCursorPos = true;
|
||||||
|
+ window->wl.askedCursorPosX = x;
|
||||||
|
+ window->wl.askedCursorPosY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
|
||||||
|
@@ -2819,6 +2820,15 @@ static const struct zwp_relative_pointer_v1_listener relativePointerListener =
|
||||||
|
static void lockedPointerHandleLocked(void* userData,
|
||||||
|
struct zwp_locked_pointer_v1* lockedPointer)
|
||||||
|
{
|
||||||
|
+ _GLFWwindow* window = userData;
|
||||||
|
+
|
||||||
|
+ if (window->wl.didAskForSetCursorPos)
|
||||||
|
+ {
|
||||||
|
+ window->wl.didAskForSetCursorPos = false;
|
||||||
|
+ zwp_locked_pointer_v1_set_cursor_position_hint(window->wl.lockedPointer,
|
||||||
|
+ wl_fixed_from_double(window->wl.askedCursorPosX),
|
||||||
|
+ wl_fixed_from_double(window->wl.askedCursorPosY));
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lockedPointerHandleUnlocked(void* userData,
|
||||||
|
--
|
||||||
|
2.42.0
|
||||||
|
|
||||||
4
flatpak/prime-run
Normal file
4
flatpak/prime-run
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __GLX_VENDOR_LIBRARY_NAME=nvidia
|
||||||
|
exec "$@"
|
||||||
11
flatpak/prismlauncher
Normal file
11
flatpak/prismlauncher
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# discord RPC
|
||||||
|
for i in {0..9}; do
|
||||||
|
test -S "$XDG_RUNTIME_DIR"/discord-ipc-"$i" || ln -sf {app/com.discordapp.Discord,"$XDG_RUNTIME_DIR"}/discord-ipc-"$i";
|
||||||
|
done
|
||||||
|
|
||||||
|
export PATH="${PATH}${PATH:+:}/usr/lib/extensions/vulkan/gamescope/bin:/usr/lib/extensions/vulkan/MangoHud/bin"
|
||||||
|
export VK_LAYER_PATH="/usr/lib/extensions/vulkan/share/vulkan/implicit_layer.d/"
|
||||||
|
|
||||||
|
exec /app/bin/prismrun "$@"
|
||||||
1
flatpak/shared-modules
Submodule
1
flatpak/shared-modules
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit f2b0c16a2a217a1822ce5a6538ba8f755ed1dd32
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -37,8 +37,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
@ -46,16 +44,16 @@
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "QObjectPtr.h"
|
#include <BaseInstance.h>
|
||||||
|
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class LaunchController;
|
class LaunchController;
|
||||||
class LocalPeer;
|
class LocalPeer;
|
||||||
class InstanceWindow;
|
class InstanceWindow;
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class ViewLogWindow;
|
|
||||||
class SetupWizard;
|
class SetupWizard;
|
||||||
class GenericPageProvider;
|
class GenericPageProvider;
|
||||||
class QFile;
|
class QFile;
|
||||||
|
|
@ -74,12 +72,6 @@ class ITheme;
|
||||||
class MCEditTool;
|
class MCEditTool;
|
||||||
class ThemeManager;
|
class ThemeManager;
|
||||||
class IconTheme;
|
class IconTheme;
|
||||||
class BaseInstance;
|
|
||||||
|
|
||||||
class LogModel;
|
|
||||||
|
|
||||||
struct MinecraftTarget;
|
|
||||||
class MinecraftAccount;
|
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
class Index;
|
class Index;
|
||||||
|
|
@ -97,6 +89,7 @@ class Index;
|
||||||
#define APPLICATION_DYN (dynamic_cast<Application*>(QCoreApplication::instance()))
|
#define APPLICATION_DYN (dynamic_cast<Application*>(QCoreApplication::instance()))
|
||||||
|
|
||||||
class Application : public QApplication {
|
class Application : public QApplication {
|
||||||
|
// friends for the purpose of limiting access to deprecated stuff
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum Status { StartingUp, Failed, Succeeded, Initialized };
|
enum Status { StartingUp, Failed, Succeeded, Initialized };
|
||||||
|
|
@ -117,29 +110,29 @@ class Application : public QApplication {
|
||||||
|
|
||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
|
|
||||||
SettingsObject* settings() const { return m_settings.get(); }
|
std::shared_ptr<SettingsObject> settings() const { return m_settings; }
|
||||||
|
|
||||||
qint64 timeSinceStart() const { return m_startTime.msecsTo(QDateTime::currentDateTime()); }
|
qint64 timeSinceStart() const { return startTime.msecsTo(QDateTime::currentDateTime()); }
|
||||||
|
|
||||||
QIcon logo();
|
QIcon getThemedIcon(const QString& name);
|
||||||
|
|
||||||
ThemeManager* themeManager() { return m_themeManager.get(); }
|
ThemeManager* themeManager() { return m_themeManager.get(); }
|
||||||
|
|
||||||
ExternalUpdater* updater() { return m_updater.get(); }
|
shared_qobject_ptr<ExternalUpdater> updater() { return m_updater; }
|
||||||
|
|
||||||
void triggerUpdateCheck();
|
void triggerUpdateCheck();
|
||||||
|
|
||||||
TranslationsModel* translations();
|
std::shared_ptr<TranslationsModel> translations();
|
||||||
|
|
||||||
JavaInstallList* javalist();
|
std::shared_ptr<JavaInstallList> javalist();
|
||||||
|
|
||||||
InstanceList* instances() const { return m_instances.get(); }
|
std::shared_ptr<InstanceList> instances() const { return m_instances; }
|
||||||
|
|
||||||
IconList* icons() const { return m_icons.get(); }
|
std::shared_ptr<IconList> icons() const { return m_icons; }
|
||||||
|
|
||||||
MCEditTool* mcedit() const { return m_mcedit.get(); }
|
MCEditTool* mcedit() const { return m_mcedit.get(); }
|
||||||
|
|
||||||
AccountList* accounts() const { return m_accounts.get(); }
|
shared_qobject_ptr<AccountList> accounts() const { return m_accounts; }
|
||||||
|
|
||||||
Status status() const { return m_status; }
|
Status status() const { return m_status; }
|
||||||
|
|
||||||
|
|
@ -147,11 +140,11 @@ class Application : public QApplication {
|
||||||
|
|
||||||
void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
|
void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
|
||||||
|
|
||||||
QNetworkAccessManager* network();
|
shared_qobject_ptr<QNetworkAccessManager> network();
|
||||||
|
|
||||||
HttpMetaCache* metacache();
|
shared_qobject_ptr<HttpMetaCache> metacache();
|
||||||
|
|
||||||
Meta::Index* metadataIndex();
|
shared_qobject_ptr<Meta::Index> metadataIndex();
|
||||||
|
|
||||||
void updateCapabilities();
|
void updateCapabilities();
|
||||||
|
|
||||||
|
|
@ -167,6 +160,7 @@ class Application : public QApplication {
|
||||||
QString getFlameAPIKey();
|
QString getFlameAPIKey();
|
||||||
QString getModrinthAPIToken();
|
QString getModrinthAPIToken();
|
||||||
QString getUserAgent();
|
QString getUserAgent();
|
||||||
|
QString getUserAgentUncached();
|
||||||
|
|
||||||
/// this is the root of the 'installation'. Used for automatic updates
|
/// this is the root of the 'installation'. Used for automatic updates
|
||||||
const QString& root() { return m_rootPath; }
|
const QString& root() { return m_rootPath; }
|
||||||
|
|
@ -187,9 +181,8 @@ class Application : public QApplication {
|
||||||
*/
|
*/
|
||||||
bool openJsonEditor(const QString& filename);
|
bool openJsonEditor(const QString& filename);
|
||||||
|
|
||||||
InstanceWindow* showInstanceWindow(BaseInstance* instance, QString page = QString());
|
InstanceWindow* showInstanceWindow(InstancePtr instance, QString page = QString());
|
||||||
MainWindow* showMainWindow(bool minimized = false);
|
MainWindow* showMainWindow(bool minimized = false);
|
||||||
ViewLogWindow* showLogWindow();
|
|
||||||
|
|
||||||
void updateIsRunning(bool running);
|
void updateIsRunning(bool running);
|
||||||
bool updatesAreAllowed();
|
bool updatesAreAllowed();
|
||||||
|
|
@ -199,12 +192,12 @@ class Application : public QApplication {
|
||||||
bool updaterEnabled();
|
bool updaterEnabled();
|
||||||
QString updaterBinaryName();
|
QString updaterBinaryName();
|
||||||
|
|
||||||
QUrl normalizeImportUrl(const QString& url);
|
QUrl normalizeImportUrl(QString const& url);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateAllowedChanged(bool status);
|
void updateAllowedChanged(bool status);
|
||||||
void globalSettingsAboutToOpen();
|
void globalSettingsAboutToOpen();
|
||||||
void globalSettingsApplied();
|
void globalSettingsClosed();
|
||||||
int currentCatChanged(int index);
|
int currentCatChanged(int index);
|
||||||
|
|
||||||
void oauthReplyRecieved(QVariantMap);
|
void oauthReplyRecieved(QVariantMap);
|
||||||
|
|
@ -214,18 +207,19 @@ class Application : public QApplication {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool launch(BaseInstance* instance,
|
bool launch(InstancePtr instance,
|
||||||
LaunchMode mode = LaunchMode::Normal,
|
bool online = true,
|
||||||
std::shared_ptr<MinecraftTarget> targetToJoin = nullptr,
|
bool demo = false,
|
||||||
shared_qobject_ptr<MinecraftAccount> accountToUse = nullptr,
|
MinecraftTarget::Ptr targetToJoin = nullptr,
|
||||||
const QString& offlineName = QString());
|
MinecraftAccountPtr accountToUse = nullptr);
|
||||||
bool kill(BaseInstance* instance);
|
bool kill(InstancePtr instance);
|
||||||
void closeCurrentWindow();
|
void closeCurrentWindow();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_windowClose();
|
void on_windowClose();
|
||||||
void messageReceived(const QByteArray& message);
|
void messageReceived(const QByteArray& message);
|
||||||
void controllerFinished();
|
void controllerSucceeded();
|
||||||
|
void controllerFailed(const QString& error);
|
||||||
void setupWizardFinished(int status);
|
void setupWizardFinished(int status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -242,26 +236,22 @@ class Application : public QApplication {
|
||||||
bool shouldExitNow() const;
|
bool shouldExitNow() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QString, int> m_qsaveResources;
|
QDateTime startTime;
|
||||||
mutable QMutex m_qsaveResourcesMutex;
|
|
||||||
|
|
||||||
private:
|
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
||||||
QDateTime m_startTime;
|
|
||||||
|
|
||||||
std::unique_ptr<QNetworkAccessManager> m_network;
|
shared_qobject_ptr<ExternalUpdater> m_updater;
|
||||||
|
shared_qobject_ptr<AccountList> m_accounts;
|
||||||
|
|
||||||
std::unique_ptr<ExternalUpdater> m_updater;
|
shared_qobject_ptr<HttpMetaCache> m_metacache;
|
||||||
std::unique_ptr<AccountList> m_accounts;
|
shared_qobject_ptr<Meta::Index> m_metadataIndex;
|
||||||
|
|
||||||
std::unique_ptr<HttpMetaCache> m_metacache;
|
std::shared_ptr<SettingsObject> m_settings;
|
||||||
std::unique_ptr<Meta::Index> m_metadataIndex;
|
std::shared_ptr<InstanceList> m_instances;
|
||||||
|
std::shared_ptr<IconList> m_icons;
|
||||||
std::unique_ptr<SettingsObject> m_settings;
|
std::shared_ptr<JavaInstallList> m_javalist;
|
||||||
std::unique_ptr<InstanceList> m_instances;
|
std::shared_ptr<TranslationsModel> m_translations;
|
||||||
std::unique_ptr<IconList> m_icons;
|
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
||||||
std::unique_ptr<JavaInstallList> m_javalist;
|
|
||||||
std::unique_ptr<TranslationsModel> m_translations;
|
|
||||||
std::unique_ptr<GenericPageProvider> m_globalSettingsProvider;
|
|
||||||
std::unique_ptr<MCEditTool> m_mcedit;
|
std::unique_ptr<MCEditTool> m_mcedit;
|
||||||
QSet<QString> m_features;
|
QSet<QString> m_features;
|
||||||
std::unique_ptr<ThemeManager> m_themeManager;
|
std::unique_ptr<ThemeManager> m_themeManager;
|
||||||
|
|
@ -278,10 +268,15 @@ class Application : public QApplication {
|
||||||
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
|
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
// used on Windows to attach the standard IO streams
|
||||||
|
bool consoleAttached = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME: attach to instances instead.
|
// FIXME: attach to instances instead.
|
||||||
struct InstanceXtras {
|
struct InstanceXtras {
|
||||||
InstanceWindow* window = nullptr;
|
InstanceWindow* window = nullptr;
|
||||||
std::unique_ptr<LaunchController> controller;
|
shared_qobject_ptr<LaunchController> controller;
|
||||||
};
|
};
|
||||||
std::map<QString, InstanceXtras> m_instanceExtras;
|
std::map<QString, InstanceXtras> m_instanceExtras;
|
||||||
mutable QMutex m_instanceExtrasMutex;
|
mutable QMutex m_instanceExtrasMutex;
|
||||||
|
|
@ -294,9 +289,6 @@ class Application : public QApplication {
|
||||||
// main window, if any
|
// main window, if any
|
||||||
MainWindow* m_mainWindow = nullptr;
|
MainWindow* m_mainWindow = nullptr;
|
||||||
|
|
||||||
// log window, if any
|
|
||||||
ViewLogWindow* m_viewLogWindow = nullptr;
|
|
||||||
|
|
||||||
// peer launcher instance connector - used to implement single instance launcher and signalling
|
// peer launcher instance connector - used to implement single instance launcher and signalling
|
||||||
LocalPeer* m_peerInstance = nullptr;
|
LocalPeer* m_peerInstance = nullptr;
|
||||||
|
|
||||||
|
|
@ -309,17 +301,17 @@ class Application : public QApplication {
|
||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
QString m_worldToJoin;
|
QString m_worldToJoin;
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_launchOffline = false;
|
|
||||||
QString m_offlineName;
|
|
||||||
bool m_liveCheck = false;
|
bool m_liveCheck = false;
|
||||||
QList<QUrl> m_urlsToImport;
|
QList<QUrl> m_urlsToImport;
|
||||||
QString m_instanceIdToShowWindowOf;
|
QString m_instanceIdToShowWindowOf;
|
||||||
bool m_showMainWindow = false;
|
|
||||||
std::unique_ptr<QFile> logFile;
|
std::unique_ptr<QFile> logFile;
|
||||||
std::unique_ptr<LogModel> logModel;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void addQSavePath(QString);
|
void addQSavePath(QString);
|
||||||
void removeQSavePath(QString);
|
void removeQSavePath(QString);
|
||||||
bool checkQSavePath(QString);
|
bool checkQSavePath(QString);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, int> m_qsaveResources;
|
||||||
|
mutable QMutex m_qsaveResourcesMutex;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - Minecraft Launcher
|
|
||||||
* Copyright (C) 2025 Octol1ttle <l1ttleofficial@outlook.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(ASSERT_NEVER)
|
|
||||||
#error ASSERT_NEVER already defined
|
|
||||||
#else
|
|
||||||
#define ASSERT_NEVER(cond) (Q_ASSERT((cond) == false), (cond))
|
|
||||||
#endif
|
|
||||||
|
|
@ -42,10 +42,8 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "Json.h"
|
|
||||||
#include "launch/LaunchTask.h"
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "settings/OverrideSetting.h"
|
#include "settings/OverrideSetting.h"
|
||||||
#include "settings/Setting.h"
|
#include "settings/Setting.h"
|
||||||
|
|
@ -54,26 +52,9 @@
|
||||||
#include "Commandline.h"
|
#include "Commandline.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
int getConsoleMaxLines(SettingsObject* settings)
|
BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : QObject()
|
||||||
{
|
{
|
||||||
auto lineSetting = settings->getSetting("ConsoleMaxLines");
|
m_settings = settings;
|
||||||
bool conversionOk = false;
|
|
||||||
int maxLines = lineSetting->get().toInt(&conversionOk);
|
|
||||||
if (!conversionOk) {
|
|
||||||
maxLines = lineSetting->defValue().toInt();
|
|
||||||
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
|
|
||||||
}
|
|
||||||
return maxLines;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shouldStopOnConsoleOverflow(SettingsObject* settings)
|
|
||||||
{
|
|
||||||
return settings->get("ConsoleOverflowStop").toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseInstance::BaseInstance(SettingsObject* globalSettings, std::unique_ptr<SettingsObject> settings, const QString& rootDir) : QObject()
|
|
||||||
{
|
|
||||||
m_settings = std::move(settings);
|
|
||||||
m_global_settings = globalSettings;
|
m_global_settings = globalSettings;
|
||||||
m_rootDir = rootDir;
|
m_rootDir = rootDir;
|
||||||
|
|
||||||
|
|
@ -88,7 +69,6 @@ BaseInstance::BaseInstance(SettingsObject* globalSettings, std::unique_ptr<Setti
|
||||||
m_settings->registerSetting("lastTimePlayed", 0);
|
m_settings->registerSetting("lastTimePlayed", 0);
|
||||||
|
|
||||||
m_settings->registerSetting("linkedInstances", "[]");
|
m_settings->registerSetting("linkedInstances", "[]");
|
||||||
m_settings->registerSetting("shortcuts", QString());
|
|
||||||
|
|
||||||
// Game time override
|
// Game time override
|
||||||
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
|
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
|
||||||
|
|
@ -123,13 +103,10 @@ BaseInstance::BaseInstance(SettingsObject* globalSettings, std::unique_ptr<Setti
|
||||||
m_settings->registerSetting("ManagedPackName", "");
|
m_settings->registerSetting("ManagedPackName", "");
|
||||||
m_settings->registerSetting("ManagedPackVersionID", "");
|
m_settings->registerSetting("ManagedPackVersionID", "");
|
||||||
m_settings->registerSetting("ManagedPackVersionName", "");
|
m_settings->registerSetting("ManagedPackVersionName", "");
|
||||||
m_settings->registerSetting("ManagedPackURL", "");
|
|
||||||
|
|
||||||
m_settings->registerSetting("Profiler", "");
|
m_settings->registerSetting("Profiler", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseInstance::~BaseInstance() {}
|
|
||||||
|
|
||||||
QString BaseInstance::getPreLaunchCommand()
|
QString BaseInstance::getPreLaunchCommand()
|
||||||
{
|
{
|
||||||
return settings()->get("PreLaunchCommand").toString();
|
return settings()->get("PreLaunchCommand").toString();
|
||||||
|
|
@ -197,35 +174,46 @@ void BaseInstance::copyManagedPack(BaseInstance& other)
|
||||||
m_settings->set("ManagedPackName", other.getManagedPackName());
|
m_settings->set("ManagedPackName", other.getManagedPackName());
|
||||||
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
|
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
|
||||||
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
|
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
|
||||||
|
}
|
||||||
|
|
||||||
if (APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() && m_settings->get("AutomaticJava").toBool() &&
|
int BaseInstance::getConsoleMaxLines() const
|
||||||
m_settings->get("OverrideJavaLocation").toBool()) {
|
{
|
||||||
m_settings->set("OverrideJavaLocation", false);
|
auto lineSetting = m_settings->getSetting("ConsoleMaxLines");
|
||||||
m_settings->set("JavaPath", "");
|
bool conversionOk = false;
|
||||||
|
int maxLines = lineSetting->get().toInt(&conversionOk);
|
||||||
|
if (!conversionOk) {
|
||||||
|
maxLines = lineSetting->defValue().toInt();
|
||||||
|
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
|
||||||
}
|
}
|
||||||
|
return maxLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseInstance::shouldStopOnConsoleOverflow() const
|
||||||
|
{
|
||||||
|
return m_settings->get("ConsoleOverflowStop").toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList BaseInstance::getLinkedInstances() const
|
QStringList BaseInstance::getLinkedInstances() const
|
||||||
{
|
{
|
||||||
auto setting = m_settings->get("linkedInstances").toString();
|
return m_settings->get("linkedInstances").toStringList();
|
||||||
return Json::toStringList(setting);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::setLinkedInstances(const QStringList& list)
|
void BaseInstance::setLinkedInstances(const QStringList& list)
|
||||||
{
|
{
|
||||||
m_settings->set("linkedInstances", Json::fromStringList(list));
|
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
|
||||||
|
m_settings->set("linkedInstances", list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::addLinkedInstanceId(const QString& id)
|
void BaseInstance::addLinkedInstanceId(const QString& id)
|
||||||
{
|
{
|
||||||
auto linkedInstances = getLinkedInstances();
|
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
|
||||||
linkedInstances.append(id);
|
linkedInstances.append(id);
|
||||||
setLinkedInstances(linkedInstances);
|
setLinkedInstances(linkedInstances);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::removeLinkedInstanceId(const QString& id)
|
bool BaseInstance::removeLinkedInstanceId(const QString& id)
|
||||||
{
|
{
|
||||||
auto linkedInstances = getLinkedInstances();
|
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
|
||||||
int numRemoved = linkedInstances.removeAll(id);
|
int numRemoved = linkedInstances.removeAll(id);
|
||||||
setLinkedInstances(linkedInstances);
|
setLinkedInstances(linkedInstances);
|
||||||
return numRemoved > 0;
|
return numRemoved > 0;
|
||||||
|
|
@ -233,7 +221,7 @@ bool BaseInstance::removeLinkedInstanceId(const QString& id)
|
||||||
|
|
||||||
bool BaseInstance::isLinkedToInstanceId(const QString& id) const
|
bool BaseInstance::isLinkedToInstanceId(const QString& id) const
|
||||||
{
|
{
|
||||||
auto linkedInstances = getLinkedInstances();
|
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
|
||||||
return linkedInstances.contains(id);
|
return linkedInstances.contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -339,11 +327,11 @@ QString BaseInstance::instanceRoot() const
|
||||||
return m_rootDir;
|
return m_rootDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsObject* BaseInstance::settings()
|
SettingsObjectPtr BaseInstance::settings()
|
||||||
{
|
{
|
||||||
loadSpecificSettings();
|
loadSpecificSettings();
|
||||||
|
|
||||||
return m_settings.get();
|
return m_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::canLaunch() const
|
bool BaseInstance::canLaunch() const
|
||||||
|
|
@ -398,63 +386,6 @@ void BaseInstance::setName(QString val)
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::syncInstanceDirName(const QString& newRoot) const
|
|
||||||
{
|
|
||||||
auto oldRoot = instanceRoot();
|
|
||||||
return oldRoot == newRoot || QFile::rename(oldRoot, newRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseInstance::registerShortcut(const ShortcutData& data)
|
|
||||||
{
|
|
||||||
auto currentShortcuts = shortcuts();
|
|
||||||
currentShortcuts.append(data);
|
|
||||||
qDebug() << "Registering shortcut for instance" << id() << "with name" << data.name << "and path" << data.filePath;
|
|
||||||
setShortcuts(currentShortcuts);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseInstance::setShortcuts(const QList<ShortcutData>& shortcuts)
|
|
||||||
{
|
|
||||||
// FIXME: if no change, do not set. setting involves saving a file.
|
|
||||||
QJsonArray array;
|
|
||||||
for (const auto& elem : shortcuts) {
|
|
||||||
array.append(QJsonObject{ { "name", elem.name }, { "filePath", elem.filePath }, { "target", static_cast<int>(elem.target) } });
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonDocument document;
|
|
||||||
document.setArray(array);
|
|
||||||
m_settings->set("shortcuts", QString::fromUtf8(document.toJson(QJsonDocument::Compact)));
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<ShortcutData> BaseInstance::shortcuts() const
|
|
||||||
{
|
|
||||||
auto data = m_settings->get("shortcuts").toString().toUtf8();
|
|
||||||
QJsonParseError parseError;
|
|
||||||
auto document = QJsonDocument::fromJson(data, &parseError);
|
|
||||||
if (parseError.error != QJsonParseError::NoError || !document.isArray())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
QList<ShortcutData> results;
|
|
||||||
for (const auto& elem : document.array()) {
|
|
||||||
if (!elem.isObject())
|
|
||||||
continue;
|
|
||||||
auto dict = elem.toObject();
|
|
||||||
if (!dict.contains("name") || !dict.contains("filePath") || !dict.contains("target"))
|
|
||||||
continue;
|
|
||||||
int value = dict["target"].toInt(-1);
|
|
||||||
if (!dict["name"].isString() || !dict["filePath"].isString() || value < 0 || value >= 3)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QString shortcutName = dict["name"].toString();
|
|
||||||
QString filePath = dict["filePath"].toString();
|
|
||||||
if (!QDir(filePath).exists()) {
|
|
||||||
qWarning() << "Shortcut" << shortcutName << "for instance" << name() << "have non-existent path" << filePath;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
results.append({ shortcutName, filePath, static_cast<ShortcutTarget>(value) });
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BaseInstance::name() const
|
QString BaseInstance::name() const
|
||||||
{
|
{
|
||||||
return m_settings->get("name").toString();
|
return m_settings->get("name").toString();
|
||||||
|
|
@ -471,17 +402,12 @@ QStringList BaseInstance::extraArguments()
|
||||||
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
|
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchTask* BaseInstance::getLaunchTask()
|
shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
|
||||||
{
|
{
|
||||||
return m_launchProcess.get();
|
return m_launchProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::updateRuntimeContext()
|
void BaseInstance::updateRuntimeContext()
|
||||||
{
|
{
|
||||||
// NOOP
|
// NOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::isLegacy()
|
|
||||||
{
|
|
||||||
return traits().contains("legacyLaunch") || traits().contains("alphaLaunch");
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QList>
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
@ -52,6 +50,7 @@
|
||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
|
#include "pathmatcher/IPathMatcher.h"
|
||||||
#include "settings/INIFile.h"
|
#include "settings/INIFile.h"
|
||||||
|
|
||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
@ -64,19 +63,8 @@ class Task;
|
||||||
class LaunchTask;
|
class LaunchTask;
|
||||||
class BaseInstance;
|
class BaseInstance;
|
||||||
|
|
||||||
/// Shortcut saving target representations
|
// pointer for lazy people
|
||||||
enum class ShortcutTarget { Desktop, Applications, Other };
|
using InstancePtr = std::shared_ptr<BaseInstance>;
|
||||||
|
|
||||||
/// Shortcut data representation
|
|
||||||
struct ShortcutData {
|
|
||||||
QString name;
|
|
||||||
QString filePath;
|
|
||||||
ShortcutTarget target = ShortcutTarget::Other;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Console settings
|
|
||||||
int getConsoleMaxLines(SettingsObject* settings);
|
|
||||||
bool shouldStopOnConsoleOverflow(SettingsObject* settings);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Base class for instances.
|
* \brief Base class for instances.
|
||||||
|
|
@ -86,11 +74,11 @@ bool shouldStopOnConsoleOverflow(SettingsObject* settings);
|
||||||
* To create a new instance type, create a new class inheriting from this class
|
* To create a new instance type, create a new class inheriting from this class
|
||||||
* and implement the pure virtual functions.
|
* and implement the pure virtual functions.
|
||||||
*/
|
*/
|
||||||
class BaseInstance : public QObject {
|
class BaseInstance : public QObject, public std::enable_shared_from_this<BaseInstance> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
protected:
|
protected:
|
||||||
/// no-touchy!
|
/// no-touchy!
|
||||||
BaseInstance(SettingsObject* globalSettings, std::unique_ptr<SettingsObject> settings, const QString& rootDir);
|
BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir);
|
||||||
|
|
||||||
public: /* types */
|
public: /* types */
|
||||||
enum class Status {
|
enum class Status {
|
||||||
|
|
@ -100,7 +88,7 @@ class BaseInstance : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// virtual destructor to make sure the destruction is COMPLETE
|
/// virtual destructor to make sure the destruction is COMPLETE
|
||||||
virtual ~BaseInstance();
|
virtual ~BaseInstance() {}
|
||||||
|
|
||||||
virtual void saveNow() = 0;
|
virtual void saveNow() = 0;
|
||||||
|
|
||||||
|
|
@ -138,14 +126,6 @@ class BaseInstance : public QObject {
|
||||||
QString name() const;
|
QString name() const;
|
||||||
void setName(QString val);
|
void setName(QString val);
|
||||||
|
|
||||||
/// Sync name and rename instance dir accordingly; returns true if successful
|
|
||||||
bool syncInstanceDirName(const QString& newRoot) const;
|
|
||||||
|
|
||||||
/// Register a created shortcut
|
|
||||||
void registerShortcut(const ShortcutData& data);
|
|
||||||
QList<ShortcutData> shortcuts() const;
|
|
||||||
void setShortcuts(const QList<ShortcutData>& shortcuts);
|
|
||||||
|
|
||||||
/// Value used for instance window titles
|
/// Value used for instance window titles
|
||||||
QString windowTitle() const;
|
QString windowTitle() const;
|
||||||
|
|
||||||
|
|
@ -168,6 +148,9 @@ class BaseInstance : public QObject {
|
||||||
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
|
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
|
||||||
void copyManagedPack(BaseInstance& other);
|
void copyManagedPack(BaseInstance& other);
|
||||||
|
|
||||||
|
/// guess log level from a line of game log
|
||||||
|
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; }
|
||||||
|
|
||||||
virtual QStringList extraArguments();
|
virtual QStringList extraArguments();
|
||||||
|
|
||||||
/// Traits. Normally inside the version, depends on instance implementation.
|
/// Traits. Normally inside the version, depends on instance implementation.
|
||||||
|
|
@ -190,7 +173,7 @@ class BaseInstance : public QObject {
|
||||||
*
|
*
|
||||||
* \return A pointer to this instance's settings object.
|
* \return A pointer to this instance's settings object.
|
||||||
*/
|
*/
|
||||||
virtual SettingsObject* settings();
|
virtual SettingsObjectPtr settings();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Loads settings specific to an instance type if they're not already loaded.
|
* \brief Loads settings specific to an instance type if they're not already loaded.
|
||||||
|
|
@ -201,10 +184,10 @@ class BaseInstance : public QObject {
|
||||||
virtual QList<Task::Ptr> createUpdateTask() = 0;
|
virtual QList<Task::Ptr> createUpdateTask() = 0;
|
||||||
|
|
||||||
/// returns a valid launcher (task container)
|
/// returns a valid launcher (task container)
|
||||||
virtual LaunchTask* createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
|
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
|
||||||
|
|
||||||
/// returns the current launch task (if any)
|
/// returns the current launch task (if any)
|
||||||
LaunchTask* getLaunchTask();
|
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Create envrironment variables for running the instance
|
* Create envrironment variables for running the instance
|
||||||
|
|
@ -212,10 +195,15 @@ class BaseInstance : public QObject {
|
||||||
virtual QProcessEnvironment createEnvironment() = 0;
|
virtual QProcessEnvironment createEnvironment() = 0;
|
||||||
virtual QProcessEnvironment createLaunchEnvironment() = 0;
|
virtual QProcessEnvironment createLaunchEnvironment() = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
|
||||||
|
*/
|
||||||
|
virtual IPathMatcher::Ptr getLogFileMatcher() = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the root folder to use for looking up log files
|
* Returns the root folder to use for looking up log files
|
||||||
*/
|
*/
|
||||||
virtual QStringList getLogFileSearchPaths() = 0;
|
virtual QString getLogFileRoot() = 0;
|
||||||
|
|
||||||
virtual QString getStatusbarDescription() = 0;
|
virtual QString getStatusbarDescription() = 0;
|
||||||
|
|
||||||
|
|
@ -272,18 +260,19 @@ class BaseInstance : public QObject {
|
||||||
|
|
||||||
Status currentStatus() const;
|
Status currentStatus() const;
|
||||||
|
|
||||||
|
int getConsoleMaxLines() const;
|
||||||
|
bool shouldStopOnConsoleOverflow() const;
|
||||||
|
|
||||||
QStringList getLinkedInstances() const;
|
QStringList getLinkedInstances() const;
|
||||||
void setLinkedInstances(const QStringList& list);
|
void setLinkedInstances(const QStringList& list);
|
||||||
void addLinkedInstanceId(const QString& id);
|
void addLinkedInstanceId(const QString& id);
|
||||||
bool removeLinkedInstanceId(const QString& id);
|
bool removeLinkedInstanceId(const QString& id);
|
||||||
bool isLinkedToInstanceId(const QString& id) const;
|
bool isLinkedToInstanceId(const QString& id) const;
|
||||||
|
|
||||||
bool isLegacy();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void changeStatus(Status newStatus);
|
void changeStatus(Status newStatus);
|
||||||
|
|
||||||
SettingsObject* globalSettings() const { return m_global_settings; }
|
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); }
|
||||||
|
|
||||||
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
||||||
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
||||||
|
|
@ -294,7 +283,7 @@ class BaseInstance : public QObject {
|
||||||
*/
|
*/
|
||||||
void propertiesChanged(BaseInstance* inst);
|
void propertiesChanged(BaseInstance* inst);
|
||||||
|
|
||||||
void launchTaskChanged(LaunchTask*);
|
void launchTaskChanged(shared_qobject_ptr<LaunchTask>);
|
||||||
|
|
||||||
void runningStatusChanged(bool running);
|
void runningStatusChanged(bool running);
|
||||||
|
|
||||||
|
|
@ -307,10 +296,10 @@ class BaseInstance : public QObject {
|
||||||
|
|
||||||
protected: /* data */
|
protected: /* data */
|
||||||
QString m_rootDir;
|
QString m_rootDir;
|
||||||
std::unique_ptr<SettingsObject> m_settings;
|
SettingsObjectPtr m_settings;
|
||||||
// InstanceFlags m_flags;
|
// InstanceFlags m_flags;
|
||||||
bool m_isRunning = false;
|
bool m_isRunning = false;
|
||||||
std::unique_ptr<LaunchTask> m_launchProcess;
|
shared_qobject_ptr<LaunchTask> m_launchProcess;
|
||||||
QDateTime m_timeStarted;
|
QDateTime m_timeStarted;
|
||||||
RuntimeContext m_runtimeContext;
|
RuntimeContext m_runtimeContext;
|
||||||
|
|
||||||
|
|
@ -320,7 +309,7 @@ class BaseInstance : public QObject {
|
||||||
bool m_hasUpdate = false;
|
bool m_hasUpdate = false;
|
||||||
bool m_hasBrokenVersion = false;
|
bool m_hasBrokenVersion = false;
|
||||||
|
|
||||||
SettingsObject* m_global_settings;
|
SettingsObjectWeakPtr m_global_settings;
|
||||||
bool m_specific_settings_loaded = false;
|
bool m_specific_settings_loaded = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,28 +24,27 @@
|
||||||
*/
|
*/
|
||||||
class BaseVersion {
|
class BaseVersion {
|
||||||
public:
|
public:
|
||||||
// TODO: delete
|
|
||||||
using Ptr = std::shared_ptr<BaseVersion>;
|
using Ptr = std::shared_ptr<BaseVersion>;
|
||||||
virtual ~BaseVersion() {}
|
virtual ~BaseVersion() {}
|
||||||
/*!
|
/*!
|
||||||
* A string used to identify this version in config files.
|
* A string used to identify this version in config files.
|
||||||
* This should be unique within the version list or shenanigans will occur.
|
* This should be unique within the version list or shenanigans will occur.
|
||||||
*/
|
*/
|
||||||
virtual QString descriptor() const = 0;
|
virtual QString descriptor() = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* The name of this version as it is displayed to the user.
|
* The name of this version as it is displayed to the user.
|
||||||
* For example: "1.5.1"
|
* For example: "1.5.1"
|
||||||
*/
|
*/
|
||||||
virtual QString name() const = 0;
|
virtual QString name() = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* This should return a string that describes
|
* This should return a string that describes
|
||||||
* the kind of version this is (Stable, Beta, Snapshot, whatever)
|
* the kind of version this is (Stable, Beta, Snapshot, whatever)
|
||||||
*/
|
*/
|
||||||
virtual QString typeString() const = 0;
|
virtual QString typeString() const = 0;
|
||||||
virtual bool operator<(BaseVersion& a) const { return name() < a.name(); }
|
virtual bool operator<(BaseVersion& a) { return name() < a.name(); }
|
||||||
virtual bool operator>(BaseVersion& a) const { return name() > a.name(); }
|
virtual bool operator>(BaseVersion& a) { return name() > a.name(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(BaseVersion::Ptr)
|
Q_DECLARE_METATYPE(BaseVersion::Ptr)
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class BaseVersionList : public QAbstractListModel {
|
||||||
* The task returned by this function should reset the model when it's done.
|
* The task returned by this function should reset the model when it's done.
|
||||||
* \return A pointer to a task that reloads the version list.
|
* \return A pointer to a task that reloads the version list.
|
||||||
*/
|
*/
|
||||||
virtual Task::Ptr getLoadTask(bool forceReload = false) = 0;
|
virtual Task::Ptr getLoadTask() = 0;
|
||||||
|
|
||||||
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
||||||
// loaded.
|
// loaded.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -12,10 +12,10 @@
|
||||||
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
DataMigrationTask::DataMigrationTask(const QString& sourcePath, const QString& targetPath, Filter pathMatcher)
|
DataMigrationTask::DataMigrationTask(const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathMatcher)
|
||||||
: Task(), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
|
: Task(), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
|
||||||
{
|
{
|
||||||
m_copy.matcher(m_pathMatcher).whitelist(true);
|
m_copy.matcher(m_pathMatcher.get()).whitelist(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataMigrationTask::executeTask()
|
void DataMigrationTask::executeTask()
|
||||||
|
|
@ -24,7 +24,7 @@ void DataMigrationTask::executeTask()
|
||||||
|
|
||||||
// 1. Scan
|
// 1. Scan
|
||||||
// Check how many files we gotta copy
|
// Check how many files we gotta copy
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
|
||||||
return m_copy(true); // dry run to collect amount of files
|
return m_copy(true); // dry run to collect amount of files
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
||||||
|
|
@ -37,7 +37,11 @@ void DataMigrationTask::dryRunFinished()
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
||||||
|
#else
|
||||||
|
if (!m_copyFuture.result()) {
|
||||||
|
#endif
|
||||||
emitFailed(tr("Failed to scan source path."));
|
emitFailed(tr("Failed to scan source path."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +57,7 @@ void DataMigrationTask::dryRunFinished()
|
||||||
setProgress(m_copy.totalCopied(), m_toCopy);
|
setProgress(m_copy.totalCopied(), m_toCopy);
|
||||||
setStatus(tr("Copying %1…").arg(shortenedName));
|
setStatus(tr("Copying %1…").arg(shortenedName));
|
||||||
});
|
});
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
|
||||||
return m_copy(false); // actually copy now
|
return m_copy(false); // actually copy now
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
||||||
|
|
@ -63,7 +67,7 @@ void DataMigrationTask::dryRunFinished()
|
||||||
|
|
||||||
void DataMigrationTask::dryRunAborted()
|
void DataMigrationTask::dryRunAborted()
|
||||||
{
|
{
|
||||||
emitAborted();
|
emitFailed(tr("Aborted"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataMigrationTask::copyFinished()
|
void DataMigrationTask::copyFinished()
|
||||||
|
|
@ -71,7 +75,11 @@ void DataMigrationTask::copyFinished()
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
||||||
|
#else
|
||||||
|
if (!m_copyFuture.result()) {
|
||||||
|
#endif
|
||||||
emitFailed(tr("Some paths could not be copied!"));
|
emitFailed(tr("Some paths could not be copied!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -81,5 +89,5 @@ void DataMigrationTask::copyFinished()
|
||||||
|
|
||||||
void DataMigrationTask::copyAborted()
|
void DataMigrationTask::copyAborted()
|
||||||
{
|
{
|
||||||
emitAborted();
|
emitFailed(tr("Aborted"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Filter.h"
|
#include "pathmatcher/IPathMatcher.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
class DataMigrationTask : public Task {
|
class DataMigrationTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DataMigrationTask(const QString& sourcePath, const QString& targetPath, Filter pathmatcher);
|
explicit DataMigrationTask(const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher);
|
||||||
~DataMigrationTask() override = default;
|
~DataMigrationTask() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -33,7 +33,7 @@ class DataMigrationTask : public Task {
|
||||||
private:
|
private:
|
||||||
const QString& m_sourcePath;
|
const QString& m_sourcePath;
|
||||||
const QString& m_targetPath;
|
const QString& m_targetPath;
|
||||||
const Filter m_pathMatcher;
|
const IPathMatcher::Ptr m_pathMatcher;
|
||||||
|
|
||||||
FS::copy m_copy;
|
FS::copy m_copy;
|
||||||
int m_toCopy = 0;
|
int m_toCopy = 0;
|
||||||
|
|
|
||||||
23
launcher/DefaultVariable.h
Normal file
23
launcher/DefaultVariable.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class DefaultVariable {
|
||||||
|
public:
|
||||||
|
DefaultVariable(const T& value) { defaultValue = value; }
|
||||||
|
DefaultVariable<T>& operator=(const T& value)
|
||||||
|
{
|
||||||
|
currentValue = value;
|
||||||
|
is_default = currentValue == defaultValue;
|
||||||
|
is_explicit = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator const T&() const { return is_default ? defaultValue : currentValue; }
|
||||||
|
bool isDefault() const { return is_default; }
|
||||||
|
bool isExplicit() const { return is_explicit; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T currentValue;
|
||||||
|
T defaultValue;
|
||||||
|
bool is_default = true;
|
||||||
|
bool is_explicit = false;
|
||||||
|
};
|
||||||
|
|
@ -44,4 +44,4 @@ QIcon FastFileIconProvider::icon(const QFileInfo& info) const
|
||||||
}
|
}
|
||||||
|
|
||||||
return QApplication::style()->standardIcon(icon);
|
return QApplication::style()->standardIcon(icon);
|
||||||
}
|
}
|
||||||
|
|
@ -23,4 +23,4 @@
|
||||||
class FastFileIconProvider : public QFileIconProvider {
|
class FastFileIconProvider : public QFileIconProvider {
|
||||||
public:
|
public:
|
||||||
QIcon icon(const QFileInfo& info) const override;
|
QIcon icon(const QFileInfo& info) const override;
|
||||||
};
|
};
|
||||||
|
|
@ -40,11 +40,12 @@
|
||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
|
#include <algorithm>
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "SeparatorPrefixTree.h"
|
#include "SeparatorPrefixTree.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
FileIgnoreProxy::FileIgnoreProxy(QString root, QObject* parent) : QSortFilterProxyModel(parent), m_root(root) {}
|
FileIgnoreProxy::FileIgnoreProxy(QString root, QObject* parent) : QSortFilterProxyModel(parent), root(root) {}
|
||||||
// NOTE: Sadly, we have to do sorting ourselves.
|
// NOTE: Sadly, we have to do sorting ourselves.
|
||||||
bool FileIgnoreProxy::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
bool FileIgnoreProxy::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
||||||
{
|
{
|
||||||
|
|
@ -103,10 +104,10 @@ QVariant FileIgnoreProxy::data(const QModelIndex& index, int role) const
|
||||||
if (index.column() == 0 && role == Qt::CheckStateRole) {
|
if (index.column() == 0 && role == Qt::CheckStateRole) {
|
||||||
QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel());
|
QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel());
|
||||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||||
auto cover = m_blocked.cover(blockedPath);
|
auto cover = blocked.cover(blockedPath);
|
||||||
if (!cover.isNull()) {
|
if (!cover.isNull()) {
|
||||||
return QVariant(Qt::Unchecked);
|
return QVariant(Qt::Unchecked);
|
||||||
} else if (m_blocked.exists(blockedPath)) {
|
} else if (blocked.exists(blockedPath)) {
|
||||||
return QVariant(Qt::PartiallyChecked);
|
return QVariant(Qt::PartiallyChecked);
|
||||||
} else {
|
} else {
|
||||||
return QVariant(Qt::Checked);
|
return QVariant(Qt::Checked);
|
||||||
|
|
@ -129,7 +130,7 @@ bool FileIgnoreProxy::setData(const QModelIndex& index, const QVariant& value, i
|
||||||
|
|
||||||
QString FileIgnoreProxy::relPath(const QString& path) const
|
QString FileIgnoreProxy::relPath(const QString& path) const
|
||||||
{
|
{
|
||||||
return QDir(m_root).relativeFilePath(path);
|
return QDir(root).relativeFilePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
||||||
|
|
@ -145,18 +146,18 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (state == Qt::Unchecked) {
|
if (state == Qt::Unchecked) {
|
||||||
// blocking a path
|
// blocking a path
|
||||||
auto& node = m_blocked.insert(blockedPath);
|
auto& node = blocked.insert(blockedPath);
|
||||||
// get rid of all blocked nodes below
|
// get rid of all blocked nodes below
|
||||||
node.clear();
|
node.clear();
|
||||||
changed = true;
|
changed = true;
|
||||||
} else if (state == Qt::Checked || state == Qt::PartiallyChecked) {
|
} else if (state == Qt::Checked || state == Qt::PartiallyChecked) {
|
||||||
if (!m_blocked.remove(blockedPath)) {
|
if (!blocked.remove(blockedPath)) {
|
||||||
auto cover = m_blocked.cover(blockedPath);
|
auto cover = blocked.cover(blockedPath);
|
||||||
qDebug() << "Blocked by cover" << cover;
|
qDebug() << "Blocked by cover" << cover;
|
||||||
// uncover
|
// uncover
|
||||||
m_blocked.remove(cover);
|
blocked.remove(cover);
|
||||||
// block all contents, except for any cover
|
// block all contents, except for any cover
|
||||||
QModelIndex rootIndex = fsm->index(FS::PathCombine(m_root, cover));
|
QModelIndex rootIndex = fsm->index(FS::PathCombine(root, cover));
|
||||||
QModelIndex doing = rootIndex;
|
QModelIndex doing = rootIndex;
|
||||||
int row = 0;
|
int row = 0;
|
||||||
QStack<QModelIndex> todo;
|
QStack<QModelIndex> todo;
|
||||||
|
|
@ -178,7 +179,7 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
||||||
todo.push(node);
|
todo.push(node);
|
||||||
} else {
|
} else {
|
||||||
// or just block this one.
|
// or just block this one.
|
||||||
m_blocked.insert(relpath);
|
blocked.insert(relpath);
|
||||||
}
|
}
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
|
|
@ -228,7 +229,7 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||||
auto found = m_blocked.find(blockedPath);
|
auto found = blocked.find(blockedPath);
|
||||||
if (found) {
|
if (found) {
|
||||||
return !found->leaf();
|
return !found->leaf();
|
||||||
}
|
}
|
||||||
|
|
@ -238,8 +239,8 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
|
||||||
void FileIgnoreProxy::setBlockedPaths(QStringList paths)
|
void FileIgnoreProxy::setBlockedPaths(QStringList paths)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_blocked.clear();
|
blocked.clear();
|
||||||
m_blocked.insert(paths);
|
blocked.insert(paths);
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,45 +267,10 @@ bool FileIgnoreProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceP
|
||||||
|
|
||||||
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
|
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
|
||||||
{
|
{
|
||||||
if (m_ignoreFiles.contains(fileInfo.fileName())) {
|
return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()));
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& suffix : m_ignoreFilesSuffixes) {
|
|
||||||
if (fileInfo.fileName().endsWith(suffix)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileIgnoreProxy::filterFile(const QFileInfo& file) const
|
bool FileIgnoreProxy::filterFile(const QString& fileName) const
|
||||||
{
|
{
|
||||||
return m_blocked.covers(relPath(file.absoluteFilePath())) || ignoreFile(file);
|
return blocked.covers(fileName) || ignoreFile(QFileInfo(QDir(root), fileName));
|
||||||
}
|
|
||||||
|
|
||||||
void FileIgnoreProxy::loadBlockedPathsFromFile(const QString& fileName)
|
|
||||||
{
|
|
||||||
QFile ignoreFile(fileName);
|
|
||||||
if (!ignoreFile.open(QIODevice::ReadOnly)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto ignoreData = ignoreFile.readAll();
|
|
||||||
auto string = QString::fromUtf8(ignoreData);
|
|
||||||
setBlockedPaths(string.split('\n', Qt::SkipEmptyParts));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileIgnoreProxy::saveBlockedPathsToFile(const QString& fileName)
|
|
||||||
{
|
|
||||||
auto ignoreData = blockedPaths().toStringList().join('\n').toUtf8();
|
|
||||||
try {
|
|
||||||
FS::write(fileName, ignoreData);
|
|
||||||
} catch (const Exception& e) {
|
|
||||||
qWarning() << e.cause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,20 +61,15 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
|
||||||
|
|
||||||
void setBlockedPaths(QStringList paths);
|
void setBlockedPaths(QStringList paths);
|
||||||
|
|
||||||
inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return m_blocked; }
|
inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return blocked; }
|
||||||
inline SeparatorPrefixTree<'/'>& blockedPaths() { return m_blocked; }
|
inline SeparatorPrefixTree<'/'>& blockedPaths() { return blocked; }
|
||||||
|
|
||||||
// list of file names that need to be removed completely from model
|
// list of file names that need to be removed completely from model
|
||||||
inline QStringList& ignoreFilesWithName() { return m_ignoreFiles; }
|
inline QStringList& ignoreFilesWithName() { return m_ignoreFiles; }
|
||||||
inline QStringList& ignoreFilesWithSuffix() { return m_ignoreFilesSuffixes; }
|
|
||||||
// list of relative paths that need to be removed completely from model
|
// list of relative paths that need to be removed completely from model
|
||||||
inline SeparatorPrefixTree<'/'>& ignoreFilesWithPath() { return m_ignoreFilePaths; }
|
inline SeparatorPrefixTree<'/'>& ignoreFilesWithPath() { return m_ignoreFilePaths; }
|
||||||
|
|
||||||
bool filterFile(const QFileInfo& fileName) const;
|
bool filterFile(const QString& fileName) const;
|
||||||
|
|
||||||
void loadBlockedPathsFromFile(const QString& fileName);
|
|
||||||
|
|
||||||
void saveBlockedPathsToFile(const QString& fileName);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const;
|
bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const;
|
||||||
|
|
@ -83,9 +78,8 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
|
||||||
bool ignoreFile(QFileInfo file) const;
|
bool ignoreFile(QFileInfo file) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString m_root;
|
const QString root;
|
||||||
SeparatorPrefixTree<'/'> m_blocked;
|
SeparatorPrefixTree<'/'> blocked;
|
||||||
QStringList m_ignoreFiles;
|
QStringList m_ignoreFiles;
|
||||||
QStringList m_ignoreFilesSuffixes;
|
|
||||||
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
|
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include <qcontainerfwd.h>
|
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
@ -60,8 +59,10 @@
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <objbase.h>
|
||||||
#include <objidl.h>
|
#include <objidl.h>
|
||||||
#include <shlguid.h>
|
#include <shlguid.h>
|
||||||
|
#include <shlobj.h>
|
||||||
#include <shobjidl.h>
|
#include <shobjidl.h>
|
||||||
#include <sys/utime.h>
|
#include <sys/utime.h>
|
||||||
#include <versionhelpers.h>
|
#include <versionhelpers.h>
|
||||||
|
|
@ -76,8 +77,24 @@
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
|
||||||
|
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
|
||||||
|
#define GHC_USE_STD_FS
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
#endif // MacOS min version check
|
||||||
|
#endif // Other OSes version check
|
||||||
|
|
||||||
|
#ifndef GHC_USE_STD_FS
|
||||||
|
#include <ghc/filesystem.hpp>
|
||||||
|
namespace fs = ghc::filesystem;
|
||||||
|
#endif
|
||||||
|
|
||||||
// clone
|
// clone
|
||||||
#if defined(Q_OS_LINUX)
|
#if defined(Q_OS_LINUX)
|
||||||
|
|
@ -106,10 +123,6 @@ namespace fs = std::filesystem;
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#if defined(__MINGW32__)
|
||||||
|
|
||||||
// Avoid re-defining structs retroactively added to MinGW
|
|
||||||
// https://github.com/mingw-w64/mingw-w64/issues/90#issuecomment-2829284729
|
|
||||||
#if __MINGW64_VERSION_MAJOR < 13
|
|
||||||
|
|
||||||
struct _DUPLICATE_EXTENTS_DATA {
|
struct _DUPLICATE_EXTENTS_DATA {
|
||||||
HANDLE FileHandle;
|
HANDLE FileHandle;
|
||||||
LARGE_INTEGER SourceFileOffset;
|
LARGE_INTEGER SourceFileOffset;
|
||||||
|
|
@ -119,7 +132,6 @@ struct _DUPLICATE_EXTENTS_DATA {
|
||||||
|
|
||||||
using DUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA;
|
using DUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA;
|
||||||
using PDUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA*;
|
using PDUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA*;
|
||||||
#endif
|
|
||||||
|
|
||||||
struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
|
struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
|
||||||
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
|
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
|
||||||
|
|
@ -283,9 +295,6 @@ bool copyFileAttributes(QString src, QString dst)
|
||||||
if (attrs == INVALID_FILE_ATTRIBUTES)
|
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||||
return false;
|
return false;
|
||||||
return SetFileAttributesW(dst.toStdWString().c_str(), attrs);
|
return SetFileAttributesW(dst.toStdWString().c_str(), attrs);
|
||||||
#else
|
|
||||||
Q_UNUSED(src);
|
|
||||||
Q_UNUSED(dst);
|
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -332,8 +341,8 @@ bool copy::operator()(const QString& offset, bool dryRun)
|
||||||
opt |= copy_opts::overwrite_existing;
|
opt |= copy_opts::overwrite_existing;
|
||||||
|
|
||||||
// Function that'll do the actual copying
|
// Function that'll do the actual copying
|
||||||
auto copy_file = [this, dryRun, src, dst, opt, &err](QString src_path, QString relative_dst_path) {
|
auto copy_file = [&](QString src_path, QString relative_dst_path) {
|
||||||
if (m_matcher && (m_matcher(relative_dst_path) != m_whitelist))
|
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto dst_path = PathCombine(dst, relative_dst_path);
|
auto dst_path = PathCombine(dst, relative_dst_path);
|
||||||
|
|
@ -419,8 +428,8 @@ void create_link::make_link_list(const QString& offset)
|
||||||
m_recursive = true;
|
m_recursive = true;
|
||||||
|
|
||||||
// Function that'll do the actual linking
|
// Function that'll do the actual linking
|
||||||
auto link_file = [this, dst](QString src_path, QString relative_dst_path) {
|
auto link_file = [&](QString src_path, QString relative_dst_path) {
|
||||||
if (m_matcher && (m_matcher(relative_dst_path) != m_whitelist)) {
|
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) {
|
||||||
qDebug() << "path" << relative_dst_path << "in black list or not in whitelist";
|
qDebug() << "path" << relative_dst_path << "in black list or not in whitelist";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -436,7 +445,7 @@ void create_link::make_link_list(const QString& offset)
|
||||||
link_file(src, "");
|
link_file(src, "");
|
||||||
} else {
|
} else {
|
||||||
if (m_debug)
|
if (m_debug)
|
||||||
qDebug().nospace() << "linking recursively: " << src << " to " << dst << ", max_depth: " << m_max_depth;
|
qDebug() << "linking recursively:" << src << "to" << dst << ", max_depth:" << m_max_depth;
|
||||||
QDir src_dir(src);
|
QDir src_dir(src);
|
||||||
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
||||||
|
|
||||||
|
|
@ -514,7 +523,7 @@ void create_link::runPrivileged(const QString& offset)
|
||||||
|
|
||||||
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric();
|
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric();
|
||||||
|
|
||||||
connect(&m_linkServer, &QLocalServer::newConnection, this, [this, &gotResults]() {
|
connect(&m_linkServer, &QLocalServer::newConnection, this, [&]() {
|
||||||
qDebug() << "Client connected, sending out pairs";
|
qDebug() << "Client connected, sending out pairs";
|
||||||
// construct block of data to send
|
// construct block of data to send
|
||||||
QByteArray block;
|
QByteArray block;
|
||||||
|
|
@ -596,7 +605,7 @@ void create_link::runPrivileged(const QString& offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalLinkFileProcess* linkFileProcess = new ExternalLinkFileProcess(serverName, m_useHardLinks, this);
|
ExternalLinkFileProcess* linkFileProcess = new ExternalLinkFileProcess(serverName, m_useHardLinks, this);
|
||||||
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [this, &gotResults]() { emit finishedPrivileged(gotResults); });
|
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [&]() { emit finishedPrivileged(gotResults); });
|
||||||
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
||||||
|
|
||||||
linkFileProcess->start();
|
linkFileProcess->start();
|
||||||
|
|
@ -684,34 +693,11 @@ bool deletePath(QString path)
|
||||||
return err.value() == 0;
|
return err.value() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deleteContents(const QString& path)
|
|
||||||
{
|
|
||||||
const QFileInfo info(path);
|
|
||||||
if (!info.exists()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!info.isDir()) {
|
|
||||||
qWarning() << "Attempted to delete contents of non-directory path:" << path;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
for (const auto& entry : fs::directory_iterator(StringUtils::toStdString(path))) {
|
|
||||||
std::error_code err;
|
|
||||||
|
|
||||||
fs::remove_all(entry.path(), err);
|
|
||||||
if (err.value() != 0) {
|
|
||||||
qWarning().nospace() << "Could not delete directory entry " << entry.path() << ": " << QString::fromStdString(err.message());
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool trash(QString path, QString* pathInTrash)
|
bool trash(QString path, QString* pathInTrash)
|
||||||
{
|
{
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
||||||
if (DesktopServices::isFlatpak())
|
if (DesktopServices::isFlatpak())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -720,6 +706,7 @@ bool trash(QString path, QString* pathInTrash)
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
return QFile::moveToTrash(path, pathInTrash);
|
return QFile::moveToTrash(path, pathInTrash);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2)
|
QString PathCombine(const QString& path1, const QString& path2)
|
||||||
|
|
@ -753,7 +740,11 @@ int pathDepth(const QString& path)
|
||||||
|
|
||||||
QFileInfo info(path);
|
QFileInfo info(path);
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), QString::SkipEmptyParts);
|
||||||
|
#else
|
||||||
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts);
|
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts);
|
||||||
|
#endif
|
||||||
|
|
||||||
int numParts = parts.length();
|
int numParts = parts.length();
|
||||||
numParts -= parts.count(".");
|
numParts -= parts.count(".");
|
||||||
|
|
@ -773,7 +764,11 @@ QString pathTruncate(const QString& path, int depth)
|
||||||
return pathTruncate(trunc, depth);
|
return pathTruncate(trunc, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), QString::SkipEmptyParts);
|
||||||
|
#else
|
||||||
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts);
|
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (parts.startsWith(".") && !path.startsWith(".")) {
|
if (parts.startsWith(".") && !path.startsWith(".")) {
|
||||||
parts.removeFirst();
|
parts.removeFirst();
|
||||||
|
|
@ -823,33 +818,68 @@ QString NormalizePath(QString path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
static const QString BAD_WIN_CHARS = "<>:\"|?*\r\n";
|
||||||
const QString g_badChars = "<>:\"|?*\r\n!";
|
static const QString BAD_NTFS_CHARS = "<>:\"|?*";
|
||||||
QString removeChars(QString source, QChar replace, const QString& extraChars = "")
|
static const QString BAD_HFS_CHARS = ":";
|
||||||
{
|
|
||||||
auto badChars = g_badChars;
|
|
||||||
if (!extraChars.isEmpty()) {
|
|
||||||
badChars += extraChars;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& c : source) {
|
static const QString BAD_FILENAME_CHARS = BAD_WIN_CHARS + "\\/";
|
||||||
if (c.unicode() < 0x20 || !c.isPrint() || badChars.contains(c)) {
|
|
||||||
c = replace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
||||||
{
|
{
|
||||||
return removeChars(std::move(string), replaceWith, "\\/");
|
for (int i = 0; i < string.length(); i++)
|
||||||
|
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
|
||||||
|
string[i] = replaceWith;
|
||||||
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RemoveInvalidPathChars(QString string, QChar replaceWith)
|
QString RemoveInvalidPathChars(QString path, QChar replaceWith)
|
||||||
{
|
{
|
||||||
return removeChars(std::move(string), replaceWith);
|
QString invalidChars;
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
invalidChars = BAD_WIN_CHARS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the null character is ignored in this check as it was not a problem until now
|
||||||
|
switch (statFS(path).fsType) {
|
||||||
|
case FilesystemType::FAT: // similar to NTFS
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::NTFS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::REFS: // similar to NTFS(should be available only on windows)
|
||||||
|
invalidChars += BAD_NTFS_CHARS;
|
||||||
|
break;
|
||||||
|
// case FilesystemType::EXT:
|
||||||
|
// case FilesystemType::EXT_2_OLD:
|
||||||
|
// case FilesystemType::EXT_2_3_4:
|
||||||
|
// case FilesystemType::XFS:
|
||||||
|
// case FilesystemType::BTRFS:
|
||||||
|
// case FilesystemType::NFS:
|
||||||
|
// case FilesystemType::ZFS:
|
||||||
|
case FilesystemType::APFS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::HFS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::HFSPLUS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::HFSX:
|
||||||
|
invalidChars += BAD_HFS_CHARS;
|
||||||
|
break;
|
||||||
|
// case FilesystemType::FUSEBLK:
|
||||||
|
// case FilesystemType::F2FS:
|
||||||
|
// case FilesystemType::UNKNOWN:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidChars.size() != 0) {
|
||||||
|
for (int i = 0; i < path.length(); i++) {
|
||||||
|
if (path.at(i) < ' ' || invalidChars.contains(path.at(i))) {
|
||||||
|
path[i] = replaceWith;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DirNameFromString(QString string, QString inDir)
|
QString DirNameFromString(QString string, QString inDir)
|
||||||
|
|
@ -885,70 +915,48 @@ QString getDesktopDir()
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getApplicationsDir()
|
|
||||||
{
|
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString quoteArgs(const QStringList& args, const QString& wrap, const QString& escapeChar, bool wrapOnlyIfNeeded = false)
|
|
||||||
{
|
|
||||||
QString result;
|
|
||||||
|
|
||||||
auto size = args.size();
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
QString arg = args[i];
|
|
||||||
arg.replace(wrap, escapeChar);
|
|
||||||
|
|
||||||
bool needsWrapping = !wrapOnlyIfNeeded || arg.contains(' ') || arg.contains('\t') || arg.contains(wrap);
|
|
||||||
|
|
||||||
if (needsWrapping)
|
|
||||||
result += wrap + arg + wrap;
|
|
||||||
else
|
|
||||||
result += arg;
|
|
||||||
|
|
||||||
if (i < size - 1)
|
|
||||||
result += ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cross-platform Shortcut creation
|
// Cross-platform Shortcut creation
|
||||||
QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
|
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
|
||||||
{
|
{
|
||||||
if (destination.isEmpty()) {
|
if (destination.isEmpty()) {
|
||||||
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
||||||
}
|
}
|
||||||
if (!ensureFilePathExists(destination)) {
|
if (!ensureFilePathExists(destination)) {
|
||||||
qWarning() << "Destination path can't be created!";
|
qWarning() << "Destination path can't be created!";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
QDir application = destination + ".app/";
|
// Create the Application
|
||||||
|
QDir applicationDirectory =
|
||||||
|
QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/" + BuildConfig.LAUNCHER_NAME + " Instances/";
|
||||||
|
|
||||||
|
if (!applicationDirectory.mkpath(".")) {
|
||||||
|
qWarning() << "Couldn't create application directory";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir application = applicationDirectory.path() + "/" + name + ".app/";
|
||||||
|
|
||||||
if (application.exists()) {
|
if (application.exists()) {
|
||||||
qWarning() << "Application already exists!";
|
qWarning() << "Application already exists!";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!application.mkpath(".")) {
|
if (!application.mkpath(".")) {
|
||||||
qWarning() << "Couldn't create application";
|
qWarning() << "Couldn't create application";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir content = application.path() + "/Contents/";
|
QDir content = application.path() + "/Contents/";
|
||||||
QDir resources = content.path() + "/Resources/";
|
QDir resources = content.path() + "/Resources/";
|
||||||
QDir binaryDir = content.path() + "/MacOS/";
|
QDir binaryDir = content.path() + "/MacOS/";
|
||||||
QFile info(content.path() + "/Info.plist");
|
QFile info = content.path() + "/Info.plist";
|
||||||
|
|
||||||
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
|
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
|
||||||
qWarning() << "Couldn't create directories within application";
|
qWarning() << "Couldn't create directories within application";
|
||||||
return QString();
|
return false;
|
||||||
}
|
|
||||||
if (!info.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
||||||
qWarning() << "Failed to open file" << info.fileName() << "for writing:" << info.errorString();
|
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
info.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
|
|
||||||
QFile(icon).rename(resources.path() + "/Icon.icns");
|
QFile(icon).rename(resources.path() + "/Icon.icns");
|
||||||
|
|
||||||
|
|
@ -956,13 +964,12 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
QString exec = binaryDir.path() + "/Run.command";
|
QString exec = binaryDir.path() + "/Run.command";
|
||||||
|
|
||||||
QFile f(exec);
|
QFile f(exec);
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString();
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
QTextStream stream(&f);
|
QTextStream stream(&f);
|
||||||
|
|
||||||
auto argstring = quoteArgs(args, "\"", "\\\"");
|
QString argstring;
|
||||||
|
if (!args.empty())
|
||||||
|
argstring = " \"" + args.join("\" \"") + "\"";
|
||||||
|
|
||||||
stream << "#!/bin/bash" << "\n";
|
stream << "#!/bin/bash" << "\n";
|
||||||
stream << "\"" << target << "\" " << argstring << "\n";
|
stream << "\"" << target << "\" " << argstring << "\n";
|
||||||
|
|
@ -996,23 +1003,22 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
"</dict>\n"
|
"</dict>\n"
|
||||||
"</plist>";
|
"</plist>";
|
||||||
|
|
||||||
return application.path();
|
return true;
|
||||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
|
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
|
||||||
destination += ".desktop";
|
destination += ".desktop";
|
||||||
QFile f(destination);
|
QFile f(destination);
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString();
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
QTextStream stream(&f);
|
QTextStream stream(&f);
|
||||||
|
|
||||||
auto argstring = quoteArgs(args, "'", "'\\''");
|
QString argstring;
|
||||||
|
if (!args.empty())
|
||||||
|
argstring = " '" + args.join("' '") + "'";
|
||||||
|
|
||||||
stream << "[Desktop Entry]" << "\n";
|
stream << "[Desktop Entry]" << "\n";
|
||||||
stream << "Type=Application" << "\n";
|
stream << "Type=Application" << "\n";
|
||||||
stream << "Categories=Game;ActionGame;AdventureGame;Simulation" << "\n";
|
stream << "Categories=Game;ActionGame;AdventureGame;Simulation" << "\n";
|
||||||
stream << "Exec=\"" << target.toLocal8Bit() << "\" " << argstring.toLocal8Bit() << "\n";
|
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
|
||||||
stream << "Name=" << name.toLocal8Bit() << "\n";
|
stream << "Name=" << name.toLocal8Bit() << "\n";
|
||||||
if (!icon.isEmpty()) {
|
if (!icon.isEmpty()) {
|
||||||
stream << "Icon=" << icon.toLocal8Bit() << "\n";
|
stream << "Icon=" << icon.toLocal8Bit() << "\n";
|
||||||
|
|
@ -1023,38 +1029,51 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
|
|
||||||
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
||||||
|
|
||||||
return destination;
|
return true;
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
QFileInfo targetInfo(target);
|
QFileInfo targetInfo(target);
|
||||||
|
|
||||||
if (!targetInfo.exists()) {
|
if (!targetInfo.exists()) {
|
||||||
qWarning() << "Target file does not exist!";
|
qWarning() << "Target file does not exist!";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
target = targetInfo.absoluteFilePath();
|
target = targetInfo.absoluteFilePath();
|
||||||
|
|
||||||
if (target.length() >= MAX_PATH) {
|
if (target.length() >= MAX_PATH) {
|
||||||
qWarning() << "Target file path is too long!";
|
qWarning() << "Target file path is too long!";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!icon.isEmpty() && icon.length() >= MAX_PATH) {
|
if (!icon.isEmpty() && icon.length() >= MAX_PATH) {
|
||||||
qWarning() << "Icon path is too long!";
|
qWarning() << "Icon path is too long!";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
destination += ".lnk";
|
destination += ".lnk";
|
||||||
|
|
||||||
if (destination.length() >= MAX_PATH) {
|
if (destination.length() >= MAX_PATH) {
|
||||||
qWarning() << "Destination path is too long!";
|
qWarning() << "Destination path is too long!";
|
||||||
return QString();
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString argStr;
|
||||||
|
int argCount = args.count();
|
||||||
|
for (int i = 0; i < argCount; i++) {
|
||||||
|
if (args[i].contains(' ')) {
|
||||||
|
argStr.append('"').append(args[i]).append('"');
|
||||||
|
} else {
|
||||||
|
argStr.append(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < argCount - 1) {
|
||||||
|
argStr.append(" ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto argStr = quoteArgs(args, "\"", "\\\"", true);
|
|
||||||
if (argStr.length() >= MAX_PATH) {
|
if (argStr.length() >= MAX_PATH) {
|
||||||
qWarning() << "Arguments string is too long!";
|
qWarning() << "Arguments string is too long!";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
@ -1063,7 +1082,7 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
hres = CoInitialize(nullptr);
|
hres = CoInitialize(nullptr);
|
||||||
if (FAILED(hres)) {
|
if (FAILED(hres)) {
|
||||||
qWarning() << "Failed to initialize COM!";
|
qWarning() << "Failed to initialize COM!";
|
||||||
return QString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
WCHAR wsz[MAX_PATH];
|
WCHAR wsz[MAX_PATH];
|
||||||
|
|
@ -1101,28 +1120,26 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
hres = ppf->Save(wsz, TRUE);
|
hres = ppf->Save(wsz, TRUE);
|
||||||
if (FAILED(hres)) {
|
if (FAILED(hres)) {
|
||||||
qWarning() << "IPresistFile->Save() failed";
|
qWarning() << "IPresistFile->Save() failed";
|
||||||
qWarning() << "hres =" << hres;
|
qWarning() << "hres = " << hres;
|
||||||
}
|
}
|
||||||
ppf->Release();
|
ppf->Release();
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to query IPersistFile interface from IShellLink instance";
|
qWarning() << "Failed to query IPersistFile interface from IShellLink instance";
|
||||||
qWarning() << "hres =" << hres;
|
qWarning() << "hres = " << hres;
|
||||||
}
|
}
|
||||||
psl->Release();
|
psl->Release();
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to create IShellLink instance";
|
qWarning() << "Failed to create IShellLink instance";
|
||||||
qWarning() << "hres =" << hres;
|
qWarning() << "hres = " << hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
// go away COM, nobody likes you
|
// go away COM, nobody likes you
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
|
|
||||||
if (SUCCEEDED(hres))
|
return SUCCEEDED(hres);
|
||||||
return destination;
|
|
||||||
return QString();
|
|
||||||
#else
|
#else
|
||||||
qWarning("Desktop Shortcuts not supported on your platform!");
|
qWarning("Desktop Shortcuts not supported on your platform!");
|
||||||
return QString();
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1278,8 +1295,8 @@ bool clone::operator()(const QString& offset, bool dryRun)
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
|
|
||||||
// Function that'll do the actual cloneing
|
// Function that'll do the actual cloneing
|
||||||
auto cloneFile = [this, dryRun, dst, &err](QString src_path, QString relative_dst_path) {
|
auto cloneFile = [&](QString src_path, QString relative_dst_path) {
|
||||||
if (m_matcher && (m_matcher(relative_dst_path) != m_whitelist))
|
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto dst_path = PathCombine(dst, relative_dst_path);
|
auto dst_path = PathCombine(dst, relative_dst_path);
|
||||||
|
|
@ -1400,14 +1417,14 @@ bool win_ioctl_clone(const std::wstring& src_path, const std::wstring& dst_path,
|
||||||
ULONG fs_flags;
|
ULONG fs_flags;
|
||||||
if (!GetVolumeInformationByHandleW(hSourceFile, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0)) {
|
if (!GetVolumeInformationByHandleW(hSourceFile, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0)) {
|
||||||
ec = std::error_code(GetLastError(), std::system_category());
|
ec = std::error_code(GetLastError(), std::system_category());
|
||||||
qDebug() << "Failed to get Filesystem information for" << src_path.c_str();
|
qDebug() << "Failed to get Filesystem information for " << src_path.c_str();
|
||||||
CloseHandle(hSourceFile);
|
CloseHandle(hSourceFile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING)) {
|
if (!(fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING)) {
|
||||||
SetLastError(ERROR_NOT_CAPABLE);
|
SetLastError(ERROR_NOT_CAPABLE);
|
||||||
ec = std::error_code(GetLastError(), std::system_category());
|
ec = std::error_code(GetLastError(), std::system_category());
|
||||||
qWarning() << "Filesystem at" << src_path.c_str() << "does not support reflink";
|
qWarning() << "Filesystem at " << src_path.c_str() << " does not support reflink";
|
||||||
CloseHandle(hSourceFile);
|
CloseHandle(hSourceFile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1703,14 +1720,4 @@ QString getUniqueResourceName(const QString& filePath)
|
||||||
|
|
||||||
return newFileName;
|
return newFileName;
|
||||||
}
|
}
|
||||||
bool removeFiles(QStringList listFile)
|
|
||||||
{
|
|
||||||
bool ret = true;
|
|
||||||
// For each file
|
|
||||||
for (int i = 0; i < listFile.count(); i++) {
|
|
||||||
// Remove
|
|
||||||
ret = ret && QFile::remove(listFile.at(i));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} // namespace FS
|
} // namespace FS
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
#include "Filter.h"
|
#include "pathmatcher/IPathMatcher.h"
|
||||||
|
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
|
|
@ -115,9 +115,9 @@ class copy : public QObject {
|
||||||
m_followSymlinks = follow;
|
m_followSymlinks = follow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
copy& matcher(Filter filter)
|
copy& matcher(const IPathMatcher* filter)
|
||||||
{
|
{
|
||||||
m_matcher = std::move(filter);
|
m_matcher = filter;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
copy& whitelist(bool whitelist)
|
copy& whitelist(bool whitelist)
|
||||||
|
|
@ -147,7 +147,7 @@ class copy : public QObject {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_followSymlinks = true;
|
bool m_followSymlinks = true;
|
||||||
Filter m_matcher = nullptr;
|
const IPathMatcher* m_matcher = nullptr;
|
||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
bool m_overwrite = false;
|
bool m_overwrite = false;
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
|
|
@ -209,9 +209,9 @@ class create_link : public QObject {
|
||||||
m_useHardLinks = useHard;
|
m_useHardLinks = useHard;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
create_link& matcher(Filter filter)
|
create_link& matcher(const IPathMatcher* filter)
|
||||||
{
|
{
|
||||||
m_matcher = std::move(filter);
|
m_matcher = filter;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
create_link& whitelist(bool whitelist)
|
create_link& whitelist(bool whitelist)
|
||||||
|
|
@ -260,7 +260,7 @@ class create_link : public QObject {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_useHardLinks = false;
|
bool m_useHardLinks = false;
|
||||||
Filter m_matcher = nullptr;
|
const IPathMatcher* m_matcher = nullptr;
|
||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
bool m_recursive = true;
|
bool m_recursive = true;
|
||||||
|
|
||||||
|
|
@ -291,15 +291,6 @@ bool move(const QString& source, const QString& dest);
|
||||||
*/
|
*/
|
||||||
bool deletePath(QString path);
|
bool deletePath(QString path);
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a folder's contents recursively but not the folder itself.
|
|
||||||
* @param path The path to the folder.
|
|
||||||
* @return Whether the deletion was completely successful.
|
|
||||||
*/
|
|
||||||
bool deleteContents(const QString& path);
|
|
||||||
|
|
||||||
bool removeFiles(QStringList listFile);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trash a folder / file
|
* Trash a folder / file
|
||||||
*/
|
*/
|
||||||
|
|
@ -362,18 +353,14 @@ bool checkProblemticPathJava(QDir folder);
|
||||||
// Get the Directory representing the User's Desktop
|
// Get the Directory representing the User's Desktop
|
||||||
QString getDesktopDir();
|
QString getDesktopDir();
|
||||||
|
|
||||||
// Get the Directory representing the User's Applications directory
|
|
||||||
QString getApplicationsDir();
|
|
||||||
|
|
||||||
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
|
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
|
||||||
// Equivalent to doing QDir::rename, but allowing for overrides
|
// Equivalent to doing QDir::rename, but allowing for overrides
|
||||||
bool overrideFolder(QString overwritten_path, QString override_path);
|
bool overrideFolder(QString overwritten_path, QString override_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a shortcut to the specified target file at the specified destination path.
|
* Creates a shortcut to the specified target file at the specified destination path.
|
||||||
* Returns null QString if creation failed; otherwise returns the path to the created shortcut.
|
|
||||||
*/
|
*/
|
||||||
QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
|
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
|
||||||
|
|
||||||
enum class FilesystemType {
|
enum class FilesystemType {
|
||||||
FAT,
|
FAT,
|
||||||
|
|
@ -501,9 +488,9 @@ class clone : public QObject {
|
||||||
m_src.setPath(src);
|
m_src.setPath(src);
|
||||||
m_dst.setPath(dst);
|
m_dst.setPath(dst);
|
||||||
}
|
}
|
||||||
clone& matcher(Filter filter)
|
clone& matcher(const IPathMatcher* filter)
|
||||||
{
|
{
|
||||||
m_matcher = std::move(filter);
|
m_matcher = filter;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
clone& whitelist(bool whitelist)
|
clone& whitelist(bool whitelist)
|
||||||
|
|
@ -527,7 +514,7 @@ class clone : public QObject {
|
||||||
bool operator()(const QString& offset, bool dryRun = false);
|
bool operator()(const QString& offset, bool dryRun = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Filter m_matcher = nullptr;
|
const IPathMatcher* m_matcher = nullptr;
|
||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
QDir m_dst;
|
QDir m_dst;
|
||||||
|
|
|
||||||
37
launcher/Filter.cpp
Normal file
37
launcher/Filter.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include "Filter.h"
|
||||||
|
|
||||||
|
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
|
bool ContainsFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
return value.contains(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
|
bool ExactFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
return value == pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExactIfPresentFilter::ExactIfPresentFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
|
bool ExactIfPresentFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
return value.isEmpty() || value == pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
|
||||||
|
{
|
||||||
|
pattern.setPattern(regexp);
|
||||||
|
pattern.optimize();
|
||||||
|
}
|
||||||
|
bool RegexpFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
auto match = pattern.match(value);
|
||||||
|
bool matched = match.hasMatch();
|
||||||
|
return invert ? (!matched) : (matched);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExactListFilter::ExactListFilter(const QStringList& pattern) : m_pattern(pattern) {}
|
||||||
|
bool ExactListFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
return m_pattern.isEmpty() || m_pattern.contains(value);
|
||||||
|
}
|
||||||
|
|
@ -3,52 +3,59 @@
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
using Filter = std::function<bool(const QString&)>;
|
class Filter {
|
||||||
|
public:
|
||||||
|
virtual ~Filter() = default;
|
||||||
|
virtual bool accepts(const QString& value) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
namespace Filters {
|
class ContainsFilter : public Filter {
|
||||||
inline Filter inverse(Filter filter)
|
public:
|
||||||
{
|
ContainsFilter(const QString& pattern);
|
||||||
return [filter = std::move(filter)](const QString& src) { return !filter(src); };
|
virtual ~ContainsFilter() = default;
|
||||||
}
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
inline Filter any(QList<Filter> filters)
|
private:
|
||||||
{
|
QString pattern;
|
||||||
return [filters = std::move(filters)](const QString& src) {
|
};
|
||||||
for (auto& filter : filters)
|
|
||||||
if (filter(src))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
class ExactFilter : public Filter {
|
||||||
};
|
public:
|
||||||
}
|
ExactFilter(const QString& pattern);
|
||||||
|
virtual ~ExactFilter() = default;
|
||||||
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
inline Filter equals(QString pattern)
|
private:
|
||||||
{
|
QString pattern;
|
||||||
return [pattern = std::move(pattern)](const QString& src) { return src == pattern; };
|
};
|
||||||
}
|
|
||||||
|
|
||||||
inline Filter equalsAny(QStringList patterns = {})
|
class ExactIfPresentFilter : public Filter {
|
||||||
{
|
public:
|
||||||
return [patterns = std::move(patterns)](const QString& src) { return patterns.isEmpty() || patterns.contains(src); };
|
ExactIfPresentFilter(const QString& pattern);
|
||||||
}
|
virtual ~ExactIfPresentFilter() override = default;
|
||||||
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
inline Filter equalsOrEmpty(QString pattern)
|
private:
|
||||||
{
|
QString pattern;
|
||||||
return [pattern = std::move(pattern)](const QString& src) { return src.isEmpty() || src == pattern; };
|
};
|
||||||
}
|
|
||||||
|
|
||||||
inline Filter contains(QString pattern)
|
class RegexpFilter : public Filter {
|
||||||
{
|
public:
|
||||||
return [pattern = std::move(pattern)](const QString& src) { return src.contains(pattern); };
|
RegexpFilter(const QString& regexp, bool invert);
|
||||||
}
|
virtual ~RegexpFilter() = default;
|
||||||
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
inline Filter startsWith(QString pattern)
|
private:
|
||||||
{
|
QRegularExpression pattern;
|
||||||
return [pattern = std::move(pattern)](const QString& src) { return src.startsWith(pattern); };
|
bool invert = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
inline Filter regexp(QRegularExpression pattern)
|
class ExactListFilter : public Filter {
|
||||||
{
|
public:
|
||||||
return [pattern = std::move(pattern)](const QString& src) { return pattern.match(src).hasMatch(); };
|
ExactListFilter(const QStringList& pattern = {});
|
||||||
}
|
virtual ~ExactListFilter() = default;
|
||||||
} // namespace Filters
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList m_pattern;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,6 @@
|
||||||
#include "GZip.h"
|
#include "GZip.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDebug>
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
|
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
|
||||||
{
|
{
|
||||||
|
|
@ -138,82 +136,3 @@ bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inf(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
|
|
||||||
{
|
|
||||||
constexpr auto CHUNK = 16384;
|
|
||||||
int ret;
|
|
||||||
unsigned have;
|
|
||||||
z_stream strm;
|
|
||||||
memset(&strm, 0, sizeof(strm));
|
|
||||||
char in[CHUNK];
|
|
||||||
unsigned char out[CHUNK];
|
|
||||||
|
|
||||||
ret = inflateInit2(&strm, (16 + MAX_WBITS));
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* decompress until deflate stream ends or end of file */
|
|
||||||
do {
|
|
||||||
strm.avail_in = source->read(in, CHUNK);
|
|
||||||
if (source->error()) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
if (strm.avail_in == 0)
|
|
||||||
break;
|
|
||||||
strm.next_in = reinterpret_cast<Bytef*>(in);
|
|
||||||
|
|
||||||
/* run inflate() on input until output buffer not full */
|
|
||||||
do {
|
|
||||||
strm.avail_out = CHUNK;
|
|
||||||
strm.next_out = out;
|
|
||||||
ret = inflate(&strm, Z_NO_FLUSH);
|
|
||||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
|
||||||
switch (ret) {
|
|
||||||
case Z_NEED_DICT:
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
[[fallthrough]];
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
have = CHUNK - strm.avail_out;
|
|
||||||
if (!handleBlock(QByteArray(reinterpret_cast<const char*>(out), have))) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
|
|
||||||
/* done when inflate() says it's done */
|
|
||||||
} while (ret != Z_STREAM_END);
|
|
||||||
|
|
||||||
/* clean up and return */
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString zerr(int ret)
|
|
||||||
{
|
|
||||||
switch (ret) {
|
|
||||||
case Z_ERRNO:
|
|
||||||
return QObject::tr("error handling file");
|
|
||||||
case Z_STREAM_ERROR:
|
|
||||||
return QObject::tr("invalid compression level");
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
return QObject::tr("invalid or incomplete deflate data");
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
return QObject::tr("out of memory");
|
|
||||||
case Z_VERSION_ERROR:
|
|
||||||
return QObject::tr("zlib version mismatch!");
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QString GZip::readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
|
|
||||||
{
|
|
||||||
auto ret = inf(source, handleBlock);
|
|
||||||
return zerr(ret);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
namespace GZip {
|
class GZip {
|
||||||
|
public:
|
||||||
bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
|
static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
|
||||||
bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
|
static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
|
||||||
QString readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock);
|
};
|
||||||
|
|
||||||
} // namespace GZip
|
|
||||||
|
|
|
||||||
|
|
@ -1,355 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - Minecraft Launcher
|
|
||||||
* Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "HardwareInfo.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
|
|
||||||
namespace {
|
|
||||||
QString afterColon(QString str)
|
|
||||||
{
|
|
||||||
return str.remove(0, str.indexOf(':') + 2).trimmed();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
bool readFromOutput(const char* command, F function)
|
|
||||||
{
|
|
||||||
FILE* file = popen(command, "r"); // NOLINT(*-command-processor)
|
|
||||||
if (!file) {
|
|
||||||
qWarning().nospace() << "Could not execute command '" << command << "': " << strerror(errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr size_t bufferSize = 512;
|
|
||||||
std::array<char, bufferSize> buffer{};
|
|
||||||
while (fgets(buffer.data(), bufferSize, file) != nullptr) {
|
|
||||||
function(buffer.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
const int exitCode = pclose(file);
|
|
||||||
if (exitCode != 0) {
|
|
||||||
if (exitCode == -1) {
|
|
||||||
qWarning().nospace() << "Could not close stream for command '" << command << "': " << strerror(errno);
|
|
||||||
} else {
|
|
||||||
qWarning().nospace() << "Command '" << command << "' exited with code " << exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <QSettings>
|
|
||||||
|
|
||||||
#include <dxgi1_6.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <wrl/client.h>
|
|
||||||
using Microsoft::WRL::ComPtr;
|
|
||||||
|
|
||||||
QString HardwareInfo::cpuInfo()
|
|
||||||
{
|
|
||||||
const QSettings registry(R"(HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0)", QSettings::NativeFormat);
|
|
||||||
return registry.value("ProcessorNameString").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::totalRamMiB()
|
|
||||||
{
|
|
||||||
MEMORYSTATUSEX status;
|
|
||||||
status.dwLength = sizeof status;
|
|
||||||
|
|
||||||
if (GlobalMemoryStatusEx(&status) == TRUE) {
|
|
||||||
// transforming bytes -> mib
|
|
||||||
return status.ullTotalPhys / 1024 / 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Could not get total RAM: GlobalMemoryStatusEx";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::availableRamMiB()
|
|
||||||
{
|
|
||||||
MEMORYSTATUSEX status;
|
|
||||||
status.dwLength = sizeof status;
|
|
||||||
|
|
||||||
if (GlobalMemoryStatusEx(&status) == TRUE) {
|
|
||||||
// transforming bytes -> mib
|
|
||||||
return status.ullAvailPhys / 1024 / 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Could not get available RAM: GlobalMemoryStatusEx";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList HardwareInfo::gpuInfo()
|
|
||||||
{
|
|
||||||
ComPtr<IDXGIFactory6> factory;
|
|
||||||
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
qWarning() << "Could not create DXGI factory:" << Qt::hex << hr;
|
|
||||||
return { "GPU discovery failed: could not create DXGI factory" };
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT i = 0;
|
|
||||||
ComPtr<IDXGIAdapter> adapter;
|
|
||||||
QStringList out;
|
|
||||||
while (factory->EnumAdapterByGpuPreference(i, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&adapter)) != DXGI_ERROR_NOT_FOUND) {
|
|
||||||
DXGI_ADAPTER_DESC desc;
|
|
||||||
hr = adapter->GetDesc(&desc);
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
out << "GPU: " + QString::fromWCharArray(desc.Description); // NOLINT(*-pro-bounds-array-to-pointer-decay, *-no-array-decay)
|
|
||||||
} else {
|
|
||||||
qWarning() << "Could not get DXGI adapter description:" << Qt::hex << hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(Q_OS_MACOS)
|
|
||||||
#include "sys/sysctl.h"
|
|
||||||
|
|
||||||
QString HardwareInfo::cpuInfo()
|
|
||||||
{
|
|
||||||
std::array<char, 512> buffer{};
|
|
||||||
size_t bufferSize = buffer.size();
|
|
||||||
if (sysctlbyname("machdep.cpu.brand_string", &buffer, &bufferSize, nullptr, 0) == 0) {
|
|
||||||
return { buffer.data() };
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Could not get CPU model: sysctlbyname";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::totalRamMiB()
|
|
||||||
{
|
|
||||||
uint64_t memsize = 0;
|
|
||||||
size_t memsizeSize = sizeof memsize;
|
|
||||||
if (sysctlbyname("hw.memsize", &memsize, &memsizeSize, nullptr, 0) == 0) {
|
|
||||||
// transforming bytes -> mib
|
|
||||||
return memsize / 1024 / 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Could not get total RAM: sysctlbyname";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::availableRamMiB()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MacOSHardwareInfo::MemoryPressureLevel MacOSHardwareInfo::memoryPressureLevel()
|
|
||||||
{
|
|
||||||
uint32_t level = 0;
|
|
||||||
size_t levelSize = sizeof level;
|
|
||||||
if (sysctlbyname("kern.memorystatus_vm_pressure_level", &level, &levelSize, nullptr, 0) == 0) {
|
|
||||||
return static_cast<MemoryPressureLevel>(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Could not get memory pressure level: sysctlbyname";
|
|
||||||
return MemoryPressureLevel::Normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MacOSHardwareInfo::memoryPressureLevelName()
|
|
||||||
{
|
|
||||||
// The names are internal, users refer to levels by their graph colors in Activity Monitor
|
|
||||||
switch (memoryPressureLevel()) {
|
|
||||||
case MemoryPressureLevel::Normal:
|
|
||||||
return "Green";
|
|
||||||
case MemoryPressureLevel::Warning:
|
|
||||||
return "Yellow";
|
|
||||||
case MemoryPressureLevel::Critical:
|
|
||||||
return "Red";
|
|
||||||
default:
|
|
||||||
Q_ASSERT(false);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList HardwareInfo::gpuInfo()
|
|
||||||
{
|
|
||||||
QStringList out;
|
|
||||||
const bool success = readFromOutput("system_profiler SPDisplaysDataType", [&](const QString& str) {
|
|
||||||
// Chipset Model: Intel HD Graphics 620
|
|
||||||
if (str.contains("Chipset Model")) {
|
|
||||||
out << "GPU: " + afterColon(str);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!success) {
|
|
||||||
return { "GPU discovery failed: could not read from system_profiler" };
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(Q_OS_LINUX)
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
QString HardwareInfo::cpuInfo()
|
|
||||||
{
|
|
||||||
std::ifstream cpuin("/proc/cpuinfo");
|
|
||||||
for (std::string line; std::getline(cpuin, line);) {
|
|
||||||
// model name : AMD Ryzen 7 5800X 8-Core Processor
|
|
||||||
if (const QString str = QString::fromStdString(line); str.startsWith("model name")) {
|
|
||||||
return afterColon(str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Could not get CPU model: /proc/cpuinfo";
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
uint64_t readMemInfo(const QString& searchTarget)
|
|
||||||
{
|
|
||||||
std::ifstream memin("/proc/meminfo");
|
|
||||||
for (std::string line; std::getline(memin, line);) {
|
|
||||||
// MemTotal: 16287480 kB
|
|
||||||
if (const QString str = QString::fromStdString(line); str.startsWith(searchTarget)) {
|
|
||||||
bool ok = false;
|
|
||||||
const uint total = str.simplified().section(' ', 1, 1).toUInt(&ok);
|
|
||||||
if (!ok) {
|
|
||||||
qWarning() << "Could not read /proc/meminfo: failed to parse string:" << str;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// transforming kib -> mib
|
|
||||||
return total / 1024;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Could not read /proc/meminfo: search target not found:" << searchTarget;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::totalRamMiB()
|
|
||||||
{
|
|
||||||
return readMemInfo("MemTotal");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::availableRamMiB()
|
|
||||||
{
|
|
||||||
return readMemInfo("MemAvailable");
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList HardwareInfo::gpuInfo()
|
|
||||||
{
|
|
||||||
bool readingGpuInfo = false;
|
|
||||||
QString gpu;
|
|
||||||
QString driverInUse = "NONE";
|
|
||||||
QString driversAvailable = "NONE";
|
|
||||||
QStringList out;
|
|
||||||
|
|
||||||
const bool success = readFromOutput("lspci -k", [&](const QString& str) {
|
|
||||||
// clang-format off
|
|
||||||
// 04:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (rev e7)
|
|
||||||
// Subsystem: Sapphire Technology Limited Radeon RX 580 Pulse 4GB
|
|
||||||
// Kernel driver in use: amdgpu
|
|
||||||
// Kernel modules: amdgpu
|
|
||||||
// clang-format on
|
|
||||||
if (str.contains("VGA compatible controller") || str.contains("3D controller")) {
|
|
||||||
readingGpuInfo = true;
|
|
||||||
} else if (!str.startsWith('\t')) {
|
|
||||||
if (readingGpuInfo) {
|
|
||||||
out << QString("GPU: %1 (driver in use: %2; drivers available: %3)").arg(gpu, driverInUse, driversAvailable);
|
|
||||||
driverInUse = "NONE";
|
|
||||||
driversAvailable = "NONE";
|
|
||||||
}
|
|
||||||
readingGpuInfo = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!readingGpuInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString value = afterColon(str);
|
|
||||||
if (str.contains("Subsystem")) {
|
|
||||||
gpu = value;
|
|
||||||
}
|
|
||||||
if (str.contains("Kernel driver in use")) {
|
|
||||||
driverInUse = value;
|
|
||||||
}
|
|
||||||
if (str.contains("Kernel modules")) {
|
|
||||||
driversAvailable = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!success) {
|
|
||||||
return { "GPU discovery failed: could not read from lspci" };
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
QString HardwareInfo::cpuInfo()
|
|
||||||
{
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::totalRamMiB()
|
|
||||||
{
|
|
||||||
uint64_t out = 0;
|
|
||||||
|
|
||||||
const bool success = readFromOutput("sysctl hw.physmem", [&](const QString& str) {
|
|
||||||
const uint64_t mem = str.mid(12).toULong();
|
|
||||||
|
|
||||||
// transforming kib -> mib
|
|
||||||
out = mem / 1024;
|
|
||||||
});
|
|
||||||
if (!success) {
|
|
||||||
qWarning() << "Could not get total RAM: could not read from sysctl";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
uint64_t HardwareInfo::totalRamMiB()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint64_t HardwareInfo::availableRamMiB()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList HardwareInfo::gpuInfo()
|
|
||||||
{
|
|
||||||
return { "GPU discovery failed: not implemented for this OS" };
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - Minecraft Launcher
|
|
||||||
* Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace HardwareInfo {
|
|
||||||
QString cpuInfo();
|
|
||||||
uint64_t totalRamMiB();
|
|
||||||
uint64_t availableRamMiB();
|
|
||||||
QStringList gpuInfo();
|
|
||||||
} // namespace HardwareInfo
|
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
|
||||||
namespace MacOSHardwareInfo {
|
|
||||||
enum class MemoryPressureLevel : uint8_t {
|
|
||||||
Normal = 1,
|
|
||||||
Warning = 2,
|
|
||||||
Critical = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
MemoryPressureLevel memoryPressureLevel();
|
|
||||||
QString memoryPressureLevelName();
|
|
||||||
} // namespace MacOSHardwareInfo
|
|
||||||
#endif
|
|
||||||
|
|
@ -189,4 +189,4 @@ void InstanceCopyPrefs::enableDontLinkSaves(bool b)
|
||||||
void InstanceCopyPrefs::enableUseClone(bool b)
|
void InstanceCopyPrefs::enableUseClone(bool b)
|
||||||
{
|
{
|
||||||
useClone = b;
|
useClone = b;
|
||||||
}
|
}
|
||||||
|
|
@ -8,23 +8,23 @@
|
||||||
|
|
||||||
struct InstanceCopyPrefs {
|
struct InstanceCopyPrefs {
|
||||||
public:
|
public:
|
||||||
bool allTrue() const;
|
[[nodiscard]] bool allTrue() const;
|
||||||
QString getSelectedFiltersAsRegex() const;
|
[[nodiscard]] QString getSelectedFiltersAsRegex() const;
|
||||||
QString getSelectedFiltersAsRegex(const QStringList& additionalFilters) const;
|
[[nodiscard]] QString getSelectedFiltersAsRegex(const QStringList& additionalFilters) const;
|
||||||
// Getters
|
// Getters
|
||||||
bool isCopySavesEnabled() const;
|
[[nodiscard]] bool isCopySavesEnabled() const;
|
||||||
bool isKeepPlaytimeEnabled() const;
|
[[nodiscard]] bool isKeepPlaytimeEnabled() const;
|
||||||
bool isCopyGameOptionsEnabled() const;
|
[[nodiscard]] bool isCopyGameOptionsEnabled() const;
|
||||||
bool isCopyResourcePacksEnabled() const;
|
[[nodiscard]] bool isCopyResourcePacksEnabled() const;
|
||||||
bool isCopyShaderPacksEnabled() const;
|
[[nodiscard]] bool isCopyShaderPacksEnabled() const;
|
||||||
bool isCopyServersEnabled() const;
|
[[nodiscard]] bool isCopyServersEnabled() const;
|
||||||
bool isCopyModsEnabled() const;
|
[[nodiscard]] bool isCopyModsEnabled() const;
|
||||||
bool isCopyScreenshotsEnabled() const;
|
[[nodiscard]] bool isCopyScreenshotsEnabled() const;
|
||||||
bool isUseSymLinksEnabled() const;
|
[[nodiscard]] bool isUseSymLinksEnabled() const;
|
||||||
bool isLinkRecursivelyEnabled() const;
|
[[nodiscard]] bool isLinkRecursivelyEnabled() const;
|
||||||
bool isUseHardLinksEnabled() const;
|
[[nodiscard]] bool isUseHardLinksEnabled() const;
|
||||||
bool isDontLinkSavesEnabled() const;
|
[[nodiscard]] bool isDontLinkSavesEnabled() const;
|
||||||
bool isUseCloneEnabled() const;
|
[[nodiscard]] bool isUseCloneEnabled() const;
|
||||||
// Setters
|
// Setters
|
||||||
void enableCopySaves(bool b);
|
void enableCopySaves(bool b);
|
||||||
void enableKeepPlaytime(bool b);
|
void enableKeepPlaytime(bool b);
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Filter.h"
|
|
||||||
#include "NullInstance.h"
|
#include "NullInstance.h"
|
||||||
|
#include "pathmatcher/RegexpMatcher.h"
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
InstanceCopyTask::InstanceCopyTask(BaseInstance* origInstance, const InstanceCopyPrefs& prefs)
|
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
|
||||||
{
|
{
|
||||||
m_origInstance = origInstance;
|
m_origInstance = origInstance;
|
||||||
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();
|
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();
|
||||||
|
|
@ -30,8 +30,9 @@ InstanceCopyTask::InstanceCopyTask(BaseInstance* origInstance, const InstanceCop
|
||||||
if (!filters.isEmpty()) {
|
if (!filters.isEmpty()) {
|
||||||
// Set regex filter:
|
// Set regex filter:
|
||||||
// FIXME: get this from the original instance type...
|
// FIXME: get this from the original instance type...
|
||||||
QRegularExpression regexp(filters, QRegularExpression::CaseInsensitiveOption);
|
auto matcherReal = new RegexpMatcher(filters);
|
||||||
m_matcher = Filters::regexp(regexp);
|
matcherReal->caseSensitive(false);
|
||||||
|
m_matcher.reset(matcherReal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +43,7 @@ void InstanceCopyTask::executeTask()
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
||||||
if (m_useClone) {
|
if (m_useClone) {
|
||||||
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
folderClone.matcher(m_matcher);
|
folderClone.matcher(m_matcher.get());
|
||||||
|
|
||||||
folderClone(true);
|
folderClone(true);
|
||||||
setProgress(0, folderClone.totalCloned());
|
setProgress(0, folderClone.totalCloned());
|
||||||
|
|
@ -64,13 +65,14 @@ void InstanceCopyTask::executeTask()
|
||||||
|
|
||||||
savesCopy = std::make_unique<FS::copy>(FS::PathCombine(m_origInstance->gameRoot(), "saves"),
|
savesCopy = std::make_unique<FS::copy>(FS::PathCombine(m_origInstance->gameRoot(), "saves"),
|
||||||
FS::PathCombine(staging_mc_dir, "saves"));
|
FS::PathCombine(staging_mc_dir, "saves"));
|
||||||
|
savesCopy->followSymlinks(true);
|
||||||
(*savesCopy)(true);
|
(*savesCopy)(true);
|
||||||
setProgress(0, savesCopy->totalCopied());
|
setProgress(0, savesCopy->totalCopied());
|
||||||
connect(savesCopy.get(), &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
connect(savesCopy.get(), &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
}
|
}
|
||||||
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
int depth = m_linkRecursively ? -1 : 0; // we need to at least link the top level instead of the instance folder
|
int depth = m_linkRecursively ? -1 : 0; // we need to at least link the top level instead of the instance folder
|
||||||
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher);
|
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher.get());
|
||||||
|
|
||||||
folderLink(true);
|
folderLink(true);
|
||||||
setProgress(0, m_progressTotal + folderLink.totalToLink());
|
setProgress(0, m_progressTotal + folderLink.totalToLink());
|
||||||
|
|
@ -89,7 +91,7 @@ void InstanceCopyTask::executeTask()
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
bool got_priv_results = false;
|
bool got_priv_results = false;
|
||||||
|
|
||||||
connect(&folderLink, &FS::create_link::finishedPrivileged, this, [&got_priv_results, &loop](bool gotResults) {
|
connect(&folderLink, &FS::create_link::finishedPrivileged, this, [&](bool gotResults) {
|
||||||
if (!gotResults) {
|
if (!gotResults) {
|
||||||
qDebug() << "Privileged run exited without results!";
|
qDebug() << "Privileged run exited without results!";
|
||||||
}
|
}
|
||||||
|
|
@ -125,11 +127,11 @@ void InstanceCopyTask::executeTask()
|
||||||
return !there_were_errors;
|
return !there_were_errors;
|
||||||
}
|
}
|
||||||
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
folderCopy.matcher(m_matcher);
|
folderCopy.followSymlinks(false).matcher(m_matcher.get());
|
||||||
|
|
||||||
folderCopy(true);
|
folderCopy(true);
|
||||||
setProgress(0, folderCopy.totalCopied());
|
setProgress(0, folderCopy.totalCopied());
|
||||||
connect(&folderCopy, &FS::copy::fileCopied, [this]() { setProgress(m_progress + 1, m_progressTotal); });
|
connect(&folderCopy, &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
return folderCopy();
|
return folderCopy();
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
||||||
|
|
@ -146,9 +148,9 @@ void InstanceCopyTask::copyFinished()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: shouldn't this be able to report errors?
|
// FIXME: shouldn't this be able to report errors?
|
||||||
auto instanceSettings = std::make_unique<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||||
|
|
||||||
BaseInstance* inst(new NullInstance(m_globalSettings, std::move(instanceSettings), m_stagingPath));
|
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
|
||||||
inst->setName(name());
|
inst->setName(name());
|
||||||
inst->setIconKey(m_instIcon);
|
inst->setIconKey(m_instIcon);
|
||||||
if (!m_keepPlaytime) {
|
if (!m_keepPlaytime) {
|
||||||
|
|
@ -196,4 +198,4 @@ bool InstanceCopyTask::abort()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "Filter.h"
|
|
||||||
#include "InstanceCopyPrefs.h"
|
#include "InstanceCopyPrefs.h"
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
@ -15,7 +14,7 @@
|
||||||
class InstanceCopyTask : public InstanceTask {
|
class InstanceCopyTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstanceCopyTask(BaseInstance* origInstance, const InstanceCopyPrefs& prefs);
|
explicit InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
|
|
@ -26,10 +25,10 @@ class InstanceCopyTask : public InstanceTask {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* data */
|
/* data */
|
||||||
BaseInstance* m_origInstance;
|
InstancePtr m_origInstance;
|
||||||
QFuture<bool> m_copyFuture;
|
QFuture<bool> m_copyFuture;
|
||||||
QFutureWatcher<bool> m_copyFutureWatcher;
|
QFutureWatcher<bool> m_copyFutureWatcher;
|
||||||
Filter m_matcher;
|
std::unique_ptr<IPathMatcher> m_matcher;
|
||||||
bool m_keepPlaytime;
|
bool m_keepPlaytime;
|
||||||
bool m_useLinks = false;
|
bool m_useLinks = false;
|
||||||
bool m_useHardLinks = false;
|
bool m_useHardLinks = false;
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,7 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include "FileSystem.h"
|
||||||
#include "Application.h"
|
|
||||||
#include "InstanceTask.h"
|
|
||||||
#include "minecraft/MinecraftLoadAndCheck.h"
|
|
||||||
#include "tasks/SequentialTask.h"
|
|
||||||
|
|
||||||
bool InstanceCreationTask::abort()
|
|
||||||
{
|
|
||||||
if (!canAbort()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_abort = true;
|
|
||||||
if (m_gameFilesTask) {
|
|
||||||
return m_gameFilesTask->abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return InstanceTask::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCreationTask::executeTask()
|
void InstanceCreationTask::executeTask()
|
||||||
{
|
{
|
||||||
|
|
@ -37,15 +19,13 @@ void InstanceCreationTask::executeTask()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_instance = createInstance();
|
if (!createInstance()) {
|
||||||
if (!m_instance) {
|
if (m_abort)
|
||||||
if (m_abort) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << "Instance creation failed!";
|
qWarning() << "Instance creation failed!";
|
||||||
if (!m_error_message.isEmpty()) {
|
if (!m_error_message.isEmpty()) {
|
||||||
qWarning() << "Reason:" << m_error_message;
|
qWarning() << "Reason: " << m_error_message;
|
||||||
emitFailed(tr("Error while creating new instance:\n%1").arg(m_error_message));
|
emitFailed(tr("Error while creating new instance:\n%1").arg(m_error_message));
|
||||||
} else {
|
} else {
|
||||||
emitFailed(tr("Error while creating new instance."));
|
emitFailed(tr("Error while creating new instance."));
|
||||||
|
|
@ -64,10 +44,9 @@ void InstanceCreationTask::executeTask()
|
||||||
setStatus(tr("Removing old conflicting files..."));
|
setStatus(tr("Removing old conflicting files..."));
|
||||||
qDebug() << "Removing old files";
|
qDebug() << "Removing old files";
|
||||||
|
|
||||||
for (const QString& path : m_filesToRemove) {
|
for (const QString& path : m_files_to_remove) {
|
||||||
if (!QFile::exists(path)) {
|
if (!QFile::exists(path))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Removing" << path;
|
qDebug() << "Removing" << path;
|
||||||
|
|
||||||
|
|
@ -82,61 +61,6 @@ void InstanceCreationTask::executeTask()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!m_abort)
|
||||||
if (!m_abort) {
|
emitSucceeded();
|
||||||
if (!APPLICATION->settings()->get("DownloadGameFilesDuringInstanceCreation").toBool()) {
|
|
||||||
emitSucceeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setAbortable(true);
|
|
||||||
setAbortButtonText(tr("Skip"));
|
|
||||||
qDebug() << "Downloading game files";
|
|
||||||
|
|
||||||
auto updateTasks = m_instance->createUpdateTask();
|
|
||||||
if (updateTasks.isEmpty()) {
|
|
||||||
emitSucceeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto task = makeShared<SequentialTask>();
|
|
||||||
task->addTask(makeShared<MinecraftLoadAndCheck>(m_instance.get(), Net::Mode::Online));
|
|
||||||
for (const auto& t : updateTasks) {
|
|
||||||
task->addTask(t);
|
|
||||||
}
|
|
||||||
connect(task.get(), &Task::finished, this, [this, task] {
|
|
||||||
if (task->wasSuccessful() || m_abort) {
|
|
||||||
emitSucceeded();
|
|
||||||
} else {
|
|
||||||
emitFailed(tr("Could not download game files: %1").arg(task->failReason()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
propagateFromOther(task.get());
|
|
||||||
setDetails(tr("Downloading game files"));
|
|
||||||
|
|
||||||
m_gameFilesTask = task;
|
|
||||||
m_gameFilesTask->start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCreationTask::scheduleToDelete(QWidget* parent, const QDir& dir, const QString& path, bool checkDisabled)
|
|
||||||
{
|
|
||||||
if (path.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (path.startsWith("saves/")) {
|
|
||||||
if (m_shouldDeleteSaves == ShouldDeleteSaves::NotAsked) {
|
|
||||||
m_shouldDeleteSaves = askIfShouldDeleteSaves(parent);
|
|
||||||
}
|
|
||||||
if (m_shouldDeleteSaves == ShouldDeleteSaves::No) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qDebug() << "Scheduling" << path << "for removal";
|
|
||||||
m_filesToRemove.append(dir.absoluteFilePath(path));
|
|
||||||
if (checkDisabled) {
|
|
||||||
if (path.endsWith(".disabled")) { // remove it if it was enabled/disabled by user
|
|
||||||
m_filesToRemove.append(dir.absoluteFilePath(path.chopped(9)));
|
|
||||||
} else {
|
|
||||||
m_filesToRemove.append(dir.absoluteFilePath(path + ".disabled"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
|
||||||
|
|
||||||
class InstanceCreationTask : public InstanceTask {
|
class InstanceCreationTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -10,8 +9,6 @@ class InstanceCreationTask : public InstanceTask {
|
||||||
InstanceCreationTask() = default;
|
InstanceCreationTask() = default;
|
||||||
virtual ~InstanceCreationTask() = default;
|
virtual ~InstanceCreationTask() = default;
|
||||||
|
|
||||||
bool abort() override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void executeTask() final override;
|
void executeTask() final override;
|
||||||
|
|
||||||
|
|
@ -30,24 +27,20 @@ class InstanceCreationTask : public InstanceTask {
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*
|
*
|
||||||
* Returns the instance if it was created or nullptr otherwise.
|
* Returns whether the instance creation was successful (true) or not (false).
|
||||||
*/
|
*/
|
||||||
virtual std::unique_ptr<MinecraftInstance> createInstance() { return nullptr; }
|
virtual bool createInstance() { return false; };
|
||||||
|
|
||||||
QString getError() const { return m_error_message; }
|
QString getError() const { return m_error_message; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setError(const QString& message) { m_error_message = message; };
|
void setError(const QString& message) { m_error_message = message; };
|
||||||
void scheduleToDelete(QWidget* parent, const QDir& dir, const QString& path, bool checkDisabled = false);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_abort = false;
|
bool m_abort = false;
|
||||||
|
|
||||||
QStringList m_filesToRemove;
|
QStringList m_files_to_remove;
|
||||||
ShouldDeleteSaves m_shouldDeleteSaves;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_error_message;
|
QString m_error_message;
|
||||||
std::unique_ptr<MinecraftInstance> m_instance;
|
|
||||||
Task::Ptr m_gameFilesTask;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - Minecraft Launcher
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "InstanceDirUpdate.h"
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "FileSystem.h"
|
|
||||||
|
|
||||||
#include "InstanceList.h"
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
|
||||||
|
|
||||||
QString askToUpdateInstanceDirName(BaseInstance* instance, const QString& oldName, const QString& newName, QWidget* parent)
|
|
||||||
{
|
|
||||||
if (oldName == newName)
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString();
|
|
||||||
if (renamingMode == "MetadataOnly")
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
auto oldRoot = instance->instanceRoot();
|
|
||||||
auto newDirName = FS::DirNameFromString(newName, QFileInfo(oldRoot).dir().absolutePath());
|
|
||||||
auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newDirName);
|
|
||||||
if (oldRoot == newRoot)
|
|
||||||
return QString();
|
|
||||||
if (oldRoot == FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newName))
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
// Check for conflict
|
|
||||||
if (QDir(newRoot).exists()) {
|
|
||||||
QMessageBox::warning(parent, QObject::tr("Cannot rename instance"),
|
|
||||||
QObject::tr("New instance root (%1) already exists. <br />Only the metadata will be renamed.").arg(newRoot));
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask if we should rename
|
|
||||||
if (renamingMode == "AskEverytime") {
|
|
||||||
auto checkBox = new QCheckBox(QObject::tr("&Remember my choice"), parent);
|
|
||||||
auto dialog =
|
|
||||||
CustomMessageBox::selectable(parent, QObject::tr("Rename instance folder"),
|
|
||||||
QObject::tr("Would you also like to rename the instance folder?\n\n"
|
|
||||||
"Old name: %1\n"
|
|
||||||
"New name: %2")
|
|
||||||
.arg(oldName, newName),
|
|
||||||
QMessageBox::Question, QMessageBox::No | QMessageBox::Yes, QMessageBox::NoButton, checkBox);
|
|
||||||
|
|
||||||
auto res = dialog->exec();
|
|
||||||
if (checkBox->isChecked()) {
|
|
||||||
if (res == QMessageBox::Yes)
|
|
||||||
APPLICATION->settings()->set("InstRenamingMode", "PhysicalDir");
|
|
||||||
else
|
|
||||||
APPLICATION->settings()->set("InstRenamingMode", "MetadataOnly");
|
|
||||||
}
|
|
||||||
if (res == QMessageBox::No)
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for linked instances
|
|
||||||
if (!checkLinkedInstances(instance->id(), parent, QObject::tr("Renaming")))
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
// Now we can confirm that a renaming is happening
|
|
||||||
if (!instance->syncInstanceDirName(newRoot)) {
|
|
||||||
QMessageBox::warning(parent, QObject::tr("Cannot rename instance"),
|
|
||||||
QObject::tr("An error occurred when performing the following renaming operation: <br/>"
|
|
||||||
" - Old instance root: %1<br/>"
|
|
||||||
" - New instance root: %2<br/>"
|
|
||||||
"Only the metadata is renamed.")
|
|
||||||
.arg(oldRoot, newRoot));
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
return newRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb)
|
|
||||||
{
|
|
||||||
auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id);
|
|
||||||
if (!linkedInstances.empty()) {
|
|
||||||
auto response = CustomMessageBox::selectable(parent, QObject::tr("There are linked instances"),
|
|
||||||
QObject::tr("The following instance(s) might reference files in this instance:\n\n"
|
|
||||||
"%1\n\n"
|
|
||||||
"%2 it could break the other instance(s), \n\n"
|
|
||||||
"Do you wish to proceed?",
|
|
||||||
nullptr, linkedInstances.count())
|
|
||||||
.arg(linkedInstances.join("\n"))
|
|
||||||
.arg(verb),
|
|
||||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
|
||||||
->exec();
|
|
||||||
if (response != QMessageBox::Yes)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - Minecraft Launcher
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "BaseInstance.h"
|
|
||||||
|
|
||||||
/// Update instanceRoot to make it sync with name/id; return newRoot if a directory rename happened
|
|
||||||
QString askToUpdateInstanceDirName(BaseInstance* instance, const QString& oldName, const QString& newName, QWidget* parent);
|
|
||||||
|
|
||||||
/// Check if there are linked instances, and display a warning; return true if the operation should proceed
|
|
||||||
bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb);
|
|
||||||
|
|
@ -38,11 +38,10 @@
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include "MMCZip.h"
|
||||||
#include "NullInstance.h"
|
#include "NullInstance.h"
|
||||||
|
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
#include "archive/ArchiveReader.h"
|
|
||||||
#include "archive/ExtractZipTask.h"
|
|
||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
#include "icons/IconUtils.h"
|
#include "icons/IconUtils.h"
|
||||||
|
|
||||||
|
|
@ -55,10 +54,12 @@
|
||||||
|
|
||||||
#include "net/ApiDownload.h"
|
#include "net/ApiDownload.h"
|
||||||
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <quazip/quazipdir.h>
|
||||||
|
|
||||||
InstanceImportTask::InstanceImportTask(const QUrl& sourceUrl, QWidget* parent, QMap<QString, QString>&& extra_info)
|
InstanceImportTask::InstanceImportTask(const QUrl& sourceUrl, QWidget* parent, QMap<QString, QString>&& extra_info)
|
||||||
: m_sourceUrl(sourceUrl), m_extra_info(extra_info), m_parent(parent)
|
: m_sourceUrl(sourceUrl), m_extra_info(extra_info), m_parent(parent)
|
||||||
{}
|
{}
|
||||||
|
|
@ -71,6 +72,7 @@ bool InstanceImportTask::abort()
|
||||||
bool wasAborted = false;
|
bool wasAborted = false;
|
||||||
if (m_task)
|
if (m_task)
|
||||||
wasAborted = m_task->abort();
|
wasAborted = m_task->abort();
|
||||||
|
Task::abort();
|
||||||
return wasAborted;
|
return wasAborted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,14 +110,39 @@ void InstanceImportTask::downloadFromUrl()
|
||||||
filesNetJob->start();
|
filesNetJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString cleanPath(QString path)
|
QString InstanceImportTask::getRootFromZip(QuaZip* zip, const QString& root)
|
||||||
{
|
{
|
||||||
if (path == ".")
|
if (!isRunning()) {
|
||||||
return QString();
|
return {};
|
||||||
QString result = path;
|
}
|
||||||
if (result.startsWith("./"))
|
QuaZipDir rootDir(zip, root);
|
||||||
result = result.mid(2);
|
for (auto&& fileName : rootDir.entryList(QDir::Files)) {
|
||||||
return result;
|
setDetails(fileName);
|
||||||
|
if (fileName == "instance.cfg") {
|
||||||
|
qDebug() << "MultiMC:" << true;
|
||||||
|
m_modpackType = ModpackType::MultiMC;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
if (fileName == "manifest.json") {
|
||||||
|
qDebug() << "Flame:" << true;
|
||||||
|
m_modpackType = ModpackType::Flame;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse the search to non-ignored subfolders
|
||||||
|
for (auto&& fileName : rootDir.entryList(QDir::Dirs)) {
|
||||||
|
if ("overrides/" == fileName)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QString result = getRootFromZip(zip, root + fileName);
|
||||||
|
if (!result.isEmpty())
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processZipPack()
|
void InstanceImportTask::processZipPack()
|
||||||
|
|
@ -125,47 +152,33 @@ void InstanceImportTask::processZipPack()
|
||||||
qDebug() << "Attempting to create instance from" << m_archivePath;
|
qDebug() << "Attempting to create instance from" << m_archivePath;
|
||||||
|
|
||||||
// open the zip and find relevant files in it
|
// open the zip and find relevant files in it
|
||||||
MMCZip::ArchiveReader packZip(m_archivePath);
|
auto packZip = std::make_shared<QuaZip>(m_archivePath);
|
||||||
|
if (!packZip->open(QuaZip::mdUnzip)) {
|
||||||
|
emitFailed(tr("Unable to open supplied modpack zip file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuaZipDir packZipDir(packZip.get());
|
||||||
qDebug() << "Attempting to determine instance type";
|
qDebug() << "Attempting to determine instance type";
|
||||||
|
|
||||||
QString root;
|
QString root;
|
||||||
|
|
||||||
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
||||||
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
|
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
|
||||||
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
|
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
|
||||||
auto detectInstance = [this, &extractDir, &root](MMCZip::ArchiveReader::File* f, bool& stop) {
|
if (packZipDir.exists("/modrinth.index.json")) {
|
||||||
if (!isRunning()) {
|
// process as Modrinth pack
|
||||||
stop = true;
|
qDebug() << "Modrinth:" << true;
|
||||||
return true;
|
m_modpackType = ModpackType::Modrinth;
|
||||||
}
|
} else if (packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json")) {
|
||||||
auto fileName = f->filename();
|
// process as Technic pack
|
||||||
if (fileName == "modrinth.index.json") {
|
qDebug() << "Technic:" << true;
|
||||||
// process as Modrinth pack
|
extractDir.mkpath("minecraft");
|
||||||
qDebug() << "Modrinth:" << true;
|
extractDir.cd("minecraft");
|
||||||
m_modpackType = ModpackType::Modrinth;
|
m_modpackType = ModpackType::Technic;
|
||||||
stop = true;
|
} else {
|
||||||
} else if (fileName == "bin/modpack.jar" || fileName == "bin/version.json") {
|
root = getRootFromZip(packZip.get());
|
||||||
// process as Technic pack
|
setDetails("");
|
||||||
qDebug() << "Technic:" << true;
|
|
||||||
extractDir.mkpath("minecraft");
|
|
||||||
extractDir.cd("minecraft");
|
|
||||||
m_modpackType = ModpackType::Technic;
|
|
||||||
stop = true;
|
|
||||||
} else if (fileName == "manifest.json") {
|
|
||||||
qDebug() << "Flame:" << true;
|
|
||||||
m_modpackType = ModpackType::Flame;
|
|
||||||
stop = true;
|
|
||||||
} else if (QFileInfo fileInfo(fileName); fileInfo.fileName() == "instance.cfg") {
|
|
||||||
qDebug() << "MultiMC:" << true;
|
|
||||||
m_modpackType = ModpackType::MultiMC;
|
|
||||||
root = cleanPath(fileInfo.path());
|
|
||||||
stop = true;
|
|
||||||
}
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
if (!packZip.parse(detectInstance)) {
|
|
||||||
emitFailed(tr("Unable to open supplied modpack zip file."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (m_modpackType == ModpackType::Unknown) {
|
if (m_modpackType == ModpackType::Unknown) {
|
||||||
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
||||||
|
|
@ -174,7 +187,7 @@ void InstanceImportTask::processZipPack()
|
||||||
setStatus(tr("Extracting modpack"));
|
setStatus(tr("Extracting modpack"));
|
||||||
|
|
||||||
// make sure we extract just the pack
|
// make sure we extract just the pack
|
||||||
auto zipTask = makeShared<MMCZip::ExtractZipTask>(m_archivePath, extractDir, root);
|
auto zipTask = makeShared<MMCZip::ExtractZipTask>(packZip, extractDir, root);
|
||||||
|
|
||||||
auto progressStep = std::make_shared<TaskStepProgress>();
|
auto progressStep = std::make_shared<TaskStepProgress>();
|
||||||
connect(zipTask.get(), &Task::finished, this, [this, progressStep] {
|
connect(zipTask.get(), &Task::finished, this, [this, progressStep] {
|
||||||
|
|
@ -199,7 +212,6 @@ void InstanceImportTask::processZipPack()
|
||||||
progressStep->status = status;
|
progressStep->status = status;
|
||||||
stepProgress(*progressStep);
|
stepProgress(*progressStep);
|
||||||
});
|
});
|
||||||
connect(zipTask.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
|
|
||||||
m_task.reset(zipTask);
|
m_task.reset(zipTask);
|
||||||
zipTask->start();
|
zipTask->start();
|
||||||
}
|
}
|
||||||
|
|
@ -251,25 +263,6 @@ void InstanceImportTask::extractFinished()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool installIcon(QString root, QString instIconKey)
|
|
||||||
{
|
|
||||||
auto importIconPath = IconUtils::findBestIconIn(root, instIconKey);
|
|
||||||
if (importIconPath.isNull() || !QFile::exists(importIconPath))
|
|
||||||
importIconPath = IconUtils::findBestIconIn(root, "icon.png");
|
|
||||||
if (importIconPath.isNull() || !QFile::exists(importIconPath))
|
|
||||||
importIconPath = IconUtils::findBestIconIn(FS::PathCombine(root, "overrides"), "icon.png");
|
|
||||||
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
|
||||||
// import icon
|
|
||||||
auto iconList = APPLICATION->icons();
|
|
||||||
if (iconList->iconFileExists(instIconKey)) {
|
|
||||||
iconList->deleteIcon(instIconKey);
|
|
||||||
}
|
|
||||||
iconList->installIcon(importIconPath, instIconKey + "." + QFileInfo(importIconPath).suffix());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceImportTask::processFlame()
|
void InstanceImportTask::processFlame()
|
||||||
{
|
{
|
||||||
shared_qobject_ptr<FlameCreationTask> inst_creation_task = nullptr;
|
shared_qobject_ptr<FlameCreationTask> inst_creation_task = nullptr;
|
||||||
|
|
@ -295,14 +288,6 @@ void InstanceImportTask::processFlame()
|
||||||
}
|
}
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
inst_creation_task->setName(*this);
|
||||||
// if the icon was specified by user, use that. otherwise pull icon from the pack
|
|
||||||
if (m_instIcon == "default") {
|
|
||||||
auto iconKey = QString("Flame_%1_Icon").arg(name());
|
|
||||||
|
|
||||||
if (installIcon(m_stagingPath, iconKey)) {
|
|
||||||
m_instIcon = iconKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inst_creation_task->setIcon(m_instIcon);
|
inst_creation_task->setIcon(m_instIcon);
|
||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
||||||
|
|
@ -320,11 +305,8 @@ void InstanceImportTask::processFlame()
|
||||||
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
||||||
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
connect(inst_creation_task.get(), &Task::aborted, this, &Task::abort);
|
||||||
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
connect(inst_creation_task.get(), &Task::abortButtonTextChanged, this, &Task::setAbortButtonText);
|
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
|
|
||||||
|
|
||||||
m_task.reset(inst_creation_task);
|
m_task.reset(inst_creation_task);
|
||||||
setAbortable(true);
|
setAbortable(true);
|
||||||
|
|
@ -342,9 +324,9 @@ void InstanceImportTask::processTechnic()
|
||||||
void InstanceImportTask::processMultiMC()
|
void InstanceImportTask::processMultiMC()
|
||||||
{
|
{
|
||||||
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||||
auto instanceSettings = std::make_unique<INISettingsObject>(configPath);
|
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||||
|
|
||||||
NullInstance instance(m_globalSettings, std::move(instanceSettings), m_stagingPath);
|
NullInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||||
|
|
||||||
// reset time played on import... because packs.
|
// reset time played on import... because packs.
|
||||||
instance.resetTimePlayed();
|
instance.resetTimePlayed();
|
||||||
|
|
@ -358,7 +340,17 @@ void InstanceImportTask::processMultiMC()
|
||||||
} else {
|
} else {
|
||||||
m_instIcon = instance.iconKey();
|
m_instIcon = instance.iconKey();
|
||||||
|
|
||||||
installIcon(instance.instanceRoot(), m_instIcon);
|
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
||||||
|
if (importIconPath.isNull() || !QFile::exists(importIconPath))
|
||||||
|
importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), "icon.png");
|
||||||
|
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
||||||
|
// import icon
|
||||||
|
auto iconList = APPLICATION->icons();
|
||||||
|
if (iconList->iconFileExists(m_instIcon)) {
|
||||||
|
iconList->deleteIcon(m_instIcon);
|
||||||
|
}
|
||||||
|
iconList->installIcon(importIconPath, m_instIcon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
@ -386,8 +378,8 @@ void InstanceImportTask::processModrinth()
|
||||||
} else {
|
} else {
|
||||||
QString pack_id;
|
QString pack_id;
|
||||||
if (!m_sourceUrl.isEmpty()) {
|
if (!m_sourceUrl.isEmpty()) {
|
||||||
static const QRegularExpression s_regex(R"(data\/([^\/]*)\/versions)");
|
QRegularExpression regex(R"(data\/([^\/]*)\/versions)");
|
||||||
pack_id = s_regex.match(m_sourceUrl.toString()).captured(1);
|
pack_id = regex.match(m_sourceUrl.toString()).captured(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Find a way to get the ID in directly imported ZIPs
|
// FIXME: Find a way to get the ID in directly imported ZIPs
|
||||||
|
|
@ -395,14 +387,6 @@ void InstanceImportTask::processModrinth()
|
||||||
}
|
}
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
inst_creation_task->setName(*this);
|
||||||
// if the icon was specified by user, use that. otherwise pull icon from the pack
|
|
||||||
if (m_instIcon == "default") {
|
|
||||||
auto iconKey = QString("Modrinth_%1_Icon").arg(name());
|
|
||||||
|
|
||||||
if (installIcon(m_stagingPath, iconKey)) {
|
|
||||||
m_instIcon = iconKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inst_creation_task->setIcon(m_instIcon);
|
inst_creation_task->setIcon(m_instIcon);
|
||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
||||||
|
|
@ -420,11 +404,8 @@ void InstanceImportTask::processModrinth()
|
||||||
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
||||||
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
connect(inst_creation_task.get(), &Task::aborted, this, &Task::abort);
|
||||||
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
connect(inst_creation_task.get(), &Task::abortButtonTextChanged, this, &Task::setAbortButtonText);
|
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
|
|
||||||
|
|
||||||
m_task.reset(inst_creation_task);
|
m_task.reset(inst_creation_task);
|
||||||
setAbortable(true);
|
setAbortable(true);
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue