Compare commits
8 Commits
7719e27fe8
...
79f83b71de
Author | SHA1 | Date | |
---|---|---|---|
|
79f83b71de | ||
|
639f18426f | ||
|
9859f26604 | ||
|
1217fe0480 | ||
|
cc916c0ed6 | ||
|
628c26ef81 | ||
|
cd0eee8b20 | ||
|
ef986305c0 |
15
.gitignore
vendored
15
.gitignore
vendored
@ -1,7 +1,10 @@
|
||||
*
|
||||
!/**/
|
||||
!*.rs
|
||||
!.gitignore
|
||||
!README.md
|
||||
!LICENSE
|
||||
|
||||
target
|
||||
*.test
|
||||
.env
|
||||
todo
|
||||
.nextsync
|
||||
.nextsyncignore
|
||||
test
|
||||
tests/nextcloud-docker-dev
|
||||
tests/data
|
||||
|
205
Cargo.lock
generated
205
Cargo.lock
generated
@ -64,6 +64,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
@ -111,7 +117,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"strsim",
|
||||
"textwrap 0.11.0",
|
||||
"unicode-width",
|
||||
@ -181,33 +187,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
@ -312,6 +304,17 @@ version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
@ -361,12 +364,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
@ -503,17 +500,6 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.1",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.7.2"
|
||||
@ -543,15 +529,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
version = "0.2.153"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@ -639,10 +625,12 @@ dependencies = [
|
||||
"indicatif",
|
||||
"lazy_static",
|
||||
"md5",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rpassword",
|
||||
"rust-crypto",
|
||||
"tempfile",
|
||||
"textwrap 0.13.4",
|
||||
"tokio",
|
||||
"xml-rs",
|
||||
@ -685,7 +673,7 @@ version = "0.10.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12df40a956736488b7b44fe79fe12d4f245bb5b3f5a1f6095e499760015be392"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@ -741,7 +729,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
@ -776,6 +764,12 @@ version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
@ -817,6 +811,27 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
@ -832,6 +847,15 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
@ -847,16 +871,7 @@ version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -958,16 +973,15 @@ checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.19"
|
||||
version = "0.38.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
|
||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.4.2",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -997,7 +1011,7 @@ version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -1102,15 +1116,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.5.0"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||
checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1484,6 +1497,15 @@ dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
@ -1514,6 +1536,21 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@ -1526,6 +1563,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
@ -1538,6 +1581,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
@ -1550,6 +1599,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
@ -1562,6 +1617,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
@ -1574,6 +1635,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@ -1586,6 +1653,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
@ -1598,6 +1671,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
|
@ -22,6 +22,8 @@ indicatif = "0.17.5"
|
||||
md5 = "0.7.0"
|
||||
futures-util = "0.3.28"
|
||||
rpassword = "7.2"
|
||||
rand = "0.8"
|
||||
tempfile = "3.10.0"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
@ -6,4 +6,6 @@ pub mod clone;
|
||||
pub mod push;
|
||||
pub mod config;
|
||||
pub mod remote_diff;
|
||||
pub mod remote;
|
||||
pub mod pull;
|
||||
pub mod credential;
|
||||
|
@ -1,16 +1,12 @@
|
||||
use std::io::Write;
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::{Path, PathBuf};
|
||||
use clap::Values;
|
||||
use glob::glob;
|
||||
use crate::store::index;
|
||||
use crate::store::{self, object::Object};
|
||||
use crate::utils::{self, path};
|
||||
use crate::utils::nextsyncignore::{self, ignore_file};
|
||||
use crate::utils::path::{normalize_relative, repo_root, path_buf_to_string};
|
||||
|
||||
use super::status::get_all_objs;
|
||||
|
||||
pub struct AddArgs<'a> {
|
||||
pub files: Option<Values<'a>>,
|
||||
pub force: bool,
|
||||
|
@ -59,11 +59,15 @@ pub fn clone(args: CloneArgs) {
|
||||
std::process::exit(1);
|
||||
} else {
|
||||
init::init();
|
||||
let mut remote_config = api_props.username.clone();
|
||||
remote_config.push_str("@");
|
||||
remote_config.push_str(api_props.host.strip_prefix("https://").unwrap());
|
||||
remote_config.push_str(&api_props.root);
|
||||
if config::set("remote", &remote_config).is_err() {
|
||||
|
||||
// set remote origin in config file
|
||||
let mut remote_url = api_props.username.clone();
|
||||
remote_url.push_str("@");
|
||||
remote_url.push_str(api_props.host.strip_prefix("https://").unwrap());
|
||||
remote_url.push_str(&api_props.root);
|
||||
|
||||
if config::add_remote("origin", &remote_url).is_err()
|
||||
{
|
||||
eprintln!("err: not able to save remote");
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,144 @@
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{self, Write};
|
||||
use clap::Values;
|
||||
use std::io::{self, Write, BufRead, Seek, SeekFrom};
|
||||
use crate::utils::{path, read};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn set(var: &str, val: &str) -> io::Result<()> {
|
||||
pub struct ConfigSetArgs<'a> {
|
||||
pub name: Option<Values<'a>>,
|
||||
pub value: Option<Values<'a>>,
|
||||
}
|
||||
|
||||
pub fn config_set(args: ConfigSetArgs) {
|
||||
// configure possible options and their associated category
|
||||
let mut option_categories: HashMap<&str, &str> = HashMap::new();
|
||||
option_categories.insert("force_insecure", "core");
|
||||
option_categories.insert("token", "core");
|
||||
|
||||
let name = args.name.unwrap().next().unwrap();
|
||||
let value = args.value.unwrap().next().unwrap();
|
||||
|
||||
// get category of option
|
||||
let category = option_categories.get(name);
|
||||
if category.is_none() {
|
||||
eprintln!("fatal: '{}' is not a valid option.", name);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
write_option_in_cat(category.unwrap(), name, value);
|
||||
}
|
||||
|
||||
|
||||
pub fn find_option_in_cat(category: &str, option: &str) -> Option<String> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
|
||||
// todo check if exist
|
||||
let mut in_target_category = false;
|
||||
if let Ok(mut lines) = read::read_lines(root) {
|
||||
|
||||
for line in lines {
|
||||
|
||||
if let Ok(line) = line {
|
||||
let trimmed_line = line.trim();
|
||||
|
||||
if trimmed_line.starts_with('[') && trimmed_line.ends_with(']') {
|
||||
in_target_category = trimmed_line == format!("[{}]", category);
|
||||
} else if in_target_category {
|
||||
let parts: Vec<&str> = trimmed_line.splitn(2, '=').collect();
|
||||
if parts.len() == 2 && parts[0].trim() == option {
|
||||
return Some(parts[1].trim().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn write_option_in_cat(category: &str, option: &str, value: &str) -> io::Result<()> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&root)?;
|
||||
|
||||
let mut in_target_category = false;
|
||||
let mut option_found = false;
|
||||
|
||||
// Go to the beginning of the file
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
// Create a temporary file to hold the modified content
|
||||
let mut tmp_file = tempfile::Builder::new()
|
||||
.prefix(".nextsyncconfig")
|
||||
.tempfile()?;
|
||||
|
||||
let reader = io::BufReader::new(&file);
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let trimmed_line = line.trim();
|
||||
|
||||
if trimmed_line.starts_with('[') && trimmed_line.ends_with(']') {
|
||||
// if we were already in target category we are now leaving it
|
||||
// add option only if not found before
|
||||
if in_target_category && !option_found {
|
||||
writeln!(&mut tmp_file, "\t{} = {}", option, value)?;
|
||||
} else if !in_target_category {
|
||||
in_target_category = trimmed_line == format!("[{}]", category);
|
||||
}
|
||||
}
|
||||
|
||||
if in_target_category && !option_found && trimmed_line.starts_with(&format!("{} =", option)) {
|
||||
// Option already exists, update its value
|
||||
writeln!(&mut tmp_file, "\t{} = {}", option, value)?;
|
||||
option_found = true;
|
||||
} else {
|
||||
// Write the original line
|
||||
writeln!(&mut tmp_file, "{}", line)?;
|
||||
}
|
||||
}
|
||||
|
||||
// add to last category
|
||||
if in_target_category && !option_found {
|
||||
writeln!(&mut tmp_file, "\t{} = {}", option, value)?;
|
||||
}
|
||||
|
||||
// if the category didn't exist create it and add the option
|
||||
if !in_target_category {
|
||||
writeln!(&mut tmp_file, "[{}]", category)?;
|
||||
writeln!(&mut tmp_file, "\t{} = {}", option, value)?;
|
||||
}
|
||||
|
||||
// Flush and sync the temporary file to ensure data is written to disk
|
||||
tmp_file.flush()?;
|
||||
|
||||
// Go back to the beginning of the file
|
||||
tmp_file.seek(SeekFrom::Start(0))?;
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
// Copy the contents of the temporary file to the original file
|
||||
io::copy(&mut tmp_file, &mut file)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
pub fn add_remote(name: &str, url: &str) -> io::Result<()> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
|
||||
// check if there is already a remote with this name
|
||||
if get_remote(name).is_some()
|
||||
{
|
||||
eprintln!("error: remote {} already exists.", name);
|
||||
std::process::exit(3);
|
||||
}
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
@ -14,10 +146,34 @@ pub fn set(var: &str, val: &str) -> io::Result<()> {
|
||||
.append(true)
|
||||
.open(root)?;
|
||||
|
||||
let mut line = var.to_owned();
|
||||
line.push_str(" ");
|
||||
line.push_str(val);
|
||||
writeln!(file, "{}", line)?;
|
||||
writeln!(file, "[remote \"{}\"]", name)?;
|
||||
writeln!(file, "\turl = {}", url)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_remote(name: &str) -> Option<String> {
|
||||
find_option_in_cat(&format!("remote \"{}\"", name), "url")
|
||||
}
|
||||
|
||||
pub fn get_core(name: &str) -> Option<String> {
|
||||
find_option_in_cat("core", name)
|
||||
}
|
||||
|
||||
pub fn add_core(name: &str, value: &str) -> io::Result<()> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(root)?;
|
||||
|
||||
writeln!(file, "[core]")?;
|
||||
writeln!(file, "\t{} = {}", name, value)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -28,7 +184,7 @@ pub fn get(var: &str) -> Option<String> {
|
||||
if let Ok(lines) = read::read_lines(root) {
|
||||
for line in lines {
|
||||
if let Ok(l) = line {
|
||||
if l.starts_with(var.clone()) {
|
||||
if l.starts_with(var) {
|
||||
let (_, val) = l.split_once(" ").unwrap();
|
||||
return Some(val.to_owned());
|
||||
}
|
||||
@ -37,3 +193,5 @@ pub fn get(var: &str) -> Option<String> {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
|
55
src/commands/credential.rs
Normal file
55
src/commands/credential.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use clap::Values;
|
||||
use crate::commands::clone::get_url_props;
|
||||
use crate::services::api::ApiError::RequestError;
|
||||
|
||||
use crate::services::login::Login;
|
||||
use crate::services::api_call::ApiCall;
|
||||
use crate::commands::config;
|
||||
|
||||
pub struct CredentialArgs<'a> {
|
||||
pub username: Option<Values<'a>>,
|
||||
pub password: Option<Values<'a>>,
|
||||
}
|
||||
|
||||
pub fn credential_add(args: CredentialArgs) {
|
||||
// get remote if exists
|
||||
let remote = match config::get_remote("origin") {
|
||||
None => {
|
||||
eprintln!("fatal: No remote origin, impossible to send request to get token");
|
||||
std::process::exit(1);
|
||||
},
|
||||
Some(remote) => remote
|
||||
};
|
||||
let (host, _, _) = get_url_props(&remote);
|
||||
|
||||
// get username and password
|
||||
let username = args.username.unwrap().next().unwrap();
|
||||
let password = match args.password {
|
||||
Some(mut pwd) => pwd.next().unwrap().to_owned(),
|
||||
None => {
|
||||
println!("Please enter the password for {}: ", username);
|
||||
rpassword::read_password().unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
// get token
|
||||
let get_token = Login::new()
|
||||
.set_auth(username, &password)
|
||||
.set_host(Some(host))
|
||||
.send_login();
|
||||
|
||||
// deal with error
|
||||
if let Err(err) = get_token {
|
||||
if let RequestError(err) = err {
|
||||
eprintln!("fatal: Failed to get token for these credential. ({})", err);
|
||||
}
|
||||
else {
|
||||
eprintln!("fatal: Failed to get token for these credential.");
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
// save token
|
||||
let _ = config::write_option_in_cat("core", "token", get_token.unwrap().as_str());
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ pub mod copied;
|
||||
|
||||
pub fn push() {
|
||||
// todo err when pushing new folder
|
||||
let _remote = match config::get("remote") {
|
||||
let _remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: no remote set in configuration");
|
||||
|
@ -32,11 +32,11 @@ impl PushChange for New {
|
||||
|
||||
match res {
|
||||
Err(ApiError::IncorrectRequest(err)) => {
|
||||
eprintln!("fatal: error pushing file {}: {}", obj.name, err.status());
|
||||
eprintln!("fatal: error pushing file '{}': {}", obj.name, err.status());
|
||||
std::process::exit(1);
|
||||
},
|
||||
Err(ApiError::RequestError(_)) => {
|
||||
eprintln!("fatal: request error pushing file {}", obj.name);
|
||||
eprintln!("fatal: request error pushing file '{}'", obj.name);
|
||||
std::process::exit(1);
|
||||
}
|
||||
_ => (),
|
||||
|
21
src/commands/remote.rs
Normal file
21
src/commands/remote.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use clap::Values;
|
||||
|
||||
use crate::commands::config;
|
||||
|
||||
pub struct RemoteArgs<'a> {
|
||||
pub name: Option<Values<'a>>,
|
||||
pub url: Option<Values<'a>>,
|
||||
}
|
||||
|
||||
pub fn remote_add(args: RemoteArgs) {
|
||||
if args.name.is_none() || args.url.is_none() {
|
||||
eprintln!("Missing argument: remote add command need a name and an url");
|
||||
return;
|
||||
}
|
||||
|
||||
let name = args.name.unwrap().next().unwrap();
|
||||
let url = args.url.unwrap().next().unwrap();
|
||||
|
||||
let _ = config::add_remote(name, url);
|
||||
}
|
||||
|
@ -20,9 +20,11 @@ fn main() {
|
||||
.subcommand(subcommands::add::create())
|
||||
.subcommand(subcommands::push::create())
|
||||
.subcommand(subcommands::reset::create())
|
||||
.subcommand(subcommands::remote::create())
|
||||
.subcommand(subcommands::config::create())
|
||||
.subcommand(subcommands::remote_diff::create())
|
||||
.subcommand(subcommands::pull::create())
|
||||
.subcommand(subcommands::credential::create())
|
||||
.subcommand(
|
||||
SubCommand::with_name("test")
|
||||
);
|
||||
@ -39,6 +41,8 @@ fn main() {
|
||||
("config", Some(args)) => subcommands::config::handler(args),
|
||||
("remote-diff", Some(args)) => subcommands::remote_diff::handler(args),
|
||||
("pull", Some(args)) => subcommands::pull::handler(args),
|
||||
("remote", Some(args)) => subcommands::remote::handler(args),
|
||||
("credential", Some(args)) => subcommands::credential::handler(args),
|
||||
|
||||
(_, _) => {},
|
||||
};
|
||||
|
@ -42,12 +42,19 @@ impl ApiBuilder {
|
||||
}
|
||||
|
||||
pub fn set_url(&mut self, method: Method, url: &str) -> &mut ApiBuilder {
|
||||
self.request = Some(self.client.request(method, url));
|
||||
let mut new_url = url.to_owned();
|
||||
if let Some(active) = config::get_core("force_insecure") {
|
||||
if active == "true" {
|
||||
new_url = url.replace("https", "http");
|
||||
}
|
||||
}
|
||||
|
||||
self.request = Some(self.client.request(method, new_url));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build_request(&mut self, method: Method, path: &str) -> &mut ApiBuilder {
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
@ -64,8 +71,8 @@ impl ApiBuilder {
|
||||
if path != "/" {
|
||||
url.push_str(path);
|
||||
}
|
||||
self.request = Some(self.client.request(method, url));
|
||||
self
|
||||
|
||||
self.set_url(method, &url)
|
||||
}
|
||||
|
||||
pub fn set_req(&mut self, meth: Method, p: &str, api_props: &ApiProps) -> &mut ApiBuilder {
|
||||
@ -79,8 +86,8 @@ impl ApiBuilder {
|
||||
if p != "/" {
|
||||
url.push_str(p);
|
||||
}
|
||||
self.request = Some(self.client.request(meth, url));
|
||||
self
|
||||
|
||||
self.set_url(meth, &url)
|
||||
}
|
||||
|
||||
pub fn set_basic_auth(&mut self, login: String, pwd: String) -> &mut ApiBuilder {
|
||||
|
@ -24,7 +24,7 @@ impl Copy {
|
||||
pub fn set_url_copy(&mut self, url: &str, destination: &str) -> &mut Copy {
|
||||
self.api_builder.build_request(Method::from_bytes(b"COPY").unwrap(), url);
|
||||
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
|
@ -28,7 +28,11 @@ impl ApiCall for Login {
|
||||
|
||||
let url = match self.host.clone() {
|
||||
Some(h) => {
|
||||
let mut u = String::from("https://");
|
||||
let mut u = if &h[0..8] == "https://" || &h[0..7] == "http://" {
|
||||
String::new()
|
||||
} else {
|
||||
String::from("https://")
|
||||
};
|
||||
u.push_str(&h);
|
||||
u.push_str("/ocs/v2.php/core/getapppassword");
|
||||
u
|
||||
@ -53,6 +57,12 @@ impl Login {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_auth(&mut self, username: &str, password: &str) -> &mut Login {
|
||||
self.login = username.to_owned();
|
||||
self.password = password.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_host(&mut self, host: Option<String>) -> &mut Login {
|
||||
self.host = host;
|
||||
self
|
||||
|
@ -25,7 +25,7 @@ impl Move {
|
||||
pub fn set_url_move(&mut self, url: &str, destination: &str) -> &mut Move {
|
||||
self.api_builder.build_request(Method::from_bytes(b"MOVE").unwrap(), url);
|
||||
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
|
@ -67,7 +67,7 @@ impl ApiCall for ReqProps {
|
||||
}
|
||||
|
||||
fn set_url(&mut self, url: &str) -> &mut ReqProps {
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
|
@ -39,7 +39,7 @@ impl RequestManager {
|
||||
{
|
||||
if self.host.is_none()
|
||||
{
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
// todo ask user instead
|
||||
@ -56,6 +56,7 @@ impl RequestManager {
|
||||
|
||||
pub fn get_token(&mut self) -> String {
|
||||
if self.token.is_none() {
|
||||
// look in global config
|
||||
if let Some(token) = gconfig::read_token() {
|
||||
if !token.is_empty() {
|
||||
self.token = Some(token);
|
||||
@ -63,10 +64,21 @@ impl RequestManager {
|
||||
}
|
||||
}
|
||||
|
||||
// look in local config
|
||||
if let Some(token) = config::find_option_in_cat("core", "token")
|
||||
{
|
||||
if !token.is_empty() {
|
||||
self.token = Some(token);
|
||||
return self.token.clone().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// ask for a token
|
||||
let get_token = Login::new()
|
||||
.ask_auth()
|
||||
.set_host(Some(self.get_host()))
|
||||
.send_login();
|
||||
|
||||
// todo deal with error cases
|
||||
self.token = Some(get_token.unwrap());
|
||||
if let Err(err) = gconfig::write_token(&self.token.clone().unwrap()) {
|
||||
|
@ -131,7 +131,7 @@ fn rm(hash: &str) -> io::Result<()> {
|
||||
|
||||
fn rm_node(path: &Path, node: &str) -> io::Result<()> {
|
||||
let mut root = path::objects();
|
||||
let (dir, rest) = hash_obj(path.clone().to_str().unwrap());
|
||||
let (dir, rest) = hash_obj(path.to_str().unwrap());
|
||||
|
||||
root.push(dir);
|
||||
root.push(rest);
|
||||
@ -143,7 +143,7 @@ fn rm_node(path: &Path, node: &str) -> io::Result<()> {
|
||||
fn add_node(path: &Path, node: &str) -> io::Result<()> {
|
||||
let mut root = path::objects();
|
||||
|
||||
let (dir, rest) = hash_obj(path.clone().to_str().unwrap());
|
||||
let (dir, rest) = hash_obj(path.to_str().unwrap());
|
||||
|
||||
root.push(dir);
|
||||
if !root.exists() {
|
||||
@ -168,7 +168,7 @@ fn update_dates(mut path: PathBuf, date: &str) -> io::Result<()> {
|
||||
let (dir, res) = hash_obj(path.to_str().unwrap());
|
||||
obj_p.push(dir);
|
||||
obj_p.push(res);
|
||||
update_date(obj_p.clone(), date.clone())?;
|
||||
update_date(obj_p.clone(), date)?;
|
||||
obj_p.pop();
|
||||
obj_p.pop();
|
||||
}
|
||||
|
@ -7,3 +7,5 @@ pub mod push;
|
||||
pub mod config;
|
||||
pub mod remote_diff;
|
||||
pub mod pull;
|
||||
pub mod remote;
|
||||
pub mod credential;
|
||||
|
@ -1,5 +1,4 @@
|
||||
use clap::{App, Arg, SubCommand, ArgMatches};
|
||||
use std::borrow::Cow;
|
||||
use textwrap::{fill, Options};
|
||||
|
||||
use crate::commands::clone::{self, CloneArgs};
|
||||
|
@ -1,29 +1,53 @@
|
||||
use clap::{App, Arg, SubCommand, ArgMatches};
|
||||
use crate::commands::config::ConfigSetArgs;
|
||||
|
||||
use crate::commands;
|
||||
|
||||
pub fn create() -> App<'static, 'static> {
|
||||
SubCommand::with_name("config")
|
||||
.about("Get and set repository or global options")
|
||||
.subcommand(
|
||||
SubCommand::with_name("get")
|
||||
.about("Get the value of a configuration variable")
|
||||
.arg(
|
||||
Arg::with_name("variable")
|
||||
Arg::with_name("name")
|
||||
.help("The name of the configuration variable")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.value_name("VARIABLE")
|
||||
.index(1)
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("set")
|
||||
.about("Set a configuration variable")
|
||||
.arg(
|
||||
Arg::with_name("name")
|
||||
.help("The name of the configuration variable")
|
||||
.required(true)
|
||||
.index(1)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("value")
|
||||
.help("The value to set")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.value_name("VALUE")
|
||||
.index(2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn handler(args: &ArgMatches<'_>) {
|
||||
if let Some(mut var) = args.values_of("variable") {
|
||||
if let Some(mut val) = args.values_of("value") {
|
||||
if commands::config::set(var.next().unwrap(), val.next().unwrap()).is_err() {
|
||||
eprintln!("fatal: cannot save the value");
|
||||
}
|
||||
|
||||
match args.subcommand() {
|
||||
("set", Some(set_matches)) => {
|
||||
commands::config::config_set(ConfigSetArgs {
|
||||
name: set_matches.values_of("name"),
|
||||
value: set_matches.values_of("value"),
|
||||
});
|
||||
}
|
||||
_ => println!("Invalid or missing subcommand for 'config'"),
|
||||
}
|
||||
// AddArgs {
|
||||
// files: args.values_of("files"),
|
||||
// force: args.is_present("force"),
|
||||
// all: args.is_present("all"),
|
||||
// });
|
||||
}
|
||||
|
39
src/subcommands/credential.rs
Normal file
39
src/subcommands/credential.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use clap::{App, Arg, SubCommand, ArgMatches};
|
||||
|
||||
use crate::commands;
|
||||
use crate::commands::credential::CredentialArgs;
|
||||
|
||||
pub fn create() -> App<'static, 'static> {
|
||||
SubCommand::with_name("credential")
|
||||
.about("Manage set of credentials")
|
||||
.subcommand(
|
||||
SubCommand::with_name("add")
|
||||
.arg(
|
||||
Arg::with_name("username")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.value_name("NAME")
|
||||
.help("The username used to connect to nextcloud"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("password")
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.value_name("PASSWORD")
|
||||
.help("The passowd used to connect to nextcloud (optional)"),
|
||||
)
|
||||
.about("Add a new set of credential")
|
||||
)
|
||||
}
|
||||
|
||||
pub fn handler(args: &ArgMatches<'_>) {
|
||||
match args.subcommand() {
|
||||
("add", Some(add_matches)) => {
|
||||
commands::credential::credential_add(CredentialArgs {
|
||||
username: add_matches.values_of("username"),
|
||||
password: add_matches.values_of("password"),
|
||||
});
|
||||
}
|
||||
_ => println!("Invalid or missing subcommand for 'credential'"),
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use clap::{App, SubCommand};
|
||||
|
||||
pub fn create() -> App<'static, 'static> {
|
||||
SubCommand::with_name("push")
|
||||
|
37
src/subcommands/remote.rs
Normal file
37
src/subcommands/remote.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use clap::{App, Arg, SubCommand, ArgMatches};
|
||||
|
||||
use crate::commands;
|
||||
use crate::commands::remote::RemoteArgs;
|
||||
|
||||
pub fn create() -> App<'static, 'static> {
|
||||
SubCommand::with_name("remote")
|
||||
.about("Manage set of tracked repositories")
|
||||
.subcommand(
|
||||
SubCommand::with_name("add")
|
||||
.arg(
|
||||
Arg::with_name("name")
|
||||
.required(true)
|
||||
.index(1)
|
||||
.help("The name of the remote"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("url")
|
||||
.required(true)
|
||||
.index(2)
|
||||
.help("The url of the remote"),
|
||||
)
|
||||
.about("Add a new remote to this repository")
|
||||
)
|
||||
}
|
||||
|
||||
pub fn handler(args: &ArgMatches<'_>) {
|
||||
match args.subcommand() {
|
||||
("add", Some(add_matches)) => {
|
||||
commands::remote::remote_add(RemoteArgs {
|
||||
name: add_matches.values_of("name"),
|
||||
url: add_matches.values_of("url"),
|
||||
});
|
||||
}
|
||||
_ => println!("Invalid or missing subcommand for 'remote'"),
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use clap::{App, SubCommand};
|
||||
|
||||
pub fn create() -> App<'static, 'static> {
|
||||
SubCommand::with_name("reset")
|
||||
|
@ -18,7 +18,7 @@ impl Clone for ApiProps {
|
||||
}
|
||||
|
||||
pub fn get_api_props() -> ApiProps {
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
@ -39,6 +39,8 @@ pub fn get_relative_s(p: String, api_props: &ApiProps) -> String {
|
||||
final_p = final_p.strip_prefix("/remote.php/dav/files/").unwrap().to_string();
|
||||
final_p = final_p.strip_prefix(&api_props.username).unwrap().to_string();
|
||||
final_p = final_p.strip_prefix(&api_props.root).unwrap().to_string();
|
||||
if final_p.starts_with("/") {
|
||||
final_p = final_p.strip_prefix("/").unwrap().to_string();
|
||||
}
|
||||
final_p
|
||||
}
|
||||
|
216
tests/tests.rs
Normal file
216
tests/tests.rs
Normal file
@ -0,0 +1,216 @@
|
||||
use std::process::{Command, Output};
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use rand::{distributions::Alphanumeric, Rng}; // 0.8
|
||||
use std::fs::{self, File, Permissions};
|
||||
use std::io::{Write, BufReader, BufRead};
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
struct ServerTest {
|
||||
user: String,
|
||||
volume: PathBuf,
|
||||
test_id: String
|
||||
}
|
||||
|
||||
impl ServerTest {
|
||||
fn new(id: String) -> Self {
|
||||
let mut volume = env::current_dir().unwrap();
|
||||
volume = volume.join("tests/data/admin/files");
|
||||
|
||||
ServerTest {
|
||||
user: String::from("admin"),
|
||||
volume,
|
||||
test_id: id
|
||||
}
|
||||
}
|
||||
|
||||
fn init(mut self) -> Self {
|
||||
self.add_dir(self.test_id.clone());
|
||||
self.volume = self.volume.join(self.test_id.clone());
|
||||
self.sync_test()
|
||||
}
|
||||
|
||||
fn clean(mut self) -> Self {
|
||||
self.remove_dir(self.test_id.clone());
|
||||
self.sync_root()
|
||||
}
|
||||
|
||||
fn add_dir(&mut self, path: String) -> &mut ServerTest {
|
||||
let mut full_path = self.volume.clone();
|
||||
full_path.push(path);
|
||||
|
||||
match fs::create_dir(&full_path) {
|
||||
Ok(_) => {
|
||||
// Set permissions to 777 to allow nextcloud to access it (workaround avoiding to
|
||||
// set group and owner to www-data)
|
||||
if let Err(e) = fs::set_permissions(&full_path, Permissions::from_mode(0o777)) {
|
||||
eprintln!("Error setting permissions: {}", e);
|
||||
}
|
||||
},
|
||||
Err(e) => eprintln!("Error creating directory: {}", e),
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn remove_dir(&mut self, path: String) -> &mut ServerTest {
|
||||
let mut full_path = self.volume.clone();
|
||||
full_path.push(path);
|
||||
|
||||
let _ = fs::remove_dir_all(&full_path);
|
||||
self
|
||||
}
|
||||
|
||||
fn sync_root(self) -> Self {
|
||||
self.sync("")
|
||||
}
|
||||
|
||||
fn sync_test(self) -> Self {
|
||||
let test_id = self.test_id.clone();
|
||||
self.sync(&test_id)
|
||||
}
|
||||
|
||||
fn sync(self, path: &str) -> Self {
|
||||
// perform the occ files:scan command inside the nextcloud docker container
|
||||
|
||||
let nextcloud_docker = "master-nextcloud-1";
|
||||
let mut args = String::from("exec -ti --user www-data");
|
||||
args.push_str(nextcloud_docker);
|
||||
args.push_str("/var/www/html/occ files:scan --path=/");
|
||||
args.push_str(&self.user);
|
||||
args.push_str("files/");
|
||||
args.push_str(path);
|
||||
|
||||
let _output = Command::new("docker")
|
||||
.args(args.split(" "))
|
||||
.output()
|
||||
.expect("Could not execute nextsync command");
|
||||
self
|
||||
}
|
||||
|
||||
fn has_file(&mut self, file: &str, content: &str) -> bool {
|
||||
let full_path = self.volume.clone().join(file);
|
||||
|
||||
if !full_path.exists() {
|
||||
eprintln!("File '{}' does't exists", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
let file = File::open(full_path).unwrap();
|
||||
for line in BufReader::new(file).lines(){
|
||||
if let Ok(line) = line {
|
||||
return line == content;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct ClientTest {
|
||||
user: String,
|
||||
volume: String,
|
||||
test_id: String,
|
||||
exe_path: PathBuf,
|
||||
}
|
||||
|
||||
impl ClientTest {
|
||||
fn new(id: String) -> Self {
|
||||
|
||||
// create a directory in /tmp with the given id
|
||||
let mut vol = String::from("/tmp/");
|
||||
vol.push_str(&id);
|
||||
let _ = fs::create_dir(vol.clone());
|
||||
|
||||
// get nextsync path
|
||||
let mut exe_path = env::current_dir().unwrap();
|
||||
exe_path = exe_path.join("target/debug/nextsync");
|
||||
|
||||
let _ = env::set_current_dir(vol.clone());
|
||||
|
||||
// build the client
|
||||
ClientTest {
|
||||
user: String::from("admin"),
|
||||
volume: vol,
|
||||
test_id: id,
|
||||
exe_path
|
||||
}
|
||||
}
|
||||
|
||||
fn init(mut self) -> Self {
|
||||
self.run_cmd_ok("init");
|
||||
|
||||
// set remote url
|
||||
let url = String::from(format!("{}@nextcloud.local/{}", self.user, self.test_id));
|
||||
self.run_cmd_ok(&format!("remote add origin {}", url));
|
||||
|
||||
// set force_unsecure as debug server has not certificate
|
||||
self.run_cmd_ok("config set force_insecure true");
|
||||
|
||||
// set token for request
|
||||
self.run_cmd_ok(&format!("credential add {} {}", self.user, self.user));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn clean(self) -> Self {
|
||||
let _ = fs::remove_dir_all(&self.volume);
|
||||
self
|
||||
}
|
||||
|
||||
fn run_cmd_ok(&mut self, args: &str) -> Output {
|
||||
let output = self.run_cmd(args);
|
||||
if !output.status.success() {
|
||||
println!("Failed to execute: '{}'", args);
|
||||
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
|
||||
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
|
||||
}
|
||||
assert!(output.status.success());
|
||||
output
|
||||
}
|
||||
|
||||
fn run_cmd(&mut self, args: &str) -> Output {
|
||||
let output = Command::new(self.exe_path.to_str().unwrap())
|
||||
.args(args.split(" "))
|
||||
.output()
|
||||
.expect("Could not execute nextsync command");
|
||||
return output;
|
||||
}
|
||||
|
||||
fn add_file(&mut self, name: &str, content: &str) -> std::io::Result<()> {
|
||||
let mut path = self.volume.clone();
|
||||
path.push_str("/");
|
||||
path.push_str(name);
|
||||
|
||||
let mut file = File::create(path)?;
|
||||
file.write_all(content.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_random_test_id() -> String {
|
||||
let mut id: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(7)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
id.push_str("_nextsync");
|
||||
id.to_owned()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test1() {
|
||||
let id = get_random_test_id();
|
||||
dbg!(id.clone());
|
||||
let mut server = ServerTest::new(id.clone()).init();
|
||||
let mut client = ClientTest::new(id).init();
|
||||
|
||||
let _ = client.add_file("file1", "foo");
|
||||
client.run_cmd_ok("add file1");
|
||||
client.run_cmd_ok("push");
|
||||
|
||||
// tests
|
||||
assert!(server.has_file("file1", "foo"));
|
||||
|
||||
client.clean();
|
||||
server.clean();
|
||||
}
|
Loading…
Reference in New Issue
Block a user