Skip to content
Merged

Fix ci #1307

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 2 additions & 82 deletions .github/workflows/_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
maturin build --release \
--target ${{ matrix.arch == 'aarch64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu' }} \
--out "$TMPDIR"
cd ../..
mkdir -p openviking/lib
python3 <<PY
import glob
import os
import sys
import zipfile

whls = glob.glob(os.path.join("$TMPDIR", "ragfs_python-*.whl"))
assert whls, "maturin produced no wheel"

with zipfile.ZipFile(whls[0]) as zf:
for name in zf.namelist():
bn = os.path.basename(name)
if bn.startswith("ragfs_python") and (bn.endswith(".so") or bn.endswith(".pyd")):
dst = os.path.join("openviking", "lib", bn)
with zf.open(name) as src, open(dst, "wb") as f:
f.write(src.read())
os.chmod(dst, 0o755)
print(f"Extracted {bn} -> {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

Expand All @@ -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
Expand Down Expand Up @@ -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
maturin build --release --target x86_64-pc-windows-msvc --out "$TMPDIR"
else
maturin build --release --out "$TMPDIR"
fi
cd ../..
mkdir -p openviking/lib
python3 <<PY
import glob
import os
import sys
import zipfile

whls = glob.glob(os.path.join("$TMPDIR", "ragfs_python-*.whl"))
assert whls, "maturin produced no wheel"

with zipfile.ZipFile(whls[0]) as zf:
for name in zf.namelist():
bn = os.path.basename(name)
if bn.startswith("ragfs_python") and (bn.endswith(".so") or bn.endswith(".pyd")):
dst = os.path.join("openviking", "lib", bn)
with zf.open(name) as src, open(dst, "wb") as f:
f.write(src.read())
os.chmod(dst, 0o755)
print(f"Extracted {bn} -> {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

Expand All @@ -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
Expand Down
26 changes: 12 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/ragfs-python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
20 changes: 10 additions & 10 deletions crates/ragfs-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ impl RAGFSBindingClient {
}

/// Get client capabilities.
fn get_capabilities(&self) -> PyResult<HashMap<String, PyObject>> {
Python::with_gil(|py| {
fn get_capabilities(&self) -> PyResult<HashMap<String, Py<PyAny>>> {
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"];
Expand All @@ -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<PyObject> {
fn ls(&self, path: String) -> PyResult<Py<PyAny>> {
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)?;
Expand All @@ -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<PyObject> {
fn read(&self, path: String, offset: i64, size: i64, stream: bool) -> PyResult<Py<PyAny>> {
if stream {
return Err(PyRuntimeError::new_err(
"Streaming not supported in binding mode",
Expand All @@ -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<PyObject> {
fn cat(&self, path: String, offset: i64, size: i64, stream: bool) -> PyResult<Py<PyAny>> {
self.read(path, offset, size, stream)
}

Expand Down Expand Up @@ -265,13 +265,13 @@ impl RAGFSBindingClient {
}

/// Get file/directory information.
fn stat(&self, path: String) -> PyResult<PyObject> {
fn stat(&self, path: String) -> PyResult<Py<PyAny>> {
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())
})
Expand Down Expand Up @@ -432,7 +432,7 @@ impl RAGFSBindingClient {
case_insensitive: bool,
stream: bool,
node_limit: Option<i32>,
) -> PyResult<PyObject> {
) -> PyResult<Py<PyAny>> {
let _ = (path, pattern, recursive, case_insensitive, stream, node_limit);
Err(PyRuntimeError::new_err(
"grep not yet implemented in ragfs-python",
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
13 changes: 10 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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:
Expand Down
45 changes: 45 additions & 0 deletions tests/misc/test_root_docker_image_packaging.py
Original file line number Diff line number Diff line change
@@ -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 <<PY" not in workflow


def test_ragfs_python_uses_pyo3_version_with_python_314_support():
cargo_toml = _read_text("crates/ragfs-python/Cargo.toml")

assert 'pyo3 = { version = "0.27"' in cargo_toml


def test_root_build_system_includes_maturin_for_isolated_builds():
pyproject = _read_text("pyproject.toml")
setup_py = _read_text("setup.py")

assert '"maturin>=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
Loading
Loading