Skip to content

Commit 4b16dab

Browse files
committed
merge from trunk. travisci xenil plus more
2 parents c0c850e + 4d3c0c8 commit 4b16dab

File tree

18 files changed

+474
-121
lines changed

18 files changed

+474
-121
lines changed

.travis.yml

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
1+
# check syntax using:
2+
# https://config.travis-ci.com/explore
3+
14
os: linux
25

36
language: python
47

58
cache: pip
69

7-
python:
8-
- 2.7
9-
- 3.4
10-
- 3.6
11-
- 3.7
12-
- 3.8
13-
- 3.9-dev
14-
- nightly
15-
1610
#I would like to build and test the maint-1.6 and trunk/default
1711
#but we need different environments for these:
1812
# maint-1.6 only python 2, install only psycopg2 version with support for
@@ -23,29 +17,18 @@ branches:
2317
# - maint-1.6
2418

2519
dist:
26-
- xenial
27-
28-
# Commented out stanza for bionic 18.04. Currently testing on
29-
# xenial 16.04.
30-
# Consider move to this after 2.1.0 release. Python 3.4
31-
# is not supported on bionic and 3.4 is obsolete. Was retained
32-
# because 3.4 was EPEL version for centos 7. With centos demise,
33-
# remove it from 'python:' settings and test earliest still supported
34-
# release, last two production releases and nightly to cut down on cost
35-
# of testing.
36-
# dist:
37-
# - bionic
38-
#
39-
# python:
40-
# - 2.7
41-
# - 3.6
42-
# - 3.8
43-
# - 3.9-dev
44-
# - nightly
45-
#
46-
# services:
47-
# - mysql
48-
# - postgresql
20+
- bionic
21+
22+
python:
23+
- 2.7
24+
- 3.9-dev
25+
- 3.8
26+
- 3.6
27+
- nightly
28+
29+
services:
30+
- mysql
31+
- postgresql
4932

5033
jobs:
5134
allow_failures: # nightly not ready for prime time yet.
@@ -102,7 +85,7 @@ before_install:
10285
- GPGME_VERSION=1.11.1
10386
- cd /tmp
10487
- curl -s -O https://www.gnupg.org/ftp/gcrypt/gpgme/gpgme-$GPGME_VERSION.tar.bz2
105-
- tar -jxvf gpgme-$GPGME_VERSION.tar.bz2
88+
- tar -jxf gpgme-$GPGME_VERSION.tar.bz2
10689
- cd gpgme-$GPGME_VERSION
10790
- ./configure --prefix=$VIRTUAL_ENV
10891
- make && make install
@@ -137,11 +120,27 @@ before_script:
137120
# needed for test_mysql.mysqlDBTest.testFilteringSpecialChars
138121
- sed -i 's/CREATE DATABASE \%s/CREATE DATABASE \%s COLLATE utf8_general_ci/' roundup/backends/back_mysql.py
139122

123+
# build the .mo translation files and install them into a tree
124+
# (locale/locale under roundup directory root)
125+
# suitable for use by gettext.
126+
- (cd locale; make local_install; ls -lR locale/de/LC_MESSAGES)
127+
140128
script:
141129
- PATH=$VIRTUAL_ENV/bin:$PATH
142130
- export LD_LIBRARY_PATH=$VIRTUAL_ENV/lib:$LD_LIBRARY_PATH
143-
- py.test -v --maxfail=20 test/ --cov=roundup
144-
131+
- if [[ "$TRAVIS_PYTHON_VERSION" != "2."* ]]; then
132+
py.test
133+
-W default
134+
-W "ignore:SelectableGroups:DeprecationWarning"
135+
-W "ignore:the imp module:DeprecationWarning:gpg.gpgme:15"
136+
-W "ignore:'U' mode::docutils.io"
137+
-W "ignore:unclosed:ResourceWarning:roundup.roundup.demo"
138+
-W "ignore:unclosed file:ResourceWarning:enum"
139+
-v --maxfail=20 test/ --cov=roundup;
140+
fi
141+
- if [[ "$TRAVIS_PYTHON_VERSION" == "2."* ]]; then
142+
py.test -v --maxfail=20 test/ --cov=roundup;
143+
fi
145144

146145
after_success:
147146
- codecov

