'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var _regeneratorRuntime = _interopDefault(require('babel-runtime/regenerator'));
var _asyncToGenerator = _interopDefault(require('babel-runtime/helpers/asyncToGenerator'));
var _classCallCheck = _interopDefault(require('babel-runtime/helpers/classCallCheck'));
var _createClass = _interopDefault(require('babel-runtime/helpers/createClass'));
var models_js = require('./models.js');
var _getIterator = _interopDefault(require('babel-runtime/core-js/get-iterator'));
var _Set = _interopDefault(require('babel-runtime/core-js/set'));
var path = _interopDefault(require('path'));
var _Map = _interopDefault(require('babel-runtime/core-js/map'));
var AsyncLock = _interopDefault(require('async-lock'));
var ignore = _interopDefault(require('ignore'));
var buffer = require('buffer');
var shasum = _interopDefault(require('shasum'));
var _slicedToArray = _interopDefault(require('babel-runtime/helpers/slicedToArray'));
var simpleGet = _interopDefault(require('simple-get'));
var concat = _interopDefault(require('simple-concat'));
var pify = _interopDefault(require('pify'));
var utils_js = require('./utils.js');
var stream = require('stream');

// @flow
/** @ignore */
var GitConfigManager = function () {
  function GitConfigManager() {
    _classCallCheck(this, GitConfigManager);
  }

  _createClass(GitConfigManager, null, [{
    key: 'get',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
        var _fs = _ref.fs,
            gitdir = _ref.gitdir;
        var fs, text;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                // We can improve efficiency later if needed.
                // TODO: read from full list of git config files

                _context.next = 3;
                return fs.read(gitdir + '/config', { encoding: 'utf8' });

              case 3:
                text = _context.sent;
                return _context.abrupt('return', models_js.GitConfig.from(text));

              case 5:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

      function get(_x) {
        return _ref2.apply(this, arguments);
      }

      return get;
    }()
  }, {
    key: 'save',
    value: function () {
      var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref3) {
        var _fs = _ref3.fs,
            gitdir = _ref3.gitdir,
            config = _ref3.config;
        var fs;
        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                // We can improve efficiency later if needed.
                // TODO: handle saving to the correct global/user/repo location

                _context2.next = 3;
                return fs.write(gitdir + '/config', config.toString(), {
                  encoding: 'utf8'
                });

              case 3:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function save(_x2) {
        return _ref4.apply(this, arguments);
      }

      return save;
    }()
  }]);

  return GitConfigManager;
}();

// @flow
// TODO: Add file locks.

/** @ignore */
var GitShallowManager = function () {
  function GitShallowManager() {
    _classCallCheck(this, GitShallowManager);
  }

  _createClass(GitShallowManager, null, [{
    key: 'read',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
        var fs = _ref.fs,
            gitdir = _ref.gitdir;
        var oids, text;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                oids = new _Set();
                _context.next = 3;
                return fs.read(path.join(gitdir, 'shallow'), { encoding: 'utf8' });

              case 3:
                text = _context.sent;

                if (!(text === null)) {
                  _context.next = 6;
                  break;
                }

                return _context.abrupt('return', oids);

              case 6:
                text.trim().split('\n').map(function (oid) {
                  return oids.add(oid);
                });
                return _context.abrupt('return', oids);

              case 8:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

      function read(_x) {
        return _ref2.apply(this, arguments);
      }

      return read;
    }()
  }, {
    key: 'write',
    value: function () {
      var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref3) {
        var fs = _ref3.fs,
            gitdir = _ref3.gitdir,
            oids = _ref3.oids;

        var text, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, oid;

        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                text = '';
                _iteratorNormalCompletion = true;
                _didIteratorError = false;
                _iteratorError = undefined;
                _context2.prev = 4;

                for (_iterator = _getIterator(oids); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                  oid = _step.value;

                  text += oid + '\n';
                }
                _context2.next = 12;
                break;

              case 8:
                _context2.prev = 8;
                _context2.t0 = _context2['catch'](4);
                _didIteratorError = true;
                _iteratorError = _context2.t0;

              case 12:
                _context2.prev = 12;
                _context2.prev = 13;

                if (!_iteratorNormalCompletion && _iterator.return) {
                  _iterator.return();
                }

              case 15:
                _context2.prev = 15;

                if (!_didIteratorError) {
                  _context2.next = 18;
                  break;
                }

                throw _iteratorError;

              case 18:
                return _context2.finish(15);

              case 19:
                return _context2.finish(12);

              case 20:
                _context2.next = 22;
                return fs.write(path.join(gitdir, 'shallow'), text, {
                  encoding: 'utf8'
                });

              case 22:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this, [[4, 8, 12, 20], [13,, 15, 19]]);
      }));

      function write(_x2) {
        return _ref4.apply(this, arguments);
      }

      return write;
    }()
  }]);

  return GitShallowManager;
}();

// @flow
// import LockManager from 'travix-lock-manager'
// import Lock from '../utils'

// TODO: replace with an LRU cache?
var map /*: Map<string, GitIndex> */ = new _Map();
// const lm = new LockManager()
var lock = new AsyncLock();

/** @ignore */
var GitIndexManager = function () {
  function GitIndexManager() {
    _classCallCheck(this, GitIndexManager);
  }

  _createClass(GitIndexManager, null, [{
    key: 'acquire',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref, closure) {
        var _fs = _ref.fs,
            filepath = _ref.filepath;
        var fs;
        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                _context2.next = 3;
                return lock.acquire(filepath, _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
                  var index, rawIndexFile, buffer$$1;
                  return _regeneratorRuntime.wrap(function _callee$(_context) {
                    while (1) {
                      switch (_context.prev = _context.next) {
                        case 0:
                          index = map.get(filepath);

                          if (!(index === undefined)) {
                            _context.next = 7;
                            break;
                          }

                          _context.next = 4;
                          return fs.read(filepath);

                        case 4:
                          rawIndexFile = _context.sent;

                          index = models_js.GitIndex.from(rawIndexFile);
                          // cache the GitIndex object so we don't need to re-read it
                          // every time.
                          // TODO: save the stat data for the index so we know whether
                          // the cached file is stale (modified by an outside process).
                          map.set(filepath, index);
                          // await fileLock.cancel()

                        case 7:
                          _context.next = 9;
                          return closure(index);

                        case 9:
                          if (!index._dirty) {
                            _context.next = 14;
                            break;
                          }

                          // Acquire a file lock while we're writing the index file
                          // let fileLock = await Lock(filepath)
                          buffer$$1 = index.toObject();
                          _context.next = 13;
                          return fs.write(filepath, buffer$$1);

                        case 13:
                          index._dirty = false;

                        case 14:
                          // For now, discard our cached object so that external index
                          // manipulation is picked up. TODO: use lstat and compare
                          // file times to determine if our cached object should be
                          // discarded.
                          map.delete(filepath);

                        case 15:
                        case 'end':
                          return _context.stop();
                      }
                    }
                  }, _callee, this);
                })));

              case 3:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function acquire(_x, _x2) {
        return _ref2.apply(this, arguments);
      }

      return acquire;
    }()
  }]);

  return GitIndexManager;
}();

