Peer Pressure

Stuff to look at about looking at stuff. From Chris Dent. What?

Archive

Dec
14th
Mon
permalink

Tiddlywebweb to App Engine

In the previous posting I showed how to get TiddlyWeb working with Google App Engine but left things a bit hanging: There was no easy way to get some initial content bootstrapped into the hosted TiddlyWeb. It is possible to do direct HTTP calls to the server, using something like curl, but that can be a bit cumbersome. Another option is to use tiddlywebweb, I’ll describe that method here.

tiddlywebweb was first mentioned on this blog in a posting that described how to make a store for TiddlyWeb and ranted a bit about how useful a well described and nicely constrained HTTP API can be. tiddlywebweb uses the TiddlyWeb HTTP API to store and retrieve content to and from a remote TiddlyWeb server. Talking to a TiddlyWeb server is exactly what we need to solve our app engine problem, so let’s do it.

If you’ve followed the instructions in the previous posting you have, running in your local app engine SDK, a TiddlyWeb server at http://localhost:8080/. If you go that URL you’ll see there are links for bags and recipes, but no bags and recipes to be found, and no tiddlers. Leave the server running. In a terminal window do the following:

mkdir gaeproxy
cd gaeproxy
sudo pip install -U tiddlywebplugins.tiddlywebweb

If you don’t want to install all the dependencies (because you already have them) you can add a --no-deps after the -U. If you prefer to work with a virtualenv, go for it, the goals here are:

  • Make a directory in which we will create a tiddlyweb instance.
  • Install tiddlywebplugins.tiddlywebweb.

Once the install is done, we need to create, in the gaeproxy directory, a tiddlywebconfig.py file with the following contents:

config = {
    'log_level': 'DEBUG',
    'server_store': ['tiddlywebplugins.tiddlywebweb', {
        'server_base': 'http://localhost:8080',
    }],
    'system_plugins': ['tiddlywebwiki'],
    'twanager_plugins': ['tiddlywebwiki'],
}

You can then run a command to confirm a) that things aren’t going to blow up 2. that there’s nothing in the store:

twanager lbags

This should return nothing but also report no errors. If you get errors you’ll want to confirm that your configuration is correct, you have the required modules installed, and your app engine application is running.

Once you’ve confirmed there’s nothing in the store, we can put some stuff in there:

twanager bag system </dev/null
twanager bag common </dev/null
echo $'/bags/system/tiddlers\n/bags/common/tiddlers' | \
    twanager recipe default
twanager update

Those commands create two bags, system and common, create a recipe using those bags and then update the contents of the bags with tiddlers provided by the tiddlywebwiki plugin.

Now go to app engine TiddlyWeb at http://localhost:8080/recipes/default/tiddlers.wiki and see if you have a wiki.

Another useful command that works over tiddlywebweb is imwiki. If you have a TiddlyWiki you’d like to import into your app engine setup, go to your gaeproxy directory, and twanager imwiki common < mywikifile.html.

So there’s the basics of using tiddlywebweb with a TiddlyWeb hosted on google app engine. If you’ve deployed your application to Google’s appspot, update the tiddlywebconfig.py in the gaeproxy directory so that server_base points to the appspot domain instead of localhost.

There are some limitations with this approach:

  • User entities are not exposed over the TiddlyWeb HTTP API, so twanager commands for manipulating users (lusers, adduser, addrole, userpass) will not work. In the app engine setting this doesn’t really matter as Google users are used, not TiddlyWeb users.
  • If you’re not familiar with directly manipulating tiddlywebconfig.py and TiddlyWeb instances, this process may be rather opaque. FND has done some experimenting with creating instances that take out some of the steps. Perhaps he will post the details.

This combination of stuff has so many little happy web bits.

Comments (View)
Dec
11th
Fri
permalink

Smooth TiddlyWeb on App Engine

It’s been possible to run TiddlyWeb on Google App Engine for more than a year now, but the process to get things started and keep code up to date has been cumbersome. Recent changes to how TiddlyWeb is packaged and deployed have made the process a good deal easier. Assuming you can satisfy the following requirements

then here is the process to get a basic working app:

git clone git://github.com/tiddlyweb/tiddlyweb-plugins.git 
cd tiddlyweb-plugins/googleappengine
make go

After that process completes, in the subdirectory called go will be a working app engine application of tiddlywebwiki. You can host with you local SDK appengine launcher or toolset and visit it at http://0.0.0.0:8080/. If you want to deploy it to appspot.com you will need to:

  • Edit app.yaml to change the name of the application.
  • Edit tiddlywebconfig.py to change the host in the non-dev server_host configuration item.

