##// END OF EJS Templates
changed dulwich git interface to gitweb + subprocessio
marcink -
r2382:034e4fe1 beta
parent child Browse files
Show More
@@ -0,0 +1,181 b''
1 import os
2 import socket
3 import logging
4 import subprocess
5
6 from webob import Request, Response, exc
7
8 from rhodecode.lib import subprocessio
9
10 log = logging.getLogger(__name__)
11
12
13 class FileWrapper(object):
14
15 def __init__(self, fd, content_length):
16 self.fd = fd
17 self.content_length = content_length
18 self.remain = content_length
19
20 def read(self, size):
21 if size <= self.remain:
22 try:
23 data = self.fd.read(size)
24 except socket.error:
25 raise IOError(self)
26 self.remain -= size
27 elif self.remain:
28 data = self.fd.read(self.remain)
29 self.remain = 0
30 else:
31 data = None
32 return data
33
34 def __repr__(self):
35 return '<FileWrapper %s len: %s, read: %s>' % (
36 self.fd, self.content_length, self.content_length - self.remain
37 )
38
39
40 class GitRepository(object):
41 git_folder_signature = set(['config', 'head', 'info', 'objects', 'refs'])
42 commands = ['git-upload-pack', 'git-receive-pack']
43
44 def __init__(self, repo_name, content_path):
45 files = set([f.lower() for f in os.listdir(content_path)])
46 if not (self.git_folder_signature.intersection(files)
47 == self.git_folder_signature):
48 raise OSError('%s missing git signature' % content_path)
49 self.content_path = content_path
50 self.valid_accepts = ['application/x-%s-result' %
51 c for c in self.commands]
52 self.repo_name = repo_name
53
54 def _get_fixedpath(self, path):
55 """
56 Small fix for repo_path
57
58 :param path:
59 :type path:
60 """
61 return path.split(self.repo_name, 1)[-1].strip('/')
62
63 def inforefs(self, request, environ):
64 """
65 WSGI Response producer for HTTP GET Git Smart
66 HTTP /info/refs request.
67 """
68
69 git_command = request.GET['service']
70 if git_command not in self.commands:
71 log.debug('command %s not allowed' % git_command)
72 return exc.HTTPMethodNotAllowed()
73
74 # note to self:
75 # please, resist the urge to add '\n' to git capture and increment
76 # line count by 1.
77 # The code in Git client not only does NOT need '\n', but actually
78 # blows up if you sprinkle "flush" (0000) as "0001\n".
79 # It reads binary, per number of bytes specified.
80 # if you do add '\n' as part of data, count it.
81 smart_server_advert = '# service=%s' % git_command
82 try:
83 out = subprocessio.SubprocessIOChunker(
84 r'git %s --stateless-rpc --advertise-refs "%s"' % (
85 git_command[4:], self.content_path),
86 starting_values=[
87 str(hex(len(smart_server_advert) + 4)[2:]
88 .rjust(4, '0') + smart_server_advert + '0000')
89 ]
90 )
91 except EnvironmentError, e:
92 log.exception(e)
93 raise exc.HTTPExpectationFailed()
94 resp = Response()
95 resp.content_type = 'application/x-%s-advertisement' % str(git_command)
96 resp.app_iter = out
97 return resp
98
99 def backend(self, request, environ):
100 """
101 WSGI Response producer for HTTP POST Git Smart HTTP requests.
102 Reads commands and data from HTTP POST's body.
103 returns an iterator obj with contents of git command's
104 response to stdout
105 """
106 git_command = self._get_fixedpath(request.path_info)
107 if git_command not in self.commands:
108 log.debug('command %s not allowed' % git_command)
109 return exc.HTTPMethodNotAllowed()
110
111 if 'CONTENT_LENGTH' in environ:
112 inputstream = FileWrapper(environ['wsgi.input'],
113 request.content_length)
114 else:
115 inputstream = environ['wsgi.input']
116
117 try:
118 out = subprocessio.SubprocessIOChunker(
119 r'git %s --stateless-rpc "%s"' % (git_command[4:],
120 self.content_path),
121 inputstream=inputstream
122 )
123 except EnvironmentError, e:
124 log.exception(e)
125 raise exc.HTTPExpectationFailed()
126
127 if git_command in [u'git-receive-pack']:
128 # updating refs manually after each push.
129 # Needed for pre-1.7.0.4 git clients using regular HTTP mode.
130 subprocess.call(u'git --git-dir "%s" '
131 'update-server-info' % self.content_path,
132 shell=True)
133
134 resp = Response()
135 resp.content_type = 'application/x-%s-result' % git_command.encode('utf8')
136 resp.app_iter = out
137 return resp
138
139 def __call__(self, environ, start_response):
140 request = Request(environ)
141 _path = self._get_fixedpath(request.path_info)
142 if _path.startswith('info/refs'):
143 app = self.inforefs
144 elif [a for a in self.valid_accepts if a in request.accept]:
145 app = self.backend
146 try:
147 resp = app(request, environ)
148 except exc.HTTPException, e:
149 resp = e
150 log.exception(e)
151 except Exception, e:
152 log.exception(e)
153 resp = exc.HTTPInternalServerError()
154 return resp(environ, start_response)
155
156
157 class GitDirectory(object):
158
159 def __init__(self, repo_root, repo_name):
160 repo_location = os.path.join(repo_root, repo_name)
161 if not os.path.isdir(repo_location):
162 raise OSError(repo_location)
163
164 self.content_path = repo_location
165 self.repo_name = repo_name
166 self.repo_location = repo_location
167
168 def __call__(self, environ, start_response):
169 content_path = self.content_path
170 try:
171 app = GitRepository(self.repo_name, content_path)
172 except (AssertionError, OSError):
173 if os.path.isdir(os.path.join(content_path, '.git')):
174 app = GitRepository(os.path.join(content_path, '.git'))
175 else:
176 return exc.HTTPNotFound()(environ, start_response)
177 return app(environ, start_response)
178
179
180 def make_wsgi_app(repo_name, repo_root):
181 return GitDirectory(repo_root, repo_name)
@@ -0,0 +1,401 b''
1 '''
2 Module provides a class allowing to wrap communication over subprocess.Popen
3 input, output, error streams into a meaningfull, non-blocking, concurrent
4 stream processor exposing the output data as an iterator fitting to be a
5 return value passed by a WSGI applicaiton to a WSGI server per PEP 3333.
6
7 Copyright (c) 2011 Daniel Dotsenko <dotsa@hotmail.com>
8
9 This file is part of git_http_backend.py Project.
10
11 git_http_backend.py Project is free software: you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public License as
13 published by the Free Software Foundation, either version 2.1 of the License,
14 or (at your option) any later version.
15
16 git_http_backend.py Project is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with git_http_backend.py Project.
23 If not, see <http://www.gnu.org/licenses/>.
24 '''
25 import os
26 import subprocess
27 import threading
28 from collections import deque
29
30
31 class StreamFeeder(threading.Thread):
32 """
33 Normal writing into pipe-like is blocking once the buffer is filled.
34 This thread allows a thread to seep data from a file-like into a pipe
35 without blocking the main thread.
36 We close inpipe once the end of the source stream is reached.
37 """
38 def __init__(self, source):
39 super(StreamFeeder, self).__init__()
40 self.daemon = True
41 filelike = False
42 self.bytes = b''
43 if type(source) in (type(''), bytes, bytearray): # string-like
44 self.bytes = bytes(source)
45 else: # can be either file pointer or file-like
46 if type(source) in (int, long): # file pointer it is
47 ## converting file descriptor (int) stdin into file-like
48 try:
49 source = os.fdopen(source, 'rb', 16384)
50 except:
51 pass
52 # let's see if source is file-like by now
53 try:
54 filelike = source.read
55 except:
56 pass
57 if not filelike and not self.bytes:
58 raise TypeError("StreamFeeder's source object must be a readable file-like, a file descriptor, or a string-like.")
59 self.source = source
60 self.readiface, self.writeiface = os.pipe()
61
62 def run(self):
63 t = self.writeiface
64 if self.bytes:
65 os.write(t, self.bytes)
66 else:
67 s = self.source
68 b = s.read(4096)
69 while b:
70 os.write(t, b)
71 b = s.read(4096)
72 os.close(t)
73
74 @property
75 def output(self):
76 return self.readiface
77
78
79 class InputStreamChunker(threading.Thread):
80 def __init__(self, source, target, buffer_size, chunk_size):
81
82 super(InputStreamChunker, self).__init__()
83
84 self.daemon = True # die die die.
85
86 self.source = source
87 self.target = target
88 self.chunk_count_max = int(buffer_size / chunk_size) + 1
89 self.chunk_size = chunk_size
90
91 self.data_added = threading.Event()
92 self.data_added.clear()
93
94 self.keep_reading = threading.Event()
95 self.keep_reading.set()
96
97 self.EOF = threading.Event()
98 self.EOF.clear()
99
100 self.go = threading.Event()
101 self.go.set()
102
103 def stop(self):
104 self.go.clear()
105 self.EOF.set()
106 try:
107 # this is not proper, but is done to force the reader thread let
108 # go of the input because, if successful, .close() will send EOF
109 # down the pipe.
110 self.source.close()
111 except:
112 pass
113
114 def run(self):
115 s = self.source
116 t = self.target
117 cs = self.chunk_size
118 ccm = self.chunk_count_max
119 kr = self.keep_reading
120 da = self.data_added
121 go = self.go
122 b = s.read(cs)
123 while b and go.is_set():
124 if len(t) > ccm:
125 kr.clear()
126 kr.wait(2)
127 # # this only works on 2.7.x and up
128 # if not kr.wait(10):
129 # raise Exception("Timed out while waiting for input to be read.")
130 # instead we'll use this
131 if len(t) > ccm + 3:
132 raise IOError("Timed out while waiting for input from subprocess.")
133 t.append(b)
134 da.set()
135 b = s.read(cs)
136 self.EOF.set()
137 da.set() # for cases when done but there was no input.
138
139
140 class BufferedGenerator():
141 '''
142 Class behaves as a non-blocking, buffered pipe reader.
143 Reads chunks of data (through a thread)
144 from a blocking pipe, and attaches these to an array (Deque) of chunks.
145 Reading is halted in the thread when max chunks is internally buffered.
146 The .next() may operate in blocking or non-blocking fashion by yielding
147 '' if no data is ready
148 to be sent or by not returning until there is some data to send
149 When we get EOF from underlying source pipe we raise the marker to raise
150 StopIteration after the last chunk of data is yielded.
151 '''
152
153 def __init__(self, source, buffer_size=65536, chunk_size=4096,
154 starting_values=[], bottomless=False):
155
156 if bottomless:
157 maxlen = int(buffer_size / chunk_size)
158 else:
159 maxlen = None
160
161 self.data = deque(starting_values, maxlen)
162
163 self.worker = InputStreamChunker(source, self.data, buffer_size,
164 chunk_size)
165 if starting_values:
166 self.worker.data_added.set()
167 self.worker.start()
168
169 ####################
170 # Generator's methods
171 ####################
172
173 def __iter__(self):
174 return self
175
176 def next(self):
177 while not len(self.data) and not self.worker.EOF.is_set():
178 self.worker.data_added.clear()
179 self.worker.data_added.wait(0.2)
180 if len(self.data):
181 self.worker.keep_reading.set()
182 return bytes(self.data.popleft())
183 elif self.worker.EOF.is_set():
184 raise StopIteration
185
186 def throw(self, type, value=None, traceback=None):
187 if not self.worker.EOF.is_set():
188 raise type(value)
189
190 def start(self):
191 self.worker.start()
192
193 def stop(self):
194 self.worker.stop()
195
196 def close(self):
197 try:
198 self.worker.stop()
199 self.throw(GeneratorExit)
200 except (GeneratorExit, StopIteration):
201 pass
202
203 def __del__(self):
204 self.close()
205
206 ####################
207 # Threaded reader's infrastructure.
208 ####################
209 @property
210 def input(self):
211 return self.worker.w
212
213 @property
214 def data_added_event(self):
215 return self.worker.data_added
216
217 @property
218 def data_added(self):
219 return self.worker.data_added.is_set()
220
221 @property
222 def reading_paused(self):
223 return not self.worker.keep_reading.is_set()
224
225 @property
226 def done_reading_event(self):
227 '''
228 Done_reding does not mean that the iterator's buffer is empty.
229 Iterator might have done reading from underlying source, but the read
230 chunks might still be available for serving through .next() method.
231
232 @return An Event class instance.
233 '''
234 return self.worker.EOF
235
236 @property
237 def done_reading(self):
238 '''
239 Done_reding does not mean that the iterator's buffer is empty.
240 Iterator might have done reading from underlying source, but the read
241 chunks might still be available for serving through .next() method.
242
243 @return An Bool value.
244 '''
245 return self.worker.EOF.is_set()
246
247 @property
248 def length(self):
249 '''
250 returns int.
251
252 This is the lenght of the que of chunks, not the length of
253 the combined contents in those chunks.
254
255 __len__() cannot be meaningfully implemented because this
256 reader is just flying throuh a bottomless pit content and
257 can only know the lenght of what it already saw.
258
259 If __len__() on WSGI server per PEP 3333 returns a value,
260 the responce's length will be set to that. In order not to
261 confuse WSGI PEP3333 servers, we will not implement __len__
262 at all.
263 '''
264 return len(self.data)
265
266 def prepend(self, x):
267 self.data.appendleft(x)
268
269 def append(self, x):
270 self.data.append(x)
271
272 def extend(self, o):
273 self.data.extend(o)
274
275 def __getitem__(self, i):
276 return self.data[i]
277
278
279 class SubprocessIOChunker():
280 '''
281 Processor class wrapping handling of subprocess IO.
282
283 In a way, this is a "communicate()" replacement with a twist.
284
285 - We are multithreaded. Writing in and reading out, err are all sep threads.
286 - We support concurrent (in and out) stream processing.
287 - The output is not a stream. It's a queue of read string (bytes, not unicode)
288 chunks. The object behaves as an iterable. You can "for chunk in obj:" us.
289 - We are non-blocking in more respects than communicate()
290 (reading from subprocess out pauses when internal buffer is full, but
291 does not block the parent calling code. On the flip side, reading from
292 slow-yielding subprocess may block the iteration until data shows up. This
293 does not block the parallel inpipe reading occurring parallel thread.)
294
295 The purpose of the object is to allow us to wrap subprocess interactions into
296 and interable that can be passed to a WSGI server as the application's return
297 value. Because of stream-processing-ability, WSGI does not have to read ALL
298 of the subprocess's output and buffer it, before handing it to WSGI server for
299 HTTP response. Instead, the class initializer reads just a bit of the stream
300 to figure out if error ocurred or likely to occur and if not, just hands the
301 further iteration over subprocess output to the server for completion of HTTP
302 response.
303
304 The real or perceived subprocess error is trapped and raised as one of
305 EnvironmentError family of exceptions
306
307 Example usage:
308 # try:
309 # answer = SubprocessIOChunker(
310 # cmd,
311 # input,
312 # buffer_size = 65536,
313 # chunk_size = 4096
314 # )
315 # except (EnvironmentError) as e:
316 # print str(e)
317 # raise e
318 #
319 # return answer
320
321
322 '''
323 def __init__(self, cmd, inputstream=None, buffer_size=65536,
324 chunk_size=4096, starting_values=[]):
325 '''
326 Initializes SubprocessIOChunker
327
328 @param cmd A Subprocess.Popen style "cmd". Can be string or array of strings
329 @param inputstream (Default: None) A file-like, string, or file pointer.
330 @param buffer_size (Default: 65536) A size of total buffer per stream in bytes.
331 @param chunk_size (Default: 4096) A max size of a chunk. Actual chunk may be smaller.
332 @param starting_values (Default: []) An array of strings to put in front of output que.
333 '''
334
335 if inputstream:
336 input_streamer = StreamFeeder(inputstream)
337 input_streamer.start()
338 inputstream = input_streamer.output
339
340 _p = subprocess.Popen(cmd,
341 bufsize=-1,
342 shell=True,
343 stdin=inputstream,
344 stdout=subprocess.PIPE,
345 stderr=subprocess.PIPE
346 )
347
348 bg_out = BufferedGenerator(_p.stdout, buffer_size, chunk_size, starting_values)
349 bg_err = BufferedGenerator(_p.stderr, 16000, 1, bottomless=True)
350
351 while not bg_out.done_reading and not bg_out.reading_paused and not bg_err.length:
352 # doing this until we reach either end of file, or end of buffer.
353 bg_out.data_added_event.wait(1)
354 bg_out.data_added_event.clear()
355
356 # at this point it's still ambiguous if we are done reading or just full buffer.
357 # Either way, if error (returned by ended process, or implied based on
358 # presence of stuff in stderr output) we error out.
359 # Else, we are happy.
360 _returncode = _p.poll()
361 if _returncode or (_returncode == None and bg_err.length):
362 try:
363 _p.terminate()
364 except:
365 pass
366 bg_out.stop()
367 bg_err.stop()
368 raise EnvironmentError("Subprocess exited due to an error.\n" + "".join(bg_err))
369
370 self.process = _p
371 self.output = bg_out
372 self.error = bg_err
373
374 def __iter__(self):
375 return self
376
377 def next(self):
378 if self.process.poll():
379 raise EnvironmentError("Subprocess exited due to an error:\n" + ''.join(self.error))
380 return self.output.next()
381
382 def throw(self, type, value=None, traceback=None):
383 if self.output.length or not self.output.done_reading:
384 raise type(value)
385
386 def close(self):
387 try:
388 self.process.terminate()
389 except:
390 pass
391 try:
392 self.output.close()
393 except:
394 pass
395 try:
396 self.error.close()
397 except:
398 pass
399
400 def __del__(self):
401 self.close()
@@ -1,688 +1,690 b''
1 .. _changelog:
1 .. _changelog:
2
2
3 =========
3 =========
4 Changelog
4 Changelog
5 =========
5 =========
6
6
7 1.4.0 (**2012-XX-XX**)
7 1.4.0 (**2012-XX-XX**)
8 ----------------------
8 ----------------------
9
9
10 :status: in-progress
10 :status: in-progress
11 :branch: beta
11 :branch: beta
12
12
13 news
13 news
14 ++++
14 ++++
15
15
16 - new codereview system
16 - new codereview system
17 - email map, allowing users to have multiple email addresses mapped into
17 - email map, allowing users to have multiple email addresses mapped into
18 their accounts
18 their accounts
19 - changed setup-app into setup-rhodecode and added default options to it.
19 - changed setup-app into setup-rhodecode and added default options to it.
20 - new git repos are created as bare now by default
20 - new git repos are created as bare now by default
21 - #464 added links to groups in permission box
21 - #464 added links to groups in permission box
22 - #465 mentions autocomplete inside comments boxes
22 - #465 mentions autocomplete inside comments boxes
23 - #469 added --update-only option to whoosh to re-index only given list
23 - #469 added --update-only option to whoosh to re-index only given list
24 of repos in index
24 of repos in index
25 - rhodecode-api CLI client
25 - rhodecode-api CLI client
26 - new git http protocol replaced buggy dulwich implementation.
27 Now based on pygrack & gitweb
26
28
27 fixes
29 fixes
28 +++++
30 +++++
29
31
30 - improved translations
32 - improved translations
31 - fixes issue #455 Creating an archive generates an exception on Windows
33 - fixes issue #455 Creating an archive generates an exception on Windows
32 - fixes #448 Download ZIP archive keeps file in /tmp open and results
34 - fixes #448 Download ZIP archive keeps file in /tmp open and results
33 in out of disk space
35 in out of disk space
34 - fixes issue #454 Search results under Windows include proceeding
36 - fixes issue #454 Search results under Windows include proceeding
35 backslash
37 backslash
36 - fixed issue #450. Rhodecode no longer will crash when bad revision is
38 - fixed issue #450. Rhodecode no longer will crash when bad revision is
37 present in journal data.
39 present in journal data.
38 - fix for issue #417, git execution was broken on windows for certain
40 - fix for issue #417, git execution was broken on windows for certain
39 commands.
41 commands.
40 - fixed #413. Don't disable .git directory for bare repos on deleting
42 - fixed #413. Don't disable .git directory for bare repos on deleting
41 - fixed issue #459. Changed the way of obtaining logger in reindex task.
43 - fixed issue #459. Changed the way of obtaining logger in reindex task.
42
44
43 1.3.6 (**2012-05-17**)
45 1.3.6 (**2012-05-17**)
44 ----------------------
46 ----------------------
45
47
46 news
48 news
47 ++++
49 ++++
48
50
49 - chinese traditional translation
51 - chinese traditional translation
50 - changed setup-app into setup-rhodecode and added arguments for auto-setup
52 - changed setup-app into setup-rhodecode and added arguments for auto-setup
51 mode that doesn't need user interaction
53 mode that doesn't need user interaction
52
54
53 fixes
55 fixes
54 +++++
56 +++++
55
57
56 - fixed no scm found warning
58 - fixed no scm found warning
57 - fixed __future__ import error on rcextensions
59 - fixed __future__ import error on rcextensions
58 - made simplejson required lib for speedup on JSON encoding
60 - made simplejson required lib for speedup on JSON encoding
59 - fixes #449 bad regex could get more than revisions from parsing history
61 - fixes #449 bad regex could get more than revisions from parsing history
60 - don't clear DB session when CELERY_EAGER is turned ON
62 - don't clear DB session when CELERY_EAGER is turned ON
61
63
62 1.3.5 (**2012-05-10**)
64 1.3.5 (**2012-05-10**)
63 ----------------------
65 ----------------------
64
66
65 news
67 news
66 ++++
68 ++++
67
69
68 - use ext_json for json module
70 - use ext_json for json module
69 - unified annotation view with file source view
71 - unified annotation view with file source view
70 - notification improvements, better inbox + css
72 - notification improvements, better inbox + css
71 - #419 don't strip passwords for login forms, make rhodecode
73 - #419 don't strip passwords for login forms, make rhodecode
72 more compatible with LDAP servers
74 more compatible with LDAP servers
73 - Added HTTP_X_FORWARDED_FOR as another method of extracting
75 - Added HTTP_X_FORWARDED_FOR as another method of extracting
74 IP for pull/push logs. - moved all to base controller
76 IP for pull/push logs. - moved all to base controller
75 - #415: Adding comment to changeset causes reload.
77 - #415: Adding comment to changeset causes reload.
76 Comments are now added via ajax and doesn't reload the page
78 Comments are now added via ajax and doesn't reload the page
77 - #374 LDAP config is discarded when LDAP can't be activated
79 - #374 LDAP config is discarded when LDAP can't be activated
78 - limited push/pull operations are now logged for git in the journal
80 - limited push/pull operations are now logged for git in the journal
79 - bumped mercurial to 2.2.X series
81 - bumped mercurial to 2.2.X series
80 - added support for displaying submodules in file-browser
82 - added support for displaying submodules in file-browser
81 - #421 added bookmarks in changelog view
83 - #421 added bookmarks in changelog view
82
84
83 fixes
85 fixes
84 +++++
86 +++++
85
87
86 - fixed dev-version marker for stable when served from source codes
88 - fixed dev-version marker for stable when served from source codes
87 - fixed missing permission checks on show forks page
89 - fixed missing permission checks on show forks page
88 - #418 cast to unicode fixes in notification objects
90 - #418 cast to unicode fixes in notification objects
89 - #426 fixed mention extracting regex
91 - #426 fixed mention extracting regex
90 - fixed remote-pulling for git remotes remopositories
92 - fixed remote-pulling for git remotes remopositories
91 - fixed #434: Error when accessing files or changesets of a git repository
93 - fixed #434: Error when accessing files or changesets of a git repository
92 with submodules
94 with submodules
93 - fixed issue with empty APIKEYS for users after registration ref. #438
95 - fixed issue with empty APIKEYS for users after registration ref. #438
94 - fixed issue with getting README files from git repositories
96 - fixed issue with getting README files from git repositories
95
97
96 1.3.4 (**2012-03-28**)
98 1.3.4 (**2012-03-28**)
97 ----------------------
99 ----------------------
98
100
99 news
101 news
100 ++++
102 ++++
101
103
102 - Whoosh logging is now controlled by the .ini files logging setup
104 - Whoosh logging is now controlled by the .ini files logging setup
103 - added clone-url into edit form on /settings page
105 - added clone-url into edit form on /settings page
104 - added help text into repo add/edit forms
106 - added help text into repo add/edit forms
105 - created rcextensions module with additional mappings (ref #322) and
107 - created rcextensions module with additional mappings (ref #322) and
106 post push/pull/create repo hooks callbacks
108 post push/pull/create repo hooks callbacks
107 - implemented #377 Users view for his own permissions on account page
109 - implemented #377 Users view for his own permissions on account page
108 - #399 added inheritance of permissions for users group on repos groups
110 - #399 added inheritance of permissions for users group on repos groups
109 - #401 repository group is automatically pre-selected when adding repos
111 - #401 repository group is automatically pre-selected when adding repos
110 inside a repository group
112 inside a repository group
111 - added alternative HTTP 403 response when client failed to authenticate. Helps
113 - added alternative HTTP 403 response when client failed to authenticate. Helps
112 solving issues with Mercurial and LDAP
114 solving issues with Mercurial and LDAP
113 - #402 removed group prefix from repository name when listing repositories
115 - #402 removed group prefix from repository name when listing repositories
114 inside a group
116 inside a group
115 - added gravatars into permission view and permissions autocomplete
117 - added gravatars into permission view and permissions autocomplete
116 - #347 when running multiple RhodeCode instances, properly invalidates cache
118 - #347 when running multiple RhodeCode instances, properly invalidates cache
117 for all registered servers
119 for all registered servers
118
120
119 fixes
121 fixes
120 +++++
122 +++++
121
123
122 - fixed #390 cache invalidation problems on repos inside group
124 - fixed #390 cache invalidation problems on repos inside group
123 - fixed #385 clone by ID url was loosing proxy prefix in URL
125 - fixed #385 clone by ID url was loosing proxy prefix in URL
124 - fixed some unicode problems with waitress
126 - fixed some unicode problems with waitress
125 - fixed issue with escaping < and > in changeset commits
127 - fixed issue with escaping < and > in changeset commits
126 - fixed error occurring during recursive group creation in API
128 - fixed error occurring during recursive group creation in API
127 create_repo function
129 create_repo function
128 - fixed #393 py2.5 fixes for routes url generator
130 - fixed #393 py2.5 fixes for routes url generator
129 - fixed #397 Private repository groups shows up before login
131 - fixed #397 Private repository groups shows up before login
130 - fixed #396 fixed problems with revoking users in nested groups
132 - fixed #396 fixed problems with revoking users in nested groups
131 - fixed mysql unicode issues + specified InnoDB as default engine with
133 - fixed mysql unicode issues + specified InnoDB as default engine with
132 utf8 charset
134 utf8 charset
133 - #406 trim long branch/tag names in changelog to not break UI
135 - #406 trim long branch/tag names in changelog to not break UI
134
136
135 1.3.3 (**2012-03-02**)
137 1.3.3 (**2012-03-02**)
136 ----------------------
138 ----------------------
137
139
138 news
140 news
139 ++++
141 ++++
140
142
141
143
142 fixes
144 fixes
143 +++++
145 +++++
144
146
145 - fixed some python2.5 compatibility issues
147 - fixed some python2.5 compatibility issues
146 - fixed issues with removed repos was accidentally added as groups, after
148 - fixed issues with removed repos was accidentally added as groups, after
147 full rescan of paths
149 full rescan of paths
148 - fixes #376 Cannot edit user (using container auth)
150 - fixes #376 Cannot edit user (using container auth)
149 - fixes #378 Invalid image urls on changeset screen with proxy-prefix
151 - fixes #378 Invalid image urls on changeset screen with proxy-prefix
150 configuration
152 configuration
151 - fixed initial sorting of repos inside repo group
153 - fixed initial sorting of repos inside repo group
152 - fixes issue when user tried to resubmit same permission into user/user_groups
154 - fixes issue when user tried to resubmit same permission into user/user_groups
153 - bumped beaker version that fixes #375 leap error bug
155 - bumped beaker version that fixes #375 leap error bug
154 - fixed raw_changeset for git. It was generated with hg patch headers
156 - fixed raw_changeset for git. It was generated with hg patch headers
155 - fixed vcs issue with last_changeset for filenodes
157 - fixed vcs issue with last_changeset for filenodes
156 - fixed missing commit after hook delete
158 - fixed missing commit after hook delete
157 - fixed #372 issues with git operation detection that caused a security issue
159 - fixed #372 issues with git operation detection that caused a security issue
158 for git repos
160 for git repos
159
161
160 1.3.2 (**2012-02-28**)
162 1.3.2 (**2012-02-28**)
161 ----------------------
163 ----------------------
162
164
163 news
165 news
164 ++++
166 ++++
165
167
166
168
167 fixes
169 fixes
168 +++++
170 +++++
169
171
170 - fixed git protocol issues with repos-groups
172 - fixed git protocol issues with repos-groups
171 - fixed git remote repos validator that prevented from cloning remote git repos
173 - fixed git remote repos validator that prevented from cloning remote git repos
172 - fixes #370 ending slashes fixes for repo and groups
174 - fixes #370 ending slashes fixes for repo and groups
173 - fixes #368 improved git-protocol detection to handle other clients
175 - fixes #368 improved git-protocol detection to handle other clients
174 - fixes #366 When Setting Repository Group To Blank Repo Group Wont Be
176 - fixes #366 When Setting Repository Group To Blank Repo Group Wont Be
175 Moved To Root
177 Moved To Root
176 - fixes #371 fixed issues with beaker/sqlalchemy and non-ascii cache keys
178 - fixes #371 fixed issues with beaker/sqlalchemy and non-ascii cache keys
177 - fixed #373 missing cascade drop on user_group_to_perm table
179 - fixed #373 missing cascade drop on user_group_to_perm table
178
180
179 1.3.1 (**2012-02-27**)
181 1.3.1 (**2012-02-27**)
180 ----------------------
182 ----------------------
181
183
182 news
184 news
183 ++++
185 ++++
184
186
185
187
186 fixes
188 fixes
187 +++++
189 +++++
188
190
189 - redirection loop occurs when remember-me wasn't checked during login
191 - redirection loop occurs when remember-me wasn't checked during login
190 - fixes issues with git blob history generation
192 - fixes issues with git blob history generation
191 - don't fetch branch for git in file history dropdown. Causes unneeded slowness
193 - don't fetch branch for git in file history dropdown. Causes unneeded slowness
192
194
193 1.3.0 (**2012-02-26**)
195 1.3.0 (**2012-02-26**)
194 ----------------------
196 ----------------------
195
197
196 news
198 news
197 ++++
199 ++++
198
200
199 - code review, inspired by github code-comments
201 - code review, inspired by github code-comments
200 - #215 rst and markdown README files support
202 - #215 rst and markdown README files support
201 - #252 Container-based and proxy pass-through authentication support
203 - #252 Container-based and proxy pass-through authentication support
202 - #44 branch browser. Filtering of changelog by branches
204 - #44 branch browser. Filtering of changelog by branches
203 - mercurial bookmarks support
205 - mercurial bookmarks support
204 - new hover top menu, optimized to add maximum size for important views
206 - new hover top menu, optimized to add maximum size for important views
205 - configurable clone url template with possibility to specify protocol like
207 - configurable clone url template with possibility to specify protocol like
206 ssh:// or http:// and also manually alter other parts of clone_url.
208 ssh:// or http:// and also manually alter other parts of clone_url.
207 - enabled largefiles extension by default
209 - enabled largefiles extension by default
208 - optimized summary file pages and saved a lot of unused space in them
210 - optimized summary file pages and saved a lot of unused space in them
209 - #239 option to manually mark repository as fork
211 - #239 option to manually mark repository as fork
210 - #320 mapping of commit authors to RhodeCode users
212 - #320 mapping of commit authors to RhodeCode users
211 - #304 hashes are displayed using monospace font
213 - #304 hashes are displayed using monospace font
212 - diff configuration, toggle white lines and context lines
214 - diff configuration, toggle white lines and context lines
213 - #307 configurable diffs, whitespace toggle, increasing context lines
215 - #307 configurable diffs, whitespace toggle, increasing context lines
214 - sorting on branches, tags and bookmarks using YUI datatable
216 - sorting on branches, tags and bookmarks using YUI datatable
215 - improved file filter on files page
217 - improved file filter on files page
216 - implements #330 api method for listing nodes ar particular revision
218 - implements #330 api method for listing nodes ar particular revision
217 - #73 added linking issues in commit messages to chosen issue tracker url
219 - #73 added linking issues in commit messages to chosen issue tracker url
218 based on user defined regular expression
220 based on user defined regular expression
219 - added linking of changesets in commit messages
221 - added linking of changesets in commit messages
220 - new compact changelog with expandable commit messages
222 - new compact changelog with expandable commit messages
221 - firstname and lastname are optional in user creation
223 - firstname and lastname are optional in user creation
222 - #348 added post-create repository hook
224 - #348 added post-create repository hook
223 - #212 global encoding settings is now configurable from .ini files
225 - #212 global encoding settings is now configurable from .ini files
224 - #227 added repository groups permissions
226 - #227 added repository groups permissions
225 - markdown gets codehilite extensions
227 - markdown gets codehilite extensions
226 - new API methods, delete_repositories, grante/revoke permissions for groups
228 - new API methods, delete_repositories, grante/revoke permissions for groups
227 and repos
229 and repos
228
230
229
231
230 fixes
232 fixes
231 +++++
233 +++++
232
234
233 - rewrote dbsession management for atomic operations, and better error handling
235 - rewrote dbsession management for atomic operations, and better error handling
234 - fixed sorting of repo tables
236 - fixed sorting of repo tables
235 - #326 escape of special html entities in diffs
237 - #326 escape of special html entities in diffs
236 - normalized user_name => username in api attributes
238 - normalized user_name => username in api attributes
237 - fixes #298 ldap created users with mixed case emails created conflicts
239 - fixes #298 ldap created users with mixed case emails created conflicts
238 on saving a form
240 on saving a form
239 - fixes issue when owner of a repo couldn't revoke permissions for users
241 - fixes issue when owner of a repo couldn't revoke permissions for users
240 and groups
242 and groups
241 - fixes #271 rare JSON serialization problem with statistics
243 - fixes #271 rare JSON serialization problem with statistics
242 - fixes #337 missing validation check for conflicting names of a group with a
244 - fixes #337 missing validation check for conflicting names of a group with a
243 repositories group
245 repositories group
244 - #340 fixed session problem for mysql and celery tasks
246 - #340 fixed session problem for mysql and celery tasks
245 - fixed #331 RhodeCode mangles repository names if the a repository group
247 - fixed #331 RhodeCode mangles repository names if the a repository group
246 contains the "full path" to the repositories
248 contains the "full path" to the repositories
247 - #355 RhodeCode doesn't store encrypted LDAP passwords
249 - #355 RhodeCode doesn't store encrypted LDAP passwords
248
250
249 1.2.5 (**2012-01-28**)
251 1.2.5 (**2012-01-28**)
250 ----------------------
252 ----------------------
251
253
252 news
254 news
253 ++++
255 ++++
254
256
255 fixes
257 fixes
256 +++++
258 +++++
257
259
258 - #340 Celery complains about MySQL server gone away, added session cleanup
260 - #340 Celery complains about MySQL server gone away, added session cleanup
259 for celery tasks
261 for celery tasks
260 - #341 "scanning for repositories in None" log message during Rescan was missing
262 - #341 "scanning for repositories in None" log message during Rescan was missing
261 a parameter
263 a parameter
262 - fixed creating archives with subrepos. Some hooks were triggered during that
264 - fixed creating archives with subrepos. Some hooks were triggered during that
263 operation leading to crash.
265 operation leading to crash.
264 - fixed missing email in account page.
266 - fixed missing email in account page.
265 - Reverted Mercurial to 2.0.1 for windows due to bug in Mercurial that makes
267 - Reverted Mercurial to 2.0.1 for windows due to bug in Mercurial that makes
266 forking on windows impossible
268 forking on windows impossible
267
269
268 1.2.4 (**2012-01-19**)
270 1.2.4 (**2012-01-19**)
269 ----------------------
271 ----------------------
270
272
271 news
273 news
272 ++++
274 ++++
273
275
274 - RhodeCode is bundled with mercurial series 2.0.X by default, with
276 - RhodeCode is bundled with mercurial series 2.0.X by default, with
275 full support to largefiles extension. Enabled by default in new installations
277 full support to largefiles extension. Enabled by default in new installations
276 - #329 Ability to Add/Remove Groups to/from a Repository via AP
278 - #329 Ability to Add/Remove Groups to/from a Repository via AP
277 - added requires.txt file with requirements
279 - added requires.txt file with requirements
278
280
279 fixes
281 fixes
280 +++++
282 +++++
281
283
282 - fixes db session issues with celery when emailing admins
284 - fixes db session issues with celery when emailing admins
283 - #331 RhodeCode mangles repository names if the a repository group
285 - #331 RhodeCode mangles repository names if the a repository group
284 contains the "full path" to the repositories
286 contains the "full path" to the repositories
285 - #298 Conflicting e-mail addresses for LDAP and RhodeCode users
287 - #298 Conflicting e-mail addresses for LDAP and RhodeCode users
286 - DB session cleanup after hg protocol operations, fixes issues with
288 - DB session cleanup after hg protocol operations, fixes issues with
287 `mysql has gone away` errors
289 `mysql has gone away` errors
288 - #333 doc fixes for get_repo api function
290 - #333 doc fixes for get_repo api function
289 - #271 rare JSON serialization problem with statistics enabled
291 - #271 rare JSON serialization problem with statistics enabled
290 - #337 Fixes issues with validation of repository name conflicting with
292 - #337 Fixes issues with validation of repository name conflicting with
291 a group name. A proper message is now displayed.
293 a group name. A proper message is now displayed.
292 - #292 made ldap_dn in user edit readonly, to get rid of confusion that field
294 - #292 made ldap_dn in user edit readonly, to get rid of confusion that field
293 doesn't work
295 doesn't work
294 - #316 fixes issues with web description in hgrc files
296 - #316 fixes issues with web description in hgrc files
295
297
296 1.2.3 (**2011-11-02**)
298 1.2.3 (**2011-11-02**)
297 ----------------------
299 ----------------------
298
300
299 news
301 news
300 ++++
302 ++++
301
303
302 - added option to manage repos group for non admin users
304 - added option to manage repos group for non admin users
303 - added following API methods for get_users, create_user, get_users_groups,
305 - added following API methods for get_users, create_user, get_users_groups,
304 get_users_group, create_users_group, add_user_to_users_groups, get_repos,
306 get_users_group, create_users_group, add_user_to_users_groups, get_repos,
305 get_repo, create_repo, add_user_to_repo
307 get_repo, create_repo, add_user_to_repo
306 - implements #237 added password confirmation for my account
308 - implements #237 added password confirmation for my account
307 and admin edit user.
309 and admin edit user.
308 - implements #291 email notification for global events are now sent to all
310 - implements #291 email notification for global events are now sent to all
309 administrator users, and global config email.
311 administrator users, and global config email.
310
312
311 fixes
313 fixes
312 +++++
314 +++++
313
315
314 - added option for passing auth method for smtp mailer
316 - added option for passing auth method for smtp mailer
315 - #276 issue with adding a single user with id>10 to usergroups
317 - #276 issue with adding a single user with id>10 to usergroups
316 - #277 fixes windows LDAP settings in which missing values breaks the ldap auth
318 - #277 fixes windows LDAP settings in which missing values breaks the ldap auth
317 - #288 fixes managing of repos in a group for non admin user
319 - #288 fixes managing of repos in a group for non admin user
318
320
319 1.2.2 (**2011-10-17**)
321 1.2.2 (**2011-10-17**)
320 ----------------------
322 ----------------------
321
323
322 news
324 news
323 ++++
325 ++++
324
326
325 - #226 repo groups are available by path instead of numerical id
327 - #226 repo groups are available by path instead of numerical id
326
328
327 fixes
329 fixes
328 +++++
330 +++++
329
331
330 - #259 Groups with the same name but with different parent group
332 - #259 Groups with the same name but with different parent group
331 - #260 Put repo in group, then move group to another group -> repo becomes unavailable
333 - #260 Put repo in group, then move group to another group -> repo becomes unavailable
332 - #258 RhodeCode 1.2 assumes egg folder is writable (lockfiles problems)
334 - #258 RhodeCode 1.2 assumes egg folder is writable (lockfiles problems)
333 - #265 ldap save fails sometimes on converting attributes to booleans,
335 - #265 ldap save fails sometimes on converting attributes to booleans,
334 added getter and setter into model that will prevent from this on db model level
336 added getter and setter into model that will prevent from this on db model level
335 - fixed problems with timestamps issues #251 and #213
337 - fixed problems with timestamps issues #251 and #213
336 - fixes #266 RhodeCode allows to create repo with the same name and in
338 - fixes #266 RhodeCode allows to create repo with the same name and in
337 the same parent as group
339 the same parent as group
338 - fixes #245 Rescan of the repositories on Windows
340 - fixes #245 Rescan of the repositories on Windows
339 - fixes #248 cannot edit repos inside a group on windows
341 - fixes #248 cannot edit repos inside a group on windows
340 - fixes #219 forking problems on windows
342 - fixes #219 forking problems on windows
341
343
342 1.2.1 (**2011-10-08**)
344 1.2.1 (**2011-10-08**)
343 ----------------------
345 ----------------------
344
346
345 news
347 news
346 ++++
348 ++++
347
349
348
350
349 fixes
351 fixes
350 +++++
352 +++++
351
353
352 - fixed problems with basic auth and push problems
354 - fixed problems with basic auth and push problems
353 - gui fixes
355 - gui fixes
354 - fixed logger
356 - fixed logger
355
357
356 1.2.0 (**2011-10-07**)
358 1.2.0 (**2011-10-07**)
357 ----------------------
359 ----------------------
358
360
359 news
361 news
360 ++++
362 ++++
361
363
362 - implemented #47 repository groups
364 - implemented #47 repository groups
363 - implemented #89 Can setup google analytics code from settings menu
365 - implemented #89 Can setup google analytics code from settings menu
364 - implemented #91 added nicer looking archive urls with more download options
366 - implemented #91 added nicer looking archive urls with more download options
365 like tags, branches
367 like tags, branches
366 - implemented #44 into file browsing, and added follow branch option
368 - implemented #44 into file browsing, and added follow branch option
367 - implemented #84 downloads can be enabled/disabled for each repository
369 - implemented #84 downloads can be enabled/disabled for each repository
368 - anonymous repository can be cloned without having to pass default:default
370 - anonymous repository can be cloned without having to pass default:default
369 into clone url
371 into clone url
370 - fixed #90 whoosh indexer can index chooses repositories passed in command
372 - fixed #90 whoosh indexer can index chooses repositories passed in command
371 line
373 line
372 - extended journal with day aggregates and paging
374 - extended journal with day aggregates and paging
373 - implemented #107 source code lines highlight ranges
375 - implemented #107 source code lines highlight ranges
374 - implemented #93 customizable changelog on combined revision ranges -
376 - implemented #93 customizable changelog on combined revision ranges -
375 equivalent of githubs compare view
377 equivalent of githubs compare view
376 - implemented #108 extended and more powerful LDAP configuration
378 - implemented #108 extended and more powerful LDAP configuration
377 - implemented #56 users groups
379 - implemented #56 users groups
378 - major code rewrites optimized codes for speed and memory usage
380 - major code rewrites optimized codes for speed and memory usage
379 - raw and diff downloads are now in git format
381 - raw and diff downloads are now in git format
380 - setup command checks for write access to given path
382 - setup command checks for write access to given path
381 - fixed many issues with international characters and unicode. It uses utf8
383 - fixed many issues with international characters and unicode. It uses utf8
382 decode with replace to provide less errors even with non utf8 encoded strings
384 decode with replace to provide less errors even with non utf8 encoded strings
383 - #125 added API KEY access to feeds
385 - #125 added API KEY access to feeds
384 - #109 Repository can be created from external Mercurial link (aka. remote
386 - #109 Repository can be created from external Mercurial link (aka. remote
385 repository, and manually updated (via pull) from admin panel
387 repository, and manually updated (via pull) from admin panel
386 - beta git support - push/pull server + basic view for git repos
388 - beta git support - push/pull server + basic view for git repos
387 - added followers page and forks page
389 - added followers page and forks page
388 - server side file creation (with binary file upload interface)
390 - server side file creation (with binary file upload interface)
389 and edition with commits powered by codemirror
391 and edition with commits powered by codemirror
390 - #111 file browser file finder, quick lookup files on whole file tree
392 - #111 file browser file finder, quick lookup files on whole file tree
391 - added quick login sliding menu into main page
393 - added quick login sliding menu into main page
392 - changelog uses lazy loading of affected files details, in some scenarios
394 - changelog uses lazy loading of affected files details, in some scenarios
393 this can improve speed of changelog page dramatically especially for
395 this can improve speed of changelog page dramatically especially for
394 larger repositories.
396 larger repositories.
395 - implements #214 added support for downloading subrepos in download menu.
397 - implements #214 added support for downloading subrepos in download menu.
396 - Added basic API for direct operations on rhodecode via JSON
398 - Added basic API for direct operations on rhodecode via JSON
397 - Implemented advanced hook management
399 - Implemented advanced hook management
398
400
399 fixes
401 fixes
400 +++++
402 +++++
401
403
402 - fixed file browser bug, when switching into given form revision the url was
404 - fixed file browser bug, when switching into given form revision the url was
403 not changing
405 not changing
404 - fixed propagation to error controller on simplehg and simplegit middlewares
406 - fixed propagation to error controller on simplehg and simplegit middlewares
405 - fixed error when trying to make a download on empty repository
407 - fixed error when trying to make a download on empty repository
406 - fixed problem with '[' chars in commit messages in journal
408 - fixed problem with '[' chars in commit messages in journal
407 - fixed #99 Unicode errors, on file node paths with non utf-8 characters
409 - fixed #99 Unicode errors, on file node paths with non utf-8 characters
408 - journal fork fixes
410 - journal fork fixes
409 - removed issue with space inside renamed repository after deletion
411 - removed issue with space inside renamed repository after deletion
410 - fixed strange issue on formencode imports
412 - fixed strange issue on formencode imports
411 - fixed #126 Deleting repository on Windows, rename used incompatible chars.
413 - fixed #126 Deleting repository on Windows, rename used incompatible chars.
412 - #150 fixes for errors on repositories mapped in db but corrupted in
414 - #150 fixes for errors on repositories mapped in db but corrupted in
413 filesystem
415 filesystem
414 - fixed problem with ascendant characters in realm #181
416 - fixed problem with ascendant characters in realm #181
415 - fixed problem with sqlite file based database connection pool
417 - fixed problem with sqlite file based database connection pool
416 - whoosh indexer and code stats share the same dynamic extensions map
418 - whoosh indexer and code stats share the same dynamic extensions map
417 - fixes #188 - relationship delete of repo_to_perm entry on user removal
419 - fixes #188 - relationship delete of repo_to_perm entry on user removal
418 - fixes issue #189 Trending source files shows "show more" when no more exist
420 - fixes issue #189 Trending source files shows "show more" when no more exist
419 - fixes issue #197 Relative paths for pidlocks
421 - fixes issue #197 Relative paths for pidlocks
420 - fixes issue #198 password will require only 3 chars now for login form
422 - fixes issue #198 password will require only 3 chars now for login form
421 - fixes issue #199 wrong redirection for non admin users after creating a repository
423 - fixes issue #199 wrong redirection for non admin users after creating a repository
422 - fixes issues #202, bad db constraint made impossible to attach same group
424 - fixes issues #202, bad db constraint made impossible to attach same group
423 more than one time. Affects only mysql/postgres
425 more than one time. Affects only mysql/postgres
424 - fixes #218 os.kill patch for windows was missing sig param
426 - fixes #218 os.kill patch for windows was missing sig param
425 - improved rendering of dag (they are not trimmed anymore when number of
427 - improved rendering of dag (they are not trimmed anymore when number of
426 heads exceeds 5)
428 heads exceeds 5)
427
429
428 1.1.8 (**2011-04-12**)
430 1.1.8 (**2011-04-12**)
429 ----------------------
431 ----------------------
430
432
431 news
433 news
432 ++++
434 ++++
433
435
434 - improved windows support
436 - improved windows support
435
437
436 fixes
438 fixes
437 +++++
439 +++++
438
440
439 - fixed #140 freeze of python dateutil library, since new version is python2.x
441 - fixed #140 freeze of python dateutil library, since new version is python2.x
440 incompatible
442 incompatible
441 - setup-app will check for write permission in given path
443 - setup-app will check for write permission in given path
442 - cleaned up license info issue #149
444 - cleaned up license info issue #149
443 - fixes for issues #137,#116 and problems with unicode and accented characters.
445 - fixes for issues #137,#116 and problems with unicode and accented characters.
444 - fixes crashes on gravatar, when passed in email as unicode
446 - fixes crashes on gravatar, when passed in email as unicode
445 - fixed tooltip flickering problems
447 - fixed tooltip flickering problems
446 - fixed came_from redirection on windows
448 - fixed came_from redirection on windows
447 - fixed logging modules, and sql formatters
449 - fixed logging modules, and sql formatters
448 - windows fixes for os.kill issue #133
450 - windows fixes for os.kill issue #133
449 - fixes path splitting for windows issues #148
451 - fixes path splitting for windows issues #148
450 - fixed issue #143 wrong import on migration to 1.1.X
452 - fixed issue #143 wrong import on migration to 1.1.X
451 - fixed problems with displaying binary files, thanks to Thomas Waldmann
453 - fixed problems with displaying binary files, thanks to Thomas Waldmann
452 - removed name from archive files since it's breaking ui for long repo names
454 - removed name from archive files since it's breaking ui for long repo names
453 - fixed issue with archive headers sent to browser, thanks to Thomas Waldmann
455 - fixed issue with archive headers sent to browser, thanks to Thomas Waldmann
454 - fixed compatibility for 1024px displays, and larger dpi settings, thanks to
456 - fixed compatibility for 1024px displays, and larger dpi settings, thanks to
455 Thomas Waldmann
457 Thomas Waldmann
456 - fixed issue #166 summary pager was skipping 10 revisions on second page
458 - fixed issue #166 summary pager was skipping 10 revisions on second page
457
459
458
460
459 1.1.7 (**2011-03-23**)
461 1.1.7 (**2011-03-23**)
460 ----------------------
462 ----------------------
461
463
462 news
464 news
463 ++++
465 ++++
464
466
465 fixes
467 fixes
466 +++++
468 +++++
467
469
468 - fixed (again) #136 installation support for FreeBSD
470 - fixed (again) #136 installation support for FreeBSD
469
471
470
472
471 1.1.6 (**2011-03-21**)
473 1.1.6 (**2011-03-21**)
472 ----------------------
474 ----------------------
473
475
474 news
476 news
475 ++++
477 ++++
476
478
477 fixes
479 fixes
478 +++++
480 +++++
479
481
480 - fixed #136 installation support for FreeBSD
482 - fixed #136 installation support for FreeBSD
481 - RhodeCode will check for python version during installation
483 - RhodeCode will check for python version during installation
482
484
483 1.1.5 (**2011-03-17**)
485 1.1.5 (**2011-03-17**)
484 ----------------------
486 ----------------------
485
487
486 news
488 news
487 ++++
489 ++++
488
490
489 - basic windows support, by exchanging pybcrypt into sha256 for windows only
491 - basic windows support, by exchanging pybcrypt into sha256 for windows only
490 highly inspired by idea of mantis406
492 highly inspired by idea of mantis406
491
493
492 fixes
494 fixes
493 +++++
495 +++++
494
496
495 - fixed sorting by author in main page
497 - fixed sorting by author in main page
496 - fixed crashes with diffs on binary files
498 - fixed crashes with diffs on binary files
497 - fixed #131 problem with boolean values for LDAP
499 - fixed #131 problem with boolean values for LDAP
498 - fixed #122 mysql problems thanks to striker69
500 - fixed #122 mysql problems thanks to striker69
499 - fixed problem with errors on calling raw/raw_files/annotate functions
501 - fixed problem with errors on calling raw/raw_files/annotate functions
500 with unknown revisions
502 with unknown revisions
501 - fixed returned rawfiles attachment names with international character
503 - fixed returned rawfiles attachment names with international character
502 - cleaned out docs, big thanks to Jason Harris
504 - cleaned out docs, big thanks to Jason Harris
503
505
504 1.1.4 (**2011-02-19**)
506 1.1.4 (**2011-02-19**)
505 ----------------------
507 ----------------------
506
508
507 news
509 news
508 ++++
510 ++++
509
511
510 fixes
512 fixes
511 +++++
513 +++++
512
514
513 - fixed formencode import problem on settings page, that caused server crash
515 - fixed formencode import problem on settings page, that caused server crash
514 when that page was accessed as first after server start
516 when that page was accessed as first after server start
515 - journal fixes
517 - journal fixes
516 - fixed option to access repository just by entering http://server/<repo_name>
518 - fixed option to access repository just by entering http://server/<repo_name>
517
519
518 1.1.3 (**2011-02-16**)
520 1.1.3 (**2011-02-16**)
519 ----------------------
521 ----------------------
520
522
521 news
523 news
522 ++++
524 ++++
523
525
524 - implemented #102 allowing the '.' character in username
526 - implemented #102 allowing the '.' character in username
525 - added option to access repository just by entering http://server/<repo_name>
527 - added option to access repository just by entering http://server/<repo_name>
526 - celery task ignores result for better performance
528 - celery task ignores result for better performance
527
529
528 fixes
530 fixes
529 +++++
531 +++++
530
532
531 - fixed ehlo command and non auth mail servers on smtp_lib. Thanks to
533 - fixed ehlo command and non auth mail servers on smtp_lib. Thanks to
532 apollo13 and Johan Walles
534 apollo13 and Johan Walles
533 - small fixes in journal
535 - small fixes in journal
534 - fixed problems with getting setting for celery from .ini files
536 - fixed problems with getting setting for celery from .ini files
535 - registration, password reset and login boxes share the same title as main
537 - registration, password reset and login boxes share the same title as main
536 application now
538 application now
537 - fixed #113: to high permissions to fork repository
539 - fixed #113: to high permissions to fork repository
538 - fixed problem with '[' chars in commit messages in journal
540 - fixed problem with '[' chars in commit messages in journal
539 - removed issue with space inside renamed repository after deletion
541 - removed issue with space inside renamed repository after deletion
540 - db transaction fixes when filesystem repository creation failed
542 - db transaction fixes when filesystem repository creation failed
541 - fixed #106 relation issues on databases different than sqlite
543 - fixed #106 relation issues on databases different than sqlite
542 - fixed static files paths links to use of url() method
544 - fixed static files paths links to use of url() method
543
545
544 1.1.2 (**2011-01-12**)
546 1.1.2 (**2011-01-12**)
545 ----------------------
547 ----------------------
546
548
547 news
549 news
548 ++++
550 ++++
549
551
550
552
551 fixes
553 fixes
552 +++++
554 +++++
553
555
554 - fixes #98 protection against float division of percentage stats
556 - fixes #98 protection against float division of percentage stats
555 - fixed graph bug
557 - fixed graph bug
556 - forced webhelpers version since it was making troubles during installation
558 - forced webhelpers version since it was making troubles during installation
557
559
558 1.1.1 (**2011-01-06**)
560 1.1.1 (**2011-01-06**)
559 ----------------------
561 ----------------------
560
562
561 news
563 news
562 ++++
564 ++++
563
565
564 - added force https option into ini files for easier https usage (no need to
566 - added force https option into ini files for easier https usage (no need to
565 set server headers with this options)
567 set server headers with this options)
566 - small css updates
568 - small css updates
567
569
568 fixes
570 fixes
569 +++++
571 +++++
570
572
571 - fixed #96 redirect loop on files view on repositories without changesets
573 - fixed #96 redirect loop on files view on repositories without changesets
572 - fixed #97 unicode string passed into server header in special cases (mod_wsgi)
574 - fixed #97 unicode string passed into server header in special cases (mod_wsgi)
573 and server crashed with errors
575 and server crashed with errors
574 - fixed large tooltips problems on main page
576 - fixed large tooltips problems on main page
575 - fixed #92 whoosh indexer is more error proof
577 - fixed #92 whoosh indexer is more error proof
576
578
577 1.1.0 (**2010-12-18**)
579 1.1.0 (**2010-12-18**)
578 ----------------------
580 ----------------------
579
581
580 news
582 news
581 ++++
583 ++++
582
584
583 - rewrite of internals for vcs >=0.1.10
585 - rewrite of internals for vcs >=0.1.10
584 - uses mercurial 1.7 with dotencode disabled for maintaining compatibility
586 - uses mercurial 1.7 with dotencode disabled for maintaining compatibility
585 with older clients
587 with older clients
586 - anonymous access, authentication via ldap
588 - anonymous access, authentication via ldap
587 - performance upgrade for cached repos list - each repository has its own
589 - performance upgrade for cached repos list - each repository has its own
588 cache that's invalidated when needed.
590 cache that's invalidated when needed.
589 - performance upgrades on repositories with large amount of commits (20K+)
591 - performance upgrades on repositories with large amount of commits (20K+)
590 - main page quick filter for filtering repositories
592 - main page quick filter for filtering repositories
591 - user dashboards with ability to follow chosen repositories actions
593 - user dashboards with ability to follow chosen repositories actions
592 - sends email to admin on new user registration
594 - sends email to admin on new user registration
593 - added cache/statistics reset options into repository settings
595 - added cache/statistics reset options into repository settings
594 - more detailed action logger (based on hooks) with pushed changesets lists
596 - more detailed action logger (based on hooks) with pushed changesets lists
595 and options to disable those hooks from admin panel
597 and options to disable those hooks from admin panel
596 - introduced new enhanced changelog for merges that shows more accurate results
598 - introduced new enhanced changelog for merges that shows more accurate results
597 - new improved and faster code stats (based on pygments lexers mapping tables,
599 - new improved and faster code stats (based on pygments lexers mapping tables,
598 showing up to 10 trending sources for each repository. Additionally stats
600 showing up to 10 trending sources for each repository. Additionally stats
599 can be disabled in repository settings.
601 can be disabled in repository settings.
600 - gui optimizations, fixed application width to 1024px
602 - gui optimizations, fixed application width to 1024px
601 - added cut off (for large files/changesets) limit into config files
603 - added cut off (for large files/changesets) limit into config files
602 - whoosh, celeryd, upgrade moved to paster command
604 - whoosh, celeryd, upgrade moved to paster command
603 - other than sqlite database backends can be used
605 - other than sqlite database backends can be used
604
606
605 fixes
607 fixes
606 +++++
608 +++++
607
609
608 - fixes #61 forked repo was showing only after cache expired
610 - fixes #61 forked repo was showing only after cache expired
609 - fixes #76 no confirmation on user deletes
611 - fixes #76 no confirmation on user deletes
610 - fixes #66 Name field misspelled
612 - fixes #66 Name field misspelled
611 - fixes #72 block user removal when he owns repositories
613 - fixes #72 block user removal when he owns repositories
612 - fixes #69 added password confirmation fields
614 - fixes #69 added password confirmation fields
613 - fixes #87 RhodeCode crashes occasionally on updating repository owner
615 - fixes #87 RhodeCode crashes occasionally on updating repository owner
614 - fixes #82 broken annotations on files with more than 1 blank line at the end
616 - fixes #82 broken annotations on files with more than 1 blank line at the end
615 - a lot of fixes and tweaks for file browser
617 - a lot of fixes and tweaks for file browser
616 - fixed detached session issues
618 - fixed detached session issues
617 - fixed when user had no repos he would see all repos listed in my account
619 - fixed when user had no repos he would see all repos listed in my account
618 - fixed ui() instance bug when global hgrc settings was loaded for server
620 - fixed ui() instance bug when global hgrc settings was loaded for server
619 instance and all hgrc options were merged with our db ui() object
621 instance and all hgrc options were merged with our db ui() object
620 - numerous small bugfixes
622 - numerous small bugfixes
621
623
622 (special thanks for TkSoh for detailed feedback)
624 (special thanks for TkSoh for detailed feedback)
623
625
624
626
625 1.0.2 (**2010-11-12**)
627 1.0.2 (**2010-11-12**)
626 ----------------------
628 ----------------------
627
629
628 news
630 news
629 ++++
631 ++++
630
632
631 - tested under python2.7
633 - tested under python2.7
632 - bumped sqlalchemy and celery versions
634 - bumped sqlalchemy and celery versions
633
635
634 fixes
636 fixes
635 +++++
637 +++++
636
638
637 - fixed #59 missing graph.js
639 - fixed #59 missing graph.js
638 - fixed repo_size crash when repository had broken symlinks
640 - fixed repo_size crash when repository had broken symlinks
639 - fixed python2.5 crashes.
641 - fixed python2.5 crashes.
640
642
641
643
642 1.0.1 (**2010-11-10**)
644 1.0.1 (**2010-11-10**)
643 ----------------------
645 ----------------------
644
646
645 news
647 news
646 ++++
648 ++++
647
649
648 - small css updated
650 - small css updated
649
651
650 fixes
652 fixes
651 +++++
653 +++++
652
654
653 - fixed #53 python2.5 incompatible enumerate calls
655 - fixed #53 python2.5 incompatible enumerate calls
654 - fixed #52 disable mercurial extension for web
656 - fixed #52 disable mercurial extension for web
655 - fixed #51 deleting repositories don't delete it's dependent objects
657 - fixed #51 deleting repositories don't delete it's dependent objects
656
658
657
659
658 1.0.0 (**2010-11-02**)
660 1.0.0 (**2010-11-02**)
659 ----------------------
661 ----------------------
660
662
661 - security bugfix simplehg wasn't checking for permissions on commands
663 - security bugfix simplehg wasn't checking for permissions on commands
662 other than pull or push.
664 other than pull or push.
663 - fixed doubled messages after push or pull in admin journal
665 - fixed doubled messages after push or pull in admin journal
664 - templating and css corrections, fixed repo switcher on chrome, updated titles
666 - templating and css corrections, fixed repo switcher on chrome, updated titles
665 - admin menu accessible from options menu on repository view
667 - admin menu accessible from options menu on repository view
666 - permissions cached queries
668 - permissions cached queries
667
669
668 1.0.0rc4 (**2010-10-12**)
670 1.0.0rc4 (**2010-10-12**)
669 --------------------------
671 --------------------------
670
672
671 - fixed python2.5 missing simplejson imports (thanks to Jens BΓ€ckman)
673 - fixed python2.5 missing simplejson imports (thanks to Jens BΓ€ckman)
672 - removed cache_manager settings from sqlalchemy meta
674 - removed cache_manager settings from sqlalchemy meta
673 - added sqlalchemy cache settings to ini files
675 - added sqlalchemy cache settings to ini files
674 - validated password length and added second try of failure on paster setup-app
676 - validated password length and added second try of failure on paster setup-app
675 - fixed setup database destroy prompt even when there was no db
677 - fixed setup database destroy prompt even when there was no db
676
678
677
679
678 1.0.0rc3 (**2010-10-11**)
680 1.0.0rc3 (**2010-10-11**)
679 -------------------------
681 -------------------------
680
682
681 - fixed i18n during installation.
683 - fixed i18n during installation.
682
684
683 1.0.0rc2 (**2010-10-11**)
685 1.0.0rc2 (**2010-10-11**)
684 -------------------------
686 -------------------------
685
687
686 - Disabled dirsize in file browser, it's causing nasty bug when dir renames
688 - Disabled dirsize in file browser, it's causing nasty bug when dir renames
687 occure. After vcs is fixed it'll be put back again.
689 occure. After vcs is fixed it'll be put back again.
688 - templating/css rewrites, optimized css. No newline at end of file
690 - templating/css rewrites, optimized css.
@@ -1,301 +1,303 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.middleware.simplegit
3 rhodecode.lib.middleware.simplegit
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 SimpleGit middleware for handling git protocol request (push/clone etc.)
6 SimpleGit middleware for handling git protocol request (push/clone etc.)
7 It's implemented with basic auth function
7 It's implemented with basic auth function
8
8
9 :created_on: Apr 28, 2010
9 :created_on: Apr 28, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 import re
28 import re
29 import logging
29 import logging
30 import traceback
30 import traceback
31
31
32 from dulwich import server as dulserver
32 from dulwich import server as dulserver
33
33
34
34
35 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
35 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
36
36
37 def handle(self):
37 def handle(self):
38 write = lambda x: self.proto.write_sideband(1, x)
38 write = lambda x: self.proto.write_sideband(1, x)
39
39
40 graph_walker = dulserver.ProtocolGraphWalker(self,
40 graph_walker = dulserver.ProtocolGraphWalker(self,
41 self.repo.object_store,
41 self.repo.object_store,
42 self.repo.get_peeled)
42 self.repo.get_peeled)
43 objects_iter = self.repo.fetch_objects(
43 objects_iter = self.repo.fetch_objects(
44 graph_walker.determine_wants, graph_walker, self.progress,
44 graph_walker.determine_wants, graph_walker, self.progress,
45 get_tagged=self.get_tagged)
45 get_tagged=self.get_tagged)
46
46
47 # Did the process short-circuit (e.g. in a stateless RPC call)? Note
47 # Did the process short-circuit (e.g. in a stateless RPC call)? Note
48 # that the client still expects a 0-object pack in most cases.
48 # that the client still expects a 0-object pack in most cases.
49 if objects_iter is None:
49 if objects_iter is None:
50 return
50 return
51
51
52 self.progress("counting objects: %d, done.\n" % len(objects_iter))
52 self.progress("counting objects: %d, done.\n" % len(objects_iter))
53 dulserver.write_pack_objects(dulserver.ProtocolFile(None, write),
53 dulserver.write_pack_objects(dulserver.ProtocolFile(None, write),
54 objects_iter)
54 objects_iter)
55 messages = []
55 messages = []
56 messages.append('thank you for using rhodecode')
56 messages.append('thank you for using rhodecode')
57
57
58 for msg in messages:
58 for msg in messages:
59 self.progress(msg + "\n")
59 self.progress(msg + "\n")
60 # we are done
60 # we are done
61 self.proto.write("0000")
61 self.proto.write("0000")
62
62
63
63
64 dulserver.DEFAULT_HANDLERS = {
64 dulserver.DEFAULT_HANDLERS = {
65 #git-ls-remote, git-clone, git-fetch and git-pull
65 #git-ls-remote, git-clone, git-fetch and git-pull
66 'git-upload-pack': SimpleGitUploadPackHandler,
66 'git-upload-pack': SimpleGitUploadPackHandler,
67 #git-push
67 #git-push
68 'git-receive-pack': dulserver.ReceivePackHandler,
68 'git-receive-pack': dulserver.ReceivePackHandler,
69 }
69 }
70
70
71 from dulwich.repo import Repo
71 from dulwich.repo import Repo
72 from dulwich.web import make_wsgi_chain
72 from dulwich.web import make_wsgi_chain
73
73
74 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
74 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
75
75
76 from rhodecode.lib.utils2 import safe_str
76 from rhodecode.lib.utils2 import safe_str
77 from rhodecode.lib.base import BaseVCSController
77 from rhodecode.lib.base import BaseVCSController
78 from rhodecode.lib.auth import get_container_username
78 from rhodecode.lib.auth import get_container_username
79 from rhodecode.lib.utils import is_valid_repo, make_ui
79 from rhodecode.lib.utils import is_valid_repo, make_ui
80 from rhodecode.model.db import User
80 from rhodecode.model.db import User
81
81
82 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
82 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
83
83
84 log = logging.getLogger(__name__)
84 log = logging.getLogger(__name__)
85
85
86
86
87 GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
87 GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
88
88
89
89
90 def is_git(environ):
90 def is_git(environ):
91 path_info = environ['PATH_INFO']
91 path_info = environ['PATH_INFO']
92 isgit_path = GIT_PROTO_PAT.match(path_info)
92 isgit_path = GIT_PROTO_PAT.match(path_info)
93 log.debug('pathinfo: %s detected as GIT %s' % (
93 log.debug('pathinfo: %s detected as GIT %s' % (
94 path_info, isgit_path != None)
94 path_info, isgit_path != None)
95 )
95 )
96 return isgit_path
96 return isgit_path
97
97
98
98
99 class SimpleGit(BaseVCSController):
99 class SimpleGit(BaseVCSController):
100
100
101 def _handle_request(self, environ, start_response):
101 def _handle_request(self, environ, start_response):
102
102
103 if not is_git(environ):
103 if not is_git(environ):
104 return self.application(environ, start_response)
104 return self.application(environ, start_response)
105
105
106 ipaddr = self._get_ip_addr(environ)
106 ipaddr = self._get_ip_addr(environ)
107 username = None
107 username = None
108 self._git_first_op = False
108 self._git_first_op = False
109 # skip passing error to error controller
109 # skip passing error to error controller
110 environ['pylons.status_code_redirect'] = True
110 environ['pylons.status_code_redirect'] = True
111
111
112 #======================================================================
112 #======================================================================
113 # EXTRACT REPOSITORY NAME FROM ENV
113 # EXTRACT REPOSITORY NAME FROM ENV
114 #======================================================================
114 #======================================================================
115 try:
115 try:
116 repo_name = self.__get_repository(environ)
116 repo_name = self.__get_repository(environ)
117 log.debug('Extracted repo name is %s' % repo_name)
117 log.debug('Extracted repo name is %s' % repo_name)
118 except:
118 except:
119 return HTTPInternalServerError()(environ, start_response)
119 return HTTPInternalServerError()(environ, start_response)
120
120
121 # quick check if that dir exists...
121 # quick check if that dir exists...
122 if is_valid_repo(repo_name, self.basepath) is False:
122 if is_valid_repo(repo_name, self.basepath) is False:
123 return HTTPNotFound()(environ, start_response)
123 return HTTPNotFound()(environ, start_response)
124
124
125 #======================================================================
125 #======================================================================
126 # GET ACTION PULL or PUSH
126 # GET ACTION PULL or PUSH
127 #======================================================================
127 #======================================================================
128 action = self.__get_action(environ)
128 action = self.__get_action(environ)
129
129
130 #======================================================================
130 #======================================================================
131 # CHECK ANONYMOUS PERMISSION
131 # CHECK ANONYMOUS PERMISSION
132 #======================================================================
132 #======================================================================
133 if action in ['pull', 'push']:
133 if action in ['pull', 'push']:
134 anonymous_user = self.__get_user('default')
134 anonymous_user = self.__get_user('default')
135 username = anonymous_user.username
135 username = anonymous_user.username
136 anonymous_perm = self._check_permission(action, anonymous_user,
136 anonymous_perm = self._check_permission(action, anonymous_user,
137 repo_name)
137 repo_name)
138
138
139 if anonymous_perm is not True or anonymous_user.active is False:
139 if anonymous_perm is not True or anonymous_user.active is False:
140 if anonymous_perm is not True:
140 if anonymous_perm is not True:
141 log.debug('Not enough credentials to access this '
141 log.debug('Not enough credentials to access this '
142 'repository as anonymous user')
142 'repository as anonymous user')
143 if anonymous_user.active is False:
143 if anonymous_user.active is False:
144 log.debug('Anonymous access is disabled, running '
144 log.debug('Anonymous access is disabled, running '
145 'authentication')
145 'authentication')
146 #==============================================================
146 #==============================================================
147 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
147 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
148 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
148 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
149 #==============================================================
149 #==============================================================
150
150
151 # Attempting to retrieve username from the container
151 # Attempting to retrieve username from the container
152 username = get_container_username(environ, self.config)
152 username = get_container_username(environ, self.config)
153
153
154 # If not authenticated by the container, running basic auth
154 # If not authenticated by the container, running basic auth
155 if not username:
155 if not username:
156 self.authenticate.realm = \
156 self.authenticate.realm = \
157 safe_str(self.config['rhodecode_realm'])
157 safe_str(self.config['rhodecode_realm'])
158 result = self.authenticate(environ)
158 result = self.authenticate(environ)
159 if isinstance(result, str):
159 if isinstance(result, str):
160 AUTH_TYPE.update(environ, 'basic')
160 AUTH_TYPE.update(environ, 'basic')
161 REMOTE_USER.update(environ, result)
161 REMOTE_USER.update(environ, result)
162 username = result
162 username = result
163 else:
163 else:
164 return result.wsgi_application(environ, start_response)
164 return result.wsgi_application(environ, start_response)
165
165
166 #==============================================================
166 #==============================================================
167 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
167 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
168 #==============================================================
168 #==============================================================
169 if action in ['pull', 'push']:
169 if action in ['pull', 'push']:
170 try:
170 try:
171 user = self.__get_user(username)
171 user = self.__get_user(username)
172 if user is None or not user.active:
172 if user is None or not user.active:
173 return HTTPForbidden()(environ, start_response)
173 return HTTPForbidden()(environ, start_response)
174 username = user.username
174 username = user.username
175 except:
175 except:
176 log.error(traceback.format_exc())
176 log.error(traceback.format_exc())
177 return HTTPInternalServerError()(environ,
177 return HTTPInternalServerError()(environ,
178 start_response)
178 start_response)
179
179
180 #check permissions for this repository
180 #check permissions for this repository
181 perm = self._check_permission(action, user, repo_name)
181 perm = self._check_permission(action, user, repo_name)
182 if perm is not True:
182 if perm is not True:
183 return HTTPForbidden()(environ, start_response)
183 return HTTPForbidden()(environ, start_response)
184 extras = {
184 extras = {
185 'ip': ipaddr,
185 'ip': ipaddr,
186 'username': username,
186 'username': username,
187 'action': action,
187 'action': action,
188 'repository': repo_name,
188 'repository': repo_name,
189 'scm': 'git',
189 'scm': 'git',
190 }
190 }
191
191
192 #===================================================================
192 #===================================================================
193 # GIT REQUEST HANDLING
193 # GIT REQUEST HANDLING
194 #===================================================================
194 #===================================================================
195 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
195 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
196 log.debug('Repository path is %s' % repo_path)
196 log.debug('Repository path is %s' % repo_path)
197
197
198 baseui = make_ui('db')
198 baseui = make_ui('db')
199 self.__inject_extras(repo_path, baseui, extras)
199 self.__inject_extras(repo_path, baseui, extras)
200
200
201 try:
201 try:
202 # invalidate cache on push
202 # invalidate cache on push
203 if action == 'push':
203 if action == 'push':
204 self._invalidate_cache(repo_name)
204 self._invalidate_cache(repo_name)
205 self._handle_githooks(repo_name, action, baseui, environ)
205 self._handle_githooks(repo_name, action, baseui, environ)
206
206
207 log.info('%s action on GIT repo "%s"' % (action, repo_name))
207 log.info('%s action on GIT repo "%s"' % (action, repo_name))
208 app = self.__make_app(repo_name, repo_path)
208 app = self.__make_app(repo_name, repo_path)
209 return app(environ, start_response)
209 return app(environ, start_response)
210 except Exception:
210 except Exception:
211 log.error(traceback.format_exc())
211 log.error(traceback.format_exc())
212 return HTTPInternalServerError()(environ, start_response)
212 return HTTPInternalServerError()(environ, start_response)
213
213
214 def __make_app(self, repo_name, repo_path):
214 def __make_app(self, repo_name, repo_path):
215 """
215 """
216 Make an wsgi application using dulserver
216 Make an wsgi application using dulserver
217
217
218 :param repo_name: name of the repository
218 :param repo_name: name of the repository
219 :param repo_path: full path to the repository
219 :param repo_path: full path to the repository
220 """
220 """
221 _d = {'/' + repo_name: Repo(repo_path)}
222 backend = dulserver.DictBackend(_d)
223 gitserve = make_wsgi_chain(backend)
224
221
225 return gitserve
222 from rhodecode.lib.middleware.pygrack import make_wsgi_app
223 app = make_wsgi_app(
224 repo_root=os.path.dirname(repo_path),
225 repo_name=repo_name,
226 )
227 return app
226
228
227 def __get_repository(self, environ):
229 def __get_repository(self, environ):
228 """
230 """
229 Get's repository name out of PATH_INFO header
231 Get's repository name out of PATH_INFO header
230
232
231 :param environ: environ where PATH_INFO is stored
233 :param environ: environ where PATH_INFO is stored
232 """
234 """
233 try:
235 try:
234 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
236 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
235 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
237 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
236 except:
238 except:
237 log.error(traceback.format_exc())
239 log.error(traceback.format_exc())
238 raise
240 raise
239
241
240 return repo_name
242 return repo_name
241
243
242 def __get_user(self, username):
244 def __get_user(self, username):
243 return User.get_by_username(username)
245 return User.get_by_username(username)
244
246
245 def __get_action(self, environ):
247 def __get_action(self, environ):
246 """
248 """
247 Maps git request commands into a pull or push command.
249 Maps git request commands into a pull or push command.
248
250
249 :param environ:
251 :param environ:
250 """
252 """
251 service = environ['QUERY_STRING'].split('=')
253 service = environ['QUERY_STRING'].split('=')
252
254
253 if len(service) > 1:
255 if len(service) > 1:
254 service_cmd = service[1]
256 service_cmd = service[1]
255 mapping = {
257 mapping = {
256 'git-receive-pack': 'push',
258 'git-receive-pack': 'push',
257 'git-upload-pack': 'pull',
259 'git-upload-pack': 'pull',
258 }
260 }
259 op = mapping[service_cmd]
261 op = mapping[service_cmd]
260 self._git_stored_op = op
262 self._git_stored_op = op
261 return op
263 return op
262 else:
264 else:
263 # try to fallback to stored variable as we don't know if the last
265 # try to fallback to stored variable as we don't know if the last
264 # operation is pull/push
266 # operation is pull/push
265 op = getattr(self, '_git_stored_op', 'pull')
267 op = getattr(self, '_git_stored_op', 'pull')
266 return op
268 return op
267
269
268 def _handle_githooks(self, repo_name, action, baseui, environ):
270 def _handle_githooks(self, repo_name, action, baseui, environ):
269 from rhodecode.lib.hooks import log_pull_action, log_push_action
271 from rhodecode.lib.hooks import log_pull_action, log_push_action
270 service = environ['QUERY_STRING'].split('=')
272 service = environ['QUERY_STRING'].split('=')
271 if len(service) < 2:
273 if len(service) < 2:
272 return
274 return
273
275
274 from rhodecode.model.db import Repository
276 from rhodecode.model.db import Repository
275 _repo = Repository.get_by_repo_name(repo_name)
277 _repo = Repository.get_by_repo_name(repo_name)
276 _repo = _repo.scm_instance
278 _repo = _repo.scm_instance
277 _repo._repo.ui = baseui
279 _repo._repo.ui = baseui
278
280
279 push_hook = 'pretxnchangegroup.push_logger'
281 push_hook = 'pretxnchangegroup.push_logger'
280 pull_hook = 'preoutgoing.pull_logger'
282 pull_hook = 'preoutgoing.pull_logger'
281 _hooks = dict(baseui.configitems('hooks')) or {}
283 _hooks = dict(baseui.configitems('hooks')) or {}
282 if action == 'push' and _hooks.get(push_hook):
284 if action == 'push' and _hooks.get(push_hook):
283 log_push_action(ui=baseui, repo=_repo._repo)
285 log_push_action(ui=baseui, repo=_repo._repo)
284 elif action == 'pull' and _hooks.get(pull_hook):
286 elif action == 'pull' and _hooks.get(pull_hook):
285 log_pull_action(ui=baseui, repo=_repo._repo)
287 log_pull_action(ui=baseui, repo=_repo._repo)
286
288
287 def __inject_extras(self, repo_path, baseui, extras={}):
289 def __inject_extras(self, repo_path, baseui, extras={}):
288 """
290 """
289 Injects some extra params into baseui instance
291 Injects some extra params into baseui instance
290
292
291 :param baseui: baseui instance
293 :param baseui: baseui instance
292 :param extras: dict with extra params to put into baseui
294 :param extras: dict with extra params to put into baseui
293 """
295 """
294
296
295 # make our hgweb quiet so it doesn't print output
297 # make our hgweb quiet so it doesn't print output
296 baseui.setconfig('ui', 'quiet', 'true')
298 baseui.setconfig('ui', 'quiet', 'true')
297
299
298 #inject some additional parameters that will be available in ui
300 #inject some additional parameters that will be available in ui
299 #for hooks
301 #for hooks
300 for k, v in extras.items():
302 for k, v in extras.items():
301 baseui.setconfig('rhodecode_extras', k, v)
303 baseui.setconfig('rhodecode_extras', k, v)
General Comments 0
You need to be logged in to leave comments. Login now