aboutsummaryrefslogtreecommitdiff
path: root/flatpak/com.fluorine.manager.yml
blob: 5ed65dc45b910311f33d18b1f0f7cb48247fdb42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
app-id: com.fluorine.manager
runtime: org.kde.Platform
runtime-version: '6.10'
sdk: org.kde.Sdk
sdk-extensions:
  - org.freedesktop.Sdk.Extension.rust-stable
command: fluorine-manager

finish-args:
  - --share=ipc
  - --share=network
  - --socket=x11
  - --socket=wayland
  - --device=all
  - --filesystem=home
  - --filesystem=/mnt
  - --filesystem=/media
  - --filesystem=/run/media
  - --filesystem=~/.steam:ro
  - --filesystem=~/.local/share/Steam
  - --filesystem=~/.var/app/com.valvesoftware.Steam:ro
  - --talk-name=org.freedesktop.Flatpak

cleanup:
  - /include
  - /lib/cmake
  - /lib/pkgconfig
  - /share/doc
  - /share/man
  - '*.a'
  - '*.la'

modules:
  # ── 1. Boost ──
  - name: boost
    buildsystem: simple
    build-commands:
      - ./bootstrap.sh --prefix=/app --with-libraries=program_options,thread,filesystem,system,locale
      - ./b2 install -j$FLATPAK_BUILDER_N_JOBS link=shared variant=release
    sources:
      - type: archive
        url: https://archives.boost.io/release/1.87.0/source/boost_1_87_0.tar.gz
        sha256: f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d

  # ── 2. spdlog ──
  - name: spdlog
    buildsystem: cmake-ninja
    config-opts:
      - -DCMAKE_BUILD_TYPE=Release
      - -DSPDLOG_BUILD_SHARED=ON
    sources:
      - type: git
        url: https://github.com/gabime/spdlog.git
        tag: v1.15.2

  # ── 3. tinyxml2 ──
  - name: tinyxml2
    buildsystem: cmake-ninja
    config-opts:
      - -DCMAKE_BUILD_TYPE=Release
    sources:
      - type: git
        url: https://github.com/leethomason/tinyxml2.git
        tag: 10.0.0

  # ── 4. tomlplusplus ──
  - name: tomlplusplus
    buildsystem: cmake-ninja
    config-opts:
      - -DCMAKE_BUILD_TYPE=Release
    sources:
      - type: git
        url: https://github.com/marzer/tomlplusplus.git
        tag: v3.4.0

  # ── 5. libfuse3 ──
  # Built manually to install fusermount3 without setuid (chown root fails in sandbox).
  # default_library=both produces libfuse3.a so the VFS helper can link statically.
  - name: libfuse3
    buildsystem: simple
    build-commands:
      - meson setup _build --prefix=/app -Dexamples=false -Dtests=false -Dutils=true -Ddefault_library=both
      - ninja -C _build
      # Install library and headers (skip meson install which runs chown).
      - ninja -C _build install || true
      # Ensure fusermount3 is installed even if install_helper.sh failed.
      - install -Dm755 _build/util/fusermount3 /app/bin/fusermount3 2>/dev/null || true
    sources:
      - type: git
        url: https://github.com/libfuse/libfuse.git
        tag: fuse-3.16.2

  # ── 6. libloot ──
  # libloot has a Rust crate at the root and a C++ cmake project in cpp/.
  # The Rust static library must be built first, then cmake links against it.
  - name: libloot
    buildsystem: simple
    build-options:
      append-path: /usr/lib/sdk/rust-stable/bin
      env:
        CARGO_HOME: /run/build/libloot/cargo
      # Network needed for cargo deps and cmake FetchContent (googletest).
      build-args:
        - --share=network
    build-commands:
      # Build Rust static library first.
      - cargo build --release
      # Build the C++ shared library (links against Rust static lib).
      - |
        cmake -S cpp -B cpp/build -G Ninja \
          -DCMAKE_BUILD_TYPE=Release \
          -DBUILD_SHARED_LIBS=ON \
          -DLIBLOOT_INSTALL_DOCS=OFF \
          -DCMAKE_INSTALL_PREFIX=/app
      - cmake --build cpp/build --parallel
      - cmake --install cpp/build
      # Create pkg-config metadata.
      - mkdir -p /app/lib/pkgconfig
      - |
        printf '%s\n' \
          'prefix=/app' \
          'exec_prefix=${prefix}' \
          'libdir=${prefix}/lib' \
          'includedir=${prefix}/include' \
          '' \
          'Name: libloot' \
          'Description: LOOT C++ API library' \
          'Version: 0.29.0' \
          'Libs: -L${libdir} -lloot' \
          'Cflags: -I${includedir}' \
          > /app/lib/pkgconfig/libloot.pc
    sources:
      - type: git
        url: https://github.com/loot/libloot.git
        branch: master

  # ── 7. icoutils ──
  - name: icoutils
    buildsystem: autotools
    build-options:
      # icoutils 0.32.3 uses K&R-style () declarations that GCC 14+ rejects.
      cflags: -std=gnu17
    sources:
      - type: archive
        url: https://download.savannah.gnu.org/releases/icoutils/icoutils-0.32.3.tar.bz2
        sha256: 17abe02d043a253b68b47e3af69c9fc755b895db68fdc8811786125df564c6e0

  # ── 8. cabextract ──
  # Required by winetricks for extracting Windows cab archives.
  - name: cabextract
    buildsystem: autotools
    sources:
      - type: archive
        url: https://www.cabextract.org.uk/cabextract-1.11.tar.gz
        sha256: b5546db1155e4c718ff3d4b278573604f30dd64c3c5bfd4657cd089b823a3ac6

  # ── 9. Portable Python runtime ──
  # Pre-built Python used as the embedded interpreter for MO2's Python plugins.
  # pip packages are installed via network during build (--share=network).
  - name: portable-python
    buildsystem: simple
    build-options:
      build-args:
        - --share=network
    build-commands:
      # Extract, trim, symlink, and install pip packages in one step
      # (each build-command runs in its own shell).
      - |
        set -e
        mkdir -p /app/lib/fluorine/python
        unzip portable-python.zip -d /tmp/pp
        PP_DIR="$(find /tmp/pp -maxdepth 1 -mindepth 1 -type d | head -1)"
        cp -a "${PP_DIR}/." /app/lib/fluorine/python/
        rm -rf /tmp/pp
        # Versioned soname symlink (pybind11 links against libpython3.13.so.1.0).
        if [ -f /app/lib/fluorine/python/lib/libpython3.13.so ] && \
           [ ! -f /app/lib/fluorine/python/lib/libpython3.13.so.1.0 ]; then
          ln -sf libpython3.13.so /app/lib/fluorine/python/lib/libpython3.13.so.1.0
        fi
        # Trim test suites and unnecessary files.
        rm -rf /app/lib/fluorine/python/lib/python3.13/test \
               /app/lib/fluorine/python/lib/python3.13/unittest/test \
               /app/lib/fluorine/python/lib/python3.13/idlelib \
               /app/lib/fluorine/python/lib/python3.13/tkinter \
               /app/lib/fluorine/python/lib/python3.13/turtledemo \
               /app/lib/fluorine/python/include \
               /app/lib/fluorine/python/share \
               2>/dev/null || true
        find /app/lib/fluorine/python -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
        find /app/lib/fluorine/python -name "*.pyc" -delete 2>/dev/null || true
        # Install uv for Python package management.
        curl -LsSf https://astral.sh/uv/install.sh | INSTALLER_NO_MODIFY_PATH=1 UV_INSTALL_DIR=/app/bin sh
        # Install Python packages via uv (PyQt6 for plugin UI, psutil, vdf).
        /app/bin/uv pip install --python /app/lib/fluorine/python/bin/python3 PyQt6 psutil vdf
    sources:
      - type: file
        url: https://github.com/bjia56/portable-python/releases/download/cpython-v3.13.9-build.0/python-headless-3.13.9-linux-x86_64.zip
        sha256: d03507d107da86d74aa38bbc4957b8db5753de567024c5724a254909ae6b86d6
        dest-filename: portable-python.zip

  # ── 10. Fluorine Manager (main project) ──
  # uv (installed in portable-python step) handles pybind11 + sip for the build.
  - name: fluorine
    buildsystem: simple
    build-options:
      append-path: /usr/lib/sdk/rust-stable/bin
      env:
        CARGO_HOME: /run/build/fluorine/cargo
        PYTHONPATH: /app/lib/python3/dist-packages
      # Network needed for FetchContent (7zip, etc.) and cargo deps.
      build-args:
        - --share=network
    build-commands:
      # ── Configure and build ──
      # Install pybind11 + sip into /app (SDK /usr is read-only).
      # Uses SDK's python3 directly (not a venv) so find_package(Python)
      # finds Development headers on cmake reconfiguration.
      - |
        /app/bin/uv pip install --target /app/lib/python3/dist-packages pybind11==2.13.6 sip
        PYBIND11_DIR="$(python3 -c 'import pybind11; print(pybind11.get_cmake_dir())')"
        cmake -S . -B _build -G Ninja \
          -DCMAKE_BUILD_TYPE=Release \
          -DCMAKE_PREFIX_PATH=/app \
          -DPython_EXECUTABLE=/usr/bin/python3 \
          -Dpybind11_DIR="${PYBIND11_DIR}" \
          -DBUILD_PLUGIN_PYTHON=ON
      - cmake --build _build --parallel

      # ── Create output layout ──
      - mkdir -p /app/lib/fluorine/plugins /app/lib/fluorine/dlls /app/lib/fluorine/lib

      # Main binary.
      - cp -f _build/src/src/ModOrganizer /app/lib/fluorine/ModOrganizer-core

      # umu-run (patch and repackage if present).
      - |
        if [ -f _build/src/src/umu-run ]; then
          UMU_PATCH_DIR="$(mktemp -d)"
          cd "${UMU_PATCH_DIR}"
          python3 << 'PATCHEOF'
        import zipfile, pathlib
        zf = zipfile.ZipFile('/run/build/fluorine/_build/src/src/umu-run')
        zf.extractall('src')
        run_py = pathlib.Path('src/umu/umu_run.py')
        src = run_py.read_text()
        old1 = '    env["STEAM_COMPAT_INSTALL_PATH"] = os.environ.get("STEAM_COMPAT_INSTALL_PATH", "")'
        new1 = (old1
            + '\n    env["STEAM_COMPAT_CLIENT_INSTALL_PATH"] = os.environ.get('
            + '\n        "STEAM_COMPAT_CLIENT_INSTALL_PATH", ""'
            + '\n    )')
        if old1 in src and 'STEAM_COMPAT_CLIENT_INSTALL_PATH"] = os.environ' not in src:
            src = src.replace(old1, new1)
        old2 = '            os.environ[key] = val'
        new2 = (old2
            + '\n\n        # GE-Proton treats games with UMU_ID as non-Steam titles and skips'
            + '\n        # the steam.exe DRM bridge.  Remove it for Steam games.'
            + '\n        if "UMU_ID" in os.environ and env.get("SteamAppId", "0") != "0":'
            + '\n            del os.environ["UMU_ID"]')
        if old2 in src and 'del os.environ["UMU_ID"]' not in src:
            src = src.replace(old2, new2, 1)
        run_py.write_text(src)
        PATCHEOF
          python3 -m zipapp src -o /app/lib/fluorine/umu-run -p '/usr/bin/env python3'
          chmod +x /app/lib/fluorine/umu-run
          cd /run/build/fluorine
          rm -rf "${UMU_PATCH_DIR}"
        fi

      # VFS helper (standalone, runs on host for Flatpak FUSE support).
      # Statically linked against libfuse3 — no runtime deps beyond glibc.
      - test -f _build/src/src/mo2-vfs-helper && cp -f _build/src/src/mo2-vfs-helper /app/lib/fluorine/ || true
      - test -f _build/src/src/mo2-process-helper && cp -f _build/src/src/mo2-process-helper /app/lib/fluorine/ || true

      # lootcli.
      - test -f _build/libs/lootcli/src/lootcli && cp -f _build/libs/lootcli/src/lootcli /app/lib/fluorine/ || true

      # icoutils (symlink from /app/bin where the icoutils module installed them).
      - ln -sf /app/bin/wrestool /app/lib/fluorine/wrestool
      - ln -sf /app/bin/icotool /app/lib/fluorine/icotool
      - ln -sf /app/bin/fusermount3 /app/lib/fluorine/fusermount3
      - ln -sf /app/bin/cabextract /app/lib/fluorine/cabextract

      # fluorine-manager CLI helper.
      - test -f src/fluorine-manager && cp -f src/fluorine-manager /app/lib/fluorine/ || true

      # MO2 plugins (.so).
      - |
        find _build/libs -type f \( \
          -name "libgame_*.so" -o \
          -name "libinstaller_*.so" -o \
          -name "libfomod_plus_*.so" -o \
          -name "libpreview_*.so" -o \
          -name "libdiagnose_*.so" -o \
          -name "libcheck_*.so" -o \
          -name "libtool_*.so" -o \
          -name "libinieditor.so" -o \
          -name "libinibakery.so" -o \
          -name "libbsa_extractor.so" -o \
          -name "libbsa_packer.so" -o \
          -name "libproxy.so" \
        \) -exec cp -f {} /app/lib/fluorine/plugins/ \;

      # Python plugin payload.
      - |
        for f in libplugin_python.so lzokay.py winreg.py \
                 DDSPreview.py Form43Checker.py ScriptExtenderPluginChecker.py; do
          [ -f "_build/src/src/plugins/${f}" ] && cp -f "_build/src/src/plugins/${f}" /app/lib/fluorine/plugins/
        done
        for d in basic_games data libs dlls; do
          [ -d "_build/src/src/plugins/${d}" ] && cp -a "_build/src/src/plugins/${d}" /app/lib/fluorine/plugins/
        done
        rm -f /app/lib/fluorine/plugins/FNIS*.py

      # Source-tree Python plugins (rootbuilder, omod installer, etc.).
      - |
        for f in src/plugins/*.py; do
          [ -f "${f}" ] && cp -f "${f}" /app/lib/fluorine/plugins/
        done

      # Stylesheets / themes.
      - cp -a src/src/stylesheets /app/lib/fluorine/stylesheets

      # 7z runtime.
      - |
        if [ -f _build/src/src/dlls/7z.so ]; then
          cp -f _build/src/src/dlls/7z.so /app/lib/fluorine/dlls/7z.so
          cp -f _build/src/src/dlls/7z.so /app/lib/fluorine/dlls/7zip.dll
        fi

      # Project shared libraries.
      - cp -f _build/libs/uibase/src/libuibase.so /app/lib/fluorine/lib/
      - cp -f _build/libs/libbsarch/liblibbsarch.so /app/lib/fluorine/lib/
      - cp -f _build/libs/archive/src/libarchive.so /app/lib/fluorine/lib/
      - test -f _build/libs/plugin_python/src/runner/librunner.so && cp -f _build/libs/plugin_python/src/runner/librunner.so /app/lib/fluorine/lib/ || true
      - test -f libs/bsa_ffi/target/release/libbsa_ffi.so && cp -f libs/bsa_ffi/target/release/libbsa_ffi.so /app/lib/fluorine/lib/ || true
      - test -f libs/nak_ffi/target/release/libnak_ffi.so && cp -f libs/nak_ffi/target/release/libnak_ffi.so /app/lib/fluorine/lib/ || true

      # Boost libraries (from /app/lib where the boost module installed them).
      - cp -Lf /app/lib/libboost_program_options.so* /app/lib/fluorine/lib/ 2>/dev/null || true
      - cp -Lf /app/lib/libboost_thread.so* /app/lib/fluorine/lib/ 2>/dev/null || true

      # libloot (from /app/lib where the libloot module installed it).
      - |
        if [ -f /app/lib/libloot.so.0 ]; then
          cp -Lf /app/lib/libloot.so.0 /app/lib/fluorine/lib/
          ln -sf libloot.so.0 /app/lib/fluorine/lib/libloot.so
        elif [ -f /app/lib/libloot.so ]; then
          cp -Lf /app/lib/libloot.so /app/lib/fluorine/lib/
        fi

      # Build-tree Python plugin payload.
      - test -d _build/src/src/python && cp -a _build/src/src/python/. /app/lib/fluorine/python/ || true

      # Strip binaries.
      - strip --strip-unneeded /app/lib/fluorine/ModOrganizer-core 2>/dev/null || true
      - find /app/lib/fluorine/plugins -name "*.so" -exec strip --strip-unneeded {} \; 2>/dev/null || true
      - find /app/lib/fluorine/dlls \( -name "*.so" -o -name "*.dll" \) -exec strip --strip-unneeded {} \; 2>/dev/null || true
      - find /app/lib/fluorine/lib -name "*.so*" -exec strip --strip-unneeded {} \; 2>/dev/null || true
      - test -f /app/lib/fluorine/lootcli && strip --strip-unneeded /app/lib/fluorine/lootcli 2>/dev/null || true
      - test -f /app/lib/fluorine/mo2-vfs-helper && strip --strip-unneeded /app/lib/fluorine/mo2-vfs-helper 2>/dev/null || true
      - test -f /app/lib/fluorine/mo2-process-helper && strip --strip-unneeded /app/lib/fluorine/mo2-process-helper 2>/dev/null || true

      # Install wrapper script, desktop file, metainfo, and icon.
      - install -Dm755 flatpak/fluorine-manager-wrapper.sh /app/bin/fluorine-manager
      - install -Dm644 flatpak/com.fluorine.manager.desktop /app/share/applications/com.fluorine.manager.desktop
      - install -Dm644 flatpak/com.fluorine.manager.metainfo.xml /app/share/metainfo/com.fluorine.manager.metainfo.xml
      - install -Dm644 flatpak/com.fluorine.manager.png /app/share/icons/hicolor/256x256/apps/com.fluorine.manager.png

    sources:
      - type: dir
        path: ..