@@ -31,9 +31,11 @@ use crate::{
3131 identifier:: LocIdent ,
3232 label:: Label ,
3333 metrics:: increment,
34+ parser:: grammar:: StaticFieldPathParser ,
3435 term:: {
3536 make:: { self as mk_term, builder} ,
3637 record:: Field ,
38+ string:: NickelString ,
3739 BinaryOp , MergePriority , RichTerm , Term ,
3840 } ,
3941} ;
@@ -148,6 +150,26 @@ impl FieldOverride {
148150 let input_id = cache. replace_string ( SourcePath :: CliFieldAssignment , assignment) ;
149151 let s = cache. source ( input_id) ;
150152
153+ if s. contains ( "=@" ) || s. contains ( "=%" ) || s. contains ( "=^" ) {
154+ let parser = StaticFieldPathParser :: new ( ) ;
155+ let splitted = s. split_once ( '=' ) . unwrap ( ) ;
156+ let field_name: & str = splitted. 0 ;
157+ let path = parser
158+ . parse_strict ( input_id, Lexer :: new ( field_name) )
159+ // We just need to report an error here
160+ . map_err ( |mut errs| {
161+ errs. errors . pop ( ) . expect (
162+ "because parsing of the field assignment failed, the error \
163+ list must be non-empty, put .pop() failed",
164+ )
165+ } ) ?;
166+ return Ok ( FieldOverride {
167+ path : FieldPath ( path) ,
168+ value : splitted. 1 . to_owned ( ) ,
169+ priority,
170+ } ) ;
171+ }
172+
151173 let parser = CliFieldAssignmentParser :: new ( ) ;
152174 let ( path, _, span_value) = parser
153175 . parse_strict ( input_id, Lexer :: new ( s) )
@@ -435,15 +457,52 @@ impl<EC: EvalCache> Program<EC> {
435457 let mut record = builder:: Record :: new ( ) ;
436458
437459 for ovd in self . overrides . iter ( ) . cloned ( ) {
438- let value_file_id = self
439- . vm
440- . import_resolver_mut ( )
441- . add_string ( SourcePath :: Override ( ovd. path . clone ( ) ) , ovd. value ) ;
442- self . vm . prepare_eval ( value_file_id) ?;
443- record = record
444- . path ( ovd. path . 0 )
445- . priority ( ovd. priority )
446- . value ( Term :: ResolvedImport ( value_file_id) ) ;
460+ if let Some ( s) = ovd. value . strip_prefix ( '^' ) {
461+ // literal string
462+ let v = Term :: Str ( NickelString :: from ( s) ) ;
463+ record = record. path ( ovd. path . 0 ) . priority ( ovd. priority ) . value ( v) ;
464+ } else if let Some ( s) = ovd. value . strip_prefix ( '@' ) {
465+ // read raw string from file
466+ match std:: fs:: read_to_string ( s) {
467+ Ok ( val) => {
468+ let v = Term :: Str ( NickelString :: from ( val) ) ;
469+ record = record. path ( ovd. path . 0 ) . priority ( ovd. priority ) . value ( v) ;
470+ }
471+ Err ( e) => {
472+ return Err ( Error :: IOError ( IOError ( format ! (
473+ "Error reading file `{s}`: {e}"
474+ ) ) ) )
475+ }
476+ }
477+ } else if let Some ( s) = ovd. value . strip_prefix ( '%' ) {
478+ // read raw string from specified environment variable
479+ match std:: env:: var ( s) {
480+ Ok ( val) => {
481+ let v = Term :: Str ( NickelString :: from ( val) ) ;
482+ record = record. path ( ovd. path . 0 ) . priority ( ovd. priority ) . value ( v) ;
483+ }
484+ Err ( std:: env:: VarError :: NotPresent ) => {
485+ return Err ( Error :: IOError ( IOError ( format ! (
486+ "Environment variable `{s}` not found"
487+ ) ) ) )
488+ }
489+ Err ( std:: env:: VarError :: NotUnicode ( ..) ) => {
490+ return Err ( Error :: IOError ( IOError ( format ! (
491+ "Environment variable `{s}` has non-unicode content"
492+ ) ) ) )
493+ }
494+ }
495+ } else {
496+ let value_file_id = self
497+ . vm
498+ . import_resolver_mut ( )
499+ . add_string ( SourcePath :: Override ( ovd. path . clone ( ) ) , ovd. value ) ;
500+ self . vm . prepare_eval ( value_file_id) ?;
501+ record = record
502+ . path ( ovd. path . 0 )
503+ . priority ( ovd. priority )
504+ . value ( Term :: ResolvedImport ( value_file_id) ) ;
505+ }
447506 }
448507
449508 let t = self . vm . prepare_eval ( self . main_id ) ?;
0 commit comments