use std::fs;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
const CMAKE_UTILS: &str = include_str!("../../cmake/CMakeUtils.cmake");
const CMAKE_CONFIG: &str = include_str!("../../cmake/CMakeConfig.cmake");
const CMAKE_FUNCTIONS: &str = include_str!("../../cmake/CMakeFunctions.cmake");
const CMAKE_EXTRA_FLAGS: &str = include_str!("../../cmake/CMakeExtraFlags.cmake");
const CCGO_DEPENDENCIES: &str = include_str!("../../cmake/CCGODependencies.cmake");
const FIND_CCGO_DEPENDENCIES: &str = include_str!("../../cmake/FindCCGODependencies.cmake");
const IOS_TOOLCHAIN: &str = include_str!("../../cmake/ios.toolchain.cmake");
const TVOS_TOOLCHAIN: &str = include_str!("../../cmake/tvos.toolchain.cmake");
const WATCHOS_TOOLCHAIN: &str = include_str!("../../cmake/watchos.toolchain.cmake");
const WINDOWS_MSVC_TOOLCHAIN: &str = include_str!("../../cmake/windows-msvc.toolchain.cmake");
const TEMPLATE_ROOT_CMAKELISTS: &str = include_str!("../../cmake/template/Root.CMakeLists.txt.in");
const TEMPLATE_SRC_CMAKELISTS: &str = include_str!("../../cmake/template/Src.CMakeLists.txt.in");
const TEMPLATE_TESTS_CMAKELISTS: &str = include_str!("../../cmake/template/Tests.CMakeLists.txt.in");
const TEMPLATE_BENCHES_CMAKELISTS: &str = include_str!("../../cmake/template/Benches.CMakeLists.txt.in");
const TEMPLATE_THIRD_PARTY_CMAKELISTS: &str = include_str!("../../cmake/template/ThirdParty.CMakeLists.txt.in");
const TEMPLATE_EXTERNAL_CMAKELISTS: &str = include_str!("../../cmake/template/External.CMakeLists.txt.in");
const TEMPLATE_EXTERNAL_DOWNLOAD: &str = include_str!("../../cmake/template/External.Download.txt.in");
const TEMPLATE_SRC_SUBDIR_CMAKELISTS: &str = include_str!("../../cmake/template/Src.SubDir.CMakeLists.txt.in");
pub fn get_cmake_dir() -> Result<PathBuf> {
let home = std::env::var("HOME")
.or_else(|_| std::env::var("USERPROFILE"))
.context("Failed to get home directory from HOME or USERPROFILE env var")?;
let home = PathBuf::from(home);
let cmake_dir = home.join(".ccgo/cmake");
if cmake_dir.exists() && is_templates_current(&cmake_dir) {
return Ok(cmake_dir);
}
fs::create_dir_all(&cmake_dir)
.with_context(|| format!("Failed to create CMake directory: {}", cmake_dir.display()))?;
write_templates(&cmake_dir)?;
Ok(cmake_dir)
}
fn is_templates_current(cmake_dir: &Path) -> bool {
let key_files = [
"CMakeUtils.cmake",
"CMakeFunctions.cmake",
"ios.toolchain.cmake",
"template/Root.CMakeLists.txt.in",
];
for file in &key_files {
if !cmake_dir.join(file).exists() {
return false;
}
}
true
}
fn write_templates(cmake_dir: &Path) -> Result<()> {
write_file(cmake_dir, "CMakeUtils.cmake", CMAKE_UTILS)?;
write_file(cmake_dir, "CMakeConfig.cmake", CMAKE_CONFIG)?;
write_file(cmake_dir, "CMakeFunctions.cmake", CMAKE_FUNCTIONS)?;
write_file(cmake_dir, "CMakeExtraFlags.cmake", CMAKE_EXTRA_FLAGS)?;
write_file(cmake_dir, "CCGODependencies.cmake", CCGO_DEPENDENCIES)?;
write_file(cmake_dir, "FindCCGODependencies.cmake", FIND_CCGO_DEPENDENCIES)?;
write_file(cmake_dir, "ios.toolchain.cmake", IOS_TOOLCHAIN)?;
write_file(cmake_dir, "tvos.toolchain.cmake", TVOS_TOOLCHAIN)?;
write_file(cmake_dir, "watchos.toolchain.cmake", WATCHOS_TOOLCHAIN)?;
write_file(cmake_dir, "windows-msvc.toolchain.cmake", WINDOWS_MSVC_TOOLCHAIN)?;
let template_dir = cmake_dir.join("template");
fs::create_dir_all(&template_dir)?;
write_file(&template_dir, "Root.CMakeLists.txt.in", TEMPLATE_ROOT_CMAKELISTS)?;
write_file(&template_dir, "Src.CMakeLists.txt.in", TEMPLATE_SRC_CMAKELISTS)?;
write_file(&template_dir, "Tests.CMakeLists.txt.in", TEMPLATE_TESTS_CMAKELISTS)?;
write_file(&template_dir, "Benches.CMakeLists.txt.in", TEMPLATE_BENCHES_CMAKELISTS)?;
write_file(&template_dir, "ThirdParty.CMakeLists.txt.in", TEMPLATE_THIRD_PARTY_CMAKELISTS)?;
write_file(&template_dir, "External.CMakeLists.txt.in", TEMPLATE_EXTERNAL_CMAKELISTS)?;
write_file(&template_dir, "External.Download.txt.in", TEMPLATE_EXTERNAL_DOWNLOAD)?;
write_file(&template_dir, "Src.SubDir.CMakeLists.txt.in", TEMPLATE_SRC_SUBDIR_CMAKELISTS)?;
Ok(())
}
fn write_file(dir: &Path, filename: &str, content: &str) -> Result<()> {
let path = dir.join(filename);
fs::write(&path, content)
.with_context(|| format!("Failed to write {}", path.display()))?;
Ok(())
}
#[allow(dead_code)]
pub fn clean_cmake_dir() -> Result<()> {
let home = std::env::var("HOME")
.or_else(|_| std::env::var("USERPROFILE"))
.context("Failed to get home directory from HOME or USERPROFILE env var")?;
let home = PathBuf::from(home);
let cmake_dir = home.join(".ccgo/cmake");
if cmake_dir.exists() {
fs::remove_dir_all(&cmake_dir)
.with_context(|| format!("Failed to remove {}", cmake_dir.display()))?;
}
Ok(())
}