Meteor:执行shell的调用方法(clone git repo)

off*_*ass 5 git bash shell meteor

问题:

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

方法函数基本上是:创建一个目录,然后用给定的克隆git repo name.

这是非常简单的东西,但Meteor不会这样做.我已经圈了好几个小时了.一切都在普通的bash或节点中工作.在那一刻:

创建目录 - >服务器重启 - > meteor抛出错误声明目录已存在 - > meteor删除目录 - >服务器重启

码:

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...';
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

更新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;
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我添加"mkdir " + dircmd,我仍然有同样的问题:

创建目录 - >服务器重启 - > meteor抛出错误声明目录已存在 - > meteor删除目录 - >服务器重启

解:

Meteor正在重启,因为其目录中的某些内容已更改(projects).然后在启动时重新运行该方法.这是方法调用的一个单独问题.

来自update 1/@ Rebolon的答案的代码是解决方案.

Reb*_*lon 2

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

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

实际上你的代码表明你想返回给客户端不同的信息:

  1. 我接到电话,命令正在等待处理
  2. 命令已完成且正常或出现错误

但实际上它无法工作,因为使用wrapAsync cmd(...) 将等到它完成后再返回“Pending ...”,因此客户端只会收到“Pending ...”响应。

您是否真的需要通知客户端该命令正在等待,然后它就完成了?如果是,您可以使用状态集合,您可以在其中存储命令的状态(已接收/待处理/确定/错误...),然后在您的方法中您只需更新集合,并且在您的客户端中只需订阅此状态集合。

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