This commit is contained in:
Tommy Parnell
2021-05-10 09:14:30 -04:00
commit 9973df7b42
12 changed files with 1215 additions and 0 deletions

262
native/Cargo.lock generated Normal file
View File

@@ -0,0 +1,262 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "cc"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cslice"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "697c714f50560202b1f4e2e09cd50a421881c83e9025db75d15f276616f04f40"
[[package]]
name = "incre"
version = "0.1.0"
dependencies = [
"metrohash",
"neon",
"neon-build",
"serde",
"serde_json",
"walkdir",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "memchr"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "metrohash"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ba553cb19e2acbc54baa16faef215126243fe45e53357a3b2e9f4ebc7b0506c"
[[package]]
name = "neon"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7567f84d17e451c0f6c4e6799a4702294b97debd2db007ab1453f85714bfcb80"
dependencies = [
"cslice",
"neon-build",
"neon-runtime",
"semver",
"smallvec",
]
[[package]]
name = "neon-build"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd3ca70b6bc64f337131b1ec6181adadcf6f0df30ec99ee6cd25652bcb6c831"
dependencies = [
"neon-sys",
]
[[package]]
name = "neon-runtime"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a1a13a60640ef807aac092a2a4ae08bc9bc701b516bd39cc54cfe441935b3d3"
dependencies = [
"cfg-if",
"neon-sys",
"smallvec",
]
[[package]]
name = "neon-sys"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94fca3a6fcf36b82a80f9897afb211264aa1e924b9b157c75e073a0f919c43e0"
dependencies = [
"cc",
"regex",
]
[[package]]
name = "proc-macro2"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "syn"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

22
native/Cargo.toml Normal file
View File

@@ -0,0 +1,22 @@
[package]
name = "incre"
version = "0.1.0"
authors = ["tparnell <tommy@terribledev.io>"]
license = "MIT"
build = "build.rs"
edition = "2018"
exclude = ["artifacts.json", "index.node"]
[lib]
name = "incre"
crate-type = ["cdylib"]
[build-dependencies]
neon-build = "0.8.1"
[dependencies]
neon = "0.8.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
walkdir = "2"
metrohash = "1.0"

7
native/build.rs Normal file
View File

@@ -0,0 +1,7 @@
extern crate neon_build;
fn main() {
neon_build::setup(); // must be called in build.rs
// add project-specific build logic here...
}

110
native/src/cache.rs Normal file
View File

@@ -0,0 +1,110 @@
use std::path::Path;
use std::collections::HashSet;
use std::time::SystemTime;
use std::io;
use std::fs;
use serde::{Serialize, Deserialize};
use std::hash::{Hash, Hasher};
use metrohash::{MetroHash};
#[derive(Serialize, Deserialize)]
pub struct CachedEntry {
pub files: HashSet<CachedFile>,
}
impl CachedEntry {
pub fn new(files: HashSet<CachedFile>) -> CachedEntry {
CachedEntry {
files,
}
}
// todo Error handle better
pub fn from_file(path: &str) -> io::Result<CachedEntry> {
println!("Attempting to read {}", path);
// Path::new(path).exists()
fs::metadata(path)?;
let file = fs::read_to_string(path)?;
Ok(serde_json::from_str(&file)?)
}
pub fn was_changed(&self) -> io::Result<bool> {
let mut changed = false;
for cached_file in self.files.iter() {
if cached_file.was_changed()? {
changed = true;
break;
}
}
Ok(changed)
}
pub fn is_empty(&self) -> bool {
self.files.is_empty()
}
pub fn write(&self, name: &str, cache_dir: &str) -> io::Result<()> {
let cached_entry_filename = format!("{}", name);
let cached_directory_path = Path::new(cache_dir);
if !cached_directory_path.exists() {
fs::create_dir(cached_directory_path)?
}
let cached_entry_path = cached_directory_path.join(cached_entry_filename);
let f = std::io::BufWriter::new(fs::File::create(&cached_entry_path)?);
serde_json::to_writer(f, self)?;
Ok(())
}
}
#[derive(Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct CachedFile {
path: String,
size: u64,
modified: SystemTime,
hash: u64,
}
impl CachedFile {
pub fn from_filename(filename: &str) -> io::Result<CachedFile> {
let file_metadata = fs::metadata(filename)?;
let size = file_metadata.len();
let modified = file_metadata.modified()?;
// TODO: find async way to read file.
let hash = calculate_hash(&fs::read(filename)?);
Ok(CachedFile {
path: filename.to_string(),
size,
modified,
hash,
})
}
pub fn was_changed(&self) -> io::Result<bool> {
let mut changed = false;
// println!("Checking if {} has changed", &self.path);
match fs::metadata(&self.path) {
Ok(file_metadata) => {
let size = file_metadata.len();
let modified = file_metadata.modified()?;
if self.size != size || self.modified != modified {
let hash = calculate_hash(&fs::read(&self.path)?);
if self.hash != hash {
changed = true;
}
}
}
// means previously cached file cannot be read
// most likely due to the entrypoint of an npm module
// being changed.
Err(_) => {
changed = true;
}
}
Ok(changed)
}
}
fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = MetroHash::new();
t.hash(&mut s);
s.finish()
}

