From 29f1eeb9e5c39ce2f1034c608f385c0abee2d367 Mon Sep 17 00:00:00 2001
From: CrazyMax <crazy-max@users.noreply.github.com>
Date: Wed, 23 Jun 2021 16:11:52 +0200
Subject: [PATCH] Use built-in `getExecOutput`

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
---
 __tests__/buildx.test.ts |  45 +-
 dist/index.js            | 860 +++++++++++++++++++--------------------
 src/buildx.ts            | 169 ++++----
 src/docker.ts            |   7 -
 src/exec.ts              |  34 --
 src/main.ts              |  33 +-
 6 files changed, 569 insertions(+), 579 deletions(-)
 delete mode 100644 src/docker.ts
 delete mode 100644 src/exec.ts

diff --git a/__tests__/buildx.test.ts b/__tests__/buildx.test.ts
index de68108..9b98f87 100644
--- a/__tests__/buildx.test.ts
+++ b/__tests__/buildx.test.ts
@@ -1,18 +1,40 @@
 import fs = require('fs');
-import * as docker from '../src/docker';
 import * as buildx from '../src/buildx';
 import * as path from 'path';
 import * as os from 'os';
 import * as semver from 'semver';
 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', () => {
-  it('valid', async () => {
-    await exec.exec('docker', ['buildx', 'version']);
-    const version = await buildx.getVersion();
-    console.log(`version: ${version}`);
-    expect(semver.valid(version)).not.toBeNull();
-  }, 100000);
+  async function 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)(
+    'valid',
+    async () => {
+      const version = await buildx.getVersion();
+      console.log(`version: ${version}`);
+      expect(semver.valid(version)).not.toBeNull();
+    },
+    100000
+  );
 });
 
 describe('parseVersion', () => {
@@ -27,7 +49,14 @@ describe('parseVersion', () => {
 
 describe('inspect', () => {
   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)(
     'valid',
diff --git a/dist/index.js b/dist/index.js
index 39522db..ddf7a2a 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -49,6 +49,13 @@ module.exports =
 /************************************************************************/
 /******/ ({
 
+/***/ 4:
+/***/ (function(module) {
+
+module.exports = require("child_process");
+
+/***/ }),
+
 /***/ 8:
 /***/ (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 });
-const core = __importStar(__webpack_require__(186));
-const exec = __importStar(__webpack_require__(514));
 const os = __importStar(__webpack_require__(87));
 const path = __importStar(__webpack_require__(622));
 const semver = __importStar(__webpack_require__(383));
 const buildx = __importStar(__webpack_require__(295));
 const context = __importStar(__webpack_require__(842));
-const mexec = __importStar(__webpack_require__(757));
 const stateHelper = __importStar(__webpack_require__(647));
+const core = __importStar(__webpack_require__(186));
+const exec = __importStar(__webpack_require__(514));
 function run() {
     var _a;
     return __awaiter(this, void 0, void 0, function* () {
@@ -600,18 +606,26 @@ function cleanup() {
     return __awaiter(this, void 0, void 0, function* () {
         if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
             core.startGroup(`BuildKit container logs`);
-            yield mexec.exec('docker', ['logs', `${stateHelper.containerName}`], false).then(res => {
-                if (res.stderr.length > 0 && !res.success) {
-                    core.warning(res.stderr);
+            yield exec
+                .getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
+                ignoreReturnCode: true
+            })
+                .then(res => {
+                if (res.stderr.length > 0 && res.exitCode != 0) {
+                    core.warning(res.stderr.trim());
                 }
             });
             core.endGroup();
         }
         if (stateHelper.builderName.length > 0) {
             core.startGroup(`Removing builder`);
-            yield mexec.exec('docker', ['buildx', 'rm', `${stateHelper.builderName}`], false).then(res => {
-                if (res.stderr.length > 0 && !res.success) {
-                    core.warning(res.stderr);
+            yield exec
+                .getExecOutput('docker', ['buildx', 'rm', `${stateHelper.builderName}`], {
+                ignoreReturnCode: true
+            })
+                .then(res => {
+                if (res.stderr.length > 0 && res.exitCode != 0) {
+                    core.warning(res.stderr.trim());
                 }
             });
             core.endGroup();
@@ -706,9 +720,344 @@ module.exports = gt
 /***/ }),
 
 /***/ 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;
 const os = __importStar(__webpack_require__(87));
 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 io = __importStar(__webpack_require__(436));
 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 });
-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 path = __importStar(__webpack_require__(622));
 const semver = __importStar(__webpack_require__(383));
 const util = __importStar(__webpack_require__(669));
 const context = __importStar(__webpack_require__(842));
-const exec = __importStar(__webpack_require__(757));
 const github = __importStar(__webpack_require__(928));
 const core = __importStar(__webpack_require__(186));
+const exec = __importStar(__webpack_require__(514));
 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() {
     return __awaiter(this, void 0, void 0, function* () {
-        return yield exec.exec(`docker`, ['buildx', 'version'], true).then(res => {
-            if (res.stderr.length > 0 && !res.success) {
-                throw new Error(res.stderr);
+        return yield exec
+            .getExecOutput('docker', ['buildx', 'version'], {
+            ignoreReturnCode: true,
+            silent: true
+        })
+            .then(res => {
+            if (res.stderr.length > 0 && res.exitCode != 0) {
+                throw new Error(res.stderr.trim());
             }
             return parseVersion(res.stdout);
         });
@@ -2268,28 +2638,22 @@ function parseVersion(stdout) {
     return __awaiter(this, void 0, void 0, function* () {
         const matches = /\sv?([0-9.]+)/.exec(stdout);
         if (!matches) {
-            throw new Error(`Cannot parse Buildx version`);
+            throw new Error(`Cannot parse buildx version`);
         }
         return semver.clean(matches[1]);
     });
 }
 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) {
     return __awaiter(this, void 0, void 0, function* () {
-        return yield exec.exec(`docker`, ['buildx', 'inspect', name], true).then(res => {
-            if (res.stderr.length > 0 && !res.success) {
-                throw new Error(res.stderr);
+        return yield exec
+            .getExecOutput(`docker`, ['buildx', 'inspect', name], {
+            ignoreReturnCode: true,
+            silent: true
+        })
+            .then(res => {
+            if (res.stderr.length > 0 && res.exitCode != 0) {
+                throw new Error(res.stderr.trim());
             }
             const builder = {};
             itlines: for (const line of res.stdout.trim().split(`\n`)) {
@@ -2412,20 +2776,30 @@ function filename(version) {
 }
 function getBuildKitVersion(containerID) {
     return __awaiter(this, void 0, void 0, function* () {
-        return exec.exec(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], true).then(bkitimage => {
-            if (bkitimage.success && bkitimage.stdout.length > 0) {
-                return exec.exec(`docker`, ['run', '--rm', bkitimage.stdout, '--version'], true).then(bkitversion => {
-                    if (bkitversion.success && bkitversion.stdout.length > 0) {
+        return exec
+            .getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], {
+            ignoreReturnCode: true,
+            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}`;
                     }
                     else if (bkitversion.stderr.length > 0) {
-                        core.warning(bkitversion.stderr);
+                        core.warning(bkitversion.stderr.trim());
                     }
                     return bkitversion.stdout;
                 });
             }
             else if (bkitimage.stderr.length > 0) {
-                core.warning(bkitimage.stderr);
+                core.warning(bkitimage.stderr.trim());
             }
             return bkitimage.stdout;
         });
@@ -2879,7 +3253,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
 Object.defineProperty(exports, "__esModule", { value: true });
 exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0;
 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 util_1 = __webpack_require__(669);
 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
 /* eslint @typescript-eslint/no-require-imports: 0 */
 const os = __webpack_require__(87);
-const cp = __webpack_require__(129);
+const cp = __webpack_require__(4);
 const fs = __webpack_require__(747);
 function _findMatch(versionSpec, stable, candidates, archFilter) {
     return __awaiter(this, void 0, void 0, function* () {
@@ -6458,348 +6832,6 @@ function issueCommand(command, message) {
 exports.issueCommand = issueCommand;
 //# 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:
@@ -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:
 /***/ (function(__unusedmodule, exports, __webpack_require__) {
 
@@ -7907,7 +7877,7 @@ class Range {
 }
 module.exports = Range
 
-const LRU = __webpack_require__(722)
+const LRU = __webpack_require__(129)
 const cache = new LRU({ max: 1000 })
 
 const parseOptions = __webpack_require__(785)
diff --git a/src/buildx.ts b/src/buildx.ts
index 65a1dcc..d3045c5 100644
--- a/src/buildx.ts
+++ b/src/buildx.ts
@@ -3,9 +3,9 @@ import * as path from 'path';
 import * as semver from 'semver';
 import * as util from 'util';
 import * as context from './context';
-import * as exec from './exec';
 import * as github from './github';
 import * as core from '@actions/core';
+import * as exec from '@actions/exec';
 import * as tc from '@actions/tool-cache';
 
 export type Builder = {
@@ -18,77 +18,92 @@ export type Builder = {
   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> {
-  return await exec.exec(`docker`, ['buildx', 'version'], true).then(res => {
-    if (res.stderr.length > 0 && !res.success) {
-      throw new Error(res.stderr);
-    }
-    return parseVersion(res.stdout);
-  });
+  return await exec
+    .getExecOutput('docker', ['buildx', 'version'], {
+      ignoreReturnCode: true,
+      silent: true
+    })
+    .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> {
   const matches = /\sv?([0-9.]+)/.exec(stdout);
   if (!matches) {
-    throw new Error(`Cannot parse Buildx version`);
+    throw new Error(`Cannot parse buildx version`);
   }
   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> {
-  return await exec.exec(`docker`, ['buildx', 'inspect', name], true).then(res => {
-    if (res.stderr.length > 0 && !res.success) {
-      throw new Error(res.stderr);
-    }
-    const builder: Builder = {};
-    itlines: for (const line of res.stdout.trim().split(`\n`)) {
-      const [key, ...rest] = line.split(':');
-      const value = rest.map(v => v.trim()).join(':');
-      if (key.length == 0 || value.length == 0) {
-        continue;
+  return await exec
+    .getExecOutput(`docker`, ['buildx', 'inspect', name], {
+      ignoreReturnCode: true,
+      silent: true
+    })
+    .then(res => {
+      if (res.stderr.length > 0 && res.exitCode != 0) {
+        throw new Error(res.stderr.trim());
       }
-      switch (key) {
-        case 'Name': {
-          if (builder.name == undefined) {
-            builder.name = value;
-          } else {
-            builder.node_name = value;
+      const builder: Builder = {};
+      itlines: for (const line of res.stdout.trim().split(`\n`)) {
+        const [key, ...rest] = line.split(':');
+        const value = rest.map(v => v.trim()).join(':');
+        if (key.length == 0 || value.length == 0) {
+          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> {
@@ -173,19 +188,29 @@ async function filename(version: string): Promise<string> {
 }
 
 export async function getBuildKitVersion(containerID: string): Promise<string> {
-  return exec.exec(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], true).then(bkitimage => {
-    if (bkitimage.success && bkitimage.stdout.length > 0) {
-      return exec.exec(`docker`, ['run', '--rm', bkitimage.stdout, '--version'], true).then(bkitversion => {
-        if (bkitversion.success && bkitversion.stdout.length > 0) {
-          return `${bkitimage.stdout} => ${bkitversion.stdout}`;
-        } else if (bkitversion.stderr.length > 0) {
-          core.warning(bkitversion.stderr);
-        }
-        return bkitversion.stdout;
-      });
-    } else if (bkitimage.stderr.length > 0) {
-      core.warning(bkitimage.stderr);
-    }
-    return bkitimage.stdout;
-  });
+  return exec
+    .getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], {
+      ignoreReturnCode: true,
+      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}`;
+            } 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;
+    });
 }
diff --git a/src/docker.ts b/src/docker.ts
deleted file mode 100644
index a35b384..0000000
--- a/src/docker.ts
+++ /dev/null
@@ -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;
-  });
-}
diff --git a/src/exec.ts b/src/exec.ts
deleted file mode 100644
index 3d0c4ce..0000000
--- a/src/exec.ts
+++ /dev/null
@@ -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()
-  };
-};
diff --git a/src/main.ts b/src/main.ts
index b4f2955..0d5d202 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,12 +1,11 @@
-import * as core from '@actions/core';
-import * as exec from '@actions/exec';
 import * as os from 'os';
 import * as path from 'path';
 import * as semver from 'semver';
 import * as buildx from './buildx';
 import * as context from './context';
-import * as mexec from './exec';
 import * as stateHelper from './state-helper';
+import * as core from '@actions/core';
+import * as exec from '@actions/exec';
 
 async function run(): Promise<void> {
   try {
@@ -94,21 +93,29 @@ async function run(): Promise<void> {
 async function cleanup(): Promise<void> {
   if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
     core.startGroup(`BuildKit container logs`);
-    await mexec.exec('docker', ['logs', `${stateHelper.containerName}`], false).then(res => {
-      if (res.stderr.length > 0 && !res.success) {
-        core.warning(res.stderr);
-      }
-    });
+    await exec
+      .getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
+        ignoreReturnCode: true
+      })
+      .then(res => {
+        if (res.stderr.length > 0 && res.exitCode != 0) {
+          core.warning(res.stderr.trim());
+        }
+      });
     core.endGroup();
   }
 
   if (stateHelper.builderName.length > 0) {
     core.startGroup(`Removing builder`);
-    await mexec.exec('docker', ['buildx', 'rm', `${stateHelper.builderName}`], false).then(res => {
-      if (res.stderr.length > 0 && !res.success) {
-        core.warning(res.stderr);
-      }
-    });
+    await exec
+      .getExecOutput('docker', ['buildx', 'rm', `${stateHelper.builderName}`], {
+        ignoreReturnCode: true
+      })
+      .then(res => {
+        if (res.stderr.length > 0 && res.exitCode != 0) {
+          core.warning(res.stderr.trim());
+        }
+      });
     core.endGroup();
   }
 }