{-# LANGUAGE RecordWildCards #-}
module Distribution.AppImage
( AppImage(..)
, AppDirCustomize
, appImageBuildHook
)
where
import Control.Monad
import Data.Maybe
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,
appIcons :: [FilePath],
appResources :: [FilePath],
appDirCustomize :: Maybe AppDirCustomize
}
type AppDirCustomize
= FilePath
-> Args
-> BuildFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
appImageBuildHook
:: [AppImage]
-> Args
-> BuildFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
appImageBuildHook apps args flags pkg buildInfo =
when (buildOS == Linux) $
mapM_ (makeBundle args flags pkg buildInfo) apps
makeBundle :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> AppImage -> IO ()
makeBundle args flags pkg buildInfo app@AppImage{..} = do
let bdir = buildDir buildInfo
verb = fromFlagOrDefault normal (buildVerbosity flags)
unless (hasExecutable pkg appName) $
die' verb ("No executable defined for the AppImage bundle: " ++ appName)
when (null appIcons) $
die' verb ("No icon defined for the AppImage bundle: " ++ appName)
withTempDirectory verb bdir "appimage." $ \appDir -> do
deployExe (bdir </> appName </> appName) app appDir verb
bundleFiles appResources (appDir </> "usr" </> "share" </> appName) verb
fromMaybe noCustomization appDirCustomize appDir args flags pkg buildInfo
bundleApp appDir verb
hasExecutable :: PackageDescription -> String -> Bool
hasExecutable pkg name =
any (\e -> exeName e == fromString name) (executables pkg)
deployExe :: FilePath -> AppImage -> FilePath -> Verbosity -> IO ()
deployExe exe AppImage{..} appDir verb = do
prog <- findProg "linuxdeploy" verb
runProgram verb prog $
[ "--appdir=" ++ appDir
, "--executable=" ++ exe
, "--desktop-file=" ++ appDesktop ] ++
map ("--icon-file=" ++) appIcons
bundleFiles :: [FilePath] -> FilePath -> Verbosity -> IO ()
bundleFiles files dest verb = prepare >> mapM_ copy files
where
prepare = createDirectoryIfMissingVerbose verb True dest
copy file = copyFileVerbose verb file (dest </> takeFileName file)
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 }
noCustomization :: AppDirCustomize
noCustomization _ _ _ _ _ = return ()
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))