#process #group #command #session #pty

无 std process-wrap

封装命令,以在组、会话或作业等中启动进程

7 个稳定版本

8.0.2 2024年5月31日
8.0.0 2024年4月20日
7.1.0 2024年4月20日
6.0.1 2024年3月11日
5.3.0 2024年3月11日

操作系统 类别中排名第 113

Download history 350/week @ 2024-05-03 399/week @ 2024-05-10 503/week @ 2024-05-17 385/week @ 2024-05-24 4507/week @ 2024-05-31 6291/week @ 2024-06-07 6507/week @ 2024-06-14 6555/week @ 2024-06-21 6405/week @ 2024-06-28 7065/week @ 2024-07-05 7630/week @ 2024-07-12 7756/week @ 2024-07-19 7591/week @ 2024-07-26 8184/week @ 2024-08-02 8422/week @ 2024-08-09 7358/week @ 2024-08-16

每月下载量 32,968
用于 8 个 crate (直接使用 4 个)

Apache-2.0 或 MIT 许可

175KB
1.5K SLoC

Crate release version Crate license: Apache 2.0 or MIT CI status

process-wrap

  • API 文档.
  • 双许可 Apache 2.0 和 MIT。
  • command-group 的继任者。
  • 最低支持的 Rust 版本:1.75.0。
    • 仅支持最新的稳定 rustc 版本。
    • MSRV 的增加不会引起主要版本号的升级。

与 command-group 不同,process-wrap 不实现单一的跨平台 API。相反,它提供可组合的封装,每个封装实现一个关注点。开发者需要根据自己的用例和平台选择适当的封装。

作为 command-group 的继任者(并且包含大量的 command-group 代码),版本号从 6.0.0 开始。你可以将其视为对 command-group 的破坏性更改,尽管范式相当不同。保留了 command-group 的完整测试套件:process-wrap 以功能一致性为起点。

快速开始

[dependencies]
process-wrap = { version = "8.0.2", features = ["tokio1"] }

默认情况下,crate 什么都不做,你需要启用 std 或 Tokio "前端"。启用了一组默认的封装;你可以选择仅编译所需的封装,请参阅 功能列表

use tokio::process::Command;
use process_wrap::tokio::*;

let mut child = TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ProcessGroup::leader())
  .spawn()?;
let status = Box::into_pin(child.wait()).await?;
dbg!(status);

或 Windows 平台

use tokio::process::Command;
use process_wrap::tokio::*;

let mut child = TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(JobObject::new())
  .spawn()?;
let status = Box::into_pin(child.wait()).await?;
dbg!(status);

或会话

use tokio::process::Command;
use process_wrap::tokio::*;

let mut child = TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ProcessSession)
  .spawn()?;
let status = Box::into_pin(child.wait()).await?;
dbg!(status);

或多个封装

use tokio::process::Command;
use process_wrap::tokio::*;

let mut child = TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ProcessSession)
  .wrap(KillOnDrop)
  .spawn()?;
let status = Box::into_pin(child.wait()).await?;
dbg!(status);

或 std

[dependencies]
process-wrap = { version = "8.0.2", features = ["std"] }
use std::process::Command;
use process_wrap::std::*;

let mut child = StdCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ProcessGroup::leader())
  .spawn()?;
let status = child.wait()?;
dbg!(status);

封装

作业对象

  • 平台:Windows
  • 与 command-group 类似。
  • 功能: job-object(默认)
TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(JobObject)
  .spawn()?;

进程组

  • 平台:POSIX(Linux、Mac、BSD 等)
  • 与 command-group >=5.0.0 类似。
  • 功能: process-group(默认)
TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ProcessGroup::leader())
  .spawn()?;

或加入不同的组

TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ProcessGroup::attach_to(pgid))
  .spawn()?;

对于 Windows 进程组,使用 CreationFlags::NEW_PROCESS_GROUP 和/或 JobObject::new()

