From 77e81dd3c7e9c2f395544b1702a48e53e89f5609 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Fri, 28 Apr 2017 09:35:51 +0200 Subject: [PATCH 1/1] Initial import --- addOption-null-shortname-php-parse.php | 65 +++++++++++++++++++++++++++ addOption-null-shortname.sh | 81 ++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 addOption-null-shortname-php-parse.php create mode 100755 addOption-null-shortname.sh diff --git a/addOption-null-shortname-php-parse.php b/addOption-null-shortname-php-parse.php new file mode 100644 index 0000000..49dbf73 --- /dev/null +++ b/addOption-null-shortname-php-parse.php @@ -0,0 +1,65 @@ + + */ + +/* + * php-parse is installed with: + * composer global require nikic/php-parser + */ +include getenv('HOME') . '/.config/composer/vendor/autoload.php'; + +use PhpParser\Node; +use PhpParser\NodeTraverser; +use PhpParser\NodeVisitorAbstract; +use PhpParser\ParserFactory; +use PhpParser\PrettyPrinter; + +class AddOptionSecondArgumentVisitor extends NodeVisitorAbstract { + + public function leaveNode(Node $node) { + if ($node instanceof Node\Expr\MethodCall && $node->name === "addOption") { + + $shortname_arg = $node->args[1]; + + // If it's a constant expression (e.g. false or null) make it null. + if ($shortname_arg->value instanceof Node\Expr\ConstFetch) { + $shortname_arg->value->name = new Node\Name("null"); + } + elseif ($shortname_arg->value instanceof Node\Scalar\String_) { + // If it's an empty string, make it null keeping the attributes. + if (empty($shortname_arg->value->value)) { + $old_attributes = $shortname_arg->value->getAttributes(); + $shortname_arg->value = new Node\Expr\ConstFetch(new Node\Name("null"), $old_attributes); + } + } + else { + echo "UNEXPECTED argument type\n"; + } + } + } + +} + +$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); +$traverser = new NodeTraverser(); +$prettyPrinter = new PrettyPrinter\Standard(); + +$traverser->addVisitor(new AddOptionSecondArgumentVisitor()); + +try { + $code = file_get_contents($argv[1]); + $stmts = $parser->parse($code); + $stmts = $traverser->traverse($stmts); + + // $stmts is an array of statement nodes. + $code = $prettyPrinter->prettyPrintFile($stmts); + echo $code; + +} +catch (Error $e) { + echo 'Parse Error: ', $e->getMessage(); +} diff --git a/addOption-null-shortname.sh b/addOption-null-shortname.sh new file mode 100755 index 0000000..c677e99 --- /dev/null +++ b/addOption-null-shortname.sh @@ -0,0 +1,81 @@ +#!/bin/sh + +# Change the second argument of "addOption" to null. +# +# Copyright (C) 2017 Antonio Ospite + +set -e +set -x + +[ "x$1" = "x" ] && { echo "usage: $(basename $0) " 2>&1; exit 1; } + +DRUPAL_CONSOLE_DIR="$1" +PHP_PARSER_RESULTS_DIR=__php_parser_results +LOG_FILE=null_shortname.log + +echo "This will loose all unstaged changes, Continue?" +read response +case $response in + y|Y|yes|YES) ;; + *) echo "Aborting" 2>&1; exit 1; ;; +esac + +rm -rf "$PHP_PARSER_RESULTS_DIR" +mkdir "$PHP_PARSER_RESULTS_DIR" + +rm -f "$LOG_FILE" + +git -C "$DRUPAL_CONSOLE_DIR" checkout . + +git -C "$DRUPAL_CONSOLE_DIR" grep -l addOption | +while read file; +do + PARSED_FILE="$(echo "$file" | sed -e 's/\//_/g')" + SRC_FILE="${DRUPAL_CONSOLE_DIR}/${file}" + + # Do a first conversion with php-parser, this looses the original + # formatting, but it's robust because it uses an actual parser, so the + # result can be used to validate the sed solution below. + php addOption-null-shortname-php-parse.php "$SRC_FILE" > "${PHP_PARSER_RESULTS_DIR}/${PARSED_FILE}" + + # The sed expression does this: + # - look for addOption; + # - append the next two lines to the pattern space (N;N;), to cover the case + # when the arguments on different lines; + # - separate the arguments, but also consider what the characters after the + # first comma are, sometimes there is a space and sometimes there is + # a newline with the indentation following, and we want to keep those as + # they were. + # - if it's false or an empty string, replace the second argument which + # would be in \3, with null + # - keep everything else as it was. + # + # The sed commands after the substitution tell to go on (N;N;) if there is + # no substitution (t) and to print and delete the pattern (P;D;) when + # a substitution succeed. + # + # This covers the case when another pattern is in the three lines which are + # being analyzed, e.g: + # + # ->addOption('quick', '', InputOption::VALUE_NONE, $this->trans('commands.database.query.options.quick')) + # ->addOption('debug', '', InputOption::VALUE_NONE, $this->trans('commands.database.query.options.debug')) + # ->addOption('html', '', InputOption::VALUE_NONE, $this->trans('commands.database.query.options.html')) + # ->addOption('xml', '', InputOption::VALUE_NONE, $this->trans('commands.database.query.options.xml')) + # ->addOption('raw', '', InputOption::VALUE_NONE, $this->trans('commands.database.query.options.raw')) + # ->addOption('vertical', '', InputOption::VALUE_NONE, $this->trans('commands.database.query.options.vertical')) + # ->addOption('batch', '', InputOption::VALUE_NONE, $this->trans('commands.database.query.options.batch')) + # + # See also https://unix.stackexchange.com/questions/26284 + sed -e "/addOption/{N;N;s/addOption(\([^,]*\),\([ \n]*\)\(''\|false\),\(.*\)/addOption(\1,\2null,\4/;ty;N;N;:y;P;D}" -i "$SRC_FILE" + + # Pretty print with php-parse the files converted with sed, so that they can be compared + # with the ones converted with addOption-null-shortname-php-parse.php from above. + php-parse -p "$SRC_FILE" | grep -v "^==" > "${PHP_PARSER_RESULTS_DIR}/${PARSED_FILE}.sed" + + # And print a report of the difference between the two conversion, if the + # sed command is correct there should be no difference at all. + echo "$file" >> "$LOG_FILE" + wdiff -3 "${PHP_PARSER_RESULTS_DIR}/${PARSED_FILE}" "${PHP_PARSER_RESULTS_DIR}/${PARSED_FILE}.sed" >> "$LOG_FILE" || true + echo >> "$LOG_FILE" + echo >> "$LOG_FILE" +done -- 2.1.4