Coffeescript --watch switch not working with node 0.4.7 - node.js

The --watch directive to the coffeescript compiler doesn't work with node.js 0.4.7. How to fix?
(Node 0.4.7 is currently required for deployment on Heroku.)

There is no fs.watch method in node.js 0.4.7. Replace the watch function at line 198 in command.js with the following:
watch = function(source, base) {
return fs.stat(source, function(err, prevStats) {
if (err) throw err;
return fs.watchFile(source, function(curr, prev) {
return fs.stat(source, function(err, stats) {
if (err) throw err;
if (stats.size === prevStats.size && stats.mtime.getTime() === prevStats.mtime.getTime()) {
return;
}
prevStats = stats;
return fs.readFile(source, function(err, code) {
if (err) throw err;
return compileScript(source, code.toString(), base);
});
});
});
});
};

If you can't upgrade to Node 0.6, try Jitter. It's a single-purpose command line utility that does what coffee -cw did before CoffeeScript 1.1.3. Plus it has a few little extras, like Growl notifications when compilation fails.

Here's a watchscript I wrote after having same experience with coffeescript -w option not working. It finds and watches .coffee, .less, .jade files for change and triggers their corresponding compilers in response. Generates colored output for easy detection of when the compilation failed.
/*
* Tested on node 0.6, Ubuntu
*/
#!/usr/bin/node
COLOR_GREEN="\033[01;32m"
COLOR_RED="\033[01;31m"
COLOR_YELLOW="\033[01;33m"
COLOR_BLUE="\033[01;34m"
COLOR_NORMAL="\033[00m"
var fs = require('fs');
var coffeescript, jade, less;
try {
coffeescript = require('/usr/lib/node_modules/coffee-script'); // after npm -g install coffee-script
} catch(e) {
console.log(COLOR_RED,String(e),COLOR_NORMAL);
}
try {
jade = require('/usr/lib/node_modules/jade'); // after npm -g install jade
} catch(e) {
console.log(COLOR_RED,String(e),COLOR_NORMAL);
}
try {
less = require('/usr/lib/node_modules/less'); // after npm -g install less
} catch(e) {
console.log(COLOR_RED,String(e),COLOR_NORMAL);
}
console.log(
'Watch Support',
(coffeescript ? COLOR_GREEN : COLOR_RED),' coffeescript ',COLOR_NORMAL,
(jade ? COLOR_GREEN : COLOR_RED),' jade ',COLOR_NORMAL,
(less ? COLOR_GREEN : COLOR_RED),' less ',COLOR_NORMAL
);
var compile = function (fname) {
var source = fs.readFileSync(fname).toString();
try {
if(/\.jade$/.test(fname)) {
var html = jade.compile(source,{pretty:true})();
var htmlfname = fname.replace(/\.jade$/,'.html');
fs.writeFileSync(htmlfname, html);
console.log(COLOR_GREEN,'Success ',fname,new Date(),COLOR_NORMAL)
} else if(/\.coffee$/.test(fname)) {
var js = coffeescript.compile(source);
var jsfname = fname.replace(/\.coffee$/,'.js');
fs.writeFileSync(jsfname, js);
console.log(COLOR_GREEN,'Success ',fname,new Date(),COLOR_NORMAL)
} else if(/\.less$/.test(fname)) {
var lessparser = new(less.Parser);
var cssfname = fname.replace(/\.less$/,'.css');
lessparser.parse(source, function (e, tree) {
if(e) {
console.log(COLOR_RED,'Failed ',fname,String(e),COLOR_NORMAL);
} else {
fs.writeFileSync(cssfname, tree.toCSS());
console.log(COLOR_GREEN,'Success ',fname,new Date(),COLOR_NORMAL)
}
});
}
} catch(e) {
console.log(COLOR_RED,'Failed ',fname,String(e),COLOR_NORMAL)
}
}
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = dir + '/' + file;
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
function main() {
if(process.argv.length > 2) {
dirName = process.argv[2];
} else {
dirName = '.';
}
stats = fs.statSync(dirName);
if(stats.isDirectory()) {
walk(dirName,function (err, files) {
var watching = 0;
files.forEach(function (fname) {
if(/\.coffee$|\.less$|\.jade$/.test(fname)) {
fs.watchFile(fname,{persistent:true,interval:500},
function (cur,prev) {
if(cur.mtime.getTime() != prev.mtime.getTime()) {
compile(fname);
}
}
);
watching++;
}
});
if(watching) {
console.log('Watching '+watching+' file(s) in '+
COLOR_YELLOW+dirName+COLOR_NORMAL);
} else {
console.log('No coffee/jade/less files found to watch');
}
});
} else {
// It's a file
var fname = dirName;
if(/\.coffee$|\.less$|\.jade$/.test(fname)) {
fs.watchFile(fname,{persistent:true,interval:500},
function (cur,prev) {
if(cur.mtime.getTime() != prev.mtime.getTime()) {
compile(fname);
}
}
);
console.log('Watching '+COLOR_YELLOW+fname+COLOR_NORMAL);
} else {
console.log('No coffee/jade/less files found to watch');
}
}
}
main();
If you prefer gist: https://gist.github.com/3083080

