use crate::stored_path::{StoredPath, StoredPathBuf};
use crate::Error;
use crate::Result;
use crate::Template;
use crate::LICENSE_FILE_NAME;
use crate::RTF_FILE_EXTENSION;
use camino::Utf8Path;
use camino::Utf8PathBuf;
use log::trace;
use log::warn;
use std::str::FromStr;
use cargo_metadata::Package;
#[derive(Clone, Debug)]
pub struct Licenses {
pub source: Option<License>,
pub end_user: Option<License>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct License {
pub stored_path: StoredPathBuf,
pub name: Option<String>,
pub generate: Option<(Utf8PathBuf, Template)>,
}
impl License {
fn from_stored_path(path: &StoredPath) -> Self {
Self {
name: None,
stored_path: path.to_owned(),
generate: None,
}
}
}
impl Licenses {
pub fn new(
dest_dir: Option<&Utf8Path>,
license_path: Option<&StoredPath>,
eula_path: Option<&StoredPath>,
package: &Package,
) -> Result<Self> {
let source_license = Self::find_source_license(dest_dir, license_path, package)?;
let end_user_license =
Self::find_end_user_license(eula_path, package, source_license.as_ref())?;
Ok(Self {
source: source_license,
end_user: end_user_license,
})
}
fn find_source_license(
dest_dir: Option<&Utf8Path>,
path: Option<&StoredPath>,
package: &Package,
) -> Result<Option<License>> {
trace!("finding source license for {}", package.name);
if let Some(path) = path {
trace!("explicit source-license path passed as argument, using that");
return Ok(Some(License::from_stored_path(path)));
}
let package_dir = package.manifest_path.parent().expect("non-root Cargo.toml");
let dest_dir = dest_dir
.map(|p| p.to_owned())
.unwrap_or_else(|| package_dir.join(crate::WIX));
if let Some(license) = package
.metadata
.get("wix")
.and_then(|w| w.as_object())
.and_then(|t| t.get("license"))
{
trace!("[package.manifest.wix].license is specified");
if let Some(license_enabled) = license.as_bool() {
if !license_enabled {
trace!("[package.manifest.wix].license is false, disabling license support");
return Ok(None);
} else {
trace!("[package.manifest.wix].license is true, continuing to auto-detect");
}
} else if let Some(path) = license.as_str() {
trace!("[package.manifest.wix].license is a path, using that");
if package_dir.join(path).exists() {
return Ok(Some(License::from_stored_path(StoredPath::new(path))));
} else {
return Err(Error::Generic(format!(
r#"{} specifies package.metadata.wix.license="{}" in its Cargo.toml, but no such file exists."#,
package.name, path,
)));
}
} else {
trace!("[package.manifest.wix].license is an invalid type");
return Err(Error::Generic(format!(
"{}'s [package.metadata.wix].license must be a bool or a path",
package.name
)));
}
}
if let Some(path) = &package.license_file {
trace!("Cargo.toml license_file is specified, using that");
if package_dir.join(path).exists() {
return Ok(Some(License::from_stored_path(
&StoredPathBuf::from_utf8_path(path),
)));
} else {
return Err(Error::Generic(format!(
r#"{} specifies license-file="{}" in its Cargo.toml, but no such file exists."#,
package.name, path,
)));
}
}
if let Some(name) = package.license.clone() {
trace!("Cargo.toml license is specified");
if let Ok(generate) = Template::from_str(&name) {
trace!("Found a matching template, generating that");
let file_name = format!("{LICENSE_FILE_NAME}.{RTF_FILE_EXTENSION}");
let dest_file = dest_dir.join(file_name);
let rel_file = dest_file.strip_prefix(package_dir).unwrap_or(&dest_file);
let stored_path = StoredPathBuf::from_utf8_path(rel_file);
return Ok(Some(License {
name: None,
stored_path,
generate: Some((dest_file, generate)),
}));
} else {
trace!("No matching template, ignoring license");
}
}
trace!("No source-license found");
Ok(None)
}
fn find_end_user_license(
path: Option<&StoredPath>,
package: &Package,
source_license: Option<&License>,
) -> Result<Option<License>> {
trace!("finding end-user-license for {}", package.name);
if let Some(path) = path {
trace!("explicit end-user-license path passed as argument, using that");
return Ok(Some(License::from_stored_path(path)));
}
let package_dir = package.manifest_path.parent().expect("non-root Cargo.toml");
if let Some(eula) = package
.metadata
.get("wix")
.and_then(|w| w.as_object())
.and_then(|t| t.get("eula"))
{
trace!("[package.manifest.wix].eula is specified");
if let Some(eula_enabled) = eula.as_bool() {
if !eula_enabled {
trace!("[package.manifest.wix].eula is false, disabling license support");
return Ok(None);
} else {
trace!("[package.manifest.wix].eula is true, continuing to auto-detect");
}
} else if let Some(path) = eula.as_str() {
trace!("[package.manifest.wix].eula is a path, using that");
if package_dir.join(path).exists() {
return Ok(Some(License::from_stored_path(StoredPath::new(path))));
} else {
return Err(Error::Generic(format!(
r#"{} specifies package.metadata.wix.eula="{}" in its Cargo.toml, but no such file exists."#,
package.name, path,
)));
}
} else {
trace!("[package.manifest.wix].eula is an invalid type");
return Err(Error::Generic(format!(
"{}'s [package.metadata.wix].eula must be a bool or a path",
package.name
)));
}
}
if let Some(license) = source_license {
trace!("source-license is defined");
let path = &license.stored_path;
if path.extension() == Some(RTF_FILE_EXTENSION) {
trace!("using path from license");
return Ok(Some(License::from_stored_path(path)));
}
}
trace!("No end-user-license found");
warn!(
"Could not find your project's EULA. The license agreement dialog will be excluded \
from the installer. You can add one by either:
* Setting 'package.license' to a recognized value (MIT, Apache-2.0, or GPL-3.0)
* Setting 'package.license-file', 'package.metadata.wix.license', or 'package.metadata.wix.eula' \
to point to an RTF file
* Passing an RTF file with --license or --eula to the cargo-wix CLI
* Editing the generated WiX Source (wxs) with a text editor
To supress this warning, set 'package.metadata.wix.eula = false'"
);
Ok(None)
}
}