Skip to content

Commit 856e2cf

Browse files
committed
Merge branch 'develop'
2 parents b02128a + 6de0a44 commit 856e2cf

105 files changed

Lines changed: 6533 additions & 1470 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-windows.yaml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,33 @@ jobs:
3030
- name: Enable Corepack
3131
run: corepack enable
3232

33+
- name: Cache node_modules
34+
uses: actions/cache@v4
35+
with:
36+
path: |
37+
.yarn/cache
38+
.yarn/install-state.gz
39+
**/node_modules
40+
key: ${{ runner.os }}-18-modules-${{ hashFiles('**/yarn.lock') }}
41+
3342
- name: Prepare Environment
3443
run: yarn install --immutable
3544
env:
3645
CI: true
3746

47+
- name: Cache pkg/electron binaries
48+
uses: actions/cache@v4
49+
with:
50+
key: ${{ runner.os }}-natives-${{ hashFiles('node_modules/**/expected-shas.json') }}-${{ hashFiles('node_modules/**/electron/package.json') }}
51+
path: |
52+
${{ github.workspace }}/.cache
53+
3854
- name: Run build
3955
env:
4056
CI: true
41-
PKG_CACHE_PATH: ${{ runner.temp }}
57+
ELECTRON_CACHE: ${{ github.workspace }}/.cache/electron
58+
ELECTRON_BUILDER_CACHE: ${{ github.workspace }}/.cache/electron-builder
59+
PKG_CACHE_PATH: ${{ github.workspace }}/.cache/yao-pkg
4260
run: |
4361
# try and avoid timeout errors
4462

.github/workflows/lint-and-test.yaml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ jobs:
3030
- name: Enable Corepack
3131
run: corepack enable
3232

33+
- name: Cache node_modules
34+
uses: actions/cache@v4
35+
with:
36+
path: |
37+
.yarn/cache
38+
.yarn/install-state.gz
39+
**/node_modules
40+
key: ${{ runner.os }}-18-modules-${{ hashFiles('**/yarn.lock') }}
41+
3342
- name: Prepare Environment
3443
run: yarn install --immutable
3544
env:
@@ -50,9 +59,9 @@ jobs:
5059
strategy:
5160
fail-fast: false
5261
matrix:
53-
node_version: ['20', '22', '24']
62+
node_version: ['24']
5463
os: [ubuntu-latest, windows-latest] # [windows-latest, macOS-latest]
55-
timeout-minutes: 10
64+
timeout-minutes: 15
5665
steps:
5766
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
5867
- uses: actions/checkout@v6
@@ -65,6 +74,21 @@ jobs:
6574
node-version: ${{ matrix.node_version }}
6675
cache: 'yarn'
6776

77+
- name: Cache node_modules
78+
uses: actions/cache@v4
79+
with:
80+
path: |
81+
.yarn/cache
82+
.yarn/install-state.gz
83+
**/node_modules
84+
key: ${{ runner.os }}-${{ matrix.node_version }}-modules-${{ hashFiles('**/yarn.lock') }}
85+
86+
- name: Cache ffmpeg binaries
87+
uses: actions/cache@v4
88+
with:
89+
path: '.ffmpeg'
90+
key: ${{ runner.os }}-ffmpeg-${{ hashFiles('**/ffmpegReleases.json') }}
91+
6892
- name: Enable Corepack
6993
run: corepack enable
7094

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ apps/single-app/app/expectedPackages.json_smartbull
4242
signtool.exe
4343
apps/single-app/app/tmp/
4444
apps/single-app/app/tmpRenderHTML/
45+
apps/html-renderer/app/tmp/

DEVELOPER.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ yarn test
207207
yarn start:single-app
208208

209209
# Start the single-app in local-only mode, using packages from expectedPackages.json
210-
yarn start:single-app -- -- --watchFiles=true --noCore=true --logLevel=debug
210+
yarn start:single-app -- -- --watchFiles=true --noCore=true --logLevel=debug --executableAliases='ffmpeg=C:\\ffmpeg\\ffmpeg.exe;ffprobe=C:\\ffmpeg\\ffprobe.exe;kairos-converter=C:\\Program Files\\Panasonic\\KairosCreator\\bin\\KairosConverter.exe'
211211

