Meteor:调用方法来执行shell(克隆git-reo)



问题:

在Meteor中,如何从客户端调用方法(传递name(,让服务器执行一些shell命令?

方法的基本功能是:创建一个目录,然后用给定的name克隆git-reo。

这是非常简单的东西,但流星不会这么做。我已经绕了好几个小时了。所有东西都可以在常规bash或node中工作。目前:

目录被创建->服务器重新启动->流星抛出错误,声称目录已经存在->流星删除目录->服务器重新开始

代码:

var cmd, exec, fs;
if (Meteor.isClient) {
  Template.app.events({
    'click button': function() {
        Meteor.call('clone', "NAMEHERE", function(error, result) {
          if (error) {
            console.log(error);
          } else {
            console.log(result);
          }
        });
    }
  });
}
if (Meteor.isServer) {
  fs = Npm.require('fs');
  exec = Npm.require('child_process').exec;
  cmd = Meteor.wrapAsync(exec);
  Meteor.methods({
    'clone': function(name) {
      var dir;
      dir = process.env.PWD + "/projects/" + name;
      cmd("mkdir " + dir + "; git clone git@gitlab.com:username/" + name + ".git " + dir, Meteor.bindEnvironment(function(error, stdout, stderr) {
        if (error) {
          throw new Meteor.Error('error...');
        } else {
          console.log('done');
        }
      }));
      return 'cloning...';
    }
  });
}

更新1

如果我事先手动创建文件夹,以下代码将成功克隆repo:

if (Meteor.isClient) {
  Template.all.events({
    'click button': function() {
      Meteor.call('clone', this.name);
    }
  });
}

if (Meteor.isServer) {
  exec = Npm.require('child_process').exec;
  cmd = Meteor.wrapAsync(exec);
  Meteor.methods({
    'clone': function(name) {
      var dir, res;
      dir = process.env.PWD + "/projects/" + name;
      res = cmd(git clone git@gitlab.com:username/" + name + ".git " + dir);
      return res;
    }
  });
}

然而,如果我将"mkdir " + dir添加到cmd,我仍然会遇到同样的问题:

目录被创建->服务器重新启动->流星抛出错误,声称目录已经存在->流星删除目录->服务器重新开始

解决方案:

Meteor正在重新启动,因为其目录中的某些内容发生了更改(projects(。然后在启动时重新运行该方法。这是方法调用的另一个问题。

更新1/@Rebolon的答案就是解决方案。

您的Meteor.call正常,问题似乎出在服务器端:您正确地使用wrapAsync来打包exec-npm对象,但随后您错误地使用了cmd-var:您只需要发送一个参数,如下所示:

var res = cmd("mkdir " + dir + "; git clone git@gitlab.com:username/" + name + ".git " + dir);
return res;

实际上,你的代码显示你想向客户端返回不同的信息:

  1. 我接到电话,命令挂起
  2. 命令已完成且正常或出现错误

但事实上,它无法工作,因为使用wrapAsync cmd(…(将等到它完成后再返回"Pending…"因此,客户端将只收到"挂起…"响应。

你真的需要通知客户端命令挂起,然后它就完成了吗?如果是,您可以使用状态集合来存储命令的状态(received/pending/ok/error…(,然后在您的方法中,您只需要更新集合,而在您的客户端中,只需订阅此状态集合。

你可以看看这个项目,我在服务器上使用exec(带有重试包(和一个集合来管理挂起状态:https://github.com/MeteorLyon/satis-easy

您的Meteor.call代码不在事件的功能块中。像这样的东西应该起作用:

if (Meteor.isClient) {
  Template.app.events({
    'click button': function() {
        Meteor.call('clone', "NAMEHERE", function(error, result) {
          if (error) {
            return console.log(error);
          } else {
            return console.log(result);
          }
        });
    }
  });
}

最新更新