Refactor remote commands into remote subdirectory

This commit is contained in:
2026-03-20 16:24:09 +01:00
parent 344e10ac46
commit 1d04649cbf
5 changed files with 77 additions and 91 deletions
+2 -2
View File
@@ -50,8 +50,8 @@ this will check the health, and if not setup, it will prompt you to set up the C
- `shsf file overwrite`: Overwrite an existing file in a storage. (use `shsf file overwrite -h` first) - `shsf file overwrite`: Overwrite an existing file in a storage. (use `shsf file overwrite -h` first)
- `shsf file delete`: Delete a file from a storage. (use `shsf file delete -h` first) - `shsf file delete`: Delete a file from a storage. (use `shsf file delete -h` first)
- `shsf file list`: List files in a storage. (use `shsf file list -h` first) - `shsf file list`: List files in a storage. (use `shsf file list -h` first)
- `shsf remote --id <id> --into <path>`: Pull files from a function into a local directory. - `shsf remote pull --id <id> --into <path> [--force]`: Pull files from a function into a local directory.
- `shsf remote --id <id> --from <path> [--force]`: Push files from a local directory to a function. - `shsf remote push --id <id> --from <path> [--force]`: Push files from a local directory to a function.
## Instructions ## Instructions
Use these commands for when you need to interact with shsf from the command line. Its faster than using the ui for almost all ops. Use these commands for when you need to interact with shsf from the command line. Its faster than using the ui for almost all ops.
-12
View File
@@ -1,12 +0,0 @@
import { describe, it, expect, vi } from 'vitest';
import { action } from '../commands/remote.js';
import axios from 'axios';
vi.mock('axios');
describe('remote command', () => {
it('should validate inputs', async () => {
// Simple test for now
await expect(action({})).resolves.not.toThrow();
});
});
-77
View File
@@ -1,77 +0,0 @@
import { Command } from 'commander';
import axios from 'axios';
import { loadConfig } from '../config.js';
import chalk from 'chalk';
import fs from 'fs';
import path from 'path';
export async function action(options: any) {
const config = await loadConfig();
const api = axios.create({
baseURL: config.apiBaseUrl,
headers: { 'Authorization': `Bearer ${config.token}` }
});
if (options.into) {
// PULL
try {
const response = await api.get(`/functions/${options.id}/files`);
const files = response.data; // Assuming { filename: string, content: string }[]
if (!fs.existsSync(options.into)) {
fs.mkdirSync(options.into, { recursive: true });
} else if (fs.readdirSync(options.into).length > 0 && !options.force) {
console.error(chalk.red(`Directory ${options.into} is not empty. Use --force to overwrite.`));
return;
}
for (const file of files) {
fs.writeFileSync(path.join(options.into, file.filename), file.content);
}
console.log(chalk.green(`Successfully pulled files into ${options.into}`));
} catch (e) {
console.error(chalk.red('Failed to pull files'), e);
}
} else if (options.from) {
// PUSH
if (!fs.existsSync(options.from)) {
console.error(chalk.red(`Source ${options.from} does not exist.`));
return;
}
const files = fs.readdirSync(options.from).map(file => ({
filename: file,
content: fs.readFileSync(path.join(options.from, file), 'utf-8')
}));
if (!options.force) {
console.log(chalk.yellow(`Pushing ${files.length} files. Review: ${files.map(f => f.filename).join(', ')}`));
if (files.length > 5) {
console.log(chalk.yellow('Too many modifications. Please use --force to confirm.'));
return;
}
}
try {
await api.post(`/functions/${options.id}/files`, { files });
console.log(chalk.green('Successfully pushed files.'));
} catch (e) {
console.error(chalk.red('Failed to push files'), e);
}
} else {
console.error(chalk.red('Must specify --into or --from'));
}
}
export default {
name: 'remote',
description: 'sync remote functions to/from local storage',
options: [
{ name: '--id <id>', description: 'function id', required: true },
{ name: '--into <path>', description: 'target directory for pull' },
{ name: '--from <path>', description: 'source directory for push' },
{ name: '--force', description: 'force push/pull without confirmation' }
],
action
};
+36
View File
@@ -0,0 +1,36 @@
import chalk from "chalk";
import { getApiClient } from "../../api.js";
import fs from "fs";
import path from "path";
export const pullDefinition = {
name: "pull",
description: "Pull files from a remote function.",
options: [
{ name: "--id <id>", description: "Function ID", required: true },
{ name: "--into <path>", description: "Target directory", required: true },
{ name: "--force", description: "Force overwrite" },
],
action: async (options: any) => {
const client = await getApiClient();
try {
const response = await client.get(`/functions/${options.id}/files`);
const files = response.data; // Expecting { filename: string, content: string }[]
if (!fs.existsSync(options.into)) {
fs.mkdirSync(options.into, { recursive: true });
} else if (fs.readdirSync(options.into).length > 0 && !options.force) {
console.error(chalk.red(`Directory ${options.into} is not empty. Use --force to overwrite.`));
return;
}
for (const file of files) {
fs.writeFileSync(path.join(options.into, file.filename), file.content);
}
console.log(chalk.green(`Successfully pulled ${files.length} files into ${options.into}`));
} catch (error: any) {
console.error(chalk.red(`Failed to pull files: ${error.message}`));
}
},
};
+39
View File
@@ -0,0 +1,39 @@
import chalk from "chalk";
import { getApiClient } from "../../api.js";
import fs from "fs";
import path from "path";
export const pushDefinition = {
name: "push",
description: "Push files to a remote function.",
options: [
{ name: "--id <id>", description: "Function ID", required: true },
{ name: "--from <path>", description: "Source directory", required: true },
{ name: "--force", description: "Force overwrite" },
],
action: async (options: any) => {
const client = await getApiClient();
if (!fs.existsSync(options.from)) {
console.error(chalk.red(`Source ${options.from} does not exist.`));
return;
}
const files = fs.readdirSync(options.from).map(file => ({
filename: file,
content: fs.readFileSync(path.join(options.from, file), 'utf-8')
}));
if (!options.force && files.length > 5) {
console.log(chalk.yellow('Too many modifications. Please use --force to confirm.'));
return;
}
try {
await client.post(`/functions/${options.id}/files`, { files });
console.log(chalk.green(`Successfully pushed ${files.length} files to function ${options.id}`));
} catch (error: any) {
console.error(chalk.red(`Failed to push files: ${error.message}`));
}
},
};