Compare commits

..

2 Commits

Author SHA1 Message Date
Giacomo Cusinato
5d282f3849 fix: bundle theia native dependencies with stricter permissions 2025-11-05 16:37:01 +01:00
Giacomo Cusinato
2f7667136e chore: remove allow-dyld-environment-variables entitlement 2025-11-05 11:06:14 +01:00
8 changed files with 24 additions and 52 deletions

View File

@@ -67,7 +67,3 @@ export function truncateLines(
} }
return [lines, charCount]; return [lines, charCount];
} }
export function joinLines(lines: Line[]): string {
return lines.map((line: Line) => line.message).join('');
}

View File

@@ -52,9 +52,6 @@ export namespace SerialMonitor {
}, },
'vscode/output.contribution/clearOutput.label' 'vscode/output.contribution/clearOutput.label'
); );
export const COPY_OUTPUT = {
id: 'serial-monitor-copy-output',
};
} }
} }
@@ -152,12 +149,6 @@ export class MonitorViewContribution
'Clear Output' 'Clear Output'
), ),
}); });
registry.registerItem({
id: SerialMonitor.Commands.COPY_OUTPUT.id,
command: SerialMonitor.Commands.COPY_OUTPUT.id,
icon: codicon('copy'),
tooltip: nls.localize('arduino/serial/copyOutput', 'Copy Output'),
});
} }
override registerCommands(commands: CommandRegistry): void { override registerCommands(commands: CommandRegistry): void {
@@ -170,15 +161,6 @@ export class MonitorViewContribution
} }
}, },
}); });
commands.registerCommand(SerialMonitor.Commands.COPY_OUTPUT, {
isEnabled: (widget) => widget instanceof MonitorWidget,
isVisible: (widget) => widget instanceof MonitorWidget,
execute: (widget) => {
if (widget instanceof MonitorWidget) {
widget.copyOutput();
}
},
});
if (this.toggleCommand) { if (this.toggleCommand) {
commands.registerCommand(this.toggleCommand, { commands.registerCommand(this.toggleCommand, {
execute: () => this.toggle(), execute: () => this.toggle(),

View File

@@ -28,7 +28,6 @@ import {
import { MonitorModel } from '../../monitor-model'; import { MonitorModel } from '../../monitor-model';
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
import { serialMonitorWidgetLabel } from '../../../common/nls'; import { serialMonitorWidgetLabel } from '../../../common/nls';
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
@injectable() @injectable()
export class MonitorWidget extends ReactWidget { export class MonitorWidget extends ReactWidget {
@@ -48,7 +47,6 @@ export class MonitorWidget extends ReactWidget {
*/ */
protected closing = false; protected closing = false;
protected readonly clearOutputEmitter = new Emitter<void>(); protected readonly clearOutputEmitter = new Emitter<void>();
protected readonly copyOutputEmitter = new Emitter<void>();
@inject(MonitorModel) @inject(MonitorModel)
private readonly monitorModel: MonitorModel; private readonly monitorModel: MonitorModel;
@@ -58,8 +56,6 @@ export class MonitorWidget extends ReactWidget {
private readonly boardsServiceProvider: BoardsServiceProvider; private readonly boardsServiceProvider: BoardsServiceProvider;
@inject(FrontendApplicationStateService) @inject(FrontendApplicationStateService)
private readonly appStateService: FrontendApplicationStateService; private readonly appStateService: FrontendApplicationStateService;
@inject(ClipboardService)
private readonly clipboardService: ClipboardService;
private readonly toDisposeOnReset: DisposableCollection; private readonly toDisposeOnReset: DisposableCollection;
@@ -107,10 +103,6 @@ export class MonitorWidget extends ReactWidget {
this.update(); this.update();
} }
copyOutput(): void {
this.copyOutputEmitter.fire();
}
override dispose(): void { override dispose(): void {
this.toDisposeOnReset.dispose(); this.toDisposeOnReset.dispose();
super.dispose(); super.dispose();
@@ -255,8 +247,6 @@ export class MonitorWidget extends ReactWidget {
monitorModel={this.monitorModel} monitorModel={this.monitorModel}
monitorManagerProxy={this.monitorManagerProxy} monitorManagerProxy={this.monitorManagerProxy}
clearConsoleEvent={this.clearOutputEmitter.event} clearConsoleEvent={this.clearOutputEmitter.event}
copyOutputEvent={this.copyOutputEmitter.event}
clipboardService={this.clipboardService}
height={Math.floor(this.widgetHeight - 50)} height={Math.floor(this.widgetHeight - 50)}
/> />
</div> </div>

View File

@@ -3,10 +3,9 @@ import { Event } from '@theia/core/lib/common/event';
import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { areEqual, FixedSizeList as List } from 'react-window'; import { areEqual, FixedSizeList as List } from 'react-window';
import dateFormat from 'dateformat'; import dateFormat from 'dateformat';
import { messagesToLines, truncateLines, joinLines } from './monitor-utils'; import { messagesToLines, truncateLines } from './monitor-utils';
import { MonitorManagerProxyClient } from '../../../common/protocol'; import { MonitorManagerProxyClient } from '../../../common/protocol';
import { MonitorModel } from '../../monitor-model'; import { MonitorModel } from '../../monitor-model';
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
export type Line = { message: string; timestamp?: Date; lineLen: number }; export type Line = { message: string; timestamp?: Date; lineLen: number };
@@ -75,9 +74,6 @@ export class SerialMonitorOutput extends React.Component<
this.props.clearConsoleEvent(() => this.props.clearConsoleEvent(() =>
this.setState({ lines: [], charCount: 0 }) this.setState({ lines: [], charCount: 0 })
), ),
this.props.copyOutputEvent(() =>
this.props.clipboardService.writeText(joinLines(this.state.lines))
),
this.props.monitorModel.onChange(({ property }) => { this.props.monitorModel.onChange(({ property }) => {
if (property === 'timestamp') { if (property === 'timestamp') {
const { timestamp } = this.props.monitorModel; const { timestamp } = this.props.monitorModel;
@@ -134,8 +130,6 @@ export namespace SerialMonitorOutput {
readonly monitorModel: MonitorModel; readonly monitorModel: MonitorModel;
readonly monitorManagerProxy: MonitorManagerProxyClient; readonly monitorManagerProxy: MonitorManagerProxyClient;
readonly clearConsoleEvent: Event<void>; readonly clearConsoleEvent: Event<void>;
readonly copyOutputEvent: Event<void>;
readonly clipboardService: ClipboardService;
readonly height: number; readonly height: number;
} }

View File

@@ -2,7 +2,6 @@ import { expect } from 'chai';
import { import {
messagesToLines, messagesToLines,
truncateLines, truncateLines,
joinLines,
} from '../../browser/serial/monitor/monitor-utils'; } from '../../browser/serial/monitor/monitor-utils';
import { Line } from '../../browser/serial/monitor/serial-monitor-send-output'; import { Line } from '../../browser/serial/monitor/serial-monitor-send-output';
import { set, reset } from 'mockdate'; import { set, reset } from 'mockdate';
@@ -16,7 +15,6 @@ type TestLine = {
charCount: number; charCount: number;
maxCharacters?: number; maxCharacters?: number;
}; };
expectedJoined?: string;
}; };
const date = new Date(); const date = new Date();
@@ -24,7 +22,6 @@ const testLines: TestLine[] = [
{ {
messages: ['Hello'], messages: ['Hello'],
expected: { lines: [{ message: 'Hello', lineLen: 5 }], charCount: 5 }, expected: { lines: [{ message: 'Hello', lineLen: 5 }], charCount: 5 },
expectedJoined: 'Hello',
}, },
{ {
messages: ['Hello', 'Dog!'], messages: ['Hello', 'Dog!'],
@@ -39,7 +36,6 @@ const testLines: TestLine[] = [
], ],
charCount: 10, charCount: 10,
}, },
expectedJoined: 'Hello\nDog!'
}, },
{ {
messages: ['Dog!'], messages: ['Dog!'],
@@ -71,7 +67,6 @@ const testLines: TestLine[] = [
{ message: "You're a good boy!", lineLen: 8 }, { message: "You're a good boy!", lineLen: 8 },
], ],
}, },
expectedJoined: "Hello Dog!\n Who's a good boy?\nYou're a good boy!",
}, },
{ {
messages: ['boy?\n', "You're a good boy!"], messages: ['boy?\n', "You're a good boy!"],
@@ -121,7 +116,6 @@ const testLines: TestLine[] = [
{ message: 'Yo', lineLen: 2 }, { message: 'Yo', lineLen: 2 },
], ],
}, },
expectedJoined: "Hello Dog!\nWho's a good boy?\nYo",
}, },
]; ];
@@ -171,10 +165,6 @@ describe('Monitor Utils', () => {
}); });
expect(totalCharCount).to.equal(charCount); expect(totalCharCount).to.equal(charCount);
} }
if (testLine.expectedJoined) {
const joined_str = joinLines(testLine.expected.lines);
expect(joined_str).to.equal(testLine.expectedJoined);
}
}); });
}); });
}); });

