aio does the following:
aio is not doing anything of the following things:
Basically aio is a program runner, which cares for dependency resolution.
Binding a C++ library like Urho3D to a different programming language involves the interplay of different binary components. First, you need to compile the base library, in this case Urho3D. In addition you need to compile the binding code - which is usually also written in C++ - and link it to the library. Then you need to compile the target program in Haskell and make the Haskell compiler to successfully link the binding layer. All this is only working if you care about library settings, compiler versions and other configuration topics and this for 3 different target platforms. It can be done and it is not totally sophisticated, but it turned out, it is nothing which is easily done by the starting hobby programmer.
Therefore I’ve chosen a different approach. As a first important step, I broke the strict dependency of the Haskell program from the binding library by loading the library dynamically with dlopen. Then I provide the correct pre-compiled binaries for the C++ libraries and the binding code for all three target platforms as downloads. Finally I added a small utility which downloads the correct versions of all components together and which starts them correctly by making each component aware of the location of the others.
You might recognize in the last step the aio tool. By the way this has been heavily inspired by 0install. You can think of aio being a simpler version of 0install with some additions for the specific purpose used here. aio is written in go and you can check the source here github repository
Fire up arriccio without parameter and you will get a short helping introduction. If you look closer at the arriccio commands you’ll see that most of them take the url or a name - an alias - as parameter. The primary key for distinguishing components is the url. Since url’s tend to be long and difficult to remember, you can attach an alias for day to day use with arriccio. During the initial setup, some shortcuts have been set already, so if you start aio list alias
you will get a list of already ‘pre-defined’ components.
HGamer3D - http://www.hgamer3d.org/tools/HGamer3D.0218
3DEdit - http://www.hgamer3d.org/tools/Urho3DEditor-1.6
AssetImporter - http://www.hgamer3d.org/tools/AssetImporter-1.6
Edit - http://www.hgamer3d.org/tools/Edit.0917
Let’s try now one of those components in isolation for purpose of getting more used to arriccio. Simply issue the following command in a shell:
aio 3DEdit
What happens? The first time you try to run a component with arriccio it needs to download the component to your machine. So the tool comes back with a question and asks, if you are ok with that. Have a closer look, it gives you a tar.gz filename it is going to download and a signing key. This signing key identifies the person who created the downloaded data, which in this case is me, I signed the components from HGamer3D with my key. Arriccio will check if the data has not being messed up somehow by verifying the signature.
If you answer with “yes” a download will appear, and after that the 3DEditor is displayed (taken from the Urho3D project).
Try some other commands of arriccio, for example the license command which gives you licensing information on the component you name.
Note
There are actually two versions of commands for running components:
aio <component url> <parameters>
aio start <component url> <parameters>
The first one starts the component with parameters in the same console with console output. The second version starts a detached program, which does not show console output.
In HGamer3D different components are implemented for
Urho3D-1.6
)HG3DEngineGio.0517
)Intonaco.0517
)Run.0517
)MediaPack1.0617
)To separate specifically the Haskell binary from the underlying C++ technologies, this binary loads libraries dynamicall with dlopen
. The information, where to find the needed libraries is provided by mechanisms implemented in the arriccio tool. This has the advantage that the Haskell programs itself do not depend on statically linked C, C++ libraries, there is no library mentioned in the cabal file, which increases the maintainability of the overall solution.
If you are going to stick components together to one working program, you need a kind of resolver, which looks up the current environemnt where those components need to run, gather the fitting pieces together, make them aware of each other and start them. Those steps are performed by arriccio. The entry point to understand how it works is the meta-information, placed at the component url, the most important parameter to any arricio command.
The Component Url
Components are uniquely identified by their component url. For example the Run.0517
component of HGamer3D is identified by http://www.hgamer3d.org/tools/Run.0517
. This url is used in all places where a reference to this component needs to be made. As a component provides one unique piece of functionality, the name reflects the action or content of the specific component. In the case of the Run.0517
component it is obious that this component enables to run HGamer3D programs. The aio program can be used to start those component, the command:
aio http://www.hgamer3d.org/tools/Run.0517 ./game
starts the Run.0517
component and invokes the program ./game
to execute it. The reason why a component is started, to start another program is simple, it prepares the environment in a way, that ./game
is able to find its dependencies, namely all the media files and the HGamer3D runtime libraries.
The arriccio.toml file
If you open one of the component url’s in your browser you will see, that there is specific information contained in the file, which is opened. This file is called the arriccio.toml
file and the format of it is toml a kind of dialect of yaml. So behind each component url an arriccio.toml file is waiting with meta-information, describing the component. This information is read by the arriccio tool and gives all needed information to execute the component and to resolve any additional dependencies. To give you a deeper understanding of arriccio, we will go through the structure of this file below.
Let’s have a look at the first lines of the HG3DEngineGio.0517
component arriccio.toml file:
id-url = "http://www.hgamer3d.org/component/HG3DEngineGio.0517"
description = "HGamer3D fresco component which delivers the C++ binding towards the Urho3D engine."
license-short = "Apache 2.0 License"
signing-key = "https://www.github.com/urs-of-the-backwoods.keys"
Pretty self-explanatory, is it? The header of the component metadata gives information about the id, the license and the purpose of the component. It also contains a signing-key url. This url contains the public key of a cryptographic key pair and is used by arriccio to verify that the component is originating from the author who owns the corresponding private key. In this case it says that the github user urs-of-the-backwoods signed the arriccio.toml file with his private key. Arriccio checks this before doing anyhting with the component.
Now let’s have a look at the further details of the arriccio.toml
file.
[[implementation]]
architecture = "amd64"
operating-system = "windows"
archive-download-location = "http://www.hgamer3d.org/downloads/gamegio-amd64-windows-2.0.0.tar.gz"
[[implementation.dependency]]
id-url = "http://www.hgamer3d.org/tools/Urho3D-1.6"
environment-settings = ["add-path PATH ./bin"]
[[implementation]]
architecture = "amd64"
operating-system = "linux"
archive-download-location = "http://www.hgamer3d.org/downloads/gamegio-amd64-linux-2.0.0.tar.gz"
[[implementation.dependency]]
id-url = "http://www.hgamer3d.org/tools/Urho3D-1.6"
environment-settings = ["add-path LD_LIBRARY_PATH ./bin"]
[[implementation]]
architecture = "amd64"
operating-system = "darwin"
archive-download-location = "http://www.hgamer3d.org/downloads/gamegio-amd64-darwin-2.0.0.tar.gz"
[[implementation.dependency]]
id-url = "http://www.hgamer3d.org/tools/Urho3D-1.6"
environment-settings = ["add-path LD_LIBRARY_PATH ./bin"]
This now is much more interesting. You need to get a little knowledge on toml, before going ahead. The double square brackets indicate arrays with an array entry below it. It is also important to understand that although all blocks have the same indentation the top lines implementation
and implementation.dependency
indicate that the dependencies are actually part of the implementation, so you need to read this as if the dependencies are one level below the implementations.
So what does it mean? Each implementation
section describes one specific implementation of the component. So in this case, the first lines contain the specification for an implmentation, which runs on machines with Linux as its OS and an amd64 cpu architecture (essentially 64 bit). Finally there is a location indication and a signing-key again which gives the data of the implementation. This data is downloaded by arriccio and cached on the local system so it can be used by other components or directly by arriccio if this component is started.
Below the implementation you will find its dependencies. And this is the most important part in this file. Each specific implementation may depend on other components. Those dependencies are specified by the id of the component, which is needed, its version region and a field called Environment
. The dependencies of the HG3DEngineGio.0517
component is only one component, the Urho3D-1.6
component.
The environment field gives information which is used by arriccio to interconnect the dependencies with the components. Since components have no knowledge about each other, we need to tell the HG3DEngineGio.0517
component about the existence and location of the Urho3D-1.6
component. This is done at runtime by the arriccio tool. This tool populates the environment with entries giving information about the location of the dependencies. In the case of the Urho3D-1.6
dependency, arriccio modifies an environment variable called LD_LIBRARY_PATH
and adds to it the location where arriccio downloaded the Urho3D-1.6
component. Upon start, the HG3DEngineGio.0517
component is reading this environment variable and therefore is able to locate the Urho3D-1.6
component. This is a mechanism called dependency injection and it decouples components from each other.
And what is this specific component about? The HG3DEngineGio.0517
component is the C++ binding library, which abstracts functionality from the Urho3D ++ game engine to be used later by the Haskell binding. It is a dynamic library and it uses the Urho3D engine. The latter is actually contained in the Urho3D-1.6
component, so it is clear that the binding library needs the Urho3D engine as a pre-requisite. Arriccio also makes sure, that only the correct versions are interconnected and the fields operating-system
and architecture
make sure, that only components which can be run by the underlying hardware are chosen. As you can see, this also enables one component arriccio.toml
file to specify all implementations for all supported platforms, so there is really just one arriccio.toml
file for one component and it contains all information for all implementations. If you look into the http://www.hgamer3d.org/component/HG3DEngineGio.0517
component, you will see that there are additional entries for the Windows and OS X platforms.
Internal Cache
Arriccio keeps its data in ~/.aio
. In this folder there is a database of local alias and directory definitions. In addition there are two subfolders, cache
and impl
. The cache
folder contains caches of the component arriccio.toml files. Therefore all programs work without internet connection, once a set of component arriccio.toml files have been cached. The impl
folder contains the data of the implementations. Names in those folders are according to the hash values of the component urls for the component meta-data and of the file urls for the implementation data. You can do a find
on the ~/.aio folder and see, how the structure looks like after downloading for example the Run
component.
An update to the cache is not initiated automatically, instead aio runs without internet connection happily, once the dependencies have been downloaded the first time. Therefore to get updates, you need to issue the aio update
command with the respective component url as parameter to force it. There is a philosophy of versioning underneath all that, which will be explained in a future chapter.
Note
Arriccio is not well behaving currently, if there is not enough space in ~/.aio
. So please make sure you have enough free space available.
Signatures
Arriccio uses ssh keys and hashing, to generate a signature for component url files and the implementation files. You can sign files with your private key yourself, by using the following command:
aio sign <file> ~/.ssh/id_rsa
The resulting signature file needs to be placed at the same location as the file itself. You can check a signature with the aio verify
command. If you place the public key somewhere in the internet everybody can check if the file has been signed by yourself. Arriccio does those checks automatically by comparing if the meta-data files and the implementation content files have a signature file at the same url (with appended .sig
extension) which matches the data and the public key, given in the arriccio.toml file.
Versioning
to be done
Execution and Commands
to be done
Environment Parameters
to be done
You can use arriccio, to build your own components. What you need to do is roughly the following steps:
aio sign
command.arriccio.toml
file, place it on a web-server.And that is it, you now can use arriccio, to start your own programs.
This works also in case you need additional media files for a program you wrote with HGamer3D. You also can distribute the games itself this way. Have a look at the existing components, to see how there arriccio.toml
files are structured.
If you start arriccio without any parameter, you will get the following help text:
aio (arriccio, all in one) command:
aio alias <name> <url> - gives an alias to a target url
aio list alias - list given alias
aio remove-alias <name> <url> - removes an alias
aio local <url> <local-dir> - caches a local implementation dir for a target url
aio list local - list given local dirs
aio remove-local <url> - removes a local implementation dir
aio sign <file> <private key> - create signature for file with private key
aio verify <file> <public key> - verify if signature is correct
aio deps <name> | <url> - prints dependencies
aio unsafe <name> | <url> [args] - process a target url without asking for confirmation
aio version - displays version information
aio info <name> | <url> - prints information about a component
aio license <name> | <url> - prints detailed license information about a component
aio update <name> | <url> [args] - updates a target component - re-read url from internet
aio start <name> | <url> [args] - executes a target component - no console
aio <name> | <url> [args] - executes a target component - with console i/o