Hello community, here is the log from the commit of package asciinema for openSUSE:Factory checked in at 2018-04-05 15:34:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/asciinema (Old) and /work/SRC/openSUSE:Factory/.asciinema.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "asciinema" Thu Apr 5 15:34:49 2018 rev:5 rq:593653 version:2.0.1 Changes: -------- --- /work/SRC/openSUSE:Factory/asciinema/asciinema.changes 2018-02-14 09:45:42.828734500 +0100 +++ /work/SRC/openSUSE:Factory/.asciinema.new/asciinema.changes 2018-04-05 15:34:52.365147552 +0200 @@ -1,0 +2,9 @@ +Thu Apr 5 04:14:49 UTC 2018 - avvissu@yandex.by + +- Upadte to 2.0.1: + * Fixed example in asciicast v2 format doc + * Replaced deprecated encodestring with encodebytes + * Fixed location of config dir (mv ~/.asciinema ~/.config/asciinema) + * Internal refactorings + +------------------------------------------------------------------- Old: ---- asciinema-2.0.0.tar.gz New: ---- asciinema-2.0.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ asciinema.spec ++++++ --- /var/tmp/diff_new_pack.EjuIuQ/_old 2018-04-05 15:34:52.917127603 +0200 +++ /var/tmp/diff_new_pack.EjuIuQ/_new 2018-04-05 15:34:52.917127603 +0200 @@ -17,7 +17,7 @@ Name: asciinema -Version: 2.0.0 +Version: 2.0.1 Release: 0 Summary: Terminal session recorder License: GPL-3.0+ ++++++ asciinema-2.0.0.tar.gz -> asciinema-2.0.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/CHANGELOG.md new/asciinema-2.0.1/CHANGELOG.md --- old/asciinema-2.0.0/CHANGELOG.md 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/CHANGELOG.md 2018-04-04 09:05:41.000000000 +0200 @@ -1,5 +1,12 @@ # asciinema changelog +## 2.0.1 (2018-04-04) + +* Fixed example in asciicast v2 format doc (thanks Josh "@anowlcalledjosh" Holland!) +* Replaced deprecated `encodestring` (since Python 3.1) with `encodebytes` (thanks @delirious-lettuce!) +* Fixed location of config dir (you can `mv ~/.asciinema ~/.config/asciinema`) +* Internal refactorings + ## 2.0 (2018-02-10) This major release brings many new features, improvements and bugfixes. The most diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/__init__.py new/asciinema-2.0.1/asciinema/__init__.py --- old/asciinema-2.0.0/asciinema/__init__.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/__init__.py 2018-04-04 09:05:41.000000000 +0200 @@ -1,7 +1,7 @@ import sys __author__ = 'Marcin Kulik' -__version__ = '2.0.0' +__version__ = '2.0.1' if sys.version_info[0] < 3: raise ImportError('Python < 3 is unsupported.') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/asciicast/events.py new/asciinema-2.0.1/asciinema/asciicast/events.py --- old/asciinema-2.0.0/asciinema/asciicast/events.py 1970-01-01 01:00:00.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/asciicast/events.py 2018-04-04 09:05:41.000000000 +0200 @@ -0,0 +1,28 @@ +def to_relative_time(events): + prev_time = 0 + + for frame in events: + time, type, data = frame + delay = time - prev_time + prev_time = time + yield [delay, type, data] + + +def to_absolute_time(events): + time = 0 + + for frame in events: + delay, type, data = frame + time = time + delay + yield [time, type, data] + + +def cap_relative_time(events, time_limit): + if time_limit: + return ([min(delay, time_limit), type, data] for delay, type, data in events) + else: + return events + + +def adjust_speed(events, speed): + return ([delay / speed, type, data] for delay, type, data in events) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/asciicast/frames.py new/asciinema-2.0.1/asciinema/asciicast/frames.py --- old/asciinema-2.0.0/asciinema/asciicast/frames.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/asciicast/frames.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,28 +0,0 @@ -def to_relative_time(frames): - prev_time = 0 - - for frame in frames: - time, data = frame - delay = time - prev_time - prev_time = time - yield [delay, data] - - -def to_absolute_time(frames): - time = 0 - - for frame in frames: - delay, data = frame - time = time + delay - yield [time, data] - - -def cap_relative_time(frames, time_limit): - if time_limit: - return ([min(delay, time_limit), text] for delay, text in frames) - else: - return frames - - -def adjust_speed(frames, speed): - return ([delay / speed, text] for delay, text in frames) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/asciicast/v1.py new/asciinema-2.0.1/asciinema/asciicast/v1.py --- old/asciinema-2.0.0/asciinema/asciicast/v1.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/asciicast/v1.py 2018-04-04 09:05:41.000000000 +0200 @@ -1,7 +1,7 @@ import json import json.decoder -from asciinema.asciicast.frames import to_absolute_time +from asciinema.asciicast.events import to_absolute_time try: @@ -16,13 +16,26 @@ class Asciicast: - def __init__(self, stdout): + def __init__(self, attrs): self.version = 1 - self.__stdout = stdout + self.__attrs = attrs self.idle_time_limit = None # v1 doesn't store it - def stdout(self): - return to_absolute_time(self.__stdout) + @property + def v2_header(self): + keys = ['width', 'height', 'duration', 'command', 'title', 'env'] + header = {k: v for k, v in self.__attrs.items() if k in keys and v is not None} + return header + + def __stdout_events(self): + for time, data in self.__attrs['stdout']: + yield [time, 'o', data] + + def events(self): + return self.stdout_events() + + def stdout_events(self): + return to_absolute_time(self.__stdout_events()) class open_from_file(): @@ -37,7 +50,7 @@ attrs = json.loads(self.first_line + self.file.read()) if attrs.get('version') == 1: - return Asciicast(attrs['stdout']) + return Asciicast(attrs) else: raise LoadError(self.FORMAT_ERROR) except JSONDecodeError as e: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/asciicast/v2.py new/asciinema-2.0.1/asciinema/asciicast/v2.py --- old/asciinema-2.0.0/asciinema/asciicast/v2.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/asciicast/v2.py 2018-04-04 09:05:41.000000000 +0200 @@ -21,22 +21,24 @@ class Asciicast: - def __init__(self, f, idle_time_limit): + def __init__(self, f, header): self.version = 2 self.__file = f - self.idle_time_limit = idle_time_limit + self.v2_header = header + self.idle_time_limit = header.get('idle_time_limit') - def stdout(self): + def events(self): for line in self.__file: - time, type, data = json.loads(line) + yield json.loads(line) + def stdout_events(self): + for time, type, data in self.events(): if type == 'o': - yield [time, data] + yield [time, type, data] def build_from_header_and_file(header, f): - idle_time_limit = header.get('idle_time_limit') - return Asciicast(f, idle_time_limit) + return Asciicast(f, header) class open_from_file(): @@ -64,19 +66,76 @@ with open(path, mode='rt', encoding='utf-8') as f: first_line = f.readline() with open_from_file(first_line, f) as a: - for last_frame in a.stdout(): + for last_frame in a.stdout_events(): pass return last_frame[0] -def write_json_lines_from_queue(path, mode, queue): - with open(path, mode=mode, buffering=1) as f: - for json_value in iter(queue.get, None): - line = json.dumps(json_value, ensure_ascii=False, indent=None, separators=(', ', ': ')) - f.write(line + '\n') +class writer(): + def __init__(self, path, width=None, height=None, header=None, mode='w', buffering=-1): + self.path = path + self.mode = mode + self.buffering = buffering + self.stdin_decoder = codecs.getincrementaldecoder('UTF-8')('replace') + self.stdout_decoder = codecs.getincrementaldecoder('UTF-8')('replace') -class writer(): + if mode == 'w': + self.header = {'version': 2, 'width': width, 'height': height} + self.header.update(header or {}) + assert type(self.header['width']) == int, 'width or header missing' + assert type(self.header['height']) == int, 'height or header missing' + else: + self.header = None + + def __enter__(self): + self.file = open(self.path, mode=self.mode, buffering=self.buffering) + + if self.header: + self.__write_line(self.header) + + return self + + def __exit__(self, exc_type, exc_value, exc_traceback): + self.file.close() + + def write_event(self, ts, etype=None, data=None): + if etype is None: + ts, etype, data = ts + + ts = round(ts, 6) + + if etype == 'o': + if type(data) == str: + data = data.encode(encoding='utf-8', errors='strict') + text = self.stdout_decoder.decode(data) + self.__write_line([ts, etype, text]) + elif etype == 'i': + if type(data) == str: + data = data.encode(encoding='utf-8', errors='strict') + text = self.stdin_decoder.decode(data) + self.__write_line([ts, etype, text]) + else: + self.__write_line([ts, etype, data]) + + def write_stdout(self, ts, data): + self.write_event(ts, 'o', data) + + def write_stdin(self, ts, data): + self.write_event(ts, 'i', data) + + def __write_line(self, obj): + line = json.dumps(obj, ensure_ascii=False, indent=None, separators=(', ', ': ')) + self.file.write(line + '\n') + + +def write_json_lines_from_queue(path, header, mode, queue): + with writer(path, header=header, mode=mode, buffering=1) as w: + for event in iter(queue.get, None): + w.write_event(event) + + +class async_writer(): def __init__(self, path, header, rec_stdin, start_time_offset=0): self.path = path @@ -84,18 +143,14 @@ self.rec_stdin = rec_stdin self.start_time_offset = start_time_offset self.queue = Queue() - self.stdin_decoder = codecs.getincrementaldecoder('UTF-8')('replace') - self.stdout_decoder = codecs.getincrementaldecoder('UTF-8')('replace') def __enter__(self): mode = 'a' if self.start_time_offset > 0 else 'w' self.process = Process( target=write_json_lines_from_queue, - args=(self.path, mode, self.queue) + args=(self.path, self.header, mode, self.queue) ) self.process.start() - if self.start_time_offset == 0: - self.queue.put(self.header) self.start_time = time.time() - self.start_time_offset return self @@ -105,18 +160,12 @@ def write_stdin(self, data): if self.rec_stdin: - text = self.stdin_decoder.decode(data) - - if text: - ts = round(time.time() - self.start_time, 6) - self.queue.put([ts, 'i', text]) + ts = time.time() - self.start_time + self.queue.put([ts, 'i', data]) def write_stdout(self, data): - text = self.stdout_decoder.decode(data) - - if text: - ts = round(time.time() - self.start_time, 6) - self.queue.put([ts, 'o', text]) + ts = time.time() - self.start_time + self.queue.put([ts, 'o', data]) class Recorder: @@ -149,5 +198,5 @@ if title: header['title'] = title - with writer(path, header, rec_stdin, start_time_offset) as w: + with async_writer(path, header, rec_stdin, start_time_offset) as w: self.pty_recorder.record_command(['sh', '-c', command], w, command_env) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/commands/cat.py new/asciinema-2.0.1/asciinema/commands/cat.py --- old/asciinema-2.0.0/asciinema/commands/cat.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/commands/cat.py 2018-04-04 09:05:41.000000000 +0200 @@ -13,7 +13,7 @@ def execute(self): try: with asciicast.open_from_url(self.filename) as a: - for t, text in a.stdout(): + for t, _type, text in a.stdout_events(): sys.stdout.write(text) sys.stdout.flush() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/config.py new/asciinema-2.0.1/asciinema/config.py --- old/asciinema-2.0.0/asciinema/config.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/config.py 2018-04-04 09:05:41.000000000 +0200 @@ -131,10 +131,11 @@ elif env_xdg_config_home: config_home = path.join(env_xdg_config_home, "asciinema") elif env_home: - if path.isfile(path.join(env_home, ".config", "asciinema", "config")): - config_home = path.join(env_home, ".config", "asciinema") + if path.isfile(path.join(env_home, ".asciinema", "config")): + # location for versions < 1.1 + config_home = path.join(env_home, ".asciinema") else: - config_home = path.join(env_home, ".asciinema") # location for versions < 1.1 + config_home = path.join(env_home, ".config", "asciinema") else: raise Exception("need $HOME or $XDG_CONFIG_HOME or $ASCIINEMA_CONFIG_HOME") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/player.py new/asciinema-2.0.1/asciinema/player.py --- old/asciinema-2.0.0/asciinema/player.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/player.py 2018-04-04 09:05:41.000000000 +0200 @@ -2,7 +2,7 @@ import sys import time -import asciinema.asciicast.frames as frames +import asciinema.asciicast.events as ev from asciinema.term import raw, read_blocking @@ -19,18 +19,18 @@ def _play(self, asciicast, idle_time_limit, speed, stdin): idle_time_limit = idle_time_limit or asciicast.idle_time_limit - stdout = asciicast.stdout() - stdout = frames.to_relative_time(stdout) - stdout = frames.cap_relative_time(stdout, idle_time_limit) - stdout = frames.to_absolute_time(stdout) - stdout = frames.adjust_speed(stdout, speed) + stdout = asciicast.stdout_events() + stdout = ev.to_relative_time(stdout) + stdout = ev.cap_relative_time(stdout, idle_time_limit) + stdout = ev.to_absolute_time(stdout) + stdout = ev.adjust_speed(stdout, speed) base_time = time.time() ctrl_c = False paused = False pause_time = None - for t, text in stdout: + for t, _type, text in stdout: delay = t - (time.time() - base_time) while stdin and not ctrl_c and delay > 0: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/asciinema/urllib_http_adapter.py new/asciinema-2.0.1/asciinema/urllib_http_adapter.py --- old/asciinema-2.0.0/asciinema/urllib_http_adapter.py 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/asciinema/urllib_http_adapter.py 2018-04-04 09:05:41.000000000 +0200 @@ -67,7 +67,7 @@ if password: auth = "%s:%s" % (username, password) - encoded_auth = base64.encodestring(auth.encode('utf-8'))[:-1] + encoded_auth = base64.encodebytes(auth.encode('utf-8'))[:-1] headers["Authorization"] = b"Basic " + encoded_auth request = Request(url, data=body, headers=headers, method="POST") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/doc/asciicast-v2.md new/asciinema-2.0.1/doc/asciicast-v2.md --- old/asciinema-2.0.0/doc/asciicast-v2.md 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/doc/asciicast-v2.md 2018-04-04 09:05:41.000000000 +0200 @@ -71,8 +71,8 @@ ```json "env": { - "SHELL": "xterm-256color", - "TERM": "/bin/bash" + "SHELL": "/bin/bash", + "TERM": "xterm-256color" } ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/man/asciinema.1 new/asciinema-2.0.1/man/asciinema.1 --- old/asciinema-2.0.0/man/asciinema.1 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/man/asciinema.1 2018-04-04 09:05:41.000000000 +0200 @@ -1,6 +1,6 @@ -.\" Automatically generated by Pandoc 2.1.1 +.\" Automatically generated by Pandoc 2.1.3 .\" -.TH "ASCIINEMA" "1" "" "Version 2.0" "asciinema" +.TH "ASCIINEMA" "1" "" "Version 2.0.1" "asciinema" .hy .SH NAME .PP diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/man/asciinema.1.md new/asciinema-2.0.1/man/asciinema.1.md --- old/asciinema-2.0.0/man/asciinema.1.md 2018-02-10 22:47:22.000000000 +0100 +++ new/asciinema-2.0.1/man/asciinema.1.md 2018-04-04 09:05:41.000000000 +0200 @@ -1,4 +1,4 @@ -% ASCIINEMA(1) Version 2.0 | asciinema +% ASCIINEMA(1) Version 2.0.1 | asciinema NAME ==== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asciinema-2.0.0/tests/asciicast/v2_test.py new/asciinema-2.0.1/tests/asciicast/v2_test.py --- old/asciinema-2.0.0/tests/asciicast/v2_test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/asciinema-2.0.1/tests/asciicast/v2_test.py 2018-04-04 09:05:41.000000000 +0200 @@ -0,0 +1,24 @@ +from ..test_helper import Test +import asciinema.asciicast.v2 as v2 +import tempfile +import json + + +class TestWriter(Test): + + def test_writing(self): + _file, path = tempfile.mkstemp() + + with v2.writer(path, width=80, height=24) as w: + w.write_stdout(1, 'x') # ensure it supports both str and bytes + w.write_stdout(2, bytes.fromhex('78 c5 bc c3 b3 c5')) + w.write_stdout(3, bytes.fromhex('82 c4 87')) + w.write_stdout(4, bytes.fromhex('78 78')) + + with open(path, 'r') as f: + lines = list(map(json.loads, f.read().strip().split('\n'))) + assert lines == [{"version": 2, "width": 80, "height": 24}, + [1, "o", "x"], + [2, "o", "xżó"], + [3, "o", "łć"], + [4, "o", "xx"]], 'got:\n\n%s' % lines