Skip to content

Commit

Permalink
Fix: fixed issues with copying files and overriding
Browse files Browse the repository at this point in the history
  • Loading branch information
Dexagod committed Jan 8, 2025
1 parent 097d232 commit 633381c
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 48 deletions.
36 changes: 19 additions & 17 deletions src/commands/solid-copy.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import fs from 'fs'
import path from 'path'
import { getFile, getContentType, createContainerAt } from "@inrupt/solid-client"
import { isRemote, isDirectory, FileInfo, ensureDirectoryExistence, fixLocalPath, readRemoteDirectoryRecursively, checkRemoteFileExists, writeErrorString, isDirectoryContents } from '../utils/util';
import { isRemote, isDirectory, FileInfo, ensureDirectoryExistence, fixLocalPath, readRemoteDirectoryRecursively, checkRemoteFileExists, writeErrorString, isDirectoryContents, resourceExists } from '../utils/util';
import Blob from 'fetch-blob'
import { requestUserCLIConfirmation } from '../utils/userInteractions';
import { requestUserCLIConfirmationDefaultNegative } from '../utils/userInteractions';
import BashlibError from '../utils/errors/BashlibError';
import { BashlibErrorMessage } from '../utils/errors/BashlibError';
import type { Logger } from '../logger';
import { ICommandOptions, setOptionDefaults } from './solid-command';
import { resourceExists } from './solid-touch';

const mime = require('mime-types');

