test(git): make repository more testable
Adds a layer around Repository to allow the use of a mock. Mock has still to be implemented.
This commit is contained in:
parent
6757723b77
commit
58e991b2b7
18 changed files with 295 additions and 182 deletions
|
@ -5,6 +5,7 @@ edition = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
git-next-server = { workspace = true }
|
git-next-server = { workspace = true }
|
||||||
|
git-next-git = { workspace = true }
|
||||||
|
|
||||||
# CLI parsing
|
# CLI parsing
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
|
|
|
@ -30,6 +30,7 @@ enum Server {
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let fs = fs::new(PathBuf::default());
|
let fs = fs::new(PathBuf::default());
|
||||||
let net = Network::new_real();
|
let net = Network::new_real();
|
||||||
|
let repo = git_next_git::repository::new();
|
||||||
let commands = Commands::parse();
|
let commands = Commands::parse();
|
||||||
|
|
||||||
match commands.command {
|
match commands.command {
|
||||||
|
@ -41,7 +42,7 @@ async fn main() {
|
||||||
git_next_server::init(fs);
|
git_next_server::init(fs);
|
||||||
}
|
}
|
||||||
Server::Start => {
|
Server::Start => {
|
||||||
git_next_server::start(fs, net).await;
|
git_next_server::start(fs, net, repo).await;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,8 +381,6 @@ mod forge_type {
|
||||||
mod gitdir {
|
mod gitdir {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use derive_more::Deref;
|
|
||||||
|
|
||||||
use crate::GitDir;
|
use crate::GitDir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,36 +1,9 @@
|
||||||
use std::ops::Deref;
|
#[derive(Debug, derive_more::Display)]
|
||||||
|
|
||||||
use tracing::{debug, info};
|
|
||||||
|
|
||||||
use super::{RepoDetails, Repository};
|
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From, derive_more::Display)]
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
UnableToOpenRepo(Box<gix::open::Error>),
|
UnableToOpenRepo(String),
|
||||||
NoFetchRemoteFound,
|
NoFetchRemoteFound,
|
||||||
Connect(Box<gix::remote::connect::Error>),
|
Connect(String),
|
||||||
Fetch(String),
|
Fetch(String),
|
||||||
|
Lock,
|
||||||
}
|
}
|
||||||
impl std::error::Error for Error {}
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields(repo = %repo_details))]
|
|
||||||
pub fn fetch(repository: &Repository, repo_details: &RepoDetails) -> Result<(), Error> {
|
|
||||||
let repository = repository.deref().to_thread_local();
|
|
||||||
let Some(remote) = repository.find_default_remote(gix::remote::Direction::Fetch) else {
|
|
||||||
return Err(Error::NoFetchRemoteFound);
|
|
||||||
};
|
|
||||||
debug!(?remote, "fetch remote");
|
|
||||||
|
|
||||||
remote
|
|
||||||
.map_err(|e| Error::Fetch(e.to_string()))?
|
|
||||||
.connect(gix::remote::Direction::Fetch)
|
|
||||||
.map_err(Box::new)?
|
|
||||||
.prepare_fetch(gix::progress::Discard, Default::default())
|
|
||||||
.map_err(|e| Error::Fetch(e.to_string()))?
|
|
||||||
.receive(gix::progress::Discard, &Default::default())
|
|
||||||
.map_err(|e| Error::Fetch(e.to_string()))?;
|
|
||||||
|
|
||||||
info!("fetched");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,11 +13,10 @@ pub mod validate;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub use commit::Commit;
|
pub use commit::Commit;
|
||||||
pub use fetch::fetch;
|
|
||||||
pub use generation::Generation;
|
pub use generation::Generation;
|
||||||
pub use git_ref::GitRef;
|
pub use git_ref::GitRef;
|
||||||
pub use git_remote::GitRemote;
|
pub use git_remote::GitRemote;
|
||||||
pub use push::push;
|
|
||||||
pub use repo_details::RepoDetails;
|
pub use repo_details::RepoDetails;
|
||||||
|
pub use repository::open::OpenRepository;
|
||||||
pub use repository::Repository;
|
pub use repository::Repository;
|
||||||
pub use validate::validate;
|
pub use validate::validate;
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
use std::ops::Deref;
|
use super::GitRef;
|
||||||
|
|
||||||
use git_next_config::BranchName;
|
|
||||||
use secrecy::ExposeSecret;
|
|
||||||
use tracing::{info, warn};
|
|
||||||
|
|
||||||
use super::{GitRef, RepoDetails, Repository};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Force {
|
pub enum Force {
|
||||||
|
@ -20,60 +14,12 @@ impl std::fmt::Display for Force {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: (#72) reimplement using `gix`
|
|
||||||
#[tracing::instrument(skip_all, fields(branch = %branch_name, to = %to_commit, force = %force))]
|
|
||||||
pub fn push(
|
|
||||||
repository: &Repository,
|
|
||||||
repo_details: &RepoDetails,
|
|
||||||
branch_name: BranchName,
|
|
||||||
to_commit: GitRef,
|
|
||||||
force: Force,
|
|
||||||
) -> Result {
|
|
||||||
let origin = repo_details.origin();
|
|
||||||
let force = match force {
|
|
||||||
Force::No => "".to_string(),
|
|
||||||
Force::From(old_ref) => format!("--force-with-lease={branch_name}:{old_ref}"),
|
|
||||||
};
|
|
||||||
// INFO: never log the command as it contains the API token within the 'origin'
|
|
||||||
let command: secrecy::Secret<String> = format!(
|
|
||||||
"/usr/bin/git push {} {to_commit}:{branch_name} {force}",
|
|
||||||
origin.expose_secret()
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
let git_dir = repository.deref().git_dir();
|
|
||||||
let ctx = gix::diff::command::Context {
|
|
||||||
git_dir: Some(git_dir.to_path_buf()),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
match gix::command::prepare(command.expose_secret())
|
|
||||||
.with_context(ctx)
|
|
||||||
.with_shell_allow_argument_splitting()
|
|
||||||
.stdout(std::process::Stdio::null())
|
|
||||||
.stderr(std::process::Stdio::null())
|
|
||||||
.spawn()
|
|
||||||
{
|
|
||||||
Ok(mut child) => match child.wait() {
|
|
||||||
Ok(_) => {
|
|
||||||
info!("Branch updated");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
warn!(?err, ?git_dir, "Failed (wait)");
|
|
||||||
Err(Error::Push)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
warn!(?err, ?git_dir, "Failed (spawn)");
|
|
||||||
Err(Error::Push)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From, derive_more::Display)]
|
#[derive(Debug, derive_more::From, derive_more::Display)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Open(Box<gix::open::Error>),
|
Open(Box<gix::open::Error>),
|
||||||
Fetch(super::fetch::Error),
|
Fetch(super::fetch::Error),
|
||||||
Push,
|
Push,
|
||||||
|
Lock,
|
||||||
}
|
}
|
||||||
impl std::error::Error for Error {}
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,221 @@
|
||||||
//
|
//
|
||||||
use std::{ops::Deref as _, path::PathBuf, sync::atomic::AtomicBool};
|
use std::{
|
||||||
|
ops::Deref as _,
|
||||||
|
sync::{atomic::AtomicBool, Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
use git_next_config::{BranchName, GitDir, Hostname, RepoPath};
|
||||||
|
use tracing::{info, warn};
|
||||||
|
|
||||||
|
use crate::{fetch, push, GitRef, GitRemote};
|
||||||
|
|
||||||
use super::RepoDetails;
|
use super::RepoDetails;
|
||||||
|
|
||||||
#[derive(Debug, Clone, derive_more::From, derive_more::Deref)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Repository(gix::ThreadSafeRepository);
|
pub enum Repository {
|
||||||
impl Repository {
|
Real,
|
||||||
pub fn open(gitdir: impl Into<PathBuf>) -> Result<Self, Error> {
|
Mock,
|
||||||
Ok(Self(gix::ThreadSafeRepository::open(gitdir.into())?))
|
}
|
||||||
}
|
pub const fn new() -> Repository {
|
||||||
pub fn clone(repo_details: &RepoDetails) -> Result<Self, Error> {
|
Repository::Real
|
||||||
use secrecy::ExposeSecret;
|
}
|
||||||
let origin = repo_details.origin();
|
pub const fn mock() -> Repository {
|
||||||
let (repository, _outcome) =
|
Repository::Mock
|
||||||
gix::prepare_clone_bare(origin.expose_secret().as_str(), repo_details.gitdir.deref())?
|
}
|
||||||
.fetch_only(gix::progress::Discard, &AtomicBool::new(false))?;
|
mod mock {
|
||||||
|
use super::*;
|
||||||
|
pub struct MockRepository;
|
||||||
|
impl RepositoryLike for MockRepository {
|
||||||
|
fn open(&self, _gitdir: &GitDir) -> Result<open::OpenRepository, Error> {
|
||||||
|
Ok(open::OpenRepository::Mock)
|
||||||
|
}
|
||||||
|
|
||||||
Ok(repository.into_sync().into())
|
fn git_clone(&self, _repo_details: &RepoDetails) -> Result<open::OpenRepository, Error> {
|
||||||
|
Ok(open::OpenRepository::Mock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RepositoryLike {
|
||||||
|
fn open(&self, gitdir: &GitDir) -> Result<open::OpenRepository, Error>;
|
||||||
|
fn git_clone(&self, repo_details: &RepoDetails) -> Result<open::OpenRepository, Error>;
|
||||||
|
}
|
||||||
|
impl std::ops::Deref for Repository {
|
||||||
|
type Target = dyn RepositoryLike;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
Self::Real => &real::RealRepository,
|
||||||
|
Self::Mock => &mock::MockRepository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mod real {
|
||||||
|
use super::*;
|
||||||
|
pub struct RealRepository;
|
||||||
|
impl RepositoryLike for RealRepository {
|
||||||
|
fn open(&self, gitdir: &GitDir) -> Result<open::OpenRepository, Error> {
|
||||||
|
Ok(open::OpenRepository::Real(open::RealOpenRepository::new(
|
||||||
|
Arc::new(Mutex::new(
|
||||||
|
gix::ThreadSafeRepository::open(gitdir.to_path_buf())?.to_thread_local(),
|
||||||
|
)),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn git_clone(&self, repo_details: &RepoDetails) -> Result<open::OpenRepository, Error> {
|
||||||
|
use secrecy::ExposeSecret;
|
||||||
|
let origin = repo_details.origin();
|
||||||
|
let (repository, _outcome) = gix::prepare_clone_bare(
|
||||||
|
origin.expose_secret().as_str(),
|
||||||
|
repo_details.gitdir.deref(),
|
||||||
|
)?
|
||||||
|
.fetch_only(gix::progress::Discard, &AtomicBool::new(false))?;
|
||||||
|
|
||||||
|
Ok(open::OpenRepository::Real(open::RealOpenRepository::new(
|
||||||
|
Arc::new(Mutex::new(repository)),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod open {
|
||||||
|
use super::*;
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OpenRepository {
|
||||||
|
Real(RealOpenRepository),
|
||||||
|
Mock, // TODO: (#38) contain a mock model of a repo
|
||||||
|
}
|
||||||
|
pub trait OpenRepositoryLike {
|
||||||
|
fn find_default_remote(&self, direction: Direction) -> Option<GitRemote>;
|
||||||
|
fn fetch(&self) -> Result<(), fetch::Error>;
|
||||||
|
fn push(
|
||||||
|
&self,
|
||||||
|
repo_details: &RepoDetails,
|
||||||
|
branch_name: BranchName,
|
||||||
|
to_commit: GitRef,
|
||||||
|
force: push::Force,
|
||||||
|
) -> Result<(), push::Error>;
|
||||||
|
}
|
||||||
|
impl std::ops::Deref for OpenRepository {
|
||||||
|
type Target = dyn OpenRepositoryLike;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
Self::Real(real) => real,
|
||||||
|
Self::Mock => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, derive_more::Constructor)]
|
||||||
|
pub struct RealOpenRepository(Arc<Mutex<gix::Repository>>);
|
||||||
|
impl OpenRepositoryLike for RealOpenRepository {
|
||||||
|
fn find_default_remote(&self, direction: Direction) -> Option<GitRemote> {
|
||||||
|
let Ok(repository) = self.0.lock() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(Ok(remote)) = repository.find_default_remote(direction.into()) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let url = remote.url(direction.into())?;
|
||||||
|
let host = url.host()?;
|
||||||
|
let path = url.path.to_string();
|
||||||
|
let path = path.strip_prefix('/').map_or(path.as_str(), |path| path);
|
||||||
|
let path = path.strip_suffix(".git").map_or(path, |path| path);
|
||||||
|
Some(GitRemote::new(
|
||||||
|
Hostname::new(host),
|
||||||
|
RepoPath::new(path.to_string()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch(&self) -> Result<(), fetch::Error> {
|
||||||
|
let Ok(repository) = self.0.lock() else {
|
||||||
|
return Err(fetch::Error::Lock);
|
||||||
|
};
|
||||||
|
let Some(Ok(remote)) = repository.find_default_remote(Direction::Fetch.into()) else {
|
||||||
|
return Err(fetch::Error::NoFetchRemoteFound);
|
||||||
|
};
|
||||||
|
remote
|
||||||
|
.connect(gix::remote::Direction::Fetch)
|
||||||
|
.map_err(|e| fetch::Error::Connect(e.to_string()))?
|
||||||
|
.prepare_fetch(gix::progress::Discard, Default::default())
|
||||||
|
.map_err(|e| fetch::Error::Fetch(e.to_string()))?
|
||||||
|
.receive(gix::progress::Discard, &Default::default())
|
||||||
|
.map_err(|e| fetch::Error::Fetch(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: (#72) reimplement using `gix`
|
||||||
|
fn push(
|
||||||
|
&self,
|
||||||
|
repo_details: &RepoDetails,
|
||||||
|
branch_name: BranchName,
|
||||||
|
to_commit: GitRef,
|
||||||
|
force: push::Force,
|
||||||
|
) -> Result<(), push::Error> {
|
||||||
|
let origin = repo_details.origin();
|
||||||
|
let force = match force {
|
||||||
|
push::Force::No => "".to_string(),
|
||||||
|
push::Force::From(old_ref) => format!("--force-with-lease={branch_name}:{old_ref}"),
|
||||||
|
};
|
||||||
|
// INFO: never log the command as it contains the API token within the 'origin'
|
||||||
|
use secrecy::ExposeSecret;
|
||||||
|
let command: secrecy::Secret<String> = format!(
|
||||||
|
"/usr/bin/git push {} {to_commit}:{branch_name} {force}",
|
||||||
|
origin.expose_secret()
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let git_dir = self
|
||||||
|
.0
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| push::Error::Lock)
|
||||||
|
.map(|r| r.git_dir().to_path_buf())?;
|
||||||
|
|
||||||
|
let ctx = gix::diff::command::Context {
|
||||||
|
git_dir: Some(git_dir.clone()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
match gix::command::prepare(command.expose_secret())
|
||||||
|
.with_context(ctx)
|
||||||
|
.with_shell_allow_argument_splitting()
|
||||||
|
.stdout(std::process::Stdio::null())
|
||||||
|
.stderr(std::process::Stdio::null())
|
||||||
|
.spawn()
|
||||||
|
{
|
||||||
|
Ok(mut child) => match child.wait() {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Branch updated");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!(?err, ?git_dir, "Failed (wait)");
|
||||||
|
Err(push::Error::Push)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
warn!(?err, ?git_dir, "Failed (spawn)");
|
||||||
|
Err(push::Error::Push)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Direction {
|
||||||
|
/// Push local changes to the remote.
|
||||||
|
Push,
|
||||||
|
/// Fetch changes from the remote to the local repository.
|
||||||
|
Fetch,
|
||||||
|
}
|
||||||
|
impl From<Direction> for gix::remote::Direction {
|
||||||
|
fn from(value: Direction) -> Self {
|
||||||
|
match value {
|
||||||
|
Direction::Push => Self::Push,
|
||||||
|
Direction::Fetch => Self::Fetch,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
use std::ops::Deref as _;
|
|
||||||
|
|
||||||
use git_next_config::{Hostname, RepoPath};
|
|
||||||
use gix::remote::Direction;
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use super::{GitRemote, RepoDetails, Repository};
|
use crate::repository::{open::OpenRepository, Direction};
|
||||||
|
|
||||||
|
use super::{GitRemote, RepoDetails};
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub fn validate(repository: &Repository, repo_details: &RepoDetails) -> Result<()> {
|
pub fn validate(repository: &OpenRepository, repo_details: &RepoDetails) -> Result<()> {
|
||||||
let git_remote = repo_details.git_remote();
|
let git_remote = repo_details.git_remote();
|
||||||
let push_remote = find_default_remote(repository, Direction::Push)?;
|
let Some(push_remote) = repository.find_default_remote(Direction::Push) else {
|
||||||
let fetch_remote = find_default_remote(repository, Direction::Fetch)?;
|
return Err(Error::NoDefaultPushRemote);
|
||||||
|
};
|
||||||
|
let Some(fetch_remote) = repository.find_default_remote(Direction::Fetch) else {
|
||||||
|
return Err(Error::NoDefaultFetchRemote);
|
||||||
|
};
|
||||||
info!(config = %git_remote, push = %push_remote, fetch = %fetch_remote, "Check remotes match");
|
info!(config = %git_remote, push = %push_remote, fetch = %fetch_remote, "Check remotes match");
|
||||||
if git_remote != push_remote {
|
if git_remote != push_remote {
|
||||||
return Err(Error::MismatchDefaultPushRemote {
|
return Err(Error::MismatchDefaultPushRemote {
|
||||||
|
@ -27,35 +29,11 @@ pub fn validate(repository: &Repository, repo_details: &RepoDetails) -> Result<(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields(?direction))]
|
|
||||||
pub fn find_default_remote(
|
|
||||||
repository: &Repository,
|
|
||||||
direction: gix::remote::Direction,
|
|
||||||
) -> Result<GitRemote> {
|
|
||||||
let repository = repository.deref().to_thread_local();
|
|
||||||
let Some(Ok(remote)) = repository.find_default_remote(gix::remote::Direction::Push) else {
|
|
||||||
return Err(Error::NoDefaultPushRemote);
|
|
||||||
};
|
|
||||||
let Some(url) = remote.url(direction) else {
|
|
||||||
return Err(Error::NoUrlForDefaultPushRemote);
|
|
||||||
};
|
|
||||||
let Some(host) = url.host() else {
|
|
||||||
return Err(Error::NoHostnameForDefaultPushRemote);
|
|
||||||
};
|
|
||||||
let path = url.path.to_string();
|
|
||||||
let path = path.strip_prefix('/').map_or(path.as_str(), |path| path);
|
|
||||||
let path = path.strip_suffix(".git").map_or(path, |path| path);
|
|
||||||
info!(%host, %path, "found");
|
|
||||||
Ok(GitRemote::new(
|
|
||||||
Hostname::new(host),
|
|
||||||
RepoPath::new(path.to_string()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result<T> = core::result::Result<T, Error>;
|
type Result<T> = core::result::Result<T, Error>;
|
||||||
#[derive(Debug, derive_more::Display)]
|
#[derive(Debug, derive_more::Display)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
NoDefaultPushRemote,
|
NoDefaultPushRemote,
|
||||||
|
NoDefaultFetchRemote,
|
||||||
NoUrlForDefaultPushRemote,
|
NoUrlForDefaultPushRemote,
|
||||||
NoHostnameForDefaultPushRemote,
|
NoHostnameForDefaultPushRemote,
|
||||||
UnableToOpenRepo(String),
|
UnableToOpenRepo(String),
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub async fn advance_next(
|
||||||
dev_commit_history: Vec<git::Commit>,
|
dev_commit_history: Vec<git::Commit>,
|
||||||
repo_config: RepoConfig,
|
repo_config: RepoConfig,
|
||||||
forge: gitforge::Forge,
|
forge: gitforge::Forge,
|
||||||
repository: git::Repository,
|
repository: git::OpenRepository,
|
||||||
addr: Addr<super::RepoActor>,
|
addr: Addr<super::RepoActor>,
|
||||||
message_token: super::MessageToken,
|
message_token: super::MessageToken,
|
||||||
) {
|
) {
|
||||||
|
@ -82,7 +82,7 @@ pub async fn advance_main(
|
||||||
next: git::Commit,
|
next: git::Commit,
|
||||||
repo_config: RepoConfig,
|
repo_config: RepoConfig,
|
||||||
forge: gitforge::Forge,
|
forge: gitforge::Forge,
|
||||||
repository: git::Repository,
|
repository: git::OpenRepository,
|
||||||
addr: Addr<RepoActor>,
|
addr: Addr<RepoActor>,
|
||||||
message_token: super::MessageToken,
|
message_token: super::MessageToken,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub mod webhook;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
use git::OpenRepository;
|
||||||
use git_next_config::{ForgeType, RepoConfig};
|
use git_next_config::{ForgeType, RepoConfig};
|
||||||
use git_next_git::{self as git, Generation, RepoDetails};
|
use git_next_git::{self as git, Generation, RepoDetails};
|
||||||
use kxio::network::Network;
|
use kxio::network::Network;
|
||||||
|
@ -28,7 +29,7 @@ pub struct RepoActor {
|
||||||
last_main_commit: Option<git::Commit>,
|
last_main_commit: Option<git::Commit>,
|
||||||
last_next_commit: Option<git::Commit>,
|
last_next_commit: Option<git::Commit>,
|
||||||
last_dev_commit: Option<git::Commit>,
|
last_dev_commit: Option<git::Commit>,
|
||||||
repository: Option<git::Repository>,
|
repository: Option<OpenRepository>,
|
||||||
net: Network,
|
net: Network,
|
||||||
forge: gitforge::Forge,
|
forge: gitforge::Forge,
|
||||||
}
|
}
|
||||||
|
@ -38,10 +39,11 @@ impl RepoActor {
|
||||||
webhook: Webhook,
|
webhook: Webhook,
|
||||||
generation: Generation,
|
generation: Generation,
|
||||||
net: Network,
|
net: Network,
|
||||||
|
repo: git::Repository,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let forge = match details.forge.forge_type() {
|
let forge = match details.forge.forge_type() {
|
||||||
#[cfg(feature = "forgejo")]
|
#[cfg(feature = "forgejo")]
|
||||||
ForgeType::ForgeJo => gitforge::Forge::new_forgejo(details.clone(), net.clone()),
|
ForgeType::ForgeJo => gitforge::Forge::new_forgejo(details.clone(), net.clone(), repo),
|
||||||
ForgeType::MockForge => gitforge::Forge::new_mock(),
|
ForgeType::MockForge => gitforge::Forge::new_mock(),
|
||||||
};
|
};
|
||||||
debug!(?forge, "new");
|
debug!(?forge, "new");
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use git_next_config::{ForgeConfig, ForgeName, GitDir, RepoAlias, ServerRepoConfig};
|
use git_next_config::{ForgeConfig, ForgeName, GitDir, RepoAlias, ServerRepoConfig};
|
||||||
use git_next_git::{Generation, RepoDetails};
|
use git_next_git::{Generation, RepoDetails, Repository};
|
||||||
use kxio::{fs::FileSystem, network::Network};
|
use kxio::{fs::FileSystem, network::Network};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ pub struct Server {
|
||||||
webhook: Option<Addr<WebhookActor>>,
|
webhook: Option<Addr<WebhookActor>>,
|
||||||
fs: FileSystem,
|
fs: FileSystem,
|
||||||
net: Network,
|
net: Network,
|
||||||
|
repo: Repository,
|
||||||
}
|
}
|
||||||
impl Actor for Server {
|
impl Actor for Server {
|
||||||
type Context = Context<Self>;
|
type Context = Context<Self>;
|
||||||
|
@ -110,13 +111,14 @@ impl Handler<ServerConfig> for Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn new(fs: FileSystem, net: Network) -> Self {
|
pub fn new(fs: FileSystem, net: Network, repo: Repository) -> Self {
|
||||||
let generation = Generation::new();
|
let generation = Generation::new();
|
||||||
Self {
|
Self {
|
||||||
generation,
|
generation,
|
||||||
webhook: None,
|
webhook: None,
|
||||||
fs,
|
fs,
|
||||||
net,
|
net,
|
||||||
|
repo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn create_forge_data_directories(
|
fn create_forge_data_directories(
|
||||||
|
@ -175,6 +177,7 @@ impl Server {
|
||||||
let server_storage = server_storage.clone();
|
let server_storage = server_storage.clone();
|
||||||
let webhook = webhook.clone();
|
let webhook = webhook.clone();
|
||||||
let net = self.net.clone();
|
let net = self.net.clone();
|
||||||
|
let repo = self.repo;
|
||||||
let generation = self.generation;
|
let generation = self.generation;
|
||||||
move |(repo_alias, server_repo_config)| {
|
move |(repo_alias, server_repo_config)| {
|
||||||
let span = tracing::info_span!("create_actor", alias = %repo_alias, config = %server_repo_config);
|
let span = tracing::info_span!("create_actor", alias = %repo_alias, config = %server_repo_config);
|
||||||
|
@ -202,7 +205,8 @@ impl Server {
|
||||||
gitdir,
|
gitdir,
|
||||||
);
|
);
|
||||||
info!("Starting Repo Actor");
|
info!("Starting Repo Actor");
|
||||||
let actor = RepoActor::new(repo_details, webhook.clone(), generation, net.clone());
|
let actor =
|
||||||
|
RepoActor::new(repo_details, webhook.clone(), generation, net.clone(), repo);
|
||||||
(forge_name.clone(), repo_alias, actor)
|
(forge_name.clone(), repo_alias, actor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
|
use git::repository::Direction;
|
||||||
use git_next_config::{
|
use git_next_config::{
|
||||||
ForgeType, GitDir, Hostname, RepoBranches, RepoConfig, RepoConfigSource, RepoPath,
|
ForgeType, GitDir, Hostname, RepoBranches, RepoConfig, RepoConfigSource, RepoPath,
|
||||||
ServerRepoConfig,
|
ServerRepoConfig,
|
||||||
};
|
};
|
||||||
use git_next_git::{self as git, Generation, GitRemote, Repository};
|
use git_next_git::{self as git, Generation, GitRemote};
|
||||||
use gix::remote::Direction;
|
|
||||||
use kxio::fs;
|
use kxio::fs;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
@ -179,8 +179,11 @@ fn repo_details_find_default_push_remote_finds_correct_remote() -> Result<()> {
|
||||||
.with_hostname(Hostname::new("git.kemitix.net"));
|
.with_hostname(Hostname::new("git.kemitix.net"));
|
||||||
repo_details.repo_path = RepoPath::new("kemitix/git-next".to_string());
|
repo_details.repo_path = RepoPath::new("kemitix/git-next".to_string());
|
||||||
let gitdir = &repo_details.gitdir;
|
let gitdir = &repo_details.gitdir;
|
||||||
let repository = Repository::open(gitdir)?;
|
let repository = git::repository::new().open(gitdir)?;
|
||||||
let found_git_remote = git::validate::find_default_remote(&repository, Direction::Push)?;
|
let_assert!(
|
||||||
|
Some(found_git_remote) = repository.find_default_remote(Direction::Push),
|
||||||
|
"Default Push Remote not found"
|
||||||
|
);
|
||||||
let config_git_remote = repo_details.git_remote();
|
let config_git_remote = repo_details.git_remote();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -207,7 +210,7 @@ fn gitdir_validate_should_pass_a_valid_git_repo() -> Result<()> {
|
||||||
.with_hostname(Hostname::new("git.kemitix.net"));
|
.with_hostname(Hostname::new("git.kemitix.net"));
|
||||||
repo_details.repo_path = RepoPath::new("kemitix/git-next".to_string());
|
repo_details.repo_path = RepoPath::new("kemitix/git-next".to_string());
|
||||||
let gitdir = &repo_details.gitdir;
|
let gitdir = &repo_details.gitdir;
|
||||||
let repository = Repository::open(gitdir)?;
|
let repository = git::repository::new().open(gitdir)?;
|
||||||
git::validate(&repository, &repo_details)?;
|
git::validate(&repository, &repo_details)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -226,7 +229,7 @@ fn gitdir_validate_should_fail_a_git_repo_with_wrong_remote() -> Result<()> {
|
||||||
);
|
);
|
||||||
repo_details.repo_path = RepoPath::new("hello/world".to_string());
|
repo_details.repo_path = RepoPath::new("hello/world".to_string());
|
||||||
let gitdir = &repo_details.gitdir;
|
let gitdir = &repo_details.gitdir;
|
||||||
let repository = Repository::open(gitdir)?;
|
let repository = git::repository::new().open(gitdir)?;
|
||||||
let_assert!(Err(_) = git::validate(&repository, &repo_details));
|
let_assert!(Err(_) = git::validate(&repository, &repo_details));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub struct ValidatedPositions {
|
||||||
|
|
||||||
pub async fn validate_positions(
|
pub async fn validate_positions(
|
||||||
forge: &gitforge::forgejo::ForgeJoEnv,
|
forge: &gitforge::forgejo::ForgeJoEnv,
|
||||||
repository: &git::Repository,
|
repository: &git::OpenRepository,
|
||||||
repo_config: RepoConfig,
|
repo_config: RepoConfig,
|
||||||
) -> Result<ValidatedPositions, Error> {
|
) -> Result<ValidatedPositions, Error> {
|
||||||
let repo_details = &forge.repo_details;
|
let repo_details = &forge.repo_details;
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::time::Duration;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use git::OpenRepository;
|
||||||
use git_next_config::{BranchName, GitDir, RepoConfig};
|
use git_next_config::{BranchName, GitDir, RepoConfig};
|
||||||
use git_next_git::{self as git, GitRef, RepoDetails, Repository};
|
use git_next_git::{self as git, GitRef, RepoDetails, Repository};
|
||||||
use kxio::network::{self, Network};
|
use kxio::network::{self, Network};
|
||||||
|
@ -21,10 +22,15 @@ struct ForgeJo;
|
||||||
pub struct ForgeJoEnv {
|
pub struct ForgeJoEnv {
|
||||||
repo_details: RepoDetails,
|
repo_details: RepoDetails,
|
||||||
net: Network,
|
net: Network,
|
||||||
|
repo: Repository,
|
||||||
}
|
}
|
||||||
impl ForgeJoEnv {
|
impl ForgeJoEnv {
|
||||||
pub(super) const fn new(repo_details: RepoDetails, net: Network) -> Self {
|
pub(super) const fn new(repo_details: RepoDetails, net: Network, repo: Repository) -> Self {
|
||||||
Self { repo_details, net }
|
Self {
|
||||||
|
repo_details,
|
||||||
|
net,
|
||||||
|
repo,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
@ -47,7 +53,7 @@ impl super::ForgeLike for ForgeJoEnv {
|
||||||
|
|
||||||
async fn branches_validate_positions(
|
async fn branches_validate_positions(
|
||||||
&self,
|
&self,
|
||||||
repository: git::Repository,
|
repository: git::OpenRepository,
|
||||||
repo_config: RepoConfig,
|
repo_config: RepoConfig,
|
||||||
addr: Addr<RepoActor>,
|
addr: Addr<RepoActor>,
|
||||||
message_token: MessageToken,
|
message_token: MessageToken,
|
||||||
|
@ -71,19 +77,13 @@ impl super::ForgeLike for ForgeJoEnv {
|
||||||
|
|
||||||
fn branch_reset(
|
fn branch_reset(
|
||||||
&self,
|
&self,
|
||||||
repository: &git::Repository,
|
repository: &git::OpenRepository,
|
||||||
branch_name: BranchName,
|
branch_name: BranchName,
|
||||||
to_commit: GitRef,
|
to_commit: GitRef,
|
||||||
force: git::push::Force,
|
force: git::push::Force,
|
||||||
) -> git::push::Result {
|
) -> git::push::Result {
|
||||||
git::fetch(repository, &self.repo_details)?;
|
repository.fetch()?;
|
||||||
git::push(
|
repository.push(&self.repo_details, branch_name, to_commit, force)
|
||||||
repository,
|
|
||||||
&self.repo_details,
|
|
||||||
branch_name,
|
|
||||||
to_commit,
|
|
||||||
force,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn commit_status(&self, commit: &git::Commit) -> gitforge::CommitStatus {
|
async fn commit_status(&self, commit: &git::Commit) -> gitforge::CommitStatus {
|
||||||
|
@ -130,12 +130,12 @@ impl super::ForgeLike for ForgeJoEnv {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repo_clone(&self, gitdir: GitDir) -> Result<Repository, git::repository::Error> {
|
fn repo_clone(&self, gitdir: GitDir) -> Result<OpenRepository, git::repository::Error> {
|
||||||
let repository = if !gitdir.exists() {
|
let repository = if !gitdir.exists() {
|
||||||
info!("Local copy not found - cloning...");
|
info!("Local copy not found - cloning...");
|
||||||
Repository::clone(&self.repo_details)?
|
self.repo.git_clone(&self.repo_details)?
|
||||||
} else {
|
} else {
|
||||||
Repository::open(gitdir)?
|
self.repo.open(&gitdir)?
|
||||||
};
|
};
|
||||||
info!("Validating...");
|
info!("Validating...");
|
||||||
git::validate(&repository, &self.repo_details)
|
git::validate(&repository, &self.repo_details)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
use git::OpenRepository;
|
||||||
use git_next_config::{BranchName, GitDir, RepoConfig};
|
use git_next_config::{BranchName, GitDir, RepoConfig};
|
||||||
use git_next_git::{self as git, GitRef, Repository};
|
use git_next_git::{self as git, GitRef};
|
||||||
|
|
||||||
use crate::{actors::repo::RepoActor, gitforge, types::MessageToken};
|
use crate::{actors::repo::RepoActor, gitforge, types::MessageToken};
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ impl super::ForgeLike for MockForgeEnv {
|
||||||
|
|
||||||
async fn branches_validate_positions(
|
async fn branches_validate_positions(
|
||||||
&self,
|
&self,
|
||||||
_repository: Repository,
|
_repository: OpenRepository,
|
||||||
_repo_config: RepoConfig,
|
_repo_config: RepoConfig,
|
||||||
_addr: actix::prelude::Addr<RepoActor>,
|
_addr: actix::prelude::Addr<RepoActor>,
|
||||||
_message_token: MessageToken,
|
_message_token: MessageToken,
|
||||||
|
@ -41,7 +42,7 @@ impl super::ForgeLike for MockForgeEnv {
|
||||||
|
|
||||||
fn branch_reset(
|
fn branch_reset(
|
||||||
&self,
|
&self,
|
||||||
_repository: &Repository,
|
_repository: &OpenRepository,
|
||||||
_branch_name: BranchName,
|
_branch_name: BranchName,
|
||||||
_to_commit: GitRef,
|
_to_commit: GitRef,
|
||||||
_force: git::push::Force,
|
_force: git::push::Force,
|
||||||
|
@ -53,7 +54,7 @@ impl super::ForgeLike for MockForgeEnv {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repo_clone(&self, _gitdir: GitDir) -> Result<Repository, git::repository::Error> {
|
fn repo_clone(&self, _gitdir: GitDir) -> Result<OpenRepository, git::repository::Error> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use git::OpenRepository;
|
||||||
use git_next_config::{BranchName, GitDir, RepoConfig};
|
use git_next_config::{BranchName, GitDir, RepoConfig};
|
||||||
use git_next_git::{self as git, GitRef, RepoDetails, Repository};
|
use git_next_git::{self as git, GitRef, RepoDetails};
|
||||||
use kxio::network::Network;
|
use kxio::network::Network;
|
||||||
|
|
||||||
#[cfg(feature = "forgejo")]
|
#[cfg(feature = "forgejo")]
|
||||||
|
@ -38,7 +39,7 @@ pub trait ForgeLike {
|
||||||
/// positions as needed.
|
/// positions as needed.
|
||||||
async fn branches_validate_positions(
|
async fn branches_validate_positions(
|
||||||
&self,
|
&self,
|
||||||
repository: Repository,
|
repository: OpenRepository,
|
||||||
repo_config: RepoConfig,
|
repo_config: RepoConfig,
|
||||||
addr: actix::prelude::Addr<super::actors::repo::RepoActor>,
|
addr: actix::prelude::Addr<super::actors::repo::RepoActor>,
|
||||||
message_token: MessageToken,
|
message_token: MessageToken,
|
||||||
|
@ -47,7 +48,7 @@ pub trait ForgeLike {
|
||||||
/// Moves a branch to a new commit.
|
/// Moves a branch to a new commit.
|
||||||
fn branch_reset(
|
fn branch_reset(
|
||||||
&self,
|
&self,
|
||||||
repository: &Repository,
|
repository: &OpenRepository,
|
||||||
branch_name: BranchName,
|
branch_name: BranchName,
|
||||||
to_commit: GitRef,
|
to_commit: GitRef,
|
||||||
force: git::push::Force,
|
force: git::push::Force,
|
||||||
|
@ -57,7 +58,7 @@ pub trait ForgeLike {
|
||||||
async fn commit_status(&self, commit: &git::Commit) -> CommitStatus;
|
async fn commit_status(&self, commit: &git::Commit) -> CommitStatus;
|
||||||
|
|
||||||
/// Clones a repo to disk.
|
/// Clones a repo to disk.
|
||||||
fn repo_clone(&self, gitdir: GitDir) -> Result<Repository, git::repository::Error>;
|
fn repo_clone(&self, gitdir: GitDir) -> Result<OpenRepository, git::repository::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -74,8 +75,12 @@ impl Forge {
|
||||||
Self::Mock(mock_forge::MockForgeEnv::new())
|
Self::Mock(mock_forge::MockForgeEnv::new())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "forgejo")]
|
#[cfg(feature = "forgejo")]
|
||||||
pub const fn new_forgejo(repo_details: RepoDetails, net: Network) -> Self {
|
pub const fn new_forgejo(
|
||||||
Self::ForgeJo(forgejo::ForgeJoEnv::new(repo_details, net))
|
repo_details: RepoDetails,
|
||||||
|
net: Network,
|
||||||
|
repo: git::Repository,
|
||||||
|
) -> Self {
|
||||||
|
Self::ForgeJo(forgejo::ForgeJoEnv::new(repo_details, net, repo))
|
||||||
}
|
}
|
||||||
#[cfg(feature = "github")]
|
#[cfg(feature = "github")]
|
||||||
pub const fn new_github(net: Network) -> Self {
|
pub const fn new_github(net: Network) -> Self {
|
||||||
|
|
|
@ -13,6 +13,7 @@ fn test_name() {
|
||||||
panic!("fs")
|
panic!("fs")
|
||||||
};
|
};
|
||||||
let net = Network::new_mock();
|
let net = Network::new_mock();
|
||||||
|
let repo = git::repository::mock();
|
||||||
let repo_details = common::repo_details(
|
let repo_details = common::repo_details(
|
||||||
1,
|
1,
|
||||||
Generation::new(),
|
Generation::new(),
|
||||||
|
@ -20,7 +21,7 @@ fn test_name() {
|
||||||
Some(common::repo_config(1, RepoConfigSource::Repo)),
|
Some(common::repo_config(1, RepoConfigSource::Repo)),
|
||||||
GitDir::new(fs.base()),
|
GitDir::new(fs.base()),
|
||||||
);
|
);
|
||||||
let forge = Forge::new_forgejo(repo_details, net);
|
let forge = Forge::new_forgejo(repo_details, net, repo);
|
||||||
assert_eq!(forge.name(), "forgejo");
|
assert_eq!(forge.name(), "forgejo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ async fn test_branches_get() {
|
||||||
let body = include_str!("./data-forgejo-branches-get.json");
|
let body = include_str!("./data-forgejo-branches-get.json");
|
||||||
net.add_get_response(&url, StatusCode::OK, body);
|
net.add_get_response(&url, StatusCode::OK, body);
|
||||||
let net = Network::from(net);
|
let net = Network::from(net);
|
||||||
|
let repo = git::repository::mock();
|
||||||
|
|
||||||
let repo_details = common::repo_details(
|
let repo_details = common::repo_details(
|
||||||
1,
|
1,
|
||||||
|
@ -48,7 +50,7 @@ async fn test_branches_get() {
|
||||||
GitDir::new(fs.base()),
|
GitDir::new(fs.base()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let forge = Forge::new_forgejo(repo_details, net.clone());
|
let forge = Forge::new_forgejo(repo_details, net.clone(), repo);
|
||||||
|
|
||||||
let_assert!(Ok(branches) = forge.branches_get_all().await);
|
let_assert!(Ok(branches) = forge.branches_get_all().await);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub mod types;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
use git_next_git::Repository;
|
||||||
use kxio::{fs::FileSystem, network::Network};
|
use kxio::{fs::FileSystem, network::Network};
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -38,11 +39,11 @@ pub fn init(fs: FileSystem) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(fs: FileSystem, net: Network) {
|
pub async fn start(fs: FileSystem, net: Network, repo: Repository) {
|
||||||
init_logging();
|
init_logging();
|
||||||
|
|
||||||
info!("Starting Server...");
|
info!("Starting Server...");
|
||||||
let server = Server::new(fs.clone(), net.clone()).start();
|
let server = Server::new(fs.clone(), net.clone(), repo).start();
|
||||||
server.do_send(FileUpdated);
|
server.do_send(FileUpdated);
|
||||||
|
|
||||||
info!("Starting File Watcher...");
|
info!("Starting File Watcher...");
|
||||||
|
|
Loading…
Reference in a new issue