split squeebot executable
This commit is contained in:
parent
0fe2d6dd85
commit
1ec3870ad7
32
README.md
32
README.md
@ -14,8 +14,8 @@ The primary configuration will be located in `<path>/configs/squeebot.json`.
|
|||||||
In order to install plugins, you have to add a repository. Repositories are JSON files served over HTTP.
|
In order to install plugins, you have to add a repository. Repositories are JSON files served over HTTP.
|
||||||
|
|
||||||
For example, installing core plugins (Interactive mode `-i` on `squeebotd`):
|
For example, installing core plugins (Interactive mode `-i` on `squeebotd`):
|
||||||
1. `repository install https://(TODO)/repository.json`
|
1. `repository install https://squeebot.lunasqu.ee/pkg/plugins-core/repository.json`
|
||||||
2. `plugin install control mqtt`
|
2. `plugin install control simplecommands`
|
||||||
3. `plugin list`
|
3. `plugin list`
|
||||||
|
|
||||||
## Interactive mode commands
|
## Interactive mode commands
|
||||||
@ -58,7 +58,31 @@ Plugin manifest (`plugin.json`) example:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Deploying the repository
|
### Deploying the repository
|
||||||
You can configure deployment options using a file called `deployment.json` in your repository root. Currently supported deployment methods:
|
You can configure deployment options using a file called `deployment.json` in your repository root.
|
||||||
1. TODO!
|
|
||||||
|
|
||||||
In order to activate your configured deployment, use the `-d` flag when building your repository. `-o` flag skips build and deploys immediately.
|
In order to activate your configured deployment, use the `-d` flag when building your repository. `-o` flag skips build and deploys immediately.
|
||||||
|
|
||||||
|
#### Development
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"devSqueebot": "<full path to environment>.json",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `-d dev` to deploy this.
|
||||||
|
|
||||||
|
#### SSH deployment
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"prod": {
|
||||||
|
"ssh": true,
|
||||||
|
"key": "<path to id_rsa>",
|
||||||
|
"host": "<ssh host>",
|
||||||
|
"user": "<ssh user>",
|
||||||
|
"target": "<full remote path>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Official repositories
|
||||||
|
All official repositories [are here](https://gitlab.icynet.eu/Squeebot/official-plugins). Production-ready builds are available to download via Squeebot CLI from `https://squeebot.lunasqu.ee/pkg/<repo name>/repository.json` by using the `repository install` command.
|
||||||
|
84
package-lock.json
generated
84
package-lock.json
generated
@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@squeebot/cli",
|
"name": "@squeebot/cli",
|
||||||
"version": "3.1.1",
|
"version": "3.4.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@squeebot/cli",
|
"name": "@squeebot/cli",
|
||||||
"version": "3.1.1",
|
"version": "3.4.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@squeebot/core": "^3.3.1",
|
"@squeebot/core": "^3.3.3",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"node-watch": "^0.7.1",
|
"node-watch": "^0.7.1",
|
||||||
"tar": "^6.1.11",
|
"tar": "^6.1.11",
|
||||||
@ -76,28 +76,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@squeebot/core": {
|
"node_modules/@squeebot/core": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@squeebot/core/-/core-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@squeebot/core/-/core-3.3.3.tgz",
|
||||||
"integrity": "sha512-pkLMbZ0ZLC0isBlGbOCyu28NalBOjmwAkC0RmPN19DysohEF7XBdMMBss72IT3fXeAK6mEKO7pHZS4XAHVZa0Q==",
|
"integrity": "sha512-JKmHXAl2E3nXk5lE96DVyLFp/oQXu7zQb0ZcNuL6p5tdzjJW2f9GMzKYkc/6UxqijqRuwX0Km5qcSBYkp1JRJg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dateformat": "^4.0.0",
|
"dateformat": "^4.5.1",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^10.0.0",
|
||||||
"semver": "^7.3.2",
|
"semver": "^7.3.5",
|
||||||
"tar": "^6.0.5"
|
"tar": "^6.1.11"
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@squeebot/core/node_modules/fs-extra": {
|
|
||||||
"version": "9.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
|
||||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"at-least-node": "^1.0.0",
|
|
||||||
"graceful-fs": "^4.2.0",
|
|
||||||
"jsonfile": "^6.0.1",
|
|
||||||
"universalify": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@squeebot/core/node_modules/semver": {
|
"node_modules/@squeebot/core/node_modules/semver": {
|
||||||
@ -192,14 +178,6 @@
|
|||||||
"sprintf-js": "~1.0.2"
|
"sprintf-js": "~1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/at-least-node": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
@ -575,9 +553,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/require-directory": {
|
"node_modules/require-directory": {
|
||||||
@ -852,27 +830,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@squeebot/core": {
|
"@squeebot/core": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@squeebot/core/-/core-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@squeebot/core/-/core-3.3.3.tgz",
|
||||||
"integrity": "sha512-pkLMbZ0ZLC0isBlGbOCyu28NalBOjmwAkC0RmPN19DysohEF7XBdMMBss72IT3fXeAK6mEKO7pHZS4XAHVZa0Q==",
|
"integrity": "sha512-JKmHXAl2E3nXk5lE96DVyLFp/oQXu7zQb0ZcNuL6p5tdzjJW2f9GMzKYkc/6UxqijqRuwX0Km5qcSBYkp1JRJg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"dateformat": "^4.0.0",
|
"dateformat": "^4.5.1",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^10.0.0",
|
||||||
"semver": "^7.3.2",
|
"semver": "^7.3.5",
|
||||||
"tar": "^6.0.5"
|
"tar": "^6.1.11"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs-extra": {
|
|
||||||
"version": "9.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
|
||||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
|
||||||
"requires": {
|
|
||||||
"at-least-node": "^1.0.0",
|
|
||||||
"graceful-fs": "^4.2.0",
|
|
||||||
"jsonfile": "^6.0.1",
|
|
||||||
"universalify": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "7.3.5",
|
"version": "7.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||||
@ -955,11 +922,6 @@
|
|||||||
"sprintf-js": "~1.0.2"
|
"sprintf-js": "~1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"at-least-node": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
|
||||||
},
|
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
@ -1262,9 +1224,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"path-parse": {
|
"path-parse": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"require-directory": {
|
"require-directory": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@squeebot/cli",
|
"name": "@squeebot/cli",
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"description": "Squeebot v3 runtime, environments and configuration",
|
"description": "Squeebot v3 runtime, environments and configuration",
|
||||||
"main": "dist/squeebot.js",
|
"main": "dist/squeebot.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"typescript": "^4.4.2"
|
"typescript": "^4.4.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@squeebot/core": "^3.3.1",
|
"@squeebot/core": "^3.3.3",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"node-watch": "^0.7.1",
|
"node-watch": "^0.7.1",
|
||||||
"tar": "^6.1.11",
|
"tar": "^6.1.11",
|
||||||
|
12
src/build/default/environment.default.ts
Normal file
12
src/build/default/environment.default.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { IEnvironment } from '@squeebot/core/lib/types';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export function defaultEnvironment(location: string): IEnvironment {
|
||||||
|
return {
|
||||||
|
configurationPath: path.join(location, 'plugins'),
|
||||||
|
environment: 'development',
|
||||||
|
path: location,
|
||||||
|
pluginsPath: path.join(location, 'plugins'),
|
||||||
|
repositoryPath: path.join(location, 'plugins'),
|
||||||
|
};
|
||||||
|
}
|
4
src/build/default/gitignore.default.ts
Normal file
4
src/build/default/gitignore.default.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
export const gitignore = `/node_modules/
|
||||||
|
/.out/
|
||||||
|
deployment.json`;
|
12
src/build/default/tsconfig.default.ts
Normal file
12
src/build/default/tsconfig.default.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export const tsConfig = {
|
||||||
|
compilerOptions: {
|
||||||
|
downlevelIteration: true,
|
||||||
|
esModuleInterop: true,
|
||||||
|
experimentalDecorators: true,
|
||||||
|
forceConsistentCasingInFileNames: true,
|
||||||
|
skipLibCheck: true,
|
||||||
|
sourceMap: false,
|
||||||
|
strict: true,
|
||||||
|
target: 'es5',
|
||||||
|
},
|
||||||
|
};
|
32
src/build/environment.ts
Normal file
32
src/build/environment.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a Squeebot environment
|
||||||
|
* @param name Environment name
|
||||||
|
* @param location Install path
|
||||||
|
*/
|
||||||
|
export async function newEnvironment(
|
||||||
|
name?: string,
|
||||||
|
location?: string
|
||||||
|
): Promise<void> {
|
||||||
|
if (!name) {
|
||||||
|
name = 'squeebot';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
location = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = path.resolve(process.cwd(), location);
|
||||||
|
|
||||||
|
const envFile = path.join(location, name + '.json');
|
||||||
|
await fs.ensureDir(location);
|
||||||
|
await fs.writeJson(envFile, {
|
||||||
|
environment: 'production',
|
||||||
|
path: location,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('\nNew environment file:\t', envFile);
|
||||||
|
console.log('Environment path:\t', location);
|
||||||
|
}
|
24
src/build/execute.ts
Normal file
24
src/build/execute.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import child_process from 'child_process';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a shell command
|
||||||
|
* @param cmd Shell command
|
||||||
|
* @param loc Working directory
|
||||||
|
*/
|
||||||
|
export function execute(cmd: any[], loc: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const cproc = child_process.spawn(cmd[0], cmd.slice(1), {
|
||||||
|
cwd: loc,
|
||||||
|
});
|
||||||
|
|
||||||
|
cproc.stdout.pipe(process.stdout);
|
||||||
|
cproc.stderr.pipe(process.stderr);
|
||||||
|
|
||||||
|
cproc.on('exit', (code: number) => {
|
||||||
|
if (code !== 0) {
|
||||||
|
return reject(new Error('Build failed!'));
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
130
src/build/repository/build.ts
Normal file
130
src/build/repository/build.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import { PluginMetaLoader } from '@squeebot/core/lib/plugin';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import tar from 'tar';
|
||||||
|
|
||||||
|
import { defaultEnvironment } from '../default/environment.default';
|
||||||
|
import { execute } from '../execute';
|
||||||
|
import { deploy } from './deploy';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build repository ready for deployment
|
||||||
|
* @param location Repository location
|
||||||
|
* @param out Create output files for deployment (false - only compile tsc in-place)
|
||||||
|
* @param doDeploy Deployment name
|
||||||
|
* @param onlyDeploy Deploy only without building
|
||||||
|
*/
|
||||||
|
export async function buildRepository(
|
||||||
|
location?: string,
|
||||||
|
out = true,
|
||||||
|
doDeploy?: string,
|
||||||
|
onlyDeploy = false
|
||||||
|
): Promise<void> {
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
location = process.cwd();
|
||||||
|
}
|
||||||
|
|
||||||
|
location = path.resolve(process.cwd(), location);
|
||||||
|
const outDir = path.join(location, '.out');
|
||||||
|
|
||||||
|
// Check for repository metadata
|
||||||
|
const buildMetaFile = path.join(location, 'squeebot.repo.json');
|
||||||
|
if (!await fs.pathExists(buildMetaFile)) {
|
||||||
|
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read repository metadata
|
||||||
|
const meta = await fs.readJson(buildMetaFile);
|
||||||
|
const env = defaultEnvironment(location);
|
||||||
|
env.pluginsPath = location;
|
||||||
|
|
||||||
|
if (!meta.name) {
|
||||||
|
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Detected repository "%s"!', meta.name);
|
||||||
|
|
||||||
|
if (onlyDeploy) {
|
||||||
|
if (!await fs.pathExists(outDir)) {
|
||||||
|
throw new Error(`You need to build before deploying!`);
|
||||||
|
} else {
|
||||||
|
return deploy(meta.name, location, outDir, doDeploy as string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run typescript build
|
||||||
|
if (meta.typescript) {
|
||||||
|
console.log('Running build task..');
|
||||||
|
await execute(['npm', 'run', 'build'], location);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Detecting plugins in this environment..');
|
||||||
|
|
||||||
|
const loader = new PluginMetaLoader(env);
|
||||||
|
const plugins = await loader.loadAll(false);
|
||||||
|
|
||||||
|
console.log('Found the following plugins:', plugins.map((plugin) => {
|
||||||
|
return `${plugin.name}@${plugin.version}`;
|
||||||
|
}).join(', '));
|
||||||
|
|
||||||
|
const savedList = plugins.map((plugin) => ({
|
||||||
|
name: plugin.name,
|
||||||
|
version: plugin.version,
|
||||||
|
}));
|
||||||
|
|
||||||
|
meta.plugins = savedList;
|
||||||
|
await fs.writeJson(buildMetaFile, meta, { spaces: 2 });
|
||||||
|
|
||||||
|
if (!out) {
|
||||||
|
console.log('Done!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Creating repository index');
|
||||||
|
await fs.remove(outDir);
|
||||||
|
await fs.ensureDir(outDir);
|
||||||
|
await fs.writeJSON(path.join(outDir, 'repository.json'), {
|
||||||
|
created: Math.floor(Date.now() / 1000),
|
||||||
|
name: meta.name,
|
||||||
|
plugins: meta.plugins,
|
||||||
|
schema: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Copying plugins');
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const src = path.join(location, plugin.name);
|
||||||
|
const dst = path.join(outDir, plugin.name);
|
||||||
|
await fs.copy(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.typescript) {
|
||||||
|
console.log('Stripping source files');
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const plOut = path.join(outDir, plugin.name);
|
||||||
|
const listAllFiles = await fs.readdir(plOut);
|
||||||
|
for (const f of listAllFiles) {
|
||||||
|
if (f.match(/(\.d)?\.ts$/i) != null) {
|
||||||
|
await fs.remove(path.join(plOut, f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Creating tarballs');
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const plOut = path.join(outDir, plugin.name);
|
||||||
|
await tar.c({
|
||||||
|
gzip: true,
|
||||||
|
file: plOut + '.plugin.tgz',
|
||||||
|
C: outDir,
|
||||||
|
}, [plugin.name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doDeploy == null) {
|
||||||
|
console.log('Done!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy(meta.name, location, outDir, doDeploy);
|
||||||
|
}
|
69
src/build/repository/create.ts
Normal file
69
src/build/repository/create.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
|
||||||
|
import { NPMExecutor } from '@squeebot/core/lib/npm';
|
||||||
|
|
||||||
|
import { defaultEnvironment } from '../default/environment.default';
|
||||||
|
import { gitignore } from '../default/gitignore.default';
|
||||||
|
import { tsConfig } from '../default/tsconfig.default';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new repository, complete with typescript and git.
|
||||||
|
* @param name Repository name
|
||||||
|
* @param location Repository path
|
||||||
|
* @param typescript Use typescript
|
||||||
|
*/
|
||||||
|
export async function newRepository(
|
||||||
|
name: string,
|
||||||
|
location?: string,
|
||||||
|
typescript = true): Promise<void> {
|
||||||
|
if (!name) {
|
||||||
|
throw new Error('Repository needs a name!');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
location = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = path.resolve(process.cwd(), location);
|
||||||
|
console.log('Creating a new repository development environment at', location);
|
||||||
|
|
||||||
|
await fs.ensureDir(location);
|
||||||
|
const env = defaultEnvironment(location);
|
||||||
|
|
||||||
|
console.log('Creating package.json and installing base requirements');
|
||||||
|
const executor = new NPMExecutor(env, '@squeebot/core');
|
||||||
|
await executor.loadPackageFile();
|
||||||
|
|
||||||
|
let gitIgnore = gitignore + '';
|
||||||
|
|
||||||
|
if (typescript) {
|
||||||
|
console.log('Installing TypeScript support');
|
||||||
|
await executor.installPackage('typescript');
|
||||||
|
await fs.writeJson(path.join(location, 'tsconfig.json'), tsConfig);
|
||||||
|
gitIgnore += '\n*.js';
|
||||||
|
gitIgnore += '\n*.d.ts';
|
||||||
|
gitIgnore += '\n*.tsbuildinfo';
|
||||||
|
|
||||||
|
console.log('Adding TypeScript scripts to package.json');
|
||||||
|
const pkgjson = path.join(location, 'package.json');
|
||||||
|
const contents = await fs.readJson(pkgjson);
|
||||||
|
contents.scripts = {
|
||||||
|
build: 'tsc',
|
||||||
|
watch: 'tsc -w',
|
||||||
|
};
|
||||||
|
await fs.writeJson(pkgjson, contents, { spaces: 2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Creating .gitignore');
|
||||||
|
await fs.writeFile(path.join(location, '.gitignore'), gitIgnore);
|
||||||
|
|
||||||
|
console.log('Writing build metadata');
|
||||||
|
await fs.writeJson(path.join(location, 'squeebot.repo.json'), {
|
||||||
|
name,
|
||||||
|
plugins: [],
|
||||||
|
typescript,
|
||||||
|
}, { spaces: 2 });
|
||||||
|
|
||||||
|
console.log('\nDone! Your repository "%s" lives at:', name, location);
|
||||||
|
}
|
45
src/build/repository/deploy.ts
Normal file
45
src/build/repository/deploy.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import { sshDeploy } from './deployment/ssh';
|
||||||
|
import { developDeploy } from './deployment/develop';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy according to configuration
|
||||||
|
* @param name Repository name
|
||||||
|
* @param location Repository path
|
||||||
|
* @param outDir Output directory
|
||||||
|
* @param deployment Deployment name
|
||||||
|
*/
|
||||||
|
export async function deploy(
|
||||||
|
name: string,
|
||||||
|
location: string,
|
||||||
|
outDir: string,
|
||||||
|
deployment: string): Promise<void> {
|
||||||
|
const deployFile = path.join(location, 'deployment.json');
|
||||||
|
|
||||||
|
if (!await fs.pathExists(deployFile)) {
|
||||||
|
throw new Error('deployment.json file is missing! Can\'t deploy!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = await fs.readJson(deployFile);
|
||||||
|
|
||||||
|
// If we have a path to a metadata file, we copy the output directory to
|
||||||
|
// the plugins directory, overwriting existing plugins with the same name!
|
||||||
|
if ((deployment.indexOf('dev') === 0 || deployment.indexOf('squee') === 0)
|
||||||
|
&& meta.devSqueebot) {
|
||||||
|
console.log('\n [!!!] DEPLOYING REPOSITORY FOR DEVELOPMENT [!!!]\n');
|
||||||
|
developDeploy(location, meta, outDir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other deployment methods come here
|
||||||
|
if (deployment in meta) {
|
||||||
|
console.log('\n [!!!] DEPLOYING REPOSITORY [!!!]\n');
|
||||||
|
const dpl = meta[deployment];
|
||||||
|
if (dpl.ssh) {
|
||||||
|
await sshDeploy(outDir, dpl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
46
src/build/repository/deployment/develop.ts
Normal file
46
src/build/repository/deployment/develop.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import { loadEnvironment } from '@squeebot/core/lib/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy to a local environment
|
||||||
|
* @param location Repository location
|
||||||
|
* @param meta Deployment metadata
|
||||||
|
* @param outDir Repository output files
|
||||||
|
*/
|
||||||
|
export async function developDeploy(
|
||||||
|
location: string,
|
||||||
|
meta: Record<string, string | number>,
|
||||||
|
outDir: string,
|
||||||
|
): Promise<void> {
|
||||||
|
console.log('Deploying to a configured Squeebot development environment');
|
||||||
|
const devbotPath = path.resolve(location, meta.devSqueebot as string);
|
||||||
|
|
||||||
|
console.log('Path:', devbotPath);
|
||||||
|
|
||||||
|
if (!await fs.pathExists(devbotPath)) {
|
||||||
|
throw new Error('Development Squeebot environment file doesn\'t exist!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const devEnv = await loadEnvironment(devbotPath);
|
||||||
|
if (!devEnv.pluginsPath) {
|
||||||
|
throw new Error('Bad development Squeebot environment file!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const pluginsPath = path.resolve(devEnv.path, devEnv.pluginsPath);
|
||||||
|
|
||||||
|
console.log('Copying plugins to', pluginsPath);
|
||||||
|
const listAllFiles = await fs.readdir(outDir);
|
||||||
|
for (const f of listAllFiles) {
|
||||||
|
if (f === 'repository' || f.indexOf('.tgz') !== -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const dst = path.join(pluginsPath, f);
|
||||||
|
await fs.copy(path.join(outDir, f), dst, {
|
||||||
|
overwrite: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Done!');
|
||||||
|
}
|
46
src/build/repository/deployment/ssh.ts
Normal file
46
src/build/repository/deployment/ssh.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import { execute } from '../../execute';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy using ssh and rsync
|
||||||
|
* @param outDir Repoistory output
|
||||||
|
* @param sshconf ssh deployment configuration
|
||||||
|
*/
|
||||||
|
export async function sshDeploy(
|
||||||
|
outDir: string,
|
||||||
|
sshconf: any
|
||||||
|
): Promise<void> {
|
||||||
|
|
||||||
|
const key = sshconf.key;
|
||||||
|
const host = sshconf.host;
|
||||||
|
const username = sshconf.user;
|
||||||
|
const port = sshconf.port || 22;
|
||||||
|
const target = sshconf.target;
|
||||||
|
const args = sshconf.args || '-rltgoDzvO';
|
||||||
|
|
||||||
|
if (!key || !host || !username || !target) {
|
||||||
|
console.error('SSH deployment requires more arguments.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Deploying to %s@%s:%d%s', username, host, port, target);
|
||||||
|
|
||||||
|
const fileList = (await fs.readdir(outDir)).filter((val) => {
|
||||||
|
return val === 'repository.json' || val.match('.tgz$');
|
||||||
|
}).map((x) => path.join(outDir, x));
|
||||||
|
|
||||||
|
const pargs = [
|
||||||
|
'rsync',
|
||||||
|
args,
|
||||||
|
'-e',
|
||||||
|
`ssh -i ${key} -p ${port}`,
|
||||||
|
...fileList,
|
||||||
|
`${username}@${host}:${target}`,
|
||||||
|
];
|
||||||
|
|
||||||
|
console.log(pargs.join(' '));
|
||||||
|
await execute(pargs, outDir);
|
||||||
|
|
||||||
|
console.log('Done!');
|
||||||
|
}
|
57
src/build/watch.ts
Normal file
57
src/build/watch.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import fs from 'fs-extra';
|
||||||
|
import watch from 'node-watch';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import { buildRepository } from './repository/build';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a filesystem watch task for a repository directory
|
||||||
|
* Equivalent to tsc -w
|
||||||
|
* @param location Repository path
|
||||||
|
* @param out Create output files. False - dry run.
|
||||||
|
* @param doDeploy Use deployment after build success
|
||||||
|
*/
|
||||||
|
export async function watchRepository(
|
||||||
|
location?: string,
|
||||||
|
out = true,
|
||||||
|
doDeploy?: string): Promise<void> {
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
location = process.cwd();
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildMetaFile = path.join(location, 'squeebot.repo.json');
|
||||||
|
if (!await fs.pathExists(buildMetaFile)) {
|
||||||
|
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = await fs.readJson(buildMetaFile);
|
||||||
|
if (!meta.name) {
|
||||||
|
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Watching repository "%s"!', meta.name);
|
||||||
|
|
||||||
|
watch(location, {
|
||||||
|
recursive: true,
|
||||||
|
filter(f, skip): any {
|
||||||
|
if (/\/node_modules/.test(f) ||
|
||||||
|
/\.out/.test(f) ||
|
||||||
|
/\.git/.test(f) ||
|
||||||
|
/\.json$/.test(f)) {
|
||||||
|
return skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.typescript && /\.js$/.test(f)) {
|
||||||
|
return skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
}, (evt, f) => {
|
||||||
|
console.log(`\n ==> ${f} changed, rebuilding...`);
|
||||||
|
buildRepository(location, out, doDeploy).catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
10
src/core.ts
10
src/core.ts
@ -20,6 +20,9 @@ const defaultConfiguration: {[key: string]: any} = {
|
|||||||
name: 'squeebot',
|
name: 'squeebot',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference implementation of a Squeebot system using core classes.
|
||||||
|
*/
|
||||||
export class Squeebot implements ISqueebotCore {
|
export class Squeebot implements ISqueebotCore {
|
||||||
public npm: NPMExecutor = new NPMExecutor(this.environment, '@squeebot/core');
|
public npm: NPMExecutor = new NPMExecutor(this.environment, '@squeebot/core');
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ export class Squeebot implements ISqueebotCore {
|
|||||||
const getManifest = this.pluginManager.getAvailableByName(pluginName);
|
const getManifest = this.pluginManager.getAvailableByName(pluginName);
|
||||||
if (!getManifest) {
|
if (!getManifest) {
|
||||||
logger.error(new Error(`Failed to start ${pluginName}: no manifest available. You might not have installed it.`));
|
logger.error(new Error(`Failed to start ${pluginName}: no manifest available. You might not have installed it.`));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -116,13 +119,16 @@ export class Squeebot implements ISqueebotCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.warn('Shutting down..');
|
logger.warn('Shutting down..');
|
||||||
|
|
||||||
this.shuttingDown = true;
|
this.shuttingDown = true;
|
||||||
|
|
||||||
|
// Subsystems confirmed shutdown, go ahead and exit.
|
||||||
this.stream.on('core', 'shutdown', (state: number) => {
|
this.stream.on('core', 'shutdown', (state: number) => {
|
||||||
if (state > 0) {
|
if (state > 0) {
|
||||||
this.config.save().then((x) => process.exit(0));
|
this.config.save().then((x) => process.exit(0));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Prompt subsystems to prepare for shutting down
|
||||||
this.stream.emitTo('core', 'shutdown', 0);
|
this.stream.emitTo('core', 'shutdown', 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
393
src/squeebot.ts
393
src/squeebot.ts
@ -1,394 +1,10 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import child_process from 'child_process';
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import watch from 'node-watch';
|
|
||||||
import path from 'path';
|
|
||||||
import yargs from 'yargs';
|
import yargs from 'yargs';
|
||||||
import tar from 'tar';
|
|
||||||
|
|
||||||
import { logger } from '@squeebot/core/lib/core';
|
import { newEnvironment } from './build/environment';
|
||||||
import { NPMExecutor } from '@squeebot/core/lib/npm';
|
import { buildRepository } from './build/repository/build';
|
||||||
import { IEnvironment } from '@squeebot/core/lib/types';
|
import { newRepository } from './build/repository/create';
|
||||||
|
import { watchRepository } from './build/watch';
|
||||||
import { loadEnvironment } from '@squeebot/core/lib/core';
|
|
||||||
import { PluginMetaLoader } from '@squeebot/core/lib/plugin';
|
|
||||||
|
|
||||||
const tsConfig = {
|
|
||||||
compilerOptions: {
|
|
||||||
downlevelIteration: true,
|
|
||||||
esModuleInterop: true,
|
|
||||||
experimentalDecorators: true,
|
|
||||||
forceConsistentCasingInFileNames: true,
|
|
||||||
skipLibCheck: true,
|
|
||||||
sourceMap: false,
|
|
||||||
strict: true,
|
|
||||||
target: 'es5',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const gitignore = `/node_modules/
|
|
||||||
/.out/
|
|
||||||
deployment.json`;
|
|
||||||
|
|
||||||
function dummyEnvironment(location: string): IEnvironment {
|
|
||||||
return {
|
|
||||||
configurationPath: path.join(location, 'plugins'),
|
|
||||||
environment: 'development',
|
|
||||||
path: location,
|
|
||||||
pluginsPath: path.join(location, 'plugins'),
|
|
||||||
repositoryPath: path.join(location, 'plugins'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function execute(cmd: any[], loc: string): Promise<void> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const cproc = child_process.spawn(cmd[0], cmd.slice(1), {
|
|
||||||
cwd: loc,
|
|
||||||
});
|
|
||||||
|
|
||||||
cproc.stdout.pipe(process.stdout);
|
|
||||||
cproc.stderr.pipe(process.stderr);
|
|
||||||
|
|
||||||
cproc.on('exit', (code: number) => {
|
|
||||||
if (code !== 0) {
|
|
||||||
return reject(new Error('Build failed!'));
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function newEnvironment(
|
|
||||||
name?: string,
|
|
||||||
location?: string): Promise<void> {
|
|
||||||
if (!name) {
|
|
||||||
name = 'squeebot';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!location) {
|
|
||||||
location = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
location = path.resolve(process.cwd(), location);
|
|
||||||
|
|
||||||
const envFile = path.join(location, name + '.json');
|
|
||||||
await fs.ensureDir(location);
|
|
||||||
await fs.writeJson(envFile, {
|
|
||||||
environment: 'production',
|
|
||||||
path: location,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('\nNew environment file:\t', envFile);
|
|
||||||
console.log('Environment path:\t', location);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function newRepository(
|
|
||||||
name: string,
|
|
||||||
location?: string,
|
|
||||||
typescript = true): Promise<void> {
|
|
||||||
if (!name) {
|
|
||||||
throw new Error('Repository needs a name!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!location) {
|
|
||||||
location = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
location = path.resolve(process.cwd(), location);
|
|
||||||
console.log('Creating a new repository development environment at', location);
|
|
||||||
|
|
||||||
await fs.ensureDir(location);
|
|
||||||
const env = dummyEnvironment(location);
|
|
||||||
|
|
||||||
console.log('Creating package.json and installing base requirements');
|
|
||||||
const executor = new NPMExecutor(env, '@squeebot/core');
|
|
||||||
await executor.loadPackageFile();
|
|
||||||
|
|
||||||
let gitIgnore = gitignore + '';
|
|
||||||
|
|
||||||
if (typescript) {
|
|
||||||
console.log('Installing TypeScript support');
|
|
||||||
await executor.installPackage('typescript');
|
|
||||||
await fs.writeJson(path.join(location, 'tsconfig.json'), tsConfig);
|
|
||||||
gitIgnore += '\n*.js';
|
|
||||||
gitIgnore += '\n*.d.ts';
|
|
||||||
gitIgnore += '\n*.tsbuildinfo';
|
|
||||||
|
|
||||||
console.log('Adding TypeScript scripts to package.json');
|
|
||||||
const pkgjson = path.join(location, 'package.json');
|
|
||||||
const contents = await fs.readJson(pkgjson);
|
|
||||||
contents.scripts = {
|
|
||||||
build: 'tsc',
|
|
||||||
watch: 'tsc -w',
|
|
||||||
};
|
|
||||||
await fs.writeJson(pkgjson, contents, { spaces: 2 });
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Creating .gitignore');
|
|
||||||
await fs.writeFile(path.join(location, '.gitignore'), gitIgnore);
|
|
||||||
|
|
||||||
console.log('Writing build metadata');
|
|
||||||
await fs.writeJson(path.join(location, 'squeebot.repo.json'), {
|
|
||||||
name,
|
|
||||||
plugins: [],
|
|
||||||
typescript,
|
|
||||||
}, { spaces: 2 });
|
|
||||||
|
|
||||||
console.log('\nDone! Your repository "%s" lives at:', name, location);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sshDeploy(
|
|
||||||
outDir: string,
|
|
||||||
sshconf: any): Promise<void> {
|
|
||||||
|
|
||||||
const key = sshconf.key;
|
|
||||||
const host = sshconf.host;
|
|
||||||
const username = sshconf.user;
|
|
||||||
const port = sshconf.port || 22;
|
|
||||||
const target = sshconf.target;
|
|
||||||
const args = sshconf.args || '-rltgoDzvO';
|
|
||||||
|
|
||||||
if (!key || !host || !username || !target) {
|
|
||||||
console.error('SSH deployment requires more arguments.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Deploying to %s@%s:%d%s', username, host, port, target);
|
|
||||||
|
|
||||||
const fileList = (await fs.readdir(outDir)).filter((val) => {
|
|
||||||
return val === 'repository.json' || val.match('.tgz$');
|
|
||||||
}).map((x) => path.join(outDir, x));
|
|
||||||
|
|
||||||
const pargs = [
|
|
||||||
'rsync',
|
|
||||||
args,
|
|
||||||
'-e',
|
|
||||||
`ssh -i ${key} -p ${port}`,
|
|
||||||
...fileList,
|
|
||||||
`${username}@${host}:${target}`,
|
|
||||||
];
|
|
||||||
|
|
||||||
console.log(pargs.join(' '));
|
|
||||||
await execute(pargs, outDir);
|
|
||||||
|
|
||||||
console.log('Done!');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function deploy(
|
|
||||||
name: string,
|
|
||||||
location: string,
|
|
||||||
outDir: string,
|
|
||||||
deployment: string): Promise<void> {
|
|
||||||
const deployFile = path.join(location, 'deployment.json');
|
|
||||||
|
|
||||||
if (!await fs.pathExists(deployFile)) {
|
|
||||||
throw new Error('deployment.json file is missing! Can\'t deploy!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const meta = await fs.readJson(deployFile);
|
|
||||||
|
|
||||||
// If we have a path to a metadata file, we copy the output directory to
|
|
||||||
// the plugins directory, overwriting existing plugins with the same name!
|
|
||||||
if ((deployment.indexOf('dev') === 0 || deployment.indexOf('squee') === 0) &&
|
|
||||||
meta.devSqueebot) {
|
|
||||||
console.log('Deploying to a configured Squeebot development environment');
|
|
||||||
const devbotPath = path.resolve(location, meta.devSqueebot);
|
|
||||||
|
|
||||||
console.log('Path:', devbotPath);
|
|
||||||
|
|
||||||
if (!await fs.pathExists(devbotPath)) {
|
|
||||||
throw new Error('Development Squeebot environment file doesn\'t exist!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const devEnv = await loadEnvironment(devbotPath);
|
|
||||||
if (!devEnv.pluginsPath) {
|
|
||||||
throw new Error('Bad development Squeebot environment file!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const pluginsPath = path.resolve(devEnv.path, devEnv.pluginsPath);
|
|
||||||
|
|
||||||
console.log('Copying plugins to', pluginsPath);
|
|
||||||
const listAllFiles = await fs.readdir(outDir);
|
|
||||||
for (const f of listAllFiles) {
|
|
||||||
if (f === 'repository' || f.indexOf('.tgz') !== -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const dst = path.join(pluginsPath, f);
|
|
||||||
await fs.copy(path.join(outDir, f), dst, {
|
|
||||||
overwrite: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Done!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deployment in meta) {
|
|
||||||
const dpl = meta[deployment];
|
|
||||||
if (dpl.ssh) {
|
|
||||||
await sshDeploy(outDir, dpl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function buildRepository(
|
|
||||||
location?: string,
|
|
||||||
out = true,
|
|
||||||
doDeploy?: string,
|
|
||||||
onlyDeploy = false): Promise<void> {
|
|
||||||
if (!location) {
|
|
||||||
location = process.cwd();
|
|
||||||
}
|
|
||||||
location = path.resolve(process.cwd(), location);
|
|
||||||
const outDir = path.join(location, '.out');
|
|
||||||
|
|
||||||
const buildMetaFile = path.join(location, 'squeebot.repo.json');
|
|
||||||
if (!await fs.pathExists(buildMetaFile)) {
|
|
||||||
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const meta = await fs.readJson(buildMetaFile);
|
|
||||||
const env = dummyEnvironment(location);
|
|
||||||
env.pluginsPath = location;
|
|
||||||
|
|
||||||
if (!meta.name) {
|
|
||||||
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Detected repository "%s"!', meta.name);
|
|
||||||
|
|
||||||
if (onlyDeploy) {
|
|
||||||
if (!await fs.pathExists(outDir)) {
|
|
||||||
throw new Error(`You need to build before deploying!`);
|
|
||||||
} else {
|
|
||||||
return deploy(meta.name, location, outDir, doDeploy as string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (meta.typescript) {
|
|
||||||
console.log('Running build task..');
|
|
||||||
await execute(['npm', 'run', 'build'], location);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Detecting plugins in this environment..');
|
|
||||||
|
|
||||||
const loader = new PluginMetaLoader(env);
|
|
||||||
const plugins = await loader.loadAll(false);
|
|
||||||
const savedList: any[] = [];
|
|
||||||
|
|
||||||
console.log('Found the following plugins:', plugins.map((plugin) => {
|
|
||||||
return `${plugin.name}@${plugin.version}`;
|
|
||||||
}).join(', '));
|
|
||||||
|
|
||||||
plugins.forEach((plugin) => {
|
|
||||||
savedList.push({
|
|
||||||
name: plugin.name,
|
|
||||||
version: plugin.version,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
meta.plugins = savedList;
|
|
||||||
await fs.writeJson(buildMetaFile, meta, { spaces: 2 });
|
|
||||||
|
|
||||||
if (!out) {
|
|
||||||
console.log('Done!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Creating repository index');
|
|
||||||
await fs.remove(outDir);
|
|
||||||
await fs.ensureDir(outDir);
|
|
||||||
await fs.writeJSON(path.join(outDir, 'repository.json'), {
|
|
||||||
created: Math.floor(Date.now() / 1000),
|
|
||||||
name: meta.name,
|
|
||||||
plugins: meta.plugins,
|
|
||||||
schema: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Copying plugins');
|
|
||||||
for (const plugin of plugins) {
|
|
||||||
const src = path.join(location, plugin.name);
|
|
||||||
const dst = path.join(outDir, plugin.name);
|
|
||||||
await fs.copy(src, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (meta.typescript) {
|
|
||||||
console.log('Stripping source files');
|
|
||||||
for (const plugin of plugins) {
|
|
||||||
const plOut = path.join(outDir, plugin.name);
|
|
||||||
const listAllFiles = await fs.readdir(plOut);
|
|
||||||
for (const f of listAllFiles) {
|
|
||||||
if (f.match(/(\.d)?\.ts$/i) != null) {
|
|
||||||
await fs.remove(path.join(plOut, f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Creating tarballs');
|
|
||||||
for (const plugin of plugins) {
|
|
||||||
const plOut = path.join(outDir, plugin.name);
|
|
||||||
await tar.c({
|
|
||||||
gzip: true,
|
|
||||||
file: plOut + '.plugin.tgz',
|
|
||||||
C: outDir,
|
|
||||||
}, [plugin.name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doDeploy == null) {
|
|
||||||
console.log('Done!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\n [!!!] DEPLOYING REPOSITORY [!!!]\n');
|
|
||||||
|
|
||||||
deploy(meta.name, location, outDir, doDeploy);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function watchRepository(
|
|
||||||
location?: string,
|
|
||||||
out = true,
|
|
||||||
doDeploy?: string,
|
|
||||||
onlyDeploy = false): Promise<void> {
|
|
||||||
|
|
||||||
if (!location) {
|
|
||||||
location = process.cwd();
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildMetaFile = path.join(location, 'squeebot.repo.json');
|
|
||||||
if (!await fs.pathExists(buildMetaFile)) {
|
|
||||||
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const meta = await fs.readJson(buildMetaFile);
|
|
||||||
if (!meta.name) {
|
|
||||||
throw new Error(`${location} is not a valid squeebot repository development environment!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Watching repository "%s"!', meta.name);
|
|
||||||
|
|
||||||
watch(location, {
|
|
||||||
recursive: true,
|
|
||||||
filter(f, skip): any {
|
|
||||||
if (/\/node_modules/.test(f) ||
|
|
||||||
/\.out/.test(f) ||
|
|
||||||
/\.git/.test(f) ||
|
|
||||||
/\.json$/.test(f)) {
|
|
||||||
return skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (meta.typescript && /\.js$/.test(f)) {
|
|
||||||
return skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
}, (evt, f) => {
|
|
||||||
console.log(`\n ==> ${f} changed, rebuilding...`);
|
|
||||||
buildRepository(location, out, doDeploy, onlyDeploy).catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const yar = yargs.scriptName('squeebot')
|
const yar = yargs.scriptName('squeebot')
|
||||||
.command('new [name] [path]', 'create a new Squeebot environment', (y) => {
|
.command('new [name] [path]', 'create a new Squeebot environment', (y) => {
|
||||||
@ -452,7 +68,6 @@ const yar = yargs.scriptName('squeebot')
|
|||||||
dargs[0] as string,
|
dargs[0] as string,
|
||||||
dargs[1] as boolean,
|
dargs[1] as boolean,
|
||||||
dargs[2] as string,
|
dargs[2] as string,
|
||||||
dargs[3] as boolean,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import readline from 'readline';
|
|||||||
import yargs from 'yargs';
|
import yargs from 'yargs';
|
||||||
|
|
||||||
import { loadEnvironment } from '@squeebot/core/lib/core';
|
import { loadEnvironment } from '@squeebot/core/lib/core';
|
||||||
import { IEnvironment } from '@squeebot/core/lib/types';
|
|
||||||
|
|
||||||
import { Squeebot } from './core';
|
import { Squeebot } from './core';
|
||||||
import { SqueebotCLI } from './cli';
|
import { SqueebotCLI } from './cli';
|
||||||
@ -24,14 +23,13 @@ async function start(argv: any): Promise<void> {
|
|||||||
root = path.resolve(argv.root);
|
root = path.resolve(argv.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
const enviroFile = path.resolve(process.cwd(), argv.environment);
|
const env = await loadEnvironment(argv.environment, root);
|
||||||
const env: IEnvironment = await loadEnvironment(argv.environment, root);
|
|
||||||
|
|
||||||
// Change working directory to the environment
|
// Change working directory to the environment
|
||||||
process.chdir(env.path as string);
|
process.chdir(env.path as string);
|
||||||
|
|
||||||
|
// Create and initialize the Squeebot instance
|
||||||
const sb = new Squeebot(env);
|
const sb = new Squeebot(env);
|
||||||
|
|
||||||
await sb.initialize(argv.e !== true);
|
await sb.initialize(argv.e !== true);
|
||||||
|
|
||||||
// Create a CLI if interactive mode is enabled
|
// Create a CLI if interactive mode is enabled
|
||||||
|
Loading…
Reference in New Issue
Block a user