openship 0.6.6 → 0.6.7

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.
Files changed (58) hide show
  1. package/dist/bare-7QD623QV.js +29 -0
  2. package/dist/{chunk-Q7WGTQQ5.js → chunk-2ANV5ZQ5.js} +1 -1
  3. package/dist/{chunk-UJ6JZM65.js → chunk-2VSW6Q6C.js} +601 -382
  4. package/dist/{chunk-PCPVTH6M.js → chunk-5T4UVOM3.js} +6 -4
  5. package/dist/{chunk-YMMQRE5J.js → chunk-BLEXTYRK.js} +1 -1
  6. package/dist/{chunk-OBPKYXQL.js → chunk-CIJV43LH.js} +71 -32
  7. package/dist/{chunk-NK5N5LXN.js → chunk-DDFUESPJ.js} +24 -9
  8. package/dist/{chunk-6FH4AXVY.js → chunk-E2X26PXR.js} +1 -1
  9. package/dist/{chunk-HKRQXPTI.js → chunk-FYPFEDPZ.js} +1 -1
  10. package/dist/{chunk-UVNMQM7W.js → chunk-FZ6QCF6B.js} +8 -6
  11. package/dist/{chunk-MLYSEZQB.js → chunk-GGIAIGUL.js} +15 -66
  12. package/dist/{chunk-2YM3NI2E.js → chunk-GIPJNNI5.js} +38 -44
  13. package/dist/{chunk-ZFJXPCQP.js → chunk-H3WT3A6R.js} +4 -3
  14. package/dist/chunk-H4FS5BED.js +936 -0
  15. package/dist/{chunk-CBLD2HS5.js → chunk-J2XM3QSP.js} +8 -5
  16. package/dist/{chunk-FE7ZZQSE.js → chunk-J3K6XABC.js} +3 -3
  17. package/dist/{chunk-77QDF6UD.js → chunk-LHFXSC36.js} +428 -93
  18. package/dist/{chunk-YIMOCZBZ.js → chunk-MEE6OZFP.js} +3 -3
  19. package/dist/chunk-N5YZMO33.js +111 -0
  20. package/dist/{chunk-QVW76WDL.js → chunk-NRTJRNAE.js} +58 -16
  21. package/dist/{chunk-WVAML4H6.js → chunk-PPEBIY5F.js} +247 -61
  22. package/dist/{chunk-4I2BM2DT.js → chunk-PVP4RGWT.js} +3 -3
  23. package/dist/{chunk-RSR7PFIQ.js → chunk-QHMDCYZ3.js} +4 -4
  24. package/dist/chunk-R4VDPFLS.js +106 -0
  25. package/dist/{chunk-VTGPEC6B.js → chunk-RDXT4BQB.js} +6 -4
  26. package/dist/{chunk-LFE5KQ7Y.js → chunk-S6B2Z3OO.js} +142 -57
  27. package/dist/chunk-UWEV6XTS.js +249 -0
  28. package/dist/{chunk-5DMWSTOM.js → chunk-VQM6JHJB.js} +940 -224
  29. package/dist/{chunk-SM26HDS2.js → chunk-VSTFHUCV.js} +44 -50
  30. package/dist/chunk-WU54BXFE.js +70 -0
  31. package/dist/{chunk-LUKYPVJ4.js → chunk-XWHWTHEL.js} +313 -469
  32. package/dist/{chunk-A4GXYE4L.js → chunk-ZPJ74LXE.js} +22 -20
  33. package/dist/cloud-KNNABE3O.js +40 -0
  34. package/dist/{detect-OIE5V3VZ.js → detect-G4DR3U2N.js} +9 -6
  35. package/dist/{docker-VTR2GK5Y.js → docker-YOVPCIB4.js} +11 -8
  36. package/dist/{docker-edge-executor-22IBXNYJ.js → docker-edge-executor-QFXD3337.js} +8 -6
  37. package/dist/edge-import-CRFVSR6P.js +56 -0
  38. package/dist/{edge-preflight-GBNCPNVU.js → edge-preflight-MXERVAMG.js} +15 -12
  39. package/dist/{ensure-container-edge-KPI2CVXJ.js → ensure-container-edge-F4JUNQIK.js} +13 -10
  40. package/dist/{executor-7LXXZPBR.js → executor-CVPAYYHR.js} +8 -6
  41. package/dist/host-channel-preflight-QTDNGLCK.js +54 -0
  42. package/dist/index.js +84 -48
  43. package/dist/{local-executor-WOFZD72X.js → local-executor-ODC6RANU.js} +3 -2
  44. package/dist/{nginx-KUFMLMAC.js → nginx-KLFF43TC.js} +11 -8
  45. package/dist/{openresty-lua-ATTH35BE.js → openresty-lua-VKWUV4GB.js} +6 -5
  46. package/dist/{privilege-I4W3ZNZK.js → privilege-7D3SSOL3.js} +6 -5
  47. package/dist/server/index.js +8813 -5232
  48. package/dist/setup-I5AJC6NJ.js +25 -0
  49. package/dist/{ssh-client-JBMA7SN4.js → ssh-client-625VWGKP.js} +3 -2
  50. package/dist/up-QXTOOVXC.js +61 -0
  51. package/package.json +1 -1
  52. package/dist/bare-OXJVW3AK.js +0 -25
  53. package/dist/chunk-LH2PLRQO.js +0 -434
  54. package/dist/cloud-75VIT4KV.js +0 -37
  55. package/dist/edge-import-WJUB4M7F.js +0 -52
  56. package/dist/host-channel-preflight-KE6OONYK.js +0 -50
  57. package/dist/setup-XGLGUUFW.js +0 -22
  58. package/dist/up-K4BV7466.js +0 -57
@@ -4,17 +4,20 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  assembleGitClone,
7
+ dockerBuildContextDirectory,
8
+ generateDockerfile,
7
9
  localGitSshWriter,
8
10
  materializeGitSsh,
9
- sq
10
- } from "./chunk-LH2PLRQO.js";
11
+ normalizeDockerRelativePath,
12
+ resolveContextDockerfileCandidates,
13
+ resolveDockerRootDirectory,
14
+ resolveDockerfileCandidates,
15
+ resolveWithinDirectory
16
+ } from "./chunk-H4FS5BED.js";
11
17
  import {
12
18
  getTarCreateEnv,
13
19
  prepareSourceTarArgs
14
- } from "./chunk-Q7WGTQQ5.js";
15
- import {
16
- packageManagerEnsureCommand
17
- } from "./chunk-UJ6JZM65.js";
20
+ } from "./chunk-2ANV5ZQ5.js";
18
21
  import {
19
22
  __commonJS,
20
23
  __toESM
@@ -478,451 +481,227 @@ var require_ignore = __commonJS({
478
481
  }
479
482
  });
