##// END OF EJS Templates
release: Merge default into stable for release preparation
milka -
r931:eba75433 merge stable
parent child Browse files
Show More
@@ -0,0 +1,10 b''
1 diff -rup configparser-4.0.2-orig/pyproject.toml configparser-4.0.2/pyproject.toml
2 --- configparser-4.0.2-orig/pyproject.toml 2021-03-22 21:28:11.000000000 +0100
3 +++ configparser-4.0.2/pyproject.toml 2021-03-22 21:28:11.000000000 +0100
4 @@ -1,5 +1,5 @@
5 [build-system]
6 -requires = ["setuptools>=40.7", "wheel", "setuptools_scm>=1.15"]
7 +requires = ["setuptools<=42.0", "wheel", "setuptools_scm<6.0.0"]
8 build-backend = "setuptools.build_meta"
9
10 [tool.black]
@@ -0,0 +1,7 b''
1 diff -rup importlib-metadata-1.6.0-orig/yproject.toml importlib-metadata-1.6.0/pyproject.toml
2 --- importlib-metadata-1.6.0-orig/yproject.toml 2021-03-22 22:10:33.000000000 +0100
3 +++ importlib-metadata-1.6.0/pyproject.toml 2021-03-22 22:11:09.000000000 +0100
4 @@ -1,3 +1,3 @@
5 [build-system]
6 -requires = ["setuptools>=30.3", "wheel", "setuptools_scm"]
7 +requires = ["setuptools<42.0", "wheel", "setuptools_scm<6.0.0"]
@@ -0,0 +1,10 b''
1 diff -rup zip-1.2.0-orig/pyproject.toml zip-1.2.0/pyproject.toml
2 --- zip-1.2.0-orig/pyproject.toml 2021-03-23 10:55:37.000000000 +0100
3 +++ zip-1.2.0/pyproject.toml 2021-03-23 10:56:05.000000000 +0100
4 @@ -1,5 +1,5 @@
5 [build-system]
6 -requires = ["setuptools>=34.4", "wheel", "setuptools_scm>=1.15"]
7 +requires = ["setuptools<42.0", "wheel", "setuptools_scm<6.0.0"]
8 build-backend = "setuptools.build_meta"
9
10 [tool.black]
@@ -1,6 +1,5 b''
1 1 [bumpversion]
2 current_version = 4.24.1
2 current_version = 4.25.0
3 3 message = release: Bump version {current_version} to {new_version}
4 4
5 5 [bumpversion:file:vcsserver/VERSION]
6
@@ -1,16 +1,14 b''
1 1 [DEFAULT]
2 2 done = false
3 3
4 4 [task:bump_version]
5 5 done = true
6 6
7 7 [task:fixes_on_stable]
8 done = true
9 8
10 9 [task:pip2nix_generated]
11 done = true
12 10
13 11 [release]
14 state = prepared
15 version = 4.24.1
12 state = in_progress
13 version = 4.25.0
16 14
@@ -1,12 +1,12 b''
1 1 diff -rup pytest-4.6.5-orig/setup.py pytest-4.6.5/setup.py
2 2 --- pytest-4.6.5-orig/setup.py 2018-04-10 10:23:04.000000000 +0200
3 3 +++ pytest-4.6.5/setup.py 2018-04-10 10:23:34.000000000 +0200
4 4 @@ -24,7 +24,7 @@ INSTALL_REQUIRES = [
5 5 def main():
6 6 setup(
7 7 use_scm_version={"write_to": "src/_pytest/_version.py"},
8 8 - setup_requires=["setuptools-scm", "setuptools>=40.0"],
9 + setup_requires=["setuptools-scm", "setuptools<=42.0"],
9 + setup_requires=["setuptools-scm<6.0.0", "setuptools<=42.0"],
10 10 package_dir={"": "src"},
11 11 # fmt: off
12 12 extras_require={ No newline at end of file
@@ -1,78 +1,126 b''
1 1 # Overrides for the generated python-packages.nix
2 2 #
3 3 # This function is intended to be used as an extension to the generated file
4 4 # python-packages.nix. The main objective is to add needed dependencies of C
5 5 # libraries and tweak the build instructions where needed.
6 6
7 7 { pkgs
8 8 , basePythonPackages
9 9 }:
10 10
11 11 let
12 12 sed = "sed -i";
13 13
14 14 in
15 15
16 16 self: super: {
17 17
18 18 "cffi" = super."cffi".override (attrs: {
19 19 buildInputs = [
20 20 pkgs.libffi
21 21 ];
22 22 });
23 23
24 "ipython" = super."ipython".override (attrs: {
25 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
26 self."setuptools-scm"
27 ];
28 });
29
24 30 "gevent" = super."gevent".override (attrs: {
25 31 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
26 # NOTE: (marcink) odd requirements from gevent aren't set properly,
32 # NOTE: (marcink) odd requirements from gevent aren not set properly,
27 33 # thus we need to inject psutil manually
28 34 self."psutil"
29 35 ];
30 36 });
31 37
32 38 "hgsubversion" = super."hgsubversion".override (attrs: {
33 39 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
34 40 pkgs.sqlite
35 41 #basePythonPackages.sqlite3
36 42 self.mercurial
37 43 ];
38 44 });
39 45
40 46 "subvertpy" = super."subvertpy".override (attrs: {
41 47 SVN_PREFIX = "${pkgs.subversion.dev}";
42 48 propagatedBuildInputs = [
43 49 pkgs.apr.dev
44 50 pkgs.aprutil
45 51 pkgs.subversion
46 52 ];
47 53 });
48 54
49 55 "mercurial" = super."mercurial".override (attrs: {
50 56 propagatedBuildInputs = [
51 57 # self.python.modules.curses
52 58 ];
53 59 });
54 60
55 61 "dulwich" = super."dulwich".override (attrs: {
56 62 patches = [
57 63 ./patches/dulwich/handle-dir-refs.patch
58 64 ];
59 65 });
60 66
61 67 "pygit2" = super."pygit2".override (attrs: {
62 68 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
63 69 pkgs.libffi
64 70 pkgs.libgit2rc
65 71 ];
66 72 });
67 73
68 74 "pytest" = super."pytest".override (attrs: {
69 75 patches = [
70 76 ./patches/pytest/setuptools.patch
71 77 ];
72 78 });
73 79
80 "pytest-runner" = super."pytest-runner".override (attrs: {
81 propagatedBuildInputs = [
82 self."setuptools-scm"
83 ];
84 });
85
86 "py" = super."py".override (attrs: {
87 propagatedBuildInputs = [
88 self."setuptools-scm"
89 ];
90 });
91
92 "configparser" = super."configparser".override (attrs: {
93 patches = [
94 ./patches/configparser/pyproject.patch
95 ];
96 propagatedBuildInputs = [
97 self."setuptools-scm"
98 ];
99 });
100
101 "importlib-metadata" = super."importlib-metadata".override (attrs: {
102
103 patches = [
104 ./patches/importlib_metadata/pyproject.patch
105 ];
106
107 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
108 self."setuptools-scm"
109 ];
110
111 });
112
113 "zipp" = super."zipp".override (attrs: {
114 patches = [
115 ./patches/zipp/pyproject.patch
116 ];
117 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
118 self."setuptools-scm"
119 ];
120 });
121
74 122 # Avoid that base packages screw up the build process
75 123 inherit (basePythonPackages)
76 124 setuptools;
77 125
78 126 }
@@ -1,1090 +1,1103 b''
1 1 # Generated by pip2nix 0.8.0.dev1
2 2 # See https://github.com/johbo/pip2nix
3 3
4 4 { pkgs, fetchurl, fetchgit, fetchhg }:
5 5
6 6 self: super: {
7 7 "atomicwrites" = super.buildPythonPackage {
8 8 name = "atomicwrites-1.3.0";
9 9 doCheck = false;
10 10 src = fetchurl {
11 11 url = "https://files.pythonhosted.org/packages/ec/0f/cd484ac8820fed363b374af30049adc8fd13065720fd4f4c6be8a2309da7/atomicwrites-1.3.0.tar.gz";
12 12 sha256 = "19ngcscdf3jsqmpcxn6zl5b6anmsajb6izp1smcd1n02midl9abm";
13 13 };
14 14 meta = {
15 15 license = [ pkgs.lib.licenses.mit ];
16 16 };
17 17 };
18 18 "attrs" = super.buildPythonPackage {
19 19 name = "attrs-19.3.0";
20 20 doCheck = false;
21 21 src = fetchurl {
22 22 url = "https://files.pythonhosted.org/packages/98/c3/2c227e66b5e896e15ccdae2e00bbc69aa46e9a8ce8869cc5fa96310bf612/attrs-19.3.0.tar.gz";
23 23 sha256 = "0wky4h28n7xnr6xv69p9z6kv8bzn50d10c3drmd9ds8gawbcxdzp";
24 24 };
25 25 meta = {
26 26 license = [ pkgs.lib.licenses.mit ];
27 27 };
28 28 };
29 29 "backports.shutil-get-terminal-size" = super.buildPythonPackage {
30 30 name = "backports.shutil-get-terminal-size-1.0.0";
31 31 doCheck = false;
32 32 src = fetchurl {
33 33 url = "https://files.pythonhosted.org/packages/ec/9c/368086faa9c016efce5da3e0e13ba392c9db79e3ab740b763fe28620b18b/backports.shutil_get_terminal_size-1.0.0.tar.gz";
34 34 sha256 = "107cmn7g3jnbkp826zlj8rrj19fam301qvaqf0f3905f5217lgki";
35 35 };
36 36 meta = {
37 37 license = [ pkgs.lib.licenses.mit ];
38 38 };
39 39 };
40 40 "beautifulsoup4" = super.buildPythonPackage {
41 41 name = "beautifulsoup4-4.6.3";
42 42 doCheck = false;
43 43 src = fetchurl {
44 44 url = "https://files.pythonhosted.org/packages/88/df/86bffad6309f74f3ff85ea69344a078fc30003270c8df6894fca7a3c72ff/beautifulsoup4-4.6.3.tar.gz";
45 45 sha256 = "041dhalzjciw6qyzzq7a2k4h1yvyk76xigp35hv5ibnn448ydy4h";
46 46 };
47 47 meta = {
48 48 license = [ pkgs.lib.licenses.mit ];
49 49 };
50 50 };
51 51 "cffi" = super.buildPythonPackage {
52 52 name = "cffi-1.12.3";
53 53 doCheck = false;
54 54 propagatedBuildInputs = [
55 55 self."pycparser"
56 56 ];
57 57 src = fetchurl {
58 58 url = "https://files.pythonhosted.org/packages/93/1a/ab8c62b5838722f29f3daffcc8d4bd61844aa9b5f437341cc890ceee483b/cffi-1.12.3.tar.gz";
59 59 sha256 = "0x075521fxwv0mfp4cqzk7lvmw4n94bjw601qkcv314z5s182704";
60 60 };
61 61 meta = {
62 62 license = [ pkgs.lib.licenses.mit ];
63 63 };
64 64 };
65 65 "configobj" = super.buildPythonPackage {
66 66 name = "configobj-5.0.6";
67 67 doCheck = false;
68 68 propagatedBuildInputs = [
69 69 self."six"
70 70 ];
71 71 src = fetchurl {
72 72 url = "https://code.rhodecode.com/upstream/configobj/artifacts/download/0-012de99a-b1e1-4f64-a5c0-07a98a41b324.tar.gz?md5=6a513f51fe04b2c18cf84c1395a7c626";
73 73 sha256 = "0kqfrdfr14mw8yd8qwq14dv2xghpkjmd3yjsy8dfcbvpcc17xnxp";
74 74 };
75 75 meta = {
76 76 license = [ pkgs.lib.licenses.bsdOriginal ];
77 77 };
78 78 };
79 79 "configparser" = super.buildPythonPackage {
80 80 name = "configparser-4.0.2";
81 81 doCheck = false;
82 82 src = fetchurl {
83 83 url = "https://files.pythonhosted.org/packages/16/4f/48975536bd488d3a272549eb795ac4a13a5f7fcdc8995def77fbef3532ee/configparser-4.0.2.tar.gz";
84 84 sha256 = "1priacxym85yjcf68hh38w55nqswaxp71ryjyfdk222kg9l85ln7";
85 85 };
86 86 meta = {
87 87 license = [ pkgs.lib.licenses.mit ];
88 88 };
89 89 };
90 90 "contextlib2" = super.buildPythonPackage {
91 91 name = "contextlib2-0.6.0.post1";
92 92 doCheck = false;
93 93 src = fetchurl {
94 94 url = "https://files.pythonhosted.org/packages/02/54/669207eb72e3d8ae8b38aa1f0703ee87a0e9f88f30d3c0a47bebdb6de242/contextlib2-0.6.0.post1.tar.gz";
95 95 sha256 = "0bhnr2ac7wy5l85ji909gyljyk85n92w8pdvslmrvc8qih4r1x01";
96 96 };
97 97 meta = {
98 98 license = [ pkgs.lib.licenses.psfl ];
99 99 };
100 100 };
101 101 "cov-core" = super.buildPythonPackage {
102 102 name = "cov-core-1.15.0";
103 103 doCheck = false;
104 104 propagatedBuildInputs = [
105 105 self."coverage"
106 106 ];
107 107 src = fetchurl {
108 108 url = "https://files.pythonhosted.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
109 109 sha256 = "0k3np9ymh06yv1ib96sb6wfsxjkqhmik8qfsn119vnhga9ywc52a";
110 110 };
111 111 meta = {
112 112 license = [ pkgs.lib.licenses.mit ];
113 113 };
114 114 };
115 115 "coverage" = super.buildPythonPackage {
116 116 name = "coverage-4.5.4";
117 117 doCheck = false;
118 118 src = fetchurl {
119 119 url = "https://files.pythonhosted.org/packages/85/d5/818d0e603685c4a613d56f065a721013e942088047ff1027a632948bdae6/coverage-4.5.4.tar.gz";
120 120 sha256 = "0p0j4di6h8k6ica7jwwj09azdcg4ycxq60i9qsskmsg94cd9yzg0";
121 121 };
122 122 meta = {
123 123 license = [ pkgs.lib.licenses.asl20 ];
124 124 };
125 125 };
126 126 "decorator" = super.buildPythonPackage {
127 127 name = "decorator-4.1.2";
128 128 doCheck = false;
129 129 src = fetchurl {
130 130 url = "https://files.pythonhosted.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz";
131 131 sha256 = "1d8npb11kxyi36mrvjdpcjij76l5zfyrz2f820brf0l0rcw4vdkw";
132 132 };
133 133 meta = {
134 134 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
135 135 };
136 136 };
137 137 "dogpile.cache" = super.buildPythonPackage {
138 138 name = "dogpile.cache-0.9.0";
139 139 doCheck = false;
140 140 propagatedBuildInputs = [
141 141 self."decorator"
142 142 ];
143 143 src = fetchurl {
144 144 url = "https://files.pythonhosted.org/packages/ac/6a/9ac405686a94b7f009a20a50070a5786b0e1aedc707b88d40d0c4b51a82e/dogpile.cache-0.9.0.tar.gz";
145 145 sha256 = "0sr1fn6b4k5bh0cscd9yi8csqxvj4ngzildav58x5p694mc86j5k";
146 146 };
147 147 meta = {
148 148 license = [ pkgs.lib.licenses.bsdOriginal ];
149 149 };
150 150 };
151 151 "dogpile.core" = super.buildPythonPackage {
152 152 name = "dogpile.core-0.4.1";
153 153 doCheck = false;
154 154 src = fetchurl {
155 155 url = "https://files.pythonhosted.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz";
156 156 sha256 = "0xpdvg4kr1isfkrh1rfsh7za4q5a5s6l2kf9wpvndbwf3aqjyrdy";
157 157 };
158 158 meta = {
159 159 license = [ pkgs.lib.licenses.bsdOriginal ];
160 160 };
161 161 };
162 162 "dulwich" = super.buildPythonPackage {
163 163 name = "dulwich-0.13.0";
164 164 doCheck = false;
165 165 src = fetchurl {
166 166 url = "https://files.pythonhosted.org/packages/84/95/732d280eee829dacc954e8109f97b47abcadcca472c2ab013e1635eb4792/dulwich-0.13.0.tar.gz";
167 167 sha256 = "0f1jwvrh549c4rgavkn3wizrch904s73s4fmrxykxy9cw8s57lwf";
168 168 };
169 169 meta = {
170 170 license = [ pkgs.lib.licenses.gpl2Plus ];
171 171 };
172 172 };
173 173 "enum34" = super.buildPythonPackage {
174 174 name = "enum34-1.1.10";
175 175 doCheck = false;
176 176 src = fetchurl {
177 177 url = "https://files.pythonhosted.org/packages/11/c4/2da1f4952ba476677a42f25cd32ab8aaf0e1c0d0e00b89822b835c7e654c/enum34-1.1.10.tar.gz";
178 178 sha256 = "0j7ji699fwswm4vg6w1v07fkbf8dkzdm6gfh88jvs5nqgr3sgrnc";
179 179 };
180 180 meta = {
181 181 license = [ pkgs.lib.licenses.bsdOriginal ];
182 182 };
183 183 };
184 184 "funcsigs" = super.buildPythonPackage {
185 185 name = "funcsigs-1.0.2";
186 186 doCheck = false;
187 187 src = fetchurl {
188 188 url = "https://files.pythonhosted.org/packages/94/4a/db842e7a0545de1cdb0439bb80e6e42dfe82aaeaadd4072f2263a4fbed23/funcsigs-1.0.2.tar.gz";
189 189 sha256 = "0l4g5818ffyfmfs1a924811azhjj8ax9xd1cffr1mzd3ycn0zfx7";
190 190 };
191 191 meta = {
192 192 license = [ { fullName = "ASL"; } pkgs.lib.licenses.asl20 ];
193 193 };
194 194 };
195 195 "gevent" = super.buildPythonPackage {
196 196 name = "gevent-1.5.0";
197 197 doCheck = false;
198 198 propagatedBuildInputs = [
199 199 self."greenlet"
200 200 ];
201 201 src = fetchurl {
202 202 url = "https://files.pythonhosted.org/packages/5a/79/2c63d385d017b5dd7d70983a463dfd25befae70c824fedb857df6e72eff2/gevent-1.5.0.tar.gz";
203 203 sha256 = "0aac3d4vhv5n4rsb6cqzq0d1xx9immqz4fmpddw35yxkwdc450dj";
204 204 };
205 205 meta = {
206 206 license = [ pkgs.lib.licenses.mit ];
207 207 };
208 208 };
209 209 "gprof2dot" = super.buildPythonPackage {
210 210 name = "gprof2dot-2017.9.19";
211 211 doCheck = false;
212 212 src = fetchurl {
213 213 url = "https://files.pythonhosted.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz";
214 214 sha256 = "17ih23ld2nzgc3xwgbay911l6lh96jp1zshmskm17n1gg2i7mg6f";
215 215 };
216 216 meta = {
217 217 license = [ { fullName = "GNU Lesser General Public License v3 or later (LGPLv3+)"; } { fullName = "LGPL"; } ];
218 218 };
219 219 };
220 220 "greenlet" = super.buildPythonPackage {
221 221 name = "greenlet-0.4.15";
222 222 doCheck = false;
223 223 src = fetchurl {
224 224 url = "https://files.pythonhosted.org/packages/f8/e8/b30ae23b45f69aa3f024b46064c0ac8e5fcb4f22ace0dca8d6f9c8bbe5e7/greenlet-0.4.15.tar.gz";
225 225 sha256 = "1g4g1wwc472ds89zmqlpyan3fbnzpa8qm48z3z1y6mlk44z485ll";
226 226 };
227 227 meta = {
228 228 license = [ pkgs.lib.licenses.mit ];
229 229 };
230 230 };
231 231 "gunicorn" = super.buildPythonPackage {
232 232 name = "gunicorn-19.9.0";
233 233 doCheck = false;
234 234 src = fetchurl {
235 235 url = "https://files.pythonhosted.org/packages/47/52/68ba8e5e8ba251e54006a49441f7ccabca83b6bef5aedacb4890596c7911/gunicorn-19.9.0.tar.gz";
236 236 sha256 = "1wzlf4xmn6qjirh5w81l6i6kqjnab1n1qqkh7zsj1yb6gh4n49ps";
237 237 };
238 238 meta = {
239 239 license = [ pkgs.lib.licenses.mit ];
240 240 };
241 241 };
242 242 "hg-evolve" = super.buildPythonPackage {
243 243 name = "hg-evolve-9.1.0";
244 244 doCheck = false;
245 245 src = fetchurl {
246 246 url = "https://files.pythonhosted.org/packages/20/36/5a6655975aa0c663be91098d31a0b24841acad44fe896aa2bdee77c6b883/hg-evolve-9.1.0.tar.gz";
247 247 sha256 = "1mna81cmzxxn7s2nwz3g1xgdjlcc1axkvfmwg7gjqghwn3pdraps";
248 248 };
249 249 meta = {
250 250 license = [ { fullName = "GPLv2+"; } ];
251 251 };
252 252 };
253 253 "hgsubversion" = super.buildPythonPackage {
254 254 name = "hgsubversion-1.9.3";
255 255 doCheck = false;
256 256 propagatedBuildInputs = [
257 257 self."mercurial"
258 258 self."subvertpy"
259 259 ];
260 260 src = fetchurl {
261 261 url = "https://files.pythonhosted.org/packages/a3/53/6d205e641f3e09abcf1ddaed66e5e4b20da22d0145566d440a02c9e35f0d/hgsubversion-1.9.3.tar.gz";
262 262 sha256 = "0nymcjlch8c4zjbncrs30p2nrbylsf25g3h6mr0zzzxr141h3sig";
263 263 };
264 264 meta = {
265 265 license = [ pkgs.lib.licenses.gpl1 ];
266 266 };
267 267 };
268 268 "hupper" = super.buildPythonPackage {
269 269 name = "hupper-1.10.2";
270 270 doCheck = false;
271 271 src = fetchurl {
272 272 url = "https://files.pythonhosted.org/packages/41/24/ea90fef04706e54bd1635c05c50dc9cf87cda543c59303a03e7aa7dda0ce/hupper-1.10.2.tar.gz";
273 273 sha256 = "0am0p6g5cz6xmcaf04xq8q6dzdd9qz0phj6gcmpsckf2mcyza61q";
274 274 };
275 275 meta = {
276 276 license = [ pkgs.lib.licenses.mit ];
277 277 };
278 278 };
279 279 "importlib-metadata" = super.buildPythonPackage {
280 280 name = "importlib-metadata-1.6.0";
281 281 doCheck = false;
282 282 propagatedBuildInputs = [
283 283 self."zipp"
284 284 self."pathlib2"
285 285 self."contextlib2"
286 286 self."configparser"
287 287 ];
288 288 src = fetchurl {
289 289 url = "https://files.pythonhosted.org/packages/b4/1b/baab42e3cd64c9d5caac25a9d6c054f8324cdc38975a44d600569f1f7158/importlib_metadata-1.6.0.tar.gz";
290 290 sha256 = "07icyggasn38yv2swdrd8z6i0plazmc9adavsdkbqqj91j53ll9l";
291 291 };
292 292 meta = {
293 293 license = [ pkgs.lib.licenses.asl20 ];
294 294 };
295 295 };
296 296 "ipdb" = super.buildPythonPackage {
297 297 name = "ipdb-0.13.2";
298 298 doCheck = false;
299 299 propagatedBuildInputs = [
300 300 self."setuptools"
301 301 self."ipython"
302 302 ];
303 303 src = fetchurl {
304 304 url = "https://files.pythonhosted.org/packages/2c/bb/a3e1a441719ebd75c6dac8170d3ddba884b7ee8a5c0f9aefa7297386627a/ipdb-0.13.2.tar.gz";
305 305 sha256 = "0jcd849rx30y3wcgzsqbn06v0yjlzvb9x3076q0yxpycdwm1ryvp";
306 306 };
307 307 meta = {
308 308 license = [ pkgs.lib.licenses.bsdOriginal ];
309 309 };
310 310 };
311 311 "ipython" = super.buildPythonPackage {
312 312 name = "ipython-5.1.0";
313 313 doCheck = false;
314 314 propagatedBuildInputs = [
315 315 self."setuptools"
316 316 self."decorator"
317 317 self."pickleshare"
318 318 self."simplegeneric"
319 319 self."traitlets"
320 320 self."prompt-toolkit"
321 321 self."pygments"
322 322 self."pexpect"
323 323 self."backports.shutil-get-terminal-size"
324 324 self."pathlib2"
325 325 self."pexpect"
326 326 ];
327 327 src = fetchurl {
328 328 url = "https://files.pythonhosted.org/packages/89/63/a9292f7cd9d0090a0f995e1167f3f17d5889dcbc9a175261719c513b9848/ipython-5.1.0.tar.gz";
329 329 sha256 = "0qdrf6aj9kvjczd5chj1my8y2iq09am9l8bb2a1334a52d76kx3y";
330 330 };
331 331 meta = {
332 332 license = [ pkgs.lib.licenses.bsdOriginal ];
333 333 };
334 334 };
335 335 "ipython-genutils" = super.buildPythonPackage {
336 336 name = "ipython-genutils-0.2.0";
337 337 doCheck = false;
338 338 src = fetchurl {
339 339 url = "https://files.pythonhosted.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz";
340 340 sha256 = "1a4bc9y8hnvq6cp08qs4mckgm6i6ajpndp4g496rvvzcfmp12bpb";
341 341 };
342 342 meta = {
343 343 license = [ pkgs.lib.licenses.bsdOriginal ];
344 344 };
345 345 };
346 346 "mako" = super.buildPythonPackage {
347 347 name = "mako-1.1.0";
348 348 doCheck = false;
349 349 propagatedBuildInputs = [
350 350 self."markupsafe"
351 351 ];
352 352 src = fetchurl {
353 353 url = "https://files.pythonhosted.org/packages/b0/3c/8dcd6883d009f7cae0f3157fb53e9afb05a0d3d33b3db1268ec2e6f4a56b/Mako-1.1.0.tar.gz";
354 354 sha256 = "0jqa3qfpykyn4fmkn0kh6043sfls7br8i2bsdbccazcvk9cijsd3";
355 355 };
356 356 meta = {
357 357 license = [ pkgs.lib.licenses.mit ];
358 358 };
359 359 };
360 360 "markupsafe" = super.buildPythonPackage {
361 361 name = "markupsafe-1.1.1";
362 362 doCheck = false;
363 363 src = fetchurl {
364 364 url = "https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz";
365 365 sha256 = "0sqipg4fk7xbixqd8kq6rlkxj664d157bdwbh93farcphf92x1r9";
366 366 };
367 367 meta = {
368 368 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd3 ];
369 369 };
370 370 };
371 371 "mercurial" = super.buildPythonPackage {
372 372 name = "mercurial-5.1.1";
373 373 doCheck = false;
374 374 src = fetchurl {
375 375 url = "https://files.pythonhosted.org/packages/22/39/e1a95f6048aa0785b82f5faad8281ae7320894a635cb4a57e19479639c92/mercurial-5.1.1.tar.gz";
376 376 sha256 = "17z42rfjdkrks4grzgac66nfh285zf1pwxd2zwx1p71pw2jqpz1m";
377 377 };
378 378 meta = {
379 379 license = [ pkgs.lib.licenses.gpl1 pkgs.lib.licenses.gpl2Plus ];
380 380 };
381 381 };
382 382 "mock" = super.buildPythonPackage {
383 383 name = "mock-3.0.5";
384 384 doCheck = false;
385 385 propagatedBuildInputs = [
386 386 self."six"
387 387 self."funcsigs"
388 388 ];
389 389 src = fetchurl {
390 390 url = "https://files.pythonhosted.org/packages/2e/ab/4fe657d78b270aa6a32f027849513b829b41b0f28d9d8d7f8c3d29ea559a/mock-3.0.5.tar.gz";
391 391 sha256 = "1hrp6j0yrx2xzylfv02qa8kph661m6yq4p0mc8fnimch9j4psrc3";
392 392 };
393 393 meta = {
394 394 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "OSI Approved :: BSD License"; } ];
395 395 };
396 396 };
397 397 "more-itertools" = super.buildPythonPackage {
398 398 name = "more-itertools-5.0.0";
399 399 doCheck = false;
400 400 propagatedBuildInputs = [
401 401 self."six"
402 402 ];
403 403 src = fetchurl {
404 404 url = "https://files.pythonhosted.org/packages/dd/26/30fc0d541d9fdf55faf5ba4b0fd68f81d5bd2447579224820ad525934178/more-itertools-5.0.0.tar.gz";
405 405 sha256 = "1r12cm6mcdwdzz7d47a6g4l437xsvapdlgyhqay3i2nrlv03da9q";
406 406 };
407 407 meta = {
408 408 license = [ pkgs.lib.licenses.mit ];
409 409 };
410 410 };
411 411 "msgpack-python" = super.buildPythonPackage {
412 412 name = "msgpack-python-0.5.6";
413 413 doCheck = false;
414 414 src = fetchurl {
415 415 url = "https://files.pythonhosted.org/packages/8a/20/6eca772d1a5830336f84aca1d8198e5a3f4715cd1c7fc36d3cc7f7185091/msgpack-python-0.5.6.tar.gz";
416 416 sha256 = "16wh8qgybmfh4pjp8vfv78mdlkxfmcasg78lzlnm6nslsfkci31p";
417 417 };
418 418 meta = {
419 419 license = [ pkgs.lib.licenses.asl20 ];
420 420 };
421 421 };
422 422 "packaging" = super.buildPythonPackage {
423 423 name = "packaging-20.3";
424 424 doCheck = false;
425 425 propagatedBuildInputs = [
426 426 self."pyparsing"
427 427 self."six"
428 428 ];
429 429 src = fetchurl {
430 430 url = "https://files.pythonhosted.org/packages/65/37/83e3f492eb52d771e2820e88105f605335553fe10422cba9d256faeb1702/packaging-20.3.tar.gz";
431 431 sha256 = "18xpablq278janh03bai9xd4kz9b0yfp6vflazn725ns9x3jna9w";
432 432 };
433 433 meta = {
434 434 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "BSD or Apache License, Version 2.0"; } pkgs.lib.licenses.asl20 ];
435 435 };
436 436 };
437 437 "pastedeploy" = super.buildPythonPackage {
438 438 name = "pastedeploy-2.1.0";
439 439 doCheck = false;
440 440 src = fetchurl {
441 441 url = "https://files.pythonhosted.org/packages/c4/e9/972a1c20318b3ae9edcab11a6cef64308fbae5d0d45ab52c6f8b2b8f35b8/PasteDeploy-2.1.0.tar.gz";
442 442 sha256 = "16qsq5y6mryslmbp5pn35x4z8z3ndp5rpgl42h226879nrw9hmg7";
443 443 };
444 444 meta = {
445 445 license = [ pkgs.lib.licenses.mit ];
446 446 };
447 447 };
448 448 "pathlib2" = super.buildPythonPackage {
449 449 name = "pathlib2-2.3.5";
450 450 doCheck = false;
451 451 propagatedBuildInputs = [
452 452 self."six"
453 453 self."scandir"
454 454 ];
455 455 src = fetchurl {
456 456 url = "https://files.pythonhosted.org/packages/94/d8/65c86584e7e97ef824a1845c72bbe95d79f5b306364fa778a3c3e401b309/pathlib2-2.3.5.tar.gz";
457 457 sha256 = "0s4qa8c082fdkb17izh4mfgwrjd1n5pya18wvrbwqdvvb5xs9nbc";
458 458 };
459 459 meta = {
460 460 license = [ pkgs.lib.licenses.mit ];
461 461 };
462 462 };
463 463 "pexpect" = super.buildPythonPackage {
464 464 name = "pexpect-4.8.0";
465 465 doCheck = false;
466 466 propagatedBuildInputs = [
467 467 self."ptyprocess"
468 468 ];
469 469 src = fetchurl {
470 470 url = "https://files.pythonhosted.org/packages/e5/9b/ff402e0e930e70467a7178abb7c128709a30dfb22d8777c043e501bc1b10/pexpect-4.8.0.tar.gz";
471 471 sha256 = "032cg337h8awydgypz6f4wx848lw8dyrj4zy988x0lyib4ws8rgw";
472 472 };
473 473 meta = {
474 474 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
475 475 };
476 476 };
477 477 "pickleshare" = super.buildPythonPackage {
478 478 name = "pickleshare-0.7.5";
479 479 doCheck = false;
480 480 propagatedBuildInputs = [
481 481 self."pathlib2"
482 482 ];
483 483 src = fetchurl {
484 484 url = "https://files.pythonhosted.org/packages/d8/b6/df3c1c9b616e9c0edbc4fbab6ddd09df9535849c64ba51fcb6531c32d4d8/pickleshare-0.7.5.tar.gz";
485 485 sha256 = "1jmghg3c53yp1i8cm6pcrm280ayi8621rwyav9fac7awjr3kss47";
486 486 };
487 487 meta = {
488 488 license = [ pkgs.lib.licenses.mit ];
489 489 };
490 490 };
491 491 "plaster" = super.buildPythonPackage {
492 492 name = "plaster-1.0";
493 493 doCheck = false;
494 494 propagatedBuildInputs = [
495 495 self."setuptools"
496 496 ];
497 497 src = fetchurl {
498 498 url = "https://files.pythonhosted.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz";
499 499 sha256 = "1hy8k0nv2mxq94y5aysk6hjk9ryb4bsd13g83m60hcyzxz3wflc3";
500 500 };
501 501 meta = {
502 502 license = [ pkgs.lib.licenses.mit ];
503 503 };
504 504 };
505 505 "plaster-pastedeploy" = super.buildPythonPackage {
506 506 name = "plaster-pastedeploy-0.7";
507 507 doCheck = false;
508 508 propagatedBuildInputs = [
509 509 self."pastedeploy"
510 510 self."plaster"
511 511 ];
512 512 src = fetchurl {
513 513 url = "https://files.pythonhosted.org/packages/99/69/2d3bc33091249266a1bd3cf24499e40ab31d54dffb4a7d76fe647950b98c/plaster_pastedeploy-0.7.tar.gz";
514 514 sha256 = "1zg7gcsvc1kzay1ry5p699rg2qavfsxqwl17mqxzr0gzw6j9679r";
515 515 };
516 516 meta = {
517 517 license = [ pkgs.lib.licenses.mit ];
518 518 };
519 519 };
520 520 "pluggy" = super.buildPythonPackage {
521 521 name = "pluggy-0.13.1";
522 522 doCheck = false;
523 523 propagatedBuildInputs = [
524 524 self."importlib-metadata"
525 525 ];
526 526 src = fetchurl {
527 527 url = "https://files.pythonhosted.org/packages/f8/04/7a8542bed4b16a65c2714bf76cf5a0b026157da7f75e87cc88774aa10b14/pluggy-0.13.1.tar.gz";
528 528 sha256 = "1c35qyhvy27q9ih9n899f3h4sdnpgq027dbiilly2qb5cvgarchm";
529 529 };
530 530 meta = {
531 531 license = [ pkgs.lib.licenses.mit ];
532 532 };
533 533 };
534 534 "prompt-toolkit" = super.buildPythonPackage {
535 535 name = "prompt-toolkit-1.0.18";
536 536 doCheck = false;
537 537 propagatedBuildInputs = [
538 538 self."six"
539 539 self."wcwidth"
540 540 ];
541 541 src = fetchurl {
542 542 url = "https://files.pythonhosted.org/packages/c5/64/c170e5b1913b540bf0c8ab7676b21fdd1d25b65ddeb10025c6ca43cccd4c/prompt_toolkit-1.0.18.tar.gz";
543 543 sha256 = "09h1153wgr5x2ny7ds0w2m81n3bb9j8hjb8sjfnrg506r01clkyx";
544 544 };
545 545 meta = {
546 546 license = [ pkgs.lib.licenses.bsdOriginal ];
547 547 };
548 548 };
549 549 "psutil" = super.buildPythonPackage {
550 550 name = "psutil-5.7.0";
551 551 doCheck = false;
552 552 src = fetchurl {
553 553 url = "https://files.pythonhosted.org/packages/c4/b8/3512f0e93e0db23a71d82485ba256071ebef99b227351f0f5540f744af41/psutil-5.7.0.tar.gz";
554 554 sha256 = "03jykdi3dgf1cdal9bv4fq9zjvzj9l9bs99gi5ar81sdl5nc2pk8";
555 555 };
556 556 meta = {
557 557 license = [ pkgs.lib.licenses.bsdOriginal ];
558 558 };
559 559 };
560 560 "ptyprocess" = super.buildPythonPackage {
561 561 name = "ptyprocess-0.6.0";
562 562 doCheck = false;
563 563 src = fetchurl {
564 564 url = "https://files.pythonhosted.org/packages/7d/2d/e4b8733cf79b7309d84c9081a4ab558c89d8c89da5961bf4ddb050ca1ce0/ptyprocess-0.6.0.tar.gz";
565 565 sha256 = "1h4lcd3w5nrxnsk436ar7fwkiy5rfn5wj2xwy9l0r4mdqnf2jgwj";
566 566 };
567 567 meta = {
568 568 license = [ ];
569 569 };
570 570 };
571 571 "py" = super.buildPythonPackage {
572 572 name = "py-1.8.0";
573 573 doCheck = false;
574 574 src = fetchurl {
575 575 url = "https://files.pythonhosted.org/packages/f1/5a/87ca5909f400a2de1561f1648883af74345fe96349f34f737cdfc94eba8c/py-1.8.0.tar.gz";
576 576 sha256 = "0lsy1gajva083pzc7csj1cvbmminb7b4l6a0prdzyb3fd829nqyw";
577 577 };
578 578 meta = {
579 579 license = [ pkgs.lib.licenses.mit ];
580 580 };
581 581 };
582 582 "pycparser" = super.buildPythonPackage {
583 583 name = "pycparser-2.20";
584 584 doCheck = false;
585 585 src = fetchurl {
586 586 url = "https://files.pythonhosted.org/packages/0f/86/e19659527668d70be91d0369aeaa055b4eb396b0f387a4f92293a20035bd/pycparser-2.20.tar.gz";
587 587 sha256 = "1w0m3xvlrzq4lkbvd1ngfm8mdw64r1yxy6n7djlw6qj5d0km6ird";
588 588 };
589 589 meta = {
590 590 license = [ pkgs.lib.licenses.bsdOriginal ];
591 591 };
592 592 };
593 593 "pygit2" = super.buildPythonPackage {
594 594 name = "pygit2-0.28.2";
595 595 doCheck = false;
596 596 propagatedBuildInputs = [
597 597 self."cffi"
598 598 self."six"
599 599 ];
600 600 src = fetchurl {
601 601 url = "https://files.pythonhosted.org/packages/4c/64/88c2a4eb2d22ca1982b364f41ff5da42d61de791d7eb68140e7f8f7eb721/pygit2-0.28.2.tar.gz";
602 602 sha256 = "11kzj5mjkspvplnpdb6bj8dcj6rgmkk986k8hjcklyg5yaxkz32d";
603 603 };
604 604 meta = {
605 605 license = [ { fullName = "GPLv2 with linking exception"; } ];
606 606 };
607 607 };
608 608 "pygments" = super.buildPythonPackage {
609 609 name = "pygments-2.4.2";
610 610 doCheck = false;
611 611 src = fetchurl {
612 612 url = "https://files.pythonhosted.org/packages/7e/ae/26808275fc76bf2832deb10d3a3ed3107bc4de01b85dcccbe525f2cd6d1e/Pygments-2.4.2.tar.gz";
613 613 sha256 = "15v2sqm5g12bqa0c7wikfh9ck2nl97ayizy1hpqhmws5gqalq748";
614 614 };
615 615 meta = {
616 616 license = [ pkgs.lib.licenses.bsdOriginal ];
617 617 };
618 618 };
619 619 "pyparsing" = super.buildPythonPackage {
620 620 name = "pyparsing-2.4.7";
621 621 doCheck = false;
622 622 src = fetchurl {
623 623 url = "https://files.pythonhosted.org/packages/c1/47/dfc9c342c9842bbe0036c7f763d2d6686bcf5eb1808ba3e170afdb282210/pyparsing-2.4.7.tar.gz";
624 624 sha256 = "1hgc8qrbq1ymxbwfbjghv01fm3fbpjwpjwi0bcailxxzhf3yq0y2";
625 625 };
626 626 meta = {
627 627 license = [ pkgs.lib.licenses.mit ];
628 628 };
629 629 };
630 630 "pyramid" = super.buildPythonPackage {
631 631 name = "pyramid-1.10.4";
632 632 doCheck = false;
633 633 propagatedBuildInputs = [
634 634 self."hupper"
635 635 self."plaster"
636 636 self."plaster-pastedeploy"
637 637 self."setuptools"
638 638 self."translationstring"
639 639 self."venusian"
640 640 self."webob"
641 641 self."zope.deprecation"
642 642 self."zope.interface"
643 643 self."repoze.lru"
644 644 ];
645 645 src = fetchurl {
646 646 url = "https://files.pythonhosted.org/packages/c2/43/1ae701c9c6bb3a434358e678a5e72c96e8aa55cf4cb1d2fa2041b5dd38b7/pyramid-1.10.4.tar.gz";
647 647 sha256 = "0rkxs1ajycg2zh1c94xlmls56mx5m161sn8112skj0amza6cn36q";
648 648 };
649 649 meta = {
650 650 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
651 651 };
652 652 };
653 653 "pyramid-mako" = super.buildPythonPackage {
654 654 name = "pyramid-mako-1.1.0";
655 655 doCheck = false;
656 656 propagatedBuildInputs = [
657 657 self."pyramid"
658 658 self."mako"
659 659 ];
660 660 src = fetchurl {
661 661 url = "https://files.pythonhosted.org/packages/63/7b/5e2af68f675071a6bad148c1c393928f0ef5fcd94e95cbf53b89d6471a83/pyramid_mako-1.1.0.tar.gz";
662 662 sha256 = "1qj0m091mnii86j2q1d82yir22nha361rvhclvg3s70z8iiwhrh0";
663 663 };
664 664 meta = {
665 665 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
666 666 };
667 667 };
668 668 "pytest" = super.buildPythonPackage {
669 669 name = "pytest-4.6.5";
670 670 doCheck = false;
671 671 propagatedBuildInputs = [
672 672 self."py"
673 673 self."six"
674 674 self."packaging"
675 675 self."attrs"
676 676 self."atomicwrites"
677 677 self."pluggy"
678 678 self."importlib-metadata"
679 679 self."wcwidth"
680 680 self."funcsigs"
681 681 self."pathlib2"
682 682 self."more-itertools"
683 683 ];
684 684 src = fetchurl {
685 685 url = "https://files.pythonhosted.org/packages/2a/c6/1d1f32f6a5009900521b12e6560fb6b7245b0d4bc3fb771acd63d10e30e1/pytest-4.6.5.tar.gz";
686 686 sha256 = "0iykwwfp4h181nd7rsihh2120b0rkawlw7rvbl19sgfspncr3hwg";
687 687 };
688 688 meta = {
689 689 license = [ pkgs.lib.licenses.mit ];
690 690 };
691 691 };
692 692 "pytest-cov" = super.buildPythonPackage {
693 693 name = "pytest-cov-2.7.1";
694 694 doCheck = false;
695 695 propagatedBuildInputs = [
696 696 self."pytest"
697 697 self."coverage"
698 698 ];
699 699 src = fetchurl {
700 700 url = "https://files.pythonhosted.org/packages/bb/0f/3db7ff86801883b21d5353b258c994b1b8e2abbc804e2273b8d0fd19004b/pytest-cov-2.7.1.tar.gz";
701 701 sha256 = "0filvmmyqm715azsl09ql8hy2x7h286n6d8z5x42a1wpvvys83p0";
702 702 };
703 703 meta = {
704 704 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ];
705 705 };
706 706 };
707 707 "pytest-profiling" = super.buildPythonPackage {
708 708 name = "pytest-profiling-1.7.0";
709 709 doCheck = false;
710 710 propagatedBuildInputs = [
711 711 self."six"
712 712 self."pytest"
713 713 self."gprof2dot"
714 714 ];
715 715 src = fetchurl {
716 716 url = "https://files.pythonhosted.org/packages/39/70/22a4b33739f07f1732a63e33bbfbf68e0fa58cfba9d200e76d01921eddbf/pytest-profiling-1.7.0.tar.gz";
717 717 sha256 = "0abz9gi26jpcfdzgsvwad91555lpgdc8kbymicmms8k2fqa8z4wk";
718 718 };
719 719 meta = {
720 720 license = [ pkgs.lib.licenses.mit ];
721 721 };
722 722 };
723 723 "pytest-runner" = super.buildPythonPackage {
724 724 name = "pytest-runner-5.1";
725 725 doCheck = false;
726 726 src = fetchurl {
727 727 url = "https://files.pythonhosted.org/packages/d9/6d/4b41a74b31720e25abd4799be72d54811da4b4d0233e38b75864dcc1f7ad/pytest-runner-5.1.tar.gz";
728 728 sha256 = "0ykfcnpp8c22winj63qzc07l5axwlc9ikl8vn05sc32gv3417815";
729 729 };
730 730 meta = {
731 731 license = [ pkgs.lib.licenses.mit ];
732 732 };
733 733 };
734 734 "pytest-sugar" = super.buildPythonPackage {
735 735 name = "pytest-sugar-0.9.2";
736 736 doCheck = false;
737 737 propagatedBuildInputs = [
738 738 self."pytest"
739 739 self."termcolor"
740 740 self."packaging"
741 741 ];
742 742 src = fetchurl {
743 743 url = "https://files.pythonhosted.org/packages/55/59/f02f78d1c80f7e03e23177f60624c8106d4f23d124c921df103f65692464/pytest-sugar-0.9.2.tar.gz";
744 744 sha256 = "1asq7yc4g8bx2sn7yy974mhc9ywvaihasjab4inkirdwn9s7mn7w";
745 745 };
746 746 meta = {
747 747 license = [ pkgs.lib.licenses.bsdOriginal ];
748 748 };
749 749 };
750 750 "pytest-timeout" = super.buildPythonPackage {
751 751 name = "pytest-timeout-1.3.3";
752 752 doCheck = false;
753 753 propagatedBuildInputs = [
754 754 self."pytest"
755 755 ];
756 756 src = fetchurl {
757 757 url = "https://files.pythonhosted.org/packages/13/48/7a166eaa29c1dca6cc253e3ba5773ff2e4aa4f567c1ea3905808e95ac5c1/pytest-timeout-1.3.3.tar.gz";
758 758 sha256 = "1cczcjhw4xx5sjkhxlhc5c1bkr7x6fcyx12wrnvwfckshdvblc2a";
759 759 };
760 760 meta = {
761 761 license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ];
762 762 };
763 763 };
764 764 "redis" = super.buildPythonPackage {
765 765 name = "redis-3.5.3";
766 766 doCheck = false;
767 767 src = fetchurl {
768 768 url = "https://files.pythonhosted.org/packages/b3/17/1e567ff78c83854e16b98694411fe6e08c3426af866ad11397cddceb80d3/redis-3.5.3.tar.gz";
769 769 sha256 = "0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2";
770 770 };
771 771 meta = {
772 772 license = [ pkgs.lib.licenses.mit ];
773 773 };
774 774 };
775 775 "repoze.lru" = super.buildPythonPackage {
776 776 name = "repoze.lru-0.7";
777 777 doCheck = false;
778 778 src = fetchurl {
779 779 url = "https://files.pythonhosted.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz";
780 780 sha256 = "0xzz1aw2smy8hdszrq8yhnklx6w1r1mf55061kalw3iq35gafa84";
781 781 };
782 782 meta = {
783 783 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
784 784 };
785 785 };
786 786 "rhodecode-vcsserver" = super.buildPythonPackage {
787 name = "rhodecode-vcsserver-4.24.1";
787 name = "rhodecode-vcsserver-4.25.0";
788 788 buildInputs = [
789 789 self."pytest"
790 790 self."py"
791 791 self."pytest-cov"
792 792 self."pytest-sugar"
793 793 self."pytest-runner"
794 794 self."pytest-profiling"
795 795 self."pytest-timeout"
796 796 self."gprof2dot"
797 797 self."mock"
798 798 self."cov-core"
799 799 self."coverage"
800 800 self."webtest"
801 801 self."beautifulsoup4"
802 802 self."configobj"
803 803 ];
804 804 doCheck = true;
805 805 propagatedBuildInputs = [
806 806 self."configobj"
807 807 self."dogpile.cache"
808 808 self."dogpile.core"
809 809 self."decorator"
810 810 self."dulwich"
811 811 self."hgsubversion"
812 812 self."hg-evolve"
813 813 self."mako"
814 814 self."markupsafe"
815 815 self."mercurial"
816 816 self."msgpack-python"
817 817 self."pastedeploy"
818 818 self."pyramid"
819 819 self."pyramid-mako"
820 820 self."pygit2"
821 821 self."repoze.lru"
822 822 self."redis"
823 823 self."simplejson"
824 824 self."subprocess32"
825 825 self."subvertpy"
826 826 self."six"
827 827 self."translationstring"
828 828 self."webob"
829 829 self."zope.deprecation"
830 830 self."zope.interface"
831 831 self."gevent"
832 832 self."greenlet"
833 833 self."gunicorn"
834 834 self."waitress"
835 835 self."ipdb"
836 836 self."ipython"
837 837 self."pytest"
838 838 self."py"
839 839 self."pytest-cov"
840 840 self."pytest-sugar"
841 841 self."pytest-runner"
842 842 self."pytest-profiling"
843 843 self."pytest-timeout"
844 844 self."gprof2dot"
845 845 self."mock"
846 846 self."cov-core"
847 847 self."coverage"
848 848 self."webtest"
849 849 self."beautifulsoup4"
850 850 ];
851 851 src = ./.;
852 852 meta = {
853 853 license = [ { fullName = "GPL V3"; } { fullName = "GNU General Public License v3 or later (GPLv3+)"; } ];
854 854 };
855 855 };
856 856 "scandir" = super.buildPythonPackage {
857 857 name = "scandir-1.10.0";
858 858 doCheck = false;
859 859 src = fetchurl {
860 860 url = "https://files.pythonhosted.org/packages/df/f5/9c052db7bd54d0cbf1bc0bb6554362bba1012d03e5888950a4f5c5dadc4e/scandir-1.10.0.tar.gz";
861 861 sha256 = "1bkqwmf056pkchf05ywbnf659wqlp6lljcdb0y88wr9f0vv32ijd";
862 862 };
863 863 meta = {
864 864 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
865 865 };
866 866 };
867 867 "setproctitle" = super.buildPythonPackage {
868 868 name = "setproctitle-1.1.10";
869 869 doCheck = false;
870 870 src = fetchurl {
871 871 url = "https://files.pythonhosted.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz";
872 872 sha256 = "163kplw9dcrw0lffq1bvli5yws3rngpnvrxrzdw89pbphjjvg0v2";
873 873 };
874 874 meta = {
875 875 license = [ pkgs.lib.licenses.bsdOriginal ];
876 876 };
877 877 };
878 878 "setuptools" = super.buildPythonPackage {
879 879 name = "setuptools-44.1.0";
880 880 doCheck = false;
881 881 src = fetchurl {
882 882 url = "https://files.pythonhosted.org/packages/ed/7b/bbf89ca71e722b7f9464ebffe4b5ee20a9e5c9a555a56e2d3914bb9119a6/setuptools-44.1.0.zip";
883 883 sha256 = "1jja896zvd1ppccnjbhkgagxbwchgq6vfamp6qn1hvywq6q9cjkr";
884 884 };
885 885 meta = {
886 886 license = [ pkgs.lib.licenses.mit ];
887 887 };
888 888 };
889
890 "setuptools-scm" = super.buildPythonPackage {
891 name = "setuptools-scm-3.5.0";
892 doCheck = false;
893 src = fetchurl {
894 url = "https://files.pythonhosted.org/packages/b2/f7/60a645aae001a2e06cf4b8db2fba9d9f36b8fd378f10647e3e218b61b74b/setuptools_scm-3.5.0.tar.gz";
895 sha256 = "5bdf21a05792903cafe7ae0c9501182ab52497614fa6b1750d9dbae7b60c1a87";
896 };
897 meta = {
898 license = [ pkgs.lib.licenses.psfl ];
899 };
900 };
901
889 902 "simplegeneric" = super.buildPythonPackage {
890 903 name = "simplegeneric-0.8.1";
891 904 doCheck = false;
892 905 src = fetchurl {
893 906 url = "https://files.pythonhosted.org/packages/3d/57/4d9c9e3ae9a255cd4e1106bb57e24056d3d0709fc01b2e3e345898e49d5b/simplegeneric-0.8.1.zip";
894 907 sha256 = "0wwi1c6md4vkbcsfsf8dklf3vr4mcdj4mpxkanwgb6jb1432x5yw";
895 908 };
896 909 meta = {
897 910 license = [ pkgs.lib.licenses.zpl21 ];
898 911 };
899 912 };
900 913 "simplejson" = super.buildPythonPackage {
901 914 name = "simplejson-3.16.0";
902 915 doCheck = false;
903 916 src = fetchurl {
904 917 url = "https://files.pythonhosted.org/packages/e3/24/c35fb1c1c315fc0fffe61ea00d3f88e85469004713dab488dee4f35b0aff/simplejson-3.16.0.tar.gz";
905 918 sha256 = "19cws1syk8jzq2pw43878dv6fjkb0ifvjpx0i9aajix6kc9jkwxi";
906 919 };
907 920 meta = {
908 921 license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ];
909 922 };
910 923 };
911 924 "six" = super.buildPythonPackage {
912 925 name = "six-1.11.0";
913 926 doCheck = false;
914 927 src = fetchurl {
915 928 url = "https://files.pythonhosted.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
916 929 sha256 = "1scqzwc51c875z23phj48gircqjgnn3af8zy2izjwmnlxrxsgs3h";
917 930 };
918 931 meta = {
919 932 license = [ pkgs.lib.licenses.mit ];
920 933 };
921 934 };
922 935 "subprocess32" = super.buildPythonPackage {
923 936 name = "subprocess32-3.5.4";
924 937 doCheck = false;
925 938 src = fetchurl {
926 939 url = "https://files.pythonhosted.org/packages/32/c8/564be4d12629b912ea431f1a50eb8b3b9d00f1a0b1ceff17f266be190007/subprocess32-3.5.4.tar.gz";
927 940 sha256 = "17f7mvwx2271s1wrl0qac3wjqqnrqag866zs3qc8v5wp0k43fagb";
928 941 };
929 942 meta = {
930 943 license = [ pkgs.lib.licenses.psfl ];
931 944 };
932 945 };
933 946 "subvertpy" = super.buildPythonPackage {
934 947 name = "subvertpy-0.10.1";
935 948 doCheck = false;
936 949 src = fetchurl {
937 950 url = "https://files.pythonhosted.org/packages/9d/76/99fa82affce75f5ac0f7dbe513796c3f37311ace0c68e1b063683b4f9b99/subvertpy-0.10.1.tar.gz";
938 951 sha256 = "061ncy9wjz3zyv527avcrdyk0xygyssyy7p1644nhzhwp8zpybij";
939 952 };
940 953 meta = {
941 954 license = [ pkgs.lib.licenses.lgpl21Plus pkgs.lib.licenses.gpl2Plus ];
942 955 };
943 956 };
944 957 "termcolor" = super.buildPythonPackage {
945 958 name = "termcolor-1.1.0";
946 959 doCheck = false;
947 960 src = fetchurl {
948 961 url = "https://files.pythonhosted.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
949 962 sha256 = "0fv1vq14rpqwgazxg4981904lfyp84mnammw7y046491cv76jv8x";
950 963 };
951 964 meta = {
952 965 license = [ pkgs.lib.licenses.mit ];
953 966 };
954 967 };
955 968 "traitlets" = super.buildPythonPackage {
956 969 name = "traitlets-4.3.3";
957 970 doCheck = false;
958 971 propagatedBuildInputs = [
959 972 self."ipython-genutils"
960 973 self."six"
961 974 self."decorator"
962 975 self."enum34"
963 976 ];
964 977 src = fetchurl {
965 978 url = "https://files.pythonhosted.org/packages/75/b0/43deb021bc943f18f07cbe3dac1d681626a48997b7ffa1e7fb14ef922b21/traitlets-4.3.3.tar.gz";
966 979 sha256 = "1xsrwgivpkxlbr4dfndfsi098s29yqgswgjc1qqn69yxklvfw8yh";
967 980 };
968 981 meta = {
969 982 license = [ pkgs.lib.licenses.bsdOriginal ];
970 983 };
971 984 };
972 985 "translationstring" = super.buildPythonPackage {
973 986 name = "translationstring-1.3";
974 987 doCheck = false;
975 988 src = fetchurl {
976 989 url = "https://files.pythonhosted.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
977 990 sha256 = "0bdpcnd9pv0131dl08h4zbcwmgc45lyvq3pa224xwan5b3x4rr2f";
978 991 };
979 992 meta = {
980 993 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
981 994 };
982 995 };
983 996 "venusian" = super.buildPythonPackage {
984 997 name = "venusian-1.2.0";
985 998 doCheck = false;
986 999 src = fetchurl {
987 1000 url = "https://files.pythonhosted.org/packages/7e/6f/40a9d43ac77cb51cb62be5b5662d170f43f8037bdc4eab56336c4ca92bb7/venusian-1.2.0.tar.gz";
988 1001 sha256 = "0ghyx66g8ikx9nx1mnwqvdcqm11i1vlq0hnvwl50s48bp22q5v34";
989 1002 };
990 1003 meta = {
991 1004 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
992 1005 };
993 1006 };
994 1007 "waitress" = super.buildPythonPackage {
995 1008 name = "waitress-1.3.1";
996 1009 doCheck = false;
997 1010 src = fetchurl {
998 1011 url = "https://files.pythonhosted.org/packages/a6/e6/708da7bba65898e5d759ade8391b1077e49d07be0b0223c39f5be04def56/waitress-1.3.1.tar.gz";
999 1012 sha256 = "1iysl8ka3l4cdrr0r19fh1cv28q41mwpvgsb81ji7k4shkb0k3i7";
1000 1013 };
1001 1014 meta = {
1002 1015 license = [ pkgs.lib.licenses.zpl21 ];
1003 1016 };
1004 1017 };
1005 1018 "wcwidth" = super.buildPythonPackage {
1006 1019 name = "wcwidth-0.1.9";
1007 1020 doCheck = false;
1008 1021 src = fetchurl {
1009 1022 url = "https://files.pythonhosted.org/packages/25/9d/0acbed6e4a4be4fc99148f275488580968f44ddb5e69b8ceb53fc9df55a0/wcwidth-0.1.9.tar.gz";
1010 1023 sha256 = "1wf5ycjx8s066rdvr0fgz4xds9a8zhs91c4jzxvvymm1c8l8cwzf";
1011 1024 };
1012 1025 meta = {
1013 1026 license = [ pkgs.lib.licenses.mit ];
1014 1027 };
1015 1028 };
1016 1029 "webob" = super.buildPythonPackage {
1017 1030 name = "webob-1.8.5";
1018 1031 doCheck = false;
1019 1032 src = fetchurl {
1020 1033 url = "https://files.pythonhosted.org/packages/9d/1a/0c89c070ee2829c934cb6c7082287c822e28236a4fcf90063e6be7c35532/WebOb-1.8.5.tar.gz";
1021 1034 sha256 = "11khpzaxc88q31v25ic330gsf56fwmbdc9b30br8mvp0fmwspah5";
1022 1035 };
1023 1036 meta = {
1024 1037 license = [ pkgs.lib.licenses.mit ];
1025 1038 };
1026 1039 };
1027 1040 "webtest" = super.buildPythonPackage {
1028 1041 name = "webtest-2.0.34";
1029 1042 doCheck = false;
1030 1043 propagatedBuildInputs = [
1031 1044 self."six"
1032 1045 self."webob"
1033 1046 self."waitress"
1034 1047 self."beautifulsoup4"
1035 1048 ];
1036 1049 src = fetchurl {
1037 1050 url = "https://files.pythonhosted.org/packages/2c/74/a0e63feee438735d628631e2b70d82280276a930637ac535479e5fad9427/WebTest-2.0.34.tar.gz";
1038 1051 sha256 = "0x1y2c8z4fmpsny4hbp6ka37si2g10r5r2jwxhvv5mx7g3blq4bi";
1039 1052 };
1040 1053 meta = {
1041 1054 license = [ pkgs.lib.licenses.mit ];
1042 1055 };
1043 1056 };
1044 1057 "zipp" = super.buildPythonPackage {
1045 1058 name = "zipp-1.2.0";
1046 1059 doCheck = false;
1047 1060 propagatedBuildInputs = [
1048 1061 self."contextlib2"
1049 1062 ];
1050 1063 src = fetchurl {
1051 1064 url = "https://files.pythonhosted.org/packages/78/08/d52f0ea643bc1068d6dc98b412f4966a9b63255d20911a23ac3220c033c4/zipp-1.2.0.tar.gz";
1052 1065 sha256 = "1c91lnv1bxjimh8as27hz7bghsjkkbxn1d37xq7in9c82iai0167";
1053 1066 };
1054 1067 meta = {
1055 1068 license = [ pkgs.lib.licenses.mit ];
1056 1069 };
1057 1070 };
1058 1071 "zope.deprecation" = super.buildPythonPackage {
1059 1072 name = "zope.deprecation-4.4.0";
1060 1073 doCheck = false;
1061 1074 propagatedBuildInputs = [
1062 1075 self."setuptools"
1063 1076 ];
1064 1077 src = fetchurl {
1065 1078 url = "https://files.pythonhosted.org/packages/34/da/46e92d32d545dd067b9436279d84c339e8b16de2ca393d7b892bc1e1e9fd/zope.deprecation-4.4.0.tar.gz";
1066 1079 sha256 = "1pz2cv7gv9y1r3m0bdv7ks1alagmrn5msm5spwdzkb2by0w36i8d";
1067 1080 };
1068 1081 meta = {
1069 1082 license = [ pkgs.lib.licenses.zpl21 ];
1070 1083 };
1071 1084 };
1072 1085 "zope.interface" = super.buildPythonPackage {
1073 1086 name = "zope.interface-4.6.0";
1074 1087 doCheck = false;
1075 1088 propagatedBuildInputs = [
1076 1089 self."setuptools"
1077 1090 ];
1078 1091 src = fetchurl {
1079 1092 url = "https://files.pythonhosted.org/packages/4e/d0/c9d16bd5b38de44a20c6dc5d5ed80a49626fafcb3db9f9efdc2a19026db6/zope.interface-4.6.0.tar.gz";
1080 1093 sha256 = "1rgh2x3rcl9r0v0499kf78xy86rnmanajf4ywmqb943wpk50sg8v";
1081 1094 };
1082 1095 meta = {
1083 1096 license = [ pkgs.lib.licenses.zpl21 ];
1084 1097 };
1085 1098 };
1086 1099
1087 1100 ### Test requirements
1088 1101
1089 1102
1090 1103 }
@@ -1,1 +1,1 b''
1 4.24.1 No newline at end of file
1 4.25.0 No newline at end of file
@@ -1,856 +1,855 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2020 RhodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 from __future__ import absolute_import
19 19
20 20 import os
21 21 import subprocess
22 22 import time
23 23 from urllib2 import URLError
24 24 import urlparse
25 25 import logging
26 26 import posixpath as vcspath
27 27 import StringIO
28 28 import urllib
29 29 import traceback
30 30
31 31 import svn.client
32 32 import svn.core
33 33 import svn.delta
34 34 import svn.diff
35 35 import svn.fs
36 36 import svn.repos
37 37
38 38 from vcsserver import svn_diff, exceptions, subprocessio, settings
39 39 from vcsserver.base import RepoFactory, raise_from_original, ArchiveNode, archive_repo
40 40 from vcsserver.exceptions import NoContentException
41 from vcsserver.utils import safe_str
41 42 from vcsserver.vcs_base import RemoteBase
42 43
43 44 log = logging.getLogger(__name__)
44 45
45 46
46 47 svn_compatible_versions_map = {
47 48 'pre-1.4-compatible': '1.3',
48 49 'pre-1.5-compatible': '1.4',
49 50 'pre-1.6-compatible': '1.5',
50 51 'pre-1.8-compatible': '1.7',
51 52 'pre-1.9-compatible': '1.8',
52 53 }
53 54
54 55 current_compatible_version = '1.12'
55 56
56 57
57 58 def reraise_safe_exceptions(func):
58 59 """Decorator for converting svn exceptions to something neutral."""
59 60 def wrapper(*args, **kwargs):
60 61 try:
61 62 return func(*args, **kwargs)
62 63 except Exception as e:
63 64 if not hasattr(e, '_vcs_kind'):
64 65 log.exception("Unhandled exception in svn remote call")
65 66 raise_from_original(exceptions.UnhandledException(e))
66 67 raise
67 68 return wrapper
68 69
69 70
70 71 class SubversionFactory(RepoFactory):
71 72 repo_type = 'svn'
72 73
73 74 def _create_repo(self, wire, create, compatible_version):
74 75 path = svn.core.svn_path_canonicalize(wire['path'])
75 76 if create:
76 77 fs_config = {'compatible-version': current_compatible_version}
77 78 if compatible_version:
78 79
79 80 compatible_version_string = \
80 81 svn_compatible_versions_map.get(compatible_version) \
81 82 or compatible_version
82 83 fs_config['compatible-version'] = compatible_version_string
83 84
84 85 log.debug('Create SVN repo with config "%s"', fs_config)
85 86 repo = svn.repos.create(path, "", "", None, fs_config)
86 87 else:
87 88 repo = svn.repos.open(path)
88 89
89 90 log.debug('Got SVN object: %s', repo)
90 91 return repo
91 92
92 93 def repo(self, wire, create=False, compatible_version=None):
93 94 """
94 95 Get a repository instance for the given path.
95 96 """
96 97 return self._create_repo(wire, create, compatible_version)
97 98
98 99
99 100 NODE_TYPE_MAPPING = {
100 101 svn.core.svn_node_file: 'file',
101 102 svn.core.svn_node_dir: 'dir',
102 103 }
103 104
104 105
105 106 class SvnRemote(RemoteBase):
106 107
107 108 def __init__(self, factory, hg_factory=None):
108 109 self._factory = factory
109 110 # TODO: Remove once we do not use internal Mercurial objects anymore
110 111 # for subversion
111 112 self._hg_factory = hg_factory
112 113
113 114 @reraise_safe_exceptions
114 115 def discover_svn_version(self):
115 116 try:
116 117 import svn.core
117 118 svn_ver = svn.core.SVN_VERSION
118 119 except ImportError:
119 120 svn_ver = None
120 121 return svn_ver
121 122
122 123 @reraise_safe_exceptions
123 124 def is_empty(self, wire):
124 125
125 126 try:
126 127 return self.lookup(wire, -1) == 0
127 128 except Exception:
128 129 log.exception("failed to read object_store")
129 130 return False
130 131
131 132 def check_url(self, url, config_items):
132 133 # this can throw exception if not installed, but we detect this
133 134 from hgsubversion import svnrepo
134 135
135 136 baseui = self._hg_factory._create_config(config_items)
136 137 # uuid function get's only valid UUID from proper repo, else
137 138 # throws exception
138 139 try:
139 140 svnrepo.svnremoterepo(baseui, url).svn.uuid
140 141 except Exception:
141 142 tb = traceback.format_exc()
142 143 log.debug("Invalid Subversion url: `%s`, tb: %s", url, tb)
143 144 raise URLError(
144 145 '"%s" is not a valid Subversion source url.' % (url, ))
145 146 return True
146 147
147 148 def is_path_valid_repository(self, wire, path):
148 149
149 150 # NOTE(marcink): short circuit the check for SVN repo
150 151 # the repos.open might be expensive to check, but we have one cheap
151 152 # pre condition that we can use, to check for 'format' file
152 153
153 154 if not os.path.isfile(os.path.join(path, 'format')):
154 155 return False
155 156
156 157 try:
157 158 svn.repos.open(path)
158 159 except svn.core.SubversionException:
159 160 tb = traceback.format_exc()
160 161 log.debug("Invalid Subversion path `%s`, tb: %s", path, tb)
161 162 return False
162 163 return True
163 164
164 165 @reraise_safe_exceptions
165 166 def verify(self, wire,):
166 167 repo_path = wire['path']
167 168 if not self.is_path_valid_repository(wire, repo_path):
168 169 raise Exception(
169 170 "Path %s is not a valid Subversion repository." % repo_path)
170 171
171 172 cmd = ['svnadmin', 'info', repo_path]
172 173 stdout, stderr = subprocessio.run_command(cmd)
173 174 return stdout
174 175
175 176 def lookup(self, wire, revision):
176 177 if revision not in [-1, None, 'HEAD']:
177 178 raise NotImplementedError
178 179 repo = self._factory.repo(wire)
179 180 fs_ptr = svn.repos.fs(repo)
180 181 head = svn.fs.youngest_rev(fs_ptr)
181 182 return head
182 183
183 184 def lookup_interval(self, wire, start_ts, end_ts):
184 185 repo = self._factory.repo(wire)
185 186 fsobj = svn.repos.fs(repo)
186 187 start_rev = None
187 188 end_rev = None
188 189 if start_ts:
189 190 start_ts_svn = apr_time_t(start_ts)
190 191 start_rev = svn.repos.dated_revision(repo, start_ts_svn) + 1
191 192 else:
192 193 start_rev = 1
193 194 if end_ts:
194 195 end_ts_svn = apr_time_t(end_ts)
195 196 end_rev = svn.repos.dated_revision(repo, end_ts_svn)
196 197 else:
197 198 end_rev = svn.fs.youngest_rev(fsobj)
198 199 return start_rev, end_rev
199 200
200 201 def revision_properties(self, wire, revision):
201 202
202 203 cache_on, context_uid, repo_id = self._cache_on(wire)
203 204 @self.region.conditional_cache_on_arguments(condition=cache_on)
204 205 def _revision_properties(_repo_id, _revision):
205 206 repo = self._factory.repo(wire)
206 207 fs_ptr = svn.repos.fs(repo)
207 208 return svn.fs.revision_proplist(fs_ptr, revision)
208 209 return _revision_properties(repo_id, revision)
209 210
210 211 def revision_changes(self, wire, revision):
211 212
212 213 repo = self._factory.repo(wire)
213 214 fsobj = svn.repos.fs(repo)
214 215 rev_root = svn.fs.revision_root(fsobj, revision)
215 216
216 217 editor = svn.repos.ChangeCollector(fsobj, rev_root)
217 218 editor_ptr, editor_baton = svn.delta.make_editor(editor)
218 219 base_dir = ""
219 220 send_deltas = False
220 221 svn.repos.replay2(
221 222 rev_root, base_dir, svn.core.SVN_INVALID_REVNUM, send_deltas,
222 223 editor_ptr, editor_baton, None)
223 224
224 225 added = []
225 226 changed = []
226 227 removed = []
227 228
228 229 # TODO: CHANGE_ACTION_REPLACE: Figure out where it belongs
229 230 for path, change in editor.changes.iteritems():
230 231 # TODO: Decide what to do with directory nodes. Subversion can add
231 232 # empty directories.
232 233
233 234 if change.item_kind == svn.core.svn_node_dir:
234 235 continue
235 236 if change.action in [svn.repos.CHANGE_ACTION_ADD]:
236 237 added.append(path)
237 238 elif change.action in [svn.repos.CHANGE_ACTION_MODIFY,
238 239 svn.repos.CHANGE_ACTION_REPLACE]:
239 240 changed.append(path)
240 241 elif change.action in [svn.repos.CHANGE_ACTION_DELETE]:
241 242 removed.append(path)
242 243 else:
243 244 raise NotImplementedError(
244 245 "Action %s not supported on path %s" % (
245 246 change.action, path))
246 247
247 248 changes = {
248 249 'added': added,
249 250 'changed': changed,
250 251 'removed': removed,
251 252 }
252 253 return changes
253 254
254 255 @reraise_safe_exceptions
255 256 def node_history(self, wire, path, revision, limit):
256 257 cache_on, context_uid, repo_id = self._cache_on(wire)
257 258 @self.region.conditional_cache_on_arguments(condition=cache_on)
258 259 def _assert_correct_path(_context_uid, _repo_id, _path, _revision, _limit):
259 260 cross_copies = False
260 261 repo = self._factory.repo(wire)
261 262 fsobj = svn.repos.fs(repo)
262 263 rev_root = svn.fs.revision_root(fsobj, revision)
263 264
264 265 history_revisions = []
265 266 history = svn.fs.node_history(rev_root, path)
266 267 history = svn.fs.history_prev(history, cross_copies)
267 268 while history:
268 269 __, node_revision = svn.fs.history_location(history)
269 270 history_revisions.append(node_revision)
270 271 if limit and len(history_revisions) >= limit:
271 272 break
272 273 history = svn.fs.history_prev(history, cross_copies)
273 274 return history_revisions
274 275 return _assert_correct_path(context_uid, repo_id, path, revision, limit)
275 276
276 277 def node_properties(self, wire, path, revision):
277 278 cache_on, context_uid, repo_id = self._cache_on(wire)
278 279 @self.region.conditional_cache_on_arguments(condition=cache_on)
279 280 def _node_properties(_repo_id, _path, _revision):
280 281 repo = self._factory.repo(wire)
281 282 fsobj = svn.repos.fs(repo)
282 283 rev_root = svn.fs.revision_root(fsobj, revision)
283 284 return svn.fs.node_proplist(rev_root, path)
284 285 return _node_properties(repo_id, path, revision)
285 286
286 287 def file_annotate(self, wire, path, revision):
287 288 abs_path = 'file://' + urllib.pathname2url(
288 289 vcspath.join(wire['path'], path))
289 290 file_uri = svn.core.svn_path_canonicalize(abs_path)
290 291
291 292 start_rev = svn_opt_revision_value_t(0)
292 293 peg_rev = svn_opt_revision_value_t(revision)
293 294 end_rev = peg_rev
294 295
295 296 annotations = []
296 297
297 298 def receiver(line_no, revision, author, date, line, pool):
298 299 annotations.append((line_no, revision, line))
299 300
300 301 # TODO: Cannot use blame5, missing typemap function in the swig code
301 302 try:
302 303 svn.client.blame2(
303 304 file_uri, peg_rev, start_rev, end_rev,
304 305 receiver, svn.client.create_context())
305 306 except svn.core.SubversionException as exc:
306 307 log.exception("Error during blame operation.")
307 308 raise Exception(
308 309 "Blame not supported or file does not exist at path %s. "
309 310 "Error %s." % (path, exc))
310 311
311 312 return annotations
312 313
313 314 def get_node_type(self, wire, path, revision=None):
314 315
315 316 cache_on, context_uid, repo_id = self._cache_on(wire)
316 317 @self.region.conditional_cache_on_arguments(condition=cache_on)
317 318 def _get_node_type(_repo_id, _path, _revision):
318 319 repo = self._factory.repo(wire)
319 320 fs_ptr = svn.repos.fs(repo)
320 321 if _revision is None:
321 322 _revision = svn.fs.youngest_rev(fs_ptr)
322 323 root = svn.fs.revision_root(fs_ptr, _revision)
323 324 node = svn.fs.check_path(root, path)
324 325 return NODE_TYPE_MAPPING.get(node, None)
325 326 return _get_node_type(repo_id, path, revision)
326 327
327 328 def get_nodes(self, wire, path, revision=None):
328 329
329 330 cache_on, context_uid, repo_id = self._cache_on(wire)
330 331 @self.region.conditional_cache_on_arguments(condition=cache_on)
331 332 def _get_nodes(_repo_id, _path, _revision):
332 333 repo = self._factory.repo(wire)
333 334 fsobj = svn.repos.fs(repo)
334 335 if _revision is None:
335 336 _revision = svn.fs.youngest_rev(fsobj)
336 337 root = svn.fs.revision_root(fsobj, _revision)
337 338 entries = svn.fs.dir_entries(root, path)
338 339 result = []
339 340 for entry_path, entry_info in entries.iteritems():
340 341 result.append(
341 342 (entry_path, NODE_TYPE_MAPPING.get(entry_info.kind, None)))
342 343 return result
343 344 return _get_nodes(repo_id, path, revision)
344 345
345 346 def get_file_content(self, wire, path, rev=None):
346 347 repo = self._factory.repo(wire)
347 348 fsobj = svn.repos.fs(repo)
348 349 if rev is None:
349 350 rev = svn.fs.youngest_revision(fsobj)
350 351 root = svn.fs.revision_root(fsobj, rev)
351 352 content = svn.core.Stream(svn.fs.file_contents(root, path))
352 353 return content.read()
353 354
354 355 def get_file_size(self, wire, path, revision=None):
355 356
356 357 cache_on, context_uid, repo_id = self._cache_on(wire)
357 358 @self.region.conditional_cache_on_arguments(condition=cache_on)
358 359 def _get_file_size(_repo_id, _path, _revision):
359 360 repo = self._factory.repo(wire)
360 361 fsobj = svn.repos.fs(repo)
361 362 if _revision is None:
362 363 _revision = svn.fs.youngest_revision(fsobj)
363 364 root = svn.fs.revision_root(fsobj, _revision)
364 365 size = svn.fs.file_length(root, path)
365 366 return size
366 367 return _get_file_size(repo_id, path, revision)
367 368
368 369 def create_repository(self, wire, compatible_version=None):
369 370 log.info('Creating Subversion repository in path "%s"', wire['path'])
370 371 self._factory.repo(wire, create=True,
371 372 compatible_version=compatible_version)
372 373
373 374 def get_url_and_credentials(self, src_url):
374 375 obj = urlparse.urlparse(src_url)
375 376 username = obj.username or None
376 377 password = obj.password or None
377 378 return username, password, src_url
378 379
379 380 def import_remote_repository(self, wire, src_url):
380 381 repo_path = wire['path']
381 382 if not self.is_path_valid_repository(wire, repo_path):
382 383 raise Exception(
383 384 "Path %s is not a valid Subversion repository." % repo_path)
384 385
385 386 username, password, src_url = self.get_url_and_credentials(src_url)
386 387 rdump_cmd = ['svnrdump', 'dump', '--non-interactive',
387 388 '--trust-server-cert-failures=unknown-ca']
388 389 if username and password:
389 390 rdump_cmd += ['--username', username, '--password', password]
390 391 rdump_cmd += [src_url]
391 392
392 393 rdump = subprocess.Popen(
393 394 rdump_cmd,
394 395 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
395 396 load = subprocess.Popen(
396 397 ['svnadmin', 'load', repo_path], stdin=rdump.stdout)
397 398
398 399 # TODO: johbo: This can be a very long operation, might be better
399 400 # to track some kind of status and provide an api to check if the
400 401 # import is done.
401 402 rdump.wait()
402 403 load.wait()
403 404
404 405 log.debug('Return process ended with code: %s', rdump.returncode)
405 406 if rdump.returncode != 0:
406 407 errors = rdump.stderr.read()
407 408 log.error('svnrdump dump failed: statuscode %s: message: %s',
408 409 rdump.returncode, errors)
409 410 reason = 'UNKNOWN'
410 411 if 'svnrdump: E230001:' in errors:
411 412 reason = 'INVALID_CERTIFICATE'
412 413
413 414 if reason == 'UNKNOWN':
414 415 reason = 'UNKNOWN:{}'.format(errors)
415 416 raise Exception(
416 417 'Failed to dump the remote repository from %s. Reason:%s' % (
417 418 src_url, reason))
418 419 if load.returncode != 0:
419 420 raise Exception(
420 421 'Failed to load the dump of remote repository from %s.' %
421 422 (src_url, ))
422 423
423 424 def commit(self, wire, message, author, timestamp, updated, removed):
424 425 assert isinstance(message, str)
425 426 assert isinstance(author, str)
426 427
427 428 repo = self._factory.repo(wire)
428 429 fsobj = svn.repos.fs(repo)
429 430
430 431 rev = svn.fs.youngest_rev(fsobj)
431 432 txn = svn.repos.fs_begin_txn_for_commit(repo, rev, author, message)
432 433 txn_root = svn.fs.txn_root(txn)
433 434
434 435 for node in updated:
435 436 TxnNodeProcessor(node, txn_root).update()
436 437 for node in removed:
437 438 TxnNodeProcessor(node, txn_root).remove()
438 439
439 440 commit_id = svn.repos.fs_commit_txn(repo, txn)
440 441
441 442 if timestamp:
442 443 apr_time = apr_time_t(timestamp)
443 444 ts_formatted = svn.core.svn_time_to_cstring(apr_time)
444 445 svn.fs.change_rev_prop(fsobj, commit_id, 'svn:date', ts_formatted)
445 446
446 447 log.debug('Committed revision "%s" to "%s".', commit_id, wire['path'])
447 448 return commit_id
448 449
449 450 def diff(self, wire, rev1, rev2, path1=None, path2=None,
450 451 ignore_whitespace=False, context=3):
451 452
452 453 wire.update(cache=False)
453 454 repo = self._factory.repo(wire)
454 455 diff_creator = SvnDiffer(
455 456 repo, rev1, path1, rev2, path2, ignore_whitespace, context)
456 457 try:
457 458 return diff_creator.generate_diff()
458 459 except svn.core.SubversionException as e:
459 460 log.exception(
460 461 "Error during diff operation operation. "
461 462 "Path might not exist %s, %s" % (path1, path2))
462 463 return ""
463 464
464 465 @reraise_safe_exceptions
465 466 def is_large_file(self, wire, path):
466 467 return False
467 468
468 469 @reraise_safe_exceptions
469 470 def is_binary(self, wire, rev, path):
470 471 cache_on, context_uid, repo_id = self._cache_on(wire)
471 472
472 473 @self.region.conditional_cache_on_arguments(condition=cache_on)
473 474 def _is_binary(_repo_id, _rev, _path):
474 475 raw_bytes = self.get_file_content(wire, path, rev)
475 476 return raw_bytes and '\0' in raw_bytes
476 477
477 478 return _is_binary(repo_id, rev, path)
478 479
479 480 @reraise_safe_exceptions
480 481 def run_svn_command(self, wire, cmd, **opts):
481 482 path = wire.get('path', None)
482 483
483 484 if path and os.path.isdir(path):
484 485 opts['cwd'] = path
485 486
486 safe_call = False
487 if '_safe' in opts:
488 safe_call = True
487 safe_call = opts.pop('_safe', False)
489 488
490 489 svnenv = os.environ.copy()
491 490 svnenv.update(opts.pop('extra_env', {}))
492 491
493 492 _opts = {'env': svnenv, 'shell': False}
494 493
495 494 try:
496 495 _opts.update(opts)
497 496 p = subprocessio.SubprocessIOChunker(cmd, **_opts)
498 497
499 498 return ''.join(p), ''.join(p.error)
500 499 except (EnvironmentError, OSError) as err:
501 500 if safe_call:
502 return '', err
501 return '', safe_str(err).strip()
503 502 else:
504 503 cmd = ' '.join(cmd) # human friendly CMD
505 504 tb_err = ("Couldn't run svn command (%s).\n"
506 505 "Original error was:%s\n"
507 506 "Call options:%s\n"
508 507 % (cmd, err, _opts))
509 508 log.exception(tb_err)
510 509 raise exceptions.VcsException()(tb_err)
511 510
512 511 @reraise_safe_exceptions
513 512 def install_hooks(self, wire, force=False):
514 513 from vcsserver.hook_utils import install_svn_hooks
515 514 repo_path = wire['path']
516 515 binary_dir = settings.BINARY_DIR
517 516 executable = None
518 517 if binary_dir:
519 518 executable = os.path.join(binary_dir, 'python')
520 519 return install_svn_hooks(
521 520 repo_path, executable=executable, force_create=force)
522 521
523 522 @reraise_safe_exceptions
524 523 def get_hooks_info(self, wire):
525 524 from vcsserver.hook_utils import (
526 525 get_svn_pre_hook_version, get_svn_post_hook_version)
527 526 repo_path = wire['path']
528 527 return {
529 528 'pre_version': get_svn_pre_hook_version(repo_path),
530 529 'post_version': get_svn_post_hook_version(repo_path),
531 530 }
532 531
533 532 @reraise_safe_exceptions
534 533 def archive_repo(self, wire, archive_dest_path, kind, mtime, archive_at_path,
535 534 archive_dir_name, commit_id):
536 535
537 536 def walk_tree(root, root_dir, _commit_id):
538 537 """
539 538 Special recursive svn repo walker
540 539 """
541 540
542 541 filemode_default = 0o100644
543 542 filemode_executable = 0o100755
544 543
545 544 file_iter = svn.fs.dir_entries(root, root_dir)
546 545 for f_name in file_iter:
547 546 f_type = NODE_TYPE_MAPPING.get(file_iter[f_name].kind, None)
548 547
549 548 if f_type == 'dir':
550 549 # return only DIR, and then all entries in that dir
551 550 yield os.path.join(root_dir, f_name), {'mode': filemode_default}, f_type
552 551 new_root = os.path.join(root_dir, f_name)
553 552 for _f_name, _f_data, _f_type in walk_tree(root, new_root, _commit_id):
554 553 yield _f_name, _f_data, _f_type
555 554 else:
556 555 f_path = os.path.join(root_dir, f_name).rstrip('/')
557 556 prop_list = svn.fs.node_proplist(root, f_path)
558 557
559 558 f_mode = filemode_default
560 559 if prop_list.get('svn:executable'):
561 560 f_mode = filemode_executable
562 561
563 562 f_is_link = False
564 563 if prop_list.get('svn:special'):
565 564 f_is_link = True
566 565
567 566 data = {
568 567 'is_link': f_is_link,
569 568 'mode': f_mode,
570 569 'content_stream': svn.core.Stream(svn.fs.file_contents(root, f_path)).read
571 570 }
572 571
573 572 yield f_path, data, f_type
574 573
575 574 def file_walker(_commit_id, path):
576 575 repo = self._factory.repo(wire)
577 576 root = svn.fs.revision_root(svn.repos.fs(repo), int(commit_id))
578 577
579 578 def no_content():
580 579 raise NoContentException()
581 580
582 581 for f_name, f_data, f_type in walk_tree(root, path, _commit_id):
583 582 file_path = f_name
584 583
585 584 if f_type == 'dir':
586 585 mode = f_data['mode']
587 586 yield ArchiveNode(file_path, mode, False, no_content)
588 587 else:
589 588 mode = f_data['mode']
590 589 is_link = f_data['is_link']
591 590 data_stream = f_data['content_stream']
592 591 yield ArchiveNode(file_path, mode, is_link, data_stream)
593 592
594 593 return archive_repo(file_walker, archive_dest_path, kind, mtime, archive_at_path,
595 594 archive_dir_name, commit_id)
596 595
597 596
598 597 class SvnDiffer(object):
599 598 """
600 599 Utility to create diffs based on difflib and the Subversion api
601 600 """
602 601
603 602 binary_content = False
604 603
605 604 def __init__(
606 605 self, repo, src_rev, src_path, tgt_rev, tgt_path,
607 606 ignore_whitespace, context):
608 607 self.repo = repo
609 608 self.ignore_whitespace = ignore_whitespace
610 609 self.context = context
611 610
612 611 fsobj = svn.repos.fs(repo)
613 612
614 613 self.tgt_rev = tgt_rev
615 614 self.tgt_path = tgt_path or ''
616 615 self.tgt_root = svn.fs.revision_root(fsobj, tgt_rev)
617 616 self.tgt_kind = svn.fs.check_path(self.tgt_root, self.tgt_path)
618 617
619 618 self.src_rev = src_rev
620 619 self.src_path = src_path or self.tgt_path
621 620 self.src_root = svn.fs.revision_root(fsobj, src_rev)
622 621 self.src_kind = svn.fs.check_path(self.src_root, self.src_path)
623 622
624 623 self._validate()
625 624
626 625 def _validate(self):
627 626 if (self.tgt_kind != svn.core.svn_node_none and
628 627 self.src_kind != svn.core.svn_node_none and
629 628 self.src_kind != self.tgt_kind):
630 629 # TODO: johbo: proper error handling
631 630 raise Exception(
632 631 "Source and target are not compatible for diff generation. "
633 632 "Source type: %s, target type: %s" %
634 633 (self.src_kind, self.tgt_kind))
635 634
636 635 def generate_diff(self):
637 636 buf = StringIO.StringIO()
638 637 if self.tgt_kind == svn.core.svn_node_dir:
639 638 self._generate_dir_diff(buf)
640 639 else:
641 640 self._generate_file_diff(buf)
642 641 return buf.getvalue()
643 642
644 643 def _generate_dir_diff(self, buf):
645 644 editor = DiffChangeEditor()
646 645 editor_ptr, editor_baton = svn.delta.make_editor(editor)
647 646 svn.repos.dir_delta2(
648 647 self.src_root,
649 648 self.src_path,
650 649 '', # src_entry
651 650 self.tgt_root,
652 651 self.tgt_path,
653 652 editor_ptr, editor_baton,
654 653 authorization_callback_allow_all,
655 654 False, # text_deltas
656 655 svn.core.svn_depth_infinity, # depth
657 656 False, # entry_props
658 657 False, # ignore_ancestry
659 658 )
660 659
661 660 for path, __, change in sorted(editor.changes):
662 661 self._generate_node_diff(
663 662 buf, change, path, self.tgt_path, path, self.src_path)
664 663
665 664 def _generate_file_diff(self, buf):
666 665 change = None
667 666 if self.src_kind == svn.core.svn_node_none:
668 667 change = "add"
669 668 elif self.tgt_kind == svn.core.svn_node_none:
670 669 change = "delete"
671 670 tgt_base, tgt_path = vcspath.split(self.tgt_path)
672 671 src_base, src_path = vcspath.split(self.src_path)
673 672 self._generate_node_diff(
674 673 buf, change, tgt_path, tgt_base, src_path, src_base)
675 674
676 675 def _generate_node_diff(
677 676 self, buf, change, tgt_path, tgt_base, src_path, src_base):
678 677
679 678 if self.src_rev == self.tgt_rev and tgt_base == src_base:
680 679 # makes consistent behaviour with git/hg to return empty diff if
681 680 # we compare same revisions
682 681 return
683 682
684 683 tgt_full_path = vcspath.join(tgt_base, tgt_path)
685 684 src_full_path = vcspath.join(src_base, src_path)
686 685
687 686 self.binary_content = False
688 687 mime_type = self._get_mime_type(tgt_full_path)
689 688
690 689 if mime_type and not mime_type.startswith('text'):
691 690 self.binary_content = True
692 691 buf.write("=" * 67 + '\n')
693 692 buf.write("Cannot display: file marked as a binary type.\n")
694 693 buf.write("svn:mime-type = %s\n" % mime_type)
695 694 buf.write("Index: %s\n" % (tgt_path, ))
696 695 buf.write("=" * 67 + '\n')
697 696 buf.write("diff --git a/%(tgt_path)s b/%(tgt_path)s\n" % {
698 697 'tgt_path': tgt_path})
699 698
700 699 if change == 'add':
701 700 # TODO: johbo: SVN is missing a zero here compared to git
702 701 buf.write("new file mode 10644\n")
703 702
704 703 #TODO(marcink): intro to binary detection of svn patches
705 704 # if self.binary_content:
706 705 # buf.write('GIT binary patch\n')
707 706
708 707 buf.write("--- /dev/null\t(revision 0)\n")
709 708 src_lines = []
710 709 else:
711 710 if change == 'delete':
712 711 buf.write("deleted file mode 10644\n")
713 712
714 713 #TODO(marcink): intro to binary detection of svn patches
715 714 # if self.binary_content:
716 715 # buf.write('GIT binary patch\n')
717 716
718 717 buf.write("--- a/%s\t(revision %s)\n" % (
719 718 src_path, self.src_rev))
720 719 src_lines = self._svn_readlines(self.src_root, src_full_path)
721 720
722 721 if change == 'delete':
723 722 buf.write("+++ /dev/null\t(revision %s)\n" % (self.tgt_rev, ))
724 723 tgt_lines = []
725 724 else:
726 725 buf.write("+++ b/%s\t(revision %s)\n" % (
727 726 tgt_path, self.tgt_rev))
728 727 tgt_lines = self._svn_readlines(self.tgt_root, tgt_full_path)
729 728
730 729 if not self.binary_content:
731 730 udiff = svn_diff.unified_diff(
732 731 src_lines, tgt_lines, context=self.context,
733 732 ignore_blank_lines=self.ignore_whitespace,
734 733 ignore_case=False,
735 734 ignore_space_changes=self.ignore_whitespace)
736 735 buf.writelines(udiff)
737 736
738 737 def _get_mime_type(self, path):
739 738 try:
740 739 mime_type = svn.fs.node_prop(
741 740 self.tgt_root, path, svn.core.SVN_PROP_MIME_TYPE)
742 741 except svn.core.SubversionException:
743 742 mime_type = svn.fs.node_prop(
744 743 self.src_root, path, svn.core.SVN_PROP_MIME_TYPE)
745 744 return mime_type
746 745
747 746 def _svn_readlines(self, fs_root, node_path):
748 747 if self.binary_content:
749 748 return []
750 749 node_kind = svn.fs.check_path(fs_root, node_path)
751 750 if node_kind not in (
752 751 svn.core.svn_node_file, svn.core.svn_node_symlink):
753 752 return []
754 753 content = svn.core.Stream(svn.fs.file_contents(fs_root, node_path)).read()
755 754 return content.splitlines(True)
756 755
757 756
758 757 class DiffChangeEditor(svn.delta.Editor):
759 758 """
760 759 Records changes between two given revisions
761 760 """
762 761
763 762 def __init__(self):
764 763 self.changes = []
765 764
766 765 def delete_entry(self, path, revision, parent_baton, pool=None):
767 766 self.changes.append((path, None, 'delete'))
768 767
769 768 def add_file(
770 769 self, path, parent_baton, copyfrom_path, copyfrom_revision,
771 770 file_pool=None):
772 771 self.changes.append((path, 'file', 'add'))
773 772
774 773 def open_file(self, path, parent_baton, base_revision, file_pool=None):
775 774 self.changes.append((path, 'file', 'change'))
776 775
777 776
778 777 def authorization_callback_allow_all(root, path, pool):
779 778 return True
780 779
781 780
782 781 class TxnNodeProcessor(object):
783 782 """
784 783 Utility to process the change of one node within a transaction root.
785 784
786 785 It encapsulates the knowledge of how to add, update or remove
787 786 a node for a given transaction root. The purpose is to support the method
788 787 `SvnRemote.commit`.
789 788 """
790 789
791 790 def __init__(self, node, txn_root):
792 791 assert isinstance(node['path'], str)
793 792
794 793 self.node = node
795 794 self.txn_root = txn_root
796 795
797 796 def update(self):
798 797 self._ensure_parent_dirs()
799 798 self._add_file_if_node_does_not_exist()
800 799 self._update_file_content()
801 800 self._update_file_properties()
802 801
803 802 def remove(self):
804 803 svn.fs.delete(self.txn_root, self.node['path'])
805 804 # TODO: Clean up directory if empty
806 805
807 806 def _ensure_parent_dirs(self):
808 807 curdir = vcspath.dirname(self.node['path'])
809 808 dirs_to_create = []
810 809 while not self._svn_path_exists(curdir):
811 810 dirs_to_create.append(curdir)
812 811 curdir = vcspath.dirname(curdir)
813 812
814 813 for curdir in reversed(dirs_to_create):
815 814 log.debug('Creating missing directory "%s"', curdir)
816 815 svn.fs.make_dir(self.txn_root, curdir)
817 816
818 817 def _svn_path_exists(self, path):
819 818 path_status = svn.fs.check_path(self.txn_root, path)
820 819 return path_status != svn.core.svn_node_none
821 820
822 821 def _add_file_if_node_does_not_exist(self):
823 822 kind = svn.fs.check_path(self.txn_root, self.node['path'])
824 823 if kind == svn.core.svn_node_none:
825 824 svn.fs.make_file(self.txn_root, self.node['path'])
826 825
827 826 def _update_file_content(self):
828 827 assert isinstance(self.node['content'], str)
829 828 handler, baton = svn.fs.apply_textdelta(
830 829 self.txn_root, self.node['path'], None, None)
831 830 svn.delta.svn_txdelta_send_string(self.node['content'], handler, baton)
832 831
833 832 def _update_file_properties(self):
834 833 properties = self.node.get('properties', {})
835 834 for key, value in properties.iteritems():
836 835 svn.fs.change_node_prop(
837 836 self.txn_root, self.node['path'], key, value)
838 837
839 838
840 839 def apr_time_t(timestamp):
841 840 """
842 841 Convert a Python timestamp into APR timestamp type apr_time_t
843 842 """
844 843 return timestamp * 1E6
845 844
846 845
847 846 def svn_opt_revision_value_t(num):
848 847 """
849 848 Put `num` into a `svn_opt_revision_value_t` structure.
850 849 """
851 850 value = svn.core.svn_opt_revision_value_t()
852 851 value.number = num
853 852 revision = svn.core.svn_opt_revision_t()
854 853 revision.kind = svn.core.svn_opt_revision_number
855 854 revision.value = value
856 855 return revision
General Comments 0
You need to be logged in to leave comments. Login now