mirror of
https://github.com/qwjyh/xdbm
synced 2024-11-22 14:50:12 +09:00
change init command & add integration test
- now need to specify device name via cmd arg - can use private repository with ssh key or ssh-agent - adding integration test utility crates
This commit is contained in:
parent
9935f79920
commit
4283e1e98a
8 changed files with 387 additions and 59 deletions
207
Cargo.lock
generated
207
Cargo.lock
generated
|
@ -65,6 +65,36 @@ version = "1.0.75"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assert_cmd"
|
||||||
|
version = "2.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"bstr",
|
||||||
|
"doc-comment",
|
||||||
|
"predicates",
|
||||||
|
"predicates-core",
|
||||||
|
"predicates-tree",
|
||||||
|
"wait-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assert_fs"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2cd762e110c8ed629b11b6cde59458cc1c71de78ebbcc30099fc8e0403a2a2ec"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"doc-comment",
|
||||||
|
"globwalk",
|
||||||
|
"predicates",
|
||||||
|
"predicates-core",
|
||||||
|
"predicates-tree",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -83,6 +113,17 @@ version = "2.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "1.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byte-unit"
|
name = "byte-unit"
|
||||||
version = "4.0.19"
|
version = "4.0.19"
|
||||||
|
@ -229,6 +270,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "difflib"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "5.0.1"
|
version = "5.0.1"
|
||||||
|
@ -250,6 +297,12 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.16"
|
version = "1.0.16"
|
||||||
|
@ -291,6 +344,21 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "float-cmp"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
@ -326,6 +394,30 @@ dependencies = [
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "globset"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"bstr",
|
||||||
|
"log",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "globwalk"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"ignore",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
|
@ -360,6 +452,22 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ignore"
|
||||||
|
version = "0.4.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"globset",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"same-file",
|
||||||
|
"walkdir",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -499,9 +607,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.6.4"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
|
@ -533,6 +641,12 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "normalize-line-endings"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ntapi"
|
name = "ntapi"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -542,6 +656,15 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.18.0"
|
version = "1.18.0"
|
||||||
|
@ -613,6 +736,36 @@ version = "0.3.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "predicates"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"difflib",
|
||||||
|
"float-cmp",
|
||||||
|
"normalize-line-endings",
|
||||||
|
"predicates-core",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "predicates-core"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "predicates-tree"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
|
||||||
|
dependencies = [
|
||||||
|
"predicates-core",
|
||||||
|
"termtree",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.70"
|
version = "1.0.70"
|
||||||
|
@ -719,6 +872,15 @@ version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -827,6 +989,19 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"redox_syscall",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -836,6 +1011,12 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termtree"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.50"
|
version = "1.0.50"
|
||||||
|
@ -939,6 +1120,25 @@ version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"same-file",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -1113,6 +1313,8 @@ name = "xdbm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"assert_cmd",
|
||||||
|
"assert_fs",
|
||||||
"byte-unit",
|
"byte-unit",
|
||||||
"clap",
|
"clap",
|
||||||
"clap-verbosity-flag",
|
"clap-verbosity-flag",
|
||||||
|
@ -1122,6 +1324,7 @@ dependencies = [
|
||||||
"inquire",
|
"inquire",
|
||||||
"log",
|
"log",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
|
"predicates",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
|
|
|
@ -20,3 +20,8 @@ byte-unit = "4.0.19"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
pathdiff = "0.2.1"
|
pathdiff = "0.2.1"
|
||||||
unicode-width = "0.1.11"
|
unicode-width = "0.1.11"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
assert_cmd = "2.0.14"
|
||||||
|
assert_fs = "1.1.1"
|
||||||
|
predicates = "3.1.0"
|
||||||
|
|
11
README.md
11
README.md
|
@ -1,4 +1,13 @@
|
||||||
# TODO:
|
# TODO:
|
||||||
- [ ] split subcommands to functions
|
- [x] split subcommands to functions
|
||||||
|
- [ ] write test for init subcommand
|
||||||
|
- [ ] write test with existing repo
|
||||||
|
- [ ] with ssh credential
|
||||||
|
- [ ] ssh-agent
|
||||||
|
- [ ] specify key
|
||||||
|
- [ ] add sync subcommand
|
||||||
|
- [ ] add check subcommand
|
||||||
- [ ] reorganize cmd option for storage
|
- [ ] reorganize cmd option for storage
|
||||||
- [ ] use subcommand
|
- [ ] use subcommand
|
||||||
|
|
||||||
|
<!-- vim: set sw=2 ts=2: -->
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::PathBuf;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use clap_verbosity_flag::Verbosity;
|
use clap_verbosity_flag::Verbosity;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
pub(crate) struct Cli {
|
pub(crate) struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
|
@ -20,13 +20,21 @@ pub(crate) struct Cli {
|
||||||
pub(crate) verbose: Verbosity,
|
pub(crate) verbose: Verbosity,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub(crate) enum Commands {
|
pub(crate) enum Commands {
|
||||||
/// Initialize for this device.
|
/// Initialize for this device.
|
||||||
/// Provide `repo_url` to use existing repository, otherwise this device will be configured as the
|
|
||||||
/// first device.
|
|
||||||
Init {
|
Init {
|
||||||
|
/// Name for this device
|
||||||
|
device_name: String,
|
||||||
|
/// Url for existing repository. Empty if init for the first time.
|
||||||
|
#[arg(short, long)]
|
||||||
repo_url: Option<String>, // url?
|
repo_url: Option<String>, // url?
|
||||||
|
/// Whether to use ssh-agent
|
||||||
|
#[arg(long)]
|
||||||
|
use_sshagent: bool,
|
||||||
|
/// Manually specify ssh key
|
||||||
|
#[arg(long)]
|
||||||
|
ssh_key: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Manage storages.
|
/// Manage storages.
|
||||||
|
@ -42,14 +50,14 @@ pub(crate) enum Commands {
|
||||||
Check {},
|
Check {},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args, Debug)]
|
||||||
#[command(args_conflicts_with_subcommands = true)]
|
#[command(args_conflicts_with_subcommands = true)]
|
||||||
pub(crate) struct StorageArgs {
|
pub(crate) struct StorageArgs {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub(crate) command: StorageCommands,
|
pub(crate) command: StorageCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub(crate) enum StorageCommands {
|
pub(crate) enum StorageCommands {
|
||||||
/// Add new storage.
|
/// Add new storage.
|
||||||
Add {
|
Add {
|
||||||
|
|
|
@ -1,24 +1,91 @@
|
||||||
//! Init subcommand.
|
//! Init subcommand.
|
||||||
//! Initialize xdbm for the device.
|
//! Initialize xdbm for the device.
|
||||||
|
|
||||||
use crate::{
|
use crate::{add_and_commit, full_status, get_devices, write_devices, Device, DEVICESFILE};
|
||||||
add_and_commit, full_status, get_devices, set_device_name, write_devices, Device, DEVICESFILE,
|
use anyhow::{anyhow, Context, Ok, Result};
|
||||||
};
|
use core::panic;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use git2::{Cred, RemoteCallbacks, Repository};
|
||||||
use git2::Repository;
|
use inquire::Password;
|
||||||
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
use std::path::{self, Path};
|
use std::path::{self, Path, PathBuf};
|
||||||
|
|
||||||
pub(crate) fn cmd_init(repo_url: Option<String>, config_dir: &path::PathBuf) -> Result<()> {
|
fn clone_repo(
|
||||||
let is_first_device: bool;
|
repo_url: &String,
|
||||||
|
use_sshagent: bool,
|
||||||
|
ssh_key: Option<PathBuf>,
|
||||||
|
config_dir: &path::PathBuf,
|
||||||
|
) -> Result<Repository> {
|
||||||
|
// dont use credentials
|
||||||
|
if ssh_key.is_none() && !use_sshagent {
|
||||||
|
info!("No authentication will be used.");
|
||||||
|
info!("Use either ssh_key or ssh-agent to access private repository");
|
||||||
|
return Ok(Repository::clone(&repo_url, &config_dir)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
// using credentials
|
||||||
|
let mut callbacks = RemoteCallbacks::new();
|
||||||
|
callbacks.credentials(|_url, username_from_url, _allowed_types| {
|
||||||
|
if let Some(key) = &ssh_key {
|
||||||
|
info!("Using provided ssh key to access the repository");
|
||||||
|
let passwd = match Password::new("SSH passphrase").prompt() {
|
||||||
|
std::result::Result::Ok(s) => Some(s),
|
||||||
|
Err(err) => {
|
||||||
|
error!("Failed to get ssh passphrase: {:?}", err);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Cred::ssh_key(
|
||||||
|
username_from_url
|
||||||
|
.context("No username found from the url")
|
||||||
|
.unwrap(),
|
||||||
|
None,
|
||||||
|
&key as &Path,
|
||||||
|
passwd.as_deref(),
|
||||||
|
)
|
||||||
|
} else if use_sshagent {
|
||||||
|
// use ssh agent
|
||||||
|
info!("Using ssh agent to access the repository");
|
||||||
|
Cred::ssh_key_from_agent(
|
||||||
|
username_from_url
|
||||||
|
.context("No username found from the url")
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
error!("no ssh_key and use_sshagent");
|
||||||
|
panic!("This option must be unreachable.")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// fetch options
|
||||||
|
let mut fo = git2::FetchOptions::new();
|
||||||
|
fo.remote_callbacks(callbacks);
|
||||||
|
|
||||||
|
let mut builder = git2::build::RepoBuilder::new();
|
||||||
|
builder.fetch_options(fo);
|
||||||
|
|
||||||
|
Ok(builder.clone(&repo_url, config_dir)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn cmd_init(
|
||||||
|
device_name: String,
|
||||||
|
repo_url: Option<String>,
|
||||||
|
use_sshagent: bool,
|
||||||
|
ssh_key: Option<PathBuf>,
|
||||||
|
config_dir: &path::PathBuf,
|
||||||
|
) -> Result<()> {
|
||||||
|
// validate device name
|
||||||
|
if device_name.chars().count() == 0 {
|
||||||
|
log::error!("Device name cannnot by empty");
|
||||||
|
return Err(anyhow!("Device name is empty"));
|
||||||
|
}
|
||||||
// get repo or initialize it
|
// get repo or initialize it
|
||||||
let repo = match repo_url {
|
let (is_first_device, repo) = match repo_url {
|
||||||
Some(repo_url) => {
|
Some(repo_url) => {
|
||||||
trace!("repo: {}", repo_url);
|
trace!("repo: {}", repo_url);
|
||||||
let repo = Repository::clone(&repo_url, &config_dir)?;
|
let repo = clone_repo(&repo_url, use_sshagent, ssh_key, config_dir)?;
|
||||||
is_first_device = false;
|
(false, repo)
|
||||||
repo
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
trace!("No repo provided");
|
trace!("No repo provided");
|
||||||
|
@ -37,14 +104,15 @@ pub(crate) fn cmd_init(repo_url: Option<String>, config_dir: &path::PathBuf) ->
|
||||||
add_and_commit(&repo, Path::new(".gitignore"), "Add devname to gitignore.")?;
|
add_and_commit(&repo, Path::new(".gitignore"), "Add devname to gitignore.")?;
|
||||||
full_status(&repo)?;
|
full_status(&repo)?;
|
||||||
}
|
}
|
||||||
is_first_device = true;
|
(true, repo)
|
||||||
repo
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
full_status(&repo)?;
|
full_status(&repo)?;
|
||||||
|
|
||||||
// set device name
|
// set device name
|
||||||
let device = set_device_name()?;
|
// let device = set_device_name()?;
|
||||||
|
let device = Device::new(device_name);
|
||||||
|
trace!("Device information: {:?}", device);
|
||||||
|
|
||||||
// save devname
|
// save devname
|
||||||
let devname_path = &config_dir.join("devname");
|
let devname_path = &config_dir.join("devname");
|
||||||
|
|
|
@ -87,7 +87,8 @@ pub fn get_device(config_dir: &Path) -> Result<Device> {
|
||||||
/// Get `Vec<Device>` from yaml file in `config_dir`.
|
/// Get `Vec<Device>` from yaml file in `config_dir`.
|
||||||
pub fn get_devices(config_dir: &Path) -> Result<Vec<Device>> {
|
pub fn get_devices(config_dir: &Path) -> Result<Vec<Device>> {
|
||||||
trace!("get_devices");
|
trace!("get_devices");
|
||||||
let f = File::open(config_dir.join(DEVICESFILE))?;
|
let f =
|
||||||
|
File::open(config_dir.join(DEVICESFILE)).context(format!("{} not found", DEVICESFILE))?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
let yaml: Vec<Device> =
|
let yaml: Vec<Device> =
|
||||||
serde_yaml::from_reader(reader).context("Failed to parse devices.yml")?;
|
serde_yaml::from_reader(reader).context("Failed to parse devices.yml")?;
|
||||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -45,11 +45,13 @@ fn main() -> Result<()> {
|
||||||
.filter_level(cli.verbose.log_level_filter())
|
.filter_level(cli.verbose.log_level_filter())
|
||||||
.init();
|
.init();
|
||||||
trace!("Start logging...");
|
trace!("Start logging...");
|
||||||
|
trace!("args: {:?}", cli);
|
||||||
|
|
||||||
let config_dir: std::path::PathBuf = match cli.config_dir {
|
let config_dir: std::path::PathBuf = match cli.config_dir {
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => {
|
None => {
|
||||||
let mut config_dir = dirs::config_local_dir().context("Failed to get default config dir.")?;
|
let mut config_dir =
|
||||||
|
dirs::config_local_dir().context("Failed to get default config dir.")?;
|
||||||
config_dir.push("xdbm");
|
config_dir.push("xdbm");
|
||||||
config_dir
|
config_dir
|
||||||
}
|
}
|
||||||
|
@ -57,7 +59,12 @@ fn main() -> Result<()> {
|
||||||
trace!("Config dir: {:?}", config_dir);
|
trace!("Config dir: {:?}", config_dir);
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::Init { repo_url } => cmd_init::cmd_init(repo_url, &config_dir)?,
|
Commands::Init {
|
||||||
|
device_name,
|
||||||
|
repo_url,
|
||||||
|
use_sshagent,
|
||||||
|
ssh_key,
|
||||||
|
} => cmd_init::cmd_init(device_name, repo_url, use_sshagent, ssh_key, &config_dir)?,
|
||||||
Commands::Storage(storage) => {
|
Commands::Storage(storage) => {
|
||||||
let repo = Repository::open(&config_dir).context(
|
let repo = Repository::open(&config_dir).context(
|
||||||
"Repository doesn't exist on the config path. Please run init to initialize the repository.",
|
"Repository doesn't exist on the config path. Please run init to initialize the repository.",
|
||||||
|
@ -98,38 +105,6 @@ fn main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set device name interactively.
|
|
||||||
fn set_device_name() -> Result<Device> {
|
|
||||||
let validator = |input: &str| {
|
|
||||||
if input.chars().count() == 0 {
|
|
||||||
Ok(Validation::Invalid("Need at least 1 character.".into()))
|
|
||||||
} else {
|
|
||||||
Ok(Validation::Valid)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let device_name = Text::new("Provide name for this device:")
|
|
||||||
.with_validator(validator)
|
|
||||||
.prompt();
|
|
||||||
|
|
||||||
let device_name = match device_name {
|
|
||||||
Ok(device_name) => {
|
|
||||||
println!("device name: {}", device_name);
|
|
||||||
device_name
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
println!("Error {}", err);
|
|
||||||
return Err(anyhow!(err));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let device = Device::new(device_name);
|
|
||||||
trace!("Device information: {:?}", device);
|
|
||||||
trace!("Serialized: \n{}", serde_yaml::to_string(&device).unwrap());
|
|
||||||
|
|
||||||
return Ok(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ask_unique_name(storages: &HashMap<String, Storage>, target: String) -> Result<String> {
|
fn ask_unique_name(storages: &HashMap<String, Storage>, target: String) -> Result<String> {
|
||||||
let mut disk_name = String::new();
|
let mut disk_name = String::new();
|
||||||
loop {
|
loop {
|
||||||
|
|
59
tests/cli.rs
Normal file
59
tests/cli.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use assert_cmd::prelude::*;
|
||||||
|
use assert_fs::prelude::*;
|
||||||
|
|
||||||
|
mod cmd_init {
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
use assert_cmd::{cargo::CommandCargoExt, Command};
|
||||||
|
use predicates::prelude::predicate;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_with_tmpdir() -> Result<()> {
|
||||||
|
let config_dir = assert_fs::TempDir::new()?;
|
||||||
|
let mut cmd = Command::cargo_bin("xdbm")?;
|
||||||
|
cmd.arg("-c")
|
||||||
|
.arg(config_dir.path())
|
||||||
|
.arg("init")
|
||||||
|
.arg("testdev");
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(""));
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_to_string(config_dir.path().join("devname"))?,
|
||||||
|
"testdev\n"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_with_existing_repo() -> Result<()> {
|
||||||
|
// 1st device
|
||||||
|
let config_dir_1 = assert_fs::TempDir::new()?;
|
||||||
|
let mut cmd1 = Command::cargo_bin("xdbm")?;
|
||||||
|
cmd1.arg("-c")
|
||||||
|
.arg(config_dir_1.path())
|
||||||
|
.arg("init")
|
||||||
|
.arg("first");
|
||||||
|
cmd1.assert().success().stdout(predicate::str::contains(""));
|
||||||
|
|
||||||
|
// 2nd device
|
||||||
|
let config_dir_2 = assert_fs::TempDir::new()?;
|
||||||
|
let mut cmd2 = Command::cargo_bin("xdbm")?;
|
||||||
|
cmd2.arg("-c")
|
||||||
|
.arg(config_dir_2.path())
|
||||||
|
.arg("init")
|
||||||
|
.arg("second")
|
||||||
|
.arg("-r")
|
||||||
|
.arg(config_dir_1.path());
|
||||||
|
cmd2.assert().success().stdout(predicate::str::contains(""));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_to_string(config_dir_2.path().join("devname"))?,
|
||||||
|
"second\n"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
std::fs::read_to_string(config_dir_2.path().join("devices.yml"))?.contains("first")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
std::fs::read_to_string(config_dir_2.path().join("devices.yml"))?.contains("second")
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue