diff.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. 'use strict';
  2. /**
  3. * diff
  4. * @module gulp-git/lib/diff
  5. */
  6. var Vinyl = require('vinyl');
  7. var through = require('through2');
  8. var log = require('fancy-log');
  9. var path = require('path');
  10. var exec = require('child_process').exec;
  11. var catFile = require('./catFile');
  12. // https://git-scm.com/docs/git-diff#_raw_output_format
  13. /* eslint-disable */
  14. var RE_DIFF_RESULT = /\:(\w+)\s+(\w+)\s+(\w+)(?:\.{3})?\s+(\w+)(?:\.{3})?\s+(\w+)(\u0000|\t|\s+)(.+?)(?:\6|\n)(?:([^:]+?)\6)?/g;
  15. /* eslint-enable */
  16. function getReaslt(data) {
  17. var result = [];
  18. if (data && data.length) {
  19. var str = data.toString();
  20. var match;
  21. RE_DIFF_RESULT.lastIndex = 0;
  22. while ((match = RE_DIFF_RESULT.exec(str))) {
  23. result.push({
  24. // mode for compare "src"
  25. srcMode: match[1],
  26. // mode for compare "dst"
  27. dstMode: match[2],
  28. // sha1 for compare "src"
  29. srcHash: match[3],
  30. // sha1 for compare "dst"
  31. dstHash: match[4],
  32. // status
  33. status: match[5],
  34. // path for compare "src"
  35. srcPath: match[7],
  36. // path for compare "dst"
  37. dstPath: match[8] || match[7],
  38. });
  39. }
  40. }
  41. return result;
  42. }
  43. /**
  44. * @typedef {Object} diffOptions
  45. * @property {string} cwd {@link https://github.com/gulpjs/vinyl-fs#optionscwd}
  46. * @property {string} base {@link https://github.com/gulpjs/vinyl-fs#optionsbase}
  47. * @property {boolean} read {@link https://github.com/gulpjs/vinyl-fs#optionsread}
  48. * @property {boolean} buffer {@link https://github.com/gulpjs/vinyl-fs#optionsbuffer}
  49. * @property {boolean} stripBOM {@link https://github.com/gulpjs/vinyl-fs#optionsstripbom}
  50. * @property {boolean} log show log in console
  51. * @property {string[]} args Command parameter for `git diff`
  52. */
  53. /**
  54. * get git diff result as a stream of vinyl `File` objects.
  55. *
  56. * @example
  57. const git = require('gulp-git');
  58. const eslint = require('gulp-eslint');
  59. git.diff('--cached', {
  60. args: '-- *.js'
  61. })
  62. .pipe(eslint())
  63. * @param {string} compare compare arg for `git diff`
  64. * @param {diffOptions} opt [diffOptions]{@link module:gulp-git/lib/diff~diffOptions}
  65. * @returns {stream} stream of vinyl `File` objects.
  66. */
  67. module.exports = function (compare, opt) {
  68. if (!opt) opt = {};
  69. if (!opt.cwd) opt.cwd = process.cwd();
  70. // https://github.com/gulpjs/vinyl-fs#optionsread
  71. if (undefined === opt.read || null === opt.read) opt.read = true;
  72. if (undefined === opt.log || null === opt.log) opt.log = true;
  73. var srcStream = through.obj();
  74. var cmd = compare;
  75. if (!/--diff-filter=/.test(opt.args)) {
  76. cmd += ' --diff-filter=ACM';
  77. }
  78. if (opt.args) {
  79. cmd += ' ' + opt.args;
  80. }
  81. var maxBuffer = opt.maxBuffer || 200 * 1024;
  82. exec('git diff --raw -z ' + cmd, {cwd: opt.cwd, maxBuffer: maxBuffer}, function(err, stdout) {
  83. if (err) return srcStream.emit('error', err);
  84. var files = getReaslt(stdout);
  85. if (opt.log) {
  86. log('git diff --name-status ' + cmd + '\n' + files.map(function(diff) {
  87. return diff.status + '\t' + diff.dstPath;
  88. }).join('\n'));
  89. }
  90. files.forEach(function(diff) {
  91. srcStream.write(new Vinyl({
  92. path: path.resolve(opt.cwd, diff.dstPath),
  93. cwd: opt.cwd,
  94. base: opt.base,
  95. git: {
  96. hash: diff.dstHash,
  97. diff: diff
  98. }
  99. }));
  100. });
  101. srcStream.end();
  102. });
  103. if (opt.read) {
  104. // read file contents when opt.read is `true`
  105. return srcStream.pipe(catFile(opt));
  106. }
  107. return srcStream;
  108. };