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
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
Cargo is a community build plugin for Lithe. It uses Lithe's native Cargo
tool window and Build Output to build, check, test, clean, and run Rust projects.

**0.1.1 is a preview release.** Native disk-installation and full UI acceptance
**0.1.2 is unreleased preview source.** Native disk-installation and full UI acceptance
are still pending. Automated integration and host compatibility run in this
repository's CI.
The plugin requires a Lithe preview with API 3 `buildSystems: 2`, `settings: 2`,
The plugin requires a Lithe preview with API 3 `buildSystems: 1`, `executableResolution: 1`, `settings: 2`,
`buildProviders: 1` and `serverProcess: 1`. Windows is not supported yet.

## Install
Expand All @@ -15,7 +15,9 @@ Install Rust/Cargo 1.70+ and Node.js 20.3+ first. Node runs the metadata provide
Cargo and rust-analyzer are not bundled. Existing Rust language intelligence
continues to use Lithe's Rust language service.

Download `cargo-build-0.1.1-darwin.zip` from [Releases](https://github.com/Lithe-IDEA/lithe-plugin-cargo/releases).
For this branch, build `dist/cargo-build-0.1.2-darwin.zip` with `node scripts/package.mjs`.
The published 0.1.1 preview remains available from [Releases](https://github.com/Lithe-IDEA/lithe-plugin-cargo/releases)
and keeps its older host requirements.
In Lithe, choose Settings → Plugins → Install from Disk, select the ZIP,
review Cargo/Node and its permissions, and restart. Enable Cargo, open the
Cargo workspace root, then open the Cargo tool window and load the project model.
Expand All @@ -32,7 +34,7 @@ same executable. A missing, non-executable or too-old selection fails visibly
instead of silently choosing a different Cargo installation. The executable's
parent directory is placed first on PATH for companion tools.

Version 0.1.1 requires a preview host with `buildSystems: 2` and `settings: 2`.
Version 0.1.2 requires a preview host with `buildSystems: 1`, `executableResolution: 1` and `settings: 2`.
Its exact tested host revision is recorded in `sdk.lock.json`; older hosts keep
using the compatible 0.1.0 release through the Store. Existing published ZIPs
are immutable and are never replaced.
Expand Down Expand Up @@ -137,3 +139,9 @@ Published ZIP bytes are immutable: fixes require a new version.

The Store index records the repository URL, API requirements, release URL and
archive SHA-256. First inclusion and pre-releases use a reviewed Store pull request.

The 0.1.2 source migrates custom Cargo selection to the shared ordered executable
candidates. Published 0.1.0/0.1.1 preview archives remain immutable. A compatible
host must advertise `executableResolution: 1`; the setting is a candidate ahead
of automatic PATH discovery, with empty values skipped and explicit failures
reported by the host. Maven/Gradle-style automatic candidates need no path setting.
2 changes: 1 addition & 1 deletion io.github.lithe-idea.cargo-build/backend/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
import { createBackend, PluginError } from './vendor/lithe-plugin-sdk/index.mjs';
import { registerCargoProvider } from './provider.mjs';

const backend = createBackend({ name: 'cargo-build', version: '0.1.1' });
const backend = createBackend({ name: 'cargo-build', version: '0.1.2' });
registerCargoProvider(backend, PluginError);
await backend.listen();
10 changes: 6 additions & 4 deletions io.github.lithe-idea.cargo-build/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"schemaVersion": 2,
"id": "io.github.lithe-idea.cargo-build",
"displayName": "Cargo",
"version": "0.1.1",
"version": "0.1.2",
"pluginAPIVersion": 3,
"requires": { "buildProviders": 1, "buildSystems": 2, "serverProcess": 1, "settings": 2 },
"requires": { "buildProviders": 1, "buildSystems": 1, "executableResolution": 1, "serverProcess": 1, "settings": 2 },
"vendor": { "id": "io.github.lithe-idea", "displayName": "Lithe Community", "signatureRequirement": "none" },
"permissions": ["languageServer.launch", "process.build"],
"activationEvents": ["onBuildSystem:cargo"],
Expand All @@ -21,8 +21,10 @@
"displayName": "Cargo",
"detection": { "markers": ["Cargo.toml"], "nesting": "outermost" },
"invocation": {
"executableSetting": "cargoPath",
"executables": [{ "kind": "command", "command": "cargo" }],
"executables": [
{ "id": "selected", "kind": "setting", "settingID": "cargoPath" },
{ "kind": "command", "command": "cargo" }
],
"globalArguments": ["--color", "never"],
"version": { "arguments": ["--version"], "pattern": "cargo (\\d+\\.\\d+\\.\\d+)" },
"minimumVersion": "1.70"
Expand Down
2 changes: 1 addition & 1 deletion sdk.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schemaVersion": 1,
"source": {
"repository": "https://github.com/1lck/Lithe-IDEA",
"revision": "a972d4204ce4c178d0314872119c11db8d435341"
"revision": "d06d5bf9f41729de1051e7f73c1c10648bc3a691"
},
"files": [
{
Expand Down
4 changes: 2 additions & 2 deletions test/core.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { build, core, integrationSkip, workspace } from './support/core.mjs';

test('Core validates the distributable manifest and requires a provider-capable host', { timeout: 15000, skip: integrationSkip }, async () => {
const manifest = JSON.parse(await readFile(join(repository, 'io.github.lithe-idea.cargo-build/plugin.json'), 'utf8'));
const hostCapabilities = { buildSystems: [1, 2], buildProviders: [1], serverProcess: [1], settings: [1, 2] };
const hostCapabilities = { buildSystems: [1, 2], buildProviders: [1], serverProcess: [1], settings: [1, 2], executableResolution: [1] };
assert.equal((await core('plugins.declarative.validate', { manifest, hostCapabilities })).status, 'ok');
const review = await core('plugins.marketplace.installReview', { manifest, hostCapabilities });
assert.equal(review.status, 'ok');
for (const kind of ['runtimeBuildProvider', 'buildSystem']) assert.ok(review.review.programs.some((item) => item.kind === kind));
const oldHost = await core('plugins.declarative.validate', { manifest, hostCapabilities: { ...hostCapabilities, buildSystems: [1] } });
const oldHost = await core('plugins.declarative.validate', { manifest, hostCapabilities: { ...hostCapabilities, executableResolution: [] } });
assert.equal(oldHost.error.code, 'plugin.api.unsupported');
const unsupported = await core('plugins.declarative.validate', { manifest, hostCapabilities: { buildSystems: [1], serverProcess: [1] } });
assert.equal(unsupported.error.code, 'plugin.api.unsupported');
Expand Down
10 changes: 5 additions & 5 deletions test/integration.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ test('packaged provider loads a real Cargo workspace; build/test/run/clean leave
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
await writeFile(tool, `#!/bin/sh\nprintf '%s\\n' "$1" >> ${quote(calls)}\nexec ${quote(discovered.stdout.trim())} "$@"\n`, { mode: 0o755 });
const configured = await build('build.invocationPlan', { root: '.', platform: 'macos', settings: { cargoPath: tool } });
assert.equal(configured.invocation.configuredExecutable, tool);
assert.equal(configured.invocation.executables[0].path, tool);
const automatic = await build('build.invocationPlan', { root: '.', platform: 'macos', settings: { cargoPath: '' } });
assert.equal(automatic.invocation.configuredExecutable, undefined);
assert.deepEqual(automatic.invocation.executables, [{ kind: 'command', command: 'cargo' }]);
assert.equal(automatic.invocation.executables[0].path, null);
assert.deepEqual(automatic.invocation.executables, [{ kind: 'setting', settingID: 'cargoPath', path: null }, { kind: 'command', command: 'cargo' }]);
const built = await buildPackage(join(scratch, 'packages'));
const baseline = await snapshot(built.directory);
const backend = spawn(process.execPath, [join(built.directory, 'backend/main.mjs')], {
Expand All @@ -62,7 +62,7 @@ test('packaged provider loads a real Cargo workspace; build/test/run/clean leave
});
const initialized = await host.initialize({ litheBuild: { versions: [1] } }, pathToFileURL(root).href + '/');
assert.equal(initialized.result.capabilities.experimental.litheBuild.version, 1);
const modelPlan = await build('build.modelPlan', { root: '.', options: { offline: true }, tool: { executable: configured.invocation.configuredExecutable } });
const modelPlan = await build('build.modelPlan', { root: '.', options: { offline: true }, tool: { executable: configured.invocation.executables[0].path } });
const loaded = await host.request(modelPlan.plan.provider.method, modelPlan.plan.provider.params);
assert.equal(loaded.error, undefined, JSON.stringify(loaded.error));
assert.deepEqual(loaded.result, { format: 'litheBuildModel', version: 1, ...JSON.parse(await readFile(join(here, 'fixtures/model.json'))) });
Expand All @@ -74,7 +74,7 @@ test('packaged provider loads a real Cargo workspace; build/test/run/clean leave
// separately hand-written Cargo command lines in this integration test.
const cargo = async (command, request) => {
const { plan } = await build(command, { root: '.', options, ...request });
return runProcess(configured.invocation.configuredExecutable, plan.arguments, {
return runProcess(configured.invocation.executables[0].path, plan.arguments, {
cwd: join(root, plan.workingDirectory), env: { ...process.env, ...plan.environment, CARGO_TARGET_DIR: join(scratch, 'target') },
signal: AbortSignal.timeout(20000), maxOutputBytes: 1024 * 1024
});
Expand Down
Loading