##// END OF EJS Templates
py3: open files as binary or not, depending on how we want to use them...
Mads Kiilerich -
r7991:a553bc3a default
parent child Browse files
Show More
@@ -1,142 +1,142 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14
15 15 from __future__ import print_function
16 16
17 17 import errno
18 18 import os
19 19 from multiprocessing.util import Finalize
20 20
21 21 from kallithea.lib.compat import kill
22 22
23 23
24 24 class LockHeld(Exception):
25 25 pass
26 26
27 27
28 28 class DaemonLock(object):
29 29 """daemon locking
30 30 USAGE:
31 31 try:
32 32 l = DaemonLock('/path/tolockfile',desc='test lock')
33 33 main()
34 34 l.release()
35 35 except LockHeld:
36 36 sys.exit(1)
37 37 """
38 38
39 39 def __init__(self, file_, callbackfn=None,
40 40 desc='daemon lock', debug=False):
41 41 self.pidfile = file_
42 42 self.callbackfn = callbackfn
43 43 self.desc = desc
44 44 self.debug = debug
45 45 self.held = False
46 46 # run the lock automatically!
47 47 self.lock()
48 48 self._finalize = Finalize(self, DaemonLock._on_finalize,
49 49 args=(self, debug), exitpriority=10)
50 50
51 51 @staticmethod
52 52 def _on_finalize(lock, debug):
53 53 if lock.held:
54 54 if debug:
55 55 print('lock held finalizing and running lock.release()')
56 56 lock.release()
57 57
58 58 def lock(self):
59 59 """
60 60 locking function, if lock is present it
61 61 will raise LockHeld exception
62 62 """
63 63 lockname = str(os.getpid())
64 64 if self.debug:
65 65 print('running lock')
66 66 self.trylock()
67 67 self.makelock(lockname, self.pidfile)
68 68 return True
69 69
70 70 def trylock(self):
71 71 running_pid = False
72 72 if self.debug:
73 73 print('checking for already running process')
74 74 try:
75 75 with open(self.pidfile, 'r') as f:
76 76 try:
77 77 running_pid = int(f.readline())
78 78 except ValueError:
79 79 running_pid = -1
80 80
81 81 if self.debug:
82 82 print('lock file present running_pid: %s, '
83 83 'checking for execution' % (running_pid,))
84 84 # Now we check the PID from lock file matches to the current
85 85 # process PID
86 86 if running_pid:
87 87 try:
88 88 kill(running_pid, 0)
89 89 except OSError as exc:
90 90 if exc.errno in (errno.ESRCH, errno.EPERM):
91 91 print ("Lock File is there but"
92 92 " the program is not running")
93 93 print("Removing lock file for the: %s" % running_pid)
94 94 self.release()
95 95 else:
96 96 raise
97 97 else:
98 98 print("You already have an instance of the program running")
99 99 print("It is running as process %s" % running_pid)
100 100 raise LockHeld()
101 101
102 102 except IOError as e:
103 103 if e.errno != 2:
104 104 raise
105 105
106 106 def release(self):
107 107 """releases the pid by removing the pidfile
108 108 """
109 109 if self.debug:
110 110 print('trying to release the pidlock')
111 111
112 112 if self.callbackfn:
113 113 #execute callback function on release
114 114 if self.debug:
115 115 print('executing callback function %s' % self.callbackfn)
116 116 self.callbackfn()
117 117 try:
118 118 if self.debug:
119 119 print('removing pidfile %s' % self.pidfile)
120 120 os.remove(self.pidfile)
121 121 self.held = False
122 122 except OSError as e:
123 123 if self.debug:
124 124 print('removing pidfile failed %s' % e)
125 125 pass
126 126
127 127 def makelock(self, lockname, pidfile):
128 128 """
129 129 this function will make an actual lock
130 130
131 131 :param lockname: actual pid of file
132 132 :param pidfile: the file to write the pid in
133 133 """
134 134 if self.debug:
135 135 print('creating a file %s and pid: %s' % (pidfile, lockname))
136 136
137 137 dir_, file_ = os.path.split(pidfile)
138 138 if not os.path.isdir(dir_):
139 139 os.makedirs(dir_)
140 with open(self.pidfile, 'wb') as f:
140 with open(self.pidfile, 'w') as f:
141 141 f.write(lockname)
142 142 self.held = True
@@ -1,103 +1,103 b''
1 1 import datetime
2 2 import io
3 3 import os
4 4 import tarfile
5 5 import tempfile
6 6 import zipfile
7 7
8 8 import pytest
9 9
10 10 from kallithea.lib.vcs.exceptions import VCSError
11 11 from kallithea.lib.vcs.nodes import FileNode
12 12 from kallithea.tests.vcs.base import _BackendTestMixin
13 13 from kallithea.tests.vcs.conf import TESTS_TMP_PATH
14 14
15 15
16 16 class ArchivesTestCaseMixin(_BackendTestMixin):
17 17
18 18 @classmethod
19 19 def _get_commits(cls):
20 20 start_date = datetime.datetime(2010, 1, 1, 20)
21 21 for x in xrange(5):
22 22 yield {
23 23 'message': 'Commit %d' % x,
24 24 'author': 'Joe Doe <joe.doe@example.com>',
25 25 'date': start_date + datetime.timedelta(hours=12 * x),
26 26 'added': [
27 27 FileNode('%d/file_%d.txt' % (x, x),
28 28 content='Foobar %d' % x),
29 29 ],
30 30 }
31 31
32 32 def test_archive_zip(self):
33 33 path = tempfile.mkstemp(dir=TESTS_TMP_PATH, prefix='test_archive_zip-')[1]
34 34 with open(path, 'wb') as f:
35 35 self.tip.fill_archive(stream=f, kind='zip', prefix='repo')
36 36 out = zipfile.ZipFile(path)
37 37
38 38 for x in xrange(5):
39 39 node_path = '%d/file_%d.txt' % (x, x)
40 40 decompressed = out.read('repo/' + node_path)
41 41 assert decompressed == self.tip.get_node(node_path).content
42 42
43 43 def test_archive_tgz(self):
44 44 path = tempfile.mkstemp(dir=TESTS_TMP_PATH, prefix='test_archive_tgz-')[1]
45 45 with open(path, 'wb') as f:
46 46 self.tip.fill_archive(stream=f, kind='tgz', prefix='repo')
47 47 outdir = tempfile.mkdtemp(dir=TESTS_TMP_PATH, prefix='test_archive_tgz-', suffix='-outdir')
48 48
49 49 outfile = tarfile.open(path, 'r|gz')
50 50 outfile.extractall(outdir)
51 51
52 52 for x in xrange(5):
53 53 node_path = '%d/file_%d.txt' % (x, x)
54 assert open(os.path.join(outdir, 'repo/' + node_path)).read() == self.tip.get_node(node_path).content
54 assert open(os.path.join(outdir, 'repo/' + node_path), 'rb').read() == self.tip.get_node(node_path).content
55 55
56 56 def test_archive_tbz2(self):
57 57 path = tempfile.mkstemp(dir=TESTS_TMP_PATH, prefix='test_archive_tbz2-')[1]
58 58 with open(path, 'w+b') as f:
59 59 self.tip.fill_archive(stream=f, kind='tbz2', prefix='repo')
60 60 outdir = tempfile.mkdtemp(dir=TESTS_TMP_PATH, prefix='test_archive_tbz2-', suffix='-outdir')
61 61
62 62 outfile = tarfile.open(path, 'r|bz2')
63 63 outfile.extractall(outdir)
64 64
65 65 for x in xrange(5):
66 66 node_path = '%d/file_%d.txt' % (x, x)
67 assert open(os.path.join(outdir, 'repo/' + node_path)).read() == self.tip.get_node(node_path).content
67 assert open(os.path.join(outdir, 'repo/' + node_path), 'rb').read() == self.tip.get_node(node_path).content
68 68
69 69 def test_archive_default_stream(self):
70 70 tmppath = tempfile.mkstemp(dir=TESTS_TMP_PATH, prefix='test_archive_default_stream-')[1]
71 71 with open(tmppath, 'wb') as stream:
72 72 self.tip.fill_archive(stream=stream)
73 73 mystream = io.BytesIO()
74 74 self.tip.fill_archive(stream=mystream)
75 75 mystream.seek(0)
76 76 with open(tmppath, 'rb') as f:
77 77 file_content = f.read()
78 78 stringio_content = mystream.read()
79 79 # the gzip header contains a MTIME header
80 80 # because is takes a little bit of time from one fill_archive call to the next
81 81 # this part may differ so don't include that part in the comparison
82 82 assert file_content[:4] == stringio_content[:4]
83 83 assert file_content[8:] == stringio_content[8:]
84 84
85 85 def test_archive_wrong_kind(self):
86 86 with pytest.raises(VCSError):
87 87 self.tip.fill_archive(kind='wrong kind')
88 88
89 89 def test_archive_empty_prefix(self):
90 90 with pytest.raises(VCSError):
91 91 self.tip.fill_archive(prefix='')
92 92
93 93 def test_archive_prefix_with_leading_slash(self):
94 94 with pytest.raises(VCSError):
95 95 self.tip.fill_archive(prefix='/any')
96 96
97 97
98 98 class TestGitArchive(ArchivesTestCaseMixin):
99 99 backend_alias = 'git'
100 100
101 101
102 102 class TestHgArchive(ArchivesTestCaseMixin):
103 103 backend_alias = 'hg'
@@ -1,161 +1,161 b''
1 1 #!/usr/bin/env python2
2 2 # -*- coding: utf-8 -*-
3 3 import os
4 4 import platform
5 5 import sys
6 6
7 7 import setuptools
8 8 # monkey patch setuptools to use distutils owner/group functionality
9 9 from setuptools.command import sdist
10 10
11 11
12 12 if sys.version_info < (2, 6) or sys.version_info >= (3,):
13 13 raise Exception('Kallithea requires python 2.7')
14 14
15 15
16 16 here = os.path.abspath(os.path.dirname(__file__))
17 17
18 18
19 19 def _get_meta_var(name, data, callback_handler=None):
20 20 import re
21 21 matches = re.compile(r'(?:%s)\s*=\s*(.*)' % name).search(data)
22 22 if matches:
23 23 if not callable(callback_handler):
24 24 callback_handler = lambda v: v
25 25
26 26 return callback_handler(eval(matches.groups()[0]))
27 27
28 _meta = open(os.path.join(here, 'kallithea', '__init__.py'), 'rb')
28 _meta = open(os.path.join(here, 'kallithea', '__init__.py'), 'r')
29 29 _metadata = _meta.read()
30 30 _meta.close()
31 31
32 32 callback = lambda V: ('.'.join(map(str, V[:3])) + '.'.join(V[3:]))
33 33 __version__ = _get_meta_var('VERSION', _metadata, callback)
34 34 __license__ = _get_meta_var('__license__', _metadata)
35 35 __author__ = _get_meta_var('__author__', _metadata)
36 36 __url__ = _get_meta_var('__url__', _metadata)
37 37 # defines current platform
38 38 __platform__ = platform.system()
39 39
40 40 is_windows = __platform__ in ['Windows']
41 41
42 42 requirements = [
43 43 "alembic >= 0.8.0, < 1.1",
44 44 "gearbox >= 0.1.0, < 1",
45 45 "waitress >= 0.8.8, < 1.4",
46 46 "WebOb >= 1.7, < 1.9",
47 47 "backlash >= 0.1.2, < 1",
48 48 "TurboGears2 >= 2.3.10, < 2.5",
49 49 "tgext.routes >= 0.2.0, < 1",
50 50 "Beaker >= 1.7.0, < 2",
51 51 "WebHelpers2 >= 2.0, < 2.1",
52 52 "FormEncode >= 1.3.0, < 1.4",
53 53 "SQLAlchemy >= 1.1, < 1.4",
54 54 "Mako >= 0.9.0, < 1.1",
55 55 "Pygments >= 2.2.0, < 2.5",
56 56 "Whoosh >= 2.5.0, < 2.8",
57 57 "celery >= 3.1, < 4.0", # TODO: celery 4 doesn't work
58 58 "Babel >= 1.3, < 2.8",
59 59 "python-dateutil >= 1.5.0, < 2.9",
60 60 "Markdown >= 2.2.1, < 3.2",
61 61 "docutils >= 0.11, < 0.15",
62 62 "URLObject >= 2.3.4, < 2.5",
63 63 "Routes >= 2.0, < 2.5",
64 64 "dulwich >= 0.14.1, < 0.20",
65 65 "mercurial >= 5.1, < 5.3",
66 66 "decorator >= 3.3.2, < 4.5",
67 67 "Paste >= 2.0.3, < 3.1",
68 68 "bleach >= 3.0, < 3.2",
69 69 "Click >= 7.0, < 8",
70 70 "ipaddr >= 2.1.10, < 2.3",
71 71 "paginate >= 0.5, < 0.6",
72 72 "paginate_sqlalchemy >= 0.3.0, < 0.4",
73 73 ]
74 74
75 75 if not is_windows:
76 76 requirements.append("bcrypt >= 3.1.0, < 3.2")
77 77
78 78 dependency_links = [
79 79 ]
80 80
81 81 classifiers = [
82 82 'Development Status :: 4 - Beta',
83 83 'Environment :: Web Environment',
84 84 'Framework :: Pylons',
85 85 'Intended Audience :: Developers',
86 86 'License :: OSI Approved :: GNU General Public License (GPL)',
87 87 'Operating System :: OS Independent',
88 88 'Programming Language :: Python',
89 89 'Programming Language :: Python :: 2.7',
90 90 'Topic :: Software Development :: Version Control',
91 91 ]
92 92
93 93
94 94 # additional files from project that goes somewhere in the filesystem
95 95 # relative to sys.prefix
96 96 data_files = []
97 97
98 98 description = ('Kallithea is a fast and powerful management tool '
99 99 'for Mercurial and Git with a built in push/pull server, '
100 100 'full text search and code-review.')
101 101
102 102 keywords = ' '.join([
103 103 'kallithea', 'mercurial', 'git', 'code review',
104 104 'repo groups', 'ldap', 'repository management', 'hgweb replacement',
105 105 'hgwebdir', 'gitweb replacement', 'serving hgweb',
106 106 ])
107 107
108 108 # long description
109 109 README_FILE = 'README.rst'
110 110 try:
111 111 long_description = open(README_FILE).read()
112 112 except IOError as err:
113 113 sys.stderr.write(
114 114 "[WARNING] Cannot find file specified as long_description (%s)\n"
115 115 % README_FILE
116 116 )
117 117 long_description = description
118 118
119 119
120 120 sdist_org = sdist.sdist
121 121 class sdist_new(sdist_org):
122 122 def initialize_options(self):
123 123 sdist_org.initialize_options(self)
124 124 self.owner = self.group = 'root'
125 125 sdist.sdist = sdist_new
126 126
127 127 packages = setuptools.find_packages(exclude=['ez_setup'])
128 128
129 129 setuptools.setup(
130 130 name='Kallithea',
131 131 version=__version__,
132 132 description=description,
133 133 long_description=long_description,
134 134 keywords=keywords,
135 135 license=__license__,
136 136 author=__author__,
137 137 author_email='kallithea@sfconservancy.org',
138 138 dependency_links=dependency_links,
139 139 url=__url__,
140 140 install_requires=requirements,
141 141 classifiers=classifiers,
142 142 data_files=data_files,
143 143 packages=packages,
144 144 include_package_data=True,
145 145 message_extractors={'kallithea': [
146 146 ('**.py', 'python', None),
147 147 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
148 148 ('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
149 149 ('public/**', 'ignore', None)]},
150 150 zip_safe=False,
151 151 entry_points="""
152 152 [console_scripts]
153 153 kallithea-api = kallithea.bin.kallithea_api:main
154 154 kallithea-gist = kallithea.bin.kallithea_gist:main
155 155 kallithea-config = kallithea.bin.kallithea_config:main
156 156 kallithea-cli = kallithea.bin.kallithea_cli:cli
157 157
158 158 [paste.app_factory]
159 159 main = kallithea.config.middleware:make_app
160 160 """,
161 161 )
General Comments 0
You need to be logged in to leave comments. Login now