Skip to content

Commit fb32005

Browse files
authored
Merge pull request #59 from rust3ds/feature/refactor-paths-romfs
Refactor: use camino utf8-path types where applicable
2 parents 51d41d8 + a8d9d15 commit fb32005

File tree

4 files changed

+91
-106
lines changed

4 files changed

+91
-106
lines changed

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ toml = "0.5.6"
2020
clap = { version = "4.0.15", features = ["derive", "wrap_help"] }
2121
shlex = "1.3.0"
2222
serde_json = "1.0.108"
23+
camino = "1.1"

src/command.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::sync::OnceLock;
66
use cargo_metadata::Message;
77
use clap::{Args, Parser, Subcommand};
88

9-
use crate::{build_3dsx, build_smdh, cargo, get_metadata, link, print_command, CTRConfig};
9+
use crate::{build_3dsx, cargo, get_metadata, link, print_command, CTRConfig};
1010

1111
#[derive(Parser, Debug)]
1212
#[command(name = "cargo", bin_name = "cargo")]
@@ -348,10 +348,10 @@ impl Build {
348348
/// This callback handles building the application as a `.3dsx` file.
349349
fn callback(&self, config: &Option<CTRConfig>) {
350350
if let Some(config) = config {
351-
eprintln!("Building smdh: {}", config.path_smdh().display());
352-
build_smdh(config, self.verbose);
351+
eprintln!("Building smdh: {}", config.path_smdh());
352+
config.build_smdh(self.verbose);
353353

354-
eprintln!("Building 3dsx: {}", config.path_3dsx().display());
354+
eprintln!("Building 3dsx: {}", config.path_3dsx());
355355
build_3dsx(config, self.verbose);
356356
}
357357
}

src/lib.rs

Lines changed: 83 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
pub mod command;
22
mod graph;
33

4-
use core::fmt;
54
use std::ffi::OsStr;
65
use std::io::{BufRead, BufReader};
7-
use std::path::{Path, PathBuf};
6+
use std::path::PathBuf;
87
use std::process::{Command, ExitStatus, Stdio};
9-
use std::{env, io, process};
8+
use std::{env, fmt, io, process};
109

11-
use cargo_metadata::{Message, MetadataCommand};
12-
use command::{Input, Test};
10+
use camino::{Utf8Path, Utf8PathBuf};
11+
use cargo_metadata::{Message, MetadataCommand, Package};
1312
use rustc_version::Channel;
1413
use semver::Version;
1514
use tee::TeeReader;
1615

17-
use crate::command::{CargoCmd, Run};
16+
use crate::command::{CargoCmd, Input, Run, Test};
1817
use crate::graph::UnitGraph;
1918

2019
/// Build a command using [`make_cargo_build_command`] and execute it,
@@ -281,13 +280,12 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig {
281280

282281
let (package, artifact) = (package.unwrap(), artifact.unwrap());
283282

284-
let mut icon = String::from("./icon.png");
283+
let mut icon_path = Utf8PathBuf::from("./icon.png");
285284

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");
291289
}
292290

293291
// for now assume a single "kind" since we only support one output artifact
@@ -301,52 +299,28 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig {
301299
_ => artifact.target.name,
302300
};
303301

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);
308303

309304
CTRConfig {
310305
name,
311-
author,
306+
authors: package.authors,
312307
description: package
313308
.description
314-
.clone()
315309
.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(),
319314
}
320315
}
321316

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)
350324
}
351325

352326
/// Builds the 3dsx using `3dsxtool`.
@@ -356,18 +330,14 @@ pub fn build_3dsx(config: &CTRConfig, verbose: bool) {
356330
command
357331
.arg(&config.target_path)
358332
.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}");
371341
process::exit(1);
372342
}
373343

@@ -411,56 +381,69 @@ pub fn link(config: &CTRConfig, run_args: &Run, verbose: bool) {
411381
}
412382
}
413383

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)]
447385
pub struct CTRConfig {
448386
name: String,
449-
author: String,
387+
authors: Vec<String>,
450388
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>,
454393
}
455394

456395
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 {
458398
self.target_path.with_extension("3dsx")
459399
}
460400

461-
pub fn path_smdh(&self) -> PathBuf {
401+
/// Get the path to the output `.smdh` file.
402+
pub fn path_smdh(&self) -> Utf8PathBuf {
462403
self.target_path.with_extension("smdh")
463404
}
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+
}
464447
}
465448

466449
#[derive(Ord, PartialOrd, PartialEq, Eq, Debug)]

0 commit comments

Comments
 (0)