init
This commit is contained in:
262
native/Cargo.lock
generated
Normal file
262
native/Cargo.lock
generated
Normal 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
22
native/Cargo.toml
Normal 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
7
native/build.rs
Normal 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
110
native/src/cache.rs
Normal 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
89
native/src/lib.rs
Normal 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)
|
||||
});
|
||||
Reference in New Issue
Block a user