packages feed

hsinstall-2.7: src/app/HSInstall/AppImage.hs

{-# LANGUAGE OverloadedStrings #-}

module HSInstall.AppImage
  ( mkAppImage, prepAppImageFiles )
  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 ( ExeFile (..), TmplDir (..), dumpStockIcon
  , tmplDir )
import HSInstall.DeploymentInfo
  ( BinDir (..)
  , PrefixDir (..)
  , DeploymentInfo (binDir, prefixDir, version)
  , prettyShow
  )


data DesktopFileStatus = CreateNewDesktop | DesktopExists


desktopDir :: FilePath
desktopDir = op TmplDir tmplDir </> "share" </> "applications"

iconDir :: FilePath
iconDir = op TmplDir tmplDir </> "share" </> "icons" </> "hicolor" </> "scalable" </> "apps"


prepAppImageFiles :: ExeFile -> IO DesktopFileStatus
prepAppImageFiles (ExeFile exeFp) = do
  -- Check and possibly create new icon
  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 </> exeFp <.> "desktop"
  desktopFileExists <- Dir.doesFileExist desktopPath
  return $ if desktopFileExists then DesktopExists else CreateNewDesktop


newtype Arg = Arg String

mkAppImage :: ExeFile -> DeploymentInfo -> DesktopFileStatus -> IO ()

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 = op ExeFile exeFile <.> "desktop"
  Dir.createDirectoryIfMissing True desktopDir
  Dir.copyFile
    ((op PrefixDir . prefixDir $ di) </> "share" </> "applications" </> desktopFile)
    (desktopDir </> desktopFile)


mkAppImage' :: ExeFile -> DeploymentInfo -> Arg -> IO ()
mkAppImage' (ExeFile exeFp) di (Arg desktopArg) = do
  setEnv "VERSION" (prettyShow . version $ di)
  callProcess "linuxdeploy-x86_64.AppImage"
    [ "--appdir=" ++ (takeDirectory . op PrefixDir . prefixDir $ di)
    , "--executable=" <> ((op BinDir . binDir $ di) </> exeFp)
    , desktopArg
    , "--icon-file=" ++ (iconDir </> exeFp <.> "svg")
    , "--output=appimage"
    ]