1+ use serde_json:: json;
2+ use clap:: ValueEnum ;
3+ use serde:: Deserialize ;
4+ use crate :: logging:: ask_value;
15use crate :: mod_file:: { PlatformName , ToGeodeString } ;
26use crate :: util:: mod_file:: DependencyImportance ;
37use crate :: { done, fail, fatal, index, info, warn, NiceUnwrap } ;
@@ -18,6 +22,15 @@ use std::{
1822 fs,
1923 path:: { Path , PathBuf } ,
2024} ;
25+ use serde_json:: Value ;
26+
27+ #[ derive( Debug , Deserialize , Hash , PartialEq , Eq , Clone , Copy , ValueEnum ) ]
28+ #[ serde( rename_all = "lowercase" ) ]
29+ pub enum ResourceType {
30+ Sprite ,
31+ Font ,
32+ File
33+ }
2134
2235#[ derive( Subcommand , Debug ) ]
2336#[ clap( rename_all = "kebab-case" ) ]
@@ -51,6 +64,13 @@ pub enum Project {
5164 #[ clap( long, num_args( 0 ..) ) ]
5265 externals : Vec < String > ,
5366 } ,
67+
68+ /// Add a resource to the mod.json file
69+ Add {
70+ /// Type of resource to add
71+ resource : ResourceType ,
72+ files : Vec < PathBuf >
73+ }
5474}
5575
5676fn find_build_directory ( root : & Path ) -> Option < PathBuf > {
@@ -517,6 +537,80 @@ pub fn check_dependencies(
517537 }
518538}
519539
540+ fn add_resource ( dir : & Path , resource : ResourceType , files : Vec < PathBuf > ) {
541+ let mut mod_json: HashMap < String , Value > = serde_json:: from_reader ( fs:: File :: open ( dir. join ( "mod.json" ) ) . ok ( ) . nice_unwrap ( "Must be inside a project with a mod.json" ) )
542+ . nice_unwrap ( "Unable to read mod.json" ) ;
543+
544+
545+ let mut do_thing = |name : & str , othername : & str | {
546+ let resource = mod_json. get ( "resources" )
547+ . and_then ( |x| x. get ( name) )
548+ . and_then ( |x| x. as_array ( ) )
549+ . unwrap_or ( & vec ! [ ] )
550+ . clone ( ) ;
551+
552+ let mut new_resource: Vec < Value > = resource. into_iter ( ) . chain ( files. clone ( ) . into_iter ( ) . filter_map ( |x| {
553+ if !x. exists ( ) {
554+ warn ! ( "{} {} does not exist" , othername, x. display( ) ) ;
555+ return None
556+ } else {
557+ Some ( Value :: String ( x. as_os_str ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ) )
558+ }
559+ } ) ) . collect ( ) ;
560+
561+ let mut duplicates: Vec < _ > = new_resource. iter ( ) . filter ( |x| new_resource. iter ( ) . filter ( |y| y == x) . count ( ) > 1 ) . collect ( ) ;
562+ duplicates. dedup ( ) ;
563+ duplicates. into_iter ( ) . for_each ( |x| warn ! ( "Duplicate {}: {}" , othername, x) ) ;
564+
565+ new_resource. dedup ( ) ;
566+
567+ * mod_json. entry ( "resources" . to_string ( ) ) . or_insert ( json ! ( { } ) )
568+ . as_object_mut ( ) . nice_unwrap ( "resources is not an object" )
569+ . entry ( name. to_string ( ) ) . or_insert ( json ! ( [ ] ) )
570+ . as_array_mut ( ) . nice_unwrap ( & format ! ( "{} is not an array" , name) ) = new_resource;
571+ } ;
572+
573+ match resource {
574+ ResourceType :: Sprite => do_thing ( "sprites" , "Sprite" ) ,
575+ ResourceType :: File => do_thing ( "files" , "File" ) ,
576+
577+ ResourceType :: Font => {
578+ let fonts = mod_json. get ( "resources" )
579+ . and_then ( |x| x. get ( "fonts" ) )
580+ . and_then ( |x| x. as_array ( ) )
581+ . unwrap_or ( & vec ! [ ] )
582+ . clone ( ) ;
583+
584+ let mut new_fonts: Vec < Value > = fonts. into_iter ( ) . chain ( files. into_iter ( ) . filter_map ( |x| {
585+ if !x. exists ( ) {
586+ warn ! ( "Font {} does not exist" , x. display( ) ) ;
587+ return None
588+ } else {
589+ Some ( json ! ( {
590+ "path" : x. as_os_str( ) . to_str( ) . unwrap( ) . to_string( ) ,
591+ "size" : ask_value( "Font Size" , None , true ) . parse:: <u32 >( ) . ok( ) . nice_unwrap( "Invalid font size!" )
592+ } ) )
593+ }
594+ } ) ) . collect ( ) ;
595+
596+ let mut duplicates: Vec < _ > = new_fonts. iter ( ) . filter_map ( |x| x. get ( "path" ) ) . filter ( |x| new_fonts. iter ( ) . filter ( |y| y. get ( "path" ) . map ( |y| y == * x) . unwrap_or ( false ) ) . count ( ) > 1 ) . collect ( ) ;
597+ duplicates. dedup ( ) ;
598+ duplicates. into_iter ( ) . for_each ( |x| warn ! ( "Duplicate Font: {}" , x) ) ;
599+
600+ new_fonts. dedup ( ) ;
601+
602+ * mod_json. entry ( "resources" . to_string ( ) ) . or_insert ( json ! ( { } ) )
603+ . as_object_mut ( ) . nice_unwrap ( "resources is not an object" )
604+ . entry ( "fonts" . to_string ( ) ) . or_insert ( json ! ( [ ] ) )
605+ . as_array_mut ( ) . nice_unwrap ( "fonts is not an array" ) = new_fonts;
606+ }
607+ } ;
608+
609+ fs:: write ( dir. join ( "mod.json" ) , serde_json:: to_string_pretty ( & mod_json) . unwrap ( ) ) . nice_unwrap ( "Failed to save mod.json" ) ;
610+
611+ done ! ( "Resource added to mod.json" ) ;
612+ }
613+
520614pub fn subcommand ( cmd : Project ) {
521615 match cmd {
522616 Project :: New { path } => template:: build_template ( path) ,
@@ -531,5 +625,10 @@ pub fn subcommand(cmd: Project) {
531625 platform,
532626 externals,
533627 ) ,
628+ Project :: Add { resource, files } => add_resource (
629+ & std:: env:: current_dir ( ) . unwrap ( ) ,
630+ resource,
631+ files
632+ ) ,
534633 }
535634}
0 commit comments