##// END OF EJS Templates
ssh: fix invocation of custom hgrc
marcink -
r3660:703a84f2 default
parent child Browse files
Show More
@@ -1,147 +1,147 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 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 sys
22 import sys
23 import logging
23 import logging
24 import tempfile
24 import tempfile
25 import textwrap
25 import textwrap
26 import collections
26 import collections
27 from .base import VcsServer
27 from .base import VcsServer
28 from rhodecode.model.db import RhodeCodeUi
28 from rhodecode.model.db import RhodeCodeUi
29 from rhodecode.model.settings import VcsSettingsModel
29 from rhodecode.model.settings import VcsSettingsModel
30
30
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33
33
34 class MercurialTunnelWrapper(object):
34 class MercurialTunnelWrapper(object):
35 process = None
35 process = None
36
36
37 def __init__(self, server):
37 def __init__(self, server):
38 self.server = server
38 self.server = server
39 self.stdin = sys.stdin
39 self.stdin = sys.stdin
40 self.stdout = sys.stdout
40 self.stdout = sys.stdout
41 self.hooks_env_fd, self.hooks_env_path = tempfile.mkstemp(prefix='hgrc_rhodecode_')
41 self.hooks_env_fd, self.hooks_env_path = tempfile.mkstemp(prefix='hgrc_rhodecode_')
42
42
43 def create_hooks_env(self):
43 def create_hooks_env(self):
44 repo_name = self.server.repo_name
44 repo_name = self.server.repo_name
45 hg_flags = self.config_to_hgrc(repo_name)
45 hg_flags = self.server.config_to_hgrc(repo_name)
46
46
47 content = textwrap.dedent(
47 content = textwrap.dedent(
48 '''
48 '''
49 # RhodeCode SSH hooks version=2.0.0
49 # RhodeCode SSH hooks version=2.0.0
50 {custom}
50 {custom}
51 '''
51 '''
52 ).format(custom='\n'.join(hg_flags))
52 ).format(custom='\n'.join(hg_flags))
53
53
54 root = self.server.get_root_store()
54 root = self.server.get_root_store()
55 hgrc_custom = os.path.join(root, repo_name, '.hg', 'hgrc_rhodecode')
55 hgrc_custom = os.path.join(root, repo_name, '.hg', 'hgrc_rhodecode')
56 hgrc_main = os.path.join(root, repo_name, '.hg', 'hgrc')
56 hgrc_main = os.path.join(root, repo_name, '.hg', 'hgrc')
57
57
58 # cleanup custom hgrc file
58 # cleanup custom hgrc file
59 if os.path.isfile(hgrc_custom):
59 if os.path.isfile(hgrc_custom):
60 with open(hgrc_custom, 'wb') as f:
60 with open(hgrc_custom, 'wb') as f:
61 f.write('')
61 f.write('')
62 log.debug('Cleanup custom hgrc file under %s', hgrc_custom)
62 log.debug('Cleanup custom hgrc file under %s', hgrc_custom)
63
63
64 # write temp
64 # write temp
65 with os.fdopen(self.hooks_env_fd, 'w') as hooks_env_file:
65 with os.fdopen(self.hooks_env_fd, 'w') as hooks_env_file:
66 hooks_env_file.write(content)
66 hooks_env_file.write(content)
67
67
68 return self.hooks_env_path
68 return self.hooks_env_path
69
69
70 def remove_configs(self):
70 def remove_configs(self):
71 os.remove(self.hooks_env_path)
71 os.remove(self.hooks_env_path)
72
72
73 def command(self, hgrc_path):
73 def command(self, hgrc_path):
74 root = self.server.get_root_store()
74 root = self.server.get_root_store()
75
75
76 command = (
76 command = (
77 "cd {root}; HGRCPATH={hgrc} {hg_path} -R {root}{repo_name} "
77 "cd {root}; HGRCPATH={hgrc} {hg_path} -R {root}{repo_name} "
78 "serve --stdio".format(
78 "serve --stdio".format(
79 root=root, hg_path=self.server.hg_path,
79 root=root, hg_path=self.server.hg_path,
80 repo_name=self.server.repo_name, hgrc=hgrc_path))
80 repo_name=self.server.repo_name, hgrc=hgrc_path))
81 log.debug("Final CMD: %s", command)
81 log.debug("Final CMD: %s", command)
82 return command
82 return command
83
83
84 def run(self, extras):
84 def run(self, extras):
85 # at this point we cannot tell, we do further ACL checks
85 # at this point we cannot tell, we do further ACL checks
86 # inside the hooks
86 # inside the hooks
87 action = '?'
87 action = '?'
88 # permissions are check via `pre_push_ssh_auth` hook
88 # permissions are check via `pre_push_ssh_auth` hook
89 self.server.update_environment(action=action, extras=extras)
89 self.server.update_environment(action=action, extras=extras)
90 custom_hgrc_file = self.create_hooks_env()
90 custom_hgrc_file = self.create_hooks_env()
91
91
92 try:
92 try:
93 return os.system(self.command(custom_hgrc_file))
93 return os.system(self.command(custom_hgrc_file))
94 finally:
94 finally:
95 self.remove_configs()
95 self.remove_configs()
96
96
97
97
98 class MercurialServer(VcsServer):
98 class MercurialServer(VcsServer):
99 backend = 'hg'
99 backend = 'hg'
100 cli_flags = ['phases', 'largefiles', 'extensions', 'experimental', 'hooks']
100 cli_flags = ['phases', 'largefiles', 'extensions', 'experimental', 'hooks']
101
101
102 def __init__(self, store, ini_path, repo_name, user, user_permissions, config, env):
102 def __init__(self, store, ini_path, repo_name, user, user_permissions, config, env):
103 super(MercurialServer, self).__init__(user, user_permissions, config, env)
103 super(MercurialServer, self).__init__(user, user_permissions, config, env)
104
104
105 self.store = store
105 self.store = store
106 self.ini_path = ini_path
106 self.ini_path = ini_path
107 self.repo_name = repo_name
107 self.repo_name = repo_name
108 self._path = self.hg_path = config.get('app:main', 'ssh.executable.hg')
108 self._path = self.hg_path = config.get('app:main', 'ssh.executable.hg')
109 self.tunnel = MercurialTunnelWrapper(server=self)
109 self.tunnel = MercurialTunnelWrapper(server=self)
110
110
111 def config_to_hgrc(self, repo_name):
111 def config_to_hgrc(self, repo_name):
112 ui_sections = collections.defaultdict(list)
112 ui_sections = collections.defaultdict(list)
113 ui = VcsSettingsModel(repo=repo_name).get_ui_settings(section=None, key=None)
113 ui = VcsSettingsModel(repo=repo_name).get_ui_settings(section=None, key=None)
114
114
115 # write default hooks
115 # write default hooks
116 default_hooks = [
116 default_hooks = [
117 ('pretxnchangegroup.ssh_auth', 'python:vcsserver.hooks.pre_push_ssh_auth'),
117 ('pretxnchangegroup.ssh_auth', 'python:vcsserver.hooks.pre_push_ssh_auth'),
118 ('pretxnchangegroup.ssh', 'python:vcsserver.hooks.pre_push_ssh'),
118 ('pretxnchangegroup.ssh', 'python:vcsserver.hooks.pre_push_ssh'),
119 ('changegroup.ssh', 'python:vcsserver.hooks.post_push_ssh'),
119 ('changegroup.ssh', 'python:vcsserver.hooks.post_push_ssh'),
120
120
121 ('preoutgoing.ssh', 'python:vcsserver.hooks.pre_pull_ssh'),
121 ('preoutgoing.ssh', 'python:vcsserver.hooks.pre_pull_ssh'),
122 ('outgoing.ssh', 'python:vcsserver.hooks.post_pull_ssh'),
122 ('outgoing.ssh', 'python:vcsserver.hooks.post_pull_ssh'),
123 ]
123 ]
124
124
125 for k, v in default_hooks:
125 for k, v in default_hooks:
126 ui_sections['hooks'].append((k, v))
126 ui_sections['hooks'].append((k, v))
127
127
128 for entry in ui:
128 for entry in ui:
129 if not entry.active:
129 if not entry.active:
130 continue
130 continue
131 sec = entry.section
131 sec = entry.section
132 key = entry.key
132 key = entry.key
133
133
134 if sec in self.cli_flags:
134 if sec in self.cli_flags:
135 # we want only custom hooks, so we skip builtins
135 # we want only custom hooks, so we skip builtins
136 if sec == 'hooks' and key in RhodeCodeUi.HOOKS_BUILTIN:
136 if sec == 'hooks' and key in RhodeCodeUi.HOOKS_BUILTIN:
137 continue
137 continue
138
138
139 ui_sections[sec].append([key, entry.value])
139 ui_sections[sec].append([key, entry.value])
140
140
141 flags = []
141 flags = []
142 for _sec, key_val in ui_sections.items():
142 for _sec, key_val in ui_sections.items():
143 flags.append(' ')
143 flags.append(' ')
144 flags.append('[{}]'.format(_sec))
144 flags.append('[{}]'.format(_sec))
145 for key, val in key_val:
145 for key, val in key_val:
146 flags.append('{}= {}'.format(key, val))
146 flags.append('{}= {}'.format(key, val))
147 return flags
147 return flags
General Comments 0
You need to be logged in to leave comments. Login now