1use std::path::{Path, PathBuf};
 2
 3use anyhow::{Context as _, Result};
 4use clap::Parser;
 5
 6use crate::workspace::load_workspace;
 7
 8#[derive(Parser)]
 9pub struct LicensesArgs {}
10
11pub fn run_licenses(_args: LicensesArgs) -> Result<()> {
12    const LICENSE_FILES: &[&str] = &["LICENSE-APACHE", "LICENSE-GPL", "LICENSE-AGPL"];
13
14    let workspace = load_workspace()?;
15
16    for package in workspace.workspace_packages() {
17        let crate_dir = package
18            .manifest_path
19            .parent()
20            .with_context(|| format!("no crate directory for {}", package.name))?;
21
22        if let Some(license_file) = first_license_file(crate_dir, LICENSE_FILES) {
23            if !license_file.is_symlink() {
24                println!("{} is not a symlink", license_file.display());
25            }
26
27            continue;
28        }
29
30        println!("Missing license: {}", package.name);
31    }
32
33    Ok(())
34}
35
36fn first_license_file(path: impl AsRef<Path>, license_files: &[&str]) -> Option<PathBuf> {
37    for license_file in license_files {
38        let path_to_license = path.as_ref().join(license_file);
39        if path_to_license.exists() {
40            return Some(path_to_license);
41        }
42    }
43
44    None
45}