packages feed

too-many-cells-3.0.1.0: src/TooManyCells/Program/Utility.hs

{- TooManyCells.Program.Utility
Gregory W. Schwartz

Utility functions for the command line program.
-}

{-# LANGUAGE BangPatterns      #-}

module TooManyCells.Program.Utility where

-- Remote
import Control.Exception (SomeException (..), try, evaluate)
import Control.Monad (guard)
import Control.Monad.Trans.Maybe (runMaybeT, MaybeT (..))
import Data.Bool (bool)
import Data.List (isInfixOf)
import Data.Maybe (fromMaybe)
import Text.Read (readMaybe)
import qualified System.Directory as FP
import qualified System.FilePath as FP
import qualified Turtle as TU

-- Local
import TooManyCells.File.Types
import TooManyCells.Matrix.Types
import TooManyCells.Program.Options

-- | Read or return an error.
readOrErr :: (Read a) => String -> String -> a
readOrErr err = fromMaybe (error err) . readMaybe

-- | Normalization defaults.
getNormalization :: Subcommand -> [NormType] -> [NormType]
getNormalization (MakeTreeCommand opts) xs =
  if null xs then [TfIdfNorm] else xs
getNormalization (InteractiveCommand opts) xs =
  if null xs then [TfIdfNorm] else xs
getNormalization _ xs = if null xs then [NoneNorm] else xs

-- | Get the file type of an input matrix. Returns either a left file (i.e. CSV)
-- or a right matrix market.
getMatrixFileType :: FilePath -> IO (Either MatrixFileType MatrixFileType)
getMatrixFileType path = do
  fileExist      <- FP.doesFileExist path
  directoryExist <- FP.doesDirectoryExist path
  compressedFileExist <- FP.doesFileExist $ path FP.</> "matrix.mtx.gz"

  let fragmentsFile = (\ (x, y) -> isInfixOf "fragments" x && y == ".tsv.gz")
                    . FP.splitExtensions
                    . FP.takeFileName
                    $ path
      matrixFile
        | fileExist && (FP.takeExtension path == ".bdg") = Left . BedGraph $ path
        | fileExist && (FP.takeExtension path == ".bw") = Left . BigWig $ path
        | fileExist && not fragmentsFile = Left . DecompressedMatrix . MatrixFile $ path
        | fileExist && fragmentsFile = Left . CompressedFragments . FragmentsFile $ path
        | directoryExist && not compressedFileExist = Right . DecompressedMatrix . MatrixFile $ path FP.</> "matrix.mtx"
        | directoryExist && compressedFileExist = Right . CompressedMatrix . MatrixFile $ path FP.</> "matrix.mtx.gz"
        | directoryExist = error "Cannot determine matrix pointed to, are there too many matrices here?"
        | otherwise = error "\nMatrix path does not exist."

  return matrixFile

-- | Check if file exists and is not empty. Currently may have a handle closing
-- issue, do not use for now.
nonEmptyFileExists :: TU.FilePath -> IO Bool
nonEmptyFileExists path = either (const' False) (/= TU.B 0)
                      <$> (try $ TU.du path :: IO (Either SomeException TU.Size))
  where
    const' !x !y = x