Related

Node.js writing data to file throws an error

Got this error when I run my program
TypeError: Callback is not a function
// Update data from a new file
lib.update = function(dir,file,callback){
//Open the file for writing
fs.open(lib.baseDir+dir+'/'+'.json','r+',function(err,fileDescriptor){
if(!err && fileDescriptor){
var stringData= JSON.stringify(data);
//Truncate the file before writing
fs.truncate(fileDescriptor,function(err){
if(!err){
//Write to the file and close it
fs.writeFile(fileDescriptor,stringData,function(err){
if(!err){
fs.close(fileDescriptor,function(err){
if(!err){
callback(false);
}else {
callback('Error closing existing file!')
}
})
}else {
callback('Error writing to existing file')
}
});
}else {
callback('Error Truncating file')
}
});
}else {
callback('Could not open file for updating! May not exist yet')
}
});
}
I propose you to refactor your code to be a little more clear about what you are doing. Something like this, it will help you find where errors come. Using promises better than use a lot of callbacks.
Just my contribution.
lib.update = function(dir, file, data) {
const updateP = new CustomPromise();
openFile()
.then(truncateFile)
.then(writeFile.bind(this, JSON.stringify(data)))
.then(closeFile)
.then(updateP.resolve) // at this point all the functions was successful
.catch((errorType) =>
errorType !== ERROR_TYPE.ERROR_CLOSING_FILE // something fail try to close the file
? closeFile().finally(() => updateP.reject(errorType))
: updateP.reject(errorType),
);
return updateP.promise;
};
// Constants
const ERROR_TYPE = Object.freeze({
ERROR_OPEN_FILE: 'error-open-file',
ERROR_TRUNCATING_FILE: 'error-truncating-file',
ERROR_WRITING_FILE: 'error-writing-file',
ERROR_CLOSING_FILE: 'error-closing-file',
});
// Private functions
function CustomPromise() {
this.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
});
}
function openFile() {
const openP = new CustomPromise();
fs.open(lib.baseDir + dir + '/' + '.json', 'r+', function(err, fileDescriptor) {
(err || !fileDescriptor) && openP.reject(ERROR_TYPE.ERROR_OPEN_FILE);
openP.resolve(fileDescriptor);
});
return openP.promise;
}
function truncateFile(fileDescriptor) {
const truncateP = new CustomPromise();
fs.truncate(fileDescriptor, function(err) {
err && truncateP.reject(ERROR_TYPE.ERROR_TRUNCATING_FILE);
truncateP.resolve(fileDescriptor);
});
return truncateP.promise;
}
function writeFile(data, fileDescriptor) {
const writeFileP = new CustomPromise();
fs.writeFile(fileDescriptor, data, function(err) {
err && writeFileP.reject(ERROR_TYPE.ERROR_WRITING_FILE);
writeFileP.resolve(fileDescriptor);
});
return writeFileP.promise;
}
function closeFile(fileDescriptor) {
const closeP = new CustomPromise();
fs.close(fileDescriptor, function(err) {
err && closeP.reject(ERROR_TYPE.ERROR_CLOSING_FILE);
closeP.resolve();
});
return closeP.promise;
}

Node js Promises with recursive function

