-- | Demo tutorial, accessed with --demomoduleDevelopment.Shake.Internal.Demo(demo )whereimportDevelopment.Shake.Internal.Paths importDevelopment.Shake.Command importControl.Exception.ExtraimportControl.MonadimportData.CharimportData.ListimportData.MaybeimportSystem.DirectoryimportSystem.ExitimportSystem.FilePathimportGeneral.Extra importDevelopment.Shake.FilePath (exe )importSystem.IOimportSystem.Info.Extrademo::Bool->IO()demo auto =dohSetBufferingstdoutNoBufferingputStrLn$"% Welcome to the Shake v"++shakeVersionString ++" demo mode!"putStr"% Detecting machine configuration... "hasManual <-hasManualData ghc <-isJust<$>findExecutable"ghc"(gcc ,gccPath )<-findGcc shakeLib <-wrap $fmap(not.null.words.fromStdout)(cmd "ghc-pkg list --simple-output shake")ninja <-findExecutable"ninja"putStrLn"done\n"letpath =ifisWindowsthen"%PATH%"else"$PATH"require ghc $"% You don't have 'ghc' on your "++path ++", which is required to run the demo."require gcc $"% You don't have 'gcc' on your "++path ++", which is required to run the demo."require shakeLib "% You don't have the 'shake' library installed with GHC, which is required to run the demo."require hasManual "% You don't have the Shake data files installed, which are required to run the demo."empty <-all(all(=='.'))<$>getDirectoryContents"."dir <-ifempty thengetCurrentDirectoryelsedohome <-getHomeDirectorydir <-getDirectoryContentshome return$home </>head(map("shake-demo"++)("":mapshow[2..])\\dir )putStrLn"% The Shake demo uses an empty directory, OK to use:"putStrLn$"% "++dir b <-yesNo auto require b "% Please create an empty directory to run the demo from, then run 'shake --demo' again."putStr"% Copying files... "copyManualData dir unlessisWindows$dop <-getPermissions$dir </>"build.sh"setPermissions(dir </>"build.sh")p {executable=True}putStrLn"done"letpause =doputStr"% Press ENTER to continue: "ifauto thenputLine ""elsegetLineletexecute x =doputStrLn$"% RUNNING: "++x cmd (Cwd dir )(AddPath [](maybeToListgccPath ))Shell x ::IO()letbuild =ifisWindowsthen"build"else"./build.sh"putStrLn"\n% [1/5] Building an example project with Shake."pause putStrLn$"% RUNNING: cd "++dir execute build putStrLn"\n% [2/5] Running the produced example."pause execute $"_build"</>"run"<.>exe putStrLn"\n% [3/5] Rebuilding an example project with Shake (nothing should change)."pause execute build putStrLn"\n% [4/5] Cleaning the build."pause execute $build ++" clean"putStrLn"\n% [5/5] Rebuilding with 2 threads and profiling."pause execute $build ++" -j2 --report --report=-"putStrLn"\n% See the profiling summary above, or look at the HTML profile report in"putStrLn$"% "++dir </>"report.html"putStrLn"\n% Demo complete - all the examples can be run from:"putStrLn$"% "++dir putStrLn"% For more info see https://shakebuild.com"when(isJustninja )$doputStrLn"\n% PS. Shake can also execute Ninja build files"putStrLn"% For more info see https://shakebuild.com/ninja"-- | Require the user to press @y@ before continuing.yesNo::Bool->IOBoolyesNo auto =doputStr"% [Y/N] (then ENTER): "x <-ifauto thenputLine "y"elsefmap(maptoLower)getLineif"y"`isPrefixOf`x thenreturnTrueelseif"n"`isPrefixOf`x thenreturnFalseelseyesNo auto putLine::String->IOStringputLine x =putStrLnx >>returnx -- | Replace exceptions with 'False'.wrap::IOBool->IOBoolwrap act =act `catch_`const(returnFalse)-- | Require a condition to be true, or exit with a message.require::Bool->String->IO()require b msg =unlessb $putStrLnmsg >>exitFailure