{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving, DeriveDataTypeable, ScopedTypeVariables #-}moduleDevelopment.Shake.Files((?>>),(*>>))whereimportControl.DeepSeqimportControl.MonadimportControl.Monad.IO.ClassimportData.BinaryimportData.HashableimportData.MaybeimportData.TypeableimportqualifiedData.ByteString.Char8asBSimportDevelopment.Shake.CoreimportDevelopment.Shake.FileimportDevelopment.Shake.FilePatternimportDevelopment.Shake.FileTimeinfix1?>>,*>>newtypeFiles=Files[BS.ByteString]deriving(Typeable,Eq,Hashable,Binary)instanceNFDataFileswherernf(Filesxs)=fxswheref[]=()f(x:xs)=x`seq`fxsnewtypeFileTimes=FileTimes[FileTime]deriving(Typeable,Show,Eq,Hashable,Binary,NFData)instanceShowFileswhereshow(Filesxs)=unwords$mapBS.unpackxsinstanceRuleFilesFileTimeswherevalidStored(Filesxs)(FileTimests)=fmap(==mapJustts)$mapMgetModTimeMaybexs-- | Define a rule for building multiple files at the same time.-- As an example, a single invokation of GHC produces both @.hi@ and @.o@ files:---- @-- [\"*.o\",\"*.hi\"] '*>>' \\[o,hi] -> do-- let hs = 'Development.Shake.FilePath.replaceExtension' o \"hs\"-- 'Development.Shake.need' ... -- all files the .hs import-- 'Development.Shake.system'' \"ghc\" [\"-c\",hs]-- @---- However, in practice, it's usually easier to define rules with '*>' and make the @.hi@ depend-- on the @.o@. When defining rules that build multiple files, all the 'FilePattern' values must-- have the same sequence of @\/\/@ and @*@ wildcards in the same order.(*>>)::[FilePattern]->([FilePath]->Action())->Rules()ps*>>act|not$compatibleps=error$"All patterns to *>> must have the same number and position of // and * wildcards\n"++unwordsps|otherwise=doforM_ps$\p->p*>\file->do_::FileTimes<-apply1$Files$map(BS.pack.substitute(extractpfile))psreturn()rule$\(Filesxs_)->letxs=mapBS.unpackxs_inifnot$lengthxs==lengthps&&and(zipWith(?==)psxs)thenNothingelseJust$doactxsliftIO$getFileTimes"*>>"xs_-- | Define a rule for building multiple files at the same time, a more powerful-- and more dangerous version of '*>>'.---- Given an application @test ?>> ...@, @test@ should return @Just@ if the rule applies, and should-- return the list of files that will be produced. This list /must/ include the file passed as an argument and should-- obey the invariant:---- > test x == Just ys ==> x `elem` ys && all ((== Just ys) . test) ys---- As an example of a function satisfying the invariaint:---- > test x | takeExtension x `elem` [".hi",".o"]-- > = Just [dropExtension x <.> "hi", dropExtension x <.> "o"]-- > test _ = Nothing---- Regardless of whether @Foo.hi@ or @Foo.o@ is passed, the function always returns @[Foo.hi, Foo.o]@.(?>>)::(FilePath->Maybe[FilePath])->([FilePath]->Action())->Rules()(?>>)testact=doletcheckedTestx=casetestxofNothing->NothingJustys|x`elem`ys&&all((==Justys).test)ys->Justys|otherwise->error$"Invariant broken in ?>> when trying on "++xisJust.checkedTest?>\x->do_::FileTimes<-apply1$Files$mapBS.pack$fromJust$testxreturn()rule$\(Filesxs_)->letxs@(x:_)=mapBS.unpackxs_incasecheckedTestxofJustys|ys==xs->Just$doactxsliftIO$getFileTimes"?>>"xs_Justys->error$"Error, ?>> is incompatible with "++showxs++" vs "++showysNothing->NothinggetFileTimes::String->[BS.ByteString]->IOFileTimesgetFileTimesnamexs=doys<-mapMgetModTimeMaybexscasesequenceysofJustys->return$FileTimesysNothing->doletmissing=length$filterisNothingyserror$"Error, "++name++" rule failed to build "++showmissing++" file"++(ifmissing==1then""else"s")++" (out of "++show(lengthxs)++")"++concat["\n "++BS.unpackx++ifisNothingythen" - MISSING"else""|(x,y)<-zipxsys]