pub async fn download_tarball(app: &App, package: VoltPackage, _state: State) -> Result<()> {
    let package_instance = package.clone();

    let package_name = package.name.clone();
    let package_version = package.version.clone();

    // @types/eslint
    if package_name.starts_with('@') && package_name.contains('/') {
        let package_directory_location = app
            .volt_dir
            .join(&package.name.split('/').collect::<Vec<&str>>()[0]);

        if !Path::new(&package_directory_location).exists() {
            create_dir_all(&package_directory_location)
                .await
                .map_err(VoltError::CreateDirError)?;
        }
    }

    // Directory to extract tarball to
    let mut extract_directory = PathBuf::from(&app.volt_dir);

    // @types/eslint
    if package.clone().name.starts_with('@') && package.clone().name.contains('/') {
        if cfg!(target_os = "windows") {
            let name = package.clone().name.replace('/', r"\");

            let split = name.split('\\').collect::<Vec<&str>>();

            // C:\Users\xtrem\.volt\@types
            extract_directory = extract_directory.join(split[0]);
        } else {
            let name = package.clone().name;
            let split = name.split('/').collect::<Vec<&str>>();

            // ~/.volt/@types
            extract_directory = extract_directory.join(split[0]);
        }
    }

    let client = reqwest::ClientBuilder::new()
        .use_rustls_tls()
        .build()
        .unwrap();

    let existing_check = cacache::read_sync(
        &extract_directory,
        format!(
            "pkg::{}::{}::{}",
            &package_name, &package_version, package.integrity
        ),
    );

    // if package is not already installed
    if existing_check.is_err() {
        // Tarball bytes response
        let bytes: bytes::Bytes = client
            .get(package_instance.tarball)
            .send()
            .await
            .unwrap()
            .bytes()
            .await
            .unwrap();

        let algorithm;

        // there are only 2 supported algorithms
        // sha1 and sha512
        // so we can be sure that if it doesn't start with sha1, it's going to have to be sha512
        if package.integrity.starts_with("sha1") {
            algorithm = Algorithm::Sha1;
        } else {
            algorithm = Algorithm::Sha512;
        }

        // Verify If Bytes == (Sha512 | Sha1) of Tarball
        if package.integrity == App::calc_hash(&bytes, algorithm).unwrap() {
            // Create node_modules
            create_dir_all(&app.node_modules_dir).await.unwrap();

            // let node_modules_dep_path = app.node_modules_dir.join(&package.name);
            let node_modules_dep_path = app.node_modules_dir.clone();

            // Initialize tarfile decoder while directly passing in bytes

            let bytes = Arc::new(bytes);

            let bytes_ref = bytes.clone();

            futures::try_join!(
                tokio::task::spawn_blocking(move || {
                    let node_gz_decoder = GzDecoder::new(&**bytes_ref);

                    let mut node_archive = Archive::new(node_gz_decoder);

                    for entry in node_archive.entries().unwrap() {
                        let mut entry = entry.unwrap();
                        let path = entry.path().unwrap();
                        let mut new_path = PathBuf::new();

                        for component in path.components() {
                            if component.as_os_str() == "package" {
                                new_path.push(Component::Normal(OsStr::new(&package.name)));
                            } else {
                                new_path.push(component)
                            }
                        }

                        std::fs::create_dir_all(
                            node_modules_dep_path
                                .to_path_buf()
                                .join(&new_path)
                                .parent()
                                .unwrap(),
                        )
                        .unwrap();

                        match entry.unpack(node_modules_dep_path.to_path_buf().join(&new_path)) {
                            Ok(_v) => {}
                            Err(err) => {
                                println!("{:?}", err);
                            }
                        }
                    }
                }),
                tokio::task::spawn_blocking(move || {
                    let gz_decoder = GzDecoder::new(&**bytes);

                    let mut archive = Archive::new(gz_decoder);

                    let mut cas_file_map: HashMap<String, Integrity> = HashMap::new();

                    for entry in archive.entries().unwrap() {
                        let mut entry = entry.unwrap();
                        let mut buffer = vec![];

                        entry.read_to_end(&mut buffer).unwrap();

                        let sri =
                            cacache::write_hash_sync(extract_directory.clone(), &buffer).unwrap();

                        cas_file_map
                            .insert(entry.path().unwrap().to_str().unwrap().to_string(), sri);
                    }

                    cacache::write_sync(
                        extract_directory.clone(),
                        format!(
                            "pkg::{}::{}::{}",
                            &package_name, &package_version, package.integrity
                        ),
                        serde_json::to_string(&cas_file_map).unwrap(),
                    )
                    .unwrap();
                })
            )
            .unwrap();
        } else {
            return Err(VoltError::ChecksumVerificationError.into());
        }
    } else {
        // package is already downloaded and extracted to the ~/.volt folder.
        let buf = existing_check.unwrap();

        let cas_file_map: HashMap<String, Integrity> =
            serde_json::from_str(&String::from_utf8(buf).unwrap()).unwrap();

        for item in cas_file_map.iter() {
            let contents = cacache::read_hash_sync(&extract_directory, item.1).unwrap();

            let data = String::from_utf8(contents).unwrap();

            // generate node_modules path
            let path = app.node_modules_dir.join(format!(
                "{}/{}",
                package.name,
                item.0.strip_prefix("package/").unwrap()
            ));

            std::fs::create_dir_all(path.parent().unwrap()).unwrap();

            let mut file = File::create(path).unwrap();
            file.write_all(data.as_bytes()).unwrap();
        }
    }

    Ok(())
}
/// downloads and extracts tarball file from package
downloads and extracts tarball file from package
downloads and extracts tarball file from package
pub async fn download_tarball(app: &App, package: VoltPackage, _state: State) -> Result<()> {
    let package_instance = package.clone();
    let package_name = package.name.clone();
    let package_version = package.version.clone();
    // @types/eslint
    if package_name.starts_with('@') && package_name.contains('/') {
        let package_directory_location = app
            .volt_dir
            .join(&package.name.split('/').collect::<Vec<&str>>()[0]);
        if !Path::new(&package_directory_location).exists() {
            create_dir_all(&package_directory_location)
                .await
                .map_err(VoltError::CreateDirError)?;
        }
    }
    // Directory to extract tarball to
    let mut extract_directory = PathBuf::from(&app.volt_dir);
    // @types/eslint
    if package.clone().name.starts_with('@') && package.clone().name.contains('/') {
        if cfg!(target_os = "windows") {
            let name = package.clone().name.replace('/', r"\");
            let split = name.split('\\').collect::<Vec<&str>>();
            // C:\Users\xtrem\.volt\@types
            extract_directory = extract_directory.join(split[0]);
        } else {
            let name = package.clone().name;
            let split = name.split('/').collect::<Vec<&str>>();
            // ~/.volt/@types
            extract_directory = extract_directory.join(split[0]);
        }
    }
    let client = reqwest::ClientBuilder::new()
        .use_rustls_tls()
        .build()
        .unwrap();
    let existing_check = cacache::read_sync(
        &extract_directory,
        format!(
            "pkg::{}::{}::{}",
            &package_name, &package_version, package.integrity
        ),
    );
    // if package is not already installed
    if existing_check.is_err() {
        // Tarball bytes response
        let bytes: bytes::Bytes = client
            .get(package_instance.tarball)
            .send()
            .await
            .unwrap()
            .bytes()
            .await
            .unwrap();
        let algorithm;
        // there are only 2 supported algorithms
        // sha1 and sha512
        // so we can be sure that if it doesn't start with sha1, it's going to have to be sha512
        if package.integrity.starts_with("sha1") {
            algorithm = Algorithm::Sha1;
        } else {
            algorithm = Algorithm::Sha512;
        }
        // Verify If Bytes == (Sha512 | Sha1) of Tarball
        if package.integrity == App::calc_hash(&bytes, algorithm).unwrap() {
            // Create node_modules
            create_dir_all(&app.node_modules_dir).await.unwrap();
            // let node_modules_dep_path = app.node_modules_dir.join(&package.name);
            let node_modules_dep_path = app.node_modules_dir.clone();
            // Initialize tarfile decoder while directly passing in bytes
            let bytes = Arc::new(bytes);
            let bytes_ref = bytes.clone();
            futures::try_join!(
                tokio::task::spawn_blocking(move || {
                    let node_gz_decoder = GzDecoder::new(&**bytes_ref);
                    let mut node_archive = Archive::new(node_gz_decoder);
                    for entry in node_archive.entries().unwrap() {
                        let mut entry = entry.unwrap();
                        let path = entry.path().unwrap();
                        let mut new_path = PathBuf::new();
                        for component in path.components() {
                            if component.as_os_str() == "package" {
                                new_path.push(Component::Normal(OsStr::new(&package.name)));
                            } else {
                                new_path.push(component)
                            }
                        }
                        std::fs::create_dir_all(
                            node_modules_dep_path
                                .to_path_buf()
                                .join(&new_path)
                                .parent()
                                .unwrap(),
                        )
                        .unwrap();
                        match entry.unpack(node_modules_dep_path.to_path_buf().join(&new_path)) {
                            Ok(_v) => {}
                            Err(err) => {
                                println!("{:?}", err);
                            }
                        }
                    }
                }),
                tokio::task::spawn_blocking(move || {
                    let gz_decoder = GzDecoder::new(&**bytes);
                    let mut archive = Archive::new(gz_decoder);
                    let mut cas_file_map: HashMap<String, Integrity> = HashMap::new();
                    for entry in archive.entries().unwrap() {
                        let mut entry = entry.unwrap();
                        let mut buffer = vec![];
                        entry.read_to_end(&mut buffer).unwrap();
                        let sri =
                            cacache::write_hash_sync(extract_directory.clone(), &buffer).unwrap();
                        cas_file_map
                            .insert(entry.path().unwrap().to_str().unwrap().to_string(), sri);
                    }
                    cacache::write_sync(
                        extract_directory.clone(),
                        format!(
                            "pkg::{}::{}::{}",
                            &package_name, &package_version, package.integrity
                        ),
                        serde_json::to_string(&cas_file_map).unwrap(),
                    )
                    .unwrap();
                })
            )
            .unwrap();
        } else {
            return Err(VoltError::ChecksumVerificationError.into());
        }
    } else {
        // package is already downloaded and extracted to the ~/.volt folder.
        let buf = existing_check.unwrap();
        let cas_file_map: HashMap<String, Integrity> =
            serde_json::from_str(&String::from_utf8(buf).unwrap()).unwrap();
        for item in cas_file_map.iter() {
            let contents = cacache::read_hash_sync(&extract_directory, item.1).unwrap();
            let data = String::from_utf8(contents).unwrap();
            // generate node_modules path
            let path = app.node_modules_dir.join(format!(
                "{}/{}",
                package.name,
                item.0.strip_prefix("package/").unwrap()
            ));
            std::fs::create_dir_all(path.parent().unwrap()).unwrap();
            let mut file = File::create(path).unwrap();
            file.write_all(data.as_bytes()).unwrap();
        }
    }
    Ok(())
}
pub async fn download_tarball ( app : & App , package : VoltPackage , _state : State ) -> Result < ( ) > { let package_instance = package . clone ( ) ; let package_name = package . name . clone ( ) ; let package_version = package . version . clone ( ) ; // @types/eslint if package_name . starts_with ( '@' ) && package_name . contains ( '/' ) { let package_directory_location = app . volt_dir . join ( & package . name . split ( '/' ) . collect :: < Vec < & str > > ( ) [ 0 ] ) ; if ! Path :: new ( & package_directory_location ) . exists ( ) { create_dir_all ( & package_directory_location ) . await . map_err ( VoltError :: CreateDirError ) ? ; } } // Directory to extract tarball to let mut extract_directory = PathBuf :: from ( & app . volt_dir ) ; // @types/eslint if package . clone ( ) . name . starts_with ( '@' ) && package . clone ( ) . name . contains ( '/' ) { if cfg ! ( target_os " " ) { let name = package . clone ( ) . name . replace ( '/' , r"\" ) ; let split = name . split ( '\\' ) . collect :: < Vec < & str > > ( ) ; // C:\Users\xtrem\.volt\@types extract_directory = extract_directory . join ( split [ 0 ] ) ; } else { let name = package . clone ( ) . name ; let split = name . split ( '/' ) . collect :: < Vec < & str > > ( ) ; // ~/.volt/@types extract_directory = extract_directory . join ( split [ 0 ] ) ; } } let client = reqwest :: ClientBuilder :: new ( ) . use_rustls_tls ( ) . build ( ) . unwrap ( ) ; let existing_check = cacache :: read_sync ( & extract_directory , format ! ( " " package_name package_version package integrity ) , ) ; // if package is not already installed if existing_check . is_err ( ) { // Tarball bytes response let bytes : bytes :: Bytes = client . get ( package_instance . tarball ) . send ( ) . await . unwrap ( ) . bytes ( ) . await . unwrap ( ) ; let algorithm ; // there are only 2 supported algorithms // sha1 and sha512 // so we can be sure that if it doesn't start with sha1, it's going to have to be sha512 if package . integrity . starts_with ( " " ) { algorithm = Algorithm :: Sha1 ; } else { algorithm = Algorithm :: Sha512 ; } // Verify If Bytes == (Sha512 | Sha1) of Tarball if package . integrity == App :: calc_hash ( & bytes , algorithm ) . unwrap ( ) { // Create node_modules create_dir_all ( & app . node_modules_dir ) . await . unwrap ( ) ; // let node_modules_dep_path = app.node_modules_dir.join(&package.name); let node_modules_dep_path = app . node_modules_dir . clone ( ) ; // Initialize tarfile decoder while directly passing in bytes let bytes = Arc :: new ( bytes ) ; let bytes_ref = bytes . clone ( ) ; futures :: try_join ! ( tokio task spawn_blocking ( move { let node_gz_decoder GzDecoder new ( bytes_ref ) let mut node_archive Archive new ( node_gz_decoder ) for entry in node_archive entries ( ) unwrap ( ) { let mut entry entry unwrap ( ) let path entry path ( ) unwrap ( ) let mut new_path PathBuf new ( ) for component in path components ( ) { if component as_os_str ( ) " " { new_path push ( Component Normal ( OsStr new ( package name ) ) ) } else { new_path push ( component ) } } std fs create_dir_all ( node_modules_dep_path to_path_buf ( ) join ( new_path ) parent ( ) unwrap ( ) ) unwrap ( ) match entry unpack ( node_modules_dep_path to_path_buf ( ) join ( new_path ) ) { Ok ( _v ) { } Err ( err ) { println ( " " err ) } } } } ) tokio task spawn_blocking ( move { let gz_decoder GzDecoder new ( bytes ) let mut archive Archive new ( gz_decoder ) let mut cas_file_map HashMap String Integrity HashMap new ( ) for entry in archive entries ( ) unwrap ( ) { let mut entry entry unwrap ( ) let mut buffer vec [ ] entry read_to_end ( mut buffer ) unwrap ( ) let sri cacache write_hash_sync ( extract_directory clone ( ) buffer ) unwrap ( ) cas_file_map insert ( entry path ( ) unwrap ( ) to_str ( ) unwrap ( ) to_string ( ) sri ) } cacache write_sync ( extract_directory clone ( ) format ( " " package_name package_version package integrity ) serde_json to_string ( cas_file_map ) unwrap ( ) ) unwrap ( ) } ) ) . unwrap ( ) ; } else { return Err ( VoltError :: ChecksumVerificationError . into ( ) ) ; } } else { // package is already downloaded and extracted to the ~/.volt folder. let buf = existing_check . unwrap ( ) ; let cas_file_map : HashMap < String , Integrity > = serde_json :: from_str ( & String :: from_utf8 ( buf ) . unwrap ( ) ) . unwrap ( ) ; for item in cas_file_map . iter ( ) { let contents = cacache :: read_hash_sync ( & extract_directory , item . 1 ) . unwrap ( ) ; let data = String :: from_utf8 ( contents ) . unwrap ( ) ; // generate node_modules path let path = app . node_modules_dir . join ( format ! ( " " package name item 0 strip_prefix ( " " ) unwrap ( ) ) ) ; std :: fs :: create_dir_all ( path . parent ( ) . unwrap ( ) ) . unwrap ( ) ; let mut file = File :: create ( path ) . unwrap ( ) ; file . write_all ( data . as_bytes ( ) ) . unwrap ( ) ; } } Ok ( ( ) ) }
downloads and extracts tarball file from package
downloads and extracts tarball file from package
app
&App
package
VoltPackage
_state
State