##// END OF EJS Templates
release: Merge default into stable for release preparation
marcink -
r595:0d6e5c13 merge stable
parent child Browse files
Show More
@@ -0,0 +1,26 b''
1 diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
2 --- a/Documentation/git-send-email.txt
3 +++ b/Documentation/git-send-email.txt
4 @@ -208,8 +208,7 @@ a password is obtained using 'git-credential'.
5 specify a full pathname of a sendmail-like program instead;
6 the program must support the `-i` option. Default value can
7 be specified by the `sendemail.smtpServer` configuration
8 - option; the built-in default is to search for `sendmail` in
9 - `/usr/sbin`, `/usr/lib` and $PATH if such program is
10 + option; the built-in default is to search in $PATH if such program is
11 available, falling back to `localhost` otherwise.
12
13 --smtp-server-port=<port>::
14 diff --git a/git-send-email.perl b/git-send-email.perl
15 --- a/git-send-email.perl
16 +++ b/git-send-email.perl
17 @@ -944,8 +944,7 @@ if (defined $reply_to) {
18 }
19
20 if (!defined $smtp_server) {
21 - my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
22 - push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
23 + my @sendmail_paths = map {"$_/sendmail"} split /:/, $ENV{PATH};
24 foreach (@sendmail_paths) {
25 if (-x $_) {
26 $smtp_server = $_;
@@ -0,0 +1,12 b''
1 diff --git a/t/test-lib.sh b/t/test-lib.sh
2 --- a/t/test-lib.sh
3 +++ b/t/test-lib.sh
4 @@ -923,7 +923,7 @@
5 then
6 GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) ||
7 error "Cannot run git from $GIT_TEST_INSTALLED."
8 - PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR:$PATH
9 + PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR/t/helper:$GIT_BUILD_DIR:$PATH
10 GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
11 else # normal case, use ../bin-wrappers only unless $with_dashes:
12 git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
@@ -1,5 +1,5 b''
1 1 [bumpversion]
2 current_version = 4.14.1
2 current_version = 4.15.0
3 3 message = release: Bump version {current_version} to {new_version}
4 4
5 5 [bumpversion:file:vcsserver/VERSION]
@@ -5,12 +5,10 b' done = false'
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.14.1
12 state = in_progress
13 version = 4.15.0
16 14
@@ -1,17 +1,19 b''
1 1 self: super: {
2 2 # bump GIT version
3 3 git = super.lib.overrideDerivation super.git (oldAttrs: {
4 name = "git-2.17.2";
4 name = "git-2.19.1";
5 5 src = self.fetchurl {
6 url = "https://www.kernel.org/pub/software/scm/git/git-2.17.2.tar.xz";
7 sha256 = "1ghljlxmyqphx13qspy382cpl2pbkbwbhqm7w7z57r9mkhswx668";
6 url = "https://www.kernel.org/pub/software/scm/git/git-2.19.1.tar.xz";
7 sha256 = "1dfv43lmdnxz42504jc89sihbv1d4d6kgqcz3c5ji140kfm5cl1l";
8 8 };
9 9
10 # patches come from: https://github.com/NixOS/nixpkgs/tree/master/pkgs/applications/version-management/git-and-tools/git
10 11 patches = [
11 12 ./patches/git/docbook2texi.patch
12 ./patches/git/symlinks-in-bin.patch
13 13 ./patches/git/git-sh-i18n.patch
14 14 ./patches/git/ssh-path.patch
15 ./patches/git/git-send-email-honor-PATH.patch
16 ./patches/git/installCheck-path.patch
15 17 ];
16 18
17 19 });
@@ -2,29 +2,29 b' This patch does two things: (1) use the '
2 2 and (2) make sure `gitman.info' isn't produced since it's broken (duplicate
3 3 node names).
4 4
5 diff -ru git-1.8.4-orig/Documentation/Makefile git-1.8.4/Documentation/Makefile
6 --- git-1.8.4-orig/Documentation/Makefile 2013-08-23 21:38:43.000000000 +0200
7 +++ git-1.8.4/Documentation/Makefile 2013-09-30 14:48:51.532890378 +0200
8 @@ -101,7 +101,7 @@
9
5 diff --git a/Documentation/Makefile b/Documentation/Makefile
6 --- a/Documentation/Makefile
7 +++ b/Documentation/Makefile
8 @@ -122,7 +122,7 @@
9
10 10 MAKEINFO = makeinfo
11 11 INSTALL_INFO = install-info
12 12 -DOCBOOK2X_TEXI = docbook2x-texi
13 13 +DOCBOOK2X_TEXI = docbook2texi
14 14 DBLATEX = dblatex
15 ifndef PERL_PATH
16 PERL_PATH = /usr/bin/perl
17 @@ -205,7 +205,7 @@
15 ASCIIDOC_DBLATEX_DIR = /etc/asciidoc/dblatex
16 DBLATEX_COMMON = -p $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.xsl -s $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.sty
17 @@ -240,7 +240,7 @@
18 18 man5: $(DOC_MAN5)
19 19 man7: $(DOC_MAN7)
20
20
21 21 -info: git.info gitman.info
22 22 +info: git.info
23
23
24 24 pdf: user-manual.pdf
25
26 @@ -221,10 +221,9 @@
27
25
26 @@ -256,10 +256,9 @@
27
28 28 install-info: info
29 29 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
30 30 - $(INSTALL) -m 644 git.info gitman.info $(DESTDIR)$(infodir)
@@ -154,14 +154,14 b' self: super: {'
154 154 };
155 155 };
156 156 "gevent" = super.buildPythonPackage {
157 name = "gevent-1.3.6";
157 name = "gevent-1.3.7";
158 158 doCheck = false;
159 159 propagatedBuildInputs = [
160 160 self."greenlet"
161 161 ];
162 162 src = fetchurl {
163 url = "https://files.pythonhosted.org/packages/49/13/aa4bb3640b5167fe58875d3d7e65390cdb14f9682a41a741a566bb560842/gevent-1.3.6.tar.gz";
164 sha256 = "1ih4k73dqz2zb561hda99vbanja3m6cdch3mgxxn1mla3qwkqhbv";
163 url = "https://files.pythonhosted.org/packages/10/c1/9499b146bfa43aa4f1e0ed1bab1bd3209a4861d25650c11725036c731cf5/gevent-1.3.7.tar.gz";
164 sha256 = "0b0fr04qdk1p4sniv87fh8z5psac60x01pv054kpgi94520g81iz";
165 165 };
166 166 meta = {
167 167 license = [ pkgs.lib.licenses.mit ];
@@ -212,26 +212,26 b' self: super: {'
212 212 };
213 213 };
214 214 "hgsubversion" = super.buildPythonPackage {
215 name = "hgsubversion-1.9.2";
215 name = "hgsubversion-1.9.3";
216 216 doCheck = false;
217 217 propagatedBuildInputs = [
218 218 self."mercurial"
219 219 self."subvertpy"
220 220 ];
221 221 src = fetchurl {
222 url = "https://files.pythonhosted.org/packages/05/80/3a3cef10dd65e86528ef8d7ac57a41ebc782d0f3c6cfa4fed021aa9fbee0/hgsubversion-1.9.2.tar.gz";
223 sha256 = "16490narhq14vskml3dam8g5y3w3hdqj3g8bgm2b0c0i85l1xvcz";
222 url = "https://files.pythonhosted.org/packages/a3/53/6d205e641f3e09abcf1ddaed66e5e4b20da22d0145566d440a02c9e35f0d/hgsubversion-1.9.3.tar.gz";
223 sha256 = "0nymcjlch8c4zjbncrs30p2nrbylsf25g3h6mr0zzzxr141h3sig";
224 224 };
225 225 meta = {
226 226 license = [ pkgs.lib.licenses.gpl1 ];
227 227 };
228 228 };
229 229 "hupper" = super.buildPythonPackage {
230 name = "hupper-1.3.1";
230 name = "hupper-1.4.2";
231 231 doCheck = false;
232 232 src = fetchurl {
233 url = "https://files.pythonhosted.org/packages/cf/4b/467b826a84c8594b81f414b5ab6794e981951dac90ca40abaf9ea1cb36b0/hupper-1.3.1.tar.gz";
234 sha256 = "03mf13n6i4dd60wlb9m99ddl4m3lmly70cjp7f82vdkibfl1v6l9";
233 url = "https://files.pythonhosted.org/packages/f1/75/1915dc7650b4867fa3049256e24ca8eddb5989998fcec788cf52b9812dfc/hupper-1.4.2.tar.gz";
234 sha256 = "16vb9fkiaakdpcp6pn56h3w0dwvm67bxq2k2dv4i382qhqwphdzb";
235 235 };
236 236 meta = {
237 237 license = [ pkgs.lib.licenses.mit ];
@@ -502,11 +502,11 b' self: super: {'
502 502 };
503 503 };
504 504 "pygments" = super.buildPythonPackage {
505 name = "pygments-2.2.0";
505 name = "pygments-2.3.0";
506 506 doCheck = false;
507 507 src = fetchurl {
508 url = "https://files.pythonhosted.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
509 sha256 = "1k78qdvir1yb1c634nkv6rbga8wv4289xarghmsbbvzhvr311bnv";
508 url = "https://files.pythonhosted.org/packages/63/a2/91c31c4831853dedca2a08a0f94d788fc26a48f7281c99a303769ad2721b/Pygments-2.3.0.tar.gz";
509 sha256 = "1z34ms51dh4jq4h3cizp7vd1dmsxcbvffkjsd2xxfav22nn6lrl2";
510 510 };
511 511 meta = {
512 512 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -656,7 +656,7 b' self: super: {'
656 656 };
657 657 };
658 658 "rhodecode-vcsserver" = super.buildPythonPackage {
659 name = "rhodecode-vcsserver-4.14.1";
659 name = "rhodecode-vcsserver-4.15.0";
660 660 buildInputs = [
661 661 self."pytest"
662 662 self."py"
@@ -750,11 +750,11 b' self: super: {'
750 750 };
751 751 };
752 752 "setuptools" = super.buildPythonPackage {
753 name = "setuptools-40.4.3";
753 name = "setuptools-40.6.2";
754 754 doCheck = false;
755 755 src = fetchurl {
756 url = "https://files.pythonhosted.org/packages/6e/9c/6a003320b00ef237f94aa74e4ad66c57a7618f6c79d67527136e2544b728/setuptools-40.4.3.zip";
757 sha256 = "058v6zns4634n4al2nmmvp15j8nrgwn8wjrbdks47wk3vm05gg5c";
756 url = "https://files.pythonhosted.org/packages/b0/d1/8acb42f391cba52e35b131e442e80deffbb8d0676b93261d761b1f0ef8fb/setuptools-40.6.2.zip";
757 sha256 = "0r2c5hapirlzm34h7pl1lgkm6gk7bcrlrdj28qgsvaqg3f74vfw6";
758 758 };
759 759 meta = {
760 760 license = [ pkgs.lib.licenses.mit ];
@@ -8,7 +8,7 b' dogpile.cache==0.6.7'
8 8 dogpile.core==0.4.1
9 9 decorator==4.1.2
10 10 dulwich==0.13.0
11 hgsubversion==1.9.2
11 hgsubversion==1.9.3
12 12 hg-evolve==8.0.1
13 13 mako==1.0.7
14 14 markupsafe==1.0.0
@@ -20,7 +20,7 b' psutil==5.4.7'
20 20 pyramid==1.9.2
21 21 pyramid-mako==1.0.2
22 22
23 pygments==2.2.0
23 pygments==2.3.0
24 24 pathlib2==2.3.2
25 25 repoze.lru==0.7
26 26 simplejson==3.11.1
@@ -34,7 +34,7 b' zope.deprecation==4.3.0'
34 34 zope.interface==4.5.0
35 35
36 36 ## http servers
37 gevent==1.3.6
37 gevent==1.3.7
38 38 greenlet==0.4.15
39 39 gunicorn==19.9.0
40 40 waitress==1.1.0
@@ -1,1 +1,1 b''
1 4.14.1 No newline at end of file
1 4.15.0 No newline at end of file
@@ -518,15 +518,6 b' class GitRemote(object):'
518 518 return repo.get_description()
519 519
520 520 @reraise_safe_exceptions
521 def get_file_history(self, wire, file_path, commit_id, limit):
522 repo = self._factory.repo(wire)
523 include = [commit_id]
524 paths = [file_path]
525
526 walker = repo.get_walker(include, paths=paths, max_entries=limit)
527 return [x.commit.id for x in walker]
528
529 @reraise_safe_exceptions
530 521 def get_missing_revs(self, wire, rev1, rev2, path2):
531 522 repo = self._factory.repo(wire)
532 523 LocalGitClient(thin_packs=False).fetch(path2, repo)
@@ -417,7 +417,7 b' class HgRemote(object):'
417 417 raise exceptions.LookupException(e)()
418 418
419 419 @reraise_safe_exceptions
420 def file_history(self, wire, revision, path, limit):
420 def node_history(self, wire, revision, path, limit):
421 421 repo = self._factory.repo(wire)
422 422
423 423 ctx = repo[revision]
@@ -439,7 +439,7 b' class HgRemote(object):'
439 439 return [x for x in history]
440 440
441 441 @reraise_safe_exceptions
442 def file_history_untill(self, wire, revision, path, limit):
442 def node_history_untill(self, wire, revision, path, limit):
443 443 repo = self._factory.repo(wire)
444 444 ctx = repo[revision]
445 445 fctx = ctx.filectx(path)
@@ -42,7 +42,7 b' def install_git_hooks(repo_path, bare, e'
42 42 if not bare:
43 43 hooks_path = os.path.join(repo_path, '.git', 'hooks')
44 44 if not os.path.isdir(hooks_path):
45 os.makedirs(hooks_path, mode=0777)
45 os.makedirs(hooks_path, mode=0o777)
46 46
47 47 tmpl_post = pkg_resources.resource_string(
48 48 'vcsserver', '/'.join(
@@ -69,7 +69,7 b' def install_git_hooks(repo_path, bare, e'
69 69 template = template.replace('_ENV_', executable)
70 70 template = template.replace('_PATH_', path)
71 71 f.write(template)
72 os.chmod(_hook_file, 0755)
72 os.chmod(_hook_file, 0o755)
73 73 except IOError:
74 74 log.exception('error writing hook file %s', _hook_file)
75 75 else:
@@ -89,7 +89,7 b' def install_svn_hooks(repo_path, executa'
89 89 executable = executable or sys.executable
90 90 hooks_path = os.path.join(repo_path, 'hooks')
91 91 if not os.path.isdir(hooks_path):
92 os.makedirs(hooks_path, mode=0777)
92 os.makedirs(hooks_path, mode=0o777)
93 93
94 94 tmpl_post = pkg_resources.resource_string(
95 95 'vcsserver', '/'.join(
@@ -118,7 +118,7 b' def install_svn_hooks(repo_path, executa'
118 118 template = template.replace('_PATH_', path)
119 119
120 120 f.write(template)
121 os.chmod(_hook_file, 0755)
121 os.chmod(_hook_file, 0o755)
122 122 except IOError:
123 123 log.exception('error writing hook file %s', _hook_file)
124 124 else:
@@ -52,7 +52,16 b' class HooksHttpClient(object):'
52 52 log.error('Connection failed on %s', connection)
53 53 raise
54 54 response = connection.getresponse()
55 return json.loads(response.read())
55
56 response_data = response.read()
57
58 try:
59 return json.loads(response_data)
60 except Exception:
61 log.exception('Failed to decode hook response json data. '
62 'response_code:%s, raw_data:%s',
63 response.status, response_data)
64 raise
56 65
57 66 def _serialize(self, hook_name, extras):
58 67 data = {
@@ -197,6 +197,28 b' class WsgiProxy(object):'
197 197 yield msgpack.packb(d)
198 198
199 199
200 def not_found(request):
201 return {'status': '404 NOT FOUND'}
202
203
204 class VCSViewPredicate(object):
205 def __init__(self, val, config):
206 self.remotes = val
207
208 def text(self):
209 return 'vcs view method = %s' % (self.remotes.keys(),)
210
211 phash = text
212
213 def __call__(self, context, request):
214 """
215 View predicate that returns true if given backend is supported by
216 defined remotes.
217 """
218 backend = request.matchdict.get('backend')
219 return backend in self.remotes
220
221
200 222 class HTTPApplication(object):
201 223 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
202 224
@@ -256,7 +278,7 b' class HTTPApplication(object):'
256 278
257 279 # ensure we have our dir created
258 280 if not os.path.isdir(default_cache_dir):
259 os.makedirs(default_cache_dir, mode=0755)
281 os.makedirs(default_cache_dir, mode=0o755)
260 282
261 283 # exception store cache
262 284 _string_setting(
@@ -279,9 +301,7 b' class HTTPApplication(object):'
279 301 1024)
280 302
281 303 def _configure(self):
282 self.config.add_renderer(
283 name='msgpack',
284 factory=self._msgpack_renderer_factory)
304 self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory)
285 305
286 306 self.config.add_route('service', '/_service')
287 307 self.config.add_route('status', '/status')
@@ -291,23 +311,20 b' class HTTPApplication(object):'
291 311 self.config.add_route('stream_git', '/stream/git/*repo_name')
292 312 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
293 313
294 self.config.add_view(
295 self.status_view, route_name='status', renderer='json')
296 self.config.add_view(
297 self.service_view, route_name='service', renderer='msgpack')
314 self.config.add_view(self.status_view, route_name='status', renderer='json')
315 self.config.add_view(self.service_view, route_name='service', renderer='msgpack')
298 316
299 317 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
300 318 self.config.add_view(self.git_proxy(), route_name='git_proxy')
301 self.config.add_view(
302 self.vcs_view, route_name='vcs', renderer='msgpack',
303 custom_predicates=[self.is_vcs_view])
319 self.config.add_view(self.vcs_view, route_name='vcs', renderer='msgpack',
320 vcs_view=self._remotes)
304 321
305 322 self.config.add_view(self.hg_stream(), route_name='stream_hg')
306 323 self.config.add_view(self.git_stream(), route_name='stream_git')
307 324
308 def notfound(request):
309 return {'status': '404 NOT FOUND'}
310 self.config.add_notfound_view(notfound, renderer='json')
325 self.config.add_view_predicate('vcs_view', VCSViewPredicate)
326
327 self.config.add_notfound_view(not_found, renderer='json')
311 328
312 329 self.config.add_view(self.handle_vcs_exception, context=Exception)
313 330
@@ -543,14 +560,6 b' class HTTPApplication(object):'
543 560
544 561 return _git_stream
545 562
546 def is_vcs_view(self, context, request):
547 """
548 View predicate that returns true if given backend is supported by
549 defined remotes.
550 """
551 backend = request.matchdict.get('backend')
552 return backend in self._remotes
553
554 563 def handle_vcs_exception(self, exception, request):
555 564 _vcs_kind = getattr(exception, '_vcs_kind', '')
556 565 if _vcs_kind == 'repo_locked':
@@ -36,8 +36,7 b' def environ():'
36 36
37 37
38 38 def _get_python_args(script):
39 return [sys.executable, '-c',
40 'import sys; import time; import shutil; ' + script]
39 return [sys.executable, '-c', 'import sys; import time; import shutil; ' + script]
41 40
42 41
43 42 def test_raise_exception_on_non_zero_return_code(environ):
@@ -48,8 +47,11 b' def test_raise_exception_on_non_zero_ret'
48 47
49 48 def test_does_not_fail_on_non_zero_return_code(environ):
50 49 args = _get_python_args('sys.exit(1)')
51 output = ''.join(subprocessio.SubprocessIOChunker(
52 args, shell=False, fail_on_return_code=False, env=environ))
50 output = ''.join(
51 subprocessio.SubprocessIOChunker(
52 args, shell=False, fail_on_return_code=False, env=environ
53 )
54 )
53 55
54 56 assert output == ''
55 57
@@ -64,49 +66,56 b' def test_raise_exception_on_stderr(envir'
64 66
65 67 def test_does_not_fail_on_stderr(environ):
66 68 args = _get_python_args('sys.stderr.write("X"); time.sleep(1);')
67 output = ''.join(subprocessio.SubprocessIOChunker(
68 args, shell=False, fail_on_stderr=False, env=environ))
69 output = ''.join(
70 subprocessio.SubprocessIOChunker(
71 args, shell=False, fail_on_stderr=False, env=environ
72 )
73 )
69 74
70 75 assert output == ''
71 76
72 77
73 @pytest.mark.parametrize('size', [1, 10**5])
78 @pytest.mark.parametrize('size', [1, 10 ** 5])
74 79 def test_output_with_no_input(size, environ):
75 print type(environ)
80 print(type(environ))
76 81 data = 'X'
77 82 args = _get_python_args('sys.stdout.write("%s" * %d)' % (data, size))
78 output = ''.join(subprocessio.SubprocessIOChunker(
79 args, shell=False, env=environ))
83 output = ''.join(subprocessio.SubprocessIOChunker(args, shell=False, env=environ))
80 84
81 85 assert output == data * size
82 86
83 87
84 @pytest.mark.parametrize('size', [1, 10**5])
88 @pytest.mark.parametrize('size', [1, 10 ** 5])
85 89 def test_output_with_no_input_does_not_fail(size, environ):
86 90 data = 'X'
87 args = _get_python_args(
88 'sys.stdout.write("%s" * %d); sys.exit(1)' % (data, size))
89 output = ''.join(subprocessio.SubprocessIOChunker(
90 args, shell=False, fail_on_return_code=False, env=environ))
91 args = _get_python_args('sys.stdout.write("%s" * %d); sys.exit(1)' % (data, size))
92 output = ''.join(
93 subprocessio.SubprocessIOChunker(
94 args, shell=False, fail_on_return_code=False, env=environ
95 )
96 )
91 97
92 print len(data * size), len(output)
98 print("{} {}".format(len(data * size), len(output)))
93 99 assert output == data * size
94 100
95 101
96 @pytest.mark.parametrize('size', [1, 10**5])
102 @pytest.mark.parametrize('size', [1, 10 ** 5])
97 103 def test_output_with_input(size, environ):
98 104 data = 'X' * size
99 105 inputstream = io.BytesIO(data)
100 106 # This acts like the cat command.
101 107 args = _get_python_args('shutil.copyfileobj(sys.stdin, sys.stdout)')
102 output = ''.join(subprocessio.SubprocessIOChunker(
103 args, shell=False, inputstream=inputstream, env=environ))
108 output = ''.join(
109 subprocessio.SubprocessIOChunker(
110 args, shell=False, inputstream=inputstream, env=environ
111 )
112 )
104 113
105 print len(data), len(output)
114 print("{} {}".format(len(data * size), len(output)))
106 115 assert output == data
107 116
108 117
109 @pytest.mark.parametrize('size', [1, 10**5])
118 @pytest.mark.parametrize('size', [1, 10 ** 5])
110 119 def test_output_with_input_skipping_iterator(size, environ):
111 120 data = 'X' * size
112 121 inputstream = io.BytesIO(data)
@@ -115,8 +124,9 b' def test_output_with_input_skipping_iter'
115 124
116 125 # Note: assigning the chunker makes sure that it is not deleted too early
117 126 chunker = subprocessio.SubprocessIOChunker(
118 args, shell=False, inputstream=inputstream, env=environ)
127 args, shell=False, inputstream=inputstream, env=environ
128 )
119 129 output = ''.join(chunker.output)
120 130
121 print len(data), len(output)
131 print("{} {}".format(len(data * size), len(output)))
122 132 assert output == data
General Comments 0
You need to be logged in to leave comments. Login now