1
1
pub mod command;
2
2
mod graph;
3
3
4
- use core:: fmt;
5
4
use std:: ffi:: OsStr ;
6
5
use std:: io:: { BufRead , BufReader } ;
7
- use std:: path:: { Path , PathBuf } ;
6
+ use std:: path:: PathBuf ;
8
7
use std:: process:: { Command , ExitStatus , Stdio } ;
9
- use std:: { env, io, process} ;
8
+ use std:: { env, fmt , io, process} ;
10
9
11
- use cargo_metadata :: { Message , MetadataCommand } ;
12
- use command :: { Input , Test } ;
10
+ use camino :: { Utf8Path , Utf8PathBuf } ;
11
+ use cargo_metadata :: { Message , MetadataCommand , Package } ;
13
12
use rustc_version:: Channel ;
14
13
use semver:: Version ;
15
14
use tee:: TeeReader ;
16
15
17
- use crate :: command:: { CargoCmd , Run } ;
16
+ use crate :: command:: { CargoCmd , Input , Run , Test } ;
18
17
use crate :: graph:: UnitGraph ;
19
18
20
19
/// Build a command using [`make_cargo_build_command`] and execute it,
@@ -281,13 +280,12 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig {
281
280
282
281
let ( package, artifact) = ( package. unwrap ( ) , artifact. unwrap ( ) ) ;
283
282
284
- let mut icon = String :: from ( "./icon.png" ) ;
283
+ let mut icon_path = Utf8PathBuf :: from ( "./icon.png" ) ;
285
284
286
- if !Path :: new ( & icon) . exists ( ) {
287
- icon = format ! (
288
- "{}/libctru/default_icon.png" ,
289
- env:: var( "DEVKITPRO" ) . unwrap( )
290
- ) ;
285
+ if !icon_path. exists ( ) {
286
+ icon_path = Utf8PathBuf :: from ( env:: var ( "DEVKITPRO" ) . unwrap ( ) )
287
+ . join ( "libctru" )
288
+ . join ( "default_icon.png" ) ;
291
289
}
292
290
293
291
// for now assume a single "kind" since we only support one output artifact
@@ -301,52 +299,28 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig {
301
299
_ => artifact. target . name ,
302
300
} ;
303
301
304
- let author = match package. authors . as_slice ( ) {
305
- [ name, ..] => name. clone ( ) ,
306
- [ ] => String :: from ( "Unspecified Author" ) , // as standard with the devkitPRO toolchain
307
- } ;
302
+ let romfs_dir = get_romfs_dir ( & package) ;
308
303
309
304
CTRConfig {
310
305
name,
311
- author ,
306
+ authors : package . authors ,
312
307
description : package
313
308
. description
314
- . clone ( )
315
309
. unwrap_or_else ( || String :: from ( "Homebrew Application" ) ) ,
316
- icon,
317
- target_path : artifact. executable . unwrap ( ) . into ( ) ,
318
- cargo_manifest_path : package. manifest_path . into ( ) ,
310
+ icon_path,
311
+ romfs_dir,
312
+ manifest_dir : package. manifest_path . parent ( ) . unwrap ( ) . into ( ) ,
313
+ target_path : artifact. executable . unwrap ( ) ,
319
314
}
320
315
}
321
316
322
- /// Builds the smdh using `smdhtool`.
323
- /// This will fail if `smdhtool` is not within the running directory or in a directory found in $PATH
324
- pub fn build_smdh ( config : & CTRConfig , verbose : bool ) {
325
- let mut command = Command :: new ( "smdhtool" ) ;
326
- command
327
- . arg ( "--create" )
328
- . arg ( & config. name )
329
- . arg ( & config. description )
330
- . arg ( & config. author )
331
- . arg ( & config. icon )
332
- . arg ( config. path_smdh ( ) )
333
- . stdin ( Stdio :: inherit ( ) )
334
- . stdout ( Stdio :: inherit ( ) )
335
- . stderr ( Stdio :: inherit ( ) ) ;
336
-
337
- if verbose {
338
- print_command ( & command) ;
339
- }
340
-
341
- let mut process = command
342
- . spawn ( )
343
- . expect ( "smdhtool command failed, most likely due to 'smdhtool' not being in $PATH" ) ;
344
-
345
- let status = process. wait ( ) . unwrap ( ) ;
346
-
347
- if !status. success ( ) {
348
- process:: exit ( status. code ( ) . unwrap_or ( 1 ) ) ;
349
- }
317
+ fn get_romfs_dir ( package : & Package ) -> Option < Utf8PathBuf > {
318
+ package
319
+ . metadata
320
+ . get ( "cargo-3ds" ) ?
321
+ . get ( "romfs_dir" ) ?
322
+ . as_str ( )
323
+ . map ( Utf8PathBuf :: from)
350
324
}
351
325
352
326
/// Builds the 3dsx using `3dsxtool`.
@@ -356,18 +330,14 @@ pub fn build_3dsx(config: &CTRConfig, verbose: bool) {
356
330
command
357
331
. arg ( & config. target_path )
358
332
. arg ( config. path_3dsx ( ) )
359
- . arg ( format ! ( "--smdh={}" , config. path_smdh( ) . to_string_lossy( ) ) ) ;
360
-
361
- // If romfs directory exists, automatically include it
362
- let ( romfs_path, is_default_romfs) = get_romfs_path ( config) ;
363
- if romfs_path. is_dir ( ) {
364
- eprintln ! ( "Adding RomFS from {}" , romfs_path. display( ) ) ;
365
- command. arg ( format ! ( "--romfs={}" , romfs_path. to_string_lossy( ) ) ) ;
366
- } else if !is_default_romfs {
367
- eprintln ! (
368
- "Could not find configured RomFS dir: {}" ,
369
- romfs_path. display( )
370
- ) ;
333
+ . arg ( format ! ( "--smdh={}" , config. path_smdh( ) ) ) ;
334
+
335
+ let romfs = config. romfs_dir ( ) ;
336
+ if romfs. is_dir ( ) {
337
+ eprintln ! ( "Adding RomFS from {romfs}" ) ;
338
+ command. arg ( format ! ( "--romfs={romfs}" ) ) ;
339
+ } else if config. romfs_dir . is_some ( ) {
340
+ eprintln ! ( "Could not find configured RomFS dir: {romfs}" ) ;
371
341
process:: exit ( 1 ) ;
372
342
}
373
343
@@ -411,56 +381,69 @@ pub fn link(config: &CTRConfig, run_args: &Run, verbose: bool) {
411
381
}
412
382
}
413
383
414
- /// Read the `RomFS` path from the Cargo manifest. If it's unset, use the default.
415
- /// The returned boolean is true when the default is used.
416
- pub fn get_romfs_path ( config : & CTRConfig ) -> ( PathBuf , bool ) {
417
- let manifest_path = & config. cargo_manifest_path ;
418
- let manifest_str = std:: fs:: read_to_string ( manifest_path)
419
- . unwrap_or_else ( |e| panic ! ( "Could not open {}: {e}" , manifest_path. display( ) ) ) ;
420
- let manifest_data: toml:: Value =
421
- toml:: de:: from_str ( & manifest_str) . expect ( "Could not parse Cargo manifest as TOML" ) ;
422
-
423
- // Find the romfs setting and compute the path
424
- let mut is_default = false ;
425
- let romfs_dir_setting = manifest_data
426
- . as_table ( )
427
- . and_then ( |table| table. get ( "package" ) )
428
- . and_then ( toml:: Value :: as_table)
429
- . and_then ( |table| table. get ( "metadata" ) )
430
- . and_then ( toml:: Value :: as_table)
431
- . and_then ( |table| table. get ( "cargo-3ds" ) )
432
- . and_then ( toml:: Value :: as_table)
433
- . and_then ( |table| table. get ( "romfs_dir" ) )
434
- . and_then ( toml:: Value :: as_str)
435
- . unwrap_or_else ( || {
436
- is_default = true ;
437
- "romfs"
438
- } ) ;
439
- let mut romfs_path = manifest_path. clone ( ) ;
440
- romfs_path. pop ( ) ; // Pop Cargo.toml
441
- romfs_path. push ( romfs_dir_setting) ;
442
-
443
- ( romfs_path, is_default)
444
- }
445
-
446
- #[ derive( Default ) ]
384
+ #[ derive( Default , Debug ) ]
447
385
pub struct CTRConfig {
448
386
name : String ,
449
- author : String ,
387
+ authors : Vec < String > ,
450
388
description : String ,
451
- icon : String ,
452
- target_path : PathBuf ,
453
- cargo_manifest_path : PathBuf ,
389
+ icon_path : Utf8PathBuf ,
390
+ target_path : Utf8PathBuf ,
391
+ manifest_dir : Utf8PathBuf ,
392
+ romfs_dir : Option < Utf8PathBuf > ,
454
393
}
455
394
456
395
impl CTRConfig {
457
- pub fn path_3dsx ( & self ) -> PathBuf {
396
+ /// Get the path to the output `.3dsx` file.
397
+ pub fn path_3dsx ( & self ) -> Utf8PathBuf {
458
398
self . target_path . with_extension ( "3dsx" )
459
399
}
460
400
461
- pub fn path_smdh ( & self ) -> PathBuf {
401
+ /// Get the path to the output `.smdh` file.
402
+ pub fn path_smdh ( & self ) -> Utf8PathBuf {
462
403
self . target_path . with_extension ( "smdh" )
463
404
}
405
+
406
+ /// Get the absolute path to the romfs directory, defaulting to `romfs` if not specified.
407
+ pub fn romfs_dir ( & self ) -> Utf8PathBuf {
408
+ self . manifest_dir
409
+ . join ( self . romfs_dir . as_deref ( ) . unwrap_or ( Utf8Path :: new ( "romfs" ) ) )
410
+ }
411
+
412
+ /// Builds the smdh using `smdhtool`.
413
+ /// This will fail if `smdhtool` is not within the running directory or in a directory found in $PATH
414
+ pub fn build_smdh ( & self , verbose : bool ) {
415
+ let author = if self . authors . is_empty ( ) {
416
+ String :: from ( "Unspecified Author" ) // as standard with the devkitPRO toolchain
417
+ } else {
418
+ self . authors . join ( ", " )
419
+ } ;
420
+
421
+ let mut command = Command :: new ( "smdhtool" ) ;
422
+ command
423
+ . arg ( "--create" )
424
+ . arg ( & self . name )
425
+ . arg ( & self . description )
426
+ . arg ( author)
427
+ . arg ( & self . icon_path )
428
+ . arg ( self . path_smdh ( ) )
429
+ . stdin ( Stdio :: inherit ( ) )
430
+ . stdout ( Stdio :: inherit ( ) )
431
+ . stderr ( Stdio :: inherit ( ) ) ;
432
+
433
+ if verbose {
434
+ print_command ( & command) ;
435
+ }
436
+
437
+ let mut process = command
438
+ . spawn ( )
439
+ . expect ( "smdhtool command failed, most likely due to 'smdhtool' not being in $PATH" ) ;
440
+
441
+ let status = process. wait ( ) . unwrap ( ) ;
442
+
443
+ if !status. success ( ) {
444
+ process:: exit ( status. code ( ) . unwrap_or ( 1 ) ) ;
445
+ }
446
+ }
464
447
}
465
448
466
449
#[ derive( Ord , PartialOrd , PartialEq , Eq , Debug ) ]
0 commit comments