// @flow
// I'm putting this in a Manager because I reckon it could benefit
// from a LOT of cacheing.

// TODO: Implement .git/info/exclude

/** @ignore */
var GitIgnoreManager = function () {
  function GitIgnoreManager() {
    _classCallCheck(this, GitIgnoreManager);
  }

  _createClass(GitIgnoreManager, null, [{
    key: 'isIgnored',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
        var _fs = _ref.fs,
            dir = _ref.dir,
            _ref$gitdir = _ref.gitdir,
            gitdir = _ref$gitdir === undefined ? path.join(dir, '.git') : _ref$gitdir,
            filepath = _ref.filepath;

        var fs, pairs, pieces, i, folder, file, ignoredStatus, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, p, _file, ign, unign, parentdir;

        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                pairs = [{
                  gitignore: path.join(dir, '.gitignore'),
                  filepath: filepath
                }];
                pieces = filepath.split('/');

                for (i = 1; i < pieces.length; i++) {
                  folder = pieces.slice(0, i).join('/');
                  file = pieces.slice(i).join('/');

                  pairs.push({
                    gitignore: path.join(dir, folder, '.gitignore'),
                    filepath: file
                  });
                }
                ignoredStatus = false;
                _iteratorNormalCompletion = true;
                _didIteratorError = false;
                _iteratorError = undefined;
                _context.prev = 8;
                _iterator = _getIterator(pairs);

              case 10:
                if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
                  _context.next = 32;
                  break;
                }

                p = _step.value;
                _file = void 0;
                _context.prev = 13;
                _context.next = 16;
                return fs.read(p.gitignore, 'utf8');

              case 16:
                _file = _context.sent;
                _context.next = 23;
                break;

              case 19:
                _context.prev = 19;
                _context.t0 = _context['catch'](13);

                if (!(_context.t0.code === 'NOENT')) {
                  _context.next = 23;
                  break;
                }

                return _context.abrupt('continue', 29);

              case 23:
                ign = ignore().add(_file);
                unign = ignore().add('**\n' + _file);
                // If the parent directory is excluded, we are done.
                // "It is not possible to re-include a file if a parent directory of that file is excluded. Git doesn’t list excluded directories for performance reasons, so any patterns on contained files have no effect, no matter where they are defined."
                // source: https://git-scm.com/docs/gitignore

                parentdir = path.dirname(p.filepath);

                if (!ign.ignores(parentdir)) {
                  _context.next = 28;
                  break;
                }

                return _context.abrupt('return', true);

              case 28:
                // If the file is currently ignored, test for UNignoring.
                if (ignoredStatus) {
                  ignoredStatus = unign.ignores(p.filepath);
                } else {
                  ignoredStatus = ign.ignores(p.filepath);
                }

              case 29:
                _iteratorNormalCompletion = true;
                _context.next = 10;
                break;

              case 32:
                _context.next = 38;
                break;

              case 34:
                _context.prev = 34;
                _context.t1 = _context['catch'](8);
                _didIteratorError = true;
                _iteratorError = _context.t1;

              case 38:
                _context.prev = 38;
                _context.prev = 39;

                if (!_iteratorNormalCompletion && _iterator.return) {
                  _iterator.return();
                }

              case 41:
                _context.prev = 41;

                if (!_didIteratorError) {
                  _context.next = 44;
                  break;
                }

                throw _iteratorError;

              case 44:
                return _context.finish(41);

              case 45:
                return _context.finish(38);

              case 46:
                return _context.abrupt('return', ignoredStatus);

              case 47:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this, [[8, 34, 38, 46], [13, 19], [39,, 41, 45]]);
      }));

      function isIgnored(_x) {
        return _ref2.apply(this, arguments);
      }

      return isIgnored;
    }()
  }]);

  return GitIgnoreManager;
}();

var PackfileCache = new _Map();

