mirror of
https://github.com/asciinema/asciinema.git
synced 2025-12-16 11:48:13 +01:00
Merge pull request #472 from asciinema/recorder-refa
Recorder refactoring
This commit is contained in:
@@ -17,7 +17,7 @@ def record_asciicast( # pylint: disable=too-many-arguments
|
|||||||
command: Any = None,
|
command: Any = None,
|
||||||
append: bool = False,
|
append: bool = False,
|
||||||
idle_time_limit: Optional[int] = None,
|
idle_time_limit: Optional[int] = None,
|
||||||
rec_stdin: bool = False,
|
record_stdin: bool = False,
|
||||||
title: Optional[str] = None,
|
title: Optional[str] = None,
|
||||||
metadata: Any = None,
|
metadata: Any = None,
|
||||||
command_env: Any = None,
|
command_env: Any = None,
|
||||||
@@ -28,7 +28,7 @@ def record_asciicast( # pylint: disable=too-many-arguments
|
|||||||
command=command,
|
command=command,
|
||||||
append=append,
|
append=append,
|
||||||
idle_time_limit=idle_time_limit,
|
idle_time_limit=idle_time_limit,
|
||||||
rec_stdin=rec_stdin,
|
record_stdin=record_stdin,
|
||||||
title=title,
|
title=title,
|
||||||
metadata=metadata,
|
metadata=metadata,
|
||||||
command_env=command_env,
|
command_env=command_env,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class RecordCommand(Command): # pylint: disable=too-many-instance-attributes
|
|||||||
Command.__init__(self, args, config, env)
|
Command.__init__(self, args, config, env)
|
||||||
self.quiet = args.quiet
|
self.quiet = args.quiet
|
||||||
self.filename = args.filename
|
self.filename = args.filename
|
||||||
self.rec_stdin = args.stdin
|
self.record_stdin = args.stdin
|
||||||
self.command = args.command
|
self.command = args.command
|
||||||
self.env_whitelist = args.env
|
self.env_whitelist = args.env
|
||||||
self.title = args.title
|
self.title = args.title
|
||||||
@@ -107,9 +107,9 @@ class RecordCommand(Command): # pylint: disable=too-many-instance-attributes
|
|||||||
idle_time_limit=self.idle_time_limit,
|
idle_time_limit=self.idle_time_limit,
|
||||||
command_env=self.env,
|
command_env=self.env,
|
||||||
capture_env=vars_,
|
capture_env=vars_,
|
||||||
rec_stdin=self.rec_stdin,
|
record_stdin=self.record_stdin,
|
||||||
writer=self.writer,
|
writer=self.writer,
|
||||||
notifier=self.notifier,
|
notify=self.notifier.notify,
|
||||||
key_bindings=self.key_bindings,
|
key_bindings=self.key_bindings,
|
||||||
cols_override=self.cols_override,
|
cols_override=self.cols_override,
|
||||||
rows_override=self.rows_override,
|
rows_override=self.rows_override,
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class CustomCommandNotifier(Notifier):
|
|||||||
|
|
||||||
|
|
||||||
class NoopNotifier: # pylint: disable=too-few-public-methods
|
class NoopNotifier: # pylint: disable=too-few-public-methods
|
||||||
def notify(self) -> None:
|
def notify(self, text: str) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,20 +16,14 @@ from .term import raw
|
|||||||
# pylint: disable=too-many-arguments,too-many-locals,too-many-statements
|
# pylint: disable=too-many-arguments,too-many-locals,too-many-statements
|
||||||
def record(
|
def record(
|
||||||
command: Any,
|
command: Any,
|
||||||
|
env: Dict[str, str],
|
||||||
writer: Any,
|
writer: Any,
|
||||||
get_tty_size: Callable[[], Tuple[int, int]],
|
get_tty_size: Callable[[], Tuple[int, int]],
|
||||||
env: Any = None,
|
notify: Callable[[str], None],
|
||||||
rec_stdin: bool = False,
|
key_bindings: Dict[str, Any],
|
||||||
time_offset: float = 0,
|
|
||||||
notifier: Any = None,
|
|
||||||
key_bindings: Optional[Dict[str, Any]] = None,
|
|
||||||
tty_stdin_fd: int = pty.STDIN_FILENO,
|
tty_stdin_fd: int = pty.STDIN_FILENO,
|
||||||
tty_stdout_fd: int = pty.STDOUT_FILENO,
|
tty_stdout_fd: int = pty.STDOUT_FILENO,
|
||||||
) -> None:
|
) -> None:
|
||||||
if env is None:
|
|
||||||
env = os.environ
|
|
||||||
if key_bindings is None:
|
|
||||||
key_bindings = {}
|
|
||||||
master_fd: Any = None
|
master_fd: Any = None
|
||||||
start_time: Optional[float] = None
|
start_time: Optional[float] = None
|
||||||
pause_time: Optional[float] = None
|
pause_time: Optional[float] = None
|
||||||
@@ -37,10 +31,6 @@ def record(
|
|||||||
prefix_key = key_bindings.get("prefix")
|
prefix_key = key_bindings.get("prefix")
|
||||||
pause_key = key_bindings.get("pause")
|
pause_key = key_bindings.get("pause")
|
||||||
|
|
||||||
def _notify(text: str) -> None:
|
|
||||||
if notifier:
|
|
||||||
notifier.notify(text)
|
|
||||||
|
|
||||||
def _set_pty_size() -> None:
|
def _set_pty_size() -> None:
|
||||||
"""
|
"""
|
||||||
Sets the window size of the child pty based on the window size
|
Sets the window size of the child pty based on the window size
|
||||||
@@ -94,16 +84,16 @@ def record(
|
|||||||
assert start_time is not None
|
assert start_time is not None
|
||||||
start_time += time.time() - pause_time
|
start_time += time.time() - pause_time
|
||||||
pause_time = None
|
pause_time = None
|
||||||
_notify("Resumed recording")
|
notify("Resumed recording")
|
||||||
else:
|
else:
|
||||||
pause_time = time.time()
|
pause_time = time.time()
|
||||||
_notify("Paused recording")
|
notify("Paused recording")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
_write_master(data)
|
_write_master(data)
|
||||||
|
|
||||||
if rec_stdin and not pause_time:
|
if not pause_time:
|
||||||
assert start_time is not None
|
assert start_time is not None
|
||||||
writer.write_stdin(time.time() - start_time, data)
|
writer.write_stdin(time.time() - start_time, data)
|
||||||
|
|
||||||
@@ -186,7 +176,7 @@ def record(
|
|||||||
|
|
||||||
_set_pty_size()
|
_set_pty_size()
|
||||||
|
|
||||||
start_time = time.time() - time_offset
|
start_time = time.time()
|
||||||
|
|
||||||
with raw(tty_stdin_fd):
|
with raw(tty_stdin_fd):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ def record( # pylint: disable=too-many-arguments,too-many-locals
|
|||||||
command: Any = None,
|
command: Any = None,
|
||||||
append: bool = False,
|
append: bool = False,
|
||||||
idle_time_limit: Optional[int] = None,
|
idle_time_limit: Optional[int] = None,
|
||||||
rec_stdin: bool = False,
|
record_stdin: bool = False,
|
||||||
title: Optional[str] = None,
|
title: Optional[str] = None,
|
||||||
metadata: Any = None,
|
metadata: Any = None,
|
||||||
command_env: Optional[Dict[Any, Any]] = None,
|
command_env: Optional[Dict[Any, Any]] = None,
|
||||||
capture_env: Any = None,
|
capture_env: Any = None,
|
||||||
writer: Type[w2] = v2.writer,
|
writer: Type[w2] = v2.writer,
|
||||||
record_: Callable[..., None] = pty.record,
|
record_: Callable[..., None] = pty.record,
|
||||||
notifier: Any = None,
|
notify: Callable[[str], None] = lambda _: None,
|
||||||
key_bindings: Optional[Dict[str, Any]] = None,
|
key_bindings: Optional[Dict[str, Any]] = None,
|
||||||
cols_override: Optional[int] = None,
|
cols_override: Optional[int] = None,
|
||||||
rows_override: Optional[int] = None,
|
rows_override: Optional[int] = None,
|
||||||
@@ -70,22 +70,18 @@ def record( # pylint: disable=too-many-arguments,too-many-locals
|
|||||||
if append and os.stat(path_).st_size > 0:
|
if append and os.stat(path_).st_size > 0:
|
||||||
time_offset = v2.get_duration(path_)
|
time_offset = v2.get_duration(path_)
|
||||||
|
|
||||||
with async_notifier(notifier) as _notifier:
|
with async_notifier(notify) as _notifier:
|
||||||
with async_writer(
|
sync_writer = writer(
|
||||||
writer,
|
path_, full_metadata, append, on_error=_notifier.notify
|
||||||
path_,
|
)
|
||||||
full_metadata,
|
|
||||||
append,
|
with async_writer(sync_writer, time_offset, record_stdin) as _writer:
|
||||||
_notifier.queue,
|
|
||||||
) as _writer:
|
|
||||||
record_(
|
record_(
|
||||||
["sh", "-c", command],
|
["sh", "-c", command],
|
||||||
|
command_env,
|
||||||
_writer,
|
_writer,
|
||||||
get_tty_size,
|
get_tty_size,
|
||||||
command_env,
|
_notifier.notify,
|
||||||
rec_stdin,
|
|
||||||
time_offset,
|
|
||||||
_notifier,
|
|
||||||
key_bindings,
|
key_bindings,
|
||||||
tty_stdin_fd=tty_stdin_fd,
|
tty_stdin_fd=tty_stdin_fd,
|
||||||
tty_stdout_fd=tty_stdout_fd,
|
tty_stdout_fd=tty_stdout_fd,
|
||||||
@@ -94,60 +90,44 @@ def record( # pylint: disable=too-many-arguments,too-many-locals
|
|||||||
|
|
||||||
class async_writer(async_worker):
|
class async_writer(async_worker):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self, writer: w2, time_offset: float, record_stdin: bool
|
||||||
writer: Type[w2],
|
|
||||||
path_: str,
|
|
||||||
metadata: Any,
|
|
||||||
append: bool = False,
|
|
||||||
notifier_q: Any = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
async_worker.__init__(self)
|
async_worker.__init__(self)
|
||||||
self.writer = writer
|
self.writer = writer
|
||||||
self.path = path_
|
self.time_offset = time_offset
|
||||||
self.metadata = metadata
|
self.record_stdin = record_stdin
|
||||||
self.append = append
|
|
||||||
self.notifier_q = notifier_q
|
|
||||||
|
|
||||||
def write_stdin(self, ts: float, data: Any) -> None:
|
def write_stdin(self, ts: float, data: Any) -> None:
|
||||||
self.enqueue([ts, "i", data])
|
if self.record_stdin:
|
||||||
|
self.enqueue([ts, "i", data])
|
||||||
|
|
||||||
def write_stdout(self, ts: float, data: Any) -> None:
|
def write_stdout(self, ts: float, data: Any) -> None:
|
||||||
self.enqueue([ts, "o", data])
|
self.enqueue([ts, "o", data])
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
with self.writer(
|
with self.writer as w:
|
||||||
self.path,
|
|
||||||
metadata=self.metadata,
|
|
||||||
append=self.append,
|
|
||||||
on_error=self.__on_error,
|
|
||||||
) as w:
|
|
||||||
event: Tuple[float, str, Any]
|
event: Tuple[float, str, Any]
|
||||||
for event in iter(self.queue.get, None):
|
for event in iter(self.queue.get, None):
|
||||||
assert event is not None
|
assert event is not None
|
||||||
ts, etype, data = event
|
ts, etype, data = event
|
||||||
|
|
||||||
if etype == "o":
|
if etype == "o":
|
||||||
w.write_stdout(ts, data)
|
w.write_stdout(self.time_offset + ts, data)
|
||||||
elif etype == "i":
|
elif etype == "i":
|
||||||
w.write_stdin(ts, data)
|
w.write_stdin(self.time_offset + ts, data)
|
||||||
|
|
||||||
def __on_error(self, reason: str) -> None:
|
|
||||||
if self.notifier_q:
|
|
||||||
self.notifier_q.put(reason)
|
|
||||||
|
|
||||||
|
|
||||||
class async_notifier(async_worker):
|
class async_notifier(async_worker):
|
||||||
def __init__(self, notifier: Any) -> None:
|
def __init__(self, notify: Callable[[str], None]) -> None:
|
||||||
async_worker.__init__(self)
|
async_worker.__init__(self)
|
||||||
self.notifier = notifier
|
self._notify = notify
|
||||||
|
|
||||||
def notify(self, text: str) -> None:
|
def notify(self, text: str) -> None:
|
||||||
self.enqueue(text)
|
self.enqueue(text)
|
||||||
|
|
||||||
def perform(self, text: str) -> None:
|
def perform(self, text: str) -> None:
|
||||||
try:
|
try:
|
||||||
if self.notifier:
|
self._notify(text)
|
||||||
self.notifier.notify(text)
|
|
||||||
except: # pylint: disable=bare-except # noqa: E722
|
except: # pylint: disable=bare-except # noqa: E722
|
||||||
# we catch *ALL* exceptions here because we don't want failed
|
# we catch *ALL* exceptions here because we don't want failed
|
||||||
# notification to crash the recording session
|
# notification to crash the recording session
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import asciinema.pty_
|
|||||||
from .test_helper import Test
|
from .test_helper import Test
|
||||||
|
|
||||||
|
|
||||||
class FakeStdout:
|
class Writer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.data = []
|
self.data = []
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class TestRecord(Test):
|
|||||||
self.real_os_write(fd, data)
|
self.real_os_write(fd, data)
|
||||||
|
|
||||||
def test_record_command_writes_to_stdout(self):
|
def test_record_command_writes_to_stdout(self):
|
||||||
output = FakeStdout()
|
writer = Writer()
|
||||||
|
|
||||||
command = [
|
command = [
|
||||||
"python3",
|
"python3",
|
||||||
@@ -44,6 +44,9 @@ class TestRecord(Test):
|
|||||||
"; sys.stdout.write('bar')"
|
"; sys.stdout.write('bar')"
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
asciinema.pty_.record(command, output, lambda: (80, 24))
|
|
||||||
|
|
||||||
assert output.data == [b"foo", b"bar"]
|
asciinema.pty_.record(
|
||||||
|
command, {}, writer, lambda: (80, 24), lambda s: None, {}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert writer.data == [b"foo", b"bar"]
|
||||||
|
|||||||
Reference in New Issue
Block a user