mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Better error message when package version not exists (#4429)
This commit is contained in:
parent
09e3bbd3b4
commit
e90c30903d
@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use crate::args::PackageStorageArgs;
|
use crate::args::PackageStorageArgs;
|
||||||
use codespan_reporting::term::{self, termcolor};
|
use codespan_reporting::term::{self, termcolor};
|
||||||
use ecow::eco_format;
|
use ecow::eco_format;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
use termcolor::WriteColor;
|
use termcolor::WriteColor;
|
||||||
use typst::diag::{bail, PackageError, PackageResult, StrResult};
|
use typst::diag::{bail, PackageError, PackageResult, StrResult};
|
||||||
use typst::syntax::package::{
|
use typst::syntax::package::{
|
||||||
@ -21,6 +22,7 @@ const DEFAULT_PACKAGES_SUBDIR: &str = "typst/packages";
|
|||||||
pub struct PackageStorage {
|
pub struct PackageStorage {
|
||||||
pub package_cache_path: Option<PathBuf>,
|
pub package_cache_path: Option<PathBuf>,
|
||||||
pub package_path: Option<PathBuf>,
|
pub package_path: Option<PathBuf>,
|
||||||
|
index: OnceCell<Vec<PackageInfo>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageStorage {
|
impl PackageStorage {
|
||||||
@ -31,7 +33,11 @@ impl PackageStorage {
|
|||||||
let package_path = args.package_path.clone().or_else(|| {
|
let package_path = args.package_path.clone().or_else(|| {
|
||||||
dirs::data_dir().map(|data_dir| data_dir.join(DEFAULT_PACKAGES_SUBDIR))
|
dirs::data_dir().map(|data_dir| data_dir.join(DEFAULT_PACKAGES_SUBDIR))
|
||||||
});
|
});
|
||||||
Self { package_cache_path, package_path }
|
Self {
|
||||||
|
package_cache_path,
|
||||||
|
package_path,
|
||||||
|
index: OnceCell::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make a package available in the on-disk cache.
|
/// Make a package available in the on-disk cache.
|
||||||
@ -53,7 +59,7 @@ impl PackageStorage {
|
|||||||
|
|
||||||
// Download from network if it doesn't exist yet.
|
// Download from network if it doesn't exist yet.
|
||||||
if spec.namespace == "preview" {
|
if spec.namespace == "preview" {
|
||||||
download_package(spec, &dir)?;
|
self.download_package(spec, &dir)?;
|
||||||
if dir.exists() {
|
if dir.exists() {
|
||||||
return Ok(dir);
|
return Ok(dir);
|
||||||
}
|
}
|
||||||
@ -71,7 +77,7 @@ impl PackageStorage {
|
|||||||
if spec.namespace == "preview" {
|
if spec.namespace == "preview" {
|
||||||
// For `@preview`, download the package index and find the latest
|
// For `@preview`, download the package index and find the latest
|
||||||
// version.
|
// version.
|
||||||
download_index()?
|
self.download_index()?
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|package| package.name == spec.name)
|
.filter(|package| package.name == spec.name)
|
||||||
.map(|package| package.version)
|
.map(|package| package.version)
|
||||||
@ -95,8 +101,13 @@ impl PackageStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PackageStorage {
|
||||||
/// Download a package over the network.
|
/// Download a package over the network.
|
||||||
fn download_package(spec: &PackageSpec, package_dir: &Path) -> PackageResult<()> {
|
fn download_package(
|
||||||
|
&self,
|
||||||
|
spec: &PackageSpec,
|
||||||
|
package_dir: &Path,
|
||||||
|
) -> PackageResult<()> {
|
||||||
// The `@preview` namespace is the only namespace that supports on-demand
|
// The `@preview` namespace is the only namespace that supports on-demand
|
||||||
// fetching.
|
// fetching.
|
||||||
assert_eq!(spec.namespace, "preview");
|
assert_eq!(spec.namespace, "preview");
|
||||||
@ -108,9 +119,15 @@ fn download_package(spec: &PackageSpec, package_dir: &Path) -> PackageResult<()>
|
|||||||
let data = match download_with_progress(&url) {
|
let data = match download_with_progress(&url) {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(ureq::Error::Status(404, _)) => {
|
Err(ureq::Error::Status(404, _)) => {
|
||||||
return Err(PackageError::NotFound(spec.clone()))
|
if let Ok(version) = self.determine_latest_version(&spec.versionless()) {
|
||||||
|
return Err(PackageError::VersionNotFound(spec.clone(), version));
|
||||||
|
} else {
|
||||||
|
return Err(PackageError::NotFound(spec.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(PackageError::NetworkFailed(Some(eco_format!("{err}"))))
|
||||||
}
|
}
|
||||||
Err(err) => return Err(PackageError::NetworkFailed(Some(eco_format!("{err}")))),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let decompressed = flate2::read::GzDecoder::new(data.as_slice());
|
let decompressed = flate2::read::GzDecoder::new(data.as_slice());
|
||||||
@ -121,7 +138,10 @@ fn download_package(spec: &PackageSpec, package_dir: &Path) -> PackageResult<()>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Download the `@preview` package index.
|
/// Download the `@preview` package index.
|
||||||
fn download_index() -> StrResult<Vec<PackageInfo>> {
|
///
|
||||||
|
/// To avoid downloading the index multiple times, the result is cached.
|
||||||
|
fn download_index(&self) -> StrResult<&Vec<PackageInfo>> {
|
||||||
|
self.index.get_or_try_init(|| {
|
||||||
let url = format!("{HOST}/preview/index.json");
|
let url = format!("{HOST}/preview/index.json");
|
||||||
match download(&url) {
|
match download(&url) {
|
||||||
Ok(response) => response
|
Ok(response) => response
|
||||||
@ -132,6 +152,8 @@ fn download_index() -> StrResult<Vec<PackageInfo>> {
|
|||||||
}
|
}
|
||||||
Err(err) => bail!("failed to fetch package index ({err})"),
|
Err(err) => bail!("failed to fetch package index ({err})"),
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print that a package downloading is happening.
|
/// Print that a package downloading is happening.
|
||||||
|
@ -85,6 +85,15 @@ pub struct PackageSpec {
|
|||||||
pub version: PackageVersion,
|
pub version: PackageVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PackageSpec {
|
||||||
|
pub fn versionless(&self) -> VersionlessPackageSpec {
|
||||||
|
VersionlessPackageSpec {
|
||||||
|
namespace: self.namespace.clone(),
|
||||||
|
name: self.name.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromStr for PackageSpec {
|
impl FromStr for PackageSpec {
|
||||||
type Err = EcoString;
|
type Err = EcoString;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use std::string::FromUtf8Error;
|
|||||||
use comemo::Tracked;
|
use comemo::Tracked;
|
||||||
use ecow::{eco_vec, EcoVec};
|
use ecow::{eco_vec, EcoVec};
|
||||||
|
|
||||||
use crate::syntax::package::PackageSpec;
|
use crate::syntax::package::{PackageSpec, PackageVersion};
|
||||||
use crate::syntax::{Span, Spanned, SyntaxError};
|
use crate::syntax::{Span, Spanned, SyntaxError};
|
||||||
use crate::{World, WorldExt};
|
use crate::{World, WorldExt};
|
||||||
|
|
||||||
@ -503,6 +503,8 @@ pub type PackageResult<T> = Result<T, PackageError>;
|
|||||||
pub enum PackageError {
|
pub enum PackageError {
|
||||||
/// The specified package does not exist.
|
/// The specified package does not exist.
|
||||||
NotFound(PackageSpec),
|
NotFound(PackageSpec),
|
||||||
|
/// The specified package found, but the version does not exist.
|
||||||
|
VersionNotFound(PackageSpec, PackageVersion),
|
||||||
/// Failed to retrieve the package through the network.
|
/// Failed to retrieve the package through the network.
|
||||||
NetworkFailed(Option<EcoString>),
|
NetworkFailed(Option<EcoString>),
|
||||||
/// The package archive was malformed.
|
/// The package archive was malformed.
|
||||||
@ -519,6 +521,13 @@ impl Display for PackageError {
|
|||||||
Self::NotFound(spec) => {
|
Self::NotFound(spec) => {
|
||||||
write!(f, "package not found (searched for {spec})",)
|
write!(f, "package not found (searched for {spec})",)
|
||||||
}
|
}
|
||||||
|
Self::VersionNotFound(spec, latest) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"package found, but version {} does not exist (latest is {})",
|
||||||
|
spec.version, latest,
|
||||||
|
)
|
||||||
|
}
|
||||||
Self::NetworkFailed(Some(err)) => {
|
Self::NetworkFailed(Some(err)) => {
|
||||||
write!(f, "failed to download package ({err})")
|
write!(f, "failed to download package ({err})")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user