From fe1e04f499916281ecfd3c267da7bb3bb990ed96 Mon Sep 17 00:00:00 2001 From: AntoineGautier Date: Fri, 26 Sep 2025 10:38:35 +0200 Subject: [PATCH 1/2] chore: Remove binaries from repo (stored as artifacts) --- .github/workflows/cmake.yml | 45 +++++--------------------- .github/workflows/master-release.yml | 10 ------ .github/workflows/staging-release.yml | 25 ++++++++++++-- .gitignore | 1 + pyfunnel/lib/darwin64/libfunnel.dylib | Bin 101536 -> 0 bytes pyfunnel/lib/linux64/libfunnel.so | Bin 42968 -> 0 bytes pyfunnel/lib/win64/funnel.dll | Bin 37376 -> 0 bytes pyfunnel/lib/win64/funnel.lib | Bin 8002 -> 0 bytes 8 files changed, 32 insertions(+), 49 deletions(-) delete mode 100755 pyfunnel/lib/darwin64/libfunnel.dylib delete mode 100644 pyfunnel/lib/linux64/libfunnel.so delete mode 100644 pyfunnel/lib/win64/funnel.dll delete mode 100644 pyfunnel/lib/win64/funnel.lib diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index a1f6c97..be4c91e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -86,40 +86,11 @@ jobs: shell: bash run: ctest -C $BUILD_TYPE --verbose - - name: Stage binaries - if: | - contains(matrix.python-version, '3.12') && - ( - (github.event_name == 'push' && github.ref == 'refs/heads/master') || - (github.event_name == 'workflow_call') - ) - run: | - git config --global pull.rebase true - git add ${{ github.workspace }}/pyfunnel/lib - - - name: Push Linux & macOS binaries - if: | - (contains(matrix.os, 'ubuntu') || matrix.os == 'macos-latest') && - contains(matrix.python-version, '3.12') && - ( - (github.event_name == 'push' && github.ref == 'refs/heads/master') || - (github.event_name == 'workflow_call') - ) - run: | - git config --global user.name "${GH_USERNAME}" - git config --global user.email "${GH_USERNAME}@users.noreply.github.com" - git diff-index --quiet HEAD || { git commit -m "Add ${{ matrix.os }} binaries" && git pull && git push; } - - # We use cmd /c because powershell <7 does not support chain operators. - - name: Push Windows binaries - if: | - matrix.os == 'windows-latest' && - contains(matrix.python-version, '3.12') && - ( - (github.event_name == 'push' && github.ref == 'refs/heads/master') || - (github.event_name == 'workflow_call') - ) - run: | - git config --global user.name "${{ env.GH_USERNAME }}" - git config --global user.email "${{ env.GH_USERNAME }}@users.noreply.github.com" - cmd /c 'git diff-index --quiet HEAD || ( git commit -m "Add ${{ matrix.os }} binaries" && git pull && git push )' + - name: Upload platform-specific binaries as artifacts + if: contains(matrix.python-version, '3.12') + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.os }} + path: ${{ github.workspace }}/pyfunnel/lib/ + retention-days: 30 + if-no-files-found: error diff --git a/.github/workflows/master-release.yml b/.github/workflows/master-release.yml index c178e14..7afba59 100644 --- a/.github/workflows/master-release.yml +++ b/.github/workflows/master-release.yml @@ -98,16 +98,6 @@ jobs: exit 1 fi - - name: Check for binaries - run: | - if [ -d "pyfunnel/lib" ] && [ "$(ls -A pyfunnel/lib)" ]; then - echo "✅ Binaries found in pyfunnel/lib" - ls -la pyfunnel/lib/ - else - echo "❌ No binaries found in pyfunnel/lib" - exit 1 - fi - merge-to-master: needs: validate-staging runs-on: ubuntu-latest diff --git a/.github/workflows/staging-release.yml b/.github/workflows/staging-release.yml index 224ae0a..221cdac 100644 --- a/.github/workflows/staging-release.yml +++ b/.github/workflows/staging-release.yml @@ -83,6 +83,18 @@ jobs: with: ref: staging + - name: Download all binary artifacts + uses: actions/download-artifact@v4 + with: + pattern: binaries-* + path: pyfunnel/lib/ + merge-multiple: true + + - name: Debug - List downloaded artifacts + run: | + echo "Contents of pyfunnel/lib/ after artifact download:" + find pyfunnel/lib/ -type f -ls || echo "No files found" + - name: Setup Python uses: actions/setup-python@v4 with: @@ -112,6 +124,14 @@ jobs: uses: actions/checkout@v4 with: ref: staging + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Download all binary artifacts + uses: actions/download-artifact@v4 + with: + pattern: binaries-* + path: pyfunnel/lib/ + merge-multiple: true - name: Install from Test PyPI if: github.event.inputs.installation_mode == 'test-pypi' @@ -140,6 +160,9 @@ jobs: - name: Create staging validation marker run: | + git config --global user.name "${GH_USERNAME}" + git config --global user.email "${GH_USERNAME}@users.noreply.github.com" + # Create validation marker indicating successful staging pipeline echo "Staging pipeline completed successfully on $(date)" > .staging-validated echo "Version: ${{ needs.version-bump.outputs.new-release-version }}" >> .staging-validated @@ -150,8 +173,6 @@ jobs: fi echo "Binaries: Built and committed" >> .staging-validated - git config --global user.name "${GH_USERNAME}" - git config --global user.email "${GH_USERNAME}@users.noreply.github.com" git add .staging-validated git commit -m "chore: mark staging pipeline as validated" git push origin staging diff --git a/.gitignore b/.gitignore index f541cdb..70c18ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Binaries *.py[cod] +pyfunnel/lib # Object files *.o diff --git a/pyfunnel/lib/darwin64/libfunnel.dylib b/pyfunnel/lib/darwin64/libfunnel.dylib deleted file mode 100755 index c79acfc2597f8ad968ec92bb5d9953b4c3c63f33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101536 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 diff --git a/pyfunnel/lib/linux64/libfunnel.so b/pyfunnel/lib/linux64/libfunnel.so deleted file mode 100644 index da9498b8a9db44c1188dea175f2573e809adb12f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42968 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 diff --git a/pyfunnel/lib/win64/funnel.dll b/pyfunnel/lib/win64/funnel.dll deleted file mode 100644 index d8a9745346996a57a07af62e6c1ded96624c2744..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37376 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 z 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

