define([ "dcl/dcl", 'dojo/has', 'nxapp/manager/ManagerBase', 'nxapp/utils/_LogMixin', 'xide/types', 'xide/factory', "dojo/node!path", "dojo/node!fs", "dojo/node!child_process", "dojo/node!chokidar" ], function (dcl, has, ManagerBase, _LogMixin, types, factory, path, fs, child_process, chokidar) { var isWindows = has('windows'); var isARM = has('arm'); isWindows = true; var useWatcher = isWindows === true || isARM === true; var useChokidar = true; var debug = false; return dcl([ManagerBase, _LogMixin], { declaredClass: "nxapp.manager.FileManager", watcher: null, resolve: function (_path) { var result = ""; var _libRoot = path.resolve(dojoConfig.libRoot); var _clientRoot = path.resolve(dojoConfig.clientRoot); if (fs.existsSync(path.resolve(_path))) { return _path; } if (_path[0] == '/') { _path = path.resolve(_path); } else if (path.resolve(_libRoot + '/' + _path)) { result = path.resolve(_libRoot + '/' + _path); } else if (fs.existsSync(path.resolve(_path))) { //try absolute result = path.resolve(_path); } else if (path.resolve(_clientRoot + '/' + _path)) { //try client root result = path.resolve(_clientRoot + '/' + _path); } return result; }, watch: function (path, watch) { try { if (fs.existsSync(path) && watch) { if (this.watcher && this.watcher.add) { this.watcher.add(path); } } } catch (e) { } }, initChokidar: function (profile) { for (var i = 0; i < profile.watchr.paths.length; i++) { var _path = profile.watchr.paths[i]; var _libRoot = path.resolve(dojoConfig.libRoot); var _clientRoot = path.resolve(dojoConfig.clientRoot); if (_path[0] == '/') { _path = path.resolve(_path); } else if (path.resolve(_path) && fs.existsSync(_path)) { //try lib root profile.watchr.paths[i] = path.resolve(_path); } else if (fs.existsSync(path.resolve(_libRoot + '/' + _path))) { //try lib root profile.watchr.paths[i] = path.resolve(_libRoot + '/' + _path); } else if (fs.existsSync(path.resolve(_path))) { //try absolute profile.watchr.paths[i] = path.resolve(_path); } else if (path.resolve(_clientRoot + '/' + _path)) { //try client root profile.watchr.paths[i] = path.resolve(_clientRoot + '/' + _path); } } var thiz = this; function modulePath(_path) { _path = _path.replace(dojoConfig.libRoot + '/', ''); if (_path.startsWith('/')) { _path = _path.replace('/', ''); } return _path; } var watcher = chokidar.watch(profile.watchr.paths, { ignored: function (path) { if (path.indexOf('metadata') !== -1) { return true; }; if (path.indexOf('.git') !== -1) { return true; }; return false; }, persistent: true, ignoreInitial: true, awaitWriteFinish: true }); watcher.on('addDir', function (filePath) { watcher.add(filePath); debug && console.log('add dir ' + filePath); factory.publish(types.EVENTS.ON_FILE_CHANGED, { path: filePath, modulePath: modulePath(filePath) }, thiz); }); watcher.on('add', function (filePath) { debug && console.log('add file' + filePath); factory.publish(types.EVENTS.ON_FILE_CHANGED, { path: filePath, modulePath: modulePath(filePath), type: 'added' }, thiz); }); watcher.on('unlinkDir', function (filePath) { watcher.unwatch(filePath); factory.publish(types.EVENTS.ON_FILE_CHANGED, { path: filePath, modulePath: modulePath(filePath), type: 'delete' }, thiz); }); watcher.on('change', function (filePath) { debug && console.log('changed ' + filePath); thiz.publish(types.EVENTS.ON_FILE_CHANGED, { path: filePath, modulePath: modulePath(filePath), type: 'changed' }, thiz); }); watcher.on('raw', function (event, path, details) { //console.log('Raw event info:', [event, path, details]); if (event === 'rename') { try { var fs = fs.statSync(details.watchedPath); } catch (e) { if (details.watchedPath.indexOf(path) !== -1) { debug && console.error('removed :' + details.watchedPath); factory.publish(types.EVENTS.ON_FILE_CHANGED, { path: details.watchedPath, modulePath: details.watchedPath.replace(dojoConfig.libRoot, ''), type: 'delete' }, thiz); } } } }); this.watcher = watcher; }, /** * Plain Watchr version * @param profile */ initWindows_Watchr: function (profile) { /* for(var i = 0 ; i < profile.watchr.paths.length ; i++){ if(profile.watchr.paths[i][0]=='/'){ profile.watchr.paths[i]= path.resolve(profile.watchr.paths[i]); }else{ profile.watchr.paths[i]= path.resolve(dojoConfig.root + '/' +profile.watchr.paths[i]); } } */ for (var i = 0; i < profile.watchr.paths.length; i++) { var _path = profile.watchr.paths[i]; var _libRoot = path.resolve(dojoConfig.libRoot); var _clientRoot = path.resolve(dojoConfig.clientRoot); if (_path[0] == '/') { _path = path.resolve(_path); } else if (path.resolve(_libRoot + '/' + _path)) { //try lib root profile.watchr.paths[i] = path.resolve(_libRoot + '/' + _path); } else if (fs.existsSync(path.resolve(_path))) { //try absolute profile.watchr.paths[i] = path.resolve(_path); } else if (path.resolve(_clientRoot + '/' + _path)) { //try client root profile.watchr.paths[i] = path.resolve(_clientRoot + '/' + _path); } } //console.dir(profile.watchr.paths); _.each(profile.watchr.paths, function (path) { //debug && console.log('start watching ' + path); }); var thiz = this; watchr.watch({ paths: profile.watchr.paths, interval: 500, listeners: { log: function (logLevel) { }, error: function (err) { console.log('an error occured:', err); }, watching: function (err, watcherInstance, isWatching) { if (err) { debug && console.error("watching the path " + watcherInstance.path + " failed with error", err); } else { debug && console.error("watching the path " + watcherInstance.path + " completed"); } }, change: function (changeType, filePath, fileCurrentStat, filePreviousStat) { if (!filePath) { return; } debug && console.log('file changed: ' + filePath.replace(dojoConfig.libRoot, '') + ' actual file' + filePath); factory.publish(types.EVENTS.ON_FILE_CHANGED, { path: filePath, modulePath: filePath.replace(dojoConfig.libRoot, '') }, thiz); } }, next: function (err, watchers) { if (err) { return console.log("watching everything failed with error", err); } else { console.log('watching everything completed'); } // Close watchers after 60 seconds /* setTimeout(function(){ var i; console.log('Stop watching our paths'); for ( i=0; i 5) { var parts = line.split('|'); if (parts.length == 3) { notify(path.resolve(parts[0] + '/' + parts[2]), parts[1]); } } } }, function () { console.log('end : ' + foo.stdout); } ); }, /** * Mac/Linux version * @param profile * @returns {*} */ init: function (profile) { if (useChokidar) { return this.initChokidar(profile); } if (isWindows || isARM) { return this.initWindows_Watchr(profile); //return this.initWindows(profile); } ///return this.initWindows_Watchr(profile); var thiz = this; var _req = require; try { _req(['dojo/node!gbaumgart.inotify-plusplus'], function (notify) { thiz.initLinux(profile, notify); }); } catch (e) { debug && console.error('cant load inotify, proceed with watchr ' + e.message); return this.initWindows_Watchr(profile); } }, initLinux: function (profile, inotify) { for (var i = 0; i < profile.watchr.paths.length; i++) { var _path = profile.watchr.paths[i]; var _libRoot = path.resolve(dojoConfig.libRoot); var _clientRoot = path.resolve(dojoConfig.clientRoot); if (_path[0] == '/') { _path = path.resolve(_path); } else if (path.resolve(_libRoot + '/' + _path)) { //try lib root profile.watchr.paths[i] = path.resolve(_libRoot + '/' + _path); } else if (fs.existsSync(path.resolve(_path))) { //try absolute profile.watchr.paths[i] = path.resolve(_path); } else if (path.resolve(_clientRoot + '/' + _path)) { //try client root profile.watchr.paths[i] = path.resolve(_clientRoot + '/' + _path); } } var thiz = this; function readDir(start, callback) { // Use lstat to resolve symlink if we are passed a symlink fs.lstat(start, function (err, stat) { if (err) { return callback(err); } var found = { dirs: [], files: [] }, total = 0, processed = 0; function isDir(abspath) { fs.stat(abspath, function (err, stat) { if (stat.isDirectory()) { found.dirs.push(abspath); // If we found a directory, recurse! readDir(abspath, function (err, data) { found.dirs = found.dirs.concat(data.dirs); found.files = found.files.concat(data.files); if (++processed == total) { callback(null, found); } }); } else { /* found.files.push(abspath); if(++processed == total) { callback(null, found); } */ } }); } // Read through all the files in this directory if (stat.isDirectory()) { fs.readdir(start, function (err, files) { total = files.length; if (total === 0) { callback(null, found); } for (var x = 0, l = files.length; x < l; x++) { isDir(path.join(start, files[x])); if (total === 0) { callback(null, found); } } }); } else { return callback(new Error("path: " + start + " is not a directory")); } }); } var _walk = function (dir) { var results = []; if (fs.existsSync(dir)) { var list = fs.readdirSync(dir); list.forEach(function (file) { file = dir + '/' + file; var stat = fs.statSync(file); if (stat && stat.isDirectory()) { results.push(file); results = results.concat(_walk(file)); } }); } return results }; var directive = (function () { // private variables var count = 0, validate_watch, move, cookies = {}; // shared method move = function (ev) { var pre = cookies[ev.cookie]; if (pre) { cookies[ev.cookie] = undefined; delete cookies[ev.cookie]; } else { // expires the cookie if the move doesn't complete in this watch cookies[ev.cookie] = ev; setTimeout(function () { cookies[ev.cookie] = undefined; delete cookies[ev.cookie]; }, 500); } }; // will listen to three events // multiple events may fire at the same time return { all_events: function (ev) { // example ev: { watch: '/path/to/watch', masks: '["access", "move_to"]', cookie: 1, name: 'name_of_file' } //validate_watch(); //console.log("all_events : file changed! path " + path.resolve(ev.watch + '/' +ev.name) + ' mask:' + ev.masks.toString()) ; count += 1; if (!ev || !ev.name || !ev.name.indexOf) { //console.log('a0'); return; } if (ev.name.indexOf('.git') != -1 || ev.name.indexOf('.tmp') != -1) { //console.log('a1'); return; } if (ev.name.indexOf('_jb_old_') != -1 || ev.name.indexOf('_jb_bak_') != -1) { //console.log('a2'); return; } if (ev.masks.toString().indexOf('access') != -1) { //console.log('a3'); return; } if (ev.masks.toString().indexOf('moved_to') != -1) { //console.log('a4'); //console.log('moved to'); //console.log("xxx masks were just activated: '" + ev.masks.toString() + "' for '" + ev.name + "'."); //return; } //console.log("file changed! path " + path.resolve(ev.watch + '/' +ev.name)); //console.log("These masks were just activated: '" + ev.masks.toString() + "' for '" + ev.name + "'."); //console.log("all_events : file changed! path " + path.resolve(ev.watch + '/' +ev.name) + ' mask:' + ev.masks.toString()) ; var _path = path.resolve(ev.watch + '/' + ev.name); var mask = ev.masks.toString().replace('all_events,', ''); var type = 'changed'; if (mask.indexOf('delete') !== -1) { type = 'deleted'; } if (_path) { factory.publish(types.EVENTS.ON_FILE_CHANGED, { path: _path, modulePath: _path.replace(dojoConfig.libRoot, ''), type: type }, thiz); } }, close_write: function (ev) { //console.log("close-write : file changed! path " + path.resolve(ev.watch + '/' +ev.name) + ' mask ' + ev.masks.toString()); count += 1; if (ev.name.indexOf('.git') != -1 || ev.name.indexOf('.tmp') != -1) { return; } if (ev.name.indexOf('_jb_old_') != -1 || ev.name.indexOf('_jb_bak_') != -1) { return; } if (ev.masks.toString().indexOf('access') != -1) { return; } if (ev.masks.toString().indexOf('moved_to') != -1) { // console.log("xxx masks were just activated: '" + ev.masks.toString() + "' for '" + ev.name + "'."); return; } //console.log("These masks were just activated: '" + ev.masks.toString() + "' for '" + ev.name + "'."); //console.log('close write',ev); var _path = path.resolve(ev.watch + '/' + ev.name); if (_path) { //console.log('-file changed'); factory.publish(types.EVENTS.ON_FILE_CHANGED, { path: _path, modulePath: _path.replace(dojoConfig.libRoot, '') }, thiz); } }, access: true, moved_to: true, moved_from: true, "delete": true }; }()); var Inotify = inotify.create(false); for (var j = 0; j < profile.watchr.paths.length; j++) { var dir = profile.watchr.paths[j]; if (!fs.existsSync(dir)) { debug && console.error('directory : ' + dir + ' doesnt exists'); continue; } debug && console.log('start watching ' + dir); var _results = _walk(dir); Inotify.watch(directive, dir); for (var i = 0; i < _results.length; i++) { var _dir = _results[i]; /*console.log('start watching ' + _dir);*/ Inotify.watch(directive, _dir); } } } }); });