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
use std::env;
use std::path::{Path, PathBuf};
use std::fs::{create_dir_all, metadata, File};
use std::io::{BufWriter, Write};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

use project::{Crate, Project};
use error::*;

pub struct ProxyCrate<'a> {
    project: &'a Project,
    path: PathBuf,
}

const DEFAULT_MANIFEST_PREFIX: &str = r#"
[package]
name = "proxy"
version = "0.0.0"

[lib]
crate_type = ["dylib"]

[dependencies]
"#;

const DEFAULT_LIB_PREFIX: &str = r#"
#![feature(lang_items)]
#![no_std]

"#;

const DEFAULT_LIB_SUFFIX: &str = r#"

// Needed because we compile `dylib`...
#[lang = "panic_fmt"]
fn panic_fmt() -> ! {
    loop {}
}
"#;

impl<'a> ProxyCrate<'a> {
    pub fn new(project: &'a Project) -> Result<Self> {
        let mut path = env::temp_dir().join("ptx-builder");

        path.push(&project.get_rustc_name());
        path.push(format!("{:x}", Self::get_project_hash(project)));

        create_dir_all(&path)?;
        create_dir_all(&path.join("src"))?;

        Ok(ProxyCrate { project, path })
    }

    pub fn get_output_path(&self) -> PathBuf {
        self.path.join("target")
    }

    pub fn initialize(&mut self) -> Result<()> {
        if let Err(_) = metadata(self.path.join("Cargo.toml")) {
            let mut writer = BufWriter::new(File::create(self.path.join("Cargo.toml"))?);

            writer.write_all(DEFAULT_MANIFEST_PREFIX.as_bytes())?;
            writer.write_all(
                format!(
                    r#"{} = {{ path = {:?} }} "#,
                    self.project.get_name(),
                    self.project.get_path()
                ).as_bytes(),
            )?;
        }

        if let Err(_) = metadata(self.path.join("src/lib.rs")) {
            let mut writer = BufWriter::new(File::create(self.path.join("src/lib.rs"))?);

            writer.write_all(DEFAULT_LIB_PREFIX.as_bytes())?;
            writer.write_all(
                format!("extern crate {name};", name = self.project.get_rustc_name()).as_bytes(),
            )?;
            writer.write_all(DEFAULT_LIB_SUFFIX.as_bytes())?;
        }

        Ok(())
    }

    fn get_project_hash(project: &Project) -> u64 {
        let mut hasher = DefaultHasher::new();
        project.hash(&mut hasher);

        hasher.finish()
    }
}

impl<'a> Crate for ProxyCrate<'a> {
    fn get_path(&self) -> &Path {
        &self.path.as_path()
    }

    fn get_name(&self) -> &str {
        "proxy"
    }

    fn get_rustc_name(&self) -> &str {
        "proxy"
    }
}