From 5c4adb5be20a308588f2c7ea1e71439eae9cedcc Mon Sep 17 00:00:00 2001 From: Daniil Frumin Date: Mon, 24 Jun 2013 22:35:38 +0400 Subject: [PATCH] Adds MountSettings With MountSettings a user is able to specify a list of known usernames/hosts configurations with ports and private ssh keys. The settings are stored as a [MountSettings] value in a ~/.vadosettings file. If the file is absent or vado has failed to read it then the settings are defaulted to standart vagrant ones. --- README.md | 33 +++++++++++++--- src/Main.hs | 13 +++--- src/System/Process/Vado.hs | 81 ++++++++++++++++++++++++++++---------- 3 files changed, 95 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 891d881..eb39f8f 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,34 @@ and makes vim work nicely). vagrant ======= -This is not tied to vagrant, but can be used with it and is -faster than 'vagrant ssh'. If the user detected in 'mount' -is 'vagrant' and the host is '127.0.0.1' then it will default to -port 2222 and use '~/.vagrant.d/insecure_private_key' for -authentication. +This is not tied to vagrant, but can be used with it and is faster +than 'vagrant ssh'. If the user and host detected in 'mount' are +specified in the '~/.vadosettings' file, then the specified key and +port will be used. If the file is not present or incorrectly formatted +then the default settings for vagrant will be used: + - User: vagrant + - Host: 127.0.0.1 + - Port: 2222 + - Key file: ~/.vagrant.d/insecure_private_key + +### Example '.vadosettings' file + +```haskell +[ + MountSettings { + sshfsUser = "vagrant" + , sshfsHost = "localhost" + , sshfsPort = 2222 + , idFile = "/Users/dan/.vagrant.d/insecure_private_key" + }, + MountSettings { + sshfsUser = "vagrant" + , sshfsHost = "server.local" + , sshfsPort = 2233 + , idFile = "/Users/dan/keys/local_server_key" + } +] +``` install diff --git a/src/Main.hs b/src/Main.hs index 37a206a..12f7ffc 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -24,7 +24,7 @@ import System.Environment (getArgs) import Data.List (isPrefixOf) import System.Exit (exitWith, ExitCode(..)) import System.Process (rawSystem) -import System.Process.Vado (getMountPoint, vado) +import System.Process.Vado (getMountPoint, vado, readSettings, defMountSettings) -- | Main function for vado main = do @@ -33,11 +33,13 @@ main = do (sshopts,cmd:rest) -> do currentDir <- getCurrentDirectory mbMountPoint <- getMountPoint currentDir + ms <- readSettings case mbMountPoint of - Left mp -> vado mp currentDir sshopts cmd rest + Left mp -> vado mp ms currentDir sshopts cmd rest >>= rawSystem "ssh" >>= exitWith Right err -> hPutStrLn stderr err >> (exitWith $ ExitFailure 1) _ -> do + defSettings <- defMountSettings hPutStrLn stderr $ "Usage vado [ssh options] command [args]\n\n" @@ -45,9 +47,8 @@ main = do ++ "machine that corrisponds to the current directory locally.\n\n" ++ "The ssh options must start with a dash '-'.\n" - ++ "If the mount point is 'vagrant@127.0.0.1'\n" - ++ "then the most common vagrant connection options\n" - ++ " -p2222 and -i~/.vagrant.d/insecure_private_key\n" - ++ "are included automatically." + ++ "You can specify port and key location settings\n" + ++ "in the ~/.vadosettings file.\nExample contents:\n" + ++ show [defSettings] exitWith $ ExitFailure 1 diff --git a/src/System/Process/Vado.hs b/src/System/Process/Vado.hs index ef54978..82c9bcf 100644 --- a/src/System/Process/Vado.hs +++ b/src/System/Process/Vado.hs @@ -1,5 +1,6 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} ----------------------------------------------------------------------------- -- -- Module : System.Process.Vado @@ -20,18 +21,22 @@ module System.Process.Vado ( MountPoint(..) , parseMountPoint , getMountPoint + , MountSettings(..) + , readSettings + , defMountSettings , vado ) where import Control.Applicative ((<$>)) import Data.Text (pack, unpack, Text) -import Data.List (isPrefixOf) +import Data.List (isPrefixOf, find) import Data.Monoid (mconcat) import Data.Attoparsec.Text (parse, string, Parser, IResult(..)) import qualified Data.Attoparsec.Text as P (takeWhile1) import Data.Text.IO (hPutStrLn) import System.FilePath (addTrailingPathSeparator, makeRelative, ()) -import Data.Maybe (catMaybes) +import Data.Maybe (catMaybes, fromMaybe) +import Text.Read (readMaybe) import System.Exit (ExitCode) import System.Process (readProcess) import System.Directory (getHomeDirectory, getCurrentDirectory) @@ -48,6 +53,26 @@ instance Show MountPoint where show MountPoint {..} = unpack (mconcat [remoteUser, "@", remoteHost, ":"]) ++ remoteDir ++ " on " ++ localDir ++ " " +-- | Mount point settings +data MountSettings = MountSettings { + sshfsUser :: Text + , sshfsHost :: Text + , sshfsPort :: Int + , idFile :: FilePath + } deriving (Show, Read) + +-- | Default mount settings for vagrant +defMountSettings :: IO MountSettings +defMountSettings = do + homeDir <- getHomeDirectory + return MountSettings { + sshfsUser = "vagrant" + , sshfsHost = "127.0.0.1" + , sshfsPort = 2222 + , idFile = homeDir ".vagrant.d/insecure_private_key" + } + + -- | Parser for a line of output from the 'mount' command mountPointParser :: Parser MountPoint mountPointParser = do @@ -89,33 +114,47 @@ getMountPoint dir = do _ -> "The following remote mount points were not suitable\n" ++ concatMap (\mp -> " " ++ show mp ++ "\n") mountPoints + +-- | Read a list of predefined mount points from the +-- ~/.vadosettings files +readSettings :: IO [MountSettings] +readSettings = do + homeDir <- getHomeDirectory + settings :: Maybe [MountSettings] <- readMaybe <$> + readFile (homeDir ".vadosettings") + defaultSettings <- defMountSettings + return $ fromMaybe [defaultSettings] settings + -- | Get a list of arguments to pass to ssh to run command on a remote machine -- in the directory that is mounted locally -vado :: MountPoint -- ^ Mount point found using 'getMountPoint' - -> FilePath -- ^ Local directory you want the command to run in. - -- Normally this will be the same directory - -- you passed to 'getMountPoint'. - -- The vado will run the command in the remote - -- directory that maps to this one. - -> [String] -- ^ Options to pass to ssh. If the mount point is 'vagrant@127.0.0.1' - -- then the most common vagrant connection options - -- ('-p2222' and '-i~/.vagrant.d/insecure_private_key') - -- are included automatically - -> FilePath -- ^ Command to run - -> [String] -- ^ Arguments to pass to the command - -> IO [String] -- ^ Full list of arguments that should be passed to ssh -vado MountPoint{..} cwd sshopts cmd args = do +vado :: MountPoint -- ^ Mount point found using 'getMountPoint' + -> [MountSettings] -- ^ SSH settings from the '.vadosettings' files + -> FilePath -- ^ Local directory you want the command to run in. + -- Normally this will be the same directory + -- you passed to 'getMountPoint'. + -- The vado will run the command in the remote + -- directory that maps to this one. + -> [String] -- ^ Options to pass to ssh. If the mount point is 'vagrant@127.0.0.1' + -- then the most common vagrant connection options + -- ('-p2222' and '-i~/.vagrant.d/insecure_private_key') + -- are included automatically + -> FilePath -- ^ Command to run + -> [String] -- ^ Arguments to pass to the command + -> IO [String] -- ^ Full list of arguments that should be passed to ssh +vado MountPoint{..} settings cwd sshopts cmd args = do homeDir <- getHomeDirectory -- Work out where the current directory is on the remote machine let destinationDir = remoteDir makeRelative localDir cwd -- Run ssh with return $ [unpack $ mconcat [remoteUser, "@", remoteHost]] - ++ case (remoteUser, remoteHost) of - ("vagrant","127.0.0.1") -> -- Default options for vagrant - ["-p2222", - "-i" ++ homeDir ".vagrant.d/insecure_private_key"] - _ -> [] + ++ case find (\MountSettings{..} -> + remoteUser == sshfsUser + && remoteHost == sshfsHost) settings of + Just MountSettings{..} -> + [ "-p" ++ show sshfsPort + , "-i" ++ idFile ] + Nothing -> [] ++ sshopts ++ ["cd", translate destinationDir, "&&", cmd] ++ args