use crate::project::Package;
use crate::project::Project;
use libflate::gzip::{Decoder, Encoder};
use std::io::{Read, Write};
use walkdir::WalkDir;
use serde_derive::{Deserialize, Serialize};
use std::fs::{create_dir, File};
use std::io;
use std::io::ErrorKind;
use std::path::Path;
use std::sync::Mutex;
use tar::Archive;
lazy_static! {
#[derive(Debug)]
pub static ref PROGRAM_DATA: Mutex<String> = {
let home_dir = match dirs::home_dir(){
Some(dir) => format!("{}", dir.as_path().display()),
None => panic!("this program won't work without a homedir"),
};
let cppdir = format!("{}/{}", home_dir, ".cppbuild");
let path = Path::new(cppdir.as_str());
if !path.exists(){
match create_dir(cppdir.as_str()){
Ok(()) => (),
Err(e) => panic!("error: {}", e),
}
}
Mutex::new(cppdir)
};
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RepoEntry {
name: String,
version: String,
build_type: PackageType,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Index {
packages: Vec<Package>,
}
impl Index {
pub fn contains(&self, package: &Package) -> bool {
for pack in self.packages.iter() {
if pack == package {
return true;
}
}
false
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Version {
raw: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum PackageType {
CppBuild,
Make,
Shell,
Raw,
PkgConfig,
}
pub fn download_packages(packages: &[(String, String)]) -> io::Result<()> {
for (name, version) in packages.iter() {
println!("arch: {}", get_arch()?);
let response = reqwest::blocking::get(
format!(
"http://localhost/cppbuild/{}/{}-{}.tar.gz",
get_arch()?,
name,
version
)
.as_str(),
)
.unwrap();
let bytes: Vec<u8> = response.bytes().unwrap().to_vec();
println!("bytes recv: {}", bytes.len());
let mut decoder = Decoder::new(&*bytes)?;
let mut decoded_data = Vec::new();
decoder.read_to_end(&mut decoded_data)?;
let mut a = Archive::new(&*decoded_data);
a.unpack(format!("{}/{}-{}/", PROGRAM_DATA.lock().unwrap(), name, version).as_str())?;
}
Ok(())
}
pub fn generate_package(kind: PackageType, path: &str) -> std::io::Result<()> {
match kind {
PackageType::CppBuild => {
let project = Project::from_file(path)?;
println!("path: {}", path);
compress(path, &project.get_name(), &project.get_version())?;
Ok(())
}
PackageType::Make => Ok(()),
PackageType::Shell => Ok(()),
PackageType::Raw => Ok(()),
PackageType::PkgConfig => {
let conf = pkg_config::Config::new();
match conf.probe(path) {
Ok(lib) => {
for link in lib.link_paths.iter() {
for l in lib.libs.iter() {
let path_name = format!("{}/{}", link.display(), l);
let file: &Path = &Path::new(&path_name);
if file.exists() && file.is_file() {
}
}
}
}
Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
}
Ok(())
}
}
}
pub fn compress(path: &str, name: &str, version: &str) -> std::io::Result<String> {
use tar::Builder;
let tarpath = format!("{}/target/{}-{}.tar", path, name, version);
let tarfile = File::create(tarpath.as_str())?;
let mut archive = Builder::new(tarfile);
for entry in WalkDir::new(path).follow_links(true) {
let entry = match entry {
Ok(ent) => ent,
Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
};
let path = entry.path();
let filename = format!("{}", path.display());
if !filename.contains("target") && path.is_file() {
println!("{}", filename);
archive.append_file(path, &mut File::open(path)?)?;
}
}
archive.finish()?;
let mut tarfile = File::open(tarpath.as_str())?;
let mut encoder = match Encoder::new(Vec::new()) {
Ok(ent) => ent,
Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
};
let mut data = Vec::new();
tarfile.read_to_end(&mut data)?;
println!("size of data: {}", data.len());
let mut cursor = std::io::Cursor::new(data);
io::copy(&mut cursor, &mut encoder)?;
let encoded_data = match encoder.finish().into_result() {
Ok(data) => data,
Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
};
let mut targz = File::create(format!("{}.gz", tarpath).as_str())?;
targz.write_all(&encoded_data)?;
std::fs::remove_file(tarpath.as_str())?;
Ok(format!("{}.gz", tarpath))
}
pub fn generate_pc(package: &Package, path: &str) -> std::io::Result<()> {
let mut file = File::create(format!("{}/target/{}.pc", path, package.get_name()).as_str())?;
file.write_all(b"prefix=\n")?;
file.write_all(b"exec_prefix=${prefix}\n")?;
file.write_all(format!("libdir={}/{}-{}/target/\n", "${prefix}", package.get_name(), package.get_version()).as_bytes())?;
file.write_all(format!("includedir={}/{}-{}/headers/\n", "${prefix}", package.get_name(), package.get_version()).as_bytes())?;
file.write_all(format!("Name: {}\n", package.get_name()).as_bytes())?;
file.write_all(format!("Version: {}\n", package.get_version()).as_bytes())?;
if let Some(desc) = package.get_description(){
file.write_all(format!("Description: {}\n", desc).as_bytes())?;
};
file.write_all(format!("Libs: -L{} -l{}\n", "${libdir}", package.get_name()).as_bytes())?;
file.write_all(b"CFlags: -I${includedir}\n")?;
Ok(())
}
pub fn get_arch() -> std::io::Result<String> {
let rust_info = rust_info::get();
Ok(format!(
"{}-{}",
match rust_info.target_arch {
Some(arch) => arch,
None =>
return Err(std::io::Error::new(
ErrorKind::Other,
"Failed to get architecture"
)),
},
match rust_info.target_os {
Some(arch) => arch,
None =>
return Err(std::io::Error::new(
ErrorKind::Other,
"Failed to get architecture"
)),
}
))
}