From: Martin Mares Date: Thu, 15 May 2008 10:21:02 +0000 (+0200) Subject: Integrated the submitter to the build system. X-Git-Tag: python-dummy-working~196 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=8578967cba7d1deeae6ec4ea516e492e4496cdd2;p=eval.git Integrated the submitter to the build system. --- diff --git a/Makefile b/Makefile index 79a1193..e183f4c 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ include $(s)/box/Makefile include $(s)/utils/Makefile include $(s)/eval/Makefile include $(s)/judge/Makefile +include $(s)/submit/Makefile # And finally the default rules of the build system include $(s)/build/Makebottom diff --git a/submit/MO/Submit.pm b/submit/MO/Submit.pm deleted file mode 100644 index ba55961..0000000 --- a/submit/MO/Submit.pm +++ /dev/null @@ -1,186 +0,0 @@ -# A Perl module for communicating with the MO Submit Server -# (c) 2007 Martin Mares - -package MO::Submit; - -use strict; -use warnings; - -use IO::Socket::INET; -use IO::Socket::SSL; # qw(debug3); -use Sherlock::Object; -use POSIX; - -sub new($) { - my $user = $ENV{"USER"} or die "Environment variable USER not set\n"; - my $home = $ENV{"HOME"} or die "Environment variable HOME not set\n"; - my $mo = "$home/.mo"; - my $root = $ENV{"MO_ROOT"} or die "Environment variable MO_ROOT not set\n"; - my $self = { - "Contest" => "CEOI 2007", - "Server" => "ceoi-gamma:8888", - "Key" => "$mo/key.pem", # Keys and certificates - "Cert" => "$mo/cert.pem", - "CACert" => "$mo/ca-cert.pem", - "Trace" => defined $ENV{"MO_SUBMIT_TRACE"}, - "Checks" => 1, # Run `check' before submitting - "AllowOverride" => 1, # Allow overriding a failed check - "History" => "$home/.history", # Keep submission history in this directory - "RefreshTimer" => 60000, # How often GUI sends STATUS commands [ms] - "root" => $root, - "user" => $user, - "sk" => undef, - "error" => undef, - }; - return bless $self; -} - -sub DESTROY($) { - my $self = shift @_; - $self->disconnect; -} - -sub log($$) { - my ($self, $msg) = @_; - print STDERR "SUBMIT: $msg\n" if $self->{"Trace"}; -} - -sub err($$) { - my ($self, $msg) = @_; - print STDERR "ERROR: $msg\n" if $self->{"Trace"}; - $self->{"error"} = $msg; - $self->disconnect; -} - -sub is_connected($) { - my $self = shift @_; - return defined $self->{"sk"}; -} - -sub disconnect($) { - my $self = shift @_; - if ($self->is_connected) { - close $self->{"sk"}; - $self->{"sk"} = undef; - $self->log("Disconnected"); - } -} - -sub connect($) { - my $self = shift @_; - $self->disconnect; - - $self->log("Connecting to submit server"); - my $sk = new IO::Socket::INET( - PeerAddr => $self->{"Server"}, - Proto => "tcp", - ); - if (!defined $sk) { - $self->err("Cannot connect to server: $!"); - return undef; - } - my $z = <$sk>; - if (!defined $z) { - $self->err("Server failed to send a welcome message"); - close $sk; - return undef; - } - chomp $z; - if ($z !~ /^\+/) { - $self->err("Server rejected the connection: $z"); - close $sk; - return undef; - } - if ($z =~ /TLS/) { - $self->log("Starting TLS"); - $sk = IO::Socket::SSL->start_SSL( - $sk, - SSL_version => 'TLSv1', - SSL_use_cert => 1, - SSL_key_file => $self->{"Key"}, - SSL_cert_file => $self->{"Cert"}, - SSL_ca_file => $self->{"CACert"}, - SSL_verify_mode => 3, - ); - if (!defined $sk) { - $self->err("Cannot establish TLS connection: " . IO::Socket::SSL::errstr()); - return undef; - } - } - $self->{"sk"} = $sk; - $sk->autoflush(0); - - $self->log("Logging in"); - my $req = new Sherlock::Object("U" => $self->{"user"}); - my $reply = $self->request($req); - my $err = $reply->get("-"); - if (defined $err) { - $self->err("Cannot log in: $err"); - return undef; - } - - $self->log("Connected"); - return 1; -} - -sub request($$) { - my ($self, $obj) = @_; - my $sk = $self->{"sk"}; - local $SIG{'PIPE'} = 'ignore'; - $obj->write($sk); - print $sk "\n"; - $sk->flush(); - if ($sk->error) { - $self->err("Connection broken"); - return undef; - } - return $self->reply; -} - -sub reply($) { - my ($self, $obj) = @_; - my $sk = $self->{"sk"}; - my $reply = new Sherlock::Object; - if ($reply->read($sk)) { - return $reply; - } else { - $self->err("Connection broken"); - return undef; - } -} - -sub send_file($$$) { - my ($self, $fh, $size) = @_; - my $sk = $self->{"sk"}; - local $SIG{'PIPE'} = 'ignore'; - while ($size) { - my $l = ($size < 4096 ? $size : 4096); - my $buf = ""; - if ($fh->read($buf, $l) != $l) { - $self->err("File shrunk during upload"); - return undef; - } - $sk->write($buf, $l); - if ($sk->error) { - $self->err("Connection broken"); - return undef; - } - $size -= $l; - } - return $self->reply; -} - -sub write_history($$$$$) { - my ($self, $task, $part, $ext, $filename) = @_; - my $hist = $self->{"History"}; - -d $hist or mkdir $hist or return "Unable to create $hist: $!"; - my $now = POSIX::strftime("%H:%M:%S", localtime(time)); - my $maybe_part = ($part eq $task) ? "" : ":$part"; - my $name = "$hist/$now-$task$maybe_part.$ext"; - $self->log("Backing up to $name"); - `cp "$filename" "$name"`; - return "Unable to back up $filename as $name" if $?; - return undef; -} - -1; diff --git a/submit/Makefile b/submit/Makefile index f30f86c..fe9f0bd 100644 --- a/submit/Makefile +++ b/submit/Makefile @@ -1,22 +1,46 @@ -UCWCF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --cflags libucw libsh) -UCWLF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --libs libucw libsh) +# Makefile for MO-Eval submitter +# (c) 2008 Martin Mares + TLSCF:=$(shell libgnutls-config --cflags) TLSLF:=$(shell libgnutls-config --libs) GCRCF:=$(shell libgcrypt-config --cflags) -CFLAGS+=$(UCWCF) $(TLSCF) $(GCRCF) -LDLIBS+=$(UCWLF) $(TLSLF) +DIRS+=submit +SDIR=$(o)/submit + +### The submit server ### + +PROGS+=$(addprefix $(SDIR)/,submitd privkey connect) + +$(SHERLOCK_PERL_MODS): PERL_MODULE_DIR=MO + +$(SDIR)/submitd: $(addprefix $(SDIR)/,submitd.o commands.o tasks.o) $(LIBUCW) $(LIBSH) +$(SDIR)/submitd: CFLAGS+=$(TLSCF) $(GCRCF) +$(SDIR)/submitd: LIBS+=$(TLSLF) + +$(SDIR)/connect: $(SDIR)/connect.o $(LIBUCW) +$(SDIR)/connect: CFLAGS+=$(TLSCF) $(GCRCF) +$(SDIR)/connect: LIBS+=$(TLSLF) + +$(SDIR)/privkey: $(SDIR)/privkey.o $(LIBUCW) +$(SDIR)/privkey: CFLAGS+=$(TLSCF) $(GCRCF) +$(SDIR)/privkey: LIBS+=$(TLSLF) + +### Submitter perl module ### -all: submitd privkey lib +EXTRA_RUNDIRS+=lib/perl5/MO +SUBMIT_PERL_MODS=$(o)/submit/Submit.pm +PROGS+=$(SUBMIT_PERL_MODS) -submitd: submitd.o commands.o tasks.o -submitd.o: submitd.c submitd.h -commands.o: commands.c submitd.h -tasks.o: tasks.c submitd.h -connect: connect.o -connect.o: connect.c -privkey: privkey.o -privkey.o: privkey.c +### The submit client and utilities ### + +PROGS+=$(addprefix $(SDIR)/,contest create-certs remote-status remote-submit show-submits) + +$(SDIR)/contest: $(s)/submit/contest.pl +$(SDIR)/create-certs: $(s)/submit/create-certs.sh +$(SDIR)/remote-status: $(s)/submit/remote-status.pl +$(SDIR)/remote-submit: $(s)/submit/remote-submit.pl +$(SDIR)/show-submits: $(s)/submit/show-submits.pl certs: certtool --generate-privkey --outfile ca-key.pem @@ -28,22 +52,3 @@ certs: certtool --generate-request --load-privkey client-key.pem --outfile client-req.pem --template client-cert.tpl certtool --generate-certificate --load-request client-req.pem --outfile client-cert.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template client-cert.tpl # Beware of serial numbers - -lib: .lib-stamp lib/perl5/MO/Submit.pm lib/perl5/Sherlock/Object.pm - -.lib-stamp: - mkdir -p lib/perl5/{MO,Sherlock} - touch .lib-stamp - -lib/perl5/MO/Submit.pm: MO/Submit.pm - cp $^ $@ - -lib/perl5/Sherlock/Object.pm: $(LIBUCW)/lib/perl5/Sherlock/Object.pm - cp $^ $@ - -clean: - rm -f `find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core -or -name .depend -or -name .#*` - rm -f submitd connect privkey - rm -rf lib .lib-stamp - -.PHONY: lib diff --git a/submit/Submit.pm b/submit/Submit.pm new file mode 100644 index 0000000..ba55961 --- /dev/null +++ b/submit/Submit.pm @@ -0,0 +1,186 @@ +# A Perl module for communicating with the MO Submit Server +# (c) 2007 Martin Mares + +package MO::Submit; + +use strict; +use warnings; + +use IO::Socket::INET; +use IO::Socket::SSL; # qw(debug3); +use Sherlock::Object; +use POSIX; + +sub new($) { + my $user = $ENV{"USER"} or die "Environment variable USER not set\n"; + my $home = $ENV{"HOME"} or die "Environment variable HOME not set\n"; + my $mo = "$home/.mo"; + my $root = $ENV{"MO_ROOT"} or die "Environment variable MO_ROOT not set\n"; + my $self = { + "Contest" => "CEOI 2007", + "Server" => "ceoi-gamma:8888", + "Key" => "$mo/key.pem", # Keys and certificates + "Cert" => "$mo/cert.pem", + "CACert" => "$mo/ca-cert.pem", + "Trace" => defined $ENV{"MO_SUBMIT_TRACE"}, + "Checks" => 1, # Run `check' before submitting + "AllowOverride" => 1, # Allow overriding a failed check + "History" => "$home/.history", # Keep submission history in this directory + "RefreshTimer" => 60000, # How often GUI sends STATUS commands [ms] + "root" => $root, + "user" => $user, + "sk" => undef, + "error" => undef, + }; + return bless $self; +} + +sub DESTROY($) { + my $self = shift @_; + $self->disconnect; +} + +sub log($$) { + my ($self, $msg) = @_; + print STDERR "SUBMIT: $msg\n" if $self->{"Trace"}; +} + +sub err($$) { + my ($self, $msg) = @_; + print STDERR "ERROR: $msg\n" if $self->{"Trace"}; + $self->{"error"} = $msg; + $self->disconnect; +} + +sub is_connected($) { + my $self = shift @_; + return defined $self->{"sk"}; +} + +sub disconnect($) { + my $self = shift @_; + if ($self->is_connected) { + close $self->{"sk"}; + $self->{"sk"} = undef; + $self->log("Disconnected"); + } +} + +sub connect($) { + my $self = shift @_; + $self->disconnect; + + $self->log("Connecting to submit server"); + my $sk = new IO::Socket::INET( + PeerAddr => $self->{"Server"}, + Proto => "tcp", + ); + if (!defined $sk) { + $self->err("Cannot connect to server: $!"); + return undef; + } + my $z = <$sk>; + if (!defined $z) { + $self->err("Server failed to send a welcome message"); + close $sk; + return undef; + } + chomp $z; + if ($z !~ /^\+/) { + $self->err("Server rejected the connection: $z"); + close $sk; + return undef; + } + if ($z =~ /TLS/) { + $self->log("Starting TLS"); + $sk = IO::Socket::SSL->start_SSL( + $sk, + SSL_version => 'TLSv1', + SSL_use_cert => 1, + SSL_key_file => $self->{"Key"}, + SSL_cert_file => $self->{"Cert"}, + SSL_ca_file => $self->{"CACert"}, + SSL_verify_mode => 3, + ); + if (!defined $sk) { + $self->err("Cannot establish TLS connection: " . IO::Socket::SSL::errstr()); + return undef; + } + } + $self->{"sk"} = $sk; + $sk->autoflush(0); + + $self->log("Logging in"); + my $req = new Sherlock::Object("U" => $self->{"user"}); + my $reply = $self->request($req); + my $err = $reply->get("-"); + if (defined $err) { + $self->err("Cannot log in: $err"); + return undef; + } + + $self->log("Connected"); + return 1; +} + +sub request($$) { + my ($self, $obj) = @_; + my $sk = $self->{"sk"}; + local $SIG{'PIPE'} = 'ignore'; + $obj->write($sk); + print $sk "\n"; + $sk->flush(); + if ($sk->error) { + $self->err("Connection broken"); + return undef; + } + return $self->reply; +} + +sub reply($) { + my ($self, $obj) = @_; + my $sk = $self->{"sk"}; + my $reply = new Sherlock::Object; + if ($reply->read($sk)) { + return $reply; + } else { + $self->err("Connection broken"); + return undef; + } +} + +sub send_file($$$) { + my ($self, $fh, $size) = @_; + my $sk = $self->{"sk"}; + local $SIG{'PIPE'} = 'ignore'; + while ($size) { + my $l = ($size < 4096 ? $size : 4096); + my $buf = ""; + if ($fh->read($buf, $l) != $l) { + $self->err("File shrunk during upload"); + return undef; + } + $sk->write($buf, $l); + if ($sk->error) { + $self->err("Connection broken"); + return undef; + } + $size -= $l; + } + return $self->reply; +} + +sub write_history($$$$$) { + my ($self, $task, $part, $ext, $filename) = @_; + my $hist = $self->{"History"}; + -d $hist or mkdir $hist or return "Unable to create $hist: $!"; + my $now = POSIX::strftime("%H:%M:%S", localtime(time)); + my $maybe_part = ($part eq $task) ? "" : ":$part"; + my $name = "$hist/$now-$task$maybe_part.$ext"; + $self->log("Backing up to $name"); + `cp "$filename" "$name"`; + return "Unable to back up $filename as $name" if $?; + return undef; +} + +1; diff --git a/submit/contest b/submit/contest deleted file mode 100755 index 7d54456..0000000 --- a/submit/contest +++ /dev/null @@ -1,546 +0,0 @@ -#!/usr/bin/perl -# Contest UI for the MO Submitter -# (c) 2007 Martin Mares - -use strict; -use warnings; - -BEGIN { - defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n"; -} -use lib $ENV{"MO_ROOT"} . "/lib/perl5"; -use lib $ENV{"MO_ROOT"} . "/submit/lib/perl5"; - -use MO::Submit; -use Sherlock::Object; -use POSIX; -use IO::File; -use File::stat; -use Gtk2 -init; - -my $conn = new MO::Submit; - -### GUI INITIALIZATION ### - -sub init_refresh(); -sub start_refresh_timer($); -sub stop_refresh_timer(); -my $force_refresh = 0; -sub refresh(); - -sub submit($); - -my $busy_cursor = Gtk2::Gdk::Cursor->new('watch'); - -# The main window -my $window = Gtk2::Window->new('toplevel'); -$window->signal_connect("delete-event" => sub { Gtk2->main_quit }); -$window->set_title($conn->{"Contest"} . " Submitter"); -$window->set_wmclass("submitter", "Submitter"); -$window->set_default_size(640, 480); - -# The title label -my $title_lab = Gtk2::Label->new; -$title_lab->set_markup("" . $conn->{"Contest"} . ""); - -# The row of buttons -my $b_submit = Gtk2::Button->new('Submit'); -$b_submit->set_image(Gtk2::Image->new_from_stock('gtk-apply', 'button')); -$b_submit->signal_connect(clicked => sub { submit(0) }); -$b_submit->set_sensitive(0); - -my $b_check = Gtk2::Button->new('Check'); -$b_check->set_image(Gtk2::Image->new_from_stock('gtk-find', 'button')); -$b_check->signal_connect(clicked => sub { submit(1) }); -$b_check->set_sensitive(0); - -my $b_refresh = Gtk2::Button->new('Refresh'); -$b_refresh->set_image(Gtk2::Image->new_from_stock('gtk-refresh', 'button')); -$b_refresh->signal_connect(clicked => sub { start_refresh_timer(1) }); - -my $button_box = Gtk2::HBox->new; -$button_box->pack_start_defaults($b_submit); -$button_box->pack_start_defaults($b_check); -$button_box->pack_start_defaults($b_refresh); -$button_box->set_border_width(5); - -# The list of tasks -my $task_store = Gtk2::ListStore->new('Glib::String', 'Glib::String'); - -my $task_view = Gtk2::TreeView->new($task_store); -my $task_renderer = Gtk2::CellRendererText->new; -my $task_col1 = Gtk2::TreeViewColumn->new_with_attributes("Task", $task_renderer, "text", 0); -$task_view->append_column($task_col1); -my $task_col2 = Gtk2::TreeViewColumn->new_with_attributes("Status", $task_renderer, "text", 1); -$task_view->append_column($task_col2); -$task_view->set_headers_visible(0); - -my $task_scroll = Gtk2::ScrolledWindow->new; -$task_scroll->set_policy("automatic", "automatic"); -$task_scroll->add($task_view); -$task_scroll->set_border_width(5); - -my $task_frame = Gtk2::Frame->new("Tasks"); -$task_frame->add($task_scroll); - -my $selected_task; -my $task_sel = $task_view->get_selection; -$task_sel->set_mode('single'); -$task_sel->signal_connect(changed => sub { - my $iter = $_[0]->get_selected; - if ($iter) { - $selected_task = $task_store->get($iter, 0); - $b_submit->set_sensitive(1); - $b_check->set_sensitive(1); - } else { - $selected_task = undef; - print "Deselected task\n"; - $b_submit->set_sensitive(0); - $b_check->set_sensitive(0); - } -}); - -my $status_bar = Gtk2::Statusbar->new; -my $bar_ctx = $status_bar->get_context_id('xyzzy'); - -my $vbox = Gtk2::VBox->new; -$vbox->pack_start($title_lab, 0, 0, 10); -$vbox->pack_start($task_frame, 1, 1, 0); -$vbox->pack_start($button_box, 0, 0, 0); -$vbox->pack_start($status_bar, 0, 0, 0); - -$window->add($vbox); -$window->signal_connect("expose-event" => sub { init_refresh(); return 0; }); -$window->show_all; - -### REFRESHING ### - -my $last_status_id; - -sub msg($) { - print "GUI: ", $_[0], "\n" if $conn->{"Trace"}; -} - -sub status($) { - msg($_[0]); - defined $last_status_id and $status_bar->remove($bar_ctx, $last_status_id); - $last_status_id = $status_bar->push($bar_ctx, shift @_); -} - -sub busy($) { - status($_[0]); - $window->window->set_cursor($busy_cursor); - $window->Gtk2::Gdk::flush; -} - -sub ready($) { - status($_[0]); - $window->window->set_cursor(undef); - $window->Gtk2::Gdk::flush; -} - -my $window_inited = 0; -sub init_refresh() -{ - if (!$window_inited) { - $force_refresh = 1; - start_refresh_timer(1); - $window_inited = 1; - } - return 1; -} - -my $refresh_timer_id; - -sub timed_refresh() -{ - refresh(); - return 1; # We wish to re-run the timer -} - -sub start_refresh_timer($) { - my ($go) = @_; - stop_refresh_timer(); - refresh() if $go; - $refresh_timer_id = Glib::Timeout->add($conn->{"RefreshTimer"}, \&timed_refresh); -} - -sub stop_refresh_timer() { - if (defined $refresh_timer_id) { - Glib::Source->remove($refresh_timer_id); - $refresh_timer_id = undef; - } -} - -my $task_status_object; -my @task_parts = (); -my @task_stat = (); - -sub recalc_task_list() { - my @new_tp = (); - my @new_stat = (); - foreach my $t ($task_status_object->getarray("(T")) { - my $task = $t->get("T"); - foreach my $p ($t->getarray("(P")) { - my $part = $p->get("P"); - my $taskpart = ($task eq $part) ? $task : "$task/$part"; - push @new_tp, $taskpart; - my $status = "---"; - my $current_ver = $p->get("V"); - foreach my $v ($p->getarray("(V")) { - if ($v->get("V") == $current_ver) { - my $time = strftime("%H:%M:%S", localtime $v->get("T")); - $status = "OK (" . - "$part." . $v->get("X") . ", " . - $v->get("L") . " bytes, " . - $v->get("S") . " $time)"; - last; - } - } - push @new_stat, $status; - } - } - - if (join("\n", @new_tp) ne join("\n", @task_parts)) { - # The tasks have changed, repopulate the whole structure - $task_store->clear; - my @s = @new_stat; - foreach my $taskpart (@new_tp) { - my $iter = $task_store->append; - $task_store->set($iter, - 0, $taskpart, - 1, shift @s); - } - } else { - # Update the task status - my @s = @task_stat; - my @ns = @new_stat; - $task_store->foreach(sub { - my ($obj, $path, $iter) = @_; - if ($s[0] ne $ns[0]) { - $task_store->set($iter, 1, $ns[0]); - } - shift @s; - shift @ns; - return 0; - }); - } - - @task_parts = @new_tp; - @task_stat = @new_stat; -} - -sub refresh() -{ - if (!$conn->is_connected || $force_refresh) { - busy("Connecting to server..."); - if ($conn->connect) { - ready("Connected successfully"); - } else { - ready($conn->{"error"}); - } - } - if ($conn->is_connected) { - busy("Updating status..."); - my $r = new Sherlock::Object("!" => "STATUS"); - $r = $conn->request($r); - if (!defined $r) { - ready($conn->{"error"}); - } elsif ($r->get("-")) { - ready($r->get("-")); - } else { - $task_status_object = $r; - recalc_task_list; - $force_refresh = 0; - ready("Ready"); - } - } - if (!$conn->is_connected && !$force_refresh) { - # Retry - $conn->log("Retrying"); - $force_refresh = 1; - refresh(); - } -} - -### SUBMITTING ### - -my $subwin; -my $chooser; -my $subwin_vbox; -my $subwin_label; -my $bbutton_box; -my $submitting_label; -my $text_frame; -my $status_label; -my $check_only; -my $submit_filename; -my $submit_extension; -my %submit_fn_cache = (); - -sub end_submit($) { - my ($close) = @_; - $subwin->destroy if $close; - start_refresh_timer(1); -} - -sub finish_submit() { - my $button = Gtk2::Button->new_from_stock('gtk-close'); - $button->signal_connect(clicked => sub { end_submit(1) }); - - $bbutton_box = Gtk2::HButtonBox->new; - $bbutton_box->pack_start_defaults($button); - $subwin_vbox->pack_start($bbutton_box, 0, 0, 10); - - ready("Ready"); - $subwin->show_all; - $subwin->window->set_cursor(undef); -} - -sub submit_ok() { - $status_label->set_markup("Submitted OK"); - $submitting_label->set_markup("The task has been successfully submitted."); - refresh(); - finish_submit(); -} - -sub submit_failed($) { - my ($msg) = @_; - $status_label->set_markup("Submit failed"); - $submitting_label->set_markup("$msg"); - finish_submit(); -} - -sub run_submit() { - my ($task, $part) = split /\//, $selected_task; - defined $part or $part = $task; - - if (defined $conn->{"History"}) { - busy("Submitting locally to " . $conn->{"History"}); - my $err = $conn->write_history($task, $part, $submit_extension, $submit_filename); - if (defined $err) { - submit_failed("Recording to local history failed\n($err)"); - return; - } - } - - if ($conn->is_connected) { - busy("Checking server status..."); - my $r = new Sherlock::Object("!" => "NOP"); - $r = $conn->request($r); - } - if (!$conn->is_connected) { - busy("Reconnecting to server..."); - if (!$conn->connect) { - ready($conn->{"error"}); - submit_failed("Unable to connect to the server"); - return; - } - } - busy("Submitting..."); - - my $fh = new IO::File($submit_filename); - if (!$fh) { - submit_failed("Unable to open $submit_filename\n($!)"); - return; - } - my $stat = File::stat::populate($fh->stat); - if (!$stat) { - submit_failed("Unable to stat $submit_filename\n($!)"); - return; - } - my $size = $stat->size; - - my $r = new Sherlock::Object("!" => "SUBMIT", "T" => $task, "P" => $part, "X" => $submit_extension, "S" => $size); - $r = $conn->request($r); - if (!defined($r)) { - submit_failed("Connection to the server lost"); - return; - } elsif ($r->get("-")) { - submit_failed($r->get("-")); - return; - } - - $r = $conn->send_file($fh, $size); - if (!defined($r)) { - submit_failed("Connection to the server lost"); - return; - } elsif ($r->get("-")) { - submit_failed($r->get("-")); - return; - } - - close $fh; - submit_ok(); -} - -sub checks_ok() { - if ($check_only) { - $status_label->set_markup("Checked successfully"); - $submitting_label->set_markup("The task has passed the checks."); - finish_submit(); - return; - } - - $status_label->set_markup("Submitting"); - $subwin->show_all; - - # Continue when everything is displayed - Glib::Idle->add(sub { - $window->Gtk2::Gdk::flush; - run_submit(); - return 0; - }); -} - -sub checks_override() { - $submitting_label = Gtk2::Label->new("Please wait..."); - $subwin_vbox->pack_start_defaults($submitting_label); - - $subwin->window->set_cursor($busy_cursor); - $bbutton_box->destroy; - $text_frame->destroy; - checks_ok(); -} - -sub checks_failed($) { - my ($msg) = @_; - - $status_label->set_markup("Check failed"); - $submitting_label->destroy; - - my $text_buffer = Gtk2::TextBuffer->new; - $text_buffer->set_text($msg); - - my $text_view = Gtk2::TextView->new_with_buffer($text_buffer); - $text_view->set_editable(0); - $text_view->set_cursor_visible(0); - - my $text_scroll = Gtk2::ScrolledWindow->new; - $text_scroll->set_policy("automatic", "automatic"); - $text_scroll->add($text_view); - - $text_frame = Gtk2::Frame->new("Checker log"); - $text_frame->add($text_scroll); - - $subwin_vbox->pack_start_defaults($text_frame); - - if ($check_only || !$conn->{"AllowOverride"}) { - finish_submit(); - return; - } - - my $close_button = Gtk2::Button->new_from_stock('gtk-close'); - $close_button->signal_connect(clicked => sub { end_submit(1) }); - - my $anyway_button = Gtk2::Button->new('Submit anyway'); - $anyway_button->signal_connect(clicked => \&checks_override); - - $bbutton_box = Gtk2::HButtonBox->new; - $bbutton_box->pack_start_defaults($anyway_button); - $bbutton_box->pack_start_defaults($close_button); - $bbutton_box->set_border_width(5); - $subwin_vbox->pack_start($bbutton_box, 0, 0, 10); - - ready("Ready"); - $subwin->show_all; - $subwin->window->set_cursor(undef); -} - -sub run_checks() { - ($submit_extension) = ($submit_filename =~ /\.([^.]+)$/); - if (!$submit_extension) { - checks_failed("The filename does not have a valid extension"); - return; - } - if (!$conn->{"Checks"}) { - checks_ok(); - return; - } - my $root = $conn->{"root"}; - my ($task, $part) = split /\//, $selected_task; - defined $part or $part = ""; - my $verdict = `$root/bin/check -s "$submit_filename" $task $part 2>&1`; - if ($?) { - checks_failed($verdict); - } else { - checks_ok(); - } -} - -sub do_submit() { - $submit_filename = $chooser->get_filename; - $submit_fn_cache{$selected_task} = $submit_filename; - msg "Selected $submit_filename"; - defined $submit_filename or return; - -f $submit_filename or return; - - $chooser->destroy; - $bbutton_box->destroy; - - $status_label->set_markup("Checking"); - - $submitting_label = Gtk2::Label->new("Please wait..."); - $subwin_vbox->pack_start_defaults($submitting_label); - $subwin->show_all; - $subwin->window->set_cursor($busy_cursor); - - # Continue when everything is displayed - Glib::Idle->add(sub { - $window->Gtk2::Gdk::flush; - run_checks(); - return 0; - }); -} - -sub submit($) { - $check_only = shift @_; - - stop_refresh_timer(); - - $subwin = Gtk2::Window->new('toplevel'); - $subwin->set_default_size(640, 480); - $subwin->set_modal(1); - $subwin->set_transient_for($window); - $subwin->set_destroy_with_parent(1); - $subwin->set_title("Submit task $selected_task"); - $subwin->set_wmclass("submitter", "Submitter"); - $subwin->signal_connect("delete-event" => sub { end_submit(0); return 0; }); - - my $bb_submit = Gtk2::Button->new($check_only ? 'Check' : 'Submit'); - $bb_submit->set_image(Gtk2::Image->new_from_stock('gtk-apply', 'button')); - $bb_submit->signal_connect(clicked => \&do_submit); - - my $bb_cancel = Gtk2::Button->new_from_stock('gtk-cancel'); - $bb_cancel->signal_connect(clicked => sub { end_submit(1) }); - - $bbutton_box = Gtk2::HButtonBox->new; - $bbutton_box->pack_start_defaults($bb_submit); - $bbutton_box->pack_start_defaults($bb_cancel); - $bbutton_box->set_border_width(5); - - my $subwin_label = Gtk2::Label->new; - $subwin_label->set_markup("" . ($check_only ? "Checking" : "Submitting") . " $selected_task"); - - $status_label = Gtk2::Label->new; - $status_label->set_markup("Please select file to " . ($check_only ? "check" : "submit") . ""); - - $chooser = Gtk2::FileChooserWidget->new("open"); - $chooser->set_local_only(1); - $chooser->signal_connect("file-activated" => \&do_submit); - $chooser->set_filename($submit_fn_cache{$selected_task}) if defined $submit_fn_cache{$selected_task}; - - $subwin_vbox = Gtk2::VBox->new; - $subwin_vbox->pack_start($subwin_label, 0, 0, 10); - $subwin_vbox->pack_start($status_label, 0, 0, 10); - $subwin_vbox->pack_start_defaults($chooser); - $subwin_vbox->pack_start($bbutton_box, 0, 0, 0); - - $subwin->add($subwin_vbox); - $subwin->show_all; -} - -### MAIN ### - -Gtk2->main; -exit 0; diff --git a/submit/contest.pl b/submit/contest.pl new file mode 100755 index 0000000..7d54456 --- /dev/null +++ b/submit/contest.pl @@ -0,0 +1,546 @@ +#!/usr/bin/perl +# Contest UI for the MO Submitter +# (c) 2007 Martin Mares + +use strict; +use warnings; + +BEGIN { + defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n"; +} +use lib $ENV{"MO_ROOT"} . "/lib/perl5"; +use lib $ENV{"MO_ROOT"} . "/submit/lib/perl5"; + +use MO::Submit; +use Sherlock::Object; +use POSIX; +use IO::File; +use File::stat; +use Gtk2 -init; + +my $conn = new MO::Submit; + +### GUI INITIALIZATION ### + +sub init_refresh(); +sub start_refresh_timer($); +sub stop_refresh_timer(); +my $force_refresh = 0; +sub refresh(); + +sub submit($); + +my $busy_cursor = Gtk2::Gdk::Cursor->new('watch'); + +# The main window +my $window = Gtk2::Window->new('toplevel'); +$window->signal_connect("delete-event" => sub { Gtk2->main_quit }); +$window->set_title($conn->{"Contest"} . " Submitter"); +$window->set_wmclass("submitter", "Submitter"); +$window->set_default_size(640, 480); + +# The title label +my $title_lab = Gtk2::Label->new; +$title_lab->set_markup("" . $conn->{"Contest"} . ""); + +# The row of buttons +my $b_submit = Gtk2::Button->new('Submit'); +$b_submit->set_image(Gtk2::Image->new_from_stock('gtk-apply', 'button')); +$b_submit->signal_connect(clicked => sub { submit(0) }); +$b_submit->set_sensitive(0); + +my $b_check = Gtk2::Button->new('Check'); +$b_check->set_image(Gtk2::Image->new_from_stock('gtk-find', 'button')); +$b_check->signal_connect(clicked => sub { submit(1) }); +$b_check->set_sensitive(0); + +my $b_refresh = Gtk2::Button->new('Refresh'); +$b_refresh->set_image(Gtk2::Image->new_from_stock('gtk-refresh', 'button')); +$b_refresh->signal_connect(clicked => sub { start_refresh_timer(1) }); + +my $button_box = Gtk2::HBox->new; +$button_box->pack_start_defaults($b_submit); +$button_box->pack_start_defaults($b_check); +$button_box->pack_start_defaults($b_refresh); +$button_box->set_border_width(5); + +# The list of tasks +my $task_store = Gtk2::ListStore->new('Glib::String', 'Glib::String'); + +my $task_view = Gtk2::TreeView->new($task_store); +my $task_renderer = Gtk2::CellRendererText->new; +my $task_col1 = Gtk2::TreeViewColumn->new_with_attributes("Task", $task_renderer, "text", 0); +$task_view->append_column($task_col1); +my $task_col2 = Gtk2::TreeViewColumn->new_with_attributes("Status", $task_renderer, "text", 1); +$task_view->append_column($task_col2); +$task_view->set_headers_visible(0); + +my $task_scroll = Gtk2::ScrolledWindow->new; +$task_scroll->set_policy("automatic", "automatic"); +$task_scroll->add($task_view); +$task_scroll->set_border_width(5); + +my $task_frame = Gtk2::Frame->new("Tasks"); +$task_frame->add($task_scroll); + +my $selected_task; +my $task_sel = $task_view->get_selection; +$task_sel->set_mode('single'); +$task_sel->signal_connect(changed => sub { + my $iter = $_[0]->get_selected; + if ($iter) { + $selected_task = $task_store->get($iter, 0); + $b_submit->set_sensitive(1); + $b_check->set_sensitive(1); + } else { + $selected_task = undef; + print "Deselected task\n"; + $b_submit->set_sensitive(0); + $b_check->set_sensitive(0); + } +}); + +my $status_bar = Gtk2::Statusbar->new; +my $bar_ctx = $status_bar->get_context_id('xyzzy'); + +my $vbox = Gtk2::VBox->new; +$vbox->pack_start($title_lab, 0, 0, 10); +$vbox->pack_start($task_frame, 1, 1, 0); +$vbox->pack_start($button_box, 0, 0, 0); +$vbox->pack_start($status_bar, 0, 0, 0); + +$window->add($vbox); +$window->signal_connect("expose-event" => sub { init_refresh(); return 0; }); +$window->show_all; + +### REFRESHING ### + +my $last_status_id; + +sub msg($) { + print "GUI: ", $_[0], "\n" if $conn->{"Trace"}; +} + +sub status($) { + msg($_[0]); + defined $last_status_id and $status_bar->remove($bar_ctx, $last_status_id); + $last_status_id = $status_bar->push($bar_ctx, shift @_); +} + +sub busy($) { + status($_[0]); + $window->window->set_cursor($busy_cursor); + $window->Gtk2::Gdk::flush; +} + +sub ready($) { + status($_[0]); + $window->window->set_cursor(undef); + $window->Gtk2::Gdk::flush; +} + +my $window_inited = 0; +sub init_refresh() +{ + if (!$window_inited) { + $force_refresh = 1; + start_refresh_timer(1); + $window_inited = 1; + } + return 1; +} + +my $refresh_timer_id; + +sub timed_refresh() +{ + refresh(); + return 1; # We wish to re-run the timer +} + +sub start_refresh_timer($) { + my ($go) = @_; + stop_refresh_timer(); + refresh() if $go; + $refresh_timer_id = Glib::Timeout->add($conn->{"RefreshTimer"}, \&timed_refresh); +} + +sub stop_refresh_timer() { + if (defined $refresh_timer_id) { + Glib::Source->remove($refresh_timer_id); + $refresh_timer_id = undef; + } +} + +my $task_status_object; +my @task_parts = (); +my @task_stat = (); + +sub recalc_task_list() { + my @new_tp = (); + my @new_stat = (); + foreach my $t ($task_status_object->getarray("(T")) { + my $task = $t->get("T"); + foreach my $p ($t->getarray("(P")) { + my $part = $p->get("P"); + my $taskpart = ($task eq $part) ? $task : "$task/$part"; + push @new_tp, $taskpart; + my $status = "---"; + my $current_ver = $p->get("V"); + foreach my $v ($p->getarray("(V")) { + if ($v->get("V") == $current_ver) { + my $time = strftime("%H:%M:%S", localtime $v->get("T")); + $status = "OK (" . + "$part." . $v->get("X") . ", " . + $v->get("L") . " bytes, " . + $v->get("S") . " $time)"; + last; + } + } + push @new_stat, $status; + } + } + + if (join("\n", @new_tp) ne join("\n", @task_parts)) { + # The tasks have changed, repopulate the whole structure + $task_store->clear; + my @s = @new_stat; + foreach my $taskpart (@new_tp) { + my $iter = $task_store->append; + $task_store->set($iter, + 0, $taskpart, + 1, shift @s); + } + } else { + # Update the task status + my @s = @task_stat; + my @ns = @new_stat; + $task_store->foreach(sub { + my ($obj, $path, $iter) = @_; + if ($s[0] ne $ns[0]) { + $task_store->set($iter, 1, $ns[0]); + } + shift @s; + shift @ns; + return 0; + }); + } + + @task_parts = @new_tp; + @task_stat = @new_stat; +} + +sub refresh() +{ + if (!$conn->is_connected || $force_refresh) { + busy("Connecting to server..."); + if ($conn->connect) { + ready("Connected successfully"); + } else { + ready($conn->{"error"}); + } + } + if ($conn->is_connected) { + busy("Updating status..."); + my $r = new Sherlock::Object("!" => "STATUS"); + $r = $conn->request($r); + if (!defined $r) { + ready($conn->{"error"}); + } elsif ($r->get("-")) { + ready($r->get("-")); + } else { + $task_status_object = $r; + recalc_task_list; + $force_refresh = 0; + ready("Ready"); + } + } + if (!$conn->is_connected && !$force_refresh) { + # Retry + $conn->log("Retrying"); + $force_refresh = 1; + refresh(); + } +} + +### SUBMITTING ### + +my $subwin; +my $chooser; +my $subwin_vbox; +my $subwin_label; +my $bbutton_box; +my $submitting_label; +my $text_frame; +my $status_label; +my $check_only; +my $submit_filename; +my $submit_extension; +my %submit_fn_cache = (); + +sub end_submit($) { + my ($close) = @_; + $subwin->destroy if $close; + start_refresh_timer(1); +} + +sub finish_submit() { + my $button = Gtk2::Button->new_from_stock('gtk-close'); + $button->signal_connect(clicked => sub { end_submit(1) }); + + $bbutton_box = Gtk2::HButtonBox->new; + $bbutton_box->pack_start_defaults($button); + $subwin_vbox->pack_start($bbutton_box, 0, 0, 10); + + ready("Ready"); + $subwin->show_all; + $subwin->window->set_cursor(undef); +} + +sub submit_ok() { + $status_label->set_markup("Submitted OK"); + $submitting_label->set_markup("The task has been successfully submitted."); + refresh(); + finish_submit(); +} + +sub submit_failed($) { + my ($msg) = @_; + $status_label->set_markup("Submit failed"); + $submitting_label->set_markup("$msg"); + finish_submit(); +} + +sub run_submit() { + my ($task, $part) = split /\//, $selected_task; + defined $part or $part = $task; + + if (defined $conn->{"History"}) { + busy("Submitting locally to " . $conn->{"History"}); + my $err = $conn->write_history($task, $part, $submit_extension, $submit_filename); + if (defined $err) { + submit_failed("Recording to local history failed\n($err)"); + return; + } + } + + if ($conn->is_connected) { + busy("Checking server status..."); + my $r = new Sherlock::Object("!" => "NOP"); + $r = $conn->request($r); + } + if (!$conn->is_connected) { + busy("Reconnecting to server..."); + if (!$conn->connect) { + ready($conn->{"error"}); + submit_failed("Unable to connect to the server"); + return; + } + } + busy("Submitting..."); + + my $fh = new IO::File($submit_filename); + if (!$fh) { + submit_failed("Unable to open $submit_filename\n($!)"); + return; + } + my $stat = File::stat::populate($fh->stat); + if (!$stat) { + submit_failed("Unable to stat $submit_filename\n($!)"); + return; + } + my $size = $stat->size; + + my $r = new Sherlock::Object("!" => "SUBMIT", "T" => $task, "P" => $part, "X" => $submit_extension, "S" => $size); + $r = $conn->request($r); + if (!defined($r)) { + submit_failed("Connection to the server lost"); + return; + } elsif ($r->get("-")) { + submit_failed($r->get("-")); + return; + } + + $r = $conn->send_file($fh, $size); + if (!defined($r)) { + submit_failed("Connection to the server lost"); + return; + } elsif ($r->get("-")) { + submit_failed($r->get("-")); + return; + } + + close $fh; + submit_ok(); +} + +sub checks_ok() { + if ($check_only) { + $status_label->set_markup("Checked successfully"); + $submitting_label->set_markup("The task has passed the checks."); + finish_submit(); + return; + } + + $status_label->set_markup("Submitting"); + $subwin->show_all; + + # Continue when everything is displayed + Glib::Idle->add(sub { + $window->Gtk2::Gdk::flush; + run_submit(); + return 0; + }); +} + +sub checks_override() { + $submitting_label = Gtk2::Label->new("Please wait..."); + $subwin_vbox->pack_start_defaults($submitting_label); + + $subwin->window->set_cursor($busy_cursor); + $bbutton_box->destroy; + $text_frame->destroy; + checks_ok(); +} + +sub checks_failed($) { + my ($msg) = @_; + + $status_label->set_markup("Check failed"); + $submitting_label->destroy; + + my $text_buffer = Gtk2::TextBuffer->new; + $text_buffer->set_text($msg); + + my $text_view = Gtk2::TextView->new_with_buffer($text_buffer); + $text_view->set_editable(0); + $text_view->set_cursor_visible(0); + + my $text_scroll = Gtk2::ScrolledWindow->new; + $text_scroll->set_policy("automatic", "automatic"); + $text_scroll->add($text_view); + + $text_frame = Gtk2::Frame->new("Checker log"); + $text_frame->add($text_scroll); + + $subwin_vbox->pack_start_defaults($text_frame); + + if ($check_only || !$conn->{"AllowOverride"}) { + finish_submit(); + return; + } + + my $close_button = Gtk2::Button->new_from_stock('gtk-close'); + $close_button->signal_connect(clicked => sub { end_submit(1) }); + + my $anyway_button = Gtk2::Button->new('Submit anyway'); + $anyway_button->signal_connect(clicked => \&checks_override); + + $bbutton_box = Gtk2::HButtonBox->new; + $bbutton_box->pack_start_defaults($anyway_button); + $bbutton_box->pack_start_defaults($close_button); + $bbutton_box->set_border_width(5); + $subwin_vbox->pack_start($bbutton_box, 0, 0, 10); + + ready("Ready"); + $subwin->show_all; + $subwin->window->set_cursor(undef); +} + +sub run_checks() { + ($submit_extension) = ($submit_filename =~ /\.([^.]+)$/); + if (!$submit_extension) { + checks_failed("The filename does not have a valid extension"); + return; + } + if (!$conn->{"Checks"}) { + checks_ok(); + return; + } + my $root = $conn->{"root"}; + my ($task, $part) = split /\//, $selected_task; + defined $part or $part = ""; + my $verdict = `$root/bin/check -s "$submit_filename" $task $part 2>&1`; + if ($?) { + checks_failed($verdict); + } else { + checks_ok(); + } +} + +sub do_submit() { + $submit_filename = $chooser->get_filename; + $submit_fn_cache{$selected_task} = $submit_filename; + msg "Selected $submit_filename"; + defined $submit_filename or return; + -f $submit_filename or return; + + $chooser->destroy; + $bbutton_box->destroy; + + $status_label->set_markup("Checking"); + + $submitting_label = Gtk2::Label->new("Please wait..."); + $subwin_vbox->pack_start_defaults($submitting_label); + $subwin->show_all; + $subwin->window->set_cursor($busy_cursor); + + # Continue when everything is displayed + Glib::Idle->add(sub { + $window->Gtk2::Gdk::flush; + run_checks(); + return 0; + }); +} + +sub submit($) { + $check_only = shift @_; + + stop_refresh_timer(); + + $subwin = Gtk2::Window->new('toplevel'); + $subwin->set_default_size(640, 480); + $subwin->set_modal(1); + $subwin->set_transient_for($window); + $subwin->set_destroy_with_parent(1); + $subwin->set_title("Submit task $selected_task"); + $subwin->set_wmclass("submitter", "Submitter"); + $subwin->signal_connect("delete-event" => sub { end_submit(0); return 0; }); + + my $bb_submit = Gtk2::Button->new($check_only ? 'Check' : 'Submit'); + $bb_submit->set_image(Gtk2::Image->new_from_stock('gtk-apply', 'button')); + $bb_submit->signal_connect(clicked => \&do_submit); + + my $bb_cancel = Gtk2::Button->new_from_stock('gtk-cancel'); + $bb_cancel->signal_connect(clicked => sub { end_submit(1) }); + + $bbutton_box = Gtk2::HButtonBox->new; + $bbutton_box->pack_start_defaults($bb_submit); + $bbutton_box->pack_start_defaults($bb_cancel); + $bbutton_box->set_border_width(5); + + my $subwin_label = Gtk2::Label->new; + $subwin_label->set_markup("" . ($check_only ? "Checking" : "Submitting") . " $selected_task"); + + $status_label = Gtk2::Label->new; + $status_label->set_markup("Please select file to " . ($check_only ? "check" : "submit") . ""); + + $chooser = Gtk2::FileChooserWidget->new("open"); + $chooser->set_local_only(1); + $chooser->signal_connect("file-activated" => \&do_submit); + $chooser->set_filename($submit_fn_cache{$selected_task}) if defined $submit_fn_cache{$selected_task}; + + $subwin_vbox = Gtk2::VBox->new; + $subwin_vbox->pack_start($subwin_label, 0, 0, 10); + $subwin_vbox->pack_start($status_label, 0, 0, 10); + $subwin_vbox->pack_start_defaults($chooser); + $subwin_vbox->pack_start($bbutton_box, 0, 0, 0); + + $subwin->add($subwin_vbox); + $subwin->show_all; +} + +### MAIN ### + +Gtk2->main; +exit 0; diff --git a/submit/create-certs b/submit/create-certs deleted file mode 100755 index 5e4abb2..0000000 --- a/submit/create-certs +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# A script for creation of all the certificates used by submitd -# (c) 2007 Martin Mares - -set -e -if [ ! -f submit/ca-cert.tpl ] ; then - echo >&2 "Please run from the MO root directory." - exit 1 -fi - -umask 033 -rm -rf certs -mkdir certs - -echo "### Creating CA certificate ###" -submit/privkey >certs/ca-key.pem -certtool --generate-self-signed --load-privkey certs/ca-key.pem --outfile certs/ca-cert.pem --template submit/ca-cert.tpl - -echo "### Creating server certificate ###" -submit/privkey >certs/server-key.pem -certtool --generate-request --load-privkey certs/server-key.pem --outfile certs/server-req.pem --template submit/server-cert.tpl -certtool --generate-certificate --load-request certs/server-req.pem --outfile certs/server-cert.pem --load-ca-certificate certs/ca-cert.pem --load-ca-privkey certs/ca-key.pem --template submit/server-cert.tpl - -seq=1 -for user in `bin/mo-get-users` ; do - seq=$(($seq+1)) - echo "### Creating certificate for user #$seq ($user) ###" - sed certs/$user-cert.tpl "s/cn = \".*\"/cn = \"$user\"/; s/serial = .*/serial = $seq/;" - submit/privkey >certs/$user-key.pem - certtool --generate-request --load-privkey certs/$user-key.pem --outfile certs/$user-req.pem --template certs/$user-cert.tpl - certtool --generate-certificate --load-request certs/$user-req.pem --outfile certs/$user-cert.pem --load-ca-certificate certs/ca-cert.pem --load-ca-privkey certs/ca-key.pem --template certs/$user-cert.tpl -done diff --git a/submit/create-certs.sh b/submit/create-certs.sh new file mode 100755 index 0000000..5e4abb2 --- /dev/null +++ b/submit/create-certs.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# A script for creation of all the certificates used by submitd +# (c) 2007 Martin Mares + +set -e +if [ ! -f submit/ca-cert.tpl ] ; then + echo >&2 "Please run from the MO root directory." + exit 1 +fi + +umask 033 +rm -rf certs +mkdir certs + +echo "### Creating CA certificate ###" +submit/privkey >certs/ca-key.pem +certtool --generate-self-signed --load-privkey certs/ca-key.pem --outfile certs/ca-cert.pem --template submit/ca-cert.tpl + +echo "### Creating server certificate ###" +submit/privkey >certs/server-key.pem +certtool --generate-request --load-privkey certs/server-key.pem --outfile certs/server-req.pem --template submit/server-cert.tpl +certtool --generate-certificate --load-request certs/server-req.pem --outfile certs/server-cert.pem --load-ca-certificate certs/ca-cert.pem --load-ca-privkey certs/ca-key.pem --template submit/server-cert.tpl + +seq=1 +for user in `bin/mo-get-users` ; do + seq=$(($seq+1)) + echo "### Creating certificate for user #$seq ($user) ###" + sed certs/$user-cert.tpl "s/cn = \".*\"/cn = \"$user\"/; s/serial = .*/serial = $seq/;" + submit/privkey >certs/$user-key.pem + certtool --generate-request --load-privkey certs/$user-key.pem --outfile certs/$user-req.pem --template certs/$user-cert.tpl + certtool --generate-certificate --load-request certs/$user-req.pem --outfile certs/$user-cert.pem --load-ca-certificate certs/ca-cert.pem --load-ca-privkey certs/ca-key.pem --template certs/$user-cert.tpl +done diff --git a/submit/remote-status b/submit/remote-status deleted file mode 100755 index 0461057..0000000 --- a/submit/remote-status +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -BEGIN { - defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n"; -} -use lib $ENV{"MO_ROOT"} . "/lib/perl5"; -use lib $ENV{"MO_ROOT"} . "/submit/lib/perl5"; - -use MO::Submit; -use Sherlock::Object; -use POSIX; - -@ARGV == 0 or die "Usage: remote-status\n"; - -my $conn = new MO::Submit; -$conn->connect or die $conn->{"error"} . "\n"; - -sub or_die($) { - my $r = shift @_; - if (!defined $r) { die $conn->{"error"} . "\n"; } - my $err = $r->get("-"); - if ($err) { die "$err\n"; } -} - -my $r = new Sherlock::Object("!" => "STATUS"); -$r = $conn->request($r); -or_die($r); -#$r->write_indented(*STDOUT); - -foreach my $t ($r->getarray("(T")) { - my $task = $t->get("T"); - foreach my $p ($t->getarray("(P")) { - my $part = $p->get("P"); - my $name = $task; - $part eq $task or $name .= "/$part"; - printf "%-16s", $name; - - my $current_ver = $p->get("V"); - my $printed = 0; - foreach my $v ($p->getarray("(V")) { - if ($v->get("V") == $current_ver) { - my $time = strftime("%H:%M:%S", localtime $v->get("T")); - print "OK (", - "$part.", $v->get("X"), ", ", - $v->get("L"), " bytes, ", - $v->get("S"), " $time)\n"; - $printed = 1; - } - } - $printed or print "---\n"; - } -} - -$conn->disconnect; diff --git a/submit/remote-status.pl b/submit/remote-status.pl new file mode 100755 index 0000000..0461057 --- /dev/null +++ b/submit/remote-status.pl @@ -0,0 +1,57 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +BEGIN { + defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n"; +} +use lib $ENV{"MO_ROOT"} . "/lib/perl5"; +use lib $ENV{"MO_ROOT"} . "/submit/lib/perl5"; + +use MO::Submit; +use Sherlock::Object; +use POSIX; + +@ARGV == 0 or die "Usage: remote-status\n"; + +my $conn = new MO::Submit; +$conn->connect or die $conn->{"error"} . "\n"; + +sub or_die($) { + my $r = shift @_; + if (!defined $r) { die $conn->{"error"} . "\n"; } + my $err = $r->get("-"); + if ($err) { die "$err\n"; } +} + +my $r = new Sherlock::Object("!" => "STATUS"); +$r = $conn->request($r); +or_die($r); +#$r->write_indented(*STDOUT); + +foreach my $t ($r->getarray("(T")) { + my $task = $t->get("T"); + foreach my $p ($t->getarray("(P")) { + my $part = $p->get("P"); + my $name = $task; + $part eq $task or $name .= "/$part"; + printf "%-16s", $name; + + my $current_ver = $p->get("V"); + my $printed = 0; + foreach my $v ($p->getarray("(V")) { + if ($v->get("V") == $current_ver) { + my $time = strftime("%H:%M:%S", localtime $v->get("T")); + print "OK (", + "$part.", $v->get("X"), ", ", + $v->get("L"), " bytes, ", + $v->get("S"), " $time)\n"; + $printed = 1; + } + } + $printed or print "---\n"; + } +} + +$conn->disconnect; diff --git a/submit/remote-submit b/submit/remote-submit deleted file mode 100755 index c2e13a0..0000000 --- a/submit/remote-submit +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -BEGIN { - defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n"; -} -use lib $ENV{"MO_ROOT"} . "/submit"; -use lib $ENV{"MO_ROOT"} . "/lib/perl5"; - -use MO::Submit; -use Sherlock::Object; -use File::stat; - -@ARGV == 2 || @ARGV == 3 or die "Usage: remote-submit [] \n"; -my $task = $ARGV[0]; -my $part = $task; -if (@ARGV == 3) { - $part = $ARGV[1]; - shift @ARGV; -} -my $file = $ARGV[1]; -my ($ext) = ($file =~ /\.([^.]+)$/) or die "Unable to determine filename extension\n"; - -open F, $file or die "Unable to open $file: $!\n"; -my $s = stat(*F) or die; -my $size = $s->size; - -my $conn = new MO::Submit; - -my $he = $conn->write_history($task, $part, $ext, $file); -if (defined $he) { die "$he\n"; } - -$conn->connect or die $conn->{"error"} . "\n"; - -sub or_die($) { - my $r = shift @_; - if (!defined $r) { die $conn->{"error"} . "\n"; } - my $err = $r->get("-"); - if ($err) { die "$err\n"; } -} - -my $r = new Sherlock::Object("!" => "SUBMIT", "T" => $task, "P" => $part, "X" => $ext, "S" => $size); -$r = $conn->request($r); -or_die($r); - -$r = $conn->send_file(\*F, $size); -or_die($r); - -print "Submitted OK.\n"; - -$conn->disconnect; -close F; diff --git a/submit/remote-submit.pl b/submit/remote-submit.pl new file mode 100755 index 0000000..c2e13a0 --- /dev/null +++ b/submit/remote-submit.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +BEGIN { + defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n"; +} +use lib $ENV{"MO_ROOT"} . "/submit"; +use lib $ENV{"MO_ROOT"} . "/lib/perl5"; + +use MO::Submit; +use Sherlock::Object; +use File::stat; + +@ARGV == 2 || @ARGV == 3 or die "Usage: remote-submit [] \n"; +my $task = $ARGV[0]; +my $part = $task; +if (@ARGV == 3) { + $part = $ARGV[1]; + shift @ARGV; +} +my $file = $ARGV[1]; +my ($ext) = ($file =~ /\.([^.]+)$/) or die "Unable to determine filename extension\n"; + +open F, $file or die "Unable to open $file: $!\n"; +my $s = stat(*F) or die; +my $size = $s->size; + +my $conn = new MO::Submit; + +my $he = $conn->write_history($task, $part, $ext, $file); +if (defined $he) { die "$he\n"; } + +$conn->connect or die $conn->{"error"} . "\n"; + +sub or_die($) { + my $r = shift @_; + if (!defined $r) { die $conn->{"error"} . "\n"; } + my $err = $r->get("-"); + if ($err) { die "$err\n"; } +} + +my $r = new Sherlock::Object("!" => "SUBMIT", "T" => $task, "P" => $part, "X" => $ext, "S" => $size); +$r = $conn->request($r); +or_die($r); + +$r = $conn->send_file(\*F, $size); +or_die($r); + +print "Submitted OK.\n"; + +$conn->disconnect; +close F; diff --git a/submit/show-submits b/submit/show-submits deleted file mode 100755 index ffc8aad..0000000 --- a/submit/show-submits +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl - -use lib "lib/perl5"; -use Sherlock::Object; - -foreach my $user (split /\s+/,`cd solutions && echo *`) { - print "$user:\t"; - if (open S, "solutions/$user/status") { - my @status = (); - my $s = new Sherlock::Object; - $s->read(\*S) or die "Cannot load status"; - foreach my $t ($s->getarray("(T")) { - my $task = $t->get("T"); - foreach my $p ($t->getarray("(P")) { - my $part = $p->get("P"); - my $ver = $p->get("V"); - my $name = $task . ($part eq $task ? "" : "/$part"); - push @status, "$name(v$ver)"; - } - } - close S; - print join(" ", @status), "\n"; - } else { - print "---\n"; - } -} diff --git a/submit/show-submits.pl b/submit/show-submits.pl new file mode 100755 index 0000000..ffc8aad --- /dev/null +++ b/submit/show-submits.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use lib "lib/perl5"; +use Sherlock::Object; + +foreach my $user (split /\s+/,`cd solutions && echo *`) { + print "$user:\t"; + if (open S, "solutions/$user/status") { + my @status = (); + my $s = new Sherlock::Object; + $s->read(\*S) or die "Cannot load status"; + foreach my $t ($s->getarray("(T")) { + my $task = $t->get("T"); + foreach my $p ($t->getarray("(P")) { + my $part = $p->get("P"); + my $ver = $p->get("V"); + my $name = $task . ($part eq $task ? "" : "/$part"); + push @status, "$name(v$ver)"; + } + } + close S; + print join(" ", @status), "\n"; + } else { + print "---\n"; + } +}