a haskell program for finding your new freebsd ports
the source code for this package is now hosted on github
newports.hs is a trivial haskell script that can be used to find what ports have been updated on your system in the last N days, which you would typically want to know after doing a daily cvsup. the instructions are easy - the script only takes one argument - a number signifying the age in days of ports you want displayed. if you wanted to use runhaskell utility, you could run it like:
runhaskell newports.hs 1
the code is under a bsd license.
here is a haskell HackageDB package for this script.
if you find bugs, errors, or want to suggest changes, let me know!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
this is a trivial script to tell us when a freebsd port has been updated | |
within the last N days, where N is the argument provided to the script on the | |
command line. | |
this code is licensed under a "bsd" license, which is stated below | |
Copyright (c) 2007, Brad Clawsie. All rights reserved. | |
http://b7j0c.org/stuff/license.txt | |
-} | |
module Main (main) where | |
import qualified System.Directory as D | |
(getDirectoryContents,doesDirectoryExist,getModificationTime) | |
import qualified System.Time as T | |
(normalizeTimeDiff,diffClockTimes,getClockTime,tdSec,ClockTime(..)) | |
import qualified System.Environment as S (getArgs) | |
import qualified System.Exit as E (exitWith,ExitCode(..)) | |
import qualified Control.Monad as M (liftM,mapM,filterM) | |
import qualified Data.Char as C (isDigit) | |
main :: IO () | |
main = do | |
args <- S.getArgs | |
let useMsg = "use: newports [age-in-days]" :: String | |
case (length args == 1) of | |
False -> error useMsg | |
True -> | |
let rawArg = head args in | |
case (all C.isDigit rawArg) of | |
False -> error useMsg | |
{- we will base our age comparisons on seconds, so we | |
convert our arg to a day count as seconds -} | |
True -> let age = 86400 * (read rawArg :: Int) in | |
do | |
now <- T.getClockTime | |
let portsBase = "/usr/ports" :: FilePath | |
dirs <- portsDirs portsBase | |
allPorts <- M.mapM portsDirs dirs | |
{- allPorts :: [[FilePath]] -} | |
allPortDates <- M.liftM concat | |
(M.mapM getModTimes allPorts) | |
{- allPortDates:: [(FilePath,ClockTime)] | |
where the ClockTime indicates the port mtime -} | |
let newPorts = filter (isNewPort now age) allPortDates | |
case (length newPorts) of | |
0 -> E.exitWith E.ExitSuccess | |
_ -> do | |
M.mapM putStrLn (map fst newPorts) | |
E.exitWith E.ExitSuccess | |
where | |
isNewPort :: T.ClockTime -> Int -> | |
(FilePath,T.ClockTime) -> Bool | |
isNewPort now age (port,mtime) = | |
let diff = T.tdSec(T.diffClockTimes now mtime) in | |
diff <= age | |
portsDirs :: FilePath -> IO [FilePath] | |
portsDirs d = do | |
rawDirs <- D.getDirectoryContents d | |
l <- M.filterM (D.doesDirectoryExist) $ | |
map ((d ++ "/") ++) $ | |
filter (\x -> (head x) /= '.') rawDirs | |
return l | |
getModTimes :: [FilePath] -> IO [(FilePath,T.ClockTime)] | |
getModTimes d = do | |
t <- M.mapM D.getModificationTime d | |
return $ zip d t |
last update 2010-12-04