Merge lp:~nataliabidart/magicicada-server/use-venv-dependencies into lp:magicicada-server

Proposed by Natalia Bidart on 2018-04-04
Status: Merged
Approved by: Natalia Bidart on 2018-04-13
Approved revision: 92
Merged at revision: 86
Proposed branch: lp:~nataliabidart/magicicada-server/use-venv-dependencies
Merge into: lp:magicicada-server
Diff against target: 1048 lines (+186/-427)
29 files modified
.bzrignore (+1/-2)
.travis.yml (+7/-7)
Dockerfile (+15/-0)
Makefile (+48/-56)
README.rst (+0/-6)
config-manager.txt (+0/-4)
dependencies-devel.txt (+5/-10)
dependencies.txt (+1/-15)
dev-scripts/check_readme.sh (+0/-8)
dev-scripts/cmd_client.py (+2/-6)
dev-scripts/dev_launcher.py (+0/-87)
dev-scripts/sd_test.sh (+0/-29)
dev-scripts/start-dbus.sh (+0/-1)
dev-scripts/stop-dbus.sh (+1/-2)
dev-scripts/supervisor-config-dev.py (+57/-13)
dev-scripts/supervisor-dev.conf.tpl (+5/-5)
dev-scripts/supervisor_templates.py (+0/-65)
dev-scripts/supervisorctl-dev (+0/-6)
lib/ubuntuone/supervisor/config_helpers.py (+3/-1)
lib/ubuntuone/supervisor/heartbeat_listener.py (+1/-1)
lib/ubuntuone/supervisor/start-supervisord.py (+7/-5)
magicicada/metrics/services.py (+0/-34)
magicicada/metrics/tests/test_services.py (+0/-38)
magicicada/server/server.py (+3/-12)
magicicada/server/ssl_proxy.py (+2/-2)
magicicada/server/tests/test_basic.py (+0/-9)
requirements-devel.txt (+8/-0)
requirements.txt (+17/-0)
test (+3/-3)
To merge this branch: bzr merge lp:~nataliabidart/magicicada-server/use-venv-dependencies
Reviewer Review Type Date Requested Status
Facundo Batista 2018-04-04 Approve on 2018-04-10
Review via email: mp+342653@code.launchpad.net

Commit message

- Use devel and non-devel dependencies from a virtualenv.
- Clean former usage of revno from versioninfo.
- Provide travis and docker files so tests can be run in Travis using a xenial image.

To post a comment you must log in.
Facundo Batista (facundo) wrote :

Looks fine

review: Approve
92. By Natalia Bidart on 2018-04-12

