Skip to content

Commit

Permalink
feat: Allow dynamically adding CLI parameters in configs
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimvh committed Apr 15, 2022
1 parent e651999 commit bedab90
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 30 deletions.
6 changes: 6 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- The server can be started with a new parameter to automatically generate accounts and pods,
for more info see [here](guides/seeding-pods.md).
- A new `RedirectingHttpHandler` class has been added which can be used to redirect certain URLs.
- A new default configuration `config/https-file-cli.json`
that can set the HTTPS parameters through the CLI has been added.
This is also an example of how to add CLI parameters through a custom configuration.

### Configuration changes
You might need to make changes to your v3 configuration if you use a custom config.
Expand All @@ -18,6 +21,8 @@ The following changes pertain to the imports in the default configs:
The following changes are relevant for v3 custom configs that replaced certain features.
- The key/value storage configs in `config/storage/key-value/*` have been changed to reduce config duplication.
All storages there that were only relevant for 1 class have been moved to the config of that class.
- Due to a parameter rename in `CombinedSettingsResolver`,
`config/app/variables/resolver/resolver.json` has been updated.

### Interface changes
These changes are relevant if you wrote custom modules for the server that depend on existing interfaces.
Expand All @@ -27,6 +32,7 @@ These changes are relevant if you wrote custom modules for the server that depen
and has been moved to a separate `ResourceSet` interface.
- Several `ModesExtractor`s `PermissionBasedAuthorizer` now take a `ResourceSet` as constructor parameter.
- `RepresentationMetadata` no longer accepts strings for predicates in any of its functions.
- `CombinedSettingsResolver` parameter `computers` has been renamed to `resolvers`.

