mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
add a 'task sync' command using a copy of the test server
This commit is contained in:
parent
a81c84d7c7
commit
8f7e2e2790
5 changed files with 153 additions and 24 deletions
|
@ -1,7 +1,5 @@
|
|||
use clap::{App, ArgMatches};
|
||||
use failure::{Error, Fallible};
|
||||
use std::path::Path;
|
||||
use taskchampion::{taskstorage, Replica};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -12,6 +10,7 @@ mod gc;
|
|||
mod info;
|
||||
mod list;
|
||||
mod pending;
|
||||
mod sync;
|
||||
|
||||
/// Get a list of all subcommands in this crate
|
||||
pub(crate) fn subcommands() -> Vec<Box<dyn SubCommand>> {
|
||||
|
@ -21,6 +20,7 @@ pub(crate) fn subcommands() -> Vec<Box<dyn SubCommand>> {
|
|||
list::cmd(),
|
||||
pending::cmd(),
|
||||
info::cmd(),
|
||||
sync::cmd(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -54,24 +54,4 @@ pub(crate) trait SubCommandInvocation: std::fmt::Debug {
|
|||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
/// A command invocation contains all of the necessary regarding a single invocation of the CLI.
|
||||
#[derive(Debug)]
|
||||
pub struct CommandInvocation {
|
||||
pub(crate) subcommand: Box<dyn SubCommandInvocation>,
|
||||
}
|
||||
|
||||
impl CommandInvocation {
|
||||
pub(crate) fn new(subcommand: Box<dyn SubCommandInvocation>) -> Self {
|
||||
Self { subcommand }
|
||||
}
|
||||
|
||||
pub fn run(self) -> Fallible<()> {
|
||||
self.subcommand.run(&self)
|
||||
}
|
||||
|
||||
fn get_replica(&self) -> Replica {
|
||||
Replica::new(Box::new(
|
||||
taskstorage::KVStorage::new(Path::new("/tmp/tasks")).unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
pub use shared::CommandInvocation;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use clap::Arg;
|
||||
use failure::{format_err, Fallible};
|
||||
use taskchampion::{Replica, Task, Uuid};
|
||||
use std::path::Path;
|
||||
use taskchampion::{server, taskstorage, Replica, Task, Uuid};
|
||||
|
||||
pub(super) fn task_arg<'a>() -> Arg<'a, 'a> {
|
||||
Arg::with_name("task")
|
||||
|
@ -26,3 +27,31 @@ pub(super) fn get_task<S: AsRef<str>>(replica: &mut Replica, task_arg: S) -> Fal
|
|||
|
||||
Err(format_err!("Cannot interpret {:?} as a task", task_arg))
|
||||
}
|
||||
|
||||
/// A command invocation contains all of the necessary regarding a single invocation of the CLI.
|
||||
#[derive(Debug)]
|
||||
pub struct CommandInvocation {
|
||||
pub(crate) subcommand: Box<dyn super::SubCommandInvocation>,
|
||||
}
|
||||
|
||||
impl CommandInvocation {
|
||||
pub(crate) fn new(subcommand: Box<dyn super::SubCommandInvocation>) -> Self {
|
||||
Self { subcommand }
|
||||
}
|
||||
|
||||
pub fn run(self) -> Fallible<()> {
|
||||
self.subcommand.run(&self)
|
||||
}
|
||||
|
||||
// -- utilities for command invocations
|
||||
|
||||
pub(super) fn get_replica(&self) -> Replica {
|
||||
Replica::new(Box::new(
|
||||
taskstorage::KVStorage::new(Path::new("/tmp/tasks")).unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn get_server(&self) -> impl server::Server {
|
||||
server::LocalServer::new()
|
||||
}
|
||||
}
|
||||
|
|
39
cli/src/cmd/sync.rs
Normal file
39
cli/src/cmd/sync.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use clap::{App, ArgMatches, SubCommand as ClapSubCommand};
|
||||
use failure::Fallible;
|
||||
|
||||
use crate::cmd::{ArgMatchResult, CommandInvocation};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Invocation {}
|
||||
|
||||
define_subcommand! {
|
||||
fn decorate_app<'a>(&self, app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app.subcommand(ClapSubCommand::with_name("sync").about("sync with the server"))
|
||||
}
|
||||
|
||||
fn arg_match<'a>(&self, matches: &ArgMatches<'a>) -> ArgMatchResult {
|
||||
match matches.subcommand() {
|
||||
("sync", _) => ArgMatchResult::Ok(Box::new(Invocation {})),
|
||||
_ => ArgMatchResult::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subcommand_invocation! {
|
||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||
let mut replica = command.get_replica();
|
||||
let mut server = command.get_server();
|
||||
replica.sync(&mut server)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_command() {
|
||||
with_subcommand_invocation!(vec!["task", "sync"], |_inv| {});
|
||||
}
|
||||
}
|
79
taskchampion/src/server/local.rs
Normal file
79
taskchampion/src/server/local.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
use crate::server::{
|
||||
AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId, NO_VERSION_ID,
|
||||
};
|
||||
use failure::Fallible;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
struct Version {
|
||||
version_id: VersionId,
|
||||
parent_version_id: VersionId,
|
||||
history_segment: HistorySegment,
|
||||
}
|
||||
|
||||
pub struct LocalServer {
|
||||
latest_version_id: VersionId,
|
||||
// NOTE: indexed by parent_version_id!
|
||||
versions: HashMap<VersionId, Version>,
|
||||
}
|
||||
|
||||
impl LocalServer {
|
||||
/// A test server has no notion of clients, signatures, encryption, etc.
|
||||
pub fn new() -> LocalServer {
|
||||
LocalServer {
|
||||
latest_version_id: NO_VERSION_ID,
|
||||
versions: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Server for LocalServer {
|
||||
/// Add a new version. If the given version number is incorrect, this responds with the
|
||||
/// appropriate version and expects the caller to try again.
|
||||
fn add_version(
|
||||
&mut self,
|
||||
parent_version_id: VersionId,
|
||||
history_segment: HistorySegment,
|
||||
) -> Fallible<AddVersionResult> {
|
||||
// no client lookup
|
||||
// no signature validation
|
||||
|
||||
// check the parent_version_id for linearity
|
||||
if self.latest_version_id != NO_VERSION_ID {
|
||||
if parent_version_id != self.latest_version_id {
|
||||
return Ok(AddVersionResult::ExpectedParentVersion(
|
||||
self.latest_version_id,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// invent a new ID for this version
|
||||
let version_id = Uuid::new_v4();
|
||||
|
||||
self.versions.insert(
|
||||
parent_version_id,
|
||||
Version {
|
||||
version_id,
|
||||
parent_version_id,
|
||||
history_segment,
|
||||
},
|
||||
);
|
||||
self.latest_version_id = version_id;
|
||||
|
||||
Ok(AddVersionResult::Ok(version_id))
|
||||
}
|
||||
|
||||
/// Get a vector of all versions after `since_version`
|
||||
fn get_child_version(&self, parent_version_id: VersionId) -> Fallible<GetVersionResult> {
|
||||
if let Some(version) = self.versions.get(&parent_version_id) {
|
||||
Ok(GetVersionResult::Version {
|
||||
version_id: version.version_id,
|
||||
parent_version_id: version.parent_version_id,
|
||||
history_segment: version.history_segment.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(GetVersionResult::NoSuchVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
#[cfg(test)]
|
||||
pub(crate) mod test;
|
||||
|
||||
mod local;
|
||||
mod signing;
|
||||
mod types;
|
||||
|
||||
pub use local::LocalServer;
|
||||
pub use types::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue