pubm 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/bin/cli.js +130 -62
- package/dist/index.cjs +122 -54
- package/dist/index.js +130 -62
- package/package.json +1 -1
package/README.md
CHANGED
package/bin/cli.js
CHANGED
|
@@ -5249,50 +5249,6 @@ function link2(text, url) {
|
|
|
5249
5249
|
return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
|
|
5250
5250
|
}
|
|
5251
5251
|
|
|
5252
|
-
// src/utils/rollback.ts
|
|
5253
|
-
var rollbacks = [];
|
|
5254
|
-
function addRollback(rollback2, context) {
|
|
5255
|
-
rollbacks.push({ fn: rollback2, ctx: context });
|
|
5256
|
-
}
|
|
5257
|
-
var called = false;
|
|
5258
|
-
async function rollback() {
|
|
5259
|
-
if (called) return void 0;
|
|
5260
|
-
called = true;
|
|
5261
|
-
if (rollbacks.length <= 0) return void 0;
|
|
5262
|
-
console.log("Rollback...");
|
|
5263
|
-
const results = await Promise.allSettled(
|
|
5264
|
-
rollbacks.map(({ fn, ctx }) => fn(ctx))
|
|
5265
|
-
);
|
|
5266
|
-
const failures = results.filter(
|
|
5267
|
-
(r) => r.status === "rejected"
|
|
5268
|
-
);
|
|
5269
|
-
if (failures.length > 0) {
|
|
5270
|
-
for (const failure of failures) {
|
|
5271
|
-
console.error(
|
|
5272
|
-
`Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
|
|
5273
|
-
);
|
|
5274
|
-
}
|
|
5275
|
-
console.log(
|
|
5276
|
-
"Rollback completed with errors. Some operations may require manual recovery."
|
|
5277
|
-
);
|
|
5278
|
-
} else {
|
|
5279
|
-
console.log("Rollback completed");
|
|
5280
|
-
}
|
|
5281
|
-
}
|
|
5282
|
-
|
|
5283
|
-
// src/utils/listr.ts
|
|
5284
|
-
function createListr(...args) {
|
|
5285
|
-
const listr = new Listr(...args);
|
|
5286
|
-
listr.isRoot = () => false;
|
|
5287
|
-
listr.externalSignalHandler = rollback;
|
|
5288
|
-
return listr;
|
|
5289
|
-
}
|
|
5290
|
-
|
|
5291
|
-
// src/utils/package.ts
|
|
5292
|
-
import { readFile as readFile2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
5293
|
-
import path8 from "node:path";
|
|
5294
|
-
import process11 from "node:process";
|
|
5295
|
-
|
|
5296
5252
|
// src/ecosystem/rust.ts
|
|
5297
5253
|
import { readFile, stat as stat2, writeFile } from "node:fs/promises";
|
|
5298
5254
|
import path7 from "node:path";
|
|
@@ -5339,6 +5295,17 @@ var RustEcosystem = class extends Ecosystem {
|
|
|
5339
5295
|
pkg.version = newVersion;
|
|
5340
5296
|
await writeFile(filePath, stringify(cargo));
|
|
5341
5297
|
}
|
|
5298
|
+
async dependencies() {
|
|
5299
|
+
const cargo = await this.readCargoToml();
|
|
5300
|
+
const deps = [];
|
|
5301
|
+
for (const section of ["dependencies", "build-dependencies"]) {
|
|
5302
|
+
const sectionData = cargo[section];
|
|
5303
|
+
if (sectionData) {
|
|
5304
|
+
deps.push(...Object.keys(sectionData));
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
return deps;
|
|
5308
|
+
}
|
|
5342
5309
|
manifestFiles() {
|
|
5343
5310
|
return ["Cargo.toml"];
|
|
5344
5311
|
}
|
|
@@ -5353,7 +5320,96 @@ var RustEcosystem = class extends Ecosystem {
|
|
|
5353
5320
|
}
|
|
5354
5321
|
};
|
|
5355
5322
|
|
|
5323
|
+
// src/utils/crate-graph.ts
|
|
5324
|
+
async function sortCratesByDependencyOrder(cratePaths) {
|
|
5325
|
+
if (cratePaths.length <= 1) return cratePaths;
|
|
5326
|
+
const crateInfos = await Promise.all(
|
|
5327
|
+
cratePaths.map(async (cratePath) => {
|
|
5328
|
+
const eco = new RustEcosystem(cratePath);
|
|
5329
|
+
const name = await eco.packageName();
|
|
5330
|
+
const deps = await eco.dependencies();
|
|
5331
|
+
return { cratePath, name, deps };
|
|
5332
|
+
})
|
|
5333
|
+
);
|
|
5334
|
+
const nameSet = new Set(crateInfos.map((c) => c.name));
|
|
5335
|
+
const nameToPath = new Map(crateInfos.map((c) => [c.name, c.cratePath]));
|
|
5336
|
+
const internalDeps = /* @__PURE__ */ new Map();
|
|
5337
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
5338
|
+
for (const name of nameSet) {
|
|
5339
|
+
inDegree.set(name, 0);
|
|
5340
|
+
}
|
|
5341
|
+
for (const crate of crateInfos) {
|
|
5342
|
+
const filtered = crate.deps.filter((d2) => nameSet.has(d2));
|
|
5343
|
+
internalDeps.set(crate.name, filtered);
|
|
5344
|
+
for (const _dep of filtered) {
|
|
5345
|
+
inDegree.set(crate.name, (inDegree.get(crate.name) ?? 0) + 1);
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
const queue = [];
|
|
5349
|
+
for (const [name, degree] of inDegree) {
|
|
5350
|
+
if (degree === 0) queue.push(name);
|
|
5351
|
+
}
|
|
5352
|
+
const sorted = [];
|
|
5353
|
+
while (queue.length > 0) {
|
|
5354
|
+
const current = queue.shift();
|
|
5355
|
+
sorted.push(current);
|
|
5356
|
+
for (const [name, deps] of internalDeps) {
|
|
5357
|
+
if (deps.includes(current)) {
|
|
5358
|
+
const newDegree = (inDegree.get(name) ?? 0) - 1;
|
|
5359
|
+
inDegree.set(name, newDegree);
|
|
5360
|
+
if (newDegree === 0) queue.push(name);
|
|
5361
|
+
}
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5364
|
+
if (sorted.length !== nameSet.size) {
|
|
5365
|
+
throw new Error("Circular dependency detected among configured crates");
|
|
5366
|
+
}
|
|
5367
|
+
return sorted.map((name) => nameToPath.get(name));
|
|
5368
|
+
}
|
|
5369
|
+
|
|
5370
|
+
// src/utils/rollback.ts
|
|
5371
|
+
var rollbacks = [];
|
|
5372
|
+
function addRollback(rollback2, context) {
|
|
5373
|
+
rollbacks.push({ fn: rollback2, ctx: context });
|
|
5374
|
+
}
|
|
5375
|
+
var called = false;
|
|
5376
|
+
async function rollback() {
|
|
5377
|
+
if (called) return void 0;
|
|
5378
|
+
called = true;
|
|
5379
|
+
if (rollbacks.length <= 0) return void 0;
|
|
5380
|
+
console.log("Rollback...");
|
|
5381
|
+
const results = await Promise.allSettled(
|
|
5382
|
+
rollbacks.map(({ fn, ctx }) => fn(ctx))
|
|
5383
|
+
);
|
|
5384
|
+
const failures = results.filter(
|
|
5385
|
+
(r) => r.status === "rejected"
|
|
5386
|
+
);
|
|
5387
|
+
if (failures.length > 0) {
|
|
5388
|
+
for (const failure of failures) {
|
|
5389
|
+
console.error(
|
|
5390
|
+
`Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
|
|
5391
|
+
);
|
|
5392
|
+
}
|
|
5393
|
+
console.log(
|
|
5394
|
+
"Rollback completed with errors. Some operations may require manual recovery."
|
|
5395
|
+
);
|
|
5396
|
+
} else {
|
|
5397
|
+
console.log("Rollback completed");
|
|
5398
|
+
}
|
|
5399
|
+
}
|
|
5400
|
+
|
|
5401
|
+
// src/utils/listr.ts
|
|
5402
|
+
function createListr(...args) {
|
|
5403
|
+
const listr = new Listr(...args);
|
|
5404
|
+
listr.isRoot = () => false;
|
|
5405
|
+
listr.externalSignalHandler = rollback;
|
|
5406
|
+
return listr;
|
|
5407
|
+
}
|
|
5408
|
+
|
|
5356
5409
|
// src/utils/package.ts
|
|
5410
|
+
import { readFile as readFile2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
5411
|
+
import path8 from "node:path";
|
|
5412
|
+
import process11 from "node:process";
|
|
5357
5413
|
var cachedPackageJson = {};
|
|
5358
5414
|
var cachedJsrJson = {};
|
|
5359
5415
|
function patchCachedJsrJson(contents, { cwd = process11.cwd() } = {}) {
|
|
@@ -5588,7 +5644,7 @@ function collectRegistries(ctx) {
|
|
|
5588
5644
|
|
|
5589
5645
|
// src/registry/crates.ts
|
|
5590
5646
|
import path9 from "node:path";
|
|
5591
|
-
import { exec as exec3 } from "tinyexec";
|
|
5647
|
+
import { exec as exec3, NonZeroExitError } from "tinyexec";
|
|
5592
5648
|
|
|
5593
5649
|
// src/registry/registry.ts
|
|
5594
5650
|
var Registry = class {
|
|
@@ -5670,9 +5726,10 @@ var CratesRegistry = class extends Registry {
|
|
|
5670
5726
|
await exec3("cargo", args, { throwOnError: true });
|
|
5671
5727
|
return true;
|
|
5672
5728
|
} catch (error) {
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5729
|
+
const stderr = error instanceof NonZeroExitError ? error.output?.stderr : void 0;
|
|
5730
|
+
const message = stderr ? `Failed to run \`cargo publish\`:
|
|
5731
|
+
${stderr}` : "Failed to run `cargo publish`";
|
|
5732
|
+
throw new CratesError(message, { cause: error });
|
|
5676
5733
|
}
|
|
5677
5734
|
}
|
|
5678
5735
|
async isPublished() {
|
|
@@ -5767,7 +5824,7 @@ import { ListrEnquirerPromptAdapter } from "@listr2/prompt-adapter-enquirer";
|
|
|
5767
5824
|
import npmCli from "@npmcli/promise-spawn";
|
|
5768
5825
|
|
|
5769
5826
|
// src/registry/jsr.ts
|
|
5770
|
-
import { exec as exec4, NonZeroExitError } from "tinyexec";
|
|
5827
|
+
import { exec as exec4, NonZeroExitError as NonZeroExitError2 } from "tinyexec";
|
|
5771
5828
|
|
|
5772
5829
|
// src/utils/db.ts
|
|
5773
5830
|
import { createCipheriv, createDecipheriv, createHash } from "node:crypto";
|
|
@@ -5946,7 +6003,7 @@ var JsrRegisry = class extends Registry {
|
|
|
5946
6003
|
this.packageCreationUrls = void 0;
|
|
5947
6004
|
return true;
|
|
5948
6005
|
} catch (error) {
|
|
5949
|
-
const stderr = error instanceof
|
|
6006
|
+
const stderr = error instanceof NonZeroExitError2 ? error.output?.stderr : void 0;
|
|
5950
6007
|
if (stderr?.includes("don't exist")) {
|
|
5951
6008
|
const urls = [...stderr.matchAll(/https:\/\/jsr\.io\/new\S+/g)].map(
|
|
5952
6009
|
(m) => m[0]
|
|
@@ -6206,7 +6263,7 @@ async function jsrRegistry() {
|
|
|
6206
6263
|
}
|
|
6207
6264
|
|
|
6208
6265
|
// src/registry/npm.ts
|
|
6209
|
-
import { exec as exec5, NonZeroExitError as
|
|
6266
|
+
import { exec as exec5, NonZeroExitError as NonZeroExitError3 } from "tinyexec";
|
|
6210
6267
|
var NpmError = class extends AbstractError {
|
|
6211
6268
|
constructor() {
|
|
6212
6269
|
super(...arguments);
|
|
@@ -6263,7 +6320,7 @@ var NpmRegistry = class extends Registry {
|
|
|
6263
6320
|
await this.npm(["whoami"]);
|
|
6264
6321
|
return true;
|
|
6265
6322
|
} catch (error) {
|
|
6266
|
-
if (error instanceof
|
|
6323
|
+
if (error instanceof NonZeroExitError3) {
|
|
6267
6324
|
return false;
|
|
6268
6325
|
}
|
|
6269
6326
|
throw new NpmError("Failed to run `npm whoami`", { cause: error });
|
|
@@ -6341,7 +6398,7 @@ var NpmRegistry = class extends Registry {
|
|
|
6341
6398
|
await this.npm(["publish", "--provenance", "--access", "public"]);
|
|
6342
6399
|
return true;
|
|
6343
6400
|
} catch (error) {
|
|
6344
|
-
if (error instanceof
|
|
6401
|
+
if (error instanceof NonZeroExitError3 && error.output?.stderr.includes("EOTP")) {
|
|
6345
6402
|
return false;
|
|
6346
6403
|
}
|
|
6347
6404
|
throw this.classifyPublishError(error);
|
|
@@ -6353,7 +6410,7 @@ var NpmRegistry = class extends Registry {
|
|
|
6353
6410
|
await this.npm(args);
|
|
6354
6411
|
return true;
|
|
6355
6412
|
} catch (error) {
|
|
6356
|
-
if (error instanceof
|
|
6413
|
+
if (error instanceof NonZeroExitError3 && error.output?.stderr.includes("EOTP")) {
|
|
6357
6414
|
return false;
|
|
6358
6415
|
}
|
|
6359
6416
|
throw this.classifyPublishError(error);
|
|
@@ -6369,7 +6426,7 @@ var NpmRegistry = class extends Registry {
|
|
|
6369
6426
|
};
|
|
6370
6427
|
}
|
|
6371
6428
|
classifyPublishError(error) {
|
|
6372
|
-
if (error instanceof
|
|
6429
|
+
if (error instanceof NonZeroExitError3) {
|
|
6373
6430
|
const stderr = error.output?.stderr ?? "";
|
|
6374
6431
|
if (stderr.includes("EOTP")) {
|
|
6375
6432
|
return new NpmError("OTP required for publishing", { cause: error });
|
|
@@ -7108,13 +7165,24 @@ function registryTask(registry) {
|
|
|
7108
7165
|
return npmPublishTasks;
|
|
7109
7166
|
}
|
|
7110
7167
|
}
|
|
7111
|
-
function collectPublishTasks(ctx) {
|
|
7168
|
+
async function collectPublishTasks(ctx) {
|
|
7112
7169
|
if (ctx.packages?.length) {
|
|
7113
|
-
|
|
7114
|
-
(pkg) => pkg.registries.map(
|
|
7115
|
-
(reg) => reg === "crates" ? createCratesPublishTask(pkg.path) : registryTask(reg)
|
|
7116
|
-
)
|
|
7170
|
+
const nonCratesTasks = ctx.packages.flatMap(
|
|
7171
|
+
(pkg) => pkg.registries.filter((reg) => reg !== "crates").map((reg) => registryTask(reg))
|
|
7117
7172
|
);
|
|
7173
|
+
const cratesPaths = ctx.packages.filter((pkg) => pkg.registries.includes("crates")).map((pkg) => pkg.path);
|
|
7174
|
+
if (cratesPaths.length === 0) {
|
|
7175
|
+
return nonCratesTasks;
|
|
7176
|
+
}
|
|
7177
|
+
const sortedPaths = await sortCratesByDependencyOrder(cratesPaths);
|
|
7178
|
+
const sequentialCratesTask = {
|
|
7179
|
+
title: "Publishing to crates.io (sequential)",
|
|
7180
|
+
task: (_ctx, task) => task.newListr(
|
|
7181
|
+
sortedPaths.map((p) => createCratesPublishTask(p)),
|
|
7182
|
+
{ concurrent: false }
|
|
7183
|
+
)
|
|
7184
|
+
};
|
|
7185
|
+
return [...nonCratesTasks, sequentialCratesTask];
|
|
7118
7186
|
}
|
|
7119
7187
|
return collectRegistries(ctx).map(registryTask);
|
|
7120
7188
|
}
|
|
@@ -7136,7 +7204,7 @@ async function run(options) {
|
|
|
7136
7204
|
await createListr(
|
|
7137
7205
|
options.publishOnly ? {
|
|
7138
7206
|
title: "Publishing",
|
|
7139
|
-
task: (ctx2, parentTask) => parentTask.newListr(collectPublishTasks(ctx2), {
|
|
7207
|
+
task: async (ctx2, parentTask) => parentTask.newListr(await collectPublishTasks(ctx2), {
|
|
7140
7208
|
concurrent: true
|
|
7141
7209
|
})
|
|
7142
7210
|
} : [
|
|
@@ -7225,7 +7293,7 @@ async function run(options) {
|
|
|
7225
7293
|
{
|
|
7226
7294
|
skip: (ctx2) => options.skipPublish || !!ctx2.preview,
|
|
7227
7295
|
title: "Publishing",
|
|
7228
|
-
task: (ctx2, parentTask) => parentTask.newListr(collectPublishTasks(ctx2), {
|
|
7296
|
+
task: async (ctx2, parentTask) => parentTask.newListr(await collectPublishTasks(ctx2), {
|
|
7229
7297
|
concurrent: true
|
|
7230
7298
|
})
|
|
7231
7299
|
},
|
package/dist/index.cjs
CHANGED
|
@@ -4814,50 +4814,6 @@ function link2(text, url) {
|
|
|
4814
4814
|
return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
|
|
4815
4815
|
}
|
|
4816
4816
|
|
|
4817
|
-
// src/utils/rollback.ts
|
|
4818
|
-
var rollbacks = [];
|
|
4819
|
-
function addRollback(rollback2, context) {
|
|
4820
|
-
rollbacks.push({ fn: rollback2, ctx: context });
|
|
4821
|
-
}
|
|
4822
|
-
var called = false;
|
|
4823
|
-
async function rollback() {
|
|
4824
|
-
if (called) return void 0;
|
|
4825
|
-
called = true;
|
|
4826
|
-
if (rollbacks.length <= 0) return void 0;
|
|
4827
|
-
console.log("Rollback...");
|
|
4828
|
-
const results = await Promise.allSettled(
|
|
4829
|
-
rollbacks.map(({ fn, ctx }) => fn(ctx))
|
|
4830
|
-
);
|
|
4831
|
-
const failures = results.filter(
|
|
4832
|
-
(r) => r.status === "rejected"
|
|
4833
|
-
);
|
|
4834
|
-
if (failures.length > 0) {
|
|
4835
|
-
for (const failure of failures) {
|
|
4836
|
-
console.error(
|
|
4837
|
-
`Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
|
|
4838
|
-
);
|
|
4839
|
-
}
|
|
4840
|
-
console.log(
|
|
4841
|
-
"Rollback completed with errors. Some operations may require manual recovery."
|
|
4842
|
-
);
|
|
4843
|
-
} else {
|
|
4844
|
-
console.log("Rollback completed");
|
|
4845
|
-
}
|
|
4846
|
-
}
|
|
4847
|
-
|
|
4848
|
-
// src/utils/listr.ts
|
|
4849
|
-
function createListr(...args) {
|
|
4850
|
-
const listr = new Listr(...args);
|
|
4851
|
-
listr.isRoot = () => false;
|
|
4852
|
-
listr.externalSignalHandler = rollback;
|
|
4853
|
-
return listr;
|
|
4854
|
-
}
|
|
4855
|
-
|
|
4856
|
-
// src/utils/package.ts
|
|
4857
|
-
var import_promises3 = require("fs/promises");
|
|
4858
|
-
var import_node_path3 = __toESM(require("path"), 1);
|
|
4859
|
-
var import_node_process5 = __toESM(require("process"), 1);
|
|
4860
|
-
|
|
4861
4817
|
// src/ecosystem/rust.ts
|
|
4862
4818
|
var import_promises2 = require("fs/promises");
|
|
4863
4819
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
@@ -4904,6 +4860,17 @@ var RustEcosystem = class extends Ecosystem {
|
|
|
4904
4860
|
pkg.version = newVersion;
|
|
4905
4861
|
await (0, import_promises2.writeFile)(filePath, (0, import_smol_toml.stringify)(cargo));
|
|
4906
4862
|
}
|
|
4863
|
+
async dependencies() {
|
|
4864
|
+
const cargo = await this.readCargoToml();
|
|
4865
|
+
const deps = [];
|
|
4866
|
+
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4867
|
+
const sectionData = cargo[section];
|
|
4868
|
+
if (sectionData) {
|
|
4869
|
+
deps.push(...Object.keys(sectionData));
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
return deps;
|
|
4873
|
+
}
|
|
4907
4874
|
manifestFiles() {
|
|
4908
4875
|
return ["Cargo.toml"];
|
|
4909
4876
|
}
|
|
@@ -4918,7 +4885,96 @@ var RustEcosystem = class extends Ecosystem {
|
|
|
4918
4885
|
}
|
|
4919
4886
|
};
|
|
4920
4887
|
|
|
4888
|
+
// src/utils/crate-graph.ts
|
|
4889
|
+
async function sortCratesByDependencyOrder(cratePaths) {
|
|
4890
|
+
if (cratePaths.length <= 1) return cratePaths;
|
|
4891
|
+
const crateInfos = await Promise.all(
|
|
4892
|
+
cratePaths.map(async (cratePath) => {
|
|
4893
|
+
const eco = new RustEcosystem(cratePath);
|
|
4894
|
+
const name = await eco.packageName();
|
|
4895
|
+
const deps = await eco.dependencies();
|
|
4896
|
+
return { cratePath, name, deps };
|
|
4897
|
+
})
|
|
4898
|
+
);
|
|
4899
|
+
const nameSet = new Set(crateInfos.map((c) => c.name));
|
|
4900
|
+
const nameToPath = new Map(crateInfos.map((c) => [c.name, c.cratePath]));
|
|
4901
|
+
const internalDeps = /* @__PURE__ */ new Map();
|
|
4902
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
4903
|
+
for (const name of nameSet) {
|
|
4904
|
+
inDegree.set(name, 0);
|
|
4905
|
+
}
|
|
4906
|
+
for (const crate of crateInfos) {
|
|
4907
|
+
const filtered = crate.deps.filter((d2) => nameSet.has(d2));
|
|
4908
|
+
internalDeps.set(crate.name, filtered);
|
|
4909
|
+
for (const _dep of filtered) {
|
|
4910
|
+
inDegree.set(crate.name, (inDegree.get(crate.name) ?? 0) + 1);
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4913
|
+
const queue = [];
|
|
4914
|
+
for (const [name, degree] of inDegree) {
|
|
4915
|
+
if (degree === 0) queue.push(name);
|
|
4916
|
+
}
|
|
4917
|
+
const sorted = [];
|
|
4918
|
+
while (queue.length > 0) {
|
|
4919
|
+
const current = queue.shift();
|
|
4920
|
+
sorted.push(current);
|
|
4921
|
+
for (const [name, deps] of internalDeps) {
|
|
4922
|
+
if (deps.includes(current)) {
|
|
4923
|
+
const newDegree = (inDegree.get(name) ?? 0) - 1;
|
|
4924
|
+
inDegree.set(name, newDegree);
|
|
4925
|
+
if (newDegree === 0) queue.push(name);
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
if (sorted.length !== nameSet.size) {
|
|
4930
|
+
throw new Error("Circular dependency detected among configured crates");
|
|
4931
|
+
}
|
|
4932
|
+
return sorted.map((name) => nameToPath.get(name));
|
|
4933
|
+
}
|
|
4934
|
+
|
|
4935
|
+
// src/utils/rollback.ts
|
|
4936
|
+
var rollbacks = [];
|
|
4937
|
+
function addRollback(rollback2, context) {
|
|
4938
|
+
rollbacks.push({ fn: rollback2, ctx: context });
|
|
4939
|
+
}
|
|
4940
|
+
var called = false;
|
|
4941
|
+
async function rollback() {
|
|
4942
|
+
if (called) return void 0;
|
|
4943
|
+
called = true;
|
|
4944
|
+
if (rollbacks.length <= 0) return void 0;
|
|
4945
|
+
console.log("Rollback...");
|
|
4946
|
+
const results = await Promise.allSettled(
|
|
4947
|
+
rollbacks.map(({ fn, ctx }) => fn(ctx))
|
|
4948
|
+
);
|
|
4949
|
+
const failures = results.filter(
|
|
4950
|
+
(r) => r.status === "rejected"
|
|
4951
|
+
);
|
|
4952
|
+
if (failures.length > 0) {
|
|
4953
|
+
for (const failure of failures) {
|
|
4954
|
+
console.error(
|
|
4955
|
+
`Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
|
|
4956
|
+
);
|
|
4957
|
+
}
|
|
4958
|
+
console.log(
|
|
4959
|
+
"Rollback completed with errors. Some operations may require manual recovery."
|
|
4960
|
+
);
|
|
4961
|
+
} else {
|
|
4962
|
+
console.log("Rollback completed");
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4965
|
+
|
|
4966
|
+
// src/utils/listr.ts
|
|
4967
|
+
function createListr(...args) {
|
|
4968
|
+
const listr = new Listr(...args);
|
|
4969
|
+
listr.isRoot = () => false;
|
|
4970
|
+
listr.externalSignalHandler = rollback;
|
|
4971
|
+
return listr;
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4921
4974
|
// src/utils/package.ts
|
|
4975
|
+
var import_promises3 = require("fs/promises");
|
|
4976
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
4977
|
+
var import_node_process5 = __toESM(require("process"), 1);
|
|
4922
4978
|
var cachedPackageJson = {};
|
|
4923
4979
|
var cachedJsrJson = {};
|
|
4924
4980
|
function patchCachedJsrJson(contents, { cwd = import_node_process5.default.cwd() } = {}) {
|
|
@@ -5235,9 +5291,10 @@ var CratesRegistry = class extends Registry {
|
|
|
5235
5291
|
await (0, import_tinyexec2.exec)("cargo", args, { throwOnError: true });
|
|
5236
5292
|
return true;
|
|
5237
5293
|
} catch (error) {
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5294
|
+
const stderr = error instanceof import_tinyexec2.NonZeroExitError ? error.output?.stderr : void 0;
|
|
5295
|
+
const message = stderr ? `Failed to run \`cargo publish\`:
|
|
5296
|
+
${stderr}` : "Failed to run `cargo publish`";
|
|
5297
|
+
throw new CratesError(message, { cause: error });
|
|
5241
5298
|
}
|
|
5242
5299
|
}
|
|
5243
5300
|
async isPublished() {
|
|
@@ -6676,13 +6733,24 @@ function registryTask(registry) {
|
|
|
6676
6733
|
return npmPublishTasks;
|
|
6677
6734
|
}
|
|
6678
6735
|
}
|
|
6679
|
-
function collectPublishTasks(ctx) {
|
|
6736
|
+
async function collectPublishTasks(ctx) {
|
|
6680
6737
|
if (ctx.packages?.length) {
|
|
6681
|
-
|
|
6682
|
-
(pkg) => pkg.registries.map(
|
|
6683
|
-
(reg) => reg === "crates" ? createCratesPublishTask(pkg.path) : registryTask(reg)
|
|
6684
|
-
)
|
|
6738
|
+
const nonCratesTasks = ctx.packages.flatMap(
|
|
6739
|
+
(pkg) => pkg.registries.filter((reg) => reg !== "crates").map((reg) => registryTask(reg))
|
|
6685
6740
|
);
|
|
6741
|
+
const cratesPaths = ctx.packages.filter((pkg) => pkg.registries.includes("crates")).map((pkg) => pkg.path);
|
|
6742
|
+
if (cratesPaths.length === 0) {
|
|
6743
|
+
return nonCratesTasks;
|
|
6744
|
+
}
|
|
6745
|
+
const sortedPaths = await sortCratesByDependencyOrder(cratesPaths);
|
|
6746
|
+
const sequentialCratesTask = {
|
|
6747
|
+
title: "Publishing to crates.io (sequential)",
|
|
6748
|
+
task: (_ctx, task) => task.newListr(
|
|
6749
|
+
sortedPaths.map((p) => createCratesPublishTask(p)),
|
|
6750
|
+
{ concurrent: false }
|
|
6751
|
+
)
|
|
6752
|
+
};
|
|
6753
|
+
return [...nonCratesTasks, sequentialCratesTask];
|
|
6686
6754
|
}
|
|
6687
6755
|
return collectRegistries(ctx).map(registryTask);
|
|
6688
6756
|
}
|
|
@@ -6704,7 +6772,7 @@ async function run(options) {
|
|
|
6704
6772
|
await createListr(
|
|
6705
6773
|
options.publishOnly ? {
|
|
6706
6774
|
title: "Publishing",
|
|
6707
|
-
task: (ctx2, parentTask) => parentTask.newListr(collectPublishTasks(ctx2), {
|
|
6775
|
+
task: async (ctx2, parentTask) => parentTask.newListr(await collectPublishTasks(ctx2), {
|
|
6708
6776
|
concurrent: true
|
|
6709
6777
|
})
|
|
6710
6778
|
} : [
|
|
@@ -6793,7 +6861,7 @@ async function run(options) {
|
|
|
6793
6861
|
{
|
|
6794
6862
|
skip: (ctx2) => options.skipPublish || !!ctx2.preview,
|
|
6795
6863
|
title: "Publishing",
|
|
6796
|
-
task: (ctx2, parentTask) => parentTask.newListr(collectPublishTasks(ctx2), {
|
|
6864
|
+
task: async (ctx2, parentTask) => parentTask.newListr(await collectPublishTasks(ctx2), {
|
|
6797
6865
|
concurrent: true
|
|
6798
6866
|
})
|
|
6799
6867
|
},
|
package/dist/index.js
CHANGED
|
@@ -4781,50 +4781,6 @@ function link2(text, url) {
|
|
|
4781
4781
|
return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
|
|
4782
4782
|
}
|
|
4783
4783
|
|
|
4784
|
-
// src/utils/rollback.ts
|
|
4785
|
-
var rollbacks = [];
|
|
4786
|
-
function addRollback(rollback2, context) {
|
|
4787
|
-
rollbacks.push({ fn: rollback2, ctx: context });
|
|
4788
|
-
}
|
|
4789
|
-
var called = false;
|
|
4790
|
-
async function rollback() {
|
|
4791
|
-
if (called) return void 0;
|
|
4792
|
-
called = true;
|
|
4793
|
-
if (rollbacks.length <= 0) return void 0;
|
|
4794
|
-
console.log("Rollback...");
|
|
4795
|
-
const results = await Promise.allSettled(
|
|
4796
|
-
rollbacks.map(({ fn, ctx }) => fn(ctx))
|
|
4797
|
-
);
|
|
4798
|
-
const failures = results.filter(
|
|
4799
|
-
(r) => r.status === "rejected"
|
|
4800
|
-
);
|
|
4801
|
-
if (failures.length > 0) {
|
|
4802
|
-
for (const failure of failures) {
|
|
4803
|
-
console.error(
|
|
4804
|
-
`Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
|
|
4805
|
-
);
|
|
4806
|
-
}
|
|
4807
|
-
console.log(
|
|
4808
|
-
"Rollback completed with errors. Some operations may require manual recovery."
|
|
4809
|
-
);
|
|
4810
|
-
} else {
|
|
4811
|
-
console.log("Rollback completed");
|
|
4812
|
-
}
|
|
4813
|
-
}
|
|
4814
|
-
|
|
4815
|
-
// src/utils/listr.ts
|
|
4816
|
-
function createListr(...args) {
|
|
4817
|
-
const listr = new Listr(...args);
|
|
4818
|
-
listr.isRoot = () => false;
|
|
4819
|
-
listr.externalSignalHandler = rollback;
|
|
4820
|
-
return listr;
|
|
4821
|
-
}
|
|
4822
|
-
|
|
4823
|
-
// src/utils/package.ts
|
|
4824
|
-
import { readFile as readFile2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
4825
|
-
import path3 from "node:path";
|
|
4826
|
-
import process7 from "node:process";
|
|
4827
|
-
|
|
4828
4784
|
// src/ecosystem/rust.ts
|
|
4829
4785
|
import { readFile, stat as stat2, writeFile } from "node:fs/promises";
|
|
4830
4786
|
import path2 from "node:path";
|
|
@@ -4871,6 +4827,17 @@ var RustEcosystem = class extends Ecosystem {
|
|
|
4871
4827
|
pkg.version = newVersion;
|
|
4872
4828
|
await writeFile(filePath, stringify(cargo));
|
|
4873
4829
|
}
|
|
4830
|
+
async dependencies() {
|
|
4831
|
+
const cargo = await this.readCargoToml();
|
|
4832
|
+
const deps = [];
|
|
4833
|
+
for (const section of ["dependencies", "build-dependencies"]) {
|
|
4834
|
+
const sectionData = cargo[section];
|
|
4835
|
+
if (sectionData) {
|
|
4836
|
+
deps.push(...Object.keys(sectionData));
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
return deps;
|
|
4840
|
+
}
|
|
4874
4841
|
manifestFiles() {
|
|
4875
4842
|
return ["Cargo.toml"];
|
|
4876
4843
|
}
|
|
@@ -4885,7 +4852,96 @@ var RustEcosystem = class extends Ecosystem {
|
|
|
4885
4852
|
}
|
|
4886
4853
|
};
|
|
4887
4854
|
|
|
4855
|
+
// src/utils/crate-graph.ts
|
|
4856
|
+
async function sortCratesByDependencyOrder(cratePaths) {
|
|
4857
|
+
if (cratePaths.length <= 1) return cratePaths;
|
|
4858
|
+
const crateInfos = await Promise.all(
|
|
4859
|
+
cratePaths.map(async (cratePath) => {
|
|
4860
|
+
const eco = new RustEcosystem(cratePath);
|
|
4861
|
+
const name = await eco.packageName();
|
|
4862
|
+
const deps = await eco.dependencies();
|
|
4863
|
+
return { cratePath, name, deps };
|
|
4864
|
+
})
|
|
4865
|
+
);
|
|
4866
|
+
const nameSet = new Set(crateInfos.map((c) => c.name));
|
|
4867
|
+
const nameToPath = new Map(crateInfos.map((c) => [c.name, c.cratePath]));
|
|
4868
|
+
const internalDeps = /* @__PURE__ */ new Map();
|
|
4869
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
4870
|
+
for (const name of nameSet) {
|
|
4871
|
+
inDegree.set(name, 0);
|
|
4872
|
+
}
|
|
4873
|
+
for (const crate of crateInfos) {
|
|
4874
|
+
const filtered = crate.deps.filter((d2) => nameSet.has(d2));
|
|
4875
|
+
internalDeps.set(crate.name, filtered);
|
|
4876
|
+
for (const _dep of filtered) {
|
|
4877
|
+
inDegree.set(crate.name, (inDegree.get(crate.name) ?? 0) + 1);
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4880
|
+
const queue = [];
|
|
4881
|
+
for (const [name, degree] of inDegree) {
|
|
4882
|
+
if (degree === 0) queue.push(name);
|
|
4883
|
+
}
|
|
4884
|
+
const sorted = [];
|
|
4885
|
+
while (queue.length > 0) {
|
|
4886
|
+
const current = queue.shift();
|
|
4887
|
+
sorted.push(current);
|
|
4888
|
+
for (const [name, deps] of internalDeps) {
|
|
4889
|
+
if (deps.includes(current)) {
|
|
4890
|
+
const newDegree = (inDegree.get(name) ?? 0) - 1;
|
|
4891
|
+
inDegree.set(name, newDegree);
|
|
4892
|
+
if (newDegree === 0) queue.push(name);
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
}
|
|
4896
|
+
if (sorted.length !== nameSet.size) {
|
|
4897
|
+
throw new Error("Circular dependency detected among configured crates");
|
|
4898
|
+
}
|
|
4899
|
+
return sorted.map((name) => nameToPath.get(name));
|
|
4900
|
+
}
|
|
4901
|
+
|
|
4902
|
+
// src/utils/rollback.ts
|
|
4903
|
+
var rollbacks = [];
|
|
4904
|
+
function addRollback(rollback2, context) {
|
|
4905
|
+
rollbacks.push({ fn: rollback2, ctx: context });
|
|
4906
|
+
}
|
|
4907
|
+
var called = false;
|
|
4908
|
+
async function rollback() {
|
|
4909
|
+
if (called) return void 0;
|
|
4910
|
+
called = true;
|
|
4911
|
+
if (rollbacks.length <= 0) return void 0;
|
|
4912
|
+
console.log("Rollback...");
|
|
4913
|
+
const results = await Promise.allSettled(
|
|
4914
|
+
rollbacks.map(({ fn, ctx }) => fn(ctx))
|
|
4915
|
+
);
|
|
4916
|
+
const failures = results.filter(
|
|
4917
|
+
(r) => r.status === "rejected"
|
|
4918
|
+
);
|
|
4919
|
+
if (failures.length > 0) {
|
|
4920
|
+
for (const failure of failures) {
|
|
4921
|
+
console.error(
|
|
4922
|
+
`Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
|
|
4923
|
+
);
|
|
4924
|
+
}
|
|
4925
|
+
console.log(
|
|
4926
|
+
"Rollback completed with errors. Some operations may require manual recovery."
|
|
4927
|
+
);
|
|
4928
|
+
} else {
|
|
4929
|
+
console.log("Rollback completed");
|
|
4930
|
+
}
|
|
4931
|
+
}
|
|
4932
|
+
|
|
4933
|
+
// src/utils/listr.ts
|
|
4934
|
+
function createListr(...args) {
|
|
4935
|
+
const listr = new Listr(...args);
|
|
4936
|
+
listr.isRoot = () => false;
|
|
4937
|
+
listr.externalSignalHandler = rollback;
|
|
4938
|
+
return listr;
|
|
4939
|
+
}
|
|
4940
|
+
|
|
4888
4941
|
// src/utils/package.ts
|
|
4942
|
+
import { readFile as readFile2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
4943
|
+
import path3 from "node:path";
|
|
4944
|
+
import process7 from "node:process";
|
|
4889
4945
|
var cachedPackageJson = {};
|
|
4890
4946
|
var cachedJsrJson = {};
|
|
4891
4947
|
function patchCachedJsrJson(contents, { cwd = process7.cwd() } = {}) {
|
|
@@ -5120,7 +5176,7 @@ function collectRegistries(ctx) {
|
|
|
5120
5176
|
|
|
5121
5177
|
// src/registry/crates.ts
|
|
5122
5178
|
import path4 from "node:path";
|
|
5123
|
-
import { exec as exec3 } from "tinyexec";
|
|
5179
|
+
import { exec as exec3, NonZeroExitError } from "tinyexec";
|
|
5124
5180
|
|
|
5125
5181
|
// src/registry/registry.ts
|
|
5126
5182
|
var Registry = class {
|
|
@@ -5202,9 +5258,10 @@ var CratesRegistry = class extends Registry {
|
|
|
5202
5258
|
await exec3("cargo", args, { throwOnError: true });
|
|
5203
5259
|
return true;
|
|
5204
5260
|
} catch (error) {
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5261
|
+
const stderr = error instanceof NonZeroExitError ? error.output?.stderr : void 0;
|
|
5262
|
+
const message = stderr ? `Failed to run \`cargo publish\`:
|
|
5263
|
+
${stderr}` : "Failed to run `cargo publish`";
|
|
5264
|
+
throw new CratesError(message, { cause: error });
|
|
5208
5265
|
}
|
|
5209
5266
|
}
|
|
5210
5267
|
async isPublished() {
|
|
@@ -5299,7 +5356,7 @@ import { ListrEnquirerPromptAdapter } from "@listr2/prompt-adapter-enquirer";
|
|
|
5299
5356
|
import npmCli from "@npmcli/promise-spawn";
|
|
5300
5357
|
|
|
5301
5358
|
// src/registry/jsr.ts
|
|
5302
|
-
import { exec as exec4, NonZeroExitError } from "tinyexec";
|
|
5359
|
+
import { exec as exec4, NonZeroExitError as NonZeroExitError2 } from "tinyexec";
|
|
5303
5360
|
|
|
5304
5361
|
// src/utils/db.ts
|
|
5305
5362
|
import { createCipheriv, createDecipheriv, createHash } from "node:crypto";
|
|
@@ -5478,7 +5535,7 @@ var JsrRegisry = class extends Registry {
|
|
|
5478
5535
|
this.packageCreationUrls = void 0;
|
|
5479
5536
|
return true;
|
|
5480
5537
|
} catch (error) {
|
|
5481
|
-
const stderr = error instanceof
|
|
5538
|
+
const stderr = error instanceof NonZeroExitError2 ? error.output?.stderr : void 0;
|
|
5482
5539
|
if (stderr?.includes("don't exist")) {
|
|
5483
5540
|
const urls = [...stderr.matchAll(/https:\/\/jsr\.io\/new\S+/g)].map(
|
|
5484
5541
|
(m) => m[0]
|
|
@@ -5738,7 +5795,7 @@ async function jsrRegistry() {
|
|
|
5738
5795
|
}
|
|
5739
5796
|
|
|
5740
5797
|
// src/registry/npm.ts
|
|
5741
|
-
import { exec as exec5, NonZeroExitError as
|
|
5798
|
+
import { exec as exec5, NonZeroExitError as NonZeroExitError3 } from "tinyexec";
|
|
5742
5799
|
var NpmError = class extends AbstractError {
|
|
5743
5800
|
constructor() {
|
|
5744
5801
|
super(...arguments);
|
|
@@ -5795,7 +5852,7 @@ var NpmRegistry = class extends Registry {
|
|
|
5795
5852
|
await this.npm(["whoami"]);
|
|
5796
5853
|
return true;
|
|
5797
5854
|
} catch (error) {
|
|
5798
|
-
if (error instanceof
|
|
5855
|
+
if (error instanceof NonZeroExitError3) {
|
|
5799
5856
|
return false;
|
|
5800
5857
|
}
|
|
5801
5858
|
throw new NpmError("Failed to run `npm whoami`", { cause: error });
|
|
@@ -5873,7 +5930,7 @@ var NpmRegistry = class extends Registry {
|
|
|
5873
5930
|
await this.npm(["publish", "--provenance", "--access", "public"]);
|
|
5874
5931
|
return true;
|
|
5875
5932
|
} catch (error) {
|
|
5876
|
-
if (error instanceof
|
|
5933
|
+
if (error instanceof NonZeroExitError3 && error.output?.stderr.includes("EOTP")) {
|
|
5877
5934
|
return false;
|
|
5878
5935
|
}
|
|
5879
5936
|
throw this.classifyPublishError(error);
|
|
@@ -5885,7 +5942,7 @@ var NpmRegistry = class extends Registry {
|
|
|
5885
5942
|
await this.npm(args);
|
|
5886
5943
|
return true;
|
|
5887
5944
|
} catch (error) {
|
|
5888
|
-
if (error instanceof
|
|
5945
|
+
if (error instanceof NonZeroExitError3 && error.output?.stderr.includes("EOTP")) {
|
|
5889
5946
|
return false;
|
|
5890
5947
|
}
|
|
5891
5948
|
throw this.classifyPublishError(error);
|
|
@@ -5901,7 +5958,7 @@ var NpmRegistry = class extends Registry {
|
|
|
5901
5958
|
};
|
|
5902
5959
|
}
|
|
5903
5960
|
classifyPublishError(error) {
|
|
5904
|
-
if (error instanceof
|
|
5961
|
+
if (error instanceof NonZeroExitError3) {
|
|
5905
5962
|
const stderr = error.output?.stderr ?? "";
|
|
5906
5963
|
if (stderr.includes("EOTP")) {
|
|
5907
5964
|
return new NpmError("OTP required for publishing", { cause: error });
|
|
@@ -6640,13 +6697,24 @@ function registryTask(registry) {
|
|
|
6640
6697
|
return npmPublishTasks;
|
|
6641
6698
|
}
|
|
6642
6699
|
}
|
|
6643
|
-
function collectPublishTasks(ctx) {
|
|
6700
|
+
async function collectPublishTasks(ctx) {
|
|
6644
6701
|
if (ctx.packages?.length) {
|
|
6645
|
-
|
|
6646
|
-
(pkg) => pkg.registries.map(
|
|
6647
|
-
(reg) => reg === "crates" ? createCratesPublishTask(pkg.path) : registryTask(reg)
|
|
6648
|
-
)
|
|
6702
|
+
const nonCratesTasks = ctx.packages.flatMap(
|
|
6703
|
+
(pkg) => pkg.registries.filter((reg) => reg !== "crates").map((reg) => registryTask(reg))
|
|
6649
6704
|
);
|
|
6705
|
+
const cratesPaths = ctx.packages.filter((pkg) => pkg.registries.includes("crates")).map((pkg) => pkg.path);
|
|
6706
|
+
if (cratesPaths.length === 0) {
|
|
6707
|
+
return nonCratesTasks;
|
|
6708
|
+
}
|
|
6709
|
+
const sortedPaths = await sortCratesByDependencyOrder(cratesPaths);
|
|
6710
|
+
const sequentialCratesTask = {
|
|
6711
|
+
title: "Publishing to crates.io (sequential)",
|
|
6712
|
+
task: (_ctx, task) => task.newListr(
|
|
6713
|
+
sortedPaths.map((p) => createCratesPublishTask(p)),
|
|
6714
|
+
{ concurrent: false }
|
|
6715
|
+
)
|
|
6716
|
+
};
|
|
6717
|
+
return [...nonCratesTasks, sequentialCratesTask];
|
|
6650
6718
|
}
|
|
6651
6719
|
return collectRegistries(ctx).map(registryTask);
|
|
6652
6720
|
}
|
|
@@ -6668,7 +6736,7 @@ async function run(options) {
|
|
|
6668
6736
|
await createListr(
|
|
6669
6737
|
options.publishOnly ? {
|
|
6670
6738
|
title: "Publishing",
|
|
6671
|
-
task: (ctx2, parentTask) => parentTask.newListr(collectPublishTasks(ctx2), {
|
|
6739
|
+
task: async (ctx2, parentTask) => parentTask.newListr(await collectPublishTasks(ctx2), {
|
|
6672
6740
|
concurrent: true
|
|
6673
6741
|
})
|
|
6674
6742
|
} : [
|
|
@@ -6757,7 +6825,7 @@ async function run(options) {
|
|
|
6757
6825
|
{
|
|
6758
6826
|
skip: (ctx2) => options.skipPublish || !!ctx2.preview,
|
|
6759
6827
|
title: "Publishing",
|
|
6760
|
-
task: (ctx2, parentTask) => parentTask.newListr(collectPublishTasks(ctx2), {
|
|
6828
|
+
task: async (ctx2, parentTask) => parentTask.newListr(await collectPublishTasks(ctx2), {
|
|
6761
6829
|
concurrent: true
|
|
6762
6830
|
})
|
|
6763
6831
|
},
|