Merge pull request #1019 from qitechgmbh/615-test-nixos-builds-in-ci-cd
Rework github pipeline
This commit is contained in:
24 files changed
+520
-5964
No files matched your search
@@ -3,50 +3,73 @@ name: Electron
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "**"
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
- master
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: electron
|
||||
|
||||
jobs:
|
||||
build-electron:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: electron
|
||||
|
||||
steps:
|
||||
- name: Setup Node.js
|
||||
- &checkout
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- &setup-node
|
||||
name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "18" # or '20' for latest LTS
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
cache-dependency-path: |
|
||||
electron/package-lock.json
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- &install
|
||||
name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
node_modules/
|
||||
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-npm-
|
||||
|
||||
- name: Install
|
||||
run: npm i
|
||||
|
||||
- name: Build
|
||||
- name: Compile
|
||||
run: tsc
|
||||
|
||||
- name: Format
|
||||
run: npm run format
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *setup-node
|
||||
- *install
|
||||
|
||||
- name: Test
|
||||
run: npm run test
|
||||
|
||||
- name: Package
|
||||
run: npm run package
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *setup-node
|
||||
- *install
|
||||
|
||||
- name: Format
|
||||
run: npm run format
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *setup-node
|
||||
- *install
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
@@ -0,0 +1,96 @@
|
||||
name: Nix CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
NIX_PATH: nixpkgs=channel:nixos-25.05
|
||||
|
||||
jobs:
|
||||
electron:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- &checkout
|
||||
name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- &nix-install
|
||||
uses: nixbuild/nix-quick-install-action@v34
|
||||
with:
|
||||
nix_conf: |
|
||||
keep-env-derivations = true
|
||||
keep-outputs = true
|
||||
|
||||
- uses: nix-community/cache-nix-action@v6
|
||||
with:
|
||||
primary-key: nix-electron-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock', './electron/package-lock.json') }}
|
||||
restore-prefixes-first-match: nix-${{ runner.os }}-
|
||||
purge: true
|
||||
purge-prefixes: nix-electron-${{ runner.os }}-
|
||||
|
||||
- name: Build Electron in Nix
|
||||
run: nix build ".#packages.x86_64-linux.electron"
|
||||
|
||||
rust:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *nix-install
|
||||
|
||||
- uses: nix-community/cache-nix-action@v6
|
||||
with:
|
||||
primary-key: nix-server-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock', './Cargo.lock') }}
|
||||
restore-prefixes-first-match: nix-${{ runner.os }}-
|
||||
purge: true
|
||||
purge-prefixes: nix-server-${{ runner.os }}-
|
||||
|
||||
- name: Build Server in Nix
|
||||
run: nix build ".#packages.x86_64-linux.server"
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [electron, rust]
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *nix-install
|
||||
|
||||
- name: Use both Electron and Server Nix Store
|
||||
uses: nix-community/cache-nix-action@v6
|
||||
with:
|
||||
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock', './Cargo.lock', './electron/package-lock.json') }}
|
||||
|
||||
# if no hit on the primary key, merge individual caches
|
||||
restore-prefixes-all-matches: |
|
||||
nix-electron-${{ runner.os }}-
|
||||
nix-server-${{ runner.os }}-
|
||||
|
||||
- name: Build Flake and System Configuration
|
||||
run: nix build ".#nixosConfigurations.nixos.config.system.build.toplevel" --impure
|
||||
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *nix-install
|
||||
|
||||
- name: Format
|
||||
run: nix run 'nixpkgs#nixfmt-classic' $(find . nixos -name '*.nix')
|
||||
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *nix-install
|
||||
|
||||
- name: Build Flake and Configuration.nix
|
||||
run: nix flake check "." --impure
|
||||
+46
-10
@@ -3,9 +3,10 @@ name: Rust
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "**"
|
||||
- master
|
||||
pull_request:
|
||||
branches: "*"
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -16,14 +17,24 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Install libudev development package
|
||||
- &udev-install
|
||||
name: Install libudev development package
|
||||
run: sudo apt-get update && sudo apt-get install -y libudev-dev
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set Rust version
|
||||
run: rustup override set ${{ env.RUST_VERSION }}
|
||||
- name: Install Formatter
|
||||
run: rustup component add rustfmt
|
||||
- name: Cache Rust dependencies
|
||||
|
||||
- &checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- &setup-rust
|
||||
name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
profile: minimal
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- &cargo-cache
|
||||
name: Cache Rust dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
@@ -41,11 +52,36 @@ jobs:
|
||||
RUSTFLAGS: "-D warnings"
|
||||
run: cargo build --verbose
|
||||
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *setup-rust
|
||||
|
||||
- name: Format
|
||||
run: cargo fmt --check --verbose
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *udev-install
|
||||
- *checkout
|
||||
- *setup-rust
|
||||
- *cargo-cache
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
|
||||
mock:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- *udev-install
|
||||
- *checkout
|
||||
- *setup-rust
|
||||
- *cargo-cache
|
||||
|
||||
- name: Mock Machine
|
||||
run: cargo build --features development-build --features mock-machine
|
||||
run: cargo build --features "development-build,mock-machine"
|
||||
@@ -88,6 +88,7 @@ typings/
|
||||
# Vite
|
||||
.vite/
|
||||
dist/
|
||||
dist-electron/
|
||||
|
||||
# Electron-Forge
|
||||
out/
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import type { ForgeConfig } from "@electron-forge/shared-types";
|
||||
import { VitePlugin } from "@electron-forge/plugin-vite";
|
||||
import { FusesPlugin } from "@electron-forge/plugin-fuses";
|
||||
import { FuseV1Options, FuseVersion } from "@electron/fuses";
|
||||
|
||||
const config: ForgeConfig = {
|
||||
packagerConfig: {
|
||||
executableName: "electron-shadcn",
|
||||
asar: true,
|
||||
icon: "src/assets/icon",
|
||||
},
|
||||
rebuildConfig: {},
|
||||
plugins: [
|
||||
new VitePlugin({
|
||||
// `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
|
||||
// If you are familiar with Vite configuration, it will look really familiar.
|
||||
build: [
|
||||
{
|
||||
// `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
|
||||
entry: "src/main.ts",
|
||||
config: "vite.main.config.ts",
|
||||
},
|
||||
{
|
||||
entry: "src/preload.ts",
|
||||
config: "vite.preload.config.ts",
|
||||
},
|
||||
],
|
||||
renderer: [
|
||||
{
|
||||
name: "main_window",
|
||||
config: "vite.renderer.config.ts",
|
||||
},
|
||||
],
|
||||
}),
|
||||
// Fuses are used to enable/disable various Electron functionality
|
||||
// at package time, before code signing the application
|
||||
new FusesPlugin({
|
||||
version: FuseVersion.V1,
|
||||
[FuseV1Options.RunAsNode]: false,
|
||||
[FuseV1Options.EnableCookieEncryption]: true,
|
||||
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
|
||||
[FuseV1Options.EnableNodeCliInspectArguments]: false,
|
||||
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
|
||||
[FuseV1Options.OnlyLoadAppFromAsar]: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
Vendored
-35
@@ -1,35 +0,0 @@
|
||||
export {}; // Make this a module
|
||||
|
||||
declare global {
|
||||
// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Vite
|
||||
// plugin that tells the Electron app where to look for the Vite-bundled app code (depending on
|
||||
// whether you're running in development or production).
|
||||
const MAIN_WINDOW_VITE_DEV_SERVER_URL: string;
|
||||
const MAIN_WINDOW_VITE_NAME: string;
|
||||
|
||||
namespace NodeJS {
|
||||
interface Process {
|
||||
// Used for hot reload after preload scripts.
|
||||
viteDevServers: Record<string, import("vite").ViteDevServer>;
|
||||
}
|
||||
}
|
||||
|
||||
type VitePluginConfig = ConstructorParameters<
|
||||
typeof import("@electron-forge/plugin-vite").VitePlugin
|
||||
>[0];
|
||||
|
||||
interface VitePluginRuntimeKeys {
|
||||
VITE_DEV_SERVER_URL: `${string}_VITE_DEV_SERVER_URL`;
|
||||
VITE_NAME: `${string}_VITE_NAME`;
|
||||
}
|
||||
}
|
||||
|
||||
declare module "vite" {
|
||||
interface ConfigEnv<
|
||||
K extends keyof VitePluginConfig = keyof VitePluginConfig,
|
||||
> {
|
||||
root: string;
|
||||
forgeConfig: VitePluginConfig;
|
||||
forgeConfigSelf: VitePluginConfig[K][number];
|
||||
}
|
||||
}
|
||||
Generated
+26
-5286
File diff suppressed because it is too large.
Load diff
+4
-13
@@ -6,10 +6,8 @@
|
||||
"main": ".vite/build/main.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make",
|
||||
"publish": "electron-forge publish",
|
||||
"start": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"lint:write": "eslint . --fix",
|
||||
"format": "prettier --check .",
|
||||
@@ -22,15 +20,6 @@
|
||||
},
|
||||
"author": "",
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^7.6.1",
|
||||
"@electron-forge/maker-deb": "^7.8.0",
|
||||
"@electron-forge/maker-rpm": "^7.8.3",
|
||||
"@electron-forge/maker-squirrel": "^7.6.1",
|
||||
"@electron-forge/maker-zip": "^7.6.1",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "^7.6.1",
|
||||
"@electron-forge/plugin-fuses": "^7.10.2",
|
||||
"@electron-forge/plugin-vite": "^7.6.1",
|
||||
"@electron-forge/shared-types": "^7.4.0",
|
||||
"@electron/fuses": "^1.8.0",
|
||||
"@eslint/compat": "^1.2.6",
|
||||
"@eslint/js": "^9.18.0",
|
||||
@@ -62,6 +51,8 @@
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.24.1",
|
||||
"vite": "^6.4.1",
|
||||
"vite-plugin-electron": "^0.29.0",
|
||||
"vite-plugin-electron-renderer": "^0.14.6",
|
||||
"vitest": "^3.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
+11
-9
@@ -1,13 +1,14 @@
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import registerListeners from "./helpers/ipc/listeners-register";
|
||||
// "electron-squirrel-startup" seems broken when packaging with vite
|
||||
//import started from "electron-squirrel-startup";
|
||||
import path from "path";
|
||||
import {
|
||||
installExtension,
|
||||
REACT_DEVELOPER_TOOLS,
|
||||
} from "electron-devtools-installer";
|
||||
|
||||
const ARG1 = process.argv[1] ?? "./main.js";
|
||||
const DIR = path.dirname(ARG1);
|
||||
|
||||
// Set consistent app ID for Windows taskbar and GNOME dock integration
|
||||
app.setAppUserModelId("de.qitech.control-electron");
|
||||
|
||||
@@ -29,7 +30,9 @@ if (!gotTheLock) {
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
const preload = path.join(__dirname, "preload.js");
|
||||
const preload = path.join(DIR, "preload.js");
|
||||
console.log("Setting preload.js to", preload);
|
||||
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 800,
|
||||
@@ -43,7 +46,7 @@ function createWindow() {
|
||||
preload: preload,
|
||||
},
|
||||
// Add icon path for better integration
|
||||
icon: path.join(__dirname, "../assets/icon.png"),
|
||||
icon: path.join(DIR, "icon.png"),
|
||||
// Set window class explicitly for Linux/GNOME integration
|
||||
title: "QiTech Control",
|
||||
});
|
||||
@@ -53,12 +56,11 @@ function createWindow() {
|
||||
|
||||
registerListeners(mainWindow);
|
||||
|
||||
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
||||
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
|
||||
if (process.env.VITE_DEV_SERVER_URL) {
|
||||
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
|
||||
} else {
|
||||
mainWindow.loadFile(
|
||||
path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`),
|
||||
);
|
||||
const index = path.join(DIR, "index.html");
|
||||
mainWindow.loadFile(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import exposeContexts from "./helpers/ipc/context-exposer";
|
||||
|
||||
console.log("preload.js loaded");
|
||||
exposeContexts();
|
||||
@@ -1,119 +0,0 @@
|
||||
import path from "path";
|
||||
import { builtinModules } from "node:module";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import type { ConfigEnv, Plugin, UserConfig } from "vite";
|
||||
import pkg from "./package.json";
|
||||
|
||||
export const builtins = [
|
||||
"electron",
|
||||
...builtinModules.map((m) => [m, `node:${m}`]).flat(),
|
||||
];
|
||||
|
||||
export const external = [
|
||||
...builtins,
|
||||
...Object.keys(
|
||||
"dependencies" in pkg ? (pkg.dependencies as Record<string, unknown>) : {},
|
||||
),
|
||||
];
|
||||
|
||||
export function getBuildConfig(env: ConfigEnv<"build">): UserConfig {
|
||||
const { root, mode, command } = env;
|
||||
|
||||
return {
|
||||
root,
|
||||
mode,
|
||||
publicDir: path.resolve(__dirname, "public"),
|
||||
build: {
|
||||
// Prevent multiple builds from interfering with each other.
|
||||
emptyOutDir: false,
|
||||
// 🚧 Multiple builds may conflict.
|
||||
outDir: ".vite/build",
|
||||
watch: command === "serve" ? {} : null,
|
||||
minify: command === "build",
|
||||
},
|
||||
resolve: {
|
||||
preserveSymlinks: true,
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
"@root": path.resolve(__dirname, ".."),
|
||||
},
|
||||
},
|
||||
clearScreen: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefineKeys(names: string[]) {
|
||||
const define: { [name: string]: VitePluginRuntimeKeys } = {};
|
||||
|
||||
return names.reduce((acc, name) => {
|
||||
const NAME = name.toUpperCase();
|
||||
const keys: VitePluginRuntimeKeys = {
|
||||
VITE_DEV_SERVER_URL: `${NAME}_VITE_DEV_SERVER_URL`,
|
||||
VITE_NAME: `${NAME}_VITE_NAME`,
|
||||
};
|
||||
|
||||
return { ...acc, [name]: keys };
|
||||
}, define);
|
||||
}
|
||||
|
||||
export function getBuildDefine(env: ConfigEnv<"build">) {
|
||||
const { command, forgeConfig } = env;
|
||||
const names = forgeConfig.renderer
|
||||
.filter(({ name }) => name != null)
|
||||
.map(({ name }) => name!);
|
||||
const defineKeys = getDefineKeys(names);
|
||||
const define = Object.entries(defineKeys).reduce(
|
||||
(acc, [name, keys]) => {
|
||||
const { VITE_DEV_SERVER_URL, VITE_NAME } = keys;
|
||||
const def = {
|
||||
[VITE_DEV_SERVER_URL]:
|
||||
command === "serve"
|
||||
? JSON.stringify(process.env[VITE_DEV_SERVER_URL])
|
||||
: undefined,
|
||||
[VITE_NAME]: JSON.stringify(name),
|
||||
};
|
||||
return { ...acc, ...def };
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
);
|
||||
|
||||
return define;
|
||||
}
|
||||
|
||||
export function pluginExposeRenderer(name: string): Plugin {
|
||||
const { VITE_DEV_SERVER_URL } = getDefineKeys([name])[name];
|
||||
|
||||
return {
|
||||
name: "@electron-forge/plugin-vite:expose-renderer",
|
||||
configureServer(server) {
|
||||
process.viteDevServers ??= {};
|
||||
// Expose server for preload scripts hot reload.
|
||||
process.viteDevServers[name] = server;
|
||||
|
||||
server.httpServer?.once("listening", () => {
|
||||
const addressInfo = server.httpServer!.address() as AddressInfo;
|
||||
// Expose env constant for main process use.
|
||||
process.env[VITE_DEV_SERVER_URL] =
|
||||
`http://localhost:${addressInfo?.port}`;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function pluginHotRestart(command: "reload" | "restart"): Plugin {
|
||||
return {
|
||||
name: "@electron-forge/plugin-vite:hot-restart",
|
||||
closeBundle() {
|
||||
if (command === "reload") {
|
||||
for (const server of Object.values(process.viteDevServers)) {
|
||||
// Preload scripts hot reload.
|
||||
server.ws.send({ type: "full-reload" });
|
||||
}
|
||||
} else {
|
||||
// Main process hot restart.
|
||||
// https://github.com/electron/forge/blob/v7.2.0/packages/api/core/src/api/start.ts#L216-L223
|
||||
process.stdin.emit("data", "rs");
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import react from "@vitejs/plugin-react";
|
||||
import electron from "vite-plugin-electron/simple";
|
||||
import path from "path";
|
||||
|
||||
// https://vitejs.dev/config
|
||||
export default {
|
||||
publicDir: path.resolve(__dirname, "public"),
|
||||
resolve: {
|
||||
preserveSymlinks: true,
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
"@root": path.resolve(__dirname, ".."),
|
||||
},
|
||||
},
|
||||
clearScreen: false,
|
||||
plugins: [
|
||||
electron({
|
||||
main: {
|
||||
entry: "src/main.ts",
|
||||
onstart: ({ startup }) => {
|
||||
startup(["./dist-electron/main.js"]);
|
||||
},
|
||||
},
|
||||
preload: {
|
||||
// Shortcut of `build.rollupOptions.input`
|
||||
input: "src/preload.ts",
|
||||
},
|
||||
// Optional: Use Node.js API in the Renderer process
|
||||
renderer: {},
|
||||
}),
|
||||
react({
|
||||
babel: {
|
||||
plugins: [["babel-plugin-react-compiler"]],
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
import type { ConfigEnv, UserConfig } from "vite";
|
||||
import { defineConfig, mergeConfig } from "vite";
|
||||
import {
|
||||
getBuildConfig,
|
||||
getBuildDefine,
|
||||
external,
|
||||
pluginHotRestart,
|
||||
} from "./vite.base.config";
|
||||
|
||||
// https://vitejs.dev/config
|
||||
export default defineConfig((env) => {
|
||||
const forgeEnv = env as ConfigEnv<"build">;
|
||||
const { forgeConfigSelf } = forgeEnv;
|
||||
const config: UserConfig = {
|
||||
build: {
|
||||
lib: {
|
||||
entry: forgeConfigSelf.entry!,
|
||||
fileName: () => "[name].js",
|
||||
formats: ["cjs"],
|
||||
},
|
||||
rollupOptions: {
|
||||
external,
|
||||
},
|
||||
},
|
||||
plugins: [pluginHotRestart("restart")],
|
||||
resolve: {
|
||||
// Load the Node.js entry.
|
||||
mainFields: ["module", "jsnext:main", "jsnext"],
|
||||
},
|
||||
};
|
||||
|
||||
return mergeConfig(getBuildConfig(forgeEnv), config);
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import type { ConfigEnv, UserConfig } from "vite";
|
||||
import { defineConfig, mergeConfig } from "vite";
|
||||
import { getBuildConfig, external, pluginHotRestart } from "./vite.base.config";
|
||||
|
||||
// https://vitejs.dev/config
|
||||
export default defineConfig((env) => {
|
||||
const forgeEnv = env as ConfigEnv<"build">;
|
||||
const { forgeConfigSelf } = forgeEnv;
|
||||
const config: UserConfig = {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external,
|
||||
// Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`.
|
||||
input: forgeConfigSelf.entry!,
|
||||
output: {
|
||||
format: "cjs",
|
||||
// It should not be split chunks.
|
||||
inlineDynamicImports: true,
|
||||
entryFileNames: "[name].js",
|
||||
chunkFileNames: "[name].js",
|
||||
assetFileNames: "[name].[ext]",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [pluginHotRestart("reload")],
|
||||
};
|
||||
|
||||
return mergeConfig(getBuildConfig(forgeEnv), config);
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
import react from "@vitejs/plugin-react";
|
||||
import type { ConfigEnv, UserConfig } from "vite";
|
||||
import { defineConfig, mergeConfig } from "vite";
|
||||
import { pluginExposeRenderer, getBuildConfig } from "./vite.base.config";
|
||||
|
||||
// https://vitejs.dev/config
|
||||
export default defineConfig((env) => {
|
||||
const forgeEnv = env as ConfigEnv<"renderer">;
|
||||
const { forgeConfigSelf } = forgeEnv;
|
||||
const name = forgeConfigSelf.name ?? "";
|
||||
|
||||
return mergeConfig(getBuildConfig(env), {
|
||||
base: "./",
|
||||
build: {
|
||||
outDir: `.vite/renderer/${name}`,
|
||||
},
|
||||
plugins: [
|
||||
pluginExposeRenderer(name),
|
||||
react({
|
||||
babel: {
|
||||
plugins: [["babel-plugin-react-compiler"]],
|
||||
},
|
||||
}),
|
||||
],
|
||||
}) as UserConfig;
|
||||
});
|
||||
@@ -5,9 +5,7 @@
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
|
||||
|
||||
# Crane for Rust builds with dependency caching
|
||||
crane = {
|
||||
url = "github:ipetkov/crane";
|
||||
};
|
||||
crane = { url = "github:ipetkov/crane"; };
|
||||
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
@@ -21,24 +19,21 @@
|
||||
};
|
||||
|
||||
# Add flake-utils which was missing
|
||||
flake-utils = {
|
||||
url = "github:numtide/flake-utils";
|
||||
};
|
||||
flake-utils = { url = "github:numtide/flake-utils"; };
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, crane, flake-utils, qitech-control, home-manager, ... }:
|
||||
outputs =
|
||||
{ self, nixpkgs, crane, flake-utils, qitech-control, home-manager, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [
|
||||
# Add our own overlay for QiTech packages
|
||||
# Add our own overlay for QiTech packages with commit hash support
|
||||
(final: prev: {
|
||||
qitechPackages = {
|
||||
server = final.callPackage ./nixos/packages/server.nix {
|
||||
craneLib = crane.mkLib final;
|
||||
};
|
||||
electron = final.callPackage ./nixos/packages/electron.nix {
|
||||
nodejs = final.nodejs_22;
|
||||
craneLib = crane.mkLib pkgs;
|
||||
};
|
||||
electron = final.callPackage ./nixos/packages/electron.nix { };
|
||||
};
|
||||
})
|
||||
];
|
||||
@@ -46,8 +41,6 @@
|
||||
pkgs = import nixpkgs { inherit system overlays; };
|
||||
gitInfo = import ./nixos/gitInfo.nix { inherit pkgs; };
|
||||
|
||||
craneLib = crane.mkLib pkgs;
|
||||
|
||||
# Use Rust 1.86 stable from nixpkgs
|
||||
rust = pkgs.rustc;
|
||||
in {
|
||||
@@ -57,7 +50,7 @@
|
||||
default = self.packages.${system}.server;
|
||||
};
|
||||
|
||||
devShells.default = craneLib.devShell {
|
||||
devShells.default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
pkg-config
|
||||
libudev-zero
|
||||
@@ -65,8 +58,11 @@
|
||||
nodejs_22
|
||||
nodePackages.npm
|
||||
lldb
|
||||
electron
|
||||
];
|
||||
|
||||
ELECTON_SKIP_BINARY_DOWNLOAD = 1;
|
||||
|
||||
hardeningDisable = [ "fortify" ];
|
||||
|
||||
shellHook = ''
|
||||
@@ -75,55 +71,53 @@
|
||||
echo "Node version: $(${pkgs.nodejs_22}/bin/node --version)"
|
||||
'';
|
||||
};
|
||||
}
|
||||
) // {
|
||||
nixosModules.qitech = import ./nixos/modules/qitech.nix;
|
||||
nixosModules.default = self.nixosModules.qitech;
|
||||
}) // {
|
||||
nixosModules.qitech = import ./nixos/modules/qitech.nix;
|
||||
nixosModules.default = self.nixosModules.qitech;
|
||||
|
||||
# Define nixosConfigurations outside of eachDefaultSystem
|
||||
nixosConfigurations =
|
||||
let
|
||||
system = builtins.currentSystem;
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
gitInfo = import ./nixos/gitInfo.nix { inherit pkgs; };
|
||||
in {
|
||||
# Replace "nixos" with your actual hostname
|
||||
nixos = nixpkgs.lib.nixosSystem {
|
||||
system = system;
|
||||
specialArgs = {
|
||||
gitInfo = gitInfo; # Pass gitInfo to modules
|
||||
# Define nixosConfigurations outside of eachDefaultSystem
|
||||
nixosConfigurations = let
|
||||
system = builtins.currentSystem;
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
gitInfo = import ./nixos/gitInfo.nix { inherit pkgs; };
|
||||
in {
|
||||
# Replace "nixos" with your actual hostname
|
||||
nixos = nixpkgs.lib.nixosSystem {
|
||||
system = system;
|
||||
specialArgs = {
|
||||
gitInfo = gitInfo; # Pass gitInfo to modules
|
||||
};
|
||||
modules = [
|
||||
# Apply the overlays to the system
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
# Add our own overlay for QiTech packages with commit hash support
|
||||
(final: prev: {
|
||||
qitechPackages = {
|
||||
server = final.callPackage ./nixos/packages/server.nix {
|
||||
craneLib = crane.mkLib final;
|
||||
};
|
||||
electron =
|
||||
final.callPackage ./nixos/packages/electron.nix { };
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
./nixos/os/configuration.nix
|
||||
|
||||
# QiTech Control module
|
||||
self.nixosModules.qitech
|
||||
|
||||
# Home Manager module
|
||||
home-manager.nixosModules.home-manager
|
||||
{
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
home-manager.users.qitech = import ./nixos/os/home.nix;
|
||||
}
|
||||
];
|
||||
};
|
||||
modules = [
|
||||
# Apply the overlays to the system
|
||||
{ nixpkgs.overlays = [
|
||||
# Add our own overlay for QiTech packages with commit hash support
|
||||
(final: prev: {
|
||||
qitechPackages = {
|
||||
server = final.callPackage ./nixos/packages/server.nix {
|
||||
craneLib = crane.mkLib final;
|
||||
};
|
||||
electron = final.callPackage ./nixos/packages/electron.nix {
|
||||
nodejs = final.nodejs_22;
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
./nixos/os/configuration.nix
|
||||
|
||||
# QiTech Control module
|
||||
self.nixosModules.qitech
|
||||
|
||||
# Home Manager module
|
||||
home-manager.nixosModules.home-manager
|
||||
{
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
home-manager.users.qitech = import ./nixos/os/home.nix;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
+2
-3
@@ -1,5 +1,4 @@
|
||||
{ pkgs ? import <nixpkgs> {}
|
||||
}:
|
||||
{ pkgs ? import <nixpkgs> { } }:
|
||||
|
||||
let
|
||||
# Use the flake's packages when available
|
||||
@@ -8,7 +7,7 @@ let
|
||||
in {
|
||||
server = flake.packages.${system}.server;
|
||||
electron = flake.packages.${system}.electron;
|
||||
|
||||
|
||||
# Use the flake's development shell for consistency
|
||||
shell = flake.devShells.${system}.default;
|
||||
}
|
||||
+2
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
let
|
||||
# Generate Git info in the store
|
||||
gitInfoDerivation = pkgs.runCommand "git-info" {} ''
|
||||
gitInfoDerivation = pkgs.runCommand "git-info" { } ''
|
||||
gitTimestamp="${builtins.getEnv "GIT_TIMESTAMP"}"
|
||||
gitCommit="${builtins.getEnv "GIT_COMMIT"}"
|
||||
gitUrl="${builtins.getEnv "GIT_URL"}"
|
||||
@@ -21,5 +21,4 @@ let
|
||||
}
|
||||
EOF
|
||||
'';
|
||||
in
|
||||
builtins.fromJSON (builtins.readFile "${gitInfoDerivation}/git-info.json")
|
||||
in builtins.fromJSON (builtins.readFile "${gitInfoDerivation}/git-info.json")
|
||||
+57
-60
@@ -2,30 +2,30 @@
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.qitech;
|
||||
let cfg = config.services.qitech;
|
||||
in {
|
||||
options.services.qitech = {
|
||||
enable = mkEnableOption "QiTech Control";
|
||||
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to open ports in the firewall for the QiTech server";
|
||||
description =
|
||||
"Whether to open ports in the firewall for the QiTech server";
|
||||
};
|
||||
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "qitech-service";
|
||||
description = "User account under which the service runs";
|
||||
};
|
||||
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "qitech-service";
|
||||
description = "Group under which the service runs";
|
||||
};
|
||||
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.qitech-control-server or null;
|
||||
@@ -34,12 +34,11 @@ in {
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.package != null;
|
||||
message = "No QiTech server package available. Please add it to your pkgs or explicitly set services.qitech.package.";
|
||||
}
|
||||
];
|
||||
assertions = [{
|
||||
assertion = cfg.package != null;
|
||||
message =
|
||||
"No QiTech server package available. Please add it to your pkgs or explicitly set services.qitech.package.";
|
||||
}];
|
||||
|
||||
users.users.${cfg.user} = {
|
||||
isSystemUser = true;
|
||||
@@ -47,72 +46,72 @@ in {
|
||||
description = "QiTech service user";
|
||||
extraGroups = [ "realtime" "plugdev" "dialout" "uucp" ];
|
||||
};
|
||||
|
||||
users.groups.${cfg.group} = {};
|
||||
|
||||
|
||||
users.groups.${cfg.group} = { };
|
||||
|
||||
# Install the Electron app system-wide
|
||||
environment.systemPackages = [
|
||||
pkgs.qitechPackages.electron
|
||||
];
|
||||
|
||||
environment.systemPackages = [ pkgs.qitechPackages.electron ];
|
||||
|
||||
# Configure udev rules for EtherCAT device access
|
||||
services.udev.extraRules = ''
|
||||
# Allow access to network devices for ethercrab
|
||||
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="*", TAG+="uaccess", TAG+="udev-acl", GROUP="${cfg.group}"
|
||||
|
||||
|
||||
# USB device access if needed
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="*", ATTRS{idProduct}=="*", MODE="0660", GROUP="${cfg.group}"
|
||||
'';
|
||||
|
||||
|
||||
# Configure the systemd service
|
||||
systemd.services.qitech-control-server = {
|
||||
description = "QiTech Control Server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ExecStart = "${cfg.package}/bin/server";
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
|
||||
# Capabilities
|
||||
CapabilityBoundingSet = "CAP_NET_RAW CAP_IPC_LOCK CAP_NET_ADMIN CAP_SYS_NICE CAP_DAC_OVERRIDE";
|
||||
AmbientCapabilities = "CAP_NET_RAW CAP_IPC_LOCK CAP_NET_ADMIN CAP_SYS_NICE CAP_DAC_OVERRIDE";
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ExecStart = "${cfg.package}/bin/server";
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
|
||||
# Hardening options
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
# Capabilities
|
||||
CapabilityBoundingSet =
|
||||
"CAP_NET_RAW CAP_IPC_LOCK CAP_NET_ADMIN CAP_SYS_NICE CAP_DAC_OVERRIDE";
|
||||
AmbientCapabilities =
|
||||
"CAP_NET_RAW CAP_IPC_LOCK CAP_NET_ADMIN CAP_SYS_NICE CAP_DAC_OVERRIDE";
|
||||
|
||||
# Open only /proc/irq explicitly
|
||||
ReadWritePaths = [ "/proc/irq" ];
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = false;
|
||||
# Hardening options
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
|
||||
# Must disable this to allow /proc/irq writes
|
||||
ProtectKernelTunables = false;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK AF_PACKET";
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false;
|
||||
# Open only /proc/irq explicitly
|
||||
ReadWritePaths = [ "/proc/irq" ];
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = false;
|
||||
|
||||
# Logging
|
||||
StandardOutput = "journal";
|
||||
StandardError = "journal";
|
||||
SyslogIdentifier = "qitech-control-server";
|
||||
};
|
||||
# Must disable this to allow /proc/irq writes
|
||||
ProtectKernelTunables = false;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies =
|
||||
"AF_UNIX AF_INET AF_INET6 AF_NETLINK AF_PACKET";
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false;
|
||||
|
||||
# Logging
|
||||
StandardOutput = "journal";
|
||||
StandardError = "journal";
|
||||
SyslogIdentifier = "qitech-control-server";
|
||||
};
|
||||
|
||||
|
||||
environment = {
|
||||
RUST_BACKTRACE = "full";
|
||||
RUST_LOG = "info";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
# Add real-time privileges
|
||||
security.pam.loginLimits = [
|
||||
{
|
||||
@@ -134,12 +133,10 @@ serviceConfig = {
|
||||
value = "-20";
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
# Open firewall if requested
|
||||
networking.firewall = mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ 3001 ];
|
||||
};
|
||||
|
||||
networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ 3001 ]; };
|
||||
|
||||
# Desktop integration
|
||||
xdg.mime.enable = true;
|
||||
xdg.icons.enable = true;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
fileSystems."/" = {
|
||||
device = "/dev/null";
|
||||
fsType = "tmpfs";
|
||||
};
|
||||
swapDevices = [ ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
}
|
||||
+21
-26
@@ -1,25 +1,23 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
gitInfo = import ../gitInfo.nix { inherit pkgs; };
|
||||
in
|
||||
{
|
||||
imports =
|
||||
[ # Include the results of the hardware scan.
|
||||
let gitInfo = import ../gitInfo.nix { inherit pkgs; };
|
||||
in {
|
||||
imports = [
|
||||
(if builtins.pathExists "/etc/nixos/hardware-configuration.nix" then
|
||||
/etc/nixos/hardware-configuration.nix
|
||||
];
|
||||
else
|
||||
./ci-hardware-configuration.nix)
|
||||
];
|
||||
|
||||
# Bootloader.
|
||||
boot.loader.systemd-boot = {
|
||||
enable = true;
|
||||
consoleMode = "max"; # Use the highest available resolution
|
||||
consoleMode = "max"; # Use the highest available resolution
|
||||
};
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.kernelPackages = pkgs.linuxPackages_6_13;
|
||||
boot.kernelModules = [ "i915" ];
|
||||
|
||||
|
||||
|
||||
boot.kernelParams = [
|
||||
# Realtime Preemption
|
||||
"preempt=full"
|
||||
@@ -45,20 +43,20 @@ in
|
||||
# Should ONLY be used in completely trusted environments
|
||||
# - Improves performance by 7-43%
|
||||
"mitigation=off"
|
||||
"intel_pstate=performance" # Intel CPU-specific performance mode (if applicable)
|
||||
"intel_pstate=performance" # Intel CPU-specific performance mode (if applicable)
|
||||
|
||||
# Memory Management
|
||||
"transparent_hugepage=always" # Use larger memory pages for memory intense applications
|
||||
"nmi_watchdog=0" # Disable NMI watchdog for reduced CPU overhead and realtime execution
|
||||
"nmi_watchdog=0" # Disable NMI watchdog for reduced CPU overhead and realtime execution
|
||||
|
||||
# High-throughput ethernet parameters
|
||||
"pcie_aspm=off" # Disable PCIe power management for NICs
|
||||
"intel_iommu=off" # Disable IOMMU (performance gain)
|
||||
"pcie_aspm=off" # Disable PCIe power management for NICs
|
||||
"intel_iommu=off" # Disable IOMMU (performance gain)
|
||||
|
||||
# Reliability
|
||||
"panic=10" # Auto-reboot 10 seconds after kernel panic
|
||||
"oops=panic" # Treat kernel oops as panic for auto-recovery
|
||||
"usbcore.autosuspend=-1" # Possibly fixes dre disconnect issue?
|
||||
"panic=10" # Auto-reboot 10 seconds after kernel panic
|
||||
"oops=panic" # Treat kernel oops as panic for auto-recovery
|
||||
"usbcore.autosuspend=-1" # Possibly fixes dre disconnect issue?
|
||||
|
||||
"isolcpus=2,3" # Isolate cpus 2 and 3 from scheduler for better latency, 2 runs ethercatthread and 3 runs server control-loop
|
||||
"nohz_full=2,3" # In this mode, the periodic scheduler tick is stopped when only one task is running, reducing kernel interruptions on those CPUs.
|
||||
@@ -68,10 +66,10 @@ in
|
||||
|
||||
# Add these system settings for a more comprehensive kiosk setup
|
||||
boot.kernel.sysctl = {
|
||||
"kernel.panic_on_oops" = 1; # Reboot on kernel oops
|
||||
"kernel.panic" = 10; # Reboot after 10 seconds on panic
|
||||
"vm.swappiness" = 10; # Reduce swap usage
|
||||
"kernel.sysrq" = 1; # Enable SysRq for emergency control
|
||||
"kernel.panic_on_oops" = 1; # Reboot on kernel oops
|
||||
"kernel.panic" = 10; # Reboot after 10 seconds on panic
|
||||
"vm.swappiness" = 10; # Reduce swap usage
|
||||
"kernel.sysrq" = 1; # Enable SysRq for emergency control
|
||||
};
|
||||
|
||||
nix = {
|
||||
@@ -79,13 +77,11 @@ in
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
settings = {
|
||||
sandbox = false;
|
||||
};
|
||||
settings = { sandbox = false; };
|
||||
};
|
||||
|
||||
# Create a realtime group
|
||||
users.groups.realtime = {};
|
||||
users.groups.realtime = { };
|
||||
|
||||
# Configure real-time privileges
|
||||
security.pam.loginLimits = [
|
||||
@@ -209,7 +205,6 @@ in
|
||||
extraPackages = with pkgs; [ mesa ];
|
||||
};
|
||||
|
||||
|
||||
services.libinput.enable = true;
|
||||
services.libinput.touchpad.tapping = true;
|
||||
services.touchegg.enable = true;
|
||||
|
||||
+54
-55
@@ -1,9 +1,7 @@
|
||||
{ config, pkgs, lib, ... }: {
|
||||
home.stateVersion = "24.11";
|
||||
|
||||
home.packages = with pkgs; [
|
||||
pkgs.qitechPackages.electron
|
||||
];
|
||||
home.packages = with pkgs; [ pkgs.qitechPackages.electron ];
|
||||
|
||||
# Add autostart entry for the QiTech electron app
|
||||
xdg.configFile."autostart/de.qitech.control-electron.desktop".text = ''
|
||||
@@ -18,53 +16,53 @@
|
||||
X-GNOME-Autostart-enabled=true
|
||||
X-GNOME-Autostart-Phase=Applications
|
||||
'';
|
||||
|
||||
|
||||
dconf.settings = {
|
||||
# Set GNOME wallpaper
|
||||
"org/gnome/desktop/background" = {
|
||||
picture-uri = "https://i.postimg.cc/Z5XJtNMW/qitech-industries-wallpaper.jpg";
|
||||
picture-uri-dark = "https://i.postimg.cc/Z5XJtNMW/qitech-industries-wallpaper.jpg";
|
||||
picture-uri =
|
||||
"https://i.postimg.cc/Z5XJtNMW/qitech-industries-wallpaper.jpg";
|
||||
picture-uri-dark =
|
||||
"https://i.postimg.cc/Z5XJtNMW/qitech-industries-wallpaper.jpg";
|
||||
picture-options = "zoom";
|
||||
};
|
||||
|
||||
# Enable on-screen keyboard
|
||||
"org/gnome/desktop/a11y/applications" = {
|
||||
screen-keyboard-enabled = true;
|
||||
};
|
||||
|
||||
"org/gnome/desktop/a11y/applications" = { screen-keyboard-enabled = true; };
|
||||
|
||||
# Configure on-screen keyboard (optional)
|
||||
"org/gnome/desktop/a11y" = {
|
||||
always-show-universal-access-status = true;
|
||||
};
|
||||
"org/gnome/desktop/a11y" = { always-show-universal-access-status = true; };
|
||||
|
||||
# Disable screen blanking/timeout
|
||||
"org/gnome/desktop/session" = {
|
||||
idle-delay = lib.gvariant.mkUint32 0; # Use uint32 format to ensure proper type
|
||||
idle-delay =
|
||||
lib.gvariant.mkUint32 0; # Use uint32 format to ensure proper type
|
||||
};
|
||||
|
||||
# Disable automatic suspend and screen dimming
|
||||
"org/gnome/settings-daemon/plugins/power" = {
|
||||
sleep-inactive-ac-type = "nothing";
|
||||
sleep-inactive-battery-type = "nothing";
|
||||
power-button-action = "nothing";
|
||||
idle-dim = false;
|
||||
sleep-inactive-ac-timeout = lib.gvariant.mkUint32 0;
|
||||
sleep-inactive-battery-timeout = lib.gvariant.mkUint32 0;
|
||||
ambient-enabled = false;
|
||||
};
|
||||
|
||||
# Disable screen lock
|
||||
"org/gnome/desktop/screensaver" = {
|
||||
lock-enabled = false;
|
||||
idle-activation-enabled = false;
|
||||
lock-delay = lib.gvariant.mkUint32 0;
|
||||
};
|
||||
# Disable automatic suspend and screen dimming
|
||||
"org/gnome/settings-daemon/plugins/power" = {
|
||||
sleep-inactive-ac-type = "nothing";
|
||||
sleep-inactive-battery-type = "nothing";
|
||||
power-button-action = "nothing";
|
||||
idle-dim = false;
|
||||
sleep-inactive-ac-timeout = lib.gvariant.mkUint32 0;
|
||||
sleep-inactive-battery-timeout = lib.gvariant.mkUint32 0;
|
||||
ambient-enabled = false;
|
||||
};
|
||||
|
||||
# Disable screen lock
|
||||
"org/gnome/desktop/screensaver" = {
|
||||
lock-enabled = false;
|
||||
idle-activation-enabled = false;
|
||||
lock-delay = lib.gvariant.mkUint32 0;
|
||||
};
|
||||
|
||||
# Interface settings with hot-corners disabled
|
||||
"org/gnome/desktop/interface" = {
|
||||
enable-animations = true;
|
||||
show-battery-percentage = true;
|
||||
enable-hot-corners = false; # Prevent activities from opening with hot corners
|
||||
enable-hot-corners =
|
||||
false; # Prevent activities from opening with hot corners
|
||||
};
|
||||
|
||||
# Show dock on all monitors and always visible
|
||||
@@ -74,48 +72,49 @@
|
||||
dock-fixed = true;
|
||||
autohide = false;
|
||||
intellihide = false;
|
||||
multi-monitor = true; # Show dock on all monitors
|
||||
isolate-monitors = false; # Don't isolate workspaces per monitor
|
||||
isolate-workspaces = false; # Don't isolate dock content per workspace
|
||||
multi-monitor = true; # Show dock on all monitors
|
||||
isolate-monitors = false; # Don't isolate workspaces per monitor
|
||||
isolate-workspaces = false; # Don't isolate dock content per workspace
|
||||
};
|
||||
|
||||
|
||||
# Configure display settings
|
||||
"org/gnome/mutter" = {
|
||||
workspaces-only-on-primary = false; # Show workspaces on all monitors
|
||||
dynamic-workspaces = false; # Disable dynamic workspaces
|
||||
workspaces-only-on-primary = false; # Show workspaces on all monitors
|
||||
dynamic-workspaces = false; # Disable dynamic workspaces
|
||||
};
|
||||
|
||||
|
||||
"org/gnome/desktop/wm/preferences" = {
|
||||
num-workspaces = 1; # Set a fixed number of workspaces (default: 4)
|
||||
num-workspaces = 1; # Set a fixed number of workspaces (default: 4)
|
||||
};
|
||||
|
||||
"org/gnome/desktop/lockdown" = {
|
||||
disable-lock-screen = true; # Disable lock screen
|
||||
disable-log-out = false; # Enable logout option (To be able to reboot manually)
|
||||
disable-user-switching = true; # Disable user switching
|
||||
disable-screensaver = true; # Disable screensaver
|
||||
user-adminstration-disabled = true; # Disable user administration
|
||||
disable-lock-screen = true; # Disable lock screen
|
||||
disable-log-out =
|
||||
false; # Enable logout option (To be able to reboot manually)
|
||||
disable-user-switching = true; # Disable user switching
|
||||
disable-screensaver = true; # Disable screensaver
|
||||
user-adminstration-disabled = true; # Disable user administration
|
||||
};
|
||||
|
||||
|
||||
"org/gnome/shell" = {
|
||||
always-show-log-out = true;
|
||||
enabled-extensions = [
|
||||
"dash-to-dock@micxgx.gmail.com"
|
||||
"no-overview@fthx"
|
||||
];
|
||||
enabled-extensions =
|
||||
[ "dash-to-dock@micxgx.gmail.com" "no-overview@fthx" ];
|
||||
favorite-apps = [
|
||||
"de.qitech.control-electron.desktop" # The desktop entry from the QiTech app
|
||||
"de.qitech.control-electron.desktop" # The desktop entry from the QiTech app
|
||||
"org.gnome.Settings.desktop"
|
||||
];
|
||||
disable-user-extensions = false;
|
||||
disable-extension-version-validation = true;
|
||||
welcome-dialog-last-shown-version = "999.999.999"; # Prevents welcome screen
|
||||
looking-glass-history = [];
|
||||
welcome-dialog-last-shown-version =
|
||||
"999.999.999"; # Prevents welcome screen
|
||||
looking-glass-history = [ ];
|
||||
};
|
||||
|
||||
|
||||
# Disable automatic Activities overview on startup
|
||||
"org/gnome/shell/extensions/ding" = {
|
||||
start-corner = "top-left"; # This can help with preventing Activities from opening
|
||||
start-corner =
|
||||
"top-left"; # This can help with preventing Activities from opening
|
||||
};
|
||||
};
|
||||
}
|
||||
+24
-87
@@ -1,104 +1,41 @@
|
||||
{ lib
|
||||
, stdenv
|
||||
, makeWrapper
|
||||
, nodejs
|
||||
, electron
|
||||
, nodePackages
|
||||
, git
|
||||
, cacert
|
||||
, fetchFromGitHub
|
||||
}:
|
||||
{ lib, buildNpmPackage, electron }:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
buildNpmPackage rec {
|
||||
pname = "qitech-control-electron";
|
||||
version = "1.0.0";
|
||||
|
||||
srcs = [ ../../electron ../../docs ];
|
||||
sourceRoot = "electron";
|
||||
|
||||
nativeBuildInputs = [
|
||||
nodejs
|
||||
nodePackages.npm
|
||||
git
|
||||
makeWrapper
|
||||
cacert
|
||||
];
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD = 1;
|
||||
|
||||
# Environment variables for the build
|
||||
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||
GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||
npm_config_update_notifier = false;
|
||||
npm_config_cache = "$TMPDIR/npm-cache";
|
||||
makeCacheWritable = true;
|
||||
npmDepsHash = "sha256-gk/YC3+gc5DVvPS4ght9WmFcuc2FAX/UB+lIuQn436U=";
|
||||
npmFlags = [ "--no-audit" "--no-fund" ];
|
||||
|
||||
# Let Electron Forge see more output
|
||||
ELECTRON_ENABLE_LOGGING = "true";
|
||||
DEBUG = "*";
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
buildPhase = ''
|
||||
export HOME=$TMPDIR
|
||||
mkdir -p $out/share/qitech-control-electron
|
||||
cp -rv dist/* $out/share/qitech-control-electron
|
||||
cp -rv dist-electron/* $out/share/qitech-control-electron
|
||||
cp -v src/assets/icon.png $out/share/qitech-control-electron
|
||||
|
||||
# Setup git
|
||||
mkdir -p $HOME
|
||||
${git}/bin/git config --global --add safe.directory '*'
|
||||
${git}/bin/git config --global user.email "nixbuild@localhost"
|
||||
${git}/bin/git config --global user.name "Nix Builder"
|
||||
if [ -f src/assets/icon.png ]; then
|
||||
mkdir -p $out/share/icons/hicolor/256x256/apps $out/share/pixmaps
|
||||
|
||||
# Install dependencies
|
||||
echo "Installing dependencies..."
|
||||
npm ci --no-audit --no-fund || npm install --no-audit --no-fund --legacy-peer-deps
|
||||
|
||||
# First try the 'make' command which does a full build + package
|
||||
echo "Creating distributable..."
|
||||
NODE_ENV=production npm run make || {
|
||||
echo "Make failed, trying package instead..."
|
||||
NODE_ENV=production npm run package
|
||||
}
|
||||
|
||||
# List the output directories to see what we got
|
||||
echo "Created artifacts:"
|
||||
find out -type d | sort
|
||||
find out -type f -name "*.js" | sort
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/share/qitech-control-electron $out/bin $out/share/applications $out/share/icons/hicolor/256x256/apps
|
||||
|
||||
# First check for a full distribution in the 'out/make' directory
|
||||
if [ -d "out/make" ]; then
|
||||
echo "Using distribution from 'out/make'"
|
||||
find out/make -type d -name "*linux*" -exec cp -r {} $out/share/qitech-control-electron \; || true
|
||||
fi
|
||||
|
||||
# If no distribution was found, use the packaged version
|
||||
if [ ! "$(ls -A $out/share/qitech-control-electron)" ]; then
|
||||
echo "Using packaged app from 'out'"
|
||||
find out -maxdepth 1 -type d -name "*linux-x64" -exec cp -r {}/* $out/share/qitech-control-electron \; || true
|
||||
fi
|
||||
|
||||
# If still nothing, try the Electron Forge template approach
|
||||
if [ ! "$(ls -A $out/share/qitech-control-electron)" ]; then
|
||||
echo "No packaged app found, using source + .vite directory"
|
||||
cp -r . $out/share/qitech-control-electron/
|
||||
fi
|
||||
|
||||
# Copy the icon
|
||||
if [ -f "src/assets/icon.png" ]; then
|
||||
echo "Copying icon from src/assets/icon.png"
|
||||
cp src/assets/icon.png $out/share/icons/hicolor/256x256/apps/de.qitech.control-electron.png
|
||||
|
||||
# Also create a symlink with the application name for compatibility
|
||||
mkdir -p $out/share/pixmaps
|
||||
ln -sf $out/share/icons/hicolor/256x256/apps/de.qitech.control-electron.png $out/share/pixmaps/qitech-control-electron.png
|
||||
ln -sf $out/share/icons/hicolor/256x256/apps/de.qitech.control-electron.png \
|
||||
$out/share/pixmaps/qitech-control-electron.png
|
||||
fi
|
||||
|
||||
# Create the executable wrapper with proper app ID and niceness
|
||||
# electron needs a little bit of niceness, otherwise it will lag
|
||||
# wrapper
|
||||
mkdir -p $out/bin
|
||||
cat > $out/bin/qitech-control-electron << EOF
|
||||
#!/bin/sh
|
||||
cd $out/share/qitech-control-electron
|
||||
# enable gpu and ignore driver blacklists for electron
|
||||
# gpu drivers may be blacklisted because of the usage of PREEMPT_RT Kernel
|
||||
exec nice -n -20 ${electron}/bin/electron "$out/share/qitech-control-electron" \
|
||||
appdir="$out/share/qitech-control-electron"
|
||||
cd "\$appdir"
|
||||
exec nice -n -20 ${electron}/bin/electron "\$appdir/main.js" \
|
||||
--no-sandbox \
|
||||
--class=de.qitech.control-electron \
|
||||
--name="QiTech Control" \
|
||||
@@ -108,11 +45,12 @@ installPhase = ''
|
||||
--ignore-gpu-blocklist \
|
||||
--enable-gpu-rasterization \
|
||||
--disable-software-rasterizer \
|
||||
"\$@"
|
||||
"$@"
|
||||
EOF
|
||||
chmod +x $out/bin/qitech-control-electron
|
||||
|
||||
# Create desktop entry with consistent application ID
|
||||
# desktop entry
|
||||
mkdir -p $out/share/applications
|
||||
cat > $out/share/applications/de.qitech.control-electron.desktop << EOF
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
@@ -127,7 +65,6 @@ installPhase = ''
|
||||
EOF
|
||||
'';
|
||||
|
||||
|
||||
meta = with lib; {
|
||||
description = "QiTech Control Electron";
|
||||
homepage = "https://qitech.de";
|
||||
|
||||
+20
-30
@@ -1,38 +1,28 @@
|
||||
{ lib
|
||||
, pkgs
|
||||
, pkg-config
|
||||
, libudev-zero
|
||||
, libpcap
|
||||
, craneLib
|
||||
}:
|
||||
{ lib, pkgs, pkg-config, libudev-zero, libpcap, craneLib }:
|
||||
|
||||
let
|
||||
# Bind variables so they can be inherited inside inner calls
|
||||
pname = "server";
|
||||
version = "1.0.0";
|
||||
strictDeps = true;
|
||||
nativeBuildInputs = [ pkg-config ];
|
||||
buildInputs = [ libpcap libudev-zero ];
|
||||
commonArgs = {
|
||||
pname = "server";
|
||||
version = "1.0.0";
|
||||
strictDeps = true;
|
||||
|
||||
# Cleaned source
|
||||
src = craneLib.cleanCargoSource ../..;
|
||||
nativeBuildInputs = [ pkg-config ];
|
||||
buildInputs = [ libpcap libudev-zero ];
|
||||
|
||||
# Safe fallback for CARGO_BUILD_JOBS in impure builds
|
||||
cargoJobs = if (builtins.tryEval (builtins.getEnv "CARGO_BUILD_JOBS")).success
|
||||
then builtins.getEnv "CARGO_BUILD_JOBS"
|
||||
else "2";
|
||||
in
|
||||
src = craneLib.cleanCargoSource ../..;
|
||||
|
||||
craneLib.buildPackage {
|
||||
inherit pname version src strictDeps nativeBuildInputs buildInputs;
|
||||
CARGO_BUILD_JOBS =
|
||||
if (builtins.tryEval (builtins.getEnv "CARGO_BUILD_JOBS")).success then
|
||||
builtins.getEnv "CARGO_BUILD_JOBS"
|
||||
else
|
||||
"2";
|
||||
|
||||
# Use the safe cargoJobs variable
|
||||
CARGO_BUILD_JOBS = cargoJobs;
|
||||
|
||||
# Build cargo dependencies once for caching
|
||||
cargoArtifacts = craneLib.buildDepsOnly {
|
||||
inherit src strictDeps nativeBuildInputs buildInputs pname version;
|
||||
cargoExtraArgs =
|
||||
"--features tracing-journald,io-uring --no-default-features";
|
||||
};
|
||||
|
||||
cargoExtraArgs = "-p server --features tracing-journald,io-uring --no-default-features";
|
||||
}
|
||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||
in craneLib.buildPackage (commonArgs // {
|
||||
|
||||
inherit cargoArtifacts;
|
||||
})
|
||||
Reference in new issue
Block a user