Does `File.info(string)/File::Info.new(string)` resolve symbolic links? - crystal-lang

I'm using Crystal 0.25.0 and File.info(string).symlink? returns false when it should return true in the following sample:
`mkdir -p /tmp/delete`
Dir.cd "/tmp/delete"
`rm -f b`
`touch a`
`ln -s a b`
puts File.info("b").symlink?.inspect # false
puts File.info("b").type # File
puts Process.run("test", "-L b".split).success? # true
puts Process.run("test", "-L a".split).success? # false
It seems to resolve the link. Is this the expected behaviour?

Yes, File.info follows symlinks by default. This is the expected behavior, but you can disable it by passing follow_symlinks: false to the method:
File.info("b", follow_symlinks: false).symlink? # => true
This behavior is documented under File.info in the API docs.

If you don't need the File::Info instance for anything else, you can just use File.symlink? which essentially calls info(path, follow_symlinks: false).symlink?.

Related

makefile: toggle value of variable based on boolean env var

I have an env var INTEGRATION that is set to true or false.
I would like to set the values of variables based on whether INTEGRATION is set to true or false.
I have tried:
ifeq ($(INTEGRATION),false)
PRODUCTION_URL="production"
else
PRODUCTION_URL="integration"
endif
and also
if [ ${SNOOTY_INTEGRATION} == false ]; then \
echo "HIT THE TRUTH"; \
PRODUCTION_URL="https://docs.mongodb.com"; \
fi
after running
export INTEGRATION=true
make help
in terminal, I run make help:
help:
echo "prod url ${PRODUCTION_URL}";
in the first case, it print prod url integration and in the second case, it prints prod url -- when the desired behavior is for it to print, prod url production
Running env INTEGRATION=true is wrong.
That doesn't set the environment variable in the current shell: it only sets that environment variable in the env command.
You can either use:
$ export INTEGRATION=true
$ make help
(set the variable in the shell, so all subsequent commands can see it until you un-export it again), or you can use:
$ env INTEGRATION=true make help
Which is essentially the same thing as (the more common and shorter):
$ INTEGRATION=true make help
(set the variable only for this invocation of make).
But you can't use:
$ env INTEGRATION=true
$ make help
ETA
If that doesn't work there must be something else about your environment you haven't explained. Please provide a complete self-contained example that shows the problem. For example, I don't know what the shell if-statement you show in your question is for or how it relates to the rest of your question. This works for me:
$ cat Makefile
ifeq ($(INTEGRATION),false)
PRODUCTION_URL="production"
else
PRODUCTION_URL="integration"
endif
help:
echo "prod url ${PRODUCTION_URL}";
$ make help
echo "prod url "integration"";
prod url integration
$ export INTEGRATION=true
$ make help
echo "prod url "integration"";
prod url integration
$ export INTEGRATION=false
$ make help
echo "prod url "production"";
prod url production

How to pass input parameters to make? [duplicate]