CHANGES.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ onwards Python 3.4 and later are also supported.
1515

1616
Fixed:
1717

18+
- issue2551161 - Fix ResourceWarnings when running with -W default.
19+
Cleaned up leaking file descriptors from zopetal pre-compile, python
20+
module compile and loading localization file. (John Rouillard)
21+
- When using roundup-server with native SSL, only accept TLS v1.2.
22+
Previously it used to accept only TLS v1.1. 1.1 is deprecated by
23+
chrome. I don't expect this to be a major problem since a front
24+
end server (apache, Nginx...) is usually customer facing and
25+
terminates SSL.
26+
- Fix hang when valid user without authorization for REST tries to use
27+
the rest interface.
28+
1829
Features:
1930

2031
- issue2551147 - Enable compression of http responses in roundup.

issues/extensions/templating.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import logging
2+
logger = logging.getLogger('extension')
3+
4+
import sys
5+
from roundup import __version__ as roundup_version
6+
def AboutPage(db):
7+
"report useful info about this tracker"
8+
9+
def is_module_loaded(module):
10+
modules = sys.modules.keys()
11+
return module in modules
12+
13+
def get_status_of_module(module, prefix=None, version=True):
14+
modules = sys.modules.keys()
15+
is_enabled = module in modules
16+
if is_enabled:
17+
if module == 'pyme':
18+
from pyme import version
19+
version="version %s"%version.versionstr
20+
elif module == 'pychart':
21+
from pychart import version
22+
version="version %s"%version.version
23+
elif module == 'sqlite3':
24+
from sqlite3 import version
25+
version="version %s"%version
26+
else:
27+
if version:
28+
m = __import__(module)
29+
try:
30+
version="version %s"%m.__version__
31+
except AttributeError:
32+
version="version unavailable - exception thrown"
33+
else:
34+
version="version unavailable"
35+
36+
if prefix:
37+
return "%s %s %s enabled: %s"%(prefix, module, version, is_enabled)
38+
else:
39+
return "Module: %s %s enabled: %s"%(module, version, is_enabled)
40+
else:
41+
if prefix:
42+
return "%s %s enabled: %s"%(prefix, module, is_enabled)
43+
else:
44+
return "Module: %s enabled: %s"%(module, is_enabled)
45+
46+
info = []
47+
48+
info.append("Tracker name: %s<br>"%db.config['TRACKER_NAME'])
49+
50+
info.append("<h2>Operating environment</h2>")
51+
info.append('<a href="http://roundup.sourceforge.net/">Roundup</a> version: %s<br>'%roundup_version)
52+
info.append("Python Version: %s<br>"%sys.version)
53+
54+
info.append("<h2>Configuration</h2>")
55+
56+
backend = db.config['RDBMS_BACKEND']
57+
info.append("Roundup backend: %s<br>"%backend)
58+
if backend != 'anydbm':
59+
info.append("Roundup db cache: %s<br>"%db.config['RDBMS_CACHE_SIZE'])
60+
info.append("Roundup isolation_level: %s<br>"%db.config['RDBMS_ISOLATION_LEVEL'])
61+
62+
info.append("Roundup template: %s<br>"%db.config['TEMPLATE_ENGINE'])
63+
64+
info.append("<h2>Database modules</h2>")
65+
info.append(get_status_of_module('anydbm', version=False) + "<br>")
66+
info.append(get_status_of_module('sqlite3') + "<br>")
67+
info.append(get_status_of_module('MySQLdb') + "<br>")
68+
info.append(get_status_of_module('psycopg2') + "<br>")
69+
70+
info.append("<h2>Other modules</h2>")
71+
72+
info.append(get_status_of_module('pytz') + "<br>")
73+
if is_module_loaded('xapian'):
74+
info.append(get_status_of_module('xapian', prefix="Test indexer:") +
75+
"<br>")
76+
elif is_module_loaded('whoosh'):
77+
info.append(get_status_of_module('whoosh', prefix="Test indexer:") +
78+
"<br>")
79+
else:
80+
info.append("Text indexer: Native enabled: True<br>")
81+
82+
info.append(get_status_of_module('pyme') + "<br>")
83+
info.append(get_status_of_module('OpenSSL') + "<br>")
84+
info.append(get_status_of_module('pychart') + "<br>")
85+
86+
info.append(get_status_of_module('jinja2') + "<br>")
87+
88+
if db._db.getuid() == "1":
89+
#may leak sensitive info about system, directory paths etc.
90+
#and keys so require admin user access. Consider expanding
91+
#to Admin rights for tracker.
92+
info.append("")
93+
info.append("Module Path: %r"%sys.path)
94+
95+
info.append("<h2>Environment Variables</h2>")
96+
info.append("<pre>") # include pre to prevent wrapping of values
97+
for key in db._client.env.keys():
98+
info.append("%s=%s"%(key,db._client.env[key]) + "<br>")
99+
info.append("</pre>")
100+
return "\n".join(info)
101+
102+
def init(instance):
103+
instance.registerUtil('AboutPage', AboutPage)
104+

