Parent: [b1ab1b] (diff)

Child: [893fd1] (diff)

Download this file

uprclfolders.py    234 lines (193 with data), 7.3 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
import os
import shlex
import urllib
import sys
from uprclutils import *
from recoll import recoll
from recoll import rclconfig
g_myprefix = '0$uprcl$folders'
# Internal init: create the directory tree (folders view) from the doc
# array by splitting the url in each doc.
#
# The dirvec vector has one entry for each directory. Each entry is a
# dictionary, mapping the names inside the directory to a pair (i,j),
# where:
# - i is an index into dirvec if the name is a directory, else -1
# - j is the index of the doc inside the doc array (or -1 if there is no doc)
#
# Entry 0 in dirvec is special: it holds the 'topdirs' from the recoll
# configuration. The entries are paths instead of simple names, and
# the doc index (j) is 0. The dir index points normally to a dirvec
# entry.
# Create new directory entry: insert in father and append dirvec slot (with ".." entry)
def _createdir(dirvec, fathidx, docidx, nm):
dirvec.append({})
dirvec[fathidx][nm] = (len(dirvec) - 1, docidx)
dirvec[-1][".."] = (fathidx, -1)
return len(dirvec) - 1
def _rcl2folders(docs, confdir):
global dirvec
dirvec = []
rclconf = rclconfig.RclConfig(confdir)
topdirs = [os.path.expanduser(d) for d in
shlex.split(rclconf.getConfParam('topdirs'))]
topdirs = [d.rstrip('/') for d in topdirs]
dirvec.append({})
dirvec[0][".."] = (0, -1)
for d in topdirs:
dirvec.append({})
dirvec[0][d] = (len(dirvec)-1, -1)
dirvec[-1][".."] = (0, -1)
# Walk the doc list and update the directory tree according to the
# url (create intermediary directories if needed, create leaf
# entry
for docidx in range(len(docs)):
doc = docs[docidx]
url = doc.getbinurl()
url = url[7:]
try:
decoded = url.decode('utf-8')
except:
decoded = urllib.quote(url).decode('utf-8')
# Determine the root entry (topdirs element). Special because
# path not simple name
fathidx = -1
for rtpath,idx in dirvec[0].iteritems():
if url.startswith(rtpath):
fathidx = idx[0]
break
if fathidx == -1:
uplog("No parent in topdirs: %s" % decoded)
continue
# Compute rest of path
url1 = url[len(rtpath):]
if len(url1) == 0:
continue
# Split path, then walk the vector, possibly creating
# directory entries as needed
path = url1.split('/')[1:]
#uplog("%s"%path, file=sys.stderr)
for idx in range(len(path)):
elt = path[idx]
if elt in dirvec[fathidx]:
# This path element was already seen
# If this is the last entry in the path, maybe update
# the doc idx (previous entries were created for
# intermediate elements without a Doc).
#uplog("NEED TO UPDATE DOC")
dirvec[fathidx][elt] = (dirvec[fathidx][elt][0], docidx)
# Update fathidx for next iteration
fathidx = dirvec[fathidx][elt][0]
else:
# Element has no entry in father directory (hence no
# dirvec entry either).
if idx != len(path) -1:
# This is an intermediate element. Create a
# Doc-less directory
fathidx = _createdir(dirvec, fathidx, -1, elt)
else:
# Last element. If directory, needs a dirvec entry
if doc.mtype == 'inode/directory':
fathidx = _createdir(dirvec, fathidx, docidx, elt)
else:
dirvec[fathidx][elt] = (-1, docidx)
if False:
for ent in dirvec:
uplog("%s" % ent)
return dirvec
# Internal init: fetch all the docs by querying Recoll with [mime:*],
# which is guaranteed to match every doc without overflowing the query
# size (because the number of mime types is limited). Something like
# title:* would overflow.
def _fetchalldocs(confdir):
allthedocs = []
rcldb = recoll.connect(confdir=confdir)
rclq = rcldb.query()
rclq.execute("mime:*", stemming=0)
uplog("Estimated alldocs query results: %d" % (rclq.rowcount))
maxcnt = 0
totcnt = 0
while True:
docs = rclq.fetchmany()
for doc in docs:
allthedocs.append(doc)
totcnt += 1
if (maxcnt > 0 and totcnt >= maxcnt) or len(docs) != rclq.arraysize:
break
uplog("Retrieved %d docs" % (totcnt,))
return allthedocs
# Initialize (read recoll data and build tree)
def inittree(confdir):
global g_alldocs, g_dirvec
g_alldocs = _fetchalldocs(confdir)
g_dirvec = _rcl2folders(g_alldocs, confdir)
def _objidtodiridx(pid):
if not pid.startswith(g_myprefix):
raise Exception("folders.browse: bad pid %s" % pid)
if len(g_alldocs) == 0:
raise Exception("folders:browse: no docs")
diridx = pid[len(g_myprefix):]
if not diridx:
diridx = 0
else:
if diridx[1] != 'd':
raise Exception("folders:browse: called on non dir objid %s" % pid)
diridx = int(diridx[2:])
if diridx >= len(g_dirvec):
raise Exception("folders:browse: bad pid %s" % pid)
return diridx
# Browse method
# objid is like folders$index
# flag is meta or children.
def browse(pid, flag, httphp, pathprefix):
diridx = _objidtodiridx(pid)
entries = []
# The basename call is just for diridx==0 (topdirs). Remove it if
# this proves a performance issue
for nm,ids in g_dirvec[diridx].iteritems():
#uplog("folders:browse: got nm %s" % nm.decode('utf-8'))
if nm == "..":
continue
thisdiridx = ids[0]
thisdocidx = ids[1]
if thisdiridx >= 0:
id = g_myprefix + '$' + 'd' + str(thisdiridx)
entries.append(rcldirentry(id, pid, os.path.basename(nm)))
else:
# Not a directory. docidx had better been set
if thisdocidx == -1:
uplog("folders:docidx -1 for non-dir entry %s"%nm)
continue
doc = g_alldocs[thisdocidx]
id = g_myprefix + '$' + 'i' + str(thisdocidx)
e = rcldoctoentry(id, pid, httphp, pathprefix, doc)
if e:
entries.append(e)
return sorted(entries, cmp=cmpentries)
# return path for objid, which has to be a container. This is good old pwd
def dirpath(objid):
# We may get called from search, on the top dir (above [folders]). Return
# empty in this case
try:
diridx = _objidtodiridx(objid)
except:
return ""
if diridx == 0:
return "/"
lpath = []
while True:
fathidx = g_dirvec[diridx][".."][0]
for nm, ids in g_dirvec[fathidx].iteritems():
if ids[0] == diridx:
lpath.append(nm)
break
diridx = fathidx
if diridx == 0:
break
if not lpath:
path = "/"
else:
path = ""
for elt in reversed(lpath):
path += elt + "/"
return path