Merge pull request #94 from crazy-max/exec-output

Use built-in `getExecOutput`
This commit is contained in:
CrazyMax 2021-06-23 16:42:15 +02:00 committed by GitHub
commit e168301d39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 569 additions and 579 deletions

@ -1,18 +1,40 @@
import fs = require('fs'); import fs = require('fs');
import * as docker from '../src/docker';
import * as buildx from '../src/buildx'; import * as buildx from '../src/buildx';
import * as path from 'path'; import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import * as semver from 'semver'; import * as semver from 'semver';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
describe('isAvailable', () => {
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput');
buildx.isAvailable();
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
silent: true,
ignoreReturnCode: true
});
});
describe('getVersion', () => { describe('getVersion', () => {
it('valid', async () => { async function isDaemonRunning() {
await exec.exec('docker', ['buildx', 'version']); return await exec
const version = await buildx.getVersion(); .getExecOutput(`docker`, ['version', '--format', '{{.Server.Os}}'], {
console.log(`version: ${version}`); ignoreReturnCode: true,
expect(semver.valid(version)).not.toBeNull(); silent: true
}, 100000); })
.then(res => {
return !res.stdout.includes(' ') && res.exitCode == 0;
});
}
(isDaemonRunning() ? it : it.skip)(
'valid',
async () => {
const version = await buildx.getVersion();
console.log(`version: ${version}`);
expect(semver.valid(version)).not.toBeNull();
},
100000
);
}); });
describe('parseVersion', () => { describe('parseVersion', () => {
@ -27,7 +49,14 @@ describe('parseVersion', () => {
describe('inspect', () => { describe('inspect', () => {
async function isDaemonRunning() { async function isDaemonRunning() {
return await docker.isDaemonRunning(); return await exec
.getExecOutput(`docker`, ['version', '--format', '{{.Server.Os}}'], {
ignoreReturnCode: true,
silent: true
})
.then(res => {
return !res.stdout.includes(' ') && res.exitCode == 0;
});
} }
(isDaemonRunning() ? it : it.skip)( (isDaemonRunning() ? it : it.skip)(
'valid', 'valid',

860
dist/index.js generated vendored

@ -49,6 +49,13 @@ module.exports =
/************************************************************************/ /************************************************************************/
/******/ ({ /******/ ({
/***/ 4:
/***/ (function(module) {
module.exports = require("child_process");
/***/ }),
/***/ 8: /***/ 8:
/***/ (function(module, __unusedexports, __webpack_require__) { /***/ (function(module, __unusedexports, __webpack_require__) {
@ -509,15 +516,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}); });
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(__webpack_require__(186));
const exec = __importStar(__webpack_require__(514));
const os = __importStar(__webpack_require__(87)); const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const semver = __importStar(__webpack_require__(383)); const semver = __importStar(__webpack_require__(383));
const buildx = __importStar(__webpack_require__(295)); const buildx = __importStar(__webpack_require__(295));
const context = __importStar(__webpack_require__(842)); const context = __importStar(__webpack_require__(842));
const mexec = __importStar(__webpack_require__(757));
const stateHelper = __importStar(__webpack_require__(647)); const stateHelper = __importStar(__webpack_require__(647));
const core = __importStar(__webpack_require__(186));
const exec = __importStar(__webpack_require__(514));
function run() { function run() {
var _a; var _a;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@ -600,18 +606,26 @@ function cleanup() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) { if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
core.startGroup(`BuildKit container logs`); core.startGroup(`BuildKit container logs`);
yield mexec.exec('docker', ['logs', `${stateHelper.containerName}`], false).then(res => { yield exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
core.warning(res.stderr); ignoreReturnCode: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
} }
}); });
core.endGroup(); core.endGroup();
} }
if (stateHelper.builderName.length > 0) { if (stateHelper.builderName.length > 0) {
core.startGroup(`Removing builder`); core.startGroup(`Removing builder`);
yield mexec.exec('docker', ['buildx', 'rm', `${stateHelper.builderName}`], false).then(res => { yield exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput('docker', ['buildx', 'rm', `${stateHelper.builderName}`], {
core.warning(res.stderr); ignoreReturnCode: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
} }
}); });
core.endGroup(); core.endGroup();
@ -706,9 +720,344 @@ module.exports = gt
/***/ }), /***/ }),
/***/ 129: /***/ 129:
/***/ (function(module) { /***/ (function(module, __unusedexports, __webpack_require__) {
"use strict";
// A linked list to keep track of recently-used-ness
const Yallist = __webpack_require__(665)
const MAX = Symbol('max')
const LENGTH = Symbol('length')
const LENGTH_CALCULATOR = Symbol('lengthCalculator')
const ALLOW_STALE = Symbol('allowStale')
const MAX_AGE = Symbol('maxAge')
const DISPOSE = Symbol('dispose')
const NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet')
const LRU_LIST = Symbol('lruList')
const CACHE = Symbol('cache')
const UPDATE_AGE_ON_GET = Symbol('updateAgeOnGet')
const naiveLength = () => 1
// lruList is a yallist where the head is the youngest
// item, and the tail is the oldest. the list contains the Hit
// objects as the entries.
// Each Hit object has a reference to its Yallist.Node. This
// never changes.
//
// cache is a Map (or PseudoMap) that matches the keys to
// the Yallist.Node object.
class LRUCache {
constructor (options) {
if (typeof options === 'number')
options = { max: options }
if (!options)
options = {}
if (options.max && (typeof options.max !== 'number' || options.max < 0))
throw new TypeError('max must be a non-negative number')
// Kind of weird to have a default max of Infinity, but oh well.
const max = this[MAX] = options.max || Infinity
const lc = options.length || naiveLength
this[LENGTH_CALCULATOR] = (typeof lc !== 'function') ? naiveLength : lc
this[ALLOW_STALE] = options.stale || false
if (options.maxAge && typeof options.maxAge !== 'number')
throw new TypeError('maxAge must be a number')
this[MAX_AGE] = options.maxAge || 0
this[DISPOSE] = options.dispose
this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
this[UPDATE_AGE_ON_GET] = options.updateAgeOnGet || false
this.reset()
}
// resize the cache when the max changes.
set max (mL) {
if (typeof mL !== 'number' || mL < 0)
throw new TypeError('max must be a non-negative number')
this[MAX] = mL || Infinity
trim(this)
}
get max () {
return this[MAX]
}
set allowStale (allowStale) {
this[ALLOW_STALE] = !!allowStale
}
get allowStale () {
return this[ALLOW_STALE]
}
set maxAge (mA) {
if (typeof mA !== 'number')
throw new TypeError('maxAge must be a non-negative number')
this[MAX_AGE] = mA
trim(this)
}
get maxAge () {
return this[MAX_AGE]
}
// resize the cache when the lengthCalculator changes.
set lengthCalculator (lC) {
if (typeof lC !== 'function')
lC = naiveLength
if (lC !== this[LENGTH_CALCULATOR]) {
this[LENGTH_CALCULATOR] = lC
this[LENGTH] = 0
this[LRU_LIST].forEach(hit => {
hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
this[LENGTH] += hit.length
})
}
trim(this)
}
get lengthCalculator () { return this[LENGTH_CALCULATOR] }
get length () { return this[LENGTH] }
get itemCount () { return this[LRU_LIST].length }
rforEach (fn, thisp) {
thisp = thisp || this
for (let walker = this[LRU_LIST].tail; walker !== null;) {
const prev = walker.prev
forEachStep(this, fn, walker, thisp)
walker = prev
}
}
forEach (fn, thisp) {
thisp = thisp || this
for (let walker = this[LRU_LIST].head; walker !== null;) {
const next = walker.next
forEachStep(this, fn, walker, thisp)
walker = next
}
}
keys () {
return this[LRU_LIST].toArray().map(k => k.key)
}
values () {
return this[LRU_LIST].toArray().map(k => k.value)
}
reset () {
if (this[DISPOSE] &&
this[LRU_LIST] &&
this[LRU_LIST].length) {
this[LRU_LIST].forEach(hit => this[DISPOSE](hit.key, hit.value))
}
this[CACHE] = new Map() // hash of items by key
this[LRU_LIST] = new Yallist() // list of items in order of use recency
this[LENGTH] = 0 // length of items in the list
}
dump () {
return this[LRU_LIST].map(hit =>
isStale(this, hit) ? false : {
k: hit.key,
v: hit.value,
e: hit.now + (hit.maxAge || 0)
}).toArray().filter(h => h)
}
dumpLru () {
return this[LRU_LIST]
}
set (key, value, maxAge) {
maxAge = maxAge || this[MAX_AGE]
if (maxAge && typeof maxAge !== 'number')
throw new TypeError('maxAge must be a number')
const now = maxAge ? Date.now() : 0
const len = this[LENGTH_CALCULATOR](value, key)
if (this[CACHE].has(key)) {
if (len > this[MAX]) {
del(this, this[CACHE].get(key))
return false
}
const node = this[CACHE].get(key)
const item = node.value
// dispose of the old one before overwriting
// split out into 2 ifs for better coverage tracking
if (this[DISPOSE]) {
if (!this[NO_DISPOSE_ON_SET])
this[DISPOSE](key, item.value)
}
item.now = now
item.maxAge = maxAge
item.value = value
this[LENGTH] += len - item.length
item.length = len
this.get(key)
trim(this)
return true
}
const hit = new Entry(key, value, len, now, maxAge)
// oversized objects fall out of cache automatically.
if (hit.length > this[MAX]) {
if (this[DISPOSE])
this[DISPOSE](key, value)
return false
}
this[LENGTH] += hit.length
this[LRU_LIST].unshift(hit)
this[CACHE].set(key, this[LRU_LIST].head)
trim(this)
return true
}
has (key) {
if (!this[CACHE].has(key)) return false
const hit = this[CACHE].get(key).value
return !isStale(this, hit)
}
get (key) {
return get(this, key, true)
}
peek (key) {
return get(this, key, false)
}
pop () {
const node = this[LRU_LIST].tail
if (!node)
return null
del(this, node)
return node.value
}
del (key) {
del(this, this[CACHE].get(key))
}
load (arr) {
// reset the cache
this.reset()
const now = Date.now()
// A previous serialized cache has the most recent items first
for (let l = arr.length - 1; l >= 0; l--) {
const hit = arr[l]
const expiresAt = hit.e || 0
if (expiresAt === 0)
// the item was created without expiration in a non aged cache
this.set(hit.k, hit.v)
else {
const maxAge = expiresAt - now
// dont add already expired items
if (maxAge > 0) {
this.set(hit.k, hit.v, maxAge)
}
}
}
}
prune () {
this[CACHE].forEach((value, key) => get(this, key, false))
}
}
const get = (self, key, doUse) => {
const node = self[CACHE].get(key)
if (node) {
const hit = node.value
if (isStale(self, hit)) {
del(self, node)
if (!self[ALLOW_STALE])
return undefined
} else {
if (doUse) {
if (self[UPDATE_AGE_ON_GET])
node.value.now = Date.now()
self[LRU_LIST].unshiftNode(node)
}
}
return hit.value
}
}
const isStale = (self, hit) => {
if (!hit || (!hit.maxAge && !self[MAX_AGE]))
return false
const diff = Date.now() - hit.now
return hit.maxAge ? diff > hit.maxAge
: self[MAX_AGE] && (diff > self[MAX_AGE])
}
const trim = self => {
if (self[LENGTH] > self[MAX]) {
for (let walker = self[LRU_LIST].tail;
self[LENGTH] > self[MAX] && walker !== null;) {
// We know that we're about to delete this one, and also
// what the next least recently used key will be, so just
// go ahead and set it now.
const prev = walker.prev
del(self, walker)
walker = prev
}
}
}
const del = (self, node) => {
if (node) {
const hit = node.value
if (self[DISPOSE])
self[DISPOSE](hit.key, hit.value)
self[LENGTH] -= hit.length
self[CACHE].delete(hit.key)
self[LRU_LIST].removeNode(node)
}
}
class Entry {
constructor (key, value, length, now, maxAge) {
this.key = key
this.value = value
this.length = length
this.now = now
this.maxAge = maxAge || 0
}
}
const forEachStep = (self, fn, node, thisp) => {
let hit = node.value
if (isStale(self, hit)) {
del(self, node)
if (!self[ALLOW_STALE])
hit = undefined
}
if (hit)
fn.call(thisp, hit.value, hit.key, self)
}
module.exports = LRUCache
module.exports = require("child_process");
/***/ }), /***/ }),
@ -763,7 +1112,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.argStringToArray = exports.ToolRunner = void 0; exports.argStringToArray = exports.ToolRunner = void 0;
const os = __importStar(__webpack_require__(87)); const os = __importStar(__webpack_require__(87));
const events = __importStar(__webpack_require__(614)); const events = __importStar(__webpack_require__(614));
const child = __importStar(__webpack_require__(129)); const child = __importStar(__webpack_require__(4));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const io = __importStar(__webpack_require__(436)); const io = __importStar(__webpack_require__(436));
const ioUtil = __importStar(__webpack_require__(962)); const ioUtil = __importStar(__webpack_require__(962));
@ -2243,21 +2592,42 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}); });
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.getBuildKitVersion = exports.install = exports.inspect = exports.isAvailable = exports.parseVersion = exports.getVersion = void 0; exports.getBuildKitVersion = exports.install = exports.inspect = exports.parseVersion = exports.getVersion = exports.isAvailable = void 0;
const fs = __importStar(__webpack_require__(747)); const fs = __importStar(__webpack_require__(747));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const semver = __importStar(__webpack_require__(383)); const semver = __importStar(__webpack_require__(383));
const util = __importStar(__webpack_require__(669)); const util = __importStar(__webpack_require__(669));
const context = __importStar(__webpack_require__(842)); const context = __importStar(__webpack_require__(842));
const exec = __importStar(__webpack_require__(757));
const github = __importStar(__webpack_require__(928)); const github = __importStar(__webpack_require__(928));
const core = __importStar(__webpack_require__(186)); const core = __importStar(__webpack_require__(186));
const exec = __importStar(__webpack_require__(514));
const tc = __importStar(__webpack_require__(784)); const tc = __importStar(__webpack_require__(784));
function isAvailable() {
return __awaiter(this, void 0, void 0, function* () {
return yield exec
.getExecOutput('docker', ['buildx'], {
ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
return false;
}
return res.exitCode == 0;
});
});
}
exports.isAvailable = isAvailable;
function getVersion() { function getVersion() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
return yield exec.exec(`docker`, ['buildx', 'version'], true).then(res => { return yield exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput('docker', ['buildx', 'version'], {
throw new Error(res.stderr); ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
} }
return parseVersion(res.stdout); return parseVersion(res.stdout);
}); });
@ -2268,28 +2638,22 @@ function parseVersion(stdout) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const matches = /\sv?([0-9.]+)/.exec(stdout); const matches = /\sv?([0-9.]+)/.exec(stdout);
if (!matches) { if (!matches) {
throw new Error(`Cannot parse Buildx version`); throw new Error(`Cannot parse buildx version`);
} }
return semver.clean(matches[1]); return semver.clean(matches[1]);
}); });
} }
exports.parseVersion = parseVersion; exports.parseVersion = parseVersion;
function isAvailable() {
return __awaiter(this, void 0, void 0, function* () {
return yield exec.exec(`docker`, ['buildx'], true).then(res => {
if (res.stderr.length > 0 && !res.success) {
return false;
}
return res.success;
});
});
}
exports.isAvailable = isAvailable;
function inspect(name) { function inspect(name) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
return yield exec.exec(`docker`, ['buildx', 'inspect', name], true).then(res => { return yield exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput(`docker`, ['buildx', 'inspect', name], {
throw new Error(res.stderr); ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
} }
const builder = {}; const builder = {};
itlines: for (const line of res.stdout.trim().split(`\n`)) { itlines: for (const line of res.stdout.trim().split(`\n`)) {
@ -2412,20 +2776,30 @@ function filename(version) {
} }
function getBuildKitVersion(containerID) { function getBuildKitVersion(containerID) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
return exec.exec(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], true).then(bkitimage => { return exec
if (bkitimage.success && bkitimage.stdout.length > 0) { .getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], {
return exec.exec(`docker`, ['run', '--rm', bkitimage.stdout, '--version'], true).then(bkitversion => { ignoreReturnCode: true,
if (bkitversion.success && bkitversion.stdout.length > 0) { silent: true
})
.then(bkitimage => {
if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) {
return exec
.getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout, '--version'], {
ignoreReturnCode: true,
silent: true
})
.then(bkitversion => {
if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) {
return `${bkitimage.stdout} => ${bkitversion.stdout}`; return `${bkitimage.stdout} => ${bkitversion.stdout}`;
} }
else if (bkitversion.stderr.length > 0) { else if (bkitversion.stderr.length > 0) {
core.warning(bkitversion.stderr); core.warning(bkitversion.stderr.trim());
} }
return bkitversion.stdout; return bkitversion.stdout;
}); });
} }
else if (bkitimage.stderr.length > 0) { else if (bkitimage.stderr.length > 0) {
core.warning(bkitimage.stderr); core.warning(bkitimage.stderr.trim());
} }
return bkitimage.stdout; return bkitimage.stdout;
}); });
@ -2879,7 +3253,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0; exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0;
const assert_1 = __webpack_require__(357); const assert_1 = __webpack_require__(357);
const childProcess = __importStar(__webpack_require__(129)); const childProcess = __importStar(__webpack_require__(4));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const util_1 = __webpack_require__(669); const util_1 = __webpack_require__(669);
const ioUtil = __importStar(__webpack_require__(962)); const ioUtil = __importStar(__webpack_require__(962));
@ -3430,7 +3804,7 @@ const core_1 = __webpack_require__(186);
// needs to be require for core node modules to be mocked // needs to be require for core node modules to be mocked
/* eslint @typescript-eslint/no-require-imports: 0 */ /* eslint @typescript-eslint/no-require-imports: 0 */
const os = __webpack_require__(87); const os = __webpack_require__(87);
const cp = __webpack_require__(129); const cp = __webpack_require__(4);
const fs = __webpack_require__(747); const fs = __webpack_require__(747);
function _findMatch(versionSpec, stable, candidates, archFilter) { function _findMatch(versionSpec, stable, candidates, archFilter) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@ -6458,348 +6832,6 @@ function issueCommand(command, message) {
exports.issueCommand = issueCommand; exports.issueCommand = issueCommand;
//# sourceMappingURL=file-command.js.map //# sourceMappingURL=file-command.js.map
/***/ }),
/***/ 722:
/***/ (function(module, __unusedexports, __webpack_require__) {
"use strict";
// A linked list to keep track of recently-used-ness
const Yallist = __webpack_require__(665)
const MAX = Symbol('max')
const LENGTH = Symbol('length')
const LENGTH_CALCULATOR = Symbol('lengthCalculator')
const ALLOW_STALE = Symbol('allowStale')
const MAX_AGE = Symbol('maxAge')
const DISPOSE = Symbol('dispose')
const NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet')
const LRU_LIST = Symbol('lruList')
const CACHE = Symbol('cache')
const UPDATE_AGE_ON_GET = Symbol('updateAgeOnGet')
const naiveLength = () => 1
// lruList is a yallist where the head is the youngest
// item, and the tail is the oldest. the list contains the Hit
// objects as the entries.
// Each Hit object has a reference to its Yallist.Node. This
// never changes.
//
// cache is a Map (or PseudoMap) that matches the keys to
// the Yallist.Node object.
class LRUCache {
constructor (options) {
if (typeof options === 'number')
options = { max: options }
if (!options)
options = {}
if (options.max && (typeof options.max !== 'number' || options.max < 0))
throw new TypeError('max must be a non-negative number')
// Kind of weird to have a default max of Infinity, but oh well.
const max = this[MAX] = options.max || Infinity
const lc = options.length || naiveLength
this[LENGTH_CALCULATOR] = (typeof lc !== 'function') ? naiveLength : lc
this[ALLOW_STALE] = options.stale || false
if (options.maxAge && typeof options.maxAge !== 'number')
throw new TypeError('maxAge must be a number')
this[MAX_AGE] = options.maxAge || 0
this[DISPOSE] = options.dispose
this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
this[UPDATE_AGE_ON_GET] = options.updateAgeOnGet || false
this.reset()
}
// resize the cache when the max changes.
set max (mL) {
if (typeof mL !== 'number' || mL < 0)
throw new TypeError('max must be a non-negative number')
this[MAX] = mL || Infinity
trim(this)
}
get max () {
return this[MAX]
}
set allowStale (allowStale) {
this[ALLOW_STALE] = !!allowStale
}
get allowStale () {
return this[ALLOW_STALE]
}
set maxAge (mA) {
if (typeof mA !== 'number')
throw new TypeError('maxAge must be a non-negative number')
this[MAX_AGE] = mA
trim(this)
}
get maxAge () {
return this[MAX_AGE]
}
// resize the cache when the lengthCalculator changes.
set lengthCalculator (lC) {
if (typeof lC !== 'function')
lC = naiveLength
if (lC !== this[LENGTH_CALCULATOR]) {
this[LENGTH_CALCULATOR] = lC
this[LENGTH] = 0
this[LRU_LIST].forEach(hit => {
hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
this[LENGTH] += hit.length
})
}
trim(this)
}
get lengthCalculator () { return this[LENGTH_CALCULATOR] }
get length () { return this[LENGTH] }
get itemCount () { return this[LRU_LIST].length }
rforEach (fn, thisp) {
thisp = thisp || this
for (let walker = this[LRU_LIST].tail; walker !== null;) {
const prev = walker.prev
forEachStep(this, fn, walker, thisp)
walker = prev
}
}
forEach (fn, thisp) {
thisp = thisp || this
for (let walker = this[LRU_LIST].head; walker !== null;) {
const next = walker.next
forEachStep(this, fn, walker, thisp)
walker = next
}
}
keys () {
return this[LRU_LIST].toArray().map(k => k.key)
}
values () {
return this[LRU_LIST].toArray().map(k => k.value)
}
reset () {
if (this[DISPOSE] &&
this[LRU_LIST] &&
this[LRU_LIST].length) {
this[LRU_LIST].forEach(hit => this[DISPOSE](hit.key, hit.value))
}
this[CACHE] = new Map() // hash of items by key
this[LRU_LIST] = new Yallist() // list of items in order of use recency
this[LENGTH] = 0 // length of items in the list
}
dump () {
return this[LRU_LIST].map(hit =>
isStale(this, hit) ? false : {
k: hit.key,
v: hit.value,
e: hit.now + (hit.maxAge || 0)
}).toArray().filter(h => h)
}
dumpLru () {
return this[LRU_LIST]
}
set (key, value, maxAge) {
maxAge = maxAge || this[MAX_AGE]
if (maxAge && typeof maxAge !== 'number')
throw new TypeError('maxAge must be a number')
const now = maxAge ? Date.now() : 0
const len = this[LENGTH_CALCULATOR](value, key)
if (this[CACHE].has(key)) {
if (len > this[MAX]) {
del(this, this[CACHE].get(key))
return false
}
const node = this[CACHE].get(key)
const item = node.value
// dispose of the old one before overwriting
// split out into 2 ifs for better coverage tracking
if (this[DISPOSE]) {
if (!this[NO_DISPOSE_ON_SET])
this[DISPOSE](key, item.value)
}
item.now = now
item.maxAge = maxAge
item.value = value
this[LENGTH] += len - item.length
item.length = len
this.get(key)
trim(this)
return true
}
const hit = new Entry(key, value, len, now, maxAge)
// oversized objects fall out of cache automatically.
if (hit.length > this[MAX]) {
if (this[DISPOSE])
this[DISPOSE](key, value)
return false
}
this[LENGTH] += hit.length
this[LRU_LIST].unshift(hit)
this[CACHE].set(key, this[LRU_LIST].head)
trim(this)
return true
}
has (key) {
if (!this[CACHE].has(key)) return false
const hit = this[CACHE].get(key).value
return !isStale(this, hit)
}
get (key) {
return get(this, key, true)
}
peek (key) {
return get(this, key, false)
}
pop () {
const node = this[LRU_LIST].tail
if (!node)
return null
del(this, node)
return node.value
}
del (key) {
del(this, this[CACHE].get(key))
}
load (arr) {
// reset the cache
this.reset()
const now = Date.now()
// A previous serialized cache has the most recent items first
for (let l = arr.length - 1; l >= 0; l--) {
const hit = arr[l]
const expiresAt = hit.e || 0
if (expiresAt === 0)
// the item was created without expiration in a non aged cache
this.set(hit.k, hit.v)
else {
const maxAge = expiresAt - now
// dont add already expired items
if (maxAge > 0) {
this.set(hit.k, hit.v, maxAge)
}
}
}
}
prune () {
this[CACHE].forEach((value, key) => get(this, key, false))
}
}
const get = (self, key, doUse) => {
const node = self[CACHE].get(key)
if (node) {
const hit = node.value
if (isStale(self, hit)) {
del(self, node)
if (!self[ALLOW_STALE])
return undefined
} else {
if (doUse) {
if (self[UPDATE_AGE_ON_GET])
node.value.now = Date.now()
self[LRU_LIST].unshiftNode(node)
}
}
return hit.value
}
}
const isStale = (self, hit) => {
if (!hit || (!hit.maxAge && !self[MAX_AGE]))
return false
const diff = Date.now() - hit.now
return hit.maxAge ? diff > hit.maxAge
: self[MAX_AGE] && (diff > self[MAX_AGE])
}
const trim = self => {
if (self[LENGTH] > self[MAX]) {
for (let walker = self[LRU_LIST].tail;
self[LENGTH] > self[MAX] && walker !== null;) {
// We know that we're about to delete this one, and also
// what the next least recently used key will be, so just
// go ahead and set it now.
const prev = walker.prev
del(self, walker)
walker = prev
}
}
}
const del = (self, node) => {
if (node) {
const hit = node.value
if (self[DISPOSE])
self[DISPOSE](hit.key, hit.value)
self[LENGTH] -= hit.length
self[CACHE].delete(hit.key)
self[LRU_LIST].removeNode(node)
}
}
class Entry {
constructor (key, value, length, now, maxAge) {
this.key = key
this.value = value
this.length = length
this.now = now
this.maxAge = maxAge || 0
}
}
const forEachStep = (self, fn, node, thisp) => {
let hit = node.value
if (isStale(self, hit)) {
del(self, node)
if (!self[ALLOW_STALE])
hit = undefined
}
if (hit)
fn.call(thisp, hit.value, hit.key, self)
}
module.exports = LRUCache
/***/ }), /***/ }),
/***/ 741: /***/ 741:
@ -6879,68 +6911,6 @@ module.exports = require("fs");
/***/ }), /***/ }),
/***/ 757:
/***/ (function(__unusedmodule, exports, __webpack_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.exec = void 0;
const aexec = __importStar(__webpack_require__(514));
exports.exec = (command, args = [], silent) => __awaiter(void 0, void 0, void 0, function* () {
let stdout = '';
let stderr = '';
const options = {
silent: silent,
ignoreReturnCode: true
};
options.listeners = {
stdout: (data) => {
stdout += data.toString();
},
stderr: (data) => {
stderr += data.toString();
}
};
const returnCode = yield aexec.exec(command, args, options);
return {
success: returnCode === 0,
stdout: stdout.trim(),
stderr: stderr.trim()
};
});
//# sourceMappingURL=exec.js.map
/***/ }),
/***/ 783: /***/ 783:
/***/ (function(__unusedmodule, exports, __webpack_require__) { /***/ (function(__unusedmodule, exports, __webpack_require__) {
@ -7907,7 +7877,7 @@ class Range {
} }
module.exports = Range module.exports = Range
const LRU = __webpack_require__(722) const LRU = __webpack_require__(129)
const cache = new LRU({ max: 1000 }) const cache = new LRU({ max: 1000 })
const parseOptions = __webpack_require__(785) const parseOptions = __webpack_require__(785)

@ -3,9 +3,9 @@ import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import * as util from 'util'; import * as util from 'util';
import * as context from './context'; import * as context from './context';
import * as exec from './exec';
import * as github from './github'; import * as github from './github';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
export type Builder = { export type Builder = {
@ -18,77 +18,92 @@ export type Builder = {
node_platforms?: string; node_platforms?: string;
}; };
export async function isAvailable(): Promise<Boolean> {
return await exec
.getExecOutput('docker', ['buildx'], {
ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
return false;
}
return res.exitCode == 0;
});
}
export async function getVersion(): Promise<string> { export async function getVersion(): Promise<string> {
return await exec.exec(`docker`, ['buildx', 'version'], true).then(res => { return await exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput('docker', ['buildx', 'version'], {
throw new Error(res.stderr); ignoreReturnCode: true,
} silent: true
return parseVersion(res.stdout); })
}); .then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
return parseVersion(res.stdout);
});
} }
export async function parseVersion(stdout: string): Promise<string> { export async function parseVersion(stdout: string): Promise<string> {
const matches = /\sv?([0-9.]+)/.exec(stdout); const matches = /\sv?([0-9.]+)/.exec(stdout);
if (!matches) { if (!matches) {
throw new Error(`Cannot parse Buildx version`); throw new Error(`Cannot parse buildx version`);
} }
return semver.clean(matches[1]); return semver.clean(matches[1]);
} }
export async function isAvailable(): Promise<Boolean> {
return await exec.exec(`docker`, ['buildx'], true).then(res => {
if (res.stderr.length > 0 && !res.success) {
return false;
}
return res.success;
});
}
export async function inspect(name: string): Promise<Builder> { export async function inspect(name: string): Promise<Builder> {
return await exec.exec(`docker`, ['buildx', 'inspect', name], true).then(res => { return await exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput(`docker`, ['buildx', 'inspect', name], {
throw new Error(res.stderr); ignoreReturnCode: true,
} silent: true
const builder: Builder = {}; })
itlines: for (const line of res.stdout.trim().split(`\n`)) { .then(res => {
const [key, ...rest] = line.split(':'); if (res.stderr.length > 0 && res.exitCode != 0) {
const value = rest.map(v => v.trim()).join(':'); throw new Error(res.stderr.trim());
if (key.length == 0 || value.length == 0) {
continue;
} }
switch (key) { const builder: Builder = {};
case 'Name': { itlines: for (const line of res.stdout.trim().split(`\n`)) {
if (builder.name == undefined) { const [key, ...rest] = line.split(':');
builder.name = value; const value = rest.map(v => v.trim()).join(':');
} else { if (key.length == 0 || value.length == 0) {
builder.node_name = value; continue;
}
switch (key) {
case 'Name': {
if (builder.name == undefined) {
builder.name = value;
} else {
builder.node_name = value;
}
break;
}
case 'Driver': {
builder.driver = value;
break;
}
case 'Endpoint': {
builder.node_endpoint = value;
break;
}
case 'Status': {
builder.node_status = value;
break;
}
case 'Flags': {
builder.node_flags = value;
break;
}
case 'Platforms': {
builder.node_platforms = value.replace(/\s/g, '');
break itlines;
} }
break;
}
case 'Driver': {
builder.driver = value;
break;
}
case 'Endpoint': {
builder.node_endpoint = value;
break;
}
case 'Status': {
builder.node_status = value;
break;
}
case 'Flags': {
builder.node_flags = value;
break;
}
case 'Platforms': {
builder.node_platforms = value.replace(/\s/g, '');
break itlines;
} }
} }
} return builder;
return builder; });
});
} }
export async function install(inputVersion: string, dockerConfigHome: string): Promise<string> { export async function install(inputVersion: string, dockerConfigHome: string): Promise<string> {
@ -173,19 +188,29 @@ async function filename(version: string): Promise<string> {
} }
export async function getBuildKitVersion(containerID: string): Promise<string> { export async function getBuildKitVersion(containerID: string): Promise<string> {
return exec.exec(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], true).then(bkitimage => { return exec
if (bkitimage.success && bkitimage.stdout.length > 0) { .getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], {
return exec.exec(`docker`, ['run', '--rm', bkitimage.stdout, '--version'], true).then(bkitversion => { ignoreReturnCode: true,
if (bkitversion.success && bkitversion.stdout.length > 0) { silent: true
return `${bkitimage.stdout} => ${bkitversion.stdout}`; })
} else if (bkitversion.stderr.length > 0) { .then(bkitimage => {
core.warning(bkitversion.stderr); if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) {
} return exec
return bkitversion.stdout; .getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout, '--version'], {
}); ignoreReturnCode: true,
} else if (bkitimage.stderr.length > 0) { silent: true
core.warning(bkitimage.stderr); })
} .then(bkitversion => {
return bkitimage.stdout; if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) {
}); return `${bkitimage.stdout} => ${bkitversion.stdout}`;
} else if (bkitversion.stderr.length > 0) {
core.warning(bkitversion.stderr.trim());
}
return bkitversion.stdout;
});
} else if (bkitimage.stderr.length > 0) {
core.warning(bkitimage.stderr.trim());
}
return bkitimage.stdout;
});
} }

