让NodeJS应用程序使用NPM更新自己

时间:2013-12-16 17:49:17

标签: javascript node.js npm spawn

Hej那里,

我正在尝试为我的NodeJS应用程序添加一些非传统功能,但我遇到了一些麻烦。 我要做的是以下内容:

我想从客户端更新我的服务器代码。 (如果愿意,可以使用自动更新功能。)

我的第一次尝试是使用NPM API并运行:

 npm.commands.install([package], function(err, data)

但当然这会导致错误告诉我在服务器运行时无法安装NPM。

我的第二次尝试是使用以下代码生成NPM更新:

  spawnProcess('npm', ['update'], { cwd: projectPath }, done);

spawnProcess函数是一个通用的spawn函数:

var projectPath = path.resolve(process.cwd());
var spawnProcess = function(command, args, options, callback) {
    var spawn = require('child_process').spawn;
    var process = spawn(command, args, options);
    var err = false;

    process.stdout.on('data', function(data) {
        console.log('stdout', data.toString());
    });

    process.stderr.on('data', function(data) {
        err = true;
        console.log('stderr', data.toString());
    });

    if (typeof callback === 'function') {
        process.on('exit', function() {
            if (!err) {
                return callback();
            }
        });
    }
};

但这给了我一个stderr,然后是'CreateProcessW:找不到文件'错误。 我不太清楚我做错了什么。

如果所有其他方法都失败了,我认为有可能写一个shellcript查杀节点,更新应用程序然后重新启动它。类似的东西:

kill -9 45728
npm update
node server

但我不知道这是否是一个合理的解决方案以及如何从我的节点服务器执行它。 我当然希望生成函数。

欢迎任何帮助。 提前谢谢!

3 个答案:

答案 0 :(得分:6)

所以我终于解决了这个问题。如果有人对我是如何做到这一点感兴趣的话,那就是:

我使用NPM api构建了一个函数来检查当前版本是否是最新的:

 exports.checkVersion = function(req, res) {
    npm.load([], function (err, npm) {
        npm.commands.search(["mediacenterjs"], function(err, data){
            if (err){
                console.log('NPM search error ' + err);
                return;
            } else{
                var currentInfo = checkCurrentVersion();
                for (var key in data) {
                    var obj = data[key];
                    if(obj.name === 'mediacenterjs' && obj.version > currentInfo.version){
                        var message = 'New version '+obj.version+' Available';
                        res.json(message);
                    }
                }
            }
        });
    });
}

var checkCurrentVersion = function(){
    var info = {};
    var data = fs.readFileSync('./package.json' , 'utf8');

    try{
        info = JSON.parse(data);
    }catch(e){
        console.log('JSON Parse Error', e);
    }

    return info;
};

如果版本不是最新的,我使用node-wget启动下载(在我的情况下是github master repo url):

var wget = require('wget');
var download = wget.download(src, output, options);
download.on('error', function(err) {
    console.log('Error', err);
    callback(output);
});
download.on('end', function(output) {
    console.log(output);
    callback(output);
});
download.on('progress', function(progress) {
    console.log(progress * 100);
});

回调基于@John Munsch'Self help'脚本启动解压缩功能,但我添加了一个检查以查看是否有先前的解压缩尝试,如果有,我删除该文件夹:

if(fs.existsSync(dir) === false){
    fs.mkdirSync(dir);
} else {
    rimraf(dir, function (err) { 
        if(err) {
            console.log('Error removing temp folder', err);
        } else {
            fileHandler.downloadFile(src, output, options, function(output){
                console.log('Done', output);
                unzip(req, res, output, dir);
            });
        }
    });
}
console.log("Unzipping New Version...");
var AdmZip = require("adm-zip");
var zip = new AdmZip(output);
zip.extractAllTo(dir, true);

fs.openSync('./configuration/update.js', 'w');

openSync函数启动我的基于'NodeMon'的文件(https://github.com/jansmolders86/mediacenterjs/blob/master/server.js),该文件会杀死服务器,因为它列出了对该特定文件的更改。最后,它重新启动并启动以下功能:

function installUpdate(output, dir){
    console.log('Installing update...');
    var fsExtra = require("fs.extra");
    fsExtra.copy(dir+'/mediacenterjs-master', './', function (err) {
        if (err) {
            console.error('Error', err);
        } else {
            console.log("success!");
            cleanUp(output, dir);
        }
    });
}

function cleanUp(output, dir) {
    console.log('Cleanup...');
    var rimraf = require('rimraf');
    rimraf(dir, function (e) {
        if(e) {
            console.log('Error removing module', e .red);
        }
    });

    if(fs.existsSync(output) === true){
        fs.unlinkSync(output);
        console.log('Done, restarting server...')
        server.start();
    }
}

感谢所有帮助我的人!

答案 1 :(得分:3)

未测试!

您是否尝试过“预启动”npm script handle?当然这意味着您将使用npm来运行您的服务器: npm start

在你的package.json中(如果有的话):

{ "scripts" :
  { 
    "start" : "node server.js",
    "prestart" : "scripts/customScript.js"
  }
}

NPM启动命令隐式默认为“start”:“node server.js”。如果您的服务器脚本名为server.js,则无需包含此脚本。你可以在customScript.js上进行npm安装,或者可以直接调用npm install,虽然我还没有测试过。

您还可以使用环境变量 process.env.npm_package_scripts_prestart

分配/读取您的处理程序

答案 2 :(得分:1)

它没有使用NPM来实现它,但这是一个我在一段时间后组合在一起的工作实验,因为我希望能够使用Node.js构建一个自我更新的应用程序,以便安装在人们的机器上(想想像SABnzbd +这样的应用程序,Couch Potato或Plex Media Server)。

示例代码的Github位于:https://github.com/JohnMunsch/selfhelp

我得到了一个示例,它可以在新版本可用时自动通知您,然后下载,更新并重新启动。即使你最终没有按原样使用它,你也应该能够从中获得一些想法。