mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-05-04 10:33:47 +01:00
feat: add dev-only installs (#32)
* feat: add dev flag * fix: do not download dev/prod dependencies at all * fix: only remove direct non-dev dependencies * refactor: formatting * fix: check sub dependencies * fix: remove arc Co-authored-by: dai <contact@daimond113.com> * chore: grammar fixes Co-authored-by: dai <contact@daimond113.com> * chore: remove eagerly implemented traits Co-authored-by: dai <contact@daimond113.com> * refactor: use method over partialeq * chore: use owned type for `DependencyType` Co-authored-by: dai <contact@daimond113.com> * refactor: simplify and improve logic * chore: formatting * fix: install mode works with force mode * chore: remove cow * chore: fits method takes owned self * chore: fix needless borrow * refactor: improve code structure * refactor: avoid manually recreating graph --------- Co-authored-by: dai <contact@daimond113.com>
This commit is contained in:
parent
c51ac12968
commit
debff41488
6 changed files with 89 additions and 31 deletions
|
@ -110,6 +110,7 @@ Installs dependencies for the current project.
|
||||||
|
|
||||||
- `--locked`: Whether to error if the lockfile is out of date.
|
- `--locked`: Whether to error if the lockfile is out of date.
|
||||||
- `--prod`: Whether to not linking dev dependencies.
|
- `--prod`: Whether to not linking dev dependencies.
|
||||||
|
- `--dev`: Whether to only link dev dependencies.
|
||||||
- `--network-concurrency <CONCURRENCY>`: The number of concurrent network
|
- `--network-concurrency <CONCURRENCY>`: The number of concurrent network
|
||||||
requests to make at most. Defaults to 16.
|
requests to make at most. Defaults to 16.
|
||||||
- `--force`: Whether to force reinstall all packages even if they are already
|
- `--force`: Whether to force reinstall all packages even if they are already
|
||||||
|
|
|
@ -9,7 +9,7 @@ use console::style;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use indicatif::MultiProgress;
|
use indicatif::MultiProgress;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
download_and_link::DownloadAndLinkOptions,
|
download_and_link::{DownloadAndLinkOptions, InstallDependenciesMode},
|
||||||
linking::generator::generate_bin_linking_module,
|
linking::generator::generate_bin_linking_module,
|
||||||
manifest::target::TargetKind,
|
manifest::target::TargetKind,
|
||||||
names::{PackageName, PackageNames},
|
names::{PackageName, PackageNames},
|
||||||
|
@ -178,7 +178,7 @@ impl ExecuteCommand {
|
||||||
DownloadAndLinkOptions::<CliReporter<Stderr>, ()>::new(reqwest)
|
DownloadAndLinkOptions::<CliReporter<Stderr>, ()>::new(reqwest)
|
||||||
.reporter(reporter)
|
.reporter(reporter)
|
||||||
.refreshed_sources(refreshed_sources)
|
.refreshed_sources(refreshed_sources)
|
||||||
.prod(true),
|
.install_dependencies_mode(InstallDependenciesMode::Prod),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("failed to download and link dependencies")?;
|
.context("failed to download and link dependencies")?;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::cli::{
|
||||||
run_on_workspace_members,
|
run_on_workspace_members,
|
||||||
};
|
};
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::Project;
|
use pesde::{download_and_link::InstallDependenciesMode, Project};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
#[derive(Debug, Args, Copy, Clone)]
|
#[derive(Debug, Args, Copy, Clone)]
|
||||||
|
@ -16,6 +16,10 @@ pub struct InstallCommand {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
prod: bool,
|
prod: bool,
|
||||||
|
|
||||||
|
/// Whether to only install dev dependencies
|
||||||
|
#[arg(long)]
|
||||||
|
dev: bool,
|
||||||
|
|
||||||
/// The maximum number of concurrent network requests
|
/// The maximum number of concurrent network requests
|
||||||
#[arg(long, default_value = "16")]
|
#[arg(long, default_value = "16")]
|
||||||
network_concurrency: NonZeroUsize,
|
network_concurrency: NonZeroUsize,
|
||||||
|
@ -30,9 +34,16 @@ pub struct InstallCommand {
|
||||||
struct CallbackError(#[from] anyhow::Error);
|
struct CallbackError(#[from] anyhow::Error);
|
||||||
impl InstallCommand {
|
impl InstallCommand {
|
||||||
pub async fn run(self, project: Project, reqwest: reqwest::Client) -> anyhow::Result<()> {
|
pub async fn run(self, project: Project, reqwest: reqwest::Client) -> anyhow::Result<()> {
|
||||||
|
let install_dependencies_mode = match (self.prod, self.dev) {
|
||||||
|
(true, true) => anyhow::bail!("cannot have both prod and dev flags enabled"),
|
||||||
|
(true, false) => InstallDependenciesMode::Prod,
|
||||||
|
(false, true) => InstallDependenciesMode::Dev,
|
||||||
|
(false, false) => InstallDependenciesMode::All,
|
||||||
|
};
|
||||||
|
|
||||||
let options = InstallOptions {
|
let options = InstallOptions {
|
||||||
locked: self.locked,
|
locked: self.locked,
|
||||||
prod: self.prod,
|
install_dependencies_mode,
|
||||||
write: true,
|
write: true,
|
||||||
network_concurrency: self.network_concurrency,
|
network_concurrency: self.network_concurrency,
|
||||||
use_lockfile: true,
|
use_lockfile: true,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::cli::{
|
||||||
run_on_workspace_members,
|
run_on_workspace_members,
|
||||||
};
|
};
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::Project;
|
use pesde::{download_and_link::InstallDependenciesMode, Project};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
#[derive(Debug, Args, Copy, Clone)]
|
#[derive(Debug, Args, Copy, Clone)]
|
||||||
|
@ -25,7 +25,7 @@ impl UpdateCommand {
|
||||||
pub async fn run(self, project: Project, reqwest: reqwest::Client) -> anyhow::Result<()> {
|
pub async fn run(self, project: Project, reqwest: reqwest::Client) -> anyhow::Result<()> {
|
||||||
let options = InstallOptions {
|
let options = InstallOptions {
|
||||||
locked: false,
|
locked: false,
|
||||||
prod: false,
|
install_dependencies_mode: InstallDependenciesMode::All,
|
||||||
write: !self.no_install,
|
write: !self.no_install,
|
||||||
network_concurrency: self.network_concurrency,
|
network_concurrency: self.network_concurrency,
|
||||||
use_lockfile: false,
|
use_lockfile: false,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use anyhow::Context as _;
|
||||||
use console::style;
|
use console::style;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
download_and_link::{DownloadAndLinkHooks, DownloadAndLinkOptions},
|
download_and_link::{DownloadAndLinkHooks, DownloadAndLinkOptions, InstallDependenciesMode},
|
||||||
engine::EngineKind,
|
engine::EngineKind,
|
||||||
graph::{DependencyGraph, DependencyGraphWithTarget},
|
graph::{DependencyGraph, DependencyGraphWithTarget},
|
||||||
lockfile::Lockfile,
|
lockfile::Lockfile,
|
||||||
|
@ -123,7 +123,7 @@ impl DownloadAndLinkHooks for InstallHooks {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct InstallOptions {
|
pub struct InstallOptions {
|
||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
pub prod: bool,
|
pub install_dependencies_mode: InstallDependenciesMode,
|
||||||
pub write: bool,
|
pub write: bool,
|
||||||
pub use_lockfile: bool,
|
pub use_lockfile: bool,
|
||||||
pub network_concurrency: NonZeroUsize,
|
pub network_concurrency: NonZeroUsize,
|
||||||
|
@ -285,7 +285,7 @@ pub async fn install(
|
||||||
.reporter(reporter)
|
.reporter(reporter)
|
||||||
.hooks(hooks)
|
.hooks(hooks)
|
||||||
.refreshed_sources(refreshed_sources.clone())
|
.refreshed_sources(refreshed_sources.clone())
|
||||||
.prod(options.prod)
|
.install_dependencies_mode(options.install_dependencies_mode)
|
||||||
.network_concurrency(options.network_concurrency)
|
.network_concurrency(options.network_concurrency)
|
||||||
.force(options.force || has_irrecoverable_changes),
|
.force(options.force || has_irrecoverable_changes),
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,9 +15,9 @@ use crate::{
|
||||||
};
|
};
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use futures::TryStreamExt as _;
|
use futures::TryStreamExt as _;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
collections::{HashMap, VecDeque},
|
||||||
collections::HashMap,
|
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
future::{self, Future},
|
future::{self, Future},
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
|
@ -65,6 +65,28 @@ impl DownloadAndLinkHooks for () {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Options for which dependencies to install.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum InstallDependenciesMode {
|
||||||
|
/// Install all dependencies
|
||||||
|
All,
|
||||||
|
/// Install all dependencies, then remove [DependencyType::Dev] dependencies
|
||||||
|
Prod,
|
||||||
|
/// Only install dependencies which are [DependencyType::Dev]
|
||||||
|
Dev,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstallDependenciesMode {
|
||||||
|
fn fits(self, dep_ty: DependencyType) -> bool {
|
||||||
|
match (self, dep_ty) {
|
||||||
|
(InstallDependenciesMode::Prod, DependencyType::Dev) => false,
|
||||||
|
(InstallDependenciesMode::Dev, dep_ty) => dep_ty == DependencyType::Dev,
|
||||||
|
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Options for downloading and linking.
|
/// Options for downloading and linking.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DownloadAndLinkOptions<Reporter = (), Hooks = ()> {
|
pub struct DownloadAndLinkOptions<Reporter = (), Hooks = ()> {
|
||||||
|
@ -76,8 +98,8 @@ pub struct DownloadAndLinkOptions<Reporter = (), Hooks = ()> {
|
||||||
pub hooks: Option<Arc<Hooks>>,
|
pub hooks: Option<Arc<Hooks>>,
|
||||||
/// The refreshed sources.
|
/// The refreshed sources.
|
||||||
pub refreshed_sources: RefreshedSources,
|
pub refreshed_sources: RefreshedSources,
|
||||||
/// Whether to skip dev dependencies.
|
/// Which dependencies to install.
|
||||||
pub prod: bool,
|
pub install_dependencies_mode: InstallDependenciesMode,
|
||||||
/// The max number of concurrent network requests.
|
/// The max number of concurrent network requests.
|
||||||
pub network_concurrency: NonZeroUsize,
|
pub network_concurrency: NonZeroUsize,
|
||||||
/// Whether to re-install all dependencies even if they are already installed
|
/// Whether to re-install all dependencies even if they are already installed
|
||||||
|
@ -97,7 +119,7 @@ where
|
||||||
reporter: None,
|
reporter: None,
|
||||||
hooks: None,
|
hooks: None,
|
||||||
refreshed_sources: Default::default(),
|
refreshed_sources: Default::default(),
|
||||||
prod: false,
|
install_dependencies_mode: InstallDependenciesMode::All,
|
||||||
network_concurrency: NonZeroUsize::new(16).unwrap(),
|
network_concurrency: NonZeroUsize::new(16).unwrap(),
|
||||||
force: false,
|
force: false,
|
||||||
}
|
}
|
||||||
|
@ -124,10 +146,13 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether to skip dev dependencies.
|
/// Sets which dependencies to install
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn prod(mut self, prod: bool) -> Self {
|
pub fn install_dependencies_mode(
|
||||||
self.prod = prod;
|
mut self,
|
||||||
|
install_dependencies: InstallDependenciesMode,
|
||||||
|
) -> Self {
|
||||||
|
self.install_dependencies_mode = install_dependencies;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +178,7 @@ impl Clone for DownloadAndLinkOptions {
|
||||||
reporter: self.reporter.clone(),
|
reporter: self.reporter.clone(),
|
||||||
hooks: self.hooks.clone(),
|
hooks: self.hooks.clone(),
|
||||||
refreshed_sources: self.refreshed_sources.clone(),
|
refreshed_sources: self.refreshed_sources.clone(),
|
||||||
prod: self.prod,
|
install_dependencies_mode: self.install_dependencies_mode,
|
||||||
network_concurrency: self.network_concurrency,
|
network_concurrency: self.network_concurrency,
|
||||||
force: self.force,
|
force: self.force,
|
||||||
}
|
}
|
||||||
|
@ -162,7 +187,7 @@ impl Clone for DownloadAndLinkOptions {
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
/// Downloads a graph of dependencies and links them in the correct order
|
/// Downloads a graph of dependencies and links them in the correct order
|
||||||
#[instrument(skip_all, fields(prod = options.prod), level = "debug")]
|
#[instrument(skip_all, fields(install_dependencies = debug(options.install_dependencies_mode)), level = "debug")]
|
||||||
pub async fn download_and_link<Reporter, Hooks>(
|
pub async fn download_and_link<Reporter, Hooks>(
|
||||||
&self,
|
&self,
|
||||||
graph: &DependencyGraph,
|
graph: &DependencyGraph,
|
||||||
|
@ -177,7 +202,7 @@ impl Project {
|
||||||
reporter,
|
reporter,
|
||||||
hooks,
|
hooks,
|
||||||
refreshed_sources,
|
refreshed_sources,
|
||||||
prod,
|
install_dependencies_mode,
|
||||||
network_concurrency,
|
network_concurrency,
|
||||||
force,
|
force,
|
||||||
} = options;
|
} = options;
|
||||||
|
@ -219,16 +244,41 @@ impl Project {
|
||||||
download_graph_options = download_graph_options.reporter(reporter);
|
download_graph_options = download_graph_options.reporter(reporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let correct_deps = if matches!(install_dependencies_mode, InstallDependenciesMode::All)
|
||||||
|
{
|
||||||
|
graph.clone()
|
||||||
|
} else {
|
||||||
|
let mut queue = graph
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, node)| {
|
||||||
|
node.direct.is_some() && install_dependencies_mode.fits(node.resolved_ty)
|
||||||
|
})
|
||||||
|
.collect::<VecDeque<_>>();
|
||||||
|
|
||||||
|
let mut correct_deps = DependencyGraph::new();
|
||||||
|
while let Some((id, node)) = queue.pop_front() {
|
||||||
|
if correct_deps.insert(id.clone(), node.clone()).is_some() {
|
||||||
|
// prevent an infinite loop with recursive dependencies
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.dependencies
|
||||||
|
.keys()
|
||||||
|
.filter_map(|id| graph.get(id).map(|node| (id, node)))
|
||||||
|
.for_each(|x| queue.push_back(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
correct_deps
|
||||||
|
};
|
||||||
|
|
||||||
let mut downloaded_graph = DependencyGraph::new();
|
let mut downloaded_graph = DependencyGraph::new();
|
||||||
|
|
||||||
let graph_to_download = if force {
|
let graph_to_download = if force {
|
||||||
Cow::Borrowed(graph)
|
correct_deps
|
||||||
} else {
|
} else {
|
||||||
let mut tasks = graph
|
let mut tasks = correct_deps
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(id, node)| {
|
.map(|(id, node)| {
|
||||||
let id = id.clone();
|
|
||||||
let node = node.clone();
|
|
||||||
let container_folder =
|
let container_folder =
|
||||||
node.container_folder_from_project(&id, self, manifest.target.kind());
|
node.container_folder_from_project(&id, self, manifest.target.kind());
|
||||||
|
|
||||||
|
@ -249,7 +299,7 @@ impl Project {
|
||||||
graph_to_download.insert(id, node);
|
graph_to_download.insert(id, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cow::Owned(graph_to_download)
|
graph_to_download
|
||||||
};
|
};
|
||||||
|
|
||||||
let downloaded = self
|
let downloaded = self
|
||||||
|
@ -418,11 +468,7 @@ impl Project {
|
||||||
.map_err(errors::DownloadAndLinkError::Hook)?;
|
.map_err(errors::DownloadAndLinkError::Hook)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if prod {
|
if matches!(install_dependencies_mode, InstallDependenciesMode::Prod) || !force {
|
||||||
graph.retain(|_, node| node.node.resolved_ty != DependencyType::Dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if prod || !force {
|
|
||||||
self.remove_unused(&graph).await?;
|
self.remove_unused(&graph).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue