{-# LANGUAGE RecordWildCards #-}
module Distribution.AppImage
( AppImage(..)
, appImageBuildHook
)
where
import Control.Monad
import Data.String
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Program
import Distribution.Simple.Program.Types
import Distribution.Simple.Setup
import Distribution.Simple.Utils
import Distribution.System
import Distribution.Verbosity
import System.FilePath
data AppImage = AppImage {
appName :: String,
appDesktop :: FilePath,
appIcon :: FilePath,
appResources :: [FilePath]
} deriving (Eq, Show)
appImageBuildHook
:: [AppImage]
-> Args
-> BuildFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
appImageBuildHook apps _ flags pkg buildInfo =
when (buildOS == Linux) $
let bdir = buildDir buildInfo
verb = fromFlagOrDefault normal (buildVerbosity flags)
in forM_ apps (makeBundle pkg bdir verb)
makeBundle :: PackageDescription -> FilePath -> Verbosity -> AppImage -> IO ()
makeBundle pkg bdir verb app@AppImage{..} = do
unless (hasExecutable pkg appName) $
die' verb ("No executable defined for the AppImage bundle: " ++ appName)
withTempDirectory verb bdir "appimage." $ \appDir -> do
let exe = bdir </> appName </> appName
share = appDir </> "usr" </> "share" </> appName
createDirectoryIfMissingVerbose verb True share
deployExe app appDir exe verb
copyResources appResources share verb
bundleApp appDir verb
hasExecutable :: PackageDescription -> String -> Bool
hasExecutable pkg name =
any (\e -> exeName e == fromString name) (executables pkg)
deployExe :: AppImage -> FilePath -> FilePath -> Verbosity -> IO ()
deployExe AppImage{..} appDir exe verb = do
prog <- findProg "linuxdeploy" verb
runProgram verb prog
[ "--appdir=" ++ appDir
, "--executable=" ++ exe
, "--desktop-file=" ++ appDesktop
, "--icon-file=" ++ appIcon
]
copyResources :: [FilePath] -> FilePath -> Verbosity -> IO ()
copyResources resources dest verb = mapM_ copy resources
where
copy res = copyFileVerbose verb res (dest </> takeFileName res)
bundleApp :: FilePath -> Verbosity -> IO ()
bundleApp appDir verb = do
prog <- findProg "appimagetool" verb
let (wdir, name) = splitFileName appDir
runProgramInvocation verb $
(programInvocation prog [name]) { progInvokeCwd = Just wdir }
findProg :: String -> Verbosity -> IO ConfiguredProgram
findProg name verb = do
found <- findProgramOnSearchPath verb defaultProgramSearchPath name
case found of
Nothing -> die' verb ("Command " ++ name ++ " is not available")
Just (path, _) -> return (simpleConfiguredProgram name (FoundOnSystem path))