Util.pm: new filedb_atomic_grep function
[girocco.git] / Girocco / Util.pm
blobbada93598e977148133e5d5d7f7501fac290ba44
1 package Girocco::Util;
3 use strict;
4 use warnings;
6 use Girocco::Config;
8 BEGIN {
9 use base qw(Exporter);
10 our @EXPORT = qw(scrypt jailed_file
11 lock_file unlock_file
12 filedb_atomic_append filedb_atomic_edit filedb_atomic_grep
13 valid_email valid_email_multi
14 valid_repo_url valid_web_url);
18 sub scrypt {
19 my ($pwd) = @_;
20 crypt($pwd||'', join ('', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));
23 sub jailed_file {
24 my ($filename) = @_;
25 $filename =~ s,^/,,;
26 $Girocco::Config::chroot."/$filename";
29 sub lock_file {
30 my ($path) = @_;
32 $path .= '.lock';
34 use Errno qw(EEXIST);
35 use Fcntl qw(O_WRONLY O_CREAT O_EXCL);
36 use IO::Handle;
37 my $handle = new IO::Handle;
39 unless (sysopen($handle, $path, O_WRONLY|O_CREAT|O_EXCL)) {
40 my $cnt = 0;
41 while (not sysopen($handle, $path, O_WRONLY|O_CREAT|O_EXCL)) {
42 ($! == EEXIST) or die "$path open failed: $!";
43 ($cnt++ < 16) or die "$path open failed: cannot open lockfile";
44 sleep(1);
47 # XXX: filedb-specific
48 chmod 0664, $path or die "$path g+w failed: $!";
50 $handle;
53 sub unlock_file {
54 my ($path, $noreplace) = @_;
56 if (!$noreplace) {
57 rename "$path.lock", $path or die "$path unlock failed: $!";
58 } else {
59 unlink "$path.lock" or die "$path unlock failed: $!";
63 sub filedb_atomic_append {
64 my ($file, $line) = @_;
65 my $id = 65536;
67 open my $src, $file or die "$file open for reading failed: $!";
68 my $dst = lock_file($file);
70 while (<$src>) {
71 my $aid = (split /:/)[2];
72 $id = $aid + 1 if ($aid >= $id);
74 print $dst $_ or die "$file(l) write failed: $!";
77 $line =~ s/\\i/$id/g;
78 print $dst "$line\n" or die "$file(l) write failed: $!";
80 close $dst or die "$file(l) close failed: $!";
81 close $src;
83 unlock_file($file);
85 $id;
88 sub filedb_atomic_edit {
89 my ($file, $fn) = @_;
91 open my $src, $file or die "$file open for reading failed: $!";
92 my $dst = lock_file($file);
94 while (<$src>) {
95 print $dst $fn->($_) or die "$file(l) write failed: $!";
98 close $dst or die "$file(l) close failed: $!";
99 close $src;
101 unlock_file($file);
104 sub filedb_atomic_grep {
105 my ($file, $fn) = @_;
106 my @results = ();
108 open my $src, $file or die "$file open for reading failed: $!";
109 my $dst = lock_file($file);
111 while (<$src>) {
112 my $result = $fn->($_);
113 push(@results, $result) if $result;
116 close $dst or die "$file(l) close failed: $!";
117 close $src;
119 unlock_file($file, 1);
120 return @results;
123 sub valid_email {
124 $_ = $_[0];
125 /^[a-zA-Z0-9+._-]+@[a-zA-Z0-9.-]+$/;
127 sub valid_email_multi {
128 $_ = $_[0];
129 # More relaxed, we just want to avoid too dangerous characters.
130 /^[a-zA-Z0-9+._, @-]+$/;
132 sub valid_web_url {
133 $_ = $_[0];
134 /^https?:\/\/[a-zA-Z0-9.:-]+(\/[_\%a-zA-Z0-9.\/~:?&=;-]*)?(#[a-zA-Z0-9._-]+)?$/;
136 sub valid_repo_url {
137 $_ = $_[0];
138 /^(https?|git|svn(\+http)?|svn(\+https)?|darcs|bzr):\/\/[a-zA-Z0-9.:-]+(\/[_\%a-zA-Z0-9.\/~-]*)?$/;