packages feed

shake 0.7 → 0.8

raw patch · 7 files changed

+118/−56 lines, 7 files

Files

Development/Shake/Directory.hs view
@@ -119,18 +119,32 @@     return res  -- | Get the contents of a directory. The result will be sorted, and will not contain---   the files @.@ or @..@ (unlike the standard Haskell version). It is usually better to---   call either 'getDirectoryFiles' or 'getDirectoryDirs'. The resulting paths will be relative+--   the entries @.@ or @..@ (unlike the standard Haskell version). The resulting paths will be relative --   to the first argument.+--+--   It is usually simpler to call either 'getDirectoryFiles' or 'getDirectoryDirs'. getDirectoryContents :: FilePath -> Action [FilePath] getDirectoryContents x = getDirAction $ GetDir x --- | Get the files in a directory that match any of a set of patterns.---   For the interpretation of the pattern see '?=='.+-- | Get the files anywhere under a directory that match any of a set of patterns.+--   For the interpretation of the patterns see '?=='. All results will be+--   relative to the 'FilePath' argument. Some examples:+--+-- > getDirectoryFiles "Config" ["//*.xml"]+-- >     -- All .xml files anywhere under the Config directory+-- >     -- If Config/foo/bar.xml exists it will return ["foo/bar.xml"]+-- > getDirectoryFiles "Modules" ["*.hs","*.lhs"]+-- >     -- All .hs or .lhs in the Modules directory+-- >     -- If Modules/foo.hs and Modules/foo.lhs exist, it will return ["foo.hs","foo.lhs"] getDirectoryFiles :: FilePath -> [FilePattern] -> Action [FilePath] getDirectoryFiles x f = getDirAction $ GetDirFiles x f --- | Get the directories contained by a directory, does not include @.@ or @..@.+-- | Get the directories in a directory, not including @.@ or @..@.+--   All directories are relative to the argument directory.+--+-- > getDirectoryDirs "/Users"+-- >    -- Return all directories in the /Users directory+-- >    -- e.g. ["Emily","Henry","Neil"] getDirectoryDirs :: FilePath -> Action [FilePath] getDirectoryDirs x = getDirAction $ GetDirDirs x @@ -139,6 +153,7 @@ contents :: FilePath -> IO [FilePath] contents = fmap (filter $ not . all (== '.')) . IO.getDirectoryContents + answer :: [FilePath] -> GetDirectoryA answer = GetDirectoryA . sort @@ -148,5 +163,25 @@ getDir GetDirDirs{..} = fmap answer $ filterM f =<< contents dir     where f x = IO.doesDirectoryExist $ dir </> x -getDir GetDirFiles{..} = fmap answer $ filterM f =<< contents dir-    where f x = if not $ any (?== x) pat then return False else IO.doesFileExist $ dir </> x+getDir GetDirFiles{..} = fmap answer $ concatMapM f $ directories pat+    where+        test = let ps = map (?==) pat in \x -> any ($ x) ps++        f (dir2,False) = do+            xs <- fmap (map (dir2 </>)) $ contents $ dir </> dir2+            flip filterM xs $ \x -> if not $ test x then return False else IO.doesFileExist $ dir </> x++        f (dir2,True) = do+            xs <- fmap (map (dir2 </>)) $ contents $ dir </> dir2+            (files,dirs) <- partitionM (\x -> IO.doesFileExist $ dir </> x) xs+            rest <- concatMapM (\d -> f (d, True)) dirs+            return $ filter test files ++ rest+++concatMapM f xs = fmap concat $ mapM f xs++partitionM f [] = return ([], [])+partitionM f (x:xs) = do+    t <- f x+    (a,b) <- partitionM f xs+    return $ if t then (x:a,b) else (a,x:b)
Development/Shake/Locks.hs view
@@ -67,7 +67,7 @@ --------------------------------------------------------------------- -- RESOURCE --- | The type representing a finite resource, which multiple build actions should respect.+-- | A type representing a finite resource, which multiple build actions should respect. --   Created with 'newResource' in the 'IO' monad before calling 'Development.Shake.shake', --   and used with 'Development.Shake.withResource' in the 'Development.Shake.Action' monad --   when defining rules.
Development/Shake/Oracle.hs view
@@ -32,30 +32,32 @@     storedValue _ = return Nothing  --- | Add extra information which your build should depend on. For example:+-- | Add extra information which rules can depend on.+--   An oracle is a function from a question type @q@, to an answer type @a@.+--   As an example, we can define an oracle allowing you to depend on the current version of GHC: -- -- @ -- newtype GhcVersion = GhcVersion () deriving (Show,Typeable,Eq,Hashable,Binary,NFData)--- 'addOracle' $ \\(GhcVersion _) -> return \"7.2.1\"+-- 'addOracle' $ \\(GhcVersion _) -> fmap (last . words . fst) $ 'Development.Shake.systemOutput' \"ghc\" [\"--version\"] -- @ -----   If a rule depends on the GHC version, it can use @'askOracle' (GhcVersion ())@, and---   if the GHC version changes, the rule will rebuild. We use a @newtype@ around @()@ to---   allow the use of @GeneralizedNewtypeDeriving@. It is common for the value returned---   by 'askOracle' to be ignored, in which case 'askOracleWith' may help avoid ambiguous type---   messages -- although a wrapper function with an explicit type is encouraged.---   The result of 'addOracle' is simply 'askOracle' restricted to the specific type of the added oracle.---   To import all the type classes required see "Development.Shake.Classes".+--   If a rule calls @'askOracle' (GhcVersion ())@, that rule will be rerun whenever the GHC version changes.+--   Some notes: -----   We require that each call to 'addOracle' uses a different type of @question@ from any---   other calls in a given set of 'Rule's, otherwise a runtime error will be raised.+-- * We define @GhcVersion@ with a @newtype@ around @()@, allowing the use of @GeneralizedNewtypeDeriving@.+--   All the necessary type classes are exported from "Development.Shake.Classes". -----   Actions passed to 'addOracle' will be run in every build they are required,+-- * Each call to 'addOracle' must use a different type of question.+--+-- * Actions passed to 'addOracle' will be run in every build they are required, --   but if their value does not change they will not invalidate any rules depending on them.---   To get a similar behaviour using files, see 'Development.Shake.alwaysRerun'.+--   To get a similar behaviour using data stored in files, see 'Development.Shake.alwaysRerun'. -----   As an example, consider tracking package versions installed with GHC:+-- * If the value returned by 'askOracle' is ignored then 'askOracleWith' may help avoid ambiguous type messages.+--   Alternatively, use the result of 'addOracle', which is 'askOracle' restricted to the correct type. --+--   As a more complex example, consider tracking Haskell package versions:+-- -- @ --newtype GhcPkgList = GhcPkgList () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) --newtype GhcPkgVersion = GhcPkgVersion String deriving (Show,Typeable,Eq,Hashable,Binary,NFData)@@ -85,7 +87,7 @@     return askOracle  --- | Get information previously added with 'addOracle', the @question@/@answer@ types must match those provided+-- | Get information previously added with 'addOracle'. The question/answer types must match those provided --   to 'addOracle'. askOracle :: ( #if __GLASGOW_HASKELL__ >= 704@@ -97,8 +99,8 @@     ) => q -> Action a askOracle question = do OracleA answer <- apply1 $ OracleQ question; return answer --- | Get information previously added with 'addOracle'. The second argument is unused, but can---   be useful to avoid ambiguous type error messages.+-- | Get information previously added with 'addOracle'. The second argument is not used, but can+--   be useful to fix the answer type, avoiding ambiguous type error messages. askOracleWith :: ( #if __GLASGOW_HASKELL__ >= 704     ShakeValue q, ShakeValue a
Development/Shake/Types.hs view
@@ -79,7 +79,7 @@         --   Can be used to implement @make --touch@.     ,shakeAbbreviations :: [(String,String)]         -- ^ Defaults to @[]@. A list of substrings that should be abbreviated in status messages, and their corresponding abbreviation.-        --   Commonly used to replace the long paths (e.g. @.make/i586-linux-gcc/output@) with an abbreviation (e.g. @$OUT@).+        --   Commonly used to replace the long paths (e.g. @.make\/i586-linux-gcc\/output@) with an abbreviation (e.g. @$OUT@).     ,shakeProgress :: IO Progress -> IO ()         -- ^ Defaults to no action. A function called on a separate thread when the build starts, allowing progress to be reported.         --   For applications that want to display progress messages, 'progressSimple' is often sufficient, but more advanced
Examples/Test/Directory.hs view
@@ -2,39 +2,62 @@ module Examples.Test.Directory(main) where  import Development.Shake+import Development.Shake.FilePath import Examples.Util import System.Directory(createDirectory)+import Data.List  +    -- Use escape characters, _o=* _l=/ __=<space>+readEsc ('_':'o':xs) = '*' : readEsc xs+readEsc ('_':'l':xs) = '/' : readEsc xs+readEsc ('_':'_':xs) = ' ' : readEsc xs+readEsc (x:xs) = x : readEsc xs+readEsc [] = []++showEsc = concatMap f+    where f '*' = "_o"+          f '/' = "_l"+          f ' ' = "__"+          f x = [x]++ main = shaken test $ \args obj -> do-    want $ map obj ["files.lst","dirs.lst","exist.lst","foodirexist.lst"]-    obj "files.lst" *> \out -> do-        x <- getDirectoryFiles (obj "") ["*.txt"]-        writeFileLines out x-    obj "dirs.lst" *> \out -> do-        x <- getDirectoryDirs (obj "")-        writeFileLines out x-    obj "exist.lst" *> \out -> do-        xs <- readFileLines $ obj "files.lst"-        ys <- mapM (doesFileExist . obj) $ xs ++ map reverse xs-        writeFileLines out $ map show ys-    obj "foodirexist.lst" *> \out -> do-        x <- doesDirectoryExist $ obj "Foo.txt"-        writeFileLines out [show x]+    want $ map obj args+    obj "*.contents" *> \out ->+        writeFileLines out =<< getDirectoryContents (obj $ readEsc $ dropExtension $ unobj out)+    obj "*.dirs" *> \out ->+        writeFileLines out =<< getDirectoryDirs (obj $ readEsc $ dropExtension $ unobj out)+    obj "*.files" *> \out -> do+        let pats = readEsc $ dropExtension $ unobj out+        let (x:xs) = ["" | " " `isPrefixOf` pats] ++ words pats+        writeFileLines out =<< getDirectoryFiles (obj x) xs +    obj "*.exist" *> \out -> do+        let xs = map obj $ words $ readEsc $ dropExtension $ unobj out+        fs <- mapM doesFileExist xs+        ds <- mapM doesDirectoryExist xs+        let bool x = if x then "1" else "0"+        writeFileLines out $ zipWith (\a b -> bool a ++ bool b) fs ds++ test build obj = do+    let demand x ys = let f = showEsc x in do build [f]; assertContents (obj f) $ unlines $ words ys     build ["clean"]-    build []-    assertContents (obj "files.lst") $ unlines []-    assertContents (obj "dirs.lst") $ unlines []-    assertContents (obj "exist.lst") $ unlines []-    assertContents (obj "foodirexist.lst") $ unlines ["False"]+    demand " *.txt.files" ""+    demand " //*.txt.files" ""+    demand ".dirs" ""+    demand "A.txt B.txt C.txt.exist" "00 00 00"      writeFile (obj "A.txt") ""     writeFile (obj "B.txt") ""-    createDirectory (obj "Foo.txt")-    build ["--sleep"]-    assertContents (obj "files.lst") $ unlines ["A.txt","B.txt"]-    assertContents (obj "dirs.lst") $ unlines ["Foo.txt"]-    assertContents (obj "exist.lst") $ unlines ["True","True","False","False"]-    assertContents (obj "foodirexist.lst") $ unlines ["True"]+    createDirectory (obj "C.txt")+    writeFile (obj "C.txt/D.txt") ""+    writeFile (obj "C.txt/E.xtx") ""+    demand " *.txt.files" "A.txt B.txt"+    demand ".dirs" "C.txt"+    demand "A.txt B.txt C.txt.exist" "10 10 01"+    demand " //*.txt.files" "A.txt B.txt C.txt/D.txt"+    demand "C.txt *.txt.files" "D.txt"+    demand " *.txt //*.xtx.files" "A.txt B.txt C.txt/E.xtx"+    demand " C.txt/*.files" "C.txt/D.txt C.txt/E.xtx"
Examples/Util.hs view
@@ -27,7 +27,8 @@         "test":extra -> do             putStrLn $ "## TESTING " ++ name             -- if the extra arguments are not --quiet/--loud it's probably going to go wrong-            test (\args -> withArgs (name:args ++ extra) $ shaken test rules sleeper) (out++)+            let obj x = if "/" `isPrefixOf` x then init out ++ x else out ++ x+            test (\args -> withArgs (name:args ++ extra) $ shaken test rules sleeper) obj             putStrLn $ "## FINISHED TESTING " ++ name         "clean":_ -> removeDirectoryRecursive out {-
shake.cabal view
@@ -1,7 +1,7 @@ cabal-version:      >= 1.8 build-type:         Simple name:               shake-version:            0.7+version:            0.8 license:            BSD3 license-file:       LICENSE category:           Development@@ -11,13 +11,14 @@ synopsis:           Build system library, like Make, but more accurate dependencies. description:     Shake is a Haskell library for writing build systems - designed as a-    replacement for make. See "Development.Shake" for an introduction,+    replacement for @make@. See "Development.Shake" for an introduction,     including an example. Further examples are included in the Cabal tarball,     under the @Examples@ directory.     .     To use Shake the user writes a Haskell program-    that imports the Shake library, defines some build rules, and calls-    'shake'. Thanks to do notation and infix operators, a simple Shake program+    that imports "Development.Shake", defines some build rules, and calls+    the 'Development.Shake.shake' function. Thanks to do notation and infix+    operators, a simple Shake build system     is not too dissimilar from a simple Makefile. However, as build systems     get more complex, Shake is able to take advantage of the excellent     abstraction facilities offered by Haskell and easily support much larger