aboutsummaryrefslogtreecommitdiff
path: root/bindings
diff options
context:
space:
mode:
authorDavid Bremner <bremner@debian.org>2012-06-17 07:38:59 -0300
committerDavid Bremner <bremner@debian.org>2012-06-17 07:38:59 -0300
commit3dc2ff6fc73d3a057ae0a3f350c42b077d7ec273 (patch)
tree19322fd5112777d877a7e31eef3efbc4ac0ef6cd /bindings
parent3b1e8a200dd4740b3c5605256e1535a681367347 (diff)
parent2ef24acf03fdd73e39d2c233016e71f194affbcf (diff)
Merge branch 'release' into squeeze-backports
Conflicts: debian/changelog
Diffstat (limited to 'bindings')
-rw-r--r--bindings/go/Makefile52
-rw-r--r--bindings/go/cmds/Makefile11
-rw-r--r--bindings/go/pkg/Makefile17
-rw-r--r--bindings/go/src/notmuch-addrlookup/addrlookup.go (renamed from bindings/go/cmds/notmuch-addrlookup.go)90
-rw-r--r--bindings/go/src/notmuch/notmuch.go (renamed from bindings/go/pkg/notmuch.go)140
-rw-r--r--bindings/python/docs/source/database.rst2
-rw-r--r--bindings/python/docs/source/filesystem.rst2
-rw-r--r--bindings/python/notmuch/database.py96
-rw-r--r--bindings/python/notmuch/directory.py4
-rw-r--r--bindings/python/notmuch/filenames.py75
-rw-r--r--bindings/python/notmuch/globals.py4
-rw-r--r--bindings/python/notmuch/message.py37
-rw-r--r--bindings/python/notmuch/messages.py18
-rw-r--r--bindings/python/notmuch/query.py4
-rw-r--r--bindings/python/notmuch/tag.py20
-rw-r--r--bindings/python/notmuch/thread.py4
-rw-r--r--bindings/python/notmuch/threads.py23
-rw-r--r--bindings/python/notmuch/version.py2
-rw-r--r--bindings/python/setup.py61
-rw-r--r--bindings/ruby/database.c25
-rw-r--r--bindings/ruby/defs.h11
-rw-r--r--bindings/ruby/extconf.rb2
-rw-r--r--bindings/ruby/init.c11
-rw-r--r--bindings/ruby/query.c57
24 files changed, 426 insertions, 342 deletions
diff --git a/bindings/go/Makefile b/bindings/go/Makefile
index aba2d595..c38f2340 100644
--- a/bindings/go/Makefile
+++ b/bindings/go/Makefile
@@ -1,30 +1,40 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
+# Makefile for the go bindings of notmuch
-include ${GOROOT}/src/Make.inc
+export GOPATH ?= $(shell pwd)
+export CGO_CFLAGS ?= -I../../../../lib
+export CGO_LDFLAGS ?= -L../../../../lib
-all: install
+GO ?= go
+GOFMT ?= gofmt
-DIRS=\
- pkg\
- cmds\
+all: notmuch notmuch-addrlookup
+.PHONY: notmuch
+notmuch:
+ $(GO) install notmuch
-clean.dirs: $(addsuffix .clean, $(DIRS))
-install.dirs: $(addsuffix .install, $(DIRS))
-nuke.dirs: $(addsuffix .nuke, $(DIRS))
-test.dirs: $(addsuffix .test, $(TEST))
-bench.dirs: $(addsuffix .bench, $(BENCH))
+.PHONY: goconfig
+goconfig:
+ if [ ! -d src/github.com/kless/goconfig/config ]; then \
+ $(GO) get github.com/kless/goconfig/config; \
+ fi
-%.clean:
- +cd $* && $(QUOTED_GOBIN)/gomake clean
+.PHONY: notmuch-addrlookup
+notmuch-addrlookup: notmuch goconfig
+ $(GO) install notmuch-addrlookup
-%.install:
- +cd $* && $(QUOTED_GOBIN)/gomake install
+.PHONY: format
+format:
+ $(GOFMT) -w=true $(GOFMT_OPTS) src/notmuch
+ $(GOFMT) -w=true $(GOFMT_OPTS) src/notmuch-addrlookup
-clean: clean.dirs
+.PHONY: check-format
+check-format:
+ $(GOFMT) -d=true $(GOFMT_OPTS) src/notmuch
+ $(GOFMT) -d=true $(GOFMT_OPTS) src/notmuch-addrlookup
-install: install.dirs
-
-#-include ${GOROOT}/src/Make.deps
+.PHONY: clean
+clean:
+ $(GO) clean notmuch
+ $(GO) clean notmuch-addrlookup
+ rm -rf pkg bin
diff --git a/bindings/go/cmds/Makefile b/bindings/go/cmds/Makefile
deleted file mode 100644
index afbc6d22..00000000
--- a/bindings/go/cmds/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ${GOROOT}/src/Make.inc
-
-TARG=notmuch-addrlookup
-GOFILES=\
- notmuch-addrlookup.go
-
-include ${GOROOT}/src/Make.cmd
diff --git a/bindings/go/pkg/Makefile b/bindings/go/pkg/Makefile
deleted file mode 100644
index de89dbc9..00000000
--- a/bindings/go/pkg/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include $(GOROOT)/src/Make.inc
-
-TARG=notmuch
-CGOFILES=notmuch.go
-CGO_LDFLAGS=-lnotmuch
-
-CLEANFILES+=notmuch_test
-
-include $(GOROOT)/src/Make.pkg
-
-%: install %.go
- $(GC) $*.go
- $(LD) -o $@ $*.$O
diff --git a/bindings/go/cmds/notmuch-addrlookup.go b/bindings/go/src/notmuch-addrlookup/addrlookup.go
index 16958e50..59283f81 100644
--- a/bindings/go/cmds/notmuch-addrlookup.go
+++ b/bindings/go/src/notmuch-addrlookup/addrlookup.go
@@ -22,18 +22,18 @@ type frequencies map[string]uint
/* Used to sort the email addresses from most to least used */
func sort_by_freq(m1, m2 *mail_addr_freq) int {
- if (m1.count[0] == m2.count[0] &&
+ if m1.count[0] == m2.count[0] &&
m1.count[1] == m2.count[1] &&
- m1.count[2] == m2.count[2]) {
+ m1.count[2] == m2.count[2] {
return 0
}
- if (m1.count[0] > m2.count[0] ||
+ if m1.count[0] > m2.count[0] ||
m1.count[0] == m2.count[0] &&
- m1.count[1] > m2.count[1] ||
+ m1.count[1] > m2.count[1] ||
m1.count[0] == m2.count[0] &&
- m1.count[1] == m2.count[1] &&
- m1.count[2] > m2.count[2]) {
+ m1.count[1] == m2.count[1] &&
+ m1.count[2] > m2.count[2] {
return -1
}
@@ -46,17 +46,17 @@ func (self *maddresses) Len() int {
return len(*self)
}
-func (self *maddresses) Less(i,j int) bool {
+func (self *maddresses) Less(i, j int) bool {
m1 := (*self)[i]
m2 := (*self)[j]
- v := sort_by_freq(m1, m2)
- if v<=0 {
+ v := sort_by_freq(m1, m2)
+ if v <= 0 {
return true
}
return false
}
-func (self *maddresses) Swap(i,j int) {
+func (self *maddresses) Swap(i, j int) {
(*self)[i], (*self)[j] = (*self)[j], (*self)[i]
}
@@ -66,7 +66,7 @@ func frequent_fullname(freqs frequencies) string {
fullname := ""
freqs_sz := len(freqs)
- for mail,freq := range freqs {
+ for mail, freq := range freqs {
if (freq > maxfreq && mail != "") || freqs_sz == 1 {
// only use the entry if it has a real name
// or if this is the only entry
@@ -86,33 +86,33 @@ func addresses_by_frequency(msgs *notmuch.Messages, name string, pass uint, addr
// "<?(?P<mail>\\b\\w+([-+.]\\w+)*\\@\\w+[-\\.\\w]*\\.([-\\.\\w]+)*\\w\\b)>?)"
pattern = `.*` + strings.ToLower(name) + `.*`
var re *regexp.Regexp = nil
- var err os.Error = nil
- if re,err = regexp.Compile(pattern); err != nil {
+ var err error = nil
+ if re, err = regexp.Compile(pattern); err != nil {
log.Printf("error: %v\n", err)
return &freqs
}
-
+
headers := []string{"from"}
if pass == 1 {
headers = append(headers, "to", "cc", "bcc")
}
- for ;msgs.Valid();msgs.MoveToNext() {
+ for ; msgs.Valid(); msgs.MoveToNext() {
msg := msgs.Get()
//println("==> msg [", msg.GetMessageId(), "]")
- for _,header := range headers {
+ for _, header := range headers {
froms := strings.ToLower(msg.GetHeader(header))
//println(" froms: ["+froms+"]")
- for _,from := range strings.Split(froms, ",", -1) {
+ for _, from := range strings.Split(froms, ",") {
from = strings.Trim(from, " ")
match := re.FindString(from)
//println(" -> match: ["+match+"]")
- occ,ok := freqs[match]
+ occ, ok := freqs[match]
if !ok {
freqs[match] = 0
occ = 0
}
- freqs[match] = occ+1
+ freqs[match] = occ + 1
}
}
}
@@ -125,7 +125,7 @@ func search_address_passes(queries [3]*notmuch.Query, name string) []string {
addr_to_realname := make(map[string]*frequencies)
var pass uint = 0 // 0-based
- for _,query := range queries {
+ for _, query := range queries {
if query == nil {
//println("**warning: idx [",idx,"] contains a nil query")
continue
@@ -133,9 +133,9 @@ func search_address_passes(queries [3]*notmuch.Query, name string) []string {
msgs := query.SearchMessages()
ht := addresses_by_frequency(msgs, name, pass, &addr_to_realname)
for addr, count := range *ht {
- freq,ok := addr_freq[addr]
+ freq, ok := addr_freq[addr]
if !ok {
- freq = &mail_addr_freq{addr:addr, count:[3]uint{0,0,0}}
+ freq = &mail_addr_freq{addr: addr, count: [3]uint{0, 0, 0}}
}
freq.count[pass] = count
addr_freq[addr] = freq
@@ -154,8 +154,8 @@ func search_address_passes(queries [3]*notmuch.Query, name string) []string {
}
sort.Sort(&addrs)
- for _,addr := range addrs {
- freqs,ok := addr_to_realname[addr.addr]
+ for _, addr := range addrs {
+ freqs, ok := addr_to_realname[addr.addr]
if ok {
val = append(val, frequent_fullname(*freqs))
} else {
@@ -179,7 +179,7 @@ type address_matcher struct {
func new_address_matcher() *address_matcher {
var cfg *config.Config
- var err os.Error
+ var err error
// honor NOTMUCH_CONFIG
home := os.Getenv("NOTMUCH_CONFIG")
@@ -187,30 +187,34 @@ func new_address_matcher() *address_matcher {
home = os.Getenv("HOME")
}
- if cfg,err = config.ReadDefault(path.Join(home, ".notmuch-config")); err != nil {
- log.Fatalf("error loading config file:",err)
+ if cfg, err = config.ReadDefault(path.Join(home, ".notmuch-config")); err != nil {
+ log.Fatalf("error loading config file:", err)
}
- db_path,_ := cfg.String("database", "path")
- primary_email,_ := cfg.String("user", "primary_email")
- addrbook_tag,err := cfg.String("user", "addrbook_tag")
+ db_path, _ := cfg.String("database", "path")
+ primary_email, _ := cfg.String("user", "primary_email")
+ addrbook_tag, err := cfg.String("user", "addrbook_tag")
if err != nil {
addrbook_tag = "addressbook"
}
- self := &address_matcher{db:nil,
- user_db_path:db_path,
- user_primary_email:primary_email,
- user_addrbook_tag:addrbook_tag}
+ self := &address_matcher{db: nil,
+ user_db_path: db_path,
+ user_primary_email: primary_email,
+ user_addrbook_tag: addrbook_tag}
return self
}
func (self *address_matcher) run(name string) {
queries := [3]*notmuch.Query{}
-
+
// open the database
- self.db = notmuch.OpenDatabase(self.user_db_path,
- notmuch.DATABASE_MODE_READ_ONLY)
+ if db, status := notmuch.OpenDatabase(self.user_db_path,
+ notmuch.DATABASE_MODE_READ_ONLY); status == notmuch.STATUS_SUCCESS {
+ self.db = db
+ } else {
+ log.Fatalf("Failed to open the database: %v\n", status)
+ }
// pass 1: look at all from: addresses with the address book tag
query := "tag:" + self.user_addrbook_tag
@@ -222,7 +226,7 @@ func (self *address_matcher) run(name string) {
// pass 2: look at all to: addresses sent from our primary mail
query = ""
if name != "" {
- query = "to:"+name+"*"
+ query = "to:" + name + "*"
}
if self.user_primary_email != "" {
query = query + " from:" + self.user_primary_email
@@ -230,17 +234,17 @@ func (self *address_matcher) run(name string) {
queries[1] = self.db.CreateQuery(query)
// if that leads only to a few hits, we check every from too
- if queries[0].CountMessages() + queries[1].CountMessages() < 10 {
+ if queries[0].CountMessages()+queries[1].CountMessages() < 10 {
query = ""
if name != "" {
- query = "from:"+name+"*"
+ query = "from:" + name + "*"
}
queries[2] = self.db.CreateQuery(query)
}
-
+
// actually retrieve and sort addresses
results := search_address_passes(queries, name)
- for _,v := range results {
+ for _, v := range results {
if v != "" && v != "\n" {
fmt.Println(v)
}
@@ -256,4 +260,4 @@ func main() {
name = os.Args[1]
}
app.run(name)
-} \ No newline at end of file
+}
diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/src/notmuch/notmuch.go
index c6844ef9..00bd53ac 100644
--- a/bindings/go/pkg/notmuch.go
+++ b/bindings/go/src/notmuch/notmuch.go
@@ -3,6 +3,8 @@
package notmuch
/*
+#cgo LDFLAGS: -lnotmuch
+
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -13,24 +15,26 @@ import "unsafe"
// Status codes used for the return values of most functions
type Status C.notmuch_status_t
+
const (
- STATUS_SUCCESS Status = 0
+ STATUS_SUCCESS Status = iota
STATUS_OUT_OF_MEMORY
- STATUS_READ_ONLY_DATABASE
- STATUS_XAPIAN_EXCEPTION
- STATUS_FILE_ERROR
- STATUS_FILE_NOT_EMAIL
- STATUS_DUPLICATE_MESSAGE_ID
- STATUS_NULL_POINTER
- STATUS_TAG_TOO_LONG
- STATUS_UNBALANCED_FREEZE_THAW
+ STATUS_READ_ONLY_DATABASE
+ STATUS_XAPIAN_EXCEPTION
+ STATUS_FILE_ERROR
+ STATUS_FILE_NOT_EMAIL
+ STATUS_DUPLICATE_MESSAGE_ID
+ STATUS_NULL_POINTER
+ STATUS_TAG_TOO_LONG
+ STATUS_UNBALANCED_FREEZE_THAW
+ STATUS_UNBALANCED_ATOMIC
- STATUS_LAST_STATUS
+ STATUS_LAST_STATUS
)
func (self Status) String() string {
var p *C.char
-
+
// p is read-only
p = C.notmuch_status_to_string(C.notmuch_status_t(self))
if p != nil {
@@ -80,27 +84,28 @@ type Filenames struct {
}
type DatabaseMode C.notmuch_database_mode_t
+
const (
- DATABASE_MODE_READ_ONLY DatabaseMode = 0
- DATABASE_MODE_READ_WRITE
+ DATABASE_MODE_READ_ONLY DatabaseMode = 0
+ DATABASE_MODE_READ_WRITE
)
// Create a new, empty notmuch database located at 'path'
-func NewDatabase(path string) *Database {
+func NewDatabase(path string) (*Database, Status) {
var c_path *C.char = C.CString(path)
defer C.free(unsafe.Pointer(c_path))
if c_path == nil {
- return nil
+ return nil, STATUS_OUT_OF_MEMORY
}
- self := &Database{db:nil}
- self.db = C.notmuch_database_create(c_path)
- if self.db == nil {
- return nil
+ self := &Database{db: nil}
+ st := Status(C.notmuch_database_create(c_path, &self.db))
+ if st != STATUS_SUCCESS {
+ return nil, st
}
- return self
+ return self, st
}
/* Open an existing notmuch database located at 'path'.
@@ -114,41 +119,41 @@ func NewDatabase(path string) *Database {
* An existing notmuch database can be identified by the presence of a
* directory named ".notmuch" below 'path'.
*
- * The caller should call notmuch_database_close when finished with
+ * The caller should call notmuch_database_destroy when finished with
* this database.
*
* In case of any failure, this function returns NULL, (after printing
* an error message on stderr).
*/
-func OpenDatabase(path string, mode DatabaseMode) *Database {
+func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) {
var c_path *C.char = C.CString(path)
defer C.free(unsafe.Pointer(c_path))
if c_path == nil {
- return nil
+ return nil, STATUS_OUT_OF_MEMORY
}
- self := &Database{db:nil}
- self.db = C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode))
- if self.db == nil {
- return nil
+ self := &Database{db: nil}
+ st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db))
+ if st != STATUS_SUCCESS {
+ return nil, st
}
- return self
+ return self, st
}
/* Close the given notmuch database, freeing all associated
* resources. See notmuch_database_open. */
func (self *Database) Close() {
- C.notmuch_database_close(self.db)
+ C.notmuch_database_destroy(self.db)
}
/* Return the database path of the given database.
*/
func (self *Database) GetPath() string {
-
- /* The return value is a string owned by notmuch so should not be
- * modified nor freed by the caller. */
+
+ /* The return value is a string owned by notmuch so should not be
+ * modified nor freed by the caller. */
var p *C.char = C.notmuch_database_get_path(self.db)
if p != nil {
s := C.GoString(p)
@@ -178,7 +183,6 @@ func (self *Database) NeedsUpgrade() bool {
// TODO: notmuch_database_upgrade
-
/* Retrieve a directory object from the database for 'path'.
*
* Here, 'path' should be a path relative to the path of 'database'
@@ -187,19 +191,20 @@ func (self *Database) NeedsUpgrade() bool {
*
* Can return NULL if a Xapian exception occurs.
*/
-func (self *Database) GetDirectory(path string) *Directory {
+func (self *Database) GetDirectory(path string) (*Directory, Status) {
var c_path *C.char = C.CString(path)
defer C.free(unsafe.Pointer(c_path))
if c_path == nil {
- return nil
+ return nil, STATUS_OUT_OF_MEMORY
}
- c_dir := C.notmuch_database_get_directory(self.db, c_path)
- if c_dir == nil {
- return nil
+ var c_dir *C.notmuch_directory_t
+ st := Status(C.notmuch_database_get_directory(self.db, c_path, &c_dir))
+ if st != STATUS_SUCCESS || c_dir == nil {
+ return nil, st
}
- return &Directory{dir:c_dir}
+ return &Directory{dir: c_dir}, st
}
/* Add a new message to the given notmuch database.
@@ -242,8 +247,7 @@ func (self *Database) GetDirectory(path string) *Directory {
* NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
* mode so no message can be added.
*/
-func
-(self *Database) AddMessage(fname string) (*Message, Status) {
+func (self *Database) AddMessage(fname string) (*Message, Status) {
var c_fname *C.char = C.CString(fname)
defer C.free(unsafe.Pointer(c_fname))
@@ -254,7 +258,7 @@ func
var c_msg *C.notmuch_message_t = new(C.notmuch_message_t)
st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg))
- return &Message{message:c_msg}, st
+ return &Message{message: c_msg}, st
}
/* Remove a message from the given notmuch database.
@@ -282,7 +286,7 @@ func
* mode so no message can be removed.
*/
func (self *Database) RemoveMessage(fname string) Status {
-
+
var c_fname *C.char = C.CString(fname)
defer C.free(unsafe.Pointer(c_fname))
@@ -306,20 +310,21 @@ func (self *Database) RemoveMessage(fname string) Status {
* * An out-of-memory situation occurs
* * A Xapian exception occurs
*/
-func (self *Database) FindMessage(message_id string) *Message {
-
+func (self *Database) FindMessage(message_id string) (*Message, Status) {
+
var c_msg_id *C.char = C.CString(message_id)
defer C.free(unsafe.Pointer(c_msg_id))
if c_msg_id == nil {
- return nil
+ return nil, STATUS_OUT_OF_MEMORY
}
- msg := C.notmuch_database_find_message(self.db, c_msg_id)
- if msg == nil {
- return nil
+ msg := &Message{message: nil}
+ st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message))
+ if st != STATUS_SUCCESS {
+ return nil, st
}
- return &Message{message:msg}
+ return msg, st
}
/* Return a list of all tags found in the database.
@@ -334,7 +339,7 @@ func (self *Database) GetAllTags() *Tags {
if tags == nil {
return nil
}
- return &Tags{tags:tags}
+ return &Tags{tags: tags}
}
/* Create a new query for 'database'.
@@ -362,7 +367,7 @@ func (self *Database) GetAllTags() *Tags {
* Will return NULL if insufficient memory is available.
*/
func (self *Database) CreateQuery(query string) *Query {
-
+
var c_query *C.char = C.CString(query)
defer C.free(unsafe.Pointer(c_query))
@@ -374,11 +379,12 @@ func (self *Database) CreateQuery(query string) *Query {
if q == nil {
return nil
}
- return &Query{query:q}
+ return &Query{query: q}
}
/* Sort values for notmuch_query_set_sort */
type Sort C.notmuch_sort_t
+
const (
SORT_OLDEST_FIRST Sort = 0
SORT_NEWEST_FIRST
@@ -391,7 +397,7 @@ func (self *Query) String() string {
// FIXME: do we own 'q' or not ?
q := C.notmuch_query_get_query_string(self.query)
//defer C.free(unsafe.Pointer(q))
-
+
if q != nil {
s := C.GoString(q)
return s
@@ -453,7 +459,7 @@ func (self *Query) SearchThreads() *Threads {
if threads == nil {
return nil
}
- return &Threads{threads:threads}
+ return &Threads{threads: threads}
}
/* Execute a query for messages, returning a notmuch_messages_t object
@@ -499,7 +505,7 @@ func (self *Query) SearchMessages() *Messages {
if msgs == nil {
return nil
}
- return &Messages{messages:msgs}
+ return &Messages{messages: msgs}
}
/* Destroy a notmuch_query_t along with any associated resources.
@@ -601,7 +607,7 @@ func (self *Messages) Get() *Message {
if msg == nil {
return nil
}
- return &Message{message:msg}
+ return &Message{message: msg}
}
/* Move the 'messages' iterator to the next message.
@@ -653,7 +659,7 @@ func (self *Messages) CollectTags() *Tags {
if tags == nil {
return nil
}
- return &Tags{tags:tags}
+ return &Tags{tags: tags}
}
/* Get the message ID of 'message'.
@@ -693,14 +699,14 @@ func (self *Message) GetMessageId() string {
* message belongs to a single thread.
*/
func (self *Message) GetThreadId() string {
-
+
if self.message == nil {
return ""
}
id := C.notmuch_message_get_thread_id(self.message)
// we dont own id
// defer C.free(unsafe.Pointer(id))
-
+
if id == nil {
return ""
}
@@ -733,7 +739,7 @@ func (self *Message) GetReplies() *Messages {
if msgs == nil {
return nil
}
- return &Messages{messages:msgs}
+ return &Messages{messages: msgs}
}
/* Get a filename for the email corresponding to 'message'.
@@ -757,7 +763,7 @@ func (self *Message) GetFileName() string {
fname := C.notmuch_message_get_filename(self.message)
// we dont own fname
// defer C.free(unsafe.Pointer(fname))
-
+
if fname == nil {
return ""
}
@@ -766,6 +772,7 @@ func (self *Message) GetFileName() string {
}
type Flag C.notmuch_message_flag_t
+
const (
MESSAGE_FLAG_MATCH Flag = 0
)
@@ -812,16 +819,16 @@ func (self *Message) GetHeader(header string) string {
if self.message == nil {
return ""
}
-
+
var c_header *C.char = C.CString(header)
defer C.free(unsafe.Pointer(c_header))
-
+
/* we dont own value */
value := C.notmuch_message_get_header(self.message, c_header)
if value == nil {
return ""
}
-
+
return C.GoString(value)
}
@@ -863,7 +870,7 @@ func (self *Message) GetTags() *Tags {
if tags == nil {
return nil
}
- return &Tags{tags:tags}
+ return &Tags{tags: tags}
}
/* The longest possible tag value. */
@@ -1120,4 +1127,5 @@ func (self *Filenames) Destroy() {
}
C.notmuch_filenames_destroy(self.fnames)
}
+
/* EOF */
diff --git a/bindings/python/docs/source/database.rst b/bindings/python/docs/source/database.rst
index ee71085f..2464bfff 100644
--- a/bindings/python/docs/source/database.rst
+++ b/bindings/python/docs/source/database.rst
@@ -9,6 +9,8 @@
.. automethod:: open(path, status=MODE.READ_ONLY)
+ .. automethod:: close
+
.. automethod:: get_path
.. automethod:: get_version
diff --git a/bindings/python/docs/source/filesystem.rst b/bindings/python/docs/source/filesystem.rst
index 685dc4d3..4eb78107 100644
--- a/bindings/python/docs/source/filesystem.rst
+++ b/bindings/python/docs/source/filesystem.rst
@@ -10,8 +10,6 @@ Files and directories
.. automethod:: Filenames.__len__
- .. automethod:: Filenames.as_generator
-
:class:`Directoy` -- A directory entry in the database
------------------------------------------------------
diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index 44d40fdb..e5c74cfb 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
import os
@@ -56,21 +56,14 @@ class Database(object):
:class:`Database` objects implement the context manager protocol
so you can use the :keyword:`with` statement to ensure that the
- database is properly closed.
+ database is properly closed. See :meth:`close` for more
+ information.
.. note::
Any function in this class can and will throw an
:exc:`NotInitializedError` if the database was not intitialized
properly.
-
- .. note::
-
- Do remember that as soon as we tear down (e.g. via `del db`) this
- object, all underlying derived objects such as queries, threads,
- messages, tags etc will be freed by the underlying library as well.
- Accessing these objects will lead to segfaults and other unexpected
- behavior. See above for more details.
"""
_std_db_path = None
"""Class attribute to cache user's default database"""
@@ -80,8 +73,8 @@ class Database(object):
"""notmuch_database_get_directory"""
_get_directory = nmlib.notmuch_database_get_directory
- _get_directory.argtypes = [NotmuchDatabaseP, c_char_p]
- _get_directory.restype = NotmuchDirectoryP
+ _get_directory.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchDirectoryP)]
+ _get_directory.restype = c_uint
"""notmuch_database_get_path"""
_get_path = nmlib.notmuch_database_get_path
@@ -95,8 +88,8 @@ class Database(object):
"""notmuch_database_open"""
_open = nmlib.notmuch_database_open
- _open.argtypes = [c_char_p, c_uint]
- _open.restype = NotmuchDatabaseP
+ _open.argtypes = [c_char_p, c_uint, POINTER(NotmuchDatabaseP)]
+ _open.restype = c_uint
"""notmuch_database_upgrade"""
_upgrade = nmlib.notmuch_database_upgrade
@@ -122,8 +115,8 @@ class Database(object):
"""notmuch_database_create"""
_create = nmlib.notmuch_database_create
- _create.argtypes = [c_char_p]
- _create.restype = NotmuchDatabaseP
+ _create.argtypes = [c_char_p, POINTER(NotmuchDatabaseP)]
+ _create.restype = c_uint
def __init__(self, path = None, create = False,
mode = MODE.READ_ONLY):
@@ -161,8 +154,13 @@ class Database(object):
else:
self.create(path)
+ _destroy = nmlib.notmuch_database_destroy
+ _destroy.argtypes = [NotmuchDatabaseP]
+ _destroy.restype = None
+
def __del__(self):
- self.close()
+ if self._db:
+ self._destroy(self._db)
def _assert_db_is_initialized(self):
"""Raises :exc:`NotInitializedError` if self._db is `None`"""
@@ -184,16 +182,17 @@ class Database(object):
:raises: :exc:`NotmuchError` in case of any failure
(possibly after printing an error message on stderr).
"""
- if self._db is not None:
+ if self._db:
raise NotmuchError(message="Cannot create db, this Database() "
"already has an open one.")
- res = Database._create(_str(path), Database.MODE.READ_WRITE)
+ db = NotmuchDatabaseP()
+ status = Database._create(_str(path), Database.MODE.READ_WRITE, byref(db))
- if not res:
- raise NotmuchError(
- message="Could not create the specified database")
- self._db = res
+ if status != STATUS.SUCCESS:
+ raise NotmuchError(status)
+ self._db = db
+ return status
def open(self, path, mode=0):
"""Opens an existing database
@@ -207,21 +206,31 @@ class Database(object):
:raises: Raises :exc:`NotmuchError` in case of any failure
(possibly after printing an error message on stderr).
"""
- res = Database._open(_str(path), mode)
+ db = NotmuchDatabaseP()
+ status = Database._open(_str(path), mode, byref(db))
- if not res:
- raise NotmuchError(message="Could not open the specified database")
- self._db = res
+ if status != STATUS.SUCCESS:
+ raise NotmuchError(status)
+ self._db = db
+ return status
_close = nmlib.notmuch_database_close
_close.argtypes = [NotmuchDatabaseP]
_close.restype = None
def close(self):
- """Close and free the notmuch database if needed"""
- if self._db is not None:
+ '''
+ Closes the notmuch database.
+
+ .. warning::
+
+ This function closes the notmuch database. From that point
+ on every method invoked on any object ever derived from
+ the closed database may cease to function and raise a
+ NotmuchError.
+ '''
+ if self._db:
self._close(self._db)
- self._db = None
def __enter__(self):
'''
@@ -337,7 +346,6 @@ class Database(object):
def get_directory(self, path):
"""Returns a :class:`Directory` of path,
- (creating it if it does not exist(?))
:param path: An unicode string containing the path relative to the path
of database (see :meth:`get_path`), or else should be an absolute
@@ -345,18 +353,9 @@ class Database(object):
:returns: :class:`Directory` or raises an exception.
:raises: :exc:`FileError` if path is not relative database or absolute
with initial components same as database.
- :raises: :exc:`ReadOnlyDatabaseError` if the database has not been
- opened in read-write mode
"""
self._assert_db_is_initialized()
- # work around libnotmuch calling exit(3), see
- # id:20120221002921.8534.57091@thinkbox.jade-hamburg.de
- # TODO: remove once this issue is resolved
- if self.mode != Database.MODE.READ_WRITE:
- raise ReadOnlyDatabaseError('The database has to be opened in '
- 'read-write mode for get_directory')
-
# sanity checking if path is valid, and make path absolute
if path and path[0] == os.sep:
# we got an absolute path
@@ -369,7 +368,13 @@ class Database(object):
#we got a relative path, make it absolute
abs_dirpath = os.path.abspath(os.path.join(self.get_path(), path))
- dir_p = Database._get_directory(self._db, _str(path))
+ dir_p = NotmuchDirectoryP()
+ status = Database._get_directory(self._db, _str(path), byref(dir_p))
+
+ if status != STATUS.SUCCESS:
+ raise NotmuchError(status)
+ if not dir_p:
+ return None
# return the Directory, init it with the absolute path
return Directory(abs_dirpath, dir_p, self)
@@ -521,19 +526,10 @@ class Database(object):
retry.
:raises: :exc:`NotInitializedError` if the database was not
intitialized.
- :raises: :exc:`ReadOnlyDatabaseError` if the database has not been
- opened in read-write mode
*Added in notmuch 0.9*"""
self._assert_db_is_initialized()
- # work around libnotmuch calling exit(3), see
- # id:20120221002921.8534.57091@thinkbox.jade-hamburg.de
- # TODO: remove once this issue is resolved
- if self.mode != Database.MODE.READ_WRITE:
- raise ReadOnlyDatabaseError('The database has to be opened in '
- 'read-write mode for get_directory')
-
msg_p = NotmuchMessageP()
status = Database._find_message_by_filename(self._db, _str(filename),
byref(msg_p))
diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py
index 284cbdce..ae115f81 100644
--- a/bindings/python/notmuch/directory.py
+++ b/bindings/python/notmuch/directory.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
from ctypes import c_uint, c_long
@@ -181,5 +181,5 @@ class Directory(object):
def __del__(self):
"""Close and free the Directory"""
- if self._dir_p is not None:
+ if self._dir_p:
self._destroy(self._dir_p)
diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py
index 12050df9..a0b29563 100644
--- a/bindings/python/notmuch/filenames.py
+++ b/bindings/python/notmuch/filenames.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
from ctypes import c_char_p
from notmuch.globals import (
@@ -32,29 +32,32 @@ from .errors import (
class Filenames(Python3StringMixIn):
"""Represents a list of filenames as returned by notmuch
- This object contains the Filenames iterator. The main function is
- as_generator() which will return a generator so we can do a Filenamesth an
- iterator over a list of notmuch filenames. Do note that the underlying
- library only provides a one-time iterator (it cannot reset the iterator to
- the start). Thus iterating over the function will "exhaust" the list of
- tags, and a subsequent iteration attempt will raise a
- :exc:`NotInitializedError`. Also note, that any function that uses
- iteration (nearly all) will also exhaust the tags. So both::
+ Objects of this class implement the iterator protocol.
- for name in filenames: print name
+ .. note::
- as well as::
+ The underlying library only provides a one-time iterator (it
+ cannot reset the iterator to the start). Thus iterating over
+ the function will "exhaust" the list of tags, and a subsequent
+ iteration attempt will raise a
+ :exc:`NotInitializedError`. Also note, that any function that
+ uses iteration (nearly all) will also exhaust the tags. So
+ both::
- number_of_names = len(names)
+ for name in filenames: print name
- and even a simple::
+ as well as::
- #str() iterates over all tags to construct a space separated list
- print(str(filenames))
+ number_of_names = len(names)
- will "exhaust" the Filenames. However, you can use
- :meth:`Message.get_filenames` repeatedly to get fresh Filenames
- objects to perform various actions on filenames.
+ and even a simple::
+
+ #str() iterates over all tags to construct a space separated list
+ print(str(filenames))
+
+ will "exhaust" the Filenames. However, you can use
+ :meth:`Message.get_filenames` repeatedly to get fresh
+ Filenames objects to perform various actions on filenames.
"""
#notmuch_filenames_get
@@ -109,28 +112,13 @@ class Filenames(Python3StringMixIn):
return file_.decode('utf-8', 'ignore')
next = __next__ # python2.x iterator protocol compatibility
- def as_generator(self):
- """Return generator of Filenames
-
- This is the main function that will usually be used by the
- user.
-
- .. deprecated:: 0.12
- :class:`Filenames` objects implement the
- iterator protocol.
- """
- return self
-
def __unicode__(self):
"""Represent Filenames() as newline-separated list of full paths
- .. note:: As this iterates over the filenames, we will not be
- able to iterate over them again (as in retrieve them)! If
- the tags have been exhausted already, this will raise a
- :exc:`NotInitializedError` on subsequent
- attempts. However, you can use
- :meth:`Message.get_filenames` repeatedly to perform
- various actions on filenames.
+ .. note::
+
+ This method exhausts the iterator object, so you will not be able to
+ iterate over them again.
"""
return "\n".join(self)
@@ -140,7 +128,7 @@ class Filenames(Python3StringMixIn):
def __del__(self):
"""Close and free the notmuch filenames"""
- if self._files_p is not None:
+ if self._files_p:
self._destroy(self._files_p)
def __len__(self):
@@ -148,15 +136,8 @@ class Filenames(Python3StringMixIn):
.. note::
- As this iterates over the files, we will not be able to
- iterate over them again! So this will fail::
-
- #THIS FAILS
- files = Database().get_directory('').get_child_files()
- if len(files) > 0: # this 'exhausts' msgs
- # next line raises
- # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED)
- for file in files: print file
+ This method exhausts the iterator object, so you will not be able to
+ iterate over them again.
"""
if not self._files_p:
raise NotInitializedError()
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 442f3e35..f5fad72a 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
import sys
from ctypes import CDLL, Structure, POINTER
@@ -22,7 +22,7 @@ from ctypes import CDLL, Structure, POINTER
#-----------------------------------------------------------------------------
#package-global instance of the notmuch library
try:
- nmlib = CDLL("libnotmuch.so.2")
+ nmlib = CDLL("libnotmuch.so.3")
except:
raise ImportError("Could not find shared 'notmuch' library.")
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index 9eb4feef..0e65694e 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
Jesse Rosenthal <jrosenthal@jhu.edu>
"""
@@ -259,7 +259,7 @@ class Message(Python3StringMixIn):
files_p = Message._get_filenames(self._msg)
- return Filenames(files_p, self).as_generator()
+ return Filenames(files_p, self)
def get_flag(self, flag):
"""Checks whether a specific flag is set for this message
@@ -614,7 +614,15 @@ class Message(Python3StringMixIn):
"""Create an internal representation of the message parts,
which can easily be output to json, text, or another output
format. The argument match tells whether this matched a
- query."""
+ query.
+
+ .. deprecated:: 0.13
+ This code adds functionality at the python
+ level that is unlikely to be useful for
+ anyone. Furthermore the python bindings strive
+ to be a thin wrapper around libnotmuch, so
+ this code will be removed in notmuch 0.14.
+ """
output = {}
output["id"] = self.get_message_id()
output["match"] = self.is_match()
@@ -660,12 +668,29 @@ class Message(Python3StringMixIn):
def format_message_as_json(self, indent=0):
"""Outputs the message as json. This is essentially the same
as python's dict format, but we run it through, just so we
- don't have to worry about the details."""
+ don't have to worry about the details.
+
+ .. deprecated:: 0.13
+ This code adds functionality at the python
+ level that is unlikely to be useful for
+ anyone. Furthermore the python bindings strive
+ to be a thin wrapper around libnotmuch, so
+ this code will be removed in notmuch 0.14.
+ """
return json.dumps(self.format_message_internal())
def format_message_as_text(self, indent=0):
"""Outputs it in the old-fashioned notmuch text form. Will be
- easy to change to a new format when the format changes."""
+ easy to change to a new format when the format changes.
+
+ .. deprecated:: 0.13
+ This code adds functionality at the python
+ level that is unlikely to be useful for
+ anyone. Furthermore the python bindings strive
+ to be a thin wrapper around libnotmuch, so
+ this code will be removed in notmuch 0.14.
+ """
+
format = self.format_message_internal()
output = "\fmessage{ id:%s depth:%d match:%d filename:%s" \
@@ -741,5 +766,5 @@ class Message(Python3StringMixIn):
def __del__(self):
"""Close and free the notmuch Message"""
- if self._msg is not None:
+ if self._msg:
self._destroy(self._msg)
diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py
index d94f91b4..59ef40af 100644
--- a/bindings/python/notmuch/messages.py
+++ b/bindings/python/notmuch/messages.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
Jesse Rosenthal <jrosenthal@jhu.edu>
"""
@@ -172,11 +172,15 @@ class Messages(object):
next = __next__ # python2.x iterator protocol compatibility
def __nonzero__(self):
- """
- :return: True if there is at least one more thread in the
- Iterator, False if not."""
- return self._msgs is not None and \
- self._valid(self._msgs) > 0
+ '''
+ Implement truth value testing. If __nonzero__ is not
+ implemented, the python runtime would fall back to `len(..) >
+ 0` thus exhausting the iterator.
+
+ :returns: True if the wrapped iterator has at least one more object
+ left.
+ '''
+ return self._msgs and self._valid(self._msgs)
_destroy = nmlib.notmuch_messages_destroy
_destroy.argtypes = [NotmuchMessagesP]
@@ -184,7 +188,7 @@ class Messages(object):
def __del__(self):
"""Close and free the notmuch Messages"""
- if self._msgs is not None:
+ if self._msgs:
self._destroy(self._msgs)
def format_messages(self, format, indent=0, entire_thread=False):
diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py
index ddaf8e08..756e63b5 100644
--- a/bindings/python/notmuch/query.py
+++ b/bindings/python/notmuch/query.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
from ctypes import c_char_p, c_uint
@@ -203,5 +203,5 @@ class Query(object):
def __del__(self):
"""Close and free the Query"""
- if self._query is not None:
+ if self._query:
self._destroy(self._query)
diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py
index 711bf533..363c3487 100644
--- a/bindings/python/notmuch/tag.py
+++ b/bindings/python/notmuch/tag.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
from ctypes import c_char_p
from notmuch.globals import (
@@ -109,15 +109,15 @@ class Tags(Python3StringMixIn):
next = __next__ # python2.x iterator protocol compatibility
def __nonzero__(self):
- """Implement bool(Tags) check that can be repeatedly used
+ '''
+ Implement truth value testing. If __nonzero__ is not
+ implemented, the python runtime would fall back to `len(..) >
+ 0` thus exhausting the iterator.
- If __nonzero__ is not implemented, "if Tags()"
- will implicitly call __len__, using up our iterator, so it is
- important that this function is defined.
-
- :returns: True if the Tags() iterator has at least one more Tag
- left."""
- return self._valid(self._tags) > 0
+ :returns: True if the wrapped iterator has at least one more object
+ left.
+ '''
+ return self._tags and self._valid(self._tags)
def __unicode__(self):
"""string representation of :class:`Tags`: a space separated list of tags
@@ -137,5 +137,5 @@ class Tags(Python3StringMixIn):
def __del__(self):
"""Close and free the notmuch tags"""
- if self._tags is not None:
+ if self._tags:
self._destroy(self._tags)
diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py
index a759c909..2f60d493 100644
--- a/bindings/python/notmuch/thread.py
+++ b/bindings/python/notmuch/thread.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
from ctypes import c_char_p, c_long, c_int
@@ -260,5 +260,5 @@ class Thread(object):
def __del__(self):
"""Close and free the notmuch Thread"""
- if self._thread is not None:
+ if self._thread:
self._destroy(self._thread)
diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py
index 225f5246..d2e0a910 100644
--- a/bindings/python/notmuch/threads.py
+++ b/bindings/python/notmuch/threads.py
@@ -14,7 +14,7 @@ for more details.
You should have received a copy of the GNU General Public License
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
from notmuch.globals import (
@@ -157,18 +157,15 @@ class Threads(Python3StringMixIn):
return i
def __nonzero__(self):
- """Check if :class:`Threads` contains at least one more valid thread
+ '''
+ Implement truth value testing. If __nonzero__ is not
+ implemented, the python runtime would fall back to `len(..) >
+ 0` thus exhausting the iterator.
- The existence of this function makes 'if Threads: foo' work, as
- that will implicitely call len() exhausting the iterator if
- __nonzero__ does not exist. This function makes `bool(Threads())`
- work repeatedly.
-
- :return: True if there is at least one more thread in the
- Iterator, False if not. None on a "Out-of-memory" error.
- """
- return self._threads is not None and \
- self._valid(self._threads) > 0
+ :returns: True if the wrapped iterator has at least one more object
+ left.
+ '''
+ return self._threads and self._valid(self._threads)
_destroy = nmlib.notmuch_threads_destroy
_destroy.argtypes = [NotmuchThreadsP]
@@ -176,5 +173,5 @@ class Threads(Python3StringMixIn):
def __del__(self):
"""Close and free the notmuch Threads"""
- if self._threads is not None:
+ if self._threads:
self._destroy(self._threads)
diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py
index 24e1d4c9..90bcadbe 100644
--- a/bindings/python/notmuch/version.py
+++ b/bindings/python/notmuch/version.py
@@ -1,2 +1,2 @@
# this file should be kept in sync with ../../../version
-__VERSION__ = '0.12'
+__VERSION__ = '0.13.2'
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index 2e58dab1..f4c338e3 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -1,14 +1,33 @@
#!/usr/bin/env python
+"""
+This file is part of notmuch.
+
+Notmuch is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Notmuch is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with notmuch. If not, see <http://www.gnu.org/licenses/>.
+
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
+"""
+
import os
-import re
from distutils.core import setup
# get the notmuch version number without importing the notmuch module
-version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+version_file = os.path.join(os.path.dirname(__file__),
'notmuch', 'version.py')
exec(compile(open(version_file).read(), version_file, 'exec'))
-assert __VERSION__, 'Failed to read the notmuch binding version number'
+assert '__VERSION__' in globals(), \
+ 'Failed to read the notmuch binding version number'
setup(name='notmuch',
version=__VERSION__,
@@ -16,32 +35,20 @@ setup(name='notmuch',
author='Sebastian Spaeth',
author_email='Sebastian@SSpaeth.de',
url='http://notmuchmail.org/',
- download_url='http://notmuchmail.org/releases/notmuch-'+__VERSION__+'.tar.gz',
+ download_url='http://notmuchmail.org/releases/notmuch-%s.tar.gz' % __VERSION__,
packages=['notmuch'],
- keywords = ["library", "email"],
- long_description="""Overview
-==============
-
-The notmuch module provides an interface to the `notmuch <http://notmuchmail.org>`_ functionality, directly interfacing with a shared notmuch library. Notmuch provides a maildatabase that allows for extremely quick searching and filtering of your email according to various criteria.
-
-The documentation for the latest cnotmuch release can be `viewed online <http://packages.python.org/notmuch>`_.
-
-The classes notmuch.Database, notmuch.Query provide most of the core functionality, returning notmuch.Messages and notmuch.Tags.
-
-Installation and Deinstallation
--------------------------------
-
-notmuch is included in the upstream notmuch source repository and it is
-packaged on http://pypi.python.org. This means you can do "easy_install
-notmuch" (or using pip) on your linux box and it will get installed
-into:
+ keywords=['library', 'email'],
+ long_description='''Overview
+========
-/usr/local/lib/python2.x/dist-packages/
+The notmuch module provides an interface to the `notmuch
+<http://notmuchmail.org>`_ functionality, directly interfacing with a
+shared notmuch library. Notmuch provides a maildatabase that allows
+for extremely quick searching and filtering of your email according to
+various criteria.
-For uninstalling, you will need to remove the "notmuch-0.x-py2.x.egg"
-directory and delete one entry refering to cnotmuch in the
-"easy-install.pth" file in that directory. There should be no trace
-left of cnotmuch then.
+The documentation for the latest notmuch release can be `viewed
+online <http://notmuch.readthedocs.org/>`_.
Requirements
------------
@@ -49,7 +56,7 @@ Requirements
You need to have notmuch installed (or rather libnotmuch.so.1). Also,
notmuch makes use of the ctypes library, and has only been tested with
python >= 2.5. It will not work on earlier python versions.
-""",
+''',
classifiers=['Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License (GPL)',
diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c
index 982fd592..e84f726d 100644
--- a/bindings/ruby/database.c
+++ b/bindings/ruby/database.c
@@ -42,6 +42,8 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self)
int create, mode;
VALUE pathv, hashv;
VALUE modev;
+ notmuch_database_t *database;
+ notmuch_status_t ret;
/* Check arguments */
rb_scan_args (argc, argv, "11", &pathv, &hashv);
@@ -73,9 +75,13 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self)
}
Check_Type (self, T_DATA);
- DATA_PTR (self) = create ? notmuch_database_create (path) : notmuch_database_open (path, mode);
- if (!DATA_PTR (self))
- rb_raise (notmuch_rb_eDatabaseError, "Failed to open database");
+ if (create)
+ ret = notmuch_database_create (path, &database);
+ else
+ ret = notmuch_database_open (path, mode, &database);
+ notmuch_rb_status_raise (ret);
+
+ DATA_PTR (self) = database;
return self;
}
@@ -110,7 +116,7 @@ notmuch_rb_database_close (VALUE self)
notmuch_database_t *db;
Data_Get_Notmuch_Database (self, db);
- notmuch_database_close (db);
+ notmuch_database_destroy (db);
DATA_PTR (self) = NULL;
return Qnil;
@@ -246,6 +252,7 @@ VALUE
notmuch_rb_database_get_directory (VALUE self, VALUE pathv)
{
const char *path;
+ notmuch_status_t ret;
notmuch_directory_t *dir;
notmuch_database_t *db;
@@ -254,11 +261,11 @@ notmuch_rb_database_get_directory (VALUE self, VALUE pathv)
SafeStringValue (pathv);
path = RSTRING_PTR (pathv);
- dir = notmuch_database_get_directory (db, path);
- if (!dir)
- rb_raise (notmuch_rb_eXapianError, "Xapian exception");
-
- return Data_Wrap_Struct (notmuch_rb_cDirectory, NULL, NULL, dir);
+ ret = notmuch_database_get_directory (db, path, &dir);
+ notmuch_rb_status_raise (ret);
+ if (dir)
+ return Data_Wrap_Struct (notmuch_rb_cDirectory, NULL, NULL, dir);
+ return Qnil;
}
/*
diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h
index 81f652fb..3f9512ba 100644
--- a/bindings/ruby/defs.h
+++ b/bindings/ruby/defs.h
@@ -1,6 +1,6 @@
/* The Ruby interface to the notmuch mail library
*
- * Copyright © 2010, 2011 Ali Polatel
+ * Copyright © 2010, 2011, 2012 Ali Polatel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -217,11 +217,20 @@ VALUE
notmuch_rb_query_get_string (VALUE self);
VALUE
+notmuch_rb_query_add_tag_exclude (VALUE self, VALUE tagv);
+
+VALUE
+notmuch_rb_query_set_omit_excluded (VALUE self, VALUE omitv);
+
+VALUE
notmuch_rb_query_search_threads (VALUE self);
VALUE
notmuch_rb_query_search_messages (VALUE self);
+VALUE
+notmuch_rb_query_count_messages (VALUE self);
+
/* threads.c */
VALUE
notmuch_rb_threads_destroy (VALUE self);
diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb
index ccac609c..7b9750f2 100644
--- a/bindings/ruby/extconf.rb
+++ b/bindings/ruby/extconf.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
# coding: utf-8
-# Copyright 2010, 2011 Ali Polatel <alip@exherbo.org>
+# Copyright 2010, 2011, 2012 Ali Polatel <alip@exherbo.org>
# Distributed under the terms of the GNU General Public License v3
require 'mkmf'
diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c
index 4405f196..3fe60fb7 100644
--- a/bindings/ruby/init.c
+++ b/bindings/ruby/init.c
@@ -1,6 +1,6 @@
/* The Ruby interface to the notmuch mail library
*
- * Copyright © 2010, 2011 Ali Polatel
+ * Copyright © 2010, 2011, 2012 Ali Polatel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -96,6 +96,12 @@ Init_notmuch (void)
*/
rb_define_const (mod, "MESSAGE_FLAG_MATCH", INT2FIX (NOTMUCH_MESSAGE_FLAG_MATCH));
/*
+ * Document-const: Notmuch::MESSAGE_FLAG_EXCLUDED
+ *
+ * Message flag "excluded"
+ */
+ rb_define_const (mod, "MESSAGE_FLAG_EXCLUDED", INT2FIX (NOTMUCH_MESSAGE_FLAG_EXCLUDED));
+ /*
* Document-const: Notmuch::TAG_MAX
*
* Maximum allowed length of a tag
@@ -234,8 +240,11 @@ Init_notmuch (void)
rb_define_method (notmuch_rb_cQuery, "sort", notmuch_rb_query_get_sort, 0); /* in query.c */
rb_define_method (notmuch_rb_cQuery, "sort=", notmuch_rb_query_set_sort, 1); /* in query.c */
rb_define_method (notmuch_rb_cQuery, "to_s", notmuch_rb_query_get_string, 0); /* in query.c */
+ rb_define_method (notmuch_rb_cQuery, "add_tag_exclude", notmuch_rb_query_add_tag_exclude, 1); /* in query.c */
+ rb_define_method (notmuch_rb_cQuery, "omit_excluded=", notmuch_rb_query_set_omit_excluded, 1); /* in query.c */
rb_define_method (notmuch_rb_cQuery, "search_threads", notmuch_rb_query_search_threads, 0); /* in query.c */
rb_define_method (notmuch_rb_cQuery, "search_messages", notmuch_rb_query_search_messages, 0); /* in query.c */
+ rb_define_method (notmuch_rb_cQuery, "count_messages", notmuch_rb_query_count_messages, 0); /* in query.c */
/*
* Document-class: Notmuch::Threads
diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c
index 74fd5858..e5ba1b7a 100644
--- a/bindings/ruby/query.c
+++ b/bindings/ruby/query.c
@@ -1,6 +1,6 @@
/* The Ruby interface to the notmuch mail library
*
- * Copyright © 2010, 2011 Ali Polatel
+ * Copyright © 2010, 2011, 2012 Ali Polatel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -89,6 +89,42 @@ notmuch_rb_query_get_string (VALUE self)
}
/*
+ * call-seq: QUERY.add_tag_exclude(tag) => nil
+ *
+ * Add a tag that will be excluded from the query results by default.
+ */
+VALUE
+notmuch_rb_query_add_tag_exclude (VALUE self, VALUE tagv)
+{
+ notmuch_query_t *query;
+ const char *tag;
+
+ Data_Get_Notmuch_Query (self, query);
+ tag = RSTRING_PTR(tagv);
+
+ notmuch_query_add_tag_exclude(query, tag);
+ return Qnil;
+}
+
+/*
+ * call-seq: QUERY.omit_excluded=(boolean) => nil
+ *
+ * Specify whether to omit excluded results or simply flag them.
+ * By default, this is set to +true+.
+ */
+VALUE
+notmuch_rb_query_set_omit_excluded (VALUE self, VALUE omitv)
+{
+ notmuch_query_t *query;
+
+ Data_Get_Notmuch_Query (self, query);
+
+ notmuch_query_set_omit_excluded (query, RTEST (omitv));
+
+ return Qnil;
+}
+
+/*
* call-seq: QUERY.search_threads => THREADS
*
* Search for threads
@@ -127,3 +163,22 @@ notmuch_rb_query_search_messages (VALUE self)
return Data_Wrap_Struct (notmuch_rb_cMessages, NULL, NULL, messages);
}
+
+/*
+ * call-seq: QUERY.count_messages => Fixnum
+ *
+ * Return an estimate of the number of messages matching a search
+ */
+VALUE
+notmuch_rb_query_count_messages (VALUE self)
+{
+ notmuch_query_t *query;
+
+ Data_Get_Notmuch_Query (self, query);
+
+ /* Xapian exceptions are not handled properly.
+ * (function may return 0 after printing a message)
+ * Thus there is nothing we can do here...
+ */
+ return UINT2FIX(notmuch_query_count_messages(query));
+}