@@ -11,6 +11,7 @@ use crate::core::dependency::DepKind;
1111use crate :: core:: { FeatureValue , Features , Workspace } ;
1212use crate :: util:: closest;
1313use crate :: util:: interning:: InternedString ;
14+ use crate :: util:: toml:: { is_embedded, ScriptSource } ;
1415use crate :: { CargoResult , GlobalContext } ;
1516
1617/// Dependency table to add deps to.
@@ -245,6 +246,10 @@ pub struct LocalManifest {
245246 pub path : PathBuf ,
246247 /// Manifest contents.
247248 pub manifest : Manifest ,
249+ /// The raw, unparsed package file
250+ pub raw : String ,
251+ /// Edit location for an embedded manifest, if relevant
252+ pub embedded : Option < Embedded > ,
248253}
249254
250255impl Deref for LocalManifest {
@@ -267,18 +272,56 @@ impl LocalManifest {
267272 if !path. is_absolute ( ) {
268273 anyhow:: bail!( "can only edit absolute paths, got {}" , path. display( ) ) ;
269274 }
270- let data = cargo_util:: paths:: read ( & path) ?;
275+ let raw = cargo_util:: paths:: read ( & path) ?;
276+ let mut data = raw. clone ( ) ;
277+ let mut embedded = None ;
278+ if is_embedded ( path) {
279+ let source = ScriptSource :: parse ( & data) ?;
280+ if let Some ( frontmatter) = source. frontmatter ( ) {
281+ embedded = Some ( Embedded :: exists ( & data, frontmatter) ) ;
282+ data = frontmatter. to_owned ( ) ;
283+ } else if let Some ( shebang) = source. shebang ( ) {
284+ embedded = Some ( Embedded :: after ( & data, shebang) ) ;
285+ data = String :: new ( ) ;
286+ } else {
287+ embedded = Some ( Embedded :: start ( ) ) ;
288+ data = String :: new ( ) ;
289+ }
290+ }
271291 let manifest = data. parse ( ) . context ( "Unable to parse Cargo.toml" ) ?;
272292 Ok ( LocalManifest {
273293 manifest,
274294 path : path. to_owned ( ) ,
295+ raw,
296+ embedded,
275297 } )
276298 }
277299
278300 /// Write changes back to the file.
279301 pub fn write ( & self ) -> CargoResult < ( ) > {
280- let s = self . manifest . data . to_string ( ) ;
281- let new_contents_bytes = s. as_bytes ( ) ;
302+ let mut manifest = self . manifest . data . to_string ( ) ;
303+ let raw = match self . embedded . as_ref ( ) {
304+ Some ( Embedded :: Implicit ( start) ) => {
305+ if !manifest. ends_with ( "\n " ) {
306+ manifest. push_str ( "\n " ) ;
307+ }
308+ let fence = "---\n " ;
309+ let prefix = & self . raw [ 0 ..* start] ;
310+ let suffix = & self . raw [ * start..] ;
311+ let empty_line = if prefix. is_empty ( ) { "\n " } else { "" } ;
312+ format ! ( "{prefix}{fence}{manifest}{fence}{empty_line}{suffix}" )
313+ }
314+ Some ( Embedded :: Explicit ( span) ) => {
315+ if !manifest. ends_with ( "\n " ) {
316+ manifest. push_str ( "\n " ) ;
317+ }
318+ let prefix = & self . raw [ 0 ..span. start ] ;
319+ let suffix = & self . raw [ span. end ..] ;
320+ format ! ( "{prefix}{manifest}{suffix}" )
321+ }
322+ None => manifest,
323+ } ;
324+ let new_contents_bytes = raw. as_bytes ( ) ;
282325
283326 cargo_util:: paths:: write_atomic ( & self . path , new_contents_bytes)
284327 }
@@ -531,6 +574,51 @@ impl std::fmt::Display for LocalManifest {
531574 }
532575}
533576
577+ /// Edit location for an embedded manifest
578+ #[ derive( Clone , Debug ) ]
579+ pub enum Embedded {
580+ /// Manifest is implicit
581+ ///
582+ /// This is the insert location for a frontmatter
583+ Implicit ( usize ) ,
584+ /// Manifest is explicit in a frontmatter
585+ ///
586+ /// This is the span of the frontmatter body
587+ Explicit ( std:: ops:: Range < usize > ) ,
588+ }
589+
590+ impl Embedded {
591+ fn start ( ) -> Self {
592+ Self :: Implicit ( 0 )
593+ }
594+
595+ fn after ( input : & str , after : & str ) -> Self {
596+ let span = substr_span ( input, after) ;
597+ let end = span. end ;
598+ Self :: Implicit ( end)
599+ }
600+
601+ fn exists ( input : & str , exists : & str ) -> Self {
602+ let span = substr_span ( input, exists) ;
603+ Self :: Explicit ( span)
604+ }
605+ }
606+
607+ fn substr_span ( haystack : & str , needle : & str ) -> std:: ops:: Range < usize > {
608+ let haystack_start_ptr = haystack. as_ptr ( ) ;
609+ let haystack_end_ptr = haystack[ haystack. len ( ) ..haystack. len ( ) ] . as_ptr ( ) ;
610+
611+ let needle_start_ptr = needle. as_ptr ( ) ;
612+ let needle_end_ptr = needle[ needle. len ( ) ..needle. len ( ) ] . as_ptr ( ) ;
613+
614+ assert ! ( needle_end_ptr < haystack_end_ptr) ;
615+ assert ! ( haystack_start_ptr <= needle_start_ptr) ;
616+ let start = needle_start_ptr as usize - haystack_start_ptr as usize ;
617+ let end = start + needle. len ( ) ;
618+
619+ start..end
620+ }
621+
534622#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
535623enum DependencyStatus {
536624 None ,
0 commit comments