How can I get the target of a symlink in Perl 6? - symlink

You can create a symlink in Perl 6:
my $symlink-path = ...;
$target.symlink: $symlink-path;
Given just the symlink how can you get the target path?
$symlink-path.IO.????
I'm looking for the exact string that is the target, not any interpretation of that (such as .resolve).

There is no equivalent in Perl 6 for that to my knowledge.
The closest thing to a solution, is to zef install P5readlink (https://modules.raku.org/dist/P5readlink) and use readlink like you would in Perl 5.

Method resolve works:
my $target = "../tmp/file".IO;
my $symlink-path = "files".IO;
$target.symlink: $symlink-path;
say $symlink-path.resolve;
say $symlink-path.resolve(:completely) ~~ $target.resolve(:completely);

Related

ddcal is not working

I am trying to use DDcal for evaluating binary decision diagrams.
When I try to evaluate some formula e.g.: a+b*c', I always get this error:
util_pipefork: can not exec dot: No such file or directory.
Does anyone have idea how I can resolve this error?
Thanks for any insight.
You can use the Python package dd for working with BDDs using either the Python or CUDD backends (disclaimer: I'm dd's author). Example:
import dd.autoref as _bdd # to use CUDD, replace `dd.bdd` with `dd.cudd`
bdd = _bdd.BDD()
bdd.declare('a', 'b', 'c')
u = bdd.add_expr(r'a \/ (b /\ ~ c)')
The syntax is described in the documentation. If you prefer writing a | (b & ~ c), that works too. The pure Python backend is installed with pip install dd.
You can also plot using dot (assuming GraphViz is installed):
bdd.dump('bdd_graph.pdf')
The method BDD.dump is described here.
About DDcal's message
grep -ilr "util_pipefork" ./* says that the error you reported from DDcal seems to be coming from the following lines:
/* Set up bidirectional pipe to/from dot. */
/* A unidirectional pipe should suffice. We'll try it some day. */
retval = util_pipefork(args,&toCommand,&fromCommand,&pid);
if (retval == 0) {
(void) fprintf(stderr,"Panic: util_pipefork returned 0!\n");
exit(2);
}
So, you need to install GraphViz, and make sure that its executables (in particular dot) are in the runtime environment's $PATH.

nmake fails on building Perl module

I am trying to build Win32::Daemon by myself. The reason I not use CPAN is because I want to dig deeper into the working of Perl modules. In the end I hope to come up with a solution for another problem by seeing this working (not of importance here).
I would see 3 options to build the module: cygwin, mingw, microsoft compiler (cl)
On MinGW it reports that it is not supported (simple if in the Makefile.PL) which expands to more errors once I modify the check to match MinGW
On Cygwin it complains about tchar.h which, as I found out, is a Windows header (MinGW does have it).
But my real goal anyway is building it with the MS compiler, so while any compilation that does not require any special libs (like it would do with cygwin I suppose) will more.
So now here goes my nmake output from running just name /f Makefile:
NMAKE : fatal error U1073: "C:/Program" could not be created.
Stop.
I roughly translated the error message from german, but the statement is simple.
What I see here seems to be a path problem (probably the spaces). I also notice the forward slash. The Makefile was created by the Makefile.PL script (I am using Active Perl v5.12.1):
use strict;
use warnings;
use Config qw(%Config);
use ExtUtils::MakeMaker;
unless ($^O eq "MSWin32" || $^O eq "cygwin") {
die "OS unsupported\n";
}
require Win32;
my %param = (
NAME => 'Win32::Daemon',
VERSION_FROM => 'Daemon.pm',
DEFINE => '-DPERL_NO_GET_CONTEXT',
OBJECT => 'CCallbackList$(OBJ_EXT) CCallbackTimer$(OBJ_EXT) Constant$(OBJ_EXT) CWinStation$(OBJ_EXT) Daemon$(OBJ_EXT) ServiceThread$(OBJ_EXT)',
XS => { 'Daemon.xs' => 'Daemon.cpp' },
);
$param{INC} .= ' -EHsc' if $Config{'cc'} =~ /^cl/i;
$param{NO_META} = 1 if eval "$ExtUtils::MakeMaker::VERSION" >= 6.10_03;
WriteMakefile(%param);
sub MY::xs_c {
'
.xs.cpp:
$(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) $(XSUBPP) $(XSPROTOARG) $(XSUBPPARGS) $*.xs >xstmp.c && $(MV) xstmp.c $*.cpp
';
}
I don't know much about the MakeMaker but I don't see anything here that I could fix and would expect that it boils down to fixing the Makefile itself by hand. I tried a couple of things like quoting but nothing helped.
The thing is, I am used to problems like this when building on Windows, but normally this is for tools that were created for Unix. This one is explicitly ONLY Windows and so I would expect it to work out of the box. So I figure that I am doing something wrong.
Any help on where to find the solution?
Thanks in advance.
Edit/Addition: I tried this on another Win7 machine with Active Perl 5.16.x and it worked like a charm. I looked at the different output from this machine and the current one which fails when running perl Makefile.PL and I recieve the following output:
... Detected uninstalled Perl. Trying to continue.
Unable to find a perl 5 (by these names: C:\Program Files\Perl64\bin\perl.exe perl.exe perl5.exe perl5.12.1.exe miniperl.exe, in these dirs: . [...] C:\Program Files\Perl64\site\bin C:\Program Files\Perl64\bin [...])
Have \progra~1\perl64\lib
Want \temp\perl---please-run-the-install-script---\lib
Writing Makefile for Win32::Daemon
I truncated the output. Now please someone explain to me: Why can I run perl Makefile.PL or perl -v but it does not find my Perl in the exact directory it is in? I reinstalled it but it did not work...
Okay I finally seem to have solved this after hours of searching. The problem lies within multiple issues.
The first command of "uninstalled perl" does not make any sense to be, but you can fix it, by supplying perl Makefile.PL PERL_SRC="C\:Program Files\Perl64". Warning: This did not work in a command shell for me, I had to use powershell, because he would not treat the path correctly. You maybe need to juggle with this a bit. Note: In the end I fixed it by installing the original Active Perl, not the one provided by my installer (company software distribution)
Now to the issue of not finding perl: This is a problem with spaces in the path. I fixed this (seemingly) by creating a symlink without spaces. Now perl Makefile.PL does not throw any errors, but nmake -f "Makefile" failed. So the solution really was: Do not have spaces in your perl-path! This sucks, and quite frankfly in 2012 this shouldn't be a problem any more but here you go.
Thanks for all the effort everyone put in, this was a tough one to solve.

How to create directories recursively in ruby?

I want to store a file as /a/b/c/d.txt, but I do not know if any of these directories exist and need to recursively create them if necessary.
How can one do this in ruby?
Use mkdir_p:
FileUtils.mkdir_p '/a/b/c'
The _p is a unix holdover for parent/path you can also use the alias mkpath if that makes more sense for you.
FileUtils.mkpath '/a/b/c'
In Ruby 1.9 FileUtils was removed from the core, so you'll have to require 'fileutils'.
Use mkdir_p to create directory recursively
path = "/tmp/a/b/c"
FileUtils.mkdir_p(path) unless File.exists?(path)
If you are running on unixy machines, don't forget you can always run a shell command under ruby by placing it in backticks.
`mkdir -p /a/b/c`
Pathname to the rescue!
Pathname('/a/b/c/d.txt').dirname.mkpath
require 'ftools'
File.makedirs
You could also use your own logic
def self.create_dir_if_not_exists(path)
recursive = path.split('/')
directory = ''
recursive.each do |sub_directory|
directory += sub_directory + '/'
Dir.mkdir(directory) unless (File.directory? directory)
end
end
So if path is 'tmp/a/b/c'
if 'tmp' doesn't exist 'tmp' gets created, then 'tmp/a/' and so on and so forth.

How can I get the last modified time of a directory in Perl on Windows?

In Perl (on Windows) how do I determine the last modified time of a directory?
Note:
opendir my($dirHandle), "$path";
my $modtime = (stat($dirHandle))[9];
results in the following error:
The dirfd function is unimplemented at scriptName.pl line lineNumber.
Apparently the real answer is just call stat on a path to the directory (not on a directory handle as many examples would have you believe) (at least for windows).
example:
my $directory = "C:\\windows";
my #stats = stat $directory;
my $modifiedTime = $stats[9];
if you want to convert it to localtime you can do:
my $modifiedTime = localtime $stats[9];
if you want to do it all in one line you can do:
my $modifiedTime = localtime((stat("C:\\Windows"))[9]);
On a side note, the Win32 UTCFileTime perl module has a syntax error which prevents the perl module from being interpreted/compiled properly. Which means when it's included in a perl script, that script also won't work properly. When I merge over all the actual code that does anything into my script and retry it, Perl eventually runs out of memory and execution halts. Either way there's the answer above.
my $dir_path = "path_of_your_directory";
my $mod_time = ( stat ( $dir_path ) )[9];
Use the Win32::UTCFileTime module on CPAN, which mirrors the built-in stat function's interface:
use Win32::UTCFileTime qw(:DEFAULT $ErrStr);
#stats = stat $file or die "stat() failed: $ErrStr\n";

How can I include Win32 modules only when I'm running my Perl script on Windows?

I have a problem that I cannot seem to find an answer to.
With Perl I need to use a script across Windows and unix platforms. Te problem is that on Windows we use Win32-pecific modules like Win32::Process, and those modules do not exist on unix.
I need a way to include those Win32 modules only on Windows.
if($^O =~ /win/i)
{
use win32::process qw(CREATE_NEW_CONSOLE);
}
else
{
#unix fork
}
The problem lies in that use statement for windows. No matter what I try this does not compile on unix.
I have tried using dynamic evals, requires, BEGIN, etc.
Is there a good solution to this problem? Any help will be greatly appreciated.
Thanks in advance,
Dan
Update:
A coworker pointed out to me this is the correct way to do it.
require Win32;
require Win32::Process;
my $flag = Win32::Process::CREATE_NEW_CONSOLE();
Win32::Process::Create($process,
$program,
$cmd,
0,
$flag, ".") || die ErrorReport();
print "Child started, pid = " . getPID() . "\n";
Thank you all for your help!
Dan
use is executed at compile time.
Instead do:
BEGIN {
if( $^O eq 'MSWin32' ) {
require Win32::Process;
# import Win32::Process qw(CREATE_NEW_CONSOLE);
Win32::Process->import(qw/ CREATE_NEW_CONSOLE /);
}
else {
#unix fork
}
}
See the perldoc for use.
Also see perlvar on $^O.
Update:
As Sinan Unur points out, it is best to avoid indirect object syntax.
I use direct method calls in every case, except, with calls to import. Probably because import masquerades as a built-in. Since import is really a class method, it should be called as a class method.
Thanks, Sinan.
Also, on Win32 systems, you need to be very careful that you get the capitalization of your module names correct. Incorrect capitalization means that symbols won't be imported properly. It can get ugly.use win32::process may appear to work fine.
Are you sure win32::process can be loaded on OSX? "darwin" matches your /win/i.
You may want to use http://search.cpan.org/dist/Sys-Info-Base/ which tries to do the right thing.
That aside, can you post an example of the code that you actually are using, the failure message you're receiving, and on which unix platform (uname -a) ?
What about a parser that modifies the file on each OS?
You could parse your perl file via a configure script that works on both operating systems to output perl with the proper Use clauses. You could even bury the parse action in the executable script to launch the code.
Originally I was thinking of precompiler directives from C would do the trick, but I don't know perl very well.
Here's an answer to your second set of questions:
Are you using strict and warnings?
Did you define an ErrorReport() subroutine? ErrorReport() is just an example in the synopsis for Win32::Process.
CREATE_NEW_CONSOLE is probably not numeric because it didn't import properly. Check the capitalization in your call to import.
Compare these one-liners:
C:\>perl -Mwin32::process -e "print 'CNC: '. CREATE_NEW_CONSOLE;
CNC: CREATE_NEW_CONSOLE
C:\>perl -Mwin32::process -Mstrict -e "print 'CNC: '. CREATE_NEW_CONSOLE;
Bareword "CREATE_NEW_CONSOLE" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
C:\>perl -MWin32::Process -e "print 'CNC: '. CREATE_NEW _CONSOLE;
CNC: 16
You could just place your platform specific code inside of an eval{}, and check for an error.
BEGIN{
eval{
require Win32::Process;
Win32::Process->import(qw'CREATE_NEW_CONSOLE');
};
if( $# ){ # $# is $EVAL_ERROR
# Unix code here
}
}

Resources