text: const Git = require('./git');
  const filenamify = require('filenamify-url');
  const copy = require('./util').copy;
  const getUser = require('./util').getUser;
  const fs = require('fs-extra');
  const globby = require('globby');
  const path = require('path');
  const util = require('util');
  
  const log = util.debuglog('gh-pages');
  
  function getCacheDir() {
    return path.relative(process.cwd(), path.resolve(__dirname, '../.cache'));
  }
  
  function getRepo(options) {
    if (options.repo) {
      return Promise.resolve(options.repo);
    } else {
      const git = new Git(process.cwd(), options.git);
      return git.getRemoteUrl(options.remote);
    }
  }
  
  exports.defaults = {
    dest: '.',
    add: false,
    git: 'git',
    depth: 1,
    dotfiles: false,
    branch: 'gh-pages',
    remote: 'origin',
    src: '**/*',
    only: '.',
    push: true,
    history: true,
    message: 'Updates',
    silent: false
  };
  
  /**
   * Push a git branch to a remote (pushes gh-pages by default).
   * @param {string} basePath The base path.
   * @param {Object} config Publish options.
   * @param {Function} callback Callback.
   */
  exports.publish = function publish(basePath, config, callback) {
    if (typeof config === 'function') {
      callback = config;
      config = {};
    }
  
    const options = Object.assign({}, exports.defaults, config);
  
    if (!callback) {
      callback = function(err) {
        if (err) {
          log(err.message);
        }
      };
    }
  
    function done(err) {
      try {
        callback(err);
      } catch (err2) {
        log('Publish callback threw: %s', err2.message);
      }
    }
  
    try {
      if (!fs.statSync(basePath).isDirectory()) {
        done(new Error('The "base" option must be an existing directory'));
        return;
      }
    } catch (err) {
      done(err);
      return;
    }
  
    const files = globby
      .sync(options.src, {
        cwd: basePath,
        dot: options.dotfiles
      })
      .filter(file => {
        return !fs.statSync(path.join(basePath, file)).isDirectory();
      });
  
    if (!Array.isArray(files) || files.length === 0) {
      done(
        new Error('The pattern in the "src" property didn\'t match any files.')
      );
      return;
    }
  
    const only = globby.sync(options.only, {cwd: basePath}).map(file => {
      return path.join(options.dest, file);
    });
  
    let repoUrl;
    let userPromise;
    if (options.user) {
      userPromise = Promise.resolve(options.user);
    } else {
      userPromise = getUser();
    }
    return userPromise.then(user =>
      getRepo(options)
        .then(repo => {
          repoUrl = repo;
          const clone = path.join(getCacheDir(), filenamify(repo));
          log('Cloning %s into %s', repo, clone);
          return Git.clone(repo, clone, options.branch, options);
        })
        .then(git => {
          return git.getRemoteUrl(options.remote).then(url => {
            if (url !== repoUrl) {
              const message =
                'Remote url mismatch.  Got "' +
                url +
                '" ' +
                'but expected "' +
                repoUrl +
                '" in ' +
                git.cwd +
                '.  Try running the `gh-pages-clean` script first.';
              throw new Error(message);
            }
            return git;
          });
        })
        .then(git => {
          // only required if someone mucks with the checkout between builds
          log('Cleaning');
          return git.clean();
        })
        .then(git => {
          log('Fetching %s', options.remote);
          return git.fetch(options.remote);
        })
        .then(git => {
          log('Checking out %s/%s ', options.remote, options.branch);
          return git.checkout(options.remote, options.branch);
        })
        .then(git => {
          if (!options.history) {
            return git.deleteRef(options.branch);
          } else {
            return git;
          }
        })
        .then(git => {
          if (!options.add) {
            log('Removing files');
            return git.rm(only.join(' '));
          } else {
            return git;
          }
        })
        .then(git => {
          log('Copying files');
          return copy(files, basePath, path.join(git.cwd, options.dest)).then(
            function() {
              return git;
            }
          );
        })
        .then(git => {
          log('Adding all');
          return git.add('.');
        })
        .then(git => {
          if (!user) {
            return git;
          }
          return git.exec('config', 'user.email', user.email).then(() => {
            if (!user.name) {
              return git;
            }
            return git.exec('config', 'user.name', user.name);
          });
        })
        .then(git => {
          log('Committing');
          return git.commit(options.message);
        })
        .then(git => {
          if (options.tag) {
            log('Tagging');
            return git.tag(options.tag).catch(error => {
              // tagging failed probably because this tag alredy exists
              log(error);
              log('Tagging failed, continuing');
              return git;
            });
          } else {
            return git;
          }
        })
        .then(git => {
          if (options.push) {
            log('Pushing');
            return git.push(options.remote, options.branch, !options.history);
          } else {
            return git;
          }
        })
        .then(
          () => done(),
          error => {
            if (options.silent) {
              error = new Error(
                'Unspecified error (run without silent option for detail)'
              );
            }
            done(error);
          }
        )
    );
  };
  
  /**
   * Clean the cache directory.
   */
  exports.clean = function clean() {
    fs.removeSync(getCacheDir());
  };
  