locale/GNUmakefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ template:
5050
--copyright-holder="See Roundup README.txt" \
5151
-o $(TEMPLATE) $(SOURCES)
5252

53+
local_install: dist
54+
for file in $(MO_FILES); do \
55+
lang=`basename $$file .mo`; \
56+
mkdir -p locale/$$lang/LC_MESSAGES; \
57+
cp $$file locale/$$lang/LC_MESSAGES/roundup.mo; \
58+
done
59+
5360
# helps to check template file before check in
5461
diff:
5562
svn diff roundup.pot|grep -v '^[-+]#'|vim -Rv -

roundup/admin.py

Lines changed: 52 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,64 +1310,60 @@ class colon_separated(csv.excel):
13101310
sys.stdout.write('Exporting %s WITHOUT the files\r\n' %
13111311
classname)
13121312

1313-
f = open(os.path.join(dir, classname+'.csv'), 'w')
1314-
writer = csv.writer(f, colon_separated)
1315-
1316-
properties = cl.getprops()
1317-
propnames = cl.export_propnames()
1318-
fields = propnames[:]
1319-
fields.append('is retired')
1320-
writer.writerow(fields)
1321-
1322-
# If a node has a key, sort all nodes by key
1323-
# with retired nodes first. Retired nodes
1324-
# must occur before a non-retired node with
1325-
# the same key. Otherwise you get an
1326-
# IntegrityError: UNIQUE constraint failed:
1327-
# _class.__retired__, _<class>._<keyname>
1328-
# on imports to rdbms.
1329-
all_nodes = cl.getnodeids()
1330-
1331-
classkey = cl.getkey()
1332-
if classkey: # False sorts before True, so negate is_retired
1333-
keysort = lambda i: (cl.get(i, classkey),
1334-
not cl.is_retired(i))
1335-
all_nodes.sort(key=keysort)
1336-
# if there is no classkey no need to sort
1337-
1338-
for nodeid in all_nodes:
1339-
if self.verbose:
1340-
sys.stdout.write('\rExporting %s - %s' %
1341-
(classname, nodeid))
1342-
sys.stdout.flush()
1343-
node = cl.getnode(nodeid)
1344-
exp = cl.export_list(propnames, nodeid)
1345-
lensum = sum([len(repr_export(node[p])) for p in propnames])
1346-
# for a safe upper bound of field length we add
1347-
# difference between CSV len and sum of all field lengths
1348-
d = sum([len(x) for x in exp]) - lensum
1349-
if not d > 0:
1350-
raise AssertionError("Bad assertion d > 0")
1351-
for p in propnames:
1352-
ll = len(repr_export(node[p])) + d
1353-
if ll > max_len:
1354-
max_len = ll
1355-
writer.writerow(exp)
1356-
if export_files and hasattr(cl, 'export_files'):
1357-
cl.export_files(dir, nodeid)
1358-
1359-
# close this file
1360-
f.close()
1313+
with open(os.path.join(dir, classname+'.csv'), 'w') as f:
1314+
writer = csv.writer(f, colon_separated)
1315+
1316+
properties = cl.getprops()
1317+
propnames = cl.export_propnames()
1318+
fields = propnames[:]
1319+
fields.append('is retired')
1320+
writer.writerow(fields)
1321+
1322+
# If a node has a key, sort all nodes by key
1323+
# with retired nodes first. Retired nodes
1324+
# must occur before a non-retired node with
1325+
# the same key. Otherwise you get an
1326+
# IntegrityError: UNIQUE constraint failed:
1327+
# _class.__retired__, _<class>._<keyname>
1328+
# on imports to rdbms.
1329+
all_nodes = cl.getnodeids()
1330+
1331+
classkey = cl.getkey()
1332+
if classkey: # False sorts before True, so negate is_retired
1333+
keysort = lambda i: (cl.get(i, classkey),
1334+
not cl.is_retired(i))
1335+
all_nodes.sort(key=keysort)
1336+
# if there is no classkey no need to sort
1337+
1338+
for nodeid in all_nodes:
1339+
if self.verbose:
1340+
sys.stdout.write('\rExporting %s - %s' %
1341+
(classname, nodeid))
1342+
sys.stdout.flush()
1343+
node = cl.getnode(nodeid)
1344+
exp = cl.export_list(propnames, nodeid)
1345+
lensum = sum([len(repr_export(node[p])) for p in propnames])
1346+
# for a safe upper bound of field length we add
1347+
# difference between CSV len and sum of all field lengths
1348+
d = sum([len(x) for x in exp]) - lensum
1349+
if not d > 0:
1350+
raise AssertionError("Bad assertion d > 0")
1351+
for p in propnames:
1352+
ll = len(repr_export(node[p])) + d
1353+
if ll > max_len:
1354+
max_len = ll
1355+
writer.writerow(exp)
1356+
if export_files and hasattr(cl, 'export_files'):
1357+
cl.export_files(dir, nodeid)
13611358

