在用于从密钥环获取密码的Turtle脚本中,使用这些密码调用ssh-add
以便他们不必手动填写,具有以下功能:
processKey :: (T.Text, T.Text) -> Shell Line -> IO ()
processKey (kn, str) pwds = do
-- Not sure why (text str) is needed here, but it won't typecheck without
-- it (despite OverloadedStrings).
let expectArg = do
ml <- grep (contains (text str)) pwds
let pass = getPwd $ cut tab (format l ml)
return $ T.unlines [ "<< EOF"
, "spawn ssh-add"
, "expect \"Enter passphrase\""
, "send " <> pass
, "expect eof"
, "EOF"
]
view (inproc "expect" [] expectArg)
where
-- Safely get the third item `cut` from the list.
getPwd xs = getPwd' 0 xs
getPwd' _ [] = ""
getPwd' n (x:xs) = if n == 2
then x
else getPwd' (n+1) xs
此函数采用(SSH密钥文件名,要在密钥环中存储的文本中搜索的字符串)和pwds :: Shell Line
的元组,这是从shell命令获取的密钥环的全部内容。
该功能的目的是grep
密码,并使用密钥文件名和密码调用ssh-add
。
问题是这个函数没有键入检查:
sshkeys-autopass.hs:45:30: error:
• Couldn't match type ‘Text’ with ‘Line’
Expected type: Shell Line
Actual type: Shell Text
• In the third argument of ‘inproc’, namely ‘expectArg’
In the first argument of ‘view’, namely
‘(inproc "expect" [] expectArg)’
In a stmt of a 'do' block: view (inproc "expect" [] expectArg)
|
45 | view (inproc "expect" [] expectArg)
| ^^^^^^^^^
似乎Shell Line
需要成为Shell Text
,请问怎么办呢?我对这种结构很糟糕或者不是惯用的Haskell(它确实有异味)的可能性持开放态度,如果是这样的话请告诉我这个功能如何更好。
答案 0 :(得分:5)
虽然我现在无法试用您的代码,但似乎通过Text
(因为T.unlines
迫使您)导致的命令往往会导致不必要的麻烦。根据{{3}}(强调我的):
(Shell a)
是a
带有副作用的受保护流
由于Shell Line
是一个流,它可以提供多个Line
。当然,有一个名为to the documentation ...
select :: Foldable f => f a -> Shell a
...将列表(或任何其他Foldable
)转换为Shell
。您可以使用它直接获得所需的Shell Line
:
{-# LANGUAGE OverloadedStrings #-}
-- etc.
let expectArg = do
ml <- grep (contains (text str)) pwds
-- unsafeTextToLine is presumably safe here,
-- as ml was a Line to begin with.
let pass = unsafeTextToLine . getPwd $ cut tab (format l ml)
select [ "<< EOF"
, "spawn ssh-add"
, "expect \"Enter passphrase\""
, "send " <> pass
, "expect eof"
, "EOF"
]
view (inproc "expect" [] expectArg)
附带问题:
不确定为什么
(text str)
在这里需要,但如果没有它就不会进行类型检查(尽管有OverloadedStrings)。
OverloadedStrings
唯一自动处理的是字符串文字。它无法将Text
值静默转换为IsString
的其他实例。使用text
的替代方法是更改您的签名,以使str
的类型为Pattern Text
而不是Text
。
从列表中安全地获取第三项
cut
。
这是一种编写getPwd
的方法,无需使用select
中的一些函数显式编写递归算法:
getPwd = fromMaybe "" . listToMaybe . drop 2
您可能也喜欢 safe 包中的Data.Maybe
:
getPwd xs = atDef "" xs 2
但这会导致另一个问题:
inproc
不想要Shell (NonEmpty Line)
。我不知道该怎么做。
atDef
是保证至少包含一个元素的列表类型。在你的情况下,缺乏一种合理的方式从NonEmpty Line
转到Line
(连接元素或选择第一个元素,例如,根本没有帮助)是一个信号,改变方法是必要的。