/** @ignore */
var GitObjectManager = function () {
  function GitObjectManager() {
    _classCallCheck(this, GitObjectManager);
  }

  _createClass(GitObjectManager, null, [{
    key: 'read',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
        var _fs = _ref.fs,
            gitdir = _ref.gitdir,
            oid = _ref.oid;

        var fs, file, getExternalRefDelta, list, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, filename, p, idxName, idx, pack, _pack, text, _GitObject$unwrap, type, object;

        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                // Look for it in the loose object directory.

                _context.next = 3;
                return fs.read(gitdir + '/objects/' + oid.slice(0, 2) + '/' + oid.slice(2));

              case 3:
                file = _context.sent;

                if (file) {
                  _context.next = 65;
                  break;
                }

                // Curry the current read method so that the packfile un-deltification
                // process can acquire external ref-deltas.
                getExternalRefDelta = function getExternalRefDelta(oid) {
                  return GitObjectManager.read({ fs: _fs, gitdir: gitdir, oid: oid });
                };
                // Iterate through all the .pack files


                _context.next = 8;
                return fs.readdir(path.join(gitdir, '/objects/pack'));

              case 8:
                list = _context.sent;

                list = list.filter(function (x) {
                  return x.endsWith('.pack');
                });
                _iteratorNormalCompletion = true;
                _didIteratorError = false;
                _iteratorError = undefined;
                _context.prev = 13;
                _iterator = _getIterator(list);

              case 15:
                if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
                  _context.next = 51;
                  break;
                }

                filename = _step.value;

                // Try to get the packfile from the in-memory cache
                p = PackfileCache.get(filename);

                if (p) {
                  _context.next = 40;
                  break;
                }

                // If not there, load it from a .idx file
                idxName = filename.replace(/pack$/, 'idx');
                _context.next = 22;
                return fs.exists(gitdir + '/objects/pack/' + idxName);

              case 22:
                if (!_context.sent) {
                  _context.next = 31;
                  break;
                }

                _context.next = 25;
                return fs.read(gitdir + '/objects/pack/' + idxName);

              case 25:
                idx = _context.sent;
                _context.next = 28;
                return models_js.GitPackIndex.fromIdx({ idx: idx, getExternalRefDelta: getExternalRefDelta });

              case 28:
                p = _context.sent;
                _context.next = 39;
                break;

              case 31:
                _context.next = 33;
                return fs.read(gitdir + '/objects/pack/' + filename);

              case 33:
                pack = _context.sent;
                _context.next = 36;
                return models_js.GitPackIndex.fromPack({ pack: pack, getExternalRefDelta: getExternalRefDelta });

              case 36:
                p = _context.sent;
                _context.next = 39;
                return fs.write(gitdir + '/objects/pack/' + idxName, p.toBuffer());

              case 39:
                PackfileCache.set(filename, p);

              case 40:
                if (!p.hashes.includes(oid)) {
                  _context.next = 48;
                  break;
                }

                if (p.pack) {
                  _context.next = 47;
                  break;
                }

                _context.next = 44;
                return fs.read(gitdir + '/objects/pack/' + filename);

              case 44:
                _pack = _context.sent;
                _context.next = 47;
                return p.load({ pack: _pack });

              case 47:
                return _context.abrupt('return', p.read({ oid: oid, getExternalRefDelta: getExternalRefDelta }));

              case 48:
                _iteratorNormalCompletion = true;
                _context.next = 15;
                break;

              case 51:
                _context.next = 57;
                break;

              case 53:
                _context.prev = 53;
                _context.t0 = _context['catch'](13);
                _didIteratorError = true;
                _iteratorError = _context.t0;

              case 57:
                _context.prev = 57;
                _context.prev = 58;

                if (!_iteratorNormalCompletion && _iterator.return) {
                  _iterator.return();
                }

              case 60:
                _context.prev = 60;

                if (!_didIteratorError) {
                  _context.next = 63;
                  break;
                }

                throw _iteratorError;

              case 63:
                return _context.finish(60);

              case 64:
                return _context.finish(57);

              case 65:
                if (file) {
                  _context.next = 71;
                  break;
                }

                _context.next = 68;
                return fs.read(gitdir + '/shallow', { encoding: 'utf8' });

              case 68:
                text = _context.sent;

                if (!(text !== null && text.includes(oid))) {
                  _context.next = 71;
                  break;
                }

                throw new Error('Failed to read git object with oid ' + oid + ' because it is a shallow commit');

              case 71:
                if (file) {
                  _context.next = 73;
                  break;
                }

                throw new Error('Failed to read git object with oid ' + oid);

              case 73:
                _GitObject$unwrap = models_js.GitObject.unwrap({ oid: oid, file: file }), type = _GitObject$unwrap.type, object = _GitObject$unwrap.object;
                return _context.abrupt('return', { type: type, object: object });

              case 75:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this, [[13, 53, 57, 65], [58,, 60, 64]]);
      }));

      function read(_x) {
        return _ref2.apply(this, arguments);
      }

      return read;
    }()
  }, {
    key: 'hash',
    value: function () {
      var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref3) {
        var gitdir = _ref3.gitdir,
            type = _ref3.type,
            object = _ref3.object;
        var buffer$$1, oid;
        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                buffer$$1 = buffer.Buffer.concat([buffer.Buffer.from(type + ' '), buffer.Buffer.from(object.byteLength.toString()), buffer.Buffer.from([0]), buffer.Buffer.from(object)]);
                oid = shasum(buffer$$1);
                return _context2.abrupt('return', oid);

              case 3:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function hash(_x2) {
        return _ref4.apply(this, arguments);
      }

      return hash;
    }()
  }, {
    key: 'write',
    value: function () {
      var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(_ref5) {
        var _fs = _ref5.fs,
            gitdir = _ref5.gitdir,
            type = _ref5.type,
            object = _ref5.object;

        var fs, _GitObject$wrap, file, oid, filepath;

        return _regeneratorRuntime.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                _GitObject$wrap = models_js.GitObject.wrap({ type: type, object: object }), file = _GitObject$wrap.file, oid = _GitObject$wrap.oid;
                filepath = gitdir + '/objects/' + oid.slice(0, 2) + '/' + oid.slice(2);
                // Don't overwrite existing git objects - this helps avoid EPERM errors.
                // Although I don't know how we'd fix corrupted objects then. Perhaps delete them
                // on read?

                _context3.next = 5;
                return fs.exists(filepath);

              case 5:
                if (_context3.sent) {
                  _context3.next = 8;
                  break;
                }

                _context3.next = 8;
                return fs.write(filepath, file);

              case 8:
                return _context3.abrupt('return', oid);

              case 9:
              case 'end':
                return _context3.stop();
            }
          }
        }, _callee3, this);
      }));

      function write(_x3) {
        return _ref6.apply(this, arguments);
      }

      return write;
    }()
  }]);

  return GitObjectManager;
}();

