Skip to content

Commit

Permalink
Merge pull request #59 from rust3ds/feature/refactor-paths-romfs
Browse files Browse the repository at this point in the history
Refactor: use camino utf8-path types where applicable
  • Loading branch information
Meziu authored Jun 13, 2024
2 parents 51d41d8 + a8d9d15 commit fb32005
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 106 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ toml = "0.5.6"
clap = { version = "4.0.15", features = ["derive", "wrap_help"] }
shlex = "1.3.0"
serde_json = "1.0.108"
camino = "1.1"
8 changes: 4 additions & 4 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::sync::OnceLock;
use cargo_metadata::Message;
use clap::{Args, Parser, Subcommand};

use crate::{build_3dsx, build_smdh, cargo, get_metadata, link, print_command, CTRConfig};
use crate::{build_3dsx, cargo, get_metadata, link, print_command, CTRConfig};

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

eprintln!("Building 3dsx: {}", config.path_3dsx().display());
eprintln!("Building 3dsx: {}", config.path_3dsx());
build_3dsx(config, self.verbose);
}
}
Expand Down
183 changes: 83 additions & 100 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
pub mod command;
mod graph;

use core::fmt;
use std::ffi::OsStr;
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::process::{Command, ExitStatus, Stdio};
use std::{env, io, process};
use std::{env, fmt, io, process};

use cargo_metadata::{Message, MetadataCommand};
use command::{Input, Test};
use camino::{Utf8Path, Utf8PathBuf};
use cargo_metadata::{Message, MetadataCommand, Package};
use rustc_version::Channel;
use semver::Version;
use tee::TeeReader;

use crate::command::{CargoCmd, Run};
use crate::command::{CargoCmd, Input, Run, Test};
use crate::graph::UnitGraph;

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

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

let mut icon = String::from("./icon.png");
let mut icon_path = Utf8PathBuf::from("./icon.png");

if !Path::new(&icon).exists() {
icon = format!(
"{}/libctru/default_icon.png",
env::var("DEVKITPRO").unwrap()
);
if !icon_path.exists() {
icon_path = Utf8PathBuf::from(env::var("DEVKITPRO").unwrap())
.join("libctru")
.join("default_icon.png");
}

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

let author = match package.authors.as_slice() {
[name, ..] => name.clone(),
[] => String::from("Unspecified Author"), // as standard with the devkitPRO toolchain
};
let romfs_dir = get_romfs_dir(&package);

CTRConfig {
name,
author,
authors: package.authors,
description: package
.description
.clone()
.unwrap_or_else(|| String::from("Homebrew Application")),
icon,
target_path: artifact.executable.unwrap().into(),
cargo_manifest_path: package.manifest_path.into(),
icon_path,
romfs_dir,
manifest_dir: package.manifest_path.parent().unwrap().into(),
target_path: artifact.executable.unwrap(),
}
}

/// Builds the smdh using `smdhtool`.
/// This will fail if `smdhtool` is not within the running directory or in a directory found in $PATH
pub fn build_smdh(config: &CTRConfig, verbose: bool) {
let mut command = Command::new("smdhtool");
command
.arg("--create")
.arg(&config.name)
.arg(&config.description)
.arg(&config.author)
.arg(&config.icon)
.arg(config.path_smdh())
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit());

if verbose {
print_command(&command);
}

let mut process = command
.spawn()
.expect("smdhtool command failed, most likely due to 'smdhtool' not being in $PATH");

let status = process.wait().unwrap();

if !status.success() {
process::exit(status.code().unwrap_or(1));
}
fn get_romfs_dir(package: &Package) -> Option<Utf8PathBuf> {
package
.metadata
.get("cargo-3ds")?
.get("romfs_dir")?
.as_str()
.map(Utf8PathBuf::from)
}

