Merge 87669550c954bae3ec5fee99fd1e1e6135a8dac0 into 9b09146a6b5e936966ed7ee73bce9dd2df3810ae

This commit is contained in:
Jonas Meurer 2025-05-07 22:24:37 +00:00 committed by GitHub
commit 66b9adc57d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 60 additions and 7 deletions

View File

@ -290,6 +290,15 @@ pub struct WorldArgs {
)]
pub inputs: Vec<(String, String)>,
/// Add a string key-path pairs where the content will visible through `sys.input-files`.
#[clap(
long = "input-file",
value_name = "key=value",
action = ArgAction::Append,
value_parser = ValueParser::new(parse_sys_input_file_pair),
)]
pub input_files: Vec<(String, Vec<u8>)>,
/// Common font arguments.
#[clap(flatten)]
pub font: FontArgs,
@ -607,6 +616,18 @@ fn parse_sys_input_pair(raw: &str) -> Result<(String, String), String> {
Ok((key, val))
}
/// Parses key/path pairs split by the first equal sign.
///
/// This functions works similar to `parse_sys_input_pair`, but the value is
/// interpreted as a path and the content of the file is read.
fn parse_sys_input_file_pair(raw: &str) -> Result<(String, Vec<u8>), String> {
let (key, value) = parse_sys_input_pair(raw)?;
match std::fs::read(&value) {
Ok(content) => Ok((key, content)),
Err(err) => Err(format!("could not read file `{value}`: {err}")),
}
}
/// Parses a UNIX timestamp according to <https://reproducible-builds.org/specs/source-date-epoch/>
fn parse_source_date_epoch(raw: &str) -> Result<DateTime<Utc>, String> {
let timestamp: i64 = raw

View File

@ -112,6 +112,12 @@ impl SystemWorld {
.map(|(k, v)| (k.as_str().into(), v.as_str().into_value()))
.collect();
let input_files: Dict = world_args
.input_files
.iter()
.map(|(k, v)| (k.as_str().into(), Bytes::new(v.to_owned()).into_value()))
.collect();
let features = process_args
.features
.iter()
@ -120,7 +126,11 @@ impl SystemWorld {
})
.collect();
Library::builder().with_inputs(inputs).with_features(features).build()
Library::builder()
.with_inputs(inputs)
.with_input_files(input_files)
.with_features(features)
.build()
};
let fonts = Fonts::searcher()

View File

@ -87,7 +87,12 @@ use crate::routines::EvalMode;
use crate::{Feature, Features};
/// Hook up all `foundations` definitions.
pub(super) fn define(global: &mut Scope, inputs: Dict, features: &Features) {
pub(super) fn define(
global: &mut Scope,
inputs: Dict,
input_files: Dict,
features: &Features,
) {
global.start_category(crate::Category::Foundations);
global.define_type::<bool>();
global.define_type::<i64>();
@ -118,7 +123,7 @@ pub(super) fn define(global: &mut Scope, inputs: Dict, features: &Features) {
global.define_func::<target>();
}
global.define("calc", calc::module());
global.define("sys", sys::module(inputs));
global.define("sys", sys::module(inputs, input_files));
global.reset_category();
}

View File

@ -3,7 +3,7 @@
use crate::foundations::{Dict, Module, Scope, Version};
/// A module with system-related things.
pub fn module(inputs: Dict) -> Module {
pub fn module(inputs: Dict, input_files: Dict) -> Module {
let mut scope = Scope::deduplicating();
scope.define(
"version",
@ -14,5 +14,6 @@ pub fn module(inputs: Dict) -> Module {
]),
);
scope.define("inputs", inputs);
scope.define("input-files", input_files);
Module::new("sys", scope)
}

View File

@ -174,6 +174,7 @@ impl Default for Library {
#[derive(Debug, Clone, Default)]
pub struct LibraryBuilder {
inputs: Option<Dict>,
input_files: Option<Dict>,
features: Features,
}
@ -184,6 +185,12 @@ impl LibraryBuilder {
self
}
/// Configure the input files visible through `sys.input-files`.
pub fn with_input_files(mut self, input_files: Dict) -> Self {
self.input_files = Some(input_files);
self
}
/// Configure in-development features that should be enabled.
///
/// No guarantees whatsover!
@ -196,7 +203,8 @@ impl LibraryBuilder {
pub fn build(self) -> Library {
let math = math::module();
let inputs = self.inputs.unwrap_or_default();
let global = global(math.clone(), inputs, &self.features);
let input_files = self.input_files.unwrap_or_default();
let global = global(math.clone(), inputs, input_files, &self.features);
Library {
global: global.clone(),
math,
@ -278,10 +286,10 @@ impl Category {
}
/// Construct the module with global definitions.
fn global(math: Module, inputs: Dict, features: &Features) -> Module {
fn global(math: Module, inputs: Dict, input_files: Dict, features: &Features) -> Module {
let mut global = Scope::deduplicating();
self::foundations::define(&mut global, inputs, features);
self::foundations::define(&mut global, inputs, input_files, features);
self::model::define(&mut global);
self::text::define(&mut global);
self::layout::define(&mut global);

View File

@ -151,6 +151,14 @@
The value is always of type [string]($str). More complex data
may be parsed manually using functions like [`json.decode`]($json.decode).
- The `sys.input-files` [dictionary], which makes external files
available to the project. An input specified in the command line as
`--input key=path` becomes available under `sys.input-files.key` as
the content of the specified file. To include spaces in the path, it may
be enclosed with single or double quotes.
The value is always of type [byte buffers]($bytes).
- name: sym
title: General
category: symbols