What make go does is install all the necessary requirements into a virtualenv and then symlink them into an app engine directory.

So now what? Now you have a TiddlyWeb setup with no content and no clear way to add content. Either read the README in the tiddlyweb-plugins/googleappengine directory, or wait for my next blog post.

Comments (View)
Dec
6th
Sun
permalink

Simplewiki for TiddlyWeb

I’ve created a plugin for TiddlyWeb that provides a very simple wiki that adheres to some old school wiki ways, including links to other pages being CamelCase, the editor being a simple textarea, and RecentChanges being provided with the same link-space as the “normal” pages. It uses markdown as its syntax, with the addition of WikiLinks.

You can get it as tiddlywebplugins.simplewiki from PyPI. The PyPI page includes installation information. The code is on github.

You can see a running version at http://simplewiki.peermore.com/wiki Feel free to play around there.

I made it as a demonstration showing how to create a particular type of application with TiddlyWeb and tiddlyweb plugins. We’ve identified a few different application types in the TiddlyWeb universe:

  • Those that exercise its identity as a server-side for TiddlyWiki.
  • Those that exercise its identity as a headless RESTful document store.
  • Those that use it as building blocks for web apps.

Simplewiki is the latter. It is a rather small amount of code that assembles other TiddlyWeb plugins as Python dependencies and packages them with an install script and the small amount of data required to get things rolling.

Note that though there have been calls for a canonical TiddlyWeb application, I don’t think this can be called one, because it only covers one aspect of TiddlyWeb application creation, and the easy aspect at that. However it is probably a useful base case for all types.

It’s probably most informative to go look at the code but the following provides an overview of how things are put together.

tiddlywebplugins.simplewiki, the Python package, started life as a copy of the pluginmaker, which provides basic fill in the blank templates for starting a TiddlyWeb plugin project. Once those blank are filled in, it is a matter of adding functionality and the pieces to support that functionality.

All of the output from SimpleWiki is HTML, so it uses the do_html decorator from tiddlywebplugins.utils to wrap web handlers with code that ensures HTML output. That output is generated from templates which are managed by the tiddlywebplugins.templates package. Fed into those templates is text that has been rendered to html by the tiddlywebplugins.markdown package.

The text comes from tiddlers stored in a configurable recipe which can optionally use bags that have policies constraining access to read, write and create the tiddlers. Tiddlers, recipes, bags, policies and authentication and authorization handling all come from core TiddlyWeb. The wiki URL route is mounted via a handler in the simplewiki plugin which adds to the routes table managed and presented by core TiddlyWeb.

To make it easy to create a new wiki, Simplewiki includes a script called simplewiki that gathers up data from the plugin and provides it to tiddlywebplugins.instancer. Instancer is described as “A TiddlyWeb plugin to simplify instance management for verticals.” This is exactly what it does. The simplewiki script runs, creating a new instance including a store with a default configuration and a recipe name “wiki” that refers to a bag named “wiki” that contains a tiddler named “FrontPage”. The bag and recipe information are contained in a python module (tiddlywebplugins.simplewiki.instance), and the tiddler is included as package data (i.e. a file contained in the package accessible by Python code). This instancer functionality is extremely powerful and will only get more so as it is improved with use.

If simplewiki is not used, the tiddlywebplugins.simplewiki may be added to any existing instance in the usual way: By adding it to ‘system_plugins’ in tiddlywebconfig.py. If that’s done then a recipe will need to be configured for the wiki to use as its data source.

So with just the basic package you get a simple functional wiki that can be configured to use access control if you like. Stop reading now if you don’t need more more than that.

But wait, there’s more!

Because the tiddlywebplugins.templates package is being used to manage templates, if a directory called templates is present in the instance, it will be checked first for templates before checking the package data. This means you can override the templates with your own, per instance.

You can add Atom feed support by installing the tiddlywebplugins.atom, and providing a link (via the templates) to the Atom feed of the recipe driving the wiki.

You can use recipe_templates to provide context dependent tiddlers in the recipe used to drive the wiki.

Simplewiki is a plugin, but is also pluggable itself. You can add PageName, function pairs to the SPECIAL_PAGES dictionary to add dynamic pages to the wiki (this is how RecentChanges works).

Creating this plugin has been a good experience as it has helped point out both strengths and weaknesses in the TiddlyWeb core, other plugins and the instancer system. Those other pieces will improve as a result. Simplewiki’s own code is quite verbose, but with some refactoring, it could probably become very small. There’s a lot of what people like to call boilerplate (that I call transparency) that could be hoisted to utility modules. If this happens then plugins will become still more focussed on just being and showing what they do, not how they do it.

