change: Use @css: instead of $PACKAGE_ROOT/

This makes usage from the command line easier,
since $ is typically used to mark variables.
This commit is contained in:
Ruben Verborgh 2021-08-03 12:31:19 +01:00
parent f28279e3a5
commit 1719857e4b
20 changed files with 67 additions and 52 deletions

View File

@ -36,15 +36,23 @@ you can run a [Docker](https://www.docker.com/) version instead.
### 💻 Installing and running locally ### 💻 Installing and running locally
After installing Node.js, After installing Node.js,
you can install and run the latest published version install the latest server version
from the [npm package repository](https://www.npmjs.com/) from the [npm package repository](https://www.npmjs.com/):
like this:
```shell ```shell
npm install -g @solid/community-server npm install -g @solid/community-server
```
To run the server with in-memory storage, use:
```shell
community-solid-server # add parameters if needed community-solid-server # add parameters if needed
``` ```
To run the server with your current folder as storage, use:
```shell
community-solid-server -c @css:config/file.json
```
### 📃 Installing and running from source ### 📃 Installing and running from source
If you rather prefer to run the latest source code version, If you rather prefer to run the latest source code version,
or if you want to try a specific [branch](https://www.npmjs.com/) of the code, or if you want to try a specific [branch](https://www.npmjs.com/) of the code,
@ -84,17 +92,17 @@ by passing parameters to the server command.
These parameters give you direct access These parameters give you direct access
to some commonly used settings: to some commonly used settings:
| parameter name | default value | description | | parameter name | default value | description |
| --------- | ------- | ----------- | | -------------- | ------------- | ----------- |
| `--port, -p` | `3000` | The TCP port on which the server runs. | | `--port, -p` | `3000` | The TCP port on which the server runs. |
| `--baseUrl. -b` | `http://localhost:$PORT/` | The public URL of your server. | | `--baseUrl. -b` | `http://localhost:$PORT/` | The public URL of your server. |
| `--loggingLevel, -l` | `info` | The detail level of logging; useful for debugging problems. | | `--loggingLevel, -l` | `info` | The detail level of logging; useful for debugging problems. |
| `--config, -c` | `config/default.json` | The configuration for the server. The default only stores data in memory; to persist to your filesystem, try `config/file.json` | | `--config, -c` | `@css:config/default.json` | The configuration for the server. The default only stores data in memory; to persist to your filesystem, use `@css:config/file.json` |
| `--rootFilePath, -f` | `./` | Root folder of the server, when using a file-based configuration. | | `--rootFilePath, -f` | `./` | Root folder of the server, when using a file-based configuration. |
| `--sparqlEndpoint, -s` | | URL of the SPARQL endpoint, when using a quadstore-based configuration. | | `--sparqlEndpoint, -s` | | URL of the SPARQL endpoint, when using a quadstore-based configuration. |
| `--showStackTrace, -t` | false | Enables detailed logging on error pages. | | `--showStackTrace, -t` | false | Enables detailed logging on error pages. |
| `--podConfigJson` | `./pod-config.json` | Path to the file that keeps track of dynamic Pod configurations. | | `--podConfigJson` | `./pod-config.json` | Path to the file that keeps track of dynamic Pod configurations. |
| `--mainModulePath, -m` | | Path from where Components.js will start its lookup when initializing configurations. | `--mainModulePath, -m` | | Path from where Components.js will start its lookup when initializing configurations.
### 🧶 Custom configurations ### 🧶 Custom configurations
More substantial changes to server behavior can be achieved More substantial changes to server behavior can be achieved

View File

@ -9,7 +9,7 @@
"store": { "@id": "urn:solid-server:default:ResourceStore" }, "store": { "@id": "urn:solid-server:default:ResourceStore" },
"generator": { "generator": {
"@type": "TemplatedResourcesGenerator", "@type": "TemplatedResourcesGenerator",
"templateFolder": "$PACKAGE_ROOT/templates/root", "templateFolder": "@css:templates/root",
"factory": { "@type": "ExtensionBasedMapperFactory" }, "factory": { "@type": "ExtensionBasedMapperFactory" },
"templateEngine": { "@type": "HandlebarsTemplateEngine" } "templateEngine": { "@type": "HandlebarsTemplateEngine" }
} }

View File

@ -9,19 +9,19 @@
"assets": [ "assets": [
{ {
"StaticAssetHandler:_assets_key": "/favicon.ico", "StaticAssetHandler:_assets_key": "/favicon.ico",
"StaticAssetHandler:_assets_value": "$PACKAGE_ROOT/templates/images/favicon.ico" "StaticAssetHandler:_assets_value": "@css:templates/images/favicon.ico"
}, },
{ {
"StaticAssetHandler:_assets_key": "/.well_known/css/styles/", "StaticAssetHandler:_assets_key": "/.well_known/css/styles/",
"StaticAssetHandler:_assets_value": "$PACKAGE_ROOT/templates/styles/" "StaticAssetHandler:_assets_value": "@css:templates/styles/"
}, },
{ {
"StaticAssetHandler:_assets_key": "/.well_known/css/fonts/", "StaticAssetHandler:_assets_key": "/.well_known/css/fonts/",
"StaticAssetHandler:_assets_value": "$PACKAGE_ROOT/templates/fonts/" "StaticAssetHandler:_assets_value": "@css:templates/fonts/"
}, },
{ {
"StaticAssetHandler:_assets_key": "/.well_known/css/images/", "StaticAssetHandler:_assets_key": "/.well_known/css/images/",
"StaticAssetHandler:_assets_value": "$PACKAGE_ROOT/templates/images/" "StaticAssetHandler:_assets_value": "@css:templates/images/"
} }
] ]
} }

View File

@ -35,7 +35,7 @@
{ {
"comment": "Will embed the result of the first engine into the main HTML template.", "comment": "Will embed the result of the first engine into the main HTML template.",
"@type": "EjsTemplateEngine", "@type": "EjsTemplateEngine",
"template": "$PACKAGE_ROOT/templates/main.html.ejs", "template": "@css:templates/main.html.ejs",
} }
] ]
} }

