packages feed

notmuch-haskell 0.2.2 → 1.0.0.3

raw patch · 4 files changed

+204/−111 lines, 4 filesdep −haskell98dep ~basedep ~containersdep ~filepathPVP ok

version bump matches the API change (PVP)

Dependencies removed: haskell98

Dependency ranges changed: base, containers, filepath, old-locale, parseargs, time

API changes (from Hackage documentation)

+ Foreign.Notmuch: MessageFlagExcluded :: MessageFlag
+ Foreign.Notmuch: databaseBeginAtomic :: Database -> IO ()
+ Foreign.Notmuch: databaseDestroy :: Database -> IO ()
+ Foreign.Notmuch: databaseEndAtomic :: Database -> IO ()
+ Foreign.Notmuch: queryCountThreads :: Query -> IO Word
+ Foreign.Notmuch: querySetOmitExcluded :: Query -> Bool -> IO ()

Files

Foreign/NOTMUCH_H.hsc view
@@ -9,6 +9,11 @@ --   gcc -E -dD notmuch.h | hsffig >NOTMUCH_H.hsc -- Later hand-edited +-- XXX As of GHC 7.2, the #include directives are simply+-- ignored, even with -fvia-C. This is pretty painful, as it+-- means that changes to APIs are not noticed by the+-- compiler. Uggh.+ #if __GLASGOW_HASKELL__ && __GLASGOW_HASKELL__ < 409 #include <Rts.h> #endif@@ -22,7 +27,7 @@  #def void _dummy_force_NOTMUCH_H_hsc_c (void) { } -{-# OPTIONS -fglasgow-exts -XForeignFunctionInterface #-}+{-# OPTIONS -XForeignFunctionInterface #-}  #include "notmuch.h" @@ -33,7 +38,6 @@   module Foreign.C.Types) where  import Foreign-import Foreign.Ptr import Foreign.C.Types import Foreign.C.String @@ -51,14 +55,20 @@   f_notmuch_status_to_string :: CInt -> IO (Ptr (CChar))  foreign import ccall "static notmuch.h notmuch_database_create"-  f_notmuch_database_create :: Ptr (CChar) -> IO (Ptr (S__notmuch_database))+  f_notmuch_database_create :: Ptr (CChar) -> Ptr (Ptr (S__notmuch_database)) -> IO (CInt)  foreign import ccall "static notmuch.h notmuch_database_open"-  f_notmuch_database_open :: Ptr (CChar) -> CInt -> IO (Ptr (S__notmuch_database))+  f_notmuch_database_open :: Ptr (CChar) -> CInt -> Ptr (Ptr (S__notmuch_database)) -> IO (CInt)  foreign import ccall "static notmuch.h notmuch_database_close"   f_notmuch_database_close :: Ptr (S__notmuch_database) -> IO (()) +foreign import ccall "static notmuch.h notmuch_database_destroy"+  f_notmuch_database_destroy :: Ptr (S__notmuch_database) -> IO (())++foreign import ccall "static notmuch.h &notmuch_database_destroy"+  pf_notmuch_database_destroy :: FunPtr (Ptr (S__notmuch_database) -> IO (()))+ foreign import ccall "static notmuch.h notmuch_database_get_path"   f_notmuch_database_get_path :: Ptr (S__notmuch_database) -> IO (Ptr (CChar)) @@ -73,8 +83,14 @@ foreign import ccall "wrapper"   w_notmuch_database_upgrade_1 :: (Ptr (CChar) -> CDouble -> IO (())) -> IO (FunPtr (Ptr (CChar) -> CDouble -> IO (()))) +foreign import ccall "static notmuch.h notmuch_database_begin_atomic"+  f_notmuch_database_begin_atomic :: Ptr (S__notmuch_database) -> IO (CInt)++foreign import ccall "static notmuch.h notmuch_database_end_atomic"+  f_notmuch_database_end_atomic :: Ptr (S__notmuch_database) -> IO (CInt)+ foreign import ccall "static notmuch.h notmuch_database_get_directory"-  f_notmuch_database_get_directory :: Ptr (S__notmuch_database) -> Ptr (CChar) -> IO (Ptr (S__notmuch_directory))+  f_notmuch_database_get_directory :: Ptr (S__notmuch_database) -> Ptr (CChar) -> Ptr (Ptr (S__notmuch_directory)) -> IO (CInt)  foreign import ccall "static notmuch.h notmuch_database_add_message"   f_notmuch_database_add_message :: Ptr (S__notmuch_database) -> Ptr (CChar) -> Ptr (Ptr (S__notmuch_message)) -> IO (CInt)@@ -83,7 +99,7 @@   f_notmuch_database_remove_message :: Ptr (S__notmuch_database) -> Ptr (CChar) -> IO (CInt)  foreign import ccall "static notmuch.h notmuch_database_find_message"-  f_notmuch_database_find_message :: Ptr (S__notmuch_database) -> Ptr (CChar) -> IO (Ptr (S__notmuch_message))+  f_notmuch_database_find_message :: Ptr (S__notmuch_database) -> Ptr (CChar) -> Ptr (Ptr (S__notmuch_message)) -> IO (CInt)  foreign import ccall "static notmuch.h notmuch_database_get_all_tags"   f_notmuch_database_get_all_tags :: Ptr (S__notmuch_database) -> IO (Ptr (S__notmuch_tags))@@ -91,6 +107,9 @@ foreign import ccall "static notmuch.h notmuch_query_create"   f_notmuch_query_create :: Ptr (S__notmuch_database) -> Ptr (CChar) -> IO (Ptr (S__notmuch_query)) +foreign import ccall "static notmuch.h notmuch_query_set_omit_excluded"+  f_notmuch_query_set_omit_excluded :: Ptr (S__notmuch_query) -> CInt -> IO (())+ foreign import ccall "static notmuch.h notmuch_query_set_sort"   f_notmuch_query_set_sort :: Ptr (S__notmuch_query) -> CInt -> IO (()) @@ -108,6 +127,9 @@  foreign import ccall "static notmuch.h notmuch_threads_valid"   f_notmuch_threads_valid :: Ptr (S__notmuch_threads) -> IO (CInt)++foreign import ccall "static notmuch.h notmuch_query_count_threads"+  f_notmuch_query_count_threads :: Ptr (S__notmuch_query) -> IO (CUInt)  foreign import ccall "static notmuch.h notmuch_threads_get"   f_notmuch_threads_get :: Ptr (S__notmuch_threads) -> IO (Ptr (S__notmuch_thread))
Foreign/Notmuch.hs view
@@ -4,22 +4,24 @@ -- Licensed LGPL v3: please see the file COPYING in this -- source distribution for licensing information. --- | This is a very preliminary higher-level Haskell binding+-- | This is a half-assed higher-level Haskell binding -- for the Notmuch (notmuchmail.org) email indexing library. -- There is no documentation here; see the Notmuch -- documentation for hints on how to use this.  module Foreign.Notmuch (   Database, databaseCreate, DatabaseMode(..),-  databaseOpen, databaseClose, databaseGetPath,+  databaseOpen, databaseClose, databaseDestroy, databaseGetPath,   databaseGetVersion, databaseNeedsUpgrade,   UpgradeCallback, databaseUpgrade,+  databaseBeginAtomic, databaseEndAtomic,   Directory, databaseGetDirectory,   Message, Messages, databaseAddMessage,   databaseRemoveMessage, databaseFindMessage,   Tags, databaseGetAllTags,-  Query, queryCreate, SortOrder(..), querySetSortOrder,-  Thread, Threads, queryThreads,+  Query, queryCreate, querySetOmitExcluded, +  SortOrder(..), querySetSortOrder,+  Thread, Threads, queryCountThreads, queryThreads,   queryMessages, queryCountMessages,   getThreadID, threadCountMessages, threadCountMatchedMessages,   threadGetToplevelMessages, threadGetAuthors,@@ -42,16 +44,19 @@ import Data.List import Data.Time import Data.Time.Clock.POSIX-import System.FilePath -newtype Database = Database (Ptr S__notmuch_database)+newtype Database = Database (ForeignPtr S__notmuch_database)  databaseCreate :: FilePath -> IO Database-databaseCreate name = do-  db <- withCString name f_notmuch_database_create-  when (db == nullPtr) $-       fail "database create failed"-  return $ Database db+databaseCreate filename = alloca dbFun where+  dbFun dbPtr = do+    let create fn =+          f_notmuch_database_create fn dbPtr+    s <- withCString filename create+    statusCheck s+    cdb <- peek dbPtr+    db <- newForeignPtr pf_notmuch_database_destroy cdb+    return $ Database db  -- XXX Deriving Enum will only work if these fields are in -- the same order as in notmuch.h and there are no gaps@@ -62,25 +67,34 @@     deriving Enum  databaseOpen :: FilePath -> DatabaseMode -> IO Database-databaseOpen name databaseMode = do-  db <- withCString name $-        flip f_notmuch_database_open $-        fromIntegral $ fromEnum databaseMode-  when (db == nullPtr) $-       fail "database open failed"-  return $ Database db+databaseOpen filename databaseMode = alloca dbFun where+  dbFun dbPtr = do+    let open mode fn =+          f_notmuch_database_open fn mode dbPtr+    s <- withCString filename (open (fromIntegral (fromEnum databaseMode)))+    statusCheck s+    cdb <- peek dbPtr+    db <- newForeignPtr pf_notmuch_database_destroy cdb+    return $ Database db +withDatabase :: Database -> ((Ptr S__notmuch_database) -> IO a) -> IO a+withDatabase (Database db) f = withForeignPtr db f+ databaseClose :: Database -> IO ()-databaseClose (Database db) = f_notmuch_database_close db+databaseClose db = withDatabase db f_notmuch_database_close +databaseDestroy :: Database -> IO ()+databaseDestroy db = withDatabase db f_notmuch_database_destroy+ databaseGetPath :: Database -> IO FilePath-databaseGetPath (Database db) =-    resultString $ f_notmuch_database_get_path db+databaseGetPath db = withDatabase db $+    resultString . f_notmuch_database_get_path  databaseGetVersion :: Database -> IO Int-databaseGetVersion (Database db) = do-  v <- f_notmuch_database_get_version db-  return $ fromIntegral v+databaseGetVersion db = +  withDatabase db $ \dbp -> do+    v <- f_notmuch_database_get_version dbp+    return $ fromIntegral v  resultBool :: IO CInt -> IO Bool resultBool = fmap (/= 0)@@ -95,8 +109,8 @@ resultWord = fmap fromIntegral  databaseNeedsUpgrade :: Database -> IO Bool-databaseNeedsUpgrade (Database db) =-    resultBool $ f_notmuch_database_needs_upgrade db+databaseNeedsUpgrade db = withDatabase db $+    resultBool . f_notmuch_database_needs_upgrade  statusCheck :: CInt -> IO () statusCheck 0 = return ()@@ -107,37 +121,65 @@ type UpgradeCallback = String -> Double -> IO ()  databaseUpgrade :: Database -> Maybe UpgradeCallback -> IO ()-databaseUpgrade (Database db) (Just callback) = do-  let ccb msg progress = do-        cmsg <- peekCString msg-        let cprogress = realToFrac progress-        callback cmsg cprogress-  cb <- w_notmuch_database_upgrade_1 ccb-  s <- f_notmuch_database_upgrade db cb nullPtr-  statusCheck s-databaseUpgrade (Database db) Nothing = do-  s <- f_notmuch_database_upgrade db nullFunPtr nullPtr-  statusCheck s+databaseUpgrade db (Just callback) = +  withDatabase db $ \dbp -> do+    let ccb msg progress = do+          cmsg <- peekCString msg+          let cprogress = realToFrac progress+          callback cmsg cprogress+    cb <- w_notmuch_database_upgrade_1 ccb+    s <- f_notmuch_database_upgrade dbp cb nullPtr+    statusCheck s+databaseUpgrade db Nothing = +  withDatabase db $ \dbp -> do+    s <- f_notmuch_database_upgrade dbp nullFunPtr nullPtr+    statusCheck s +databaseBeginAtomic :: Database -> IO ()+databaseBeginAtomic db =+  withDatabase db $ \dbp -> do+    s <- f_notmuch_database_begin_atomic dbp+    statusCheck s++databaseEndAtomic :: Database -> IO ()+databaseEndAtomic db =+  withDatabase db $ \dbp -> do+    s <- f_notmuch_database_end_atomic dbp+    statusCheck s+ newtype Directory = Directory (ForeignPtr S__notmuch_directory)  databaseGetDirectory :: Database -> FilePath -> IO Directory-databaseGetDirectory (Database db) path = withCString path $ (\p -> do-  dir <- f_notmuch_database_get_directory db p-  dirp <- newForeignPtr pf_notmuch_directory_destroy dir-  return $ Directory dirp)+databaseGetDirectory db path = alloca dirFun where+  dirFun dirPtr = withDatabase db $ \dbp -> do+    let getDirectory pathp =+          f_notmuch_database_get_directory dbp pathp dirPtr+    s <- withCString path getDirectory+    statusCheck s+    cdir <- peek dirPtr+    dir <- newForeignPtr pf_notmuch_directory_destroy cdir+    return $ Directory dir    type MessagesPtr = ForeignPtr S__notmuch_messages  type MessagePtr = ForeignPtr S__notmuch_message -data MessagesRef = QueryMessages { qmpp :: Query, msp :: MessagesPtr }-                 | ThreadMessages { tmpp :: Thread, msp :: MessagesPtr }-                 | MessageMessages { mmspp :: Message, msp :: MessagesPtr }+data MessagesRef = QueryMessages  Query MessagesPtr+                 | ThreadMessages Thread MessagesPtr+                 | MessageMessages Message MessagesPtr -data Message = MessagesMessage { msmpp :: MessagesRef, mp :: MessagePtr }-             | Message { mp :: MessagePtr }+msp :: MessagesRef -> MessagesPtr+msp (QueryMessages _ m) = m+msp (ThreadMessages _ m) = m+msp (MessageMessages _ m) = m +data Message = MessagesMessage MessagesRef MessagePtr+             | Message MessagePtr++mp :: Message -> MessagePtr+mp (MessagesMessage _ m) = m+mp (Message m) = m+ type Messages = [Message]  -- XXX We provide no way to request a null message pointer,@@ -148,10 +190,10 @@ -- succeed.  I have no idea what it should do, and this -- was easiest. databaseAddMessage :: Database -> FilePath -> IO Message-databaseAddMessage (Database db) filename = alloca msgFun where-    msgFun msgPtr = do+databaseAddMessage db filename = alloca msgFun where+    msgFun msgPtr = withDatabase db $ \dbp -> do       let addMessage fn =-              f_notmuch_database_add_message db fn msgPtr+              f_notmuch_database_add_message dbp fn msgPtr       s <- withCString filename addMessage       statusCheck s       cmsg <- peek msgPtr@@ -162,32 +204,34 @@ -- succeed.  I have no idea what it should do, and this -- was easiest. databaseRemoveMessage :: Database -> FilePath -> IO ()-databaseRemoveMessage (Database db) filename = do-  let removeMessage fn = f_notmuch_database_remove_message db fn-  s <- withCString filename removeMessage-  statusCheck s+databaseRemoveMessage db filename = +  withDatabase db $ \dbp -> do+    let removeMessage fn = f_notmuch_database_remove_message dbp fn+    s <- withCString filename removeMessage+    statusCheck s  -- XXX This might want to return a Maybe Message instead -- of failing if the message is not found.  I don't quite -- understand the use case yet. databaseFindMessage :: Database -> String -> IO Message-databaseFindMessage (Database db) msgid = do-  let findMessage mid =-          f_notmuch_database_find_message db mid-  cmsg <- withCString msgid findMessage-  when (cmsg == nullPtr) $-       fail "database find message failed"-  m <- newForeignPtr pf_notmuch_message_destroy cmsg-  return $ Message m+databaseFindMessage db msgid = alloca msgFun where+  msgFun msgPtr = withDatabase db $ \dbp -> do+    let findMessage mid =+          f_notmuch_database_find_message dbp mid msgPtr+    s <- withCString msgid findMessage+    statusCheck s+    cmsg <- peek msgPtr+    msg <- newForeignPtr pf_notmuch_message_destroy cmsg+    return $ Message msg    iterM :: Monad m => a -> (a -> m Bool) -> (a -> m b) -> m [b]-iterM coln test get = go [] coln test get-    where go acc coln test get = do+iterM coln test get = go []+    where go acc = do             cont <- test coln             case cont of               True -> do-                elem <- get coln-                go (elem : acc) coln test get+                e <- get coln+                go (e : acc)               False -> return acc  iterUnpack :: Ptr a -> (Ptr a -> IO CInt) ->@@ -217,8 +261,8 @@   databaseGetAllTags :: Database -> IO Tags-databaseGetAllTags (Database db) = do-  tags <- f_notmuch_database_get_all_tags db+databaseGetAllTags db = do+  tags <- withDatabase db $ f_notmuch_database_get_all_tags   when (tags == nullPtr) $        fail "database get all tags failed"   unpackTags tags@@ -226,13 +270,19 @@ newtype Query = Query (ForeignPtr S__notmuch_query)  queryCreate :: Database -> String -> IO Query-queryCreate (Database db) queryString = do-    query <- withCString queryString $ f_notmuch_query_create db+queryCreate db queryString = +  withDatabase db $ \dbp -> do+    query <- withCString queryString (f_notmuch_query_create dbp)     when (query == nullPtr) $-         fail "query create failed"+      fail "query create failed"     queryp <- newForeignPtr pf_notmuch_query_destroy query     return $ Query queryp +querySetOmitExcluded :: Query -> Bool -> IO ()+querySetOmitExcluded (Query query) omit = +  withForeignPtr query $ \q ->+    f_notmuch_query_set_omit_excluded q (fromIntegral (fromEnum omit))+ -- XXX Deriving Enum will only work if these fields are in -- the same order as in notmuch.h and there are no gaps -- there.@@ -253,29 +303,34 @@  type ThreadPtr = ForeignPtr S__notmuch_thread -data ThreadsRef = QueryThreads { qtspp :: Query,-                                 tsp :: ThreadsPtr }+data ThreadsRef = QueryThreads Query ThreadsPtr -data Thread = QueryThread { qtpp :: Query,-                            tp :: ThreadPtr }-            | ThreadsThread { ttpp :: ThreadsRef,-                              tp :: ThreadPtr }+data Thread = QueryThread Query ThreadPtr+            | ThreadsThread ThreadsRef ThreadPtr +tp :: Thread -> ThreadPtr+tp (QueryThread _ t) = t+tp (ThreadsThread _ t) = t+ type Threads = [Thread] +queryCountThreads :: Query -> IO Word+queryCountThreads (Query query) =+    withForeignPtr query $ resultWord . f_notmuch_query_count_threads+ queryThreads :: Query -> IO Threads queryThreads (Query query) = withForeignPtr query $ \q -> do   threads <- f_notmuch_query_search_threads q   when (threads == nullPtr) $        fail "query threads failed"-  tsp <- newForeignPtr pf_notmuch_threads_destroy threads-  let qts = QueryThreads (Query query) tsp+  t <- newForeignPtr pf_notmuch_threads_destroy threads+  let qts = QueryThreads (Query query) t   iterUnpack threads       f_notmuch_threads_valid       (\ts -> do-         t <- f_notmuch_threads_get ts-         tp <- newForeignPtr pf_notmuch_thread_destroy t-         let tst = ThreadsThread qts tp+         t' <- f_notmuch_threads_get ts+         t'' <- newForeignPtr pf_notmuch_thread_destroy t'+         let tst = ThreadsThread qts t''          return tst)       f_notmuch_threads_move_to_next @@ -285,8 +340,8 @@       f_notmuch_messages_valid       (\t -> do          m <- f_notmuch_messages_get t-         mp <- newForeignPtr pf_notmuch_message_destroy m-         let msm = MessagesMessage messages mp+         m' <- newForeignPtr pf_notmuch_message_destroy m+         let msm = MessagesMessage messages m'          return msm)       f_notmuch_messages_move_to_next @@ -399,7 +454,7 @@   peekCString path  data MessageFlag =-    MessageFlagMatch+    MessageFlagMatch | MessageFlagExcluded     deriving Enum               messageGetFlag :: Message -> MessageFlag -> IO Bool@@ -458,10 +513,10 @@  directorySetMtime :: Directory -> UTCTime -> IO () directorySetMtime (Directory dir) time = withForeignPtr dir $ \d -> do-  let t = fromIntegral $ floor $ realToFrac $ utcTimeToPOSIXSeconds time+  let t = floor $ utcTimeToPOSIXSeconds time :: Integer   when (t <= 0) $        fail "directory set mtime with invalid mtime"-  s <- f_notmuch_directory_set_mtime d t+  s <- f_notmuch_directory_set_mtime d (fromIntegral t)   statusCheck s  directoryGetMtime :: Directory -> IO UTCTime
NotmuchTest.hs view
@@ -12,7 +12,6 @@  import Control.Monad import Data.Time-import IO import System.Environment import System.Locale     @@ -21,6 +20,7 @@ dateString :: FormatTime t => t -> String dateString = formatTime defaultTimeLocale "%c" +main :: IO () main = do   argv <- getArgs   db <- if (length argv == 0)@@ -47,18 +47,21 @@   nthreadss <- mapM threadCountMessages threads   putStr $ show (sum nthreadss) ++ "/" ++ show (length threads) ++ ": "   print nthreadss-  let thread = last threads-  subject <- threadGetSubject thread-  putStrLn subject-  messages <- threadGetToplevelMessages thread-  let message = head messages-  subject' <- messageGetHeader message "Subject"-  putStrLn subject'-  date' <- messageGetHeader message "Date"-  putStrLn date'-  date <- messageGetDate message-  putStrLn $ dateString date-  localdate <- utcToLocalZonedTime date-  putStrLn $ dateString localdate+  case threads of+    [] -> return ()+    _ -> do+      let thread = last threads+      subject <- threadGetSubject thread+      putStrLn subject+      messages <- threadGetToplevelMessages thread+      let message = head messages+      subject' <- messageGetHeader message "Subject"+      putStrLn subject'+      date' <- messageGetHeader message "Date"+      putStrLn date'+      date <- messageGetDate message+      putStrLn $ dateString date+      localdate <- utcToLocalZonedTime date+      putStrLn $ dateString localdate   databaseClose db   return ()
notmuch-haskell.cabal view
@@ -1,5 +1,5 @@ Name: notmuch-haskell-Version: 0.2.2+Version: 1.0.0.3 Cabal-Version: >= 1.6 Author: Bart Massey <bart@cs.pdx.edu> Maintainer: Bart Massey <bart@cs.pdx.edu>@@ -12,17 +12,30 @@ Stability: Experimental Bug-Reports: mailto:bart@cs.pdx.edu Description:-   This is a very preliminary higher-level Haskell binding+   This is a half-assed higher-level Haskell binding    for the Notmuch (notmuchmail.org) email indexing library.  Library-  Build-Depends: base, containers, time, filepath+  Build-Depends: base >= 4.5 && < 6, containers >= 0.4.2 && < 5,+                 time >= 1.4 && < 2, filepath >= 0.1.3 && < 2   Exposed-Modules: Foreign.Notmuch   Other-Modules: Foreign.NOTMUCH_H-  Extra-Libraries: notmuch gmime-2.4 z nsl gobject-2.0 glib-2.0 talloc xapian+  Extra-Libraries: notmuch+  GHC-Options: -Wall  Executable notmuch-test   main-is: NotmuchTest.hs   other-modules: Foreign.Notmuch Foreign.NOTMUCH_H-  build-depends: base >= 4 && < 5, haskell98, old-locale, parseargs+  build-depends: base >= 4.5 && < 6, old-locale >= 1 && < 2,+                 parseargs >= 0.1.3 && < 2   Extra-Libraries: notmuch+  GHC-Options: -Wall++Source-repository head+  type: git+  location: git://github.com/BartMassey/notmuch-haskell.git++Source-repository this+  type: git+  location: git://github.com/BartMassey/notmuch-haskell.git+  tag: v1.0.0.3