-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sqlite): start importing the gcroots data
This is super crappy at the moment, but we want to ideally save most of the data in the database instead of indirectly in the filesystem. This gives us better leverage for storing other fun things, like which files we last watched for a project, or how long changes to the files took.
- Loading branch information
1 parent
dd33b50
commit 8d04978
Showing
3 changed files
with
87 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,87 @@ | ||
use std::{ | ||
ffi::OsString, | ||
os::unix::ffi::{OsStrExt, OsStringExt}, | ||
path::PathBuf, | ||
time::{Duration, SystemTime}, | ||
}; | ||
|
||
use rusqlite as sqlite; | ||
use sqlite::Connection; | ||
use slog::info; | ||
use sqlite::{named_params, Connection}; | ||
|
||
use crate::ops::{self, error::ExitError}; | ||
|
||
#[test] | ||
fn migrate_db() { | ||
pub fn migrate_db(logger: &slog::Logger) -> Result<(), ExitError> { | ||
let conn = sqlite::Connection::open_in_memory().expect("cannot open sqlite db"); | ||
conn.execute_batch( | ||
r#"CREATE TABLE foo(id INTEGER PRIMARY KEY, bla TEXT); | ||
INSERT INTO foo (id, bla) VALUES (1, 'blabla'); | ||
INSERT INTO foo (id, bla) VALUES (2, 'bubatz'); | ||
"#, | ||
r#"CREATE TABLE gc_roots( | ||
id INTEGER PRIMARY KEY, | ||
nix_file PATH, | ||
last_updated EPOCH_TIME | ||
); | ||
"#, | ||
) | ||
.unwrap(); | ||
let mut stmt = conn.prepare("SELECT * from foo;").unwrap(); | ||
let res = stmt | ||
.query_map((), |row| row.get::<_, String>("bla")) | ||
|
||
let infos = ops::list_roots(logger)?; | ||
|
||
let mut stmt = conn | ||
.prepare("INSERT INTO gc_roots (nix_file, last_updated) VALUES (:nix_file, :last_updated);") | ||
.unwrap(); | ||
for info in infos { | ||
let ts = info | ||
.timestamp | ||
.duration_since(SystemTime::UNIX_EPOCH) | ||
.expect("expect file timestamp to be a unix timestamp") | ||
.as_secs(); | ||
stmt.execute(named_params! { | ||
":nix_file": info.nix_file.map(|pb| pb.as_os_str().as_bytes().to_owned()), | ||
":last_updated": ts | ||
}) | ||
.expect("cannot insert"); | ||
} | ||
|
||
let mut stmt = conn | ||
.prepare("SELECT nix_file, last_updated from gc_roots") | ||
.unwrap(); | ||
let mut res = stmt | ||
.query_map((), |row| { | ||
let nix_file = row | ||
.get::<_, Option<Vec<u8>>>("nix_file") | ||
.unwrap() | ||
.map(|v: Vec<u8>| OsString::from_vec(v)); | ||
let t = row.get::<_, Option<u64>>("last_updated").unwrap().map(|u| { | ||
SystemTime::elapsed(&(SystemTime::UNIX_EPOCH + Duration::from_secs(u))).unwrap() | ||
}); | ||
Ok((nix_file, t, t.map(ago))) | ||
}) | ||
.unwrap() | ||
.map(|x| x.unwrap()) | ||
.collect::<Vec<String>>(); | ||
.filter_map(|r| match r { | ||
Err(_) => None, | ||
Ok(r) => r.0.map(|nix| (nix, r.1, r.2)), | ||
}) | ||
.collect::<Vec<_>>(); | ||
res.sort_by_key(|r| r.1); | ||
info!(logger, "We have these nix files: {:#?}", res); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn ago(dur: Duration) -> String { | ||
let secs = dur.as_secs(); | ||
let mins = dur.as_secs() / 60; | ||
let hours = dur.as_secs() / (60 * 60); | ||
let days = dur.as_secs() / (60 * 60 * 24); | ||
|
||
if days > 0 { | ||
return format!("{} days ago", days); | ||
} | ||
if hours > 0 { | ||
return format!("{} hours ago", hours); | ||
} | ||
if mins > 0 { | ||
return format!("{} minutes ago", mins); | ||
} | ||
|
||
assert_eq!(res, vec!["blabla", "bubatz"]); | ||
format!("{} seconds ago", secs) | ||
} |