summaryrefslogtreecommitdiff
path: root/HACKING
diff options
context:
space:
mode:
Diffstat (limited to 'HACKING')
-rw-r--r--HACKING295
1 files changed, 295 insertions, 0 deletions
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..773d247
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,295 @@
+#!/bin/less
+
+ Version 0.8c re-implements the wrapper in C, to allow better
+ cooperation between plugins via dependencies. This probably makes
+ a lot of this document out-dated, but a lot of it is still good, it
+ describes the workings of the plugins, and the repo structure.
+
+ I know this file is long* and boring. I try to keep it preened and
+ informative, but would rather spend my time actually hacking. If
+ you think you can help this file, have at it! ~ Luke Shumaker
+
+ * at 200+ lines, it's longer than any rvs source file
+
+- - -cut-here- - 8< - - - - - - - - - - - - - - - - - - - - - - - - -
+//////////////////////////////////////////////////////////////////////
+ rvs 0.7.0
+ retroactive versioning system
+ a versioning system that allows you to check
+ in commit 2 before commit 1
+//////////////////////////////////////////////////////////////////////
+
+ hacking
+
+ build basics
+
+ One of the coolest things about rvs (IMO) is how modular and
+ customizable it is. If you wish to create a fork of rvs, it would
+ be a good idea to give it a different name. This can be done
+ without even changing a single source file! Simply run configure
+ with `--name=NAME' option (variables that have `rvs' in the name
+ will not be renamed, but the user will never know this unless they
+ peek at the code).
+
+ Other options to configure and their default values are:
+
+ name='rvs'
+ The name of the program. Note that unlike most
+ variables, you should NOT call this in Makefiles
+ (`$(name)'), but use `$(rvs)' instead.
+ RVS='$(bindir)/$(rvs)'
+ Where the executable will be. `$(rvs)' is the same as
+ `$(name)' (see above). In this document it is
+ sometimes referred to as the `wrapper'.
+ SHELL='/bin/sh'
+ The shell that will be used by make, and the shell
+ that scripts will run in. (Perhaps we should make
+ these separate variables?)
+ prefix='/usr/local'
+ Standard GNU variable. Many of you will want to
+ change this to `/usr', or `/home/USER_NAME'
+ exec_prefix='$(prefix)'
+ Standard GNU variable.
+ bindir='$(exec_prefix)/bin'
+ Standard GNU variable.
+ sbindir='$(exec_prefix)/sbin'
+ Standard GNU variable.
+ libexecdir='$(exec_prefix)/libexec'
+ Standard GNU variable. The plugins will be installed
+ at $(libexecdir)/$(name)
+ srcdir=$(readlink -f `dirname "$0"`)
+ Where the source code is. The default value evaluates
+ to the directory of the `configure' script.
+
+ These can either be changed by manually changing `configure' or by
+ running it like:
+ ./configure --VAR_NAME=VALUE
+
+ In this document, the `$(VAR_NAME)' refers to whatever you set the
+ value to.
+
+ The configure script will run on any instance of `Makefile.in' in
+ $(srcdir).
+
+ Currently, rvs is distributed with 2 plugins. `repo'[sitory] is
+ the core of the rvs file database. `users' handles all usernames,
+ settings, and other info.
+
+ commands
+
+ By itself, rvs does almost nothing. All real functionality is
+ provided by plugins. When you invoke rvs, you do so in the format
+ `rvs COMMAND'. Plugins work by adding new commands.
+
+ Most commands are provided by plugins, however, a few are built in:
+ init
+ Initializes a repository in the current directory. It creates
+ `./.$(name)', and runs any initalizers for
+ plugins.
+ install PLUGIN DIR
+ Installs PLUGIN, for which the files are found in DIR. Unless
+ an older version is already installed, it adds the plugin to
+ have lowest priority (see `$(libexecdir)/$(rvs)/plugins').
+ uninstall PLUGIN
+ Uninstalls PLUGIN. Did that really need to be said?
+
+ A plugin is simply a collection of independent executable files.
+ When rvs is invoked, it looks for the COMMAND in a few places:
+ 1) checks if COMMAND is an built-in command
+ 2) looks at the file `$(libexecdir)/$(rvs)/plugins'. This is a
+ newline-delimited list of plugin names.
+ 3) loops through the directories `$(libexecdir)/$(rvs)/PLUGIN',
+ where PLUGIN is one of the values in
+ `$(libexecdir)/$(rvs)/plugins', in the order they appear in
+ the file.
+ 4) if rvs does not find the command, it reports an error
+
+ If you would like to contribute a plugin, or distribute one with a
+ fork, all you have to do is put it in `$(srcdir)/plugins/NAME'. The
+ main Makefile will recognize any directory in `$(srcdir)/plugins/'
+ as a plugin, and will run `make -C `plugins/NAME/Makefile'. It
+ should create a directory (mine use `plugins/NAME/out') to put ALL,
+ and ONLY the final files to be used by that plugin.
+
+========this is outdated but I don't really want to keep editing it ==
+
+ build system
+
+ The build system rvs uses is rather simple.
+ `./configure' does two things:
+ * create a sed script (`var.sed')
+ * run every instance of `$(srcdir)/Makefile.in' through
+ `var.sed' to generate a proper `Makefile'
+
+ `var.sed' contains all configuration variables. When it processes
+ a file every instance of `@VAR_NAME@' is replaced by that
+ variable's value. This makes `configure' act much like a GNU
+ package `configure'. Note that this replacement only happens for
+ defined variables.
+
+ Most of these can easily be changed _after_ `compilation' also:
+ VER line 4 of the wrapper
+ SHELL line 1 of each shell script
+ prefix simply move the wrapper
+ bindir simply move the wrapper
+ libexecdir move the directory, then update the line
+ `RVSDIR=...' in the wrapper
+
+ I have designed this system to be extremely modular. As you may
+ have figured out, each bit on functionality is in it's own
+ executable, and the file you call when you type `rvs' is just a
+ wrapper for them.
+
+ The wrapper is quite simple in mechanism. It simply checks if
+ `$$libdir$$/COMMAND_NAME' exists, and if so, runs that file.
+
+ The `rvs commit' command is also quite simple in design. It takes a
+ single argument; the file to commit. If no target is specified, it
+ defaults to `./'. It checks which type of file the target is, and
+ runs `rvs commit.FILE_CODE TARGET'. The file codes are as follows:
+
+ block (buffered) special b
+ character (unbuffered) special c
+ directory d
+ named pipe (FIFO) p
+ regular file f
+ symbolic link l
+ socket s
+ door (Solaris only) D
+
+ As you probably noticed (if you've looked at the blueprints or
+ source files), only directories and regular files have been
+ implemented as of rvs 0.7.0.
+
+ After `rvs commit' has done this, it creates a meta-file for that
+ commit. The meta file contains author, copyright owner, license
+ data, file permissions, timestamps, etc. The id of the meta-file is
+ written to stdout, and used to later check out that commit.
+
+ get works in much the same way as commit, only it reads the file
+ type from the meta-file, then runs `rvs get.FILE_CODE COMMIT_ID'.
+
+ If you implement any other file types, save the commit and get
+ functions in the proper locations.
+
+ Any commit function should take a filename as an argument and
+ output the according commit id to stdout. stderr should be used
+ for all messages.
+
+ Any get function should take the commit id as an argument and
+ uses stdout only if verbose, or to report errors.
+
+ To summarize, the modules are separate programs and communicate via
+ pipes, which is generally considered bad-design, and libraries
+ should be used instead. I deliberately broke this because:
+
+ 1. incompatible licenses can be used for different modules
+ 2. modules can be added/removed on the fly
+ 3. one can use any language to write new modules, without
+ having to worry about bindings`$(libexecdir)/$(rvs)
+
+ $$libdir$$/lib/
+
+ THIS WAS WRITTEN FOR rvs 0.6.2
+ THIS PORTION OF THE CODE IS BEING REVISED IN rvs 0.6.3
+
+ I have created two 'libraries' for use by rvs components. They
+ provide several functions that can be accessed by shell script by
+ using the code:
+ source "`rvs -d`/lib/stdio"
+ or
+ source "`rvs -d`/lib/rvsdb"
+ (`rvs -d' returns $$libdir$$)
+ stdio provides several functions for printing messages:
+ verbose MESSAGE
+ print MESSAGE to stdout only if $verbose is set to '-v'
+ out MESSAGE
+ print MESSAGE to stdout if $verbose isn't set to '-q'
+ warn MESSAGE
+ print "rvs: MESSAGE" to stderr
+ error MESSAGE
+ print "rvs: MESSAGE" and a quick message about `rvs --help'
+ (hinting at user error) to stderr, then exit with error
+ fatal MESSAGE
+ For internal error. Print "rvs: MESSAGE" to stderr and exit
+ with error
+ version
+ print the version information and exit with success
+
+ rvsdb provides several functions and variables for dealing with the
+ rvs database:
+ getid FILE
+ returns what the id of a given file would be if it were in
+ the database. This is used to know where to put files when
+ committing them. In 0.5.8-0.6.3 this is just the sha1sum of
+ the file
+ NOTE: the "log*" functions aren't very stable or developed
+ loginit FILE
+ initialize an rvs log at FILE. These logs are used for
+ metafiles, directory listings, and (probably) eventually
+ checkout logs
+ lograw LOG
+ prepare LOG for reading, and write the output to stdout (to
+ pipe into another function). This is mostly for internal
+ use by rvsdb
+ logread LOG VAR
+ read variable VAR from the logfile LOG
+ logwrite LOG VAR VAL
+ set variable VAR to VAL in the logfile LOG
+ logfind LOG VAL
+ return all the names of variables in logfile LOG who have
+ the value VAL
+
+ the database (.rvs/*)
+
+ So, what are all these files doing in this database? The scheme is
+ fairly simple. In the `.rvs' directory there is 1 directory, the
+ `files' directory. There used to be a folder for tmpfiles (0.5.8-
+ 0.6.2), but no more (0.6.3+). If you need a tmpfile, just run:
+ FILENAME=$(mktemp -t)
+ The `files' directory is where all the data is kept.
+
+ When any file is committed, whether it be a regular file, a
+ directory, a link, or any other type of file, 2 files are created
+ in `.rvs/files', the "raw-file" and the "meta-file". When we speak
+ of file IDs, we mean the filename of the corresponding file in
+ `.rvs/files' in rvs 0.5.8-0.6.3 this is just the sha1sum of the
+ file. The meta-file stores everything not part of the file itself;
+ the filename, file-type, author, copyright owner, file permissions,
+ timestamps, etc, and the ID of the corresponding raw-file. In the
+ case of an regular file, the raw-file contains the file itself. For
+ directories, it contains pointers to each file inside the
+ directory.
+
+ $$libdir$$/commit calls $$libdir$$/commit.FILETYPE to generate the
+ raw-file, but generates the meta-file itself (in `.rvs/tmp', then
+ calls commit.f to commit the meta-file). It then returns the ID of
+ the meta-file. Therefore, the user never deals with the IDs of
+ raw-files, and doesn't need to. The metafiles contain pointers to
+ the corresponding raw-files.
+
+ To keep things modular, commit.f is the ONLY thing that should
+ actually put files in `.rvs/files', and get.f the only thing that
+ should get them. Everything else should call them.
+
+ The repo and init are the ONLY things that should have `.rvs'
+ hardcoded into them. If the repository directory is needed, then
+ use `rvs repo'. Again, in the core, these should only be the .f
+ functions, however, it will be useful to plugins.
+
+ Why do we have the `files' directory, why don't we just put
+ everything in `.rvs'? This way:
+ * There is a spot to put user data, when we get around to writing
+ it
+
+ final thoughts
+
+ I have set up bazaar repository at Launchpad:
+ https://launchpad.net/rvs
+ Only until rvs becomes self-hosting.
+
+ If anyone needs any help, let me know, either via email, or via
+ Launchpad, I'll be happy to help/would love to have your help!
+
+~ Luke Shumaker <LukeShu@sbcglobal.net>
+Happy Hacking!