packages feed

epub-tools-2.6: src/EpubTools/EpubMeta/Edit.hs

-- License: BSD3 (see LICENSE)
-- Author: Dino Morelli <dino@ui3.info>

{-# LANGUAGE ScopedTypeVariables #-}

module EpubTools.EpubMeta.Edit
   ( edit )
   where

import Control.Exception
import Control.Monad
import System.Directory
import System.FilePath
import System.Environment
import System.Exit
import System.Process ( system )
import Text.Printf

import EpubTools.EpubMeta.Export
import EpubTools.EpubMeta.Import
import EpubTools.EpubMeta.Opts
import EpubTools.EpubMeta.Util


{- Turn an (IO a) action into a (Maybe a) with a value of Nothing
   if an IO exception is raised
-}
ioMaybe :: IO a -> IO (Maybe a)
ioMaybe action = do
   result :: (Either SomeException a) <- try action
   either (const . return $ Nothing) (return . Just) result


{- Look through the user's environment looking for their preferred 
   editor. Use /usr/bin/vi as a default if none found
-}
findEditor :: EM FilePath
findEditor = do
   mbEditor <- liftIO $ foldr (liftM2 mplus) (findExecutable "vi")
      [ ioMaybe $ getEnv "EDITOR"
      , ioMaybe $ getEnv "VISUAL"
      ]

   maybe (throwError "epubmeta: ERROR: Could not find a suitable editor in your EDITOR or VISUAL environment variables, and could not find the vi binary. Fix this situation or use epubmeta export/import.") return mbEditor


edit :: Options -> FilePath -> EM ()
edit opts = edit' $ optEdit opts


edit' :: Edit -> FilePath -> EM ()

edit' NoBackup zipPath = do
   -- Make a temp path for the OPF document
   tempDir <- liftIO $ getTemporaryDirectory
   let opfPath = tempDir </> "epubmeta-temp-content.opf"

   -- Dump the OPF document to this path
   exportOpf (defaultOptions { optExport = ToPath opfPath }) zipPath

   -- Open this file in the user's editor and wait for it
   editor <- findEditor
   ec <- liftIO $ system $ printf "%s %s" editor opfPath

   case ec of
      ExitSuccess -> do
         -- Modify the book with the now-edited OPF data
         importOpf (defaultOptions { optImport = Just opfPath }) zipPath

         -- Delete the temp file
         liftIO $ removeFile opfPath

      ExitFailure _ -> do
         -- Delete the temp file
         liftIO $ removeFile opfPath

         throwError "epubmeta: ERROR: Something went wrong during editing, your file has not been changed."

edit' (Backup suffix) zipPath = do
   liftIO $ copyFile zipPath (zipPath ++ suffix)
   edit' NoBackup zipPath

edit' NotEditing _ = undefined