进程会话

  • 平台:POSIX(Linux、Mac、BSD 等)
  • 与 command-group <5.0.0 类似。
  • 功能: process-session(默认)

这结合了创建新的会话和新的组,并将此进程设置为领导者。要从其他进程加入会话,请使用 ProcessGroup::attach_to() 代替。

TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ProcessSession)
  .spawn()?;

重置信号掩码

  • 平台:POSIX(Linux、Mac、BSD 等)
  • 功能: reset-sigmask

这会将进程的信号掩码重置,而不是从父进程继承。

TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(ResetSigmask)
  .spawn()?;

创建标志

  • 平台:Windows
  • 与 command-group 类似。
  • 特性:creation-flags(默认)

这是一个垫片,允许使用此API设置Windows进程创建标志,否则它们会被覆盖。

use windows::Win32::System::Threading::*;
TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(CreationFlags(CREATE_NO_WINDOW | CREATE_DETACHED))
  .wrap(JobObject)
  .spawn()?;

在释放时杀死

  • 平台:所有平台(仅Tokio)
  • 与 command-group 类似。
  • 特性:kill-on-drop(默认)

这是一个垫片,允许包装器处理在释放时杀死标志,因为它不能从命令中读取。

let child = TokioCommandWrap::with_new("watch", |command| { command.arg("ls"); })
  .wrap(KillOnDrop)
  .wrap(ProcessGroup::leader())
  .spawn()?;
drop(child);

您自己的

通过一组特质来实现包装器。由于底层API的不同,std和Tokio方面完全独立。当然,在实现两个时,您应该尽可能重用/共享代码。

至少,您必须实现StdCommandWrapper和/或TokioCommandWrapper。它们提供相同的功能,但在指定的确切类型上有所不同。以下是Tokio的最基本实现(以Tokio为例)

#[derive(Debug)]
pub struct YourWrapper;
impl TokioCommandWrapper for YourWrapper {}

没错,所有成员方法都是可选的。特质提供了扩展或钩子,以便在Command的生命周期中

  • fn extend(&mut self, other: Box<dyn TokioCommandWrapper>)被调用两次时。包装器类型只能存在一个,因此这提供了将第二个包装器实例的全部或部分合并到第一个实例中的机会。默认情况下,这不会做任何事情(即只有第一个注册的包装器实例的类型才会做任何事情)。

  • fn pre_spawn(&mut self, command: &mut Command, core: &TokioCommandWrap)在命令启动之前被调用,并提供对它的可变访问。它还提供了对包装器实例的可变访问,因此如果需要,可以存储状态。对core的引用提供了对其他包装器数据的访问;例如,Windows上的CreationFlags就是通过与JobObject一起工作的。默认情况下是Noop。

  • fn post_spawn(&mut self, child: &mut tokio::process::Child, core: &TokioCommandWrap)在启动后调用,应用于任何必要的清理。它提供了一种完整性,但预计不如wrap_child()使用得多。默认情况下是Noop。

  • fn wrap_child(&mut self, child: Box<dyn TokioChildWrapper>, core: &TokioCommandWrap) 在所有 post_spawn() 运行后调用。如果你的包装器需要覆盖 Child 的方法,那么它应该创建一个实现 TokioChildWrapper 的自身类型的实例,并将其返回此处。子包装器是按 顺序 的:你最终可能会得到一个 Foo(Bar(Child)) 或一个 Bar(Foo(Child)),具体取决于是否调用了 .wrap(Foo).wrap(Bar).wrap(Bar).wrap(Foo)。如果你的功能依赖于顺序,请确保在您的文档中指定!默认为无操作:不执行包装,直接返回输入的 child

有关更多详情和子包装器特质的详细信息,请参阅 API 文档

功能

前端

  • std:启用基于 std 的 API。
  • tokio1:启用基于 Tokio 的 API。

两者可以同时存在,但通常您应该使用其中一个。

封装

依赖关系

~1–41MB
~615K SLoC