aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/downloader/rar_downloader.rs
blob: 1aaa71cfe80a42baf4a5bf4b9e5769cf5e388f1c (plain)
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
//! ref: composer/src/Composer/Downloader/RarDownloader.php

use anyhow::Result;
use shirabe_external_packages::react::promise::promise_interface::PromiseInterface;
use shirabe_php_shim::{class_exists, implode, RarArchive, RuntimeException, UnexpectedValueException};
use crate::downloader::archive_downloader::ArchiveDownloader;
use crate::package::package_interface::PackageInterface;
use crate::util::ini_helper::IniHelper;
use crate::util::platform::Platform;

pub struct RarDownloader {
    inner: ArchiveDownloader,
}

impl RarDownloader {
    pub(crate) fn extract(&self, _package: &dyn PackageInterface, file: &str, path: &str) -> Result<Box<dyn PromiseInterface>> {
        let mut process_error: Option<String> = None;

        if !Platform::is_windows() {
            let command = vec![
                "sh".to_string(),
                "-c".to_string(),
                r#"unrar x -- "$0" "$1" >/dev/null && chmod -R u+w "$1""#.to_string(),
                file.to_string(),
                path.to_string(),
            ];

            if self.inner.process.execute(&command, &mut String::new()) == 0 {
                return Ok(shirabe_external_packages::react::promise::resolve(None));
            }

            process_error = Some(format!(
                "Failed to execute {}\n\n{}",
                implode(" ", &command),
                self.inner.process.get_error_output(),
            ));
        }

        if !class_exists("RarArchive") {
            let ini_message = IniHelper::get_message();
            let error = if !Platform::is_windows() {
                format!("Could not decompress the archive, enable the PHP rar extension.\n{}", ini_message)
            } else {
                format!(
                    "Could not decompress the archive, enable the PHP rar extension or install unrar.\n{}\n{}",
                    ini_message,
                    process_error.as_deref().unwrap_or(""),
                )
            };
            return Err(RuntimeException { message: error, code: 0 }.into());
        }

        let rar_archive = RarArchive::open(file);
        if rar_archive.is_none() {
            return Err(UnexpectedValueException {
                message: format!("Could not open RAR archive: {}", file),
                code: 0,
            }.into());
        }
        let rar_archive = rar_archive.unwrap();

        let entries = rar_archive.get_entries();
        if entries.is_none() {
            return Err(RuntimeException {
                message: "Could not retrieve RAR archive entries".to_string(),
                code: 0,
            }.into());
        }

        for entry in entries.unwrap() {
            if !entry.extract(path) {
                return Err(RuntimeException {
                    message: "Could not extract entry".to_string(),
                    code: 0,
                }.into());
            }
        }

        rar_archive.close();

        Ok(shirabe_external_packages::react::promise::resolve(None))
    }
}