FunctionalPerl

 view release on metacpan or  search on metacpan

lib/Chj/xperlfunc.pm  view on Meta::CPAN

a previous target. All the same it does the replace atomically.
(It works by creating a link to a temporary location then rename.)
(Hm, strange function name?)

=item xfileno $string_or_FH

Does work with both filehandles and integer strings. Croaks if it's
neither or there's an error.

=item basename $pathstring [,$suffix(es) [,$insensitive]]

Same as the shell util of the same name, except that it croaks in a
few cases (when an empty string is given, or when the given suffix
doesn't match).

=item dirname $pathstring

Same as the shell util (or about as my old FolderOfThisFile function),
except that it croaks if dirname of "/" or "." is requested.

=item xmkdir_p $pathstring

Works like unix's "mkdir -p": return false if the directory already
exists, true if it (and, if necessary, it's parent(s)) has(/have) been
created, croaks if some error happens on the way.

=item xlink_p $frompath, $topath

xlink's $frompath to $topath but 

=back

=head1 NOTE

This is alpha software! Read the status section in the package README
or on the L<website|http://functional-perl.org/>.

=cut

#'

package Chj::xperlfunc;
use strict;
use warnings;
use warnings FATAL => 'uninitialized';
use Exporter "import";

our @EXPORT = qw(
    xfork
    xfork_
    xexec
    xexec_safe
    xsystem
    xxsystem
    xsystem_safe
    xxsystem_safe
    xrename
    xmkdir
    xrmdir
    xchmod
    xchown
    xchdir
    xstat
    xlstat
    Xstat
    Xlstat
    xlocaltime
    xreadlink
    xunlink
    xlink
    xsymlink
    xutime
    xkill
    xeval
    xwaitpid
    xxwaitpid
    xwait
    xxwait
    xsysread
    xchroot
);
our @EXPORT_OK = qw(
    xspawn
    xlaunch
    xmvmkdir
    xmkdir_with_paragon
    xtmpdir_with_paragon
    xlinkunlink
    xlinkreplace
    xxcarefulrename
    xfileno
    basename
    dirname
    xmkdir_p
    xlink_p
    xgetpwnam
    xgetgrnam
    caching_getpwnam
    caching_getgrnam
    xprint
    xprintln
    xLmtimed
    XLmtimed
    xLmtime
    XLmtime
    min max
    fstype_for_device
    xgetfile_utf8 xslurp
    maybe_getfile_utf8
);

# would we really want to export these?:
#caching_getpwuid
#caching_getgrgid
our %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]);

use Carp;
use FP::Carp;
use Chj::singlequote 'singlequote_many';    # the only dependency so far
use Chj::Unix::Exitcode qw(exitcode);

lib/Chj/xperlfunc.pm  view on Meta::CPAN

        };
    } else {
        if (lstat $dest) {

            # (yes, link too already fails if target exists as a
            # dangling symlink)
            croak "xxcarefulrename: target '$dest' already exists";
        } else {
            rename $source, $dest
                or croak "xxcarefulrename(" . join(", ", @_) . "): $!";
        }
    }
}

sub xlinkreplace {
    @_ == 2 or fp_croak_arity 2;
    my ($source, $dest) = @_;
    ## schon wieder dieser temporary try mechanismus. sollte ich dringend eine generische func oder ein makro dafür haben theoretisch
# nun im gegensatz zu Tempfile.pm brauchen wir kein eval hier. Aber auch das waer ja per func/macro machbar
    my $path;
TRY: {
        for (1 .. 3) {
            $! = 0;
            my $rand = int(rand(99999) * 100000 + rand(99999));

            # well, not good enough for dangerous cases nor reasonable for
            # non-dangerous cases?
            $path = "$source.tmp$rand~";
            last TRY if link $source, $path;
        }
        croak "xlinkreplace: failed 3 attempts to create hardlinks from "
            . "'$source' to e.g. '$path': $!";
    }
    rename $path, $dest
        or croak "xlinkreplace: could not rename '$path' to '$dest': $!";
}

