{-# LANGUAGE OverloadedStrings #-}

module Poseidon.CLI.Genoconvert where

import           Poseidon.EntityTypes       (HasNameAndVersion (..))
import           Poseidon.GenotypeData      (GenoDataSource (..),
                                             GenotypeDataSpec (..),
                                             GenotypeFileSpec (..),
                                             GenotypeOutFormatSpec (..),
                                             loadGenotypeData,
                                             printSNPCopyProgress, writeVCF)
import           Poseidon.Janno             (JannoRows (..),
                                             jannoRows2EigenstratIndEntries)
import           Poseidon.Package           (PackageReadOptions (..),
                                             PoseidonPackage (..),
                                             defaultPackageReadOptions,
                                             makePseudoPackageFromGenotypeData,
                                             readPoseidonPackageCollection,
                                             writePoseidonPackage)
import           Poseidon.Utils             (PoseidonException (..), PoseidonIO,
                                             envErrorLength, envLogAction,
                                             logError, logInfo, logWarning)

import           Control.Exception          (catch, throwIO)
import           Control.Monad              (forM_, unless, when)
import           Data.List                  ((\\))
import           Data.Maybe                 (isJust)
import           Data.Time                  (getCurrentTime)
import           Pipes                      (MonadIO (liftIO), runEffect, (>->))
import           Pipes.Safe                 (runSafeT)
import           SequenceFormats.Eigenstrat (writeEigenstrat)
import           SequenceFormats.Plink      (PlinkPopNameMode,
                                             eigenstratInd2PlinkFam, writePlink)
import           System.Directory           (createDirectoryIfMissing,
                                             doesFileExist, removeFile,
                                             renameFile)
import           System.Exit                (ExitCode (..), exitWith)
import           System.FilePath            (dropTrailingPathSeparator,
                                             takeExtension, (<.>), (</>))

-- | A datatype representing command line options for the validate command
data GenoconvertOptions = GenoconvertOptions
    { GenoconvertOptions -> [GenoDataSource]
_genoconvertGenoSources     :: [GenoDataSource]
    , GenoconvertOptions -> GenotypeOutFormatSpec
_genoConvertOutFormat       :: GenotypeOutFormatSpec
    , GenoconvertOptions -> Maybe [Char]
_genoMaybeOutPackagePath    :: Maybe FilePath
    , GenoconvertOptions -> Bool
_genoconvertRemoveOld       :: Bool
    , GenoconvertOptions -> PlinkPopNameMode
_genoconvertOutPlinkPopMode :: PlinkPopNameMode
    , GenoconvertOptions -> Bool
_genoconvertOnlyLatest      :: Bool
    , GenoconvertOptions -> Bool
_genoconvertOutZip          :: Bool
    }

runGenoconvert :: GenoconvertOptions -> PoseidonIO ()
runGenoconvert :: GenoconvertOptions -> PoseidonIO ()
runGenoconvert (GenoconvertOptions [GenoDataSource]
genoSources GenotypeOutFormatSpec
outFormat Maybe [Char]
outPath
                Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
onlyLatest Bool
outZip) = do
    let pacReadOpts :: PackageReadOptions
pacReadOpts = PackageReadOptions
defaultPackageReadOptions {
          _readOptIgnoreChecksums  = True
        , _readOptIgnoreGeno       = False
        , _readOptGenoCheck        = True
        , _readOptOnlyLatest       = onlyLatest
    }
    -- load packages
    [PoseidonPackage]
properPackages <- PackageReadOptions -> [[Char]] -> PoseidonIO [PoseidonPackage]
readPoseidonPackageCollection PackageReadOptions
pacReadOpts ([[Char]] -> PoseidonIO [PoseidonPackage])
-> [[Char]] -> PoseidonIO [PoseidonPackage]
forall a b. (a -> b) -> a -> b
$
        [GenoDataSource -> [Char]
getPacBaseDir GenoDataSource
x | x :: GenoDataSource
x@PacBaseDir {} <- [GenoDataSource]
genoSources]
    [PoseidonPackage]
pseudoPackages <- (GenotypeDataSpec -> ReaderT Env IO PoseidonPackage)
-> [GenotypeDataSpec] -> PoseidonIO [PoseidonPackage]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM GenotypeDataSpec -> ReaderT Env IO PoseidonPackage
makePseudoPackageFromGenotypeData
        [GenoDataSource -> GenotypeDataSpec
getGenoDirect GenoDataSource
x | x :: GenoDataSource
x@GenoDirect {} <- [GenoDataSource]
genoSources]

    [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Unpackaged genotype data files loaded: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show ([PoseidonPackage] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PoseidonPackage]
pseudoPackages)
    -- convert
    (PoseidonPackage -> PoseidonIO ())
-> [PoseidonPackage] -> PoseidonIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (GenotypeOutFormatSpec
-> Bool
-> Maybe [Char]
-> Bool
-> PlinkPopNameMode
-> Bool
-> PoseidonPackage
-> PoseidonIO ()
convertGenoTo GenotypeOutFormatSpec
outFormat Bool
False Maybe [Char]
outPath Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
outZip) [PoseidonPackage]
properPackages
    (PoseidonPackage -> PoseidonIO ())
-> [PoseidonPackage] -> PoseidonIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (GenotypeOutFormatSpec
-> Bool
-> Maybe [Char]
-> Bool
-> PlinkPopNameMode
-> Bool
-> PoseidonPackage
-> PoseidonIO ()
convertGenoTo GenotypeOutFormatSpec
outFormat Bool
True Maybe [Char]
outPath Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
outZip) [PoseidonPackage]
pseudoPackages

illegalFormatException :: String -> PoseidonException
illegalFormatException :: [Char] -> PoseidonException
illegalFormatException [Char]
outFormat = [Char] -> PoseidonException
PoseidonGenericException ([Char] -> PoseidonException) -> [Char] -> PoseidonException
forall a b. (a -> b) -> a -> b
$
    [Char]
"Illegal outFormat " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
outFormat [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
". Outformats can be EIGENSTRAT, PLINK or VCF"

convertGenoTo :: GenotypeOutFormatSpec -> Bool -> Maybe FilePath -> Bool ->
    PlinkPopNameMode -> Bool -> PoseidonPackage -> PoseidonIO ()
convertGenoTo :: GenotypeOutFormatSpec
-> Bool
-> Maybe [Char]
-> Bool
-> PlinkPopNameMode
-> Bool
-> PoseidonPackage
-> PoseidonIO ()
convertGenoTo GenotypeOutFormatSpec
outFormat Bool
onlyGeno Maybe [Char]
outPath Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
outZip PoseidonPackage
pac = do
    -- start message
    [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$
        [Char]
"Converting genotype data in "
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" to format "
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ GenotypeOutFormatSpec -> [Char]
forall a. Show a => a -> [Char]
show GenotypeOutFormatSpec
outFormat
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ if Bool
outZip then [Char]
" (gzipped):" else [Char]
":"

    -- compile new relative file names
    let outName :: [Char]
outName = PacNameAndVersion -> [Char]
forall a. HasNameAndVersion a => a -> [Char]
getPacName (PacNameAndVersion -> [Char])
-> (PoseidonPackage -> PacNameAndVersion)
-> PoseidonPackage
-> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion (PoseidonPackage -> [Char]) -> PoseidonPackage -> [Char]
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac
    let gz :: [Char]
gz = if Bool
outZip then [Char]
"gz" else [Char]
""
    [[Char]]
outFilesRel <- case GenotypeOutFormatSpec
outFormat of
            GenotypeOutFormatSpec
GenotypeOutFormatEigenstrat -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                [[Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
"geno" [Char] -> [Char] -> [Char]
<.> [Char]
gz, [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
"snp" [Char] -> [Char] -> [Char]
<.> [Char]
gz, [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
"ind"]
            GenotypeOutFormatSpec
GenotypeOutFormatPlink -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                [[Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
"bed" [Char] -> [Char] -> [Char]
<.> [Char]
gz, [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
"bim" [Char] -> [Char] -> [Char]
<.> [Char]
gz, [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
"fam"]
            GenotypeOutFormatSpec
GenotypeOutFormatVCF -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                [[Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
"vcf" [Char] -> [Char] -> [Char]
<.> [Char]
gz]

    -- compile new absolute genotype file names
    [Char]
newBaseDir <- case Maybe [Char]
outPath of
        Just [Char]
x -> do
            -- create new directory
            [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Writing to directory (will be created if missing): " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
x
            IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ Bool -> [Char] -> IO ()
createDirectoryIfMissing Bool
True ([Char] -> [Char]
dropTrailingPathSeparator [Char]
x)
            [Char] -> ReaderT Env IO [Char]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
x
        Maybe [Char]
Nothing -> [Char] -> ReaderT Env IO [Char]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> ReaderT Env IO [Char])
-> [Char] -> ReaderT Env IO [Char]
forall a b. (a -> b) -> a -> b
$ PoseidonPackage -> [Char]
posPacBaseDir PoseidonPackage
pac
    let outFilesAbs :: [[Char]]
outFilesAbs = ([Char] -> [Char]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char]
newBaseDir [Char] -> [Char] -> [Char]
</>) [[Char]]
outFilesRel
    let outFilesAbsTemp :: [[Char]]
outFilesAbsTemp = do -- loop over files
            [Char]
f <- [[Char]]
outFilesAbs
            if [Char] -> [Char]
takeExtension [Char]
f [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char]
".gz" then
                [Char] -> [[Char]]
forall a. a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ [Char]
f [Char] -> [Char] -> [Char]
<.> [Char]
"gconvert" [Char] -> [Char] -> [Char]
<.> [Char]
"gz"
            else [Char] -> [[Char]]
forall a. a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ [Char]
f [Char] -> [Char] -> [Char]
<.> [Char]
"gconvert"

    -- check whether anything needs doing at all
    Bool
allExists <- [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool) -> ReaderT Env IO [Bool] -> ReaderT Env IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([Char] -> ReaderT Env IO Bool)
-> [[Char]] -> ReaderT Env IO [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM [Char] -> ReaderT Env IO Bool
checkFile [[Char]]
outFilesAbs
    if Bool
allExists
    then do
        if Bool
onlyGeno
        then do
            [Char] -> PoseidonIO ()
logError ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"No files were created or overwritten for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
            IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ ExitCode -> IO ()
forall a. ExitCode -> IO a
exitWith (Int -> ExitCode
ExitFailure Int
1)
        else
            [Char] -> PoseidonIO ()
logWarning ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Package already in desired file-type, skipping genotype conversion for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
    else do
        -- Convert!
        [Char] -> PoseidonIO ()
logInfo [Char]
"Processing SNPs..."
        LogA
logA <- PoseidonIO LogA
envLogAction
        UTCTime
currentTime <- IO UTCTime -> ReaderT Env IO UTCTime
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
        ErrorLength
errLength <- PoseidonIO ErrorLength
envErrorLength
        let eigenstratIndEntries :: [EigenstratIndEntry]
eigenstratIndEntries = JannoRows -> [EigenstratIndEntry]
jannoRows2EigenstratIndEntries (JannoRows -> [EigenstratIndEntry])
-> (PoseidonPackage -> JannoRows)
-> PoseidonPackage
-> [EigenstratIndEntry]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> JannoRows
posPacJanno (PoseidonPackage -> [EigenstratIndEntry])
-> PoseidonPackage -> [EigenstratIndEntry]
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac
        let jannoRows :: [JannoRow]
jannoRows = JannoRows -> [JannoRow]
getJannoRows (JannoRows -> [JannoRow]) -> JannoRows -> [JannoRow]
forall a b. (a -> b) -> a -> b
$ PoseidonPackage -> JannoRows
posPacJanno PoseidonPackage
pac
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (
            SafeT IO () -> IO ()
forall (m :: * -> *) r.
(MonadMask m, MonadIO m) =>
SafeT m r -> m r
runSafeT (SafeT IO () -> IO ()) -> SafeT IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
eigenstratProd <- [Char]
-> GenotypeDataSpec
-> SafeT IO (Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ())
forall (m :: * -> *).
MonadSafe m =>
[Char]
-> GenotypeDataSpec
-> m (Producer (EigenstratSnpEntry, GenoLine) m ())
loadGenotypeData (PoseidonPackage -> [Char]
posPacBaseDir PoseidonPackage
pac) (PoseidonPackage -> GenotypeDataSpec
posPacGenotypeData PoseidonPackage
pac)
                let outConsumer :: Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
outConsumer = case GenotypeOutFormatSpec
outFormat of
                        GenotypeOutFormatSpec
GenotypeOutFormatEigenstrat -> [Char]
-> [Char]
-> [Char]
-> [EigenstratIndEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall (m :: * -> *).
MonadSafe m =>
[Char]
-> [Char]
-> [Char]
-> [EigenstratIndEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) m ()
writeEigenstrat ([[Char]]
outFilesAbsTemp [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0)
                                                        ([[Char]]
outFilesAbsTemp [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
1)
                                                        ([[Char]]
outFilesAbsTemp [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
2)
                                                        [EigenstratIndEntry]
eigenstratIndEntries
                        GenotypeOutFormatSpec
GenotypeOutFormatPlink      -> [Char]
-> [Char]
-> [Char]
-> [PlinkFamEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall (m :: * -> *).
MonadSafe m =>
[Char]
-> [Char]
-> [Char]
-> [PlinkFamEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) m ()
writePlink ([[Char]]
outFilesAbsTemp [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0)
                                                   ([[Char]]
outFilesAbsTemp [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
1)
                                                   ([[Char]]
outFilesAbsTemp [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
2)
                                                   ((EigenstratIndEntry -> PlinkFamEntry)
-> [EigenstratIndEntry] -> [PlinkFamEntry]
forall a b. (a -> b) -> [a] -> [b]
map (PlinkPopNameMode -> EigenstratIndEntry -> PlinkFamEntry
eigenstratInd2PlinkFam PlinkPopNameMode
outPlinkPopMode) [EigenstratIndEntry]
eigenstratIndEntries)
                        GenotypeOutFormatSpec
GenotypeOutFormatVCF        -> LogA
-> [JannoRow]
-> [Char]
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall (m :: * -> *).
MonadSafe m =>
LogA
-> [JannoRow]
-> [Char]
-> Consumer (EigenstratSnpEntry, GenoLine) m ()
writeVCF LogA
logA [JannoRow]
jannoRows ([[Char]]
outFilesAbsTemp [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0)
                Effect (SafeT IO) () -> SafeT IO ()
forall (m :: * -> *) r. Monad m => Effect m r -> m r
runEffect (Effect (SafeT IO) () -> SafeT IO ())
-> Effect (SafeT IO) () -> SafeT IO ()
forall a b. (a -> b) -> a -> b
$ Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
eigenstratProd Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
-> Proxy
     ()
     (EigenstratSnpEntry, GenoLine)
     ()
     (EigenstratSnpEntry, GenoLine)
     (SafeT IO)
     ()
-> Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> LogA
-> UTCTime
-> Proxy
     ()
     (EigenstratSnpEntry, GenoLine)
     ()
     (EigenstratSnpEntry, GenoLine)
     (SafeT IO)
     ()
forall (m :: * -> *) a.
MonadIO m =>
LogA -> UTCTime -> Pipe a a m ()
printSNPCopyProgress LogA
logA UTCTime
currentTime Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
-> Effect (SafeT IO) ()
forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
outConsumer
            ) (PoseidonException -> IO ()
forall e a. Exception e => e -> IO a
throwIO (PoseidonException -> IO ())
-> (SomeException -> PoseidonException) -> SomeException -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ErrorLength -> SomeException -> PoseidonException
PoseidonGenotypeExceptionForward ErrorLength
errLength)
        -- the following will just overwrite if the file already exists, which is OK
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ())
-> ((([Char], [Char]) -> IO ()) -> IO ())
-> (([Char], [Char]) -> IO ())
-> PoseidonIO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [([Char], [Char])] -> (([Char], [Char]) -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ ([[Char]] -> [[Char]] -> [([Char], [Char])]
forall a b. [a] -> [b] -> [(a, b)]
zip [[Char]]
outFilesAbs [[Char]]
outFilesAbsTemp) ((([Char], [Char]) -> IO ()) -> PoseidonIO ())
-> (([Char], [Char]) -> IO ()) -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ \([Char]
fn, [Char]
fnTemp) ->
            [Char] -> [Char] -> IO ()
renameFile [Char]
fnTemp [Char]
fn
        [Char] -> PoseidonIO ()
logInfo [Char]
"Done"

    -- overwrite genotype data field in POSEIDON.yml file (using relative paths)
    Bool -> PoseidonIO () -> PoseidonIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool
onlyGeno Bool -> Bool -> Bool
|| Maybe [Char] -> Bool
forall a. Maybe a -> Bool
isJust Maybe [Char]
outPath) (PoseidonIO () -> PoseidonIO ()) -> PoseidonIO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ do
        GenotypeFileSpec
gFileSpec <- case GenotypeOutFormatSpec
outFormat of
                GenotypeOutFormatSpec
GenotypeOutFormatEigenstrat -> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec)
-> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$
                    [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> GenotypeFileSpec
GenotypeEigenstrat ([[Char]]
outFilesRel [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0) Maybe [Char]
forall a. Maybe a
Nothing ([[Char]]
outFilesRel [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
1) Maybe [Char]
forall a. Maybe a
Nothing ([[Char]]
outFilesRel [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
2) Maybe [Char]
forall a. Maybe a
Nothing
                GenotypeOutFormatSpec
GenotypeOutFormatPlink      -> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec)
-> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$
                    [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> GenotypeFileSpec
GenotypePlink      ([[Char]]
outFilesRel [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0) Maybe [Char]
forall a. Maybe a
Nothing ([[Char]]
outFilesRel [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
1) Maybe [Char]
forall a. Maybe a
Nothing ([[Char]]
outFilesRel [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
2) Maybe [Char]
forall a. Maybe a
Nothing
                GenotypeOutFormatSpec
GenotypeOutFormatVCF        -> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec)
-> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$ [Char] -> Maybe [Char] -> GenotypeFileSpec
GenotypeVCF ([[Char]]
outFilesRel [[Char]] -> Int -> [Char]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0) Maybe [Char]
forall a. Maybe a
Nothing
        let newGenotypeData :: GenotypeDataSpec
newGenotypeData = GenotypeFileSpec -> Maybe SNPSetSpec -> GenotypeDataSpec
GenotypeDataSpec GenotypeFileSpec
gFileSpec (GenotypeDataSpec -> Maybe SNPSetSpec
genotypeSnpSet (GenotypeDataSpec -> Maybe SNPSetSpec)
-> (PoseidonPackage -> GenotypeDataSpec)
-> PoseidonPackage
-> Maybe SNPSetSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> GenotypeDataSpec
posPacGenotypeData (PoseidonPackage -> Maybe SNPSetSpec)
-> PoseidonPackage -> Maybe SNPSetSpec
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac)
            newPac :: PoseidonPackage
newPac = PoseidonPackage
pac { posPacGenotypeData = newGenotypeData }
        [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Adjusting POSEIDON.yml for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ PoseidonPackage -> IO ()
writePoseidonPackage PoseidonPackage
newPac
        -- delete now replaced input genotype data
    Bool -> PoseidonIO () -> PoseidonIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
removeOld (PoseidonIO () -> PoseidonIO ()) -> PoseidonIO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ do
        let oldBaseDir :: [Char]
oldBaseDir = PoseidonPackage -> [Char]
posPacBaseDir PoseidonPackage
pac
        [[Char]]
oldGenoFiles <- case GenotypeDataSpec -> GenotypeFileSpec
genotypeFileSpec (GenotypeDataSpec -> GenotypeFileSpec)
-> (PoseidonPackage -> GenotypeDataSpec)
-> PoseidonPackage
-> GenotypeFileSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> GenotypeDataSpec
posPacGenotypeData (PoseidonPackage -> GenotypeFileSpec)
-> PoseidonPackage -> GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac of
                GenotypeEigenstrat [Char]
g Maybe [Char]
_ [Char]
s Maybe [Char]
_ [Char]
i Maybe [Char]
_ -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
g, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
s, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
i]
                GenotypePlink      [Char]
g Maybe [Char]
_ [Char]
s Maybe [Char]
_ [Char]
i Maybe [Char]
_ -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
g, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
s, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
i]
                GenotypeVCF        [Char]
g Maybe [Char]
_         -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
g]
        let filesToDelete :: [[Char]]
filesToDelete = [[Char]]
oldGenoFiles [[Char]] -> [[Char]] -> [[Char]]
forall a. Eq a => [a] -> [a] -> [a]
\\ [[Char]]
outFilesAbs
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ())
-> ([[Char]] -> IO ()) -> [[Char]] -> PoseidonIO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> IO ()) -> [[Char]] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ [Char] -> IO ()
removeFile ([[Char]] -> PoseidonIO ()) -> [[Char]] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [[Char]]
filesToDelete
  where
    checkFile :: FilePath -> PoseidonIO Bool
    checkFile :: [Char] -> ReaderT Env IO Bool
checkFile [Char]
fn = do
        Bool
fe <- IO Bool -> ReaderT Env IO Bool
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> ReaderT Env IO Bool) -> IO Bool -> ReaderT Env IO Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> IO Bool
doesFileExist [Char]
fn
        Bool -> PoseidonIO () -> PoseidonIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
fe (PoseidonIO () -> PoseidonIO ()) -> PoseidonIO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char] -> PoseidonIO ()
logWarning ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"File " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
fn [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" exists"
        Bool -> ReaderT Env IO Bool
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
fe