View File

@ -6,8 +6,8 @@
"@id": "urn:solid-server:auth:password:ForgotPasswordRoute", "@id": "urn:solid-server:auth:password:ForgotPasswordRoute",
"@type": "InteractionRoute", "@type": "InteractionRoute",
"route": "^/forgotpassword/?$", "route": "^/forgotpassword/?$",
"viewTemplate": "$PACKAGE_ROOT/templates/identity/email-password/forgot-password.html.ejs", "viewTemplate": "@css:templates/identity/email-password/forgot-password.html.ejs",
"responseTemplate": "$PACKAGE_ROOT/templates/identity/email-password/forgot-password-response.html.ejs", "responseTemplate": "@css:templates/identity/email-password/forgot-password-response.html.ejs",
"handler": { "handler": {
"@type": "ForgotPasswordHandler", "@type": "ForgotPasswordHandler",
"args_accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" }, "args_accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" },
@ -15,7 +15,7 @@
"args_idpPath": "/idp", "args_idpPath": "/idp",
"args_templateEngine": { "args_templateEngine": {
"@type": "EjsTemplateEngine", "@type": "EjsTemplateEngine",
"template": "$PACKAGE_ROOT/templates/identity/email-password/reset-password-email.html.ejs" "template": "@css:templates/identity/email-password/reset-password-email.html.ejs"
}, },
"args_emailSender": { "@id": "urn:solid-server:default:EmailSender" } "args_emailSender": { "@id": "urn:solid-server:default:EmailSender" }
} }

View File

@ -7,7 +7,7 @@
"@type": "InteractionRoute", "@type": "InteractionRoute",
"route": "^/login/?$", "route": "^/login/?$",
"prompt": "default", "prompt": "default",
"viewTemplate": "$PACKAGE_ROOT/templates/identity/email-password/login.html.ejs", "viewTemplate": "@css:templates/identity/email-password/login.html.ejs",
"handler": { "handler": {
"@type": "LoginHandler", "@type": "LoginHandler",
"accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" } "accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" }

View File

@ -7,8 +7,8 @@
"@id": "urn:solid-server:auth:password:ResetPasswordRoute", "@id": "urn:solid-server:auth:password:ResetPasswordRoute",
"@type": "InteractionRoute", "@type": "InteractionRoute",
"route": "^/resetpassword(/[^/]*)?$", "route": "^/resetpassword(/[^/]*)?$",
"viewTemplate": "$PACKAGE_ROOT/templates/identity/email-password/reset-password.html.ejs", "viewTemplate": "@css:templates/identity/email-password/reset-password.html.ejs",
"responseTemplate": "$PACKAGE_ROOT/templates/identity/email-password/reset-password-response.html.ejs", "responseTemplate": "@css:templates/identity/email-password/reset-password-response.html.ejs",
"handler": { "handler": {
"@type": "ResetPasswordHandler", "@type": "ResetPasswordHandler",
"accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" } "accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" }

