Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  main.rs

  Sprache: Rust
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

mod cli;
mod downloader;
mod runner;
mod test;
mod updater;

use std::collections::HashMap;
use std::fs::{create_dir, exists};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::thread;
use tempfile::TempDir;

use anyhow::{anyhow, Result};
use env_logger::{Builder, Env};
use log::info;

use crate::cli::Args;
use crate::downloader::{FileDownloader, UreqDownloader};
use crate::runner::RealRunner;
use crate::test::{run_tests, Test, TestResult};

/// Returns what we consider to be the file extension. In most cases this is
/// simply everything after the last `.`.
fn get_extension(filename: &str) -> Option<&str> {
    if filename.ends_with(".tar.xz") {
        return Some("tar.xz");
    }
    return Path::new(filename).extension()?.to_str();
}

fn main() -> Result<()> {
    Builder::from_env(Env::default().default_filter_or("info")).init();
    let args = Args::parse_and_validate();
    // Using `keep()` prevents the temporary directory from being cleaned up.
    // This is on purpose. When running in CI any necessary cleanup is handled
    // by CI (eg: making sure artifacts from an earlier task are removed before
    // a new task begins). When running locally it's preferable to keep artifacts
    // around for debugging.
    let tmpdir = TempDir::with_prefix("update-verify")?.keep();
    let tmppath = tmpdir
        .to_str()
        .ok_or_else(|| anyhow!("Couldn't parse tmpdir"))?;
    info!("Using tmpdir: {tmppath}");

    let mut cache_dir = tmpdir.clone();
    cache_dir.push("download_cache");
    create_dir(&cache_dir)?;

    let downloader = UreqDownloader;
    let runner = RealRunner;
    let parallelism = match args.parallelism {
        Some(j) => j,
        None => thread::available_parallelism()
            .map(|n| n.get())
            .unwrap_or(1),
    };
    info!("parallelism set to: {parallelism}");

    let mut tests = Vec::new();
    let mut download_dir = tmpdir.clone();
    download_dir.push("from_builds");
    create_dir(download_dir.as_path())?;

    if !exists(&args.artifact_dir)? {
        create_dir(&args.artifact_dir)?;
    }

    // Associate URLs of files we'll be downloading with an on-disk location.
    // Doing this before doing any downloads ensures that there will be no
    // conflicts in on-disk locations, and thus no need to do any locking
    // to download them in parallel.
    let mut package_dest_paths: HashMap<String, PathBuf> = HashMap::new();
    for (i, entry) in args.from.iter().enumerate() {
        let mut installer_dest_path = download_dir.clone();
        let ext = get_extension(&entry.installer)
            .ok_or_else(|| anyhow!("Couldn't find from installer extension!"))?;
        installer_dest_path.push(format!("{i}.{ext}"));
        package_dest_paths
            .entry(entry.installer.clone())
            .or_insert(installer_dest_path);
        let mut updater_dest_path = download_dir.clone();
        updater_dest_path.push(format!("{i}.updater.tar.xz"));
        // In some cases, the updater package will be the same as the installer,
        // in which case this is a no-op.
        package_dest_paths
            .entry(entry.updater_package.clone())
            .or_insert(updater_dest_path);
    }

    // Download the packages.
    // In order to chunk, we need a Vec version of `package_dest_paths`.
    let entries: Vec<_> = package_dest_paths.iter().collect();
    let chunk_size = package_dest_paths.len().div_ceil(parallelism).max(1);
    thread::scope(|s| -> Result<()> {
        let handles: Vec<_> = entries
            .chunks(chunk_size)
            .map(|chunk| {
                // Create local references that can be moved into the thread.
                let cache_dir_ref = &cache_dir;
                let downloader_ref = &downloader;

                return s.spawn(move || {
                    return chunk
                        .iter()
                        .map(|(from_package, dest_path)| {
                            return downloader_ref.fetch(from_package, dest_path, cache_dir_ref);
                        })
                        .collect::<Vec<_>>();
                });
            })
            .collect();

        // Join the threads, check for errors
        for h in handles {
            h.join()
                // Handle errors that come up when joining the thread
                .map_err(|_| anyhow::anyhow!("download thread panicked"))?;
        }

        return Ok(());
    })?;

    // Iterate over `from` builds given, download them, and create Test objects for each.
    // All `from` builds given will be tested against the complete MAR. Entries that also
    // contained a partial MAR will be additionally tested against that.
    for entry in args.from {
        tests.push(Test {
            id: entry.id.clone(),
            mar: args.complete_mar.to_path_buf(),
            from_installer: package_dest_paths[&entry.installer].clone(),
            locale: args.locale.clone(),
            updater_package: package_dest_paths[&entry.updater_package].clone(),
        });
        if let Some(partial_mar) = &entry.partial_mar {
            let mut partial_path = args.partial_mar_dir.to_path_buf();
            partial_path.push(partial_mar);
            tests.push(Test {
                id: entry.id.clone(),
                mar: partial_path,
                from_installer: package_dest_paths[&entry.installer].clone(),
                locale: args.locale.clone(),
                updater_package: package_dest_paths[&entry.updater_package].clone(),
            });
        }
    }
    let results = run_tests(
        &args.check_updates_script,
        &args.target_platform,
        &args.to_installer,
        &args.channel,
        &args.appname,
        args.cert_dir.as_deref(),
        &args.cert_override,
        tests,
        &tmpdir,
        &args.artifact_dir,
        &runner,
        parallelism,
    )?;
    let passes = results.iter().filter(|r| **r == TestResult::Pass).count();
    let fails = results.len() - passes;
    info!("Summary of results: {} PASS, {} FAIL", passes, fails);
    if fails > 0 {
        exit(1);
    }

    return Ok(());
}

#[cfg(test)]
mod tests {
    use super::get_extension;

    #[test]
    fn tar_xz() {
        assert_eq!(get_extension("foo.tar.xz"), Some("tar.xz"));
    }

    #[test]
    fn exe() {
        assert_eq!(get_extension("foo.exe"), Some("exe"));
    }

    #[test]
    fn no_ext() {
        assert_eq!(get_extension("foo"), None);
    }
}

Messung V0.5 in Prozent
C=81 H=100 G=90

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002