Files
weevil/src/commands/upgrade.rs
2026-01-26 18:27:12 -06:00

140 lines
5.2 KiB
Rust

use anyhow::{Result, bail};
use colored::*;
use std::path::PathBuf;
use std::fs;
pub fn upgrade_project(path: &str) -> Result<()> {
let project_path = PathBuf::from(path);
// Verify it's a weevil project (check for old .weevil-version or new .weevil.toml)
let has_old_version = project_path.join(".weevil-version").exists();
let has_config = project_path.join(".weevil.toml").exists();
if !has_old_version && !has_config {
bail!("Not a weevil project: {} (missing .weevil-version or .weevil.toml)", path);
}
println!("{}", format!("Upgrading project: {}", path).bright_yellow());
println!();
// Get SDK config
let sdk_config = crate::sdk::SdkConfig::new()?;
// Ensure FTC SDK has local.properties (in case it was installed before this feature)
ensure_local_properties(&sdk_config)?;
// Load or create project config
let project_config = if has_config {
println!("Found existing .weevil.toml");
crate::project::ProjectConfig::load(&project_path)?
} else {
println!("Creating .weevil.toml (migrating from old format)");
let project_name = project_path.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown");
crate::project::ProjectConfig::new(project_name, sdk_config.ftc_sdk_path.clone(), sdk_config.android_sdk_path.clone())?
};
println!("Current SDK: {}", project_config.ftc_sdk_path.display());
println!("SDK Version: {}", project_config.ftc_sdk_version);
println!();
// Files that are safe to overwrite (infrastructure, not user code)
let safe_to_overwrite = vec![
"build.gradle.kts",
"settings.gradle.kts",
"build.sh",
"build.bat",
"deploy.sh",
"deploy.bat",
"gradlew",
"gradlew.bat",
"gradle/wrapper/gradle-wrapper.properties",
"gradle/wrapper/gradle-wrapper.jar",
".gitignore",
];
println!("{}", "Updating infrastructure files...".bright_yellow());
// Create a modified SDK config that uses the project's configured FTC SDK
let project_sdk_config = crate::sdk::SdkConfig {
ftc_sdk_path: project_config.ftc_sdk_path.clone(),
android_sdk_path: sdk_config.android_sdk_path.clone(),
cache_dir: sdk_config.cache_dir.clone(),
};
// Regenerate safe files using the project's configured SDK
let builder = crate::project::ProjectBuilder::new(
&project_config.project_name,
&project_sdk_config
)?;
// Temporarily create files in a temp location
let temp_dir = tempfile::tempdir()?;
builder.create(temp_dir.path(), &project_sdk_config)?;
// Copy only the safe files
for file in safe_to_overwrite {
let src = temp_dir.path().join(file);
let dst = project_path.join(file);
if src.exists() {
if let Some(parent) = dst.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(&src, &dst)?;
println!(" {} {}", "".green(), file);
// Make executable if needed
#[cfg(unix)]
if file.ends_with(".sh") || file == "gradlew" {
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&dst)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(&dst, perms)?;
}
}
}
// Save/update the config
project_config.save(&project_path)?;
println!(" {} {}", "".green(), ".weevil.toml");
// Remove old version marker if it exists
let old_version_file = project_path.join(".weevil-version");
if old_version_file.exists() {
fs::remove_file(old_version_file)?;
println!(" {} {}", "".green(), "Removed old .weevil-version");
}
println!();
println!("{}", "═══════════════════════════════════════════════════════════".bright_green());
println!("{}", " ✓ Project Upgraded!".bright_green().bold());
println!("{}", "═══════════════════════════════════════════════════════════".bright_green());
println!();
println!("{}", "Your code in src/ was preserved.".green());
println!("{}", "Build scripts and gradle configuration updated.".green());
println!();
println!("Test it: ./gradlew test");
println!();
Ok(())
}
fn ensure_local_properties(sdk_config: &crate::sdk::SdkConfig) -> Result<()> {
let local_properties_path = sdk_config.ftc_sdk_path.join("local.properties");
if !local_properties_path.exists() {
println!("Creating local.properties in FTC SDK...");
let android_sdk_str = sdk_config.android_sdk_path
.display()
.to_string()
.replace("\\", "/");
let local_properties = format!("sdk.dir={}\n", android_sdk_str);
fs::write(&local_properties_path, local_properties)?;
println!("{} Created local.properties", "".green());
}
Ok(())
}