Aldebaran has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I'm clawing my way towards friar and updating my html template to reflect best practices. It relies on some aspects that aren't particularly-perl related, but I'm trying to use perl where I have used other software tools before. Right now, to create the filespace for a new project, I have a crummy bash script that wraps a perl script. What's more, the perl script is laden with older software tools, so I essentially want to combine what these 2 do. First a very short bash listing and then the script it wraps:

/home/bob/1.scripts/pages ------- #!/bin/bash ./ $1 $2 $3 chmod 755 $2 cd $2 chmod +x *.pl pwd ------- #!/usr/bin/perl -w use strict; use 5.010; use Cwd; use Path::Class; use File::Copy; use File::Basename; use File::Find; use File::Slurp qw(read_dir); # This script clones the template directory in $1 to $2. # Some names need munging. # $from is a populated child directory; $to is child dir to be create +d. $pop is the folder with the data. my ( $from, $to, $pop ) = @ARGV; my $ts = "template_stuff"; my $current = cwd; # choose good lexical variable for directory list: @a. say "-------------"; my $rd2 = dir($current); my @a = $rd2->dir_list(); say "a is @a"; say "-------------"; say "making directories"; # make root directory of clone: my $rd1 = dir( @a, $to ); my $srd1 = $rd1->stringify; mkdir $srd1 or warn "couldn't make $srd1: $!\n"; say "srd1 is $srd1"; # define the paths within the target directory: my $rd3 = dir( @a, $to, $ts ); my $srd3 = $rd3->stringify; mkdir $srd3 or warn "couldn't make $srd3: $!\n"; #say "srd3 is $srd3"; # stringify $from template directory: my $rd6 = dir( @a, $from, $ts ); my $srd6 = $rd6->stringify; say "srd6 is $srd6"; # copy files: opendir my $eh, $srd6 or die "dead $!\n"; while ( defined( $_ = readdir($eh) ) ) { if (m/(txt|pm|css|tmpl|pl|sh)$/) { say "matching is $_"; $a = file( $srd6, $_ ); #say "a is $a"; $b = file( $srd3, $_ ); #say "b is $b"; copy( $a, $b ); } } # copy css file to template with munged name opendir my $fh, $srd6 or die "dead $!\n"; while ( defined( $_ = readdir($fh) ) ) { if (m/^$from(\d*)\.css$/) { say "matching is $_"; say "dollar one is $1"; $a = file( $srd6, $_ ); say "a is $a"; my $munge = $to . $1 . ".css"; $b = file( $srd3, $munge ); say "b is $b"; copy( $a, $b ); } } closedir $fh; my $rd7 = dir( @a, $from ); my $srd7 = $rd7->stringify; say "srd7 is $srd7"; my @matching; opendir my $dh, $srd7 or die "dead $!\n"; while ( defined( $_ = readdir($dh) ) ) { if (m/$from(\d*)\.pl$/i) { push @matching, $_; } } closedir $dh; @matching = sort @matching; say "matched is @matching"; my $winner = pop @matching; my $newfile = "${to}"; my $a = file( $srd7, $winner ); print "a is $a\n"; my $b = file( $srd1, $newfile ); print "b is $b\n"; copy( $a, $b ); say "end of clone"; say "addressing pop"; #declare directories for this template my @dirs = qw /aimages captions ruscaptions/; #say "dirs are @dirs"; while (@dirs) { my $dir = shift @dirs; say "dir is $dir"; my $rd4 = dir( @a, $pop, $ts, $dir ); my $srd4 = $rd4->stringify; say "bla vlab $srd4"; my $rd5 = dir( @a, $to, $ts, $dir ); my $srd5 = $rd5->stringify; #say "srd5 is $srd5"; mkdir $srd5 or warn "couldn't make $srd5: $!\n"; opendir my $gh, $srd4 or warn "dir not there $!\n"; while ( defined( $_ = readdir($gh) ) ) { next if -d $_; next if $_ =~ /~$/; say "matching is $_"; $a = file( $srd4, $_ ); #say "a is $a"; $b = file( $srd5, $_ ); #say "b is $b"; copy( $a, $b ); } closedir $gh; }

What I'm fishing for here is the best way to change all this to Path::Tiny. What attributes should I give files and directories copied? I might not own everything that comes in on the $3 directory. what is the best way to own the images you copy from one directory to one of your creation?