Expand All @@ -23,8 +22,8 @@ interface SourceOptions {

export interface ICommandOptionsCopy extends ICommandOptions {
all?: boolean,
interactiveOverride?: boolean,
noOverride?: boolean,
override?: boolean,
neverOverride?: boolean,
}

export default async function copy(src: string, dst: string, options?: ICommandOptionsCopy) : Promise<{
Expand All @@ -34,8 +33,8 @@ export default async function copy(src: string, dst: string, options?: ICommandO
let commandOptions = setOptionDefaults<ICommandOptionsCopy>(options || {});
let fetch = commandOptions.fetch;
commandOptions.all = commandOptions.all || false;
commandOptions.interactiveOverride = commandOptions.interactiveOverride || false;
commandOptions.noOverride = commandOptions.noOverride || false;
commandOptions.override = commandOptions.override || false;
commandOptions.neverOverride = commandOptions.neverOverride || false;

/**************************
* Preprocess src and dst *
Expand Down Expand Up @@ -277,12 +276,12 @@ async function writeLocalFile(resourcePath: string, fileInfo: FileInfo, options:
ensureDirectoryExistence(resourcePath);

let executeWrite = true
if (options.interactiveOverride || options.noOverride) {
if (fs.existsSync(resourcePath)) {
if (options.noOverride) {
if (options.neverOverride || !options.override) {
if (await resourceExists(resourcePath, options.fetch)) {
if (options.neverOverride) {
executeWrite = false;
} else if (options.interactiveOverride) {
executeWrite = await requestUserCLIConfirmation(`Overwrite local file: ${resourcePath}`)
} else {
executeWrite = await requestUserCLIConfirmationDefaultNegative(`Overwrite local file: ${resourcePath}`)
}
}
}
Expand All @@ -309,6 +308,7 @@ async function writeLocalFile(resourcePath: string, fileInfo: FileInfo, options:

if (fileData.buffer) {
fs.writeFileSync(resourcePath, fileData.buffer)
if (options.verbose) (options.logger || console).log(`Writing local resource: ${resourcePath}`);
} else if (fileData.blob) {
let buffer = Buffer.from(await fileData.blob.arrayBuffer())
fs.writeFileSync(resourcePath, buffer)
Expand All @@ -324,17 +324,17 @@ async function writeLocalFile(resourcePath: string, fileInfo: FileInfo, options:

async function writeRemoteFile(resourcePath: string, fileInfo: FileInfo, fetch: any, options: ICommandOptionsCopy): Promise<string | undefined> {
resourcePath = resourcePath.split('$.')[0];

let executeWrite = true
if (options.interactiveOverride || options.noOverride) {
if (options.neverOverride || !options.override) {
if (await resourceExists(resourcePath, fetch)) {
if (options.noOverride) {
if (options.neverOverride) {
executeWrite = false;
} else if (options.interactiveOverride) {
executeWrite = await requestUserCLIConfirmation(`Overwrite local file: ${resourcePath}`)
} else {
executeWrite = await requestUserCLIConfirmationDefaultNegative(`Overwrite remote file: ${resourcePath}`)
}
}
}

if (!executeWrite) {
if (options.verbose) (options.logger || console).log('Skipping existing local file:', resourcePath)
return undefined;
Expand All @@ -358,6 +358,7 @@ async function writeRemoteFile(resourcePath: string, fileInfo: FileInfo, fetch:
)
if (!res.ok)
throw new BashlibError(BashlibErrorMessage.httpResponseError, resourcePath, `${res.status} ${res.statusText}`)
else if (options.verbose) (options.logger || console).log(`Writing remote resource: ${resourcePath}`);

} else if (fileData.blob) {
let res = await fetch(
Expand All @@ -372,6 +373,7 @@ async function writeRemoteFile(resourcePath: string, fileInfo: FileInfo, fetch:
)
if (!res.ok)
throw new BashlibError(BashlibErrorMessage.httpResponseError, resourcePath, `${res.status} ${res.statusText}`)
else if (options.verbose) (options.logger || console).log(`Writing remote resource: ${resourcePath}`);
} else {
throw new BashlibError(BashlibErrorMessage.cannotWriteResource, resourcePath, "No contents to write")
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/solid-edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async function editRemoteFile(url: string, options: ICommandOptionsEdit) {
}

if (updateChanges) {
await copy(tmpFilePath, remoteFileUrl, options)
await copy(tmpFilePath, remoteFileUrl, { ...options, override: true })
if (options.verbose) (options.logger || console).log('Remote file updated!');
}
else {
Expand Down
5 changes: 4 additions & 1 deletion src/commands/solid-move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import remove from './solid-remove';
import { ICommandOptions, setOptionDefaults } from './solid-command';

export interface ICommandOptionsMove extends ICommandOptions {
all: boolean,
all?: boolean,
neverOverride?: boolean,
override?: boolean,
verbose?: boolean,
}
export default async function move(source: string, destination: string, options?: ICommandOptionsMove) {
let commandOptions = setOptionDefaults<ICommandOptionsMove>(options || {});
Expand Down
20 changes: 2 additions & 18 deletions src/commands/solid-touch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FetchError, getResourceInfo } from "@inrupt/solid-client"
import { setOptionDefaults, ICommandOptions } from './solid-command';
import { resourceExists } from "../utils/util";
const mime = require('mime-types');

export interface ICommandOptionsTouch extends ICommandOptions{
Expand All @@ -14,7 +15,7 @@ export default async function touch(url: string, options?: ICommandOptionsTouch)
throw new Error('Can\'t touch containers only resources')
}

let urlExists = await resourceExists(url, commandOptions);
let urlExists = await resourceExists(url, commandOptions.fetch);

if (urlExists) {
if (commandOptions.verbose) commandOptions.logger.log(`Remote file already exists`)
Expand Down Expand Up @@ -49,21 +50,4 @@ export default async function touch(url: string, options?: ICommandOptionsTouch)
throw new Error(`HTTP Error Response requesting ${url}: ${res.status} ${res.statusText}`)
}
}
}

export async function resourceExists(url: string, options: any) {
let fetch = options.fetch;

try {
let info = await getResourceInfo(url, { fetch: fetch })
return true;
}
catch (e) {
if (e instanceof FetchError && e.response.status === 404) {
return false;
}
else {
return undefined;
}
}
}
7 changes: 3 additions & 4 deletions src/shell/commands/copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ export default class CopyCommand extends SolidCommand {
.argument('<src>', 'file or directory to be copied')
.argument('<dst>', 'destination to copy file or directory to')
.option('-a, --all', 'Copy .acl files in recursive directory copies')
.option('-i, --interactive-override', 'Interactive confirmation prompt when overriding existing files')
.option('-n, --no-override', 'Do not override existing files')
// .option('-i, --interactive-override', 'Interactive confirmation prompt when overriding existing files')
.option('-o, --override', 'Automatically override existing files')
.option('-n, --never-override', 'Automatically override existing files')
.option('-v, --verbose', 'Log all read and write operations')
.action(this.executeCommand)

Expand All @@ -40,7 +41,5 @@ export default class CopyCommand extends SolidCommand {
}
if (this.mayExit) process.exit(0)
}


}

5 changes: 3 additions & 2 deletions src/shell/commands/mv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ export default class MkdirCommand extends SolidCommand {
.argument('<src>', 'file or directory to be moved')
.argument('<dst>', 'destination of the move')
.option('-a, --all', 'Move .acl files when moving directories recursively')
.option('-i, --interactive-override', 'Interactive confirmation prompt when overriding existing files')
.option('-n, --no-override', 'Do not override existing files')
// .option('-i, --interactive-override', 'Interactive confirmation prompt when overriding existing files')
.option('-o, --override', 'Automatically override existing files')
.option('-n, --never-override', 'Automatically override existing files')
.option('-v, --verbose', 'Log all operations')
.action(this.executeCommand)

Expand Down
21 changes: 19 additions & 2 deletions src/utils/userInteractions.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import inquirer from 'inquirer';

export async function requestUserCLIConfirmation(request: string) : Promise<boolean> {
export async function requestUserCLIConfirmationDefaultNegative(request: string) : Promise<boolean> {
console.log(`${request} [y/N]`);
return await new Promise((resolve, reject) => {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on('data', (chk) => {
process.stdin.once('data', (chk) => {
process.stdin.pause();
if (chk.toString('utf8') === "y") {
resolve(true);
} else {
Expand All @@ -15,6 +16,22 @@ export async function requestUserCLIConfirmation(request: string) : Promise<bool
});
}

export async function requestUserCLIConfirmationDefaultPositive(request: string) : Promise<boolean> {
console.log(`${request} [Y/n]`);
return await new Promise((resolve, reject) => {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.once('data', (chk) => {
process.stdin.pause();
if (chk.toString('utf8') === "n") {
resolve(false);
} else {
resolve(true);
}
});
});
}

export async function requestUserIdp() {
console.log(``);

Expand Down
16 changes: 13 additions & 3 deletions src/utils/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getSolidDataset, getContainedResourceUrlAll, getUrl, getUrlAll, getThing, getThingAll, getDatetime, getInteger, SolidDataset, acp_ess_2, hasAccessibleAcl } from '@inrupt/solid-client';
import { getSolidDataset, getContainedResourceUrlAll, getUrl, getUrlAll, getThing, getThingAll, getDatetime, getInteger, SolidDataset, acp_ess_2, hasAccessibleAcl, FetchError } from '@inrupt/solid-client';
import { requestUserIdp } from './userInteractions';
import type { Logger } from '../logger';

Expand Down Expand Up @@ -524,6 +524,16 @@ export async function discoverAccessMechanism(url: string, fetch: any) {
}

export async function resourceExists(url: string, fetch: any) {
let res = await fetch(url, {method: "HEAD"})
return res.ok
try {
let res = await fetch(url, { method: "HEAD" })
return res.ok;
}
catch (e) {
if (e instanceof FetchError && e.response.status === 404) {
return false;
}
else {
return undefined;
}
}
}

0 comments on commit 633381c

Please sign in to comment.