packages feed

gdo 0.1.0 → 0.1.2

raw patch · 15 files changed

+177/−81 lines, 15 filesdep ~base

Dependency ranges changed: base

Files

+ DepInfo.hs view
@@ -0,0 +1,17 @@+module DepInfo+       ( DepInfo(..),+         depInfoUpToDate+       )+       where++data DepInfo = DepInfo { depInfoFilePath :: FilePath+                       , depInfoSavedMD5 :: Maybe String+                       , depInfoCurrentMD5 :: Maybe String+                       }+             deriving Show++-- | Returns true if the dependency has not changed since the last+-- recording.+depInfoUpToDate :: DepInfo -> Bool+depInfoUpToDate di =+  depInfoSavedMD5 di == depInfoCurrentMD5 di
Lib.hs view
@@ -4,13 +4,15 @@          -- * directory names        , getMetaDir        , getMissingDepsFile-       , metaIgnoreFiles        , getDefaultDirs          -- * Actions        , executeRecipe        , getRecipeFile        , upToDate        , recordDependency+       , recordMissingDependency+       , purgeRecordedDependencies+       , getHashesAndDepsForTarget        )        where @@ -21,21 +23,29 @@ import qualified Data.ByteString as BS import qualified Data.Map as Map (toList,fromList,insert) import           Data.Maybe (listToMaybe)-import           System.Directory (getCurrentDirectory, makeAbsolute, doesFileExist, renameFile, removeFile, createDirectoryIfMissing, getDirectoryContents)+import           System.Directory (getCurrentDirectory, makeAbsolute, doesFileExist, renameFile, removeFile, createDirectoryIfMissing, getDirectoryContents, removeDirectoryRecursive, withCurrentDirectory) import           System.Environment (getEnvironment,lookupEnv) import           System.Exit (ExitCode(ExitSuccess)) import           System.FilePath ((</>), takeBaseName, dropFileName, replaceBaseName, addExtension,splitSearchPath)-import           System.IO (hPutStrLn,stderr,hPutStr,withFile,IOMode(ReadMode,WriteMode),hFileSize)+import           System.IO (hPutStrLn,stderr,hPutStr,withFile,IOMode(ReadMode,WriteMode,AppendMode),hFileSize) import           System.IO.Error (isDoesNotExistError)-import qualified System.Process as Proc+import qualified System.Process as Proc (env, waitForProcess, createProcess, proc) +import           DepInfo++-- | Print a string to standard error output with a newline character+-- in the end. putStrLnErr :: (MonadIO m) => String -> m () putStrLnErr msg =   liftIO $ hPutStrLn stderr msg +-- | Print a string to standard error output. putStrErr :: (MonadIO m) => String -> m () putStrErr = liftIO . hPutStr stderr +-- | Get the path for the directory where the targets meta information+-- is stored.  This will only work, if you are in the same directory+-- as the target. getMetaDir :: (MonadIO m) =>               String -- ^ target name            -> m FilePath@@ -60,21 +70,23 @@               -> FilePath -- ^ recipe file               -> IO ExitCode executeRecipe target recipe = do-  createFile tempFileName+  currentDir <- getCurrentDirectory+  let tempFilePath = currentDir </> tempFileName+  createFile tempFilePath   finally     (do         process <- modEnv $ Proc.proc recipe-                   [targetDir,takeBaseName target, tempFileName]+                   [targetDir,takeBaseName target, tempFilePath]         (_,_,_,ph) <- liftIO $ Proc.createProcess process         code <- liftIO $ Proc.waitForProcess ph         if code /= ExitSuccess           then putStrLnErr $ "*** redo failed for target "++show target-          else do filesize <- getFileSize tempFileName-                  when (filesize /= 0) $ renameFile tempFileName target+          else do filesize <- getFileSize tempFilePath+                  when (filesize /= 0) $ renameFile tempFilePath target         return code     )-    (do exists <- doesFileExist tempFileName-        when exists $ removeFile tempFileName+    (do exists <- doesFileExist tempFilePath+        when exists $ removeFile tempFilePath     )   where     modEnv process = do@@ -113,6 +125,11 @@ getDefaultDirs =   maybe [] splitSearchPath <$> liftIO (lookupEnv "GDO_DEFAULTS") +hashFile :: (MonadIO m) => FilePath -> m (Digest MD5)+hashFile target = do+  bs <- liftIO $ BS.readFile target+  return $ hash bs+ upToDate :: (MonadIO m) =>             [FilePath]          -> FilePath@@ -120,18 +137,23 @@ upToDate mDefaultsDir buildTarget = do   metaDepDir <- getMetaDir buildTarget   liftIO $-    not . Prelude.null <$> getRecipeFile mDefaultsDir buildTarget >>= \canBuild ->-    if canBuild-    then do-      r <- tryJust (guard . isDoesNotExistError) $ do-        md5s <- Prelude.filter (not . (`elem` metaIgnoreFiles)) <$>-                getDirectoryContents metaDepDir-        depsNotChanged <- and <$> mapM upToDate' md5s-        noNewFiles <- not <$> newFilesCreated-        return $ depsNotChanged && noNewFiles-      return $ either (const False) id r-    else return True+    maybe+      -- When no recipe exists, we assume the target is up to date.+      (return True)+      ( const $ do+           r <- tryJust+                (guard . isDoesNotExistError)+                ( do md5s <- Prelude.filter (not . (`elem` metaIgnoreFiles)) <$>+                             getDirectoryContents metaDepDir+                     depsNotChanged <- and <$> mapM upToDate' md5s+                     noNewFiles <- not <$> newFilesCreated+                     return $ depsNotChanged && noNewFiles+                )+           return $ fromRight (const False) r+      ) =<< getRecipeFile mDefaultsDir buildTarget   where+    fromRight :: (a -> b) -> Either a b -> b+    fromRight f = either f id     upToDate' :: String -> IO Bool     upToDate' oldHash = do       metaDepDir <- getMetaDir buildTarget@@ -148,7 +170,8 @@     newFilesCreated = do       missingDepsFile <- getMissingDepsFile buildTarget       r <- tryJust (guard . isDoesNotExistError) $-           Prelude.filter (\e -> (e `notElem` metaIgnoreFiles) || Prelude.null e) .+           Prelude.filter (\e -> (e `notElem` metaIgnoreFiles) ||+                                 Prelude.null e) .            lines <$>            readFile missingDepsFile       case r of@@ -156,6 +179,22 @@        Right watchlist -> or <$> mapM                           doesFileExist watchlist +getHashesAndDepsForTarget :: FilePath -> IO [DepInfo]+getHashesAndDepsForTarget target = do+  metaDir <- getMetaDir target+  (filenames, oldMd5s) <- withCurrentDirectory metaDir $ do+    hashes <- filter (not . (`elem` metaIgnoreFiles)) <$>+              getDirectoryContents metaDir+    (,) <$> mapM readFile hashes <*> pure hashes+  md5s <- mapM hashFromPath filenames+  return (zipWith3 DepInfo+          filenames+          (map Just oldMd5s)+          (map (Just . show)  md5s))+  where+    hashFromPath :: FilePath -> IO (Digest MD5)+    hashFromPath f = hash <$> BS.readFile f+ recordDependency :: FilePath -- ^ target name                  -> FilePath -- ^ dependency name                  -> IO ()@@ -167,7 +206,16 @@   liftIO $ withFile md5file WriteMode     (`hPutStr` dep) -hashFile :: (MonadIO m) => FilePath -> m (Digest MD5)-hashFile target = do-  bs <- liftIO $ BS.readFile target-  return $ hash bs+recordMissingDependency :: FilePath -> FilePath -> IO ()+recordMissingDependency target dep = do+  metaDepsDir <- getMetaDir target+  missingDepsFile <- getMissingDepsFile target+  liftIO $ createDirectoryIfMissing True metaDepsDir+  liftIO $ withFile+    missingDepsFile+    AppendMode+    (`hPutStrLn` dep)++purgeRecordedDependencies :: FilePath -> IO ()+purgeRecordedDependencies target =+  removeDirectoryRecursive =<< getMetaDir target
Main.hs view
@@ -10,7 +10,6 @@ import           System.Environment import           System.Exit import           System.FilePath-import           System.IO import           System.IO.Error  import Lib@@ -20,16 +19,17 @@  clOption :: [OptDescr Flag] clOption = [ Option "" ["if"] (ReqArg read "MODE")-             "Redo mode, valid modes are: IfChanged, IfCreated"+             "Redo mode, valid modes are: Changed, Created"            , Option "h" ["help"] (NoArg Help)              "Print usage info"            ]  variableInfo :: String variableInfo =-  unlines-  [ "Environment variables:"-  , "\tGDO_DEFAULTS : Path to directory containing default do files"+  unlines $+  "Environment variables:" :+  map ('\t':)+  [ "GDO_DEFAULTS : List of paths to directories containing default do files"   ]  usageHeader :: String@@ -92,7 +92,7 @@   isUpToDate <- upToDate mDefaultsDir target   unless (isUpToDate && targetDoesExist) $ do     void . liftIO . tryJust (guard . isDoesNotExistError) $-      deleteDepDir+      purgeRecordedDependencies target     maybe (do targetExists <- liftIO $ doesFileExist target               unless targetExists $ do                 (liftIO . putStrLnErr)@@ -104,12 +104,10 @@                redoIfChanged mDefaultsDir target recipe                buildResult <- liftIO $ executeRecipe target recipe                when (buildResult /= ExitSuccess)-                 (do liftIO deleteDepDir+                 (do liftIO $ purgeRecordedDependencies target                      throwE buildResult)                liftIO $ putStrLnErr $ "redone "++show target)       =<< getRecipeFile mDefaultsDir target-  where-    deleteDepDir = removeDirectoryRecursive =<< getMetaDir target  redoIfCreated :: (MonadIO m) =>                  [FilePath]     -- ^ directory path of defaults@@ -120,13 +118,7 @@   depExists <- liftIO $ doesFileExist dep   if depExists     then redoIfChanged mDefaultsDir buildTarget dep-    else do metadir <- getMetaDir buildTarget-            missingDepsFile <- getMissingDepsFile buildTarget-            liftIO $ createDirectoryIfMissing True metadir-            liftIO $ withFile-              missingDepsFile-              AppendMode-              (`hPutStrLn` dep)+    else liftIO $ recordMissingDependency buildTarget dep  redoIfChanged :: MonadIO m =>                  [FilePath]     -- ^ directory of defaults
README.org view
@@ -101,11 +101,37 @@    default rule based on the targets file extension.  This only works    for files which have an extension.  Default do files are only    searched in the same directory as the target by default.  You can-   extend the search path via the environment variable *GDO_DEFAULTS*.+   extend the search path via the environment variable *GDO\_DEFAULTS*.    When specified this variable must be a list of paths seperated by    colons.  This path is searched for default do files after no    default do files was found in the same directory as the target is    in.++** EXAMPLE+   The source code you received with this product should contain a set+   of examples for using *gdo*.  These examples can be found in the+   *examples* directory.++   This small example builds the "hello world" program in C.  There+   are 3 files in this directory: The first one is the source for the+   program itself, *test.c*, the other two files are a do script for+   the final executable *test.do* and a default do script for building+   object files from C sources, *defaults/default.o.do*.  To build the+   example you have to first point to the defaults directory, so that+   *gdo* can find the default do file.  We assume that you are already+   in the examples file of the gdo source code.  Then issue *gdo* to+   build the target *test*.+   #+begin_src sh+     export GDO_DEFAULTS=$PWD/defaults+     gdo test+     # output:+     # redo "test"+     # redo "test.o"+     # redone "test.o"+     # redone "test"+   #+end_src+   Now the targets should be build. You should take a look at the do+   files to see some examples of what *gdo* is capable of.  * COPYRIGHT   Copyright (C) 2016 by Sebastian Jordan.  This file is part of *gdo*.
all.do view
@@ -1,3 +1,3 @@ #!/usr/bin/env sh -gdo --if Changed gdo tests/test default.nix README man/gdo.1+gdo --if Changed gdo default.nix README man/gdo.1
default.nix.do view
@@ -2,6 +2,9 @@  # generate a nix expression for the project +# This line is here because default.nix.do is also the default do file+# for all .nix files in the current directory.+gdo --if Created $2.do gdo --if Changed gdo.cabal  cabal2nix . > $3
+ examples/defaults/default.o.do view
@@ -0,0 +1,16 @@+#!/usr/bin/env sh++set -e++CC=cc+GDO_ENVIRONMENT=$1/environment++gdo --if Changed $2.c $(cc -MM $2.c | tr -d '\n\\' | cut -d':' -f2)+gdo --if Created $2.o.do $GDO_ENVIRONMENT++# We want to check for custom environment variables like CC+if [ -e $GDO_ENVIRONMENT ]; then+    source $GDO_ENVIRONMENT+fi++${CC} -c $2.c -o $3 > /dev/null
+ examples/test.c view
@@ -0,0 +1,7 @@+#include "stdio.h"++int main(){+  printf("Hello World!");+  return 0;+}+  
+ examples/test.do view
@@ -0,0 +1,8 @@+#!/bin/sh++set -e++gdo --if Changed test.o test.do+gdo --if Created stdio.h++gcc test.o -o $3
gdo.cabal view
@@ -2,7 +2,7 @@ -- see http://haskell.org/cabal/users-guide/  name:                gdo-version:             0.1.0+version:             0.1.2 synopsis:            recursive atomic build system description:   *gdo* is a build system similar to **GNU Make**. It builds files from@@ -22,12 +22,13 @@                    , all.do                    , clean.do                    , default.nix.do+                   , shell.nix.do                    , gdo.cabal                    , gdo.do                    , man/gdo.1.do-                   , tests/test.c-                   , tests/test.do-                   , tests/defaults/default.o.do+                   , examples/test.c+                   , examples/test.do+                   , examples/defaults/default.o.do  cabal-version:       >=1.10 @@ -38,7 +39,8 @@ executable gdo   main-is:             Main.hs   other-modules:       Lib-  build-depends:       base >=4.8 && <4.9,+                     , DepInfo+  build-depends:       base >=4.8 && <4.10,                        process >= 1.1,                        filepath >= 1.0,                        directory >= 1.2,
gdo.do view
@@ -4,7 +4,7 @@  HC="ghc -v0" -gdo --if Changed Main.hs Lib.hs+gdo --if Changed Main.hs Lib.hs DepInfo.hs gdo --if Created environment  if [ -e environment ]; then
+ shell.nix.do view
@@ -0,0 +1,8 @@+#!/bin/sh++# generate a nix expression for the project++gdo --if Changed gdo.cabal++cabal2nix . --shell > $3+
− tests/defaults/default.o.do
@@ -1,16 +0,0 @@-#!/usr/bin/env sh--set -e--CC=cc-GDO_ENVIRONMENT=$1/environment--gdo --if Changed $2.c $(cc -MM $2.c | tr -d '\n\\' | cut -d':' -f2)-gdo --if Created $2.o.do $GDO_ENVIRONMENT--# We want to check for custom environment variables like CC-if [ -e $GDO_ENVIRONMENT ]; then-    source $GDO_ENVIRONMENT-fi--${CC} -c $2.c -o $3 > /dev/null
− tests/test.c
@@ -1,7 +0,0 @@-#include "stdio.h"--int main(){-  printf("Hello World!");-  return 0;-}-  
− tests/test.do
@@ -1,8 +0,0 @@-#!/bin/sh--set -e--gdo --if Changed test.o test.do-gdo --if Created stdio.h--gcc test.o -o $3