Replies are listed 'Best First'.
Re: shedding a bash wrapper and updating to Path::Tiny
by haukex (Chancellor) on Jul 07, 2018 at 08:32 UTC
    I essentially want to combine what these 2 do
    • chmod: Path::Tiny supports a chmod method (e.g. $obj->chmod("0755") or $obj->chmod("a+x")), which it gets from File::chmod, unfortunately Path::Class, which you're using in your code, does not, but you can use Perl's chmod (just make sure to check for errors). Perl's chmod only supports numeric modes, though.
    • cd: chdir (make sure to check for errors)
    • pwd: getcwd from Cwd

    As for your code, it's pretty long and I've only skimmed it for now, but one thing I noticed is that you're using ->stringfiy a lot, into temporary variables. While certainly not wrong, it's kind of cluttering up your code a bit - for debug output, you should be able to print the objects directly, and also note that it's not necessary to stringify the objects only to turn them back into objects again later. Using $srd3 as an example:

    my $rd3 = dir( ... ); my $srd3 = $rd3->stringify; mkdir $srd3 or warn "couldn't make $srd3: $!\n"; say "srd3 is $srd3"; $b = file( $srd3, $_ );

    Can be written instead as:

    my $rd3 = dir( ... ); $rd3->mkpath(); say "rd3 is $rd3"; my $f = $rd3->file( $_ );

      Thx haukex, I think I'm calling the mkdir method properly in this script so far. I'm getting alright partial results but want to cast the final solution in the idioms of Path::Tiny. Could I save myself the mkdir call by using the module better with the touchpath method?

      I don't seem to know how to refer to the "children" I've created other than by "$_". First, output:

Re: shedding a bash wrapper and updating to Path::Tiny
by kevbot (Priest) on Jul 07, 2018 at 02:31 UTC
    Hello Datz_cozee75,

    Here is a gentle introduction to Path::Tiny: Path::Tiny: The little module that keeps on giving. After you finish up with that, then I recommend you take a closer look at the documentation for Path::Tiny. For example, some Path::Tiny methods that may be relevant to your script are children, chmod, copy, exists, is_file, is_dir, mkpath, slurp, and stringify. Also, for changing file permissions/owners take a look at the documentation for chown. I think you will be more likely to receive constructive feedback if you attempt to modify your script and post the results in this thread.

      Thank you for your reply, and I understand that it's hard to comment on code that has yet to be shown. I appreciated the remarks before I start into these: they give me goals to work towards. I've done about half of the changeover to Path::Tiny for this workspace, and I've been really pleased with results so far. I've chopped out many lines and even one entire routine. It would be very pleasing if I could wrest this software tool completely from bash. Where it starts is last html page with utf8 captions, showing a successful cloning of the last stable upgrade.

      Alright, so on all of the files copied, if they match either "pl" or "sh", then I want them set to 0755. Should I set directories containing these scripts to 0755 as well?

      Page for perlmonks shows progress with changing the path on the server directory. I've started to attack the clone script from the top, clearing out the modules I'm not gonna use anymore. For this task, I might only need Path::Tiny, but need to get some feeling as to how it works. Where I'm hung up now is with the logic from switching over from File::Copy. I've commented out what used to work:

      Where I can't follow the logic is the analog of the copy command. Terminal output is:

      $ ./ ------------- making directories ------------- copying files matching is 5.unicode1.css copy failed for /home/bob/1.scripts/pages/ +de1.css to 1/5.unicode1.css: No such file or directory at ./4.clone.p +l line 41. $

      Thanks all for comments, and I *do read* what people post for me. Please understand, I'm a pilgrim who is overachieving to become a friar, so the more-complicated method calls in Path::Tiny are a bit tough for me. I think the investment in figuring it out and switching over is gonna be time well spent.

        I finally got it to work. It's hugely verbose, so I'll put output in readmore tags. I just kept on trying things until something worked. Path::Tiny examples are in the middle of this script. I worked the examples of Path::Class given on a path class page on perladvert. Now I'm gonna start editing, making it less verbose.

        The script is still in transition, and the produced html page has the code from the $from directory and the content from the $pop directory: new html page with new content . This is what exists now. The %vars is not hooked up to anything yet in this script.

        I found that I had to stringify more than I was anticipating but could not stringify for ( $abs_pop->children ) {}. By the end, I figured out that I could use chdir and Path::Tiny to bring me where I needed to be instead of creating some ginormous path. It seems to work fine without quotes. (tested only once)

        How do I change the logic so that .tmpl files don't get set to execute because they end in pl?

        Accepting any criticisms of style. Does one use quotes in the path calls all the times or just sometimes?