@ -1,7 +0,0 @@
import * as exec from './exec';
export async function isDaemonRunning(): Promise<boolean> {
return await exec.exec(`docker`, ['version', '--format', '{{.Server.Os}}'], true).then(res => {
return !res.stdout.includes(' ') && res.success;
});
}

@ -1,34 +0,0 @@
import * as aexec from '@actions/exec';
import {ExecOptions} from '@actions/exec';
export interface ExecResult {
success: boolean;
stdout: string;
stderr: string;
}
export const exec = async (command: string, args: string[] = [], silent: boolean): Promise<ExecResult> => {
let stdout: string = '';
let stderr: string = '';
const options: ExecOptions = {
silent: silent,
ignoreReturnCode: true
};
options.listeners = {
stdout: (data: Buffer) => {
stdout += data.toString();
},
stderr: (data: Buffer) => {
stderr += data.toString();
}
};
const returnCode: number = await aexec.exec(command, args, options);
return {
success: returnCode === 0,
stdout: stdout.trim(),
stderr: stderr.trim()
};
};

@ -1,12 +1,11 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import * as buildx from './buildx'; import * as buildx from './buildx';
import * as context from './context'; import * as context from './context';
import * as mexec from './exec';
import * as stateHelper from './state-helper'; import * as stateHelper from './state-helper';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
async function run(): Promise<void> { async function run(): Promise<void> {
try { try {
@ -94,21 +93,29 @@ async function run(): Promise<void> {
async function cleanup(): Promise<void> { async function cleanup(): Promise<void> {
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) { if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
core.startGroup(`BuildKit container logs`); core.startGroup(`BuildKit container logs`);
await mexec.exec('docker', ['logs', `${stateHelper.containerName}`], false).then(res => { await exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
core.warning(res.stderr); ignoreReturnCode: true
} })
}); .then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
}
});
core.endGroup(); core.endGroup();
} }
if (stateHelper.builderName.length > 0) { if (stateHelper.builderName.length > 0) {
core.startGroup(`Removing builder`); core.startGroup(`Removing builder`);
await mexec.exec('docker', ['buildx', 'rm', `${stateHelper.builderName}`], false).then(res => { await exec
if (res.stderr.length > 0 && !res.success) { .getExecOutput('docker', ['buildx', 'rm', `${stateHelper.builderName}`], {
core.warning(res.stderr); ignoreReturnCode: true
} })
}); .then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
}
});
core.endGroup(); core.endGroup();
} }
} }