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
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use url_source::UrlSource;

use crate::resolver::Install;
use crate::sources::file_source::FileSource;
use crate::sources::registry_source::RegistrySource;
use crate::{config::DependencyOptions, sources::git_source::GitSource};
use crate::{dependency::Dependency, sources::url_source};
use crate::{resolver::Resolver, sources::dir_source::DirSource};
use log::*;
use std::path::Path;

pub trait Source: SourceClone {
    fn install(&self, dependency: &Dependency, path: &Path) -> std::io::Result<()>;

    fn installed(&self, dependency: &Dependency, destination: &Path) -> bool {
        let destination = destination.join(dependency.clone().name);
        destination.exists()
    }

    fn update_resolver(
        &self,
        resolver: &mut Resolver,
        dependency: &Dependency,
        destination: &Path,
    ) {
        let project_dir = destination.parent().unwrap();
        let destination = destination.join(dependency.clone().name);
        let config_path = destination.join("Smaug.toml");
        let config = crate::config::load(&config_path).expect("Could not find Smaug.toml");
        debug!("Package config: {:?}", config);
        let package = config.package.expect("No package configuration found.");

        for (from, to) in package.installs {
            let install_source = from.to_path(destination.as_path());
            let install_destination = to.to_path(project_dir);

            let install = Install {
                from: install_source,
                to: install_destination,
            };

            resolver.installs.push(install);
        }

        let mut requires = package
            .requires
            .iter()
            .map(|require| {
                let package_file = require.to_path(destination.clone());
                trace!("Checking package file {:?}", package_file);

                if package_file.exists() {
                    trace!("package file exists");
                    format!("smaug/{}/{}", dependency.name, require)
                } else {
                    trace!("package file does not exists");
                    require.to_string()
                }
            })
            .collect();
        resolver.requires.append(&mut requires);
    }
}

pub trait SourceClone {
    fn clone_box(&self) -> Box<dyn Source>;
}

pub fn from_dependency_options(options: &DependencyOptions) -> Option<Box<dyn Source>> {
    match options {
        DependencyOptions::Git {
            repo,
            branch,
            rev,
            tag,
        } => Some(Box::new(GitSource {
            repo: repo.clone(),
            branch: branch.clone(),
            rev: rev.clone(),
            tag: tag.clone(),
        })),
        DependencyOptions::Dir { dir: path } => Some(Box::new(DirSource {
            path: path.to_path_buf(),
        })),
        DependencyOptions::File { file: path } => Some(Box::new(FileSource {
            path: path.to_path_buf(),
        })),
        DependencyOptions::Url { url } => Some(Box::new(UrlSource {
            url: url.to_string(),
        })),
        DependencyOptions::Registry { version } => Some(Box::new(RegistrySource {
            version: version.to_string(),
        })),
    }
}

impl<T> SourceClone for T
where
    T: 'static + Source + Clone,
{
    fn clone_box(&self) -> Box<dyn Source> {
        Box::new(self.clone())
    }
}

impl Clone for Box<dyn Source> {
    fn clone(&self) -> Box<dyn Source> {
        self.clone_box()
    }
}