Comments (View)
Dec
2nd
Wed
permalink

TiddlyWeb DreamHost Experiments

These are rough notes for installing TiddlyWeb on a DreamHost hosted virtual domain. This is a fairly technical dump of some things I tried. It is not yet a straight up cookbook because there are some issues to be resolved before it can be. It might not look like it from all this text, but all of this could be compressed down to a very short shell script. That will come soon(ish).

I’ll get the big issues out of the way first. As I was winnowing down the steps involved to get things to go, it became clear that the Python (version 2.5) installed on the host was not dealing well with namespaces packages. This is unfortunate because that’s how we’ve started packaging tiddlywebplugins. The bug revealed itself as each subsequent plugin clobbering the contents of the tiddlywebplugins directory. So this process requires a custom built and installed Python. That’s covered below.

The second issue is that pip, during the install process, would like to do some renaming of temporary directory structures in. On large servers /tmp is often on another filesystem and the code pip uses explodes under those conditions. There’s a workaround by setting TMPDIR in the environment. That’s covered below too.

Step Zero: Install a New Python

Installing a modern Python keeps the namespace issues described above at bay. It needs to be done first, because what we do later requires the good Pythonic base.

I cribbed from Ryan Kanno to get Python built and installed. My slightly modified way to go is below. For the Python source URL, use whatever is under the “Source Distribution” quick links for Python 2.x.x on http://www.python.org/

$ mkdir opt
$ mkdir downloads
$ cd downloads
$ wget http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tar.bz2
$ tar jxf Python-2.6.4.tar
$ cd Python-2.6.4
$ ./configure --prefix=$HOME/opt/ --enable-unicode=ucs4
$ make # and assuming all goes well
$ make install

In $HOME/opt/bin there should be a python. Check its version:

$ cd
$ opt/bin/python -V
Python 2.6.4

Step One: Install and Setup VirtualEnv

virtualenv makes it easier to manage Python modules on a host for which you do not have root. It’s likely since we’ve installed our own Python that we wouldn’t need this step, but I’m hoping DreamHost will fix their Python, and Step Zero will go away and we can start counting from One.

For this step I cribbed from the DreamHost wiki. In these instructions we’ll use the Python we built. For the URL for virtualenv, copy the tarball link at the end of http://pypi.python.org/pypi/virtualenv

The following makes your home directory the root of your virtualenv. If you want to use many virtualenvs, this is probably not what what you want to do. But if you just want a single nice Python environment, this’ll do.

$ cd ~downloads
$ wget http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.4.3.tar.gz
$ tar zxvf virtualenv-1.4.3.tar.gz
$ ~/opt/bin/python virtualenv-1.4.3/virtualenv.py $HOME
$ echo "source bin/activate" >> ~/.bash_profile # activate updates your path nicely
$ cd
$ . .bash_profile # get those path changes

Now the python command in $HOME/bin is your main and active Python.

Step Two: Install TiddlyWeb

This is all automagic. The TMPDIR expression works around the pip problem described above.

$ cd
$ mkdir tmp
$ TMPDIR=$HOME/tmp pip -E . install -U tiddlywebwiki

A fair number of things will be installed from http://pypi.python.org/. When it is done, when you run:

$ ls bin

You should see twanager and twinstance in there.

Step Three: Create Your Instance

Now we will create our TiddlyWeb instance, which will do outside any web exposed areas. We don’t want to accidentally leak direct access to the store. You can name your instance whatever you like. We’ll call this one aleph.

$ cd # go home
$ twinstance aleph
$ cd aleph
$ ls
store  tiddlywebconfig.py

Now we will configure our instance so it is smart enough to run. We need to set two things in tiddlywebwconfig.py: server_prefix and server_host. Set server_prefix to ‘/index.cgi’ for now. Set server_host according to your hostname. If it is aleph.example.com then it will be:

'server_host': {
    'scheme': 'http',
    'host': 'aleph.example.com',
    'port': '80',
}

(Make these changes using your favorite editor on tiddlywebconfig.py.)

Step Four: Make it Go as CGI

In the DreamHost setup I was using, the web server’s document root is in playground/public. I’m not familiar enough with DreamHost to know if this is normal. I guess there can be several per user, so you’ll have to map the following to your own setup.

$ cd ~/playground/public
$ wget http://github.com/tiddlyweb/tiddlyweb/raw/master/index.cgi
$ chmod 755 index.cgi

