1
1

338 строки
6.4 KiB
Plaintext
Исполняемый файл

#!/usr/bin/env slsh
% This is a simple shell that allows one to interact with an SVN repository
% in a shell-like manner.
%
% The location of the repository may be specified either on the
% command line or via the SVN_REPOS environment variable, e.g.,
%
% svnsh $HOME/var/svn/repos
%
% Use it at your own risk!
%
private variable SVNSH_VERSION = "0.1.0-1";
private variable Repository;
private variable Repository_CWD;
private variable Echo_Commands = 0;
private variable Rline;
new_exception ("SVNError", AnyError, "svn error");
private define expand_path (path)
{
variable dir = Repository_CWD;
if (path[0] == '/')
dir = Repository;
foreach (strtok (path, "/"))
{
variable sdir = ();
if (sdir == "..")
{
if (dir == Repository)
{
vmessage ("Can't go up");
return NULL;
}
dir = path_dirname (dir);
continue;
}
if (sdir == ".")
continue;
dir = strcat (dir, "/", sdir);
}
return dir;
}
private define _svn_execute ()
{
variable args = __pop_args (_NARGS);
variable cmd = "svn " + sprintf (__push_args(args));
if (Echo_Commands)
() = fprintf (stdout, "%s\n", cmd);
variable status = system (cmd);
if (status != 0)
throw SVNError, sprintf ("%s returned %d", cmd, status);
}
private define _svn_path_exists (path)
{
if (path == NULL)
return 0;
try
{
_svn_execute ("ls %s >/dev/null 2>&1", path);
}
catch SVNError: return 0;
return 1;
}
private define _svn_cd (argv)
{
variable dir = expand_path (argv[0]);
if (0 == _svn_path_exists (dir))
{
vmessage ("%s does not exist", dir);
return;
}
Repository_CWD = dir;
}
private define get_opts (argv)
{
variable i;
variable opts = "";
variable args = String_Type[0];
variable n = length (argv);
i = 0;
while (i < n)
{
variable arg = argv[i];
if (arg[0] == '-')
{
if (arg == "-nc")
{
arg = "-m \"\"";
}
opts = strcat (opts, " ", arg);
i++;
continue;
}
args = argv[[i:]];
break;
}
return opts, args;
}
private define _svn_cp (argv)
{
variable opts, files;
(opts, files) = get_opts (argv);
if (length (files) != 2)
{
() = fprintf (stderr, "Usage: cp dir dir\n");
return;
}
variable from = expand_path (files[0]);
variable to = expand_path (files[1]);
if ((from == NULL) or (to == NULL))
return;
_svn_execute ("cp %s %s %s", opts, from, to);
}
private define _svn_ls (argv)
{
variable opts, files;
(opts, files) = get_opts (argv);
if (opts == "-l")
opts = "-v";
if (length (files) == 0)
{
_svn_execute ("ls %s %s", opts, Repository_CWD);
return;
}
foreach (files)
{
variable file = ();
file = expand_path (file);
if (file == NULL)
continue;
_svn_execute ("ls %s %s", opts, file);
}
}
private define _svn_mv (argv)
{
variable opts, files;
(opts, files) = get_opts (argv);
if (length (files) != 2)
{
() = fprintf (stderr, "Usage: mv FROM TO\n");
return;
}
variable from = expand_path (files[0]);
variable to = expand_path (files[1]);
if ((from == NULL) or (to == NULL))
{
() = fprintf (stderr, "*** mv failed\n");
return;
}
_svn_execute ("mv %s %s %s", opts, from, to);
}
private define _svn_mkdir (argv)
{
variable opts, files;
(opts, files) = get_opts (argv);
if (length (files) != 1)
{
() = fprintf (stderr, "Usage: mkdir DIR\n");
return;
}
variable dir = expand_path (files[0]);
if (dir == NULL)
return;
_svn_execute ("mkdir %s %s", opts, dir);
}
private define _svn_rm (argv)
{
variable opts, files;
(opts, files) = get_opts (argv);
if (length (files) != 1)
{
() = fprintf (stderr, "Usage: rm file\n");
return;
}
variable dir = expand_path (files[0]);
if (dir == NULL)
return;
_svn_execute ("rm %s %s", opts, dir);
}
private define _svn_most (argv)
{
if (length (argv) != 1)
{
() = fprintf (stderr, "Usage: most FILE\n");
return;
}
variable file = expand_path (argv[0]);
if (file == NULL)
return;
_svn_execute ("cat %s | most", file);
}
private define _svn_help (argv)
{
_svn_execute ("help %s", strjoin (argv, " "));
() = fprintf (stdout, "\nAlso use ? for a list of interractive commands\n");
}
private define _svn_quit (argv)
{
Rline = NULL;
exit (0);
}
private variable Cmd_Table = Assoc_Type [Ref_Type];
private define _svn_local_help (argv)
{
() = fprintf (stdout, "Local commands:\n");
foreach (assoc_get_keys (Cmd_Table))
{
variable key = ();
() = fprintf (stdout, "%s\n", key);
}
}
Cmd_Table["ls"] = &_svn_ls;
Cmd_Table["cd"] = &_svn_cd;
Cmd_Table["cp"] = &_svn_cp;
Cmd_Table["help"] = &_svn_help;
Cmd_Table["mv"] = &_svn_mv;
Cmd_Table["mkdir"] = &_svn_mkdir;
Cmd_Table["rmdir"] = &_svn_rm;
Cmd_Table["rm"] = &_svn_rm;
Cmd_Table["most"] = &_svn_most;
Cmd_Table["quit"] = &_svn_quit;
Cmd_Table["?"] = &_svn_local_help;
private define take_input ()
{
variable line;
forever
{
try
{
line = slsh_readline (Rline, sprintf ("%s> ", Repository_CWD));
}
catch UserBreakError: continue;
if (line == NULL)
break;
variable argv = strtok (line, " \t;\n");
if (length (argv) == 0)
continue;
variable cmd = argv[0];
if (length (argv) == 1)
argv = String_Type[0];
else
argv = argv[[1:]];
variable e;
try (e)
{
if (0 == assoc_key_exists (Cmd_Table, cmd))
{
() = fprintf (stderr, "%s not supported\n", cmd);
continue;
}
(@Cmd_Table[cmd])(argv);
}
catch AnyError:
{
() = fprintf (stderr, "%S:%d:%s *** Caught exception: %S\n",
e.file, e.line, e.descr, e.message);
}
}
}
public define svn_set_repository (repos)
{
!if (_svn_path_exists (repos))
{
() = fprintf (stderr, "*** Repository %s does not exist\n", repos);
exit (1);
}
Repository = repos;
Repository_CWD = repos;
}
public define slsh_main ()
{
variable repos;
if (__argc == 2)
repos = __argv[1];
else
{
repos = getenv ("SVN_REPOS");
if (repos == NULL)
{
() = fprintf (stderr, "Usage: %s [file://]repository\n", __argv[0]);
exit (1);
}
}
() = fprintf (stdout, "svnsh version %s.\nUse this at your own risk!\n", SVNSH_VERSION);
() = fprintf (stdout, "Enter ? for a list of commands.\n");
!if (is_substr (repos, "://"))
repos = strcat ("file://", repos);
svn_set_repository (repos);
slsh_readline_init ("SVNSH");
Rline = slsh_readline_new ("svnsh");
take_input ();
}