1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
pub mod platform; use std::io; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::fs::{File, metadata, create_dir_all, copy}; use std::process::Command; use directories::{ BaseDirs }; use reqwest::blocking as reqwest; use flate2::read::GzDecoder; use http::StatusCode; use std::time::{SystemTime}; pub static PRISMA_VERSION: &str = "2.23.0"; pub static ENGINE_VERSION: &str = "adf5e8cba3daf12d456d911d72b6e9418681b28b"; pub static BASE_DIR_NAME: &str = "prisma/binaries"; pub struct Engine<'a> { pub name: &'a str, pub env: &'a str, } pub const ENGINES: [Engine; 4] =[ Engine { name: "query-engine", env: "PRISMA_QUERY_ENGINE_BINARY" }, Engine { name: "migration-engine", env: "PRISMA_MIGRATION_ENGINE_BINARY" }, Engine { name: "introspection-engine", env: "PRISMA_INTROSPECTION_ENGINE_BINARY" }, Engine { name: "prisma-fmt", env: "PRISMA_FMT_BINARY" }, ]; pub fn prisma_cli_name() -> String { let variation = platform::name(); format!("prisma-cli-{}", variation) } pub fn global_temp_dir () -> PathBuf { let temp = std::env::temp_dir(); temp.join(BASE_DIR_NAME).join("engines").join(ENGINE_VERSION) } pub fn global_unpack_dir() -> PathBuf { global_temp_dir().join("unpacked") } pub fn global_cache_dir() -> PathBuf { let base_dirs = BaseDirs::new().unwrap(); let cache_dir = base_dirs.cache_dir(); cache_dir.join(BASE_DIR_NAME).join("cli").join(PRISMA_VERSION) } pub fn fetch_engine(to_dir: PathBuf, engine_name: String, binary_platform_name: String) -> Result<(), ()> { let to = platform::check_for_extension( binary_platform_name.clone(), to_dir .join(ENGINE_VERSION) .join(format!("prisma-{}-{}", engine_name, binary_platform_name)) .into_os_string().into_string().unwrap() ); let binary_platform_remote_name = match binary_platform_name.as_str() { "linux" => "linux-musl", name => name }; let url = platform::check_for_extension( binary_platform_name.clone(), format!( "https://binaries.prisma.sh/all_commits/{}/{}/{}.gz", ENGINE_VERSION, binary_platform_remote_name, engine_name ) ); match metadata(&to) { Err(_) => (), Ok(_) => { println!("{} is cached", to.to_string()); return Ok(()); } }; download(url.clone(), to.clone()).expect(&format!("could not download {} to {}", &url, &to)); Ok(()) } pub fn fetch_native(to_dir: PathBuf) -> Result<(), ()> { if !to_dir.is_absolute() { panic!("to_dir must be absolute") } download_cli(to_dir.clone()).expect("could not download engines"); for e in &ENGINES { download_engine( e.name.to_string(), to_dir.clone() ).expect("could not download engines"); }; Ok(()) } fn download_cli(to_dir: PathBuf) -> Result<(), ()> { let cli = prisma_cli_name(); let to = platform::check_for_extension( platform::name(), to_dir.join(cli).into_os_string().into_string().unwrap() ); let url = platform::check_for_extension( platform::name(), format!("https://prisma-photongo.s3-eu-west-1.amazonaws.com/{}-{}-{}.gz", "prisma-cli", PRISMA_VERSION, platform::name() ) ); match metadata(&to) { Err(_) => (), Ok(_) => { println!("{} is cached", to.to_string()); return Ok(()); } }; download(url.clone(), to.clone()).expect(&format!("could not download {} to {}", url, to)); Ok(()) } fn download_engine(name: String, to_dir: PathBuf) -> Result<String, ()> { let binary_name = platform::binary_platform_name(); let to = platform::check_for_extension( binary_name.to_string(), to_dir .join(ENGINE_VERSION) .join(format!("prisma-{}-{}", name, binary_name)) .into_os_string().into_string().unwrap() ); let url = platform::check_for_extension( binary_name.to_string(), format!("https://binaries.prisma.sh/all_commits/{}/{}/{}.gz", ENGINE_VERSION, name, &binary_name) ); match metadata(&to) { Err(_) => {}, Ok(_) => { println!("{} is cached", to.to_string()); return Ok(to); } }; let start_download = SystemTime::now(); download(url.clone(), to.clone()).expect(&format!("could not download {} to {}", url, to)); println!( "download() took {}", SystemTime::now().duration_since(start_download).unwrap().as_millis() ); Ok(to.to_string()) } fn download(url: String, to: String) -> Result<(), ()> { create_dir_all(Path::new(&to).parent().unwrap()).unwrap(); let tmp = &(to.clone() + ".tmp"); let resp = reqwest::get(&url).unwrap(); if resp.status() != StatusCode::OK { panic!("received code {} from {}", resp.status(), &url); }; let mut tmp_file = File::create(tmp).expect(&format!("could not create {}", tmp)); if !cfg!(target_os = "windows") { Command::new("chmod") .arg("+x") .arg(tmp) .output() .expect("failed to make file executable"); } let mut buffer = Vec::new(); io::BufReader::new( GzDecoder::new(resp) ).read_to_end(&mut buffer).unwrap(); tmp_file.write(buffer.as_slice()).expect("could not write to .tmp file"); copy(tmp, to).expect(&format!("could not copy file {}", url)); Ok(()) }