/// Builds the 3dsx using `3dsxtool`.
Expand All @@ -356,18 +330,14 @@ pub fn build_3dsx(config: &CTRConfig, verbose: bool) {
command
.arg(&config.target_path)
.arg(config.path_3dsx())
.arg(format!("--smdh={}", config.path_smdh().to_string_lossy()));

// If romfs directory exists, automatically include it
let (romfs_path, is_default_romfs) = get_romfs_path(config);
if romfs_path.is_dir() {
eprintln!("Adding RomFS from {}", romfs_path.display());
command.arg(format!("--romfs={}", romfs_path.to_string_lossy()));
} else if !is_default_romfs {
eprintln!(
"Could not find configured RomFS dir: {}",
romfs_path.display()
);
.arg(format!("--smdh={}", config.path_smdh()));

let romfs = config.romfs_dir();
if romfs.is_dir() {
eprintln!("Adding RomFS from {romfs}");
command.arg(format!("--romfs={romfs}"));
} else if config.romfs_dir.is_some() {
eprintln!("Could not find configured RomFS dir: {romfs}");
process::exit(1);
}

Expand Down Expand Up @@ -411,56 +381,69 @@ pub fn link(config: &CTRConfig, run_args: &Run, verbose: bool) {
}
}

/// Read the `RomFS` path from the Cargo manifest. If it's unset, use the default.
/// The returned boolean is true when the default is used.
pub fn get_romfs_path(config: &CTRConfig) -> (PathBuf, bool) {
let manifest_path = &config.cargo_manifest_path;
let manifest_str = std::fs::read_to_string(manifest_path)
.unwrap_or_else(|e| panic!("Could not open {}: {e}", manifest_path.display()));
let manifest_data: toml::Value =
toml::de::from_str(&manifest_str).expect("Could not parse Cargo manifest as TOML");

// Find the romfs setting and compute the path
let mut is_default = false;
let romfs_dir_setting = manifest_data
.as_table()
.and_then(|table| table.get("package"))
.and_then(toml::Value::as_table)
.and_then(|table| table.get("metadata"))
.and_then(toml::Value::as_table)
.and_then(|table| table.get("cargo-3ds"))
.and_then(toml::Value::as_table)
.and_then(|table| table.get("romfs_dir"))
.and_then(toml::Value::as_str)
.unwrap_or_else(|| {
is_default = true;
"romfs"
});
let mut romfs_path = manifest_path.clone();
romfs_path.pop(); // Pop Cargo.toml
romfs_path.push(romfs_dir_setting);

(romfs_path, is_default)
}

#[derive(Default)]
#[derive(Default, Debug)]
pub struct CTRConfig {
name: String,
author: String,
authors: Vec<String>,
description: String,
icon: String,
target_path: PathBuf,
cargo_manifest_path: PathBuf,
icon_path: Utf8PathBuf,
target_path: Utf8PathBuf,
manifest_dir: Utf8PathBuf,
romfs_dir: Option<Utf8PathBuf>,
}

impl CTRConfig {
pub fn path_3dsx(&self) -> PathBuf {
/// Get the path to the output `.3dsx` file.
pub fn path_3dsx(&self) -> Utf8PathBuf {
self.target_path.with_extension("3dsx")
}

pub fn path_smdh(&self) -> PathBuf {
/// Get the path to the output `.smdh` file.
pub fn path_smdh(&self) -> Utf8PathBuf {
self.target_path.with_extension("smdh")
}

/// Get the absolute path to the romfs directory, defaulting to `romfs` if not specified.
pub fn romfs_dir(&self) -> Utf8PathBuf {
self.manifest_dir
.join(self.romfs_dir.as_deref().unwrap_or(Utf8Path::new("romfs")))
}

/// Builds the smdh using `smdhtool`.
/// This will fail if `smdhtool` is not within the running directory or in a directory found in $PATH
pub fn build_smdh(&self, verbose: bool) {
let author = if self.authors.is_empty() {
String::from("Unspecified Author") // as standard with the devkitPRO toolchain
} else {
self.authors.join(", ")
};

let mut command = Command::new("smdhtool");
command
.arg("--create")
.arg(&self.name)
.arg(&self.description)
.arg(author)
.arg(&self.icon_path)
.arg(self.path_smdh())
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit());

if verbose {
print_command(&command);
}

let mut process = command
.spawn()
.expect("smdhtool command failed, most likely due to 'smdhtool' not being in $PATH");

let status = process.wait().unwrap();

if !status.success() {
process::exit(status.code().unwrap_or(1));
}
}
}

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

0 comments on commit fb32005

Please sign in to comment.