I want to read the all (text) files from a specific directory and it's all subdirecoty recursively.. I am able to read the file and append the result to a global variable. but i want to access the variable at the end of all operation. I am trying with promises but i am unable to access it. please help
var file_path = `C:\\Users\\HP\\Desktop\\test_folder`;
const fs = require('fs');
var final_array = [];
let getFolderTree = function(file_path) {
return new Promise(function(resolve, reject) {
fs.readdir(file_path, function(err, folders) {
if (err) {
console.log("error reading folder :: " + err);
} else {
if (folders.length !== 0) {
for (let i = 0; i < folders.length; i++) {
if (folders[i].endsWith("txt")) {
let text_file_path = file_path + `\\` + folders[i];
fs.readFile(text_file_path, function(error_read, data) {
if (error_read) {
console.log("error reading " + error_read);
} else {
return resolve(final_array.push(data));// want to access final_array at the end of all operations
}
});
} else {
let current_path = file_path + `\\` + folders[i];
getFolderTree(current_path);
}
}
}
}
});
});
}
getFolderTree(file_path).then(function() {
console.log(final_array); // this is not working
});
I think i have found the solution but I am still confused about how it works.
I took reference from another code and able to figure out some how.
var fs = require('fs');
var path = require('path');
let root_path = "C:\\Users\\HP\\Desktop\\test_folder";
function getAllDirectoriesPath(current_path) {
var results = [];
return new Promise(function (resolve, reject) {
fs.readdir(current_path, function (erro, sub_dirs) {
if (erro) {
console.log(error);
} else {
let no_of_subdir = sub_dirs.length;
if (!no_of_subdir) {
return resolve(results);
} else {
sub_dirs.forEach(function (dir) {
dir = path.resolve(current_path, dir);
fs.stat(dir, function (err, stat) {
if (stat && stat.isDirectory()) {
getAllDirectoriesPath(dir).then(function (res) {
results = results.concat(res);
if (!--no_of_subdir) {
resolve(results);
}
});
} else {
fs.readFile(dir, function (err, data) {
results.push(data.toString());
if (!--no_of_subdir) {
resolve(results);
}
});
}
});
});
}
}
});
});
}
getAllDirectoriesPath(root_path).then(function (results) {
console.log(results);
});

Node FS ENOENT error

I am trying to make this script create a directory, then write stuff in it. Simple XML dumps & stuff.
I cant get anything of FS to work. isDirectory, createDirectory, readFile, writeFile. My reading in another SO post suggested a lot of changes to fs.stat().
I already set the permissions for the folder, so it should not be having any permissions problem (Windows).
My 1st step in checking for previous files & creating new or opening them:
. . .
var logsDir = './logs/';
var logAccess = logsDir + 'stuff.log';
try { // The code says its an ENOENT
console.log(fs.statSync(logsDir))
if (!fs.statSync(logsDir).isDirectory()) {
fs.mkdirSync(logsDir);
}
} catch (e) {
console.error('Error ' + e.code);
}
try { // Another ENOENT
if (!fs.statSync(logAccess).isFile()) {
fs.writeFileSync(logAccess, 'die', 'utf8');
}
//data = fs.readFileSync(logAccess, 'utf8');
} catch (e) {
console.error('Error errors are dumb');
}
. . .
fs.stat(logsDir, function(err,stat){
try{
if(err)
{
var e = err.code;
throw e;
}
}
catch(e)
{
if(e == 'ENOENT')
{
fs.mkdir(logsDir);
}
else
{
console.log('Some other error ' + err.code);
}
}
});
fs.stat(logAccess, function(err,stat){
try{
if(err)
{
var e = err.code;
throw e;
}
}
catch(e)
{
if(e == 'ENOENT')
{
fs.writeFileSync(logAccess, 'die', 'utf8');
}
else
{
console.log('Some other error ' + err.code);
}
}
});
var fs = require('fs');
var express = require("express");
var app = express();
var logsDir = './logs/';
var logAccess = logsDir + 'stuff.log';
function directoryExits(logsDir){
try {
return fs.statSync(logsDir).isDirectory();
} catch (err) {
return false;
}
}
function fileExits(logAccess){
try {
return fs.statSync(logAccess).isFile();
} catch (err) {
return false;
}
}
var statsDir = directoryExits(logsDir);
var statsFile = fileExits(logAccess);
if(!statsDir)
{
fs.mkdirSync(logsDir);
console.log("Directory Created")
}
else
console.log('Directory already exists');
if(!statsFile)
{
fs.writeFileSync(logAccess, 'die', 'utf8');
}
else
console.log('File already exists');
app.listen(4000, function(){
console.log('Server running ');
});

node.js glob pattern for excluding multiple files

