Enable Darcs repo cloning over SSH using darcs executable
This commit is contained in:
parent
1c4b674550
commit
d57c95c94a
1 changed files with 59 additions and 13 deletions
|
@ -41,6 +41,7 @@ import Network.SSH
|
||||||
import Network.SSH.Channel
|
import Network.SSH.Channel
|
||||||
import Network.SSH.Crypto
|
import Network.SSH.Crypto
|
||||||
import Network.SSH.Session
|
import Network.SSH.Session
|
||||||
|
import System.Directory (doesFileExist, doesDirectoryExist)
|
||||||
import System.FilePath ((</>))
|
import System.FilePath ((</>))
|
||||||
import System.Process (CreateProcess (..), StdStream (..), createProcess, proc)
|
import System.Process (CreateProcess (..), StdStream (..), createProcess, proc)
|
||||||
|
|
||||||
|
@ -68,9 +69,17 @@ data RepoSpec
|
||||||
| SpecRepo Text
|
| SpecRepo Text
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
|
--data DarcsFile
|
||||||
|
-- = DarcsFormat
|
||||||
|
-- | DarcsMotd
|
||||||
|
-- | DarcsInventory
|
||||||
|
-- deriving Show
|
||||||
|
|
||||||
data Action
|
data Action
|
||||||
= UploadPack RepoSpec
|
-- = DarcsCopy RepoSpec DarcsFile
|
||||||
| ReceivePack RepoSpec
|
= DarcsTransferMode RepoSpec
|
||||||
|
| GitUploadPack RepoSpec
|
||||||
|
| GitReceivePack RepoSpec
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
-- | Result of running an action on the server side as a response to an SSH
|
-- | Result of running an action on the server side as a response to an SSH
|
||||||
|
@ -131,8 +140,15 @@ authorize (PublicKey name key) = do
|
||||||
-- Actions
|
-- Actions
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
repoSpecP :: Parser RepoSpec
|
--TOD TODO TODO check paths for safety... no /./ or /../ and so on
|
||||||
repoSpecP = f <$> (msh *> part) <*> optional (char '/' *> part)
|
|
||||||
|
darcsRepoSpecP :: Parser RepoSpec
|
||||||
|
darcsRepoSpecP = SpecUserRepo <$> part <* char '/' <*> part <* char '/'
|
||||||
|
where
|
||||||
|
part = takeWhile1 (/= '/')
|
||||||
|
|
||||||
|
gitRepoSpecP :: Parser RepoSpec
|
||||||
|
gitRepoSpecP = f <$> (msh *> part) <*> optional (char '/' *> part)
|
||||||
where
|
where
|
||||||
f repo Nothing = SpecRepo repo
|
f repo Nothing = SpecRepo repo
|
||||||
f sharer (Just repo) = SpecUserRepo sharer repo
|
f sharer (Just repo) = SpecUserRepo sharer repo
|
||||||
|
@ -140,8 +156,12 @@ repoSpecP = f <$> (msh *> part) <*> optional (char '/' *> part)
|
||||||
msh = optional (satisfy $ \ c -> c == '/' || c == '~')
|
msh = optional (satisfy $ \ c -> c == '/' || c == '~')
|
||||||
|
|
||||||
actionP :: Parser Action
|
actionP :: Parser Action
|
||||||
actionP = UploadPack <$> ("git-upload-pack '" *> repoSpecP <* char '\'')
|
actionP = DarcsTransferMode <$>
|
||||||
<|> ReceivePack <$> ("git-receive-pack '" *> repoSpecP <* char '\'')
|
("darcs transfer-mode --repodir " *> darcsRepoSpecP)
|
||||||
|
<|> GitUploadPack <$>
|
||||||
|
("git-upload-pack '" *> gitRepoSpecP <* char '\'')
|
||||||
|
<|> GitReceivePack <$>
|
||||||
|
("git-receive-pack '" *> gitRepoSpecP <* char '\'')
|
||||||
|
|
||||||
parseExec :: Text -> Either String Action
|
parseExec :: Text -> Either String Action
|
||||||
parseExec input = parseOnly (actionP <* endOfInput) input
|
parseExec input = parseOnly (actionP <* endOfInput) input
|
||||||
|
@ -180,22 +200,48 @@ execute cmd args = do
|
||||||
(verifyPipe mIn, verifyPipe mOut, verifyPipe mErr, ph)
|
(verifyPipe mIn, verifyPipe mOut, verifyPipe mErr, ph)
|
||||||
spawnProcess $ verifyPipes <$> createProcess config
|
spawnProcess $ verifyPipes <$> createProcess config
|
||||||
|
|
||||||
whenRepoExists :: FilePath -> Channel ActionResult -> Channel ActionResult
|
whenDarcsRepoExists :: FilePath -> Channel ActionResult -> Channel ActionResult
|
||||||
whenRepoExists repoPath action = do
|
whenDarcsRepoExists repoPath action = do
|
||||||
|
looksGood <- liftIO $ doesDirectoryExist $ repoPath </> "_darcs"
|
||||||
|
if looksGood
|
||||||
|
then action
|
||||||
|
else return $ ARFail "No such darcs repository"
|
||||||
|
|
||||||
|
whenGitRepoExists :: FilePath -> Channel ActionResult -> Channel ActionResult
|
||||||
|
whenGitRepoExists repoPath action = do
|
||||||
looksGood <- liftIO $ isRepo $ fromString repoPath
|
looksGood <- liftIO $ isRepo $ fromString repoPath
|
||||||
if looksGood
|
if looksGood
|
||||||
then action
|
then action
|
||||||
else return $ ARFail "No such git repository"
|
else return $ ARFail "No such git repository"
|
||||||
|
|
||||||
|
--darcsFilePath :: DarcsFile -> FilePath
|
||||||
|
--darcsFilePath DarcsFormat = "_darcs" </> "format"
|
||||||
|
--darcsFilePath DarcsMotd = "_darcs" </> "prefs" </> "motd"
|
||||||
|
--darcsFilePath DarcsInventory = "_darcs" </> "format"
|
||||||
|
|
||||||
runAction :: FilePath -> Bool -> Action -> Channel ActionResult
|
runAction :: FilePath -> Bool -> Action -> Channel ActionResult
|
||||||
runAction repoDir _wantReply action =
|
runAction repoDir _wantReply action =
|
||||||
case action of
|
case action of
|
||||||
UploadPack spec -> do
|
--DarcsCopy spec file -> do
|
||||||
(sharer, repo, repoPath) <- resolveSpec' repoDir spec
|
-- (_sharer, _repo, repoPath) <- resolveSpec' repoDir spec
|
||||||
whenRepoExists repoPath $ do
|
-- let filePath = repoPath </> darcsFilePath file
|
||||||
|
-- exists <- liftIO $ doesFileExist filePath
|
||||||
|
-- if exists
|
||||||
|
-- then do
|
||||||
|
-- execute "scp" ["-f", filePath]
|
||||||
|
-- return ARProcess
|
||||||
|
-- else return $ ARFail "No such file in the repo"
|
||||||
|
DarcsTransferMode spec -> do
|
||||||
|
(_sharer, _repo, repoPath) <- resolveSpec' repoDir spec
|
||||||
|
whenDarcsRepoExists repoPath $ do
|
||||||
|
execute "darcs" ["transfer-mode", "--repodir", repoPath]
|
||||||
|
return ARProcess
|
||||||
|
GitUploadPack spec -> do
|
||||||
|
(_sharer, _repo, repoPath) <- resolveSpec' repoDir spec
|
||||||
|
whenGitRepoExists repoPath $ do
|
||||||
execute "git-upload-pack" [repoPath]
|
execute "git-upload-pack" [repoPath]
|
||||||
return ARProcess
|
return ARProcess
|
||||||
ReceivePack spec -> do
|
GitReceivePack spec -> do
|
||||||
(sharer, repo, repoPath) <- resolveSpec' repoDir spec
|
(sharer, repo, repoPath) <- resolveSpec' repoDir spec
|
||||||
-- Now we need to check whether the authenticated user (can get its
|
-- Now we need to check whether the authenticated user (can get its
|
||||||
-- details with 'askAuthDetails') has write access to the repo.
|
-- details with 'askAuthDetails') has write access to the repo.
|
||||||
|
@ -204,7 +250,7 @@ runAction repoDir _wantReply action =
|
||||||
-- enough to compare them.
|
-- enough to compare them.
|
||||||
userName <- T.pack . authUser <$> askAuthDetails
|
userName <- T.pack . authUser <$> askAuthDetails
|
||||||
if userName == sharer
|
if userName == sharer
|
||||||
then whenRepoExists repoPath $ do
|
then whenGitRepoExists repoPath $ do
|
||||||
execute "git-receive-pack" [repoPath]
|
execute "git-receive-pack" [repoPath]
|
||||||
return ARProcess
|
return ARProcess
|
||||||
else return $ ARFail "You can't push to this repository"
|
else return $ ARFail "You can't push to this repository"
|
||||||
|
|
Loading…
Reference in a new issue