mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-24 22:30:03 +00:00
Write to .crates.toml
This commit is contained in:
parent
caf6f3930b
commit
1c2d005fd4
6 changed files with 207 additions and 2 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -143,6 +143,7 @@ dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"guess_host_triple",
|
"guess_host_triple",
|
||||||
|
"home",
|
||||||
"log",
|
"log",
|
||||||
"miette",
|
"miette",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -158,6 +159,7 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tinytemplate",
|
"tinytemplate",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
"url",
|
"url",
|
||||||
"xz2",
|
"xz2",
|
||||||
"zip",
|
"zip",
|
||||||
|
@ -595,6 +597,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "home"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
|
|
@ -28,6 +28,7 @@ crates_io_api = { version = "0.8.0", default-features = false, features = ["rust
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
flate2 = { version = "1.0.24", features = ["zlib-ng"], default-features = false }
|
flate2 = { version = "1.0.24", features = ["zlib-ng"], default-features = false }
|
||||||
futures-util = { version = "0.3.21", default-features = false }
|
futures-util = { version = "0.3.21", default-features = false }
|
||||||
|
home = "0.5.3"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
miette = { version = "5.1.0", features = ["fancy-no-backtrace"] }
|
miette = { version = "5.1.0", features = ["fancy-no-backtrace"] }
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.12.0"
|
||||||
|
@ -43,6 +44,7 @@ tempfile = "3.3.0"
|
||||||
thiserror = "1.0.31"
|
thiserror = "1.0.31"
|
||||||
tinytemplate = "1.2.1"
|
tinytemplate = "1.2.1"
|
||||||
tokio = { version = "1.19.1", features = ["rt-multi-thread", "process", "sync"], default-features = false }
|
tokio = { version = "1.19.1", features = ["rt-multi-thread", "process", "sync"], default-features = false }
|
||||||
|
toml = "0.5.9"
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
xz2 = "0.1.6"
|
xz2 = "0.1.6"
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use cargo_toml::Manifest;
|
||||||
use futures_util::stream::Stream;
|
use futures_util::stream::Stream;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use reqwest::{Client, ClientBuilder, Method, Response, tls};
|
use reqwest::{tls, Client, ClientBuilder, Method, Response};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tinytemplate::TinyTemplate;
|
use tinytemplate::TinyTemplate;
|
||||||
use tokio::task::block_in_place;
|
use tokio::task::block_in_place;
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub use helpers::*;
|
||||||
|
|
||||||
pub mod bins;
|
pub mod bins;
|
||||||
pub mod fetchers;
|
pub mod fetchers;
|
||||||
|
pub mod metafiles;
|
||||||
|
|
||||||
mod target;
|
mod target;
|
||||||
pub use target::*;
|
pub use target::*;
|
||||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -201,7 +201,10 @@ async fn entry() -> Result<()> {
|
||||||
|
|
||||||
// Initialize REQWESTGLOBALCONFIG
|
// Initialize REQWESTGLOBALCONFIG
|
||||||
REQWESTGLOBALCONFIG
|
REQWESTGLOBALCONFIG
|
||||||
.set(ReqwestConfig { secure: opts.secure, min_tls: opts.min_tls_version.map(|v| v.into()) })
|
.set(ReqwestConfig {
|
||||||
|
secure: opts.secure,
|
||||||
|
min_tls: opts.min_tls_version.map(|v| v.into()),
|
||||||
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Setup logging
|
// Setup logging
|
||||||
|
@ -451,6 +454,21 @@ async fn install_from_package(
|
||||||
|
|
||||||
uithread.confirm().await?;
|
uithread.confirm().await?;
|
||||||
|
|
||||||
|
debug!("Writing .crates.toml");
|
||||||
|
if let Ok(mut ctoml) = metafiles::CratesToml::load().await {
|
||||||
|
ctoml.insert(
|
||||||
|
metafiles::CrateVersionSource {
|
||||||
|
name: opts.name.into(),
|
||||||
|
version: package.version.parse().into_diagnostic()?,
|
||||||
|
source: metafiles::Source::Registry(
|
||||||
|
url::Url::parse("https://github.com/rust-lang/crates.io-index").unwrap(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
bin_files.iter().map(|bin| bin.base_name.clone()),
|
||||||
|
);
|
||||||
|
ctoml.write().await?;
|
||||||
|
}
|
||||||
|
|
||||||
info!("Installing binaries...");
|
info!("Installing binaries...");
|
||||||
block_in_place(|| {
|
block_in_place(|| {
|
||||||
for file in &bin_files {
|
for file in &bin_files {
|
||||||
|
|
173
src/metafiles.rs
Normal file
173
src/metafiles.rs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
fmt,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use miette::Diagnostic;
|
||||||
|
use semver::Version;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
use tokio::fs;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
|
pub struct CratesTomlRaw {
|
||||||
|
#[serde(default)]
|
||||||
|
pub v1: BTreeMap<String, BTreeSet<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct CratesToml(BTreeMap<CrateVersionSource, BTreeSet<String>>);
|
||||||
|
|
||||||
|
impl CratesToml {
|
||||||
|
pub fn default_path() -> Result<PathBuf, CratesTomlParseError> {
|
||||||
|
Ok(home::cargo_home()?.join(".crates.toml"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn load() -> Result<Self, CratesTomlParseError> {
|
||||||
|
Self::load_from_path(Self::default_path()?).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn load_from_path(path: impl AsRef<Path>) -> Result<Self, CratesTomlParseError> {
|
||||||
|
let file = fs::read_to_string(path).await?;
|
||||||
|
Self::from_str(&file)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, cvs: CrateVersionSource, bins: impl Iterator<Item = String>) {
|
||||||
|
self.0.insert(cvs, bins.collect());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn write(&self) -> Result<(), CratesTomlParseError> {
|
||||||
|
self.write_to_path(Self::default_path()?).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn write_to_path(&self, path: impl AsRef<Path>) -> Result<(), CratesTomlParseError> {
|
||||||
|
let raw = CratesTomlRaw {
|
||||||
|
v1: self
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|(cvs, bins)| (cvs.to_string(), bins.clone()))
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
fs::write(path, &toml::to_vec(&raw)?).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for CratesToml {
|
||||||
|
type Err = CratesTomlParseError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let raw: CratesTomlRaw = toml::from_str(s).unwrap();
|
||||||
|
|
||||||
|
Ok(Self(
|
||||||
|
raw.v1
|
||||||
|
.into_iter()
|
||||||
|
.map(|(name, bins)| CrateVersionSource::from_str(&name).map(|cvs| (cvs, bins)))
|
||||||
|
.collect::<Result<_, _>>()?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
pub enum CratesTomlParseError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
TomlParse(#[from] toml::de::Error),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
TomlWrite(#[from] toml::ser::Error),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
CvsParse(#[from] CvsParseError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct CrateVersionSource {
|
||||||
|
pub name: String,
|
||||||
|
pub version: Version,
|
||||||
|
pub source: Source,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub enum Source {
|
||||||
|
Git(Url),
|
||||||
|
Path(Url),
|
||||||
|
Registry(Url),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for CrateVersionSource {
|
||||||
|
type Err = CvsParseError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.splitn(3, ' ').collect::<Vec<_>>()[..] {
|
||||||
|
[name, version, source] => {
|
||||||
|
let version = version.parse()?;
|
||||||
|
let source = match source
|
||||||
|
.trim_matches(&['(', ')'][..])
|
||||||
|
.splitn(2, '+')
|
||||||
|
.collect::<Vec<_>>()[..]
|
||||||
|
{
|
||||||
|
["git", url] => Source::Git(Url::parse(url)?),
|
||||||
|
["path", url] => Source::Path(Url::parse(url)?),
|
||||||
|
["registry", url] => Source::Registry(Url::parse(url)?),
|
||||||
|
[kind, arg] => {
|
||||||
|
return Err(CvsParseError::UnknownSourceType {
|
||||||
|
kind: kind.to_string(),
|
||||||
|
arg: arg.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => return Err(CvsParseError::BadSource),
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
version,
|
||||||
|
source,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => Err(CvsParseError::BadFormat),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
pub enum CvsParseError {
|
||||||
|
#[error(transparent)]
|
||||||
|
UrlParse(#[from] url::ParseError),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
VersionParse(#[from] semver::Error),
|
||||||
|
|
||||||
|
#[error("unknown source type {kind}+{arg}")]
|
||||||
|
UnknownSourceType { kind: String, arg: String },
|
||||||
|
|
||||||
|
#[error("bad source format")]
|
||||||
|
BadSource,
|
||||||
|
|
||||||
|
#[error("bad CVS format")]
|
||||||
|
BadFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CrateVersionSource {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self {
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
source,
|
||||||
|
} = &self;
|
||||||
|
write!(f, "{name} {version} ({source})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Source {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Source::Git(url) => write!(f, "git+{url}"),
|
||||||
|
Source::Path(url) => write!(f, "path+{url}"),
|
||||||
|
Source::Registry(url) => write!(f, "registry+{url}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue