-
Notifications
You must be signed in to change notification settings - Fork 139
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add App Metadata To Open theia:// links. #378
* create desktop file for linux desktop integration * add protocol for mac Contributed on behalf of STMicroelectronics
- Loading branch information
1 parent
53ed45d
commit b341482
Showing
8 changed files
with
233 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
theia-extensions/launcher/src/browser/desktopfile-service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/******************************************************************************** | ||
* Copyright (C) 2024 STMicroelectronics and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the MIT License, which is available in the project root. | ||
* | ||
* SPDX-License-Identifier: MIT | ||
********************************************************************************/ | ||
|
||
import { Endpoint } from '@theia/core/lib/browser'; | ||
import { injectable } from '@theia/core/shared/inversify'; | ||
|
||
@injectable() | ||
export class DesktopFileService { | ||
|
||
async isInitialized(): Promise<boolean> { | ||
const response = await fetch(new Request(`${this.endpoint()}/initialized`), { | ||
body: undefined, | ||
method: 'GET' | ||
}).then(r => r.json()); | ||
return !!response?.initialized; | ||
} | ||
|
||
async createOrUpdateDesktopfile(create: boolean): Promise<void> { | ||
fetch(new Request(`${this.endpoint()}`), { | ||
body: JSON.stringify({ create }), | ||
method: 'PUT', | ||
headers: new Headers({ 'Content-Type': 'application/json' }) | ||
}); | ||
} | ||
|
||
protected endpoint(): string { | ||
const url = new Endpoint({ path: 'desktopfile' }).getRestUrl().toString(); | ||
return url.endsWith('/') ? url.slice(0, -1) : url; | ||
} | ||
} |
136 changes: 136 additions & 0 deletions
136
theia-extensions/launcher/src/node/desktopfile-endpoint.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/******************************************************************************** | ||
* Copyright (C) 2024 STMicroelectronics and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the MIT License, which is available in the project root. | ||
* | ||
* SPDX-License-Identifier: MIT | ||
********************************************************************************/ | ||
|
||
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application'; | ||
import { Application, Router } from '@theia/core/shared/express'; | ||
import { inject, injectable } from '@theia/core/shared/inversify'; | ||
import { Request, Response } from 'express-serve-static-core'; | ||
import { json } from 'body-parser'; | ||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; | ||
import { getStorageFilePath } from './launcher-util'; | ||
import * as fs from 'fs-extra'; | ||
import * as path from 'path'; | ||
|
||
interface DesktopFileInformation { | ||
appImage: string; | ||
declined: string[]; | ||
} | ||
|
||
@injectable() | ||
export class TheiaDesktopFileServiceEndpoint implements BackendApplicationContribution { | ||
|
||
protected static PATH = '/desktopfile'; | ||
protected static STORAGE_FILE_NAME = 'desktopfile.json'; | ||
|
||
@inject(EnvVariablesServer) | ||
protected readonly envServer: EnvVariablesServer; | ||
|
||
configure(app: Application): void { | ||
const router = Router(); | ||
router.put('/', (request, response) => this.createOrUpdateDesktopfile(request, response)); | ||
router.get('/initialized', (request, response) => this.isInitialized(request, response)); | ||
app.use(json()); | ||
app.use(TheiaDesktopFileServiceEndpoint.PATH, router); | ||
} | ||
|
||
protected async isInitialized(_request: Request, response: Response): Promise<void> { | ||
if (!process.env.APPIMAGE) { | ||
// we only want to create Desktop Files when running as an App Image | ||
response.json({ initialized: true }); | ||
} | ||
if (process.env.HOME === undefined) { | ||
// log error but assume initialized, since we can't proceed | ||
console.error('Desktop files can only be created if there is a set HOME directory'); | ||
response.json({ initialized: true }); | ||
} | ||
const storageFile = await getStorageFilePath(this.envServer, TheiaDesktopFileServiceEndpoint.STORAGE_FILE_NAME); | ||
if (!storageFile) { | ||
throw new Error('Could not resolve path to storage file.'); | ||
} | ||
if (!fs.existsSync(storageFile)) { | ||
response.json({ initialized: false }); | ||
return; | ||
} | ||
const appImageInformation = await this.readAppImageInformationFromStorage(storageFile); | ||
if (appImageInformation === undefined) { | ||
response.json({ initialized: false }); | ||
return; | ||
} | ||
if (appImageInformation.declined !== undefined && appImageInformation.declined.includes(process.env.APPIMAGE!)) { | ||
// we don't want to create Desktop Files for this App Image | ||
response.json({ initialized: true }); | ||
return; | ||
} | ||
const initialized = appImageInformation.appImage === process.env.APPIMAGE; | ||
response.json({ initialized }); | ||
} | ||
|
||
protected async readAppImageInformationFromStorage(storageFile: string): Promise<DesktopFileInformation | undefined> { | ||
if (!fs.existsSync(storageFile)) { | ||
return undefined; | ||
} | ||
try { | ||
const data: DesktopFileInformation = await fs.readJSON(storageFile); | ||
return data; | ||
} catch (error) { | ||
console.error('Failed to parse data from "', storageFile, '". Reason:', error); | ||
return undefined; | ||
} | ||
} | ||
|
||
protected async createOrUpdateDesktopfile(request: Request, response: Response): Promise<void> { | ||
const storageFile = await getStorageFilePath(this.envServer, TheiaDesktopFileServiceEndpoint.STORAGE_FILE_NAME); | ||
let appImageInformation: DesktopFileInformation | undefined = await this.readAppImageInformationFromStorage(storageFile); | ||
if (appImageInformation === undefined) { | ||
appImageInformation = { appImage: '', declined: [] }; | ||
} | ||
|
||
const createOrUpdate = request.body.create; | ||
if (createOrUpdate) { | ||
const imagePath = path.join(process.env.HOME!, '.local', 'share', 'applications', 'theia-ide-electron-app.png'); | ||
if (!fs.existsSync(imagePath)) { | ||
const appDir = process.env.APPDIR; | ||
if (appDir !== undefined) { | ||
const unpackedImagePath = path.join(appDir, 'theia-ide-electron-app.png'); | ||
if (fs.existsSync(unpackedImagePath)) { | ||
fs.copyFileSync(unpackedImagePath, imagePath); | ||
} else { | ||
console.warn('Launcher Icon not Found in App Image'); | ||
} | ||
} else { | ||
console.warn('Path for unpacked App Image not found'); | ||
} | ||
} | ||
|
||
const desktopFilePath = path.join(process.env.HOME!, '.local', 'share', 'applications', 'theia-ide-launcher.desktop'); | ||
fs.outputFileSync(desktopFilePath, this.getDesktopFileContents(process.env.APPIMAGE!, imagePath)); | ||
|
||
appImageInformation.appImage = process.env.APPIMAGE!; | ||
fs.outputJSONSync(storageFile, appImageInformation); | ||
} else { | ||
appImageInformation.declined.push(process.env.APPIMAGE!); | ||
fs.outputJSONSync(storageFile, appImageInformation); | ||
} | ||
|
||
response.sendStatus(200); | ||
} | ||
|
||
protected getDesktopFileContents(appImagePath: string, imagePath: string): string { | ||
return `[Desktop Entry] | ||
Name=TheiaIDE | ||
Exec=${appImagePath} %U | ||
Terminal=false | ||
Type=Application | ||
Icon=${imagePath} | ||
StartupWMClass=TheiaIDE | ||
MimeType=x-scheme-handler/theia; | ||
Comment=Eclipse Theia IDE product | ||
Categories=Development;`; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/******************************************************************************** | ||
* Copyright (C) 2024 STMicroelectronics and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the MIT License, which is available in the project root. | ||
* | ||
* SPDX-License-Identifier: MIT | ||
********************************************************************************/ | ||
|
||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; | ||
import URI from '@theia/core/lib/common/uri'; | ||
|
||
export async function getStorageFilePath(envServer: EnvVariablesServer, fileName: string): Promise<string> { | ||
const configDirUri = await envServer.getConfigDirUri(); | ||
const globalStorageFolderUri = new URI(configDirUri).resolve('globalStorage/theia-ide-launcher/' + fileName); | ||
const globalStorageFolderFsPath = globalStorageFolderUri.path.fsPath(); | ||
return globalStorageFolderFsPath; | ||
} |