git.delta.rocks / jrsonnet / refs/commits / 20cd69c85b05

difftreelog

feat importbin

Yaroslav Bolyukin2022-01-29parent: #2d3e912.patch.diff
in: master

9 files changed

modifiedbindings/jsonnet/src/import.rsdiffbeforeafterboth
22
3use jrsonnet_evaluator::{3use jrsonnet_evaluator::{
4 error::{Error::*, Result},4 error::{Error::*, Result},
5 throw, EvaluationState, IStr, ImportResolver,5 throw, EvaluationState, ImportResolver,
6};6};
7use std::{7use std::{
8 any::Any,8 any::Any,
30 cb: JsonnetImportCallback,30 cb: JsonnetImportCallback,
31 ctx: *mut c_void,31 ctx: *mut c_void,
32
33 out: RefCell<HashMap<PathBuf, IStr>>,32 out: RefCell<HashMap<PathBuf, Vec<u8>>>,
34}33}
35impl ImportResolver for CallbackImportResolver {34impl ImportResolver for CallbackImportResolver {
36 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {35 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {
7574
76 Ok(found_here_buf.into())75 Ok(found_here_buf.into())
77 }76 }
78 fn load_file_contents(&self, resolved: &Path) -> Result<IStr> {77 fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>> {
79 Ok(self.out.borrow().get(resolved).unwrap().clone())78 Ok(self.out.borrow().get(resolved).unwrap().clone())
80 }79 }
80
124 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))124 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))
125 }125 }
126 }126 }
127 fn load_file_contents(&self, id: &Path) -> Result<IStr> {127 fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {
128 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;128 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;
129 let mut out = String::new();129 let mut out = Vec::new();
130 file.read_to_string(&mut out)130 file.read_to_end(&mut out)
131 .map_err(|_e| ImportBadFileUtf8(id.to_owned()))?;131 .map_err(|e| ImportIo(e.to_string()))?;
132 Ok(out.into())132 Ok(out)
133 }133 }
134 unsafe fn as_any(&self) -> &dyn Any {134 unsafe fn as_any(&self) -> &dyn Any {
135 self135 self
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
82 ResolvedFileNotFound(PathBuf),82 ResolvedFileNotFound(PathBuf),
83 #[error("imported file is not valid utf-8: {0:?}")]83 #[error("imported file is not valid utf-8: {0:?}")]
84 ImportBadFileUtf8(PathBuf),84 ImportBadFileUtf8(PathBuf),
85 #[error("import io error: {0}")]
86 ImportIo(String),
85 #[error("tried to import {1} from {0}, but imports is not supported")]87 #[error("tried to import {1} from {0}, but imports is not supported")]
86 ImportNotSupported(PathBuf, PathBuf),88 ImportNotSupported(PathBuf, PathBuf),
87 #[error(89 #[error(
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
700 import_location.pop();700 import_location.pop();
701 Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)701 Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)
702 }702 }
703 ImportBin(path) => {
704 let tmp = loc.clone().0;
705 let mut import_location = tmp.to_path_buf();
706 import_location.pop();
707 let bytes = with_state(|s| s.import_file_bin(&import_location, path))?;
708 Val::Arr(ArrValue::Bytes(bytes))
709 }
703 })710 })
704}711}
705712
modifiedcrates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth
5use fs::File;5use fs::File;
6use jrsonnet_interner::IStr;6use jrsonnet_interner::IStr;
7use std::fs;7use std::fs;
8use std::io::Read;
9use std::{8use std::{
10 any::Any,9 any::Any,
11 cell::RefCell,
12 collections::HashMap,
13 path::{Path, PathBuf},10 path::{Path, PathBuf},
14 rc::Rc,11 rc::Rc,
15};12};
13use std::{convert::TryFrom, io::Read};
1614
17/// Implements file resolution logic for `import` and `importStr`15/// Implements file resolution logic for `import` and `importStr`
18pub trait ImportResolver {16pub trait ImportResolver {
21 /// where `${vendor}` is a library path.19 /// where `${vendor}` is a library path.
22 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>>;20 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>>;
21
22 fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>>;
2323
24 /// Reads file from filesystem, should be used only with path received from `resolve_file`24 /// Reads file from filesystem, should be used only with path received from `resolve_file`
25 fn load_file_contents(&self, resolved: &Path) -> Result<IStr>;25 fn load_file_str(&self, resolved: &Path) -> Result<IStr> {
26 Ok(IStr::try_from(&self.load_file_contents(resolved)? as &[u8])
27 .map_err(|_| ImportBadFileUtf8(resolved.to_path_buf()))?)
28 }
29
30 /// Reads file from filesystem, should be used only with path received from `resolve_file`
31 fn load_file_bin(&self, resolved: &Path) -> Result<Rc<[u8]>> {
32 Ok(self.load_file_contents(resolved)?.into())
33 }
2634
27 /// # Safety35 /// # Safety
28 ///36 ///
39 throw!(ImportNotSupported(from.into(), path.into()))47 throw!(ImportNotSupported(from.into(), path.into()))
40 }48 }
4149
42 fn load_file_contents(&self, _resolved: &Path) -> Result<IStr> {50 fn load_file_contents(&self, _resolved: &Path) -> Result<Vec<u8>> {
43 // Can be only caused by library direct consumer, not by supplied jsonnet
44 panic!("dummy resolver can't load any file")51 panic!("dummy resolver can't load any file")
45 }52 }
4653
79 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))86 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))
80 }87 }
81 }88 }
82 fn load_file_contents(&self, id: &Path) -> Result<IStr> {89 fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {
83 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;90 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;
84 let mut out = String::new();91 let mut out = Vec::new();
85 file.read_to_string(&mut out)92 file.read_to_end(&mut out)
86 .map_err(|_e| ImportBadFileUtf8(id.to_owned()))?;93 .map_err(|e| ImportIo(e.to_string()))?;
87 Ok(out.into())94 Ok(out)
88 }95 }
89 unsafe fn as_any(&self) -> &dyn Any {96 unsafe fn as_any(&self) -> &dyn Any {
90 panic!("this resolver can't be used as any")97 panic!("this resolver can't be used as any")
91 }98 }
92}99}
93
94type ResolutionData = (PathBuf, PathBuf);
95
96/// Caches results of the underlying resolver
97pub struct CachingImportResolver {
98 resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<Path>>>>,
99 loading_cache: RefCell<HashMap<PathBuf, Result<IStr>>>,
100 inner: Box<dyn ImportResolver>,
101}
102impl ImportResolver for CachingImportResolver {
103 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {
104 self.resolution_cache
105 .borrow_mut()
106 .entry((from.to_owned(), path.to_owned()))
107 .or_insert_with(|| self.inner.resolve_file(from, path))
108 .clone()
109 }
110
111 fn load_file_contents(&self, resolved: &Path) -> Result<IStr> {
112 self.loading_cache
113 .borrow_mut()
114 .entry(resolved.to_owned())
115 .or_insert_with(|| self.inner.load_file_contents(resolved))
116 .clone()
117 }
118 unsafe fn as_any(&self) -> &dyn Any {
119 panic!("this resolver can't be used as any")
120 }
121}
122100
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
119119
120 breakpoints: Breakpoints,120 breakpoints: Breakpoints,
121 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces121 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces
122 files: HashMap<Rc<Path>, FileData>,122 files: GcHashMap<Rc<Path>, FileData>,
123 str_files: HashMap<Rc<Path>, IStr>,123 str_files: GcHashMap<Rc<Path>, IStr>,
124 bin_files: GcHashMap<Rc<Path>, Rc<[u8]>>,
124}125}
125126
126pub struct FileData {127pub struct FileData {
276 return self.evaluate_loaded_file_raw(&file_path);277 return self.evaluate_loaded_file_raw(&file_path);
277 }278 }
278 }279 }
279 let contents = self.load_file_contents(&file_path)?;280 let contents = self.load_file_str(&file_path)?;
280 self.add_file(file_path.clone(), contents)?;281 self.add_file(file_path.clone(), contents)?;
281 self.evaluate_loaded_file_raw(&file_path)282 self.evaluate_loaded_file_raw(&file_path)
282 }283 }
283 pub(crate) fn import_file_str(&self, from: &Path, path: &Path) -> Result<IStr> {284 pub(crate) fn import_file_str(&self, from: &Path, path: &Path) -> Result<IStr> {
284 let path = self.resolve_file(from, path)?;285 let path = self.resolve_file(from, path)?;
285 if !self.data().str_files.contains_key(&path) {286 if !self.data().str_files.contains_key(&path) {
286 let file_str = self.load_file_contents(&path)?;287 let file_str = self.load_file_str(&path)?;
287 self.data_mut().str_files.insert(path.clone(), file_str);288 self.data_mut().str_files.insert(path.clone(), file_str);
288 }289 }
289 Ok(self.data().str_files.get(&path).cloned().unwrap())290 Ok(self.data().str_files.get(&path).cloned().unwrap())
290 }291 }
292 pub(crate) fn import_file_bin(&self, from: &Path, path: &Path) -> Result<Rc<[u8]>> {
293 let path = self.resolve_file(from, path)?;
294 if !self.data().bin_files.contains_key(&path) {
295 let file_bin = self.load_file_bin(&path)?;
296 self.data_mut().bin_files.insert(path.clone(), file_bin);
297 }
298 Ok(self.data().bin_files.get(&path).cloned().unwrap())
299 }
291300
292 fn evaluate_loaded_file_raw(&self, name: &Path) -> Result<Val> {301 fn evaluate_loaded_file_raw(&self, name: &Path) -> Result<Val> {
293 let expr: LocExpr = {302 let expr: LocExpr = {
603 pub fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {612 pub fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {
604 self.settings().import_resolver.resolve_file(from, path)613 self.settings().import_resolver.resolve_file(from, path)
605 }614 }
606 pub fn load_file_contents(&self, path: &Path) -> Result<IStr> {615 pub fn load_file_str(&self, path: &Path) -> Result<IStr> {
607 self.settings().import_resolver.load_file_contents(path)616 self.settings().import_resolver.load_file_str(path)
608 }617 }
618 pub fn load_file_bin(&self, path: &Path) -> Result<Rc<[u8]>> {
619 self.settings().import_resolver.load_file_bin(path)
620 }
609621
610 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {622 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {
611 Ref::map(self.settings(), |s| &*s.import_resolver)623 Ref::map(self.settings(), |s| &*s.import_resolver)
661 EvaluationState,673 EvaluationState,
662 };674 };
663 use gcmodule::{Cc, Trace};675 use gcmodule::{Cc, Trace};
664 use jrsonnet_interner::IStr;
665 use jrsonnet_parser::*;676 use jrsonnet_parser::*;
666 use std::{677 use std::{
667 path::{Path, PathBuf},678 path::{Path, PathBuf},
1165 Ok(())1176 Ok(())
1166 }1177 }
11671178
1168 struct TestImportResolver(IStr);1179 struct TestImportResolver(Vec<u8>);
1169 impl crate::import::ImportResolver for TestImportResolver {1180 impl crate::import::ImportResolver for TestImportResolver {
1170 fn resolve_file(&self, _: &Path, _: &Path) -> crate::error::Result<Rc<Path>> {1181 fn resolve_file(&self, _: &Path, _: &Path) -> crate::error::Result<Rc<Path>> {
1171 Ok(PathBuf::from("/test").into())1182 Ok(PathBuf::from("/test").into())
1172 }1183 }
11731184
1174 fn load_file_contents(&self, _: &Path) -> crate::error::Result<IStr> {1185 fn load_file_contents(&self, _: &Path) -> crate::error::Result<Vec<u8>> {
1175 Ok(self.0.clone())1186 Ok(self.0.clone())
1176 }1187 }
11771188
1178 unsafe fn as_any(&self) -> &dyn std::any::Any {1189 unsafe fn as_any(&self) -> &dyn std::any::Any {
1179 panic!()1190 panic!()
1180 }1191 }
1192
1193 fn load_file_bin(&self, _resolved: &Path) -> crate::error::Result<Rc<[u8]>> {
1194 panic!()
1195 }
1181 }1196 }
11821197
1183 #[test]1198 #[test]
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
186#[derive(Debug, Clone, Trace)]186#[derive(Debug, Clone, Trace)]
187#[force_tracking]187#[force_tracking]
188pub enum ArrValue {188pub enum ArrValue {
189 Bytes(#[skip_trace] Rc<[u8]>),
189 Lazy(Cc<Vec<LazyVal>>),190 Lazy(Cc<Vec<LazyVal>>),
190 Eager(Cc<Vec<Val>>),191 Eager(Cc<Vec<Val>>),
191 Extended(Box<(Self, Self)>),192 Extended(Box<(Self, Self)>),
197198
198 pub fn len(&self) -> usize {199 pub fn len(&self) -> usize {
199 match self {200 match self {
201 Self::Bytes(i) => i.len(),
200 Self::Lazy(l) => l.len(),202 Self::Lazy(l) => l.len(),
201 Self::Eager(e) => e.len(),203 Self::Eager(e) => e.len(),
202 Self::Extended(v) => v.0.len() + v.1.len(),204 Self::Extended(v) => v.0.len() + v.1.len(),
209211
210 pub fn get(&self, index: usize) -> Result<Option<Val>> {212 pub fn get(&self, index: usize) -> Result<Option<Val>> {
211 match self {213 match self {
214 Self::Bytes(i) => i
215 .get(index)
216 .map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),
212 Self::Lazy(vec) => {217 Self::Lazy(vec) => {
213 if let Some(v) = vec.get(index) {218 if let Some(v) = vec.get(index) {
214 Ok(Some(v.evaluate()?))219 Ok(Some(v.evaluate()?))
230235
231 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {236 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {
232 match self {237 match self {
238 Self::Bytes(i) => i
239 .get(index)
240 .map(|b| LazyVal::new_resolved(Val::Num(*b as f64))),
233 Self::Lazy(vec) => vec.get(index).cloned(),241 Self::Lazy(vec) => vec.get(index).cloned(),
234 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),242 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),
235 Self::Extended(v) => {243 Self::Extended(v) => {
245253
246 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {254 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {
247 Ok(match self {255 Ok(match self {
256 Self::Bytes(i) => {
257 let mut out = Vec::with_capacity(i.len());
258 for v in i.iter() {
259 out.push(Val::Num(*v as f64));
260 }
261 Cc::new(out)
262 }
248 Self::Lazy(vec) => {263 Self::Lazy(vec) => {
249 let mut out = Vec::with_capacity(vec.len());264 let mut out = Vec::with_capacity(vec.len());
250 for item in vec.iter() {265 for item in vec.iter() {
265280
266 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {281 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {
267 (0..self.len()).map(move |idx| match self {282 (0..self.len()).map(move |idx| match self {
283 Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),
268 Self::Lazy(l) => l[idx].evaluate(),284 Self::Lazy(l) => l[idx].evaluate(),
269 Self::Eager(e) => Ok(e[idx].clone()),285 Self::Eager(e) => Ok(e[idx].clone()),
270 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),286 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),
273289
274 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {290 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {
275 (0..self.len()).map(move |idx| match self {291 (0..self.len()).map(move |idx| match self {
292 Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),
276 Self::Lazy(l) => l[idx].clone(),293 Self::Lazy(l) => l[idx].clone(),
277 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),294 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),
278 Self::Extended(_) => self.get_lazy(idx).unwrap(),295 Self::Extended(_) => self.get_lazy(idx).unwrap(),
281298
282 pub fn reversed(self) -> Self {299 pub fn reversed(self) -> Self {
283 match self {300 match self {
301 Self::Bytes(b) => {
302 let mut out = b.to_vec();
303 out.reverse();
304 Self::Bytes(out.into())
305 }
284 Self::Lazy(vec) => {306 Self::Lazy(vec) => {
285 let mut out = (&vec as &Vec<_>).clone();307 let mut out = (&vec as &Vec<_>).clone();
286 out.reverse();308 out.reverse();
modifiedcrates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth
4use std::{4use std::{
5 borrow::Cow,5 borrow::Cow,
6 cell::RefCell,6 cell::RefCell,
7 convert::TryFrom,
7 fmt::{self, Display},8 fmt::{self, Display},
8 hash::{BuildHasherDefault, Hash, Hasher},9 hash::{BuildHasherDefault, Hash, Hasher},
9 ops::Deref,10 ops::Deref,
10 rc::Rc,11 rc::Rc,
12 str::Utf8Error,
11};13};
1214
13#[derive(Clone, PartialOrd, Ord, Eq)]15#[derive(Clone, PartialOrd, Ord, Eq)]
85 }87 }
86}88}
89
90impl TryFrom<&[u8]> for IStr {
91 type Error = Utf8Error;
92
93 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
94 let str = std::str::from_utf8(value)?;
95 Ok(str.into())
96 }
97}
8798
88impl From<String> for IStr {99impl From<String> for IStr {
89 fn from(str: String) -> Self {100 fn from(str: String) -> Self {
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
306 Import(PathBuf),306 Import(PathBuf),
307 /// importStr "file.txt"307 /// importStr "file.txt"
308 ImportStr(PathBuf),308 ImportStr(PathBuf),
309 /// importBin "file.txt"
310 ImportBin(PathBuf),
309 /// error "I'm broken"311 /// error "I'm broken"
310 ErrorStmt(LocExpr),312 ErrorStmt(LocExpr),
311 /// a(b, c)313 /// a(b, c)
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.parse().map_err(|_| "<number>") }} / expected!("<number>")53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.parse().map_err(|_| "<number>") }} / expected!("<number>")
5454
55 /// Reserved word followed by any non-alphanumberic55 /// Reserved word followed by any non-alphanumberic
56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "importbin" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()
57 rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")57 rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")
5858
59 rule keyword(id: &'static str) -> ()59 rule keyword(id: &'static str) -> ()
218 / array_comp_expr(s)218 / array_comp_expr(s)
219219
220 / keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}220 / keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}
221 / keyword("importbin") _ path:string() {Expr::ImportBin(PathBuf::from(path))}
221 / keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}222 / keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}
222223
223 / var_expr(s)224 / var_expr(s)