-- | Demo tutorial, accessed with --demo
module Development.Shake.Internal.Demo(demo) where

import Development.Shake.Internal.Paths
import Development.Shake.Command

import Control.Exception.Extra
import Control.Monad
import Data.List.Extra
import Data.Maybe
import System.Directory
import System.Exit
import System.FilePath
import General.Extra
import Development.Shake.FilePath(exe)
import System.IO
import System.Info.Extra


demo :: Bool -> IO ()
demo :: Bool -> IO ()
demo Bool
auto = do
    Handle -> BufferMode -> IO ()
hSetBuffering Handle
stdout BufferMode
NoBuffering
    String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"% Welcome to the Shake v" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
shakeVersionString String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" demo mode!"

    String -> IO ()
putStr String
"% Detecting machine configuration... "
    Bool
hasManual <- IO Bool
hasManualData
    Bool
ghc <- Maybe String -> Bool
forall a. Maybe a -> Bool
isJust (Maybe String -> Bool) -> IO (Maybe String) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (Maybe String)
findExecutable String
"ghc"
    (Bool
gcc, Maybe String
gccPath) <- IO (Bool, Maybe String)
findGcc
    Bool
shakeLib <- IO Bool -> IO Bool
wrap (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ (Stdout String -> Bool) -> IO (Stdout String) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool -> Bool
not (Bool -> Bool) -> (Stdout String -> Bool) -> Stdout String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([String] -> Bool)
-> (Stdout String -> [String]) -> Stdout String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
words (String -> [String])
-> (Stdout String -> String) -> Stdout String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Stdout String -> String
forall a. Stdout a -> a
fromStdout) (String -> IO (Stdout String)
forall args r. (Partial, CmdArguments args) => args
cmd (String
"ghc-pkg list --simple-output shake" :: String))
    Maybe String
ninja <- String -> IO (Maybe String)
findExecutable String
"ninja"
    String -> IO ()
putStrLn String
"done\n"

    let path :: String
path = if Bool
isWindows then String
"%PATH%" else String
"$PATH"
    Bool -> String -> IO ()
require Bool
ghc (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"% You don't have 'ghc' on your " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
path String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", which is required to run the demo."
    Bool -> String -> IO ()
require Bool
gcc (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"% You don't have 'gcc' on your " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
path String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", which is required to run the demo."
    Bool -> String -> IO ()
require Bool
shakeLib String
"% You don't have the 'shake' library installed with GHC, which is required to run the demo."
    Bool -> String -> IO ()
require Bool
hasManual String
"% You don't have the Shake data files installed, which are required to run the demo."

    Bool
empty <- (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ((Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'.')) ([String] -> Bool) -> IO [String] -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [String]
getDirectoryContents String
"."
    String
dir <- if Bool
empty then IO String
getCurrentDirectory else do
        String
home <- IO String
getHomeDirectory
        [String]
dir <- String -> IO [String]
getDirectoryContents String
home
        String -> IO String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ String
home String -> String -> String
</> [String] -> String
forall a. [a] -> a
head ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
"shake-demo" String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String
""String -> [String] -> [String]
forall a. a -> [a] -> [a]
:(Integer -> String) -> [Integer] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> String
forall a. Show a => a -> String
show [Integer
2..]) [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String]
dir)

    String -> IO ()
putStrLn String
"% The Shake demo uses an empty directory, OK to use:"
    String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"%     " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
dir
    Bool
b <- Bool -> IO Bool
yesNo Bool
auto
    Bool -> String -> IO ()
require Bool
b String
"% Please create an empty directory to run the demo from, then run 'shake --demo' again."

    String -> IO ()
putStr String
"% Copying files... "
    String -> IO ()
copyManualData String
dir
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
isWindows (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
         Permissions
p <- String -> IO Permissions
getPermissions (String -> IO Permissions) -> String -> IO Permissions
forall a b. (a -> b) -> a -> b
$ String
dir String -> String -> String
</> String
"build.sh"
         String -> Permissions -> IO ()
setPermissions (String
dir String -> String -> String
</> String
"build.sh") Permissions
p{executable :: Bool
executable=Bool
True}
    String -> IO ()
putStrLn String
"done"

    let pause :: IO String
pause = do
            String -> IO ()
putStr String
"% Press ENTER to continue: "
            if Bool
auto then String -> IO String
putLine String
"" else