## v3.0.0
### New features
Expand Down
34 changes: 17 additions & 17 deletions config/app/variables/resolver/resolver.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,63 @@
"comment": "Converts an input key/value object into an object mapping values to Components.js variables",
"@id": "urn:solid-server-app-setup:default:SettingsResolver",
"@type": "CombinedSettingsResolver",
"computers": [
"resolvers": [
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:baseUrl",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:baseUrl",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "BaseUrlExtractor"
}
},
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:loggingLevel",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:loggingLevel",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "KeyExtractor",
"key": "loggingLevel",
"defaultValue": "info"
}
},
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:port",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:port",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "KeyExtractor",
"key": "port",
"defaultValue": 3000
}
},
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:rootFilePath",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:rootFilePath",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "AssetPathExtractor",
"key": "rootFilePath",
"defaultPath": "./"
}
},
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:sparqlEndpoint",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:sparqlEndpoint",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "KeyExtractor",
"key": "sparqlEndpoint"
}
},
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:showStackTrace",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:showStackTrace",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "KeyExtractor",
"key": "showStackTrace",
"defaultValue": false
}
},
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:podConfigJson",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:podConfigJson",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "AssetPathExtractor",
"key": "podConfigJson",
"defaultPath": "./pod-config.json"
}
},
{
"CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:seededPodConfigJson",
"CombinedSettingsResolver:_computers_value": {
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:seededPodConfigJson",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "AssetPathExtractor",
"key": "seededPodConfigJson"
}
Expand Down
109 changes: 109 additions & 0 deletions config/https-file-cli.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^3.0.0/components/context.jsonld",
"import": [
"files-scs:config/app/main/default.json",
"files-scs:config/app/init/default.json",
"files-scs:config/app/setup/required.json",
"files-scs:config/app/variables/default.json",
"files-scs:config/http/handler/default.json",
"files-scs:config/http/middleware/websockets.json",

"files-scs:config/http/static/default.json",
"files-scs:config/identity/access/public.json",
"files-scs:config/identity/email/default.json",
"files-scs:config/identity/handler/default.json",
"files-scs:config/identity/ownership/token.json",
"files-scs:config/identity/pod/static.json",
"files-scs:config/identity/registration/enabled.json",
"files-scs:config/ldp/authentication/dpop-bearer.json",
"files-scs:config/ldp/authorization/webacl.json",
"files-scs:config/ldp/handler/default.json",
"files-scs:config/ldp/metadata-parser/default.json",
"files-scs:config/ldp/metadata-writer/default.json",
"files-scs:config/ldp/modes/default.json",
"files-scs:config/storage/backend/file.json",
"files-scs:config/storage/key-value/resource-store.json",
"files-scs:config/storage/middleware/default.json",
"files-scs:config/util/auxiliary/acl.json",
"files-scs:config/util/identifiers/suffix.json",
"files-scs:config/util/index/default.json",
"files-scs:config/util/logging/winston.json",
"files-scs:config/util/representation-conversion/default.json",
"files-scs:config/util/resource-locker/memory.json",
"files-scs:config/util/variables/default.json"
],
"@graph": [
{
"comment": [
"Adds CLI options --httpsKey and --httpsCert and uses those to start an HTTPS server.",
"The http/server-factory import above has been omitted since that feature is set below."
]
},
{
"@id": "urn:solid-server-app-setup:default:CliExtractor",
"@type": "YargsCliExtractor",
"extendedParameters": {
"httpsKey": {
"demandOption": true,
"requiresArg": true,
"type": "string",
"describe": "File path to the HTTPS key."
},
"httpsCert": {
"demandOption": true,
"requiresArg": true,
"type": "string",
"describe": "File path to the HTTPS certificate."
}
}
},
{
"comment": "Adds resolvers to assign the CLI values to the Components.js variables.",
"@id": "urn:solid-server-app-setup:default:SettingsResolver",
"@type": "CombinedSettingsResolver",
"resolvers": [
{
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:custom:variable:httpsKey",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "KeyExtractor",
"key": "httpsKey"
}
},
{
"CombinedSettingsResolver:_resolvers_key": "urn:solid-server:custom:variable:httpsCert",
"CombinedSettingsResolver:_resolvers_value": {
"@type": "KeyExtractor",
"key": "httpsCert"
}
}
]
},
{
"comment": [
"Creates an HTTPS server with the settings provided via the command line.",
"Replaces the example import from config/http/server-factory.https-example.json."
],
"@id": "urn:solid-server:default:ServerFactory",
"@type": "WebSocketServerFactory",
"baseServerFactory": {
"@id": "urn:solid-server:default:HttpServerFactory",
"@type": "BaseHttpServerFactory",
"handler": { "@id": "urn:solid-server:default:HttpHandler" },
"options_showStackTrace": { "@id": "urn:solid-server:default:variable:showStackTrace" },
"options_https": true,
"options_key": {
"@id": "urn:solid-server:custom:variable:httpsKey",
"@type": "Variable"
},
"options_cert": {
"@id": "urn:solid-server:custom:variable:httpsCert",
"@type": "Variable"
}
},
"webSocketHandler": {
"@type": "UnsecureWebSocketsProtocol",
"source": { "@id": "urn:solid-server:default:ResourceStore" }
}
}
]
}
7 changes: 5 additions & 2 deletions src/init/cli/YargsCliExtractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ export class YargsCliExtractor extends CliExtractor {
* @param parameters - Parameters that should be parsed from the CLI. @range {json}
* Format details can be found at https://yargs.js.org/docs/#api-reference-optionskey-opt
* @param options - Additional options to configure yargs. @range {json}
* @param extendedParameters - The same as @parameters. Separate variable so in Components.js
* we can have both a default set and a user-added version. @range {json}
*/
public constructor(parameters: YargsArgOptions = {}, options: CliOptions = {}) {
public constructor(parameters: YargsArgOptions = {}, options: CliOptions = {},
extendedParameters: YargsArgOptions = {}) {
super();
this.yargsArgOptions = parameters;
this.yargsArgOptions = { ...parameters, ...extendedParameters };
this.yargvOptions = options;
}

Expand Down
8 changes: 4 additions & 4 deletions src/init/variables/CombinedSettingsResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { SettingsResolver } from './SettingsResolver';
* Generates variable values by running a set of {@link SettingsExtractor}s on the input.
*/
export class CombinedSettingsResolver extends SettingsResolver {
public readonly computers: Record<string, SettingsExtractor>;
public readonly resolvers: Record<string, SettingsExtractor>;

public constructor(computers: Record<string, SettingsExtractor>) {
public constructor(resolvers: Record<string, SettingsExtractor>) {
super();
this.computers = computers;
this.resolvers = resolvers;
}

public async handle(input: Record<string, unknown>): Promise<Record<string, unknown>> {
const vars: Record<string, any> = {};
for (const [ name, computer ] of Object.entries(this.computers)) {
for (const [ name, computer ] of Object.entries(this.resolvers)) {
try {
vars[name] = await computer.handleSafe(input);
} catch (err: unknown) {
Expand Down
11 changes: 11 additions & 0 deletions test/unit/init/cli/YargsCliExtractor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { YargsCliExtractor } from '../../../../src/init/cli/YargsCliExtractor';
const error = jest.spyOn(console, 'error').mockImplementation(jest.fn());
const log = jest.spyOn(console, 'log').mockImplementation(jest.fn());
const exit = jest.spyOn(process, 'exit').mockImplementation(jest.fn() as any);

describe('A YargsCliExtractor', (): void => {
const parameters: YargsArgOptions = {
baseUrl: { alias: 'b', requiresArg: true, type: 'string' },
Expand Down Expand Up @@ -41,6 +42,16 @@ describe('A YargsCliExtractor', (): void => {
await expect(extractor.handle(argv)).resolves.toEqual(expect.objectContaining({}));
});

it('combines parameters and extra parameters.', async(): Promise<void> => {
extractor = new YargsCliExtractor(parameters, {}, { test: { alias: 't', requiresArg: true, type: 'string' }});
const argv = [ 'node', 'script', '-b', 'http://localhost:3000/', '-p', '3000', '-t', 'test' ];
await expect(extractor.handle(argv)).resolves.toEqual(expect.objectContaining({
baseUrl: 'http://localhost:3000/',
port: 3000,
test: 'test',
}));
});

it('prints usage if defined.', async(): Promise<void> => {
extractor = new YargsCliExtractor(parameters, { usage: 'node ./bin/server.js [args]' });
const argv = [ 'node', 'script', '--help' ];
Expand Down
14 changes: 7 additions & 7 deletions test/unit/init/variables/CombinedSettingsResolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ describe('A CombinedSettingsResolver', (): void => {
const values = { test: 'data' };
const varPort = 'urn:solid-server:default:variable:port';
const varLog = 'urn:solid-server:default:variable:loggingLevel';
let computerPort: jest.Mocked<SettingsExtractor>;
let computerLog: jest.Mocked<SettingsExtractor>;
let resolverPort: jest.Mocked<SettingsExtractor>;
let resolverLog: jest.Mocked<SettingsExtractor>;
let resolver: CombinedSettingsResolver;

beforeEach(async(): Promise<void> => {
computerPort = {
resolverPort = {
handleSafe: jest.fn().mockResolvedValue(3000),
} as any;

computerLog = {
resolverLog = {
handleSafe: jest.fn().mockResolvedValue('info'),
} as any;

resolver = new CombinedSettingsResolver({
[varPort]: computerPort,
[varLog]: computerLog,
[varPort]: resolverPort,
[varLog]: resolverLog,
});
});

Expand All @@ -32,7 +32,7 @@ describe('A CombinedSettingsResolver', (): void => {
});

it('rethrows the error if something goes wrong.', async(): Promise<void> => {
computerPort.handleSafe.mockRejectedValueOnce(new Error('bad data'));
resolverPort.handleSafe.mockRejectedValueOnce(new Error('bad data'));
await expect(resolver.handle(values)).rejects.toThrow(`Error in computing value for variable ${varPort}: bad data`);
});
});

0 comments on commit bedab90

Please sign in to comment.