View File

@@ -8,7 +8,5 @@
<true/> <true/>
<key>com.apple.security.cs.disable-library-validation</key> <key>com.apple.security.cs.disable-library-validation</key>
<true/> <true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@@ -1,5 +1,7 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs');
const webpack = require('webpack'); const webpack = require('webpack');
const TheiaNativeWebpackPlugin = require('@theia/native-webpack-plugin');
const frontend = require('./gen-webpack.config'); const frontend = require('./gen-webpack.config');
const backend = require('./gen-webpack.node.config'); const backend = require('./gen-webpack.node.config');
const { const {
@@ -39,6 +41,27 @@ backend.config.entry['parcel-watcher'] = {
}, },
}; };
// Override Theia native dependency bundler to assign stricter file permissions (chmod 755)
// https://github.com/eclipse-theia/theia/blob/9a52544fb4c1ea1d3d0d6bcbe106b97184279030/dev-packages/native-webpack-plugin/src/native-webpack-plugin.ts#L149
class NativeWebpackPlugin extends TheiaNativeWebpackPlugin {
// Override the method that writes/copies files
async copyExecutable(source, target) {
const targetDirectory = path.dirname(target);
await fs.promises.mkdir(targetDirectory, { recursive: true });
await fs.promises.copyFile(source, target);
await fs.promises.chmod(target, 0o755);
}
}
backend.config.plugins.push(new NativeWebpackPlugin({
out: 'native',
trash: true,
ripgrep: true,
pty: true,
nativeBindings: {
drivelist: 'drivelist/build/Release/drivelist.node',
},
}));
// Use a customized backend main that can enable the file logger in bundled mode. // Use a customized backend main that can enable the file logger in bundled mode.
backend.config.entry['main'] = require.resolve('./arduino-ide-backend-main.js'); backend.config.entry['main'] = require.resolve('./arduino-ide-backend-main.js');

View File

@@ -435,7 +435,6 @@
"autoscroll": "Autoscroll", "autoscroll": "Autoscroll",
"carriageReturn": "Carriage Return", "carriageReturn": "Carriage Return",
"connecting": "Connecting to '{0}' on '{1}'...", "connecting": "Connecting to '{0}' on '{1}'...",
"copyOutput": "Copy Output",
"message": "Message (Enter to send message to '{0}' on '{1}')", "message": "Message (Enter to send message to '{0}' on '{1}')",
"newLine": "New Line", "newLine": "New Line",
"newLineCarriageReturn": "Both NL & CR", "newLineCarriageReturn": "Both NL & CR",