feat: CLI parser, restic discovery+download, pull/push via restic CLI
- Args.kt: parses --url, --pack-folder, --token-file, --restic-binary,
--no-download, -g/--no-gui. Inline and space-separated value forms.
- Restic.kt: locates restic via 1) --restic-binary override, 2) cached
<pack-folder>/.cloud-sync/restic-<ver>, 3) system PATH (version match),
4) auto-download from github releases + sha256 verify against SHA256SUMS.
bz2 decompression via commons-compress (bzcat fallback).
- Scope.kt: per-distribution cloud-scope.json with sensible defaults
(options.txt, config/, journeymap/data/, screenshots/). Auto-excludes
.cloud-sync/ so we never leak our own credentials.
- Sync.kt: pull = restic restore latest --target <pack-folder>;
push = restic backup --files-from <generated> --exclude-file <generated>.
Empty repos handled (pull is no-op when no snapshots yet).
- 18 tests pass. Fat jar grew to 6 MB (commons-compress).
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package center.timemachine.cloud
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ArgsTest {
|
||||
@Test
|
||||
fun `parses required url and applies defaults`() {
|
||||
val a = parseArgs(arrayOf("--url=https://cloud.tm.center"))
|
||||
assertEquals("https://cloud.tm.center", a.url)
|
||||
assertTrue(a.allowDownload)
|
||||
assertFalse(a.headless)
|
||||
// default token file lives under <pack-folder>/.cloud-sync/token
|
||||
assertTrue(a.tokenFile.endsWith(".cloud-sync/token"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `url required`() {
|
||||
val ex = assertFailsWith<ArgParseException> { parseArgs(emptyArray()) }
|
||||
assertTrue(ex.message!!.contains("--url"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `space-separated values work`() {
|
||||
val a = parseArgs(arrayOf("--url", "https://x", "--pack-folder", "/srv/mc"))
|
||||
assertEquals("https://x", a.url)
|
||||
assertEquals("/srv/mc", a.packFolder.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `inline values work`() {
|
||||
val a = parseArgs(arrayOf("--url=https://x", "--pack-folder=/srv/mc"))
|
||||
assertEquals("https://x", a.url)
|
||||
assertEquals("/srv/mc", a.packFolder.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no-gui flag`() {
|
||||
val a = parseArgs(arrayOf("--url=https://x", "-g"))
|
||||
assertTrue(a.headless)
|
||||
val b = parseArgs(arrayOf("--url=https://x", "--no-gui"))
|
||||
assertTrue(b.headless)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no-download flag disables fetch`() {
|
||||
val a = parseArgs(arrayOf("--url=https://x", "--no-download"))
|
||||
assertFalse(a.allowDownload)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unknown flag rejected`() {
|
||||
val ex = assertFailsWith<ArgParseException> {
|
||||
parseArgs(arrayOf("--url=https://x", "--bogus=foo"))
|
||||
}
|
||||
assertTrue(ex.message!!.contains("--bogus"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bool flag with inline value rejected`() {
|
||||
val ex = assertFailsWith<ArgParseException> {
|
||||
parseArgs(arrayOf("--url=https://x", "--no-download=yes"))
|
||||
}
|
||||
assertTrue(ex.message!!.contains("does not take a value"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `missing value for non-bool flag rejected`() {
|
||||
val ex = assertFailsWith<ArgParseException> {
|
||||
parseArgs(arrayOf("--url=https://x", "--pack-folder"))
|
||||
}
|
||||
assertTrue(ex.message!!.contains("requires a value"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom token-file overrides default`() {
|
||||
val a = parseArgs(arrayOf(
|
||||
"--url=https://x",
|
||||
"--pack-folder=/srv/mc",
|
||||
"--token-file=/etc/cloud-creds",
|
||||
))
|
||||
assertEquals("/etc/cloud-creds", a.tokenFile.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `restic-binary override accepted`() {
|
||||
val a = parseArgs(arrayOf("--url=https://x", "--restic-binary=/opt/restic"))
|
||||
assertEquals("/opt/restic", a.resticBinary!!.toString())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user