skyblock_repo/utils/
repo.rs

1#[cfg(feature = "python")]
2pub mod python {
3	use std::fs::{File, OpenOptions, create_dir_all, exists, remove_dir_all, remove_file, rename};
4	use std::io::{self, Write};
5	use std::path::Path;
6
7	use pyo3::exceptions::{PyIOError, PyRuntimeError};
8	use pyo3::*;
9
10	/// Downloads the github SkyblockRepo data and unzips
11	#[pyfunction(name = "download_repo")]
12	#[pyo3(signature=(delete_zip=true, commit="main"))]
13	pub fn download_zip(
14		delete_zip: bool,
15		commit: &str,
16	) -> PyResult<()> {
17		let url = format!(
18			"https://github.com/SkyblockRepo/Repo/archive/{}.zip",
19			commit
20		);
21
22		let mut response = ureq::get(url)
23			.call()
24			.map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
25
26		if !exists("SkyblockRepo")? || (!exists("SkyblockRepo.zip")? && !exists("SkyblockRepo")?) {
27			if response.status() == 200 {
28				let mut file = OpenOptions::new()
29					.read(true)
30					.write(true)
31					.create_new(true)
32					.open("SkyblockRepo.zip")?;
33
34				let content = response
35					.body_mut()
36					.read_to_vec()
37					.map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
38				file.write_all(&content)?;
39
40				unzip_repo(file, commit)?;
41			} else {
42				return Err(PyErr::new::<PyRuntimeError, _>(format!(
43					"Reqwest failed with status {}",
44					response.status()
45				)));
46			}
47		} else {
48			return Ok(());
49		}
50
51		if delete_zip {
52			remove_file(Path::new("SkyblockRepo.zip"))?;
53		}
54
55		Ok(())
56	}
57
58	fn unzip_repo(
59		file: File,
60		commit: &str,
61	) -> PyResult<()> {
62		let mut archive =
63			zip::ZipArchive::new(file).map_err(|e| PyErr::new::<PyIOError, _>(e.to_string()))?;
64
65		for i in 0..archive.len() {
66			let mut file = archive
67				.by_index(i)
68				.map_err(|e| PyErr::new::<PyIOError, _>(e.to_string()))?;
69			let outpath = match file.enclosed_name() {
70				| Some(path) => path,
71				| None => continue,
72			};
73
74			if file.is_dir() {
75				create_dir_all(&outpath)?;
76			} else {
77				if let Some(p) = outpath.parent() {
78					if !p.exists() {
79						create_dir_all(p)?;
80					}
81				}
82				let mut outfile = File::create(&outpath)?;
83				io::copy(&mut file, &mut outfile)?;
84			}
85
86			#[cfg(unix)]
87			{
88				use std::os::unix::fs::PermissionsExt;
89
90				if let Some(mode) = file.unix_mode() {
91					use std::fs::{Permissions, set_permissions};
92
93					set_permissions(&outpath, Permissions::from_mode(mode))?;
94				}
95			}
96		}
97
98		rename(
99			Path::new(&format!("Repo-{}", commit)),
100			Path::new("SkyblockRepo"),
101		)?;
102
103		Ok(())
104	}
105
106	#[pyfunction(name = "delete_repo")]
107	pub fn delete_repo_files() -> PyResult<()> {
108		let _ = remove_file("SkyblockRepo.zip").or_else(|err| {
109			// stifle file not found error because you can already remove the zip in the download function
110			if err.kind() == io::ErrorKind::NotFound {
111				Ok(())
112			} else {
113				Err(err)
114			}
115		})?;
116		remove_dir_all("SkyblockRepo")?;
117		Ok(())
118	}
119}
120
121#[cfg(not(feature = "python"))]
122pub mod rust {
123	use std::fs::{File, OpenOptions, create_dir_all, exists, remove_dir_all, remove_file, rename};
124	use std::io::{self, Write};
125	use std::path::Path;
126
127	#[cfg(feature = "log")]
128	use log::{error, trace};
129
130	/// Downloads the github SkyblockRepo data and unzips
131	///
132	/// You can additonally remove the downloaded zip and only keep the extracted directory by passing in `true`
133	pub fn download_zip(
134		delete_zip: bool,
135		commit: Option<&str>,
136	) -> Result<(), Box<dyn std::error::Error>> {
137		let commit = commit.unwrap_or("main");
138		let url = format!(
139			"https://github.com/SkyblockRepo/Repo/archive/{}.zip",
140			commit
141		);
142
143		let mut response = ureq::get(url).call()?;
144
145		if !exists("SkyblockRepo")? || (!exists("SkyblockRepo.zip")? && !exists("SkyblockRepo")?) {
146			if response.status() == 200 {
147				let mut file = OpenOptions::new()
148					.read(true)
149					.write(true)
150					.create_new(true)
151					.open("SkyblockRepo.zip")?;
152
153				let content = response.body_mut().read_to_vec()?;
154				file.write_all(&content)?;
155
156				unzip_repo(file, commit)?;
157			} else {
158				return Err(format!("Reqwest failed with status {}", response.status()).into());
159			}
160		} else {
161			#[cfg(feature = "log")]
162			error!(
163				"SkyblockRepo.zip and/or SkyblockRepo/ directory are present, if you wish to refetch them, delete them."
164			);
165			return Ok(());
166		}
167
168		if delete_zip {
169			remove_file(Path::new("SkyblockRepo.zip"))?;
170		}
171
172		Ok(())
173	}
174
175	fn unzip_repo(
176		file: File,
177		commit: &str,
178	) -> Result<(), Box<dyn std::error::Error>> {
179		let mut archive = zip::ZipArchive::new(file)?;
180
181		for i in 0..archive.len() {
182			let mut file = archive.by_index(i)?;
183			let outpath = match file.enclosed_name() {
184				| Some(path) => path,
185				| None => continue,
186			};
187
188			if file.is_dir() {
189				#[cfg(feature = "log")]
190				trace!("File {} extracted to \"{}\"", i, outpath.display());
191				create_dir_all(&outpath)?;
192			} else {
193				#[cfg(feature = "log")]
194				trace!(
195					"File {} extracted to \"{}\" ({} bytes)",
196					i,
197					outpath.display(),
198					file.size()
199				);
200				if let Some(p) = outpath.parent() {
201					if !p.exists() {
202						create_dir_all(p)?;
203					}
204				}
205				let mut outfile = File::create(&outpath)?;
206				io::copy(&mut file, &mut outfile)?;
207			}
208
209			#[cfg(unix)]
210			{
211				use std::os::unix::fs::PermissionsExt;
212
213				if let Some(mode) = file.unix_mode() {
214					use std::fs::{Permissions, set_permissions};
215
216					set_permissions(&outpath, Permissions::from_mode(mode))?;
217				}
218			}
219		}
220
221		rename(
222			Path::new(&format!("Repo-{}", commit)),
223			Path::new("SkyblockRepo"),
224		)?;
225
226		Ok(())
227	}
228
229	pub fn delete_repo_files() -> Result<(), Box<dyn std::error::Error>> {
230		let _ = remove_file("SkyblockRepo.zip").or_else(|err| {
231			// stifle file not found error because you can already remove the zip in the download function
232			if err.kind() == io::ErrorKind::NotFound {
233				Ok(())
234			} else {
235				Err(err)
236			}
237		})?;
238		remove_dir_all("SkyblockRepo")?;
239		Ok(())
240	}
241}