Skip to content

breuleux/buche

master
Switch branches/tags
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
bin
 
 
 
 
 
 
 
 
 
 
src
 
 
 
 
 
 
 
 
 
 

What is buche?

Download

Buche is a language-agnostic, serverless, extensible HTML "logger". No matter what language you are using, with only a little bit of code, it can do a lot of things:

  • Display log entries in HTML and Markdown.
  • Live plots.
  • Live graphs.
  • Simple interactive interfaces like REPLs.

Here's why you might want to use it:

  • Only stdout: All you need to know to use buche is how to print JSON.
  • Serverless: You don't need to start a server or to connect to a server. Just write buche <command> ...
  • Learn by example: If you want to reproduce an existing command's output, just look at the JSON commands it prints (also: buche --inspect).
  • Extensible: It is possible to define new channel types and new components, and plugins can be installed directly through the UI!
  • Easy to use over ssh: buche <command> => buche ssh <machine> <command>. It just works.

A lot of Buche's advantages boil down to the first point: Buche works on a stream of JSON commands, and uses stdin and stdout as its interface. This means you can take everything you know about manipulating these streams, everything you know about manipulating plain files, and leverage that to make Buche do what you want.

For example, you can save a command's output in a file, and play it back to Buche. If you have results in multiple files, you can merge them in a single Buche window as simply as buche cat <file1> <file2> .... You can use jq or even grep to filter interesting parts, sed or awk for simple tweaks, etc. You can connect Buche to a fifo and funnel multiple commands into it. You can also write your own middleware to transform JSON streams in whatever way is useful to you.

plot

Install

Packages and binaries for Mac/Linux can be downloaded on the latest release page.

You can also install buche with npm:

npm install buche -g

To install plugins, you can write:

buche --install <plugin-name>

It is usually not necessary to do it on the command line, however. If a program outputs the require command to require a plugin, Buche will prompt the user to install it if it cannot be found.

Use

