import { promisify } from 'util';
import tmp from 'tmp';
import { createLogger } from './logger.js';
import { multiArgsPromisedFn, promisifyCustom } from './promisify.js';
const log = createLogger(import.meta.url);
tmp.dir[promisifyCustom] = multiArgsPromisedFn(tmp.dir);
const createTempDir = promisify(tmp.dir);
/*
 * Work with a self-destructing temporary directory in a promise chain.
 *
 * The directory will be destroyed when the promise chain is finished
 * (whether there was an error or not).
 *
 * Usage:
 *
 * withTempDir(
 *   (tmpDir) =>
 *     doSomething(tmpDir.path())
 *     .then(...)
 * );
 *
 */

export function withTempDir(makePromise) {
  const tmpDir = new TempDir();
  return tmpDir.create().then(() => {
    return makePromise(tmpDir);
  }).catch(tmpDir.errorHandler()).then(tmpDir.successHandler());
}
/*
 * Work with a self-destructing temporary directory object.
 *
 * It is safer to use withTempDir() instead but if you know
 * what you're doing you can use it directly like:
 *
 * let tmpDir = new TempDir();
 * tmpDir.create()
 *   .then(() => {
 *     // work with tmpDir.path()
 *   })
 *   .catch(tmpDir.errorHandler())
 *   .then(tmpDir.successHandler());
 *
 */

export class TempDir {
  constructor() {
    this._path = undefined;
    this._removeTempDir = undefined;
  }
  /*
   * Returns a promise that is fulfilled when the temp directory has
   * been created.
   */


  create() {
    return createTempDir({
      prefix: 'tmp-web-ext-',
      // This allows us to remove a non-empty tmp dir.
      unsafeCleanup: true
    }).then(([tmpPath, removeTempDir]) => {
      this._path = tmpPath;

      this._removeTempDir = () => new Promise((resolve, reject) => {
        // `removeTempDir` parameter is a `next` callback which
        // is called once the dir has been removed.
        const next = err => err ? reject(err) : resolve();

        removeTempDir(next);
      });

      log.debug(`Created temporary directory: ${this.path()}`);
      return this;
    });
  }
  /*
   * Get the absolute path of the temp directory.
   */


  path() {
    if (!this._path) {
      throw new Error('You cannot access path() before calling create()');
    }

    return this._path;
  }
  /*
   * Returns a callback that will catch an error, remove
   * the temporary directory, and throw the error.
   *
   * This is intended for use in a promise like
   * Promise().catch(tmp.errorHandler())
   */


  errorHandler() {
    return async error => {
      await this.remove();
      throw error;
    };
  }
  /*
   * Returns a callback that will remove the temporary direcotry.
   *
   * This is intended for use in a promise like
   * Promise().then(tmp.successHandler())
   */


  successHandler() {
    return async promiseResult => {
      await this.remove();
      return promiseResult;
    };
  }
  /*
   * Remove the temp directory.
   */


  remove() {
    if (!this._removeTempDir) {
      return;
    }

    log.debug(`Removing temporary directory: ${this.path()}`);
    return this._removeTempDir && this._removeTempDir();
  }

}
//# sourceMappingURL=temp-dir.js.map