fix: ensure that the lockfile is respected (#2000)

This commit is contained in:
Myriad-Dreamin 2025-08-07 07:42:02 +08:00 committed by GitHub
parent bd688f354e
commit c3fa0c5cb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 372 additions and 63 deletions

View file

@ -37,36 +37,37 @@ pub struct DocNewArgs {
impl DocNewArgs {
/// Converts to project input.
pub fn to_input(&self) -> ProjectInput {
let id: Id = (&self.id).into();
pub fn to_input(&self, ctx: CtxPath) -> ProjectInput {
let id: Id = self.id.id(ctx);
let root = self
.root
.as_ref()
.map(|root| ResourcePath::from_user_sys(Path::new(root)));
let main = ResourcePath::from_user_sys(Path::new(&self.id.input));
.map(|root| ResourcePath::from_user_sys(Path::new(root), ctx));
let main = ResourcePath::from_user_sys(Path::new(&self.id.input), ctx);
let font_paths = self
.font
.font_paths
.iter()
.map(|p| ResourcePath::from_user_sys(p))
.map(|p| ResourcePath::from_user_sys(p, ctx))
.collect::<Vec<_>>();
let package_path = self
.package
.package_path
.as_ref()
.map(|p| ResourcePath::from_user_sys(p));
.map(|p| ResourcePath::from_user_sys(p, ctx));
let package_cache_path = self
.package
.package_cache_path
.as_ref()
.map(|p| ResourcePath::from_user_sys(p));
.map(|p| ResourcePath::from_user_sys(p, ctx));
ProjectInput {
id: id.clone(),
lock_dir: Some(ctx.1.to_path_buf()),
root,
main,
// todo: inputs
@ -92,12 +93,13 @@ pub struct DocIdArgs {
pub input: String,
}
impl From<&DocIdArgs> for Id {
fn from(args: &DocIdArgs) -> Self {
if let Some(id) = &args.name {
impl DocIdArgs {
/// Converts to a document ID.
pub fn id(&self, ctx: CtxPath) -> Id {
if let Some(id) = &self.name {
Id::new(id.clone())
} else {
(&ResourcePath::from_user_sys(Path::new(&args.input))).into()
(&ResourcePath::from_user_sys(Path::new(&self.input), ctx)).into()
}
}
}
@ -172,7 +174,7 @@ pub struct TaskCompileArgs {
impl TaskCompileArgs {
/// Convert the arguments to a project task.
pub fn to_task(self, doc_id: Id) -> Result<ApplyProjectTask> {
pub fn to_task(self, doc_id: Id, cwd: &Path) -> Result<ApplyProjectTask> {
let new_task_id = self.task_name.map(Id::new);
let task_id = new_task_id.unwrap_or(doc_id.clone());
@ -195,6 +197,17 @@ impl TaskCompileArgs {
OutputFormat::Pdf
};
let output = self.output.as_ref().map(|output| {
let output = Path::new(output);
let output = if output.is_absolute() {
output.to_path_buf()
} else {
cwd.join(output)
};
PathPattern::new(&output.with_extension("").to_string_lossy())
});
let when = self.when.unwrap_or(TaskWhen::Never);
let mut transforms = vec![];
@ -207,7 +220,7 @@ impl TaskCompileArgs {
let export = ExportTask {
when,
output: self.output.as_deref().map(PathPattern::new),
output,
transform: transforms,
};

View file

@ -8,6 +8,7 @@ use ecow::{eco_vec, EcoVec};
use tinymist_std::error::prelude::*;
use tinymist_std::path::unix_slash;
use tinymist_std::{bail, ImmutPath};
use tinymist_task::CtxPath;
use typst::diag::EcoString;
use typst::World;
@ -25,7 +26,9 @@ impl LockFile {
self.task.iter().find(|i| &i.id == id)
}
pub fn replace_document(&mut self, input: ProjectInput) {
pub fn replace_document(&mut self, mut input: ProjectInput) {
input.lock_dir = None;
let input = input;
let id = input.id.clone();
let index = self.document.iter().position(|i| i.id == id);
if let Some(index) = index {
@ -35,7 +38,14 @@ impl LockFile {
}
}
pub fn replace_task(&mut self, task: ApplyProjectTask) {
pub fn replace_task(&mut self, mut task: ApplyProjectTask) {
if let Some(pat) = task.task.as_export_mut().and_then(|t| t.output.as_mut()) {
let rel = pat.clone().relative_to(self.lock_dir.as_ref().unwrap());
*pat = rel;
}
let task = task;
let id = task.id().clone();
let index = self.task.iter().position(|i| *i.id() == id);
if let Some(index) = index {
@ -146,6 +156,8 @@ impl LockFile {
let mut state = if old_data.trim().is_empty() {
LockFile {
// todo: reduce cost
lock_dir: Some(ImmutPath::from(cwd)),
document: vec![],
task: vec![],
route: eco_vec![],
@ -169,7 +181,9 @@ impl LockFile {
}
}
old_state.migrate()?
let mut lf = old_state.migrate()?;
lf.lock_dir = Some(ImmutPath::from(cwd));
lf
};
f(&mut state)?;
@ -213,7 +227,9 @@ impl LockFile {
let state = toml::from_str::<LockFileCompat>(data)
.context_ut("tinymist.lock file is not a valid TOML file")?;
state.migrate()
let mut lf = state.migrate()?;
lf.lock_dir = Some(dir.into());
Ok(lf)
}
}
@ -238,17 +254,18 @@ pub struct LockFileUpdate {
}
impl LockFileUpdate {
pub fn compiled(&mut self, world: &LspWorld) -> Option<Id> {
let id = Id::from_world(world)?;
pub fn compiled(&mut self, world: &LspWorld, ctx: CtxPath) -> Option<Id> {
let id = Id::from_world(world, ctx)?;
let root = ResourcePath::from_user_sys(Path::new("."));
let main = ResourcePath::from_user_sys(world.path_for_id(world.main()).ok()?.as_path());
let root = ResourcePath::from_user_sys(Path::new("."), ctx);
let main =
ResourcePath::from_user_sys(world.path_for_id(world.main()).ok()?.as_path(), ctx);
let font_resolver = &world.font_resolver;
let font_paths = font_resolver
.font_paths()
.iter()
.map(|p| ResourcePath::from_user_sys(p))
.map(|p| ResourcePath::from_user_sys(p, ctx))
.collect::<Vec<_>>();
// let system_font = font_resolver.system_font();
@ -256,10 +273,10 @@ impl LockFileUpdate {
let registry = &world.registry;
let package_path = registry
.package_path()
.map(|p| ResourcePath::from_user_sys(p));
.map(|p| ResourcePath::from_user_sys(p, ctx));
let package_cache_path = registry
.package_cache_path()
.map(|p| ResourcePath::from_user_sys(p));
.map(|p| ResourcePath::from_user_sys(p, ctx));
// todo: freeze the package paths
let _ = package_cache_path;
@ -269,6 +286,7 @@ impl LockFileUpdate {
let input = ProjectInput {
id: id.clone(),
lock_dir: Some(ctx.1.to_path_buf()),
root: Some(root),
main,
inputs: vec![],
@ -325,7 +343,7 @@ impl LockFileUpdate {
let id_hi = id >> 12;
let hash_str =
format!("{root_lo:03x}/{root_hi:013x}/{id_lo:03x}/{id_hi:016x}");
format!("{root_lo:03x}/{root_hi:013x}/{id_lo:03x}/{id_hi:013x}");
let cache_dir = cache_dir.join("tinymist/projects").join(hash_str);
let _ = std::fs::create_dir_all(&cache_dir);

View file

@ -1,5 +1,5 @@
use std::hash::Hash;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use ecow::EcoVec;
use tinymist_std::error::prelude::*;
@ -53,6 +53,9 @@ impl LockFileCompat {
/// A lock file storing project information.
#[derive(Debug, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct LockFile {
/// The directory where stores the lock file.
#[serde(skip)]
pub lock_dir: Option<ImmutPath>,
// The lock file version.
// version: String,
/// The project's document (input).
@ -72,6 +75,9 @@ pub struct LockFile {
pub struct ProjectInput {
/// The project's ID.
pub id: Id,
/// The cwd of the project when relative paths will be resolved.
#[serde(skip_serializing_if = "Option::is_none")]
pub lock_dir: Option<PathBuf>,
/// The path to the root directory of the project.
#[serde(skip_serializing_if = "Option::is_none")]
pub root: Option<ResourcePath>,
@ -93,6 +99,19 @@ pub struct ProjectInput {
pub package_cache_path: Option<ResourcePath>,
}
impl ProjectInput {
/// Returns a new project input relative to the provided lock directory.
pub fn relative_to(&self, that: &Path) -> Self {
if let Some(lock_dir) = &self.lock_dir {
if lock_dir == that {
return self.clone();
}
}
todo!()
}
}
/// A project route specifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]