Until now, Unix developers which required access to a SourceSafe repository (formerly Visual SourceSafe) had to use a Windows machine or, in the lucky case that the architecture was standard enough, pay another time. SSU provides access to local and remote SourceSafe repositories through TCP, to any POSIX system (Linux, BSDs, OS X, etc), and for free, alleviating the pain. SSU also improves the SourceSafe interface and tries to work around several design bugs.
SSU is divided into two components: a command-line Unix client and a windows-based server which runs on a machine with repository access. A single windows machine can multiplex any number of repositories and clients.
The Unix client “ss” requires only Perl >= 5.4 and network TCP port 5901 access to the server. The windows server “ssserv” requires Perl >= 5.6, but has only been tested with ActivePerl 5.8 (5.6 experienced stability problems). The server runs as a stand-alone process unless you use some service helpers (configuration as such is not described here). ssserv also requires the SourceSafe command-line client to be installed locally (usually installed automatically with the SourceSafe software).
Only SourceSafe 6.0/2005 has been tested.
Since SSU 0.7 the Digest::MD5 >= 2.11 module is now required (available from CPAN, already installed on most system including ActivePerl).
Stable, but please read Limitations. SSU supports and uniforms a good subset of the SourceSafe features and has proven to be stable when used by a team of 6 developers accessing a single server. SSU has been developed since one year now and employs some regression testing. We’re interested in feedback, we’d be glad to know about any success.
The adoption of Perl was mainly due to its presence in server environments (ss works with Perl 5.4 which is still largely installed), but may eventually be replaced with something more readable in the future.
I’ve often been questioned about this requirement, and why a tool that accesses the repository directly can’t be developed instead: it can’t be done due to the proprietary nature of the repository format.
SourceSafe is a server-less design, there’s no difference between the machine that hosts the repository (the SMB share server) and any other client. For this reason, all clients are in fact servers (or thick clients), sharing the repository across an SMB share. There are no direct communications between clients, the repository is simply locked on access and updated according to a fixed schema.
This design has a number of vital issues:
Because of “1”, most SourceSafe add-ons are sold with the sole purpose of accelerating (or just “allowing”) remote operations. Because of “2” and “3”, all add-ons (no exceptions) require a “server” component, and that component will use a working SourceSafe installation to access the repository. Because of “3”, using the real windows client under emulation (as suggested elsewhere), besides having the same network performance problems as “1”, is extremely risky, and can lead to data corruption in case of emulation glitches, network outages or crashes.
SSU solves these issues by layering a real client with a simple stateful TCP protocol. Since only relevant commands are sent remotely, network performance is really good and matches other systems like cvs-pserver. Since the repository is never exposed directly, repository data is ensured and client stability is no longer relevant. Since SSU provides better serialization and atomicity logic, the SSU server performance is often superior than real SourceSafe performance when multiple clients are involved.
You don’t need to install SSU on the server hosting the files (altough doing so will result in better performance); you can use any windows box with a SourceSafe installation that has access to the repository as outlined below:
Good I/O and network performance:
SourceSafe client <-| +------------+ |-> SSU client SourceSafe client <-| | SHARE | |-> SSU client SourceSafe client <-|-- lan --| SourceSafe |--| network |--|-> SSU client SourceSafe client <-| | SSU server | |-> SSU client SourceSafe client <-| +------------+ |-> SSU client
Poor I/O, good network performance:
+------------+ |-> SourceSafe client | SHARE |-- lan --| +------------+ | +------------+ |-> SSU client |->| SourceSafe | |-> SSU client SourceSafe Client <-| | SSU server |--| network |--|-> SSU client SourceSafe Client <-| +------------+ |-> SSU client
Poor I/O and network performance:
+---------+ |-> SourceSafe client | SHARE |-- lan --| +---------+ | +------------+ |-> SSU client |--| network |--| SourceSafe | |-> SSU client SourceSafe Client <-| | SSU server |-- lan --|-> SSU client SourceSafe Client <-| +------------+ |-> SSU client
Having to use a Windows installation may seem a limiting factor for SSU deployment, but remember that other alternatives have this implicit limitation also. Since SSU ensures better data integrity, better performance, network security and doesn’t have any cost or specific requirements, any serious administrator or project manager interested in your work should consider such a request without too much trouble.
ssserv should be installed on a windows machine with repository access. Multiple repositories can be served from the same server.
First install ActivePerl >= 5.8 and SourceSafe on the machine.
Unpack the source distribution in the target directory (eg: C:\Program Files\SSU).
Create a “ssserv.ini” file in the same directory containing:
HOME=C:\Program Files\SSU\HOME MAP=db C:\\DATA\\SSAFE_DB
Where HOME is the working directory and MAP is an association list of names to database paths (note that backslashes should be escaped, the final one is omitted). C:\\DATA\\SSAFE_DB should be replaced with the directory containing your SourceSafe database. Setting MAP correctly is critical.
Create a “ssserv.bat” file in the same directory containing:
set "PATH=%PATH%;C:\Program Files\Microsoft Visual Studio\Common\VSS\win32" perl ssserv
Setting the PATH is not necessary if the “ss.exe” executable is already visible. You may also need to specify a full path to the Perl executable if you disabled the relative option in the ActivePerl installer.
Execute the file. Logging-out may kill the process depending on your operating system (2000/XP), so proceed accordingly.
Copy “ss” to prefix/bin (where prefix is usually /usr/local), and *.pm files in prefix/lib/ss (/usr/local/lib/ss/Maps.pm etc). “ss” should be executable.
For each user create ~/.ssrc (mode 600), containing:
USER=username PASS=password HOST=hostname HOME=/home/username/projects/ MAP=dirname db/projectname
Where HOME is an absolute path to an existing directory that will contain your SourceSafe projects, and MAP is an association list of directories to databases (see the MAP configuration reference).
In the above example we assume that ss will have control of all the /home/username/projects tree, and the directory /home/username/projects/dirname will actually contain the db/projectname project (where you recall DB was configured server-side as C:\\DATA\\SSAFE_DB, yielding C:\DATA\SSAFE_DB $/projectname in SourceSafe syntax).
Execute ss get to bootstrap your tree.
Developers with experience with Perforce will be delighted to know that MAP works in the same concept as the “View” field. SSU performs a double path translation to give a “network transparent filesystem” independent of the original repository layout. Basically MAP is a list of pairs, each one containing the source path, and the destination path:
MAP performs a path translation by matching a path prefix against “source” and replacing it to “destination”. Consider the following client example:
HOME=/home/user MAP=project db/project
and this sample path:
First, the HOME prefix is removed, giving “project/file.c”; then the first map is matched, replacing “project” with “db/project” and yielding the network path “db/project/file.c”. The path is now translated again in the server, but this time “destination” is used directly as the final repository location:
“db” is replaced with C:\SSAFE_DB, giving C:\SSAFE_DB $/project/file.c.
As a recommendation for the client, you should point HOME to the directory containing your shared projects. Each project should have a MAP entry, consisting of the directory name (that will contain your project) as the left side, and the “repository name/project name” as the right side. On the server simply give repository names and paths. This will give good flexibility and reorganization possibilities on the long term.
Multiple mappings can be specified:
MAP=source destination source destination
MAP=source destination \ source destination
If either source or destination contain a space, you should quote the definition. You should also escape all backslashes (mostly for windows paths), eg:
MAP="a source" desti\\nation
The source path is always relative to the HOME directory. Multiple mappings can be used to uniform the project workspace regardless of the repository status:
MAP=project/dir db/oldproject/dir \ project db/newproject
Unfortunately MAP is not as powerful as Perforce’s. You can have overlapping patterns, but the first one that matches will be used. You can also only map directories, and there’s no wildcards.
Under ssserv (on windows) destination is limited to a fully qualified database path. Yet you can still alter the environment server-side:
MAP=db/old C:\\DB1\\SSAFE_DB \ db C:\\DB2\\SSAFE_DB \ db2 C:\\DB3\\SSAFE_DB
Upon correct configuration, each client can extract a read-only copy of the required files by using the ss get command:
$ ss get dir U dir/test.txt
Without arguments, get updates all the mappings you have configured. ss get is also used to update the source tree with the latest version available in the repository. ss get will never modify writable files (unlike cvs, merge is never attempted for now).
To modify a file you use the checkout command:
$ ss checkout dir/test.txt
ss checkout will update the specified file/files to the latest revision, make them writable and lock the repository. Under SourceSafe only a single user at a time can have a file checked-out/locked. The “multiple-checkouts” option in SourceSafe is avoided at all costs, and isn’t used by SSU (See Future developments).
When done with editing, you can checkin the file:
$ ss checkin dir/test.txt
ss does a great job in uniforming SourceSafe interaction, but still it’s limited (due to SourceSafe limitations or development status) in some ways:
The big mayor step in the SSU 1 development should be a new (and possibly better) cooperation model for SourceSafe that removes the current “multiple checkout” limitation. Read HACKING for more details.
Note that SSU is not meant to be a fully fledged revision control system for Unix, just an aid where SourceSafe access is required. Consider switching to a better revision control system instead.
You can layer your connections through SSL, for example using OpenSSH:
$ ssh -N proxy -L 5901:server:5901
and modify ~/.ssrc to connect to localhost instead of connecting to the server directly. By using the ssh’s -C flag you can also get compression for free.
Again, note that this gives you a secure transport (for example for working off-site), not a secure server.
Some commands permit to work on older versions of files, by using either a revision number, a label or a date. The revision/label/date is simply appended to the local file name, using the appropriate symbol, forming the revision syntax:
ss cat file@milestone
prints on the standard-output the contents of file labeled at “milestone”, while:
ss label -ltest file#1
labels file at revision 1 as “test”.
A file without revision syntax, or with the special “#head” spec, always refers to the latest available revision.
Although aimed at regression testing, you can use the “check” script shipped within the distribution to perform some very basic tests on the “ss” interface.
“ss” should be installed and configured to access a virgin repository. The first argument of “check” should be a mapped inexistent directory.
Some aliases are provided for users coming from different revision systems:
These are just mere aliases however: flags/syntax doesn’t change.
get/checkin/checkout use one-letter messages to inform you about state changes of your tree when operating:
|?:||File skipped (no remote file).|
|O:||File opened locally/no remote changes.|
|0:||Command completed successfully. Only in diff/diff2: no differences.|
|1:||Only in diff/diff2: some differences.|
|2:||Error or incomplete execution.|
SSU is located at https://www.thregr.org/~wavexx/software/ssu/ and distributed under the terms of the GNU LGPL license without any warranty. SSU is copyright(c) 2005-2007 of Yuri D’Elia <email@example.com>.
If you’re used to CVS, SubVersion or other serious revision control systems and started to work with SSU recently, here’s some useful tips to circumvent SourceSafe limitations (and more):
When doing the same operations on several files (like get), recursive modes are generally faster on slow links: for example it’s faster to do ss get . than ss get *.
A file revision cannot be labeled twice in SourceSafe; SSU inherits the same limitation and prevents you from removing the old label. However SourceSafe permits to label directories, directories have a version number assigned at each file change and child entries inherits the label. Thus always label directories when possible.
Deleting the same file/project twice in SourceSafe irreversibly destroys history. For this reason “ssserv” intentionally avoids destructive operations: “projects” are never really deleted and “add” tries to recover files instead of creating new ones. As a result (by default) SSU users cannot perform destructive operations. However as empty repository directories are not shown nor deleted, adding a file over an empty directory with the same name will trigger a “file already exists” error to user’s surprise.
To revert a file to an old version first checkout the file, retrieve the old version into the new one, and then checkin again:
ss co file ss cat file#oldversion > file ss ci -c 'reverting new changes' file
To move a file across directories simply copy/add/remove it. There’s really no better way. SourceSafe somewhat supports renaming a file and/or moving a directory into another, but there’s no track of the change and the operation could result in another history loss.
A file was just deleted from the repository, you wanted to know why but now “history” tells nothing more than what you already know. Check the history of the parent directory for some more clue.
When importing for the first time many new source files into the repository, you can consider switching off “AUTOREC” for greater performance.
Subscribe to ssu-users by either sending an empty email to <firstname.lastname@example.org>, using GMane (group “gmane.comp.version-control.ssu.user”) or by contacting the author at <email@example.com>. The list is about discussing bugs, usage issues and release announcements. The archives are accessible via web through http://news.gmane.org/gmane.comp.version-control.ssu.user or via news directly.