From 2b7a003794537ebf8e02f122cc2743834b47a396 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Thu, 13 Aug 2009 16:56:26 -0400 Subject: Add my CVS plugin and related patches. --- IkiWiki/Plugin/cvs.pm | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 IkiWiki/Plugin/cvs.pm (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm new file mode 100644 index 000000000..c09e4f9aa --- /dev/null +++ b/IkiWiki/Plugin/cvs.pm @@ -0,0 +1,423 @@ +#!/usr/pkg/bin/perl +package IkiWiki::Plugin::cvs; + +use warnings; +use strict; +use IkiWiki; + +sub import { + hook(type => "checkconfig", id => "cvs", call => \&checkconfig); + hook(type => "getsetup", id => "cvs", call => \&getsetup); + hook(type => "rcs", id => "rcs_update", call => \&rcs_update); + hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit); + hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit); + hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged); + hook(type => "rcs", id => "rcs_add", call => \&rcs_add); + hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove); + hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename); + hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges); + hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff); + hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); +} + +sub checkconfig () { + if (! defined $config{cvspath}) { + $config{cvspath}="ikiwiki"; + } + if (exists $config{cvspath}) { + # code depends on the path not having extraneous slashes + $config{cvspath}=~tr#/#/#s; + $config{cvspath}=~s/\/$//; + $config{cvspath}=~s/^\///; + } + if (defined $config{cvs_wrapper} && length $config{cvs_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{cvs_wrapper}, + wrappermode => (defined $config{cvs_wrappermode} ? $config{cvs_wrappermode} : "04755"), + }; + } +} + +sub getsetup () { + return + plugin => { + safe => 0, # rcs plugin + rebuild => undef, + }, + cvsrepo => { + type => "string", + example => "/cvs/wikirepo", + description => "cvs repository location", + safe => 0, # path + rebuild => 0, + }, + cvspath => { + type => "string", + example => "ikiwiki", + description => "path inside repository where the wiki is located", + safe => 0, # paranoia + rebuild => 0, + }, + cvs_wrapper => { + type => "string", + example => "/cvs/wikirepo/CVSROOT/post-commit", + description => "cvs post-commit hook to generate (triggered by CVSROOT/loginfo entry", + safe => 0, # file + rebuild => 0, + }, + cvs_wrappermode => { + type => "string", + example => '04755', + description => "mode for cvs_wrapper (can safely be made suid)", + safe => 0, + rebuild => 0, + }, + historyurl => { + type => "string", + example => "http://cvs.example.org/cvsweb.cgi/ikiwiki/[[file]]", + description => "cvsweb url to show file history ([[file]] substituted)", + safe => 1, + rebuild => 1, + }, + diffurl => { + type => "string", + example => "http://cvs.example.org/cvsweb.cgi/ikiwiki/[[file]].diff?r1=text&tr1=[[r1]]&r2=text&tr2=[[r2]]", + description => "cvsweb url to show a diff ([[file]], [[r1]], and [[r2]] substituted)", + safe => 1, + rebuild => 1, + }, +} + +sub cvs_info ($$) { + my $field=shift; + my $file=shift; + + chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); + + my $info=`cvs status $file`; + my ($ret)=$info=~/^\s*$field:\s*(\S+)/m; + return $ret; +} + +sub cvs_runcvs(@) { + my ($cmd) = @_; + unshift @$cmd, 'cvs', '-Q'; + + eval q{ + use IPC::Cmd; + }; + error($@) if $@; + + chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); + + debug("runcvs: " . join(" ", @$cmd)); + + my ($success, $error_code, $full_buf, $stdout_buf, $stderr_buf) = + IPC::Cmd::run(command => $cmd, verbose => 0); + if (! $success) { + warn(join(" ", @$cmd) . " exited with code $error_code\n"); + warn(join "", @$stderr_buf); + } + return $success; +} + +sub cvs_shquote_commit ($) { + my $message = shift; + + eval q{ + use String::ShellQuote; + }; + error($@) if $@; + + return shell_quote(IkiWiki::possibly_foolish_untaint($message)); +} + +sub cvs_is_controlling { + my $dir=shift; + $dir=$config{srcdir} unless defined($dir); + return (-d "$dir/CVS") ? 1 : 0; +} + +sub rcs_update () { + return unless cvs_is_controlling; + cvs_runcvs(['update', '-dP']); +} + +sub rcs_prepedit ($) { + # Prepares to edit a file under revision control. Returns a token + # that must be passed into rcs_commit when the file is ready + # for committing. + # The file is relative to the srcdir. + my $file=shift; + + return unless cvs_is_controlling; + + # For cvs, return the revision of the file when + # editing begins. + my $rev=cvs_info("Repository revision", "$file"); + return defined $rev ? $rev : ""; +} + +sub rcs_commit ($$$;$$) { + # Tries to commit the page; returns undef on _success_ and + # a version of the page with the rcs's conflict markers on failure. + # The file is relative to the srcdir. + my $file=shift; + my $message=shift; + my $rcstoken=shift; + my $user=shift; + my $ipaddr=shift; + + return unless cvs_is_controlling; + + if (defined $user) { + $message="web commit by $user".(length $message ? ": $message" : ""); + } + elsif (defined $ipaddr) { + $message="web commit from $ipaddr".(length $message ? ": $message" : ""); + } + + # Check to see if the page has been changed by someone + # else since rcs_prepedit was called. + my ($oldrev)=$rcstoken=~/^([0-9]+)$/; # untaint + my $rev=cvs_info("Repository revision", "$config{srcdir}/$file"); + if (defined $rev && defined $oldrev && $rev != $oldrev) { + # Merge their changes into the file that we've + # changed. + cvs_runcvs(['update', $file]) || + warn("cvs merge from $oldrev to $rev failed\n"); + } + + if (! cvs_runcvs(['commit', '-m', cvs_shquote_commit $message])) { + my $conflict=readfile("$config{srcdir}/$file"); + cvs_runcvs(['update', '-C', $file]) || + warn("cvs revert failed\n"); + return $conflict; + } + + return undef # success +} + +sub rcs_commit_staged ($$$) { + # Commits all staged changes. Changes can be staged using rcs_add, + # rcs_remove, and rcs_rename. + my ($message, $user, $ipaddr)=@_; + + if (defined $user) { + $message="web commit by $user".(length $message ? ": $message" : ""); + } + elsif (defined $ipaddr) { + $message="web commit from $ipaddr".(length $message ? ": $message" : ""); + } + + if (! cvs_runcvs(['commit', '-m', cvs_shquote_commit $message])) { + warn "cvs staged commit failed\n"; + return 1; # failure + } + return undef # success +} + +sub rcs_add ($) { + # filename is relative to the root of the srcdir + my $file=shift; + my $parent=IkiWiki::dirname($file); + my @files_to_add = ($file); + + until ((length($parent) == 0) || cvs_is_controlling("$config{srcdir}/$parent")){ + push @files_to_add, $parent; + $parent = IkiWiki::dirname($parent); + } + + while ($file = pop @files_to_add) { + cvs_runcvs(['add', $file]) || + warn("cvs add $file failed\n"); + } +} + +sub rcs_remove ($) { + # filename is relative to the root of the srcdir + my $file=shift; + + return unless cvs_is_controlling; + + cvs_runcvs(['rm', '-f', $file]) || + warn("cvs rm $file failed\n"); +} + +sub rcs_rename ($$) { + # filenames relative to the root of the srcdir + my ($src, $dest)=@_; + + return unless cvs_is_controlling; + + chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); + + if (system("mv", "$src", "$dest") != 0) { + warn("filesystem rename failed\n"); + } + + rcs_add($dest); + rcs_remove($src); +} + +sub rcs_recentchanges($) { + my $num = shift; + my @ret; + + return unless cvs_is_controlling; + + eval q{ + use Date::Parse; + }; + error($@) if $@; + + chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); + + open CVSPS, "env TZ=UTC cvsps -q --cvs-direct -z 30 -x |" || error "couldn't get cvsps output: $!\n"; + my @spsvc = reverse ; # is this great? no it is not + close CVSPS || error "couldn't close cvsps output: $!\n"; + + while (my $line = shift @spsvc) { + $line =~ /^$/ || error "expected blank line, got $line"; + + my ($rev, $user, $committype, $when); + my (@message, @pages); + + # We're reading backwards. + # Forwards, an entry looks like so: + # --------------------- + # PatchSet $rev + # Date: $when + # Author: $user (or user CGI runs as, for web commits) + # Branch: branch + # Tag: tag + # Log: + # @message_lines + # Members: + # @pages (and revisions) + # + + while ($line = shift @spsvc) { + last if ($line =~ /^Members:/); + for ($line) { + s/^\s+//; + s/\s+$//; + } + my ($page, $revs) = split(/:/, $line); + my ($oldrev, $newrev) = split(/->/, $revs); + $oldrev =~ s/INITIAL/0/; + $newrev =~ s/\(DEAD\)//; + my $diffurl = defined $config{diffurl} ? $config{diffurl} : ""; + $diffurl=~s/\[\[file\]\]/$page/g; + $diffurl=~s/\[\[r1\]\]/$oldrev/g; + $diffurl=~s/\[\[r2\]\]/$newrev/g; + unshift @pages, { + page => pagename($page), + diffurl => $diffurl, + } if length $page; + } + + while ($line = shift @spsvc) { + last if ($line =~ /^Log:$/); + chomp $line; + unshift @message, { line => $line }; + } + $committype = "web"; + if (defined $message[0] && + $message[0]->{line}=~/$config{web_commit_regexp}/) { + $user=defined $2 ? "$2" : "$3"; + $message[0]->{line}=$4; + } else { + $committype="cvs"; + } + + $line = shift @spsvc; # Tag + $line = shift @spsvc; # Branch + + $line = shift @spsvc; + if ($line =~ /^Author: (.*)$/) { + $user = $1 unless defined $user && length $user; + } else { + error "expected Author, got $line"; + } + + $line = shift @spsvc; + if ($line =~ /^Date: (.*)$/) { + $when = str2time($1, 'UTC'); + } else { + error "expected Date, got $line"; + } + + $line = shift @spsvc; + if ($line =~ /^PatchSet (.*)$/) { + $rev = $1; + } else { + error "expected PatchSet, got $line"; + } + + $line = shift @spsvc; # --------------------- + + push @ret, { + rev => $rev, + user => $user, + committype => $committype, + when => $when, + message => [@message], + pages => [@pages], + } if @pages; + return @ret if @ret >= $num; + } + + return @ret; +} + +sub rcs_diff ($) { + my $rev=IkiWiki::possibly_foolish_untaint(int(shift)); + + chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); + + # diff output is unavoidably preceded by the cvsps PatchSet entry + my @cvsps = `env TZ=UTC cvsps -q --cvs-direct -z 30 -g -s $rev`; + my $blank_lines_seen = 0; + + while (my $line = shift @cvsps) { + $blank_lines_seen++ if ($line =~ /^$/); + last if $blank_lines_seen == 2; + } + + if (wantarray) { + return @cvsps; + } else { + return join("", @cvsps); + } +} + +sub rcs_getctime ($) { + my $file=shift; + + my $cvs_log_infoline=qr/^date: (.+);\s+author/; + + open CVSLOG, "cvs -Q log -r1.1 '$file' |" + || error "couldn't get cvs log output: $!\n"; + + my $date; + while () { + if (/$cvs_log_infoline/) { + $date=$1; + } + } + close CVSLOG || warn "cvs log $file exited $?"; + + if (! defined $date) { + warn "failed to parse cvs log for $file\n"; + return 0; + } + + eval q{use Date::Parse}; + error($@) if $@; + $date=str2time($date, 'UTC'); + debug("found ctime ".localtime($date)." for $file"); + return $date; +} + +1 -- cgit v1.2.3 From 5c0e56d149c6b33d010561f64f583e7ad1c529da Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Fri, 21 Aug 2009 22:51:12 -0400 Subject: Put old unixauth plugin under git control. Needs some serious attention. --- IkiWiki/Plugin/unixauth.pm | 195 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 IkiWiki/Plugin/unixauth.pm (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/unixauth.pm b/IkiWiki/Plugin/unixauth.pm new file mode 100644 index 000000000..4f0cb4dd2 --- /dev/null +++ b/IkiWiki/Plugin/unixauth.pm @@ -0,0 +1,195 @@ +#!/usr/bin/perl +# Ikiwiki unixauth authentication. +package IkiWiki::Plugin::unixauth; + +use warnings; +use strict; +use IkiWiki 2.00; + +sub import { + hook(type => "getsetup", id => "unixauth", call => \&getsetup); + hook(type => "formbuilder_setup", id => "unixauth", + call => \&formbuilder_setup); + hook(type => "formbuilder", id => "unixauth", + call => \&formbuilder); + hook(type => "sessioncgi", id => "unixauth", call => \&sessioncgi); +} + +sub getsetup () { + return + unixauth_type => { + type => "string", + example => "checkpassword", + description => "type of authenticator; can be 'checkpassword' or 'pwauth'", + safe => 0, + rebuild => 1, + }, + unixauth_command => { + type => "string", + example => "/path/to/checkpassword", + description => "full path and any arguments", + safe => 0, + rebuild => 1, + }, + unixauth_requiressl => { + type => "boolean", + example => "1", + description => "require SSL? strongly recommended", + safe => 0, + rebuild => 1, + }, + plugin => { + description => "Unix user authentication", + safe => 0, + rebuild => 1, + }, +} + +# Checks if a string matches a user's password, and returns true or false. +sub checkpassword ($$;$) { + my $user=shift; + my $password=shift; + my $field=shift || "password"; + + # It's very important that the user not be allowed to log in with + # an empty password! + if (! length $password) { + return 0; + } + + my $ret=0; + if (! exists $config{unixauth_type}) { + # admin needs to carefully think over his configuration + return 0; + } + elsif ($config{unixauth_type} eq "checkpassword") { + open UNIXAUTH, "|$config{unixauth_command} true 3<&0" or die("Could not run $config{unixauth_type}"); + print UNIXAUTH "$user\0$password\0Y123456\0"; + close UNIXAUTH; + $ret=!($?>>8); + } + elsif ($config{unixauth_type} eq "pwauth") { + open UNIXAUTH, "|$config{unixauth_command}" or die("Could not run $config{unixauth_type}"); + print UNIXAUTH "$user\n$password\n"; + close UNIXAUTH; + $ret=!($?>>8); + } + else { + # no such authentication type + return 0; + } + + if ($ret) { + my $userinfo=IkiWiki::userinfo_retrieve(); + if (! length $user || ! defined $userinfo || + ! exists $userinfo->{$user} || ! ref $userinfo->{$user}) { + IkiWiki::userinfo_setall($user, { + 'email' => '', + 'regdate' => time, + }); + } + } + + return $ret; +} + +sub formbuilder_setup (@) { + my %params=@_; + + my $form=$params{form}; + my $session=$params{session}; + my $cgi=$params{cgi}; + + # if not under SSL, die before even showing a login form, + # unless the admin explicitly says it's fine + if (! exists $config{unixauth_requiressl}) { + $config{unixauth_requiressl} = 1; + } + if ($config{unixauth_requiressl}) { + if ((! $config{sslcookie}) || (! exists $ENV{'HTTPS'})) { + die("SSL required to login. Contact your administrator.
"); + } + } + + if ($form->title eq "signin") { + $form->field(name => "name", required => 0); + $form->field(name => "password", type => "password", required => 0); + + if ($form->submitted) { + my $submittype=$form->submitted; + # Set required fields based on how form was submitted. + my %required=( + "Login" => [qw(name password)], + ); + foreach my $opt (@{$required{$submittype}}) { + $form->field(name => $opt, required => 1); + } + + # Validate password against name for Login. + if ($submittype eq "Login") { + $form->field( + name => "password", + validate => sub { + checkpassword($form->field("name"), shift); + }, + ); + } + + # XXX is this reachable? looks like no + elsif ($submittype eq "Login") { + $form->field( + name => "name", + validate => sub { + my $name=shift; + length $name && + IkiWiki::userinfo_get($name, "regdate"); + }, + ); + } + } + else { + # First time settings. + $form->field(name => "name"); + if ($session->param("name")) { + $form->field(name => "name", value => $session->param("name")); + } + } + } + elsif ($form->title eq "preferences") { + $form->field(name => "name", disabled => 1, + value => $session->param("name"), force => 1, + fieldset => "login"); + $form->field(name => "password", disabled => 1, type => "password", + fieldset => "login"), + } +} + +sub formbuilder (@) { + my %params=@_; + + my $form=$params{form}; + my $session=$params{session}; + my $cgi=$params{cgi}; + my $buttons=$params{buttons}; + + if ($form->title eq "signin") { + if ($form->submitted && $form->validate) { + if ($form->submitted eq 'Login') { + $session->param("name", $form->field("name")); + IkiWiki::cgi_postsignin($cgi, $session); + } + } + } + elsif ($form->title eq "preferences") { + if ($form->submitted eq "Save Preferences" && $form->validate) { + my $user_name=$form->field('name'); + } + } +} + +sub sessioncgi ($$) { + my $q=shift; + my $session=shift; +} + +1 -- cgit v1.2.3 From 524de4db2639d37aa7049de4363c5d482cd34a0e Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sat, 22 Aug 2009 01:25:41 -0400 Subject: Pass along wrapper args to ikiwiki, then handle the "cvs add dir" case with a getopt hook directly in my plugin. If the wrapper change is safe, we won't need a wrapper wrapper. --- IkiWiki/Plugin/cvs.pm | 8 ++++++++ IkiWiki/Wrapper.pm | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index c09e4f9aa..076af26f3 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -6,6 +6,7 @@ use strict; use IkiWiki; sub import { + hook(type => "getopt", id => "cvs", call => \&getopt); hook(type => "checkconfig", id => "cvs", call => \&checkconfig); hook(type => "getsetup", id => "cvs", call => \&getsetup); hook(type => "rcs", id => "rcs_update", call => \&rcs_update); @@ -20,6 +21,13 @@ sub import { hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); } +sub getopt () { + # "cvs add dir" acts immediately on the repository. + # post-commit gets confused by this and doesn't need to act on it. + # If that's why we're here, terminate the process. + @ARGV == 3 && $ARGV[1] eq "NONE" && $ARGV[2] eq "NONE" && exit 0; +} + sub checkconfig () { if (! defined $config{cvspath}) { $config{cvspath}="ikiwiki"; diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm index 6555fe625..4d92716ff 100644 --- a/IkiWiki/Wrapper.pm +++ b/IkiWiki/Wrapper.pm @@ -139,7 +139,7 @@ $envsave } $pre_exec - execl("$this", "$this", NULL); + execv("$this", argv); perror("exec $this"); exit(1); } -- cgit v1.2.3 From 5bdcd4d57b2ca5dbf6e3d46a693cec4d27512020 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sat, 22 Aug 2009 02:22:36 -0400 Subject: Oops, use the more recent (and less brittle) directory test. --- IkiWiki/Plugin/cvs.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index 076af26f3..ac188d4a1 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -25,7 +25,7 @@ sub getopt () { # "cvs add dir" acts immediately on the repository. # post-commit gets confused by this and doesn't need to act on it. # If that's why we're here, terminate the process. - @ARGV == 3 && $ARGV[1] eq "NONE" && $ARGV[2] eq "NONE" && exit 0; + ((grep /New directory/, @ARGV) > 0) && exit 0; } sub checkconfig () { -- cgit v1.2.3 From 3d6bc6e1b7145d85cd9495fd0a0d0a6823869368 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 23 Aug 2009 15:18:41 -0400 Subject: Add rsync plugin, though the only rsync-specific thing about it is the assumption that uploading an entire site is efficient. --- IkiWiki/Plugin/rsync.pm | 47 +++++++++++++++++++++++++++++++++++++++++++++++ IkiWiki/Render.pm | 1 + 2 files changed, 48 insertions(+) create mode 100644 IkiWiki/Plugin/rsync.pm (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/rsync.pm b/IkiWiki/Plugin/rsync.pm new file mode 100644 index 000000000..630469528 --- /dev/null +++ b/IkiWiki/Plugin/rsync.pm @@ -0,0 +1,47 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::rsync; + +use warnings; +no warnings 'redefine'; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "rsync", call => \&getsetup); + hook(type => "checkconfig", id => "rsync", call => \&checkconfig); + hook(type => "postrefresh", id => "rsync", call => \&postrefresh); +} + +sub getsetup () { + return + plugin => { + safe => 0, + rebuild => 0, + }, + rsync_command => { + type => "string", + example => "rsync -qa --delete /path/to/destdir/ user\@host:/path/to/docroot/", + description => "command to upload regenerated pages to another host", + safe => 0, + rebuild => 0, + }, +} + +sub checkconfig { + if (! exists $config{rsync_command} || + ! defined $config{rsync_command}) { + error("Must specify rsync_command"); + } +} + +sub postrefresh () { + debug "in postrefresh hook, gonna run rsync"; + system $config{rsync_command}; + if ($? == -1) { + error("failed to execute rsync_command: $!"); + } elsif ($? != 0) { + error(sprintf("rsync_command exited %d", $? >> 8)); + } +} + +1 diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index fc8f287ce..74033fa97 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -524,6 +524,7 @@ sub refresh () { if (%rendered) { run_hooks(change => sub { shift->(keys %rendered) }); } + run_hooks(postrefresh => sub { shift->() }); } sub commandline_render () { -- cgit v1.2.3 From 844169c9b06830df33ccde8abead015128baa496 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 23 Aug 2009 15:21:39 -0400 Subject: I'm not redefining any subs after all, don't prevent those warnings. --- IkiWiki/Plugin/rsync.pm | 1 - 1 file changed, 1 deletion(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/rsync.pm b/IkiWiki/Plugin/rsync.pm index 630469528..62ecc4e38 100644 --- a/IkiWiki/Plugin/rsync.pm +++ b/IkiWiki/Plugin/rsync.pm @@ -2,7 +2,6 @@ package IkiWiki::Plugin::rsync; use warnings; -no warnings 'redefine'; use strict; use IkiWiki 3.00; -- cgit v1.2.3 From 607534cecc7ab1bfefd1df1bfe19e4d7c338029b Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 23 Aug 2009 15:43:18 -0400 Subject: Explain that command must run unattended, and lose the debug statement. --- IkiWiki/Plugin/rsync.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/rsync.pm b/IkiWiki/Plugin/rsync.pm index 62ecc4e38..3f049457b 100644 --- a/IkiWiki/Plugin/rsync.pm +++ b/IkiWiki/Plugin/rsync.pm @@ -20,7 +20,7 @@ sub getsetup () { rsync_command => { type => "string", example => "rsync -qa --delete /path/to/destdir/ user\@host:/path/to/docroot/", - description => "command to upload regenerated pages to another host", + description => "unattended command to upload regenerated pages", safe => 0, rebuild => 0, }, @@ -34,7 +34,6 @@ sub checkconfig { } sub postrefresh () { - debug "in postrefresh hook, gonna run rsync"; system $config{rsync_command}; if ($? == -1) { error("failed to execute rsync_command: $!"); -- cgit v1.2.3 From 6191f3fbb9e0189276f84e15b9582fbd352b7a9b Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sat, 29 Aug 2009 21:35:54 -0400 Subject: Remove getopt() hook (it's a dead end, unsafe to pass wrapper args to ikiwiki). Crunch on-demand module loads into one-liners. Comment why cvsps output is getting read in its entirety and reversed. --- IkiWiki/Plugin/cvs.pm | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index ac188d4a1..20b9f793a 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -6,7 +6,6 @@ use strict; use IkiWiki; sub import { - hook(type => "getopt", id => "cvs", call => \&getopt); hook(type => "checkconfig", id => "cvs", call => \&checkconfig); hook(type => "getsetup", id => "cvs", call => \&getsetup); hook(type => "rcs", id => "rcs_update", call => \&rcs_update); @@ -21,13 +20,6 @@ sub import { hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); } -sub getopt () { - # "cvs add dir" acts immediately on the repository. - # post-commit gets confused by this and doesn't need to act on it. - # If that's why we're here, terminate the process. - ((grep /New directory/, @ARGV) > 0) && exit 0; -} - sub checkconfig () { if (! defined $config{cvspath}) { $config{cvspath}="ikiwiki"; @@ -111,9 +103,7 @@ sub cvs_runcvs(@) { my ($cmd) = @_; unshift @$cmd, 'cvs', '-Q'; - eval q{ - use IPC::Cmd; - }; + eval q{use IPC::Cmd}; error($@) if $@; chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); @@ -132,9 +122,7 @@ sub cvs_runcvs(@) { sub cvs_shquote_commit ($) { my $message = shift; - eval q{ - use String::ShellQuote; - }; + eval q{use String::ShellQuote}; error($@) if $@; return shell_quote(IkiWiki::possibly_foolish_untaint($message)); @@ -274,13 +262,12 @@ sub rcs_recentchanges($) { return unless cvs_is_controlling; - eval q{ - use Date::Parse; - }; + eval q{use Date::Parse}; error($@) if $@; chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); + # there's no option to get the last N changesets, so read backwards open CVSPS, "env TZ=UTC cvsps -q --cvs-direct -z 30 -x |" || error "couldn't get cvsps output: $!\n"; my @spsvc = reverse ; # is this great? no it is not close CVSPS || error "couldn't close cvsps output: $!\n"; -- cgit v1.2.3 From b493f9b6d8e2131dd2338da05d98fded592d0943 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 00:17:42 -0400 Subject: Knock off a to-do item: "If the argument to cvs add smells like a binary file, cvs add -kb it (for attachment support)." --- IkiWiki/Plugin/cvs.pm | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index 20b9f793a..ccd9527cd 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -219,14 +219,25 @@ sub rcs_add ($) { my $parent=IkiWiki::dirname($file); my @files_to_add = ($file); + eval q{use File::MimeInfo}; + error($@) if $@; + until ((length($parent) == 0) || cvs_is_controlling("$config{srcdir}/$parent")){ push @files_to_add, $parent; $parent = IkiWiki::dirname($parent); } while ($file = pop @files_to_add) { - cvs_runcvs(['add', $file]) || - warn("cvs add $file failed\n"); + if ((@files_to_add == 0) && + (File::MimeInfo::default $file ne 'text/plain')) { + # it's a binary file, add specially + cvs_runcvs(['add', '-kb', $file]) || + warn("cvs add $file failed\n"); + } else { + # directory or regular file + cvs_runcvs(['add', $file]) || + warn("cvs add $file failed\n"); + } } } -- cgit v1.2.3 From 2d1ff30e13d91cc4fa355bc392ba6044c6a6f31e Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 01:14:22 -0400 Subject: Knock off another to-do item: "Don't slurp the entire cvsps output into memory (!)." --- IkiWiki/Plugin/cvs.pm | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index ccd9527cd..c1b40bda1 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -278,12 +278,26 @@ sub rcs_recentchanges($) { chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); - # there's no option to get the last N changesets, so read backwards - open CVSPS, "env TZ=UTC cvsps -q --cvs-direct -z 30 -x |" || error "couldn't get cvsps output: $!\n"; - my @spsvc = reverse ; # is this great? no it is not - close CVSPS || error "couldn't close cvsps output: $!\n"; + # There's no cvsps option to get the last N changesets. + # Write full output to a temp file and read backwards. - while (my $line = shift @spsvc) { + eval q{use File::Temp qw/tempfile/}; + error($@) if $@; + eval q{use File::ReadBackwards}; + error($@) if $@; + + my (undef, $tmpfile) = tempfile(OPEN=>0); + system("env TZ=UTC cvsps -q --cvs-direct -z 30 -x >$tmpfile"); + if ($? == -1) { + error "couldn't run cvsps: $!\n"; + } elsif (($? >>8) != 0) { + error "cvsps exited " . ($? >> 8) . ": $!\n"; + } + + tie(*SPSVC, 'File::ReadBackwards', $tmpfile) + || error "couldn't open $tmpfile for read: $!\n"; + + while (my $line = ) { $line =~ /^$/ || error "expected blank line, got $line"; my ($rev, $user, $committype, $when); @@ -303,7 +317,7 @@ sub rcs_recentchanges($) { # @pages (and revisions) # - while ($line = shift @spsvc) { + while ($line = ) { last if ($line =~ /^Members:/); for ($line) { s/^\s+//; @@ -323,7 +337,7 @@ sub rcs_recentchanges($) { } if length $page; } - while ($line = shift @spsvc) { + while ($line = ) { last if ($line =~ /^Log:$/); chomp $line; unshift @message, { line => $line }; @@ -337,31 +351,31 @@ sub rcs_recentchanges($) { $committype="cvs"; } - $line = shift @spsvc; # Tag - $line = shift @spsvc; # Branch + $line = ; # Tag + $line = ; # Branch - $line = shift @spsvc; + $line = ; if ($line =~ /^Author: (.*)$/) { $user = $1 unless defined $user && length $user; } else { error "expected Author, got $line"; } - $line = shift @spsvc; + $line = ; if ($line =~ /^Date: (.*)$/) { $when = str2time($1, 'UTC'); } else { error "expected Date, got $line"; } - $line = shift @spsvc; + $line = ; if ($line =~ /^PatchSet (.*)$/) { $rev = $1; } else { error "expected PatchSet, got $line"; } - $line = shift @spsvc; # --------------------- + $line = ; # --------------------- push @ret, { rev => $rev, @@ -371,9 +385,11 @@ sub rcs_recentchanges($) { message => [@message], pages => [@pages], } if @pages; - return @ret if @ret >= $num; + last if @ret >= $num; } + unlink($tmpfile) || error "couldn't unlink $tmpfile: $!\n"; + return @ret; } -- cgit v1.2.3 From 968c6c93b4cfdb0b13609d90f058e6c4d005c75d Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 01:45:09 -0400 Subject: Remove debug statement. --- IkiWiki/Plugin/cvs.pm | 2 -- 1 file changed, 2 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index c1b40bda1..66e9463be 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -108,8 +108,6 @@ sub cvs_runcvs(@) { chdir $config{srcdir} || error("Cannot chdir to $config{srcdir}: $!"); - debug("runcvs: " . join(" ", @$cmd)); - my ($success, $error_code, $full_buf, $stdout_buf, $stderr_buf) = IPC::Cmd::run(command => $cmd, verbose => 0); if (! $success) { -- cgit v1.2.3 From e972cadf78ba511af33ba19d40c5b6156569120d Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 13:49:38 -0400 Subject: Fix uninitialized value when editing a page being vivified from the basewiki. Makes the filetype-testing logic more explicit anyway. --- IkiWiki/Plugin/cvs.pm | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index 66e9463be..fa4c4da8e 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -226,13 +226,18 @@ sub rcs_add ($) { } while ($file = pop @files_to_add) { - if ((@files_to_add == 0) && - (File::MimeInfo::default $file ne 'text/plain')) { - # it's a binary file, add specially - cvs_runcvs(['add', '-kb', $file]) || - warn("cvs add $file failed\n"); + if (@files_to_add == 0) { + # file + my $filemime = File::MimeInfo::default($file); + if (defined($filemime) && $filemime eq 'text/plain') { + cvs_runcvs(['add', $file]) || + warn("cvs add $file failed\n"); + } else { + cvs_runcvs(['add', '-kb', $file]) || + warn("cvs add binary $file failed\n"); + } } else { - # directory or regular file + # directory cvs_runcvs(['add', $file]) || warn("cvs add $file failed\n"); } -- cgit v1.2.3 From 1af7d7d8429b6e73493a5f8ba877c6cfb888cfe1 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 16:13:17 -0400 Subject: On some systems the commit message gets quoted properly already. Don't requote in such cases, do quote in all others. --- IkiWiki/Plugin/cvs.pm | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index fa4c4da8e..849302df4 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -119,11 +119,21 @@ sub cvs_runcvs(@) { sub cvs_shquote_commit ($) { my $message = shift; + my $test_message = "CVS autodiscover quoting CVS"; eval q{use String::ShellQuote}; error($@) if $@; + eval q{use IPC::Cmd}; + error($@) if $@; - return shell_quote(IkiWiki::possibly_foolish_untaint($message)); + my $cmd = ['echo', shell_quote($test_message)]; + my ($success, $error_code, $full_buf, $stdout_buf, $stderr_buf) = + IPC::Cmd::run(command => $cmd, verbose => 0); + if ((grep /'$test_message'/, @$stdout_buf) > 0) { + return IkiWiki::possibly_foolish_untaint($message); + } else { + return shell_quote(IkiWiki::possibly_foolish_untaint($message)); + } } sub cvs_is_controlling { -- cgit v1.2.3 From 85844b8494dd5e032d06afd623c25b4bb4a72578 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 21:03:18 -0400 Subject: whitespace --- IkiWiki/Plugin/cvs.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index 849302df4..4735c0138 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -303,7 +303,7 @@ sub rcs_recentchanges($) { system("env TZ=UTC cvsps -q --cvs-direct -z 30 -x >$tmpfile"); if ($? == -1) { error "couldn't run cvsps: $!\n"; - } elsif (($? >>8) != 0) { + } elsif (($? >> 8) != 0) { error "cvsps exited " . ($? >> 8) . ": $!\n"; } -- cgit v1.2.3