{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving, DeriveDataTypeable #-}moduleDevelopment.Shake.File(FilePattern,need,want,defaultRuleFile,(?==),(*>),(**>),(?>))whereimportControl.Monad.IO.ClassimportData.BinaryimportData.HashableimportData.ListimportData.MaybeimportData.TypeableimportSystem.DirectoryimportSystem.TimeimportDevelopment.Shake.CoreimportSystem.FilePath(takeDirectory)-- | A type synonym for file patterns, containing @\/\/@ and @*@. For the syntax-- and semantics of 'FilePattern' see '?=='.typeFilePattern=StringnewtypeFile=FileFilePathderiving(Typeable,Eq,Hashable,Binary)newtypeFileTime=FileTimeIntderiving(Typeable,Show,Eq,Hashable,Binary)instanceShowFilewhereshow(Filex)=xgetFileTime::FilePath->IO(MaybeFileTime)getFileTimex=dob<-doesFileExistxifnotbthenreturnNothingelsedoTODt_<-getModificationTimexreturn$Just$FileTime$fromIntegraltinstanceRuleFileFileTimewherevalidStored(Filex)t=fmap(==Justt)$getFileTimex-- | This function is not actually exported, but Haddock is buggy. Please ignore.defaultRuleFile::Rules()defaultRuleFile=defaultRule$\(Filex)->Just$dores<-liftIO$getFileTimexletmsg="Error, file does not exist and no available rule: "++xreturn$fromMaybe(errormsg)res-- | Require that the following files are built before continuing. Particularly-- necessary when calling 'system''. As an example:---- > "//*.rot13" *> \out -> do-- > let src = dropExtension out-- > need [src]-- > system' ["rot13",src,"-o",out]need::[FilePath]->Action()needxs=(apply$mapFilexs::Action[FileTime])>>return()-- | Require that the following are built by the rules, used to specify the target.---- > main = shake shakeOptions $ do-- > want ["Main.exe"]-- > ...---- This program will build @Main.exe@, given sufficient rules.want::[FilePath]->Rules()wantxs=action$needxs-- | Define a rule to build files. If the first argument returns 'True' for a given file,-- the second argument will be used to build it. Usually '*>' is sufficient, but '?>' gives-- additional power. For any file used by the build system, only one rule should return 'True'.---- > (all isUpper . takeBaseName) *> \out -> do-- > let src = replaceBaseName out $ map toLower $ takeBaseName out-- > writeFile' . map toUpper =<< readFile' src(?>)::(FilePath->Bool)->(FilePath->Action())->Rules()(?>)testact=rule$\(Filex)->ifnot$testxthenNothingelseJust$doliftIO$createDirectoryIfMissingTrue$takeDirectoryxactxres<-liftIO$getFileTimexletmsg="Error, rule failed to build the file: "++xreturn$fromMaybe(errormsg)res-- | Define a set of patterns, and if any of them match, run the associate rule. See '*>'.(**>)::[FilePattern]->(FilePath->Action())->Rules()(**>)testact=(\x->any(x?==)test)?>act-- | Define a rule that matches a 'FilePattern'. No file required by the system must be-- matched by more than one pattern. For the pattern rules, see '?=='.---- > "*.asm.o" *> \out -> do-- > let src = dropExtension out-- > need [src]-- > system' ["as",src,"-o",out]---- To define a build system for multiple compiled languages, we recommend using @.asm.o@,-- @.cpp.o@, @.hs.o@, to indicate which language produces an object file.(*>)::FilePattern->(FilePath->Action())->Rules()(*>)testact=(test?==)?>act-- | Match a 'FilePattern' against a 'FilePath', There are only two special forms:---- * @*@ matches an entire path component, excluding any separators.---- * @\/\/@ matches an arbitrary number of path componenets.---- Some examples that match:---- > "//*.c" ?== "foo/bar/baz.c"-- > "*.c" ?== "baz.c"-- > "test.c" ?== "test.c"(?==)::FilePattern->FilePath->Bool(?==)('/':'/':x)y=any(x?==)$y:[i|'/':i<-tailsy](?==)('*':x)y=any(x?==)$a++take1bwhere(a,b)=break("/"`isPrefixOf`)$tailsy(?==)(x:xs)(y:ys)|x==y=xs?==ys(?==)[][]=True(?==)__=False