I'm using the npm module node-glob.
This snippet returns recursively all files in the current working directory.
var glob = require('glob');
glob('**/*', function(err, files) {
console.log(files);
});
sample output:
[ 'index.html', 'js', 'js/app.js', 'js/lib.js' ]
I want to exclude index.html and js/lib.js.
I tried to exclude these files with negative pattern '!' but without luck.
Is there a way to achieve this only by using a pattern?
I suppose it's not actual anymore but I got stuck with the same question and found an answer.
This can be done using only glob module.
We need to use options as a second parameter to glob function
glob('pattern', {options}, cb)
There is an options.ignore pattern for your needs.
var glob = require('glob');
glob("**/*",{"ignore":['index.html', 'js', 'js/app.js', 'js/lib.js']}, function (err, files) {
console.log(files);
})
Check out globby, which is pretty much glob with support for multiple patterns and a Promise API:
const globby = require('globby');
globby(['**/*', '!index.html', '!js/lib.js']).then(paths => {
console.log(paths);
});
You can use node-globule for that:
var globule = require('globule');
var result = globule.find(['**/*', '!index.html', '!js/lib.js']);
console.log(result);
Or without an external dependency:
/**
Walk directory,
list tree without regex excludes
*/
var fs = require('fs');
var path = require('path');
var walk = function (dir, regExcludes, done) {
var results = [];
fs.readdir(dir, function (err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function (file) {
file = path.join(dir, file);
var excluded = false;
var len = regExcludes.length;
var i = 0;
for (; i < len; i++) {
if (file.match(regExcludes[i])) {
excluded = true;
}
}
// Add if not in regExcludes
if(excluded === false) {
results.push(file);
// Check if its a folder
fs.stat(file, function (err, stat) {
if (stat && stat.isDirectory()) {
// If it is, walk again
walk(file, regExcludes, function (err, res) {
results = results.concat(res);
if (!--pending) { done(null, results); }
});
} else {
if (!--pending) { done(null, results); }
}
});
} else {
if (!--pending) { done(null, results); }
}
});
});
};
var regExcludes = [/index\.html/, /js\/lib\.js/, /node_modules/];
walk('.', regExcludes, function(err, results) {
if (err) {
throw err;
}
console.log(results);
});
Here is what I wrote for my project:
var glob = require('glob');
var minimatch = require("minimatch");
function globArray(patterns, options) {
var i, list = [];
if (!Array.isArray(patterns)) {
patterns = [patterns];
}
patterns.forEach(pattern => {
if (pattern[0] === "!") {
i = list.length-1;
while( i > -1) {
if (!minimatch(list[i], pattern)) {
list.splice(i,1);
}
i--;
}
}
else {
var newList = glob.sync(pattern, options);
newList.forEach(item => {
if (list.indexOf(item)===-1) {
list.push(item);
}
});
}
});
return list;
}
And call it like this (Using an array):
var paths = globArray(["**/*.css","**/*.js","!**/one.js"], {cwd: srcPath});
or this (Using a single string):
var paths = globArray("**/*.js", {cwd: srcPath});
A samples example with gulp:
gulp.task('task_scripts', function(done){
glob("./assets/**/*.js", function (er, files) {
gulp.src(files)
.pipe(gulp.dest('./public/js/'))
.on('end', done);
});
});

How to get totalsize of files in directory?