13621359
# export the journals
1363-
jf = open(os.path.join(dir, classname+'-journals.csv'), 'w')
1364-
if self.verbose:
1365-
sys.stdout.write("\nExporting Journal for %s\n" % classname)
1366-
sys.stdout.flush()
1367-
journals = csv.writer(jf, colon_separated)
1368-
for row in cl.export_journals():
1369-
journals.writerow(row)
1370-
jf.close()
1360+
with open(os.path.join(dir, classname+'-journals.csv'), 'w') as jf:
1361+
if self.verbose:
1362+
sys.stdout.write("\nExporting Journal for %s\n" % classname)
1363+
sys.stdout.flush()
1364+
journals = csv.writer(jf, colon_separated)
1365+
for row in cl.export_journals():
1366+
journals.writerow(row)
13711367
if max_len > self.db.config.CSV_FIELD_SIZE:
13721368
print("Warning: config csv_field_size should be at least %s" %
13731369
max_len, file=sys.stderr)

roundup/backends/blobfiles.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,9 @@ def storefile(self, classname, nodeid, property, content):
332332
# in multi-tracker (i.e. multi-umask) or modpython scenarios
333333
# the umask may have changed since last we set it.
334334
os.umask(self.umask)
335-
open(name, 'wb').write(content)
335+
fd = open(name, 'wb')
336+
fd.write(content)
337+
fd.close()
336338

337339
def getfile(self, classname, nodeid, property):
338340
"""Get the content of the file in the database.

roundup/backends/indexer_dbm.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ def __init__(self, db):
5151
# for now the file itself is a flag
5252
self.force_reindex()
5353
elif os.path.exists(version):
54-
version = open(version).read()
54+
fd = open(version)
55+
version = fd.read()
56+
fd.close()
5557
# check the value and reindex if it's not the latest
5658
if version.strip() != '1':
5759
self.force_reindex()
@@ -63,7 +65,9 @@ def force_reindex(self):
6365
shutil.rmtree(self.indexdb_path)
6466
os.makedirs(self.indexdb_path)
6567
os.chmod(self.indexdb_path, 0o775) # nosec - allow group write
66-
open(os.path.join(self.indexdb_path, 'version'), 'w').write('1\n')
68+
fd = open(os.path.join(self.indexdb_path, 'version'), 'w')
69+
fd.write('1\n')
70+
fd.close()
6771
self.reindex = 1
6872
self.changed = 1
6973

@@ -260,6 +264,7 @@ def save_index(self):
260264
filename = self.indexdb + initchar
261265
pickle_fh = open(filename, 'wb')
262266
pickle_fh.write(zlib.compress(pickle_str))
267+
pickle_fh.close()
263268
os.chmod(filename, 0o664)
264269

265270
# save done

0 commit comments

Comments
 (0)