1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Desktop: Download plugins from GitHub release

This commit is contained in:
Laurent Cozic 2021-06-01 11:09:46 +02:00
parent d8d83b236e
commit 8f6a47536c
3 changed files with 66 additions and 7 deletions

View File

@ -4,7 +4,7 @@ import { setupDatabaseAndSynchronizer, switchClient, supportDir, createTempDir }
async function newRepoApi(): Promise<RepositoryApi> {
const repo = new RepositoryApi(`${supportDir}/pluginRepo`, await createTempDir());
await repo.loadManifests();
await repo.initialize();
return repo;
}

View File

@ -113,7 +113,7 @@ export default function(props: Props) {
let loadError: Error = null;
try {
await repoApi().loadManifests();
await repoApi().initialize();
} catch (error) {
logger.error(error);
loadError = error;

View File

@ -1,8 +1,21 @@
import Logger from '../../Logger';
import shim from '../../shim';
import { PluginManifest } from './utils/types';
const md5 = require('md5');
const compareVersions = require('compare-versions');
const logger = Logger.create('RepositoryApi');
interface ReleaseAsset {
name: string;
browser_download_url: string;
}
interface Release {
upload_url: string;
assets: ReleaseAsset[];
}
export default class RepositoryApi {
// As a base URL, this class can support either a remote repository or a
@ -14,6 +27,7 @@ export default class RepositoryApi {
// Later on, other repo types could be supported.
private baseUrl_: string;
private tempDir_: string;
private release_: Release = null;
private manifests_: PluginManifest[] = null;
public constructor(baseUrl: string, tempDir: string) {
@ -21,7 +35,12 @@ export default class RepositoryApi {
this.tempDir_ = tempDir;
}
public async loadManifests() {
public async initialize() {
await this.loadManifests();
await this.loadRelease();
}
private async loadManifests() {
const manifestsText = await this.fetchText('manifests.json');
try {
const manifests = JSON.parse(manifestsText);
@ -34,6 +53,27 @@ export default class RepositoryApi {
}
}
private get githubApiUrl(): string {
// https://github.com/joplin/plugins
// https://api.github.com/repos/joplin/plugins/releases
return this.baseUrl_.replace(/^(https:\/\/)(github\.com\/)(.*)$/, '$1api.$2repos/$3');
}
private async loadRelease() {
this.release_ = null;
if (this.isLocalRepo) return;
try {
const response = await fetch(`${this.githubApiUrl}/releases`);
const releases = await response.json();
if (!releases.length) throw new Error('No release was found');
this.release_ = releases[0];
} catch (error) {
logger.warn('Could not load release - files will be downloaded from the repository directly:', error);
}
}
private get isLocalRepo(): boolean {
return this.baseUrl_.indexOf('http') !== 0;
}
@ -46,15 +86,34 @@ export default class RepositoryApi {
}
}
private fileUrl(relativePath: string): string {
private assetFileUrl(pluginId: string): string {
if (this.release_) {
const asset = this.release_.assets.find(asset => {
const s = asset.name.split('@');
s.pop();
const id = s.join('@');
return id === pluginId;
});
if (asset) return asset.browser_download_url;
logger.warn(`Could not get plugin from release: ${pluginId}`);
}
// If we couldn't get the plugin file from the release, get it directly
// from the repository instead.
return this.repoFileUrl(`plugins/${pluginId}/plugin.jpl`);
}
private repoFileUrl(relativePath: string): string {
return `${this.contentBaseUrl}/${relativePath}`;
}
private async fetchText(path: string): Promise<string> {
if (this.isLocalRepo) {
return shim.fsDriver().readFile(this.fileUrl(path), 'utf8');
return shim.fsDriver().readFile(this.repoFileUrl(path), 'utf8');
} else {
return shim.fetchText(this.fileUrl(path));
return shim.fetchText(this.repoFileUrl(path));
}
}
@ -86,7 +145,7 @@ export default class RepositoryApi {
const manifest = manifests.find(m => m.id === pluginId);
if (!manifest) throw new Error(`No manifest for plugin ID "${pluginId}"`);
const fileUrl = this.fileUrl(`plugins/${manifest.id}/plugin.jpl`);
const fileUrl = this.assetFileUrl(manifest.id); // this.repoFileUrl(`plugins/${manifest.id}/plugin.jpl`);
const hash = md5(Date.now() + Math.random());
const targetPath = `${this.tempDir_}/${hash}_${manifest.id}.jpl`;