1 # Copyright 2004 Ed Price.
3 # This file is part of vss2svn2 (see http://vss2svn2.tigris.org/).
5 # vss2svn2 is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # vss2svn2 is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with vss2svn2; if not, write to the Free Software Foundation,
17 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 our $VERSION = '0.5.6';
33 # provides access to real VSS repository.
35 # uses SS.EXE command.
39 # * consider "-S" or "-S-" to enable/disable "smart mode".
40 # * consider "-NL" (long filename mode)
41 # * consider all the crazy "-G" Get (et al) options...
42 # * use "-C@file" for multiline comments.
55 # XXX TODO: add nowarn, nodebug.
56 # XXX mostly duplicated from VssOle.pm.
59 my ($class, %options) = @_;
61 my $vss_dir = File
::Spec
->rel2abs($options{vss_dir
});
62 my $vss_log = File
::Spec
->rel2abs($options{vss_log
});
66 vss_cmd
=> exists $options{vss_cmd
} ?
$options{vss_cmd
} : "ss",
68 vss_user
=> $options{vss_user
},
69 vss_pass
=> exists $options{vss_pass
} ?
$options{vss_pass
} : "",
77 # creates an empty repository.
79 # currently requires VSS admin tools in PATH:
85 # note: if vss_dir (as supplied to VssOle->new) does not exist, it will
86 # be created. if it does exist, it MUST BE EMPTY.
88 # XXX duplicated from VssOle.pm.
92 croak
"repository already open" if defined $self->{vss
};
94 my $vss_cmd = $self->{vss_cmd
};
95 my $vss_dir = $self->{vss_dir
};
96 my $vss_user = $self->{vss_user
};
98 # XXX only "admin" seems to work.
99 $self->WARN ("VSS user besides 'admin' probably wont work")
100 unless lc($vss_user) eq "admin";
102 # XXX dont know how to set password.
103 $self->WARN ("password not supported")
104 if $self->{vss_pass
};
106 my $srcsafe_ini = $vss_dir . "/srcsafe.ini";
107 my $users_txt = $vss_dir . "/users.txt";
108 my $data_dir = $vss_dir . "/data";
109 my $users_dir = $vss_dir . "/users";
110 my $user_dir = $vss_dir . "/users/$vss_user";
111 my $ss_ini = $vss_dir . "/users/$vss_user/ss.ini";
113 # create VSS dir, if necessary
116 mkdir $vss_dir or croak
"error creating VSS dir ($vss_dir): $!";
118 # make sure VSS dir is empty
120 opendir(DH
, $vss_dir) or croak
"error opening VSS dir ($vss_dir): $!";
121 my @files = grep { $_ ne "." and $_ ne ".." } readdir(DH
);
122 croak
"VSS dir ($vss_dir) not empty" if @files;
127 open FH
, ">$srcsafe_ini" or croak
"error opening srcsafe.ini ($srcsafe_ini): $!";
128 print FH
"Data_path = data\n";
129 print FH
"Temp_path = temp\n";
130 print FH
"Users_path = users\n";
131 print FH
"Users_Txt = users.txt";
132 close FH
or warn "error closing srcsafe.ini ($srcsafe_ini): $!";
135 open FH
, ">$users_txt" or croak
"error creating users.txt ($users_txt): $!";
136 print FH
"$vss_user = users\\$vss_user\\ss.ini\n";
137 close FH
or warn "error closing users.txt ($users_txt): $!";
139 # create users dir, and users/<vss_user>
140 mkdir $users_dir or croak
"error creating users dir ($users_dir): $!";
141 mkdir $user_dir or croak
"error creating user dir ($user_dir): $!";
143 # create (empty) "ss.ini" file for vss_user.
144 open FH
, ">$ss_ini" or croak
"error opening user ss.ini ($ss_ini): $!";
145 close FH
or warn "error closing user ss.ini ($ss_ini): $!";
148 mkdir $data_dir or croak
"error creating data dir ($data_dir): $!";
151 # now populate data dir (the fun part).
154 # 1. create empty VSS repository in version 4 format.
156 # "mkss" adds the following files to $data_dir:
158 # * um.dat (user management)
163 $self->_exec ("mkss", $data_dir);
165 # 2. convert to version 5 format.
167 # "ddupd" prints "File um.dat may be corrupt" (why?)
168 # and adds a "loggedin" folder.
170 # XXX that message probably causes non-zero exit status...
171 eval { $self->_exec ("ddupd", $data_dir); } or
172 warn "ignoring DDUPD.EXE non-zero exit status";
174 # 3. convert to version 6 format.
176 # "ddconv" adds all the one-letter folders and some other stuff.
178 $self->_exec ("ddconv", $data_dir);
182 # SS.EXE "subcommand" list (from MSDN):
184 # XXX TODO: which ones do wildcard matching, -R for recursion, etc.
194 # CP 0 (blocks everything)
195 # Create 1 (mkdir, essentially? XXX whats diff b/t project and dir??)
201 # Directory 3 ("ls" basically)
202 # Filetype 3 (gets/sets whether file is Text vs Binary)
214 # Project - (shows "CurrentProject")
226 # WorkFold 0 (blocks everything)
228 # XXX in general maybe better to use hash args, eg:
232 # comment => "blah blah", etc.
238 # CP 0 (blocks everything)
239 # WorkFold 0 (blocks everything)
241 # note: renamed "CP" to "CurrentProject" to prevent confusion wrt
245 my ($self, $proj) = @_;
246 $self->_ss ("CP", $proj);
250 my ($self, $path) = @_;
251 $path = File
::Spec
->rel2abs ($path);
252 $self->_ss ("WorkFold", $path);
261 # Create 1 (mkdir, essentially? XXX whats diff b/t project and dir??)
267 # XXX can this add a dir? or just a file?
269 my ($self, $file) = @_;
270 $self->_ss ("Add", $file);
274 my ($self, $file) = @_;
275 $self->_ss ("Checkin", $file);
279 my ($self, $dir) = @_;
280 $self->_ss ("Create", $dir);
284 my ($self, $file) = @_;
285 $self->_ss ("Delete", $file);
289 my ($self, $file) = @_;
290 return $self->_ss ("Dir", $file);
294 my ($self, $file) = @_;
295 $self->_ss ("Get", $file);
299 my ($self, $src_file, $tgt_dir) = @_;
300 $self->_ss ("Move", $src_file, $tgt_dir);
304 my ($self, $old_file, $new_file) = @_;
305 $self->_ss ("Rename", $old_file, $new_file);
325 # Directory 3 ("ls" basically)
326 # Filetype 3 (gets/sets whether file is Text vs Binary)
346 # Project - (shows "CurrentProject")
359 my ($self, $verb, @args) = @_;
361 $ENV{SSDIR
} = $self->{vss_dir
};
365 push @other, "-I-Y"; # Yes to all prompts; XXX dubious...
366 push @other, "-Y" . $self->{vss_user
} . "," . $self->{vss_pass
};
367 push @other, "-O" . $self->{vss_log
};
368 #push @other, "-W"; # writable working copy; XXX doesnt work with all commands
371 return $self->_exec ($self->{vss_cmd
}, $verb, @args, @other);
376 my ($self, @command) = @_;
378 $self->LOG ("EXEC: @command");
379 my $ans = system (@command);
381 # error-checking based on "perldoc -f system".
382 die "error running '@command': $!" if $ans == -1;
384 die "error ($ans) from '@command'" if $ans != 0;
390 my ($self, $msg) = @_;
391 print "# XXX (ERROR) $msg\n";
395 my ($self, $msg) = @_;
396 print "# XXX (WARNING) $msg\n" unless $self->{nowarn
};
400 my ($self, $msg) = @_;
401 print "# $msg\n" unless $self->{nodebug
};
405 my ($self, $msg) = @_;
410 ###############################################################################
412 ###############################################################################
414 # see ss method for explanation of this
416 GET
=> 'is not an existing filename or project',
417 CREATE
=> 'Cannot change project to',
418 CP
=> 'Cannot change project to',
424 &$code && return $_ for @_;