Skip to content

Commit 1caa484

Browse files
authored
Merge pull request #49 from jeswr/feat/custom-logger
feat: enable users to pass a custom logger
2 parents 9ba6bee + fd6e981 commit 1caa484

38 files changed

+144
-102
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"scripts": {
1010
"test": "echo \"Error: no test specified\" && exit 1",
1111
"build": "rm -rf dist/ && tsc",
12+
"prepare": "npm run build",
1213
"release": "release-it"
1314
},
1415
"author": "",

src/authentication/AuthenticationInteractive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default async function authenticateInteractive(options: IInteractiveAuthO
4040
}
4141
}
4242
} catch (e) {
43-
if (options?.verbose) writeErrorString('Could not load existing session', e);
43+
if (options?.verbose) writeErrorString('Could not load existing session', e, options);
4444
}
4545

4646

@@ -68,7 +68,7 @@ export default async function authenticateInteractive(options: IInteractiveAuthO
6868
try {
6969
return await createFetchWithNewAccessToken(options.idp, appName, port)
7070
} catch (e) {
71-
if (options?.verbose) writeErrorString('Error creating new session', e);
71+
if (options?.verbose) writeErrorString('Error creating new session', e, options);
7272
return { fetch: crossfetch }
7373
}
7474

src/authentication/AuthenticationToken.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ export async function authenticateToken(options?: IClientCredentialsTokenAuthOpt
4343
}
4444
}
4545
} catch (e) {
46-
if (options?.verbose) writeErrorString('Could not load existing session', e);
46+
if (options?.verbose) writeErrorString('Could not load existing session', e, options);
4747
}
4848
try {
4949
return createFetchWithNewAccessToken(options);
5050
} catch (e) {
51-
if (options?.verbose) writeErrorString('Could not create new session', e);
51+
if (options?.verbose) writeErrorString('Could not create new session', e, options);
5252
return { fetch: crossfetch }
5353
}
5454
}

src/authentication/CreateFetch.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import authenticateInteractive from "./AuthenticationInteractive";
22
import { authenticateToken } from "./AuthenticationToken";
3+
import type { Logger } from '../logger';
34

45
export const DEFAULTPORT = 3435
56
export const APPNAME = "Solid-cli"
@@ -9,6 +10,7 @@ export type IInteractiveAuthOptions = {
910
sessionInfoStorageLocation?: string, // Storage location of session information to reuse in subsequent runs of the application.
1011
port?: number, // Used for redirect url of Solid login sequence
1112
verbose?: boolean,
13+
logger?: Logger,
1214
}
1315