Buche takes commands from stdout and (when applicable) outputs commands on stdin. This means you can simply pipe your application to buche: <command> | buche (if you have no need for stdin) or you can have buche run the command for you: buche <command>. (Note: in a script, you can use the shebang #!/usr/bin/env buche <language> to make the shell invoke buche when executing the script).

The best way to learn how to use Buche is by example: take a program that does something you would like to do, and either inspect its code, or inspect its output (which should be pretty simple most of the time). For this purpose, the --inspect flag makes buche print out all the commands that are exchanged between it and a program, in the following format: -> <command_to_buche> and <- <command_from_buche>. The former is what you should print, the latter is what you should parse and respond to (but don't worry too much about that, because it is only relevant if you want to write an interactive application).

Commands

Here is how buche commands work:

  • The command must be formatted as JSON and must be all on a single line (no pretty printing).
  • Except for the commands template, redirect, resource and plugin, all commands must specify a parent.
  • The parent is typically some DOM element. Plugins can define custom components that answer to custom commands.
  • Defining the address attribute on an element is required to make it addressable. Read about the log command below for more information on how this works.

log

The simplest command is log, which you can omit since it is the default. Log takes some HTML content and dumps it in the specified element. For example, this adds a div to the root element:

{"parent": "/", "command": "log", "content": "<div>Hello!</div>"}

Other elements can be reached through their address. For example:

{"parent": "/", "command": "log", "content": "<div address=\"above\">Above</div><div address=\"below\"></div>"}
{"parent": "/above", "command": "log", "content": "<b address=\"nested\">Hello</b>"}
{"parent": "/below", "command": "log", "content": "<b>World</b>"}
{"parent": "/above/nested", "command": "log", "content": ", beautiful"}

This will display, incrementally, the following HTML:

<div>Above <b>Hello, beautiful</b></div>
<div>Below <b>World</b></div>

Notice that addresses are relative: when we add the element with address nested to the element with address /above, the address of that element becomes /above/nested. It is possible to define an element with an absolute address by prepending it with a /, so the address for <div address="/notnested"></div> is /notnested regardless of where you put it.

eval

eval evaluates some JavaScript in the context of the specified parent. For example, this sets the focus on the element at /myinput:

{"parent": "/myinput", "command": "eval", "expression": "this.focus()"}

resource

The resource command does not have a parent. It simply adds a resource in the document's <head>. For example:

{"command": "resource", "content": "<style>.myclass {color: red}</style>"}

Anything you can put in <head> will work here.

plugin

The plugin command imports a plugin. It does not have a parent. If the plugin contains a slash, it will be interpreted as a path and the plugin will be fetched on the filesystem. Otherwise, buche will try to import the plugin from its global cache.

{"command": "plugin", "name": "cytoscape"}
{"command": "plugin", "name": "./index.js"}

If the plugin is not found, try installing it with buche --install <name>, e.g. buche --install cytoscape.

redirect

The redirect command redirects an address to another. This is mostly useful to redirect /stdout and /stderr, which by default go to separate tabs from the root element /. Example:

{"command": "redirect", "from": "/stdout", "to": "/"}

template

The template command, if provided, must be the first command. Either src or content can be used:

{"command": "template", "src": "my-template.html"}
{"command": "template", "content": "<div class=\"root\" address=\"/\">...</div>"}

The template should define an element with address / and may also define /stdout, /stderr and /buche/errors, which is where Buche will respectively put non-json lines on stdout, non-json lines on stderr, and various errors such as a log command without a parent. Note that Buche will still make sure all of these exist even if they are not in the template, so that nothing is accidentally thrown away.

Examples

There are several simple examples in this repository to get you started. They are here. You can also clone the repository to get to them:

git clone https://github.com/breuleux/buche
cd buche/examples
./demo/demo.py

Each example is executable and uses the --inspect or -v flag to show you the example's output stream. Executing an example works simply because the shebang in the file invokes buche, and you can look at it with head -1 example. It's all very simple. The code for most of the examples easily fit on a screen.

Some Buche functionality and channels are not in any examples yet, unfortunately, but that will come.

Language support

This section contains advice about how to best use Buche with various programming languages. In general, it is possible to use it with any language without any specific support, but there are sometimes a few tricks to remember, and some languages may have libraries to make everything even easier.

Python

IMPORTANT: By default, Python will buffer its output when it isn't directly outputting to a tty. That means the logging will be choppy, not very responsive, and might not even happen before the command is completely done executing. To solve this, pass the -u flag to python: instead of writing buche python <file>, write buche python -u <file>.

Package: There is a buche package for Python >= 3.6 which you can install with pip install buche. buche gives a nicer syntax to open channels, log into them, and notably provides a buche(object) function that pretty-prints Python objects as HTML. These objects can also be interacted with by clicking on them. See here for documentation on the package. It is recommended to run examples/pyrepl_nice.py (in this repository) for a demonstration.

Plugins

Install a plugin with this command:

buche --install <plugin-name>

To use a plugin, you must have your program print out a require command prior to using components defined by the plugin.

Stability

There is no stable release of Buche at the moment and the interface and commands may still change. Some capabilities may be removed in order to enhance security, such as the ability to inject scripts with full permissions in the output stream. Suggestions are welcome.

Writing extensions

TODO.

Still, if you feel motivated, you can look at buche-cytoscape and buche-bokeh to get a general idea of how to write an extension.

Essentially, you want to define one or more custom components, and then various command_<name> methods for any commands you want your component to understand.

Note: these plugins are installed in ~/.config/buche/node_modules.

More screenshots

Because you won't know what you want until you see it.

Graphs:

graph

Simple Python REPL:

repl

Shiny Python REPL:

repl

(If you're wondering, the hrepr package handles the pretty printing. It was written for Buche but it will also work in Jupyter, minus the ability to put objects in variables by clicking on their representation)

Merging the outputs of several commands in the same window:

merge