Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ jobs:
- name: Install dependencies
run: pnpm install

- name: Verify OpenDAL native package for Linux
run: pnpm run smoke:opendal:native -- --platform linux --arch ${{ matrix.arch }}

# - name: Install Node Runtime
# run: pnpm run installRuntime:linux:${{ matrix.arch }}

Expand All @@ -176,6 +179,9 @@ jobs:
test -f "$EXTENSION_PATH"
pnpm run smoke:duckdb:vss -- --platform linux --arch ${{ matrix.arch }} --extension-path "$EXTENSION_PATH"

- name: Verify packaged OpenDAL native package for Linux
run: pnpm run smoke:opendal:native -- --platform linux --arch ${{ matrix.arch }} --resources-path dist/linux-unpacked/resources

- name: Verify bundled plugins
shell: bash
run: |
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ jobs:
- name: Install dependencies
run: pnpm install

- name: Verify OpenDAL native package for Linux
run: pnpm run smoke:opendal:native -- --platform linux --arch ${{ matrix.arch }}

- name: Install and verify DuckDB VSS for Linux
run: |
pnpm run installRuntime:duckdb:vss -- --platform linux --arch ${{ matrix.arch }}
Expand All @@ -270,6 +273,9 @@ jobs:
test -f "$EXTENSION_PATH"
pnpm run smoke:duckdb:vss -- --platform linux --arch ${{ matrix.arch }} --extension-path "$EXTENSION_PATH"

- name: Verify packaged OpenDAL native package for Linux
run: pnpm run smoke:opendal:native -- --platform linux --arch ${{ matrix.arch }} --resources-path dist/linux-unpacked/resources

