astorm / pestle

A collection of command line scripts for Magento 2 code generation, and a PHP module system for organizing command line scripts.
MIT License
533 stars 101 forks source link

Odd behaviour when invoking runner.php directly #239

Open QwertyZW opened 7 years ago

QwertyZW commented 7 years ago

From a fresh master checkout.

Invoking runner.php directly produces a stack trace where as using pestle_dev doesn't. I'm not really sure why this is happening.

root@12c061acd73d:~/pestle# php runner.php help
PHP Fatal error:  Cannot redeclare Pulsestorm\Pestle\Library\exitWithErrorMessage() (previously declared in /root/pestle/library/a
ll.php:10393) in /root/pestle/modules/pulsestorm/pestle/library/module.php on line 10
PHP Stack trace:
PHP   1. {main}() /root/pestle/runner.php:0
PHP   2. main() /root/pestle/runner.php:7
PHP   3. Pulsestorm\Pestle\Runner\main() /root/pestle/runner.php:5
PHP   4. Pulsestorm\Pestle\Runner\doPestleImports() /root/pestle/modules/pulsestorm/pestle/runner/module.php:372
PHP   5. Pulsestorm\Pestle\Importer\pestle_import() /root/pestle/modules/pulsestorm/pestle/runner/module.php:180
PHP   6. Pulsestorm\Pestle\Importer\extractFunction() /root/pestle/modules/pulsestorm/pestle/importer/module.php:11
PHP   7. Pulsestorm\Pestle\Importer\includeModule() /root/pestle/modules/pulsestorm/pestle/importer/module.php:18
root@12c061acd73d:~/pestle# php ./pestle_dev help

                  _   _
                 | | | |
  _ __   ___  ___| |_| | ___
 | '_ \ / _ \/ __| __| |/ _ \
 | |_) |  __/\__ \ |_| |  __/
 | .__/ \___||___/\__|_|\___|
 | |
 |_|
pestle by Pulse Storm LLC

Usage:
  pestle command_name [options] [arguments]

Available commands:

Codecept
  codecept:convert-selenium-id-for-codecept  Converts a selenium IDE html test for conception

Magento2
  magento2:fix-direct-om                     ALPHA: Fixes direct use of PHP Object Manager
  magento2:fix-permissions-modphp            ALPHA: "Fixes" permissions for development boxes
  magento2:convert-system-xml                ALPHA: Partially Converts Magento 1 system.xml into Magento 2 system.xml
  magento2:convert-observers-xml             ALPHA: Partially converts Magento 1 config.xml to Magento 2
  magento2:extract-mage2-system-xml-paths    Generates Mage2 config.xml
  magento2:convert-class                     ALPHA: Partially converts Magento 1 class to Magento 2
  magento2:path-from-class                   Turns a PHP class into a Magento 2 path
  magento2:read-rest-schema                  BETA: Magento command, reads the rest schema on a Magento system
  magento2:class-from-path                   Turns a Magento file path into a PHP class
  magento2:check-templates                   Checks for incorrectly named template folder

