install-framework-core 1.0.0

[Install Framework] Core framework and basic interfaces
Documentation
// Copyright 2021 Yuri6037

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

use std::collections::HashMap;

use crate::interface::Installer;
use crate::interface::PostInstall;
use crate::interface::PostUninstall;
use crate::interface::Interface;
use crate::interface::InstallMethod;
use crate::common::get_install_dir;

pub struct InstallerBuilder<'a>
{
    name: &'static str,
    version: &'static str,
    author: &'static str,
    install: &'a mut dyn Installer,
    user_install: bool,
    sys_install: bool,
    post_install: Option<&'a mut dyn PostInstall>,
    post_uninstall: Option<&'a mut dyn PostUninstall>,
    resources: HashMap<&'static str, &'static [u8]>
}

impl <'a> InstallerBuilder<'a>
{
    pub fn new(install: &'a mut dyn Installer) -> InstallerBuilder
    {
        return InstallerBuilder
        {
            name: "Generic",
            version: "1.0",
            author: "Unknown",
            install: install,
            user_install: false,
            sys_install: false, //By default let the installer decide if it prefers system wide install or user install
            post_install: None,
            post_uninstall: None,
            resources: HashMap::new()
        };
    }

    /// Sets the global installer name
    /// 
    /// # Arguments
    /// 
    /// * `version` - The version of this installer as a static string
    pub fn set_name(mut self, name: &'static str) -> Self
    {
        self.name = name;
        return self;
    }

    /// Sets the global installer version
    /// 
    /// # Arguments
    /// 
    /// * `version` - The version of this installer as a static string
    pub fn set_version(mut self, version: &'static str) -> Self
    {
        self.version = version;
        return self;
    }

    /// Sets the global installer author
    /// 
    /// # Arguments
    /// 
    /// * `author` - The author of this installer as a static string
    pub fn set_author(mut self, author: &'static str) -> Self
    {
        self.author = author;
        return self;
    }

    /// Add a resource
    /// 
    /// # Arguments
    /// 
    /// * `path` - path to use for referencing in the install script
    /// * `bytes` - resource binary data (use include_bytes!)
    pub fn add_resource(mut self, path: &'static str, bytes: &'static [u8]) -> Self
    {
        self.resources.insert(path, bytes);
        return self;
    }

    /// Add a PostInstall step to this installer
    /// 
    /// # Arguments
    /// 
    /// * `obj` - reference to the PostInstall trait
    pub fn add_post_install_step(mut self, obj: &'a mut dyn PostInstall) -> Self
    {
        self.post_install = Some(obj);
        return self;
    }

    /// Add a PostUninstall step to this installer
    /// 
    /// # Arguments
    /// 
    /// * `obj` - reference to the PostUninstall trait
    pub fn add_post_uninstall_step(mut self, obj: &'a mut dyn PostUninstall) -> Self
    {
        self.post_uninstall = Some(obj);
        return self;
    }

    /// Allows user installs
    pub fn allow_user_install(mut self) -> Self
    {
        self.user_install = true;
        return self;
    }

    /// Allows system wide installs
    pub fn allow_system_install(mut self) -> Self
    {
        self.sys_install = true;
        return self;
    }

    fn run_internal<TInterface: Interface>(&mut self, interface: &mut TInterface) -> Result<(), TInterface::ErrorType>
    {
        interface.welcome(self.name, self.version, self.author)?;
        let mut method = InstallMethod::SystemInstall;
        if self.user_install && !self.sys_install
        {
            method = InstallMethod::UserInstall;
        }
        else if self.user_install && self.sys_install
        {
            method = interface.get_install_method()?;
        }
        let uninstall = interface.should_uninstall()?;
        let dir = get_install_dir(&method);
        if uninstall
        {
            interface.run_uninstall(self.install, &dir, method, &self.resources)?;
            if let Some(obj) = &mut self.post_uninstall
            {
                interface.run_post_uninstall(*obj, &dir)?;
            }
        }
        else
        {
            interface.run_install(self.install, &dir, method, &self.resources)?;
            if let Some(obj) = &mut self.post_install
            {
                interface.run_post_install(*obj, &dir)?;
            }
        }
        return Ok(());
    }

    pub fn run<TInterface: Interface>(&mut self, interface: &mut TInterface) -> i32
    {
        match self.run_internal(interface)
        {
            Ok(()) => interface.finish(),
            Err(e) => interface.error(e)
        }
    }
}