- name: Verify bundled plugins
shell: bash
run: |
Expand Down
19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"installRuntime:duckdb:vss:linux:x64": "node scripts/installVss.js --platform linux --arch x64",
"installRuntime:duckdb:vss:linux:arm64": "node scripts/installVss.js --platform linux --arch arm64",
"smoke:duckdb:vss": "node scripts/smoke-duckdb-vss.js",
"smoke:opendal:native": "node scripts/smoke-opendal-native.js",
"i18n": "i18n-check -s zh-CN -f i18next --locales src/renderer/src/i18n",
"i18n:en": "i18n-check -s en-US -f i18next --locales src/renderer/src/i18n",
"i18n:types": "node scripts/generate-i18n-types.js",
Expand Down Expand Up @@ -128,7 +129,7 @@
"nanoid": "^5.1.11",
"node-pty": "1.2.0-beta.14",
"ollama": "^0.6.3",
"opendal": "^0.49.4",
"opendal": "0.49.2",
"pdf-parse-new": "^1.4.1",
"qrcode": "^1.5.4",
"run-applescript": "^7.1.0",
Expand Down Expand Up @@ -220,14 +221,14 @@
"yaml": "^2.9.0"
},
"optionalDependencies": {
"@opendal/lib-darwin-arm64": "0.49.4",
"@opendal/lib-darwin-x64": "0.49.4",
"@opendal/lib-linux-arm64-gnu": "0.49.4",
"@opendal/lib-linux-arm64-musl": "0.49.4",
"@opendal/lib-linux-x64-gnu": "0.49.4",
"@opendal/lib-linux-x64-musl": "0.49.4",
"@opendal/lib-win32-arm64-msvc": "0.49.4",
"@opendal/lib-win32-x64-msvc": "0.49.4"
"@opendal/lib-darwin-arm64": "0.49.2",
"@opendal/lib-darwin-x64": "0.49.2",
"@opendal/lib-linux-arm64-gnu": "0.49.2",
"@opendal/lib-linux-arm64-musl": "0.49.2",
"@opendal/lib-linux-x64-gnu": "0.49.2",
"@opendal/lib-linux-x64-musl": "0.49.2",
"@opendal/lib-win32-arm64-msvc": "0.49.2",
"@opendal/lib-win32-x64-msvc": "0.49.2"
},
"pnpm": {
"onlyBuiltDependencies": [
Expand Down
54 changes: 54 additions & 0 deletions scripts/afterPack.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,31 @@ function getParcelWatcherBinaryPackages(platform, arch) {
}
}

function getOpendalNativePackages(platform, arch) {
const archName = getArchName(arch)

if (platform === 'darwin' && archName === 'universal') {
return ['@opendal/lib-darwin-x64', '@opendal/lib-darwin-arm64']
}

switch (`${platform}:${archName}`) {
case 'darwin:x64':
return ['@opendal/lib-darwin-x64']
case 'darwin:arm64':
return ['@opendal/lib-darwin-arm64']
case 'win32:x64':
return ['@opendal/lib-win32-x64-msvc']
case 'win32:arm64':
return ['@opendal/lib-win32-arm64-msvc']
case 'linux:x64':
return ['@opendal/lib-linux-x64-gnu']
case 'linux:arm64':
return ['@opendal/lib-linux-arm64-gnu']
default:
return []
}
}

async function pathExists(filePath) {
try {
await fs.access(filePath)
Expand Down Expand Up @@ -176,6 +201,34 @@ async function copyParcelWatcherNativePackages(context) {
}
}

async function copyOpendalNativePackages(context) {
const { arch, electronPlatformName, packager } = context
const packageNames = getOpendalNativePackages(electronPlatformName, arch)

if (packageNames.length === 0) {
return
}

const nodeModulesDir = path.join(getResourcesDir(context), 'app.asar.unpacked', 'node_modules')
const opendalDir = path.join(nodeModulesDir, 'opendal')

if (!(await pathExists(opendalDir))) {
throw new Error(
`Missing unpacked opendal at ${opendalDir}. Check electron-builder asarUnpack configuration.`
)
}

const projectDir = packager?.projectDir ?? process.cwd()

for (const packageName of packageNames) {
const sourceDir = await resolveInstalledPackageDir(projectDir, packageName)
const destinationDir = path.join(nodeModulesDir, ...packageName.split('/'))

await fs.mkdir(path.dirname(destinationDir), { recursive: true })
await fs.cp(sourceDir, destinationDir, { recursive: true, force: true, dereference: true })
}
}

function isLinux(targets) {
const re = /AppImage|snap|deb|rpm|freebsd|pacman/i
return !!targets.find((target) => re.test(target.name))
Expand Down Expand Up @@ -220,6 +273,7 @@ async function afterPack(context) {

await copyFffNativePackages(context)
await copyParcelWatcherNativePackages(context)
await copyOpendalNativePackages(context)
await encodeMacVssExtension(context)

if (isLinux(targets)) {
Expand Down
15 changes: 11 additions & 4 deletions scripts/install-sharp-for-platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

/**
* Update pnpm-workspace.yaml supportedArchitectures for different platforms
* 根据不同平台动态修改 pnpm-workspace.yaml 的 supportedArchitectures 配置
*/

import { readFileSync, writeFileSync, existsSync } from 'fs';
Expand All @@ -27,11 +26,13 @@ const platformConfigs = {
},
'linux-x64': {
os: ['current', 'linux'],
cpu: ['current', 'wasm32'], // Include wasm32 for Sharp WebAssembly
cpu: ['current', 'x64', 'wasm32'], // Include wasm32 for Sharp WebAssembly
libc: ['glibc'],
},
'linux-arm64': {
os: ['current','linux'],
cpu: ['current', 'wasm32'],
os: ['current', 'linux'],
cpu: ['current', 'arm64', 'wasm32'],
libc: ['glibc'],
},
'darwin-x64': {
os: ['current', 'darwin'],
Expand Down Expand Up @@ -74,6 +75,9 @@ try {
os: config.os,
cpu: config.cpu
};
if (config.libc) {
workspaceConfig.supportedArchitectures.libc = config.libc;
}

// Convert back to YAML with proper formatting
const finalContent = YAML.stringify(workspaceConfig, {
Expand All @@ -87,6 +91,9 @@ try {
console.log(`📋 Configuration:`);
console.log(` OS: ${config.os.join(', ')}`);
console.log(` CPU: ${config.cpu.join(', ')}`);
if (config.libc) {
console.log(` Libc: ${config.libc.join(', ')}`);
}
} catch (error) {
console.error(`❌ Failed to update pnpm-workspace.yaml: ${error.message}`);
process.exit(1);
Expand Down
187 changes: 187 additions & 0 deletions scripts/smoke-opendal-native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#!/usr/bin/env node

import fs from 'node:fs'
import path from 'node:path'
import { createRequire } from 'node:module'
import { pathToFileURL } from 'node:url'

export function parseArgs(argv) {
const options = {}
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index]
if (arg === '--') continue
if (!arg.startsWith('--')) continue
const [rawKey, inlineValue] = arg.slice(2).split('=', 2)
let value = inlineValue
if (value === undefined) {
const next = argv[index + 1]
if (next === undefined || next === '--' || next.startsWith('--')) {
throw new Error(`Missing value for --${rawKey}`)
}
value = next
index += 1
}
options[rawKey] = value
}
return options
}

function normalizePlatform(value) {
switch (value) {
case 'darwin':
case 'mac':
case 'macos':
case 'osx':
return 'darwin'
case 'win32':
case 'windows':
case 'win':
return 'win32'
case 'linux':
return 'linux'
default:
throw new Error(`Unsupported OpenDAL platform: ${value}`)
}
}

function normalizeArch(value) {
switch (value) {
case 'x64':
case 'amd64':
return 'x64'
case 'arm64':
case 'aarch64':
return 'arm64'
default:
throw new Error(`Unsupported OpenDAL architecture: ${value}`)
}
}

function getOpendalNativePackage(platform, arch) {
switch (`${platform}:${arch}`) {
case 'darwin:x64':
return '@opendal/lib-darwin-x64'
case 'darwin:arm64':
return '@opendal/lib-darwin-arm64'
case 'win32:x64':
return '@opendal/lib-win32-x64-msvc'
case 'win32:arm64':
return '@opendal/lib-win32-arm64-msvc'
case 'linux:x64':
return '@opendal/lib-linux-x64-gnu'
case 'linux:arm64':
return '@opendal/lib-linux-arm64-gnu'
default:
throw new Error(`Unsupported OpenDAL target: ${platform}/${arch}`)
}
}

function packagePathParts(packageName) {
return packageName.split('/')
}

function resolvePackageDirFromNodeModules(nodeModulesDir, packageName) {
const directDir = path.join(nodeModulesDir, ...packagePathParts(packageName))
if (fs.existsSync(path.join(directDir, 'package.json'))) {
return fs.realpathSync(directDir)
}

const pnpmNodeModulesDir = path.join(nodeModulesDir, '.pnpm', 'node_modules', ...packagePathParts(packageName))
if (fs.existsSync(path.join(pnpmNodeModulesDir, 'package.json'))) {
return fs.realpathSync(pnpmNodeModulesDir)
}

const pnpmVirtualStoreDir = path.join(nodeModulesDir, '.pnpm')
if (fs.existsSync(pnpmVirtualStoreDir)) {
for (const entry of fs.readdirSync(pnpmVirtualStoreDir, { withFileTypes: true })) {
if (!entry.isDirectory()) continue
const candidate = path.join(
pnpmVirtualStoreDir,
entry.name,
'node_modules',
...packagePathParts(packageName)
)
if (fs.existsSync(path.join(candidate, 'package.json'))) {
return fs.realpathSync(candidate)
}
}
}

throw new Error(`OpenDAL package ${packageName} not found under ${nodeModulesDir}`)
}

function assertPackageMainExists(packageDir, label) {
const packageJsonPath = path.join(packageDir, 'package.json')
if (!fs.existsSync(packageJsonPath)) {
throw new Error(`${label} package.json not found at ${packageJsonPath}`)
}

const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
if (!packageJson.main) {
throw new Error(`${label} package.json has no main field at ${packageJsonPath}`)
}

const mainPath = path.join(packageDir, packageJson.main)
if (!fs.existsSync(mainPath)) {
throw new Error(`${label} native entry not found at ${mainPath}`)
}
return mainPath
}

function maybeLoadOpendal(opendalDir, platform, arch, label) {
if (platform !== process.platform || arch !== process.arch) {
console.log(
`[OpenDAL Smoke] ${label}: target ${platform}/${arch} differs from host ${process.platform}/${process.arch}; verified file presence only.`
)
return
}

const opendalEntry = path.join(opendalDir, 'index.cjs')
const requireFromOpendal = createRequire(opendalEntry)
requireFromOpendal(opendalEntry)
console.log(`[OpenDAL Smoke] ${label}: loaded opendal from ${opendalEntry}`)
}

function smokeNodeModules({ nodeModulesDir, platform, arch, label }) {
const nativePackageName = getOpendalNativePackage(platform, arch)
const opendalDir = resolvePackageDirFromNodeModules(nodeModulesDir, 'opendal')
const nativePackageDir = resolvePackageDirFromNodeModules(nodeModulesDir, nativePackageName)
const nativeEntry = assertPackageMainExists(nativePackageDir, `${label} ${nativePackageName}`)

console.log(`[OpenDAL Smoke] ${label}: found ${nativePackageName} at ${nativePackageDir}`)
console.log(`[OpenDAL Smoke] ${label}: native entry ${nativeEntry}`)
maybeLoadOpendal(opendalDir, platform, arch, label)
}

function main() {
const args = parseArgs(process.argv.slice(2))
const platform = args.platform ? normalizePlatform(args.platform) : process.platform
const arch = args.arch ? normalizeArch(args.arch) : process.arch
const projectDir = path.resolve(args.projectDir ?? args['project-dir'] ?? process.cwd())
const resourcesPath = args.resourcesPath ?? args['resources-path']

smokeNodeModules({
nodeModulesDir: path.join(projectDir, 'node_modules'),
platform,
arch,
label: 'source'
})

if (resourcesPath) {
smokeNodeModules({
nodeModulesDir: path.join(path.resolve(resourcesPath), 'app.asar.unpacked', 'node_modules'),
platform,
arch,
label: 'packaged'
})
}
}

if (process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url) {
try {
main()
} catch (error) {
console.error('[OpenDAL Smoke] failed:', error)
process.exit(1)
}
}
Loading