Files
gitks/repository/find_license.rs
T
zhenyi 9a0c26e5f6 refactor(actor): implement Raft consensus algorithm for cluster leader election
- Add voting mechanism with term tracking and vote persistence
- Implement election triggering logic with majority vote counting
- Add primary/replica role transition handling with state management
- Integrate health check failure detection for automatic elections
- Refactor actor messaging system for distributed coordination
- Update repository registration to query cluster for existing primary
- Add broadcast mechanism for role change notifications
- Implement proper term comparison and duplicate request filtering
- Upgrade dependency versions including tokio-util for async utilities
- Optimize code formatting and line wrapping for improved readability
- Remove redundant blank lines and improve code structure consistency
- Enhance error logging and trace information for debugging purposes
2026-06-10 12:35:10 +08:00

118 lines
3.7 KiB
Rust

use crate::bare::GitBare;
use crate::error::GitResult;
use crate::pb::*;
impl GitBare {
/// Detect license by reading LICENSE/COPYING files and doing basic matching.
pub fn find_license(&self) -> GitResult<FindLicenseResponse> {
let possible_paths = [
"LICENSE",
"LICENSE.md",
"LICENSE.txt",
"LICENCE",
"LICENCE.md",
"LICENCE.txt",
"COPYING",
"COPYING.md",
"COPYING.txt",
"UNLICENSE",
];
for path in &possible_paths {
let output = std::process::Command::new("git")
.args([
"--git-dir",
&self.bare_dir.to_string_lossy(),
"show",
&format!("HEAD:{path}"),
])
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::null())
.output()
.map_err(|e| crate::error::GitError::CommandFailed {
status_code: None,
stderr: e.to_string(),
})?;
if output.status.success() {
let content = String::from_utf8_lossy(&output.stdout);
let (spdx, name, conf) = detect_license(&content);
if conf > 0.0 {
return Ok(FindLicenseResponse {
license_spdx: spdx.to_string(),
license_name: name.to_string(),
confidence: conf,
license_path: path.to_string(),
});
}
}
}
Ok(FindLicenseResponse::default())
}
}
/// Very basic license detection by keyword matching.
/// Returns (SPDX identifier, human-readable name, confidence).
fn detect_license(content: &str) -> (&'static str, &'static str, f64) {
let lower = content.to_lowercase();
// MIT
if lower.contains("permission is hereby granted, free of charge") && lower.contains("mit") {
return ("MIT", "MIT License", 0.95);
}
// Apache 2.0
if lower.contains("apache license, version 2.0") || lower.contains("apache-2.0") {
return ("Apache-2.0", "Apache License 2.0", 0.95);
}
// GPL 3.0
if lower.contains("gnu general public license") && lower.contains("version 3") {
return ("GPL-3.0", "GNU General Public License v3.0", 0.90);
}
// GPL 2.0
if lower.contains("gnu general public license") && lower.contains("version 2") {
return ("GPL-2.0", "GNU General Public License v2.0", 0.90);
}
// BSD 3
if lower.contains("redistribution and use in source and binary forms")
&& lower.contains("neither the name of")
{
return ("BSD-3-Clause", "BSD 3-Clause License", 0.85);
}
// BSD 2
if lower.contains("redistribution and use in source and binary forms") {
return ("BSD-2-Clause", "BSD 2-Clause License", 0.80);
}
// AGPL
if lower.contains("gnu affero general public license") {
return ("AGPL-3.0", "GNU Affero General Public License v3.0", 0.90);
}
// LGPL
if lower.contains("gnu lesser general public license") {
return ("LGPL-3.0", "GNU Lesser General Public License v3.0", 0.85);
}
// MPL
if lower.contains("mozilla public license") {
return ("MPL-2.0", "Mozilla Public License 2.0", 0.90);
}
// Unlicense
if lower.contains("this is free and unencumbered software released into the public domain") {
return ("Unlicense", "The Unlicense", 0.95);
}
// ISC
if lower.contains("permission to use, copy, modify, and/or distribute") && lower.contains("isc")
{
return ("ISC", "ISC License", 0.80);
}
("", "", 0.0)
}