make-package (empty) → 1.0.0
raw patch · 16 files changed
+665/−0 lines, 16 filesdep +asyncdep +basedep +bytestringsetup-changed
Dependencies added: async, base, bytestring, configurator, containers, directory, filepath, github, haskeline, mtl, process, text, time, time-lens
Files
- LICENSE +31/−0
- Setup.hs +2/−0
- files/Main.hs +9/−0
- files/Package.hs +3/−0
- files/README.md +4/−0
- files/Setup.hs +2/−0
- files/dot-gitignore +9/−0
- files/licenses/BSD3.license +24/−0
- files/licenses/MIT.license +19/−0
- files/package.cabal +24/−0
- make-package.cabal +44/−0
- make-package.conf +49/−0
- src/Github.hs +82/−0
- src/IO.hs +203/−0
- src/Main.hs +77/−0
- src/Options.hs +83/−0
+ LICENSE view
@@ -0,0 +1,31 @@+Copyright (c) 2013, Chris Done+Copyright (c) 2013, Philipp Balzarek++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Chris Done nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ files/Main.hs view
@@ -0,0 +1,9 @@+-- | Main entry point to $name.+--+-- $desc++module Main where++-- | Main entry point.+main :: IO ()+main = return ()
+ files/Package.hs view
@@ -0,0 +1,3 @@+-- | $desc++module $exposed where
+ files/README.md view
@@ -0,0 +1,4 @@+$name+=====++$desc
+ files/Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ files/dot-gitignore view
@@ -0,0 +1,9 @@+*.o+*.hi+*~+dist/+cabal-dev/+.hsenv+TAGS+tags+*.tag
+ files/licenses/BSD3.license view
@@ -0,0 +1,24 @@+Copyright (c) $year, $name+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:+ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+ * Neither the name of $name nor the+ names of its contributors may be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ files/licenses/MIT.license view
@@ -0,0 +1,19 @@+Copyright (c) $year $name++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ files/package.cabal view
@@ -0,0 +1,24 @@+name: $name+version: 0.0.0+synopsis: $desc+description: $desc+license: BSD3+license-file: LICENSE+author: $author+maintainer: $email+copyright: $year $author+category: $category+build-type: Simple+cabal-version: >=1.8++library+ hs-source-dirs: src/+ ghc-options: -Wall -O2+ exposed-modules: $exposed+ build-depends: base >= 4 && <5++executable $name+ hs-source-dirs: src/+ ghc-options: -Wall -O2+ main-is: Main.hs+ build-depends: base >= 4 && < 5
+ make-package.cabal view
@@ -0,0 +1,44 @@+name: make-package+version: 1.0.0+synopsis: Make a cabalized package+description: Create a cabalized haskell project+license: BSD3+license-file: LICENSE+copyright: Chris Done, Philipp Balzarek+author: Philipp Balzarek+maintainer: p.balzarek@googlemail.com+category: Development, Utils+homepage: https://github.com/Philonous/make-package+Bug-Reports: https://github.com/Philonous/make-package/issues/+build-type: Simple+cabal-version: >=1.8+data-files: files/package.cabal+ files/licenses/*.license+ files/Setup.hs+ files/dot-gitignore+ files/Main.hs+ files/README.md+ files/Package.hs+extra-source-files: make-package.conf++executable make-package+ hs-source-dirs: src+ main-is: Main.hs+ other-modules: Github+ , IO+ , Options+ build-depends: base >= 4 && < 5,+ async,+ bytestring,+ configurator,+ containers,+ directory,+ filepath,+ github,+ haskeline,+ mtl,+ process,+ text,+ time,+ time-lens+ ghc-options: -Wall
+ make-package.conf view
@@ -0,0 +1,49 @@+# Hashes turn the rest of the line into a comment+## lines after double hashes describe the following field++defaults{+## Default license+# license = "MIT"++## Name of the author. Will be taken from git or prompted for if unset+# author = "Igor Schmaltzhering"++## Email of the author. Will be taken from git or prompted for if unset+# email = "no@spam.please"+}++git{+ enable = true++## Commit after copying templates+ do-commit = true++## Message to use for the initial commit (default is "initial commit")+# initial-commit-message = "initial commit"+}++github{+## Enable Github interaction (Default = true)+# enable = true++## Github username+# username = "ISchmaltz"++## Time to wait before aborting github interactions (default is 5 seconds)+# timeout = 5 # seconds++## Never try to clone an existing repository (default is false)+# never-clone = false++## Never try to create github repository (default is false)+# never-create = false++ auth {+## Github oauth string. Will be used when both the oauth string and the password+## are set+# oauth = "<secret>"++# Github password+# password = "<secret>"+ }+}
+ src/Github.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}++module Github where++import Control.Applicative ((<$>))+import Control.Monad+import Control.Monad.Trans+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Github.Repos+import System.Exit (exitSuccess)+import System.Timeout++import IO++-- | Check whether a repository with the given name exists on the users github+-- accoutn and suggest cloning it+maybeClone :: T.Text -> T.Text -> MakePackage ()+maybeClone repo dir = unlessConf "github.enable" (== False) $+ unlessConf "github.never-clone" (== True) $ do+ uname <- confOrPrompt "github.username" "Github Username" ""+ liftIO $ putStrLn "Checking github for preexisting repos"+ timeoutDelay <- toSeconds <$> confLookup "github.timeout"+ mbRepoUrl <- liftIO . timeout timeoutDelay $ getRepo uname+ case mbRepoUrl of+ Nothing -> return ()+ Just (Left _) -> return ()+ Just (Right rUrl) ->+ do cloneP <- promptYesNo "clone"+ "A repository with this name already exists\+ \in your github account. Clone it instead?"+ when cloneP $ do run "git" ["clone", rUrl, T.unpack dir]+ liftIO exitSuccess+ where+ toSeconds Nothing = 5 * 10^(6::Int)+ toSeconds (Just t) = t * 10^(6::Int)+ getRepo uname = fmap repoSshUrl <$> userRepo (T.unpack uname) (T.unpack repo)++-- | Create a github repository in the users account and set it as origin if+-- permitted by configuration+handleGithub :: T.Text -> T.Text -> MakePackage ()+handleGithub repo description = unlessConf "github.enable" (== False) $+ unlessConf "github.never-create" (== True) $+ unlessEmptyPrompt "repository" $ \rName -> do+ auth <- confLookup "github.auth.oauth" >>= \case+ Just oauth -> return $ GithubOAuth oauth+ Nothing -> do uname <- confOrPrompt "github.username" "Github Username" ""+ pwd <- confOrPrompt "github.auth.password"+ "Github Password"+ ""+ return $ GithubBasicAuth (T.encodeUtf8 uname)+ (T.encodeUtf8 pwd)+ let nRepo = NewRepo { newRepoName = T.unpack rName+ , newRepoDescription = Just (T.unpack description)+ , newRepoHomepage = Nothing+ , newRepoPrivate = Nothing+ , newRepoHasIssues = Nothing+ , newRepoHasWiki = Nothing+ , newRepoAutoInit = Nothing }+ liftIO $ putStrLn "Creating github repository"+ mbRepo <- liftIO $ createRepo auth nRepo+ case mbRepo of+ Left e -> do liftIO $ putStrLn $ "An Error occured while trying to create the repository:" ++ show e+ Right r -> do liftIO $ putStrLn "Done."+ liftIO $ putStrLn "Configuring git to track the new repository"+ run "git" ["remote", "add", "origin", repoSshUrl r]+ run "git" ["config", "branch.master.remote", "origin"]+ run "git" [ "config"+ , "branch.master.merge"+ , "refs/heads/master"]+ liftIO $ putStrLn "Done."+ whenConf "git.do-commit" (== True) $ run "git" [ "push"+ , "origin"+ , "master"]+ where+ unlessEmptyPrompt c f =+ do line <- prompt c "Repo Name (blank to skip)> " repo+ if T.null line+ then return ()+ else f line
+ src/IO.hs view
@@ -0,0 +1,203 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE LambdaCase #-}++module IO where++import Control.Applicative ((<$>))+import Control.Monad.Reader+import Control.Monad.State+import Data.Char (isSpace)+import qualified Data.Configurator as Conf+import qualified Data.Configurator.Types as Conf+import Data.List (isPrefixOf, isSuffixOf)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Maybe (fromMaybe)+import Data.Monoid+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import System.Console.Haskeline as HL+import System.Console.Haskeline.MonadException()+import System.Directory+import System.Exit+import System.FilePath+import System.Process++import Paths_make_package++newtype MakePackage a = MP {unConf :: StateT (Map Text Text)+ (ReaderT Conf.Config IO)+ a}+ deriving (Monad, MonadIO, Functor)++withConfig :: MakePackage a -> IO a+withConfig (MP f) = do conf <- loadConfig+ fst <$> (runReaderT (runStateT f (Map.empty)) conf)+++stored :: Conf.Configured a =>+ Text+ -> MakePackage (Maybe a)+stored c =+ do cache <- MP get+ return $ Conf.convert . Conf.String =<< Map.lookup c cache++optionDefault :: Conf.Configured b => Text -> b -> MakePackage b+optionDefault o d = fromMaybe d `fmap` stored o++confLookup :: Conf.Configured a => Conf.Name -> MakePackage (Maybe a)+confLookup c = stored c >>= \case+ Just x -> return $ Just x+ Nothing -> liftIO . (`Conf.lookup` c) =<< MP ask++confLookupDefault :: Conf.Configured a => Conf.Name -> a -> MakePackage a+confLookupDefault c d = maybe d id <$> confLookup c++-- | Prompt user+prompt :: T.Text -> T.Text -> Text -> MakePackage T.Text+prompt c p il = stored c >>= \case+ Just x -> return x+ Nothing ->+ do ln <- liftIO $ runInputT defaultSettings $+ HL.getInputLineWithInitial (T.unpack $ p <> "> ")+ (T.unpack il, "")+ case ln of+ Nothing -> liftIO exitFailure+ Just line ->+ do setOption c (T.pack line)+ return (T.pack line)++promptYesNo :: T.Text -> T.Text -> MakePackage Bool+promptYesNo c p = stored c >>= \case+ Just x -> return x+ Nothing -> do liftIO $ T.putStrLn p+ res <- liftIO $ runInputT defaultSettings go+ setOption c (if res then "true" else "false")+ return res+ where+ go = do char <- getInputChar ("[y]yes or [n]o> ")+ case char of+ Nothing -> liftIO exitFailure+ Just 'y' -> return True+ Just 'Y' -> return True+ Just 'n' -> return False+ Just 'N' -> return False+ _ -> go+++setOption :: Text -> Text -> MakePackage ()+setOption c x = MP $ modify (Map.insert c x)++-- | Get option from configuration file or prompt user+confOrPrompt :: T.Text -> T.Text -> T.Text -> MakePackage T.Text+confOrPrompt c p i = confLookup c >>= \case+ Nothing -> prompt c p i+ Just x -> return x++-- | Get option from configuration file, git configuration or promp user+confOrGitOrPrompt :: T.Text -> T.Text -> T.Text -> T.Text -> MakePackage T.Text+confOrGitOrPrompt c gitQ p i = confLookup c >>= \case+ Just x -> return x+ Nothing -> confLookup "git.enable" >>= \case+ Just True -> queryGit (T.unpack gitQ) >>= \case+ Just x -> do setOption c x+ return x+ Nothing -> do x <- prompt c p i+ setOption c x+ return x+ _ -> do x <- prompt c p i+ setOption c x+ return x++-- | Get license from configuration or prompt+getLicense :: MakePackage T.Text+getLicense = do+ licensesDir <- liftIO $ dataFile "licenses"+ licenses <- map takeBaseName . filter (".license" `isSuffixOf` ) <$>+ liftIO (getDirectoryContents licensesDir)+ defaultLicense <- confLookup "defaults.license" >>= \case+ Nothing -> return Nothing+ Just l -> if (l `elem` licenses)+ then return . Just $ T.pack l+ else do liftIO . putStrLn $+ "Warning, configured default license \""+ ++ l ++ "\" is unknown"+ return Nothing+ case defaultLicense of+ Just l -> return l+ Nothing -> T.pack <$> selectFrom "license" licenses++-- | Query git configuration+queryGit :: String -> MakePackage (Maybe T.Text)+queryGit q = liftIO (readProcessWithExitCode "git" ["config","--get", q] "")+ >>= \case+ (ExitSuccess, res, _stderr) -> return . Just $ oneLine res+ _ -> return Nothing+ where+ oneLine = T.concat . take 1 . T.lines . T.pack++-- | Run a programm, exit with error when program returns failure code+run :: String -> [String] -> MakePackage ()+run pg args = liftIO $ rawSystem pg args >>= \case+ ExitSuccess -> return ()+ ExitFailure n -> do+ putStrLn $ "Program " ++ show pg+ ++ " exited with error code " ++ show n+ exitFailure++-- | Get the file path of packaged file+dataFile :: String -> IO String+dataFile fp = getDataFileName ("files/" <> fp)++-- | Load the configuration files+loadConfig :: IO Conf.Config+loadConfig = do+ appData <- getAppUserDataDirectory "make-package"+ home <- getHomeDirectory+ Conf.load [ Conf.Optional $ appData </> "make-package.conf"+ , Conf.Optional $ home </> ".make-package.conf"+ ]++-- | Run action unless configuration option is set and predicate is true+unlessConf :: Conf.Configured a => Conf.Name+ -> (a -> Bool)+ -> MakePackage ()+ -> MakePackage ()+unlessConf option p f = confLookup option >>= \case+ Just x | p x -> return ()+ _ -> f++-- | Run action when configuration option is set and predicate is true+whenConf :: Conf.Configured a => Conf.Name+ -> (a -> Bool)+ -> MakePackage ()+ -> MakePackage ()+whenConf option p f = confLookup option >>= \case+ Just x | p x -> f+ _ -> return ()++-- | Let the user select a string from a list+selectFrom :: String -> [String] -> MakePackage String+selectFrom p xs = liftIO $ do+ runInputT (setComplete cf defaultSettings) (HL.outputStrLn options >> go)+ where+ pairs = zip (map show [1:: Int ..]) xs+ options = unlines $ map (\(l,r) -> l <> ") " <> r ) pairs+ cf = completeWord Nothing " "+ (\wd -> return $ simpleCompletion <$> filter (wd `isPrefixOf`) xs)+ go = do+ mbln <- HL.getInputLine (p <> "> ")+ ln <- case mbln of+ Nothing -> liftIO exitFailure+ Just ln -> return . strip $ ln+ if | ln `elem` xs -> return ln+ | Just line <- ln `lookup` pairs -> return line+ | "?" <- ln -> HL.outputStrLn options >> go+ | otherwise -> do+ HL.outputStrLn $ ln ++ " is not valid, type ? to show options"+ go+ strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace
+ src/Main.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Main entry point.++module Main where++import IO+import Github+import Options++import Control.Monad (when)+import Control.Monad.Trans (liftIO)+import Data.Monoid+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Data.Time+import Data.Time.Lens+import System.Directory+import System.Exit (exitFailure)+import System.FilePath++-- import System.Process++-- | Main entry point.+main :: IO ()+main = withConfig $ do+ handleArgs+ packageName <- prompt "package" "Package Name" ""+ packageDir <- optionDefault "directory" packageName+ checkExists packageDir+ maybeClone packageName packageDir+ author <- confOrGitOrPrompt "defaults.author" "user.name" "Author" ""+ email <- confOrGitOrPrompt "defaults.email" "user.email" "Author Email" ""+ desc <- prompt "description" "Description" ""+ licenseType <- getLicense+ exposed <- prompt "modules" "Exposed Module(s)" "Main"+ category <- prompt "categories" "Category(s)" ""+ now <- liftIO getCurrentTime+ liftIO $ do createDirectoryIfMissing False (T.unpack packageName)+ setCurrentDirectory (T.unpack packageName)+ createDirectoryIfMissing False ("src/")+ let substitutions = [("name" ,packageName)+ ,("desc" ,desc)+ ,("email" ,email)+ ,("author" ,author)+ ,("year" ,T.pack (show (getL year now)))+ ,("category" ,category)+ ,("exposed" ,exposed)+ ,("license" ,licenseType)]+ copyTemplate = doCopyTemplate substitutions+ copyTemplate "package.cabal" (T.unpack (packageName <> ".cabal"))+ copyTemplate "dot-gitignore" ".gitignore"+ copyTemplate "Setup.hs" "Setup.hs"+ copyTemplate ("licenses"</> T.unpack licenseType <.> "license") "LICENSE"+ copyTemplate "README.md" "README.md"+ copyTemplate "Main.hs" "src/Main.hs"+ copyTemplate "Package.hs" (T.unpack ("src/" <> exposed <> ".hs"))+ run "cabal" ["configure"]+ unlessConf "git.enable" (== False) $ do+ run "git" ["init"]+ run "git" ["add", "."]+ whenConf "git.do-commit" (== True) $ do+ msg <- confLookupDefault "git.initial-commit-message" "initial commit"+ run "git" ["commit", "-m", msg]+ handleGithub packageName desc+ where+ checkExists pname = liftIO $+ do fileExists <- doesFileExist (T.unpack pname)+ dirExists <- doesDirectoryExist (T.unpack pname)+ when (fileExists || dirExists) $+ do putStrLn "A file or directory with this name already exists. Bailing out"+ exitFailure++ doCopyTemplate substitutions infile outfile = liftIO $+ do template <- dataFile infile >>= T.readFile+ T.writeFile outfile (substitute template substitutions)+ substitute = foldl (\str (this,that) -> T.replace ("$" <> this) that str)
+ src/Options.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE OverloadedStrings #-}++module Options where++import Control.Monad+import Control.Monad.Trans+import qualified Data.Text as T+import System.Console.GetOpt+import System.Environment+import System.Exit (exitSuccess, exitFailure)++import IO++setOpt :: T.Text -> String -> ArgDescr (MakePackage ())+setOpt o = ReqArg (setOption o . T.pack)++options :: [OptDescr (MakePackage ())]+options = [ Option "h" ["help"] (NoArg $ help [])+ "display this help text"+ , Option "P" ["package"] (setOpt "package" "string")+ "package name"+ , Option "d" ["dir"] (setOpt "directory" "string")+ "directory to initialize in (default = package name)"+ , Option "A" ["author"] (setOpt "defaults.author" "string")+ "package author"+ , Option "E" ["email"] (setOpt "defaults.email" "string")+ "package author email address"+ , Option "D" ["description"] (setOpt "description" "string")+ "package description"+ , Option "L" ["license"] (setOpt "defaults.license" "string")+ "license name"+ , Option "M" ["modules"] (setOpt "modules" "string")+ "exposed modules"+ , Option "H" ["categories"] (setOpt "categories" "string")+ "hackage categories"+ , Option "G" ["git"] (NoArg $ setOption "git.enable" "true")+ "enable git"+ , Option "g" ["no-git"] (NoArg $ setOption "git.enable" "false")+ "disable git"+ , Option "C" ["commit"] (NoArg $ setOption "git.do-commit" "true")+ "run git commit"+ , Option "c" ["no-commit"] (NoArg $ setOption "git.do-commit" "false")+ "don't run git commit"+ , Option "M" ["commit-message"] (setOpt "git.initial-commit-message"+ "string")+ "commit message to use"+ , Option "G" ["github"] (NoArg $ setOption "github.enable" "true")+ "enable github integration"+ , Option "g" ["no-github"] (NoArg $ setOption "github.enable" "false")+ "disable github integration"+ , Option "U" ["username"] (setOpt "github.username" "string")+ "github username"+ , Option "R" ["repository"] (setOpt "github.repository" "string")+ "github repository to create"+ , Option "T" ["timeout"] (setOpt "github.timeout" "int")+ "timeout for github interactions in seconds"+ , Option "K" ["clone"] (NoArg $ setOption "clone" "true")+ "clone existing repository "+ , Option "k" ["no-clone"] (NoArg $ setOption "clone" "false")+ "don't clone existing repository "+ , Option "O" ["oauth"] (setOpt "github.auth.oauth" "string")+ "github oauth token"+ , Option "P" ["password"] (setOpt "github.auth.password" "string")+ "github password"+ ]++help :: MonadIO m => [String] -> m a+help errors = liftIO $+ do forM_ errors putStrLn+ putStrLn $ usageInfo "make-package [package-name] [options]" options+ if null errors+ then exitSuccess+ else exitFailure++handleArgs :: MakePackage ()+handleArgs =+ do args <- liftIO $ getArgs+ let (opts, _, errs) = getOpt (ReturnInOrder (setOption "package" . T.pack))+ options+ args+ unless (null errs) $ help errs+ sequence_ opts