file-writer.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. Copyright 2012-2015, Yahoo Inc.
  3. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
  4. */
  5. var util = require('util'),
  6. path = require('path'),
  7. fs = require('fs'),
  8. mkdirp = require('mkdirp'),
  9. supportsColor = require('supports-color'),
  10. isAbsolute = path.isAbsolute || /* istanbul ignore next */ function (p) {
  11. return path.resolve(p) === path.normalize(p);
  12. };
  13. /**
  14. * abstract interface for writing content
  15. * @class ContentWriter
  16. * @constructor
  17. */
  18. /* istanbul ignore next: abstract class */
  19. function ContentWriter() {
  20. }
  21. /**
  22. * writes a string as-is to the destination
  23. * @param {String} str the string to write
  24. */
  25. /* istanbul ignore next: abstract class */
  26. ContentWriter.prototype.write = function () {
  27. throw new Error('write: must be overridden');
  28. };
  29. /**
  30. * returns the colorized version of a string. Typically,
  31. * content writers that write to files will return the
  32. * same string and ones writing to a tty will wrap it in
  33. * appropriate escape sequences.
  34. * @param {String} str the string to colorize
  35. * @param {String} clazz one of `high`, `medium` or `low`
  36. * @returns {String} the colorized form of the string
  37. */
  38. ContentWriter.prototype.colorize = function (str /*, clazz*/) {
  39. return str;
  40. };
  41. /**
  42. * writes a string appended with a newline to the destination
  43. * @param {String} str the string to write
  44. */
  45. ContentWriter.prototype.println = function (str) {
  46. this.write(str + '\n');
  47. };
  48. /**
  49. * closes this content writer. Should be called after all writes are complete.
  50. */
  51. ContentWriter.prototype.close = function () {
  52. };
  53. /**
  54. * a content writer that writes to a file
  55. * @param {Number} fd - the file descriptor
  56. * @extends ContentWriter
  57. * @constructor
  58. */
  59. function FileContentWriter(fd) {
  60. this.fd = fd;
  61. }
  62. util.inherits(FileContentWriter, ContentWriter);
  63. FileContentWriter.prototype.write = function (str) {
  64. fs.writeSync(this.fd, str);
  65. };
  66. FileContentWriter.prototype.close = function () {
  67. fs.closeSync(this.fd);
  68. };
  69. /**
  70. * a content writer that writes to the console
  71. * @extends ContentWriter
  72. * @constructor
  73. */
  74. function ConsoleWriter() {
  75. }
  76. util.inherits(ConsoleWriter, ContentWriter);
  77. // allow stdout to be captured for tests.
  78. var capture = false;
  79. var output = '';
  80. ConsoleWriter.prototype.write = function (str) {
  81. if (capture) {
  82. output += str;
  83. } else {
  84. process.stdout.write(str);
  85. }
  86. };
  87. ConsoleWriter.prototype.colorize = function (str, clazz) {
  88. var colors = {
  89. low: '31;1',
  90. medium: '33;1',
  91. high: '32;1'
  92. };
  93. /* istanbul ignore next: different modes for CI and local */
  94. if (supportsColor && colors[clazz]) {
  95. return '\u001b[' + colors[clazz] + 'm' + str + '\u001b[0m';
  96. }
  97. return str;
  98. };
  99. /**
  100. * utility for writing files under a specific directory
  101. * @class FileWriter
  102. * @param {String} baseDir the base directory under which files should be written
  103. * @constructor
  104. */
  105. function FileWriter(baseDir) {
  106. if (!baseDir) {
  107. throw new Error('baseDir must be specified');
  108. }
  109. this.baseDir = baseDir;
  110. }
  111. /**
  112. * static helpers for capturing stdout report output;
  113. * super useful for tests!
  114. */
  115. FileWriter.startCapture = function () {
  116. capture = true;
  117. };
  118. FileWriter.stopCapture = function () {
  119. capture = false;
  120. };
  121. FileWriter.getOutput = function () {
  122. return output;
  123. };
  124. FileWriter.resetOutput = function () {
  125. output = '';
  126. };
  127. /**
  128. * returns a FileWriter that is rooted at the supplied subdirectory
  129. * @param {String} subdir the subdirectory under which to root the
  130. * returned FileWriter
  131. * @returns {FileWriter}
  132. */
  133. FileWriter.prototype.writerForDir = function (subdir) {
  134. if (isAbsolute(subdir)) {
  135. throw new Error('Cannot create subdir writer for absolute path: ' + subdir);
  136. }
  137. return new FileWriter(this.baseDir + '/' + subdir);
  138. };
  139. /**
  140. * copies a file from a source directory to a destination name
  141. * @param {String} source path to source file
  142. * @param {String} dest relative path to destination file
  143. */
  144. FileWriter.prototype.copyFile = function (source, dest) {
  145. if (isAbsolute(dest)) {
  146. throw new Error('Cannot write to absolute path: ' + dest);
  147. }
  148. dest = path.resolve(this.baseDir, dest);
  149. mkdirp.sync(path.dirname(dest));
  150. fs.writeFileSync(dest, fs.readFileSync(source));
  151. };
  152. /**
  153. * returns a content writer for writing content to the supplied file.
  154. * @param {String|null} file the relative path to the file or the special
  155. * values `"-"` or `null` for writing to the console
  156. * @returns {ContentWriter}
  157. */
  158. FileWriter.prototype.writeFile = function (file) {
  159. if (file === null || file === '-') {
  160. return new ConsoleWriter();
  161. }
  162. if (isAbsolute(file)) {
  163. throw new Error('Cannot write to absolute path: ' + file);
  164. }
  165. file = path.resolve(this.baseDir, file);
  166. mkdirp.sync(path.dirname(file));
  167. return new FileContentWriter(fs.openSync(file, 'w'));
  168. };
  169. module.exports = FileWriter;