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.pm | 2 +- IkiWiki/Plugin/cvs.pm | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++ ikiwiki-makerepo | 52 ++++++- t/file_pruned.t | 5 +- 4 files changed, 479 insertions(+), 3 deletions(-) create mode 100644 IkiWiki/Plugin/cvs.pm diff --git a/IkiWiki.pm b/IkiWiki.pm index a11b330f2..2355c0780 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -329,7 +329,7 @@ sub getsetup () { qr/\.x?html?$/, qr/\.ikiwiki-new$/, qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//, qr/(^|\/)_MTN\//, qr/(^|\/)_darcs\//, - qr/\.dpkg-tmp$/], + qr/(^|\/)CVS\//, qr/\.dpkg-tmp$/], description => "regexps of source files to ignore", safe => 0, rebuild => 1, 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 diff --git a/ikiwiki-makerepo b/ikiwiki-makerepo index 7f82e7177..bf33a3a80 100755 --- a/ikiwiki-makerepo +++ b/ikiwiki-makerepo @@ -6,7 +6,7 @@ srcdir="$2" repository="$3" usage () { - echo "usage: ikiwiki-makerepo svn|git|monotone|darcs srcdir repository" >&2 + echo "usage: ikiwiki-makerepo cvs|svn|git|monotone|darcs srcdir repository" >&2 echo " ikiwiki-makerepo bzr|mercurial srcdir" >&2 exit 1 } @@ -39,6 +39,56 @@ fi echo "Importing $srcdir into $rcs" case "$rcs" in +cvs) + if [ -e "$srcdir/CVS" ]; then + echo "$srcdir already seems to be a cvs working copy" >&2 + exit 1 + fi + cvs -Q -d "$repository" init + cat > "$repository/CVSROOT/post-commit-wrapper" </dev/null 2>&1 +} + +main() { + exists_ikiwiki_post_commit_hook || exit 0 + called_with_exactly_one_dir "\$@" && exit 0 + # Return from commit and relinquish write lock. ikiwiki post-commit + # wants to "cvs update", which wants to take a read lock. + \$IKIWIKI_POST_COMMIT_HOOK & + return 0 +} + +main "\$@" +exit \$? +EOF + chmod +x "$repository/CVSROOT/post-commit-wrapper" + cd "$srcdir"/.. + cvs -Q -d "$repository" get -P CVSROOT + cd CVSROOT + echo .ikiwiki >> cvsignore + cvs -Q add cvsignore + echo "^ikiwiki $repository/CVSROOT/post-commit-wrapper %{sVv}" >> loginfo + cvs -Q commit -m "ikiwiki-makerepo setup" cvsignore loginfo + cd .. + rm -rf CVSROOT + cd "$srcdir" + cvs -Q -d "$repository" import -m "initial import" ikiwiki IKIWIKI PRE_CVS + cd .. + mv "$srcdir" "$srcdir.orig" + cvs -Q -d "$repository" get -P -d "$(basename "$srcdir")" ikiwiki + [ -d "$srcdir.orig/.ikiwiki" ] && mv "$srcdir.orig/.ikiwiki" "$srcdir" + rm -rf "$srcdir.orig" + echo "Directory $srcdir is now a checkout of $rcs repository $repository" +;; svn) if [ -e "$srcdir/.svn" ]; then echo "$srcdir already seems to be a svn working copy" >&2 diff --git a/t/file_pruned.t b/t/file_pruned.t index 7d46c4b7f..a05ad548f 100755 --- a/t/file_pruned.t +++ b/t/file_pruned.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 24; +use Test::More tests => 27; BEGIN { use_ok("IkiWiki"); } @@ -9,6 +9,9 @@ BEGIN { use_ok("IkiWiki"); } ok(IkiWiki::file_pruned("src/.ikiwiki/", "src")); ok(IkiWiki::file_pruned("src/.ikiwiki/index", "src")); +ok(IkiWiki::file_pruned("src/CVS", "src")); +ok(IkiWiki::file_pruned("src/subdir/CVS", "src")); +ok(IkiWiki::file_pruned("src/subdir/CVS/foo", "src")); ok(IkiWiki::file_pruned("src/.svn", "src")); ok(IkiWiki::file_pruned("src/subdir/.svn", "src")); ok(IkiWiki::file_pruned("src/subdir/.svn/foo", "src")); -- cgit v1.2.3 From b137edd0e7aebe47b771a4dffcb4d1c68b59b530 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Thu, 13 Aug 2009 17:53:07 -0400 Subject: Life is simpler on a git branch. --- doc/plugins/contrib/cvs.mdwn | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/doc/plugins/contrib/cvs.mdwn b/doc/plugins/contrib/cvs.mdwn index f466b9399..23e00201f 100644 --- a/doc/plugins/contrib/cvs.mdwn +++ b/doc/plugins/contrib/cvs.mdwn @@ -1,14 +1,11 @@ [[!template id=plugin name=cvs core=0 author="[[schmonz]]"]] +[[!template id=gitbranch branch=schmonz author="[[schmonz]]"]] + This plugin allows ikiwiki to use [[!wikipedia desc="CVS" Concurrent Versions System]] as an [[rcs]]. -### Installation and usage -7. Apply patches to [`IkiWiki.pm`](http://www.netbsd.org/~schmonz/ikiwiki-cvs/cvs-IkiWiki.pm.diff) -and [`ikiwiki-makerepo`](http://www.netbsd.org/~schmonz/ikiwiki-cvs/cvs-ikiwiki-makerepo.diff). -7. Rebuild and install ikiwiki. +### Usage 7. Install [cvsps](http://www.cobite.com/cvsps/), [[!cpan IPC::Cmd]], [[!cpan String::ShellQuote]], and [cvsweb](http://www.freebsd.org/projects/cvsweb.html) or the like. -7. Download [`cvs.pm`](http://www.netbsd.org/~schmonz/ikiwiki-cvs/cvs.pm) into a suitable `$libdir/IkiWiki/Plugin`. -7. While setting up a wiki [[by hand|setup/byhand]], also specify `--libdir` until you get to the point where you have a setup file. (This ensures the CVS plugin is found and its settings stanza included.) 7. Adjust CVS-related parameters in your setup file. Consider creating `$HOME/.cvsrc` if you don't have one already; the plugin doesn't need it, but you yourself might. Here's a good general-purpose one: @@ -20,7 +17,7 @@ Consider creating `$HOME/.cvsrc` if you don't have one already; the plugin doesn rdiff -u ### Implementation details -* Diffs are against [[3.14159|news/version_3.14159]]. `cvs.pm` started life as a copy of `svn.pm`. +* `cvs.pm` started life as a copy of [[3.14159|news/version_3.14159]]'s `svn.pm`. * `IkiWiki.pm:wiki_file_prune_regexps` avoids copying CVS metadata into `$DESTDIR`. * [[ikiwiki-makerepo]]: * creates a repository, @@ -30,7 +27,7 @@ Consider creating `$HOME/.cvsrc` if you don't have one already; the plugin doesn * CVS multi-directory commits happen separately; the post-commit hook sees only the first directory's changes in time for [[recentchanges|plugins/recentchanges]]. The next run of `ikiwiki --setup` will correctly re-render such a recentchanges entry. It should be possible to solve this problem with NetBSD's `commit_prep` and `log_accum` scripts (see below). ### To do -* Add automated tests. ([Blindly adding svn-like tests to `t/file_pruned.t`](http://www.netbsd.org/~schmonz/ikiwiki-cvs/cvs-t-file_pruned.t.diff) doesn't do the trick.) +* Add automated tests. (Blindly adding svn-like tests to `t/file_pruned.t` doesn't do the trick.) * If the argument to `cvs add` smells like a binary file, `cvs add -kb` it (for [[plugins/attachment]] support). * Don't slurp the entire `cvsps` output into memory (!). * Instead of resource-intensively scraping changesets with `cvsps`, have `ikiwiki-makerepo` set up NetBSD-like `log_accum` and `commit_prep` scripts that coalesce and keep records of commits. `cvsps` can be used as a fallback for repositories without such records. -- cgit v1.2.3 From 68d9d7d7cb0063209db07da13bc78a1bd0fd37b6 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Fri, 14 Aug 2009 17:43:12 -0400 Subject: switched my DreamHost install to pkgsrc, happily --- doc/tips/DreamHost/discussion.mdwn | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/tips/DreamHost/discussion.mdwn b/doc/tips/DreamHost/discussion.mdwn index 74f48938e..258d385ae 100644 --- a/doc/tips/DreamHost/discussion.mdwn +++ b/doc/tips/DreamHost/discussion.mdwn @@ -3,3 +3,16 @@ I managed to install ikiwiki on eggplant farms, with most basic features except I think ikiwiki is more suitable for VPS/dedicated server. Shared hosting doesn't fit. I just (2009/04/27) installed ikiwiki on DreamHost and the CPAN instructions here are unnecessarily complicated. I used "cpan" instead of "perl -MCPAN -e shell" and had no trouble with that portion of the install. --[[schmonz]] + +After tiring of managing things by hand, I've switched to using +pkgsrc as an unprivileged user. This uses a bit more disk for my +own copies of perl, python, etc., but in exchange I can `cd +.../pkgsrc/www/ikiwiki && make install` and everything just works. +Plus I get all the benefits of a package system, like easy uninstalling +and being notified of outdated or insecure software. + +The only catch: sometimes the package dependency tree gets too deep +for DreamHost's user process limit, resulting in build death. I +work around this by resuming the build partway down the tree, then +trying again from whatever I was actually trying to install. +--[[schmonz]] -- 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 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(-) 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 8f15311597c257eca37c1f20769b80ef8f6c82c0 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sat, 22 Aug 2009 02:05:59 -0400 Subject: No more wrapper wrapper. --- ikiwiki-makerepo | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/ikiwiki-makerepo b/ikiwiki-makerepo index bf33a3a80..aca8da153 100755 --- a/ikiwiki-makerepo +++ b/ikiwiki-makerepo @@ -45,38 +45,12 @@ cvs) exit 1 fi cvs -Q -d "$repository" init - cat > "$repository/CVSROOT/post-commit-wrapper" </dev/null 2>&1 -} - -main() { - exists_ikiwiki_post_commit_hook || exit 0 - called_with_exactly_one_dir "\$@" && exit 0 - # Return from commit and relinquish write lock. ikiwiki post-commit - # wants to "cvs update", which wants to take a read lock. - \$IKIWIKI_POST_COMMIT_HOOK & - return 0 -} - -main "\$@" -exit \$? -EOF - chmod +x "$repository/CVSROOT/post-commit-wrapper" cd "$srcdir"/.. cvs -Q -d "$repository" get -P CVSROOT cd CVSROOT echo .ikiwiki >> cvsignore cvs -Q add cvsignore - echo "^ikiwiki $repository/CVSROOT/post-commit-wrapper %{sVv}" >> loginfo + echo "^ikiwiki $repository/CVSROOT/post-commit %{sVv} &" >> loginfo cvs -Q commit -m "ikiwiki-makerepo setup" cvsignore loginfo cd .. rm -rf CVSROOT -- 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(-) 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 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(-) 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(-) 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 5da229aa51adcec27b109ebe2e696f7426cbd781 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 23 Aug 2009 18:25:02 -0400 Subject: Instead of passing the args through the wrapper so the CVS plugin can evaluate them, check them in the wrapper right off the bat. This doesn't prevent the deadlock in web commits that need to cvs add directories, but I'm committing so Joey can take a look if he wants. --- IkiWiki/Wrapper.pm | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm index 4d92716ff..2354717c3 100644 --- a/IkiWiki/Wrapper.pm +++ b/IkiWiki/Wrapper.pm @@ -44,6 +44,17 @@ EOF $test_receive=IkiWiki::Receive::gen_wrapper(); } + my $check_cvs_add_dir=""; + # XXX conditionalize on $config{rcs} eq 'cvs' + $check_cvs_add_dir=<<"EOF"; + { + int j; + for (j = 1; j < argc; j++) + if (strcmp(argv[j], "New directory") == 0) + exit(0); + } +EOF + my $check_commit_hook=""; my $pre_exec=""; if ($config{post_commit}) { @@ -119,6 +130,7 @@ addenv(char *var, char *val) { int main (int argc, char **argv) { char *s; +$check_cvs_add_dir $check_commit_hook $test_receive $envsave @@ -139,7 +151,7 @@ $envsave } $pre_exec - execv("$this", argv); + execl("$this", "$this", NULL); perror("exec $this"); exit(1); } -- 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(-) 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 992d0aac09a3e3e81d7ad999910a4a026984f804 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 00:05:23 -0400 Subject: The string to match might not be "New directory" exactly, so match that substring instead. --- IkiWiki/Wrapper.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm index 2354717c3..87c2ffc89 100644 --- a/IkiWiki/Wrapper.pm +++ b/IkiWiki/Wrapper.pm @@ -50,7 +50,7 @@ EOF { int j; for (j = 1; j < argc; j++) - if (strcmp(argv[j], "New directory") == 0) + if (strstr(argv[j], "New directory") != NULL) exit(0); } EOF -- 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(-) 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(-) 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(-) 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 5e94e973eeb4ba75d9c37bd801278f686f0977c3 Mon Sep 17 00:00:00 2001 From: Amitai Schlair Date: Sun, 30 Aug 2009 02:00:49 -0400 Subject: Only examine argv if the VCS is cvs. --- IkiWiki/Wrapper.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm index 87c2ffc89..cc2223d7a 100644 --- a/IkiWiki/Wrapper.pm +++ b/IkiWiki/Wrapper.pm @@ -45,8 +45,8 @@ EOF } my $check_cvs_add_dir=""; - # XXX conditionalize on $config{rcs} eq 'cvs' - $check_cvs_add_dir=<<"EOF"; + if ($config{rcs} eq 'cvs') { + $check_cvs_add_dir=<<"EOF"; { int j; for (j = 1; j < argc; j++) @@ -54,6 +54,7 @@ EOF exit(0); } EOF + } my $check_commit_hook=""; my $pre_exec=""; -- 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(-) 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(-) 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(-) 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