// This is a convenience wrapper for reading and writing files in the 'refs' directory.
/** @ignore */
var GitRefManager = function () {
  function GitRefManager() {
    _classCallCheck(this, GitRefManager);
  }

  _createClass(GitRefManager, null, [{
    key: 'updateRemoteRefs',

    /* ::
    updateRemoteRefs : ({
      gitdir: string,
      remote: string,
      refs: Map<string, string>,
      symrefs: Map<string, string>
    }) => Promise<void>
    */
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
        var _fs = _ref.fs,
            gitdir = _ref.gitdir,
            remote = _ref.remote,
            refs = _ref.refs,
            symrefs = _ref.symrefs,
            tags = _ref.tags;

        var fs, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, value, actualRefsToWrite, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _ref3, _ref4, key, _value, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, _ref5, _ref6, _key, _value2, branch, normalizeValue, _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, _ref7, _ref8, _key2, _value3, filename;

        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                // Validate input

                _iteratorNormalCompletion = true;
                _didIteratorError = false;
                _iteratorError = undefined;
                _context.prev = 4;
                _iterator = _getIterator(refs.values());

              case 6:
                if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
                  _context.next = 13;
                  break;
                }

                value = _step.value;

                if (value.match(/[0-9a-f]{40}/)) {
                  _context.next = 10;
                  break;
                }

                throw new Error('Unexpected ref contents: \'' + value + '\'');

              case 10:
                _iteratorNormalCompletion = true;
                _context.next = 6;
                break;

              case 13:
                _context.next = 19;
                break;

              case 15:
                _context.prev = 15;
                _context.t0 = _context['catch'](4);
                _didIteratorError = true;
                _iteratorError = _context.t0;

              case 19:
                _context.prev = 19;
                _context.prev = 20;

                if (!_iteratorNormalCompletion && _iterator.return) {
                  _iterator.return();
                }

              case 22:
                _context.prev = 22;

                if (!_didIteratorError) {
                  _context.next = 25;
                  break;
                }

                throw _iteratorError;

              case 25:
                return _context.finish(22);

              case 26:
                return _context.finish(19);

              case 27:
                // Combine refs and symrefs giving symrefs priority
                actualRefsToWrite = new _Map();
                _iteratorNormalCompletion2 = true;
                _didIteratorError2 = false;
                _iteratorError2 = undefined;
                _context.prev = 31;

                for (_iterator2 = _getIterator(refs); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                  _ref3 = _step2.value;
                  _ref4 = _slicedToArray(_ref3, 2);
                  key = _ref4[0];
                  _value = _ref4[1];

                  actualRefsToWrite.set(key, _value);
                }
                _context.next = 39;
                break;

              case 35:
                _context.prev = 35;
                _context.t1 = _context['catch'](31);
                _didIteratorError2 = true;
                _iteratorError2 = _context.t1;

              case 39:
                _context.prev = 39;
                _context.prev = 40;

                if (!_iteratorNormalCompletion2 && _iterator2.return) {
                  _iterator2.return();
                }

              case 42:
                _context.prev = 42;

                if (!_didIteratorError2) {
                  _context.next = 45;
                  break;
                }

                throw _iteratorError2;

              case 45:
                return _context.finish(42);

              case 46:
                return _context.finish(39);

              case 47:
                _iteratorNormalCompletion3 = true;
                _didIteratorError3 = false;
                _iteratorError3 = undefined;
                _context.prev = 50;
                for (_iterator3 = _getIterator(symrefs); !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
                  _ref5 = _step3.value;
                  _ref6 = _slicedToArray(_ref5, 2);
                  _key = _ref6[0];
                  _value2 = _ref6[1];
                  branch = _value2.replace(/^refs\/heads\//, '');

                  actualRefsToWrite.set(_key, 'ref: refs/remotes/' + remote + '/' + branch);
                }
                // Update files
                // TODO: For large repos with a history of thousands of pull requests
                // (i.e. gitlab-ce) it would be vastly more efficient to write them
                // to .git/packed-refs.
                // The trick is to make sure we a) don't write a packed ref that is
                // already shadowed by a loose ref and b) don't loose any refs already
                // in packed-refs. Doing this efficiently may be difficult. A
                // solution that might work is
                // a) load the current packed-refs file
                // b) add actualRefsToWrite, overriding the existing values if present
                // c) enumerate all the loose refs currently in .git/refs/remotes/${remote}
                // d) overwrite their value with the new value.
                // Examples of refs we need to avoid writing in loose format for efficieny's sake
                // are .git/refs/remotes/origin/refs/remotes/remote_mirror_3059
                // and .git/refs/remotes/origin/refs/merge-requests
                _context.next = 58;
                break;

              case 54:
                _context.prev = 54;
                _context.t2 = _context['catch'](50);
                _didIteratorError3 = true;
                _iteratorError3 = _context.t2;

              case 58:
                _context.prev = 58;
                _context.prev = 59;

                if (!_iteratorNormalCompletion3 && _iterator3.return) {
                  _iterator3.return();
                }

              case 61:
                _context.prev = 61;

                if (!_didIteratorError3) {
                  _context.next = 64;
                  break;
                }

                throw _iteratorError3;

              case 64:
                return _context.finish(61);

              case 65:
                return _context.finish(58);

              case 66:
                normalizeValue = function normalizeValue(value) {
                  return value.trim() + '\n';
                };

                _iteratorNormalCompletion4 = true;
                _didIteratorError4 = false;
                _iteratorError4 = undefined;
                _context.prev = 70;
                _iterator4 = _getIterator(actualRefsToWrite);

              case 72:
                if (_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done) {
                  _context.next = 94;
                  break;
                }

                _ref7 = _step4.value;
                _ref8 = _slicedToArray(_ref7, 2);
                _key2 = _ref8[0];
                _value3 = _ref8[1];

                if (!(_key2.startsWith('refs/heads') || _key2 === 'HEAD')) {
                  _context.next = 83;
                  break;
                }

                _key2 = _key2.replace(/^refs\/heads\//, '');
                _context.next = 81;
                return fs.write(path.join(gitdir, 'refs', 'remotes', remote, _key2), normalizeValue(_value3), 'utf8');

              case 81:
                _context.next = 91;
                break;

              case 83:
                if (!(tags === true && _key2.startsWith('refs/tags') && !_key2.endsWith('^{}'))) {
                  _context.next = 91;
                  break;
                }

                _key2 = _key2.replace(/^refs\/tags\//, '');
                filename = path.join(gitdir, 'refs', 'tags', _key2);
                // Git's behavior is to only fetch tags that do not conflict with tags already present.

                _context.next = 88;
                return fs.exists(filename);

              case 88:
                if (_context.sent) {
                  _context.next = 91;
                  break;
                }

                _context.next = 91;
                return fs.write(filename, normalizeValue(_value3), 'utf8');

              case 91:
                _iteratorNormalCompletion4 = true;
                _context.next = 72;
                break;

              case 94:
                _context.next = 100;
                break;

              case 96:
                _context.prev = 96;
                _context.t3 = _context['catch'](70);
                _didIteratorError4 = true;
                _iteratorError4 = _context.t3;

              case 100:
                _context.prev = 100;
                _context.prev = 101;

                if (!_iteratorNormalCompletion4 && _iterator4.return) {
                  _iterator4.return();
                }

              case 103:
                _context.prev = 103;

                if (!_didIteratorError4) {
                  _context.next = 106;
                  break;
                }

                throw _iteratorError4;

              case 106:
                return _context.finish(103);

              case 107:
                return _context.finish(100);

              case 108:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this, [[4, 15, 19, 27], [20,, 22, 26], [31, 35, 39, 47], [40,, 42, 46], [50, 54, 58, 66], [59,, 61, 65], [70, 96, 100, 108], [101,, 103, 107]]);
      }));

      function updateRemoteRefs(_x) {
        return _ref2.apply(this, arguments);
      }

      return updateRemoteRefs;
    }()
  }, {
    key: 'resolve',
    value: function () {
      var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref9) {
        var _fs = _ref9.fs,
            gitdir = _ref9.gitdir,
            ref = _ref9.ref,
            depth = _ref9.depth;
        var fs, sha, text, candidates;
        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);

                if (!(depth !== undefined)) {
                  _context2.next = 5;
                  break;
                }

                depth--;

                if (!(depth === -1)) {
                  _context2.next = 5;
                  break;
                }

                return _context2.abrupt('return', ref);

              case 5:
                sha = void 0;
                // Is it a ref pointer?

                if (!ref.startsWith('ref: ')) {
                  _context2.next = 9;
                  break;
                }

                ref = ref.slice('ref: '.length);
                return _context2.abrupt('return', GitRefManager.resolve({ fs: fs, gitdir: gitdir, ref: ref, depth: depth }));

              case 9:
                if (!(ref.length === 40 && /[0-9a-f]{40}/.test(ref))) {
                  _context2.next = 11;
                  break;
                }

                return _context2.abrupt('return', ref);

              case 11:
                if (!(ref === 'HEAD' || ref === 'MERGE_HEAD')) {
                  _context2.next = 17;
                  break;
                }

                _context2.next = 14;
                return fs.read(gitdir + '/' + ref, { encoding: 'utf8' });

              case 14:
                sha = _context2.sent;

                if (!sha) {
                  _context2.next = 17;
                  break;
                }

                return _context2.abrupt('return', GitRefManager.resolve({ fs: fs, gitdir: gitdir, ref: sha.trim(), depth: depth }));

              case 17:
                if (!ref.startsWith('refs/')) {
                  _context2.next = 23;
                  break;
                }

                _context2.next = 20;
                return fs.read(gitdir + '/' + ref, { encoding: 'utf8' });

              case 20:
                sha = _context2.sent;

                if (!sha) {
                  _context2.next = 23;
                  break;
                }

                return _context2.abrupt('return', GitRefManager.resolve({ fs: fs, gitdir: gitdir, ref: sha.trim(), depth: depth }));

              case 23:
                _context2.next = 25;
                return fs.read(gitdir + '/refs/heads/' + ref, { encoding: 'utf8' });

              case 25:
                sha = _context2.sent;

                if (!sha) {
                  _context2.next = 28;
                  break;
                }

                return _context2.abrupt('return', GitRefManager.resolve({ fs: fs, gitdir: gitdir, ref: sha.trim(), depth: depth }));

              case 28:
                _context2.next = 30;
                return fs.read(gitdir + '/refs/tags/' + ref, { encoding: 'utf8' });

              case 30:
                sha = _context2.sent;

                if (!sha) {
                  _context2.next = 33;
                  break;
                }

                return _context2.abrupt('return', GitRefManager.resolve({ fs: fs, gitdir: gitdir, ref: sha.trim(), depth: depth }));

              case 33:
                _context2.next = 35;
                return fs.read(gitdir + '/refs/remotes/' + ref, { encoding: 'utf8' });

              case 35:
                sha = _context2.sent;

                if (!sha) {
                  _context2.next = 38;
                  break;
                }

                return _context2.abrupt('return', GitRefManager.resolve({ fs: fs, gitdir: gitdir, ref: sha.trim(), depth: depth }));

              case 38:
                _context2.next = 40;
                return fs.read(gitdir + '/packed-refs', { encoding: 'utf8' });

              case 40:
                text = _context2.sent;

                if (!(text && text.includes(ref))) {
                  _context2.next = 50;
                  break;
                }

                candidates = text.trim().split('\n').filter(function (x) {
                  return x.endsWith(ref);
                }).filter(function (x) {
                  return !x.startsWith('#');
                });

                if (!(candidates.length > 1)) {
                  _context2.next = 47;
                  break;
                }

                throw new Error('Could not resolve ambiguous reference ' + ref);

              case 47:
                if (!(candidates.length === 1)) {
                  _context2.next = 50;
                  break;
                }

                sha = candidates[0].split(' ')[0];
                return _context2.abrupt('return', GitRefManager.resolve({ fs: fs, gitdir: gitdir, ref: sha.trim(), depth: depth }));

              case 50:
                throw new Error('Could not resolve reference ' + ref);

              case 51:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function resolve(_x2) {
        return _ref10.apply(this, arguments);
      }

      return resolve;
    }()
  }, {
    key: 'packedRefs',
    value: function () {
      var _ref12 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(_ref11) {
        var _fs = _ref11.fs,
            gitdir = _ref11.gitdir;

        var refs, fs, text, lines, key, _iteratorNormalCompletion5, _didIteratorError5, _iteratorError5, _iterator5, _step5, line, i, value, _value4;

        return _regeneratorRuntime.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                refs = new _Map();
                fs = new models_js.FileSystem(_fs);
                _context3.next = 4;
                return fs.read(gitdir + '/packed-refs', { encoding: 'utf8' });

              case 4:
                text = _context3.sent;

                if (text) {
                  _context3.next = 7;
                  break;
                }

                return _context3.abrupt('return', refs);

              case 7:
                lines = text.trim().split('\n').filter(function (line) {
                  return !/^\s*#/.test(line);
                });
                key = null;
                _iteratorNormalCompletion5 = true;
                _didIteratorError5 = false;
                _iteratorError5 = undefined;
                _context3.prev = 12;

                for (_iterator5 = _getIterator(lines); !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
                  line = _step5.value;
                  i = line.indexOf(' ');

                  if (line.startsWith('^')) {
                    // This is a oid for the commit associated with the annotated tag immediately preceding this line.
                    // Trim off the '^'
                    value = line.slice(1, i);
                    // The tagname^{} syntax is based on the output of `git show-ref --tags -d`

                    refs.set(key + '^{}', value);
                  } else {
                    // This is an oid followed by the ref name
                    _value4 = line.slice(0, i);

                    key = line.slice(i + 1);
                    refs.set(key, _value4);
                  }
                }
                _context3.next = 20;
                break;

              case 16:
                _context3.prev = 16;
                _context3.t0 = _context3['catch'](12);
                _didIteratorError5 = true;
                _iteratorError5 = _context3.t0;

              case 20:
                _context3.prev = 20;
                _context3.prev = 21;

                if (!_iteratorNormalCompletion5 && _iterator5.return) {
                  _iterator5.return();
                }

              case 23:
                _context3.prev = 23;

                if (!_didIteratorError5) {
                  _context3.next = 26;
                  break;
                }

                throw _iteratorError5;

              case 26:
                return _context3.finish(23);

              case 27:
                return _context3.finish(20);

              case 28:
                return _context3.abrupt('return', refs);

              case 29:
              case 'end':
                return _context3.stop();
            }
          }
        }, _callee3, this, [[12, 16, 20, 28], [21,, 23, 27]]);
      }));

      function packedRefs(_x3) {
        return _ref12.apply(this, arguments);
      }

      return packedRefs;
    }()
    // List all the refs that match the `filepath` prefix

  }, {
    key: 'listRefs',
    value: function () {
      var _ref14 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(_ref13) {
        var _fs = _ref13.fs,
            gitdir = _ref13.gitdir,
            filepath = _ref13.filepath;

        var fs, packedMap, files, _iteratorNormalCompletion6, _didIteratorError6, _iteratorError6, _iterator6, _step6, key;

        return _regeneratorRuntime.wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                packedMap = GitRefManager.packedRefs({ fs: fs, gitdir: gitdir });
                files = null;
                _context4.prev = 3;
                _context4.next = 6;
                return fs.readdirDeep(gitdir + '/' + filepath);

              case 6:
                files = _context4.sent;

                files = files.map(function (x) {
                  return x.replace(gitdir + '/' + filepath + '/', '');
                });
                _context4.next = 13;
                break;

              case 10:
                _context4.prev = 10;
                _context4.t0 = _context4['catch'](3);

                files = [];

              case 13:
                _iteratorNormalCompletion6 = true;
                _didIteratorError6 = false;
                _iteratorError6 = undefined;
                _context4.prev = 16;
                _context4.t1 = _getIterator;
                _context4.next = 20;
                return packedMap;

              case 20:
                _context4.t2 = _context4.sent.keys();
                _iterator6 = (0, _context4.t1)(_context4.t2);

              case 22:
                if (_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done) {
                  _context4.next = 28;
                  break;
                }

                key = _step6.value;

                // filter by prefix
                if (key.startsWith(filepath)) {
                  // remove prefix
                  key = key.replace(filepath + '/', '');
                  // Don't include duplicates; the loose files have precedence anyway
                  if (!files.includes(key)) {
                    files.push(key);
                  }
                }

              case 25:
                _iteratorNormalCompletion6 = true;
                _context4.next = 22;
                break;

              case 28:
                _context4.next = 34;
                break;

              case 30:
                _context4.prev = 30;
                _context4.t3 = _context4['catch'](16);
                _didIteratorError6 = true;
                _iteratorError6 = _context4.t3;

              case 34:
                _context4.prev = 34;
                _context4.prev = 35;

                if (!_iteratorNormalCompletion6 && _iterator6.return) {
                  _iterator6.return();
                }

              case 37:
                _context4.prev = 37;

                if (!_didIteratorError6) {
                  _context4.next = 40;
                  break;
                }

                throw _iteratorError6;

              case 40:
                return _context4.finish(37);

              case 41:
                return _context4.finish(34);

              case 42:
                return _context4.abrupt('return', files);

              case 43:
              case 'end':
                return _context4.stop();
            }
          }
        }, _callee4, this, [[3, 10], [16, 30, 34, 42], [35,, 37, 41]]);
      }));

      function listRefs(_x4) {
        return _ref14.apply(this, arguments);
      }

      return listRefs;
    }()
  }, {
    key: 'listBranches',
    value: function () {
      var _ref16 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(_ref15) {
        var _fs = _ref15.fs,
            gitdir = _ref15.gitdir,
            remote = _ref15.remote;
        var fs;
        return _regeneratorRuntime.wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);

                if (!remote) {
                  _context5.next = 5;
                  break;
                }

                return _context5.abrupt('return', GitRefManager.listRefs({
                  fs: fs,
                  gitdir: gitdir,
                  filepath: 'refs/remotes/' + remote
                }));

              case 5:
                return _context5.abrupt('return', GitRefManager.listRefs({ fs: fs, gitdir: gitdir, filepath: 'refs/heads' }));

              case 6:
              case 'end':
                return _context5.stop();
            }
          }
        }, _callee5, this);
      }));

      function listBranches(_x5) {
        return _ref16.apply(this, arguments);
      }

      return listBranches;
    }()
  }, {
    key: 'listTags',
    value: function () {
      var _ref18 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(_ref17) {
        var _fs = _ref17.fs,
            gitdir = _ref17.gitdir;
        var fs, tags;
        return _regeneratorRuntime.wrap(function _callee6$(_context6) {
          while (1) {
            switch (_context6.prev = _context6.next) {
              case 0:
                fs = new models_js.FileSystem(_fs);
                _context6.next = 3;
                return GitRefManager.listRefs({
                  fs: fs,
                  gitdir: gitdir,
                  filepath: 'refs/tags'
                });

              case 3:
                tags = _context6.sent;

                tags = tags.filter(function (x) {
                  return !x.endsWith('^{}');
                });
                return _context6.abrupt('return', tags);

              case 6:
              case 'end':
                return _context6.stop();
            }
          }
        }, _callee6, this);
      }));

      function listTags(_x6) {
        return _ref18.apply(this, arguments);
      }

      return listTags;
    }()
  }]);

  return GitRefManager;
}();

