~danyspin97/rinstall

26cfc10edba215a83c3fe0fb066f893da367b816 — Danilo Spinella 1 year, 1 month ago 2394e0a
Use "cargo metadata" to get target_directory in rust projects
6 files changed, 108 insertions(+), 40 deletions(-)

M Cargo.lock
M Cargo.toml
M src/install_target.rs
M src/main.rs
M src/package.rs
A src/project.rs
M Cargo.lock => Cargo.lock +7 -0
@@ 187,6 187,12 @@ dependencies = [
]

[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"

[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 301,6 307,7 @@ version = "0.1.0"
dependencies = [
 "clap",
 "color-eyre",
 "json",
 "libc",
 "serde",
 "serde_yaml",

M Cargo.toml => Cargo.toml +1 -0
@@ 6,6 6,7 @@ edition = "2018"
[dependencies]
clap = "3.0.0-beta.2"
color-eyre = "0.5"
json = "0.12"
libc = "0.2"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"

M src/install_target.rs => src/install_target.rs +2 -6
@@ 12,7 12,7 @@ impl InstallTarget {
    pub fn new(
        entry: InstallEntry,
        install_dir: &Path,
        parent_dir: Option<&Path>,
        parent_dir: &Path,
    ) -> Result<Self> {
        let destination = install_dir.join(if let Some(destination) = entry.destination {
            ensure!(


@@ 33,11 33,7 @@ impl InstallTarget {
            "the source file {:?} is not relative",
            entry.source
        );
        let source = if let Some(parent_dir) = parent_dir {
            parent_dir.join(entry.source)
        } else {
            entry.source
        };
        let source = parent_dir.join(entry.source);

        Ok(Self {
            source,

M src/main.rs => src/main.rs +21 -16
@@ 3,6 3,7 @@ mod dirs;
mod install_entry;
mod install_target;
mod package;
mod project;

use std::{env, fs, path::PathBuf};



@@ 15,6 16,7 @@ use config::Config;
use dirs::Dirs;
use install_target::InstallTarget;
use package::Package;
use project::Project;

fn main() -> Result<()> {
    color_eyre::install()?;


@@ 93,8 95,13 @@ fn main() -> Result<()> {
            .with_context(|| format!("unable to read file {:?}", install_spec))?,
    )?;

    let project_type = program.project_type.clone();

    program
        .targets(dirs)?
        .targets(
            dirs,
            Project::new_from_type(project_type, package_dir.clone())?,
        )?
        .iter()
        .try_for_each(|install| -> Result<()> {
            let InstallTarget {


@@ 111,11 118,9 @@ fn main() -> Result<()> {
                })
            });

            let source_path = package_dir.join(source);

            ensure!(source_path.exists(), "{:?} does not exists", source);
            ensure!(source.exists(), "{:?} does not exists", source);

            if source_path.is_file() {
            if source.is_file() {
                let destination = if destination.as_os_str().to_str().unwrap().ends_with('/') {
                    destination.join(
                        source


@@ 125,17 130,21 @@ fn main() -> Result<()> {
                } else {
                    destination.to_owned()
                };
                println!("Installing {:?} to {:?}", source, destination);
                println!(
                    "Installing {:?} to {:?}",
                    source.strip_prefix(&package_dir).unwrap_or(&source),
                    destination
                );
                if !dry_run {
                    fs::create_dir_all(&destination.parent().unwrap()).with_context(|| {
                        format!("unable to create directory {:?}", destination.parent())
                    })?;
                    fs::copy(source_path, &destination).with_context(|| {
                    fs::copy(source, &destination).with_context(|| {
                        format!("unable to copy file {:?} to {:?}", source, destination)
                    })?;
                }
            } else if source_path.is_dir() {
                WalkDir::new(&source_path)
            } else if source.is_dir() {
                WalkDir::new(&source)
                    .into_iter()
                    .try_for_each(|entry| -> Result<()> {
                        let entry = entry?;


@@ 144,13 153,9 @@ fn main() -> Result<()> {
                        }

                        let full_path = entry.path();
                        let relative_path =
                            full_path.strip_prefix(&source_path).with_context(|| {
                                format!(
                                    "unable to strip prefix {:?} from {:?}",
                                    source_path, full_path
                                )
                            })?;
                        let relative_path = full_path.strip_prefix(&source).with_context(|| {
                            format!("unable to strip prefix {:?} from {:?}", source, full_path)
                        })?;
                        let source = source.join(relative_path);
                        let destination = destination.join(relative_path);
                        println!("Installing {:?} to {:?}", source, destination);

M src/package.rs => src/package.rs +34 -18
@@ 5,9 5,10 @@ use std::path::{Path, PathBuf};

use crate::install_entry::InstallEntry;
use crate::install_target::InstallTarget;
use crate::project::Project;
use crate::Dirs;

#[derive(Deserialize)]
#[derive(Deserialize, Clone)]
pub enum Type {
    #[serde(rename(deserialize = "custom"))]
    Custom,


@@ 29,7 30,7 @@ enum Completion {
pub struct Package {
    name: String,
    #[serde(rename(deserialize = "type"))]
    program_type: Type,
    pub project_type: Type,
    #[serde(default)]
    exe: Vec<InstallEntry>,
    #[serde(default)]


@@ 54,14 55,10 @@ impl Package {
    pub fn targets(
        self,
        dirs: Dirs,
        project: Project,
    ) -> Result<Vec<InstallTarget>> {
        let mut results = Vec::new();

        let bin_local_root = match self.program_type {
            Type::Rust => Some(Path::new("target/release")),
            Type::Custom => None,
        };

        macro_rules! install_files {
            ( $files:tt, $install_dir:expr, $parent_dir:expr, $name:literal ) => {
                self.$files


@@ 74,20 71,35 @@ impl Package {
            };
        }

        results.extend(install_files!(exe, &dirs.bindir, bin_local_root, "exe"));
        results.extend(install_files!(libs, &dirs.libdir, None, "libs"));
        results.extend(install_files!(data, &dirs.datadir, None, "data"));
        results.extend(install_files!(config, &dirs.sysconfdir, None, "config"));
        results.extend(install_files!(exe, &dirs.bindir, &project.outputdir, "exe"));
        results.extend(install_files!(
            libs,
            &dirs.libdir,
            &project.projectdir,
            "libs"
        ));
        results.extend(install_files!(
            data,
            &dirs.datadir,
            &project.projectdir,
            "data"
        ));
        results.extend(install_files!(
            config,
            &dirs.sysconfdir,
            &project.projectdir,
            "config"
        ));
        if let Some(mandir) = &dirs.mandir {
            results.extend(install_files!(man, mandir, None, "man"));
            results.extend(install_files!(man, mandir, &project.projectdir, "man"));
        }

        let package_dir = self.name.to_owned();
        let package_doc_dir = self.name.to_owned();
        if let Some(docdir) = &dirs.docdir {
            results.extend(install_files!(
                docs,
                &docdir.join(Path::new(&package_dir)),
                None,
                &docdir.join(Path::new(&package_doc_dir)),
                &project.projectdir,
                "docs"
            ));
        }


@@ 95,14 107,14 @@ impl Package {
        results.extend(install_files!(
            desktop_files,
            &dirs.datarootdir.join("applications"),
            None,
            &project.projectdir,
            "desktop"
        ));

        results.extend(install_files!(
            appdata,
            &dirs.datarootdir.join("appdata"),
            None,
            &project.projectdir,
            "appdata"
        ));



@@ 133,7 145,11 @@ impl Package {
                            "zsh/site-functions",
                        ),
                    };
                    InstallTarget::new(entry, &dirs.datarootdir.join(parent_dir), None)
                    InstallTarget::new(
                        entry,
                        &dirs.datarootdir.join(parent_dir),
                        &project.projectdir,
                    )
                })
                .collect::<Result<Vec<InstallTarget>>>()
                .context("error while iterating completion files")?,

A src/project.rs => src/project.rs +43 -0
@@ 0,0 1,43 @@
use std::{path::PathBuf, process::Command};

use color_eyre::eyre::{Context, Result};

// Contains data about the project that will be installed
// It doesn't refer to the system and the actual installation directories
// It is only relevant for the source part in InstallEntry
pub struct Project {
    pub outputdir: PathBuf,
    pub projectdir: PathBuf,
}

use crate::package::Type;

impl Project {
    pub fn new_from_type(
        project_type: Type,
        projectdir: PathBuf,
    ) -> Result<Self> {
        Ok(match project_type {
            Type::Rust => Self {
                outputdir: PathBuf::from(
                    json::parse(&String::from_utf8_lossy(
                        &Command::new("cargo")
                            .arg("metadata")
                            .output()
                            .context("unable to run `cargo metadata`")?
                            .stdout,
                    ))
                    .context("unable to parse JSON from `cargo metadata` output")?
                        ["target_directory"]
                        .to_string(),
                )
                .join("release"),
                projectdir,
            },
            Type::Custom => Self {
                outputdir: projectdir.clone(),
                projectdir,
            },
        })
    }
}