Dedupe Unix & WASI stdlib (#8635)

Follow up to #8591 because I figured out how to deduplicate the code.
This is nicer for future patches that improve WASI support because
Unix-likes and WASI can often share the same dispatch functions.
This commit is contained in:
Joshua Megnauth authored and GitHub committed 2026-09-02 11:38:57 +09:00
1 parent 39682562b3
commit 7ceada0048
6 files changed
+59 -92

No files matched your search

+2
View File
@@ -37,6 +37,8 @@ pub mod posix;
#[cfg(all(feature = "host_env", not(any(unix, windows))))]
#[path = "posix_compat.rs"]
pub mod posix;
#[cfg(all(feature = "host_env", any(unix, target_os = "wasi")))]
pub mod posix_unix_like;
#[cfg(all(
feature = "host_env",
+1 -11
View File
@@ -13,7 +13,7 @@ pub(crate) mod module {
function::{ArgMapping, Either, OptionalArg},
host_env::crt_fd,
ospath::{OsPath, OsPathOrFd},
stdlib::os::{_os, DirFd, SupportFunc, TargetIsDirectory},
stdlib::os::{_os, DirFd, SupportFunc, SymlinkArgs},
};
use core::hint::cold_path;
use libc::intptr_t;
@@ -101,16 +101,6 @@ pub(crate) mod module {
host_nt::supports_virtual_terminal()
}
#[derive(FromArgs)]
pub(super) struct SymlinkArgs<'fd> {
src: OsPath,
dst: OsPath,
#[pyarg(flatten)]
target_is_directory: TargetIsDirectory,
#[pyarg(flatten)]
_dir_fd: DirFd<'fd, { _os::SYMLINK_DIR_FD as usize }>,
}
#[pyfunction]
pub(super) fn symlink(args: SymlinkArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
let src = args.src.to_wide_cstring(vm)?;
+13
View File
@@ -7,6 +7,7 @@ use crate::{
convert::{IntoPyException, ToPyException, ToPyObject},
function::{ArgumentError, FromArgs, FuncArgs},
host_env::{crt_fd, posix::RawMode},
ospath::OsPath,
};
use core::marker::PhantomData;
use std::{io, path::Path};
@@ -123,6 +124,18 @@ impl<const AVAILABLE: usize, KW: DirFdKeyword> FromArgs for DirFd<'_, AVAILABLE,
}
}
#[derive(FromArgs)]
pub(crate) struct SymlinkArgs<'fd> {
pub src: OsPath,
pub dst: OsPath,
#[cfg_attr(any(unix, target_os = "wasi"), expect(unused))]
#[pyarg(flatten)]
pub target_is_directory: TargetIsDirectory,
#[cfg_attr(not(unix), expect(unused))]
#[pyarg(flatten)]
pub dir_fd: DirFd<'fd, { _os::SYMLINK_DIR_FD as usize }>,
}
#[derive(FromArgs)]
pub(super) struct FollowSymlinks(
#[pyarg(named, name = "follow_symlinks", default = true)] pub bool,
+2 -35
View File
@@ -6,6 +6,7 @@ pub use rustpython_host_env::posix::set_inheritable;
#[pymodule(name = "posix", with(
super::os::_os,
super::posix_unix_like::_posix_unix_like,
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
@@ -23,8 +24,7 @@ pub mod module {
function::{ArgMapping, Either, KwArgs, OptionalArg},
ospath::{OsPath, OsPathOrFd},
stdlib::os::{
_os, DirFd, FollowSymlinks, SupportFunc, TargetIsDirectory, fs_metadata,
warn_if_bool_fd,
_os, DirFd, FollowSymlinks, SupportFunc, SymlinkArgs, fs_metadata, warn_if_bool_fd,
},
};
#[cfg(any(
@@ -384,18 +384,6 @@ pub mod module {
.map_err(|err| err.to_pyexception(vm))
}
#[pyattr]
fn environ(vm: &VirtualMachine) -> PyDictRef {
let environ = vm.ctx.new_dict();
for (key, value) in crate::host_env::os::vars_os() {
let key: PyObjectRef = vm.ctx.new_bytes(key.into_vec()).into();
let value: PyObjectRef = vm.ctx.new_bytes(value.into_vec()).into();
environ.set_item(&*key, value, vm).unwrap();
}
environ
}
#[pyfunction]
fn _create_environ(vm: &VirtualMachine) -> PyDictRef {
let environ = vm.ctx.new_dict();
@@ -407,16 +395,6 @@ pub mod module {
environ
}
#[derive(FromArgs)]
pub(super) struct SymlinkArgs<'fd> {
src: OsPath,
dst: OsPath,
#[pyarg(flatten)]
_target_is_directory: TargetIsDirectory,
#[pyarg(flatten)]
dir_fd: DirFd<'fd, { _os::SYMLINK_DIR_FD as usize }>,
}
#[pyfunction]
pub(super) fn symlink(args: SymlinkArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
let src = args.src.into_cstring(vm)?;
@@ -433,17 +411,6 @@ pub mod module {
}
}
#[pyfunction]
#[pyfunction(name = "unlink")]
fn remove(
path: OsPath,
dir_fd: DirFd<'_, { _os::UNLINK_DIR_FD as usize }>,
vm: &VirtualMachine,
) -> PyResult<()> {
rustpython_host_env::posix::unlinkat(dir_fd.get_opt(), &path)
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
}
#[cfg(not(target_os = "redox"))]
#[pyfunction]
fn fchdir(fd: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
+6 -46
View File
@@ -4,38 +4,24 @@
pub(crate) use module::module_def;
#[pymodule(name = "posix", with(super::os::_os))]
#[pymodule(name = "posix", with(
super::os::_os,
#[cfg(any(unix, target_os = "wasi"))]
super::posix_unix_like::_posix_unix_like,
))]
pub(crate) mod module {
use crate::{
Py, PyObjectRef, PyResult, VirtualMachine,
builtins::PyStrRef,
ospath::OsPath,
stdlib::os::{_os, DirFd, SupportFunc, TargetIsDirectory},
stdlib::os::{_os, DirFd, SupportFunc, SymlinkArgs, TargetIsDirectory},
};
#[cfg(not(target_os = "wasi"))]
use {crate::convert::IntoPyException, std::fs};
#[cfg(target_os = "wasi")]
use crate::exceptions::OSErrorBuilder;
#[pyfunction]
pub(super) fn access(_path: PyStrRef, _mode: u8, vm: &VirtualMachine) -> PyResult<bool> {
os_unimpl("os.access", vm)
}
#[cfg(target_os = "wasi")]
#[pyfunction]
#[pyfunction(name = "unlink")]
fn remove(
path: OsPath,
dir_fd: DirFd<'_, { _os::UNLINK_DIR_FD as usize }>,
vm: &VirtualMachine,
) -> PyResult<()> {
rustpython_host_env::posix::unlinkat(dir_fd.get_opt(), &path)
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
}
#[cfg(not(target_os = "wasi"))]
#[pyfunction]
#[pyfunction(name = "unlink")]
@@ -44,37 +30,11 @@ pub(crate) mod module {
fs::remove_file(&path).map_err(|err| err.into_pyexception(vm))
}
#[derive(FromArgs)]
#[allow(unused)]
pub(super) struct SymlinkArgs<'a> {
src: OsPath,
dst: OsPath,
#[pyarg(flatten)]
_target_is_directory: TargetIsDirectory,
#[pyarg(flatten)]
_dir_fd: DirFd<'a, { _os::SYMLINK_DIR_FD as usize }>,
}
#[pyfunction]
pub(super) fn symlink(_args: SymlinkArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
os_unimpl("os.symlink", vm)
}
#[cfg(target_os = "wasi")]
#[pyattr]
fn environ(vm: &VirtualMachine) -> crate::builtins::PyDictRef {
use rustpython_host_env::os::ffi::OsStringExt;
let environ = vm.ctx.new_dict();
for (key, value) in crate::host_env::os::vars_os() {
let key: PyObjectRef = vm.ctx.new_bytes(key.into_vec()).into();
let value: PyObjectRef = vm.ctx.new_bytes(value.into_vec()).into();
environ.set_item(&*key, value, vm).unwrap();
}
environ
}
#[allow(dead_code)]
fn os_unimpl<T>(func: &str, vm: &VirtualMachine) -> PyResult<T> {
Err(vm.new_os_error(format!("{func} is not supported on this platform")))
+35
View File
@@ -0,0 +1,35 @@
#[pymodule(sub)]
pub(crate) mod _posix_unix_like {
use rustpython_host_env::os::ffi::OsStringExt;
use crate::{
PyObjectRef, PyResult, VirtualMachine,
builtins::PyDictRef,
exceptions::OSErrorBuilder,
ospath::OsPath,
stdlib::os::{_os, DirFd},
};
#[pyattr]
fn environ(vm: &VirtualMachine) -> PyDictRef {
let environ = vm.ctx.new_dict();
for (key, value) in crate::host_env::os::vars_os() {
let key: PyObjectRef = vm.ctx.new_bytes(key.into_vec()).into();
let value: PyObjectRef = vm.ctx.new_bytes(value.into_vec()).into();
environ.set_item(&*key, value, vm).unwrap();
}
environ
}
#[pyfunction]
#[pyfunction(name = "unlink")]
fn remove(
path: OsPath,
dir_fd: DirFd<'_, { _os::UNLINK_DIR_FD as usize }>,
vm: &VirtualMachine,
) -> PyResult<()> {
rustpython_host_env::posix::unlinkat(dir_fd.get_opt(), &path)
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
}
}