CBnHV# 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 Pe)3$@f93qo=fM93>XIn- diff --git a/pyfunnel/lib/win64/funnel.lib b/pyfunnel/lib/win64/funnel.lib deleted file mode 100644 index be2033ef960ad0682298d972bbeb53af92f6f249..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8002 zcmcIpU2I&%75@Aa2%8`O#de(7n+>?ch!DWuq(Q3MO=A#F9LI8;pz@HL8{g}A)%D)h z?zIzDs8y**3!+LM+P)yvmp<@7D;}ygvMQ8N38@G~1p$Hu#Ho-4E)O6@A#G9MoI5jj zX0vzAZq{Av+jH)j+4=6woH=J^y!Cr_eq!qTvHKInpZgvxepXKpNaexgK)+Cr#Q+=t z*31Fx7J#M>pgAkCNRrTURN@tqgw{TZXGt=y3$#(a0I!lHY}hVwmL%hHCOz$+#xa^*9iK`p`w#6qk6CBx6xv^FAQJOC$;1trD{& z8S?@?DImZLBnk1g5>zM7pnCCn%NjZ`dT?yq8hrTB-m#(4@q=U5#&7O2Xyg{8kQ zOxW3SKfk$*e{DO?i08OaQoPggnRLb(wf!k*O_WS{(>XiuLdhcQo~$$G=DfVGinT%3 z%e%Jk280t@6=jZ__43npCjAo^rY=e+(;3%tPo)b!3{{qiLBph!(wcYOLEE=6sT64s zh5?g82-^wQAEu^{*qIr(fZ``z!#nBbgTg=w?IScy^b;1L?Qkw9>Ix;aTMoUEH8Eue z4H-|OMmn4JX~s_=RFu8o=KVcB*`=cFzMIc^85&gi?&Li;Swzi@UGRC_2i=Uzu7whV ztVhEz>{79m!a8lIvk1P_^QnN3Y*LZ-bXMAxBJDqR(s?U~X(@#@>z)iINJ(i8y+Hee zD3Q}!G|S{g&fY^uprojocc;Bsm&PkpO#86sj3-fJmK>Vq+(oDe`^kLTcgMX)$gN@O)yMQ?7}F_0V{Q$wu#O^W6Oe5N z770gNfL9286#1SdTqhiD170O;-vFE?TqPW72hJ0EJAl)KCBk?oaE{Qu5qO4hjqrFE z@etyhfF}uygngTVmk6yCt!D}Igj5gk0%0vh=2^l#fszjDP>)8e!fm)6t8oWnScA1# zhxKSeGg{D!Hf%sUI?#!Y=)xv!MmKs8#}*{86?ft;^x`|X8{5#gf-N=B`mH{?i}|cM zP@BP6G+8e6ic%SXmx-{V-m;-oR4EfTWnuX^DJpQZEDeZZS@{4cs+5a#s}ZbpS={T z14T{o+2OdyXHN7Ul8;D{LR<5qPYTUH+`&1>?(J6v6zuUjVL=)iNT%?>d0B6lG*eUt zZV(offn*Aa^YtWKD01^BraQF_ZOyln>7PLXD4=i0nWtM1q$l!T!JG6GePj0|hKEM> z%km<@T>KskP*i7)k{9I()-(yd0lO)^>Y1nO>c0Nk`~_77zgs<2k5iP=*fOOoLEi+A ztdrzAR7Ka>sV!{Z!e8>kZ2`OG6N`F`()X=oj+OF~{^UdQgvVY|kLUas7tRH5#_tD2 zd5I&6!f(S%29%M#tEhm5u8z6|xe1 z%fRc?Ieq4{e_!U^DX;5g)0QSPR(xf=JJljEcwcU~?~QH5T35nboDmJ$s{Lpng7>!< z7v7`IHThCwc(SgABN^W8=rMi%*S(i$vre(G(Kw~o!V=Y!CkE#(a8DZPPwf(F;YjY5 zi_Vy(eQ%8|u?Mcw9C}-8kZH9tk5DJ0gu(TXKR8kxMIZ)c8 z&Z)(Z>Ci;yo5rHM41=a>Ka1+k(2IZjl6$k7c+5Rna3RIpjH-JR%9KFIma0j!< zO;b%hiHH#X4}Sj{=bIRFs0$l|M5~p}{Xm4D<*)Tzp`$OIHi<(VYjm?!k5qDJ>AXL- z|IvTZ!I<_ z$=S{z(`sd-7Zu48cOUF(|6` zttbxfwMXWeV-s4qutepq|9$@QdmM|qiKR3JYqrY# zDr&5L_umgM^H}u|gSryY?N+}wqI~y{r_vv?U&R9sc}H)MXtlC_MD2+>|8zCj;cW>y zf}0%OboDDFVu!c)=MR6$JG?~5A})yxnicWjvv$v0JS$s?M_oYG!V$G=`TW#(-{%Z@ zr{FODhfxz#L|pml{Y@8m{_i5D@Z!uM(Q1YBA2BmOTJ_gAd1iWv!@QHzZ6o##1Xk^% From 27392b87506bdd7eb250c781603bf309bf2a0235 Mon Sep 17 00:00:00 2001 From: AntoineGautier Date: Fri, 26 Sep 2025 11:39:50 +0200 Subject: [PATCH 2/2] fix: Restore compatibility with Ubuntu 20.04 --- .github/workflows/cmake.yml | 88 ++++++++++++++++++++++++--- .github/workflows/staging-release.yml | 6 +- README.md | 14 ++--- src/mkdir_p.c | 7 +++ 4 files changed, 94 insertions(+), 21 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index be4c91e..ecbcf06 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -25,11 +25,11 @@ jobs: !contains(github.event.head_commit.message, 'ci skip') runs-on: ${{ matrix.os }} outputs: - result: ${{ steps.test.outcome }} + result: ${{ startsWith(matrix.os, 'ubuntu') && steps.ubuntu-test.outcome || steps.test.outcome }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-24.04, windows-2022, macos-14] python-version: ['3.8', '3.12'] steps: @@ -37,11 +37,73 @@ jobs: with: ref: ${{ github.event_name == 'workflow_call' && inputs.ref || github.ref }} - - name: Enable Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1.12.1 + - name: Get runner UID/GID + if: startsWith(matrix.os, 'ubuntu') + id: runner-info + run: echo "uid=$(id -u)" >> $GITHUB_OUTPUT && echo "gid=$(id -g)" >> $GITHUB_OUTPUT + + - name: Build in container for Ubuntu 20.04 (for broader compatibility) + if: startsWith(matrix.os, 'ubuntu') + uses: addnab/docker-run-action@v3 + with: + image: ubuntu:20.04 + options: -v ${{ github.workspace }}:/home/runner/funnel + shell: bash + run: | + export DEBIAN_FRONTEND=noninteractive + export TZ=UTC + apt update + apt install -y software-properties-common build-essential wget + # Python install and venv setup + if [ "${{ matrix.python-version }}" == "3.8" ]; then + apt install -y python3 python3-pip python3-venv + PYTHON_CMD=python3 + else + add-apt-repository ppa:deadsnakes/ppa + apt update && apt install -y \ + python${{ matrix.python-version }} \ + python${{ matrix.python-version }}-venv \ + python${{ matrix.python-version }}-dev \ + curl + PYTHON_CMD=python${{ matrix.python-version }} + # Install pip for the specific Python version + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + $PYTHON_CMD get-pip.py + rm get-pip.py + fi + # Create group and user matching the runner + groupadd -g ${{ steps.runner-info.outputs.gid }} runnergroup + useradd -u ${{ steps.runner-info.outputs.uid }} -g runnergroup -m runner + chown -R runner:runnergroup /home/runner + # Build and test funnel as runner + su runner << 'EOF' + # CMake install + cd /home/runner + CMAKE_VERSION=3.22.6 + wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz + tar -xzf cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz + export PATH=$PWD/cmake-${CMAKE_VERSION}-linux-x86_64/bin:$PATH + echo "CMake version: " && cmake --version + # Create and activate virtual environment + $PYTHON_CMD -m venv /venv + source /venv/bin/activate + echo "Python version: " && python --version + cd /home/runner/funnel + pip install --upgrade pip + pip install ".[dev]" # In Python 3.8 editable mode still requires setup.py + mkdir -p build && cd build && cmake .. + cmake --build . --target install --config ${{ env.BUILD_TYPE }} + ctest -C ${{ env.BUILD_TYPE }} --verbose + cd /home/runner/funnel + rm -rf pyfunnel.egg-info + EOF + + - name: Enable Developer Command Prompt on Windows if: startsWith(matrix.os, 'windows') + uses: ilammy/msvc-dev-cmd@v1.12.1 - name: Setup cmake + if: ${{ !startsWith(matrix.os, 'ubuntu') }} uses: jwlawson/actions-setup-cmake@v1.13 with: cmake-version: '3.22.x' @@ -58,6 +120,7 @@ jobs: python -m pip install --user -e ".[dev]" - name: Create Build Environment + if: ${{ !startsWith(matrix.os, 'ubuntu') }} # Some projects don't allow in-source building, so create a separate build directory # We'll use this as our working directory for all subsequent commands. run: | @@ -65,26 +128,33 @@ jobs: cmake -E make_directory ${{ github.workspace }}/build - name: Configure CMake + if: ${{ !startsWith(matrix.os, 'ubuntu') }} # Use a bash shell so we can use the same syntax for environment variable # access regardless of the host operating system shell: bash working-directory: ${{ github.workspace }}/build - # Note the current convention is to use the -S and -B options here to specify source - # and build directories, but this is only available with CMake 3.13 and higher. - # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 run: cmake .. - name: Build id: build + if: ${{ !startsWith(matrix.os, 'ubuntu') }} working-directory: ${{ github.workspace }}/build shell: bash - run: cmake --build . --target install --config $BUILD_TYPE + run: cmake --build . --target install --config ${{ env.BUILD_TYPE }} - name: Test id: test + if: ${{ !startsWith(matrix.os, 'ubuntu') }} working-directory: ${{ github.workspace }}/build shell: bash - run: ctest -C $BUILD_TYPE --verbose + run: ctest -C ${{ env.BUILD_TYPE }} --verbose + + - name: Test simple test in latest Ubuntu + id: ubuntu-test + if: startsWith(matrix.os, 'ubuntu') + run: | + # Run the test from the directory with test data + cd tests/test_bin && funnel --reference trended.csv --test simulated.csv --atolx 0.002 --atoly 0.002 - name: Upload platform-specific binaries as artifacts if: contains(matrix.python-version, '3.12') diff --git a/.github/workflows/staging-release.yml b/.github/workflows/staging-release.yml index 221cdac..dc42d1e 100644 --- a/.github/workflows/staging-release.yml +++ b/.github/workflows/staging-release.yml @@ -141,14 +141,14 @@ jobs: # Install from Test PyPI # The `--extra-index-url https://pypi.org/simple/` ensures dependencies are installed from regular PyPI - python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pyfunnel==${{ needs.version-bump.outputs.new-release-version }} + python -m pip install --user --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pyfunnel==${{ needs.version-bump.outputs.new-release-version }} - name: Install from source if: github.event.inputs.installation_mode == 'source' run: | # Install from source - python -m pip install --upgrade pip - python -m pip install . + python -m pip install --user --upgrade pip + python -m pip install --user . - name: Run test run: | diff --git a/README.md b/README.md index a5644dc..c005c33 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,9 @@ By convention, the error is `max(0, y - y_up) - min(0, y - y_low)` and hence it The software is tested on the following platforms. -- Linux x64 (Ubuntu 24.04) -- Windows x64 (Windows Server 2022) -- macOS x64 and arm64 (macOS 12) +- Linux x64: Ubuntu 20.04 and 24.04 +- Windows x64: Windows Server 2022 +- macOS x64 and arm64: macOS 14 A Python binding is available to access the library. It is supported on Python versions 3.8 through 3.12. @@ -86,11 +86,7 @@ The package `pyfunnel` provides the following functions. Displays plot in default browser. See function docstring for further details. A standalone CLI script `pyfunnel/cli.py` is available, which is also accessible via the -`funnel` entry point when the package is installed. -To access the usage instructions, use one of the following: - -- Installed package: `funnel --help` -- Standalone: `python pyfunnel/cli.py --help` +`funnel` entry point when the package is installed. To access the usage instructions, run: `funnel --help` ### Example @@ -109,7 +105,7 @@ From a Python shell with `./tests/test_bin` as the current working directory, ru Or from a terminal with `./tests/test_bin` as the current working directory, run ```bash -python ../../pyfunnel/cli.py --reference trended.csv --test simulated.csv --atolx 0.002 --atoly 0.002 +funnel --reference trended.csv --test simulated.csv --atolx 0.002 --atoly 0.002 ``` ## Build from Source diff --git a/src/mkdir_p.c b/src/mkdir_p.c index d47382a..6b959f8 100755 --- a/src/mkdir_p.c +++ b/src/mkdir_p.c @@ -20,6 +20,13 @@ int mkdir_p(const char *path) { /* Adapted from http://stackoverflow.com/a/2336245/119527 */ + + // Validate input + if (strpbrk(path, "*|<>?\"") != NULL) { + errno = EINVAL; + return -1; + } + const size_t len = strlen(path); char *_path = NULL; char *p;