From 62d2d588eef6d7e10567fb4a4adbf8cdd4a3f84a Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Mon, 16 Apr 2018 11:27:46 +0300 Subject: [PATCH 1/6] Include initial template (not rio-specific yet) --- etc/template/.gitignore | 5 ++++ etc/template/ChangeLog.md | 3 +++ etc/template/LICENSE | 30 ++++++++++++++++++++++++ etc/template/README.md | 1 + etc/template/Setup.hs | 2 ++ etc/template/app/Main.hs | 6 +++++ etc/template/package.yaml | 48 +++++++++++++++++++++++++++++++++++++++ etc/template/src/Lib.hs | 6 +++++ etc/template/test/Spec.hs | 1 + 9 files changed, 102 insertions(+) create mode 100644 etc/template/.gitignore create mode 100644 etc/template/ChangeLog.md create mode 100644 etc/template/LICENSE create mode 100644 etc/template/README.md create mode 100644 etc/template/Setup.hs create mode 100644 etc/template/app/Main.hs create mode 100644 etc/template/package.yaml create mode 100644 etc/template/src/Lib.hs create mode 100644 etc/template/test/Spec.hs diff --git a/etc/template/.gitignore b/etc/template/.gitignore new file mode 100644 index 0000000..0ff540a --- /dev/null +++ b/etc/template/.gitignore @@ -0,0 +1,5 @@ +*.cabal +*~ +*.swp +tarballs/ +.stack-work/ diff --git a/etc/template/ChangeLog.md b/etc/template/ChangeLog.md new file mode 100644 index 0000000..9d5f690 --- /dev/null +++ b/etc/template/ChangeLog.md @@ -0,0 +1,3 @@ +# Changelog for PROJECTNAME + +## Unreleased changes diff --git a/etc/template/LICENSE b/etc/template/LICENSE new file mode 100644 index 0000000..e037c72 --- /dev/null +++ b/etc/template/LICENSE @@ -0,0 +1,30 @@ +Copyright Author name here (c) 2018 + +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 Author name here 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. diff --git a/etc/template/README.md b/etc/template/README.md new file mode 100644 index 0000000..73560a0 --- /dev/null +++ b/etc/template/README.md @@ -0,0 +1 @@ +# PROJECTNAME diff --git a/etc/template/Setup.hs b/etc/template/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/etc/template/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/etc/template/app/Main.hs b/etc/template/app/Main.hs new file mode 100644 index 0000000..de1c1ab --- /dev/null +++ b/etc/template/app/Main.hs @@ -0,0 +1,6 @@ +module Main where + +import Lib + +main :: IO () +main = someFunc diff --git a/etc/template/package.yaml b/etc/template/package.yaml new file mode 100644 index 0000000..c7d4508 --- /dev/null +++ b/etc/template/package.yaml @@ -0,0 +1,48 @@ +name: PROJECTNAME +version: 0.1.0.0 +github: "githubuser/PROJECTNAME" +license: BSD3 +author: "Author name here" +maintainer: "example@example.com" +copyright: "2018 Author name here" + +extra-source-files: +- README.md +- ChangeLog.md + +# Metadata used when publishing your package +# synopsis: Short description of your package +# category: Web + +# To avoid duplicated efforts in documentation and dealing with the +# complications of embedding Haddock markup inside cabal files, it is +# common to point users to the README.md file. +description: Please see the README on Github at + +dependencies: +- base >= 4.7 && < 5 + +library: + source-dirs: src + +executables: + PROJECTNAME-exe: + main: Main.hs + source-dirs: app + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - PROJECTNAME + +tests: + PROJECTNAME-test: + main: Spec.hs + source-dirs: test + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - PROJECTNAME diff --git a/etc/template/src/Lib.hs b/etc/template/src/Lib.hs new file mode 100644 index 0000000..d36ff27 --- /dev/null +++ b/etc/template/src/Lib.hs @@ -0,0 +1,6 @@ +module Lib + ( someFunc + ) where + +someFunc :: IO () +someFunc = putStrLn "someFunc" diff --git a/etc/template/test/Spec.hs b/etc/template/test/Spec.hs new file mode 100644 index 0000000..a824f8c --- /dev/null +++ b/etc/template/test/Spec.hs @@ -0,0 +1 @@ +{-# OPTIONS_GHC -F -pgmF hspec-discover #-} From 3602cfc02f92aa0ed45ec99f651858b3aa285ad0 Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Mon, 16 Apr 2018 11:28:59 +0300 Subject: [PATCH 2/6] Add the make-template.hs script --- etc/.gitignore | 1 + etc/make-template.hs | 61 ++++++++++++++++++++++++++++++++++++++++++++ etc/stack.yaml | 5 ++++ 3 files changed, 67 insertions(+) create mode 100644 etc/.gitignore create mode 100755 etc/make-template.hs create mode 100644 etc/stack.yaml diff --git a/etc/.gitignore b/etc/.gitignore new file mode 100644 index 0000000..1f96b46 --- /dev/null +++ b/etc/.gitignore @@ -0,0 +1 @@ +/rio.hsfiles diff --git a/etc/make-template.hs b/etc/make-template.hs new file mode 100755 index 0000000..0fa5637 --- /dev/null +++ b/etc/make-template.hs @@ -0,0 +1,61 @@ +#!/usr/bin/env stack +{- stack runghc + --package rio + --package conduit + --package project-template + -- -hide-all-packages +-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +import Conduit +import RIO +import qualified RIO.ByteString as B +import qualified RIO.ByteString.Lazy as BL +import RIO.FilePath +import RIO.Process +import qualified RIO.Text as T +import Text.ProjectTemplate + +data App = App + { appLogFunc :: !LogFunc + , appProcessContext :: !ProcessContext + } + +instance HasLogFunc App where + logFuncL = lens appLogFunc (\x y -> x { appLogFunc = y }) +instance HasProcessContext App where + processContextL = lens appProcessContext (\x y -> x { appProcessContext = y }) + +start :: RIO App a -> IO a +start inner = do + appProcessContext <- mkDefaultProcessContext + lo <- logOptionsHandle stderr True + withLogFunc lo $ \appLogFunc -> runRIO App {..} inner + +splitNulls :: ByteString -> [ByteString] +splitNulls bs + | B.null bs = [] + | otherwise = + let (x, y) = B.break (== 0) bs + in x : splitNulls (B.drop 1 y) + +decode :: ByteString -> RIO App FilePath +decode bs = + case decodeUtf8' bs of + Left e -> throwIO e + Right x -> return $ T.unpack x + +main :: IO () +main = start $ do + let templatedir = "template" + + -- Make sure it passes + proc "stack" ["test"] runProcess_ + + rawout <- withWorkingDir templatedir + $ proc "git" ["ls-files", "-z"] + readProcessStdout_ + files <- mapM decode $ splitNulls $ BL.toStrict rawout + let src = forM_ files $ \fp -> yield (fp, readFileBinary $ templatedir fp) + runConduitRes $ src .| createTemplate .| sinkFile "rio.hsfiles" diff --git a/etc/stack.yaml b/etc/stack.yaml new file mode 100644 index 0000000..cf0cc86 --- /dev/null +++ b/etc/stack.yaml @@ -0,0 +1,5 @@ +resolver: lts-11.5 +packages: +- template +extra-deps: +- ../rio From 9d18839b0b55d6f945469fedf6a32e9182ddb59e Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Mon, 16 Apr 2018 11:42:49 +0300 Subject: [PATCH 3/6] Variable replacement --- etc/make-template.hs | 20 ++++++++++++++++++++ etc/template/package.yaml | 10 +++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/etc/make-template.hs b/etc/make-template.hs index 0fa5637..f416230 100755 --- a/etc/make-template.hs +++ b/etc/make-template.hs @@ -15,6 +15,8 @@ import qualified RIO.ByteString.Lazy as BL import RIO.FilePath import RIO.Process import qualified RIO.Text as T +import qualified RIO.Text.Partial as T (replace) +import RIO.Time import Text.ProjectTemplate data App = App @@ -46,6 +48,24 @@ decode bs = Left e -> throwIO e Right x -> return $ T.unpack x +readReplace :: MonadIO m => FilePath -> m ByteString +readReplace fp = do + (year, _, _) <- toGregorian . utctDay <$> getCurrentTime + (encodeUtf8 . replaces year) <$> readFileUtf8 fp + where + replaces year + = T.replace "PROJECTNAME" "{{name}}" + . T.replace "AUTHOR" "{{author-name}}{{^author-name}}Author name here{{/author-name}}" + . T.replace "MAINTAINER" "{{author-email}}{{^author-email}}example@example.com{{/author-email}}" + . T.replace "GITHUB" "{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}" + . T.replace "DESCRIPTION" "Please see the README on Github at " + . T.replace "COPYRIGHT" + (T.concat + [ "{{copyright}}{{^copyright}}{{year}}{{^year}}" + , T.pack $ show year + , "{{/year}} {{author-name}}{{^author-name}}Author name here{{/author-name}}{{/copyright}}" + ]) + main :: IO () main = start $ do let templatedir = "template" diff --git a/etc/template/package.yaml b/etc/template/package.yaml index c7d4508..3c99d06 100644 --- a/etc/template/package.yaml +++ b/etc/template/package.yaml @@ -1,10 +1,10 @@ name: PROJECTNAME version: 0.1.0.0 -github: "githubuser/PROJECTNAME" +github: GITHUB license: BSD3 -author: "Author name here" -maintainer: "example@example.com" -copyright: "2018 Author name here" +author: AUTHOR +maintainer: MAINTAINER +copyright: COPYRIGHT extra-source-files: - README.md @@ -17,7 +17,7 @@ extra-source-files: # To avoid duplicated efforts in documentation and dealing with the # complications of embedding Haddock markup inside cabal files, it is # common to point users to the README.md file. -description: Please see the README on Github at +description: DESCRIPTION dependencies: - base >= 4.7 && < 5 From f3dc9d1e6809e4546c43eae3088ac35a579d7e3a Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Mon, 16 Apr 2018 12:27:25 +0300 Subject: [PATCH 4/6] Improve the template --- etc/template/app/Main.hs | 32 +++++++++++++++++++++++++++++--- etc/template/package.yaml | 5 ++++- etc/template/src/Import.hs | 8 ++++++++ etc/template/src/Lib.hs | 6 ------ etc/template/src/Run.hs | 9 +++++++++ etc/template/src/Types.hs | 22 ++++++++++++++++++++++ etc/template/src/Util.hs | 11 +++++++++++ etc/template/test/UtilSpec.hs | 14 ++++++++++++++ 8 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 etc/template/src/Import.hs delete mode 100644 etc/template/src/Lib.hs create mode 100644 etc/template/src/Run.hs create mode 100644 etc/template/src/Types.hs create mode 100644 etc/template/src/Util.hs create mode 100644 etc/template/test/UtilSpec.hs diff --git a/etc/template/app/Main.hs b/etc/template/app/Main.hs index de1c1ab..f437c33 100644 --- a/etc/template/app/Main.hs +++ b/etc/template/app/Main.hs @@ -1,6 +1,32 @@ -module Main where +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE TemplateHaskell #-} +module Main (main) where -import Lib +import Import +import Run +import RIO.Process +import Options.Applicative.Simple +import qualified Paths_PROJECTNAME main :: IO () -main = someFunc +main = do + (options, ()) <- simpleOptions + $(simpleVersion Paths_PROJECTNAME.version) + "Header for command line arguments" + "Program description, also for command line arguments" + (Options + <$> switch ( long "verbose" + <> short 'v' + <> help "Verbose output?" + ) + ) + empty + lo <- logOptionsHandle stderr (optionsVerbose options) + pc <- mkDefaultProcessContext + withLogFunc lo $ \lf -> + let app = App + { appLogFunc = lf + , appProcessContext = pc + , appOptions = options + } + in runRIO app run diff --git a/etc/template/package.yaml b/etc/template/package.yaml index 3c99d06..e8ed121 100644 --- a/etc/template/package.yaml +++ b/etc/template/package.yaml @@ -20,7 +20,8 @@ extra-source-files: description: DESCRIPTION dependencies: -- base >= 4.7 && < 5 +- base >= 4.10 && < 5 +- rio >= 0.1.1.0 && < 0.2 library: source-dirs: src @@ -35,6 +36,7 @@ executables: - -with-rtsopts=-N dependencies: - PROJECTNAME + - optparse-simple tests: PROJECTNAME-test: @@ -46,3 +48,4 @@ tests: - -with-rtsopts=-N dependencies: - PROJECTNAME + - hspec diff --git a/etc/template/src/Import.hs b/etc/template/src/Import.hs new file mode 100644 index 0000000..13b66f1 --- /dev/null +++ b/etc/template/src/Import.hs @@ -0,0 +1,8 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module Import + ( module RIO + , module Types + ) where + +import RIO +import Types diff --git a/etc/template/src/Lib.hs b/etc/template/src/Lib.hs deleted file mode 100644 index d36ff27..0000000 --- a/etc/template/src/Lib.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Lib - ( someFunc - ) where - -someFunc :: IO () -someFunc = putStrLn "someFunc" diff --git a/etc/template/src/Run.hs b/etc/template/src/Run.hs new file mode 100644 index 0000000..60b9060 --- /dev/null +++ b/etc/template/src/Run.hs @@ -0,0 +1,9 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +module Run (run) where + +import Import + +run :: RIO App () +run = do + logInfo "We're inside the application!" diff --git a/etc/template/src/Types.hs b/etc/template/src/Types.hs new file mode 100644 index 0000000..355bff3 --- /dev/null +++ b/etc/template/src/Types.hs @@ -0,0 +1,22 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module Types where + +import RIO +import RIO.Process + +-- | Command line arguments +data Options = Options + { optionsVerbose :: !Bool + } + +data App = App + { appLogFunc :: !LogFunc + , appProcessContext :: !ProcessContext + , appOptions :: !Options + -- Add other app-specific configuration information here + } + +instance HasLogFunc App where + logFuncL = lens appLogFunc (\x y -> x { appLogFunc = y }) +instance HasProcessContext App where + processContextL = lens appProcessContext (\x y -> x { appProcessContext = y }) diff --git a/etc/template/src/Util.hs b/etc/template/src/Util.hs new file mode 100644 index 0000000..b950daa --- /dev/null +++ b/etc/template/src/Util.hs @@ -0,0 +1,11 @@ +{-# LANGUAGE NoImplicitPrelude #-} +-- | Silly utility module, used to demonstrate how to write a test +-- case. +module Util + ( plus2 + ) where + +import RIO + +plus2 :: Int -> Int +plus2 = (+ 2) diff --git a/etc/template/test/UtilSpec.hs b/etc/template/test/UtilSpec.hs new file mode 100644 index 0000000..d5bc4df --- /dev/null +++ b/etc/template/test/UtilSpec.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module UtilSpec (spec) where + +import Import +import Util +import Test.Hspec +import Test.Hspec.QuickCheck + +spec :: Spec +spec = do + describe "plus2" $ do + it "basic check" $ plus2 0 `shouldBe` 2 + it "overflow" $ plus2 maxBound `shouldBe` minBound + 1 + prop "minus 2" $ \i -> plus2 i - 2 `shouldBe` i From 7b8193fb921cabda9d1b7189fd1c0284dac6be1c Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Mon, 16 Apr 2018 13:52:23 +0300 Subject: [PATCH 5/6] Use AUTHOR (thanks @mgsloan) --- etc/template/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/template/LICENSE b/etc/template/LICENSE index e037c72..1e07d3d 100644 --- a/etc/template/LICENSE +++ b/etc/template/LICENSE @@ -1,4 +1,4 @@ -Copyright Author name here (c) 2018 +Copyright AUTHOR (c) 2018 All rights reserved. From c8a62f1f73e65e40c371b02bbd49af3824ecd991 Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Mon, 16 Apr 2018 20:05:32 +0300 Subject: [PATCH 6/6] Remove/relax upper bound (CC @roman) --- etc/template/package.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/template/package.yaml b/etc/template/package.yaml index e8ed121..1473a2c 100644 --- a/etc/template/package.yaml +++ b/etc/template/package.yaml @@ -20,8 +20,8 @@ extra-source-files: description: DESCRIPTION dependencies: -- base >= 4.10 && < 5 -- rio >= 0.1.1.0 && < 0.2 +- base >= 4.10 && < 10 +- rio >= 0.1.1.0 library: source-dirs: src