212212

213213

apps/appcontainer-node/packages/generic/src/__mocks__/@sofie-package-manager/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,7 @@ packageManagerAPI.findValue = realPackageManagerAPI.findValue
5353
packageManagerAPI.DataStore = realPackageManagerAPI.DataStore
5454
packageManagerAPI.stringifyError = realPackageManagerAPI.stringifyError
5555
packageManagerAPI.waitTime = realPackageManagerAPI.waitTime
56+
packageManagerAPI.isRunningInTest = realPackageManagerAPI.isRunningInTest
57+
packageManagerAPI.isRunningInDevelopment = realPackageManagerAPI.isRunningInDevelopment
5658

5759
module.exports = packageManagerAPI

apps/appcontainer-node/packages/generic/src/__tests__/lib/setupEnv.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export async function setupAppContainer(partialAppContainerConfig: Partial<AppCo
4747
resourceId: '',
4848
windowsDriveLetters: [],
4949
temporaryFolderPath: '',
50+
matchFilenamesWithoutExtension: false,
51+
failurePeriod: 0,
52+
failurePeriodLimit: 0,
53+
executableAliases: {},
54+
sourcePackageStabilityThreshold: 0,
5055
},
5156
workforceURL: null,
5257
},

apps/appcontainer-node/packages/generic/src/appContainer.ts

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
PackageContainerExpectation,
1818
Reason,
1919
stringifyError,
20-
setLogLevel,
2120
isNodeRunningInDebugMode,
2221
INNER_ACTION_TIMEOUT,
2322
DataStore,
@@ -33,9 +32,10 @@ import {
3332
DataId,
3433
LockId,
3534
protectString,
36-
getLogLevel,
3735
Cost,
3836
LeveledLogMethodLight,
37+
isRunningInDevelopment,
38+
isRunningInTest,
3939
} from '@sofie-package-manager/api'
4040

