@xcanwin/manyoyo 5.8.6 → 5.8.10
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/bin/manyoyo.js +63 -157
- package/lib/global-config.js +1 -198
- package/lib/image-build.js +20 -4
- package/lib/init-config.js +22 -10
- package/lib/json5-text-edit.js +238 -0
- package/lib/runtime-normalizers.js +65 -0
- package/lib/runtime-resolver.js +195 -0
- package/lib/web/server.js +76 -315
- package/package.json +1 -1
package/lib/web/server.js
CHANGED
|
@@ -10,6 +10,13 @@ const WebSocket = require('ws');
|
|
|
10
10
|
const JSON5 = require('json5');
|
|
11
11
|
const { buildContainerRunArgs } = require('../container-run');
|
|
12
12
|
const { extractAgentMessageFromCodexJsonl } = require('../codex-output');
|
|
13
|
+
const { findValueRangeByPath, applyTextReplacements } = require('../json5-text-edit');
|
|
14
|
+
const { resolveRuntimeConfig } = require('../runtime-resolver');
|
|
15
|
+
const {
|
|
16
|
+
parseEnvEntry,
|
|
17
|
+
expandHomeAliasPath,
|
|
18
|
+
normalizeVolume
|
|
19
|
+
} = require('../runtime-normalizers');
|
|
13
20
|
const {
|
|
14
21
|
resolveAgentProgram,
|
|
15
22
|
resolveAgentPromptCommandTemplate,
|
|
@@ -1636,226 +1643,6 @@ function isSensitiveConfigKey(key) {
|
|
|
1636
1643
|
return Boolean(normalized) && SENSITIVE_CONFIG_KEY_PATTERN.test(normalized);
|
|
1637
1644
|
}
|
|
1638
1645
|
|
|
1639
|
-
function readConfigQuotedString(text, startIndex) {
|
|
1640
|
-
const quote = text[startIndex];
|
|
1641
|
-
let value = '';
|
|
1642
|
-
|
|
1643
|
-
for (let i = startIndex + 1; i < text.length; i += 1) {
|
|
1644
|
-
const ch = text[i];
|
|
1645
|
-
if (ch === '\\') {
|
|
1646
|
-
value += ch;
|
|
1647
|
-
if (i + 1 < text.length) {
|
|
1648
|
-
value += text[i + 1];
|
|
1649
|
-
i += 1;
|
|
1650
|
-
}
|
|
1651
|
-
continue;
|
|
1652
|
-
}
|
|
1653
|
-
if (ch === quote) {
|
|
1654
|
-
return {
|
|
1655
|
-
value,
|
|
1656
|
-
end: i + 1
|
|
1657
|
-
};
|
|
1658
|
-
}
|
|
1659
|
-
value += ch;
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
return null;
|
|
1663
|
-
}
|
|
1664
|
-
|
|
1665
|
-
function isConfigIdentifierStart(ch) {
|
|
1666
|
-
return /[A-Za-z_$]/.test(ch);
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
function isConfigIdentifierPart(ch) {
|
|
1670
|
-
return /[A-Za-z0-9_$]/.test(ch);
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
function skipConfigTrivia(text, index) {
|
|
1674
|
-
let cursor = index;
|
|
1675
|
-
while (cursor < text.length) {
|
|
1676
|
-
const ch = text[cursor];
|
|
1677
|
-
const next = text[cursor + 1];
|
|
1678
|
-
if (/\s/.test(ch)) {
|
|
1679
|
-
cursor += 1;
|
|
1680
|
-
continue;
|
|
1681
|
-
}
|
|
1682
|
-
if (ch === '/' && next === '/') {
|
|
1683
|
-
cursor += 2;
|
|
1684
|
-
while (cursor < text.length && text[cursor] !== '\n') {
|
|
1685
|
-
cursor += 1;
|
|
1686
|
-
}
|
|
1687
|
-
continue;
|
|
1688
|
-
}
|
|
1689
|
-
if (ch === '/' && next === '*') {
|
|
1690
|
-
cursor += 2;
|
|
1691
|
-
while (cursor + 1 < text.length && !(text[cursor] === '*' && text[cursor + 1] === '/')) {
|
|
1692
|
-
cursor += 1;
|
|
1693
|
-
}
|
|
1694
|
-
cursor = cursor + 1 < text.length ? cursor + 2 : text.length;
|
|
1695
|
-
continue;
|
|
1696
|
-
}
|
|
1697
|
-
break;
|
|
1698
|
-
}
|
|
1699
|
-
return cursor;
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
function scanConfigValueEnd(text, startIndex) {
|
|
1703
|
-
let cursor = startIndex;
|
|
1704
|
-
let stringQuote = '';
|
|
1705
|
-
let lineComment = false;
|
|
1706
|
-
let blockComment = false;
|
|
1707
|
-
let depth = 0;
|
|
1708
|
-
|
|
1709
|
-
for (; cursor < text.length; cursor += 1) {
|
|
1710
|
-
const ch = text[cursor];
|
|
1711
|
-
const next = text[cursor + 1];
|
|
1712
|
-
|
|
1713
|
-
if (lineComment) {
|
|
1714
|
-
if (ch === '\n') {
|
|
1715
|
-
lineComment = false;
|
|
1716
|
-
}
|
|
1717
|
-
continue;
|
|
1718
|
-
}
|
|
1719
|
-
if (blockComment) {
|
|
1720
|
-
if (ch === '*' && next === '/') {
|
|
1721
|
-
blockComment = false;
|
|
1722
|
-
cursor += 1;
|
|
1723
|
-
}
|
|
1724
|
-
continue;
|
|
1725
|
-
}
|
|
1726
|
-
if (stringQuote) {
|
|
1727
|
-
if (ch === '\\') {
|
|
1728
|
-
cursor += 1;
|
|
1729
|
-
continue;
|
|
1730
|
-
}
|
|
1731
|
-
if (ch === stringQuote) {
|
|
1732
|
-
stringQuote = '';
|
|
1733
|
-
}
|
|
1734
|
-
continue;
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
if (ch === '/' && next === '/') {
|
|
1738
|
-
lineComment = true;
|
|
1739
|
-
cursor += 1;
|
|
1740
|
-
continue;
|
|
1741
|
-
}
|
|
1742
|
-
if (ch === '/' && next === '*') {
|
|
1743
|
-
blockComment = true;
|
|
1744
|
-
cursor += 1;
|
|
1745
|
-
continue;
|
|
1746
|
-
}
|
|
1747
|
-
if (ch === '"' || ch === '\'') {
|
|
1748
|
-
stringQuote = ch;
|
|
1749
|
-
continue;
|
|
1750
|
-
}
|
|
1751
|
-
if (ch === '{' || ch === '[' || ch === '(') {
|
|
1752
|
-
depth += 1;
|
|
1753
|
-
continue;
|
|
1754
|
-
}
|
|
1755
|
-
if (ch === '}' || ch === ']' || ch === ')') {
|
|
1756
|
-
if (depth === 0) {
|
|
1757
|
-
break;
|
|
1758
|
-
}
|
|
1759
|
-
depth -= 1;
|
|
1760
|
-
continue;
|
|
1761
|
-
}
|
|
1762
|
-
if (depth === 0 && ch === ',') {
|
|
1763
|
-
break;
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
let end = cursor;
|
|
1768
|
-
while (end > startIndex && /\s/.test(text[end - 1])) {
|
|
1769
|
-
end -= 1;
|
|
1770
|
-
}
|
|
1771
|
-
return end;
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
function findConfigRootObjectStart(text) {
|
|
1775
|
-
const start = skipConfigTrivia(String(text || ''), 0);
|
|
1776
|
-
return text[start] === '{' ? start : -1;
|
|
1777
|
-
}
|
|
1778
|
-
|
|
1779
|
-
function readConfigPropertyToken(text, startIndex) {
|
|
1780
|
-
const ch = text[startIndex];
|
|
1781
|
-
if (ch === '"' || ch === '\'') {
|
|
1782
|
-
const token = readConfigQuotedString(text, startIndex);
|
|
1783
|
-
if (!token) {
|
|
1784
|
-
return null;
|
|
1785
|
-
}
|
|
1786
|
-
return token;
|
|
1787
|
-
}
|
|
1788
|
-
if (!isConfigIdentifierStart(ch)) {
|
|
1789
|
-
return null;
|
|
1790
|
-
}
|
|
1791
|
-
let end = startIndex + 1;
|
|
1792
|
-
while (end < text.length && isConfigIdentifierPart(text[end])) {
|
|
1793
|
-
end += 1;
|
|
1794
|
-
}
|
|
1795
|
-
return {
|
|
1796
|
-
value: text.slice(startIndex, end),
|
|
1797
|
-
end
|
|
1798
|
-
};
|
|
1799
|
-
}
|
|
1800
|
-
|
|
1801
|
-
function findConfigObjectPropertyValueRange(text, objectStartIndex, propertyName) {
|
|
1802
|
-
let cursor = skipConfigTrivia(text, objectStartIndex + 1);
|
|
1803
|
-
while (cursor < text.length) {
|
|
1804
|
-
cursor = skipConfigTrivia(text, cursor);
|
|
1805
|
-
if (text[cursor] === '}') {
|
|
1806
|
-
return null;
|
|
1807
|
-
}
|
|
1808
|
-
const token = readConfigPropertyToken(text, cursor);
|
|
1809
|
-
if (!token) {
|
|
1810
|
-
return null;
|
|
1811
|
-
}
|
|
1812
|
-
cursor = skipConfigTrivia(text, token.end);
|
|
1813
|
-
if (text[cursor] !== ':') {
|
|
1814
|
-
return null;
|
|
1815
|
-
}
|
|
1816
|
-
const valueStart = skipConfigTrivia(text, cursor + 1);
|
|
1817
|
-
const valueEnd = scanConfigValueEnd(text, valueStart);
|
|
1818
|
-
if (token.value === propertyName) {
|
|
1819
|
-
return { start: valueStart, end: valueEnd };
|
|
1820
|
-
}
|
|
1821
|
-
cursor = skipConfigTrivia(text, valueEnd);
|
|
1822
|
-
if (text[cursor] === ',') {
|
|
1823
|
-
cursor += 1;
|
|
1824
|
-
continue;
|
|
1825
|
-
}
|
|
1826
|
-
if (text[cursor] === '}') {
|
|
1827
|
-
return null;
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
return null;
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
function findConfigValueRangeByPath(text, pathParts) {
|
|
1834
|
-
if (!Array.isArray(pathParts) || pathParts.length === 0) {
|
|
1835
|
-
return null;
|
|
1836
|
-
}
|
|
1837
|
-
let objectStart = findConfigRootObjectStart(text);
|
|
1838
|
-
if (objectStart === -1) {
|
|
1839
|
-
return null;
|
|
1840
|
-
}
|
|
1841
|
-
let range = null;
|
|
1842
|
-
for (let i = 0; i < pathParts.length; i += 1) {
|
|
1843
|
-
range = findConfigObjectPropertyValueRange(text, objectStart, pathParts[i]);
|
|
1844
|
-
if (!range) {
|
|
1845
|
-
return null;
|
|
1846
|
-
}
|
|
1847
|
-
if (i === pathParts.length - 1) {
|
|
1848
|
-
return range;
|
|
1849
|
-
}
|
|
1850
|
-
const nextObjectStart = skipConfigTrivia(text, range.start);
|
|
1851
|
-
if (text[nextObjectStart] !== '{') {
|
|
1852
|
-
return null;
|
|
1853
|
-
}
|
|
1854
|
-
objectStart = nextObjectStart;
|
|
1855
|
-
}
|
|
1856
|
-
return range;
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
1646
|
function collectSensitiveConfigPaths(value, pathParts = []) {
|
|
1860
1647
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1861
1648
|
return [];
|
|
@@ -1894,13 +1681,6 @@ function collectSensitivePlaceholderPaths(value, pathParts = []) {
|
|
|
1894
1681
|
return result;
|
|
1895
1682
|
}
|
|
1896
1683
|
|
|
1897
|
-
function applyConfigTextReplacements(text, replacements) {
|
|
1898
|
-
return replacements
|
|
1899
|
-
.slice()
|
|
1900
|
-
.sort((a, b) => b.start - a.start)
|
|
1901
|
-
.reduce((result, item) => `${result.slice(0, item.start)}${item.text}${result.slice(item.end)}`, text);
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
1684
|
function buildConfigPathLabel(pathParts) {
|
|
1905
1685
|
return (Array.isArray(pathParts) ? pathParts : []).join('.');
|
|
1906
1686
|
}
|
|
@@ -1908,7 +1688,7 @@ function buildConfigPathLabel(pathParts) {
|
|
|
1908
1688
|
function maskWebConfigRaw(raw, parsed) {
|
|
1909
1689
|
const text = String(raw || '');
|
|
1910
1690
|
const replacements = collectSensitiveConfigPaths(parsed).map(pathParts => {
|
|
1911
|
-
const range =
|
|
1691
|
+
const range = findValueRangeByPath(text, pathParts);
|
|
1912
1692
|
if (!range) {
|
|
1913
1693
|
throw new Error(`敏感字段定位失败: ${buildConfigPathLabel(pathParts)}`);
|
|
1914
1694
|
}
|
|
@@ -1918,7 +1698,7 @@ function maskWebConfigRaw(raw, parsed) {
|
|
|
1918
1698
|
text: JSON.stringify(WEB_CONFIG_KEEP_SECRET_PLACEHOLDER)
|
|
1919
1699
|
};
|
|
1920
1700
|
});
|
|
1921
|
-
return
|
|
1701
|
+
return applyTextReplacements(text, replacements);
|
|
1922
1702
|
}
|
|
1923
1703
|
|
|
1924
1704
|
function parseConfigRawObject(raw) {
|
|
@@ -1946,8 +1726,8 @@ function restoreWebConfigSecrets(raw, snapshot) {
|
|
|
1946
1726
|
|
|
1947
1727
|
const currentRaw = String(snapshot.raw || '');
|
|
1948
1728
|
const replacements = placeholderPaths.map(pathParts => {
|
|
1949
|
-
const editedRange =
|
|
1950
|
-
const currentRange =
|
|
1729
|
+
const editedRange = findValueRangeByPath(text, pathParts);
|
|
1730
|
+
const currentRange = findValueRangeByPath(currentRaw, pathParts);
|
|
1951
1731
|
if (!editedRange) {
|
|
1952
1732
|
throw new Error(`敏感字段定位失败: ${buildConfigPathLabel(pathParts)}`);
|
|
1953
1733
|
}
|
|
@@ -1961,7 +1741,7 @@ function restoreWebConfigSecrets(raw, snapshot) {
|
|
|
1961
1741
|
};
|
|
1962
1742
|
});
|
|
1963
1743
|
|
|
1964
|
-
return
|
|
1744
|
+
return applyTextReplacements(text, replacements);
|
|
1965
1745
|
}
|
|
1966
1746
|
|
|
1967
1747
|
function redactConfigValue(value) {
|
|
@@ -2078,23 +1858,6 @@ function validateWebHostPath(hostPath) {
|
|
|
2078
1858
|
}
|
|
2079
1859
|
}
|
|
2080
1860
|
|
|
2081
|
-
function parseEnvEntry(entryText) {
|
|
2082
|
-
const text = String(entryText || '');
|
|
2083
|
-
const idx = text.indexOf('=');
|
|
2084
|
-
if (idx <= 0) {
|
|
2085
|
-
throw new Error(`env 格式应为 KEY=VALUE: ${text}`);
|
|
2086
|
-
}
|
|
2087
|
-
const key = text.slice(0, idx);
|
|
2088
|
-
const value = text.slice(idx + 1);
|
|
2089
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
2090
|
-
throw new Error(`env key 非法: ${key}`);
|
|
2091
|
-
}
|
|
2092
|
-
if (/[\r\n\0]/.test(value) || /[;&|`$<>]/.test(value)) {
|
|
2093
|
-
throw new Error(`env value 含非法字符: ${key}`);
|
|
2094
|
-
}
|
|
2095
|
-
return { key, value };
|
|
2096
|
-
}
|
|
2097
|
-
|
|
2098
1861
|
function normalizeEnvMap(envConfig, sourceLabel) {
|
|
2099
1862
|
if (envConfig === undefined || envConfig === null) {
|
|
2100
1863
|
return {};
|
|
@@ -2113,6 +1876,15 @@ function normalizeEnvMap(envConfig, sourceLabel) {
|
|
|
2113
1876
|
return result;
|
|
2114
1877
|
}
|
|
2115
1878
|
|
|
1879
|
+
function normalizeCliEnvMap(envList) {
|
|
1880
|
+
const result = {};
|
|
1881
|
+
for (const envText of (envList || [])) {
|
|
1882
|
+
const parsed = parseEnvEntry(envText);
|
|
1883
|
+
result[parsed.key] = parsed.value;
|
|
1884
|
+
}
|
|
1885
|
+
return result;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
2116
1888
|
function normalizeStringArray(value, sourceLabel) {
|
|
2117
1889
|
if (value === undefined || value === null) {
|
|
2118
1890
|
return [];
|
|
@@ -2125,41 +1897,6 @@ function normalizeStringArray(value, sourceLabel) {
|
|
|
2125
1897
|
.filter(Boolean);
|
|
2126
1898
|
}
|
|
2127
1899
|
|
|
2128
|
-
function expandHomeAliasPath(filePath) {
|
|
2129
|
-
const text = String(filePath || '').trim();
|
|
2130
|
-
if (!text) {
|
|
2131
|
-
return text;
|
|
2132
|
-
}
|
|
2133
|
-
const homeDir = os.homedir();
|
|
2134
|
-
if (text === '~') {
|
|
2135
|
-
return homeDir;
|
|
2136
|
-
}
|
|
2137
|
-
if (text.startsWith('~/')) {
|
|
2138
|
-
return path.join(homeDir, text.slice(2));
|
|
2139
|
-
}
|
|
2140
|
-
if (text === '$HOME') {
|
|
2141
|
-
return homeDir;
|
|
2142
|
-
}
|
|
2143
|
-
if (text.startsWith('$HOME/')) {
|
|
2144
|
-
return path.join(homeDir, text.slice('$HOME/'.length));
|
|
2145
|
-
}
|
|
2146
|
-
return text;
|
|
2147
|
-
}
|
|
2148
|
-
|
|
2149
|
-
function normalizeVolume(volume) {
|
|
2150
|
-
const text = String(volume || '').trim();
|
|
2151
|
-
if (!text.startsWith('~') && !text.startsWith('$HOME')) {
|
|
2152
|
-
return text;
|
|
2153
|
-
}
|
|
2154
|
-
const separatorIndex = text.indexOf(':');
|
|
2155
|
-
if (separatorIndex === -1) {
|
|
2156
|
-
return expandHomeAliasPath(text);
|
|
2157
|
-
}
|
|
2158
|
-
const hostPath = text.slice(0, separatorIndex);
|
|
2159
|
-
const rest = text.slice(separatorIndex);
|
|
2160
|
-
return `${expandHomeAliasPath(hostPath)}${rest}`;
|
|
2161
|
-
}
|
|
2162
|
-
|
|
2163
1900
|
function parseEnvFileToArgs(filePath) {
|
|
2164
1901
|
const resolvedPath = expandHomeAliasPath(filePath);
|
|
2165
1902
|
if (!path.isAbsolute(resolvedPath)) {
|
|
@@ -2429,29 +2166,65 @@ function buildCreateRuntime(ctx, state, payload) {
|
|
|
2429
2166
|
const hasConfigPorts = hasOwn(config, 'ports');
|
|
2430
2167
|
|
|
2431
2168
|
const requestName = pickFirstString(requestOptions.containerName, body.name);
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2169
|
+
const requestEnvMap = hasRequestEnv ? normalizeEnvMap(requestOptions.env, 'createOptions.env') : {};
|
|
2170
|
+
const requestEnvList = Object.entries(requestEnvMap).map(([key, value]) => `${key}=${value}`);
|
|
2171
|
+
const requestEnvFileList = hasRequestEnvFile ? normalizeStringArray(requestOptions.envFile, 'createOptions.envFile') : [];
|
|
2172
|
+
const requestVolumeList = hasRequestVolumes ? normalizeStringArray(requestOptions.volumes, 'createOptions.volumes') : [];
|
|
2173
|
+
const requestPortList = hasRequestPorts ? normalizeStringArray(requestOptions.ports, 'createOptions.ports') : [];
|
|
2174
|
+
|
|
2175
|
+
const resolvedBase = resolveRuntimeConfig({
|
|
2176
|
+
cliOptions: {
|
|
2177
|
+
hostPath: requestOptions.hostPath,
|
|
2178
|
+
contName: requestName,
|
|
2179
|
+
contPath: requestOptions.containerPath,
|
|
2180
|
+
imageName: requestOptions.imageName,
|
|
2181
|
+
imageVer: requestOptions.imageVersion,
|
|
2182
|
+
env: requestEnvList,
|
|
2183
|
+
envFile: requestEnvFileList,
|
|
2184
|
+
volume: requestVolumeList,
|
|
2185
|
+
port: requestPortList
|
|
2186
|
+
},
|
|
2187
|
+
globalConfig: config,
|
|
2188
|
+
runConfig,
|
|
2189
|
+
globalFirstConfig: {},
|
|
2190
|
+
runFirstConfig: {},
|
|
2191
|
+
defaults: {
|
|
2192
|
+
hostPath: ctx.hostPath,
|
|
2193
|
+
containerName: `my-${ctx.formatDate()}`,
|
|
2194
|
+
containerPath: ctx.containerPath,
|
|
2195
|
+
imageName: ctx.imageName,
|
|
2196
|
+
imageVersion: ctx.imageVersion
|
|
2197
|
+
},
|
|
2198
|
+
envVars: {},
|
|
2199
|
+
argv: [],
|
|
2200
|
+
isServerMode: false,
|
|
2201
|
+
isServerStopMode: false,
|
|
2202
|
+
pickConfigValue: pickFirstString,
|
|
2203
|
+
resolveContainerNameTemplate: value => resolveNowTemplate(value, ctx.formatDate),
|
|
2204
|
+
normalizeCommandSuffix: value => {
|
|
2205
|
+
const text = String(value || '').trim();
|
|
2206
|
+
return text ? ` ${text}` : '';
|
|
2207
|
+
},
|
|
2208
|
+
normalizeJsonEnvMap: normalizeEnvMap,
|
|
2209
|
+
normalizeCliEnvMap,
|
|
2210
|
+
mergeArrayConfig: (globalValue, runValue, cliValue) => [...(globalValue || []), ...(runValue || []), ...(cliValue || [])],
|
|
2211
|
+
normalizeVolume,
|
|
2212
|
+
parseServerListen: () => ({ host: '', port: 0 })
|
|
2213
|
+
});
|
|
2214
|
+
|
|
2215
|
+
const containerName = resolvedBase.containerName;
|
|
2437
2216
|
validateContainerNameStrict(containerName);
|
|
2438
2217
|
|
|
2439
|
-
const hostPath =
|
|
2218
|
+
const hostPath = resolvedBase.hostPath;
|
|
2440
2219
|
if (typeof ctx.validateHostPath === 'function') {
|
|
2441
2220
|
ctx.validateHostPath(hostPath);
|
|
2442
2221
|
} else {
|
|
2443
2222
|
validateWebHostPath(hostPath);
|
|
2444
2223
|
}
|
|
2445
2224
|
|
|
2446
|
-
const containerPath =
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
config.containerPath,
|
|
2450
|
-
ctx.containerPath,
|
|
2451
|
-
hostPath
|
|
2452
|
-
) || hostPath;
|
|
2453
|
-
const imageName = pickFirstString(requestOptions.imageName, runConfig.imageName, config.imageName, ctx.imageName);
|
|
2454
|
-
const imageVersion = pickFirstString(requestOptions.imageVersion, runConfig.imageVersion, config.imageVersion, ctx.imageVersion);
|
|
2225
|
+
const containerPath = resolvedBase.containerPath || hostPath;
|
|
2226
|
+
const imageName = resolvedBase.imageName;
|
|
2227
|
+
const imageVersion = resolvedBase.imageVersion;
|
|
2455
2228
|
|
|
2456
2229
|
if (!/^[A-Za-z0-9][A-Za-z0-9._/:-]*$/.test(imageName)) {
|
|
2457
2230
|
throw new Error(`imageName 非法: ${imageName}`);
|
|
@@ -2510,20 +2283,14 @@ function buildCreateRuntime(ctx, state, payload) {
|
|
|
2510
2283
|
const hasRunEnv = hasOwn(runConfig, 'env');
|
|
2511
2284
|
const hasRunEnvFile = hasOwn(runConfig, 'envFile');
|
|
2512
2285
|
if (hasRequestEnv || hasRequestEnvFile || hasRunEnv || hasRunEnvFile || hasConfigEnv || hasConfigEnvFile) {
|
|
2513
|
-
const
|
|
2514
|
-
const runEnv = normalizeEnvMap(runConfig.env, runName ? `runs.${runName}.env` : 'run.env');
|
|
2515
|
-
const requestEnv = hasRequestEnv ? normalizeEnvMap(requestOptions.env, 'createOptions.env') : {};
|
|
2516
|
-
const mergedEnv = { ...configEnv, ...runEnv, ...requestEnv };
|
|
2286
|
+
const mergedEnv = resolvedBase.env;
|
|
2517
2287
|
const envArgs = [];
|
|
2518
2288
|
Object.entries(mergedEnv).forEach(([key, value]) => {
|
|
2519
2289
|
const parsed = parseEnvEntry(`${key}=${value}`);
|
|
2520
2290
|
envArgs.push('--env', `${parsed.key}=${parsed.value}`);
|
|
2521
2291
|
});
|
|
2522
2292
|
|
|
2523
|
-
const envFileList =
|
|
2524
|
-
.concat(normalizeStringArray(config.envFile, 'config.envFile'))
|
|
2525
|
-
.concat(normalizeStringArray(runConfig.envFile, runName ? `runs.${runName}.envFile` : 'run.envFile'))
|
|
2526
|
-
.concat(hasRequestEnvFile ? normalizeStringArray(requestOptions.envFile, 'createOptions.envFile') : []);
|
|
2293
|
+
const envFileList = resolvedBase.envFile;
|
|
2527
2294
|
const envFileArgs = [];
|
|
2528
2295
|
envFileList.forEach(filePath => {
|
|
2529
2296
|
envFileArgs.push(...parseEnvFileToArgs(filePath));
|
|
@@ -2535,10 +2302,7 @@ function buildCreateRuntime(ctx, state, payload) {
|
|
|
2535
2302
|
let containerVolumes = Array.isArray(ctx.containerVolumes) ? ctx.containerVolumes.slice() : [];
|
|
2536
2303
|
const hasRunVolumes = hasOwn(runConfig, 'volumes');
|
|
2537
2304
|
if (hasRequestVolumes || hasRunVolumes || hasConfigVolumes) {
|
|
2538
|
-
const volumeList =
|
|
2539
|
-
.concat(normalizeStringArray(config.volumes, 'config.volumes'))
|
|
2540
|
-
.concat(normalizeStringArray(runConfig.volumes, runName ? `runs.${runName}.volumes` : 'run.volumes'))
|
|
2541
|
-
.concat(hasRequestVolumes ? normalizeStringArray(requestOptions.volumes, 'createOptions.volumes') : []);
|
|
2305
|
+
const volumeList = resolvedBase.volumes;
|
|
2542
2306
|
containerVolumes = [];
|
|
2543
2307
|
volumeList.forEach(volume => {
|
|
2544
2308
|
containerVolumes.push('--volume', normalizeVolume(volume));
|
|
@@ -2548,10 +2312,7 @@ function buildCreateRuntime(ctx, state, payload) {
|
|
|
2548
2312
|
let containerPorts = Array.isArray(ctx.containerPorts) ? ctx.containerPorts.slice() : [];
|
|
2549
2313
|
const hasRunPorts = hasOwn(runConfig, 'ports');
|
|
2550
2314
|
if (hasRequestPorts || hasRunPorts || hasConfigPorts) {
|
|
2551
|
-
const portList =
|
|
2552
|
-
.concat(normalizeStringArray(config.ports, 'config.ports'))
|
|
2553
|
-
.concat(normalizeStringArray(runConfig.ports, runName ? `runs.${runName}.ports` : 'run.ports'))
|
|
2554
|
-
.concat(hasRequestPorts ? normalizeStringArray(requestOptions.ports, 'createOptions.ports') : []);
|
|
2315
|
+
const portList = resolvedBase.ports;
|
|
2555
2316
|
containerPorts = [];
|
|
2556
2317
|
portList.forEach(port => {
|
|
2557
2318
|
containerPorts.push('--publish', port);
|