Magento2 Generate
  magento2:generate:menu                     Generates configuration for Magento Adminhtml menu.xml files
  magento2:generate:module                   Generates new module XML, adds to file system
  magento2:generate:psr-log-level            For conversion of Zend Log Level into PSR Log Level
  magento2:generate:preference               Generates a Magento 2.1 ui grid listing and support classes.
  magento2:generate:route                    Creates a Route XML
  magento2:generate:crud-model               Generates a Magento 2 CRUD/AbstractModel class and support files
  magento2:generate:schema-upgrade           BETA: Generates a migration-based UpgradeSchema and UpgradeData classes
  magento2:generate:theme                    Generates Theme Configuration
  magento2:generate:full-module              Creates shell script with all pestle commands needed for full module output
  magento2:generate:ui:form                  Generates a Magento 2 UI Component form configuration and PHP boilerplate
  magento2:generate:observer                 Generates Magento 2 Observer
  magento2:generate:controller-edit-acl      Edits the const ADMIN_RESOURCE value of an admin controller
  magento2:generate:acl                      Generates a Magento 2 acl.xml file.
  magento2:generate:acl:change-title         Changes the title of a specific ACL rule in a Magento 2 acl.xml file
  magento2:generate:command                  Generates bin/magento command files
  magento2:generate:plugin-xml               Generates plugin XML
  magento2:generate:install                  BETA: Generates commands to install Magento via composer
  magento2:generate:config-helper            Generates a help class for reading Magento's configuration
  magento2:generate:di                       Injects a dependency into a class constructor
  magento2:generate:registration             Generates registration.php
  magento2:generate:view                     Generates view files (layout handle, phtml, Block, etc.)
  magento2:generate:ui:add-column-sections   Generates a Magento 2.1 ui grid listing and support classes.
  magento2:generate:ui:add-column-actions    Generates a Magento 2.1 ui grid listing and support classes.
  magento2:generate:ui:grid                  Generates a Magento 2.1 ui grid listing and support classes.
  magento2:generate:ui:add-to-layout         Adds a <uiComponent/> node to a named node in a layout update XML file
  magento2:generate:remove-named-node        Removes a named node from a generic XML configuration file

Magento2 Scan
  magento2:scan:registration                 Scans Magento 2 directories for missing registration.php files
  magento2:scan:acl-used                     Scans modules for ACL rule ids, makes sure they're all used/defined
  magento2:scan:class-and-namespace          BETA: Scans a Magento 2 module for misnamed PHP classes
  magento2:scan:htaccess                     ALPHA: Checks for missing Magento 2 HTACCESS files from a hard coded list

Magento2 Search
  magento2:search:search-controllers         Searches controllers

Nexmo
  nexmo:store-credentials                    One Line Description
  nexmo:verify-sendcode                      One Line Description
  nexmo:send-text                            Sends a text message
  nexmo:verify-request                       Sends initial request to verify user's phone number

Parsing
  parsing:csv-to-iif                         BETA: Converts a CSV file to .iif
  parsing:citicard                           BETA: Parses Citicard's CSV files into yaml

Pestle
  pestle:build-command-list                  Builds the command list
  pestle:baz-bar                             Another Hello World we can probably discard
  pestle:dev-namespace                       BETA: Used to move old pestle files to module.php -- still needed?
  pestle:foo-bar                             ALPHA: Another Hello World we can probably discard
  pestle:hello-argument                      A demo of pestle argument and option configuration/parsing
  pestle:dev-import                          Another Hello World we can probably discard
  pestle:export-module                       ALPHA: Seems to be a start at exporting a pestle module as functions.
  pestle:generate-command                    Generates pestle command boiler plate
  pestle:clear-cache                         BETA: Clears the pestle cache
  pestle:pestle-run-file                     ALPHA: Stub for running a single PHP file in a pestle context

Php
  php:format-php                             ALPHA: Experiments with a PHP formatter.
  php:extract-session                        ALPHA: Extracts data from a saved PHP session file
  php:test-namespace-integrity               ALPHA: Tests the "namespace integrity?  Not sure what this is anymore.

Pulsestorm
  pulsestorm:md-to-say                       Converts a markdown files to an aiff
  pulsestorm:monty-hall-problem              Runs Simulation of "Monty Hall Problem"
  pulsestorm:build-book                      BETA: Command for building No Frills Magento 2 Layout
  pulsestorm:orphan-content                  BETA: Used to scan my old pre-Wordpress archives for missing pages.
  pulsestorm:pandoc-md                       BETA: Uses pandoc to converts a markdown file to pdf, epub, epub3, html, txt

Uncategorized
  help                                       Alias for list
  list-commands                              Lists help
  selfupdate                                 Updates the pestle.phar file to the latest version
  test-output                                A test command for the output function that should probably be pruned
  testbed                                    Test Command
  hello-world                                A Hello World command.  Hello World!
  version                                    One Line Description
root@12c061acd73d:~/pestle#
astorm commented 7 years ago

This one's more an explanation/context for why this happens -- as much to get it written down somewhere as anything else. As of right now "the right" way to invoke pestle from the command line is via the pestle_dev script.

