##// END OF EJS Templates
release: merge back stable branch into default
marcink -
r2602:37989561 merge default
parent child Browse files
Show More
@@ -0,0 +1,44 b''
1 |RCE| 4.11.4 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2018-02-18
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13
14
15 General
16 ^^^^^^^
17
18
19
20 Security
21 ^^^^^^^^
22
23
24
25 Performance
26 ^^^^^^^^^^^
27
28
29
30 Fixes
31 ^^^^^
32
33 - Ssh: fixed problems with svn ssh clones in certain configurations.
34 - Caches: use individual namespaces per user to prevent beaker caching problems in database backends.
35 In some cases of large LDAP data we could generate mysql table errors
36 with too big data. Now each user will use individual row in db cache
37 - Reviewers: fixed logic with wildcard (*) match for source/target branches.
38 Reverting a regression when * didn't work as expected in branch matching.
39
40
41 Upgrade notes
42 ^^^^^^^^^^^^^
43
44 - Unscheduled bugfix release fixing several reported issues.
@@ -1,34 +1,35 b''
1 1bd3e92b7e2e2d2024152b34bb88dff1db544a71 v4.0.0
1 1bd3e92b7e2e2d2024152b34bb88dff1db544a71 v4.0.0
2 170c5398320ea6cddd50955e88d408794c21d43a v4.0.1
2 170c5398320ea6cddd50955e88d408794c21d43a v4.0.1
3 c3fe200198f5aa34cf2e4066df2881a9cefe3704 v4.1.0
3 c3fe200198f5aa34cf2e4066df2881a9cefe3704 v4.1.0
4 7fd5c850745e2ea821fb4406af5f4bff9b0a7526 v4.1.1
4 7fd5c850745e2ea821fb4406af5f4bff9b0a7526 v4.1.1
5 41c87da28a179953df86061d817bc35533c66dd2 v4.1.2
5 41c87da28a179953df86061d817bc35533c66dd2 v4.1.2
6 baaf9f5bcea3bae0ef12ae20c8b270482e62abb6 v4.2.0
6 baaf9f5bcea3bae0ef12ae20c8b270482e62abb6 v4.2.0
7 32a70c7e56844a825f61df496ee5eaf8c3c4e189 v4.2.1
7 32a70c7e56844a825f61df496ee5eaf8c3c4e189 v4.2.1
8 fa695cdb411d294679ac081d595ac654e5613b03 v4.3.0
8 fa695cdb411d294679ac081d595ac654e5613b03 v4.3.0
9 0e4dc11b58cad833c513fe17bac39e6850edf959 v4.3.1
9 0e4dc11b58cad833c513fe17bac39e6850edf959 v4.3.1
10 8a876f48f5cb1d018b837db28ff928500cb32cfb v4.4.0
10 8a876f48f5cb1d018b837db28ff928500cb32cfb v4.4.0
11 8dd86b410b1aac086ffdfc524ef300f896af5047 v4.4.1
11 8dd86b410b1aac086ffdfc524ef300f896af5047 v4.4.1
12 d2514226abc8d3b4f6fb57765f47d1b6fb360a05 v4.4.2
12 d2514226abc8d3b4f6fb57765f47d1b6fb360a05 v4.4.2
13 27d783325930af6dad2741476c0d0b1b7c8415c2 v4.5.0
13 27d783325930af6dad2741476c0d0b1b7c8415c2 v4.5.0
14 7f2016f352abcbdba4a19d4039c386e9629449da v4.5.1
14 7f2016f352abcbdba4a19d4039c386e9629449da v4.5.1
15 416fec799314c70a5c780fb28b3357b08869333a v4.5.2
15 416fec799314c70a5c780fb28b3357b08869333a v4.5.2
16 27c3b85fafc83143e6678fbc3da69e1615bcac55 v4.6.0
16 27c3b85fafc83143e6678fbc3da69e1615bcac55 v4.6.0
17 5ad13deb9118c2a5243d4032d4d9cc174e5872db v4.6.1
17 5ad13deb9118c2a5243d4032d4d9cc174e5872db v4.6.1
18 2be921e01fa24bb102696ada596f87464c3666f6 v4.7.0
18 2be921e01fa24bb102696ada596f87464c3666f6 v4.7.0
19 7198bdec29c2872c974431d55200d0398354cdb1 v4.7.1
19 7198bdec29c2872c974431d55200d0398354cdb1 v4.7.1
20 bd1c8d230fe741c2dfd7100a0ef39fd0774fd581 v4.7.2
20 bd1c8d230fe741c2dfd7100a0ef39fd0774fd581 v4.7.2
21 9731914f89765d9628dc4dddc84bc9402aa124c8 v4.8.0
21 9731914f89765d9628dc4dddc84bc9402aa124c8 v4.8.0
22 c5a2b7d0e4bbdebc4a62d7b624befe375207b659 v4.9.0
22 c5a2b7d0e4bbdebc4a62d7b624befe375207b659 v4.9.0
23 d9aa3b27ac9f7e78359775c75fedf7bfece232f1 v4.9.1
23 d9aa3b27ac9f7e78359775c75fedf7bfece232f1 v4.9.1
24 4ba4d74981cec5d6b28b158f875a2540952c2f74 v4.10.0
24 4ba4d74981cec5d6b28b158f875a2540952c2f74 v4.10.0
25 0a6821cbd6b0b3c21503002f88800679fa35ab63 v4.10.1
25 0a6821cbd6b0b3c21503002f88800679fa35ab63 v4.10.1
26 434ad90ec8d621f4416074b84f6e9ce03964defb v4.10.2
26 434ad90ec8d621f4416074b84f6e9ce03964defb v4.10.2
27 68baee10e698da2724c6e0f698c03a6abb993bf2 v4.10.3
27 68baee10e698da2724c6e0f698c03a6abb993bf2 v4.10.3
28 00821d3afd1dce3f4767cc353f84a17f7d5218a1 v4.10.4
28 00821d3afd1dce3f4767cc353f84a17f7d5218a1 v4.10.4
29 22f6744ad8cc274311825f63f953e4dee2ea5cb9 v4.10.5
29 22f6744ad8cc274311825f63f953e4dee2ea5cb9 v4.10.5
30 96eb24bea2f5f9258775245e3f09f6fa0a4dda01 v4.10.6
30 96eb24bea2f5f9258775245e3f09f6fa0a4dda01 v4.10.6
31 3121217a812c956d7dd5a5875821bd73e8002a32 v4.11.0
31 3121217a812c956d7dd5a5875821bd73e8002a32 v4.11.0
32 fa98b454715ac5b912f39e84af54345909a2a805 v4.11.1
32 fa98b454715ac5b912f39e84af54345909a2a805 v4.11.1
33 3982abcfdcc229a723cebe52d3a9bcff10bba08e v4.11.2
33 3982abcfdcc229a723cebe52d3a9bcff10bba08e v4.11.2
34 33195f145db9172f0a8f1487e09207178a6ab065 v4.11.3
34 33195f145db9172f0a8f1487e09207178a6ab065 v4.11.3
35 194c74f33e32bbae6fc4d71ec5a999cff3c13605 v4.11.4
@@ -1,81 +1,81 b''
1 .. _rhodecode-issue-trackers-ref:
1 .. _rhodecode-issue-trackers-ref:
2
2
3 Issue Tracker Integration
3 Issue Tracker Integration
4 =========================
4 =========================
5
5
6 You can set an issue tracker connection in two ways with |RCE|.
6 You can set an issue tracker connection in two ways with |RCE|.
7
7
8 * At the instance level, you can set a default issue tracker.
8 * At the instance level, you can set a default issue tracker.
9 * At the |repo| level, you can configure an integration with a different issue
9 * At the |repo| level, you can configure an integration with a different issue
10 tracker.
10 tracker.
11
11
12 To integrate |RCM| with an issue tracker, you need to define a regular
12 To integrate |RCM| with an issue tracker, you need to define a regular
13 expression that will fetch the issue ID stored in commit messages, and replace
13 expression that will fetch the issue ID stored in commit messages, and replace
14 it with a URL. This enables |RCE| to generate a link matching each issue to the
14 it with a URL. This enables |RCE| to generate a link matching each issue to the
15 target |repo|.
15 target |repo|.
16
16
17 Default Issue Tracker Configuration
17 Default Issue Tracker Configuration
18 -----------------------------------
18 -----------------------------------
19
19
20 To integrate your issue tracker, use the following steps:
20 To integrate your issue tracker, use the following steps:
21
21
22 1. Open :menuselection:`Admin --> Settings --> Issue Tracker`.
22 1. Open :menuselection:`Admin --> Settings --> Issue Tracker`.
23 2. In the new entry field, enter the following information:
23 2. In the new entry field, enter the following information:
24
24
25 * :guilabel:`Description`: A name for this set of rules.
25 * :guilabel:`Description`: A name for this set of rules.
26 * :guilabel:`Pattern`: The regular expression that will match issues
26 * :guilabel:`Pattern`: The regular expression that will match issues
27 tagged in commit messages, or more see :ref:`issue-tr-eg-ref`.
27 tagged in commit messages, or more see :ref:`issue-tr-eg-ref`.
28 * :guilabel:`URL`: The URL to your issue tracker.
28 * :guilabel:`URL`: The URL to your issue tracker.
29 * :guilabel:`Prefix`: The prefix with which you want to mark issues.
29 * :guilabel:`Prefix`: The prefix with which you want to mark issues.
30
30
31 3. Select **Add** so save the rule to your issue tracker configuration.
31 3. Select **Add** so save the rule to your issue tracker configuration.
32
32
33 Repository Issue Tracker Configuration
33 Repository Issue Tracker Configuration
34 --------------------------------------
34 --------------------------------------
35
35
36 You can configure specific |repos| to use a different issue tracker than the
36 You can configure specific |repos| to use a different issue tracker than the
37 default one. See the instructions in :ref:`repo-it`
37 default one. See the instructions in :ref:`repo-it`
38
38
39 .. _issue-tr-eg-ref:
39 .. _issue-tr-eg-ref:
40
40
41 Jira Integration
41 Jira Integration
42 ----------------
42 ----------------
43
43
44 * Regex = ``(?:^#|\s#)(\w+-\d+)``
44 * Regex = ``(?:^#|\s#)(\w+-\d+)``
45 * URL = ``https://myissueserver.com/issue/${id}``
45 * URL = ``https://myissueserver.com/browse/${id}``
46 * Issue Prefix = ``#``
46 * Issue Prefix = ``#``
47
47
48 Confluence (Wiki)
48 Confluence (Wiki)
49 -----------------
49 -----------------
50
50
51 * Regex = ``(?:conf-)([A-Z0-9]+)``
51 * Regex = ``(?:conf-)([A-Z0-9]+)``
52 * URL = ``https://example.atlassian.net/display/wiki/${id}/${repo_name}``
52 * URL = ``https://example.atlassian.net/display/wiki/${id}/${repo_name}``
53 * issue prefix = ``CONF-``
53 * issue prefix = ``CONF-``
54
54
55 Redmine Integration
55 Redmine Integration
56 -------------------
56 -------------------
57
57
58 * Regex = ``(issue-+\d+)``
58 * Regex = ``(issue-+\d+)``
59 * URL = ``https://myissueserver.com/redmine/issue/${id}``
59 * URL = ``https://myissueserver.com/redmine/issue/${id}``
60 * Issue Prefix = ``issue-``
60 * Issue Prefix = ``issue-``
61
61
62 Redmine (wiki)
62 Redmine (wiki)
63 --------------
63 --------------
64
64
65 * Regex = ``(?:wiki-)([a-zA-Z0-9]+)``
65 * Regex = ``(?:wiki-)([a-zA-Z0-9]+)``
66 * URL = ``https://example.com/redmine/projects/wiki/${repo_name}``
66 * URL = ``https://example.com/redmine/projects/wiki/${repo_name}``
67 * Issue prefix = ``Issue-``
67 * Issue prefix = ``Issue-``
68
68
69 Pivotal Tracker
69 Pivotal Tracker
70 ---------------
70 ---------------
71
71
72 * Regex = ``(?:pivot-)(?<project_id>\d+)-(?<story>\d+)``
72 * Regex = ``(?:pivot-)(?<project_id>\d+)-(?<story>\d+)``
73 * URL = ``https://www.pivotaltracker.com/s/projects/${project_id}/stories/${story}``
73 * URL = ``https://www.pivotaltracker.com/s/projects/${project_id}/stories/${story}``
74 * Issue prefix = ``Piv-``
74 * Issue prefix = ``Piv-``
75
75
76 Trello
76 Trello
77 ------
77 ------
78
78
79 * Regex = ``(?:trello-)(?<card_id>[a-zA-Z0-9]+)``
79 * Regex = ``(?:trello-)(?<card_id>[a-zA-Z0-9]+)``
80 * URL = ``https://trello.com/example.com/${card_id}``
80 * URL = ``https://trello.com/example.com/${card_id}``
81 * Issue prefix = ``Trello-``
81 * Issue prefix = ``Trello-``
@@ -1,111 +1,112 b''
1 .. _rhodecode-release-notes-ref:
1 .. _rhodecode-release-notes-ref:
2
2
3 Release Notes
3 Release Notes
4 =============
4 =============
5
5
6 |RCE| 4.x Versions
6 |RCE| 4.x Versions
7 ------------------
7 ------------------
8
8
9 .. toctree::
9 .. toctree::
10 :maxdepth: 1
10 :maxdepth: 1
11
11
12 release-notes-4.11.4.rst
12 release-notes-4.11.3.rst
13 release-notes-4.11.3.rst
13 release-notes-4.11.2.rst
14 release-notes-4.11.2.rst
14 release-notes-4.11.1.rst
15 release-notes-4.11.1.rst
15 release-notes-4.11.0.rst
16 release-notes-4.11.0.rst
16 release-notes-4.10.6.rst
17 release-notes-4.10.6.rst
17 release-notes-4.10.5.rst
18 release-notes-4.10.5.rst
18 release-notes-4.10.4.rst
19 release-notes-4.10.4.rst
19 release-notes-4.10.3.rst
20 release-notes-4.10.3.rst
20 release-notes-4.10.2.rst
21 release-notes-4.10.2.rst
21 release-notes-4.10.1.rst
22 release-notes-4.10.1.rst
22 release-notes-4.10.0.rst
23 release-notes-4.10.0.rst
23 release-notes-4.9.1.rst
24 release-notes-4.9.1.rst
24 release-notes-4.9.0.rst
25 release-notes-4.9.0.rst
25 release-notes-4.8.0.rst
26 release-notes-4.8.0.rst
26 release-notes-4.7.2.rst
27 release-notes-4.7.2.rst
27 release-notes-4.7.1.rst
28 release-notes-4.7.1.rst
28 release-notes-4.7.0.rst
29 release-notes-4.7.0.rst
29 release-notes-4.6.1.rst
30 release-notes-4.6.1.rst
30 release-notes-4.6.0.rst
31 release-notes-4.6.0.rst
31 release-notes-4.5.2.rst
32 release-notes-4.5.2.rst
32 release-notes-4.5.1.rst
33 release-notes-4.5.1.rst
33 release-notes-4.5.0.rst
34 release-notes-4.5.0.rst
34 release-notes-4.4.2.rst
35 release-notes-4.4.2.rst
35 release-notes-4.4.1.rst
36 release-notes-4.4.1.rst
36 release-notes-4.4.0.rst
37 release-notes-4.4.0.rst
37 release-notes-4.3.1.rst
38 release-notes-4.3.1.rst
38 release-notes-4.3.0.rst
39 release-notes-4.3.0.rst
39 release-notes-4.2.1.rst
40 release-notes-4.2.1.rst
40 release-notes-4.2.0.rst
41 release-notes-4.2.0.rst
41 release-notes-4.1.2.rst
42 release-notes-4.1.2.rst
42 release-notes-4.1.1.rst
43 release-notes-4.1.1.rst
43 release-notes-4.1.0.rst
44 release-notes-4.1.0.rst
44 release-notes-4.0.1.rst
45 release-notes-4.0.1.rst
45 release-notes-4.0.0.rst
46 release-notes-4.0.0.rst
46
47
47 |RCE| 3.x Versions
48 |RCE| 3.x Versions
48 ------------------
49 ------------------
49
50
50 .. toctree::
51 .. toctree::
51 :maxdepth: 1
52 :maxdepth: 1
52
53
53 release-notes-3.8.4.rst
54 release-notes-3.8.4.rst
54 release-notes-3.8.3.rst
55 release-notes-3.8.3.rst
55 release-notes-3.8.2.rst
56 release-notes-3.8.2.rst
56 release-notes-3.8.1.rst
57 release-notes-3.8.1.rst
57 release-notes-3.8.0.rst
58 release-notes-3.8.0.rst
58 release-notes-3.7.1.rst
59 release-notes-3.7.1.rst
59 release-notes-3.7.0.rst
60 release-notes-3.7.0.rst
60 release-notes-3.6.1.rst
61 release-notes-3.6.1.rst
61 release-notes-3.6.0.rst
62 release-notes-3.6.0.rst
62 release-notes-3.5.2.rst
63 release-notes-3.5.2.rst
63 release-notes-3.5.1.rst
64 release-notes-3.5.1.rst
64 release-notes-3.5.0.rst
65 release-notes-3.5.0.rst
65 release-notes-3.4.1.rst
66 release-notes-3.4.1.rst
66 release-notes-3.4.0.rst
67 release-notes-3.4.0.rst
67 release-notes-3.3.4.rst
68 release-notes-3.3.4.rst
68 release-notes-3.3.3.rst
69 release-notes-3.3.3.rst
69 release-notes-3.3.2.rst
70 release-notes-3.3.2.rst
70 release-notes-3.3.1.rst
71 release-notes-3.3.1.rst
71 release-notes-3.3.0.rst
72 release-notes-3.3.0.rst
72 release-notes-3.2.3.rst
73 release-notes-3.2.3.rst
73 release-notes-3.2.2.rst
74 release-notes-3.2.2.rst
74 release-notes-3.2.1.rst
75 release-notes-3.2.1.rst
75 release-notes-3.2.0.rst
76 release-notes-3.2.0.rst
76 release-notes-3.1.1.rst
77 release-notes-3.1.1.rst
77 release-notes-3.1.0.rst
78 release-notes-3.1.0.rst
78 release-notes-3.0.2.rst
79 release-notes-3.0.2.rst
79 release-notes-3.0.1.rst
80 release-notes-3.0.1.rst
80 release-notes-3.0.0.rst
81 release-notes-3.0.0.rst
81
82
82 |RCE| 2.x Versions
83 |RCE| 2.x Versions
83 ------------------
84 ------------------
84
85
85 .. toctree::
86 .. toctree::
86 :maxdepth: 1
87 :maxdepth: 1
87
88
88 release-notes-2.2.8.rst
89 release-notes-2.2.8.rst
89 release-notes-2.2.7.rst
90 release-notes-2.2.7.rst
90 release-notes-2.2.6.rst
91 release-notes-2.2.6.rst
91 release-notes-2.2.5.rst
92 release-notes-2.2.5.rst
92 release-notes-2.2.4.rst
93 release-notes-2.2.4.rst
93 release-notes-2.2.3.rst
94 release-notes-2.2.3.rst
94 release-notes-2.2.2.rst
95 release-notes-2.2.2.rst
95 release-notes-2.2.1.rst
96 release-notes-2.2.1.rst
96 release-notes-2.2.0.rst
97 release-notes-2.2.0.rst
97 release-notes-2.1.0.rst
98 release-notes-2.1.0.rst
98 release-notes-2.0.2.rst
99 release-notes-2.0.2.rst
99 release-notes-2.0.1.rst
100 release-notes-2.0.1.rst
100 release-notes-2.0.0.rst
101 release-notes-2.0.0.rst
101
102
102 |RCE| 1.x Versions
103 |RCE| 1.x Versions
103 ------------------
104 ------------------
104
105
105 .. toctree::
106 .. toctree::
106 :maxdepth: 1
107 :maxdepth: 1
107
108
108 release-notes-1.7.2.rst
109 release-notes-1.7.2.rst
109 release-notes-1.7.1.rst
110 release-notes-1.7.1.rst
110 release-notes-1.7.0.rst
111 release-notes-1.7.0.rst
111 release-notes-1.6.0.rst
112 release-notes-1.6.0.rst
@@ -1,228 +1,227 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import re
22 import re
23 import sys
23 import sys
24 import logging
24 import logging
25 import signal
25 import signal
26 import tempfile
26 import tempfile
27 from subprocess import Popen, PIPE
27 from subprocess import Popen, PIPE
28 import urlparse
28 import urlparse
29
29
30 from .base import VcsServer
30 from .base import VcsServer
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 class SubversionTunnelWrapper(object):
35 class SubversionTunnelWrapper(object):
36 process = None
36 process = None
37
37
38 def __init__(self, server):
38 def __init__(self, server):
39 self.server = server
39 self.server = server
40 self.timeout = 30
40 self.timeout = 30
41 self.stdin = sys.stdin
41 self.stdin = sys.stdin
42 self.stdout = sys.stdout
42 self.stdout = sys.stdout
43 self.svn_conf_fd, self.svn_conf_path = tempfile.mkstemp()
43 self.svn_conf_fd, self.svn_conf_path = tempfile.mkstemp()
44 self.hooks_env_fd, self.hooks_env_path = tempfile.mkstemp()
44 self.hooks_env_fd, self.hooks_env_path = tempfile.mkstemp()
45
45
46 self.read_only = True # flag that we set to make the hooks readonly
46 self.read_only = True # flag that we set to make the hooks readonly
47
47
48 def create_svn_config(self):
48 def create_svn_config(self):
49 content = (
49 content = (
50 '[general]\n'
50 '[general]\n'
51 'hooks-env = {}\n').format(self.hooks_env_path)
51 'hooks-env = {}\n').format(self.hooks_env_path)
52 with os.fdopen(self.svn_conf_fd, 'w') as config_file:
52 with os.fdopen(self.svn_conf_fd, 'w') as config_file:
53 config_file.write(content)
53 config_file.write(content)
54
54
55 def create_hooks_env(self):
55 def create_hooks_env(self):
56 content = (
56 content = (
57 '[default]\n'
57 '[default]\n'
58 'LANG = en_US.UTF-8\n')
58 'LANG = en_US.UTF-8\n')
59 if self.read_only:
59 if self.read_only:
60 content += 'SSH_READ_ONLY = 1\n'
60 content += 'SSH_READ_ONLY = 1\n'
61 with os.fdopen(self.hooks_env_fd, 'w') as hooks_env_file:
61 with os.fdopen(self.hooks_env_fd, 'w') as hooks_env_file:
62 hooks_env_file.write(content)
62 hooks_env_file.write(content)
63
63
64 def remove_configs(self):
64 def remove_configs(self):
65 os.remove(self.svn_conf_path)
65 os.remove(self.svn_conf_path)
66 os.remove(self.hooks_env_path)
66 os.remove(self.hooks_env_path)
67
67
68 def command(self):
68 def command(self):
69 root = self.server.get_root_store()
69 root = self.server.get_root_store()
70 command = [
70 command = [
71 self.server.svn_path, '-t',
71 self.server.svn_path, '-t',
72 '--config-file', self.svn_conf_path,
72 '--config-file', self.svn_conf_path,
73 '-r', root]
73 '-r', root]
74 log.debug("Final CMD: %s", command)
74 log.debug("Final CMD: %s", ' '.join(command))
75 return command
75 return command
76
76
77 def start(self):
77 def start(self):
78 command = self.command()
78 command = self.command()
79 self.process = Popen(command, stdin=PIPE)
79 self.process = Popen(' '.join(command), stdin=PIPE, shell=True)
80
80
81 def sync(self):
81 def sync(self):
82 while self.process.poll() is None:
82 while self.process.poll() is None:
83 next_byte = self.stdin.read(1)
83 next_byte = self.stdin.read(1)
84 if not next_byte:
84 if not next_byte:
85 break
85 break
86 self.process.stdin.write(next_byte)
86 self.process.stdin.write(next_byte)
87 self.remove_configs()
87 self.remove_configs()
88
88
89 @property
89 @property
90 def return_code(self):
90 def return_code(self):
91 return self.process.returncode
91 return self.process.returncode
92
92
93 def get_first_client_response(self):
93 def get_first_client_response(self):
94 signal.signal(signal.SIGALRM, self.interrupt)
94 signal.signal(signal.SIGALRM, self.interrupt)
95 signal.alarm(self.timeout)
95 signal.alarm(self.timeout)
96 first_response = self._read_first_client_response()
96 first_response = self._read_first_client_response()
97 signal.alarm(0)
97 signal.alarm(0)
98 return (
98 return (
99 self._parse_first_client_response(first_response)
99 self._parse_first_client_response(first_response)
100 if first_response else None)
100 if first_response else None)
101
101
102 def patch_first_client_response(self, response, **kwargs):
102 def patch_first_client_response(self, response, **kwargs):
103 self.create_hooks_env()
103 self.create_hooks_env()
104 data = response.copy()
104 data = response.copy()
105 data.update(kwargs)
105 data.update(kwargs)
106 data['url'] = self._svn_string(data['url'])
106 data['url'] = self._svn_string(data['url'])
107 data['ra_client'] = self._svn_string(data['ra_client'])
107 data['ra_client'] = self._svn_string(data['ra_client'])
108 data['client'] = data['client'] or ''
108 data['client'] = data['client'] or ''
109 buffer_ = (
109 buffer_ = (
110 "( {version} ( {capabilities} ) {url}{ra_client}"
110 "( {version} ( {capabilities} ) {url}{ra_client}"
111 "( {client}) ) ".format(**data))
111 "( {client}) ) ".format(**data))
112 self.process.stdin.write(buffer_)
112 self.process.stdin.write(buffer_)
113
113
114 def fail(self, message):
114 def fail(self, message):
115 print(
115 print(
116 "( failure ( ( 210005 {message} 0: 0 ) ) )".format(
116 "( failure ( ( 210005 {message} 0: 0 ) ) )".format(
117 message=self._svn_string(message)))
117 message=self._svn_string(message)))
118 self.remove_configs()
118 self.remove_configs()
119 self.process.kill()
119 self.process.kill()
120
120
121 def interrupt(self, signum, frame):
121 def interrupt(self, signum, frame):
122 self.fail("Exited by timeout")
122 self.fail("Exited by timeout")
123
123
124 def _svn_string(self, str_):
124 def _svn_string(self, str_):
125 if not str_:
125 if not str_:
126 return ''
126 return ''
127 return '{length}:{string} '.format(length=len(str_), string=str_)
127 return '{length}:{string} '.format(length=len(str_), string=str_)
128
128
129 def _read_first_client_response(self):
129 def _read_first_client_response(self):
130 buffer_ = ""
130 buffer_ = ""
131 brackets_stack = []
131 brackets_stack = []
132 while True:
132 while True:
133 next_byte = self.stdin.read(1)
133 next_byte = self.stdin.read(1)
134 buffer_ += next_byte
134 buffer_ += next_byte
135 if next_byte == "(":
135 if next_byte == "(":
136 brackets_stack.append(next_byte)
136 brackets_stack.append(next_byte)
137 elif next_byte == ")":
137 elif next_byte == ")":
138 brackets_stack.pop()
138 brackets_stack.pop()
139 elif next_byte == " " and not brackets_stack:
139 elif next_byte == " " and not brackets_stack:
140 break
140 break
141 return buffer_
141 return buffer_
142
142
143 def _parse_first_client_response(self, buffer_):
143 def _parse_first_client_response(self, buffer_):
144 """
144 """
145 According to the Subversion RA protocol, the first request
145 According to the Subversion RA protocol, the first request
146 should look like:
146 should look like:
147
147
148 ( version:number ( cap:word ... ) url:string ? ra-client:string
148 ( version:number ( cap:word ... ) url:string ? ra-client:string
149 ( ? client:string ) )
149 ( ? client:string ) )
150
150
151 Please check https://svn.apache.org/repos/asf/subversion/trunk/
151 Please check https://svn.apache.org/repos/asf/subversion/trunk/
152 subversion/libsvn_ra_svn/protocol
152 subversion/libsvn_ra_svn/protocol
153 """
153 """
154 version_re = r'(?P<version>\d+)'
154 version_re = r'(?P<version>\d+)'
155 capabilities_re = r'\(\s(?P<capabilities>[\w\d\-\ ]+)\s\)'
155 capabilities_re = r'\(\s(?P<capabilities>[\w\d\-\ ]+)\s\)'
156 url_re = r'\d+\:(?P<url>[\W\w]+)'
156 url_re = r'\d+\:(?P<url>[\W\w]+)'
157 ra_client_re = r'(\d+\:(?P<ra_client>[\W\w]+)\s)'
157 ra_client_re = r'(\d+\:(?P<ra_client>[\W\w]+)\s)'
158 client_re = r'(\d+\:(?P<client>[\W\w]+)\s)*'
158 client_re = r'(\d+\:(?P<client>[\W\w]+)\s)*'
159 regex = re.compile(
159 regex = re.compile(
160 r'^\(\s{version}\s{capabilities}\s{url}\s{ra_client}'
160 r'^\(\s{version}\s{capabilities}\s{url}\s{ra_client}'
161 r'\(\s{client}\)\s\)\s*$'.format(
161 r'\(\s{client}\)\s\)\s*$'.format(
162 version=version_re, capabilities=capabilities_re,
162 version=version_re, capabilities=capabilities_re,
163 url=url_re, ra_client=ra_client_re, client=client_re))
163 url=url_re, ra_client=ra_client_re, client=client_re))
164 matcher = regex.match(buffer_)
164 matcher = regex.match(buffer_)
165 return matcher.groupdict() if matcher else None
165 return matcher.groupdict() if matcher else None
166
166
167 def run(self, extras):
167 def run(self, extras):
168 action = 'pull'
168 action = 'pull'
169 self.create_svn_config()
169 self.create_svn_config()
170 self.start()
170 self.start()
171
171
172 first_response = self.get_first_client_response()
172 first_response = self.get_first_client_response()
173 if not first_response:
173 if not first_response:
174 self.fail("Repository name cannot be extracted")
174 self.fail("Repository name cannot be extracted")
175 return 1
176
175
177 url_parts = urlparse.urlparse(first_response['url'])
176 url_parts = urlparse.urlparse(first_response['url'])
178 self.server.repo_name = url_parts.path.strip('/')
177 self.server.repo_name = url_parts.path.strip('/')
179
178
180 exit_code = self.server._check_permissions(action)
179 exit_code = self.server._check_permissions(action)
181 if exit_code:
180 if exit_code:
182 return exit_code
181 return exit_code
183
182
184 # set the readonly flag to False if we have proper permissions
183 # set the readonly flag to False if we have proper permissions
185 if self.server.has_write_perm():
184 if self.server.has_write_perm():
186 self.read_only = False
185 self.read_only = False
187 self.server.update_environment(action=action, extras=extras)
186 self.server.update_environment(action=action, extras=extras)
188
187
189 self.patch_first_client_response(first_response)
188 self.patch_first_client_response(first_response)
190 self.sync()
189 self.sync()
191 return self.return_code
190 return self.return_code
192
191
193
192
194 class SubversionServer(VcsServer):
193 class SubversionServer(VcsServer):
195 backend = 'svn'
194 backend = 'svn'
196
195
197 def __init__(self, store, ini_path, repo_name,
196 def __init__(self, store, ini_path, repo_name,
198 user, user_permissions, config, env):
197 user, user_permissions, config, env):
199 super(SubversionServer, self)\
198 super(SubversionServer, self)\
200 .__init__(user, user_permissions, config, env)
199 .__init__(user, user_permissions, config, env)
201 self.store = store
200 self.store = store
202 self.ini_path = ini_path
201 self.ini_path = ini_path
203 # this is set in .run() from input stream
202 # this is set in .run() from input stream
204 self.repo_name = repo_name
203 self.repo_name = repo_name
205 self._path = self.svn_path = config.get(
204 self._path = self.svn_path = config.get(
206 'app:main', 'ssh.executable.svn')
205 'app:main', 'ssh.executable.svn')
207
206
208 self.tunnel = SubversionTunnelWrapper(server=self)
207 self.tunnel = SubversionTunnelWrapper(server=self)
209
208
210 def _handle_tunnel(self, extras):
209 def _handle_tunnel(self, extras):
211
210
212 # pre-auth
211 # pre-auth
213 action = 'pull'
212 action = 'pull'
214 # Special case for SVN, we extract repo name at later stage
213 # Special case for SVN, we extract repo name at later stage
215 # exit_code = self._check_permissions(action)
214 # exit_code = self._check_permissions(action)
216 # if exit_code:
215 # if exit_code:
217 # return exit_code, False
216 # return exit_code, False
218
217
219 req = self.env['request']
218 req = self.env['request']
220 server_url = req.host_url + req.script_name
219 server_url = req.host_url + req.script_name
221 extras['server_url'] = server_url
220 extras['server_url'] = server_url
222
221
223 log.debug('Using %s binaries from path %s', self.backend, self._path)
222 log.debug('Using %s binaries from path %s', self.backend, self._path)
224 exit_code = self.tunnel.run(extras)
223 exit_code = self.tunnel.run(extras)
225
224
226 return exit_code, action == "push"
225 return exit_code, action == "push"
227
226
228
227
General Comments 0
You need to be logged in to leave comments. Login now