From bdca145e5e078a676927fb89b8cd33ce63f48bf7 Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 28 Mar 2026 21:05:07 +0300 Subject: [PATCH 1/9] wip --- .github/workflows/build.yml | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..8589684dc --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,43 @@ +name: Build Distribution Files + +on: + push: + branches: [ fourdiff-pypi ] + pull_request: + branches: [ fourdiff-pypi ] + +jobs: + build: + runs-on: ubuntu-latest + container: + # Latest right now, based on ubuntu 24.04 + image: condaforge/miniforge3:26.1.1-3 + + # defaults: + # run: + # shell: bash -l {0} # Important for conda to work properly + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build the files + run: | + echo "Conda is ready! Python version: $(python --version)" + echo "Conda environment: $(conda info --envs | grep '*' )" + mkdir dist + echo 'hello' > dist/hello + + # === Put your actual build commands here === + # Examples: + # conda install -c conda-forge some-package another-package + # mamba env update --file environment.yml + # python build_script.py + # make build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: built-files + path: dist/ + retention-days: 7 From 94867b7d4977978f17da1a42baa1307cec6b962d Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 28 Mar 2026 21:15:35 +0300 Subject: [PATCH 2/9] wip --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8589684dc..cc7da4cb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Build the files run: | @@ -36,7 +36,7 @@ jobs: # make build - name: Upload build artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: built-files path: dist/ From 8bc84e02c7021aa5831a1968baf68bfef0aad769 Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 28 Mar 2026 21:20:33 +0300 Subject: [PATCH 3/9] wip --- .github/workflows/build.yml | 3 +++ .github/workflows/debug-ssh.yml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cc7da4cb9..ec5c47547 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,9 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 + - name: upterm ssh debug + uses: owenthereal/action-upterm@v1 + - name: Build the files run: | echo "Conda is ready! Python version: $(python --version)" diff --git a/.github/workflows/debug-ssh.yml b/.github/workflows/debug-ssh.yml index 73c37e710..a3710a699 100644 --- a/.github/workflows/debug-ssh.yml +++ b/.github/workflows/debug-ssh.yml @@ -7,7 +7,7 @@ on: description: 'Enable debug SSH?' required: false default: 'false' - pull_request: + #pull_request: jobs: build: From 1eb0cb4906e35c180f64aaf5104f7e1dec9daf7c Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 28 Mar 2026 21:23:53 +0300 Subject: [PATCH 4/9] wip --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec5c47547..be00253f7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 + - name: prepare for ssh debug + run: | + apt-get update && apt-get install -y --no-install-recommends tmux + - name: upterm ssh debug uses: owenthereal/action-upterm@v1 From 62c3d5132736d3ed98536ae664a8f988c39c9556 Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 28 Mar 2026 21:27:20 +0300 Subject: [PATCH 5/9] wip --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index be00253f7..90f798901 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: - name: prepare for ssh debug run: | - apt-get update && apt-get install -y --no-install-recommends tmux + apt-get update && apt-get install -y --no-install-recommends tmux openssh-client - name: upterm ssh debug uses: owenthereal/action-upterm@v1 From 9a3835a672577d1b95a9a849d5637827daed4b06 Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 28 Mar 2026 22:05:27 +0300 Subject: [PATCH 6/9] wip --- .github/workflows/build.yml | 23 ++++++----------------- bundler/bundler.py | 13 ++++++++++--- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90f798901..67415e17e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,26 +21,15 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - name: prepare for ssh debug - run: | - apt-get update && apt-get install -y --no-install-recommends tmux openssh-client + # - name: prepare for ssh debug + # run: | + # apt-get update && apt-get install -y --no-install-recommends tmux openssh-client - - name: upterm ssh debug - uses: owenthereal/action-upterm@v1 + # - name: upterm ssh debug + # uses: owenthereal/action-upterm@v1 - name: Build the files - run: | - echo "Conda is ready! Python version: $(python --version)" - echo "Conda environment: $(conda info --envs | grep '*' )" - mkdir dist - echo 'hello' > dist/hello - - # === Put your actual build commands here === - # Examples: - # conda install -c conda-forge some-package another-package - # mamba env update --file environment.yml - # python build_script.py - # make build + run: bundler/bundler.py --workdir work - name: Upload build artifacts uses: actions/upload-artifact@v6 diff --git a/bundler/bundler.py b/bundler/bundler.py index 84ed20266..307169278 100755 --- a/bundler/bundler.py +++ b/bundler/bundler.py @@ -7,7 +7,7 @@ import re import sys from pathlib import Path -from shutil import copy, copytree +from shutil import copy, copytree, which from subprocess import check_call from tempfile import mkdtemp, mkstemp @@ -323,11 +323,18 @@ def main(): parser = ArgumentParser(description="build and bundle") parser.add_argument("--workdir", type=Path, help="Path for work. If not given, will be chosen in /tmp") - parser.add_argument("conda", type=Path, help="path to conda executable") + parser.add_argument("--conda", type=Path, help="Path to conda executable. If not given, will be taken from PATH") args = parser.parse_args() workdir = args.workdir or Path(mkdtemp(prefix="meld-bundler-workdir-")) - build_all(args.conda, workdir) + if args.conda: + conda = args.conda + else: + conda0 = which('conda') + if conda0 is None: + raise RuntimeError("Couldn't find conda") + conda = Path(conda0) + build_all(conda, workdir) if __name__ == "__main__": From 46a066024cb63f14131109034c96bedac4a59e4a Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 28 Mar 2026 22:08:43 +0300 Subject: [PATCH 7/9] wip --- .github/workflows/build.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 67415e17e..7a97e1415 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,17 +13,13 @@ jobs: # Latest right now, based on ubuntu 24.04 image: condaforge/miniforge3:26.1.1-3 - # defaults: - # run: - # shell: bash -l {0} # Important for conda to work properly - steps: - name: Checkout repository uses: actions/checkout@v6 - # - name: prepare for ssh debug - # run: | - # apt-get update && apt-get install -y --no-install-recommends tmux openssh-client + - name: Install ubuntu packages + run: | + apt-get update && apt-get install -y --no-install-recommends tmux openssh-client build-essential pkg-config # - name: upterm ssh debug # uses: owenthereal/action-upterm@v1 From 54833c984a01347d5071daefe616cb33a3635182 Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Mon, 27 Apr 2026 09:31:32 +0300 Subject: [PATCH 8/9] wip --- .github/workflows/build.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7a97e1415..781e4e043 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,8 @@ jobs: runs-on: ubuntu-latest container: # Latest right now, based on ubuntu 24.04 - image: condaforge/miniforge3:26.1.1-3 + #image: condaforge/miniforge3:26.1.1-3 + image: ubuntu:24.04 steps: - name: Checkout repository @@ -19,8 +20,10 @@ jobs: - name: Install ubuntu packages run: | - apt-get update && apt-get install -y --no-install-recommends tmux openssh-client build-essential pkg-config + apt-get update && build-essential pkg-config python + # - name: install upterm requirements + # run: apt-get install -y --no-install-recommends tmux openssh-client # - name: upterm ssh debug # uses: owenthereal/action-upterm@v1 From 19c690b076742cfa17c4414dcc440caa39178d8a Mon Sep 17 00:00:00 2001 From: Noam Raphael Date: Sat, 22 Aug 2026 22:56:22 +0300 Subject: [PATCH 9/9] add bundler/dedup_solibs.py --- bundler/dedup_solibs.py | 119 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 bundler/dedup_solibs.py diff --git a/bundler/dedup_solibs.py b/bundler/dedup_solibs.py new file mode 100644 index 000000000..c1e87e2d3 --- /dev/null +++ b/bundler/dedup_solibs.py @@ -0,0 +1,119 @@ +from __future__ import annotations + +import os +import re +from pathlib import Path +from subprocess import check_call +from tempfile import mkstemp + + +def get_solib_groups(env: Path) -> dict[str, list[str]]: + libdir = env / 'lib' + solib_groups: dict[str, list[str]] = {} + for fn in libdir.iterdir(): + name = fn.name + if '.so' not in name: + continue + base = name[:name.index('.so') + 3] + if base == 'libgcc_s.so': + # This is special, libgcc_s.so and libgcc_s.so.1 are different + continue + solib_groups.setdefault(base, []).append(name) + for names in solib_groups.values(): + # Sort fns so the first one is the shortest one, which should be copied + names.sort(key=lambda name: len(name)) + fns = [libdir.joinpath(name) for name in names] + # In some cases there are equal files which are not symlinks. So just read all of them. + bs = [fn.read_bytes() for fn in fns] + for fn, b in zip(fns, bs): + if b != bs[0]: + raise RuntimeError(f"Expecting {fns[0]} and {fn} to have the same content") + return solib_groups + + +def fix_solib_names_in_bytes(solib_groups: dict[str, list[str]], solib_re: re.Pattern[bytes], matches: list[re.Match[bytes]], b0: bytes, is_binary: bool) -> bytes: + if is_binary: + terminators = [0] + else: + terminators = [ord(','), ord('"')] + b = bytes() + last_pos = 0 + ignore_matches_before = 0 + for match in matches: + if match.start() < ignore_matches_before: + continue + short = match.group(0) + names = solib_groups[short.decode('ascii')] + for end_pos in range(match.start(), len(b0)): + if b0[end_pos] in terminators: + break + else: + # We accept the end of string as a terminator, for the recursive call. + end_pos = len(b0) + segment = b0[match.start():end_pos] + name = segment.decode('ascii') + if name not in names: + if name == 'libGLX.so.1': + # Probably refers to the OS + continue + if is_binary: + # We can have a string like "libharfbuzz-gobject.so.0,libharfbuzz.so.0" in a binary typelib file. + # So we call ourselves with is_binary=False, to try to replace it with a shorter string. + matches2 = list(solib_re.finditer(segment)) + short = fix_solib_names_in_bytes(solib_groups, solib_re, matches2, segment, is_binary=False) + ignore_matches_before = end_pos + else: + raise RuntimeError(f"Found string {name} but it's not in {names}") + + b += b0[last_pos:match.start()] + b += short + if is_binary: + b += b'\0' * (len(segment) - len(short)) + # Note that the terminator will be copied on the next iteration + last_pos = end_pos + b += b0[last_pos:] + return b + + +def fix_solib_names(strip: Path, solib_groups: dict[str, list[str]], solib_re: re.Pattern[bytes], fn: Path) -> bytes: + b0 = fn.read_bytes() + if b0[:4] == b'\x7fELF': + fd, path = mkstemp() + try: + os.close(fd) + check_call([strip, fn, '-o', path], text=False) + b0 = Path(path).read_bytes() + finally: + os.remove(path) + matches = list(solib_re.finditer(b0)) + if not matches: + return b0 + magic = b0[:4] + if magic in (b'\x7fELF', b'GOBJ'): + is_binary = True + elif magic == b' re.Pattern[bytes]: + return re.compile(b'|'.join(re.escape(name.encode('ascii')) for name in solib_groups.keys())) + + +def test_fix_solib_names(): + solib_groups = { + 'libharfbuzz-gobject.so': ['libharfbuzz-gobject.so', 'libharfbuzz-gobject.so.0'], + 'libharfbuzz.so': ['libharfbuzz.so', 'libharfbuzz.so.0'], + } + solib_re = get_solib_re(solib_groups) + b0 = b"GOBJ\1\2\3libharfbuzz-gobject.so.0,libbla,libharfbuzz.so.0\0FOO" + fd, fn = mkstemp() + try: + os.write(fd, b0) + os.close(fd) + b1 = fix_solib_names(Path('/dev/null'), solib_groups, solib_re, Path(fn)) + finally: + os.remove(fn) + assert b1 == b"GOBJ\1\2\3libharfbuzz-gobject.so,libbla,libharfbuzz.so\0\0\0\0\0FOO"