hscrtmpl 1.6 → 2.0
raw patch · 10 files changed
+212/−82 lines, 10 filesdep +ansi-wl-pprintdep +heredocdep +optparse-applicativesetup-changednew-component:exe:args-example
Dependencies added: ansi-wl-pprint, heredoc, optparse-applicative
Files
- .gitignore +1/−3
- LICENSE +1/−1
- README.md +4/−4
- Setup.hs +0/−2
- args-example.hs +101/−0
- changelog.md +27/−0
- hscrtmpl.cabal +41/−21
- hscrtmpl.hs +36/−11
- package.yaml +0/−39
- stack.yaml +1/−1
.gitignore view
@@ -1,5 +1,3 @@ # stack build artifacts .stack-work/--# Using hpack, we don't store cabal files-*.cabal+stack.yaml.lock
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2013-2018, Dino Morelli <dino@ui3.info>+Copyright (c) 2013, Dino Morelli <dino@ui3.info> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided
README.md view
@@ -3,19 +3,19 @@ ## Synopsis -Haskell shell script template (Haskell)+Haskell shell script templates (Haskell) ## Description -A template for writing shell scripts in Haskell. Contains some-useful functions and examples of things commonly done in bash.+Templates for writing shell scripts in Haskell. Includes some useful functions+and examples of things commonly done in bash. And an example of using+optparse-applicative in a shell script. ## Getting source - Download the cabalized source package [from Hackage](http://hackage.haskell.org/package/hscrtmpl)-- Get the source with darcs: `$ git clone https://github.com/dino-/hscrtmpl.git` - Get the source with stack: `$ stack unpack hscrtmpl` - If you're just looking, [browse the source](https://github.com/dino-/hscrtmpl)
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
+ args-example.hs view
@@ -0,0 +1,101 @@+#! /usr/bin/env stack+-- stack runghc --package ansi-wl-pprint --package heredoc --package optparse-applicative+{-# LANGUAGE QuasiQuotes #-}++-- If you need a specific resolver, do this:+-- stack --resolver lts-16.11 runghc --package ...++{-+ This is a 'skeleton file' for writing shell scripts with Haskell that have+ sophisticated arg parsing with optparse-applicative.++ The idea here is to take a copy of this script and hack it to do what you+ need quickly. Throw the rest out.++ For more examples of doing common shell tasks, see the hscrtmpl.hs script+ also in this project.+++ Dino Morelli <dino@ui3.info>+ https://github.com/dino-/hscrtmpl+ version: 2.0 2023-06-27+-}++import Options.Applicative+import System.Environment ( getProgName )+import Text.Heredoc ( here )+import Text.PrettyPrint.ANSI.Leijen ( string )+import Text.Printf ( printf )+++main :: IO ()+main = do+ opts <- parseOpts+ print opts+++data Verbosity = Normal | Verbose+ deriving Show -- For debugging, possibly not needed++data Options = Options+ { optSwitch :: Bool+ , optMaybeString :: Maybe String+ , optFlag :: Verbosity+ , optString :: String+ , optArgument :: String+ , optArguments :: [String]+ }+ deriving Show -- For debugging, possibly not needed+++parseOpts :: IO Options+parseOpts = do+ pn <- getProgName+ execParser $ info (parser <**> helper)+ ( header (printf "%s - Argument parsing demo script" pn)+ <> footer'+ )+++-- For more help on building parsers: https://github.com/pcapriotti/optparse-applicative+parser :: Parser Options+parser = Options+ <$> ( switch+ ( long "switch" <> short 's'+ <> help "A switch option"+ )+ )+ <*> ( optional $ strOption+ ( long "maybe-string" <> short 'm' <> metavar "STRING"+ <> help "An optional string option"+ )+ )+ <*> ( flag Normal Verbose+ ( long "verbose" <> short 'v'+ <> help "A flag option"+ )+ )+ <*> ( strOption+ ( long "string" <> short 'S' <> metavar "STRING"+ <> help "A required string option"+ )+ )+ <*> ( argument str+ ( metavar "DIR"+ <> help "A required single argument"+ )+ )+ <*> some ( argument str+ ( metavar "FILES..."+ <> help "Multiple arguments, one or more required"+ )+ )+++footer' :: InfoMod a+footer' = footerDoc . Just $ string content+ where content = [here|OVERVIEW++Put more info here about what this script is for and how it works++v2.0 2023-06-27 Dino Morelli <dino@ui3.info>|]
changelog.md view
@@ -1,3 +1,30 @@+2.0 (2023-06-28)++ * Wrote a new args-example script+ * Added a note about specifying the Stackage resolver+ * Switched to modern cabal file instead of hpack+ * Moved Stackage resolver up to 16.11 (ghc 8.8.3)+ * Removed Setup.hs+ * Added example of custom error message with lookupEnv+ * Removed instructions for darcs+ * Removed later copyright date+ * Reorganized the functions in args-example.hs+ * Updated cabal file and README to reflect multiple scripts+++1.8 (2021-09-05)++ * Moved copyright up to 2021+ * Added stack.yaml.lock to .gitignore+ * Replace forSystem function+++1.7 (2019-08-22)++ * Added sequence expression example+ * Replaced a case statement with an if++ 1.6 (2018-10-03) * Moved copyright date up to 2018
hscrtmpl.cabal view
@@ -1,43 +1,63 @@--- This file has been generated from package.yaml by hpack version 0.28.2.------ see: https://github.com/sol/hpack------ hash: 94422872b0ab311808f7510b45c6c5bb31ee6db2edcd9e2d75de1aa77c28bb29+cabal-version: 2.2 name: hscrtmpl-version: 1.6-synopsis: Haskell shell script template-description: A template for writing shell scripts in Haskell. Contains some useful functions and examples of things commonly done in bash.+version: 2.0+synopsis: Haskell shell script templates+description: Templates for writing shell scripts in Haskell. Includes some useful functions and examples of things commonly done in bash. And an example of using optparse-applicative in a shell script. category: Application, Console, Scripting homepage: https://github.com/dino-/hscrtmpl#readme bug-reports: https://github.com/dino-/hscrtmpl/issues author: Dino Morelli-maintainer: dino@ui3.info-copyright: 2018 Dino Morelli+maintainer: Dino Morelli <dino@ui3.info>+copyright: 2013 Dino Morelli license: ISC license-file: LICENSE build-type: Simple-cabal-version: >= 1.10 extra-source-files:- .gitignore- changelog.md- package.yaml- README.md- stack.yaml+ changelog.md+ .gitignore+ README.md+ stack.yaml source-repository head type: git location: https://github.com/dino-/hscrtmpl +-- Hey! These source files are *scripts*, you don't have to build them unless+-- you want to have a binary!++common lang+ default-language: Haskell2010+ other-modules:+ Paths_hscrtmpl+ autogen-modules:+ Paths_hscrtmpl+ build-depends:+ process+ ghc-options:+ -fwarn-tabs+ -Wall+ -Wcompat+ -Wincomplete-record-updates+ -Wincomplete-uni-patterns+ -Wredundant-constraints+ executable hscrtmpl+ import: lang main-is: hscrtmpl.hs- other-modules:- Paths_hscrtmpl- ghc-options: -fwarn-tabs -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints build-depends: base >=3 && <5 , directory , filepath- , process+ -- , regex-compat , time- default-language: Haskell2010+ -- , time-locale-compat++executable args-example+ import: lang+ main-is: args-example.hs+ build-depends:+ base >=3 && <5+ , ansi-wl-pprint+ , heredoc+ , optparse-applicative
hscrtmpl.hs view
@@ -1,6 +1,9 @@ #! /usr/bin/env stack {- stack runghc -} +-- If you need a specific resolver, do this:+-- stack --resolver lts-7.8 runghc+ {- No stack? Use this #! instead of the two lines above: #! /usr/bin/env runhaskell -}@@ -25,10 +28,12 @@ Dino Morelli <dino@ui3.info> https://github.com/dino-/hscrtmpl- version: 1.6+ version: 2.0 2023-06-27 -} import Control.Monad+import Data.List+import Data.Maybe import Data.Time import Data.Time.Format ( defaultTimeLocale ) -- Or use time-locale-compat for backwards compatibility with GHC < 7.10@@ -70,8 +75,21 @@ -- environment variables (System.Environment)++ -- This will exit with a message and failure code if the variable doesn't exist! putStrLn =<< getEnv "SHELL" -- echo $SHELL + -- To handle unset variables, use lookupEnv :: String -> IO (Maybe String)++ -- someValue <- maybe someValue="${SOMEVAR:?Error: SOMEVAR not set}"+ -- (die "Error: SOMEVAR is not set")+ -- pure =<< lookupEnv "SOMEVAR"++ someValue <- fromMaybe "default value" -- someValue="${SOMEVAR:-default value}"+ <$> lookupEnv "SOMEVAR"+ putStrLn someValue++ -- arguments (System.Environment) --(arg1 : arg2 : _) <- getArgs -- arg1=$1 ; arg2=$2 @@ -79,6 +97,9 @@ printf "The %s is %d\n" -- S="answer" ; D=42 "answer" (42::Int) -- echo "The $S is $D" + -- sequence expressions+ -- [1..10] -- {1..10}+ -- execution, exit code (System.Process) ec <- system "ls -l" -- ls -l print ec -- echo $?@@ -147,14 +168,18 @@ exitBool = exitWith . toExitCode -{- This is similar to the for/in/do/done construct in bash with an- important difference. This action evaluates to ExitFailure 1 if- *any* of the command executions fails. In bash you only get the- exit code of the last one.+{- This is similar to the for/in/do/done construct in bash with an important+ difference. This action evaluates to the "worst" exit code of all IO actions+ that are passed after they are evaluated. -}-forSystem :: [String] -> IO ExitCode-forSystem cs = do- ecs <- mapM system cs- return $ case all (== ExitSuccess) ecs of- True -> ExitSuccess- False -> ExitFailure 1+sequenceWorstEC :: [IO ExitCode] -> IO ExitCode+sequenceWorstEC as =+ fromMaybe ExitSuccess . listToMaybe . reverse . sort <$> sequence as+++{- This is similar to the for/in/do/done construct in bash with an important+ difference. This action evaluates to the "worst" exit code of all shell+ commands that are passed after they are evaluated.+-}+systemWorstEC :: [String] -> IO ExitCode+systemWorstEC = sequenceWorstEC . map system
− package.yaml
@@ -1,39 +0,0 @@-name: hscrtmpl-version: '1.6'-synopsis: Haskell shell script template-description: A template for writing shell scripts in Haskell. Contains some useful functions and examples of things commonly done in bash.-license: ISC-author: Dino Morelli-maintainer: dino@ui3.info-copyright: 2018 Dino Morelli-category: Application, Console, Scripting-extra-source-files:-- changelog.md-- .gitignore-- README.md-- package.yaml-- stack.yaml--github: dino-/hscrtmpl--ghc-options:-- -fwarn-tabs-- -Wall-- -Wcompat-- -Wincomplete-record-updates-- -Wincomplete-uni-patterns-- -Wredundant-constraints--# Hey! hscrtmpl.hs is a *script*, you don't have to build it unless-# you want to have a binary!-executables:- hscrtmpl:- main: hscrtmpl.hs- dependencies:- - base >=3 && <5- - directory- - filepath- - process- # - regex-compat- - time- # - time-locale-compat
stack.yaml view
@@ -1,4 +1,4 @@-resolver: lts-12.11+resolver: lts-16.11 packages: - '.'