Skip to main content

Channel

Enum Channel 

Source
pub enum Channel {
    Installer,
    Cargo,
    Npm,
    UvTool,
    Pipx,
    Pip,
    WinGet,
    Scoop,
    Homebrew,
    Unknown,
}
Expand description

The package manager that owns the running binary.

One channel owns one binary. A copy installed through uv is upgraded through uv, never through npm, because two managers writing the same PATH entry would fight over it forever.

Variants§

§

Installer

install.sh / install.ps1 put it under the managed <config>/bin.

§

Cargo

cargo install / cargo binstall put it under ~/.cargo/bin.

§

Npm

npm install -g — the binary lives under a node_modules tree.

§

UvTool

uv tool install — under uv’s tool environments.

§

Pipx

pipx install — under a pipx venv.

§

Pip

pip install — a console script beside a Python interpreter, in the system scripts directory or a virtualenv’s.

§

WinGet

winget install — under %LOCALAPPDATA%\Microsoft\WinGet\Packages.

§

Scoop

scoop install — under ~/scoop/apps, shimmed from ~/scoop/shims.

§

Homebrew

brew install — under the Cellar, symlinked into the prefix’s bin.

§

Unknown

Anywhere else: a dev build, a hand-copied binary, a distro package.

Implementations§

Source§

impl Channel

Source

pub fn detect() -> Self

Classify the running executable.

Source

pub fn detect_at(exe: &Path, managed: Option<&Path>) -> Self

Classify exe by the directories in its path.

Purely lexical: this must not touch the network or spawn anything, and each channel’s layout is stable enough that its marker directory is a reliable fingerprint. managed is passed in rather than resolved here so tests can probe the classification without a config directory on disk.

The managed path is checked first and the three directory-owning managers next. Order is load-bearing at least once already: a Scoop install of a Rust toolchain can put .cargo inside ~/scoop, and misreading that as Cargo would send devp update to run cargo install against a directory Scoop replaces wholesale.

Source

pub fn label(self) -> &'static str

How to name this channel in a sentence addressed to the user.

Source

pub fn upgrade_command(self) -> Option<String>

The command that upgrades through this channel, as the user would type it.

None for Channel::Unknown only: there is no command to name for a binary somebody copied into place by hand.

Source

pub fn uninstall_command(self) -> Option<String>

The command that uninstalls through this channel.

None where there is no manager to tell: the installer’s own copy is deleted by devp uninstall itself, and an unrecognised copy is just a file.

Source

pub fn owns_its_files(self) -> bool

Whether a package manager keeps a record of this install that deleting the file would falsify.

When true, devp uninstall names the manager’s own command instead of quietly removing the file: pip list still showing a package whose binary is gone, or cargo install refusing to reinstall over its own bookkeeping, is worse than a leftover binary the user was told about.

Source

pub fn replaces_its_directory(self) -> bool

Whether this channel replaces its install directory wholesale on upgrade.

This is the distinction the old per-command classifiers did not have, and the one that caused a real bug. WinGet, Scoop and Homebrew each version their package directory and swap the whole thing — …\WinGet\Packages\<id>\, ~/scoop/apps/ <pkg>/<version>/, <prefix>/Cellar/<pkg>/<version>/. Anything dev-prune writes beside its own executable there is gone at the next upgrade, and anything pointing at it — a scheduled task, a git hook — is left aimed at a path that no longer exists.

So nothing durable is ever written into one of these directories. The devp twin goes to the managed <config>/bin instead, which this program owns and which no package manager will replace underneath it.

Trait Implementations§

Source§

impl Clone for Channel

Source§

fn clone(&self) -> Channel

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Channel

Source§

impl Debug for Channel

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Channel

Source§

impl PartialEq for Channel

Source§

fn eq(&self, other: &Channel) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Channel

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.