From d1537a2e70c4a502126dc193eacb3ace3276fb44 Mon Sep 17 00:00:00 2001 From: "zhoujiahui.01" Date: Wed, 8 Apr 2026 16:29:39 +0800 Subject: [PATCH 1/2] fix(ci): fix build ci --- .github/workflows/_build.yml | 10 +++++----- uv.lock | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.github/workflows/_build.yml b/.github/workflows/_build.yml index 56d8f52e3..3b1f01899 100644 --- a/.github/workflows/_build.yml +++ b/.github/workflows/_build.yml @@ -244,12 +244,12 @@ jobs: uv pip install maturin TMPDIR=$(mktemp -d) cd crates/ragfs-python - maturin build --release \ + uv run python -m maturin build --release \ --target ${{ matrix.arch == 'aarch64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu' }} \ --out "$TMPDIR" cd ../.. mkdir -p openviking/lib - python3 < Date: Wed, 8 Apr 2026 19:31:59 +0800 Subject: [PATCH 2/2] build: move ragfs-python packaging into setup.py --- .github/workflows/_build.yml | 84 +------------------ Cargo.lock | 26 +++--- crates/ragfs-python/Cargo.toml | 2 +- crates/ragfs-python/src/lib.rs | 20 ++--- pyproject.toml | 1 + setup.py | 13 ++- .../misc/test_root_docker_image_packaging.py | 45 ++++++++++ 7 files changed, 81 insertions(+), 110 deletions(-) create mode 100644 tests/misc/test_root_docker_image_packaging.py diff --git a/.github/workflows/_build.yml b/.github/workflows/_build.yml index 3b1f01899..632537387 100644 --- a/.github/workflows/_build.yml +++ b/.github/workflows/_build.yml @@ -238,55 +238,16 @@ jobs: cp target/${{ matrix.arch == 'aarch64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu' }}/release/ov openviking/bin/ chmod +x openviking/bin/ov - - name: Build ragfs-python and extract into openviking/lib/ (Linux) - shell: bash - run: | - uv pip install maturin - TMPDIR=$(mktemp -d) - cd crates/ragfs-python - uv run python -m maturin build --release \ - --target ${{ matrix.arch == 'aarch64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu' }} \ - --out "$TMPDIR" - cd ../.. - mkdir -p openviking/lib - uv run python < {dst}") - sys.exit(0) - - print("ERROR: No ragfs_python .so/.pyd found in wheel") - sys.exit(1) - PY - rm -rf "$TMPDIR" - echo "Contents of openviking/lib/:" - ls -la openviking/lib/ - name: Clean workspace (force ignore dirty) shell: bash run: | # Back up pre-built artifacts before cleaning cp -a openviking/bin /tmp/_ov_bin || true - cp -a openviking/lib /tmp/_ov_lib || true git reset --hard HEAD git clean -fd rm -rf openviking/_version.py openviking.egg-info # Restore pre-built artifacts cp -a /tmp/_ov_bin openviking/bin || true - cp -a /tmp/_ov_lib openviking/lib || true # Ignore uv.lock changes to avoid dirty state in setuptools_scm git update-index --assume-unchanged uv.lock || true @@ -302,7 +263,7 @@ jobs: echo "=== Check openviking/_version.py ===" if [ -f openviking/_version.py ]; then cat openviking/_version.py; else echo "Not found"; fi echo "=== Verify pre-built artifacts survived clean ===" - ls -la openviking/bin/ openviking/lib/ || true + ls -la openviking/bin/ || true - name: Build package (Wheel Only) run: uv build --wheel @@ -449,57 +410,16 @@ jobs: chmod +x openviking/bin/ov fi - - name: Build ragfs-python and extract into openviking/lib/ (macOS/Windows) - shell: bash - run: | - uv pip install maturin - TMPDIR=$(mktemp -d) - cd crates/ragfs-python - if [[ "${{ matrix.os }}" == "windows-latest" ]]; then - uv run python -m maturin build --release --target x86_64-pc-windows-msvc --out "$TMPDIR" - else - uv run python -m maturin build --release --out "$TMPDIR" - fi - cd ../.. - mkdir -p openviking/lib - uv run python < {dst}") - sys.exit(0) - - print("ERROR: No ragfs_python .so/.pyd found in wheel") - sys.exit(1) - PY - rm -rf "$TMPDIR" - echo "Contents of openviking/lib/:" - ls -la openviking/lib/ - name: Clean workspace (force ignore dirty) shell: bash run: | # Back up pre-built artifacts before cleaning cp -a openviking/bin /tmp/_ov_bin || true - cp -a openviking/lib /tmp/_ov_lib || true git reset --hard HEAD git clean -fd rm -rf openviking/_version.py openviking.egg-info # Restore pre-built artifacts cp -a /tmp/_ov_bin openviking/bin || true - cp -a /tmp/_ov_lib openviking/lib || true # Ignore uv.lock changes to avoid dirty state in setuptools_scm git update-index --assume-unchanged uv.lock || true @@ -515,7 +435,7 @@ jobs: echo "=== Check openviking/_version.py ===" if [ -f openviking/_version.py ]; then cat openviking/_version.py; else echo "Not found"; fi echo "=== Verify pre-built artifacts survived clean ===" - ls -la openviking/bin/ openviking/lib/ || true + ls -la openviking/bin/ || true - name: Build package (Wheel Only) run: uv build --wheel diff --git a/Cargo.lock b/Cargo.lock index d4554e4d2..3dd5e4775 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2949,11 +2949,10 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.23.5" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872" +checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d" dependencies = [ - "cfg-if", "indoc", "libc", "memoffset", @@ -2967,19 +2966,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.23.5" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb" +checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6" dependencies = [ - "once_cell", "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.23.5" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d" +checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089" dependencies = [ "libc", "pyo3-build-config", @@ -2987,9 +2985,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.23.5" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da" +checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -2999,9 +2997,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.23.5" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028" +checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9" dependencies = [ "heck", "proc-macro2", @@ -4147,9 +4145,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tempfile" diff --git a/crates/ragfs-python/Cargo.toml b/crates/ragfs-python/Cargo.toml index c132835cf..6506f20a3 100644 --- a/crates/ragfs-python/Cargo.toml +++ b/crates/ragfs-python/Cargo.toml @@ -11,6 +11,6 @@ crate-type = ["cdylib"] [dependencies] ragfs = { path = "../ragfs" } -pyo3 = { version = "0.23", features = ["extension-module"] } +pyo3 = { version = "0.27", features = ["extension-module"] } tokio = { version = "1", features = ["full"] } serde_json = "1.0" diff --git a/crates/ragfs-python/src/lib.rs b/crates/ragfs-python/src/lib.rs index 9998a69eb..6be96f4ed 100644 --- a/crates/ragfs-python/src/lib.rs +++ b/crates/ragfs-python/src/lib.rs @@ -138,8 +138,8 @@ impl RAGFSBindingClient { } /// Get client capabilities. - fn get_capabilities(&self) -> PyResult> { - Python::with_gil(|py| { + fn get_capabilities(&self) -> PyResult>> { + Python::attach(|py| { let mut m = HashMap::new(); m.insert("version".to_string(), "ragfs-python".into_pyobject(py)?.into_any().unbind()); let features = vec!["memfs", "kvfs", "queuefs", "sqlfs"]; @@ -152,13 +152,13 @@ impl RAGFSBindingClient { /// /// Returns a list of file info dicts with keys: /// name, size, mode, modTime, isDir - fn ls(&self, path: String) -> PyResult { + fn ls(&self, path: String) -> PyResult> { let fs = self.fs.clone(); let entries = self.rt.block_on(async move { fs.read_dir(&path).await }).map_err(to_py_err)?; - Python::with_gil(|py| { + Python::attach(|py| { let list = PyList::empty(py); for entry in &entries { let dict = file_info_to_py_dict(py, entry)?; @@ -176,7 +176,7 @@ impl RAGFSBindingClient { /// size: Number of bytes to read (default: -1, read all) /// stream: Not supported in binding mode #[pyo3(signature = (path, offset=0, size=-1, stream=false))] - fn read(&self, path: String, offset: i64, size: i64, stream: bool) -> PyResult { + fn read(&self, path: String, offset: i64, size: i64, stream: bool) -> PyResult> { if stream { return Err(PyRuntimeError::new_err( "Streaming not supported in binding mode", @@ -191,14 +191,14 @@ impl RAGFSBindingClient { fs.read(&path, off, sz).await }).map_err(to_py_err)?; - Python::with_gil(|py| { + Python::attach(|py| { Ok(PyBytes::new(py, &data).into()) }) } /// Read file content (alias for read). #[pyo3(signature = (path, offset=0, size=-1, stream=false))] - fn cat(&self, path: String, offset: i64, size: i64, stream: bool) -> PyResult { + fn cat(&self, path: String, offset: i64, size: i64, stream: bool) -> PyResult> { self.read(path, offset, size, stream) } @@ -265,13 +265,13 @@ impl RAGFSBindingClient { } /// Get file/directory information. - fn stat(&self, path: String) -> PyResult { + fn stat(&self, path: String) -> PyResult> { let fs = self.fs.clone(); let info = self.rt.block_on(async move { fs.stat(&path).await }).map_err(to_py_err)?; - Python::with_gil(|py| { + Python::attach(|py| { let dict = file_info_to_py_dict(py, &info)?; Ok(dict.into()) }) @@ -432,7 +432,7 @@ impl RAGFSBindingClient { case_insensitive: bool, stream: bool, node_limit: Option, - ) -> PyResult { + ) -> PyResult> { let _ = (path, pattern, recursive, case_insensitive, stream, node_limit); Err(PyRuntimeError::new_err( "grep not yet implemented in ragfs-python", diff --git a/pyproject.toml b/pyproject.toml index d518e847e..07093717f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,7 @@ requires = [ "setuptools>=61.0", "setuptools-scm>=8.0", "cmake>=3.15", + "maturin>=1.0,<2.0", "wheel", ] build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index 2a062b553..3b1275f8f 100644 --- a/setup.py +++ b/setup.py @@ -393,8 +393,7 @@ def build_ragfs_python_artifact(self): print("[OK] Skipping ragfs-python build (OV_SKIP_RAGFS_BUILD=1)") return - maturin_cmd = shutil.which("maturin") - if not maturin_cmd: + if importlib.util.find_spec("maturin") is None: print( "[SKIP] maturin not found. ragfs-python (Rust binding) will not be built.\n" " Install maturin to enable: pip install maturin\n" @@ -409,7 +408,15 @@ def build_ragfs_python_artifact(self): try: print("Building ragfs-python (Rust AGFS binding) via maturin...") env = os.environ.copy() - build_args = [maturin_cmd, "build", "--release", "--out", tmpdir] + build_args = [ + sys.executable, + "-m", + "maturin", + "build", + "--release", + "--out", + tmpdir, + ] # Respect CARGO_BUILD_TARGET for cross-compilation target = env.get("CARGO_BUILD_TARGET") if target: diff --git a/tests/misc/test_root_docker_image_packaging.py b/tests/misc/test_root_docker_image_packaging.py new file mode 100644 index 000000000..312ce4d19 --- /dev/null +++ b/tests/misc/test_root_docker_image_packaging.py @@ -0,0 +1,45 @@ +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] + + +def _read_text(relative_path: str) -> str: + return (REPO_ROOT / relative_path).read_text(encoding="utf-8") + + +def test_root_dockerfile_copies_bot_sources_into_build_context(): + dockerfile = _read_text("Dockerfile") + + assert "COPY bot/ bot/" in dockerfile + + +def test_openviking_package_includes_console_static_assets(): + pyproject = _read_text("pyproject.toml") + setup_py = _read_text("setup.py") + + assert '"console/static/**/*"' in pyproject + assert '"console/static/**/*"' in pyproject.split("vikingbot = [", maxsplit=1)[0] + assert '"console/static/**/*"' in setup_py + + +def test_build_workflow_invokes_maturin_via_python_module(): + workflow = _read_text(".github/workflows/_build.yml") + + assert "Build ragfs-python and extract into openviking/lib/" not in workflow + assert "uv run python -m maturin build --release" not in workflow + assert "uv run python <=1.0,<2.0",' in pyproject + assert '[sys.executable, "-m", "maturin", "build", "--release", "--out", tmpdir]' in setup_py + assert 'shutil.which("maturin")' not in setup_py