Init
This commit is contained in:
commit
687ce0f7bb
14 changed files with 2120 additions and 0 deletions
3
src/common/mod.rs
Normal file
3
src/common/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub static TEMP_FOLDER: &str = "temp";
|
||||
|
||||
pub mod utils;
|
17
src/common/utils/downloader.rs
Normal file
17
src/common/utils/downloader.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use std::{fs, path::PathBuf};
|
||||
|
||||
fn create_download_folder() -> Option<()> {
|
||||
fs::create_dir_all(super::super::TEMP_FOLDER).ok()
|
||||
}
|
||||
|
||||
pub fn download_file(url : &String, filename: &str) -> Option<PathBuf> {
|
||||
create_download_folder()?;
|
||||
let mut response = reqwest::blocking::get(url).ok()?;
|
||||
|
||||
let fname = std::path::Path::new(super::super::TEMP_FOLDER).join(filename);
|
||||
|
||||
let mut dest = fs::File::create(fname.clone()).ok()?;
|
||||
response.copy_to(&mut dest).ok()?;
|
||||
|
||||
Some(fname)
|
||||
}
|
55
src/common/utils/extractor.rs
Normal file
55
src/common/utils/extractor.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use crate::common;
|
||||
use std::{fs::{
|
||||
File,
|
||||
create_dir_all
|
||||
}, io, path::{self, PathBuf}};
|
||||
|
||||
pub fn extract_file(path: &PathBuf, outdir: &str) -> Option<()> {
|
||||
let file = File::open(&path).unwrap();
|
||||
let mut archive = match zip::ZipArchive::new(file) {
|
||||
Ok(archive) => archive,
|
||||
Err(err) => {
|
||||
println!("[ERROR][EXTRACTOR] {}", err);
|
||||
return None
|
||||
}
|
||||
};
|
||||
|
||||
let path = path::Path::new(common::TEMP_FOLDER).join(outdir);
|
||||
|
||||
for i in 0..archive.len() {
|
||||
let mut file = archive.by_index(i).ok()?;
|
||||
let file_path = file.enclosed_name()?;
|
||||
let output_path = path.join(file_path);
|
||||
|
||||
if (&*file.name()).ends_with('/') {
|
||||
println!("File {} extracted to \"{}\"", i, output_path.display());
|
||||
create_dir_all(&output_path).unwrap();
|
||||
} else {
|
||||
println!(
|
||||
"File {} extracted to \"{}\" ({} bytes)",
|
||||
i,
|
||||
output_path.display(),
|
||||
file.size()
|
||||
);
|
||||
if let Some(p) = output_path.parent() {
|
||||
if !p.exists() {
|
||||
create_dir_all(&p).unwrap();
|
||||
}
|
||||
}
|
||||
let mut outfile = File::create(&output_path).unwrap();
|
||||
io::copy(&mut file, &mut outfile).unwrap();
|
||||
}
|
||||
|
||||
// Get and Set permissions
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
if let Some(mode) = file.unix_mode() {
|
||||
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
39
src/common/utils/git.rs
Normal file
39
src/common/utils/git.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use serde_derive::{Serialize, Deserialize};
|
||||
use reqwest::header;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Asset {
|
||||
pub browser_download_url: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GitResponse {
|
||||
pub assets: Vec<Asset>
|
||||
}
|
||||
|
||||
pub fn get_git_release_by_version(repo: &str, version: &str) -> Option<GitResponse> {
|
||||
let url = format!("https://api.github.com/repos/{}/releases/{}", repo, version);
|
||||
|
||||
let mut headers = header::HeaderMap::new();
|
||||
headers.append(header::USER_AGENT, header::HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55"));
|
||||
|
||||
let data = reqwest::blocking::Client::builder()
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
.ok()?
|
||||
.get(url)
|
||||
.send()
|
||||
.ok()?
|
||||
.text()
|
||||
.ok()?;
|
||||
|
||||
let git_response : GitResponse = serde_json::from_str(&data)
|
||||
.ok()?;
|
||||
|
||||
Some(git_response)
|
||||
}
|
||||
|
||||
pub fn get_git_latest_release(repo: &str) -> Option<GitResponse> {
|
||||
Some(get_git_release_by_version(repo, "latest")?)
|
||||
}
|
3
src/common/utils/mod.rs
Normal file
3
src/common/utils/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod downloader;
|
||||
pub mod extractor;
|
||||
pub mod git;
|
6
src/main.rs
Normal file
6
src/main.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
mod windows;
|
||||
pub mod common;
|
||||
|
||||
fn main() {
|
||||
windows::start();
|
||||
}
|
26
src/windows/fvm/git.rs
Normal file
26
src/windows/fvm/git.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use crate::common::utils::git;
|
||||
|
||||
fn get_prefix_from_arch() -> Option<String> {
|
||||
if std::env::consts::ARCH == "x86_64" {
|
||||
Some(format!("x64"))
|
||||
} else if std::env::consts::ARCH == "x86" {
|
||||
Some(format!("ia32"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_file_url() -> Result<String, String> {
|
||||
let git_response = git::get_git_latest_release("leoafarias/fvm")
|
||||
.ok_or(format!("Failed to get git release"))?;
|
||||
|
||||
let arch_prefix = get_prefix_from_arch().ok_or(format!("Arch not supported"))?;
|
||||
|
||||
for asset in git_response.assets {
|
||||
if asset.name.contains(std::env::consts::OS) && asset.name.contains(arch_prefix.as_str()) {
|
||||
return Ok(asset.browser_download_url);
|
||||
}
|
||||
}
|
||||
|
||||
Err(format!("OS not supported"))
|
||||
}
|
33
src/windows/fvm/mod.rs
Normal file
33
src/windows/fvm/mod.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
mod git;
|
||||
|
||||
use crate::common::utils::downloader;
|
||||
use crate::common::utils::extractor;
|
||||
|
||||
// use std::process::Command;
|
||||
|
||||
pub fn install() -> Result<(), String> {
|
||||
println!("Install FVM");
|
||||
|
||||
let url = git::get_file_url()?;
|
||||
|
||||
let filename = url.split('/').last()
|
||||
.ok_or(format!("Failed to download file"))?;
|
||||
|
||||
let file = downloader::download_file(&url, &filename)
|
||||
.ok_or(format!("Failed to download file"))?;
|
||||
|
||||
extractor::extract_file(&file, "fvm")
|
||||
.ok_or(format!("Failed to extract file"))?;
|
||||
|
||||
println!("{}", url);
|
||||
|
||||
// let output = Command::new("winget")
|
||||
// .args(&[""])
|
||||
// .output()
|
||||
// .map_err(|_| format!("Permision refused ! Please run as administrator."))?;
|
||||
|
||||
|
||||
// println!("{}", std::str::from_utf8(&output.stdout).map_err(|_| format!("Internal error"))?);
|
||||
|
||||
Ok(())
|
||||
}
|
36
src/windows/mod.rs
Normal file
36
src/windows/mod.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
mod fvm;
|
||||
|
||||
use structopt::{
|
||||
StructOpt,
|
||||
clap::{
|
||||
arg_enum
|
||||
}
|
||||
};
|
||||
|
||||
arg_enum! {
|
||||
#[derive(Debug)]
|
||||
enum Tool {
|
||||
Fvm
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "autoconfig", about = "Auto install local config.")]
|
||||
struct Opt {
|
||||
#[structopt(short = "i", long = "install", help = "Available values : fvm (Flutter version manager)")]
|
||||
tools: Vec<Tool>,
|
||||
}
|
||||
|
||||
|
||||
pub fn start() {
|
||||
let opt = Opt::from_args();
|
||||
for tool in &opt.tools {
|
||||
let result = match tool {
|
||||
Tool::Fvm => fvm::install()
|
||||
};
|
||||
|
||||
if let Err(err) = result {
|
||||
eprintln!("[ERROR] {}", err);
|
||||
}
|
||||
}
|
||||
}
|
Reference in a new issue