1416
export type IUserCredentialsAuthOptions = {
@@ -17,13 +19,15 @@ export type IUserCredentialsAuthOptions = {
1719
password: string,
1820
port?: number, // Used for redirect url of Solid login sequence
1921
verbose?: boolean,
22+
logger?: Logger,
2023
}
2124

2225
export type IClientCredentialsTokenAuthOptions = {
2326
idp?: string, // This value is stored with the created client credentials token.
2427
sessionInfoStorageLocation?: string, // Storage location of session information to reuse in subsequent runs of the application.
2528
clientCredentialsTokenStorageLocation?: string, // Storage location of the stored client credentials token.
2629
verbose?: boolean,
30+
logger?: Logger,
2731
}
2832

2933
export type IClientCredentialsTokenGenerationOptions = {
@@ -32,6 +36,7 @@ export type IClientCredentialsTokenGenerationOptions = {
3236
password: string,
3337
idp: string,
3438
clientCredentialsTokenStorageLocation?: string // Storage location of the output client credentials token.
39+
logger?: Logger,
3540
}
3641

3742
export type SessionInfo = {

src/authentication/authenticate.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import SolidFetchBuilder from './CreateFetch';
22
import { getWebIDIdentityProvider, writeErrorString } from '../utils/util';
33
import inquirer from 'inquirer';
44
import { getConfigCurrentWebID, getConfigCurrentToken } from '../utils/configoptions';
5+
import type { Logger } from '../logger';
56
import crossfetch from 'cross-fetch';
67

78
export type ILoginOptions = {
@@ -13,7 +14,8 @@ export type ILoginOptions = {
1314
config?: string,
1415
clientCredentialsTokenStorageLocation?: string, // Storage location of the stored client credentials token.
1516
sessionInfoStorageLocation?: string,
16-
verbose?: boolean,
17+
verbose?: boolean,
18+
logger?: Logger,
1719
}
1820

1921

@@ -34,15 +36,15 @@ export default async function authenticate(options: ILoginOptions): Promise<{ fe
3436
try {
3537
await builder.buildFromClientCredentialsToken(options)
3638
} catch (e) {
37-
if (options.verbose) writeErrorString(`Could not authenticate using client credentials token`, e);
39+
if (options.verbose) writeErrorString(`Could not authenticate using client credentials token`, e, options);
3840
}
3941

4042
} else if (authType === 'interactive') {
4143

4244
try {
4345
await builder.buildInteractive(options);
4446
} catch (e) {
45-
if (options.verbose) writeErrorString(`Could not authenticate interactively`, e);
47+
if (options.verbose) writeErrorString(`Could not authenticate interactively`, e, options);
4648
}
4749
}
4850

src/commands/solid-copy.ts

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Blob from 'fetch-blob'
66
import { requestUserCLIConfirmation } from '../utils/userInteractions';
77
import BashlibError from '../utils/errors/BashlibError';
88
import { BashlibErrorMessage } from '../utils/errors/BashlibError';
9+
import type { Logger } from '../logger';
910

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

@@ -24,6 +25,7 @@ type CopyOptions = {
2425
all?: boolean,
2526
interactiveOverride?: boolean,
2627
noOverride?: boolean,
28+
logger?: Logger
2729
}
2830

2931
export default async function copy(src: string, dst: string, options: CopyOptions) : Promise<{
@@ -69,15 +71,15 @@ export default async function copy(src: string, dst: string, options: CopyOption
6971
**********************/
7072

7173
if (source.isDir && !destination.isDir) {
72-
console.error('Cannot copy a directory to a file')
74+
(options.logger || console).error('Cannot copy a directory to a file')
7375
process.exit(1);
7476
}
7577

7678
let resourcesToTransfer : { files: FileInfo[], directories: FileInfo[], aclfiles: FileInfo[] };
7779
if (source.isRemote) {
78-
resourcesToTransfer = await getRemoteSourceFiles(source, fetch, options.verbose, options.all)
80+
resourcesToTransfer = await getRemoteSourceFiles(source, fetch, options.verbose, options.all, options)
7981
} else {
80-
resourcesToTransfer = await getLocalSourceFiles(source, options.verbose, options.all)
82+
resourcesToTransfer = await getLocalSourceFiles(source, options.verbose, options.all, options)
8183
}
8284

8385
let destinationInfo: { files: FileInfo[], directories: FileInfo[], aclfiles: FileInfo[] } = {
@@ -169,41 +171,41 @@ export default async function copy(src: string, dst: string, options: CopyOption
169171
* UTILITY FUNCTIONS *
170172
*********************/
171173

172-
async function getLocalSourceFiles(source: srcOptions, verbose: boolean, all: boolean): Promise<{files: FileInfo[], directories: FileInfo[], aclfiles: FileInfo[]}> {
174+
async function getLocalSourceFiles(source: srcOptions, verbose: boolean, all: boolean, options?: { logger?: Logger }): Promise<{files: FileInfo[], directories: FileInfo[], aclfiles: FileInfo[]}> {
173175
if (source.isDir) {
174176
let filePathInfos = readLocalDirectoryRecursively(source.path, undefined, {verbose, all} )
175177
let files = await Promise.all(filePathInfos.files.map(async fileInfo => {
176-
fileInfo.loadFile = async () => readLocalFile(fileInfo.absolutePath, verbose)
178+
fileInfo.loadFile = async () => readLocalFile(fileInfo.absolutePath, verbose, options)
177179
return fileInfo
178180
}))
179181
let aclfiles = await Promise.all(filePathInfos.aclfiles.map(async fileInfo => {
180-
fileInfo.loadFile = async () => readLocalFile(fileInfo.absolutePath, verbose)
182+
fileInfo.loadFile = async () => readLocalFile(fileInfo.absolutePath, verbose, options)
181183
return fileInfo
182184
}))
183185
return { files, aclfiles, directories: filePathInfos.directories }
184186
} else {
185187
return { files: [ {
186188
absolutePath: source.path,
187189
relativePath: '',
188-
loadFile: async () => readLocalFile(source.path, verbose)
190+
loadFile: async () => readLocalFile(source.path, verbose, options)
189191
} ], aclfiles: [], directories: [] }
190192
}
191193
}
192194

193-
async function getRemoteSourceFiles(source: srcOptions, fetch: Function, verbose: boolean, all: boolean) : Promise<{files: FileInfo[], directories: FileInfo[], aclfiles: FileInfo[]}> {
195+
async function getRemoteSourceFiles(source: srcOptions, fetch: Function, verbose: boolean, all: boolean, options?: { logger?: Logger }) : Promise<{files: FileInfo[], directories: FileInfo[], aclfiles: FileInfo[]}> {
194196
if (source.isDir) {
195197
let discoveredResources = await readRemoteDirectoryRecursively(source.path, { fetch, verbose, all})
196198

197199
// Filter out files that return errors (e.g no authentication privileges)
198200
let files = (await Promise.all(discoveredResources.files.map(async fileInfo => {
199-
fileInfo.loadFile = async () => readRemoteFile(fileInfo.absolutePath, fetch, verbose)
201+
fileInfo.loadFile = async () => readRemoteFile(fileInfo.absolutePath, fetch, verbose, options)
200202
return fileInfo
201203
}))).filter(f => f) as FileInfo[]
202204

203205
let aclfiles : FileInfo[] = []
204206
if (all) {
205207
aclfiles = (await Promise.all(discoveredResources.aclfiles.map(async fileInfo => {
206-
fileInfo.loadFile = async () => readRemoteFile(fileInfo.absolutePath, fetch, verbose)
208+
fileInfo.loadFile = async () => readRemoteFile(fileInfo.absolutePath, fetch, verbose, options)
207209
return fileInfo
208210
}))).filter(f => f) as FileInfo[]
209211
}
@@ -212,39 +214,39 @@ async function getRemoteSourceFiles(source: srcOptions, fetch: Function, verbose
212214
return { files: [ {
213215
absolutePath: source.path,
214216
relativePath: '',
215-
loadFile: async () => readRemoteFile(source.path, fetch, verbose)
217+
loadFile: async () => readRemoteFile(source.path, fetch, verbose, options)
216218
}] , aclfiles: [], directories: [] }
217219
}
218220

219221
}
220222

221-
function readLocalFile(path: string, verbose: boolean): { buffer: Buffer, contentType: string} {
222-
if (verbose) console.log('Reading local file:', path)
223+
function readLocalFile(path: string, verbose: boolean, options?: { logger?: Logger }): { buffer: Buffer, contentType: string} {
224+
if (verbose) (options?.logger || console).log('Reading local file:', path)
223225
const file = fs.readFileSync(path)
224226
let contentType = path.endsWith('.acl') || path.endsWith('.meta') ? 'text/turtle' : mime.lookup(path)
225227
return { buffer: file, contentType };
226228
}
227229

228-
async function readRemoteFile(path: string, fetch: any, verbose: boolean) : Promise<{ blob: any, contentType: string}> {
229-
if (verbose) console.log('Reading remote file:', path)
230+
async function readRemoteFile(path: string, fetch: any, verbose: boolean, options?: { logger?: Logger }) : Promise<{ blob: any, contentType: string}> {
231+
if (verbose) (options?.logger || console).log('Reading remote file:', path)
230232
const file = await getFile(path, { fetch })
231233
const contentType = await getContentType(file) as string // TODO:: error handling?
232234
return { blob: file as any, contentType };
233235

234236
}
235237

236238
async function writeLocalDirectory(path: string, fileInfo: FileInfo, options: CopyOptions): Promise<any> {
237-
if (options.verbose) console.log('Writing local directory:', path)
239+
if (options.verbose) (options.logger || console).log('Writing local directory:', path)
238240
fs.mkdirSync(path, { recursive: true })
239241
return true;
240242
}
241243

242244
async function writeRemoteDirectory(path: string, fileInfo: FileInfo, fetch: any, options: CopyOptions): Promise<any> {
243-
if (options.verbose) console.log('Writing remote directory:', path)
245+
if (options.verbose) (options.logger || console).log('Writing remote directory:', path)
244246
try {
245247
await createContainerAt(path, { fetch })
246248
} catch (e) {
247-
if (options.verbose) writeErrorString(`Could not write directory for ${path}`, e);
249+
if (options.verbose) writeErrorString(`Could not write directory for ${path}`, e, options);
248250
}
249251
}
250252

@@ -262,11 +264,11 @@ async function writeLocalFile(resourcePath: string, fileInfo: FileInfo, options:
262264
}
263265
}
264266
if (!executeWrite) {
265-
if (options.verbose) console.log('Skipping existing local file:', resourcePath)
267+
if (options.verbose) (options.logger || console).log('Skipping existing local file:', resourcePath)
266268
return undefined;
267269
}
268270

269-
if (options.verbose) console.log('processing local file:', resourcePath)
271+
if (options.verbose) (options.logger || console).log('processing local file:', resourcePath)
270272
try {
271273
if (!fileInfo.loadFile) throw new Error(`Could not load file at location: ${fileInfo.absolutePath}`)
272274
let fileData = await fileInfo.loadFile();
@@ -287,11 +289,11 @@ async function writeLocalFile(resourcePath: string, fileInfo: FileInfo, options:
287289
let buffer = Buffer.from(await fileData.blob.arrayBuffer())
288290
fs.writeFileSync(resourcePath, buffer)
289291
} else {
290-
console.error('No content to write for:', resourcePath)
292+
(options.logger || console).error('No content to write for:', resourcePath)
291293
}
292294
return resourcePath;
293295
} catch (e) {
294-
if (options.verbose) writeErrorString(`Could not save local file ${resourcePath}`, e);
296+
if (options.verbose) writeErrorString(`Could not save local file ${resourcePath}`, e, options);
295297
return undefined;
296298
}
297299
}
@@ -310,7 +312,7 @@ async function writeRemoteFile(resourcePath: string, fileInfo: FileInfo, fetch:
310312
}
311313
}
312314
if (!executeWrite) {
313-
if (options.verbose) console.log('Skipping existing local file:', resourcePath)
315+
if (options.verbose) (options.logger || console).log('Skipping existing local file:', resourcePath)
314316
return undefined;
315317
}
316318

src/commands/solid-edit.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import path from "path"
33
import copy from "./solid-copy";
44
import fs from 'fs';
55
import { checkRemoteFileAccess, checkRemoteFileExists, getPodRoot } from "../utils/util";
6+
import type { Logger } from '../logger';
7+
68
const md5 = require('md5');
79
const child_process = require('child_process')
810

@@ -11,6 +13,7 @@ type CommandOptionEdit = {
1113
editor?: string,
1214
touch?: boolean,
1315
verbose?: boolean,
16+
logger?: Logger,
1417
}
1518

1619
export default async function edit(url: string, options: CommandOptionEdit) {
@@ -49,10 +52,10 @@ async function editRemoteFile(url: string, options: CommandOptionEdit) {
4952
child.on('exit', function (e: any, code: any) {
5053
resolve();
5154
});
52-
})
55+
});
5356

5457
// Wait for the user to finish editing the
55-
console.log('Press any key to continue');
58+
(options.logger || console).log('Press any key to continue');
5659
await new Promise<void>((resolve, reject) => {
5760
process.stdin.setRawMode(true);
5861
process.stdin.resume();
@@ -64,7 +67,7 @@ async function editRemoteFile(url: string, options: CommandOptionEdit) {
6467
let updateChanges = true;
6568
// Request user update -> required for editors that leave the terminal and continue the program.
6669
if (oldMd5 === newMd5) {
67-
console.log('Update without changes? [y/N] ');
70+
(options.logger || console).log('Update without changes? [y/N] ');
6871
updateChanges = await new Promise((resolve, reject) => {
6972
process.stdin.setRawMode(true);
7073
process.stdin.resume();
@@ -80,17 +83,17 @@ async function editRemoteFile(url: string, options: CommandOptionEdit) {
8083

8184
if (updateChanges) {
8285
await copy(tmpFilePath, remoteFileUrl, options)
83-
if (options.verbose) console.log('Remote file updated!');
86+
if (options.verbose) (options.logger || console).log('Remote file updated!');
8487
}
8588
else {
86-
if (options.verbose) console.log('Remote file untouched');
89+
if (options.verbose) (options.logger || console).log('Remote file untouched');
8790
}
8891
} catch (e) {
8992
throw e
9093
// TODO::
9194
} finally {
9295
if(tmpFilePath) fs.unlinkSync(tmpFilePath);
93-
if (options.verbose) console.log(`Removing local file file ${tmpFilePath}!`);
96+
if (options.verbose) (options.logger || console).log(`Removing local file file ${tmpFilePath}!`);
9497
}
9598
}
9699

@@ -114,24 +117,24 @@ async function editNewFile(url: string, options: CommandOptionEdit) {
114117
child.on('exit', function (e: any, code: any) {
115118
resolve();
116119
});
117-
})
120+
});
118121

119122
// Wait for the user to finish editing the
120-
console.log('Press any key to continue');
123+
(options.logger || console).log('Press any key to continue');
121124
await new Promise<void>((resolve, reject) => {
122125
process.stdin.setRawMode(true);
123126
process.stdin.resume();
124127
process.stdin.on('data', () => resolve());
125128
})
126129

127130
await copy(tmpFilePath, url, options)
128-
if (options.verbose) console.log('Remote file updated!');
131+
if (options.verbose) (options.logger || console).log('Remote file updated!');
129132
} catch (e) {
130133
throw e
131134
// TODO::
132135
} finally {
133136
if(tmpFilePath) fs.unlinkSync(tmpFilePath);
134-
if (options.verbose) console.log(`Removing local file file ${tmpFilePath}!`);
137+
if (options.verbose) (options.logger || console).log(`Removing local file file ${tmpFilePath}!`);
135138
}
136139
}
137140

0 commit comments

Comments
 (0)