packages feed

photoname-3.3: src/photoname.hs

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

{-# LANGUAGE FlexibleContexts #-}

import Control.Monad ( filterM, forM_, unless, when )
import System.Directory ( createDirectoryIfMissing )
import System.Environment ( getArgs )
import System.FilePath ( takeDirectory )
import System.Posix ( createLink, fileExist, getFileStatus,
   isRegularFile, removeLink )
import Text.Printf ( printf )

import Photoname.Common ( Ph, ask, liftIO, runRename, throwError )
import Photoname.Opts ( Options (..) , parseOpts, usageText )
import Photoname.DateFormat ( buildDatePath )
import Photoname.SerialFormat ( buildSerialPath )


{- Take a file path to a JPEG file and use EXIF information available to
   link the file at its new location below the given basedir.
-}
createNewLink :: FilePath -> Ph ()
createNewLink oldPath = do
   opts <- ask
   newPath <- if (optOldStyle opts)
      then buildSerialPath oldPath
      else buildDatePath oldPath

   -- Check for existance of the target file
   exists <- liftIO $ fileExist newPath
   when exists $ throwError $ "Destination " ++ newPath ++ " exists!"

   -- Display what will be done
   unless (optQuiet opts) $
      liftIO $ putStrLn $ oldPath ++ " -> " ++ newPath

   unless (optNoAction opts) $ do
      -- Make the target dir
      liftIO $ createDirectoryIfMissing True $ takeDirectory newPath

      -- Make the new hard link
      liftIO $ createLink oldPath newPath

      -- If user has specified, remove the original link
      when (optMove opts) $
         liftIO $ removeLink oldPath

      return ()


-- Figure out and execute what the user wants based on the supplied args.
executeCommands :: Options -> [String] -> IO ()

-- User gave no files at all. Display help
executeCommands _ [] = putStrLn usageText

-- Normal program operation, process the files with the args.
executeCommands opts filePaths = do
   -- Get rid of anything not a regular file from the list of paths
   actualPaths <- filterM
      (\p -> getFileStatus p >>= return . isRegularFile) filePaths

   -- Notify user of the switches that will be in effect.
   when (optNoAction opts) $
      putStrLn "No-action mode, nothing will be changed."

   when (optMove opts) $
      putStrLn "Removing original links after new links are in place."

   -- Do the link manipulations, and report any errors.
   forM_ actualPaths $ \path -> do
      result <- runRename opts $ createNewLink path
      either (\em -> printf "** Processing %s: %s\n" path em)
         (const return ()) result


main :: IO ()
main = do
   -- Parse the arguments
   (opts, paths) <- getArgs >>= parseOpts

   -- Do the photo naming procedure
   executeCommands opts paths

   -- Perhaps we should get an ExitCode back from all this above?