Edit index.cgi to make 3 changes:

  1. Change the first line to the full path of your Python: #!/home/your username/bin/python.
  2. Set tiddlywebconfig_dir to your instance directory: '/home/your username/aleph'.
  3. Just to be sure change, os.environ[‘PYTHON_EGG_CACHE’] to: '/home/your username/tmp''. You created thistmp` directory earlier up the page.

Go to /index.cgi/ at your host. For example: http://aleph.example.com/index.cgi/. That trailing / is required (for now). To see the default wiki try your version of http://aleph.example.com/index.cgi/recipes/default/tiddlers.wiki.

Note that because DreamHost runs the CGI script as your user (via suexec), there are no weird permissions modifications you need to make here: new files are created just fine.

If everything has gone well up to now, that should do it. What follows in Step Five is a bonus.

Step Five: Make it Go with Passenger

Passenger is a tool for hosting Rails, Rack and WSGI applications on Apache (amongst other servers). DreamHost has made it pretty easy to use for WSGI things. To use it, change to the directory above your public directory and install some more stuff:

$ cd ~/playground
$ wget http://github.com/tiddlyweb/tiddlyweb/raw/master/apache.py
$ mv apache.py passenger_wsgi.py

Edit passenger_wsgi.py in a similar way to how index.cgi was edited above:

  1. Uncomment the two lines containing INTERP. Change INTERP to the path to your Python. In our examples that is /home/your username/bin/python (replace your username with the actual username).
  2. Set dirname to '/home/your username/aleph', or wherever your tiddlywebconfig.py is.
  3. Just to be sure change, os.environ[‘PYTHON_EGG_CACHE’] to: '/home/your username/tmp''. You created thistmp` directory earlier up the page.

(Observant readers will note there’s a fair amount of conceptual and actual duplication between apache.py and index.cgi. This is a known bug and things are converging towards fixes.)

Go back to the instance directory and edit tiddlywebconfig.py to comment out server_prefix. Then visit the web, this time without index.cgi: http://aleph.example.com/ should give links to recipes and bags. Click around and you’ll eventually be in a TiddlyWiki.

Down the Road

Eventually all this can probably be compressed into two steps, something similar to the following. Still waiting on additional experimental results.

$ wget http://tiddlyweb.example.com/quick_install.sh
$ sh install.sh domain.example.com

And once we get to that point, it’s reasonable to start thinking about things like:

$ scp tiddlyweb-installer.cgi my.host.example.com:public_html
$ open http://my.host.example.com/tiddlyweb-installer.cgi

It was a bit of a silly night, so somewhere in there this video was created:

Comments (View)
Nov
24th
Tue
permalink

Templates For TiddlyWeb

There are a few ways to do server side template handling with TiddlyWeb. In one system TiddlyWiki style syntax is used to control output. That system is under development, based on the existing system TiddlyWebPages which uses Jinja2 templates that are stored in tiddlers in the TiddlyWeb store. Yet another system just uses Jinja2 directly. It’s that system which I’d like to write about today.

Jinja2 is a nicely straightforward pure Python templating system with optional C-based speedups and a syntax that is very similar to Django without requiring all the rest of Django. I like it because in addition to the standard render method on a template it also has generate which produces a generator. This can lead to some efficiencies with large pages.

Until recently using Jinja templates in TiddlyWeb was somewhat cumbersome: If you had multiple plugins each using templates, there was a fair amount of duplicated code. Now there is a new plugin tidldywebplugins.templates which abstracts that code away using just a single method for finding templates, and provides a system for packaging templates with plugins such that templates can be overridden in TiddlyWeb instances.

Use of tiddlywebplugins.templates is fairly straightforward, here’s an example:

The get_template in line 10 will first look in the directory specified by plugin_local_templates in tiddlywebconfig.py. This defaults to templates, relative to the instance, if not specified. If the template is not found then Jinja will use what is called a PackageLoader to look inside the tiddlywebplugins namespace package, in a templates directory for the template.

This allows templates to be overridden in an instance as required. It also means that plugins that are in the tiddlywebplugins namespace can put templates inside a tiddlywebplugins/templates directory in their own distribution.

The PackageLoader handling depends on a Python package being able inject content (the templates) into a package namespace that was created by a different package. This is tricky, and does not work with Python eggs. You can improve your chances of things working by doing installs with pip instead of easy_install.

get_template can be used anywhere in code that has a WSGI environ available to itself. That means it can be used in handlers (code which responds on a URL route), in serializers, in renderers, in WSGI middleware (such as HTMLPresenter). And if you don’t happen to have an environ handy you can just send an empty dictionary.

So there’s one way to handle templates in TiddlyWeb. In addition to being on PyPI, the code is also on github.

Comments (View)