sub xmkdir {
    if (@_ == 1) {
        mkdir $_[0] or croak "xmkdir($_[0]): $!";
    } elsif (@_ == 2) {
        mkdir $_[0], $_[1] or croak "xmkdir(" . join(", ", @_) . "): $!";
    } else {
        croak "xmkdir: wrong number of arguments";
    }
}

sub xrmdir {
    if (@_ == 1) {
        rmdir $_[0] or croak "xrmdir($_[0]): $!";
    } else {
        croak "xrmdir: wrong number of arguments";
    }
}

sub xchmod {
    @_ >= 1 or croak "xchmod: not enoug arguments";    # should it be >1?
    chmod shift, @_ or croak "xchmod: $!";
}

sub xchown {
    @_ >= 2 or croak "xchown: not enoug arguments";    # should it be >2?
    chown shift, shift, @_ or croak "xchown: $!";
}

sub xchdir {
    chdir $_[0] or croak "xchdir '$_[0]': $!";
}

our $time_hires = 0;

sub stat_possiblyhires {
    if ($time_hires) {
        require Time::HiRes;    # (that's not slow, right?)
        if (@_) {
            @_ == 1 or fp_croak_arity 1;
            Time::HiRes::stat($_[0])
        } else {
            Time::HiRes::stat($_)
        }
    } else {
        if (@_) {
            @_ == 1 or fp_croak_arity 1;
            stat($_[0])
        } else {
            stat($_)
        }
    }
}

sub lstat_possiblyhires {
    if ($time_hires) {
        require Chj::Linux::HiRes;
        if (@_) {
            @_ == 1 or fp_croak_arity 1;
            Chj::Linux::HiRes::lstat($_[0])
        } else {
            Chj::Linux::HiRes::lstat($_)
        }
    } else {
        if (@_) {
            @_ == 1 or fp_croak_arity 1;
            lstat($_[0])
        } else {
            lstat($_)
        }
    }
}

