packages feed

shake 0.16.2 → 0.16.3

raw patch · 17 files changed

+187/−94 lines, 17 files

Files

CHANGES.txt view
@@ -1,5 +1,10 @@ Changelog for Shake +0.16.3, released 2018-02-23+    Allow reading data files from next to the executable+    #566, require extra-1.6.1+    #565, deal with multi-file rules that don't create their contents+    Improve the documentation of getDirectoryContents 0.16.2, released 2018-02-13     Set the correct lower bound on unordered-containers of 0.2.7 0.16.1, released 2018-02-11
shake.cabal view
@@ -1,7 +1,7 @@ cabal-version:      >= 1.18 build-type:         Simple name:               shake-version:            0.16.2+version:            0.16.3 license:            BSD3 license-file:       LICENSE category:           Development, Shake@@ -35,9 +35,9 @@ extra-doc-files:     CHANGES.txt     README.md-extra-source-files:     docs/Manual.md     docs/shake-progress.png+extra-source-files:     src/Paths.hs     src/Test/C/constants.c     src/Test/C/constants.h@@ -52,7 +52,6 @@     src/Test/Tup/newmath/square.c     src/Test/Tup/newmath/square.h     src/Test/Tup/root.cfg- data-files:     docs/manual/build.bat     docs/manual/Build.hs@@ -83,7 +82,7 @@         bytestring,         deepseq >= 1.1,         directory,-        extra >= 1.5.3,+        extra >= 1.6.1,         filepath,         hashable >= 1.1.2.3,         js-flot,@@ -142,6 +141,7 @@         Development.Shake.Internal.FileName         Development.Shake.Internal.FilePattern         Development.Shake.Internal.Options+        Development.Shake.Internal.Paths         Development.Shake.Internal.Profile         Development.Shake.Internal.Progress         Development.Shake.Internal.Resource@@ -187,7 +187,7 @@         bytestring,         deepseq >= 1.1,         directory,-        extra >= 1.5.3,+        extra >= 1.6.1,         filepath,         hashable >= 1.1.2.3,         js-flot,@@ -241,6 +241,7 @@         Development.Shake.Internal.FileName         Development.Shake.Internal.FilePattern         Development.Shake.Internal.Options+        Development.Shake.Internal.Paths         Development.Shake.Internal.Profile         Development.Shake.Internal.Progress         Development.Shake.Internal.Resource@@ -291,7 +292,7 @@         bytestring,         deepseq >= 1.1,         directory,-        extra >= 1.5.3,+        extra >= 1.6.1,         filepath,         hashable >= 1.1.2.3,         js-flot,@@ -348,6 +349,7 @@         Development.Shake.Internal.FileName         Development.Shake.Internal.FilePattern         Development.Shake.Internal.Options+        Development.Shake.Internal.Paths         Development.Shake.Internal.Profile         Development.Shake.Internal.Progress         Development.Shake.Internal.Resource
src/Development/Shake/Internal/Args.hs view
@@ -6,7 +6,7 @@     shakeArgs, shakeArgsWith, shakeArgsOptionsWith     ) where -import Paths_shake+import Development.Shake.Internal.Paths import Development.Shake.Internal.Options import Development.Shake.Internal.Core.Rules import Development.Shake.Internal.Demo@@ -26,8 +26,7 @@ import Data.Functor import Data.List import Data.Maybe-import Data.Version(showVersion)-import System.Directory+import System.Directory.Extra import System.Environment import System.Exit import System.Time.Extra@@ -149,9 +148,9 @@     if Help `elem` flagsExtra then         showHelp      else if Version `elem` flagsExtra then-        putWhenLn Normal $ "Shake build system, version " ++ showVersion version+        putWhenLn Normal $ "Shake build system, version " ++ shakeVersionString      else if NumericVersion `elem` flagsExtra then-        putWhenLn Normal $ showVersion version+        putWhenLn Normal shakeVersionString      else if Demo `elem` flagsExtra then         demo $ shakeStaunch shakeOpts      else if not $ null progressReplays then do@@ -164,12 +163,8 @@      else do         when (Sleep `elem` flagsExtra) $ threadDelay 1000000         start <- offsetTime-        curdir <- getCurrentDirectory-        let redir = case changeDirectory of-                Nothing -> id-                -- get the "html" directory so it caches with the current directory-                -- required only for debug code-                Just d -> bracket_ (getDataFileName "html" >> setCurrentDirectory d) (setCurrentDirectory curdir)+        initDataDirectory -- must be done before we start changing directory+        let redir = maybe id withCurrentDirectory changeDirectory         shakeOpts <- if null progressRecords then return shakeOpts else do             t <- offsetTime             return shakeOpts{shakeProgress = \p ->@@ -184,7 +179,9 @@                         return p             }         (ran,shakeOpts,res) <- redir $ do-            when printDirectory $ putWhenLn Normal $ "shake: In directory `" ++ curdir ++ "'"+            when printDirectory $ do+                curdir <- getCurrentDirectory+                putWhenLn Normal $ "shake: In directory `" ++ curdir ++ "'"             rules <- rules shakeOpts user files             case rules of                 Nothing -> return (False, shakeOpts, Right ())
src/Development/Shake/Internal/Demo.hs view
@@ -2,20 +2,19 @@ -- | Demo tutorial, accessed with --demo module Development.Shake.Internal.Demo(demo) where -import Paths_shake+import Development.Shake.Internal.Paths import Development.Shake.Command  import Control.Applicative import Control.Exception.Extra import Control.Monad-import General.Extra import Data.Char import Data.List import Data.Maybe-import Data.Version(showVersion) import System.Directory import System.Exit import System.FilePath+import General.Extra import Development.Shake.FilePath(exe) import System.IO import System.Info.Extra@@ -25,29 +24,19 @@ demo :: Bool -> IO () demo auto = do     hSetBuffering stdout NoBuffering-    putStrLn $ "% Welcome to the Shake v" ++ showVersion version ++ " demo mode!"-    putStr "% Detecting machine configuration... "--    -- CONFIGURE+    putStrLn $ "% Welcome to the Shake v" ++ shakeVersionString ++ " demo mode!" -    manual <- getDataFileName "docs/manual"-    hasManual <- wrap $ doesDirectoryExist manual-    ghc <- findExecutable "ghc"-    gcc <- do-        v <- findExecutable "gcc"-        case v of-            Nothing | isWindows, Just ghc <- ghc -> do-                let dir = takeDirectory (takeDirectory ghc) </> "bin/mingw/gcc.exe"-                b <- wrap $ doesFileExist dir-                return $ if b then Just dir else Nothing-            _ -> return v+    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"      let path = if isWindows then "%PATH%" else "$PATH"-    require (isJust ghc) $ "% You don't have 'ghc' on your " ++ path ++ ", which is required to run the demo."-    require (isJust gcc) $ "% You don't have 'gcc' on your " ++ path ++ ", which is required to run the demo."+    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." @@ -63,9 +52,7 @@     require b "% Please create an empty directory to run the demo from, then run 'shake --demo' again."      putStr "% Copying files... "-    createDirectoryRecursive dir-    forM_ ["Build.hs","main.c","constants.c","constants.h","build" <.> if isWindows then "bat" else "sh"] $ \file ->-        copyFile (manual </> file) (dir </> file)+    copyManualData dir     unless isWindows $ do          p <- getPermissions $ dir </> "build.sh"          setPermissions (dir </> "build.sh") p{executable=True}@@ -76,7 +63,7 @@             if auto then putLine "" else getLine     let execute x = do             putStrLn $ "% RUNNING: " ++ x-            cmd (Cwd dir) Shell x :: IO ()+            cmd (Cwd dir) (AddPath [] (maybeToList gccPath)) Shell x :: IO ()     let build = if isWindows then "build" else "./build.sh"      putStrLn "\n% [1/5] Building an example project with Shake."
+ src/Development/Shake/Internal/Paths.hs view
@@ -0,0 +1,72 @@++-- | The information from Paths_shake cleaned up+module Development.Shake.Internal.Paths(+    shakeVersionString,+    initDataDirectory,+    hasManualData, copyManualData,+    readDataFileHTML+    ) where++import Paths_shake+import Control.Exception+import Control.Monad.Extra+import Data.Version+import System.Directory+import System.FilePath+import System.Info.Extra+import System.IO.Unsafe+import System.Environment.Extra+import General.Extra+import Data.Functor+import qualified Data.ByteString.Lazy as LBS+import Prelude+++shakeVersionString :: String+shakeVersionString = showVersion version+++-- We want getDataFileName to be relative to the current directory on program startup,+-- even if we issue a change directory command. Therefore, first call caches, future ones read.+{-# NOINLINE dataDirs #-}+dataDirs :: [String]+dataDirs = unsafePerformIO $ do+    datdir <- getDataDir+    exedir <- takeDirectory <$> getExecutablePath `catchIO` \_ -> return ""+    curdir <- getCurrentDirectory+    return $ [datdir] ++ [exedir | exedir /= ""] ++ [curdir]+++-- The data files may be located relative to the current directory, if so cache it in advance+initDataDirectory :: IO ()+initDataDirectory = void $ evaluate dataDirs+++getDataFile :: FilePath -> IO FilePath+getDataFile file = do+    let poss = map (</> file) dataDirs+    res <- filterM doesFileExist_ poss+    case res of+        [] -> fail $ unlines $ ("Could not find data file " ++ file ++ ", looked in:") : map ("  " ++) poss+        x:_ -> return x++hasDataFile :: FilePath -> IO Bool+hasDataFile file = anyM (\dir -> doesFileExist_ $ dir </> file) dataDirs+++readDataFileHTML :: FilePath -> IO LBS.ByteString+readDataFileHTML file = LBS.readFile =<< getDataFile ("html" </> file)+++manualFiles :: [FilePath]+manualFiles = map ("docs/manual" </>) ["Build.hs","main.c","constants.c","constants.h","build" <.> if isWindows then "bat" else "sh"]++hasManualData :: IO Bool+hasManualData = allM hasDataFile manualFiles++copyManualData :: FilePath -> IO ()+copyManualData dest = do+    createDirectoryRecursive dest+    forM_ manualFiles $ \file -> do+        src <- getDataFile file+        copyFile src (dest </> takeFileName file)
src/Development/Shake/Internal/Profile.hs view
@@ -6,11 +6,10 @@ import Data.Tuple.Extra import Data.Function import Data.List-import Data.Version import System.FilePath import Numeric.Extra import General.Extra-import Paths_shake+import Development.Shake.Internal.Paths import System.Time.Extra import qualified Data.ByteString.Lazy.Char8 as LBS @@ -55,11 +54,10 @@  generateHTML :: [ProfileEntry] -> IO LBS.ByteString generateHTML xs = do-    htmlDir <- getDataFileName "html"-    report <- LBS.readFile $ htmlDir </> "profile.html"+    report <- readDataFileHTML "profile.html"     let f name | name == "profile-data.js" = return $ LBS.pack $ "var profile =\n" ++ generateJSON xs-               | name == "version.js" = return $ LBS.pack $ "var version = " ++ show (showVersion version)-               | otherwise = LBS.readFile $ htmlDir </> name+               | name == "version.js" = return $ LBS.pack $ "var version = " ++ show shakeVersionString+               | otherwise = readDataFileHTML name     runTemplate f report  
src/Development/Shake/Internal/Progress.hs view
@@ -20,13 +20,12 @@ import Data.IORef import Data.List import Data.Maybe-import Data.Version import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as LBS import Numeric.Extra import General.Template import System.IO.Unsafe-import Paths_shake+import Development.Shake.Internal.Paths import System.Time.Extra import Data.Semigroup (Semigroup (..)) import Data.Monoid hiding ((<>))@@ -279,11 +278,10 @@  generateHTML :: [(FilePath, [ProgressEntry])] -> IO LBS.ByteString generateHTML xs = do-    htmlDir <- getDataFileName "html"-    report <- LBS.readFile $ htmlDir </> "progress.html"+    report <- readDataFileHTML "progress.html"     let f name | name == "progress-data.js" = return $ LBS.pack $ "var progress =\n" ++ generateJSON xs-               | name == "version.js" = return $ LBS.pack $ "var version = " ++ show (showVersion version)-               | otherwise = LBS.readFile $ htmlDir </> name+               | name == "version.js" = return $ LBS.pack $ "var version = " ++ show shakeVersionString+               | otherwise = readDataFileHTML name     runTemplate f report  generateJSON :: [(FilePath, [ProgressEntry])] -> String
src/Development/Shake/Internal/Rules/Directory.hs view
@@ -182,9 +182,10 @@ getEnvWithDefault def var = fromMaybe def <$> getEnv var  -- | Get the contents of a directory. The result will be sorted, and will not contain---   the entries @.@ or @..@ (unlike the standard Haskell version). The resulting paths will be relative---   to the first argument. The result is tracked as a---   dependency, and if it changes the rule will rerun in subsequent builds.+--   the entries @.@ or @..@ (unlike the standard Haskell version).+--   The resulting paths will be relative to the first argument.+--   The result itself is tracked as a dependency, but the files in the result are not.+--   If the list of files changes in subsequent builds any rule calling it will rerun. -- --   It is usually simpler to call either 'getDirectoryFiles' or 'getDirectoryDirs'. getDirectoryContents :: FilePath -> Action [FilePath]@@ -192,8 +193,9 @@  -- | 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 directory argument. The result is tracked as a---   dependency, and if it changes the rule will rerun in subsequent builds.+--   relative to the directory argument.+--   The result itself is tracked as a dependency, but the files in the result are not.+--   If the list of files changes in subsequent builds any rule calling it will rerun. --   Some examples: -- -- > getDirectoryFiles "Config" ["//*.xml"]@@ -229,8 +231,10 @@ getDirectoryFiles dir pat = fmap fromGetDirectoryA $ apply1 $ GetDirectoryFilesQ (dir,pat)  -- | Get the directories in a directory, not including @.@ or @..@.---   All directories are relative to the argument directory. The result is tracked as a---   dependency, and if it changes the rule will rerun in subsequent builds.+--   All directories are relative to the argument directory.+--   The result itself is tracked as a dependency, but the directories in the result are not.+--   If the list of directories changes in subsequent builds any rule calling it will rerun.+ --   The rules about creating entries described in 'getDirectoryFiles' also apply here. -- -- > getDirectoryDirs "/Users"
src/Development/Shake/Internal/Rules/File.hs view
@@ -72,7 +72,7 @@ data Mode     = ModePhony (Action ()) -- ^ An action with no file value     | ModeDirect (Action ()) -- ^ An action that produces this file-    | ModeForward (Action FileA) -- ^ An action that looks up a file someone else produced+    | ModeForward (Action (Maybe FileA)) -- ^ An action that looks up a file someone else produced  -- | The results of the various 'Mode' rules. data Result@@ -272,8 +272,13 @@                 Nothing -> do                     new <- liftIO $ storedValueError opts True "Error, file does not exist and no rule available:" o                     answer ResultDirect $ fromJust new-                Just (ModeForward act) ->-                    answer ResultForward =<< act+                Just (ModeForward act) -> do+                    new <- act+                    case new of+                        Nothing -> do+                            alwaysRerun+                            retNew ChangedRecomputeDiff ResultPhony+                        Just new -> answer ResultForward new                 Just (ModeDirect act) -> do                     act                     new <- liftIO $ storedValueError opts False "Error, rule finished running but did not produce file:" o@@ -320,7 +325,7 @@ -- OPTIONS ON TOP  -- | Internal method for adding forwarding actions-fileForward :: (FilePath -> Maybe (Action FileA)) -> Rules ()+fileForward :: (FilePath -> Maybe (Action (Maybe FileA))) -> Rules () fileForward act = addUserRule $ FileRule $ fmap ModeForward . act  
src/Development/Shake/Internal/Rules/Files.hs view
@@ -135,7 +135,7 @@             (if simple p then id else priority 0.5) $                 fileForward $ let op = (p ?==) in \file -> if not $ op file then Nothing else Just $ do                     FilesA res <- apply1 $ FilesQ $ map (FileQ . fileNameFromString . substitute (extract p file)) ps-                    return $ res !! i+                    return $ if null res then Nothing else Just $ res !! i         (if all simple ps then id else priority 0.5) $             addUserRule $ \(FilesQ xs_) -> let xs = map (fileNameToString . fromFileQ) xs_ in                 if not $ length xs == length ps && and (zipWith (?==) ps xs) then Nothing else Just $ do@@ -184,7 +184,7 @@         Nothing -> Nothing         Just ys -> Just $ do             FilesA res <- apply1 $ FilesQ $ map (FileQ . fileNameFromString) ys-            return $ res !! fromJust (elemIndex x ys)+            return $ if null res then Nothing else Just $ res !! fromJust (elemIndex x ys)      addUserRule $ \(FilesQ xs_) -> let xs@(x:_) = map (fileNameToString . fromFileQ) xs_ in         case checkedTest x of
src/Development/Shake/Util.hs view
@@ -79,11 +79,11 @@     let flags2 = Option "P" ["prune"] (NoArg $ Right Nothing) "Remove stale files" : map (fmapOptDescr Just) flags     pruning <- newIORef False     shakeArgsWith opts flags2 $ \opts args ->-        if any isNothing opts then do-            writeIORef pruning True-            return Nothing-        else-            act (map fromJust opts) args+        case sequence opts of+            Nothing -> do+                writeIORef pruning True+                return Nothing+            Just opts -> act opts args     whenM (readIORef pruning) $         IO.withTempFile $ \file -> do             shakeArgsWith opts{shakeLiveFiles=file : shakeLiveFiles opts} flags2 $ \opts args ->
src/General/Extra.hs view
@@ -2,6 +2,7 @@  module General.Extra(     getProcessorCount,+    findGcc,     withResultType,     whenLeft,     randomElem,@@ -11,6 +12,7 @@     fastAt,     forkFinallyUnmasked,     isAsyncException,+    doesFileExist_,     removeFile_, createDirectoryRecursive,     catchIO, tryIO, handleIO     ) where@@ -21,10 +23,13 @@ import System.Environment.Extra import System.IO.Extra import System.IO.Unsafe+import System.Info.Extra+import System.FilePath import System.Random import System.Directory import System.Exit import Control.Concurrent+import Data.Maybe import Data.Functor import Data.Primitive.Array import Control.Applicative@@ -97,11 +102,29 @@                         return $! max 1 $ length [() | x <- lines src, "processor" `isPrefixOf` x]  +-- Can you find a GCC executable? return a Bool, and optionally something to add to $PATH to run it+findGcc :: IO (Bool, Maybe FilePath)+findGcc = do+    v <- findExecutable "gcc"+    case v of+        Nothing | isWindows -> do+            ghc <- findExecutable "ghc"+            case ghc of+                Just ghc -> do+                    let gcc = takeDirectory (takeDirectory ghc) </> "mingw/bin/gcc.exe"+                    b <- doesFileExist_ gcc+                    return $ if b then (True, Just $ takeDirectory gcc) else (False, Nothing)+                _ -> return (False, Nothing)+        _ -> return (isJust v, Nothing)+++ --------------------------------------------------------------------- -- System.Random  randomElem :: [a] -> IO a randomElem xs = do+    when (null xs) $ fail "General.Extra.randomElem called with empty list, can't pick a random element"     i <- randomRIO (0, length xs - 1)     return $ xs !! i @@ -146,6 +169,9 @@  --------------------------------------------------------------------- -- System.Directory++doesFileExist_ :: FilePath -> IO Bool+doesFileExist_ x = doesFileExist x `catchIO` \_ -> return False  -- | Remove a file, but don't worry if it fails removeFile_ :: FilePath -> IO ()
src/Paths.hs view
@@ -1,23 +1,12 @@ -- | Fake cabal module for local building -module Paths_shake(getDataFileName, version) where+module Paths_shake(getDataDir, version) where  import Data.Version.Extra-import System.IO.Unsafe-import System.Directory-import Control.Exception ---- We want getDataFileName to be relative to the current directory even if--- we issue a change directory command. Therefore, first call caches, future ones read.-{-# NOINLINE curdir #-}-curdir :: String-curdir = unsafePerformIO getCurrentDirectory--getDataFileName :: FilePath -> IO FilePath-getDataFileName x = do-    evaluate curdir-    return $ curdir ++ "/" ++ x+-- If Shake can't find files in the data directory it tries relative to the executable+getDataDir :: IO FilePath+getDataDir = return "random_path_that_cannot_possibly_exist"  version :: Version version = makeVersion [0,0]
src/Test/Manual.hs view
@@ -4,6 +4,8 @@ import Development.Shake hiding (copyFileChanged) import Development.Shake.FilePath import Test.Type+import General.Extra+import Data.Maybe import System.Info.Extra  @@ -18,9 +20,11 @@     copyDirectoryChanged (root </> "src/Development") $ dest </> "Development"     copyDirectoryChanged (root </> "src/General") $ dest </> "General"     copyFileChanged (root </> "src/Paths.hs") $ dest </> "Paths_shake.hs"+    (_, gccPath) <- findGcc+    let opts = [Cwd dest, Shell, AddPath [] (maybeToList gccPath)]     let cmdline = if isWindows then "build.bat" else "/bin/sh build.sh"-    cmd_ [Cwd dest, Shell] cmdline "-j2"+    cmd_ opts cmdline "-j2"     assertExists $ dest </> "_build/run" <.> exe-    cmd_ [Cwd dest, Shell] cmdline-    cmd_ [Cwd dest, Shell] [cmdline,"clean"]+    cmd_ opts cmdline+    cmd_ opts [cmdline,"clean"]     assertMissing $ dest </> "_build/run" <.> exe
src/Test/Ninja.hs view
@@ -61,6 +61,8 @@     run "-f../../src/Test/Ninja/test5.ninja"     assertExists "output file" +    run "-f../../src/Test/Ninja/test7.ninja"+     writeFile "nocreate.log" ""     writeFile "nocreate.in" ""     run "-f../../src/Test/Ninja/nocreate.ninja"
+ src/Test/Ninja/test7.ninja view
@@ -0,0 +1,6 @@+ninja_required_version = 1.5+build test : phony a b+rule CUSTOM_COMMAND+   command = $COMMAND+build a b : CUSTOM_COMMAND+  COMMAND = cd
src/Test/Type.hs view
@@ -23,7 +23,7 @@ import General.Extra import Development.Shake.Internal.FileInfo import Development.Shake.FilePath-import Paths_shake+import Development.Shake.Internal.Paths  import Control.Exception.Extra import Control.Monad.Extra@@ -65,9 +65,7 @@     -> IO ()     -> IO () shakenEx reenter options test rules sleeper = do-    -- my debug getDataFileName (in Paths) uses a cache of the Cwd-    -- make sure we force the cache before changing directory-    getDataFileName ""+    initDataDirectory      name:args <- getArgs     putStrLn $ "## BUILD " ++ unwords (name:args)