89
native/src/lib.rs Normal file
View File

@@ -0,0 +1,89 @@
use std::iter::FromIterator;
use walkdir::DirEntry;
use std::path::Path;
use std::collections::HashSet;
use std::str::FromStr;
use neon::prelude::*;
use std::fs;
use std::process;
use std::path;
use serde::{Serialize, Deserialize};
use serde_json::Result;
use walkdir::WalkDir;
const INCRE_CONFIG_PATH: &str = "incre.config.json";
const CACHE_PATH: &str = "incre";
const CACHE_FILE: &str = "cache.json";
mod cache;
#[derive(Serialize, Deserialize)]
struct Config {
include: Vec<String>,
// exclude: Vec<String>
}
impl Config {
fn get_config() -> Option<Config> {
let exists = fs::metadata(INCRE_CONFIG_PATH).is_ok();
if !exists {
return None;
}
let file = fs::read_to_string(INCRE_CONFIG_PATH).unwrap();
Some(serde_json::from_str(&file).unwrap())
}
}
fn init(mut cx: FunctionContext) -> JsResult<JsUndefined> {
println!("Loading Config");
let configOptional = Config::get_config();
if configOptional.is_none() {
eprintln!("Unable to find config {}", INCRE_CONFIG_PATH);
std::process::exit(2)
}
let config = configOptional.unwrap();
println!("Config Loaded");
let cache: cache::CachedEntry = {
cache::CachedEntry::from_file(Path::new(CACHE_PATH).join(CACHE_FILE).to_str().unwrap()).unwrap_or(cache::CachedEntry::new(HashSet::new()))
};
let mut changed = false;
if !cache.is_empty() {
println!("Cache is not empty");
match cache.was_changed() {
Ok(result) => {
changed = result;
}
Err(_) => {}
}
} else {
println!("Cache is empty");
changed = true;
}
if changed {
println!("Changes Detected");
let files = config
.include
.into_iter()
.flat_map(|d| walk(&d))
.map(|f| cache::CachedFile::from_filename(&f))
.filter(|f| f.is_ok())
.map(|f| f.unwrap());
let newCache = cache::CachedEntry::new(HashSet::from_iter(files));
newCache.write(CACHE_FILE, CACHE_PATH).unwrap();
}
Ok(cx.undefined())
}
fn walk (dir: &str) -> Vec<String> {
WalkDir::new(dir)
.into_iter()
.filter_map(|e| e.ok())
.map(|f| String::from(f.path().to_str().unwrap_or("")))
.filter(|p| !p.is_empty() )
.collect()
}
register_module!(mut cx, {
cx.export_function("init", init)
});