Skip to content

Commit

Permalink
refactor: add more tracing, record path in for path i/o errors (#278)
Browse files Browse the repository at this point in the history
* feat: add `--target` flag and respect `target-triple` config option when packaging rust binaries

* refactor: add more tracing, record path in for path i/o errors

* fix build

* fix build macos

* fix macos again

* revert example changes

* again

* fix macOS yet again
  • Loading branch information
amr-crabnebula authored Sep 26, 2024
1 parent 41b05d0 commit 10b47fc
Show file tree
Hide file tree
Showing 29 changed files with 1,290 additions and 1,131 deletions.
1,390 changes: 669 additions & 721 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bindings/packager/nodejs/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
]
},
"targetTriple": {
"description": "The target triple we are packaging for. This mainly affects [`Config::external_binaries`].\n\nDefaults to the current OS target triple.",
"description": "The target triple we are packaging for.\n\nDefaults to the current OS target triple.",
"type": [
"string",
"null"
Expand Down
2 changes: 1 addition & 1 deletion bindings/packager/nodejs/src-ts/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export interface Config {
*/
binariesDir?: string | null;
/**
* The target triple we are packaging for. This mainly affects [`Config::external_binaries`].
* The target triple we are packaging for.
*
* Defaults to the current OS target triple.
*/
Expand Down
2 changes: 1 addition & 1 deletion crates/packager/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
]
},
"targetTriple": {
"description": "The target triple we are packaging for. This mainly affects [`Config::external_binaries`].\n\nDefaults to the current OS target triple.",
"description": "The target triple we are packaging for.\n\nDefaults to the current OS target triple.",
"type": [
"string",
"null"
Expand Down
116 changes: 92 additions & 24 deletions crates/packager/src/cli/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,46 @@

use std::{
fmt::Debug,
fs,
path::{Path, PathBuf},
};

use super::{Error, Result};
use crate::{config::Binary, Config};

fn find_nearset_pkg_name(path: &Path) -> crate::Result<Option<String>> {
fn find_nearset_pkg_name_inner() -> crate::Result<Option<String>> {
if let Ok(contents) = std::fs::read_to_string("Cargo.toml") {
let toml = toml::from_str::<toml::Table>(&contents)?;
impl Config {
pub(crate) fn name(&self) -> &str {
self.name.as_deref().unwrap_or_default()
}

/// Whether this config should be packaged or skipped
pub(crate) fn should_pacakge(&self, cli: &super::Cli) -> bool {
// Should be packaged when it is enabled and this package was in the explicit packages list specified on the CLI,
// or the packages list specified on the CLI is empty which means build all
self.enabled
&& cli
.packages
.as_ref()
.map(|packages| packages.iter().any(|p| p == self.name()))
.unwrap_or(true)
}
}

fn find_nearset_pkg_name(path: &Path) -> Result<Option<String>> {
fn find_nearset_pkg_name_inner() -> Result<Option<String>> {
if let Ok(contents) = fs::read_to_string("Cargo.toml") {
let toml = toml::from_str::<toml::Table>(&contents)
.map_err(|e| Error::FailedToParseCargoToml(Box::new(e)))?;

if let Some(name) = toml.get("package").and_then(|p| p.get("name")) {
return Ok(Some(name.to_string()));
}
}

if let Ok(contents) = std::fs::read("package.json") {
let json = serde_json::from_slice::<serde_json::Value>(&contents)?;
if let Ok(contents) = fs::read("package.json") {
let json = serde_json::from_slice::<serde_json::Value>(&contents)
.map_err(Error::FailedToParsePacakgeJson)?;

if let Some(name) = json.get("name") {
return Ok(Some(name.to_string()));
}
Expand All @@ -29,31 +53,40 @@ fn find_nearset_pkg_name(path: &Path) -> crate::Result<Option<String>> {
}

let cwd = std::env::current_dir()?;
std::env::set_current_dir(path)?;
std::env::set_current_dir(path).map_err(|e| Error::IoWithPath(path.to_path_buf(), e))?;
let res = find_nearset_pkg_name_inner();
std::env::set_current_dir(cwd)?;
std::env::set_current_dir(&cwd).map_err(|e| Error::IoWithPath(cwd, e))?;
res
}

#[tracing::instrument(level = "trace")]
pub fn parse_config_file<P: AsRef<Path> + Debug>(
path: P,
) -> crate::Result<Vec<(Option<PathBuf>, Config)>> {
let path = path.as_ref().to_path_buf().canonicalize()?;
let content = std::fs::read_to_string(&path)?;
fn parse_config_file<P: AsRef<Path> + Debug>(path: P) -> Result<Vec<(Option<PathBuf>, Config)>> {
let p = path.as_ref().to_path_buf();
let path = p.canonicalize().map_err(|e| Error::IoWithPath(p, e))?;
let content = fs::read_to_string(&path).map_err(|e| Error::IoWithPath(path.clone(), e))?;
let mut configs = match path.extension().and_then(|e| e.to_str()) {
Some("toml") => {
if let Ok(cs) = toml::from_str::<Vec<Config>>(&content) {
cs.into_iter().map(|c| (Some(path.clone()), c)).collect()
if let Ok(configs) = toml::from_str::<Vec<Config>>(&content) {
configs
.into_iter()
.map(|c| (Some(path.clone()), c))
.collect()
} else {
vec![(Some(path), toml::from_str::<Config>(&content)?)]
toml::from_str::<Config>(&content)
.map_err(|e| Error::FailedToParseTomlConfigFromPath(path.clone(), Box::new(e)))
.map(|config| vec![(Some(path), config)])?
}
}
_ => {
if let Ok(cs) = serde_json::from_str::<Vec<Config>>(&content) {
cs.into_iter().map(|c| (Some(path.clone()), c)).collect()
if let Ok(configs) = serde_json::from_str::<Vec<Config>>(&content) {
configs
.into_iter()
.map(|c| (Some(path.clone()), c))
.collect()
} else {
vec![(Some(path), serde_json::from_str::<Config>(&content)?)]
serde_json::from_str::<Config>(&content)
.map_err(|e| Error::FailedToParseJsonConfigFromPath(path.clone(), e))
.map(|config| vec![(Some(path), config)])?
}
}
};
Expand All @@ -73,7 +106,7 @@ pub fn parse_config_file<P: AsRef<Path> + Debug>(
}

#[tracing::instrument(level = "trace")]
pub fn find_config_files() -> crate::Result<Vec<PathBuf>> {
fn find_config_files() -> crate::Result<Vec<PathBuf>> {
let opts = glob::MatchOptions {
case_sensitive: false,
..Default::default()
Expand All @@ -91,9 +124,7 @@ pub fn find_config_files() -> crate::Result<Vec<PathBuf>> {
}

#[tracing::instrument(level = "trace")]
pub fn load_configs_from_cargo_workspace(
cli: &super::Cli,
) -> crate::Result<Vec<(Option<PathBuf>, Config)>> {
fn load_configs_from_cargo_workspace(cli: &super::Cli) -> Result<Vec<(Option<PathBuf>, Config)>> {
let profile = if cli.release {
"release"
} else if let Some(profile) = &cli.profile {
Expand All @@ -118,7 +149,9 @@ pub fn load_configs_from_cargo_workspace(
let mut configs = Vec::new();
for package in metadata.workspace_packages().iter() {
if let Some(config) = package.metadata.get("packager") {
let mut config: Config = serde_json::from_value(config.to_owned())?;
let mut config: Config = serde_json::from_value(config.to_owned())
.map_err(Error::FailedToParseJsonConfigCargoToml)?;

if config.name.is_none() {
config.name.replace(package.name.clone());
}
Expand Down Expand Up @@ -190,3 +223,38 @@ pub fn load_configs_from_cargo_workspace(

Ok(configs)
}

pub fn detect_configs(cli: &super::Cli) -> Result<Vec<(Option<PathBuf>, Config)>> {
let configs = match &cli.config {
// if a raw json object
Some(c) if c.starts_with('{') => serde_json::from_str::<Config>(c)
.map(|c| vec![(None, c)])
.map_err(Error::FailedToParseJsonConfig)?,
// if a raw json array
Some(c) if c.starts_with('[') => serde_json::from_str::<Vec<Config>>(c)
.map_err(Error::FailedToParseJsonConfig)?
.into_iter()
.map(|c| (None, c))
.collect(),
// if a path to config file
Some(c) => parse_config_file(c)?,
// fallback to config files and cargo workspaces configs
_ => {
let config_files = find_config_files()?
.into_iter()
.filter_map(|c| parse_config_file(c).ok())
.collect::<Vec<_>>()
.concat();

let cargo_configs = load_configs_from_cargo_workspace(cli)?;

[config_files, cargo_configs]
.concat()
.into_iter()
.filter(|(_, c)| c.should_pacakge(cli))
.collect()
}
};

Ok(configs)
}
59 changes: 59 additions & 0 deletions crates/packager/src/cli/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// Copyright 2023-2023 CrabNebula Ltd.
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use std::path::PathBuf;

use thiserror::Error;

#[non_exhaustive]
#[derive(Error, Debug)]
/// Errors returned by cargo-packager.
pub enum Error {
/// Clap error.
#[error(transparent)]
#[cfg(feature = "cli")]
Clap(#[from] clap::error::Error),
/// Error while reading cargo metadata.
#[error("Failed to read cargo metadata: {0}")]
Metadata(#[from] cargo_metadata::Error),
/// JSON parsing error.
#[error(transparent)]
Json(#[from] serde_json::Error),
/// TOML parsing error.
#[error(transparent)]
Toml(#[from] toml::de::Error),
/// JSON Config parsing error.
#[error("Failed to parse config: {0}")]
FailedToParseJsonConfig(serde_json::Error),
#[error("Failed to deserialize config from `package.metadata.packager` in Cargo.toml: {0}")]
FailedToParseJsonConfigCargoToml(serde_json::Error),
/// TOML Config parsing error.
#[error("Failed to parse config: {0}")]
FailedToParseTomlConfig(Box<toml::de::Error>),
/// Cargo.toml parsing error.
#[error("Failed to parse Cargo.toml: {0}")]
FailedToParseCargoToml(Box<toml::de::Error>),
/// package.json parsing error.
#[error("Failed to parse package.json: {0}")]
FailedToParsePacakgeJson(serde_json::Error),
/// JSON Config parsing error.
#[error("Failed to parse config at {0}: {1}")]
FailedToParseJsonConfigFromPath(PathBuf, serde_json::Error),
/// TOML Config parsing error.
#[error("Failed to parse config at {0}: {1}")]
FailedToParseTomlConfigFromPath(PathBuf, Box<toml::de::Error>),
/// I/O errors with path.
#[error("I/O Error ({0}): {1}")]
IoWithPath(PathBuf, std::io::Error),
/// I/O errors.
#[error(transparent)]
Io(#[from] std::io::Error),
/// Packaging error
#[error(transparent)]
Packaging(#[from] crate::Error),
}

/// Convenient type alias of Result type for cargo-packager.
pub type Result<T> = std::result::Result<T, Error>;
Loading

0 comments on commit 10b47fc

Please sign in to comment.