aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/downloader/gzip_downloader.rs
blob: 2158126d5cd1c380936e946aa08c62536914f625 (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
//! ref: composer/src/Composer/Downloader/GzipDownloader.php

use anyhow::Result;
use shirabe_external_packages::react::promise::promise_interface::PromiseInterface;
use shirabe_php_shim::{
    RuntimeException,
    extension_loaded, fclose, fopen, fwrite, gzclose, gzopen, gzread,
    implode, parse_url, pathinfo, strtr,
    DIRECTORY_SEPARATOR, PATHINFO_FILENAME, PHP_URL_PATH,
};
use crate::downloader::archive_downloader::ArchiveDownloader;
use crate::package::package_interface::PackageInterface;
use crate::util::platform::Platform;

pub struct GzipDownloader {
    inner: ArchiveDownloader,
}

impl GzipDownloader {
    pub(crate) fn extract(&self, package: &dyn PackageInterface, file: &str, path: &str) -> Result<Box<dyn PromiseInterface>> {
        let filename = pathinfo(
            parse_url(&strtr(&package.get_dist_url().unwrap_or_default(), "\\", "/"), PHP_URL_PATH),
            PATHINFO_FILENAME,
        );
        let target_filepath = format!("{}{}{}", path, DIRECTORY_SEPARATOR, filename);

        if !Platform::is_windows() {
            let command = vec![
                "sh".to_string(),
                "-c".to_string(),
                "gzip -cd -- \"$0\" > \"$1\"".to_string(),
                file.to_string(),
                target_filepath.clone(),
            ];

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

            if extension_loaded("zlib") {
                self.extract_using_ext(file, &target_filepath);
                return Ok(shirabe_external_packages::react::promise::resolve(None));
            }

            let process_error = format!(
                "Failed to execute {}\n\n{}",
                implode(" ", &command),
                self.inner.process.get_error_output(),
            );
            return Err(anyhow::anyhow!(RuntimeException { message: process_error, code: 0 }));
        }

        self.extract_using_ext(file, &target_filepath);

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

    fn extract_using_ext(&self, file: &str, target_filepath: &str) {
        let archive_file = gzopen(file, "rb");
        let target_file = fopen(target_filepath, "wb");
        loop {
            let string = gzread(archive_file.clone(), 4096);
            if string.is_empty() {
                break;
            }
            fwrite(target_file.clone(), &string, Platform::strlen(&string));
        }
        gzclose(archive_file);
        fclose(target_file);
    }
}