'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.examples = exports.setFlags = exports.run = undefined;

var _extends2;

function _load_extends() {
  return _extends2 = _interopRequireDefault(require('babel-runtime/helpers/extends'));
}

var _asyncToGenerator2;

function _load_asyncToGenerator() {
  return _asyncToGenerator2 = _interopRequireDefault(require('babel-runtime/helpers/asyncToGenerator'));
}

let fetchReleases = (() => {
  var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, { includePrereleases = false } = {}) {
    const token = process.env.GITHUB_TOKEN;
    const tokenUrlParameter = token ? `?access_token=${token}` : '';

    const request = yield config.requestManager.request({
      url: `https://api.github.com/repos/yarnpkg/yarn/releases${tokenUrlParameter}`,
      json: true
    });

    const releases = request.filter(function (release) {
      if (release.draft) {
        return false;
      }

      if (release.prerelease && !includePrereleases) {
        return false;
      }

      // $FlowFixMe
      release.version = semver.coerce(release.tag_name);

      if (!release.version) {
        return false;
      }

      if (!getBundleAsset(release)) {
        return false;
      }

      return true;
    });

    releases.sort(function (a, b) {
      // $FlowFixMe
      return -semver.compare(a.version, b.version);
    });

    return releases;
  });

  return function fetchReleases(_x) {
    return _ref.apply(this, arguments);
  };
})();

exports.hasWrapper = hasWrapper;

var _yarnVersion;

function _load_yarnVersion() {
  return _yarnVersion = require('../../util/yarn-version.js');
}

var _child;

function _load_child() {
  return _child = _interopRequireWildcard(require('../../util/child.js'));
}

var _buildSubCommands2;

function _load_buildSubCommands() {
  return _buildSubCommands2 = _interopRequireDefault(require('./_build-sub-commands.js'));
}

var _rc;

function _load_rc() {
  return _rc = require('../../rc.js');
}

var _fs;

function _load_fs() {
  return _fs = _interopRequireWildcard(require('../../util/fs.js'));
}

var _lockfile;

function _load_lockfile() {
  return _lockfile = require('../../lockfile');
}

var _semver;

function _load_semver() {
  return _semver = require('../../util/semver.js');
}

var _constants;

function _load_constants() {
  return _constants = require('../../constants');
}

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/* eslint-disable max-len */

const V2_NAMES = ['berry', 'stable', 'canary', 'v2', '2'];

const isLocalFile = version => version.match(/^\.{0,2}[\\/]/) || path.isAbsolute(version);
const isV2Version = version => (0, (_semver || _load_semver()).satisfiesWithPrereleases)(version, '>=2.0.0');

const chalk = require('chalk');
const invariant = require('invariant');
const path = require('path');
const semver = require('semver');

function getBundleAsset(release) {
  return release.assets.find(asset => {
    return asset.name.match(/^yarn-[0-9]+\.[0-9]+\.[0-9]+\.js$/);
  });
}

function fetchBundle(config, url) {
  return config.requestManager.request({
    url,
    buffer: true
  });
}

function hasWrapper(flags, args) {
  return false;
}

