Updating documentation

This commit is contained in:
Alex Yatskov 2015-04-06 12:55:03 +09:00
parent a1f10ebfb0
commit ef5f8cba8d
3 changed files with 270 additions and 1 deletions

19
LICENSE.txt Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2015 Alex Yatskov <alex@foosoft.net>
Author: Alex Yatskov <alex@foosoft.net>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

249
README.md Normal file
View File

@ -0,0 +1,249 @@
# Homemaker #
Homemaker is a tool for straightforward and efficient management of *nix configuration files found in the user's home
directory, commonly known as [dot-files](https://en.wikipedia.org/wiki/Dot-file). It is written in
[Golang](https://golang.org/), requires no installation, has no dependencies and makes use of simple configuration file
format inspired by [make](https://en.wikipedia.org/wiki/Make_%28software%29) to generate symlinks and execute system
commands to aid in configuring a new system for use.
## Motivation ##
Ever since switching to using Linux as my daily driver operating system, I have been searching for a way to effectively
manage settings between different computers (and system reinstalls on the same machine) while avoiding the accumulation
of cruft that plagues our home directories.
Specifically, I required a solution that had the following characteristics:
* **Do not require software installation**
The user may not have root privileges on all the computers that she accesses, making it difficult to make use
software that has additional dependencies. Even if the user has root on the machine in question, it is sub-optimal
to require her to install software packages just to bootstrap the system.
* **Support configuration variants**
The user should be able to use cherry-pick which settings they wish to use. Different system installs have different
configuration requirements; it must be possible to share common settings while keeping the unique bits unique to
each machine. Furthermore, it should be possible to store all configuration settings in one location.
* **Make no assumptions about synchronization**
While Git often works well for managing dot-files, it is not ideal for every situation. I've seen some applications
add and remove seemingly randomly-named files within their configuration directories, while others store their
settings in large, opaque binary blobs. Managing configuration settings for such poorly-behaved applications may be
easier through, [Dropbox](https://www.dropbox.com/), [rsync](https://en.wikipedia.org/wiki/Rsync), or some other
utility outside of version control.
* **Be easy to read and modify the source**
As a programmer, I always consider the underlying technology of a tool when deciding whether or not to use it. The
user should feel empowered to change and test the application without having to deal with the archaic incantations
otherwise known as shell scripts. Scripting languages can work well but are closely tied to the environment in which
they are executed.
It became apparent to me that utility which I was looking for did not exist. After making due with a simple Python
script that I hacked together, I decided that this problem deserved a clean, formal solution. I decided to create this
new utility in Go; in addition to the language itself being clear and easy to understand, executables built with the Go
compiler are statically linked, making them highly portable. The result of my work is Homemaker; I hope that you find it
suitable for your needs.
## Installation ##
If you already have the Go environment and toolchain set up, you can get the latest version by running:
```
go get github.com/FooSoft/homemaker
```
Otherwise, you can use the pre-built binaries for the architectures below:
* [amd64](http://foosoft.net/dl/homemaker/homemaker_amd64.tar.gz)
* 386 (build not available yet)
## Configuration ##
Configuration files for Homemaker can be authored in your choice of [TOML](https://github.com/toml-lang/toml),
[YAML](http://yaml.org/) or [JSON](http://json.org/) markup languages. Being the easiest to read out of the three, TOML
will be used for the example configuration files. Worry not if you are unfamiliar with this format; everything you need
to know about it will be shown below.
Let's start by looking at a basic example configuration file, `example.toml`. Notice that Homemaker determines which
markdown language processor to use based on the extension of your configuration file. Use `.toml` for TOML, `.yaml` for
YAML, and `.json` for JSON. Having a wrong file extension will prevent your configuration file from being parsed
correctly.
```
[tasks.default]
links = [
[".config/fish"],
[".config/keepassx"],
[".config/terminal"],
[".config/vlc"],
[".gitconfig"],
[".xinputrc"],
]
```
We could have just as easily written this configuration in JSON (or YAML for that matter), but it's subjectively uglier:
```
{
"tasks": {
"default": {
"links": [
[".config/fish"],
[".config/keepassx"],
[".config/terminal"],
[".config/vlc"],
[".gitconfig"],
[".xinputrc"]
]
}
}
}
```
To create symlinks based on this configuration we invoke the `homemaker` utility:
```
homemaker example.json /mnt/data/config
```
To get a better idea of what `/mnt/data/config` is, let's look at the in-program documentation:
```
Usage: homemaker [options] conf [src]
Parameters:
-clobber=false: delete files and directories at target
-dest="/home/alex": target directory for tasks
-force=true: create parent directories to target
-task="default": name of task to execute
-verbose=false: verbose output
```
For the purpose of our illustration, `src` is defined on the command line to be `/mnt/data/config`; namely the source
directory where your dot-files live (this will be your Git repository, Dropbox folder, rsync root, etc.). The symlinks
that Homemaker creates will point to the configuration files in this directory. You may have noticed that you can also
provide a destination directory via the `-dest` command line argument; this is where the symlinks should be created (and
it defaults to your home directory).
Another useful parameter is `task`; it will be initialized to the value `default` unless you override it on the command
line. In practice, this means that Homemaker will try to find a task called `default` and execute it. You can create as
many unique tasks as necessary to correspond to your configuration requirements, and then choose which one will execute
by specifying it on the command line in the format `-task=taskname`. Good candidates for tasks are computer names, as
shown in the configuration file below:
```
[tasks.flatline]
links = [
[".config/syncthing", ".config/syncthing_flatline"],
[".s3cfg"],
[".sabnzbd"],
[".ssh", ".ssh_flatline"],
]
[tasks.wintermute]
links = [
[".config/syncthing", ".config/syncthing_wintermute"],
[".ssh", ".ssh_wintermute"],
]
```
Here we see two tasks, named after the computers that will be using them, `flatline` and `wintermute`. Certain
configuration data like key pairs and other per-machine settings should only be linked on the computer that is using
them. That is to say if `flatline` and `wintermute` both try to manage the `.ssh` directory, a conflict will occur at
both the source and destination directories. We can easily resolve the source directory conflict by giving the `.ssh`
directories unique names, such as `.ssh_flatline` and `.ssh_wintermute`. The conflict at the destination directory can
be fixed as shown above; we will create per-machine tasks that will symlink only the needed directory.
You may have noticed that each entry in the `links` collection is an array, which up until now has contained only one
item. A second item can be added if the source file or directory name is different from that in the destination. If the
paths provided are relative they will be assumed to be relative to the destination and source directories respectively.
Now that we have machine specific tasks defined in our configuration file, it would be nice to still be able to share
configuration settings that are common to the two computers. We can do this by adding a `dep` array to our tasks as
shown below:
```
[tasks.common]
links = [
[".config/fish"],
[".config/keepassx"],
[".config/terminal"],
[".config/vlc"],
[".gitconfig"],
[".xinputrc"],
]
[tasks.flatline]
deps = ["common"]
links = [
[".config/syncthing", ".config/syncthing_flatline"],
[".s3cfg"],
[".sabnzbd"],
[".ssh", ".ssh_flatline"],
]
[tasks.wintermute]
deps = ["common"]
links = [
[".config/syncthing", ".config/syncthing_wintermute"],
[".ssh", ".ssh_wintermute"],
]
```
Homemaker will process the dependency tasks before processing the task itself.
In addition to creating links, Homemaker is capable of executing commands on a per-task basis. Commands should be
defined in an array called `cmds`, split into an item per each command line argument. All of the commands are executed
with `dest` as the working directory (as mentioned previously, this defaults to your home directory). If any command
returns a nonzero exit code, Homemaker will display an error message and stop.
The example task below will clone and install configuration files for [Vim](http://www.vim.org/) into the `.config`
directory, and create links to it from the home directory.
```
[tasks.vim]
cmds = [
["rm", "-rf", ".config/vim"],
["git", "clone", "https://github.com/FooSoft/dotvim", ".config/vim"],
["ln", "-sf", ".config/vim/.vimrc"],
["ln", "-sf", ".config/vim/.vim"],
]
```
## Parameters ##
Executing Homemaker with the `-help` command line argument will trigger online help to be displayed. The list below
provides a more detailed description of what the parameters do.
* `clobber`
By default, Homemaker will only remove identically-named symlinks at the destination directory. Using this parameter
will cause Homemaker to be more aggressive and delete clashing files and entire directories as well. This can be
useful for getting rid of the default configuration settings some applications write when you run them for the first
time, but should obviously be used with caution.
* `dest`
This parameter specifies destination where Homemaker is to create symlinks. This will default to the home directory
for the current user, and as long as you are just using this application to manage dot-files, will probably never
need to be changed.
* `force`
Sometimes dot-files for an application are nested within parent directories that must exist in order to allow the
symlink to be successfully created (for example the `.config` directory in `.config/vlc`). As this is the expected
behavior, this parameter defaults to `true`; however you can explicitly disable it if required.
* `task`
This parameter is used to specify which task Homemaker will process when executed. It defaults to the `default`
task, which should be used when creating a configuration file that does not have system-specific tasks specified.
* `verbose`
When something isn't going the way you expect, you can use this parameter to make Homemaker to log everything it is
doing to console.

View File

@ -70,7 +70,8 @@ func parse(filename string) (*config, error) {
} }
func usage() { func usage() {
fmt.Printf("Usage: %s [options] conf [src]\n\n", os.Args[0]) fmt.Printf("Usage: %s [options] conf [src]\n", os.Args[0])
fmt.Print("http://foosoft.net/projects/homemaker/\n\n")
fmt.Print("Parameters:\n") fmt.Print("Parameters:\n")
flag.PrintDefaults() flag.PrintDefaults()
} }