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