4141
import { WorkforceAPI } from './workforceApi'
@@ -283,9 +283,9 @@ export class AppContainer {
283283

284284
private async discoverAvailableApps() {
285285
const getWorkerArgs = (appId: AppId, pickUpCriticalExpectationsOnly: boolean): string[] => {
286-
return [
286+
const args: string[] = [
287287
// Set initial loglevel to be same as appContainer:
288-
`--logLevel=${getLogLevel()}`,
288+
`--logLevel=${this.logger.getLogLevel()}`,
289289

290290
`--workerId=${appId}`,
291291
pickUpCriticalExpectationsOnly ? `--pickUpCriticalExpectationsOnly=true` : '',
@@ -296,38 +296,54 @@ export class AppContainer {
296296
this.config.process.certificates.length
297297
? `--certificates=${this.config.process.certificates.join(';')}`
298298
: '',
299-
300-
this.config.appContainer.worker.windowsDriveLetters
301-
? `--windowsDriveLetters=${this.config.appContainer.worker.windowsDriveLetters?.join(';')}`
302-
: '',
303-
this.config.appContainer.worker.temporaryFolderPath
304-
? `--temporaryFolderPath=${this.config.appContainer.worker.temporaryFolderPath}`
305-
: '',
306-
this.config.appContainer.worker.costMultiplier
307-
? `--costMultiplier=${this.config.appContainer.worker.costMultiplier}`
308-
: '',
309-
this.config.appContainer.worker.considerCPULoad
310-
? `--considerCPULoad=${this.config.appContainer.worker.considerCPULoad}`
311-
: '',
312-
this.config.appContainer.worker.resourceId
313-
? `--resourceId=${this.config.appContainer.worker.resourceId}`
314-
: '',
315-
this.config.appContainer.worker.networkIds.length
316-
? `--networkIds=${this.config.appContainer.worker.networkIds.join(';')}`
317-
: '',
318-
this.config.appContainer.worker.failurePeriodLimit
319-
? `--failurePeriodLimit=${this.config.appContainer.worker.failurePeriodLimit}`
320-
: '',
321-
this.config.appContainer.worker.failurePeriod
322-
? `--failurePeriod=${this.config.appContainer.worker.failurePeriod}`
323-
: '',
324299
]
300+
301+
const workerArgs = this.config.appContainer.worker
302+
const keys = Object.keys(workerArgs) as (keyof AppContainerProcessConfig['appContainer']['worker'])[]
303+
for (const key of keys) {
304+
let argValue: string | undefined = undefined
305+
if (key === 'windowsDriveLetters') {
306+
argValue = workerArgs.windowsDriveLetters?.join(';')
307+
} else if (key === 'temporaryFolderPath') {
308+
argValue = workerArgs.temporaryFolderPath
309+
} else if (key === 'costMultiplier') {
310+
argValue = workerArgs.costMultiplier?.toString()
311+
} else if (key === 'considerCPULoad') {
312+
argValue = workerArgs.considerCPULoad?.toString()
313+
} else if (key === 'resourceId') {
314+
argValue = workerArgs.resourceId
315+
} else if (key === 'networkIds') {
316+
argValue = workerArgs.networkIds.join(';')
317+
} else if (key === 'failurePeriodLimit') {
318+
argValue = workerArgs.failurePeriodLimit?.toString()
319+
} else if (key === 'failurePeriod') {
320+
argValue = workerArgs.failurePeriod?.toString()
321+
} else if (key === 'sourcePackageStabilityThreshold') {
322+
argValue = workerArgs.sourcePackageStabilityThreshold?.toString()
323+
} else if (key === 'executableAliases') {
324+
argValue = workerArgs.executableAliases
325+
? Object.entries<string>(workerArgs.executableAliases)
326+
.map(([k, v]) => `${k}=${v}`)
327+
.join(';')
328+
: undefined
329+
} else if (key === 'allowedExpectationTypes') {
330+
argValue = workerArgs.allowedExpectationTypes
331+
? workerArgs.allowedExpectationTypes.join(';')
332+
: undefined
333+
} else if (key === 'matchFilenamesWithoutExtension') {
334+
// This is handled separately above, skip it here
335+
} else {
336+
assertNever(key)
337+
this.logger.error(`Unknown worker argument key: "${key}"=${workerArgs[key]}`)
338+
}
339+
340+
if (argValue) args.push(`--${key}=${argValue}`)
341+
}
342+
343+
return args
325344
}
326-
if (
327-
path.basename(process.execPath) === 'node.exe' || // windows
328-
path.basename(process.execPath) === 'node' // linux
329-
) {
330-
// Process runs as a node process, we're probably in development mode.
345+
346+
if (isRunningInDevelopment() || isRunningInTest()) {
331347
const appType = protectString<AppType>('worker')
332348
this.availableApps.set(appType, {
333349
file: process.execPath,
@@ -381,7 +397,7 @@ export class AppContainer {
381397
}
382398
async setLogLevel(logLevel: LogLevel): Promise<void> {
383399
this.logger.info(`Setting log level to "${logLevel}"`)
384-
setLogLevel(logLevel)
400+
this.logger.setLogLevel(logLevel)
385401
}
386402
async _debugKill(): Promise<void> {
387403
// This is for testing purposes only
@@ -414,7 +430,11 @@ export class AppContainer {
414430
if (this.availableApps.size === 0) {
415431
this.logger.error('No apps available')
416432
} else {
417-
this.logger.debug(`Available apps: ${Array.from(this.availableApps.keys()).join(', ')}`)
433+
this.logger.debug(
434+
`Available apps: ${Array.from(this.availableApps.entries())
435+
.map(([key, app]) => `${key}:${app.file}`)
436+
.join(', ')}`
437+
)
418438
}
419439

420440
let lastNotSupportReason: ExpectedPackageStatusAPI.Reason = {
@@ -470,7 +490,11 @@ export class AppContainer {
470490
if (this.availableApps.size === 0) {
471491
this.logger.error('No apps available')
472492
} else {
473-
this.logger.debug(`Available apps: ${Array.from(this.availableApps.keys()).join(', ')}`)
493+
this.logger.debug(
494+
`Available apps: ${Array.from(this.availableApps.entries())
495+
.map(([key, app]) => `${key}:${app.file}`)
496+
.join(', ')}`
497+
)
474498
}
475499

476500
for (const [appType, availableApp] of this.availableApps.entries()) {
@@ -633,10 +657,7 @@ export class AppContainer {
633657
availableApp: AvailableAppInfo,
634658
useCriticalOnlyMode: boolean
635659
): cp.ChildProcess {
636-
const isRunningInDevelopmentMode = process.execPath.endsWith('node.exe') || process.execPath.endsWith('node')
637-
const cwd = isRunningInDevelopmentMode
638-
? undefined // Process runs as a node process, we're probably in development mode.
639-
: path.dirname(process.execPath) // Process runs as a node process, we're probably in development mode.
660+
const cwd = isRunningInDevelopment() ? undefined : path.dirname(process.execPath)
640661

641662
let inspectPort: number | undefined = undefined
642663
if (isNodeRunningInDebugMode()) {

apps/html-renderer/app/src/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
processOptions,
66
defineArguments,
77
getProcessArgv,
8+
parseExecutableAliases,
89
} from '@sofie-package-manager/api'
910

1011
/*
@@ -58,6 +59,12 @@ const htmlRendererOptions = defineArguments({
5859
type: 'boolean',
5960
describe: 'When true, will simply trace the version and then close.',
6061
},
62+
executableAliases: {
63+
type: 'string',
64+
default: process.env.WORKER_EXECUTABLE_ALIASES || '',
65+
describe:
66+
'List of aliases for executables the worker can use. Format: "alias1=path to executable1;alias2=executable2". (This is used to alias ffmpeg for the HTML-Renderer.)',
67+
},
6168
})
6269

6370
export interface HTMLRendererOptionsConfig {
@@ -78,6 +85,8 @@ export interface HTMLRendererOptionsConfig {
7885
genericWaitStop: number | undefined
7986
interactive: boolean | undefined
8087
test: boolean | undefined
88+
/** List of aliases for executables the worker can use. */
89+
executableAliases: { [alias: string]: string }
8190
}
8291
export async function getHTMLRendererConfig(): Promise<{
8392
process: ProcessConfig
@@ -110,6 +119,7 @@ export async function getHTMLRendererConfig(): Promise<{
110119
genericWaitStop: argv.genericWaitStop,
111120
interactive: argv.interactive,
112121
test: argv.test,
122+
executableAliases: parseExecutableAliases(argv.executableAliases),
113123
},
114124
}
115125
}

apps/html-renderer/app/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ async function main(): Promise<void> {
227227
background: config.htmlRenderer.background,
228228
outputFolder: config.htmlRenderer.outputPath ?? '',
229229
tempFolder: config.htmlRenderer.tempPath ?? 'tmp',
230+
executableAliases: config.htmlRenderer.executableAliases ?? {},
230231
url,
231232
scripts,
232233
interactive,

apps/html-renderer/packages/generic/src/BrowserRenderer.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,17 @@ export class BrowserRenderer implements InteractiveAPI {
369369
const logger = this.logger.category('FFMpeg')
370370
await new Promise<void>((resolve, reject) => {
371371
let logTrace = ''
372-
const child = spawn(getFFMpegExecutable(), args, {
373-
windowsVerbatimArguments: true, // To fix an issue with ffmpeg.exe on Windows
374-
})
372+
const child = spawn(
373+
getFFMpegExecutable({
374+
getExecutable: (executableAlias: string): string | undefined => {
375+
return this.options.executableAliases[executableAlias]
376+
},
377+
}),
378+
args,
379+
{
380+
windowsVerbatimArguments: true, // To fix an issue with ffmpeg.exe on Windows
381+
}
382+
)
375383

376384
child.stdout.on('data', (data) => {
377385
options?.onStdout?.(data.toString())

0 commit comments

Comments
 (0)