diff --git a/.github/workflows/package.yaml b/.github/workflows/package.yaml index b826a20..9f4211c 100644 --- a/.github/workflows/package.yaml +++ b/.github/workflows/package.yaml @@ -87,8 +87,8 @@ jobs: - uses: actions/upload-artifact@v2 if: startsWith(matrix.os, 'ubuntu-') with: - name: Rancher Desktop-linux.zip - path: dist/rancher-desktop*.zip + name: Rancher Desktop-linux.tar.gz + path: dist/rancher-desktop*.tar.gz if-no-files-found: error - uses: actions/upload-artifact@v2 if: startsWith(matrix.os, 'ubuntu-') @@ -96,3 +96,15 @@ jobs: name: Rancher Desktop.flatpak path: dist/Rancher Desktop*.flatpak if-no-files-found: error + - uses: actions/upload-artifact@v2 + if: startsWith(matrix.os, 'ubuntu-') + with: + name: Rancher Desktop.rpm + path: dist/rancher-desktop*.rpm + if-no-files-found: error + - uses: actions/upload-artifact@v2 + if: startsWith(matrix.os, 'ubuntu-') + with: + name: Rancher Desktop.deb + path: dist/rancher-desktop*.deb + if-no-files-found: error diff --git a/background.ts b/background.ts index 807fa04..2fee6d9 100644 --- a/background.ts +++ b/background.ts @@ -124,7 +124,7 @@ async function doFirstRun() { return; } await window.openFirstRun(); - if (os.platform() === 'darwin') { + if (os.platform() === 'darwin' || os.platform() === 'linux') { await Promise.all([ linkResource('helm', true), linkResource('kim', true), // TODO: Remove when we stop shipping kim @@ -509,10 +509,20 @@ async function getVersion() { * @param state -- true to symlink, false to delete */ async function linkResource(name: string, state: boolean): Promise { - const linkPath = path.join('/usr/local/bin', name); + const linkPath = path.join(paths.integration, name); + + let err: Error | null = await new Promise((resolve) => { + fs.mkdir(paths.integration, { recursive: true }, resolve); + }); + + if (err) { + console.error(`Error creating the directory ${ paths.integration }: ${ err.message }`); + + return err; + } if (state) { - const err: Error | null = await new Promise((resolve) => { + err = await new Promise((resolve) => { fs.symlink(resources.executable(name), linkPath, 'file', resolve); }); @@ -522,7 +532,7 @@ async function linkResource(name: string, state: boolean): Promise return err; } } else { - const err: Error | null = await new Promise((resolve) => { + err = await new Promise((resolve) => { fs.unlink(linkPath, resolve); }); diff --git a/electron-builder.yml b/electron-builder.yml index 800ab44..9738c53 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -29,7 +29,10 @@ win: linux: category: Utility executableName: rancher-desktop - target: [ flatpak, zip ] + icon: ./resources/icons/linux + synopsis: Kubernetes and container management on the desktop + description: Rancher Desktop is an open-source project to bring Kubernetes and container management to the desktop + target: [ flatpak, tar.gz, rpm, deb ] nsis: license: LICENSE include: build/installer.nsh @@ -53,6 +56,7 @@ flatpak: - --filesystem=xdg-data/rancher-desktop:create - --filesystem=~/.kube:create - --filesystem=~/.kuberlr:create + - --filesystem=~/.local/bin:create - --device=kvm - --device=dri - --share=ipc @@ -63,30 +67,24 @@ flatpak: - --own-name=org.kde.* # Fixes Tray in KDE (https://github.com/flathub/im.riot.Riot/issues/100) files: - ["dist/linux-unpacked/resources/resources/linux/misc/io.rancherdesktop.app.appdata.xml", "/share/metainfo/io.rancherdesktop.app.appdata.xml"] - - ["dist/linux-unpacked/resources/resources/linux/misc/io.rancherdesktop.app.desktop", "/share/applications/io.rancherdesktop.app.desktop"] - - ["dist/linux-unpacked/resources/resources/icons/linux", "/share/icons/hicolor"] modules: - name: qemu config-opts: - "--disable-user" - "--enable-kvm" - #- "--enable-vde" - "--target-list=x86_64-softmmu" sources: - type: archive url: https://download.qemu.org/qemu-6.1.0.tar.xz sha256: eebc089db3414bbeedf1e464beda0a7515aad30f73261abc246c9b27503a3c96 - # We do not need vde under linux - #modules: - #- name: vde-2 - # sources: - # - type: git - # url: https://github.com/virtualsquare/vde-2 - # tag: vde-2 - # buildsystem: simple - # build-commands: - # - | - # cd 2.3.2 - # autoreconf --install - # ./configure --prefix=/app --disable-python --disable-cryptcab - # make install +rpm: + depends: + - qemu + fpm: + # Make sure not /usr/lib/.build-id artifacts are created + # This config is likely to be missing in non RPM based hosts + - --rpm-rpmbuild-define=_build_id_links none +deb: + depends: + - qemu-utils + - qemu-system-x86 diff --git a/resources/linux/misc/io.rancherdesktop.app.desktop b/flatpak/io.rancherdesktop.app.desktop similarity index 100% rename from resources/linux/misc/io.rancherdesktop.app.desktop rename to flatpak/io.rancherdesktop.app.desktop diff --git a/flatpak/io.rancherdesktop.app.yml b/flatpak/io.rancherdesktop.app.yml index 89035c9..691fe12 100644 --- a/flatpak/io.rancherdesktop.app.yml +++ b/flatpak/io.rancherdesktop.app.yml @@ -22,6 +22,7 @@ finish-args: - --filesystem=xdg-data/rancher-desktop:create - --filesystem=~/.kube:create - --filesystem=~/.kuberlr:create + - --filesystem=~/.local/bin:create - --talk-name=org.freedesktop.Notifications - --own-name=org.kde.* modules: @@ -32,26 +33,32 @@ modules: - type: dir path: .. dest: lib + - type: file + path: io.rancherdesktop.app.desktop + dest: lib - type: script dest-filename: electron-wrapper commands: - | export TMPDIR="$XDG_RUNTIME_DIR/app/$FLATPAK_ID" - if [ "${XDG_SESSION_TYPE}" == "wayland" ]; then - zypak-wrapper /app/lib/io.rancherdesktop.app/rancher-desktop --enable-features=UseOzonePlatform --ozone-platform=wayland "$@" - else - zypak-wrapper /app/lib/io.rancherdesktop.app/rancher-desktop "$@" - fi + zypak-wrapper /app/lib/io.rancherdesktop.app/rancher-desktop "$@" build-commands: # Bundle electron build after npm run build -- --linux --publish=never - cp -a dist/linux*unpacked /app/lib/io.rancherdesktop.app # Include FreeDesktop integration files at expected locations - rm -rf /app/share/metainfo /app/share/icons /app/share/applications - - mkdir -p /app/share/metainfo /app/share/icons /app/share/applications + - mkdir -p /app/share/metainfo /app/share/applications + - | + icons=/app/lib/io.rancherdesktop.app/resources/resources/icons/linux + for img in $(ls "${icons}"); do + size="${img//rancher-desktop./}" + size="${size%%.png}" + mkdir "/app/share/icons/hicolor/${size}/apps" -p + cp "${icons}/${img}" "/app/share/icons/hicolor/${size}/apps/io.rancherdesktop.app.png" + done - cp /app/lib/io.rancherdesktop.app/resources/resources/linux/misc/io.rancherdesktop.app.appdata.xml /app/share/metainfo - - cp /app/lib/io.rancherdesktop.app/resources/resources/linux/misc/io.rancherdesktop.app.desktop /app/share/applications - - cp -r /app/lib/io.rancherdesktop.app/resources/resources/icons/linux /app/share/icons/hicolor + - mv io.rancherdesktop.app.desktop /app/share/applications # Install app wrapper - install -Dm755 -t /app/bin/ ../electron-wrapper modules: @@ -59,22 +66,8 @@ modules: config-opts: - "--disable-user" - "--enable-kvm" - #- "--enable-vde" - "--target-list=x86_64-softmmu" sources: - type: archive url: https://download.qemu.org/qemu-6.1.0.tar.xz sha256: eebc089db3414bbeedf1e464beda0a7515aad30f73261abc246c9b27503a3c96 - #modules: - #- name: vde-2 - # sources: - # - type: git - # url: https://github.com/virtualsquare/vde-2 - # tag: vde-2 - # buildsystem: simple - # build-commands: - # - | - # cd 2.3.2 - # autoreconf --install - # ./configure --prefix=/app --disable-python --disable-cryptcab - # make install diff --git a/package.json b/package.json index 14c58c9..e11eb91 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,10 @@ "name": "rancher-desktop", "license": "Apache-2.0", "version": "0.6.0", + "author": { + "name": "SUSE", + "email": "containers@suse.com" + }, "engines": { "node": ">=14.14" }, diff --git a/resources/icons/linux/128x128/apps/io.rancherdesktop.app.png b/resources/icons/linux/rancher-desktop.128x128.png similarity index 100% rename from resources/icons/linux/128x128/apps/io.rancherdesktop.app.png rename to resources/icons/linux/rancher-desktop.128x128.png diff --git a/resources/icons/linux/16x16/apps/io.rancherdesktop.app.png b/resources/icons/linux/rancher-desktop.16x16.png similarity index 100% rename from resources/icons/linux/16x16/apps/io.rancherdesktop.app.png rename to resources/icons/linux/rancher-desktop.16x16.png diff --git a/resources/icons/linux/256x256/apps/io.rancherdesktop.app.png b/resources/icons/linux/rancher-desktop.256x256.png similarity index 100% rename from resources/icons/linux/256x256/apps/io.rancherdesktop.app.png rename to resources/icons/linux/rancher-desktop.256x256.png diff --git a/resources/icons/linux/32x32/apps/io.rancherdesktop.app.png b/resources/icons/linux/rancher-desktop.32x32.png similarity index 100% rename from resources/icons/linux/32x32/apps/io.rancherdesktop.app.png rename to resources/icons/linux/rancher-desktop.32x32.png diff --git a/resources/icons/linux/48x48/apps/io.rancherdesktop.app.png b/resources/icons/linux/rancher-desktop.48x48.png similarity index 100% rename from resources/icons/linux/48x48/apps/io.rancherdesktop.app.png rename to resources/icons/linux/rancher-desktop.48x48.png diff --git a/resources/icons/linux/512x512/apps/io.rancherdesktop.app.png b/resources/icons/linux/rancher-desktop.512x512.png similarity index 100% rename from resources/icons/linux/512x512/apps/io.rancherdesktop.app.png rename to resources/icons/linux/rancher-desktop.512x512.png diff --git a/resources/icons/linux/64x64/apps/io.rancherdesktop.app.png b/resources/icons/linux/rancher-desktop.64x64.png similarity index 100% rename from resources/icons/linux/64x64/apps/io.rancherdesktop.app.png rename to resources/icons/linux/rancher-desktop.64x64.png diff --git a/src/assets/translations/en-us.yaml b/src/assets/translations/en-us.yaml index 417dd79..f8f4c35 100644 --- a/src/assets/translations/en-us.yaml +++ b/src/assets/translations/en-us.yaml @@ -4515,7 +4515,7 @@ troubleshooting: integrations: darwin: title: Supporting Utilities - description: Create symbolic links to tools in /usr/local/bin + description: Create symbolic links to tools in windows: title: WSL Integration description: "Expose Rancher Desktop's Kubernetes configuration to Windows Subsystem for Linux (WSL) distros" diff --git a/src/components/Integration.vue b/src/components/Integration.vue index 9dc3b50..47d00fb 100644 --- a/src/components/Integration.vue +++ b/src/components/Integration.vue @@ -26,6 +26,7 @@ import Component from 'vue-class-component'; import Banner from '@/components/Banner.vue'; import Card from '@/components/Card.vue'; import Checkbox from '@/components/form/Checkbox.vue'; +import paths from '@/utils/paths'; const IntegrationProps = Vue.extend({ props: { @@ -59,7 +60,7 @@ class Integration extends IntegrationProps { * asynchronously, to prevent the user from retrying to toggle too quickly. */ protected busy: Record = {}; - protected GlobalFailureIntegrationName = '/usr/local/bin'; + protected GlobalFailureIntegrationName = paths.integration; get globalError() { return this.integrations[this.GlobalFailureIntegrationName]; diff --git a/src/k8s-engine/unixlikeIntegrations.ts b/src/k8s-engine/unixlikeIntegrations.ts index 0d911fa..4a1495f 100644 --- a/src/k8s-engine/unixlikeIntegrations.ts +++ b/src/k8s-engine/unixlikeIntegrations.ts @@ -2,6 +2,7 @@ import path from 'path'; import fs from 'fs'; import Logging from '@/utils/logging'; +import paths from '@/utils/paths'; import resources from '@/resources'; import PathConflictManager from '@/main/pathConflictManager'; import * as window from '@/window'; @@ -9,7 +10,7 @@ import * as window from '@/window'; // TODO: Remove 'kim' when we stop shipping kim const INTEGRATIONS = ['helm', 'kim', 'kubectl', 'nerdctl']; const console = Logging.background; -const PUBLIC_LINK_DIR = '/usr/local/bin'; +const PUBLIC_LINK_DIR = paths.integration; /* * There are probably going to be only two kinds of integrations: WSL for Windows, diff --git a/src/layouts/default.vue b/src/layouts/default.vue index 203eac3..a406440 100644 --- a/src/layouts/default.vue +++ b/src/layouts/default.vue @@ -41,12 +41,7 @@ export default { }, data() { - // Linux integration are not yet available - if (os.platform() === 'linux') { - return { routes: ['/General', '/K8s', '/Images', '/Troubleshooting'] }; - } else { - return { routes: ['/General', '/K8s', '/Integrations', '/Images', '/Troubleshooting'] }; - } + return { routes: ['/General', '/K8s', '/Integrations', '/Images', '/Troubleshooting'] }; }, head() { @@ -68,12 +63,7 @@ export default { mounted() { ipcRenderer.invoke('k8s-supports-port-forwarding').then((supported) => { if (supported) { - // Linux integrations are not yet available - if (os.platform() === 'linux') { - this.$data.routes = ['/General', '/K8s', '/PortForwarding', '/Images', '/Troubleshooting']; - } else { - this.$data.routes = ['/General', '/K8s', '/Integrations', '/PortForwarding', '/Images', '/Troubleshooting']; - } + this.$data.routes = ['/General', '/K8s', '/Integrations', '/PortForwarding', '/Images', '/Troubleshooting']; } }); }, diff --git a/src/main/pathConflictManager.ts b/src/main/pathConflictManager.ts index 226401a..d3ecc2b 100644 --- a/src/main/pathConflictManager.ts +++ b/src/main/pathConflictManager.ts @@ -5,6 +5,7 @@ import timers from 'timers'; import * as window from '@/window'; import pathConflict from '@/utils/pathConflict'; import Logging from '@/utils/logging'; +import paths from '@/utils/paths'; const console = Logging.background; const DebounceInterval = 500; // msec @@ -40,7 +41,7 @@ export default class PathConflictManager { let results: Array = []; try { - results = this.pathConflicts[binaryName] = await pathConflict('/usr/local/bin', binaryName); + results = this.pathConflicts[binaryName] = await pathConflict(paths.integration, binaryName); } catch (err) { console.log(`Error gathering conflicts for file ${ binaryName }`, err); // And leave results as an empty array, to clear the current warnings @@ -60,7 +61,7 @@ export default class PathConflictManager { return; } const currentPathDirectories = currentPathAsString.split(path.delimiter) - .filter(dir => path.resolve(dir) !== '/usr/local/bin'); + .filter(dir => path.resolve(dir) !== paths.integration); const namesOfInterest = ['helm', 'kim', 'kubectl', 'nerdctl']; for (const dirName of currentPathDirectories) { diff --git a/src/main/paths.ts b/src/main/paths.ts index 04a9f9c..509027b 100644 --- a/src/main/paths.ts +++ b/src/main/paths.ts @@ -25,6 +25,7 @@ class DarwinObsoletePaths implements Paths { cache = path.join(os.homedir(), 'Library', 'Caches', APP_NAME); lima = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'lima'); hyperkit = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'driver'); + integration = '/usr/local/bin'; get wslDistro(): string { throw new Error('wslDistro not available for darwin'); } @@ -67,6 +68,10 @@ class Win32ObsoletePaths implements Paths { get hyperkit(): string { throw new Error('hyperkit not available for win32'); } + + get integration(): string { + throw new Error('integration path not available for win32'); + } } /** * Remove the given directory if it is empty, and also any parent directories diff --git a/src/pages/Integrations.vue b/src/pages/Integrations.vue index f305f0f..3a0a160 100644 --- a/src/pages/Integrations.vue +++ b/src/pages/Integrations.vue @@ -7,6 +7,7 @@ import os from 'os'; import { ipcRenderer } from 'electron'; import Vue from 'vue'; import Integration from '@/components/Integration.vue'; +import paths from '@/utils/paths'; declare module 'vue/types/vue' { interface t { @@ -30,7 +31,7 @@ export default Vue.extend({ }, computed: { hasIntegration() { - return /^win|^darwin$/.test(os.platform()); + return /^win|^darwin|^linux$/.test(os.platform()); }, integrationTitle(): string { if (os.platform() !== 'win32') { @@ -41,7 +42,7 @@ export default Vue.extend({ }, integrationDescription(): string { if (os.platform() !== 'win32') { - return this.t('integrations.darwin.description'); + return `${ this.t('integrations.darwin.description') } ${ paths.integration }`; } return this.t('integrations.windows.description', { }, true); diff --git a/src/utils/__tests__/paths.spec.ts b/src/utils/__tests__/paths.spec.ts index 65f3f7b..0d598e2 100644 --- a/src/utils/__tests__/paths.spec.ts +++ b/src/utils/__tests__/paths.spec.ts @@ -37,6 +37,10 @@ describe('paths', () => { win32: Error(), darwin: '%HOME%/Library/State/rancher-desktop/driver/', }, + integration: { + win32: Error(), + darwin: '/usr/local/bin', + }, }; const table = Object.entries(cases).flatMap( diff --git a/src/utils/paths.ts b/src/utils/paths.ts index 0451e0a..98f2526 100644 --- a/src/utils/paths.ts +++ b/src/utils/paths.ts @@ -20,6 +20,8 @@ export interface Paths { wslDistroData: string; /** Directory holding Lima state (macOS-specific). */ lima: string; + /** Directory holding provided binary resources */ + integration: string; /** @deprecated Directory holding hyperkit state (macOS-specific) */ hyperkit: string; } @@ -33,6 +35,7 @@ export class DarwinPaths implements Paths { cache = path.join(os.homedir(), 'Library', 'Caches', APP_NAME); lima = path.join(os.homedir(), 'Library', 'Application Support', APP_NAME, 'lima'); hyperkit = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'driver'); + integration = '/usr/local/bin'; get wslDistro(): string { throw new Error('wslDistro not available for darwin'); } @@ -75,6 +78,10 @@ export class Win32Paths implements Paths { get hyperkit(): string { throw new Error('hyperkit not available for Windows'); } + + get integration(): string { + throw new Error('integration path not available for Windows'); + } } /** @@ -108,6 +115,10 @@ export class LinuxPaths implements Paths { return path.join(this.dataHome, APP_NAME, 'lima'); } + get integration(): string { + return path.join(os.homedir(), '.local', 'bin'); + } + get hyperkit(): string { throw new Error('hyperkit not available for Linux'); }