Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 75 additions & 50 deletions src/packaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,65 +98,90 @@ fn copy_license_files(
output: &Output,
tmp_dir_path: &Path,
) -> Result<Option<HashSet<PathBuf>>, PackagingError> {
// Early return if no license files are specified
if output.recipe.about().license_file.is_empty() {
Ok(None)
} else {
let licenses_folder = tmp_dir_path.join("info/licenses/");
fs::create_dir_all(&licenses_folder)?;
return Ok(None);
}

let copy_dir = copy_dir::CopyDir::new(
// Create licenses directory
let licenses_folder = tmp_dir_path.join("info/licenses/");
fs::create_dir_all(&licenses_folder)?;

// Define source directories to search for license files
let sources = [
(
&output.build_configuration.directories.host_prefix,
"prefix directory",
false,
),
(
&output.build_configuration.directories.work_dir,
&licenses_folder,
)
.with_globvec(&output.recipe.about().license_file)
.use_gitignore(false)
.run()?;
"source directory",
true,
),
(
&output.build_configuration.directories.recipe_dir,
"recipe directory",
true,
),
];

let copied_files_work_dir = copy_dir.copied_paths();
let any_include_matched_recipe_dir = copy_dir.any_include_glob_matched();
let license_globs = &output.recipe.about().license_file;
let mut all_copied_files = HashSet::new();
let mut any_glob_matched = false;
let mut copied_files_by_source = Vec::with_capacity(sources.len());

let copy_dir = copy_dir::CopyDir::new(
&output.build_configuration.directories.recipe_dir,
&licenses_folder,
)
.with_globvec(&output.recipe.about().license_file)
.use_gitignore(false)
.overwrite(true)
.run()?;

let copied_files_recipe_dir = copy_dir.copied_paths();
let any_include_matched_work_dir = copy_dir.any_include_glob_matched();

// if a file was copied from the recipe dir, and the work dir, we should
// issue a warning
for file in copied_files_recipe_dir {
if copied_files_work_dir.contains(file) {
let warn_str = format!(
"License file from source directory was overwritten by license file from recipe folder ({})",
file.display()
);
tracing::warn!(warn_str);
output.record_warning(&warn_str);
// Copy license files from each source directory
for (source_dir, source_name, overwrite) in sources {
let copy_dir = copy_dir::CopyDir::new(source_dir, &licenses_folder)
.with_globvec(license_globs)
.use_gitignore(false)
.overwrite(overwrite);

let result = copy_dir.run()?;

let copied_files = result.copied_paths().to_vec();
any_glob_matched |= result.any_include_glob_matched();

// Add all copied files to our result set
all_copied_files.extend(copied_files.iter().map(PathBuf::from));

copied_files_by_source.push((source_name, copied_files));
}

// Check for and warn about file conflicts
for i in 0..copied_files_by_source.len() {
for j in i + 1..copied_files_by_source.len() {
let (source_i_name, files_i) = &copied_files_by_source[i];
let (source_j_name, files_j) = &copied_files_by_source[j];

for file in files_i {
if files_j.contains(file) {
let warn_str = format!(
"License file '{}' from {} was overwritten by license file from {}",
file.file_name().unwrap_or_default().to_string_lossy(),
source_i_name,
source_j_name
);
tracing::warn!(warn_str);
output.record_warning(&warn_str);
}
}
}
}

let copied_files = copied_files_recipe_dir
.iter()
.chain(copied_files_work_dir)
.map(PathBuf::from)
.collect::<HashSet<PathBuf>>();

if !any_include_matched_work_dir && !any_include_matched_recipe_dir {
let warn_str = "No include glob matched for copying license files";
tracing::warn!(warn_str);
output.record_warning(warn_str);
}
// Warn if no globs matched
if !any_glob_matched {
let warn_str = "No include glob matched for copying license files";
tracing::warn!(warn_str);
output.record_warning(warn_str);
}

if copied_files.is_empty() {
Err(PackagingError::LicensesNotFound)
} else {
Ok(Some(copied_files))
}
// Return error if no files were copied
if all_copied_files.is_empty() {
Err(PackagingError::LicensesNotFound)
} else {
Ok(Some(all_copied_files))
}
}

Expand Down
16 changes: 15 additions & 1 deletion test-data/recipes/double_license/recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ source:

build:
number: 0
script:
- if: unix
then:
- mkdir -p $PREFIX/license-folder/
- echo "prefix-license" > $PREFIX/license-folder/prefix-license.txt
- echo "source-license" > $SRC_DIR/source-license.txt
else:
- mkdir -p %PREFIX%\license-folder\
- echo "prefix-license" > %PREFIX%\license-folder\prefix-license.txt
- echo "source-license" > %SRC_DIR%\source-license.txt

about:
license_file: license.txt
license_file:
- license.txt
- recipe_license.txt
- license-folder/prefix-license.txt
- source-license.txt
8 changes: 7 additions & 1 deletion test/end-to-end/test_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,13 @@ def test_double_license(rattler_build: RattlerBuild, recipes: Path, tmp_path: Pa
path_to_recipe = recipes / "double_license"
args = rattler_build.build_args(path_to_recipe, tmp_path)
output = rattler_build(*args, stderr=STDOUT)
assert "warning License file from source directory was overwritten" in output
assert "warning License file 'license.txt' from work directory was overwritten by license file from recipe directory" in output

pkg = get_extracted_package(tmp_path, "double_license")
assert (pkg / "info/licenses/license.txt").exists()
assert (pkg / "info/licenses/recipe_license.txt").exists()
assert (pkg / "info/licenses/prefix-license.txt").exists()
assert (pkg / "info/licenses/source-license.txt").exists()


@pytest.mark.skipif(
Expand Down
Loading