View File

@ -7,7 +7,7 @@
"@type": "InteractionRoute", "@type": "InteractionRoute",
"route": "^/confirm/?$", "route": "^/confirm/?$",
"prompt": "consent", "prompt": "consent",
"viewTemplate": "$PACKAGE_ROOT/templates/identity/email-password/confirm.html.ejs", "viewTemplate": "@css:templates/identity/email-password/confirm.html.ejs",
"handler": { "handler": {
"@type": "SessionHttpHandler", "@type": "SessionHttpHandler",
"providerFactory": { "@id": "urn:solid-server:default:IdentityProviderFactory" } "providerFactory": { "@id": "urn:solid-server:default:IdentityProviderFactory" }

View File

@ -5,7 +5,7 @@
"comment": "Generates resources based on the templates stored in the template folder.", "comment": "Generates resources based on the templates stored in the template folder.",
"@id": "urn:solid-server:default:ResourcesGenerator", "@id": "urn:solid-server:default:ResourcesGenerator",
"@type": "TemplatedResourcesGenerator", "@type": "TemplatedResourcesGenerator",
"templateFolder": "$PACKAGE_ROOT/templates/pod", "templateFolder": "@css:templates/pod",
"factory": { "factory": {
"@type": "ExtensionBasedMapperFactory" "@type": "ExtensionBasedMapperFactory"
}, },

View File

@ -6,8 +6,8 @@
"@id": "urn:solid-server:auth:password:RegistrationRoute", "@id": "urn:solid-server:auth:password:RegistrationRoute",
"@type": "InteractionRoute", "@type": "InteractionRoute",
"route": "^/register/?$", "route": "^/register/?$",
"viewTemplate": "$PACKAGE_ROOT/templates/identity/email-password/register.html.ejs", "viewTemplate": "@css:templates/identity/email-password/register.html.ejs",
"responseTemplate": "$PACKAGE_ROOT/templates/identity/email-password/register-response.html.ejs", "responseTemplate": "@css:templates/identity/email-password/register-response.html.ejs",
"handler": { "handler": {
"@type": "RegistrationHandler", "@type": "RegistrationHandler",
"args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" }, "args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },

View File

@ -12,7 +12,7 @@
"@type": "MarkdownToHtmlConverter", "@type": "MarkdownToHtmlConverter",
"templateEngine": { "templateEngine": {
"@type": "EjsTemplateEngine", "@type": "EjsTemplateEngine",
"template": "$PACKAGE_ROOT/templates/main.html.ejs" "template": "@css:templates/main.html.ejs"
} }
}, },
{ {
@ -21,7 +21,7 @@
"@type": "ContainerToTemplateConverter", "@type": "ContainerToTemplateConverter",
"templateEngine": { "templateEngine": {
"@type": "HandlebarsTemplateEngine", "@type": "HandlebarsTemplateEngine",
"template": "$PACKAGE_ROOT/templates/container.md.hbs" "template": "@css:templates/container.md.hbs"
}, },
"contentType": "text/markdown", "contentType": "text/markdown",
"identifierStrategy": { "@id": "urn:solid-server:default:IdentifierStrategy" } "identifierStrategy": { "@id": "urn:solid-server:default:IdentifierStrategy" }

View File

@ -5,9 +5,11 @@ import type { IComponentsManagerBuilderOptions, LogLevel } from 'componentsjs';
import { ComponentsManager } from 'componentsjs'; import { ComponentsManager } from 'componentsjs';
import yargs from 'yargs'; import yargs from 'yargs';
import { getLoggerFor } from '../logging/LogUtil'; import { getLoggerFor } from '../logging/LogUtil';
import { ensureTrailingSlash, resolveAssetPath } from '../util/PathUtil'; import { ensureTrailingSlash, resolveAssetPath, modulePathPlaceholder } from '../util/PathUtil';
import type { App } from './App'; import type { App } from './App';
const defaultConfig = `${modulePathPlaceholder}config/default.json`;
export interface CliParams { export interface CliParams {
loggingLevel: string; loggingLevel: string;
port: number; port: number;
@ -72,7 +74,7 @@ export class AppRunner {
}) })
.options({ .options({
baseUrl: { type: 'string', alias: 'b', requiresArg: true }, baseUrl: { type: 'string', alias: 'b', requiresArg: true },
config: { type: 'string', alias: 'c', requiresArg: true }, config: { type: 'string', alias: 'c', default: defaultConfig, requiresArg: true },
loggingLevel: { type: 'string', alias: 'l', default: 'info', requiresArg: true }, loggingLevel: { type: 'string', alias: 'l', default: 'info', requiresArg: true },
mainModulePath: { type: 'string', alias: 'm', requiresArg: true }, mainModulePath: { type: 'string', alias: 'm', requiresArg: true },
port: { type: 'number', alias: 'p', default: 3000, requiresArg: true }, port: { type: 'number', alias: 'p', default: 3000, requiresArg: true },
@ -89,7 +91,7 @@ export class AppRunner {
dumpErrorState: true, dumpErrorState: true,
logLevel: params.loggingLevel as LogLevel, logLevel: params.loggingLevel as LogLevel,
}; };
const configFile = resolveAssetPath(params.config ?? '$PACKAGE_ROOT/config/default.json'); const configFile = resolveAssetPath(params.config);
// Create and execute the app // Create and execute the app
this.createApp(loaderProperties, configFile, params) this.createApp(loaderProperties, configFile, params)

View File

@ -29,7 +29,7 @@ interface TemplateResourceLink extends ResourceLink {
* A FileIdentifierMapper will be used to generate identifiers that correspond to the relative structure. * A FileIdentifierMapper will be used to generate identifiers that correspond to the relative structure.
* *
* A relative `templateFolder` is resolved relative to cwd, * A relative `templateFolder` is resolved relative to cwd,
* unless it's preceded by $PACKAGE_ROOT/, e.g. $PACKAGE_ROOT/foo/bar. * unless it's preceded by `@css:`, e.g. `@css:foo/bar`.
*/ */
export class TemplatedResourcesGenerator implements ResourcesGenerator { export class TemplatedResourcesGenerator implements ResourcesGenerator {
private readonly templateFolder: string; private readonly templateFolder: string;

View File

@ -14,7 +14,7 @@ import type { HttpRequest } from '../HttpRequest';
/** /**
* Handler that serves static resources on specific paths. * Handler that serves static resources on specific paths.
* Relative file paths are assumed to be relative to cwd. * Relative file paths are assumed to be relative to cwd.
* Relative file paths can be preceded by $PACKAGE_ROOT/, e.g. $PACKAGE_ROOT/foo/bar, * Relative file paths can be preceded by `@css:`, e.g. `@css:foo/bar`,
* in case they need to be relative to the module root. * in case they need to be relative to the module root.
*/ */
export class StaticAssetHandler extends HttpHandler { export class StaticAssetHandler extends HttpHandler {

View File

@ -5,6 +5,7 @@ import type { Representation } from '../../ldp/representation/Representation';
import { INTERNAL_ERROR } from '../../util/ContentTypes'; import { INTERNAL_ERROR } from '../../util/ContentTypes';
import { HttpError } from '../../util/errors/HttpError'; import { HttpError } from '../../util/errors/HttpError';
import { InternalServerError } from '../../util/errors/InternalServerError'; import { InternalServerError } from '../../util/errors/InternalServerError';
import { modulePathPlaceholder } from '../../util/PathUtil';
import type { TemplateEngine } from '../../util/templates/TemplateEngine'; import type { TemplateEngine } from '../../util/templates/TemplateEngine';
import type { RepresentationConverterArgs } from './RepresentationConverter'; import type { RepresentationConverterArgs } from './RepresentationConverter';
import { TypedRepresentationConverter } from './TypedRepresentationConverter'; import { TypedRepresentationConverter } from './TypedRepresentationConverter';
@ -18,8 +19,8 @@ export interface TemplateOptions {
} }
const DEFAULT_TEMPLATE_OPTIONS: TemplateOptions = { const DEFAULT_TEMPLATE_OPTIONS: TemplateOptions = {
mainTemplatePath: '$PACKAGE_ROOT/templates/error/main.md.hbs', mainTemplatePath: `${modulePathPlaceholder}templates/error/main.md.hbs`,
codeTemplatesPath: '$PACKAGE_ROOT/templates/error/descriptions/', codeTemplatesPath: `${modulePathPlaceholder}templates/error/descriptions/`,
extension: '.md.hbs', extension: '.md.hbs',
contentType: 'text/markdown', contentType: 'text/markdown',
}; };

View File

@ -173,16 +173,20 @@ export function getModuleRoot(): string {
return joinFilePath(__dirname, '../../'); return joinFilePath(__dirname, '../../');
} }
const modulePath = '$PACKAGE_ROOT/'; /**
* A placeholder for the path to the `@solid/community-server` module root.
* The resolveAssetPath function will replace this string with the actual path.
*/
export const modulePathPlaceholder = '@css:';
/** /**
* Converts file path inputs into absolute paths. * Converts file path inputs into absolute paths.
* Works similar to `absoluteFilePath` but paths that start with '$PACKAGE_ROOT/' * Works similar to `absoluteFilePath` but paths that start with the `modulePathPlaceholder`
* will be relative to the module directory instead of the cwd. * will be relative to the module directory instead of the cwd.
*/ */
export function resolveAssetPath(path: string = modulePath): string { export function resolveAssetPath(path: string = modulePathPlaceholder): string {
if (path.startsWith(modulePath)) { if (path.startsWith(modulePathPlaceholder)) {
return joinFilePath(getModuleRoot(), path.slice(modulePath.length)); return joinFilePath(getModuleRoot(), path.slice(modulePathPlaceholder.length));
} }
return absoluteFilePath(path); return absoluteFilePath(path);
} }

View File

@ -211,7 +211,7 @@ describe('AppRunner', (): void => {
new AppRunner().runCli({ new AppRunner().runCli({
argv: [ argv: [
'node', 'script', 'node', 'script',
'--config', '$PACKAGE_ROOT/config/file.json', '--config', '@css:config/file.json',
], ],
}); });
await new Promise(setImmediate); await new Promise(setImmediate);

View File

@ -16,7 +16,7 @@ describe('A StaticAssetHandler', (): void => {
'/foo/bar/main': '/assets/scripts/bar.js', '/foo/bar/main': '/assets/scripts/bar.js',
'/foo/bar/unknown': '/assets/bar.unknown', '/foo/bar/unknown': '/assets/bar.unknown',
'/foo/bar/cwd': 'paths/cwd.txt', '/foo/bar/cwd': 'paths/cwd.txt',
'/foo/bar/module': '$PACKAGE_ROOT/paths/module.txt', '/foo/bar/module': '@css:paths/module.txt',
'/foo/bar/folder1/': '/assets/folders/1/', '/foo/bar/folder1/': '/assets/folders/1/',
'/foo/bar/folder2/': '/assets/folders/2', '/foo/bar/folder2/': '/assets/folders/2',
'/foo/bar/folder2/subfolder/': '/assets/folders/3', '/foo/bar/folder2/subfolder/': '/assets/folders/3',

View File

@ -164,9 +164,9 @@ describe('An ErrorToTemplateConverter', (): void => {
expect(templateEngine.render).toHaveBeenCalledTimes(2); expect(templateEngine.render).toHaveBeenCalledTimes(2);
expect(templateEngine.render).toHaveBeenNthCalledWith(1, expect(templateEngine.render).toHaveBeenNthCalledWith(1,
{ key: 'val' }, { key: 'val' },
{ templatePath: '$PACKAGE_ROOT/templates/error/descriptions/', templateFile: 'E0001.md.hbs' }); { templatePath: '@css:templates/error/descriptions/', templateFile: 'E0001.md.hbs' });
expect(templateEngine.render).toHaveBeenNthCalledWith(2, expect(templateEngine.render).toHaveBeenNthCalledWith(2,
{ name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' }, { name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' },
{ templateFile: '$PACKAGE_ROOT/templates/error/main.md.hbs' }); { templateFile: '@css:templates/error/main.md.hbs' });
}); });
}); });

View File

@ -141,12 +141,12 @@ describe('PathUtil', (): void => {
}); });
describe('#resolvePathInput', (): void => { describe('#resolvePathInput', (): void => {
it('interprets paths relative to the module root when starting with $PACKAGE_ROOT/.', async(): Promise<void> => { it('interprets paths relative to the module root when starting with @css:.', async(): Promise<void> => {
expect(resolveAssetPath('$PACKAGE_ROOT/foo/bar')).toBe(joinFilePath(getModuleRoot(), '/foo/bar')); expect(resolveAssetPath('@css:foo/bar')).toBe(joinFilePath(getModuleRoot(), '/foo/bar'));
}); });
it('handles ../ paths with $PACKAGE_ROOT/.', async(): Promise<void> => { it('handles ../ paths with @css:.', async(): Promise<void> => {
expect(resolveAssetPath('$PACKAGE_ROOT/foo/bar/../baz')).toBe(joinFilePath(getModuleRoot(), '/foo/baz')); expect(resolveAssetPath('@css:foo/bar/../baz')).toBe(joinFilePath(getModuleRoot(), '/foo/baz'));
}); });
it('leaves absolute paths as they are.', async(): Promise<void> => { it('leaves absolute paths as they are.', async(): Promise<void> => {