One extra iteration of cleaning:
- use the storageprotocol from the wheel (dropping build deps for it)
- check the readme.rst with a Makefile file without needing a bash script

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2016-07-13 22:18:34 +0000
3+++ .bzrignore 2018-04-12 02:08:49 +0000
4@@ -1,5 +1,4 @@
5-env
6-lib/versioninfo.py
7+.env
8 tmp/*
9 twistd.pid
10 .sourcecode/*
11
12=== modified file '.travis.yml'
13--- .travis.yml 2016-09-01 17:10:04 +0000
14+++ .travis.yml 2018-04-12 02:08:49 +0000
15@@ -1,13 +1,13 @@
16-addons:
17- postgresql: "9.5"
18+sudo: required
19+dist: trusty
20+language: bash
21
22 services:
23- - postgresql
24+ - docker
25
26 before_install:
27- - sudo apt-get update
28- - make bootstrap
29+ - docker pull ubuntu:16.04
30+ - docker build -t magicicada-test-run .
31
32 script:
33- - make clean-sourcedeps
34- - make test SOURCEDEPS_DIR=sourcedeps
35+ - docker run magicicada-test-run make test SOURCEDEPS_DIR=sourcedeps
36
37=== added file 'Dockerfile'
38--- Dockerfile 1970-01-01 00:00:00 +0000
39+++ Dockerfile 2018-04-12 02:08:49 +0000
40@@ -0,0 +1,15 @@
41+FROM ubuntu:16.04
42+
43+ADD . /home/ubuntu/magicicada
44+COPY . /home/ubuntu/magicicada
45+WORKDIR /home/ubuntu/magicicada
46+
47+RUN apt-get update && apt-get install make -y
48+RUN make docker-bootstrap
49+
50+RUN useradd -ms /bin/bash ubuntu
51+RUN chown -R ubuntu:ubuntu /home/ubuntu
52+
53+USER ubuntu
54+ENV HOME /home/ubuntu
55+ENV PG_HOST /home/ubuntu/pg_data
56
57=== modified file 'Makefile'
58--- Makefile 2018-04-05 20:57:19 +0000
59+++ Makefile 2018-04-12 02:08:49 +0000
60@@ -17,11 +17,11 @@
61 # For further info, check http://launchpad.net/magicicada-server
62
63 DJANGO_SETTINGS_MODULE ?= magicicada.settings
64-FLAKE8 = flake8
65-PYTHON = python
66+ENV = $(CURDIR)/.env
67+PYTHON = $(ENV)/bin/python
68 SRC_DIR = $(CURDIR)/magicicada
69 LIB_DIR = $(CURDIR)/lib
70-ENV = $(CURDIR)/env
71+PATH := $(ENV)/bin:$(PATH)
72 PYTHONPATH := $(SRC_DIR):$(LIB_DIR):$(CURDIR):$(PYTHONPATH)
73 DJANGO_ADMIN = $(LIB_DIR)/django/bin/django-admin.py
74 DJANGO_MANAGE = $(PYTHON) manage.py
75@@ -32,7 +32,9 @@
76 PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
77
78 START_SUPERVISORD = lib/ubuntuone/supervisor/start-supervisord.py
79+SUPERVISOR_CTL = $(ENV)/bin/supervisorctl
80
81+export PATH
82 export PYTHONPATH
83 export DJANGO_SETTINGS_MODULE
84 export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION
85@@ -44,8 +46,6 @@
86 SOURCEDEPS_SOURCECODE_DIR = $(SOURCEDEPS_DIR)/sourcecode
87 TARGET_SOURCECODE_DIR = $(CURDIR)/.sourcecode
88
89-BUILD_DEPLOY_SOURCEDEPS=magicicada-protocol
90-
91 TESTFLAGS=
92
93 TAR_EXTRA = --exclude 'tmp/*' --exclude tags
94@@ -65,53 +65,49 @@
95 ifndef EXPORT_FROM_BZR
96 $(MAKE) link-sourcedeps
97 endif
98- $(MAKE) build-sourcedeps
99 touch $(SOURCEDEPS_TAG)
100
101-build: link-sourcedeps build-sourcedeps version
102-
103 link-sourcedeps:
104 @echo "Checking out external source dependencies..."
105 dev-scripts/link-external-sourcecode -p $(SOURCEDEPS_SOURCECODE_DIR)/ \
106 -t $(TARGET_SOURCECODE_DIR) -c config-manager.txt
107
108-# no need to link sourcedeps before building them, as rollout process
109-# handles config-manager.txt automatically
110-build-for-deployment: build-deploy-sourcedeps version
111-
112-build-sourcedeps: build-deploy-sourcedeps
113+build-clientdefs:
114 @echo "Building client clientdefs.py"
115- @cd .sourcecode/magicicada-client/ubuntuone/ && sed \
116+ @cd $(TARGET_SOURCECODE_DIR)/magicicada-client/ubuntuone/ && sed \
117 -e 's|\@localedir\@|/usr/local/share/locale|g' \
118 -e 's|\@libexecdir\@|/usr/local/libexec|g' \
119 -e 's|\@GETTEXT_PACKAGE\@|ubuntuone-client|g' \
120 -e 's|\@VERSION\@|0.0.0|g' < clientdefs.py.in > clientdefs.py
121
122-build-deploy-sourcedeps:
123- @echo "Building Python extensions"
124-
125- @for sourcedep in $(BUILD_DEPLOY_SOURCEDEPS) ; do \
126- d=".sourcecode/$$sourcedep" ; \
127- if test -e "$$d/setup.py" ; then \
128- (cd "$$d" && $(PYTHON) \
129- setup.py build build_ext --inplace > /dev/null) ; \
130- fi ; \
131- done
132-
133- @echo "Generating twistd plugin cache"
134- @$(PYTHON) -c "from twisted.plugin import IPlugin, getPlugins; list(getPlugins(IPlugin));"
135-
136-tarball: build-for-deployment
137- tar czf ../filesync-server.tgz $(TAR_EXTRA) .
138-
139 bootstrap:
140 cat dependencies.txt | sudo xargs apt-get install -y --no-install-recommends
141 cat dependencies-devel.txt | sudo xargs apt-get install -y --no-install-recommends
142+ $(MAKE) $(ENV)
143+ $(MAKE) sourcedeps build-clientdefs
144+ mkdir -p tmp
145+
146+docker-bootstrap: clean
147+ cat dependencies.txt | xargs apt-get install -y --no-install-recommends
148+ cat dependencies-devel.txt | xargs apt-get install -y --no-install-recommends
149+ $(MAKE) $(ENV)
150+ $(MAKE) sourcedeps build-clientdefs
151+ mkdir -p tmp
152+
153+$(ENV): $(ENV)/bin/activate
154+
155+# only runs when requirements.txt or requirements-devel.txt changes
156+$(ENV)/bin/activate: requirements.txt requirements-devel.txt
157+ test -d $(ENV) || virtualenv $(ENV)
158+ $(ENV)/bin/pip install -Ur requirements.txt
159+ $(ENV)/bin/pip install -Ur requirements-devel.txt
160+ $(ENV)/bin/pip install ubuntuone-storageprotocol --no-deps -t $(TARGET_SOURCECODE_DIR)
161+ touch $(ENV)/bin/activate
162
163 raw-test:
164- ./test $(TESTFLAGS)
165+ $(PYTHON) test $(TESTFLAGS)
166
167-test: lint sourcedeps clean version start-db start-base start-dbus raw-test stop
168+test: lint sourcedeps start-db start-base start-dbus raw-test stop
169
170 ci-test:
171 $(MAKE) test TESTFLAGS="-1 $(TESTFLAGS)"
172@@ -119,16 +115,13 @@
173 clean:
174 rm -rf tmp/* _trial_temp $(ENV)
175
176-lint:
177- virtualenv $(ENV)
178- $(ENV)/bin/pip install flake8 rst2html5
179+check-readme:
180+ $(ENV)/bin/rst2html5 README.rst --exit-status=warning > /dev/null && echo "README.rst OK"|| ( echo "ERROR: README.rst format is incorrect!!!!!" && exit 1)
181+
182+lint: $(ENV) check-readme
183 $(ENV)/bin/flake8 --filename='*.py' --exclude='migrations' $(SRC_DIR)
184- dev-scripts/check_readme.sh
185-
186-version:
187- bzr version-info --format=python > lib/versioninfo.py || true
188-
189-start: build start-base start-filesync-server-group publish-api-port
190+
191+start: $(ENV) start-base start-filesync-server-group publish-api-port
192
193 resume: start-base start-filesync-server-group
194
195@@ -138,7 +131,7 @@
196 start-base:
197 $(MAKE) start-supervisor && $(MAKE) start-dbus || ( $(MAKE) stop ; exit 1 )
198
199-stop: stop-filesync-dummy-group stop-supervisor stop-dbus
200+stop: stop-supervisor stop-dbus
201
202 start-dbus:
203 dev-scripts/start-dbus.sh
204@@ -147,28 +140,28 @@
205 dev-scripts/stop-dbus.sh
206
207 start-supervisor:
208- @python dev-scripts/supervisor-config-dev.py
209+ $(PYTHON) dev-scripts/supervisor-config-dev.py
210 -@$(START_SUPERVISORD) dev-scripts/supervisor-dev.conf.tpl
211
212 stop-supervisor:
213- -@dev-scripts/supervisorctl-dev shutdown
214+ $(SUPERVISOR_CTL) -c $(CURDIR)/tmp/supervisor-dev.conf shutdown
215
216 start-%-group:
217- -@dev-scripts/supervisorctl-dev start $*:
218+ $(SUPERVISOR_CTL) -c $(CURDIR)/tmp/supervisor-dev.conf start $*:
219
220 stop-%-group:
221- -@dev-scripts/supervisorctl-dev stop $*:
222+ $(SUPERVISOR_CTL) -c $(CURDIR)/tmp/supervisor-dev.conf stop $*:
223
224 start-%:
225- -@dev-scripts/supervisorctl-dev start $*
226+ $(SUPERVISOR_CTL) -c $(CURDIR)/tmp/supervisor-dev.conf start $*
227
228 stop-%:
229- -@dev-scripts/supervisorctl-dev stop $*
230+ $(SUPERVISOR_CTL) -c $(CURDIR)/tmp/supervisor-dev.conf stop $*
231
232 publish-api-port:
233- python -c 'from magicicada import settings; print >> file("tmp/filesyncserver.port", "w"), settings.TCP_PORT'
234- python -c 'from magicicada import settings; print >> file("tmp/filesyncserver.port.ssl", "w"), settings.SSL_PORT'
235- python -c 'from magicicada import settings; print >> file("tmp/filesyncserver-status.port", "w"), settings.API_STATUS_PORT'
236+ $(PYTHON) -c 'from magicicada import settings; print >> file("tmp/filesyncserver.port", "w"), settings.TCP_PORT'
237+ $(PYTHON) -c 'from magicicada import settings; print >> file("tmp/filesyncserver.port.ssl", "w"), settings.SSL_PORT'
238+ $(PYTHON) -c 'from magicicada import settings; print >> file("tmp/filesyncserver-status.port", "w"), settings.API_STATUS_PORT'
239
240 shell:
241 $(DJANGO_MANAGE) shell
242@@ -179,7 +172,6 @@
243 admin:
244 $(DJANGO_ADMIN) $(ARGS)
245
246-.PHONY: sourcedeps link-sourcedeps build-sourcedeps build-deploy-sourcedeps \
247- build clean version lint test ci-test build-for-deployment \
248- clean-sourcedeps tarball start stop publish-api-port start-supervisor \
249- stop-supervisor start-dbus stop-dbus start-heapy
250+.PHONY: sourcedeps link-sourcedeps clean lint test ci-test clean-sourcedeps \
251+ start stop publish-api-port start-supervisor stop-supervisor \
252+ start-dbus stop-dbus start-heapy check-readme
253
254=== modified file 'README.rst'
255--- README.rst 2017-04-22 21:07:36 +0000
256+++ README.rst 2018-04-12 02:08:49 +0000
257@@ -75,12 +75,6 @@
258 access)::
259
260 make bootstrap
261- make sourcedeps
262-
263-If you are in Xenial, please also install virtualenv (didn't include it in
264-the previous step as it doesn't exist as a separate package in older systems)::
265-
266- sudo apt-get install virtualenv
267
268 Ensure the files 'privkey.pem' and 'cacert.pem' produced in the "Before server
269 or client" section are copied into the ~/magicicada/magicicada-server/certs
270
271=== modified file 'config-manager.txt'
272--- config-manager.txt 2018-04-05 20:57:19 +0000
273+++ config-manager.txt 2018-04-12 02:08:49 +0000
274@@ -21,9 +21,5 @@
275 #
276 # make clean-sourcedeps sourcedeps
277
278-./.sourcecode/configglue ~configglue/configglue/trunk;revno=1
279-./.sourcecode/dirspec ~ubuntuone-control-tower/dirspec/trunk;revno=14
280-./.sourcecode/django ~ubuntuone-pqm-team/django/stable;revno=17
281 ./.sourcecode/u1sync ~facundo/u1sync/opensourcing;revno=10
282 ./.sourcecode/magicicada-client ~chicharreros/magicicada-client/trunk;revno=1440
283-./.sourcecode/magicicada-protocol ~chicharreros/magicicada-protocol/trunk;revno=169
284
285=== modified file 'dependencies-devel.txt'
286--- dependencies-devel.txt 2017-04-22 21:07:36 +0000
287+++ dependencies-devel.txt 2018-04-12 02:08:49 +0000
288@@ -1,12 +1,7 @@
289 dbus
290-openssl
291+libcairo2-dev
292+libdbus-1-dev
293+libdbus-glib-1-dev
294+libgirepository1.0-dev
295+pkg-config
296 postgresql-client-9.5
297-python-dbus
298-python-gobject
299-python-httplib2
300-python-mock
301-python-mocker
302-python-pyinotify
303-python-testtools
304-python-twisted-names
305-python-virtualenv
306
307=== modified file 'dependencies.txt'
308--- dependencies.txt 2017-04-22 21:07:36 +0000
309+++ dependencies.txt 2018-04-12 02:08:49 +0000
310@@ -4,19 +4,5 @@
311 postgresql-9.5
312 postgresql-contrib
313 postgresql-plpython-9.5
314-protobuf-compiler
315-python-boto
316-python-bson
317 python-dev
318-python-iso8601
319-python-meliae
320-python-openssl
321-python-protobuf
322-python-psutil
323-python-psycopg2
324-python-setuptools
325-python-twisted-web
326-python-tz
327-python-virtualenv
328-python-yaml
329-supervisor
330+virtualenv
331
332=== removed file 'dev-scripts/check_readme.sh'
333--- dev-scripts/check_readme.sh 2015-12-27 22:18:59 +0000
334+++ dev-scripts/check_readme.sh 1970-01-01 00:00:00 +0000
335@@ -1,8 +0,0 @@
336-#/bin/bash
337-
338-OUTPUT=$(env/bin/rst2html5 README.rst 2>&1 >/dev/null)
339-if [ -n "$OUTPUT" ]; then
340- echo -e "README.rst format is incorrect!!!!!\n"
341- echo -e "Errors: \n$OUTPUT"
342- exit 1
343-fi
344
345=== modified file 'dev-scripts/cmd_client.py'
346--- dev-scripts/cmd_client.py 2018-04-05 20:57:19 +0000
347+++ dev-scripts/cmd_client.py 2018-04-12 02:08:49 +0000
348@@ -33,12 +33,8 @@
349 from threading import Thread
350 from optparse import OptionParser
351
352-try:
353- from twisted.internet import gireactor
354- gireactor.install()
355-except ImportError:
356- from twisted.internet import glib2reactor
357- glib2reactor.install()
358+from twisted.internet import gireactor
359+gireactor.install()
360
361 from dbus.mainloop.glib import DBusGMainLoop
362 DBusGMainLoop(set_as_default=True)
363
364=== removed file 'dev-scripts/dev_launcher.py'
365--- dev-scripts/dev_launcher.py 2018-04-05 20:58:20 +0000
366+++ dev-scripts/dev_launcher.py 1970-01-01 00:00:00 +0000
367@@ -1,87 +0,0 @@
368-#!/usr/bin/env python
369-
370-# Copyright 2008-2015 Canonical
371-# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros)
372-#
373-# This program is free software: you can redistribute it and/or modify
374-# it under the terms of the GNU Affero General Public License as
375-# published by the Free Software Foundation, either version 3 of the
376-# License, or (at your option) any later version.
377-#
378-# This program is distributed in the hope that it will be useful,
379-# but WITHOUT ANY WARRANTY; without even the implied warranty of
380-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
381-# GNU Affero General Public License for more details.
382-#
383-# You should have received a copy of the GNU Affero General Public License
384-# along with this program. If not, see <http://www.gnu.org/licenses/>.
385-#
386-# For further info, check http://launchpad.net/magicicada-server
387-
388-"""Script to execute client stuff in dev environment."""
389-
390-import os
391-import sys
392-
393-import _pythonpath
394-
395-# fix environment before further imports
396-os.environ["DJANGO_SETTINGS_MODULE"] = "magicicada.settings"
397-
398-from utilities import dev_launcher
399-
400-
401-def usage():
402- """Return the usage."""
403- return ("dev_launcher PROGNAME USERNAME [--machine=N] [args*]\n"
404- "runs PROGNAME with args plus:\n"
405- " --port with the local server port\n"
406- " --host localhost\n"
407- " --auth username and password for user USERNAME\n")
408-
409-
410-def main(args):
411- """run devlauncher"""
412- from optparse import OptionParser
413- if len(args) < 3:
414- print usage()
415- return
416-
417- parser = OptionParser(usage=usage())
418- parser.add_option('-p', '--port', dest='port',
419- help="The port to where connect")
420- parser.add_option('-t', '--host', dest='host',
421- help="The host to where connect")
422- parser.add_option('-a', '--auth', dest='auth',
423- help="Auth data")
424- parser.add_option('-m', '--machine', dest='machine',
425- help="Machine number (to have multiple launchers with "
426- "the same user)")
427-
428- # check to see if we have extra params for the command to execute
429- if "--" in args:
430- pos = args.index("--")
431- params = args[pos + 1:]
432- args = args[:pos]
433- else:
434- params = []
435-
436- (options, pargs) = parser.parse_args(args[1:])
437- progname, username = pargs
438- if options.machine:
439- machine_suffix = "_" + options.machine
440- else:
441- machine_suffix = None
442-
443- lib_dir = _pythonpath.get_lib_dir()
444- d = dict(
445- PYTHONPATH=lib_dir,
446- XDG_CACHE_HOME="tmp/xdg_cache",
447- )
448-
449- dev_launcher.launch(progname, username, params, environ=d, verbose=True,
450- machine_suffix=machine_suffix, host=options.host,
451- api_port=options.port, auth_data=options.auth)
452-
453-if __name__ == "__main__":
454- main(sys.argv)
455
456=== removed file 'dev-scripts/sd_test.sh'
457--- dev-scripts/sd_test.sh 2018-04-05 20:57:19 +0000
458+++ dev-scripts/sd_test.sh 1970-01-01 00:00:00 +0000
459@@ -1,29 +0,0 @@
460-#!/bin/bash
461-
462-# Copyright 2008-2015 Canonical
463-# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros)
464-#
465-# This program is free software: you can redistribute it and/or modify
466-# it under the terms of the GNU Affero General Public License as
467-# published by the Free Software Foundation, either version 3 of the
468-# License, or (at your option) any later version.
469-#
470-# This program is distributed in the hope that it will be useful,
471-# but WITHOUT ANY WARRANTY; without even the implied warranty of
472-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
473-# GNU Affero General Public License for more details.
474-#
475-# You should have received a copy of the GNU Affero General Public License
476-# along with this program. If not, see <http://www.gnu.org/licenses/>.
477-#
478-# For further info, check http://launchpad.net/magicicada-server
479-
480-# run the minimal infraestructure to run the sdtests isolated from the current session
481-ROOTDIR=${ROOTDIR:-`bzr root`}
482-ADDRESS_FILE="${ROOTDIR}/tmp/dbus.address"
483-make start-dbus
484-env DEBUG="file $DEBUG" SERVER_DEBUG="$SERVER_DEBUG" ROOTDIR=$ROOTDIR DBUS_SESSION_BUS_ADDRESS=$(cat $ADDRESS_FILE) XDG_CACHE_HOME="${ROOTDIR}/tmp/xdg_cache" \
485-${PYTHON:-python} -Wignore ./test $@
486-EXIT_VAL=$?
487-make stop-dbus
488-exit $EXIT_VAL
489
490=== modified file 'dev-scripts/start-dbus.sh'
491--- dev-scripts/start-dbus.sh 2018-04-05 20:57:19 +0000
492+++ dev-scripts/start-dbus.sh 2018-04-12 02:08:49 +0000
493@@ -41,4 +41,3 @@
494 exec 4>&-
495
496 echo "DBUS_SESSION_BUS_ADDRESS=$(cat $ADDRESS_FILE)"
497-
498
499=== modified file 'dev-scripts/stop-dbus.sh'
500--- dev-scripts/stop-dbus.sh 2018-04-05 20:57:19 +0000
501+++ dev-scripts/stop-dbus.sh 2018-04-12 02:08:49 +0000
502@@ -23,7 +23,6 @@
503 ADDRESS_FILE="${ROOTDIR}/tmp/dbus.address"
504
505 /sbin/start-stop-daemon -v --stop --oknodo --pidfile $PID_FILE
506-kill `cat $PID_FILE`
507+kill `cat $PID_FILE` || true
508 # cleanup the files created on start
509 rm -f $PID_FILE $ADDRESS_FILE
510-
511
512=== modified file 'dev-scripts/supervisor-config-dev.py'
513--- dev-scripts/supervisor-config-dev.py 2018-04-05 20:57:19 +0000
514+++ dev-scripts/supervisor-config-dev.py 2018-04-12 02:08:49 +0000
515@@ -20,24 +20,68 @@
516
517 import os
518 import socket
519+import sys
520
521 import _pythonpath # NOQA
522
523 from ubuntuone.supervisor.config_helpers import generate_server_config
524-from utilities import utils
525-
526-from supervisor_templates import TEMPLATES
527-
528-ROOTDIR = utils.get_rootdir()
529-TMPDIR = os.path.join(ROOTDIR, 'tmp')
530-if not os.path.exists(TMPDIR):
531- os.mkdir(TMPDIR)
532-
533+from utilities.utils import get_rootdir, get_tmpdir
534+
535+
536+ROOT_DIR = get_rootdir()
537+TMP_DIR = get_tmpdir()
538+
539+
540+FILESYNC_TEMPLATE = (
541+ '[program:%(instance_name)s]\n'
542+ 'command=%(basepath)s/dev-scripts/set_rlimits.sh -d %(fs_memory_limit)s '
543+ '-m %(fs_memory_limit)s -v %(fs_memory_limit)s -n %(open_fds)s '
544+ '%(basepath)s/.env/bin/twistd --pidfile %(pid_folder)s/fsync_slave_%(instance)s.pid '
545+ '-n -y %(basepath)s/magicicada/server/server.tac '
546+ '--reactor=epoll\n'
547+ 'environment=DJANGO_SETTINGS_MODULE="magicicada.settings",'
548+ 'PYTHONPATH="%(pythonpath)s",'
549+ 'FSYNC_INSTANCE_ID=%(instance)03d,'
550+ 'CONFIG="%(basepath)s/configs/%(config)s"%(environment_vars)s\n'
551+ 'autostart=false\n'
552+ 'stdout_capture_maxbytes=%(stdout_capture_maxbytes)s\n'
553+ 'stopsignal=INT\n'
554+)
555+
556+SSL_PROXY_TEMPLATE = (
557+ '[program:%(instance_name)s]\n'
558+ 'command=%(basepath)s/dev-scripts/set_rlimits.sh -d %(ssl_memory_limit)s '
559+ '-m %(ssl_memory_limit)s -v %(ssl_memory_limit)s -n %(open_fds)s '
560+ '%(basepath)s/.env/bin/twistd --pidfile %(pid_folder)s/ssl-proxy-%(instance)s.pid '
561+ '-n -y %(basepath)s/magicicada/server/ssl_proxy.tac '
562+ '--reactor=epoll\n'
563+ 'environment=DJANGO_SETTINGS_MODULE="magicicada.settings",'
564+ 'PYTHONPATH="%(pythonpath)s",'
565+ 'FSYNC_INSTANCE_ID=%(instance)03d,'
566+ 'CONFIG="%(basepath)s/configs/%(config)s",'
567+ 'FSYNC_SERVICE_NAME="ssl-proxy"%(environment_vars)s\n'
568+ 'autostart=false\n'
569+ 'stdout_capture_maxbytes=%(stdout_capture_maxbytes)s\n'
570+ 'stopsignal=INT\n'
571+)
572+
573+
574+TEMPLATES = {
575+ 'filesync': {
576+ 'name': "filesync-worker-%(instance)d",
577+ 'config': FILESYNC_TEMPLATE,
578+ },
579+ 'ssl-proxy': {
580+ 'name': "ssl-proxy-%(instance)d",
581+ 'config': SSL_PROXY_TEMPLATE,
582+ },
583+}
584
585 config_spec = {
586- "basepath": ROOTDIR,
587- "log_folder": TMPDIR,
588- "pid_folder": TMPDIR,
589+ "basepath": ROOT_DIR,
590+ "log_folder": TMP_DIR,
591+ "pid_folder": TMP_DIR,
592+ "pythonpath": ':'.join(filter(None, sys.path)),
593 }
594
595 workers = {}
596@@ -52,5 +96,5 @@
597 config_content = generate_server_config(
598 hostname, services, config_spec, TEMPLATES, None,
599 with_heartbeat=False, with_header=False)
600- with open(os.path.join(TMPDIR, 'services-supervisor.conf'), 'w') as f:
601+ with open(os.path.join(TMP_DIR, 'services-supervisor.conf'), 'w') as f:
602 f.write(config_content)
603
604=== modified file 'dev-scripts/supervisor-dev.conf.tpl'
605--- dev-scripts/supervisor-dev.conf.tpl 2017-04-22 21:07:36 +0000
606+++ dev-scripts/supervisor-dev.conf.tpl 2018-04-12 02:08:49 +0000
607@@ -25,20 +25,20 @@
608
609 [eventlistener:heartbeat]
610 command=python %(basepath)s/lib/ubuntuone/supervisor/heartbeat_listener.py --interval=10 --timeout=20 --log_level=DEBUG --log_file=%(tmp_dir)s/heartbeat.log --groups=filesync-server
611-environment=PYTHONPATH="%(basepath)s:%(basepath)s/lib"
612+environment=PYTHONPATH="%(pythonpath)s"
613 events=PROCESS_COMMUNICATION,TICK_5
614 buffer_size=42
615
616 [program:filesync]
617-command=/usr/bin/twistd --pidfile %(tmp_dir)s/filesync.pid -n -y %(basepath)s/magicicada/server/server.tac --reactor=epoll
618-environment=PYTHONPATH="%(basepath)s:%(basepath)s/lib",DJANGO_SETTINGS_MODULE="magicicada.settings",PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
619+command=%(basepath)s/.env/bin/twistd --pidfile %(tmp_dir)s/filesync.pid -n -y %(basepath)s/magicicada/server/server.tac --reactor=epoll
620+environment=PYTHONPATH="%(pythonpath)s",DJANGO_SETTINGS_MODULE="magicicada.settings",PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
621 stdout_capture_maxbytes=16384
622 autostart=false
623 stopsignal=INT
624
625 [program:ssl-proxy]
626-command=/usr/bin/twistd --pidfile %(tmp_dir)s/ssl-proxy.pid -n -y %(basepath)s/magicicada/server/ssl_proxy.tac --reactor=epoll
627-environment=PYTHONPATH="%(basepath)s:%(basepath)s/lib",DJANGO_SETTINGS_MODULE="magicicada.settings"
628+command=%(basepath)s/.env/bin/twistd --pidfile %(tmp_dir)s/ssl-proxy.pid -n -y %(basepath)s/magicicada/server/ssl_proxy.tac --reactor=epoll
629+environment=PYTHONPATH="%(pythonpath)s",DJANGO_SETTINGS_MODULE="magicicada.settings"
630 stdout_capture_maxbytes=16384
631 autostart=false
632 stopsignal=INT
633
634=== removed file 'dev-scripts/supervisor_templates.py'
635--- dev-scripts/supervisor_templates.py 2018-04-05 20:57:19 +0000
636+++ dev-scripts/supervisor_templates.py 1970-01-01 00:00:00 +0000
637@@ -1,65 +0,0 @@
638-# Copyright 2008-2015 Canonical
639-# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros)
640-#
641-# This program is free software: you can redistribute it and/or modify
642-# it under the terms of the GNU Affero General Public License as
643-# published by the Free Software Foundation, either version 3 of the
644-# License, or (at your option) any later version.
645-#
646-# This program is distributed in the hope that it will be useful,
647-# but WITHOUT ANY WARRANTY; without even the implied warranty of
648-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
649-# GNU Affero General Public License for more details.
650-#
651-# You should have received a copy of the GNU Affero General Public License
652-# along with this program. If not, see <http://www.gnu.org/licenses/>.
653-#
654-# For further info, check http://launchpad.net/magicicada-server
655-
656-"""Templates to generate supervisor config."""
657-
658-FILESYNC_TEMPLATE = (
659- '[program:%(instance_name)s]\n'
660- 'command=%(basepath)s/dev-scripts/set_rlimits.sh -d %(fs_memory_limit)s '
661- '-m %(fs_memory_limit)s -v %(fs_memory_limit)s -n %(open_fds)s '
662- '/usr/bin/twistd --pidfile %(pid_folder)s/fsync_slave_%(instance)s.pid '
663- '-n -y %(basepath)s/magicicada/server/server.tac '
664- '--reactor=epoll\n'
665- 'environment=DJANGO_SETTINGS_MODULE="magicicada.settings",'
666- 'PYTHONPATH="%(basepath)s/lib",'
667- 'FSYNC_INSTANCE_ID=%(instance)03d,'
668- 'CONFIG="%(basepath)s/configs/%(config)s"%(environment_vars)s\n'
669- 'autostart=false\n'
670- 'stdout_capture_maxbytes=%(stdout_capture_maxbytes)s\n'
671- 'stopsignal=INT\n'
672-)
673-
674-SSL_PROXY_TEMPLATE = (
675- '[program:%(instance_name)s]\n'
676- 'command=%(basepath)s/dev-scripts/set_rlimits.sh -d %(ssl_memory_limit)s '
677- '-m %(ssl_memory_limit)s -v %(ssl_memory_limit)s -n %(open_fds)s '
678- '/usr/bin/twistd '
679- '--pidfile %(pid_folder)s/ssl-proxy-%(instance)s.pid '
680- '-n -y %(basepath)s/magicicada/server/ssl_proxy.tac '
681- '--reactor=epoll\n'
682- 'environment=DJANGO_SETTINGS_MODULE="magicicada.settings",'
683- 'PYTHONPATH="%(basepath)s/lib",'
684- 'FSYNC_INSTANCE_ID=%(instance)03d,'
685- 'CONFIG="%(basepath)s/configs/%(config)s",'
686- 'FSYNC_SERVICE_NAME="ssl-proxy"%(environment_vars)s\n'
687- 'autostart=false\n'
688- 'stdout_capture_maxbytes=%(stdout_capture_maxbytes)s\n'
689- 'stopsignal=INT\n'
690-)
691-
692-
693-TEMPLATES = {
694- 'filesync': {
695- 'name': "filesync-worker-%(instance)d",
696- 'config': FILESYNC_TEMPLATE,
697- },
698- 'ssl-proxy': {
699- 'name': "ssl-proxy-%(instance)d",
700- 'config': SSL_PROXY_TEMPLATE,
701- },
702-}
703
704=== removed file 'dev-scripts/supervisorctl-dev'
705--- dev-scripts/supervisorctl-dev 2015-08-05 13:10:02 +0000
706+++ dev-scripts/supervisorctl-dev 1970-01-01 00:00:00 +0000
707@@ -1,6 +0,0 @@
708-#!/bin/bash
709-ROOT=$(dirname $0)/..
710-NAME=$(basename $0)
711-
712-export PYTHONPATH="$ROOT/lib"
713-/usr/bin/supervisorctl -c $ROOT/tmp/${NAME/supervisorctl/supervisor}.conf $*
714
715=== removed symlink 'lib/configglue'
716=== target was u'../.sourcecode/configglue/configglue/'
717=== removed symlink 'lib/dirspec'
718=== target was u'../.sourcecode/dirspec/dirspec'
719=== removed symlink 'lib/django'
720=== target was u'../.sourcecode/django/django'
721=== removed symlink 'lib/mock.py'
722=== target was u'../.sourcecode/mock/mock.py'
723=== removed symlink 'lib/oauthlib'
724=== target was u'../.sourcecode/oauthlib/oauthlib/'
725=== removed symlink 'lib/requests'
726=== target was u'../.sourcecode/requests/requests'
727=== removed symlink 'lib/requests_oauthlib'
728=== target was u'../.sourcecode/requests_oauthlib/requests_oauthlib'
729=== removed symlink 'lib/ubuntuone/status'
730=== target was u'../../.sourcecode/magicicada-client/ubuntuone/status/'
731=== modified symlink 'lib/ubuntuone/storageprotocol'
732=== target changed u'../../.sourcecode/magicicada-protocol/ubuntuone/storageprotocol' => u'../../.sourcecode/ubuntuone/storageprotocol'
733=== modified file 'lib/ubuntuone/supervisor/config_helpers.py'
734--- lib/ubuntuone/supervisor/config_helpers.py 2018-04-05 20:57:19 +0000
735+++ lib/ubuntuone/supervisor/config_helpers.py 2018-04-12 02:08:49 +0000
736@@ -20,6 +20,7 @@
737
738 import os
739 import platform
740+import sys
741
742 from utilities.utils import get_rootdir
743
744@@ -34,7 +35,7 @@
745 HEARTBEAT_LISTENER_TEMPLATE = '\n'.join((
746 "[eventlistener:heartbeat]",
747 "command=python %(basepath)s/lib/ubuntuone/supervisor/heartbeat_listener.py --interval=%(interval)s --timeout=%(timeout)s --log_level=%(log_level)s --log_file=%(log_folder)s/heartbeat_listener.log --groups=%(groups)s %(processes)s", # NOQA
748- 'environment=PYTHONPATH="%(basepath)s:%(basepath)s/lib",DJANGO_SETTINGS_MODULE="magicicada.settings"', # NOQA
749+ 'environment=PYTHONPATH="%(pythonpath)s",DJANGO_SETTINGS_MODULE="magicicada.settings"', # NOQA
750 "events=PROCESS_COMMUNICATION,TICK_5",
751 "buffer_size=%(buffer_size)s",
752 ))
753@@ -68,6 +69,7 @@
754 "log_folder": "/srv/%(base_dir)s/%(env)s-logs",
755 "pid_folder": "/srv/%(base_dir)s/var",
756 "stdout_capture_maxbytes": 16384,
757+ "pythonpath": ':'.join(filter(None, sys.path)),
758 }
759
760 base_heartbeat_listener_spec = {
761
762=== modified file 'lib/ubuntuone/supervisor/heartbeat_listener.py'
763--- lib/ubuntuone/supervisor/heartbeat_listener.py 2018-04-05 20:57:19 +0000
764+++ lib/ubuntuone/supervisor/heartbeat_listener.py 2018-04-12 02:08:49 +0000
765@@ -219,7 +219,7 @@
766
767 # main entry point, parse args and start the service.
768 if __name__ == '__main__':
769- from configglue import configglue
770+ from configglue.inischema.glue import configglue
771 from StringIO import StringIO
772 config_file = StringIO()
773 config_file.write(default_config)
774
775=== modified file 'lib/ubuntuone/supervisor/start-supervisord.py'
776--- lib/ubuntuone/supervisor/start-supervisord.py 2018-04-05 20:57:19 +0000
777+++ lib/ubuntuone/supervisor/start-supervisord.py 2018-04-12 02:08:49 +0000
778@@ -36,10 +36,12 @@
779 """Write out filled in conf template in tmp."""
780 template = open(os.path.join(ROOT_DIR, tpl)).read()
781
782- template_vars = {}
783- template_vars['inet_http_server_port'] = inet_http_server_port
784- template_vars['basepath'] = ROOT_DIR
785- template_vars['tmp_dir'] = TMP_DIR
786+ template_vars = {
787+ 'inet_http_server_port': inet_http_server_port,
788+ 'basepath': ROOT_DIR,
789+ 'tmp_dir': TMP_DIR,
790+ 'pythonpath': ':'.join(filter(None, sys.path)),
791+ }
792
793 conf = template % template_vars
794
795@@ -79,7 +81,7 @@
796 except OSError:
797 pass
798
799- os_exec("/usr/bin/supervisord", "-c", conf_file_path)
800+ os_exec(".env/bin/supervisord", "-c", conf_file_path)
801
802
803 if __name__ == "__main__":
804
805=== removed file 'magicicada/metrics/services.py'
806--- magicicada/metrics/services.py 2018-04-05 20:57:19 +0000
807+++ magicicada/metrics/services.py 1970-01-01 00:00:00 +0000
808@@ -1,34 +0,0 @@
809-# Copyright 2008-2015 Canonical
810-# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros)
811-#
812-# This program is free software: you can redistribute it and/or modify
813-# it under the terms of the GNU Affero General Public License as
814-# published by the Free Software Foundation, either version 3 of the
815-# License, or (at your option) any later version.
816-#
817-# This program is distributed in the hope that it will be useful,
818-# but WITHOUT ANY WARRANTY; without even the implied warranty of
819-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
820-# GNU Affero General Public License for more details.
821-#
822-# You should have received a copy of the GNU Affero General Public License
823-# along with this program. If not, see <http://www.gnu.org/licenses/>.
824-#
825-# For further info, check http://launchpad.net/magicicada-server
826-
827-"""Metric services."""
828-
829-from __future__ import unicode_literals
830-
831-from metrics import get_meter
832-try:
833- from versioninfo import version_info
834-except ImportError:
835- version_info = {'revno': 'Undefined'}
836-
837-meter = get_meter('service')
838-
839-
840-def revno():
841- """Trigger a service revision number update."""
842- meter.gauge('revno', version_info['revno'])
843
844=== removed file 'magicicada/metrics/tests/test_services.py'
845--- magicicada/metrics/tests/test_services.py 2018-04-05 20:57:19 +0000
846+++ magicicada/metrics/tests/test_services.py 1970-01-01 00:00:00 +0000
847@@ -1,38 +0,0 @@
848-# Copyright 2008-2015 Canonical
849-# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros)
850-#
851-# This program is free software: you can redistribute it and/or modify
852-# it under the terms of the GNU Affero General Public License as
853-# published by the Free Software Foundation, either version 3 of the
854-# License, or (at your option) any later version.
855-#
856-# This program is distributed in the hope that it will be useful,
857-# but WITHOUT ANY WARRANTY; without even the implied warranty of
858-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
859-# GNU Affero General Public License for more details.
860-#
861-# You should have received a copy of the GNU Affero General Public License
862-# along with this program. If not, see <http://www.gnu.org/licenses/>.
863-#
864-# For further info, check http://launchpad.net/magicicada-server
865-
866-"""Tests for metric services."""
867-
868-from __future__ import unicode_literals
869-
870-from mock import patch
871-from testtools import TestCase
872-
873-from metrics import get_meter
874-from metrics.services import revno, version_info
875-
876-
877-class ServicesTest(TestCase):
878- """Tests for metric services."""
879-
880- def test_meters_revno_with_gauge_meter(self):
881- """The service is able to meter a revision by gauge meter."""
882- service_meter = get_meter('service')
883- with patch.object(service_meter, 'gauge') as gauge:
884- revno()
885- gauge.assert_called_with('revno', version_info['revno'])
886
887=== modified file 'magicicada/server/server.py'
888--- magicicada/server/server.py 2018-04-05 20:57:19 +0000
889+++ magicicada/server/server.py 2018-04-12 02:08:49 +0000
890@@ -41,7 +41,6 @@
891 import twisted.web.error
892
893 import metrics
894-import metrics.services
895
896 from twisted.application.service import MultiService, Service
897 from twisted.application.internet import TCPServer
898@@ -60,14 +59,6 @@
899 from magicicada.server import auth, content, errors, stats
900 from magicicada.server.diskstorage import DiskStorage
901
902-try:
903- from versioninfo import version_info
904-except ImportError:
905- version_info = {
906- 'branch_nick': 'Unavailable',
907- 'revno': 'Unavailable',
908- }
909-
910
911 # this is the minimal cap we support (to avoid hardcoding it in the code)
912 MIN_CAP = frozenset(['no-content', 'account-info', 'resumable-uploads',
913@@ -85,6 +76,8 @@
914 # frozenset(['example2']): dict(srv_record='_https._tcp.fs.server.com')
915 }
916
917+FILESYNC_STATUS_MSG = 'filesync server'
918+
919 logger = logging.getLogger(__name__)
920
921
922@@ -381,8 +374,7 @@
923 request.RequestHandler.connectionMade(self)
924 self.factory.protocols.append(self)
925 self.log.info('Connection Made')
926- msg = '%d filesync server revision %s.\r\n' % (
927- self.PROTOCOL_VERSION, version_info['revno'])
928+ msg = '%d %s.\r\n' % (self.PROTOCOL_VERSION, FILESYNC_STATUS_MSG)
929 self.transport.write(msg)
930 self.ping_loop.start()
931 self.factory.metrics.meter('connection_made', 1)
932@@ -2685,7 +2677,6 @@
933 self.factory.rpc_dal = self.rpc_dal
934 self.metrics.meter('server_start')
935 self.metrics.increment('services_active')
936- metrics.services.revno()
937
938 self._reactor_inspector.start()
939 # only start the HeartbeatWriter if the interval is > 0
940
941=== modified file 'magicicada/server/ssl_proxy.py'
942--- magicicada/server/ssl_proxy.py 2018-04-05 20:57:19 +0000
943+++ magicicada/server/ssl_proxy.py 2018-04-12 02:08:49 +0000
944@@ -34,7 +34,7 @@
945 import metrics
946
947 from magicicada import settings
948-from magicicada.server.server import get_service_port
949+from magicicada.server.server import FILESYNC_STATUS_MSG, get_service_port
950 from magicicada.server.ssl import disable_ssl_compression
951 from ubuntuone.supervisor import utils as supervisor_utils
952
953@@ -164,7 +164,7 @@
954
955 def lineReceived(self, line):
956 """Handle a single line received."""
957- if "filesync server revision" in line:
958+ if FILESYNC_STATUS_MSG in line:
959 self.factory.deferred.callback(line)
960 else:
961 self.factory.deferred.errback(ValueError(line))
962
963=== modified file 'magicicada/server/tests/test_basic.py'
964--- magicicada/server/tests/test_basic.py 2018-04-05 20:57:19 +0000
965+++ magicicada/server/tests/test_basic.py 2018-04-12 02:08:49 +0000
966@@ -35,9 +35,6 @@
967 from ubuntuone.storageprotocol import request
968 from ubuntuone.supervisor import utils as supervisor_utils
969
970-import metrics
971-import metrics.services
972-
973 from magicicada.filesync.models import StorageUser
974 from magicicada.server.server import logger
975 from magicicada.server.testing.testcase import TestWithDatabase
976@@ -120,9 +117,6 @@
977 service_meter = mocker.mock(name='meter')
978 self.service.metrics = service_meter
979
980- revno = mocker.mock(name='revno')
981- self.patch(metrics.services, 'revno', revno)
982-
983 service_meter.meter('server_stop')
984 service_meter.decrement('services_active')
985 service_meter.meter('server_start')
986@@ -131,9 +125,6 @@
987 service_meter.timing("busy.ping", ANY)
988 mocker.count(0, None)
989
990- revno()
991- mocker.count(0, None)
992-
993 with mocker:
994 yield self.service.stopService()
995 yield self.service.startService()
996
997=== added file 'requirements-devel.txt'
998--- requirements-devel.txt 1970-01-01 00:00:00 +0000
999+++ requirements-devel.txt 2018-04-12 02:08:49 +0000
1000@@ -0,0 +1,8 @@
1001+flake8
1002+dbus-python
1003+pygobject
1004+meliae
1005+mock
1006+mocker
1007+pyinotify
1008+rst2html5
1009
1010=== added file 'requirements.txt'
1011--- requirements.txt 1970-01-01 00:00:00 +0000
1012+++ requirements.txt 2018-04-12 02:08:49 +0000
1013@@ -0,0 +1,17 @@
1014+Django<1.10
1015+bzr
1016+configglue
1017+cython
1018+pyOpenSSL
1019+protobuf
1020+psycopg2-binary
1021+# From twisted UserWarning: You do not have a working installation of the
1022+# service_identity module: 'No module named service_identity'. Please install
1023+# it from <https://pypi.python.org/pypi/service_identity> and make sure all of
1024+# its dependencies are satisfied. Without the service_identity module, Twisted
1025+# can perform only rudimentary TLS client hostname verification. Many valid
1026+# certificate/hostname mappings may be rejected.
1027+service_identity
1028+supervisor
1029+twisted
1030+https://launchpad.net/dirspec/stable-13-10/13.10/+download/dirspec-13.10.tar.gz
1031
1032=== modified file 'test'
1033--- test 2018-04-05 20:57:19 +0000
1034+++ test 2018-04-12 02:08:49 +0000
1035@@ -54,10 +54,10 @@
1036 with open(dbus_address_file) as fh:
1037 os.environ["DBUS_SESSION_BUS_ADDRESS"] = fh.read().strip()
1038
1039- # install the glib2reactor before any import of the reactor to avoid
1040+ # install the twisted reactor before any import of the reactor to avoid
1041 # using the default SelectReactor and be able to run the dbus tests
1042- from twisted.internet import glib2reactor
1043- glib2reactor.install()
1044+ from twisted.internet import gireactor
1045+ gireactor.install()
1046
1047
1048 if __name__ == "__main__":

Subscribers

People subscribed via source and target branches

to all changes: