handsy 0.0.10 → 0.0.11
raw patch · 4 files changed
+139/−20 lines, 4 filesdep +split
Dependencies added: split
Files
- handsy.cabal +27/−13
- src/System/Handsy/Tutorial.hs +84/−0
- src/System/Handsy/Util.hs +27/−4
- test/Test.hs +1/−3
handsy.cabal view
@@ -1,7 +1,18 @@ name: handsy-version: 0.0.10+version: 0.0.11 synopsis: A DSL to describe common shell operations and interpeters for running them locally and remotely.--- description: +description:+ @handsy@ is a small library mainly for applications which should make some+ operations on remote machines by SSH. It currently provides you:+ .+ * A DSL describing basic system operations('command', 'readFile', 'writeFile' etc.)+ * Two interpreters for running this DSL locally or via SSH('run' and 'runRemote')+ * Some utility functions for common commands('os', 'mkTemp' etc.)+ .+ If you're looking for a shell scripting alternative, look at @turtle@, @shelly@ or+ @shellmate@ packages. @handsy@ is mostly relevant for the ability to apply simple+ commands remotely.+ Homepage: https://github.com/utdemir/handsy license: BSD3 author: Utku Demir@@ -19,6 +30,7 @@ System.Handsy.Remote System.Handsy.Util System.Handsy.Internal+ System.Handsy.Tutorial build-depends: base >=4.6 && <4.8 , bytestring , process@@ -28,19 +40,21 @@ , shell-escape , retry , data-default-class+ , split hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall- ghc-options: -Wall+ test-suite tests- type: exitcode-stdio-1.0- main-is: Test.hs- default-language: Haskell2010- hs-source-dirs: test- build-depends: base >=4.6 && < 4.8- , handsy- , bytestring- , tasty- , tasty-hunit- , tasty-th+ type: exitcode-stdio-1.0+ main-is: Test.hs+ default-language: Haskell2010+ hs-source-dirs: test+ build-depends: base >=4.6 && < 4.8+ , handsy+ , bytestring+ , tasty+ , tasty-hunit+ , tasty-th+ ghc-options: -Wall
+ src/System/Handsy/Tutorial.hs view
@@ -0,0 +1,84 @@+{-# OPTIONS_GHC -fno-warn-unused-imports #-}++module System.Handsy.Tutorial (+ -- * Introduction+ -- $introduction++ -- * Examples+ -- $examples+ ) where++import System.Handsy+import System.Handsy.Remote+import System.Handsy.Util++{- $introduction+ @handsy@ is a small library mainly for applications which should make some+ operations on remote machines by SSH. It currently provides you:++ * A DSL describing basic system operations('command', 'readFile', 'writeFile' etc.)+ * Two interpreters for running this DSL locally or via SSH('run' and 'runRemote')+ * Some utility functions for common commands('os', 'mkTemp' etc.)++ If you're looking for a shell scripting alternative, look at @turtle@, @shelly@ or+ @shellmate@ packages. @handsy@ is mostly relevant for the ability to apply simple+ commands remotely.+-}++{- $examples+ Here is a simple demonstration:++@+import Control.Applicative ((\<$>))+import Control.Monad.IO.Class (liftIO)+import qualified Data.ByteString.Lazy as B++import qualified System.Handsy as H+import qualified System.Handsy.Remote as H+import qualified System.Handsy.Util as H++demo :: H.Handsy B.ByteString+demo = do+ os <- H.os++ -- We can do IO in Handsy monad+ liftIO . putStrLn $ "Hello from " ++ maybe \"UnknownOS\" show os ++ "!"++ tmpFile <- H.mkTemp "handsy"+ H.writeFile tmpFile "hello world!"+ H.stdout \<$\> H.command "cat" [tmpFile] H.def+@++ And now we can run it:++@+ runHere = 'H.run' H.def demo >>= print+ runThere = 'H.runRemote' H.def "root@google.com" H.def{H.sshPort=2222} demo >>= print+@++> λ> runHere+> Hello from NixOS!+> "hello world!"+> λ> runThere+> Hello from CentOS!+> "hello world!"++ Internally, Handsy converts the DSL terms into series of shell commands and+ 'run' and 'runRemote' functions describes how to apply those shell+ commands.++ You can see the given shell commands using 'debug' option:++> λ> H.run H.def{debug=True} demo >>= print+> cat /etc/os-release+> Hello from NixOS!+> mktemp $'--suffix=handsy'+> dd $'of=/run/user/1002/tmp.N3TlYC9Jfwhandsy'+> cat /run/user/1002/tmp.N3TlYC9Jfwhandsy+> "hello world!"++++-}++
src/System/Handsy/Util.hs view
@@ -9,10 +9,13 @@ import Control.Monad.IO.Class import Data.Bool import qualified Data.ByteString.Lazy.Char8 as C+import Data.List.Split import Prelude hiding (appendFile, readFile, writeFile) import System.Handsy +-- * Helpers for parsing return values of 'command' and 'shell'+ class IsReturnValue a where stdout :: a -> C.ByteString stderr :: a -> C.ByteString@@ -36,14 +39,16 @@ ExitSuccess -> True ExitFailure _ -> False --- | Waits specified number of seconds-sleep :: Int -> Handsy ()-sleep = liftIO . threadDelay . (* 1000000)- -- | Extract lines from a ByteString. Useful for parsing unix commands. strLines :: C.ByteString -> [String] strLines = lines . C.unpack +-- * Frequently used functionality++-- | Waits specified number of seconds+sleep :: Int -> Handsy ()+sleep = liftIO . threadDelay . (* 1000000)+ -- | Creates a temporary file mkTemp :: String -> Handsy String mkTemp suffix = head . strLines . fst@@ -57,3 +62,21 @@ -- | Returns if the specified process is running. Uses `pidof` isRunning :: String -> Handsy Bool isRunning p = isSuccessful <$> command "pidof" ["-s", "-x", p] def++data OS = NixOS | Debian | Ubuntu | RHEL | CentOS | Fedora | ArchLinux+ deriving (Show, Eq)++{-| Guesses the os using `/etc/os-release`. This currently only supports Linux distributions+ abiding systemd standards. -}+os :: Handsy (Maybe OS)+os = parseOsRelease <$> readFile "/etc/os-release" >>= return . \case+ Just "ubuntu" -> Just Ubuntu+ Just "debian" -> Just Debian+ Just "nixos" -> Just NixOS+ Just "rhel" -> Just RHEL+ Just "centos" -> Just CentOS+ Just "fedora" -> Just Fedora+ Just "arch" -> Just ArchLinux+ _ -> Nothing+ where parseOsRelease = fmap (filter $ not . flip elem "'\"") -- Hack to unquote+ <$> lookup "ID" . map ((\(x:xs) -> (x, concat xs)) . splitOn "=") . strLines
test/Test.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures #-} module Main where @@ -14,10 +15,7 @@ import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy.Char8 as C import Data.Char-import Data.List-import System.Exit -import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.TH