One of pestle's goals is to implement a python-like import system for PHP -- something that organizes code into individual modules, and allows users to import specific functions into their modules. Implementing this meant some Reflection and building up lists of functions in the /tmp/pestle_cache folder, and we're actively thinking of different/better ways to handle this. Those tradeoffs were acceptable to use for running this code via pestle.phar.

However -- if someone wants to use a pestle function in their own project -- the whole /tmp/pestle_cache folder seems like a burden too far. For this "pestle as PHP/Composer library" context, we generate an all.php file that contains the entire pestle library as a single include, with functions namespaced. Then, we have this library function included via a second PHP file, via the composer autoload feature

"autoload": {
    "files": ["library/autoload.php"]
},

All a user needs to do is include pestle via the composer file, and then can reuse any of our functions. Again, this is a crude, initial approach that we may change over time.

The problem this created: We want all.php loaded for folks who include this project in theirs, but for pestle.phar, pestle_dev, unit tests, etc., we do not want this all.php loaded. Instead we want the "only imports single functions" behavior.

That's why library/autoload.php has a number of early return checks that attempt to detect the context of the current request. For example -- this checks if the current context is a PHPUnit run

$backtrace = debug_backtrace();
$top       = array_pop($backtrace);
$file      = '';
if(isset($top['file']))
{ 
    $file = strToLower($top['file']);
}
$parts = explode('/', $file);
$last  = array_pop($parts);
if(strpos($last, 'phpunit') !== false)
{
    return;
}

If it is, the file returns. There's other checks as well -- but if none of them reach their respective return statements, we assume this is just some random PHP project that wants a pestle function, and we pull in all.php

include __DIR__ . '/all.php';

The Problem in this Issue: The runner.php script invokes pestle in its "real" mode, where pestle_import imports individual functions via the /tmp/pestle_cache business. However, there's not a check in autoload.php that checks if you're running runner.php directly. There are checks to see if you're invoking things via pestle, pestle.phar, or pestle_dev

//running as pestle_dev, pestle.phar, or pestle
global $argv;
if(isset($argv[0]))
{    
    $parts = explode('/', $argv[0]);
    $last = strToLower(array_pop($parts));
    if(in_array($last, ['pestle', 'pestle_dev', 'pestle.phar']))
    {
        return;
    }
}

When you're see the following error

PHP Fatal error:  Cannot redeclare Pulsestorm\Pestle\Library\exitWithErrorMessage() (previously declared in /root/pestle/library/all.php:10393) in 
/root/pestle/modules/pulsestorm/pestle/library/module.php on line 10
PHP Stack trace:

That's PHP complaining exitWithErrorMessage was already defined when the all.php file was included.

So, that's where things stand. Less a deliberate design and more a series of small steps. The pestle_import mechanism may be overhauled when we implement things like importing multiple functions are once, or an entire module's worth of functions. At that time we'll probably revisit the whole "running in pestle.phar mode vs. running in "normal composer library mode"" question.

Given all this is due for a major refactoring anyway, I'm not super wild about endlessly adding more special cases into autoload.php -- although if a pull request came in that was able to special case a direct call to runner from a "pestle as library" context I'd be open to that.

QwertyZW commented 7 years ago

I see...

I think there several ways this problem can be approached

1) How about declaring/defining a special namespace/function within runner.php and then checking for that in library/autoload.php? (with this you can name the invoking command anything you like!)

2) runner.php can check if it was called from pestle_dev and if not exec pestle_dev (hacky/short sighted approach?)

I think this part of the readme could use an update if ['pestle', 'pestle_dev', 'pestle.phar'] become the only three officially supported entry points

But I'm not sure if having the command be dependent of its name ($argv[0]) is a good idea all together like you've already mentioned

If you're interested in working on the framework itself, you can use the runner.php in the project root. I personally use it by dropping the following in my ~/bin.

#File: ~/bin/pestle_dev
#!/usr/bin/env php
<?php
require_once('/Users/alanstorm/Documents/github/astorm/pestle/runner.php');