480
483
 
481
- // ../../packages/adapters/src/runtime/docker-paths.ts
482
- import { access, readdir } from "fs/promises";
483
- import { isAbsolute, join, relative, resolve, sep } from "path";
484
- function toPosixPath(value) {
485
- return value.split(sep).filter(Boolean).join("/");
486
- }
487
- function toSafeSegments(value, label) {
488
- const segments = value.split(/[\\/]/).filter((segment) => segment && segment !== ".");
489
- if (segments.includes("..")) {
490
- throw new Error(
491
- `Invalid ${label} ${JSON.stringify(value)}: path segments must not contain "..".`
492
- );
493
- }
494
- return segments;
495
- }
496
- function normalizeDockerRelativePath(value) {
497
- const normalized = value?.trim().replace(/^\.\//, "").replace(/^\/+|\/+$/g, "");
498
- if (!normalized || normalized === ".") {
499
- return "";
500
- }
501
- return toSafeSegments(normalized, "path").join("/");
502
- }
503
- function resolveWithinDirectory(baseDir, relativePath) {
504
- const base = resolve(baseDir);
505
- const target = resolve(base, ...toSafeSegments(relativePath?.trim() ?? "", "path"));
506
- const escape = relative(base, target);
507
- if (escape === ".." || escape.startsWith(`..${sep}`) || isAbsolute(escape)) {
508
- throw new Error(`Resolved path ${JSON.stringify(target)} escapes ${JSON.stringify(base)}.`);
484
+ // ../../packages/adapters/src/runtime/docker-buildkit-trace.ts
485
+ var WIRE_VARINT = 0;
486
+ var WIRE_64BIT = 1;
487
+ var WIRE_LENGTH = 2;
488
+ var WIRE_32BIT = 5;
489
+ var WireReader = class {
490
+ constructor(buf) {
491
+ this.buf = buf;
509
492
  }
510
- return target;
511
- }
512
- function normalizeDockerRootDirectory(rootDirectory, localPath) {
513
- let normalized = rootDirectory?.trim() ?? "";
514
- if (!normalized) {
515
- return "";
493
+ pos = 0;
494
+ get done() {
495
+ return this.pos >= this.buf.length;
516
496
  }
517
- if (localPath && isAbsolute(normalized)) {
518
- const relativePath = relative(localPath, normalized);
519
- if (!relativePath || relativePath === ".") {
520
- return "";
497
+ /** Varint as a Number. Bails past 10 bytes (the protobuf maximum) so a corrupt
498
+ * buffer cannot spin. Values we actually read (`stream`, `cached`) are tiny. */
499
+ varint() {
500
+ let result = 0;
501
+ let shift = 0;
502
+ for (let i = 0; i < 10; i += 1) {
503
+ if (this.done) return null;
504
+ const byte = this.buf[this.pos];
505
+ this.pos += 1;
506
+ result += (byte & 127) * 2 ** shift;
507
+ if ((byte & 128) === 0) return result;
508
+ shift += 7;
521
509
  }
522
- if (!relativePath.startsWith("..") && !isAbsolute(relativePath)) {
523
- normalized = relativePath;
524
- }
525
- }
526
- normalized = normalized.replace(/^\.\//, "").replace(/^\/+|\/+$/g, "");
527
- if (!normalized || normalized === ".") {
528
- return "";
529
- }
530
- return toSafeSegments(normalized, "rootDirectory").join("/");
531
- }
532
- function resolveExplicitDockerfileCandidate(rootDirectory, dockerfilePath) {
533
- const normalizedRootDirectory = normalizeDockerRelativePath(rootDirectory);
534
- const normalizedDockerfilePath = normalizeDockerRelativePath(dockerfilePath);
535
- if (!normalizedDockerfilePath) {
536
- return "";
510
+ return null;
537
511
  }
538
- if (!normalizedRootDirectory) {
539
- return normalizedDockerfilePath;
512
+ /** Field header → { field, wire }. */
513
+ key() {
514
+ const tag = this.varint();
515
+ if (tag === null) return null;
516
+ const field = Math.floor(tag / 8);
517
+ if (field <= 0) return null;
518
+ return { field, wire: tag % 8 };
540
519
  }
541
- if (normalizedDockerfilePath.startsWith(`${normalizedRootDirectory}/`)) {
542
- return normalizedDockerfilePath;
520
+ bytes() {
521
+ const length = this.varint();
522
+ if (length === null || length < 0 || this.pos + length > this.buf.length) return null;
523
+ const slice = this.buf.subarray(this.pos, this.pos + length);
524
+ this.pos += length;
525
+ return slice;
543
526
  }
544
- return `${normalizedRootDirectory}/${normalizedDockerfilePath}`;
545
- }
546
- function resolveDockerfileCandidates(rootDirectory, explicitDockerfilePath) {
547
- const normalizedRootDirectory = normalizeDockerRelativePath(rootDirectory);
548
- return [
549
- resolveExplicitDockerfileCandidate(rootDirectory, explicitDockerfilePath),
550
- normalizedRootDirectory ? `${normalizedRootDirectory}/Dockerfile` : "Dockerfile",
551
- "Dockerfile"
552
- ].filter(
553
- (candidate, index, values) => Boolean(candidate) && values.indexOf(candidate) === index
554
- );
555
- }
556
- var ROOT_MANIFESTS = [
557
- "package.json",
558
- "pyproject.toml",
559
- "requirements.txt",
560
- "Pipfile",
561
- "go.mod",
562
- "Cargo.toml",
563
- "Gemfile",
564
- "composer.json",
565
- "pom.xml",
566
- "build.gradle",
567
- "build.gradle.kts",
568
- "mix.exs",
569
- "Dockerfile"
570
- ];
571
- var IGNORED_DIRS = /* @__PURE__ */ new Set([
572
- "node_modules",
573
- ".git",
574
- ".next",
575
- ".nuxt",
576
- ".output",
577
- ".turbo",
578
- ".venv",
579
- "__pycache__",
580
- "build",
581
- "dist",
582
- "target",
583
- "vendor"
584
- ]);
585
- async function pathExists(path) {
586
- return access(path).then(() => true).catch(() => false);
587
- }
588
- async function manifestCount(dir) {
589
- let count = 0;
590
- for (const file of ROOT_MANIFESTS) {
591
- if (await pathExists(join(dir, file))) {
592
- count += 1;
527
+ /** Advance past a field we don't read. Returns false when the buffer is
528
+ * malformed, which ends the scan. */
529
+ skip(wire) {
530
+ switch (wire) {
531
+ case WIRE_VARINT:
532
+ return this.varint() !== null;
533
+ case WIRE_64BIT:
534
+ this.pos += 8;
535
+ return this.pos <= this.buf.length;
536
+ case WIRE_LENGTH:
537
+ return this.bytes() !== null;
538
+ case WIRE_32BIT:
539
+ this.pos += 4;
540
+ return this.pos <= this.buf.length;
541
+ default:
542
+ return false;
593
543
  }
594
544
  }
595
- return count;
596
- }
597
- function pathSegments(path) {
598
- return path.toLowerCase().split("/").filter(Boolean);
545
+ };
546
+ var decoder = new TextDecoder("utf-8", { fatal: false });
547
+ function text(bytes) {
548
+ return decoder.decode(bytes);
599
549
  }
600
- function scorePathHints(relativePath) {
601
- const segments = pathSegments(relativePath);
602
- let score = 0;
603
- for (const segment of segments) {
604
- if (["app", "apps", "site", "sites", "web", "www", "service", "services"].includes(segment)) {
605
- score += 12;
606
- }
607
- if (["docs", "example", "examples", "test", "tests", "storybook"].includes(segment)) {
608
- score -= 18;
550
+ function decodeVertex(bytes) {
551
+ const reader = new WireReader(bytes);
552
+ const vertex = {
553
+ digest: "",
554
+ name: "",
555
+ cached: false,
556
+ started: false,
557
+ completed: false,
558
+ error: ""
559
+ };
560
+ while (!reader.done) {
561
+ const key = reader.key();
562
+ if (!key) return null;
563
+ if (key.field === 1 && key.wire === WIRE_LENGTH) {
564
+ const value = reader.bytes();
565
+ if (!value) return null;
566
+ vertex.digest = text(value);
567
+ } else if (key.field === 3 && key.wire === WIRE_LENGTH) {
568
+ const value = reader.bytes();
569
+ if (!value) return null;
570
+ vertex.name = text(value);
571
+ } else if (key.field === 4 && key.wire === WIRE_VARINT) {
572
+ const value = reader.varint();
573
+ if (value === null) return null;
574
+ vertex.cached = value !== 0;
575
+ } else if (key.field === 5 && key.wire === WIRE_LENGTH) {
576
+ if (!reader.bytes()) return null;
577
+ vertex.started = true;
578
+ } else if (key.field === 6 && key.wire === WIRE_LENGTH) {
579
+ if (!reader.bytes()) return null;
580
+ vertex.completed = true;
581
+ } else if (key.field === 7 && key.wire === WIRE_LENGTH) {
582
+ const value = reader.bytes();
583
+ if (!value) return null;
584
+ vertex.error = text(value);
585
+ } else if (!reader.skip(key.wire)) {
586
+ return null;
609
587
  }
610
588
  }
611
- return score;
589
+ return vertex;
612
590
  }
613
- async function scoreCandidate(dir, relativePath) {
614
- let score = scorePathHints(relativePath);
615
- score += await manifestCount(dir) * 20;
616
- if (relativePath) {
617
- score += 6;
618
- }
619
- return score;
620
- }
621
- async function collectCandidates(rootDir, currentDir, depth, candidates) {
622
- const relativePath = toPosixPath(relative(rootDir, currentDir));
623
- if (await manifestCount(currentDir) > 0) {
624
- candidates.push({
625
- path: relativePath,
626
- score: await scoreCandidate(currentDir, relativePath)
627
- });
628
- }
629
- if (depth >= 6) {
630
- return;
631
- }
632
- const entries = await readdir(currentDir, { withFileTypes: true }).catch(() => []);
633
- for (const entry of entries) {
634
- if (!entry.isDirectory() || IGNORED_DIRS.has(entry.name)) {
635
- continue;
591
+ function decodeLog(bytes) {
592
+ const reader = new WireReader(bytes);
593
+ let vertex = "";
594
+ let msg = null;
595
+ while (!reader.done) {
596
+ const key = reader.key();
597
+ if (!key) return null;
598
+ if (key.field === 1 && key.wire === WIRE_LENGTH) {
599
+ const value = reader.bytes();
600
+ if (!value) return null;
601
+ vertex = text(value);
602
+ } else if (key.field === 4 && key.wire === WIRE_LENGTH) {
603
+ const value = reader.bytes();
604
+ if (!value) return null;
605
+ msg = value;
606
+ } else if (!reader.skip(key.wire)) {
607
+ return null;
636
608
  }
637
- await collectCandidates(rootDir, join(currentDir, entry.name), depth + 1, candidates);
638
- }
639
- }
640
- async function resolveDockerRootDirectory(contextDir, rootDirectory, localPath) {
641
- const hasExplicitRootDirectory = typeof rootDirectory === "string";
642
- const normalized = normalizeDockerRootDirectory(rootDirectory, localPath);
643
- if (hasExplicitRootDirectory) {
644
- return normalized;
645
- }
646
- if (normalized) {
647
- return normalized;
648
- }
649
- const candidates = [];
650
- await collectCandidates(contextDir, contextDir, 0, candidates);
651
- if (candidates.length === 0) {
652
- return "";
653
- }
654
- candidates.sort((left, right) => right.score - left.score);
655
- const bestNonRoot = candidates.find((candidate) => candidate.path);
656
- if (bestNonRoot && bestNonRoot.score > 0) {
657
- return bestNonRoot.path;
658
- }
659
- return candidates[0]?.path ?? "";
660
- }
661
-
662
- // ../../packages/adapters/src/runtime/docker-build-plan.ts
663
- var DOCKER_BUILD_EVENT_PREFIX = "[openship-build]";
664
- var INLINE_BUILD_ENV_EXCLUDES = /* @__PURE__ */ new Set(["FORCE_COLOR", "TERM"]);
665
- function formatDockerBuildEvent(step, status) {
666
- return `${DOCKER_BUILD_EVENT_PREFIX} step=${step} status=${status}`;
667
- }
668
- function normalizeRelativePath(value) {
669
- const normalized = value?.trim().replace(/^\.\//, "").replace(/^\/+|\/+$/g, "");
670
- if (!normalized || normalized === ".") {
671
- return "";
672
- }
673
- return normalized;
674
- }
675
- function builderSourceDir(rootDirectory) {
676
- const normalized = normalizeDockerRootDirectory(rootDirectory);
677
- return normalized ? `/workspace/${normalized}` : "/workspace";
678
- }
679
- function buildEnvPrefix(envVars) {
680
- const assignments = Object.entries(envVars).filter(([key]) => !INLINE_BUILD_ENV_EXCLUDES.has(key)).filter(([key]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key)).map(([key, value]) => `${key}=${sq(value)}`);
681
- if (!envVars.NO_COLOR) {
682
- assignments.push("NO_COLOR='1'");
683
- }
684
- if (assignments.length === 0) {
685
- return "";
686
609
  }
687
- return `export ${assignments.join(" ")} && `;
688
- }
689
- function buildRunCommand(command, envPrefix) {
690
- return `${envPrefix}${command}`;
691
- }
692
- function runtimeCopyDirectives(config, sourceDir) {
693
- if (config.productionPaths && config.productionPaths.length > 0) {
694
- return config.productionPaths.map((path) => {
695
- const normalized = normalizeRelativePath(path);
696
- const source = normalized ? `${sourceDir}/${normalized}` : sourceDir;
697
- const target = normalized ? `/app/${normalized}` : "/app";
698
- return `COPY --from=builder ${source} ${target}`;
699
- });
700
- }
701
- return [`COPY --from=builder ${sourceDir} /app`];
702
- }
703
- function needsMultiStage(config) {
704
- return config.buildImage !== config.runtimeImage;
705
- }
706
- function workspacePrepareRunLine(config, envPrefix, workspacePrepare) {
707
- const pmEnsure = packageManagerEnsureCommand(config.packageManager);
708
- const body = pmEnsure ? `${pmEnsure} && ${workspacePrepare}` : workspacePrepare;
709
- return `RUN ${envPrefix}${body}`;
710
- }
711
- function stepsRunLine(config, envPrefix, opts) {
712
- const install = opts.install ? config.installCommand : "";
713
- const build = opts.build ? config.buildCommand : "";
714
- const steps = [];
715
- const pmEnsure = packageManagerEnsureCommand(opts.packageManager ?? config.packageManager);
716
- if (pmEnsure && (install || build)) {
717
- steps.push(pmEnsure);
718
- }
719
- if (install) {
720
- steps.push(`printf '${formatDockerBuildEvent("install", "running")}\\n'`);
721
- steps.push(buildRunCommand(install, envPrefix));
722
- steps.push(`printf '${formatDockerBuildEvent("install", "completed")}\\n'`);
723
- }
724
- if (build) {
725
- steps.push(`printf '${formatDockerBuildEvent("build", "running")}\\n'`);
726
- steps.push(buildRunCommand(build, envPrefix));
727
- steps.push(`printf '${formatDockerBuildEvent("build", "completed")}\\n'`);
728
- }
729
- return steps.length > 0 ? `RUN ${steps.join(" && ")}` : null;
730
- }
731
- function installBuildRunLine(config, envPrefix) {
732
- return stepsRunLine(config, envPrefix, { install: true, build: true });
733
- }
734
- function installRunLine(config, envPrefix) {
735
- return stepsRunLine(config, envPrefix, { install: true });
736
- }
737
- var JS_PACKAGE_MANAGERS = ["pnpm", "yarn", "bun", "npm"];
738
- function buildOnlyRunLine(config, envPrefix) {
739
- const command = config.buildCommand?.trim() ?? "";
740
- const packageManager = JS_PACKAGE_MANAGERS.find(
741
- (pm) => new RegExp(`(^|\\s|&&\\s*)${pm}\\s`).test(command)
742
- );
743
- return stepsRunLine(config, envPrefix, { build: true, packageManager });
744
- }
745
- function isPhpRuntime(config) {
746
- return /^php:/.test(config.runtimeImage) || /frankenphp/i.test(config.runtimeImage);
610
+ if (!vertex.startsWith("sha256:") || !msg?.length) return null;
611
+ return { vertex, msg: text(msg) };
747
612
  }
748
- var PHP_EXTENSIONS = [
749
- "pdo_mysql",
750
- "pdo_pgsql",
751
- "redis",
752
- "pcntl",
753
- "bcmath",
754
- "intl",
755
- "zip",
756
- "gd",
757
- "opcache"
758
- ];
759
- var PHP_EXT_INSTALLER_IMAGE = "mlocati/php-extension-installer:2";
760
- var PHP_ASSET_BUILD_IMAGE = "node:22-bookworm-slim";
761
- var PHP_EXT_INSTALL_LINE = `RUN install-php-extensions ${PHP_EXTENSIONS.join(" ")} > /dev/null`;
762
- function generatePhpDockerfile(config) {
763
- const sourceDir = builderSourceDir(
764
- normalizeDockerRootDirectory(config.rootDirectory, config.localPath)
765
- );
766
- const envPrefix = buildEnvPrefix(config.envVars);
767
- const installLine = installRunLine(config, envPrefix);
768
- const assetBuildLine = buildOnlyRunLine(config, envPrefix);
769
- const lines = [
770
- `FROM ${config.buildImage} AS builder`,
771
- // php:*-cli ships no Composer — pull the binary from the official image.
772
- `COPY --from=composer:2 /usr/bin/composer /usr/bin/composer`,
773
- `COPY --from=${PHP_EXT_INSTALLER_IMAGE} /usr/bin/install-php-extensions /usr/bin/install-php-extensions`,
774
- PHP_EXT_INSTALL_LINE,
775
- `WORKDIR /workspace`,
776
- `COPY . /workspace`,
777
- `WORKDIR ${sourceDir}`
778
- ];
779
- if (installLine) lines.push(installLine);
780
- if (assetBuildLine) {
781
- lines.push(
782
- `FROM ${PHP_ASSET_BUILD_IMAGE} AS assets`,
783
- `WORKDIR /workspace`,
784
- `COPY . /workspace`,
785
- `WORKDIR ${sourceDir}`,
786
- assetBuildLine
787
- );
788
- }
789
- const docroot = normalizeRelativePath(config.outputDirectory) || "public";
790
- lines.push(
791
- `FROM ${config.runtimeImage} AS runtime`,
792
- PHP_EXT_INSTALL_LINE,
793
- // --chown on the COPY instead of a trailing `chown -R`: the recursive form
794
- // rewrites every file into a second layer, doubling the app's size on disk.
795
- // Ownership has to be settled HERE, before anything mounts: Docker seeds a
796
- // fresh named volume from the image directory it covers, ownership included,
797
- // so `/app/storage` is only writable by the runtime user if it was already
798
- // owned by them in the image (see @repo/core volumes.ts).
799
- `COPY --from=builder --chown=www-data:www-data ${sourceDir} /app`
800
- );
801
- if (assetBuildLine) {
802
- lines.push(
803
- `COPY --from=assets --chown=www-data:www-data ${sourceDir}/${docroot} /app/${docroot}`
804
- );
805
- }
806
- lines.push(
807
- `WORKDIR /app`,
808
- // FrankenPHP's bundled Caddyfile reads the docroot from SERVER_ROOT (default
809
- // `public/`, resolved against WORKDIR). Setting it keeps the project's
810
- // outputDirectory authoritative for BOTH what gets served and where the asset
811
- // stage's output lands — otherwise a project that renamed its docroot builds
812
- // assets into one directory and serves another.
813
- `ENV SERVER_ROOT=${docroot}/`,
814
- // Caddy's config + data dirs are root-owned in the base image, and it writes
815
- // to both on startup — without this the non-root switch below fails at boot.
816
- `RUN mkdir -p /data/caddy /config/caddy && chown -R www-data:www-data /data/caddy /config/caddy`,
817
- // The frankenphp binary carries cap_net_bind_service, so dropping root here
818
- // still leaves any port bindable.
819
- `USER www-data`,
820
- `EXPOSE ${config.port}`
821
- );
822
- if (config.startCommand) {
823
- lines.push(`CMD ["sh", "-c", ${JSON.stringify(config.startCommand)}]`);
824
- }
825
- return lines.join("\n");
826
- }
827
- function staticNginxTemplateLines(port) {
828
- return [
829
- "server {",
830
- ` listen ${port} default_server;`,
831
- " root /usr/share/nginx/html;",
832
- " index index.html;",
833
- " location / { try_files $uri $uri/ /index.html; }",
834
- "}"
835
- ];
836
- }
837
- function staticBuilderOutputPath(config) {
838
- const sourceDir = builderSourceDir(
839
- normalizeDockerRootDirectory(config.rootDirectory, config.localPath)
840
- );
841
- const output = normalizeRelativePath(config.outputDirectory);
842
- return output ? `${sourceDir}/${output}` : sourceDir;
843
- }
844
- function generateStaticDockerfile(config) {
845
- const sourceDir = builderSourceDir(
846
- normalizeDockerRootDirectory(config.rootDirectory, config.localPath)
847
- );
848
- const envPrefix = buildEnvPrefix(config.envVars);
849
- const workspacePrepare = config.workspacePrepareCommand?.trim();
850
- const outputPath = staticBuilderOutputPath(config);
851
- const nginxTemplate = staticNginxTemplateLines(config.port).map((line) => `'${line}'`).join(" ");
852
- const lines = [
853
- `FROM ${config.buildImage} AS builder`,
854
- `WORKDIR /workspace`,
855
- `COPY . /workspace`
856
- ];
857
- if (workspacePrepare) {
858
- lines.push(workspacePrepareRunLine(config, envPrefix, workspacePrepare));
859
- }
860
- lines.push(`WORKDIR ${sourceDir}`);
861
- const stepsLine = installBuildRunLine(config, envPrefix);
862
- if (stepsLine) lines.push(stepsLine);
863
- if (config.staticExtractOnly) return lines.join("\n");
864
- lines.push(
865
- `FROM nginx:alpine AS runtime`,
866
- `RUN rm -f /etc/nginx/conf.d/default.conf`,
867
- `COPY --from=builder ${outputPath} /usr/share/nginx/html`,
868
- `RUN printf '%s\\n' ${nginxTemplate} > /etc/nginx/conf.d/app.conf`,
869
- `EXPOSE ${config.port}`,
870
- `CMD ["nginx", "-g", "daemon off;"]`
871
- );
872
- return lines.join("\n");
873
- }
874
- function generateDockerfile(config) {
875
- if (config.isStatic) {
876
- return generateStaticDockerfile(config);
877
- }
878
- if (isPhpRuntime(config) && needsMultiStage(config)) {
879
- return generatePhpDockerfile(config);
613
+ var BuildKitTraceDecoder = class {
614
+ numbers = /* @__PURE__ */ new Map();
615
+ announced = /* @__PURE__ */ new Set();
616
+ settled = /* @__PURE__ */ new Set();
617
+ /** Decode one `aux` payload into the lines it should add to the build log. */
618
+ push(auxBase64) {
619
+ let payload;
620
+ try {
621
+ payload = Uint8Array.from(Buffer.from(auxBase64, "base64"));
622
+ } catch {
623
+ return [];
624
+ }
625
+ if (payload.length === 0) return [];
626
+ const lines = [];
627
+ const reader = new WireReader(payload);
628
+ while (!reader.done) {
629
+ const key = reader.key();
630
+ if (!key) break;
631
+ if (key.field === 1 && key.wire === WIRE_LENGTH) {
632
+ const bytes = reader.bytes();
633
+ if (!bytes) break;
634
+ const vertex = decodeVertex(bytes);
635
+ if (vertex) lines.push(...this.renderVertex(vertex));
636
+ continue;
637
+ }
638
+ if (key.field === 3 && key.wire === WIRE_LENGTH) {
639
+ const bytes = reader.bytes();
640
+ if (!bytes) break;
641
+ const entry = decodeLog(bytes);
642
+ if (entry) lines.push(...this.renderLog(entry));
643
+ continue;
644
+ }
645
+ if (!reader.skip(key.wire)) break;
646
+ }
647
+ return lines;
880
648
  }
881
- const sourceDir = builderSourceDir(
882
- normalizeDockerRootDirectory(config.rootDirectory, config.localPath)
883
- );
884
- const multiStage = needsMultiStage(config);
885
- const envPrefix = buildEnvPrefix(config.envVars);
886
- const workspacePrepare = config.workspacePrepareCommand?.trim();
887
- const lines = multiStage ? [
888
- `FROM ${config.buildImage} AS builder`,
889
- `WORKDIR /workspace`,
890
- `COPY . /workspace`
891
- ] : [
892
- `FROM ${config.runtimeImage}`,
893
- `WORKDIR /workspace`,
894
- `COPY . /workspace`
895
- ];
896
- if (workspacePrepare) {
897
- lines.push(workspacePrepareRunLine(config, envPrefix, workspacePrepare));
649
+ numberFor(digest) {
650
+ const existing = this.numbers.get(digest);
651
+ if (existing !== void 0) return existing;
652
+ const next = this.numbers.size + 1;
653
+ this.numbers.set(digest, next);
654
+ return next;
898
655
  }
899
- lines.push(`WORKDIR ${sourceDir}`);
900
- const stepsLine = installBuildRunLine(config, envPrefix);
901
- if (stepsLine) {
902
- lines.push(stepsLine);
656
+ renderVertex(vertex) {
657
+ if (!vertex.digest) return [];
658
+ const number = this.numberFor(vertex.digest);
659
+ const lines = [];
660
+ if (vertex.name && !this.announced.has(vertex.digest)) {
661
+ this.announced.add(vertex.digest);
662
+ lines.push({ message: `#${number} ${vertex.name}`, level: "info" });
663
+ }
664
+ if ((vertex.completed || vertex.error) && !this.settled.has(vertex.digest)) {
665
+ this.settled.add(vertex.digest);
666
+ if (vertex.error) {
667
+ lines.push({ message: `#${number} ERROR: ${vertex.error}`, level: "error" });
668
+ } else if (vertex.cached) {
669
+ lines.push({ message: `#${number} CACHED`, level: "info" });
670
+ } else {
671
+ lines.push({ message: `#${number} DONE`, level: "info" });
672
+ }
673
+ }
674
+ return lines;
903
675
  }
904
- if (multiStage) {
905
- lines.push(`FROM ${config.runtimeImage} AS runtime`);
906
- lines.push(...runtimeCopyDirectives(config, sourceDir));
907
- lines.push(`WORKDIR /app`);
676
+ renderLog(entry) {
677
+ const number = this.numberFor(entry.vertex);
678
+ return entry.msg.split(/\r?\n/).filter((line) => line.trim().length > 0).map((line) => ({ message: `#${number} ${line}`, level: "info" }));
908
679
  }
909
- lines.push(`EXPOSE ${config.port}`);
910
- if (config.startCommand) {
911
- lines.push(`CMD ["sh", "-c", ${JSON.stringify(config.startCommand)}]`);
680
+ };
681
+ function dockerfileNeedsBuildKit(contents) {
682
+ if (/^\s*#\s*syntax\s*=/im.test(contents.slice(0, 4096))) return true;
683
+ for (const line of contents.split(/\r?\n/)) {
684
+ if (/^\s*#/.test(line)) continue;
685
+ const match = /^\s*(RUN|COPY|ADD)((?:\s+--[^\s]+)*)/i.exec(line);
686
+ if (!match) continue;
687
+ const flags = match[2] ?? "";
688
+ if (/--(mount|network|security)\b/i.test(flags)) return true;
689
+ if (/--(link|checksum|keep-git-dir)\b/i.test(flags)) return true;
690
+ if (/(?:^|\s)<<-?\s*['"]?[A-Za-z_][A-Za-z0-9_]*['"]?(?:\s|$)/.test(line)) return true;
912
691
  }
913
- return lines.join("\n");
692
+ return false;
914
693
  }
915
694
 
916
695
  // ../../packages/adapters/src/runtime/docker-build-context.ts
917
696
  var import_ignore = __toESM(require_ignore(), 1);
918
697
  import { spawn } from "child_process";
919
- import { access as access2, mkdtemp, readdir as readdir2, readFile, rm, writeFile } from "fs/promises";
698
+ import { access, mkdtemp, readdir, readFile, realpath, rm, stat, writeFile } from "fs/promises";
920
699
  import { tmpdir } from "os";
921
- import { join as join2, relative as relative2, sep as sep2 } from "path";
700
+ import { isAbsolute, join, relative, sep } from "path";
922
701
  var GIT_CLONE_IDLE_TIMEOUT_MS = 5 * 6e4;
923
702
  var GIT_CHECKOUT_IDLE_TIMEOUT_MS = 6e4;
924
703
  function spawnGit(args, opts) {
925
- return new Promise((resolve2, reject) => {
704
+ return new Promise((resolve, reject) => {
926
705
  const child = spawn("git", args, {
927
706
  stdio: ["ignore", "pipe", "pipe"],
928
707
  env: {
@@ -961,9 +740,9 @@ function spawnGit(args, opts) {
961
740
  });
962
741
  child.stderr?.on("data", (buf) => {
963
742
  armIdle();
964
- const text = buf.toString();
965
- stderr += text;
966
- for (const ln of text.split(/\r?\n/)) flushLine(ln);
743
+ const text2 = buf.toString();
744
+ stderr += text2;
745
+ for (const ln of text2.split(/\r?\n/)) flushLine(ln);
967
746
  });
968
747
  armIdle();
969
748
  child.on("error", (err) => {
@@ -972,14 +751,14 @@ function spawnGit(args, opts) {
972
751
  });
973
752
  child.on("close", (code) => {
974
753
  clearTimeout(idleTimer);
975
- if (code === 0) resolve2();
754
+ if (code === 0) resolve();
976
755
  else reject(new Error(`git exited with code ${code}: ${stderr.trim().slice(-500) || "no stderr"}`));
977
756
  });
978
757
  });
979
758
  }
980
759
  var GENERATED_DOCKERFILE_NAME = "Dockerfile.openship";
981
- function toPosixPath2(value) {
982
- return value.split(sep2).filter(Boolean).join("/");
760
+ function toPosixPath(value) {
761
+ return value.split(sep).filter(Boolean).join("/");
983
762
  }
984
763
  function anchorDockerignorePattern(line) {
985
764
  const trimmed = line.trim();
@@ -992,7 +771,7 @@ function anchorDockerignorePattern(line) {
992
771
  }
993
772
  async function loadDockerignoreMatcher(rootPath) {
994
773
  try {
995
- const contents = await readFile(join2(rootPath, ".dockerignore"), "utf-8");
774
+ const contents = await readFile(join(rootPath, ".dockerignore"), "utf-8");
996
775
  return (0, import_ignore.default)().add(contents.split(/\r?\n/).map(anchorDockerignorePattern));
997
776
  } catch {
998
777
  return void 0;
@@ -1009,16 +788,45 @@ function buildFilePaths(config) {
1009
788
  }
1010
789
  return paths;
1011
790
  }
791
+ function contextKeepPaths(dockerfileName) {
792
+ const paths = /* @__PURE__ */ new Set([".dockerignore"]);
793
+ const segments = dockerfileName.split("/").filter(Boolean);
794
+ for (let depth = 1; depth <= segments.length; depth += 1) {
795
+ paths.add(segments.slice(0, depth).join("/"));
796
+ }
797
+ return paths;
798
+ }
799
+ async function loadContextIgnore(buildContextDir, keep) {
800
+ const matcher = await loadDockerignoreMatcher(buildContextDir);
801
+ if (!matcher) return void 0;
802
+ return (relativePosixPath) => !keep.has(relativePosixPath) && matcher.ignores(relativePosixPath);
803
+ }
804
+ async function resolveBuildContextDir(treeDir, contextSubdir) {
805
+ const target = resolveWithinDirectory(treeDir, contextSubdir);
806
+ if (!contextSubdir) return target;
807
+ const stats = await stat(target).catch(() => null);
808
+ if (!stats?.isDirectory()) {
809
+ throw new Error(
810
+ `Build context "${contextSubdir}" is not a directory in this source. Check the service's build path.`
811
+ );
812
+ }
813
+ const [realTree, realTarget] = await Promise.all([realpath(treeDir), realpath(target)]);
814
+ const escape = relative(realTree, realTarget);
815
+ if (escape === ".." || escape.startsWith(`..${sep}`) || isAbsolute(escape)) {
816
+ throw new Error(`Build context "${contextSubdir}" resolves outside the source tree.`);
817
+ }
818
+ return target;
819
+ }
1012
820
  async function applyDockerignore(contextDir, config) {
1013
821
  const matcher = await loadDockerignoreMatcher(contextDir);
1014
822
  if (!matcher) return;
1015
823
  const buildFiles = buildFilePaths(config);
1016
824
  const prune = async (currentPath) => {
1017
- const entries = await readdir2(currentPath, { withFileTypes: true });
825
+ const entries = await readdir(currentPath, { withFileTypes: true });
1018
826
  await Promise.all(
1019
827
  entries.map(async (entry) => {
1020
- const absolutePath = join2(currentPath, entry.name);
1021
- const relativePath = toPosixPath2(relative2(contextDir, absolutePath));
828
+ const absolutePath = join(currentPath, entry.name);
829
+ const relativePath = toPosixPath(relative(contextDir, absolutePath));
1022
830
  if (!buildFiles.has(relativePath) && matcher.ignores(relativePath)) {
1023
831
  await rm(absolutePath, { recursive: true, force: true });
1024
832
  return;
@@ -1029,10 +837,12 @@ async function applyDockerignore(contextDir, config) {
1029
837
  };
1030
838
  await prune(contextDir);
1031
839
  }
1032
- async function materializeLocalSource(sourcePath, targetPath) {
1033
- const { args, cleanup } = await prepareSourceTarArgs(sourcePath);
840
+ async function materializeLocalSource(sourcePath, targetPath, outputDirectory) {
841
+ const outDir = outputDirectory?.trim().replace(/^\.\//, "").replace(/^\/+|\/+$/g, "");
842
+ const alsoInclude = outDir && outDir !== "." ? [outDir] : void 0;
843
+ const { args, cleanup } = await prepareSourceTarArgs(sourcePath, { alsoInclude });
1034
844
  try {
1035
- await new Promise((resolve2, reject) => {
845
+ await new Promise((resolve, reject) => {
1036
846
  const create = spawn("tar", args, { env: getTarCreateEnv() });
1037
847
  const extract = spawn("tar", ["-xzf", "-", "-C", targetPath]);
1038
848
  let err = "";
@@ -1045,7 +855,7 @@ async function materializeLocalSource(sourcePath, targetPath) {
1045
855
  create.on("close", (code) => createCode = code);
1046
856
  create.stdout.pipe(extract.stdin);
1047
857
  extract.on("close", (code) => {
1048
- if (code === 0 && (createCode ?? 0) === 0) return resolve2();
858
+ if (code === 0 && (createCode ?? 0) === 0) return resolve();
1049
859
  const parts = [
1050
860
  createCode ? `pack exited ${createCode}: ${createErr.trim().slice(-500)}` : "",
1051
861
  code ? `extract exited ${code}: ${err.trim().slice(-500)}` : ""
@@ -1057,23 +867,28 @@ async function materializeLocalSource(sourcePath, targetPath) {
1057
867
  await cleanup();
1058
868
  }
1059
869
  }
1060
- async function resolveDockerfileName(contextDir, rootDirectory, explicitDockerfilePath) {
1061
- const candidates = resolveDockerfileCandidates(rootDirectory, explicitDockerfilePath);
870
+ async function firstExistingCandidate(dir, candidates) {
1062
871
  for (const candidate of candidates) {
1063
- const candidatePath = join2(contextDir, ...candidate.split("/"));
1064
- const exists = await access2(candidatePath).then(() => true).catch(() => false);
872
+ const candidatePath = join(dir, ...candidate.split("/"));
873
+ const exists = await access(candidatePath).then(() => true).catch(() => false);
1065
874
  if (exists) {
1066
875
  return candidate;
1067
876
  }
1068
877
  }
1069
878
  return null;
1070
879
  }
880
+ async function resolveDockerfileName(contextDir, rootDirectory, explicitDockerfilePath) {
881
+ return firstExistingCandidate(
882
+ contextDir,
883
+ resolveDockerfileCandidates(rootDirectory, explicitDockerfilePath)
884
+ );
885
+ }
1071
886
  async function cloneGitSource(config, targetPath, onLog) {
1072
887
  let sshMaterial;
1073
888
  if (config.gitSsh) {
1074
889
  sshMaterial = await materializeGitSsh(
1075
890
  localGitSshWriter(),
1076
- await mkdtemp(join2(tmpdir(), "opsh-ghkey-")),
891
+ await mkdtemp(join(tmpdir(), "opsh-ghkey-")),
1077
892
  config.gitSsh
1078
893
  );
1079
894
  }
@@ -1104,22 +919,24 @@ async function cloneGitSource(config, targetPath, onLog) {
1104
919
  env: gitEnv
1105
920
  });
1106
921
  }
1107
- await rm(join2(targetPath, ".git"), { recursive: true, force: true });
922
+ await rm(join(targetPath, ".git"), { recursive: true, force: true });
1108
923
  } finally {
1109
924
  await sshMaterial?.cleanup();
1110
925
  }
1111
926
  }
1112
927
  async function prepareSourceTree(config, opts) {
1113
- const contextDir = await mkdtemp(join2(tmpdir(), "openship-docker-context-"));
928
+ const contextDir = await mkdtemp(join(tmpdir(), "openship-docker-context-"));
1114
929
  try {
930
+ const pruneDockerignore = !opts?.perServiceBuildContexts && !dockerBuildContextDirectory(config);
1115
931
  if (config.localPath) {
1116
- await materializeLocalSource(config.localPath, contextDir);
932
+ await materializeLocalSource(config.localPath, contextDir, config.outputDirectory);
1117
933
  } else {
1118
934
  await cloneGitSource(config, contextDir, opts?.onLog);
1119
935
  }
1120
- await applyDockerignore(contextDir, config);
936
+ if (pruneDockerignore) await applyDockerignore(contextDir, config);
1121
937
  return {
1122
938
  contextDir,
939
+ dockerignorePruned: pruneDockerignore,
1123
940
  cleanup: async () => {
1124
941
  await rm(contextDir, { recursive: true, force: true }).catch(() => {
1125
942
  });
@@ -1131,20 +948,42 @@ async function prepareSourceTree(config, opts) {
1131
948
  throw error;
1132
949
  }
1133
950
  }
951
+ function missingContextDockerfileMessage(contextSubdir, dockerfilePath, opts) {
952
+ const expected = normalizeDockerRelativePath(dockerfilePath) || "Dockerfile";
953
+ const at = `${contextSubdir}/${expected.startsWith(`${contextSubdir}/`) ? expected.slice(contextSubdir.length + 1) : expected}`;
954
+ return `No Dockerfile found in the build context "${contextSubdir}". Expected ${at}.` + // Names the file the build used to fall back to. Before #634 a build dir with no
955
+ // Dockerfile silently built the REPO ROOT's one under this service's tag, so an
956
+ // upgrade turns those deploys from "green with the wrong image" to red — and
957
+ // without this sentence the red gives no clue why.
958
+ (opts?.rootDockerfileExists ? " The source root has a Dockerfile, but it is outside this service's build context, so it is not used \u2014 set the service's build path to the directory that holds the Dockerfile you want, or add one there." : "") + (opts?.generatedRecipeRefused ? " A declared build context builds from its own Dockerfile \u2014 Openship will not generate one for it, because a generated recipe copies from the source root." : "");
959
+ }
1134
960
  async function resolveServiceDockerfile(contextDir, config, opts) {
1135
961
  const requireRepositoryDockerfile = opts?.requireRepositoryDockerfile ?? false;
1136
962
  const generatedName = opts?.generatedName ?? GENERATED_DOCKERFILE_NAME;
1137
- const resolvedRootDirectory = await resolveDockerRootDirectory(
1138
- contextDir,
1139
- config.rootDirectory,
1140
- config.localPath
1141
- );
1142
- const repositoryDockerfileName = await resolveDockerfileName(
1143
- contextDir,
1144
- resolvedRootDirectory,
1145
- config.dockerfilePath
1146
- );
963
+ const contextSubdir = dockerBuildContextDirectory(config);
964
+ const buildContextDir = await resolveBuildContextDir(contextDir, contextSubdir);
965
+ const resolvedRootDirectory = contextSubdir ? contextSubdir : await resolveDockerRootDirectory(contextDir, config.rootDirectory, config.localPath);
966
+ const repositoryDockerfileName = contextSubdir ? await firstExistingCandidate(
967
+ buildContextDir,
968
+ resolveContextDockerfileCandidates(contextSubdir, config.dockerfilePath)
969
+ ) : await resolveDockerfileName(contextDir, resolvedRootDirectory, config.dockerfilePath);
1147
970
  const hasRepositoryDockerfile = repositoryDockerfileName !== null;
971
+ if (!hasRepositoryDockerfile && contextSubdir) {
972
+ throw new Error(
973
+ missingContextDockerfileMessage(contextSubdir, config.dockerfilePath, {
974
+ generatedRecipeRefused: !requireRepositoryDockerfile,
975
+ rootDockerfileExists: await access(join(contextDir, "Dockerfile")).then(() => true).catch(() => false)
976
+ })
977
+ );
978
+ }
979
+ const explicitDockerfile = normalizeDockerRelativePath(config.dockerfilePath);
980
+ if (contextSubdir && explicitDockerfile && repositoryDockerfileName === "Dockerfile" && explicitDockerfile !== "Dockerfile" && explicitDockerfile !== `${contextSubdir}/Dockerfile`) {
981
+ opts?.onLog?.({
982
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
983
+ message: `Configured Dockerfile "${config.dockerfilePath}" was not found in build context "${contextSubdir}" \u2014 using ${contextSubdir}/Dockerfile instead.`,
984
+ level: "warn"
985
+ });
986
+ }
1148
987
  if (!hasRepositoryDockerfile && requireRepositoryDockerfile) {
1149
988
  const expectedDockerfile = config.dockerfilePath?.trim() || "Dockerfile";
1150
989
  throw new Error(
@@ -1153,7 +992,7 @@ async function resolveServiceDockerfile(contextDir, config, opts) {
1153
992
  }
1154
993
  if (!hasRepositoryDockerfile) {
1155
994
  await writeFile(
1156
- join2(contextDir, generatedName),
995
+ join(contextDir, generatedName),
1157
996
  generateDockerfile({
1158
997
  ...config,
1159
998
  rootDirectory: resolvedRootDirectory
@@ -1161,26 +1000,34 @@ async function resolveServiceDockerfile(contextDir, config, opts) {
1161
1000
  "utf-8"
1162
1001
  );
1163
1002
  }
1164
- const contextEntries = await readdir2(contextDir);
1003
+ const dockerfileName = repositoryDockerfileName ?? generatedName;
1004
+ const requiresBuildKit = hasRepositoryDockerfile ? await readFile(join(buildContextDir, ...dockerfileName.split("/")), "utf-8").then(dockerfileNeedsBuildKit).catch(() => false) : false;
1005
+ const ignoreContextPath = opts?.dockerignorePruned === false ? await loadContextIgnore(buildContextDir, contextKeepPaths(dockerfileName)) : void 0;
1006
+ const contextEntries = (await readdir(buildContextDir)).filter(
1007
+ (entry) => !ignoreContextPath?.(entry)
1008
+ );
1165
1009
  return {
1010
+ buildContextDir,
1011
+ contextSubdir,
1166
1012
  contextEntries,
1167
- dockerfileName: repositoryDockerfileName ?? generatedName,
1013
+ ignoreContextPath,
1014
+ dockerfileName,
1168
1015
  rootDirectory: resolvedRootDirectory,
1169
- usesRepositoryDockerfile: hasRepositoryDockerfile
1016
+ usesRepositoryDockerfile: hasRepositoryDockerfile,
1017
+ requiresBuildKit
1170
1018
  };
1171
1019
  }
1172
1020
  async function createDockerBuildContext(config, opts) {
1173
1021
  const tree = await prepareSourceTree(config, { onLog: opts?.onLog });
1174
1022
  try {
1175
1023
  const resolved = await resolveServiceDockerfile(tree.contextDir, config, {
1176
- requireRepositoryDockerfile: opts?.requireRepositoryDockerfile
1024
+ requireRepositoryDockerfile: opts?.requireRepositoryDockerfile,
1025
+ dockerignorePruned: tree.dockerignorePruned,
1026
+ onLog: opts?.onLog
1177
1027
  });
1178
1028
  return {
1029
+ ...resolved,
1179
1030
  contextDir: tree.contextDir,
1180
- contextEntries: resolved.contextEntries,
1181
- dockerfileName: resolved.dockerfileName,
1182
- rootDirectory: resolved.rootDirectory,
1183
- usesRepositoryDockerfile: resolved.usesRepositoryDockerfile,
1184
1031
  cleanup: tree.cleanup
1185
1032
  };
1186
1033
  } catch (error) {
@@ -1190,12 +1037,9 @@ async function createDockerBuildContext(config, opts) {
1190
1037
  }
1191
1038
 
1192
1039
  export {
1193
- normalizeDockerRelativePath,
1194
- resolveWithinDirectory,
1195
- resolveDockerfileCandidates,
1196
- staticBuilderOutputPath,
1197
- generateDockerfile,
1040
+ BuildKitTraceDecoder,
1198
1041
  prepareSourceTree,
1042
+ missingContextDockerfileMessage,
1199
1043
  resolveServiceDockerfile,
1200
1044
  createDockerBuildContext
1201
1045
  };