mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Merge pull request #70 from djmitche/issue9
Support configuration of the cli
This commit is contained in:
commit
7a2857e814
20 changed files with 228 additions and 36 deletions
75
Cargo.lock
generated
75
Cargo.lock
generated
|
@ -580,6 +580,18 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "config"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"nom",
|
||||||
|
"serde",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const_fn"
|
name = "const_fn"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -710,6 +722,26 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "3.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"redox_users",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "discard"
|
name = "discard"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -1149,6 +1181,19 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lexical-core"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"ryu",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.80"
|
version = "0.2.80"
|
||||||
|
@ -1298,6 +1343,17 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "5.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
||||||
|
dependencies = [
|
||||||
|
"lexical-core",
|
||||||
|
"memchr",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "normalize-line-endings"
|
name = "normalize-line-endings"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -2041,6 +2097,12 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stdweb"
|
name = "stdweb"
|
||||||
version = "0.4.20"
|
version = "0.4.20"
|
||||||
|
@ -2141,6 +2203,8 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"clap",
|
"clap",
|
||||||
|
"config",
|
||||||
|
"dirs 3.0.1",
|
||||||
"failure",
|
"failure",
|
||||||
"predicates",
|
"predicates",
|
||||||
"prettytable-rs",
|
"prettytable-rs",
|
||||||
|
@ -2189,7 +2253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
|
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"dirs",
|
"dirs 1.0.5",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2687,3 +2751,12 @@ dependencies = [
|
||||||
"winapi 0.2.8",
|
"winapi 0.2.8",
|
||||||
"winapi-build",
|
"winapi-build",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
|
@ -9,6 +9,8 @@ clap = "^2.33.0"
|
||||||
taskchampion = { path = "../taskchampion" }
|
taskchampion = { path = "../taskchampion" }
|
||||||
failure = "^0.1.8"
|
failure = "^0.1.8"
|
||||||
prettytable-rs = "^0.8.0"
|
prettytable-rs = "^0.8.0"
|
||||||
|
config = { version="^0.10.1", default-features=false, features=["yaml"] }
|
||||||
|
dirs = "^3.0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "^1.0.1"
|
assert_cmd = "^1.0.1"
|
||||||
|
|
|
@ -38,7 +38,7 @@ define_subcommand! {
|
||||||
subcommand_invocation! {
|
subcommand_invocation! {
|
||||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||||
let t = command
|
let t = command
|
||||||
.get_replica()
|
.get_replica()?
|
||||||
.new_task(Status::Pending, self.description.clone())
|
.new_task(Status::Pending, self.description.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("added task {}", t.get_uuid());
|
println!("added task {}", t.get_uuid());
|
||||||
|
|
|
@ -20,7 +20,7 @@ define_subcommand! {
|
||||||
|
|
||||||
subcommand_invocation! {
|
subcommand_invocation! {
|
||||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||||
command.get_replica().gc()?;
|
command.get_replica()?.gc()?;
|
||||||
println!("garbage collected.");
|
println!("garbage collected.");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ define_subcommand! {
|
||||||
|
|
||||||
subcommand_invocation! {
|
subcommand_invocation! {
|
||||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||||
let mut replica = command.get_replica();
|
let mut replica = command.get_replica()?;
|
||||||
let task = shared::get_task(&mut replica, &self.task)?;
|
let task = shared::get_task(&mut replica, &self.task)?;
|
||||||
let uuid = task.get_uuid();
|
let uuid = task.get_uuid();
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ define_subcommand! {
|
||||||
|
|
||||||
subcommand_invocation! {
|
subcommand_invocation! {
|
||||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||||
let mut replica = command.get_replica();
|
let mut replica = command.get_replica()?;
|
||||||
let mut t = Table::new();
|
let mut t = Table::new();
|
||||||
t.set_format(table::format());
|
t.set_format(table::format());
|
||||||
t.set_titles(row![b->"id", b->"description"]);
|
t.set_titles(row![b->"id", b->"description"]);
|
||||||
|
|
|
@ -36,7 +36,7 @@ define_subcommand! {
|
||||||
|
|
||||||
subcommand_invocation! {
|
subcommand_invocation! {
|
||||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||||
let mut replica = command.get_replica();
|
let mut replica = command.get_replica()?;
|
||||||
let task = shared::get_task(&mut replica, &self.task)?;
|
let task = shared::get_task(&mut replica, &self.task)?;
|
||||||
|
|
||||||
let mut task = task.into_mut(&mut replica);
|
let mut task = task.into_mut(&mut replica);
|
||||||
|
|
|
@ -25,7 +25,7 @@ define_subcommand! {
|
||||||
|
|
||||||
subcommand_invocation! {
|
subcommand_invocation! {
|
||||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||||
let working_set = command.get_replica().working_set().unwrap();
|
let working_set = command.get_replica()?.working_set().unwrap();
|
||||||
let mut t = Table::new();
|
let mut t = Table::new();
|
||||||
t.set_format(table::format());
|
t.set_format(table::format());
|
||||||
t.set_titles(row![b->"id", b->"description"]);
|
t.set_titles(row![b->"id", b->"description"]);
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use crate::settings;
|
||||||
use clap::Arg;
|
use clap::Arg;
|
||||||
|
use config::{Config, ConfigError};
|
||||||
use failure::{format_err, Fallible};
|
use failure::{format_err, Fallible};
|
||||||
use std::env;
|
use std::cell::{Ref, RefCell};
|
||||||
use std::ffi::OsString;
|
use taskchampion::{server, Replica, ReplicaConfig, ServerConfig, Task, Uuid};
|
||||||
use taskchampion::{server, taskstorage, Replica, Task, Uuid};
|
|
||||||
|
|
||||||
pub(super) fn task_arg<'a>() -> Arg<'a, 'a> {
|
pub(super) fn task_arg<'a>() -> Arg<'a, 'a> {
|
||||||
Arg::with_name("task")
|
Arg::with_name("task")
|
||||||
|
@ -33,11 +34,15 @@ pub(super) fn get_task<S: AsRef<str>>(replica: &mut Replica, task_arg: S) -> Fal
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CommandInvocation {
|
pub struct CommandInvocation {
|
||||||
pub(crate) subcommand: Box<dyn super::SubCommandInvocation>,
|
pub(crate) subcommand: Box<dyn super::SubCommandInvocation>,
|
||||||
|
settings: RefCell<Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandInvocation {
|
impl CommandInvocation {
|
||||||
pub(crate) fn new(subcommand: Box<dyn super::SubCommandInvocation>) -> Self {
|
pub(crate) fn new(subcommand: Box<dyn super::SubCommandInvocation>) -> Self {
|
||||||
Self { subcommand }
|
Self {
|
||||||
|
subcommand,
|
||||||
|
settings: RefCell::new(Config::default()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self) -> Fallible<()> {
|
pub fn run(self) -> Fallible<()> {
|
||||||
|
@ -46,20 +51,34 @@ impl CommandInvocation {
|
||||||
|
|
||||||
// -- utilities for command invocations
|
// -- utilities for command invocations
|
||||||
|
|
||||||
pub(super) fn get_replica(&self) -> Replica {
|
pub(super) fn get_settings(&self) -> Fallible<Ref<Config>> {
|
||||||
// temporarily use $TASK_DB to locate the taskdb
|
{
|
||||||
let taskdb_dir = env::var_os("TASK_DB").unwrap_or_else(|| OsString::from("/tmp/tasks"));
|
// use the special `_loaded" config value to detect whether we have
|
||||||
Replica::new(Box::new(taskstorage::KVStorage::new(taskdb_dir).unwrap()))
|
// loaded the configuration yet
|
||||||
|
let mut settings = self.settings.borrow_mut();
|
||||||
|
if let Err(ConfigError::NotFound(_)) = settings.get_bool("_loaded") {
|
||||||
|
settings.merge(settings::read_settings()?)?;
|
||||||
|
settings.set("_loaded", true)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(self.settings.borrow())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_server(&self) -> Fallible<impl server::Server> {
|
pub(super) fn get_replica(&self) -> Fallible<Replica> {
|
||||||
// temporarily use $SYNC_SERVER_ORIGIN for the sync server
|
let settings = self.get_settings()?;
|
||||||
let sync_server_origin = env::var_os("SYNC_SERVER_ORIGIN")
|
let replica_config = ReplicaConfig {
|
||||||
.map(|osstr| osstr.into_string().unwrap())
|
taskdb_dir: settings.get_str("data_dir")?.into(),
|
||||||
.unwrap_or_else(|| String::from("http://localhost:8080"));
|
};
|
||||||
Ok(server::RemoteServer::new(
|
Ok(Replica::from_config(replica_config)?)
|
||||||
sync_server_origin,
|
}
|
||||||
Uuid::parse_str("d5b55cbd-9a82-4860-9a39-41b67893b22f").unwrap(),
|
|
||||||
))
|
pub(super) fn get_server(&self) -> Fallible<Box<dyn server::Server>> {
|
||||||
|
let settings = self.get_settings()?;
|
||||||
|
let client_id = settings.get_str("server_client_id")?;
|
||||||
|
let client_id = Uuid::parse_str(&client_id)?;
|
||||||
|
Ok(server::from_config(ServerConfig::Remote {
|
||||||
|
origin: settings.get_str("server_origin")?,
|
||||||
|
client_id,
|
||||||
|
})?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ define_subcommand! {
|
||||||
|
|
||||||
subcommand_invocation! {
|
subcommand_invocation! {
|
||||||
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
fn run(&self, command: &CommandInvocation) -> Fallible<()> {
|
||||||
let mut replica = command.get_replica();
|
let mut replica = command.get_replica()?;
|
||||||
let mut server = command.get_server()?;
|
let mut server = command.get_server()?;
|
||||||
replica.sync(&mut server)?;
|
replica.sync(&mut server)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -3,6 +3,7 @@ use failure::Fallible;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
|
||||||
mod cmd;
|
mod cmd;
|
||||||
|
pub(crate) mod settings;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
use cmd::ArgMatchResult;
|
use cmd::ArgMatchResult;
|
||||||
|
|
35
cli/src/settings.rs
Normal file
35
cli/src/settings.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use config::{Config, Environment, File, FileSourceFile};
|
||||||
|
use failure::Fallible;
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub(crate) fn read_settings() -> Fallible<Config> {
|
||||||
|
let mut settings = Config::default();
|
||||||
|
|
||||||
|
// set up defaults
|
||||||
|
if let Some(mut dir) = dirs::data_local_dir() {
|
||||||
|
dir.push("taskchampion");
|
||||||
|
settings.set_default(
|
||||||
|
"data_dir",
|
||||||
|
// the config crate does not support non-string paths
|
||||||
|
dir.to_str().expect("data_local_dir is not utf-8"),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load either from the path in TASKCHAMPION_CONFIG, or from CONFIG_DIR/taskchampion
|
||||||
|
if let Some(config_file) = env::var_os("TASKCHAMPION_CONFIG") {
|
||||||
|
let config_file: PathBuf = config_file.into();
|
||||||
|
let config_file: File<FileSourceFile> = config_file.into();
|
||||||
|
settings.merge(config_file.required(true))?;
|
||||||
|
env::remove_var("TASKCHAMPION_CONFIG");
|
||||||
|
} else if let Some(mut dir) = dirs::config_dir() {
|
||||||
|
dir.push("taskchampion");
|
||||||
|
let config_file: File<FileSourceFile> = dir.into();
|
||||||
|
settings.merge(config_file.required(false))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge environment variables
|
||||||
|
settings.merge(Environment::with_prefix("TASKCHAMPION"))?;
|
||||||
|
|
||||||
|
Ok(settings)
|
||||||
|
}
|
|
@ -9,12 +9,26 @@ Note that the `task` interface does not match that of TaskWarrior.
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
Temporarily, configuration is by environment variables.
|
The `task` command will work out-of-the-box with no configuration file, using default values.
|
||||||
The directory containing the replica's task data is given by `TASK_DB`, defaulting to `/tmp/tasks`.
|
|
||||||
the origin of the sync server is given by `SYNC_SERVER_ORIGIN`, defaulting to `http://localhost:8080`.
|
Configuration is read from `taskchampion.yaml` in your config directory.
|
||||||
|
On Linux systems, that directory is `~/.config`.
|
||||||
|
On OS X, it's `~/Library/Preferences`.
|
||||||
|
On Windows, it's `AppData/Roaming` in your home directory.
|
||||||
|
The path can be overridden by setting `$TASKCHAMPION_CONFIG`.
|
||||||
|
|
||||||
|
Individual configuration parameters can be overridden by environemnt variables, converted to upper-case and prefixed with `TASKCHAMPION_`, e.g., `TASKCHAMPION_DATA_DIR`.
|
||||||
|
Nested configuration parameters cannot be overridden by environment variables.
|
||||||
|
|
||||||
|
The following configuration parameters are available:
|
||||||
|
|
||||||
|
* `data_dir` - path to a directory containing the replica's task data (which will be created if necessary).
|
||||||
|
Default: `taskchampion` in the local data directory
|
||||||
|
* `server_origin` - Origin of the taskchampion sync server, e.g., `https://taskchampion.example.com`
|
||||||
|
* `server_client_id` - Client ID to identify this replica to the sync server (a UUID)
|
||||||
|
|
||||||
## `taskchampion-sync-server`
|
## `taskchampion-sync-server`
|
||||||
|
|
||||||
Run `taskchampion-sync-server` to start the sync server.
|
Run `taskchampion-sync-server` to start the sync server.
|
||||||
It serves on port 8080 on all interfaces, using an in-memory database (meaning that all data is lost when the process exits).
|
It serves on port 8080 on all interfaces, using an in-memory database (meaning that all data is lost when the process exits).
|
||||||
Requests for previously-unknown clients are automatically added.
|
Requests for previously-unknown clients automatically create the client.
|
||||||
|
|
26
taskchampion/src/config.rs
Normal file
26
taskchampion/src/config.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
/// The configuration required for a replica. Use with [`crate::Replica::from_config`].
|
||||||
|
pub struct ReplicaConfig {
|
||||||
|
/// Path containing the task DB.
|
||||||
|
pub taskdb_dir: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The configuration for a replica's access to a sync server. Use with
|
||||||
|
/// [`crate::server::from_config`].
|
||||||
|
pub enum ServerConfig {
|
||||||
|
/// A local task database, for situations with a single replica.
|
||||||
|
Local {
|
||||||
|
/// Path containing the server's DB
|
||||||
|
server_dir: PathBuf,
|
||||||
|
},
|
||||||
|
/// A remote taskchampion-sync-server instance
|
||||||
|
Remote {
|
||||||
|
/// Sync server "origin"; a URL with schema and hostname but no path or trailing `/`
|
||||||
|
origin: String,
|
||||||
|
|
||||||
|
/// Client ID to identify this replica to the server
|
||||||
|
client_id: Uuid,
|
||||||
|
},
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ for more information about the design and usage of the tool.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
mod config;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod replica;
|
mod replica;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
@ -31,6 +32,7 @@ mod taskdb;
|
||||||
pub mod taskstorage;
|
pub mod taskstorage;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
pub use config::{ReplicaConfig, ServerConfig};
|
||||||
pub use replica::Replica;
|
pub use replica::Replica;
|
||||||
pub use task::Priority;
|
pub use task::Priority;
|
||||||
pub use task::Status;
|
pub use task::Status;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use crate::config::ReplicaConfig;
|
||||||
use crate::errors::Error;
|
use crate::errors::Error;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use crate::task::{Status, Task};
|
use crate::task::{Status, Task};
|
||||||
use crate::taskdb::TaskDB;
|
use crate::taskdb::TaskDB;
|
||||||
use crate::taskstorage::{Operation, TaskMap, TaskStorage};
|
use crate::taskstorage::{KVStorage, Operation, TaskMap, TaskStorage};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use failure::Fallible;
|
use failure::Fallible;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -21,6 +22,11 @@ impl Replica {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_config(config: ReplicaConfig) -> Fallible<Replica> {
|
||||||
|
let storage = Box::new(KVStorage::new(config.taskdb_dir)?);
|
||||||
|
Ok(Replica::new(storage))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn new_inmemory() -> Replica {
|
pub fn new_inmemory() -> Replica {
|
||||||
Replica::new(Box::new(crate::taskstorage::InMemoryStorage::new()))
|
Replica::new(Box::new(crate::taskstorage::InMemoryStorage::new()))
|
||||||
|
@ -140,7 +146,7 @@ impl Replica {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronize this replica against the given server.
|
/// Synchronize this replica against the given server.
|
||||||
pub fn sync(&mut self, server: &mut dyn Server) -> Fallible<()> {
|
pub fn sync(&mut self, server: &mut Box<dyn Server>) -> Fallible<()> {
|
||||||
self.taskdb.sync(server)
|
self.taskdb.sync(server)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub struct LocalServer<'t> {
|
||||||
|
|
||||||
impl<'t> LocalServer<'t> {
|
impl<'t> LocalServer<'t> {
|
||||||
/// A test server has no notion of clients, signatures, encryption, etc.
|
/// A test server has no notion of clients, signatures, encryption, etc.
|
||||||
pub fn new(directory: &Path) -> Fallible<LocalServer> {
|
pub fn new<P: AsRef<Path>>(directory: P) -> Fallible<LocalServer<'t>> {
|
||||||
let mut config = Config::default(directory);
|
let mut config = Config::default(directory);
|
||||||
config.bucket("versions", None);
|
config.bucket("versions", None);
|
||||||
config.bucket("numbers", None);
|
config.bucket("numbers", None);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use crate::ServerConfig;
|
||||||
|
use failure::Fallible;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test;
|
pub(crate) mod test;
|
||||||
|
|
||||||
|
@ -8,3 +11,12 @@ mod types;
|
||||||
pub use local::LocalServer;
|
pub use local::LocalServer;
|
||||||
pub use remote::RemoteServer;
|
pub use remote::RemoteServer;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
|
pub fn from_config(config: ServerConfig) -> Fallible<Box<dyn Server>> {
|
||||||
|
Ok(match config {
|
||||||
|
ServerConfig::Local { server_dir } => Box::new(LocalServer::new(server_dir)?),
|
||||||
|
ServerConfig::Remote { origin, client_id } => {
|
||||||
|
Box::new(RemoteServer::new(origin, client_id))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ impl TaskDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sync to the given server, pulling remote changes and pushing local changes.
|
/// Sync to the given server, pulling remote changes and pushing local changes.
|
||||||
pub fn sync(&mut self, server: &mut dyn Server) -> Fallible<()> {
|
pub fn sync(&mut self, server: &mut Box<dyn Server>) -> Fallible<()> {
|
||||||
let mut txn = self.storage.txn()?;
|
let mut txn = self.storage.txn()?;
|
||||||
|
|
||||||
// retry synchronizing until the server accepts our version (this allows for races between
|
// retry synchronizing until the server accepts our version (this allows for races between
|
||||||
|
@ -542,7 +542,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sync() {
|
fn test_sync() {
|
||||||
let mut server = TestServer::new();
|
let mut server: Box<dyn Server> = Box::new(TestServer::new());
|
||||||
|
|
||||||
let mut db1 = newdb();
|
let mut db1 = newdb();
|
||||||
db1.sync(&mut server).unwrap();
|
db1.sync(&mut server).unwrap();
|
||||||
|
@ -602,7 +602,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sync_create_delete() {
|
fn test_sync_create_delete() {
|
||||||
let mut server = TestServer::new();
|
let mut server: Box<dyn Server> = Box::new(TestServer::new());
|
||||||
|
|
||||||
let mut db1 = newdb();
|
let mut db1 = newdb();
|
||||||
db1.sync(&mut server).unwrap();
|
db1.sync(&mut server).unwrap();
|
||||||
|
@ -692,7 +692,7 @@ mod tests {
|
||||||
// and delete operations that results in a task existing in one TaskDB but not existing in
|
// and delete operations that results in a task existing in one TaskDB but not existing in
|
||||||
// another. So, the generated sequences focus on a single task UUID.
|
// another. So, the generated sequences focus on a single task UUID.
|
||||||
fn transform_sequences_of_operations(action_sequence in action_sequence_strategy()) {
|
fn transform_sequences_of_operations(action_sequence in action_sequence_strategy()) {
|
||||||
let mut server = TestServer::new();
|
let mut server: Box<dyn Server> = Box::new(TestServer::new());
|
||||||
let mut dbs = [newdb(), newdb(), newdb()];
|
let mut dbs = [newdb(), newdb(), newdb()];
|
||||||
|
|
||||||
for (action, db) in action_sequence {
|
for (action, db) in action_sequence {
|
||||||
|
|
|
@ -2,11 +2,13 @@ use failure::Fallible;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
mod inmemory;
|
mod inmemory;
|
||||||
mod kv;
|
mod kv;
|
||||||
mod operation;
|
mod operation;
|
||||||
|
|
||||||
pub use self::kv::KVStorage;
|
pub use self::kv::KVStorage;
|
||||||
|
#[cfg(test)]
|
||||||
pub use inmemory::InMemoryStorage;
|
pub use inmemory::InMemoryStorage;
|
||||||
|
|
||||||
pub use operation::Operation;
|
pub use operation::Operation;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue