    -- | 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 a b. (a -> b) -> IO a -> IO b
    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 a. [a] -> 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 a. a -> IO a
    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. Partial => [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 IO String
    getLine
        let execute :: String -> IO ()
    execute String
    x = do
                String -> IO ()
    putStrLn (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    "% RUNNING: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    x
                CmdOption -> CmdOption -> CmdOption -> String -> IO ()
    forall args r. (Partial, CmdArguments args) => args
    cmd (String -> CmdOption
    Cwd String
    dir) ([String] -> [String] -> CmdOption
    AddPath [] (Maybe String -> [String]
    forall a. Maybe a -> [a]
    maybeToList Maybe String
    gccPath)) CmdOption
    Shell String
    x :: IO ()
        let build :: String
    build = if Bool
    isWindows then String
    "build" else String
    "./build.sh"

        String -> IO ()
    putStrLn String
    "\n% [1/5] Building an example project with Shake."
        IO String
    pause
        String -> IO ()
    putStrLn (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    "% RUNNING: cd " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    dir
        String -> IO ()
    execute String
    build

        String -> IO ()
    putStrLn String
    "\n% [2/5] Running the produced example."
        IO String
    pause
        String -> IO ()
    execute (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    "_build" String -> String -> String
    </> String
    "run" String -> String -> String
    <.> String
    exe

        String -> IO ()
    putStrLn String
    "\n% [3/5] Rebuilding an example project with Shake (nothing should change)."
        IO String
    pause
        String -> IO ()
    execute String
    build

        String -> IO ()
    putStrLn String
    "\n% [4/5] Cleaning the build."
        IO String
    pause
        String -> IO ()
    execute (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    build String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " clean"

        String -> IO ()
    putStrLn String
    "\n% [5/5] Rebuilding with 2 threads and profiling."
        IO String
    pause
        String -> IO ()
    execute (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    build String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " -j2 --report --report=-"
        String -> IO ()
    putStrLn String
    "\n% See the profiling summary above, or look at the HTML profile report in"
        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 String -> String -> String
    </> String
    "report.html"

        String -> IO ()
    putStrLn String
    "\n% Demo complete - all the examples can be run from:"
        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
        String -> IO ()
    putStrLn String
    "% For more info see https://shakebuild.com"
        Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Maybe String -> Bool
    forall a. Maybe a -> Bool
    isJust Maybe String
    ninja) (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ do
            String -> IO ()
    putStrLn String
    "\n% PS. Shake can also execute Ninja build files"
            String -> IO ()
    putStrLn String
    "% For more info see https://shakebuild.com/ninja"

    -- | Require the user to press @y@ before continuing.
    yesNo :: Bool -> IO Bool
    yesNo :: Bool -> IO Bool
    yesNo Bool
    auto = do
        String -> IO ()
    putStr String
    "% [Y/N] (then ENTER): "
        String
    x <- if Bool
    auto then String -> IO String
    putLine String
    "y" else String -> String
    lower (String -> String) -> IO String -> IO String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO String
    getLine
        if String
    "y" String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` String
    x then
            Bool -> IO Bool
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Bool
    True
         else if String
    "n" String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` String
    x then
            Bool -> IO Bool
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Bool
    False
         else
            Bool -> IO Bool
    yesNo Bool
    auto

    putLine :: String -> IO String
    putLine :: String -> IO String
    putLine String
    x = String -> IO ()
    putStrLn String
    x IO () -> IO String -> IO String
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> String -> IO String
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure String
    x

    -- | Replace exceptions with 'False'.
    wrap :: IO Bool -> IO Bool
    wrap :: IO Bool -> IO Bool
    wrap IO Bool
    act = IO Bool
    act IO Bool -> (SomeException -> IO Bool) -> IO Bool
    forall a. IO a -> (SomeException -> IO a) -> IO a
    `catch_` IO Bool -> SomeException -> IO Bool
    forall a b. a -> b -> a
    const (Bool -> IO Bool
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Bool
    False)

    -- | Require a condition to be true, or exit with a message.
    require :: Bool -> String -> IO ()
    require :: Bool -> String -> IO ()
    require Bool
    b String
    msg = Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless Bool
    b (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String -> IO ()
    putStrLn String
    msg IO () -> IO () -> IO ()
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> IO ()
    forall a. IO a
    exitFailure