git-drive 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +77 -0
- package/.planning/codebase/ARCHITECTURE.md +151 -0
- package/.planning/codebase/CONCERNS.md +191 -0
- package/.planning/codebase/CONVENTIONS.md +169 -0
- package/.planning/codebase/INTEGRATIONS.md +94 -0
- package/.planning/codebase/STACK.md +77 -0
- package/.planning/codebase/STRUCTURE.md +157 -0
- package/.planning/codebase/TESTING.md +156 -0
- package/Dockerfile.cli +30 -0
- package/Dockerfile.server +32 -0
- package/README.md +157 -0
- package/docker-compose.yml +48 -0
- package/package.json +20 -55
- package/packages/cli/Dockerfile +26 -0
- package/packages/cli/jest.config.js +26 -0
- package/packages/cli/package.json +65 -0
- package/packages/cli/src/__tests__/commands/companion.test.ts +152 -0
- package/packages/cli/src/__tests__/commands/init.test.ts +154 -0
- package/packages/cli/src/__tests__/commands/list.test.ts +122 -0
- package/packages/cli/src/__tests__/commands/push.test.ts +155 -0
- package/packages/cli/src/__tests__/commands/restore.test.ts +135 -0
- package/packages/cli/src/__tests__/commands/status.test.ts +199 -0
- package/packages/cli/src/__tests__/config.test.ts +198 -0
- package/packages/cli/src/__tests__/e2e.test.ts +125 -0
- package/packages/cli/src/__tests__/errors.test.ts +66 -0
- package/packages/cli/src/__tests__/git.test.ts +250 -0
- package/packages/cli/src/__tests__/server.test.ts +371 -0
- package/packages/cli/src/commands/archive.ts +39 -0
- package/packages/cli/src/commands/companion.ts +205 -0
- package/packages/cli/src/commands/init.ts +130 -0
- package/packages/cli/src/commands/link.ts +151 -0
- package/packages/cli/src/commands/list.ts +94 -0
- package/packages/cli/src/commands/push.ts +77 -0
- package/packages/cli/src/commands/restore.ts +36 -0
- package/packages/cli/src/commands/status.ts +127 -0
- package/packages/cli/src/config.ts +73 -0
- package/packages/cli/src/errors.ts +23 -0
- package/packages/cli/src/git.ts +60 -0
- package/packages/cli/src/index.ts +129 -0
- package/packages/cli/src/server.ts +700 -0
- package/packages/cli/tsconfig.json +13 -0
- package/packages/git-drive-docker/package.json +15 -0
- package/packages/server/package.json +44 -0
- package/packages/server/src/index.ts +569 -0
- package/packages/server/tsconfig.json +9 -0
- package/packages/ui/README.md +73 -0
- package/packages/ui/eslint.config.js +23 -0
- package/packages/ui/index.html +13 -0
- package/packages/ui/package.json +52 -0
- package/packages/ui/postcss.config.js +6 -0
- package/packages/ui/public/vite.svg +1 -0
- package/packages/ui/src/App.css +23 -0
- package/packages/ui/src/App.test.tsx +248 -0
- package/packages/ui/src/App.tsx +803 -0
- package/packages/ui/src/assets/react.svg +8 -0
- package/packages/ui/src/assets/vite.svg +3 -0
- package/packages/ui/src/index.css +37 -0
- package/packages/ui/src/main.tsx +14 -0
- package/packages/ui/src/test/setup.ts +1 -0
- package/packages/ui/tailwind.config.js +11 -0
- package/packages/ui/tsconfig.app.json +28 -0
- package/packages/ui/tsconfig.json +26 -0
- package/packages/ui/tsconfig.node.json +12 -0
- package/packages/ui/vite.config.ts +7 -0
- package/packages/ui/vitest.config.ts +20 -0
- package/pnpm-workspace.yaml +4 -0
- package/rewrite_app.js +731 -0
- package/tsconfig.json +14 -0
- package/dist/__tests__/commands/init.test.js +0 -123
- package/dist/__tests__/commands/list.test.js +0 -91
- package/dist/__tests__/commands/push.test.js +0 -128
- package/dist/__tests__/commands/restore.test.js +0 -99
- package/dist/__tests__/commands/status.test.js +0 -151
- package/dist/__tests__/config.test.js +0 -150
- package/dist/__tests__/e2e.test.js +0 -107
- package/dist/__tests__/errors.test.js +0 -56
- package/dist/__tests__/git.test.js +0 -184
- package/dist/__tests__/server.test.js +0 -310
- package/dist/commands/archive.js +0 -32
- package/dist/commands/init.js +0 -55
- package/dist/commands/link.js +0 -175
- package/dist/commands/list.js +0 -83
- package/dist/commands/push.js +0 -112
- package/dist/commands/restore.js +0 -30
- package/dist/commands/status.js +0 -116
- package/dist/config.js +0 -62
- package/dist/errors.js +0 -30
- package/dist/git.js +0 -67
- package/dist/index.js +0 -108
- package/dist/server.js +0 -535
- /package/{ui → packages/cli/ui}/assets/index-Br8xQbJz.js +0 -0
- /package/{ui → packages/cli/ui}/assets/index-Cc2q1t5k.js +0 -0
- /package/{ui → packages/cli/ui}/assets/index-DrL7ojPA.css +0 -0
- /package/{ui → packages/cli/ui}/index.html +0 -0
- /package/{ui → packages/cli/ui}/vite.svg +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class GitDriveError extends Error {
|
|
2
|
+
constructor(message: string) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "GitDriveError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function handleError(err: unknown): void {
|
|
9
|
+
if (err instanceof GitDriveError) {
|
|
10
|
+
console.error(`error: ${err.message}`);
|
|
11
|
+
} else if (err instanceof Error) {
|
|
12
|
+
const msg = err.message;
|
|
13
|
+
// execSync errors include stderr in the message
|
|
14
|
+
const stderrMatch = msg.match(/stderr:\s*([\s\S]*)/);
|
|
15
|
+
if (stderrMatch) {
|
|
16
|
+
console.error(`error: ${stderrMatch[1].trim()}`);
|
|
17
|
+
} else {
|
|
18
|
+
console.error(`error: ${msg}`);
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
console.error("An unexpected error occurred.");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { basename } from "path";
|
|
3
|
+
import { getDiskInfo } from "node-disk-info";
|
|
4
|
+
|
|
5
|
+
export function git(args: string, cwd?: string): string {
|
|
6
|
+
return execSync(`git ${args}`, {
|
|
7
|
+
cwd,
|
|
8
|
+
encoding: "utf-8",
|
|
9
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
10
|
+
}).trim();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function listDrives(): Promise<any[]> {
|
|
14
|
+
const drives = await getDiskInfo();
|
|
15
|
+
return drives.filter((d: any) => {
|
|
16
|
+
const mp = d.mounted;
|
|
17
|
+
if (!mp) return false;
|
|
18
|
+
if (mp === "/" || mp === "100%") return false;
|
|
19
|
+
|
|
20
|
+
// Exclude temporary and system paths on all platforms
|
|
21
|
+
if (mp.startsWith("/var/") || mp.startsWith("/private/var/") || mp.startsWith("/tmp") || mp.startsWith("/private/tmp")) return false;
|
|
22
|
+
if (mp.includes("TemporaryItems") || mp.includes("NSIRD_")) return false;
|
|
23
|
+
if (mp.startsWith("/System/") || mp.startsWith("/Library/")) return false;
|
|
24
|
+
|
|
25
|
+
if (process.platform === "darwin") {
|
|
26
|
+
return mp.startsWith("/Volumes/") && !mp.startsWith("/Volumes/Recovery");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (mp.startsWith("/sys") || mp.startsWith("/proc") || mp.startsWith("/run") || mp.startsWith("/snap") || mp.startsWith("/boot")) return false;
|
|
30
|
+
if (d.filesystem === "tmpfs" || d.filesystem === "devtmpfs" || d.filesystem === "udev" || d.filesystem === "overlay") return false;
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getRepoRoot(): string {
|
|
37
|
+
return git("rev-parse --show-toplevel");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getProjectName(): string {
|
|
41
|
+
const root = getRepoRoot();
|
|
42
|
+
return basename(root);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getRemoteUrl(remoteName: string): string | null {
|
|
46
|
+
try {
|
|
47
|
+
return git(`remote get-url ${remoteName}`);
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function isGitRepo(): boolean {
|
|
54
|
+
try {
|
|
55
|
+
git("rev-parse --is-inside-work-tree");
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
import { push } from "./commands/push.js";
|
|
6
|
+
import { list } from "./commands/list.js";
|
|
7
|
+
import { status } from "./commands/status.js";
|
|
8
|
+
import { link } from "./commands/link.js";
|
|
9
|
+
import { init } from "./commands/init.js";
|
|
10
|
+
import { companion } from "./commands/companion.js";
|
|
11
|
+
import { handleError } from "./errors.js";
|
|
12
|
+
import { ensureServerRunning } from "./server.js";
|
|
13
|
+
|
|
14
|
+
// Get version from package.json
|
|
15
|
+
declare const __dirname: string;
|
|
16
|
+
const { version: VERSION } = JSON.parse(readFileSync(__dirname + '/../package.json', 'utf-8'));
|
|
17
|
+
|
|
18
|
+
const commands: Record<string, (args: string[]) => void | Promise<void>> = {
|
|
19
|
+
init,
|
|
20
|
+
push,
|
|
21
|
+
list,
|
|
22
|
+
status,
|
|
23
|
+
link,
|
|
24
|
+
companion,
|
|
25
|
+
server: startServer,
|
|
26
|
+
start: startServer,
|
|
27
|
+
ui: startServer,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Commands that don't need the server running
|
|
31
|
+
const NO_SERVER_COMMANDS = ['server', 'start', 'ui', 'companion'];
|
|
32
|
+
|
|
33
|
+
function printUsage(): void {
|
|
34
|
+
console.log(`
|
|
35
|
+
git-drive - Turn any external drive into a git remote backup for your code
|
|
36
|
+
|
|
37
|
+
Usage:
|
|
38
|
+
git-drive <command> [options]
|
|
39
|
+
|
|
40
|
+
Commands:
|
|
41
|
+
init Initialize git-drive on an external drive
|
|
42
|
+
link Link current repo to a drive
|
|
43
|
+
push Push current repo to drive
|
|
44
|
+
list Show connected drives and their status
|
|
45
|
+
status Show detailed status of drives and repos
|
|
46
|
+
companion [path] Run git-drive from a drive (companion mode)
|
|
47
|
+
server, start, ui Start the git-drive web UI server
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
-v, -V, --version Show version number
|
|
51
|
+
-h, --help Show this help message
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
git-drive init /Volumes/MyDrive Initialize git-drive on a drive
|
|
55
|
+
git-drive link Link current repo to a drive
|
|
56
|
+
git-drive push Push current repo to drive
|
|
57
|
+
git-drive list List connected drives
|
|
58
|
+
git-drive status Show detailed status
|
|
59
|
+
git-drive companion Run companion mode (interactive)
|
|
60
|
+
git-drive companion /Volumes/USB Run companion mode for specific drive
|
|
61
|
+
git-drive server Start the web UI at http://localhost:4483
|
|
62
|
+
|
|
63
|
+
Environment Variables:
|
|
64
|
+
GIT_DRIVE_PORT Port for the web server (default: 4483)
|
|
65
|
+
GIT_DRIVE_COMPANION_MODE Set to 'true' for companion mode
|
|
66
|
+
GIT_DRIVE_COMPANION_DRIVE Drive path in companion mode
|
|
67
|
+
|
|
68
|
+
Docker:
|
|
69
|
+
docker run -it --rm -v /Volumes:/Volumes -p 4483:4483 git-drive
|
|
70
|
+
|
|
71
|
+
Documentation:
|
|
72
|
+
https://github.com/josmanvis/git-drive
|
|
73
|
+
`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function startServer(_args: string[]): void {
|
|
77
|
+
console.log('\n 🚀 Starting Git Drive server...\n');
|
|
78
|
+
console.log(' Web UI: http://localhost:4483\n');
|
|
79
|
+
console.log(' Press Ctrl+C to stop\n');
|
|
80
|
+
|
|
81
|
+
const serverPath = require.resolve('./server.js');
|
|
82
|
+
const child = spawn(process.execPath, [serverPath], {
|
|
83
|
+
stdio: 'inherit',
|
|
84
|
+
env: process.env
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
child.on('error', (err) => {
|
|
88
|
+
console.error('Failed to start server:', err.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
child.on('exit', (code) => {
|
|
93
|
+
process.exit(code || 0);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const [command, ...args] = process.argv.slice(2);
|
|
98
|
+
|
|
99
|
+
(async () => {
|
|
100
|
+
try {
|
|
101
|
+
if (!command || command === "--help" || command === "-h") {
|
|
102
|
+
printUsage();
|
|
103
|
+
process.exit(0);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Handle version flags
|
|
107
|
+
if (command === "--version" || command === "-v" || command === "-V" || command === "version") {
|
|
108
|
+
console.log(`git-drive v${VERSION}`);
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const handler = commands[command];
|
|
113
|
+
if (!handler) {
|
|
114
|
+
console.error(`Unknown command: ${command}\n`);
|
|
115
|
+
printUsage();
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Ensure server is running for commands that need it
|
|
120
|
+
if (!NO_SERVER_COMMANDS.includes(command)) {
|
|
121
|
+
await ensureServerRunning();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await handler(args);
|
|
125
|
+
} catch (err) {
|
|
126
|
+
handleError(err);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
})();
|