sparkle-0.7.4: Sparkle.hs
module Main where
import Codec.Archive.Zip
import Data.Text (pack, strip, unpack)
import Data.List (isInfixOf)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Paths_sparkle
import System.Environment (getArgs)
import System.Exit (ExitCode(..))
import System.FilePath ((</>), (<.>), takeBaseName, takeFileName)
import System.Info (os)
import System.IO (hPutStrLn, stderr)
import System.IO.Temp (withSystemTempDirectory)
import System.Posix.Files (createSymbolicLink)
import System.Process
( CreateProcess(..)
, proc
, readProcess
, waitForProcess
, withCreateProcess
)
import Text.Regex.TDFA
doPackage :: FilePath -> IO ()
doPackage cmd = do
dir <- getDataDir
jarbytes <- LBS.readFile (dir </> "build/libs/sparkle.jar")
cmdpath <- unpack . strip . pack <$> readProcess "which" [cmd] ""
ldd <- case os of
"darwin" -> do
hPutStrLn
stderr
"WARNING: JAR not self contained on OS X (shared libraries not copied)."
return ""
_ -> readProcess "ldd" [cmdpath] ""
let libs =
filter (\x -> not $ any (`isInfixOf` x) ["libc.so", "libpthread.so"]) $
map (!! 1) (ldd =~ " => ([[:graph:]]+) " :: [[String]])
libentries0 <- mapM mkEntry libs
libentries <-
if os == "darwin" then return libentries0
else do
libhsapp <- makeHsTopLibrary cmdpath libs
return $ toEntry "libhsapp.so" 0 libhsapp : libentries0
cmdentry <- toEntry "hsapp" 0 <$> LBS.readFile cmdpath
let appzip =
toEntry "sparkle-app.zip" 0 $
fromArchive $
foldr addEntryToArchive emptyArchive (cmdentry : libentries)
newjarbytes = fromArchive $ addEntryToArchive appzip (toArchive jarbytes)
LBS.writeFile ("." </> takeBaseName cmd <.> "jar") newjarbytes
where
mkEntry file = toEntry (takeFileName file) 0 <$> LBS.readFile file
-- We make a library which depends on all the libraries that go into the jar.
-- This removes the need to fiddle with the rpaths of the various libraries
-- and the application executable.
makeHsTopLibrary :: FilePath -> [FilePath] -> IO LBS.ByteString
makeHsTopLibrary hsapp libs = withSystemTempDirectory "libhsapp" $ \d -> do
let f = d </> "libhsapp.so"
createSymbolicLink hsapp (d </> "hsapp")
-- Changing the directory is necessary for gcc to link hsapp with a
-- relative path. "-L d -l:hsapp" doesn't work in centos 6 where the
-- path to hsapp in the output library ends up being absolute.
callProcessCwd d "gcc" $
[ "-shared", "-Wl,-z,origin", "-Wl,-rpath=$ORIGIN", "hsapp"
, "-o", f] ++ libs
LBS.fromStrict <$> BS.readFile f
-- This is a variant of 'callProcess' which takes a working directory.
callProcessCwd :: FilePath -> FilePath -> [String] -> IO ()
callProcessCwd wd cmd args = do
exit_code <- withCreateProcess
(proc cmd args)
{ delegate_ctlc = True
, cwd = Just wd
} $ \_ _ _ p ->
waitForProcess p
case exit_code of
ExitSuccess -> return ()
ExitFailure r -> error $ "callProcessCwd: " ++ show (cmd, args, r)
main :: IO ()
main = do
argv <- getArgs
case argv of
["package", cmd] -> doPackage cmd
_ -> fail "Usage: sparkle package <command>"