How to pass argument to Makefile from command line?
I understand I can do
$ make action VAR="value"
$ value
with Makefile
VAR = "default"
action:
#echo $(VAR)
How do I get the following behavior?
$ make action value
value
How about
$make action value1 value2
value1 value2
You probably shouldn't do this; you're breaking the basic pattern of how Make works. But here it is:
action:
#echo action $(filter-out $#,$(MAKECMDGOALS))
%: # thanks to chakrit
#: # thanks to William Pursell
EDIT:
To explain the first command,
$(MAKECMDGOALS) is the list of "targets" spelled out on the command line, e.g. "action value1 value2".
$# is an automatic variable for the name of the target of the rule, in this case "action".
filter-out is a function that removes some elements from a list. So $(filter-out bar, foo bar baz) returns foo baz (it can be more subtle, but we don't need subtlety here).
Put these together and $(filter-out $#,$(MAKECMDGOALS)) returns the list of targets specified on the command line other than "action", which might be "value1 value2".
Here is a generic working solution based on #Beta's
I'm using GNU Make 4.1 with SHELL=/bin/bash atop my Makefile, so YMMV!
This allows us to accept extra arguments (by doing nothing when we get a job that doesn't match, rather than throwing an error).
%:
#:
And this is a macro which gets the args for us:
args = `arg="$(filter-out $#,$(MAKECMDGOALS))" && echo $${arg:-${1}}`
Here is a job which might call this one:
test:
#echo $(call args,defaultstring)
The result would be:
$ make test
defaultstring
$ make test hi
hi
Note! You might be better off using a "Taskfile", which is a bash pattern that works similarly to make, only without the nuances of Maketools. See https://github.com/adriancooney/Taskfile
Much easier aproach. Consider a task:
provision:
ansible-playbook -vvvv \
-i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory \
--private-key=.vagrant/machines/default/virtualbox/private_key \
--start-at-task="$(AT)" \
-u vagrant playbook.yml
Now when I want to call it I just run something like:
AT="build assets" make provision
or just:
make provision in this case AT is an empty string
Few years later, want to suggest just for this: https://github.com/casey/just
action v1 v2=default:
#echo 'take action on {{v1}} and {{v2}}...'
You will be better of defining variables and calling your make instead of using parameters:
Makefile
action: ## My action helper
#echo $$VAR_NAME
Terminal
> VAR_NAME="Hello World" make action
Hello World
don't try to do this
$ make action value1 value2
instead create script:
#! /bin/sh
# rebuild if necessary
make
# do action with arguments
action "$#"
and do this:
$ ./buildthenaction.sh value1 value2
for more explanation why do this and caveats of makefile hackery read my answer to another very similar but seemingly not duplicate question: Passing arguments to "make run"

Capistrano using wrong release path

My deploy.rb file looks like this
SSHKit.config.command_map[:rake] = "bundle exec rake"
lock '3.2.1'
set :application, 'foobar'
set :scm, :git
set :repo_url, 'git#bitbucket.org:xxxx/xxxx.git'
set :deploy_via, "copy"
set :ssh_options, { forward_agent: true }
set :assets_roles, [:web]
set :whenever_roles, [:cron]
set :format, :pretty
set :pty, true
set :linked_files, fetch(:linked_files, []).push('config/database.yml')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/assets', 'public/system', 'public/uploads')
set :keep_releases, 5
set :rvm_type, :user
set :rvm_ruby_version, '2.2.3#xxxx'
set :nvm_type, :user
set :nvm_node, 'v0.12.4'
set :nvm_map_bins, %w{node npm}
set :nvm_roles, [:web]
set :bundle_path, nil
set :bundle_binstubs, nil
set :bundle_flags, '--system'
namespace :deploy do
after :restart, :clear_cache do
on roles(:app) do
within current_path do
with rails_env: fetch(:rails_env) do
execute :rake, 'db:schema:load'
end
end
end
end
end
But when I try to do cap production deploy I'm getting following error
DEBUG [56b32b4c] Running /usr/bin/env if test ! -d /var/www/omega/current; then echo "Directory does not exist '/var/www/omega/current'" 1>&2; false; fi as deploy#XX.XX.XXX.X
DEBUG [56b32b4c] Command: if test ! -d /var/www/xxxx/current; then echo "Directory does not exist '/var/www/xxxx/current'" 1>&2; false; fi
DEBUG [56b32b4c] Directory does not exist '/var/www/xxxx/current'
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy#XX.XX.XXX.X: if test ! -d /var/www/xxxx/current; then echo "Directory does not exist '/var/www/xxxx/current'" 1>&2; false; fi exit status: 1
I don't understand what's going wrong with it and I spent quite a lot time already to debug the error but haven't had any success yet.
The reason for that particular scenario was, the current symlink was dead. Means to which directory it was pointing that was somehow deleted.
So why Capistrnao commands was causing error Directory does not exists.
By default, Capistrano will deploy your application to /var/www/[application_name] as you have set in :application. When you deploy, it looks to see whether /var/www/omega exists. It doesn't and thus it fails.
You can override the location to which it is deploying with:
set :deploy_to, '/my/deploy/dir'

Can't enable phar writing

I am actually using wamp 2.5 with PHP 5.5.12 and when I try to create a phar file it returns me the following message :
Uncaught exception 'UnexpectedValueException' with message 'creating archive "..." disabled by the php.ini setting phar.readonly'
even if I turn to off the phar.readonly option in php.ini.
So how can I enable the creation of phar files ?
I had this same problem and pieced together from info on this thread, here's what I did in over-simplified explanation:
in my PHP code that's generating this error, I added echo phpinfo(); (which displays a large table with all sort of PHP info) and in the first few rows verify the path of the php.ini file to make sure you're editing the correct php.ini.
locate on the phpinfo() table where it says phar.readonly and note that it is On.
open the php.ini file from step 1 and search for phar.readonly. Mine is on line 995 and reads ;phar.readonly = On
Change this line to phar.readonly = Off. Be sure that there is no semi-colon at the beginning of the line.
Restart your server
Confirm that you're phar project is now working as expected, and/or search on the phpinfo()table again to see that the phar.readonly setting has changed.
phar.readonly can only be disabled in php.ini due to security reasons.
If you want to check that it's is really not done using other method than php.ini then in terminal type this:-
$ php -r "ini_set('phar.readonly',0);print(ini_get('phar.readonly'));"
If it will give you 1 means phar.readonly is On.
More on phar.configuration
Need to disable in php.ini file
Type which php
Gives a different output depending on machine e.g.
/c/Apps/php/php-7.2.11/php
Then open the path given not the php file.
E.g. /c/Apps/php/php-7.2.11
Edit the php.ini file
could do
vi C:\Apps\php\php-7.2.11\php.ini
code C:\Apps\php\php-7.2.11\php.ini
[Phar]
; http://php.net/phar.readonly
phar.readonly = Off
; http://php.net/phar.require-hash
phar.require_hash = Off
Save
Using php-cli and a hashbang, we can set it on the fly without messing with the ini file.
testphar.php
#!/usr/bin/php -d phar.readonly=0
<?php
print(ini_get('phar.readonly')); // Must return 0
// make sure it doesn't exist
#unlink('brandnewphar.phar');
try {
$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar', 0, 'brandnewphar.phar');
} catch (Exception $e) {
echo 'Could not create phar:', $e;
}
echo 'The new phar has ' . $p->count() . " entries\n";
$p->startBuffering();
$p['file.txt'] = 'hi';
$p['file2.txt'] = 'there';
$p['file2.txt']->compress(Phar::GZ);
$p['file3.txt'] = 'babyface';
$p['file3.txt']->setMetadata(42);
$p->setStub('<?php
function __autoload($class)
{
include "phar://myphar.phar/" . str_replace("_", "/", $class) . ".php";
}
Phar::mapPhar("myphar.phar");
include "phar://myphar.phar/startup.php";
__HALT_COMPILER();');
$p->stopBuffering();
// Test
$m = file_get_contents("phar://brandnewphar.phar/file2.txt");
$m = explode("\n",$m);
var_dump($m);
/* Output:
* there
**/
✓ Must be set executable:
chmod +x testphar.php
✓ Must be called like this:
./testphar.php
// OUTPUT there
⚠️ Must not be called like this:
php testphar.php
// Exception, phar is read only...
⚠️ Won't work called from a CGI web server
php -S localhost:8785 testphar.php
// Exception, phar is read only...
For anyone who has changed the php.ini file, but just doesn't see any changes. Try to use the CLI version of the file. For me, it was in /etc/php/7.4/cli/php.ini
Quick Solution!
Check:
cat /etc/php/7.4/apache2/php.ini | grep phar.readonly
Fix:
sed -i 's/;phar.readonly = On/;phar.readonly = Off/g' /etc/php/7.4/apache2/php.ini

Autoconf macro for Boost MPI?

I'm searching an autoconf macro to use in my configure.ac that checks for Boost MPI.
It's not hard to find a couple of them on the Internet but none of the one I tried worked as expected.
What ax_boost_mpi.m4 do you use?
EDIT: I'll explain my requirement better. I need the macro to tell me if Boost MPI is available or not (defining HAVE_BOOST_MPI) to store the compiler and linker flags somewhere and to switch the compiler from the nornal c++ compiler to an available mpiCC or mpic++.
If the Boost MPI is not found I'd like to be able to choose if I want to stop the configuration process with an error or continue using g++ without HAVE_BOOST_MPI defined.
As a plus it should define an MPIRUN variable to allow running some checks.
I'm unaware of a turnkey solution here, but that doesn't mean one's unavailable.
With some work, you could probably adapt http://www.gnu.org/software/autoconf-archive/ax_mpi.html#ax_mpi and http://github.com/tsuna/boost.m4 to do what you want. The former digging up the MPI compiler and the latter checking for Boost MPI. You'd have to add a Boost MPI check to boost.m4 as it doesn't have one. You'd have to add your own MPIRUN-searching mechanism.
If you find a solution and/or roll your own, please do share.
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_MPI
#
# DESCRIPTION
#
# Test for MPI library from the Boost C++ libraries. The macro
# requires a preceding call to AX_BOOST_BASE, AX_BOOST_SERIALIZATION
# and AX_MPI. You also need to set CXX="$MPICXX" before calling the
# macro.
#
# This macro calls:
#
# AC_SUBST(BOOST_MPI_LIB)
#
# And sets:
#
# HAVE_BOOST_MPI
#
# LICENSE
#
# Based on Boost Serialize by:
# Copyright (c) 2008 Thomas Porschberg <thomas#randspringer.de>
#
# Copyright (c) 2010 Mirko Maischberger <mirko.maischberger#gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
AC_DEFUN([AX_BOOST_MPI],
[
AC_ARG_WITH([boost-mpi],
AS_HELP_STRING([--with-boost-mpi#<:#=special-lib#:>#],
[use the MPI library from boost - it is possible to
specify a certain library for the linker
e.g. --with-boost-mpi=boost_mpi-gcc-mt-d-1_33_1 ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_mpi_lib=""
else
want_boost="yes"
ax_boost_user_mpi_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
AC_MSG_WARN(BOOST_CPPFLAGS $BOOST_CPPFLAGS)
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
LIBS_SAVED="$LIBS"
LIBS="$LIBS $BOOST_SERIALIZATION_LIB"
export LIBS
AC_CACHE_CHECK(whether the Boost::MPI library is available,
ax_cv_boost_mpi,
[AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE(AC_LANG_PROGRAM([[#%:#include <boost/mpi.hpp>
]],
[[int argc = 0;
char **argv = 0;
boost::mpi::environment env(argc,argv);
return 0;
]]),
ax_cv_boost_mpi=yes, ax_cv_boost_mpi=no)
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_mpi" = "xyes"; then
AC_DEFINE(HAVE_BOOST_MPI,,[define if the Boost::MPI library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/#<:#^\/#:>#*//'`
if test "x$ax_boost_user_mpi_lib" = "x"; then
for libextension in `ls $BOOSTLIBDIR/libboost_mpi*.{so,a}* 2>/dev/null | grep -v python | sed 's,.*/,,' | sed -e 's;^lib\(boost_mpi.*\)\.so.*$;\1;' -e 's;^lib\(boost_mpi.*\)\.a*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_MPI_LIB="-l$ax_lib"; AC_SUBST(BOOST_MPI_LIB) link_mpi="yes"; break],
[link_mpi="no"])
done
if test "x$link_mpi" != "xyes"; then
for libextension in `ls $BOOSTLIBDIR/boost_mpi*.{dll,a}* 2>/dev/null | grep -v python | sed 's,.*/,,' | sed -e 's;^\(boost_mpi.*\)\.dll.*$;\1;' -e 's;^\(boost_mpi.*\)\.a*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_MPI_LIB="-l$ax_lib"; AC_SUBST(BOOST_MPI_LIB) link_mpi="yes"; break],
[link_mpi="no"])
done
fi
else
for ax_lib in $ax_boost_user_mpi_lib boost_mpi-$ax_boost_user_mpi_lib; do
AC_CHECK_LIB($ax_lib, exit,
[BOOST_MPI_LIB="-l$ax_lib"; AC_SUBST(BOOST_MPI_LIB) link_mpi="yes"; break],
[link_mpi="no"])
done
fi
if test "x$link_mpi" != "xyes"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
fi
fi
LIBS="$LIBS_SAVED"
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
This comment is a bit late, but I will add it here so that others searching for the same topic can find it. I had personally been looking for a function integrated into boost.m4 that defined similar variables as the other boost libraries (BOOST_MPI_LDFLAGS, BOOST_MPI_LIBS). I finally just added one and submitted a pull request here:
https://github.com/tsuna/boost.m4/pull/50
This uses the MPICXX variable for CXX/CXXCPP if it is already defined (by ax_mpi.m4, acx_mpi.m4, etc), otherwise it uses the existing CXX/CXXCPP.