You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					195 lines
				
				5.2 KiB
			
		
		
			
		
	
	
					195 lines
				
				5.2 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 Copyright 2012-2015, Yahoo Inc.
							 | 
						||
| 
								 | 
							
								 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const util = require('util');
							 | 
						||
| 
								 | 
							
								const path = require('path');
							 | 
						||
| 
								 | 
							
								const fs = require('fs');
							 | 
						||
| 
								 | 
							
								const mkdirp = require('make-dir');
							 | 
						||
| 
								 | 
							
								const supportsColor = require('supports-color');
							 | 
						||
| 
								 | 
							
								const isAbsolute =
							 | 
						||
| 
								 | 
							
								    path.isAbsolute ||
							 | 
						||
| 
								 | 
							
								    /* istanbul ignore next */ function(p) {
							 | 
						||
| 
								 | 
							
								        return path.resolve(p) === path.normalize(p);
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * abstract interface for writing content
							 | 
						||
| 
								 | 
							
								 * @class ContentWriter
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/* istanbul ignore next: abstract class */
							 | 
						||
| 
								 | 
							
								function ContentWriter() {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * writes a string as-is to the destination
							 | 
						||
| 
								 | 
							
								 * @param {String} str the string to write
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/* istanbul ignore next: abstract class */
							 | 
						||
| 
								 | 
							
								ContentWriter.prototype.write = function() {
							 | 
						||
| 
								 | 
							
								    throw new Error('write: must be overridden');
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * returns the colorized version of a string. Typically,
							 | 
						||
| 
								 | 
							
								 * content writers that write to files will return the
							 | 
						||
| 
								 | 
							
								 * same string and ones writing to a tty will wrap it in
							 | 
						||
| 
								 | 
							
								 * appropriate escape sequences.
							 | 
						||
| 
								 | 
							
								 * @param {String} str the string to colorize
							 | 
						||
| 
								 | 
							
								 * @param {String} clazz one of `high`, `medium` or `low`
							 | 
						||
| 
								 | 
							
								 * @returns {String} the colorized form of the string
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								ContentWriter.prototype.colorize = function(str /*, clazz*/) {
							 | 
						||
| 
								 | 
							
								    return str;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * writes a string appended with a newline to the destination
							 | 
						||
| 
								 | 
							
								 * @param {String} str the string to write
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								ContentWriter.prototype.println = function(str) {
							 | 
						||
| 
								 | 
							
								    this.write(str + '\n');
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * closes this content writer. Should be called after all writes are complete.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								ContentWriter.prototype.close = function() {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * a content writer that writes to a file
							 | 
						||
| 
								 | 
							
								 * @param {Number} fd - the file descriptor
							 | 
						||
| 
								 | 
							
								 * @extends ContentWriter
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function FileContentWriter(fd) {
							 | 
						||
| 
								 | 
							
								    this.fd = fd;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								util.inherits(FileContentWriter, ContentWriter);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								FileContentWriter.prototype.write = function(str) {
							 | 
						||
| 
								 | 
							
								    fs.writeSync(this.fd, str);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								FileContentWriter.prototype.close = function() {
							 | 
						||
| 
								 | 
							
								    fs.closeSync(this.fd);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * a content writer that writes to the console
							 | 
						||
| 
								 | 
							
								 * @extends ContentWriter
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function ConsoleWriter() {}
							 | 
						||
| 
								 | 
							
								util.inherits(ConsoleWriter, ContentWriter);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// allow stdout to be captured for tests.
							 | 
						||
| 
								 | 
							
								let capture = false;
							 | 
						||
| 
								 | 
							
								let output = '';
							 | 
						||
| 
								 | 
							
								ConsoleWriter.prototype.write = function(str) {
							 | 
						||
| 
								 | 
							
								    if (capture) {
							 | 
						||
| 
								 | 
							
								        output += str;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        process.stdout.write(str);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ConsoleWriter.prototype.colorize = function(str, clazz) {
							 | 
						||
| 
								 | 
							
								    const colors = {
							 | 
						||
| 
								 | 
							
								        low: '31;1',
							 | 
						||
| 
								 | 
							
								        medium: '33;1',
							 | 
						||
| 
								 | 
							
								        high: '32;1'
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* istanbul ignore next: different modes for CI and local */
							 | 
						||
| 
								 | 
							
								    if (supportsColor.stdout && colors[clazz]) {
							 | 
						||
| 
								 | 
							
								        return '\u001b[' + colors[clazz] + 'm' + str + '\u001b[0m';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return str;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * utility for writing files under a specific directory
							 | 
						||
| 
								 | 
							
								 * @class FileWriter
							 | 
						||
| 
								 | 
							
								 * @param {String} baseDir the base directory under which files should be written
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function FileWriter(baseDir) {
							 | 
						||
| 
								 | 
							
								    if (!baseDir) {
							 | 
						||
| 
								 | 
							
								        throw new Error('baseDir must be specified');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    this.baseDir = baseDir;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * static helpers for capturing stdout report output;
							 | 
						||
| 
								 | 
							
								 * super useful for tests!
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FileWriter.startCapture = function() {
							 | 
						||
| 
								 | 
							
								    capture = true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								FileWriter.stopCapture = function() {
							 | 
						||
| 
								 | 
							
								    capture = false;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								FileWriter.getOutput = function() {
							 | 
						||
| 
								 | 
							
								    return output;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								FileWriter.resetOutput = function() {
							 | 
						||
| 
								 | 
							
								    output = '';
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * returns a FileWriter that is rooted at the supplied subdirectory
							 | 
						||
| 
								 | 
							
								 * @param {String} subdir the subdirectory under which to root the
							 | 
						||
| 
								 | 
							
								 *  returned FileWriter
							 | 
						||
| 
								 | 
							
								 * @returns {FileWriter}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FileWriter.prototype.writerForDir = function(subdir) {
							 | 
						||
| 
								 | 
							
								    if (isAbsolute(subdir)) {
							 | 
						||
| 
								 | 
							
								        throw new Error(
							 | 
						||
| 
								 | 
							
								            'Cannot create subdir writer for absolute path: ' + subdir
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return new FileWriter(this.baseDir + '/' + subdir);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * copies a file from a source directory to a destination name
							 | 
						||
| 
								 | 
							
								 * @param {String} source path to source file
							 | 
						||
| 
								 | 
							
								 * @param {String} dest relative path to destination file
							 | 
						||
| 
								 | 
							
								 * @param {String} [header=undefined] optional text to prepend to destination
							 | 
						||
| 
								 | 
							
								 *  (e.g., an "this file is autogenerated" comment, copyright notice, etc.)
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FileWriter.prototype.copyFile = function(source, dest, header) {
							 | 
						||
| 
								 | 
							
								    if (isAbsolute(dest)) {
							 | 
						||
| 
								 | 
							
								        throw new Error('Cannot write to absolute path: ' + dest);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    dest = path.resolve(this.baseDir, dest);
							 | 
						||
| 
								 | 
							
								    mkdirp.sync(path.dirname(dest));
							 | 
						||
| 
								 | 
							
								    let contents;
							 | 
						||
| 
								 | 
							
								    if (header) {
							 | 
						||
| 
								 | 
							
								        contents = header + fs.readFileSync(source, 'utf8');
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        contents = fs.readFileSync(source);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    fs.writeFileSync(dest, contents);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * returns a content writer for writing content to the supplied file.
							 | 
						||
| 
								 | 
							
								 * @param {String|null} file the relative path to the file or the special
							 | 
						||
| 
								 | 
							
								 *  values `"-"` or `null` for writing to the console
							 | 
						||
| 
								 | 
							
								 * @returns {ContentWriter}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FileWriter.prototype.writeFile = function(file) {
							 | 
						||
| 
								 | 
							
								    if (file === null || file === '-') {
							 | 
						||
| 
								 | 
							
								        return new ConsoleWriter();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (isAbsolute(file)) {
							 | 
						||
| 
								 | 
							
								        throw new Error('Cannot write to absolute path: ' + file);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    file = path.resolve(this.baseDir, file);
							 | 
						||
| 
								 | 
							
								    mkdirp.sync(path.dirname(file));
							 | 
						||
| 
								 | 
							
								    return new FileContentWriter(fs.openSync(file, 'w'));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = FileWriter;
							 |