|
|
@@ -16,14 +16,12 @@ import type {
|
|
|
IGrowiPlugin, IGrowiPluginOrigin, IGrowiThemePluginMeta, IGrowiPluginMeta,
|
|
|
} from '../interfaces';
|
|
|
import { GrowiPlugin } from '../models';
|
|
|
+import { GitHubUrl } from '../models/vo/github-url';
|
|
|
|
|
|
const logger = loggerFactory('growi:plugins:plugin-utils');
|
|
|
|
|
|
const pluginStoringPath = resolveFromRoot('tmp/plugins');
|
|
|
|
|
|
-// https://regex101.com/r/fK2rV3/1
|
|
|
-const githubReposIdPattern = new RegExp(/^\/([^/]+)\/([^/]+)$/);
|
|
|
-
|
|
|
const PLUGINS_STATIC_DIR = '/static/plugins'; // configured by express.static
|
|
|
|
|
|
export type GrowiPluginResourceEntries = [installedPath: string, href: string][];
|
|
|
@@ -71,26 +69,16 @@ export class GrowiPluginService implements IGrowiPluginService {
|
|
|
}
|
|
|
|
|
|
// TODO: imprv Document version and repository version possibly different.
|
|
|
- const ghUrl = new URL(growiPlugin.origin.url);
|
|
|
- const ghPathname = ghUrl.pathname;
|
|
|
- // TODO: Branch names can be specified.
|
|
|
- const ghBranch = 'main';
|
|
|
- const match = ghPathname.match(githubReposIdPattern);
|
|
|
- if (ghUrl.hostname !== 'github.com' || match == null) {
|
|
|
- throw new Error('GitHub repository URL is invalid.');
|
|
|
- }
|
|
|
-
|
|
|
- const ghOrganizationName = match[1];
|
|
|
- const ghReposName = match[2];
|
|
|
+ const ghUrl = new GitHubUrl(growiPlugin.origin.url, growiPlugin.origin.branchName);
|
|
|
+ const { reposName, branchName, archiveUrl } = ghUrl;
|
|
|
|
|
|
- const requestUrl = `https://github.com/${ghOrganizationName}/${ghReposName}/archive/refs/heads/${ghBranch}.zip`;
|
|
|
- const zipFilePath = path.join(pluginStoringPath, `${ghBranch}.zip`);
|
|
|
+ const zipFilePath = path.join(pluginStoringPath, `${branchName}.zip`);
|
|
|
const unzippedPath = pluginStoringPath;
|
|
|
- const unzippedReposPath = path.join(pluginStoringPath, `${ghReposName}-${ghBranch}`);
|
|
|
+ const unzippedReposPath = path.join(pluginStoringPath, `${reposName}-${branchName}`);
|
|
|
|
|
|
try {
|
|
|
// download github repository to local file system
|
|
|
- await this.download(requestUrl, zipFilePath);
|
|
|
+ await this.download(archiveUrl, zipFilePath);
|
|
|
await this.unzip(zipFilePath, unzippedPath);
|
|
|
fs.renameSync(unzippedReposPath, pluginPath);
|
|
|
}
|
|
|
@@ -114,39 +102,30 @@ export class GrowiPluginService implements IGrowiPluginService {
|
|
|
* Install a plugin from URL and save it in the DB and file system.
|
|
|
*/
|
|
|
async install(origin: IGrowiPluginOrigin): Promise<string> {
|
|
|
- const ghUrl = new URL(origin.url);
|
|
|
- const ghPathname = ghUrl.pathname;
|
|
|
- // TODO: Branch names can be specified.
|
|
|
- const ghBranch = 'main';
|
|
|
-
|
|
|
- const match = ghPathname.match(githubReposIdPattern);
|
|
|
- if (ghUrl.hostname !== 'github.com' || match == null) {
|
|
|
- throw new Error('GitHub repository URL is invalid.');
|
|
|
- }
|
|
|
-
|
|
|
- const ghOrganizationName = match[1];
|
|
|
- const ghReposName = match[2];
|
|
|
- const installedPath = `${ghOrganizationName}/${ghReposName}`;
|
|
|
+ const ghUrl = new GitHubUrl(origin.url, origin.ghBranch);
|
|
|
+ const {
|
|
|
+ organizationName, reposName, branchName, archiveUrl,
|
|
|
+ } = ghUrl;
|
|
|
+ const installedPath = `${organizationName}/${reposName}`;
|
|
|
|
|
|
- const requestUrl = `https://github.com/${ghOrganizationName}/${ghReposName}/archive/refs/heads/${ghBranch}.zip`;
|
|
|
- const zipFilePath = path.join(pluginStoringPath, `${ghBranch}.zip`);
|
|
|
+ const zipFilePath = path.join(pluginStoringPath, `${branchName}.zip`);
|
|
|
const unzippedPath = pluginStoringPath;
|
|
|
- const unzippedReposPath = path.join(pluginStoringPath, `${ghReposName}-${ghBranch}`);
|
|
|
- const temporaryReposPath = path.join(pluginStoringPath, ghReposName);
|
|
|
+ const unzippedReposPath = path.join(pluginStoringPath, `${reposName}-${branchName}`);
|
|
|
+ const temporaryReposPath = path.join(pluginStoringPath, reposName);
|
|
|
const reposStoringPath = path.join(pluginStoringPath, `${installedPath}`);
|
|
|
- const organizationPath = path.join(pluginStoringPath, ghOrganizationName);
|
|
|
+ const organizationPath = path.join(pluginStoringPath, organizationName);
|
|
|
|
|
|
|
|
|
let plugins: IGrowiPlugin<IGrowiPluginMeta>[];
|
|
|
|
|
|
try {
|
|
|
// download github repository to file system's temporary path
|
|
|
- await this.download(requestUrl, zipFilePath);
|
|
|
+ await this.download(archiveUrl, zipFilePath);
|
|
|
await this.unzip(zipFilePath, unzippedPath);
|
|
|
fs.renameSync(unzippedReposPath, temporaryReposPath);
|
|
|
|
|
|
// detect plugins
|
|
|
- plugins = await GrowiPluginService.detectPlugins(origin, ghOrganizationName, ghReposName);
|
|
|
+ plugins = await GrowiPluginService.detectPlugins(origin, organizationName, reposName);
|
|
|
|
|
|
if (!fs.existsSync(organizationPath)) fs.mkdirSync(organizationPath);
|
|
|
|