var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('policies', {
  setVersion(config, reporter, flags, args) {
    return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
      const initialRange = args[0] || 'latest';
      let range = initialRange;

      let allowRc = flags.rc;

      if (range === 'rc') {
        reporter.log(`${chalk.yellow(`Warning:`)} Your current Yarn binary is currently Yarn ${(_yarnVersion || _load_yarnVersion()).version}; to avoid potential breaking changes, 'set version rc' won't receive upgrades past the 1.22.x branch.\n         To upgrade to the latest versions, run ${chalk.cyan(`yarn set version`)} ${chalk.yellow.underline(`canary`)} instead. Sorry for the inconvenience.\n`);

        range = '*';
        allowRc = true;
      }

      if (range === 'latest') {
        reporter.log(`${chalk.yellow(`Warning:`)} Your current Yarn binary is currently Yarn ${(_yarnVersion || _load_yarnVersion()).version}; to avoid potential breaking changes, 'set version latest' won't receive upgrades past the 1.22.x branch.\n         To upgrade to the latest versions, run ${chalk.cyan(`yarn set version`)} ${chalk.yellow.underline(`stable`)} instead. Sorry for the inconvenience.\n`);

        range = '*';
      }

      if (range === 'classic') {
        range = '*';
      }

      let bundleUrl;
      let bundleVersion;
      const isV2 = false;

      if (range === 'nightly' || range === 'nightlies') {
        reporter.log(`${chalk.yellow(`Warning:`)} Nightlies only exist for Yarn 1.x; starting from 2.x onwards, you should use 'canary' instead`);

        bundleUrl = 'https://nightly.yarnpkg.com/latest.js';
        bundleVersion = 'nightly';
      } else if (V2_NAMES.includes(range) || isLocalFile(range) || isV2Version(range)) {
        const normalizedRange = isV2Version(range) ? range : range === `canary` ? `canary` : `stable`;

        if (process.env.COREPACK_ROOT) {
          yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [path.join(process.env.COREPACK_ROOT, 'dist/corepack.js'), `yarn@${normalizedRange}`, `set`, `version`, normalizedRange], {
            stdio: 'inherit',
            cwd: config.cwd
          });

          return;
        } else {
          const bundle = yield fetchBundle(config, 'https://github.com/yarnpkg/berry/raw/master/packages/yarnpkg-cli/bin/yarn.js');

          const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-stable-temp.cjs`);
          yield (_fs || _load_fs()).mkdirp(path.dirname(yarnPath));
          yield (_fs || _load_fs()).writeFile(yarnPath, bundle);
          yield (_fs || _load_fs()).chmod(yarnPath, 0o755);

          try {
            yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [yarnPath, 'set', 'version', range], {
              stdio: 'inherit',
              cwd: config.lockfileFolder,
              env: (0, (_extends2 || _load_extends()).default)({}, process.env, {
                YARN_IGNORE_PATH: `1`
              })
            });
          } catch (err) {
            // eslint-disable-next-line no-process-exit
            process.exit(1);
          }

          return;
        }
      } else {
        reporter.log(`Resolving ${chalk.yellow(initialRange)} to a url...`);

        let releases = [];

        try {
          releases = yield fetchReleases(config, {
            includePrereleases: allowRc
          });
        } catch (e) {
          reporter.error(e.message);
          return;
        }

        const release = releases.find(function (release) {
          // $FlowFixMe
          return semver.satisfies(release.version, range);
        });

        if (!release) {
          throw new Error(`Release not found: ${range}`);
        }

        const asset = getBundleAsset(release);
        invariant(asset, 'The bundle asset should exist');

        bundleUrl = asset.browser_download_url;
        bundleVersion = release.version.version;
      }

      reporter.log(`Downloading ${chalk.green(bundleUrl)}...`);

      const bundle = yield fetchBundle(config, bundleUrl);

      const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-${bundleVersion}.cjs`);
      reporter.log(`Saving it into ${chalk.magenta(yarnPath)}...`);
      yield (_fs || _load_fs()).mkdirp(path.dirname(yarnPath));
      yield (_fs || _load_fs()).writeFile(yarnPath, bundle);
      yield (_fs || _load_fs()).chmod(yarnPath, 0o755);

      const targetPath = path.relative(config.lockfileFolder, yarnPath).replace(/\\/g, '/');

      if (isV2) {
        const rcPath = `${config.lockfileFolder}/.yarnrc.yml`;
        reporter.log(`Updating ${chalk.magenta(rcPath)}...`);

        yield (_fs || _load_fs()).writeFilePreservingEol(rcPath, `yarnPath: ${JSON.stringify(targetPath)}\n`);
      } else {
        const rcPath = `${config.lockfileFolder}/.yarnrc`;
        reporter.log(`Updating ${chalk.magenta(rcPath)}...`);

        const rc = (0, (_rc || _load_rc()).getRcConfigForFolder)(config.lockfileFolder);
        rc['yarn-path'] = targetPath;

        yield (_fs || _load_fs()).writeFilePreservingEol(rcPath, `${(0, (_lockfile || _load_lockfile()).stringify)(rc)}\n`);
      }

      reporter.log(`Done!`);
    })();
  }
});

const run = _buildSubCommands.run,
      setFlags = _buildSubCommands.setFlags,
      examples = _buildSubCommands.examples;
exports.run = run;
exports.setFlags = setFlags;
exports.examples = examples;