# XX: should provide a newly named function to give the object,
# instead of using wantarray. Have xstat behave like the Perl builtin
# (and then possibly drop and replace by another solution from
# core/CPAN).
sub xstat {
    my @r;
    @_ <= 1 or croak "xstat: too many arguments";
    @r = stat_possiblyhires(@_ ? @_ : $_);
    @r or croak(@_ ? "xstat: '@_': $!" : "xstat: '$_': $!");
    my $wantarray = wantarray;    ## no critic
    if ($wantarray) {
        @r
    } elsif (defined $wantarray) {
        my $self = \@r;

lib/Chj/xperlfunc.pm  view on Meta::CPAN

    sub set_yday  { my ($s, $v) = @_; $s->[7] = $v;        $s }    # 0..36[45]
    sub set_isdst { my ($s, $v) = @_; $s->[8] = $v;        $s }
    sub set_Year  { my ($s, $v) = @_; $s->[5] = $v - 1900; $s }
    sub set_Mon   { my ($s, $v) = @_; $s->[4] = $v - 1;    $s }

    #sub set_Wday
    #sub set_wDay
    # but those don't have any effect on timelocal anyway.

    sub unixtime {
        my $s = shift;
        Time::Local::timelocal(@$s)
    }

    sub iso_week_number {
        my $s = shift;

        # On which yday does week 01 start for `Year`?

        my $wDay = $s->wDay;
        my $yday = $s->yday;

        my $weekstart_day = $yday - $wDay;

        my ($offset, $weeks) = ($weekstart_day % 7, int($weekstart_day / 7));

        my $week = ($offset >= 4) ? $weeks + 2 : $weeks + 1;
        $yday < $offset ? "LASTYEAR" : $week

            # XX needs to give the year, actually! Buggy.
    }

    sub Year_and_iso_week_number {
        my $s = shift;
        $s->Year . "-W" . $s->iso_week_number

            # XX needs to give the year with the week, actually! Buggy.
    }
}

sub xlocaltime {
    @_ >= 0 and @_ <= 1 or fp_croak_arity "0-1";
    bless [localtime(defined $_[0] ? $_[0] : time)],
        "Chj::xperlfunc::xlocaltime"
}

sub xreadlink {
    my $res
        = @_ == 0 ? readlink
        : @_ == 1 ? readlink $_[0]
        :           croak "xreadlink: wrong number of arguments";
    defined $res or croak @_ ? "xreadlink @_: $!" : "xreadlink: $!";
    $res
}

sub xmkdir_with_paragon {
    @_ == 2 or @_ == 3 or fp_croak_arity "2 or 3";
    warn "UNTESTED!";
    my ($owner, $group, $mode) = (xstat $_[1])[4, 5, 2];
    xmkdir $_[0], 0;
    if (!chown $owner, $group, $_[0]) {
        $_[2] and croak "xmvmkdir: could not recreate user or group: $!";
    }
    xchmod $mode, $_[0];
}

package Chj::xperlfunc::tmpdir {

    sub DESTROY {
        my $self = shift;
        local ($@, $!);
        rmdir $$self                              ## hack
            and warn "removed tmpdir '$$self'";   ## should it warn? prolly not.
    }
}

sub xtmpdir_with_paragon {
    @_ == 1 or @_ == 2 or fp_croak_arity "1 or 2";
    my ($paragon, $strict) = @_;
    my ($owner, $group, $mode) = (xstat $paragon)[4, 5, 2];
    my $newname;
TRY: for (0 .. 2) {
        $newname = $paragon;
        $newname =~ s{(^|/)([^/]+)\z}{"$1.$2.tmp".int(rand(100000))}se;
        last TRY if mkdir $newname, 0;
        if ($! != EEXIST) {
            croak "xtmpdir_with_paragon: mkdir: $!";
        }
    }
    if (!chown $owner, $group, $newname) {
        if ($strict) {
            rmdir $newname;
            croak "xtmpdir_with_paragon: could not recreate user or group: $!";
        }
    }
    if (!chmod $mode, $newname) {
        rmdir $newname;
        croak "xtmpdir_with_paragon: chmod: $!";
    }
    return bless \$newname, 'Chj::xperlfunc::tmpdir';

    # ^ so that it will be removed upon error
}

sub xmvmkdir {
    @_ == 2 or @_ == 3 or fp_croak_arity "2 or 3";
    xrename $_[0], $_[1];
    my ($owner, $group, $mode) = (xstat $_[1])[4, 5, 2];
    xmkdir $_[0], 0;
    if (!chown $owner, $group, $_[0]) {
        $_[2] and croak "xmvmkdir: could not recreate user or group: $!";
    }
    xchmod $mode, $_[0];
}

sub xunlink {
    for (@_) {
        unlink $_ or croak "xunlink '$_': $!";
    }
}

sub xlink {
    @_ == 2 or fp_croak_arity 2;
    link $_[0], $_[1] or croak "xlink '$_[0]','$_[1]': $!";
}

sub xsymlink {
    @_ == 2 or fp_croak_arity 2;
    symlink $_[0], $_[1] or croak "xsymlink to '$_[1]': $!";
}

sub xutime {
    @_ >= 2 or fp_croak_arity ">= 2";
    my ($atime, $mtime) = (shift, shift);
    utime $atime, $mtime, @_ or croak "xutime @_: $!";
}

sub xkill {
    my $sig = shift;
    kill $sig, @_ or croak "xkill $sig @_: $!";
}

sub xchroot {
    @_ == 1 or fp_croak_arity 1;
    my ($rtd) = @_;
    chroot $rtd or die "could not chroot to '$rtd': $!";
}

sub xeval {    # meant for string eval only, of course.
    @_ == 1 or die "wrong number of arguments";
    ## hm ps should one localize $@ here?
    my $wantarray = wantarray;    ## no critic
    if (defined $wantarray) {
        if ($wantarray) {
            my @res = eval $_[0];
            if (ref $@ or $@) {
                die $@
            } else {
                @res
            }
        } else {
            my $res = eval $_[0];
            if (ref $@ or $@) {
                die $@
            } else {
                $res
            }
        }
    } else {
        eval $_[0];



( run in 0.705 second using v1.01-cache-2.11-cpan-71847e10f99 )