mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-09-11 12:25:42 +03:00
extract create current session to store
This commit is contained in:
parent
9dfe98cef2
commit
06371e4c36
@ -1,12 +1,11 @@
|
||||
use crate::{deltas, projects, sessions};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use std::{collections::HashMap, path::Path};
|
||||
use std::{collections::HashMap, path::Path, time};
|
||||
|
||||
use super::{current, persistent};
|
||||
|
||||
pub struct Store {
|
||||
project: projects::Project,
|
||||
git_repository: git2::Repository,
|
||||
|
||||
persistent: persistent::Store,
|
||||
current: current::Store,
|
||||
@ -18,7 +17,6 @@ impl Clone for Store {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
project: self.project.clone(),
|
||||
git_repository: git2::Repository::open(&self.project.path).unwrap(),
|
||||
current: self.current.clone(),
|
||||
persistent: self.persistent.clone(),
|
||||
sessions_store: self.sessions_store.clone(),
|
||||
@ -27,14 +25,9 @@ impl Clone for Store {
|
||||
}
|
||||
|
||||
impl Store {
|
||||
pub fn new(
|
||||
git_repository: git2::Repository,
|
||||
project: projects::Project,
|
||||
sessions_store: sessions::Store,
|
||||
) -> Result<Self> {
|
||||
pub fn new(project: projects::Project, sessions_store: sessions::Store) -> Result<Self> {
|
||||
Ok(Self {
|
||||
project: project.clone(),
|
||||
git_repository,
|
||||
current: current::Store::new(project.clone()),
|
||||
persistent: persistent::Store::new(project)?,
|
||||
sessions_store,
|
||||
@ -52,13 +45,23 @@ impl Store {
|
||||
) -> Result<sessions::Session> {
|
||||
// make sure we always have a session before writing deltas
|
||||
let session = match self.sessions_store.get_current()? {
|
||||
Some(mut session) => {
|
||||
session
|
||||
.touch(&self.project)
|
||||
.with_context(|| format!("failed to touch session {}", session.id))?;
|
||||
Ok(session)
|
||||
Some(session) => {
|
||||
let updated_session = sessions::Session {
|
||||
meta: sessions::Meta {
|
||||
last_timestamp_ms: time::SystemTime::now()
|
||||
.duration_since(time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis(),
|
||||
..session.meta
|
||||
},
|
||||
..session
|
||||
};
|
||||
self.sessions_store
|
||||
.update(&updated_session)
|
||||
.with_context(|| format!("failed to touch session {}", updated_session.id))?;
|
||||
Ok(updated_session)
|
||||
}
|
||||
None => sessions::Session::from_head(&self.git_repository, &self.project),
|
||||
None => self.sessions_store.create_current(),
|
||||
}?;
|
||||
|
||||
self.current.write(file_path, deltas)?;
|
||||
|
@ -26,7 +26,7 @@ fn test_project() -> Result<(git2::Repository, projects::Project)> {
|
||||
fn test_read_none() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let sessions_store = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let store = super::Store::new(repo, project, sessions_store).unwrap();
|
||||
let store = super::Store::new(project, sessions_store).unwrap();
|
||||
let file_path = Path::new("test.txt");
|
||||
let deltas = store.read(file_path);
|
||||
assert!(deltas.is_ok());
|
||||
@ -37,7 +37,7 @@ fn test_read_none() {
|
||||
fn test_read_invalid() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let sessions_store = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let store = super::Store::new(repo, project.clone(), sessions_store).unwrap();
|
||||
let store = super::Store::new(project.clone(), sessions_store).unwrap();
|
||||
let file_path = Path::new("test.txt");
|
||||
let full_file_path = project.deltas_path().join(file_path);
|
||||
|
||||
@ -52,7 +52,7 @@ fn test_read_invalid() {
|
||||
fn test_write_read() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let sessions_store = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let store = super::Store::new(repo, project, sessions_store).unwrap();
|
||||
let store = super::Store::new(project, sessions_store).unwrap();
|
||||
let file_path = Path::new("test.txt");
|
||||
|
||||
let deltas = vec![Delta {
|
||||
@ -71,7 +71,7 @@ fn test_write_read() {
|
||||
fn test_write_must_create_session() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let sessions_store = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let store = super::Store::new(clone_repo(&repo), project.clone(), sessions_store.clone()).unwrap();
|
||||
let store = super::Store::new(project.clone(), sessions_store.clone()).unwrap();
|
||||
let file_path = Path::new("test.txt");
|
||||
|
||||
let deltas = vec![Delta {
|
||||
@ -96,10 +96,10 @@ fn clone_repo(repo: &git2::Repository) -> git2::Repository {
|
||||
fn test_write_must_not_override_session() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let sessions_store = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let store = super::Store::new(clone_repo(&repo), project.clone(), sessions_store.clone()).unwrap();
|
||||
let store = super::Store::new(project.clone(), sessions_store.clone()).unwrap();
|
||||
let file_path = Path::new("test.txt");
|
||||
|
||||
let session_before_write = sessions::Session::from_head(&repo, &project);
|
||||
let session_before_write = sessions_store.create_current();
|
||||
assert!(session_before_write.is_ok());
|
||||
let session_before_write = session_before_write.unwrap();
|
||||
|
||||
|
@ -549,9 +549,12 @@ fn main() {
|
||||
|
||||
let app_handle = app.handle();
|
||||
tauri::async_runtime::spawn_blocking(move || {
|
||||
let start = std::time::Instant::now();
|
||||
log::info!("initializing app");
|
||||
if let Err(e) = init(app_handle) {
|
||||
log::error!("failed to app: {:#}", e);
|
||||
}
|
||||
log::info!("app initialized in {:?}", start.elapsed());
|
||||
});
|
||||
|
||||
Ok(())
|
||||
@ -666,12 +669,16 @@ fn init(app_handle: tauri::AppHandle) -> Result<()> {
|
||||
.watchers
|
||||
.lock()
|
||||
.unwrap()
|
||||
.watch(tx.clone(), &project, &repo.deltas_storage, &repo.sessions_storage)
|
||||
.watch(
|
||||
tx.clone(),
|
||||
&project,
|
||||
&repo.deltas_storage,
|
||||
&repo.sessions_storage,
|
||||
)
|
||||
.with_context(|| format!("{}: failed to watch project", project.id))?;
|
||||
|
||||
let git_repository = repo.git_repository;
|
||||
if let Err(err) = app_state.deltas_searcher.lock().unwrap().reindex_project(
|
||||
&git_repository,
|
||||
&repo.git_repository,
|
||||
&repo.project,
|
||||
&repo.deltas_storage,
|
||||
&repo.sessions_storage,
|
||||
|
@ -33,11 +33,7 @@ impl Repository {
|
||||
Ok(Repository {
|
||||
project: project.clone(),
|
||||
git_repository,
|
||||
deltas_storage: deltas::Store::new(
|
||||
git2::Repository::open(&project.path)?,
|
||||
project,
|
||||
sessions_storage.clone(),
|
||||
)?,
|
||||
deltas_storage: deltas::Store::new(project, sessions_storage.clone())?,
|
||||
sessions_storage,
|
||||
})
|
||||
}
|
||||
@ -355,7 +351,7 @@ impl Repository {
|
||||
// if the reference doesn't exist, we create it by creating a flushing a new session
|
||||
let mut current_session = match self.sessions_storage.get_current()? {
|
||||
Some(session) => session,
|
||||
None => sessions::Session::from_head(&self.git_repository, &self.project)?,
|
||||
None => self.sessions_storage.create_current()?,
|
||||
};
|
||||
current_session
|
||||
.flush(&self.git_repository, user, &self.project)
|
||||
@ -380,7 +376,7 @@ fn init(
|
||||
// if the reference doesn't exist, we create it by creating a flushing a new session
|
||||
let mut current_session = match sessions_storage.get_current()? {
|
||||
Some(session) => session,
|
||||
None => sessions::Session::from_head(git_repository, project)?,
|
||||
None => sessions_storage.create_current()?,
|
||||
};
|
||||
current_session
|
||||
.flush(git_repository, user, project)
|
||||
|
@ -36,9 +36,8 @@ fn test_filter_by_timestamp() {
|
||||
let index_path = tempdir().unwrap().path().to_str().unwrap().to_string();
|
||||
|
||||
let sessions_storage = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let deltas_storage =
|
||||
deltas::Store::new(clone_repo(&repo), project.clone(), sessions_storage.clone()).unwrap();
|
||||
let mut session = sessions::Session::from_head(&repo, &project).unwrap();
|
||||
let deltas_storage = deltas::Store::new(project.clone(), sessions_storage.clone()).unwrap();
|
||||
let mut session = sessions_storage.create_current().unwrap();
|
||||
deltas_storage
|
||||
.write(
|
||||
Path::new("test.txt"),
|
||||
@ -62,12 +61,8 @@ fn test_filter_by_timestamp() {
|
||||
|
||||
let mut searcher = super::Deltas::at(index_path.into()).unwrap();
|
||||
|
||||
let write_result = searcher.index_session(
|
||||
&project,
|
||||
&session,
|
||||
&deltas_storage,
|
||||
&sessions_storage,
|
||||
);
|
||||
let write_result =
|
||||
searcher.index_session(&project, &session, &deltas_storage, &sessions_storage);
|
||||
assert!(write_result.is_ok());
|
||||
|
||||
let search_result_from = searcher.search(&super::SearchQuery {
|
||||
@ -113,9 +108,8 @@ fn test_sorted_by_timestamp() {
|
||||
let index_path = tempdir().unwrap().path().to_str().unwrap().to_string();
|
||||
|
||||
let sessions_storage = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let deltas_storage =
|
||||
deltas::Store::new(clone_repo(&repo), project.clone(), sessions_storage.clone()).unwrap();
|
||||
let mut session = sessions::Session::from_head(&repo, &project).unwrap();
|
||||
let deltas_storage = deltas::Store::new(project.clone(), sessions_storage.clone()).unwrap();
|
||||
let mut session = sessions_storage.create_current().unwrap();
|
||||
deltas_storage
|
||||
.write(
|
||||
Path::new("test.txt"),
|
||||
@ -135,12 +129,8 @@ fn test_sorted_by_timestamp() {
|
||||
|
||||
let mut searcher = super::Deltas::at(index_path.into()).unwrap();
|
||||
|
||||
let write_result = searcher.index_session(
|
||||
&project,
|
||||
&session,
|
||||
&deltas_storage,
|
||||
&sessions_storage,
|
||||
);
|
||||
let write_result =
|
||||
searcher.index_session(&project, &session, &deltas_storage, &sessions_storage);
|
||||
assert!(write_result.is_ok());
|
||||
|
||||
let search_result = searcher.search(&super::SearchQuery {
|
||||
@ -164,9 +154,8 @@ fn test_simple() {
|
||||
let index_path = tempdir().unwrap().path().to_str().unwrap().to_string();
|
||||
|
||||
let sessions_storage = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let deltas_storage =
|
||||
deltas::Store::new(clone_repo(&repo), project.clone(), sessions_storage.clone()).unwrap();
|
||||
let mut session = sessions::Session::from_head(&repo, &project).unwrap();
|
||||
let deltas_storage = deltas::Store::new(project.clone(), sessions_storage.clone()).unwrap();
|
||||
let mut session = sessions_storage.create_current().unwrap();
|
||||
deltas_storage
|
||||
.write(
|
||||
Path::new("test.txt"),
|
||||
@ -186,12 +175,8 @@ fn test_simple() {
|
||||
|
||||
let mut searcher = super::Deltas::at(index_path.into()).unwrap();
|
||||
|
||||
let write_result = searcher.index_session(
|
||||
&project,
|
||||
&session,
|
||||
&deltas_storage,
|
||||
&sessions_storage,
|
||||
);
|
||||
let write_result =
|
||||
searcher.index_session(&project, &session, &deltas_storage, &sessions_storage);
|
||||
assert!(write_result.is_ok());
|
||||
|
||||
let search_result1 = searcher.search(&super::SearchQuery {
|
||||
|
@ -10,9 +10,7 @@ use std::{
|
||||
io::{BufReader, Read},
|
||||
os::unix::prelude::MetadataExt,
|
||||
path::Path,
|
||||
time,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -38,46 +36,6 @@ pub struct Session {
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn from_head(repo: &git2::Repository, project: &projects::Project) -> Result<Self> {
|
||||
let now_ts = time::SystemTime::now()
|
||||
.duration_since(time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis();
|
||||
|
||||
let activity = match std::fs::read_to_string(repo.path().join("logs/HEAD")) {
|
||||
Ok(reflog) => reflog
|
||||
.lines()
|
||||
.filter_map(|line| activity::parse_reflog_line(line).ok())
|
||||
.filter(|activity| activity.timestamp_ms >= now_ts)
|
||||
.collect::<Vec<activity::Activity>>(),
|
||||
Err(_) => Vec::new(),
|
||||
};
|
||||
|
||||
let meta = match repo.head() {
|
||||
Ok(head) => Meta {
|
||||
start_timestamp_ms: now_ts,
|
||||
last_timestamp_ms: now_ts,
|
||||
branch: Some(head.name().unwrap().to_string()),
|
||||
commit: Some(head.peel_to_commit().unwrap().id().to_string()),
|
||||
},
|
||||
Err(_) => Meta {
|
||||
start_timestamp_ms: now_ts,
|
||||
last_timestamp_ms: now_ts,
|
||||
branch: None,
|
||||
commit: None,
|
||||
},
|
||||
};
|
||||
|
||||
let session = Session {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
hash: None,
|
||||
meta,
|
||||
activity,
|
||||
};
|
||||
create(project, &session).with_context(|| "failed to create current session from head")?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
pub fn from_commit(repo: &git2::Repository, commit: &git2::Commit) -> Result<Self> {
|
||||
let tree = commit.tree().with_context(|| {
|
||||
format!("failed to get tree from commit {}", commit.id().to_string())
|
||||
@ -159,10 +117,6 @@ impl Session {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn touch(&mut self, project: &projects::Project) -> Result<()> {
|
||||
update(project, self)
|
||||
}
|
||||
|
||||
pub fn flush(
|
||||
&mut self,
|
||||
repo: &git2::Repository,
|
||||
@ -173,106 +127,6 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
fn write(session_path: &Path, session: &Session) -> Result<()> {
|
||||
if session.hash.is_some() {
|
||||
return Err(anyhow!("cannot write session that is not current"));
|
||||
}
|
||||
|
||||
let meta_path = session_path.join("meta");
|
||||
|
||||
std::fs::create_dir_all(meta_path.clone()).with_context(|| {
|
||||
format!(
|
||||
"failed to create session meta directory {}",
|
||||
meta_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let id_path = meta_path.join("id");
|
||||
std::fs::write(id_path.clone(), session.id.clone())
|
||||
.with_context(|| format!("failed to write session id to {}", id_path.display()))?;
|
||||
|
||||
let start_path = meta_path.join("start");
|
||||
std::fs::write(
|
||||
start_path.clone(),
|
||||
session.meta.start_timestamp_ms.to_string(),
|
||||
)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to write session start timestamp to {}",
|
||||
start_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let last_path = meta_path.join("last");
|
||||
std::fs::write(
|
||||
last_path.clone(),
|
||||
session.meta.last_timestamp_ms.to_string(),
|
||||
)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to write session last timestamp to {}",
|
||||
last_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
if let Some(branch) = session.meta.branch.clone() {
|
||||
let branch_path = meta_path.join("branch");
|
||||
std::fs::write(branch_path.clone(), branch).with_context(|| {
|
||||
format!(
|
||||
"failed to write session branch to {}",
|
||||
branch_path.display()
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Some(commit) = session.meta.commit.clone() {
|
||||
let commit_path = meta_path.join("commit");
|
||||
std::fs::write(commit_path.clone(), commit).with_context(|| {
|
||||
format!(
|
||||
"failed to write session commit to {}",
|
||||
commit_path.display()
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update(project: &projects::Project, session: &mut Session) -> Result<()> {
|
||||
session.meta.last_timestamp_ms = time::SystemTime::now()
|
||||
.duration_since(time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis();
|
||||
|
||||
let session_path = project.session_path();
|
||||
log::debug!("{}: updating current session", project.id);
|
||||
if session_path.exists() {
|
||||
write(&session_path, session)
|
||||
} else {
|
||||
Err(anyhow!("\"{}\" does not exist", session_path.display()))
|
||||
}
|
||||
}
|
||||
|
||||
fn create(project: &projects::Project, session: &Session) -> Result<()> {
|
||||
let session_path = project.session_path();
|
||||
log::debug!("{}: Creating current session", session_path.display());
|
||||
let meta_path = session_path.join("meta");
|
||||
if meta_path.exists() {
|
||||
Err(anyhow!("session already exists"))
|
||||
} else {
|
||||
write(&session_path, session)
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(project: &projects::Project) -> Result<()> {
|
||||
let session_path = project.session_path();
|
||||
log::debug!("{}: deleting current session", project.id);
|
||||
if session_path.exists() {
|
||||
std::fs::remove_dir_all(session_path)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn id_from_commit(repo: &git2::Repository, commit: &git2::Commit) -> Result<String> {
|
||||
let tree = commit.tree().unwrap();
|
||||
let session_id_path = Path::new("session/meta/id");
|
||||
@ -308,10 +162,6 @@ fn flush(
|
||||
));
|
||||
}
|
||||
|
||||
session
|
||||
.touch(project)
|
||||
.with_context(|| format!("failed to touch session"))?;
|
||||
|
||||
let wd_tree = build_wd_tree(&repo, &project)
|
||||
.with_context(|| "failed to build wd tree for project".to_string())?;
|
||||
|
||||
@ -377,6 +227,15 @@ fn flush(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete(project: &projects::Project) -> Result<()> {
|
||||
let session_path = project.session_path();
|
||||
log::debug!("{}: deleting current session", project.id);
|
||||
if session_path.exists() {
|
||||
std::fs::remove_dir_all(session_path)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// try to push the new gb history head to the remote
|
||||
// TODO: if we see it is not a FF, pull down the remote, determine order, rewrite the commit line, and push again
|
||||
fn push_to_remote(
|
||||
|
@ -53,29 +53,32 @@ fn test_current_none() {
|
||||
#[test]
|
||||
fn test_create_current_fails_when_meta_path_exists() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let store = super::Store::new(repo, project.clone()).unwrap();
|
||||
|
||||
let meta_path = project.session_path().join("meta");
|
||||
std::fs::create_dir_all(&meta_path).unwrap();
|
||||
|
||||
let current_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let current_session = store.create_current();
|
||||
assert!(current_session.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_current_when_session_dir_exists() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let store = super::Store::new(repo, project.clone()).unwrap();
|
||||
|
||||
let session_dir = project.session_path();
|
||||
std::fs::create_dir_all(&session_dir).unwrap();
|
||||
|
||||
let current_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let current_session = store.create_current();
|
||||
assert!(current_session.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_current_empty() {
|
||||
let (repo, project) = test_project_empty().unwrap();
|
||||
let current_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let store = super::Store::new(repo, project).unwrap();
|
||||
let current_session = store.create_current();
|
||||
assert!(current_session.is_ok());
|
||||
assert!(current_session.as_ref().unwrap().id.len() > 0);
|
||||
assert_eq!(current_session.as_ref().unwrap().hash, None);
|
||||
@ -92,7 +95,8 @@ fn test_create_current_empty() {
|
||||
#[test]
|
||||
fn test_create_current() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let current_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let store = super::Store::new(clone_repo(&repo), project).unwrap();
|
||||
let current_session = store.create_current();
|
||||
assert!(current_session.is_ok());
|
||||
assert!(current_session.as_ref().unwrap().id.len() > 0);
|
||||
assert_eq!(current_session.as_ref().unwrap().hash, None);
|
||||
@ -136,7 +140,7 @@ fn test_create_current() {
|
||||
fn test_get_current() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let store = super::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let created_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let created_session = store.create_current();
|
||||
assert!(created_session.is_ok());
|
||||
let created_session = created_session.unwrap();
|
||||
|
||||
@ -152,7 +156,7 @@ fn test_get_current() {
|
||||
fn test_flush() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let store = super::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let created_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let created_session = store.create_current();
|
||||
assert!(created_session.is_ok());
|
||||
let mut created_session = created_session.unwrap();
|
||||
|
||||
@ -183,7 +187,7 @@ fn test_flush() {
|
||||
fn test_flush_with_user() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let store = super::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let created_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let created_session = store.create_current();
|
||||
assert!(created_session.is_ok());
|
||||
let mut created_session = created_session.unwrap();
|
||||
|
||||
@ -213,7 +217,8 @@ fn test_flush_with_user() {
|
||||
#[test]
|
||||
fn test_get_persistent() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let created_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let store = super::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let created_session = store.create_current();
|
||||
assert!(created_session.is_ok());
|
||||
let mut created_session = created_session.unwrap();
|
||||
|
||||
@ -237,19 +242,19 @@ fn clone_repo(repo: &git2::Repository) -> git2::Repository {
|
||||
fn test_list() {
|
||||
let (repo, project) = test_project().unwrap();
|
||||
let store = super::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let first = super::sessions::Session::from_head(&repo, &project);
|
||||
let first = store.create_current();
|
||||
assert!(first.is_ok());
|
||||
let mut first = first.unwrap();
|
||||
first.flush(&repo, &None, &project).unwrap();
|
||||
assert!(first.hash.is_some());
|
||||
|
||||
let second = super::sessions::Session::from_head(&repo, &project);
|
||||
let second = store.create_current();
|
||||
assert!(second.is_ok());
|
||||
let mut second = second.unwrap();
|
||||
second.flush(&repo, &None, &project).unwrap();
|
||||
assert!(second.hash.is_some());
|
||||
|
||||
let current_session = super::sessions::Session::from_head(&repo, &project);
|
||||
let current_session = store.create_current();
|
||||
assert!(current_session.is_ok());
|
||||
let current = current_session.unwrap();
|
||||
|
||||
@ -272,7 +277,7 @@ fn test_list_files_from_first_presistent_session() {
|
||||
|
||||
std::fs::write(file_path.clone(), "zero").unwrap();
|
||||
|
||||
let first = super::sessions::Session::from_head(&repo, &project);
|
||||
let first = store.create_current();
|
||||
assert!(first.is_ok());
|
||||
let mut first = first.unwrap();
|
||||
first.flush(&repo, &None, &project).unwrap();
|
||||
@ -296,7 +301,7 @@ fn test_list_files_from_second_current_session() {
|
||||
let file_path = Path::new(&project.path).join("test.txt");
|
||||
std::fs::write(file_path.clone(), "zero").unwrap();
|
||||
|
||||
let first = super::sessions::Session::from_head(&repo, &project);
|
||||
let first = store.create_current();
|
||||
assert!(first.is_ok());
|
||||
let mut first = first.unwrap();
|
||||
first.flush(&repo, &None, &project).unwrap();
|
||||
@ -306,7 +311,7 @@ fn test_list_files_from_second_current_session() {
|
||||
|
||||
std::fs::write(file_path.clone(), "one").unwrap();
|
||||
|
||||
let second = super::sessions::Session::from_head(&repo, &project);
|
||||
let second = store.create_current();
|
||||
assert!(second.is_ok());
|
||||
let second = second.unwrap();
|
||||
|
||||
@ -325,7 +330,7 @@ fn test_list_files_from_second_presistent_session() {
|
||||
let file_path = Path::new(&project.path).join("test.txt");
|
||||
std::fs::write(file_path.clone(), "zero").unwrap();
|
||||
|
||||
let first = super::sessions::Session::from_head(&repo, &project);
|
||||
let first = store.create_current();
|
||||
assert!(first.is_ok());
|
||||
let mut first = first.unwrap();
|
||||
first.flush(&repo, &None, &project).unwrap();
|
||||
@ -335,7 +340,7 @@ fn test_list_files_from_second_presistent_session() {
|
||||
|
||||
std::fs::write(file_path.clone(), "one").unwrap();
|
||||
|
||||
let second = super::sessions::Session::from_head(&repo, &project);
|
||||
let second = store.create_current();
|
||||
assert!(second.is_ok());
|
||||
let mut second = second.unwrap();
|
||||
second.flush(&repo, &None, &project).unwrap();
|
||||
@ -365,7 +370,7 @@ fn test_flush_ensure_wd_structure() {
|
||||
std::fs::write(file2_path.clone(), "zero").unwrap();
|
||||
|
||||
// flush first session
|
||||
let first = super::sessions::Session::from_head(&repo, &project);
|
||||
let first = store.create_current();
|
||||
assert!(first.is_ok());
|
||||
let mut first = first.unwrap();
|
||||
first.flush(&repo, &None, &project).unwrap();
|
||||
@ -387,7 +392,7 @@ fn test_flush_ensure_wd_structure() {
|
||||
.unwrap();
|
||||
|
||||
// flush second session
|
||||
let second = super::sessions::Session::from_head(&repo, &project);
|
||||
let second = store.create_current();
|
||||
assert!(second.is_ok());
|
||||
let mut second = second.unwrap();
|
||||
second.flush(&repo, &None, &project).unwrap();
|
||||
|
@ -1,5 +1,8 @@
|
||||
use std::time;
|
||||
|
||||
use crate::{projects, sessions};
|
||||
use anyhow::{Context, Result};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct Store {
|
||||
project: projects::Project,
|
||||
@ -23,6 +26,137 @@ impl Store {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create(&self) -> Result<sessions::Session> {
|
||||
let now_ts = time::SystemTime::now()
|
||||
.duration_since(time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis();
|
||||
|
||||
let activity = match std::fs::read_to_string(self.git_repository.path().join("logs/HEAD")) {
|
||||
Ok(reflog) => reflog
|
||||
.lines()
|
||||
.filter_map(|line| sessions::activity::parse_reflog_line(line).ok())
|
||||
.filter(|activity| activity.timestamp_ms >= now_ts)
|
||||
.collect::<Vec<sessions::activity::Activity>>(),
|
||||
Err(_) => Vec::new(),
|
||||
};
|
||||
|
||||
let meta = match self.git_repository.head() {
|
||||
Ok(head) => sessions::Meta {
|
||||
start_timestamp_ms: now_ts,
|
||||
last_timestamp_ms: now_ts,
|
||||
branch: Some(head.name().unwrap().to_string()),
|
||||
commit: Some(head.peel_to_commit().unwrap().id().to_string()),
|
||||
},
|
||||
Err(_) => sessions::Meta {
|
||||
start_timestamp_ms: now_ts,
|
||||
last_timestamp_ms: now_ts,
|
||||
branch: None,
|
||||
commit: None,
|
||||
},
|
||||
};
|
||||
|
||||
let session = sessions::Session {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
hash: None,
|
||||
meta,
|
||||
activity,
|
||||
};
|
||||
|
||||
let session_path = self.project.session_path();
|
||||
log::debug!("{}: Creating current session", session_path.display());
|
||||
let meta_path = session_path.join("meta");
|
||||
if meta_path.exists() {
|
||||
return Err(anyhow::anyhow!("session already exists"));
|
||||
}
|
||||
|
||||
self.write(&session)?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
pub fn update(&self, session: &sessions::Session) -> Result<()> {
|
||||
if session.hash.is_some() {
|
||||
return Err(anyhow::anyhow!("cannot update session that is not current"));
|
||||
}
|
||||
|
||||
let session_path = self.project.session_path();
|
||||
log::debug!("{}: updating current session", self.project.id);
|
||||
if session_path.exists() {
|
||||
self.write(session)
|
||||
} else {
|
||||
Err(anyhow::anyhow!(
|
||||
"\"{}\" does not exist",
|
||||
session_path.display()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, session: &sessions::Session) -> Result<()> {
|
||||
let session_path = self.project.session_path();
|
||||
if session.hash.is_some() {
|
||||
return Err(anyhow::anyhow!("cannot write session that is not current"));
|
||||
}
|
||||
|
||||
let meta_path = session_path.join("meta");
|
||||
|
||||
std::fs::create_dir_all(meta_path.clone()).with_context(|| {
|
||||
format!(
|
||||
"failed to create session meta directory {}",
|
||||
meta_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let id_path = meta_path.join("id");
|
||||
std::fs::write(id_path.clone(), session.id.clone())
|
||||
.with_context(|| format!("failed to write session id to {}", id_path.display()))?;
|
||||
|
||||
let start_path = meta_path.join("start");
|
||||
std::fs::write(
|
||||
start_path.clone(),
|
||||
session.meta.start_timestamp_ms.to_string(),
|
||||
)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to write session start timestamp to {}",
|
||||
start_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let last_path = meta_path.join("last");
|
||||
std::fs::write(
|
||||
last_path.clone(),
|
||||
session.meta.last_timestamp_ms.to_string(),
|
||||
)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to write session last timestamp to {}",
|
||||
last_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
if let Some(branch) = session.meta.branch.clone() {
|
||||
let branch_path = meta_path.join("branch");
|
||||
std::fs::write(branch_path.clone(), branch).with_context(|| {
|
||||
format!(
|
||||
"failed to write session branch to {}",
|
||||
branch_path.display()
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Some(commit) = session.meta.commit.clone() {
|
||||
let commit_path = meta_path.join("commit");
|
||||
std::fs::write(commit_path.clone(), commit).with_context(|| {
|
||||
format!(
|
||||
"failed to write session commit to {}",
|
||||
commit_path.display()
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Result<Option<sessions::Session>> {
|
||||
let session_path = self.project.session_path();
|
||||
let meta_path = session_path.join("meta");
|
||||
|
@ -25,6 +25,18 @@ impl Store {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_current(&self) -> Result<sessions::Session> {
|
||||
self.current.create()
|
||||
}
|
||||
|
||||
pub fn update(&self, session: &sessions::Session) -> Result<()> {
|
||||
if session.hash.is_some() {
|
||||
Err(anyhow::anyhow!("cannot update session that is not current"))
|
||||
} else {
|
||||
self.current.update(session)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_files(
|
||||
&self,
|
||||
session_id: &str,
|
||||
|
@ -36,7 +36,7 @@ fn test_register_file_change_must_create_session() {
|
||||
|
||||
let sessions_storage = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let deltas_storage =
|
||||
deltas::Store::new(clone_repo(&repo), project.clone(), sessions_storage).unwrap();
|
||||
deltas::Store::new(project.clone(), sessions_storage).unwrap();
|
||||
let result =
|
||||
super::delta::register_file_change(&project, &repo, &deltas_storage, &relative_file_path);
|
||||
println!("{:?}", result);
|
||||
@ -57,7 +57,7 @@ fn test_register_file_change_must_not_change_session() {
|
||||
|
||||
let sessions_storage = sessions::Store::new(clone_repo(&repo), project.clone()).unwrap();
|
||||
let deltas_storage =
|
||||
deltas::Store::new(clone_repo(&repo), project.clone(), sessions_storage).unwrap();
|
||||
deltas::Store::new(project.clone(), sessions_storage).unwrap();
|
||||
let result =
|
||||
super::delta::register_file_change(&project, &repo, &deltas_storage, &relative_file_path);
|
||||
assert!(result.is_ok());
|
||||
|
Loading…
Reference in New Issue
Block a user