在我的 Cocoa 应用程序中,我尝试使用
NSTask
来运行一些基本的 Git 命令。每当我运行需要权限(SSH 密钥)才能访问远程的命令(例如 git push
、git pull
)时,它都会失败并出现以下错误:
权限被拒绝(公钥)。远端意外挂断
从终端运行相同的命令效果很好,所以我认为这可能是由于
NSTask
没有设置在访问 ssh 密钥的过程中使用的环境变量而导致的问题。我尝试手动设置 HOME
和 USER
环境变量,如下所示:
[task setEnvironment:[NSDictionary dictionaryWithObjectsAndKeys:NSHomeDirectory(), @"HOME", NSUserName(), @"USER", nil]];
但这没有任何效果。我是否必须在
NSTask
中设置任何特定的环境变量才能使其正常工作?
编辑:感谢达斯汀的提示,我进一步弄清楚了这一点。我使用
env
命令列出当前会话的环境变量,我发现了这个:
SSH_AUTH_SOCK=/tmp/launch-DMQopt/Listeners
为了测试,我复制了该路径并将其设置为
NSTask
的环境变量,然后再次运行代码,这次成功了!也就是说,我确信 SSH_AUTH_SOCK
每个会话都会发生变化,所以我不能只是对其进行硬编码。如何动态生成/检索此变量?
您可以尝试按照教程“Wrapping rsync or SSH in an NSTask”(来自Ira),其中确实提到了
SSH_AUTH_SOCK
变量:
自从写这篇文章以来,我意识到我省略了为 NSTask 设置环境变量的一个重要的附加步骤。
为了使无密码的基于密钥的身份验证工作,有必要从用户环境中获取变量并将其包含在 NSTask 的环境中。SSH_AUTH_SOCK
所以,例如设置环境变量时;
NSTask *task;
NSDictionary *environmentDict = [[NSProcessInfo processInfo] environment];
// Environment variables needed for password based authentication
NSMutableDictionary *env = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@"NONE", @"DISPLAY", askPassPath, @"SSH_ASKPASS",
userName,@"AUTH_USERNAME",
hostName,@"AUTH_HOSTNAME",
nil];
// Environment variable needed for key based authentication
[env setObject:[environmentDict objectForKey:@"SSH_AUTH_SOCK"] forKey:@"SSH_AUTH_SOCK"];
// Setting the task's environment
[task setEnvironment:env];
然而,OP indragie评论:
我之前尝试过这个,但由于它是用 XCode 调用的,所以
环境变量。没有被传递给它。SSH_AUTH_SOCK
从 Finder 打开应用程序可以纠正此问题。
其中
是 Askpass 可执行文件的路径,它作为应用程序主包的一部分包含在内。 (为此,请在 xcode 中的“Products”下找到可执行文件,然后将其拖到主应用程序目标上的“Copy Bundle Resources”中。)askPassPath
// Get the path of the Askpass program, which is
// setup to be included as part of the main application bundle
NSString *askPassPath = [NSBundle pathForResource:@"Askpass"
ofType:@""
inDirectory:[[NSBundle mainBundle] bundlePath]];