Module provider

Module provider 

Source
Expand description

§Command providers

Command providers can be anything from where a command could be installed. These differ from the environments in that a provider merely tells whether a program can be found there or not, but it doesn’t provide the ability to immediately run the program. On the other hand, an execution environment is something that allows the active execution of commands.

Generally speaking, a provider is any sort of package manager (cargo, pip, apt, dnf, …).

Execution environments may have zero or more providers available. Containers usually don’t have providers, whereas a host operating system will offer some means of installing packages.

§Implementing a new provider

The following instructions relate to writing a new provider in Rust, with the goal of inclusion into the application in mind. Of course you don’t have to submit your own provider for inclusion if you don’t want to. Similarly, you can write a custom provider first and then open an issue to discuss long-term reimplementation and inclusion in the application.

Here are the mandatory steps you must take to write a new provider:

  • Create a new module file in the providers module (here) and name if after the desired provider.
  • Next, in the providers root module:
    1. Include your new module (pub mod ...)
    2. Import the module into the code (use ...)
    3. Add your new module to the Provider struct
    4. Pass through the fmt::Display of your new module for Provider
  • In your new provider module:
    1. Import the prelude: use crate::provider::prelude::*;
    2. Create a new type (struct) for your provider with any internal state you need (or none at all)
    3. Implement fmt::Display, and please adhere to the projects naming convention. For example, dnf is usually referred to as DNF.
    4. Implement IsProvider for your new provider
    5. (Optional) Write some tests, in case your provider can be tested
  • In src/lib.rs:
    1. Add your provider into the providers vector

Following you will find a set of guidelines to help you in the process of writing a robust provider. It’s written as a checklist, so feel free to copy it and check the boxes if you want.

  • Interacting with the provider:
    • Test all the different existent queries you can find (i.e. when your provider returns a successful result for existing applications). Some providers change their output format based on what they find, for example by adding optional fields.
    • Test a non-existent search query (Personally I like ‘asdwasda’ for that purpose) and return such errors as ProviderError::NotFound
    • When pre-conditions for your provider aren’t fulfilled (i.e. it needs a specific application/package manager), return a ProviderError::Requirements
    • Prefer offline operation and fall back to online operation only when e.g. package manager caches don’t exist. Log an info message in such cases so the user can deduce from the log why searching took longer than expected.
    • Prefer parsing results from machine-readable output when possible
  • Error handling:
    • Never cause a panic by calling e.g. unwrap(): Prefer wrapping errors into anyhow::Error and returning that as ProviderError::ApplicationError instead. Panics ruin the TUI output and don’t add any value for the end-user.
    • If you want to recover from errors, consider writing a concrete error type for your provider
    • Check if ProviderError already has the error variant you need and reuse that before reimplementing your own version of it
  • Other things:
    • A Candidate must have at least its’ package and actions.execute fields populated. Try to populate as many as you can.
    • Prefer a precise search and returning only few relevant results over generic searches with many results. Built-in providers currently try to stick with less or equal 10 results each.
    • Try to check whether any of the results you find are already installed. Most package managers will happily report that e.g. coreutils provides the ls command, but coreutils is likely already installed.

Feel free to look at some of the existing providers as a reference.

Modules§

apt
APT provider
cargo
Search packages with cargo (Rust)
custom
Custom provider
cwd
Current Working Directory Provider
dnf
Search packages with DNF.
flatpak
Search packages with Flatpak.
pacman
Search packages with pacman
path
Path provider.

Structs§

Actions
Action specification for a Candidate.
Candidate
Potential candidate for a command.
Query
A convenient representation of a search query with its’ results.

Enums§

Error
Provider
Wrapper type for everything implementing IsProvider.

Traits§

IsProvider
A command provider.

Functions§

search_in
Search for command inside the given IsProvider, targeting a specific Environment.