hsinstall 2.6 → 2.7
raw patch · 13 files changed
+406/−229 lines, 13 filesdep +exceptionsdep +newtype-genericsPVP ok
version bump matches the API change (PVP)
Dependencies added: exceptions, newtype-generics
API changes (from Hackage documentation)
Files
- CHANGELOG.md +128/−0
- changelog.md +0/−112
- hsinstall.cabal +6/−5
- package.yaml +4/−2
- src/app/HSInstall/AppImage.hs +32/−23
- src/app/HSInstall/Build.hs +64/−0
- src/app/HSInstall/Common.hs +21/−4
- src/app/HSInstall/DeploymentInfo.hs +53/−27
- src/app/HSInstall/Except.hs +11/−2
- src/app/HSInstall/Opts.hs +44/−20
- src/app/hsinstall.hs +38/−29
- stack.yaml +1/−1
- stack.yaml.lock +4/−4
+ CHANGELOG.md view
@@ -0,0 +1,128 @@+2.7 (2021-12-01)++ * Minor changes for some hlint suggestions+ * Changed how default prefix is constructed+ * Turned off stdout/stderr buffering+ * Support projects that build with either cabal or stack+ * Removed an unused import+ * Now forcing all cabal commands to be v2-+ * Using newtype wrappers for DeploymentInfo fields+ * Using Haskell core type Version for version+ * Removed shareDir and rsrcDir from DeploymentInfo+ * Now using newtype wrappers for all Options fields+ * Added more newtype wrappers around many data types+ * Applied hlint suggestions+++2.6 (2020-01-12)++ * Moved stack resolver up to lts-14.20+ * Switched from fmt library to Text.Printf+ * Try to force hpack cabal file creation if it's missing+ * Moved copyright date up to 2020+ * Fixed various problems in the README+++2.5 (2019-12-01)++ * Using an infoHelper for the --version switch+ * Moved Stackage snapshot up to lts-14.8+ * Updated usage to reflect the new template dir behavior+ * Changed lib/HSInstall/Resources.hs to Paths.hs+ * Added custom code for recursive file copying+ * Fixed bug with default prefix directory+ * Removed the --delete switch+ * Rolled EXE argument into --mk-appimage switch+ * Changed how resources and AppImage source files are handled+ * Added a handy tip about git clean+ * Removed code to force cabal file creation+++2.4 (2019-04-26)++ * Moved copyright date up to 2019+ * Separated code into more modules for clarity+ * Switched from GetOpt to optparse-applicative+ * Fixed API doc wording+ * Adjusted code with hlint's advice+ * Now trying to force stack/hpack to generate the cabal file if it's missing+ * Added app version number to AppImage filename+++2.3 (2019-03-03)++ * Changed deployment dir name to EXECUTABLE.AppDir+ * Switched all uses of Text.Printf to the Fmt library+ * Moved Stackage resolver up to lts-13.9+++2.2 (2018-11-07)++ * Added actual exception handling+ * Reworded usage and README text+++2.1 (2018-10-22)++ * Switched to a a lighter-weight here-document library+ * Updated API documentation+++2.0 (2018-10-22)++ * Redesigned as a binary utility to be installed on a system, not a script+ * Added AppImage creation feature+ * Got rid of "bundle" style deployment, it's all FHS now with a prefix+ * Removed old sample usage app+ * Moved stackage resolver up to lts-12.13+ * Moved copyright date up to 2018+++1.6 (2017-07-01)++ * Changed base lower bound from 4.9 to 4.8+ * Updated stack snapshot to lts-8.21+ * Added HCAR listing content+ * Removed defunct cabal stability field+ * Adjusted some documentation in the README+ * Moved copyright date up to 2017+++1.5 (2016-10-16)++ * Now creating bin directory prior to stack install+ * Removed comments from auto-generated stack.yaml+++1.4 (2016-10-11)++ * Added missing files to extra-source-files+ * Added switch for making a symlink to the app directory+++1.3 (2016-10-07)++ * Fixed error in docs+++1.2 (2016-10-07)++ * Added example additional script copying code+ * Updated developer instructions+ * Added a tested-with line to the cabal file+++1.1 (2016-10-03)++ * Updated to stackage lts-7.2+++1.0 (2016-10-03)++ * Cleaned up cabal file+ * Wrote API docs+ * Cleaned up README+ * Aborting the installation if `stack install` fails+ * Added instructions for compiling install.hs+ * Added library for locating resources at runtime+ * Initial release
− changelog.md
@@ -1,112 +0,0 @@-2.6 (2020-01-12)-- * Moved stack resolver up to lts-14.20- * Switched from fmt library to Text.Printf- * Try to force hpack cabal file creation if it's missing- * Moved copyright date up to 2020- * Fixed various problems in the README---2.5 (2019-12-01)-- * Using an infoHelper for the --version switch- * Moved Stackage snapshot up to lts-14.8- * Updated usage to reflect the new template dir behavior- * Changed lib/HSInstall/Resources.hs to Paths.hs- * Added custom code for recursive file copying- * Fixed bug with default prefix directory- * Removed the --delete switch- * Rolled EXE argument into --mk-appimage switch- * Changed how resources and AppImage source files are handled- * Added a handy tip about git clean- * Removed code to force cabal file creation---2.4 (2019-04-26)-- * Moved copyright date up to 2019- * Separated code into more modules for clarity- * Switched from GetOpt to optparse-applicative- * Fixed API doc wording- * Adjusted code with hlint's advice- * Now trying to force stack/hpack to generate the cabal file if it's missing- * Added app version number to AppImage filename---2.3 (2019-03-03)-- * Changed deployment dir name to EXECUTABLE.AppDir- * Switched all uses of Text.Printf to the Fmt library- * Moved Stackage resolver up to lts-13.9---2.2 (2018-11-07)-- * Added actual exception handling- * Reworded usage and README text---2.1 (2018-10-22)-- * Switched to a a lighter-weight here-document library- * Updated API documentation---2.0 (2018-10-22)-- * Redesigned as a binary utility to be installed on a system, not a script- * Added AppImage creation feature- * Got rid of "bundle" style deployment, it's all FHS now with a prefix- * Removed old sample usage app- * Moved stackage resolver up to lts-12.13- * Moved copyright date up to 2018---1.6 (2017-07-01)-- * Changed base lower bound from 4.9 to 4.8- * Updated stack snapshot to lts-8.21- * Added HCAR listing content- * Removed defunct cabal stability field- * Adjusted some documentation in the README- * Moved copyright date up to 2017---1.5 (2016-10-16)-- * Now creating bin directory prior to stack install- * Removed comments from auto-generated stack.yaml---1.4 (2016-10-11)-- * Added missing files to extra-source-files- * Added switch for making a symlink to the app directory---1.3 (2016-10-07)-- * Fixed error in docs---1.2 (2016-10-07)-- * Added example additional script copying code- * Updated developer instructions- * Added a tested-with line to the cabal file---1.1 (2016-10-03)-- * Updated to stackage lts-7.2---1.0 (2016-10-03)-- * Cleaned up cabal file- * Wrote API docs- * Cleaned up README- * Aborting the installation if `stack install` fails- * Added instructions for compiling install.hs- * Added library for locating resources at runtime- * Initial release
hsinstall.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.2.+-- This file has been generated from package.yaml by hpack version 0.34.4. -- -- see: https://github.com/sol/hpack------ hash: eaeb3c491f0d773e1e6a91540369700f5dd54203a30fe8e3e280500279513414 name: hsinstall-version: 2.6+version: 2.7 synopsis: Install Haskell software description: This is a tool for deploying software projects into directory structures suitable for installation on a system. It builds upon the `stack install` command and adds more features. It's also a tool for easier AppImage creation. category: Utility@@ -20,7 +18,7 @@ license-file: LICENSE build-type: Simple extra-source-files:- changelog.md+ CHANGELOG.md doc/hcar/hsinstall.tex .gitignore hsinstall/share/applications/hsinstall.desktop@@ -53,6 +51,7 @@ main-is: hsinstall.hs other-modules: HSInstall.AppImage+ HSInstall.Build HSInstall.Common HSInstall.DeploymentInfo HSInstall.Except@@ -67,9 +66,11 @@ , ansi-wl-pprint , base >=4.8 && <5.0 , directory+ , exceptions , filepath , heredoc , hsinstall+ , newtype-generics , optparse-applicative , process , safe-exceptions
package.yaml view
@@ -1,5 +1,5 @@ name: hsinstall-version: '2.6'+version: '2.7' synopsis: Install Haskell software description: This is a tool for deploying software projects into directory structures suitable for installation on a system. It builds upon the `stack install` command and adds more features. It's also a tool for easier AppImage creation. license: ISC@@ -8,7 +8,7 @@ copyright: 2016-2020 Dino Morelli category: Utility extra-source-files:-- changelog.md+- CHANGELOG.md - doc/hcar/hsinstall.tex - .gitignore - hsinstall/share/applications/hsinstall.desktop@@ -44,8 +44,10 @@ dependencies: - ansi-wl-pprint - Cabal+ - exceptions - heredoc - hsinstall+ - newtype-generics - optparse-applicative - process - safe-exceptions
src/app/HSInstall/AppImage.hs view
@@ -5,64 +5,73 @@ where import Control.Monad ( unless )+import Control.Newtype.Generics ( op ) import qualified System.Directory as Dir import System.Environment ( setEnv ) import System.FilePath ( (</>), (<.>), takeDirectory ) import System.Process ( callProcess ) -import HSInstall.Common ( dumpStockIcon, tmplDir )-import HSInstall.DeploymentInfo ( DeploymentInfo (binDir, prefixDir, version) )+import HSInstall.Common ( ExeFile (..), TmplDir (..), dumpStockIcon+ , tmplDir )+import HSInstall.DeploymentInfo+ ( BinDir (..)+ , PrefixDir (..)+ , DeploymentInfo (binDir, prefixDir, version)+ , prettyShow+ ) data DesktopFileStatus = CreateNewDesktop | DesktopExists desktopDir :: FilePath-desktopDir = tmplDir </> "share" </> "applications"+desktopDir = op TmplDir tmplDir </> "share" </> "applications" iconDir :: FilePath-iconDir = tmplDir </> "share" </> "icons" </> "hicolor" </> "scalable" </> "apps"+iconDir = op TmplDir tmplDir </> "share" </> "icons" </> "hicolor" </> "scalable" </> "apps" -prepAppImageFiles :: String -> IO DesktopFileStatus-prepAppImageFiles exe = do+prepAppImageFiles :: ExeFile -> IO DesktopFileStatus+prepAppImageFiles (ExeFile exeFp) = do -- Check and possibly create new icon- let iconPath = iconDir </> exe <.> "svg"+ let iconPath = iconDir </> exeFp <.> "svg" iconExists <- Dir.doesFileExist iconPath unless iconExists $ do Dir.createDirectoryIfMissing True iconDir dumpStockIcon $ Just iconPath -- Check desktop file, return status to caller- let desktopPath = desktopDir </> exe <.> "desktop"+ let desktopPath = desktopDir </> exeFp <.> "desktop" desktopFileExists <- Dir.doesFileExist desktopPath return $ if desktopFileExists then DesktopExists else CreateNewDesktop -mkAppImage :: String -> DeploymentInfo -> DesktopFileStatus -> IO ()+newtype Arg = Arg String -mkAppImage exe di DesktopExists = do- let desktopArg = "--desktop-file=" ++- (desktopDir </> exe <.> "desktop")- mkAppImage' exe di desktopArg+mkAppImage :: ExeFile -> DeploymentInfo -> DesktopFileStatus -> IO () -mkAppImage exe di CreateNewDesktop = do- mkAppImage' exe di "--create-desktop-file"+mkAppImage exeFile di DesktopExists = do+ let desktopArg = Arg ("--desktop-file=" <>+ (desktopDir </> op ExeFile exeFile <.> "desktop"))+ mkAppImage' exeFile di desktopArg++mkAppImage exeFile di CreateNewDesktop = do+ mkAppImage' exeFile di (Arg "--create-desktop-file") -- Now copy the freshly-created .desktop file into the project sources- let desktopFile = exe <.> "desktop"+ let desktopFile = op ExeFile exeFile <.> "desktop" Dir.createDirectoryIfMissing True desktopDir Dir.copyFile- (prefixDir di </> "share" </> "applications" </> desktopFile)+ ((op PrefixDir . prefixDir $ di) </> "share" </> "applications" </> desktopFile) (desktopDir </> desktopFile) -mkAppImage' :: String -> DeploymentInfo -> String -> IO ()-mkAppImage' exe di desktopArg = do- setEnv "VERSION" $ version di+mkAppImage' :: ExeFile -> DeploymentInfo -> Arg -> IO ()+mkAppImage' (ExeFile exeFp) di (Arg desktopArg) = do+ setEnv "VERSION" (prettyShow . version $ di) callProcess "linuxdeploy-x86_64.AppImage"- [ "--appdir=" ++ (takeDirectory . prefixDir $ di)- , "--executable=" ++ (binDir di </> exe)+ [ "--appdir=" ++ (takeDirectory . op PrefixDir . prefixDir $ di)+ , "--executable=" <> ((op BinDir . binDir $ di) </> exeFp) , desktopArg- , "--icon-file=" ++ (iconDir </> exe <.> "svg")+ , "--icon-file=" ++ (iconDir </> exeFp <.> "svg") , "--output=appimage" ]
+ src/app/HSInstall/Build.hs view
@@ -0,0 +1,64 @@+module HSInstall.Build+ ( BuildTool+ , clean+ , determineBuildTool+ , installBinaries+ , makeCabal+ )+ where++import System.Directory ( getDirectoryContents )+import System.Process ( callProcess )++import HSInstall.Common ( ExeFile (..) )+import HSInstall.Except ( justDoIt )+import HSInstall.Opts ( BuildMode (AppImageExe, Project) )+++data BuildTool = Cabal | Stack++instance Show BuildTool where+ show Cabal = "cabal"+ show Stack = "stack"+++determineBuildTool :: IO BuildTool+determineBuildTool = do+ dirContents <- getDirectoryContents "."+ pure $ if "stack.yaml" `elem` dirContents+ then Stack+ else Cabal+++clean :: BuildTool -> IO ()+clean Cabal = callProcess "cabal" ["v2-clean"]+clean Stack = callProcess "stack" ["clean"]+++modeToStackArg :: BuildMode -> String+modeToStackArg (AppImageExe (ExeFile exeFp)) = ':' : exeFp+modeToStackArg Project = ""+++installBinaries :: BuildTool -> BuildMode -> FilePath -> IO ()++installBinaries Cabal _ binDir =+ callProcess "cabal"+ [ "v2-install"+ , "--install-method=copy"+ , "--overwrite-policy=always"+ , "--installdir=" ++ binDir+ ]++installBinaries Stack mode binDir =+ callProcess "stack"+ [ "install"+ , modeToStackArg mode + , "--local-bin-path=" ++ binDir+ ]+++makeCabal :: BuildTool -> IO ()+makeCabal Cabal = justDoIt $ callProcess "hpack" []+makeCabal Stack = justDoIt $ callProcess "stack" ["query"]+
src/app/HSInstall/Common.hs view
@@ -1,18 +1,35 @@+{-# LANGUAGE DeriveGeneric #-}+ module HSInstall.Common- ( dumpStockIcon+ ( ExeFile (..)+ , TmplDir (..)+ , dumpStockIcon , tmplDir ) where +import Control.Newtype.Generics import Data.Maybe ( fromMaybe )+import GHC.Generics import HSInstall.Paths ( getShareDir ) import Paths_hsinstall ( getDataDir ) import System.Directory ( copyFile )-import System.FilePath ( FilePath, (</>), (<.>) )+import System.FilePath ( (</>), (<.>) ) -tmplDir :: FilePath-tmplDir = "." </> "hsinstall"+newtype TmplDir = TmplDir FilePath+ deriving Generic++instance Newtype TmplDir++tmplDir :: TmplDir+tmplDir = pack $ "." </> "hsinstall"+++newtype ExeFile = ExeFile FilePath+ deriving Generic++instance Newtype ExeFile dumpStockIcon :: Maybe FilePath -> IO ()
src/app/HSInstall/DeploymentInfo.hs view
@@ -1,18 +1,23 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-} module HSInstall.DeploymentInfo- ( DeploymentInfo (..)+ ( BinDir (..)+ , DeploymentInfo (..)+ , DocDir (..)+ , PrefixDir (..) , constructDeploymentInfo -- re-exporting , normal+ , prettyShow ) where import Control.Applicative ( (<|>) ) import Control.Monad.Trans.Maybe ( MaybeT (..), runMaybeT )-import Data.List ( isSuffixOf )-import Data.Maybe ( listToMaybe )+import Control.Newtype.Generics+import Data.List ( find, isSuffixOf ) import Distribution.Package ( PackageId , PackageIdentifier (pkgName, pkgVersion)@@ -25,40 +30,58 @@ ( readGenericPackageDescription ) import Distribution.Pretty ( prettyShow ) import Distribution.Types.PackageName ( unPackageName )+import Distribution.Types.Version ( Version ) import Distribution.Verbosity ( normal )+import GHC.Generics hiding ( Prefix ) import System.Directory ( getDirectoryContents )-import System.FilePath ( (</>) )-import System.Process ( callProcess )+import System.FilePath ( (</>), (<.>) ) +import HSInstall.Build ( BuildTool, makeCabal )+import HSInstall.Common ( ExeFile (..) ) import HSInstall.Except ( HSInstallException (NoCabalFiles) , throwM ) import HSInstall.Opts- ( BuildMode (AppImageExe, Project) , Options (..)+ ( BuildMode (AppImageExe, Project)+ , PrefixOpt (..)+ , Options (..) ) +newtype PrefixDir = PrefixDir FilePath+ deriving Generic++instance Newtype PrefixDir++newtype BinDir = BinDir FilePath+ deriving Generic++instance Newtype BinDir++newtype DocDir = DocDir FilePath+ deriving Generic++instance Newtype DocDir+ data DeploymentInfo = DeploymentInfo- { prefixDir :: FilePath- , binDir :: FilePath- , shareDir :: FilePath- , docDir :: FilePath- , rsrcDir :: FilePath- , version :: String+ { prefixDir :: PrefixDir+ , binDir :: BinDir+ , docDir :: DocDir+ , version :: Version } locateCabalFile :: IO (Maybe FilePath)-locateCabalFile = listToMaybe . filter (isSuffixOf ".cabal")+locateCabalFile = find (isSuffixOf ".cabal") <$> getDirectoryContents "." -constructDeploymentInfo :: Options -> IO DeploymentInfo-constructDeploymentInfo opts = do+constructDeploymentInfo :: BuildTool -> Options -> IO DeploymentInfo+constructDeploymentInfo buildTool opts = do mbCabalFile <- runMaybeT- $ MaybeT (locateCabalFile)- <|> MaybeT (callProcess "stack" ["query"] >> locateCabalFile)+ $ MaybeT locateCabalFile+ <|> MaybeT (makeCabal buildTool >> locateCabalFile) maybe (throwM NoCabalFiles) (fmap (constructDeploymentInfo' opts . package . packageDescription) . readGenericPackageDescription normal) mbCabalFile@@ -66,18 +89,21 @@ constructDeploymentInfo' :: Options -> PackageId -> DeploymentInfo constructDeploymentInfo' opts pkgId =- DeploymentInfo prefixDir' binDir' shareDir'- (shareDir' </> "doc") (shareDir' </> "resources") version'+ DeploymentInfo prefixDir' (BinDir binFp)+ (DocDir $ shareFp </> "doc") (pkgVersion pkgId) where- prefixDir' = computePrefixDir (optPrefix opts) (optBuildMode opts)- binDir' = prefixDir' </> "bin"+ prefixDir'@(PrefixDir prefixFp) = computePrefixDir (optPrefix opts) (optBuildMode opts)+ binFp = prefixFp </> "bin" project = unPackageName . pkgName $ pkgId- version' = prettyShow . pkgVersion $ pkgId- shareDir' = prefixDir' </> "share" </> project+ shareFp = prefixFp </> "share" </> project -computePrefixDir :: Maybe FilePath -> BuildMode -> FilePath-computePrefixDir (Just prefix') _ = prefix'-computePrefixDir Nothing (AppImageExe exe) = (exe ++ ".AppDir") </> "usr"-computePrefixDir Nothing Project = "AppDir" </> "usr"+defaultPrefix :: PrefixDir+defaultPrefix = PrefixDir $ "AppDir" </> "usr"++computePrefixDir :: PrefixOpt -> BuildMode -> PrefixDir+computePrefixDir (Prefix prefixFp) _ = PrefixDir prefixFp+computePrefixDir NoPrefixSpecified (AppImageExe (ExeFile exeFp)) =+ over PrefixDir (exeFp <.>) defaultPrefix+computePrefixDir NoPrefixSpecified Project = defaultPrefix
src/app/HSInstall/Except.hs view
@@ -3,6 +3,7 @@ module HSInstall.Except ( HSInstallException (..)+ , justDoIt , withExceptionHandling -- Re-exported@@ -11,7 +12,8 @@ where import Control.Exception.Safe- ( Exception, Handler (..), Typeable, catches, throwM )+ ( Exception, Handler (..), Typeable, catches, catchIO, throwM )+import Control.Monad.Catch ( MonadCatch ) import GHC.IO.Exception ( IOException ) import System.Exit ( die ) @@ -21,7 +23,7 @@ deriving Typeable instance Show HSInstallException where- show NoCabalFiles = "no cabal files were found in . If this is a buildable project directory that uses hpack, try issuing any stack command like `stack query` or `stack clean` to generate the cabal file from the package.yaml"+ show NoCabalFiles = "no cabal files were found in . We tried to run `hpack` and/or `stack query` and still don't see a cabal file. Is this directory really a Haskell project?" instance Exception HSInstallException @@ -39,3 +41,10 @@ explainError :: String -> IO a explainError = die . ("Could not continue because: " ++)+++-- Just try to perform the action and eat any IO exception. We want this to+-- happen because we'll be using this to try several commands and don't expect+-- all of them to succeed.+justDoIt :: MonadCatch m => m () -> m ()+justDoIt a = catchIO a $ const (pure ())
src/app/HSInstall/Opts.hs view
@@ -1,14 +1,20 @@+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} module HSInstall.Opts ( BuildMode (..)+ , CleanSwitch (..)+ , DumpIconSwitch (..) , Options (..)+ , PrefixOpt (..) , parseOpts ) where +import Control.Newtype.Generics import Data.Version ( showVersion )+import GHC.Generics hiding ( Prefix ) import Options.Applicative import Paths_hsinstall ( version ) import System.Environment ( getProgName )@@ -16,30 +22,45 @@ import Text.PrettyPrint.ANSI.Leijen ( string ) import Text.Printf ( printf ) +import HSInstall.Common ( ExeFile (..) ) -data BuildMode = AppImageExe String | Project +newtype CleanSwitch = CleanSwitch Bool+ deriving Generic +instance Newtype CleanSwitch++newtype DumpIconSwitch = DumpIconSwitch Bool+ deriving Generic++instance Newtype DumpIconSwitch++data BuildMode = AppImageExe ExeFile | Project++data PrefixOpt = Prefix FilePath | NoPrefixSpecified+ data Options = Options- { optClean :: Bool- , optDumpIcon :: Bool+ { optClean :: CleanSwitch+ , optDumpIcon :: DumpIconSwitch , optBuildMode :: BuildMode- , optPrefix :: Maybe FilePath+ , optPrefix :: PrefixOpt } parser :: Parser Options parser = Options- <$> switch- ( long "clean"- <> short 'c'- <> help "Do 'stack clean' first"+ <$> ( CleanSwitch <$> switch+ ( long "clean"+ <> short 'c'+ <> help "Do stack or cabal 'clean' first"+ ) )- <*> switch- ( long "dump-stock-icon"- <> help "Save a default icon, unix-terminal.svg, to the current working directory"+ <*> ( DumpIconSwitch <$> switch+ ( long "dump-stock-icon"+ <> help "Save a default icon, unix-terminal.svg, to the current working directory"+ ) )- <*> ( maybe Project AppImageExe <$> optional+ <*> ( maybe Project (AppImageExe . ExeFile) <$> optional ( strOption ( long "mk-appimage" <> short 'i'@@ -48,11 +69,13 @@ ) ) )- <*> optional ( strOption- ( long "prefix"- <> short 'p'- <> metavar "DIR"- <> help "Install prefix directory (Default: AppDir/usr)"+ <*> ( maybe NoPrefixSpecified Prefix <$> optional+ ( strOption+ ( long "prefix"+ <> short 'p'+ <> metavar "DIR"+ <> help "Install prefix directory (Default: AppDir/usr)"+ ) ) ) @@ -79,14 +102,15 @@ footer' = footerDoc . Just . string . printf content . showVersion $ version where content = [here|OVERVIEW -hsinstall is a tool for installing a Haskell software project into a directory structure for deployment. It builds upon the `stack install` command and adds these features:+hsinstall is a tool for installing a Haskell software project into a directory structure for deployment. It builds upon the `stack install` and `cabal install` commands and adds these features: - Copies the `LICENSE` file into <PREFIX>/share/<PROJECT-NAME>/doc - Copies the contents of a static directory stucture in your project (named `hsinstall`) into the destination prefix directory. This can contain additional binaries or scripts, resources, documentation, etc. (more on this later in TEMPLATE DIRECTORY) - Optionally builds an AppDir directory structure for the project and produces an AppImage binary -To use hsinstall, it will be necessary to have the Haskell stack tool on your PATH:-https://docs.haskellstack.org/en/stable/README/+To use hsinstall, it will be necessary to be in the top-level directory of a Haskell project that builds with either cabal or stack. You'll need to have one or the other of the cabal or stack tools on your path as well. Basically, if you can't build the project, hsinstall can't build it either.++Also note that all cabal commands will be issued as `v2-*` commands. The older `v1-*` commands are deprecated and we don't use them. If the AppImage features are desired, you must have these tools on your PATH: linuxdeploy: https://github.com/linuxdeploy/linuxdeploy/releases
src/app/hsinstall.hs view
@@ -1,65 +1,74 @@ {-# LANGUAGE OverloadedStrings #-} import Control.Monad ( when )+import Control.Newtype.Generics ( op ) import qualified System.Directory as Dir import System.Exit ( exitSuccess ) import System.FilePath ( (</>) )-import System.Process ( callProcess )+import System.IO ( BufferMode (NoBuffering),+ hSetBuffering, stderr, stdout ) import Text.Printf ( printf ) import HSInstall.AppImage ( mkAppImage, prepAppImageFiles )-import HSInstall.Common ( dumpStockIcon, tmplDir )+import HSInstall.Build ( BuildTool, clean,+ determineBuildTool, installBinaries )+import HSInstall.Common ( TmplDir (..), dumpStockIcon, tmplDir ) import HSInstall.DeploymentInfo- ( DeploymentInfo (binDir, docDir, prefixDir)+ ( BinDir (..)+ , DeploymentInfo (binDir, docDir, prefixDir)+ , DocDir (..)+ , PrefixDir (..) , constructDeploymentInfo ) import HSInstall.Except ( withExceptionHandling ) import HSInstall.Opts- ( BuildMode (AppImageExe, Project), Options (..)+ ( BuildMode (AppImageExe, Project)+ , CleanSwitch (..), DumpIconSwitch (..)+ , Options (..) , parseOpts ) import HSInstall.System.Directory ( copyTree ) main :: IO ()-main = withExceptionHandling $ do- opts <- parseOpts-- when (optDumpIcon opts) $ dumpStockIcon Nothing >> exitSuccess+main = do+ mapM_ (flip hSetBuffering NoBuffering) [ stdout, stderr ]+ withExceptionHandling $ do+ opts <- parseOpts - di <- constructDeploymentInfo opts+ buildTool <- determineBuildTool+ putStrLn $ "Build tool detected: " <> show buildTool - when (optClean opts) $ callProcess "stack" ["clean"]- deployApplication (optBuildMode opts) di- case optBuildMode opts of- AppImageExe exe -> prepAppImageFiles exe >>= mkAppImage exe di- Project -> return ()+ when (op DumpIconSwitch . optDumpIcon $ opts) $ dumpStockIcon Nothing >> exitSuccess + di <- constructDeploymentInfo buildTool opts -modeToStackArg :: BuildMode -> String-modeToStackArg (AppImageExe exe) = ':' : exe-modeToStackArg Project = ""+ when (op CleanSwitch . optClean $ opts) $ clean buildTool+ deployApplication buildTool (optBuildMode opts) di+ case optBuildMode opts of+ AppImageExe exePath -> prepAppImageFiles exePath >>= mkAppImage exePath di+ Project -> return () -deployApplication :: BuildMode -> DeploymentInfo -> IO ()-deployApplication mode di = do+deployApplication :: BuildTool -> BuildMode -> DeploymentInfo -> IO ()+deployApplication buildTool mode di = do -- Copy the binaries- Dir.createDirectoryIfMissing True $ binDir di- callProcess "stack"- [ "install", modeToStackArg mode - , "--local-bin-path=" ++ binDir di- ]+ let binFp = op BinDir . binDir $ di+ Dir.createDirectoryIfMissing True binFp+ installBinaries buildTool mode binFp -- Copy the license let licenseFile = "LICENSE" licenseFileExists <- Dir.doesFileExist licenseFile when licenseFileExists $ do printf "\nCopying %s\n" licenseFile- Dir.createDirectoryIfMissing True $ docDir di- Dir.copyFile licenseFile (docDir di </> licenseFile)+ let docFp = op DocDir . docDir $ di+ Dir.createDirectoryIfMissing True docFp+ Dir.copyFile licenseFile (docFp </> licenseFile) -- Copy the static template directory- tmplExists <- Dir.doesDirectoryExist tmplDir+ let tmplFp = op TmplDir tmplDir+ tmplExists <- Dir.doesDirectoryExist tmplFp when tmplExists $ do- printf "\nCopying distribution files from template dir (%s)\n" tmplDir- copyTree False tmplDir (prefixDir di)+ printf "\nCopying distribution files from template dir (%s)\n" tmplFp+ copyTree False tmplFp (op PrefixDir . prefixDir $ di)
stack.yaml view
@@ -1,4 +1,4 @@-resolver: lts-14.20+resolver: lts-18.18 packages: - '.'
stack.yaml.lock view
@@ -6,7 +6,7 @@ packages: [] snapshots: - completed:- size: 524154- url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/14/20.yaml- sha256: 2f5099f69ddb6abfe64400fe1e6a604e8e628f55e6837211cd70a81eb0a8fa4d- original: lts-14.20+ size: 586296+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/18.yaml+ sha256: 63539429076b7ebbab6daa7656cfb079393bf644971156dc349d7c0453694ac2+ original: lts-18.18