How to get totalsize of files in directory ? Best way ?
Here is a simple solution using the core Nodejs fs libraries combined with the async library. It is fully asynchronous and should work just like the 'du' command.
var fs = require('fs'),
path = require('path'),
async = require('async');
function readSizeRecursive(item, cb) {
fs.lstat(item, function(err, stats) {
if (!err && stats.isDirectory()) {
var total = stats.size;
fs.readdir(item, function(err, list) {
if (err) return cb(err);
async.forEach(
list,
function(diritem, callback) {
readSizeRecursive(path.join(item, diritem), function(err, size) {
total += size;
callback(err);
});
},
function(err) {
cb(err, total);
}
);
});
}
else {
cb(err);
}
});
}
I tested the following code and it works perfectly fine.
Please do let me know if there is anything that you don't understand.
var util = require('util'),
spawn = require('child_process').spawn,
size = spawn('du', ['-sh', '/path/to/dir']);
size.stdout.on('data', function (data) {
console.log('size: ' + data);
});
// --- Everything below is optional ---
size.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
size.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
Courtesy Link
2nd method:
var util = require('util'), exec = require('child_process').exec, child;
child = exec('du -sh /path/to/dir', function(error, stdout, stderr){
console.log('stderr: ' + stderr);
if (error !== null){
console.log('exec error: ' + error);
}
});
You might want to refer the Node.js API for child_process
Use du : https://www.npmjs.org/package/du
require('du')('/home/rvagg/.npm/', function (err, size) {
console.log('The size of /home/rvagg/.npm/ is:', size, 'bytes')
})
ES6 variant:
import path_module from 'path'
import fs from 'fs'
// computes a size of a filesystem folder (or a file)
export function fs_size(path, callback)
{
fs.lstat(path, function(error, stats)
{
if (error)
{
return callback(error)
}
if (!stats.isDirectory())
{
return callback(undefined, stats.size)
}
let total = stats.size
fs.readdir(path, function(error, names)
{
if (error)
{
return callback(error)
}
let left = names.length
if (left === 0)
{
return callback(undefined, total)
}
function done(size)
{
total += size
left--
if (left === 0)
{
callback(undefined, total)
}
}
for (let name of names)
{
fs_size(path_module.join(path, name), function(error, size)
{
if (error)
{
return callback(error)
}
done(size)
})
}
})
})
}
Review the node.js File System functions. It looks like you can use a combination of fs.readdir(path, [cb]), and fs.stat(file, [cb]) to list the files in a directory and sum their sizes.
Something like this (totally untested):
var fs = require('fs');
fs.readdir('/path/to/dir', function(err, files) {
var i, totalSizeBytes=0;
if (err) throw err;
for (i=0; i<files.length; i++) {
fs.stat(files[i], function(err, stats) {
if (err) { throw err; }
if (stats.isFile()) { totalSizeBytes += stats.size; }
});
}
});
// Figure out how to wait for all callbacks to complete
// e.g. by using a countdown latch, and yield total size
// via a callback.
Note that this solution only considers the plain files stored directly in the target directory and performs no recursion. A recursive solution would come naturally by checking stats.isDirectory() and entering, although it likely complicates the "wait for completion" step.
'use strict';
const async = require('async');
const fs = require('fs');
const path = require('path')
const getSize = (item, callback) => {
let totalSize = 0;
fs.lstat(item, (err, stats) => {
if (err) return callback(err);
if (stats.isDirectory()) {
fs.readdir(item, (err, list) => {
if (err) return callback(err);
async.each(list, (listItem, cb) => {
getSize(path.join(item, listItem), (err, size) => {
totalSize += size;
cb();
});
},
(err) => {
if (err) return callback(err);
callback(null, totalSize);
});
});
} else {
// Ensure fully asynchronous API
process.nextTick(function() {
callback(null, (totalSize += stats.size))
});
}
});
}
getSize('/Applications', (err, totalSize) => { if (!err) console.log(totalSize); });
I know I'm a bit late to the part but I though I'd include my solution which uses promises based on #maerics answer:
const fs = require('fs');
const Promise = require('bluebird');
var totalSizeBytes=0;
fs.readdir('storage', function(err, files) {
if (err) throw err;
Promise.mapSeries(files, function(file){
return new Promise((resolve, reject) => {
fs.stat('storage/' + file,function(err, stats) {
if (err) { throw err; }
if (stats.isFile()) { totalSizeBytes += stats.size; resolve(); }
});
})
}).then(()=>{
console.log(totalSizeBytes);
});
});
function readSizeRecursive(folder, nested = 0) {
return new Promise(function(resolve, reject) {
const stats = fs.lstatSync(path.resolve(__dirname, '../projects/', folder));
var total = stats.size;
const list = fs.readdirSync(path.resolve(__dirname, '../projects/', folder));
if(list.length > 0){
Promise.all(list.map(async li => {
const stat = await fs.lstatSync(path.resolve(__dirname, '../projects/', folder, li));
if(stat.isDirectory() && nested == 0){
const tt = await readSizeRecursive(folder, 1);
total += tt;
} else {
total += stat.size;
}
})).then(() => resolve(convertBytes(total)));
} else {
resolve(convertBytes(total));
}
});
}
const convertBytes = function(bytes) {
const sizes = ["Bytes", "KB", "MB", "GB", "TB"]
if (bytes == 0) {
return "n/a"
}
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))
if (i == 0) {
return bytes + " " + sizes[i]
}
// return (bytes / Math.pow(1024, i)).toFixed(1) + " " + sizes[i]
return parseFloat((bytes / Math.pow(1024, i)).toFixed(1));
}
This combines async/await and the fs Promises API introduced in Node.js v14.0.0 for a clean, readable implementation:
const { readdir, stat } = require('fs/promises');
const dirSize = async directory => {
const files = await readdir( directory );
const stats = files.map( file => stat( path.join( directory, file ) ) );
let size = 0;
for await ( const stat of stats ) size += stat.size;
return size;
};
Usage:
const size = await dirSize( '/path/to/directory' );
console.log( size );
An shorter-but-less-readable alternative of the dirSize function would be:
const dirSize = async directory => {
const files = await readdir( directory );
const stats = files.map( file => stat( path.join( directory, file ) ) );
return ( await Promise.all( stats ) ).reduce( ( accumulator, { size } ) => accumulator + size, 0 );
}
A very simple synchronous solution that I implemented.
const fs = require("fs");
function getSize(path){
// Get the size of a file or folder recursively
let size = 0;
if(fs.statSync(path).isDirectory()){
const files = fs.readdirSync(path);
files.forEach(file => {
size += getSize(path + "/" + file);
});
}
else{
size += fs.statSync(path).size;
}
return size;
}

Resources