// @flow
function basicAuth(auth) {
  return 'Basic ' + buffer.Buffer.from(auth.username + ':' + auth.password).toString('base64');
}

/** @ignore */

var GitRemoteHTTP = function () {
  /*::
  GIT_URL : string
  refs : Map<string, string>
  symrefs : Map<string, string>
  capabilities : Set<string>
  auth : { username : string, password : string }
  */
  function GitRemoteHTTP(url /*: string */) {
    _classCallCheck(this, GitRemoteHTTP);

    // Auto-append the (necessary) .git if it's missing.
    if (!url.endsWith('.git')) url = url += '.git';
    this.GIT_URL = url;
  }

  _createClass(GitRemoteHTTP, [{
    key: 'preparePull',
    value: function () {
      var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return this.discover('git-upload-pack');

              case 2:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

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

      return preparePull;
    }()
  }, {
    key: 'preparePush',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                _context2.next = 2;
                return this.discover('git-receive-pack');

              case 2:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function preparePush() {
        return _ref2.apply(this, arguments);
      }

      return preparePush;
    }()
  }, {
    key: 'discover',
    value: function () {
      var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(service /*: string */) {
        var _this = this;

        var headers, res, data, read, lineOne, lineTwo, _lineTwo$toString$tri, _lineTwo$toString$tri2, firstRef, capabilities, _firstRef$split, _firstRef$split2, ref, name, line, _line$toString$trim$s, _line$toString$trim$s2, _ref4, _name, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, cap, m;

        return _regeneratorRuntime.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                this.capabilities = new _Set();
                this.refs = new _Map();
                this.symrefs = new _Map();
                headers = {};
                // headers['Accept'] = `application/x-${service}-advertisement`

                if (this.auth) {
                  headers['Authorization'] = basicAuth(this.auth);
                }
                _context3.next = 7;
                return pify(simpleGet)({
                  method: 'GET',
                  url: this.GIT_URL + '/info/refs?service=' + service,
                  headers: headers
                });

              case 7:
                res = _context3.sent;

                if (!(res.statusCode !== 200)) {
                  _context3.next = 10;
                  break;
                }

                throw new Error('Bad status code from server: ' + res.statusCode);

              case 10:
                _context3.next = 12;
                return pify(concat)(res);

              case 12:
                data = _context3.sent;

                // There is probably a better way to do this, but for now
                // let's just throw the result parser inline here.
                read = models_js.GitPktLine.reader(data);
                lineOne = read();
                // skip past any flushes

                while (lineOne === null) {
                  lineOne = read();
                }
                if (!(lineOne === true)) {
                  _context3.next = 18;
                  break;
                }

                throw new Error('Bad response from git server.');

              case 18:
                if (!(lineOne.toString('utf8') !== '# service=' + service + '\n')) {
                  _context3.next = 20;
                  break;
                }

                throw new Error('Expected \'# service=' + service + '\\n\' but got \'' + lineOne.toString('utf8') + '\'');

              case 20:
                lineTwo = read();
                // skip past any flushes

                while (lineTwo === null) {
                  lineTwo = read();
                } // In the edge case of a brand new repo, zero refs (and zero capabilities)
                // are returned.

                if (!(lineTwo === true)) {
                  _context3.next = 24;
                  break;
                }

                return _context3.abrupt('return');

              case 24:
                _lineTwo$toString$tri = lineTwo.toString('utf8').trim().split('\0'), _lineTwo$toString$tri2 = _slicedToArray(_lineTwo$toString$tri, 2), firstRef = _lineTwo$toString$tri2[0], capabilities = _lineTwo$toString$tri2[1];

                capabilities.split(' ').map(function (x) {
                  return _this.capabilities.add(x);
                });
                _firstRef$split = firstRef.split(' '), _firstRef$split2 = _slicedToArray(_firstRef$split, 2), ref = _firstRef$split2[0], name = _firstRef$split2[1];

                this.refs.set(name, ref);

              case 28:
                

                line = read();

                if (!(line === true)) {
                  _context3.next = 32;
                  break;
                }

                return _context3.abrupt('break', 35);

              case 32:
                if (line !== null) {
                  _line$toString$trim$s = line.toString('utf8').trim().split(' '), _line$toString$trim$s2 = _slicedToArray(_line$toString$trim$s, 2), _ref4 = _line$toString$trim$s2[0], _name = _line$toString$trim$s2[1];

                  this.refs.set(_name, _ref4);
                }
                _context3.next = 28;
                break;

              case 35:
                // Symrefs are thrown into the "capabilities" unfortunately.
                _iteratorNormalCompletion = true;
                _didIteratorError = false;
                _iteratorError = undefined;
                _context3.prev = 38;
                for (_iterator = _getIterator(this.capabilities); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                  cap = _step.value;

                  if (cap.startsWith('symref=')) {
                    m = cap.match(/symref=([^:]+):(.*)/);

                    if (m.length === 3) {
                      this.symrefs.set(m[1], m[2]);
                    }
                  }
                }
                _context3.next = 46;
                break;

              case 42:
                _context3.prev = 42;
                _context3.t0 = _context3['catch'](38);
                _didIteratorError = true;
                _iteratorError = _context3.t0;

              case 46:
                _context3.prev = 46;
                _context3.prev = 47;

                if (!_iteratorNormalCompletion && _iterator.return) {
                  _iterator.return();
                }

              case 49:
                _context3.prev = 49;

                if (!_didIteratorError) {
                  _context3.next = 52;
                  break;
                }

                throw _iteratorError;

              case 52:
                return _context3.finish(49);

              case 53:
                return _context3.finish(46);

              case 54:
              case 'end':
                return _context3.stop();
            }
          }
        }, _callee3, this, [[38, 42, 46, 54], [47,, 49, 53]]);
      }));

      function discover(_x) {
        return _ref3.apply(this, arguments);
      }

      return discover;
    }()
  }, {
    key: 'push',
    value: function () {
      var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(stream$$1 /*: ReadableStream */) {
        var service, _ref6, packetlines, packfile, result, response, read, line, lines, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _line, status, refAndMessage;

        return _regeneratorRuntime.wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                service = 'git-receive-pack';
                _context4.next = 3;
                return this.stream({
                  stream: stream$$1,
                  service: service
                });

              case 3:
                _ref6 = _context4.sent;
                packetlines = _ref6.packetlines;
                packfile = _ref6.packfile;
                _context4.next = 8;
                return pify(concat)(packfile);

              case 8:
                packfile = _context4.sent;
                _context4.next = 11;
                return pify(concat)(packetlines);

              case 11:
                packetlines = _context4.sent;
                result = {};
                // Parse the response!
                // I'm combining the side-band-64k and regular streams
                // because Github returns the first line in the sideband while
                // git-http-server returns it without the sideband.

                response = '';
                read = models_js.GitPktLine.reader(packfile);
                _context4.next = 17;
                return read();

              case 17:
                line = _context4.sent;

              case 18:
                if (!(line !== null && line !== true)) {
                  _context4.next = 25;
                  break;
                }

                response += line.toString('utf8') + '\n';
                _context4.next = 22;
                return read();

              case 22:
                line = _context4.sent;
                _context4.next = 18;
                break;

              case 25:
                response += packetlines.toString('utf8');

                lines = response.toString('utf8').split('\n');
                // We're expecting "unpack {unpack-result}"

                line = lines.shift();

                if (line.startsWith('unpack ')) {
                  _context4.next = 30;
                  break;
                }

                throw new Error('Unparsable response from server! Expected \'unpack ok\' or \'unpack [error message]\' but got \'' + line + '\'');

              case 30:
                if (line === 'unpack ok') {
                  result.ok = ['unpack'];
                } else {
                  result.errors = [line.trim()];
                }
                _iteratorNormalCompletion2 = true;
                _didIteratorError2 = false;
                _iteratorError2 = undefined;
                _context4.prev = 34;
                for (_iterator2 = _getIterator(lines); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                  _line = _step2.value;
                  status = _line.slice(0, 2);
                  refAndMessage = _line.slice(3);

                  if (status === 'ok') {
                    result.ok = result.ok || [];
                    result.ok.push(refAndMessage);
                  } else if (status === 'ng') {
                    result.errors = result.errors || [];
                    result.errors.push(refAndMessage);
                  }
                }
                _context4.next = 42;
                break;

              case 38:
                _context4.prev = 38;
                _context4.t0 = _context4['catch'](34);
                _didIteratorError2 = true;
                _iteratorError2 = _context4.t0;

              case 42:
                _context4.prev = 42;
                _context4.prev = 43;

                if (!_iteratorNormalCompletion2 && _iterator2.return) {
                  _iterator2.return();
                }

              case 45:
                _context4.prev = 45;

                if (!_didIteratorError2) {
                  _context4.next = 48;
                  break;
                }

                throw _iteratorError2;

              case 48:
                return _context4.finish(45);

              case 49:
                return _context4.finish(42);

              case 50:
                utils_js.log(result);
                return _context4.abrupt('return', result);

              case 52:
              case 'end':
                return _context4.stop();
            }
          }
        }, _callee4, this, [[34, 38, 42, 50], [43,, 45, 49]]);
      }));

      function push(_x2) {
        return _ref5.apply(this, arguments);
      }

      return push;
    }()
  }, {
    key: 'pull',
    value: function () {
      var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(stream$$1 /*: ReadableStream */) {
        var service, res;
        return _regeneratorRuntime.wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                service = 'git-upload-pack';
                _context5.next = 3;
                return this.stream({ stream: stream$$1, service: service });

              case 3:
                res = _context5.sent;
                return _context5.abrupt('return', res);

              case 5:
              case 'end':
                return _context5.stop();
            }
          }
        }, _callee5, this);
      }));

      function pull(_x3) {
        return _ref7.apply(this, arguments);
      }

      return pull;
    }()
  }, {
    key: 'stream',
    value: function () {
      var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(_ref8) {
        var _stream = _ref8.stream,
            service = _ref8.service;
        var headers, res, data, read, packetlines, packfile, progress, nextBit;
        return _regeneratorRuntime.wrap(function _callee7$(_context7) {
          while (1) {
            switch (_context7.prev = _context7.next) {
              case 0:
                headers = {};

                headers['content-type'] = 'application/x-' + service + '-request';
                headers['accept'] = 'application/x-' + service + '-result';
                headers['user-agent'] = 'git/' + utils_js.pkg.name + '@' + utils_js.pkg.version;
                if (this.auth) {
                  headers['authorization'] = basicAuth(this.auth);
                }
                _context7.next = 7;
                return pify(simpleGet)({
                  method: 'POST',
                  url: this.GIT_URL + '/' + service,
                  body: _stream,
                  headers: headers
                });

              case 7:
                res = _context7.sent;
                _context7.next = 10;
                return pify(concat)(res);

              case 10:
                data = _context7.sent;

                // Parse the response!
                read = models_js.GitPktLine.reader(data);
                // And now for the ridiculous side-band-64k protocol

                packetlines = new stream.PassThrough();
                packfile = new stream.PassThrough();
                progress = new stream.PassThrough();
                // TODO: Use a proper through stream?

                nextBit = function () {
                  var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
                    var line, error;
                    return _regeneratorRuntime.wrap(function _callee6$(_context6) {
                      while (1) {
                        switch (_context6.prev = _context6.next) {
                          case 0:
                            _context6.next = 2;
                            return read();

                          case 2:
                            line = _context6.sent;

                            if (!(line === null)) {
                              _context6.next = 5;
                              break;
                            }

                            return _context6.abrupt('return', nextBit());

                          case 5:
                            if (!(line === true)) {
                              _context6.next = 10;
                              break;
                            }

                            packetlines.end();
                            progress.end();
                            packfile.end();
                            return _context6.abrupt('return');

                          case 10:
                            _context6.t0 = line[0];
                            _context6.next = _context6.t0 === 1 ? 13 : _context6.t0 === 2 ? 15 : _context6.t0 === 3 ? 17 : 21;
                            break;

                          case 13:
                            // pack data
                            packfile.write(line.slice(1));
                            return _context6.abrupt('break', 22);

                          case 15:
                            // progress message
                            progress.write(line.slice(1));
                            return _context6.abrupt('break', 22);

                          case 17:
                            // fatal error message just before stream aborts
                            error = line.slice(1);

                            progress.write(error);
                            packfile.destroy(new Error(error.toString('utf8')));
                            return _context6.abrupt('return');

                          case 21:
                            // Not part of the side-band-64k protocol
                            packetlines.write(line.slice(0));

                          case 22:
                            // Careful not to blow up the stack.
                            // I think Promises in a tail-call position should be OK.
                            nextBit();

                          case 23:
                          case 'end':
                            return _context6.stop();
                        }
                      }
                    }, _callee6, this);
                  }));

                  return function nextBit() {
                    return _ref10.apply(this, arguments);
                  };
                }();

                nextBit();
                return _context7.abrupt('return', {
                  packetlines: packetlines,
                  packfile: packfile,
                  progress: progress
                });

              case 18:
              case 'end':
                return _context7.stop();
            }
          }
        }, _callee7, this);
      }));

      function stream$$1(_x4) {
        return _ref9.apply(this, arguments);
      }

      return stream$$1;
    }()
  }]);

  return GitRemoteHTTP;
}();

exports.GitConfigManager = GitConfigManager;
exports.GitShallowManager = GitShallowManager;
exports.GitIndexManager = GitIndexManager;
exports.GitIgnoreManager = GitIgnoreManager;
exports.GitObjectManager = GitObjectManager;
exports.GitRefManager = GitRefManager;
exports.GitRemoteHTTP = GitRemoteHTTP;
//# sourceMappingURL=managers.js.map
