1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
//////////////////////////////////////////////////////////////////////
rvs 0.6.1
retroactive versioning system
a versioning system that allows you to check
in commit 2 before commit 1
//////////////////////////////////////////////////////////////////////
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
hacking
There are two main parts to rvs, the wrapper, and the core. The
wrapper is a small executable, located in the PATH, and is the one
called when you type `rvs'. The core is a set of many small
executables that do all the real work.
build system
(be sure to read the `configuration' section of `README' first)
The build system rvs uses is rather simple.
`./configure' does two things:
* create a preprocessor (`tmp/var.sed')
* run `Makefile.orig' through the preprocessor to generate a
propper `Makefile'
Then, the Makefile runs each file in `source/' through the
preprocessor, and writes the resulting files to `out/'.
preprocessor
The preprocessor contains all configuration variables. When it
processes a file every instance of `$$VAR_NAME$$' is replaced by
that variable's value. Note that this replacement only happens for
defined variables.
configuration Variables
Again the configuration variables and their default values are:
VER '0.6.1'
SHELL '/usr/bin/env bash'
prefix "$HOME"
bindir 'bin'
libdir '/etc/rvs/'
The wrapper is installed at `$$prefix$$/$$bindir$$/rvs'
The core is installed at `$$libdir$$/'
The source for the wrapper is in `source/rvs'
The source for the core is in `source/rvs-core/'
$$SHELL$$ is the shell all shell scripts that are part of rvs are
run in. As of rvs 0.6.1 all executables are shell scripts.
Most of these can easily be changed _after_ compilation also:
VER line 4 of the wrapper
SHELL line 1 each shell script
prefix simply move the wrapper
bindir simply move the wrapper
libdir move the core, 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.6.2.
After `rvs commit' has done this, it creates a meta-file for that
commit. The meta file contains author, copyright owner, licence
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 propper 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 deliberatly broke this because:
1. incompatible licences 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
$$libdir$$/lib/
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:
$repo
the directory of the database (./.rvs)
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
commiting them. In 0.6.[0-2] 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 in the database? The scheme
is fairly simple. In the `.rvs' directory there are 2 directories,
the `files' directory, and the `tmp' directory. `tmp' is what it
sounds like, a place for rvs compnents to keep temporary files.
The wrapper sets TMPDIR, so you can create a unique file in there
with:
FILENAME=`tempfile`
The `files' directory is where all the data is kept.
When any file is commited, whether it be a regular file, a
directory, a link, or any other type of file, 2 file are created in
`.rvs/files', the "raw-file" and the "meta-file". When we speek of
file IDs, we mean the filename of the corresponding file in
`.rvs/files' in rvs 0.5.8-0.6.2 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.
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!
~ Luke Shumaker <LukeShu@sbcglobal.net>
Happy Hacking!
|