├── .gitignore
├── .travis.yml
├── .travis
├── deploy_public.key
└── secrets.tar.enc
├── LICENSE
├── README.md
├── bin
└── deploy.sh
├── box.json
├── box.signed.json
├── composer.json
├── phpunit.hhvm.xml
├── phpunit.php
├── phpunit.xml
├── src
├── Command
│ ├── Command.php
│ ├── InfoCommand.php
│ ├── InstallCommand.php
│ ├── UninstallCommand.php
│ └── UpdateCommand.php
├── Console
│ └── Application.php
├── EntryPoint
│ ├── bootstrap.php
│ └── main.php
├── IO
│ ├── ConsoleIO.php
│ ├── IOInterface.php
│ └── NullIO.php
├── Installer
│ ├── Installer.php
│ ├── LinuxInstaller.php
│ ├── MacInstaller.php
│ ├── UnixInstaller.php
│ └── WindowsInstaller.php
├── System
│ ├── BsdSystem.php
│ ├── LinuxSystem.php
│ ├── MacSystem.php
│ ├── System.php
│ ├── UnixSystem.php
│ └── WindowsSystem.php
└── Util
│ └── ErrorHandler.php
└── tests
└── .gitkeep
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .travis/phar_private.key
3 | .travis/deploy_private.key
4 | .travis/secrets.tar
5 | vendor/
6 | bin/box.phar
7 | composer.lock
8 | jupyter-php-installer.phar
9 | jupyter-php-installer.phar.pubkey
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | language: php
4 |
5 | cache:
6 | directories:
7 | - "$HOME/.composer/cache"
8 | - vendor
9 |
10 | matrix:
11 | fast_finish: true
12 | include:
13 | - php: 7.0
14 | env:
15 | - EXECUTE_DEPLOYMENT=true
16 | - php: 7.1
17 |
18 | before_install:
19 | - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini ; fi
20 | - travis_retry composer self-update
21 |
22 | install:
23 | - travis_retry composer install --prefer-source --no-interaction
24 | - composer info -i
25 |
26 | script:
27 | - vendor/bin/phpunit
28 |
29 | after_success:
30 | - if [[ $EXECUTE_DEPLOYMENT == 'true' && $TRAVIS_PULL_REQUEST == 'false' ]]; then composer install --no-dev --prefer-dist --no-interaction ; fi
31 | - if [[ $EXECUTE_DEPLOYMENT == 'true' && $TRAVIS_PULL_REQUEST == 'false' ]]; then ./bin/deploy.sh ; fi
32 |
--------------------------------------------------------------------------------
/.travis/deploy_public.key:
--------------------------------------------------------------------------------
1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDUXU2ODDrbfdRatnMFgSzEJHvThGeNbvgo6WYKmy35ER+CctnVrC/SQ1tcXAHC+F6GKhSoJDMVazti3i9wp69bkYmGTY/OKbYltBP5wldtD4oF1mTmWzAB6EoiPac9BNddry57sHFH7N/zlQVSf9ZuMd3iXJLTTD6VJeVWuSTiIW/efby9ICVyoGEqnNBeoxDFD3L9w6tW9IPZHh5Sma2dzr3+C4TsEGFmDFYIEtK+Ar49XH03OH7hd5xALqxxSTE5c40Dt5N106ch6eKb2BhA9fVIFbS9/hhgh+ZV5n1Y53op0CDK8aadoQTzvQK/AdfSnDoX2hQWNBPAzyTJps6q2OoZdaV+gbAahsHwOgvRn4kYChUzU201DcRi4xMI2QkQ4f+NPUTgtJnvRbZUPRO7va7PLkXEEZqFv1Xs6sE1ua7fB7NUyLb9MrQznJrX7fOHE82veoDrqn2du3cEPJ/FATqL+dzynB6YjOk7J1F7qaxSAaURM3fG12dcbZYgfVKTDo+OieLEoYqtm8FGMTPM8xIQR8wm4euEDxsh6Ex4sDMHKXIRu88Hx9VPwYUzv1vIVQfbbKIc65G91zJm91cW5t0dsKY9QD2u2PzDY9EmwNfihRY+jMP2A47OSzNCaqdx/qj7SG7GUjnlvoi1/sKhGP5gNwVtuqSnVlogN0MXyQ== castarco@litipk.com
2 |
--------------------------------------------------------------------------------
/.travis/secrets.tar.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Coder-Spirit/Jupyter-PHP-Installer/ac86a042b6db8fd196062775836831bfe675b0a7/.travis/secrets.tar.enc
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2017 Litipk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Jupyter-PHP Installer ([Main Page](https://litipk.github.io/Jupyter-PHP-Installer/))
2 |
3 | [](https://twitter.com/castarco)
4 | [](LICENSE)
5 | [](https://packagist.org/packages/Litipk/jupyter-php)
6 |
7 | ## Introduction
8 |
9 | [**Jupyter-PHP**](https://github.com/Litipk/Jupyter-PHP) is a PHP kernel for [*Jupyter*](http://jupyter.org). This
10 | repository holds an installer to make easier installing the Jupyter-PHP kernel.
11 |
12 | ## Getting started
13 |
14 | Go to the [main page](https://litipk.github.io/Jupyter-PHP-Installer/) and follow the instructions.
15 |
16 | ## Learn more
17 |
18 | * [Chat Room](https://gitter.im/Litipk/Jupyter-PHP) : If you want to have a real-time chat with other Jupyter-PHP users or developers, you can do it here.
19 | * [Group / Mail List](https://groups.io/g/jupyter-php) : If a chat room isn't enough to post your doubts or ideas, you can join to our mail list.
20 |
21 | ## How to contribute
22 |
23 | * First of all, you can take a look on the [bugtracker](https://github.com/Litipk/Jupyter-PHP-Installer/issues) and decide if there is something that you want to do :wink: . If you think there are missing improvements in this file, then you are invited to modify the TODO list.
24 | * You can also send us bug reports using the same bugtracker.
25 | * If you are really interested on helping to improve Litipk\BigNumbers, we recommend to read the [contributing guidelines](https://github.com/Litipk/Jupyter-PHP-Installer/blob/master/CONTRIBUTING.md).
26 |
27 |
28 | ## License
29 |
30 | Jupyter-PHP and its installer are licensed under the [MIT License](https://github.com/Litipk/Jupyter-PHP-Installer/blob/master/LICENSE).
31 |
--------------------------------------------------------------------------------
/bin/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "Starting build";
4 |
5 | # We only generate packages for tagged versions
6 | git describe --tags --exact-match HEAD || {
7 | echo "Skipped build";
8 | exit 0;
9 | }
10 |
11 | openssl aes-256-cbc -K $encrypted_f21abcc37842_key -iv $encrypted_f21abcc37842_iv -in .travis/secrets.tar.enc -out .travis/secrets.tar -d
12 |
13 | # Unpack secrets
14 | tar xvf .travis/secrets.tar -C .travis
15 |
16 | # Setup SSH agent:
17 | eval "$(ssh-agent -s)" #start the ssh agent
18 | chmod 600 .travis/deploy_private.key
19 | ssh-add .travis/deploy_private.key
20 |
21 | # Setup git defaults:
22 | git config --global user.email "castarco@gmail.com"
23 | git config --global user.name "Andreu Correa Casablanca"
24 |
25 | # Add SSH-based remote to GitHub repo:
26 | git remote add deploy git@github.com:Litipk/Jupyter-PHP-Installer.git
27 | git fetch deploy
28 |
29 | # Get Box and build
30 | wget https://github.com/box-project/box2/releases/download/2.7.0/box-2.7.0.phar -O ./bin/box.phar
31 | chmod a+x ./bin/box.phar
32 |
33 | # Unsigned build
34 | ./bin/box.phar build -vv
35 | mv jupyter-php-installer.phar jupyter-php-installer.phar.tmp
36 |
37 | # Signed build
38 | ./bin/box.phar build -c box.signed.json -vv
39 | mv jupyter-php-installer.phar jupyter-php-installer.signed.phar.tmp
40 | mv jupyter-php-installer.phar.pubkey jupyter-php-installer.signed.phar.pubkey.tmp
41 |
42 | # Checkout gh-pages and add PHAR file and version:
43 | git checkout -b gh-pages deploy/gh-pages
44 |
45 | # Moving unsigned build
46 | mv jupyter-php-installer.phar.tmp dist/jupyter-php-installer.phar
47 | cd dist && md5sum jupyter-php-installer.phar > jupyter-php-installer.phar.md5 && cd ..
48 | cd dist && sha1sum jupyter-php-installer.phar > jupyter-php-installer.phar.sha1 && cd ..
49 | cd dist && sha256sum jupyter-php-installer.phar > jupyter-php-installer.phar.sha256 && cd ..
50 | cd dist && sha512sum jupyter-php-installer.phar > jupyter-php-installer.phar.sha512 && cd ..
51 |
52 | # Moving signed build
53 | mv jupyter-php-installer.signed.phar.tmp dist/jupyter-php-installer.signed.phar
54 | mv jupyter-php-installer.signed.phar.pubkey.tmp dist/jupyter-php-installer.signed.phar.pubkey
55 | cd dist && md5sum jupyter-php-installer.signed.phar > jupyter-php-installer.signed.phar.md5 && cd ..
56 | cd dist && sha1sum jupyter-php-installer.signed.phar > jupyter-php-installer.signed.phar.sha1 && cd ..
57 | cd dist && sha256sum jupyter-php-installer.signed.phar > jupyter-php-installer.signed.phar.sha256 && cd ..
58 | cd dist && sha512sum jupyter-php-installer.signed.phar > jupyter-php-installer.signed.phar.sha512 && cd ..
59 | cd dist && md5sum jupyter-php-installer.signed.phar.pubkey > jupyter-php-installer.signed.phar.pubkey.md5 && cd ..
60 | cd dist && sha1sum jupyter-php-installer.signed.phar.pubkey > jupyter-php-installer.signed.phar.pubkey.sha1 && cd ..
61 | cd dist && sha256sum jupyter-php-installer.signed.phar.pubkey > jupyter-php-installer.signed.phar.pubkey.sha256 && cd ..
62 | cd dist && sha512sum jupyter-php-installer.signed.phar.pubkey > jupyter-php-installer.signed.phar.pubkey.sha512 && cd ..
63 |
64 | # Adding phar files
65 | git add dist/jupyter-php-installer.phar dist/jupyter-php-installer.signed.phar
66 |
67 | # Adding public keys
68 | git add dist/jupyter-php-installer.signed.phar.pubkey
69 |
70 | # Adding "unsigned" checksums
71 | git add dist/jupyter-php-installer.phar.md5 dist/jupyter-php-installer.phar.sha1 dist/jupyter-php-installer.phar.sha256 dist/jupyter-php-installer.phar.sha512
72 |
73 | # Adding "signed" checksums
74 | git add dist/jupyter-php-installer.signed.phar.md5 dist/jupyter-php-installer.signed.phar.sha1 dist/jupyter-php-installer.signed.phar.sha256 dist/jupyter-php-installer.signed.phar.sha512
75 |
76 | # Adding public key checksums
77 | git add dist/jupyter-php-installer.signed.phar.pubkey.md5 dist/jupyter-php-installer.signed.phar.pubkey.sha1 dist/jupyter-php-installer.signed.phar.pubkey.sha256 dist/jupyter-php-installer.signed.phar.pubkey.sha512
78 |
79 |
80 | # Commit and push:
81 | git commit -m 'Rebuilt phar'
82 | git push deploy gh-pages:gh-pages
--------------------------------------------------------------------------------
/box.json:
--------------------------------------------------------------------------------
1 | {
2 | "alias": "jupyter-php-installer.phar",
3 | "chmod": "0755",
4 | "compression": "GZ",
5 | "directories": ["src"],
6 | "files": [
7 | "LICENSE",
8 | "README.md"
9 | ],
10 | "finder": [
11 | {
12 | "name": "*.php",
13 | "exclude": ["Tests", "Tester"],
14 | "in": "vendor"
15 | }
16 | ],
17 | "git-version": "package_version",
18 | "main": "src/EntryPoint/main.php",
19 | "output": "jupyter-php-installer.phar",
20 | "stub": true
21 | }
--------------------------------------------------------------------------------
/box.signed.json:
--------------------------------------------------------------------------------
1 | {
2 | "alias": "jupyter-php-installer.phar",
3 | "chmod": "0755",
4 | "algorithm": "OPENSSL",
5 | "compression": "GZ",
6 | "directories": ["src"],
7 | "files": [
8 | "LICENSE",
9 | "README.md"
10 | ],
11 | "finder": [
12 | {
13 | "name": "*.php",
14 | "exclude": ["Tests", "Tester"],
15 | "in": "vendor"
16 | }
17 | ],
18 | "git-version": "package_version",
19 | "main": "src/EntryPoint/main.php",
20 | "output": "jupyter-php-installer.phar",
21 | "stub": true,
22 | "key": ".travis/phar_private.key"
23 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "litipk/jupyter-php-installer",
3 | "description": "An installer for Jupyter-PHP",
4 | "type": "project",
5 | "license": "MIT",
6 | "require": {
7 | "php": ">=7.0",
8 | "symfony/console": "^3.0",
9 | "seld/cli-prompt": "^1.0"
10 | },
11 | "require-dev": {
12 | "phpunit/phpunit": "^6.1"
13 | },
14 | "autoload": {
15 | "psr-4": { "Litipk\\JupyterPhpInstaller\\": "src/"}
16 | },
17 | "scripts": {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/phpunit.hhvm.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 | ./tests/
17 |
18 |
19 |
20 |
21 | ./src/
22 |
23 |
24 |
--------------------------------------------------------------------------------
/phpunit.php:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 | ./tests/
17 |
18 |
19 |
20 |
21 | ./src/
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Command/Command.php:
--------------------------------------------------------------------------------
1 | io) {
22 | $application = $this->getApplication();
23 |
24 | if ($application instanceof Application) {
25 | $this->io = $application->getIO();
26 | } else {
27 | $this->io = new NullIO();
28 | }
29 | }
30 |
31 | return $this->io;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Command/InfoCommand.php:
--------------------------------------------------------------------------------
1 | setName('info')
19 | ->setDescription('Shows info about installed Jupyter-PHP kernels.')
20 | ->setDefinition([
21 | new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details.'),
22 | new InputArgument(
23 | 'path',
24 | InputArgument::OPTIONAL,
25 | 'If is provided, then instead of looking for install paths, uses the given one.'
26 | )
27 | ])
28 | ->setHelp(
29 | "The info command looks for installed Jupyter-PHP kernels\n".
30 | "and shows info about them.\n\n".
31 | "php jupyter-php-installer.phar info\n\n"
32 | );
33 | }
34 |
35 | protected function execute(InputInterface $input, OutputInterface $output)
36 | {
37 |
38 | }
39 | }
--------------------------------------------------------------------------------
/src/Command/InstallCommand.php:
--------------------------------------------------------------------------------
1 | setName('install')
24 | ->setDescription('Installs a Jupyter-PHP kernel.')
25 | ->setDefinition([
26 | new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details.'),
27 | new InputArgument(
28 | 'path',
29 | InputArgument::OPTIONAL,
30 | 'This is the path where the Jupyter-PHP kernel will be installed.'
31 | ),
32 | new InputArgument(
33 | 'composer_cmd',
34 | InputArgument::OPTIONAL,
35 | 'The installer will use this command to execute Composer.'
36 | )
37 | ])
38 | ->setHelp(
39 | "The install command installs a Jupyter-PHP kernel in your\n".
40 | "system and makes possible that Jupyter uses it to create \"PHP\n".
41 | "Notebooks\"\n\n".
42 | "php jupyter-php-installer.phar install\n\n"
43 | );
44 | }
45 |
46 | protected function execute(InputInterface $input, OutputInterface $output)
47 | {
48 | $installPath = ($input->hasArgument('path')) ? $input->getArgument('path') : null;
49 | $composerCmd = ($input->hasArgument('composer_cmd')) ? $input->getArgument('composer_cmd') : null;
50 |
51 | $io = $this->getIO();
52 |
53 | try {
54 | $installer = Installer::getInstaller($composerCmd);
55 | } catch (\RuntimeException $e) {
56 | $io->writeError('ERROR: '.$e->getMessage());
57 | // TODO : Use verbosity levels to enable showing the stacktrace
58 | return self::RETURN_CODE_INSTALLER_INSTANTIATION_ERROR;
59 | }
60 |
61 | try {
62 | $installer->install($installPath, (bool)$input->getOption('verbose'));
63 | } catch (\RuntimeException $e) {
64 | $io->writeError('ERROR: '.$e->getMessage());
65 | // TODO : Use verbosity levels to enable showing the stacktrace
66 | return self::RETURN_CODE_INSTALLER_INSTALL_ERROR;
67 | }
68 |
69 | $io->write('The Jupyter-PHP kernel has been successfully installed.');
70 |
71 | return self::RETURN_CODE_OK;
72 | }
73 | }
--------------------------------------------------------------------------------
/src/Command/UninstallCommand.php:
--------------------------------------------------------------------------------
1 | setName('uninstall')
19 | ->setDescription('Uninstalls a Jupyter-PHP kernel.')
20 | ->setDefinition([
21 | new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details.'),
22 | new InputArgument(
23 | 'path',
24 | InputArgument::OPTIONAL,
25 | 'This is the path where the Jupyter-PHP kernel is installed.'
26 | ),
27 | new InputArgument(
28 | 'composer_cmd',
29 | InputArgument::OPTIONAL,
30 | 'The installer will use this command to execute Composer.'
31 | )
32 | ])
33 | ->setHelp(
34 | "The uninstall command uninstalls a Jupyter-PHP kernel from your\n".
35 | "system.\n\n".
36 | "php jupyter-php-installer.phar uninstall\n\n"
37 | );
38 | }
39 |
40 | protected function execute(InputInterface $input, OutputInterface $output)
41 | {
42 |
43 | }
44 | }
--------------------------------------------------------------------------------
/src/Command/UpdateCommand.php:
--------------------------------------------------------------------------------
1 | setName('update')
19 | ->setDescription('Updates the installed Jupyter-PHP kernel.')
20 | ->setDefinition([
21 | new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details.'),
22 | new InputArgument(
23 | 'path',
24 | InputArgument::OPTIONAL,
25 | 'This is the path where the Jupyter-PHP kernel is installed.'
26 | ),
27 | new InputArgument(
28 | 'composer_cmd',
29 | InputArgument::OPTIONAL,
30 | 'The installer will use this command to execute Composer.'
31 | )
32 | ])
33 | ->setHelp("The update command updates a previously installed Jupyter-PHP\n".
34 | "kernel.\n\n".
35 | "php jupyter-php-installer.phar pdate\n\n"
36 | );
37 | }
38 |
39 | protected function execute(InputInterface $input, OutputInterface $output)
40 | {
41 |
42 | }
43 | }
--------------------------------------------------------------------------------
/src/Console/Application.php:
--------------------------------------------------------------------------------
1 | handleShutdown(); });
46 | $shutdownRegistered = true;
47 | }
48 |
49 | parent::__construct('Jupyter-PHP Installer', '0.2');
50 | }
51 |
52 | /**
53 | * Starts the application, boilerplate code.
54 | * @param InputInterface|null $input
55 | * @param OutputInterface|null $output
56 | * @return int
57 | */
58 | public function run(InputInterface $input = null, OutputInterface $output = null)
59 | {
60 | if (null === $output) {
61 | $output = new ConsoleOutput(
62 | ConsoleOutput::VERBOSITY_NORMAL,
63 | null,
64 | new OutputFormatter(false, [
65 | 'highlight' => new OutputFormatterStyle('red'),
66 | 'warning' => new OutputFormatterStyle('black', 'yellow'),
67 | ])
68 | );
69 | }
70 |
71 | return parent::run($input, $output);
72 | }
73 |
74 | /**
75 | * Runs the application's business logic.
76 | * @param InputInterface $input
77 | * @param OutputInterface $output
78 | * @return int
79 | */
80 | public function doRun(InputInterface $input, OutputInterface $output)
81 | {
82 | $this->io = new ConsoleIO($input, $output, $this->getHelperSet());
83 | ErrorHandler::register($this->io);
84 | $io = $this->io;
85 |
86 | if (PHP_VERSION_ID < 70000) {
87 | $io->writeError(
88 | ''.
89 | 'This installer only officially supports PHP 7.0 and above, you will most likely encounter problems with your PHP '.
90 | PHP_VERSION.', upgrading is strongly recommended'.
91 | ''
92 | );
93 | }
94 |
95 | if (extension_loaded('xdebug')) {
96 | $io->writeError(
97 | ''.
98 | 'You are running PHP-CLI with xdebug enabled. This will have a major impact on the kernel\'s performance.'.
99 | ''
100 | );
101 | }
102 |
103 | return parent::doRun($input, $output);
104 | }
105 |
106 | /**
107 | * @return IOInterface
108 | */
109 | public function getIO()
110 | {
111 | return $this->io;
112 | }
113 |
114 | /**
115 | * Initializes all the composer commands.
116 | */
117 | protected function getDefaultCommands()
118 | {
119 | $commands = parent::getDefaultCommands();
120 | $commands[] = new InstallCommand();
121 | $commands[] = new UninstallCommand();
122 | $commands[] = new UpdateCommand();
123 | $commands[] = new InfoCommand();
124 |
125 |
126 | if ('phar:' === substr(__FILE__, 0, 5)) {
127 | // Nothing to do, yet
128 | }
129 |
130 | return $commands;
131 | }
132 |
133 | /**
134 | * Handles the program shutdown.
135 | */
136 | private function handleShutdown()
137 | {
138 | $lastError = error_get_last();
139 |
140 | if (!empty($lastError) && isset($lastError['message'])) {
141 | $this->handleShutdownLastError($lastError);
142 | }
143 | }
144 |
145 | /**
146 | * Handles the errors that caused the shutdown.
147 | * @param array $lastError
148 | */
149 | private function handleShutdownLastError(array $lastError)
150 | {
151 | if (
152 | strpos($lastError['message'], 'Allowed memory') !== false /* Zend PHP out of memory error */ ||
153 | strpos($lastError['message'], 'exceeded memory') !== false /* HHVM out of memory errors */
154 | ) {
155 | $this->explainMemoryErrorSolution();
156 | }
157 | }
158 |
159 | /**
160 | * Explains to the user what can be done to solve the memory error that caused the shutdown.
161 | */
162 | private function explainMemoryErrorSolution()
163 | {
164 | if (extension_loaded('xdebug')) {
165 | echo "\n" . 'You should disable the Xdebug extension in your php.ini settings file.' . "\n";
166 | } else {
167 | echo "\n" . 'You should increase the `memory_limit` parameter in your php.ini settings file.' . "\n";
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/EntryPoint/bootstrap.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 | function includeIfExists($file)
13 | {
14 | return file_exists($file) ? include $file : false;
15 | }
16 |
17 | if ((!$loader = includeIfExists(__DIR__ . '/../../vendor/autoload.php'))) {
18 | echo 'The dependencies are missing, you should use `composer install`.'.PHP_EOL;
19 | exit(1);
20 | }
21 |
22 | return $loader;
23 |
--------------------------------------------------------------------------------
/src/EntryPoint/main.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | run();
17 |
--------------------------------------------------------------------------------
/src/IO/ConsoleIO.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | * Andres Correa
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace Litipk\JupyterPhpInstaller\IO;
15 |
16 | use Symfony\Component\Console\Input\InputInterface;
17 | use Symfony\Component\Console\Output\ConsoleOutputInterface;
18 | use Symfony\Component\Console\Output\OutputInterface;
19 | use Symfony\Component\Console\Helper\HelperSet;
20 | use Symfony\Component\Console\Question\ConfirmationQuestion;
21 | use Symfony\Component\Console\Question\Question;
22 |
23 | /**
24 | * The Input/Output helper.
25 | *
26 | * @author François Pluchino
27 | * @author Jordi Boggiano
28 | * @author Andres Correa
29 | */
30 | final class ConsoleIO implements IOInterface
31 | {
32 | protected $input;
33 | protected $output;
34 | protected $helperSet;
35 | protected $lastMessage;
36 | protected $lastMessageErr;
37 | private $startTime;
38 |
39 | /**
40 | * Constructor.
41 | *
42 | * @param InputInterface $input The input instance
43 | * @param OutputInterface $output The output instance
44 | * @param HelperSet $helperSet The helperSet instance
45 | */
46 | public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet)
47 | {
48 | $this->input = $input;
49 | $this->output = $output;
50 | $this->helperSet = $helperSet;
51 | }
52 |
53 | public function enableDebugging($startTime)
54 | {
55 | $this->startTime = $startTime;
56 | }
57 |
58 | /**
59 | * {@inheritDoc}
60 | */
61 | public function isInteractive()
62 | {
63 | return $this->input->isInteractive();
64 | }
65 |
66 | /**
67 | * {@inheritDoc}
68 | */
69 | public function isDecorated()
70 | {
71 | return $this->output->isDecorated();
72 | }
73 |
74 | /**
75 | * {@inheritDoc}
76 | */
77 | public function isVerbose()
78 | {
79 | return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
80 | }
81 |
82 | /**
83 | * {@inheritDoc}
84 | */
85 | public function isVeryVerbose()
86 | {
87 | return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
88 | }
89 |
90 | /**
91 | * {@inheritDoc}
92 | */
93 | public function isDebug()
94 | {
95 | return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
96 | }
97 |
98 | /**
99 | * {@inheritDoc}
100 | */
101 | public function write($messages, $newline = true)
102 | {
103 | $this->doWrite($messages, $newline, false);
104 | }
105 |
106 | /**
107 | * {@inheritDoc}
108 | */
109 | public function writeError($messages, $newline = true)
110 | {
111 | $this->doWrite($messages, $newline, true);
112 | }
113 |
114 | /**
115 | * @param array $messages
116 | * @param bool $newline
117 | * @param bool $stderr
118 | */
119 | private function doWrite($messages, $newline, $stderr)
120 | {
121 | if (null !== $this->startTime) {
122 | $memoryUsage = memory_get_usage() / 1024 / 1024;
123 | $timeSpent = microtime(true) - $this->startTime;
124 | $messages = array_map(function ($message) use ($memoryUsage, $timeSpent) {
125 | return sprintf('[%.1fMB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
126 | }, (array) $messages);
127 | }
128 |
129 | if (true === $stderr && $this->output instanceof ConsoleOutputInterface) {
130 | $this->output->getErrorOutput()->write($messages, $newline);
131 | $this->lastMessageErr = join($newline ? "\n" : '', (array) $messages);
132 |
133 | return;
134 | }
135 |
136 | $this->output->write($messages, $newline);
137 | $this->lastMessage = join($newline ? "\n" : '', (array) $messages);
138 | }
139 |
140 | /**
141 | * {@inheritDoc}
142 | */
143 | public function overwrite($messages, $newline = true, $size = null)
144 | {
145 | $this->doOverwrite($messages, $newline, $size, false);
146 | }
147 |
148 | /**
149 | * {@inheritDoc}
150 | */
151 | public function overwriteError($messages, $newline = true, $size = null)
152 | {
153 | $this->doOverwrite($messages, $newline, $size, true);
154 | }
155 |
156 | /**
157 | * @param array $messages
158 | * @param bool $newline
159 | * @param int $size
160 | * @param bool $stderr
161 | */
162 | private function doOverwrite($messages, $newline, $size, $stderr)
163 | {
164 | // messages can be an array, let's convert it to string anyway
165 | $messages = join($newline ? "\n" : '', (array) $messages);
166 |
167 | // since overwrite is supposed to overwrite last message...
168 | if (!isset($size)) {
169 | // removing possible formatting of lastMessage with strip_tags
170 | $size = strlen(strip_tags($stderr ? $this->lastMessageErr : $this->lastMessage));
171 | }
172 | // ...let's fill its length with backspaces
173 | $this->doWrite(str_repeat("\x08", $size), false, $stderr);
174 |
175 | // write the new message
176 | $this->doWrite($messages, false, $stderr);
177 |
178 | $fill = $size - strlen(strip_tags($messages));
179 | if ($fill > 0) {
180 | // whitespace whatever has left
181 | $this->doWrite(str_repeat(' ', $fill), false, $stderr);
182 | // move the cursor back
183 | $this->doWrite(str_repeat("\x08", $fill), false, $stderr);
184 | }
185 |
186 | if ($newline) {
187 | $this->doWrite('', true, $stderr);
188 | }
189 |
190 | if ($stderr) {
191 | $this->lastMessageErr = $messages;
192 | } else {
193 | $this->lastMessage = $messages;
194 | }
195 | }
196 |
197 | /**
198 | * {@inheritDoc}
199 | */
200 | public function ask($question, $default = null)
201 | {
202 | $output = $this->output;
203 |
204 | if ($output instanceof ConsoleOutputInterface) {
205 | $output = $output->getErrorOutput();
206 | }
207 |
208 | /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
209 | $helper = $this->helperSet->get('question');
210 | $question = new Question($question, $default);
211 |
212 | return $helper->ask($this->input, $output, $question);
213 | }
214 |
215 | /**
216 | * {@inheritDoc}
217 | */
218 | public function askConfirmation($question, $default = true)
219 | {
220 | $output = $this->output;
221 |
222 | if ($output instanceof ConsoleOutputInterface) {
223 | $output = $output->getErrorOutput();
224 | }
225 |
226 | /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
227 | $helper = $this->helperSet->get('question');
228 | $question = new ConfirmationQuestion($question, $default);
229 |
230 | return $helper->ask($this->input, $output, $question);
231 | }
232 |
233 | /**
234 | * {@inheritDoc}
235 | */
236 | public function askAndValidate($question, $validator, $attempts = null, $default = null)
237 | {
238 | $output = $this->output;
239 |
240 | if ($output instanceof ConsoleOutputInterface) {
241 | $output = $output->getErrorOutput();
242 | }
243 |
244 | /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
245 | $helper = $this->helperSet->get('question');
246 | $question = new Question($question, $default);
247 | $question->setValidator($validator);
248 | $question->setMaxAttempts($attempts);
249 |
250 | return $helper->ask($this->input, $output, $question);
251 | }
252 |
253 | /**
254 | * {@inheritDoc}
255 | */
256 | public function askAndHideAnswer($question)
257 | {
258 | $this->writeError($question, false);
259 |
260 | return \Seld\CliPrompt\CliPrompt::hiddenPrompt(true);
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/src/IO/IOInterface.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | * Andres Correa
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 |
15 | namespace Litipk\JupyterPhpInstaller\IO;
16 |
17 |
18 | /**
19 | * The Input/Output helper interface.
20 | *
21 | * @author François Pluchino
22 | * @author Andres Correa
23 | */
24 | interface IOInterface
25 | {
26 | /**
27 | * Is this input means interactive?
28 | *
29 | * @return bool
30 | */
31 | public function isInteractive();
32 |
33 | /**
34 | * Is this output verbose?
35 | *
36 | * @return bool
37 | */
38 | public function isVerbose();
39 |
40 | /**
41 | * Is the output very verbose?
42 | *
43 | * @return bool
44 | */
45 | public function isVeryVerbose();
46 |
47 | /**
48 | * Is the output in debug verbosity?
49 | *
50 | * @return bool
51 | */
52 | public function isDebug();
53 |
54 | /**
55 | * Is this output decorated?
56 | *
57 | * @return bool
58 | */
59 | public function isDecorated();
60 |
61 | /**
62 | * Writes a message to the output.
63 | *
64 | * @param string|array $messages The message as an array of lines or a single string
65 | * @param bool $newline Whether to add a newline or not
66 | */
67 | public function write($messages, $newline = true);
68 |
69 | /**
70 | * Writes a message to the error output.
71 | *
72 | * @param string|array $messages The message as an array of lines or a single string
73 | * @param bool $newline Whether to add a newline or not
74 | */
75 | public function writeError($messages, $newline = true);
76 |
77 | /**
78 | * Overwrites a previous message to the output.
79 | *
80 | * @param string|array $messages The message as an array of lines or a single string
81 | * @param bool $newline Whether to add a newline or not
82 | * @param int $size The size of line
83 | */
84 | public function overwrite($messages, $newline = true, $size = null);
85 |
86 | /**
87 | * Overwrites a previous message to the error output.
88 | *
89 | * @param string|array $messages The message as an array of lines or a single string
90 | * @param bool $newline Whether to add a newline or not
91 | * @param int $size The size of line
92 | */
93 | public function overwriteError($messages, $newline = true, $size = null);
94 |
95 | /**
96 | * Asks a question to the user.
97 | *
98 | * @param string|array $question The question to ask
99 | * @param string $default The default answer if none is given by the user
100 | *
101 | * @throws \RuntimeException If there is no data to read in the input stream
102 | * @return string The user answer
103 | */
104 | public function ask($question, $default = null);
105 |
106 | /**
107 | * Asks a confirmation to the user.
108 | *
109 | * The question will be asked until the user answers by nothing, yes, or no.
110 | *
111 | * @param string|array $question The question to ask
112 | * @param bool $default The default answer if the user enters nothing
113 | *
114 | * @return bool true if the user has confirmed, false otherwise
115 | */
116 | public function askConfirmation($question, $default = true);
117 |
118 | /**
119 | * Asks for a value and validates the response.
120 | *
121 | * The validator receives the data to validate. It must return the
122 | * validated data when the data is valid and throw an exception
123 | * otherwise.
124 | *
125 | * @param string|array $question The question to ask
126 | * @param callback $validator A PHP callback
127 | * @param null|int $attempts Max number of times to ask before giving up (default of null means infinite)
128 | * @param mixed $default The default answer if none is given by the user
129 | *
130 | * @throws \Exception When any of the validators return an error
131 | * @return mixed
132 | */
133 | public function askAndValidate($question, $validator, $attempts = null, $default = null);
134 |
135 | /**
136 | * Asks a question to the user and hide the answer.
137 | *
138 | * @param string $question The question to ask
139 | *
140 | * @return string The answer
141 | */
142 | public function askAndHideAnswer($question);
143 | }
144 |
--------------------------------------------------------------------------------
/src/IO/NullIO.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | * Andres Correa
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace Litipk\JupyterPhpInstaller\IO;
15 |
16 | /**
17 | * IOInterface that is not interactive and never writes the output
18 | *
19 | * @author Christophe Coevoet
20 | */
21 | class NullIO implements IOInterface
22 | {
23 | /**
24 | * {@inheritDoc}
25 | */
26 | public function isInteractive()
27 | {
28 | return false;
29 | }
30 |
31 | /**
32 | * {@inheritDoc}
33 | */
34 | public function isVerbose()
35 | {
36 | return false;
37 | }
38 |
39 | /**
40 | * {@inheritDoc}
41 | */
42 | public function isVeryVerbose()
43 | {
44 | return false;
45 | }
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | public function isDebug()
51 | {
52 | return false;
53 | }
54 |
55 | /**
56 | * {@inheritDoc}
57 | */
58 | public function isDecorated()
59 | {
60 | return false;
61 | }
62 |
63 | /**
64 | * {@inheritDoc}
65 | */
66 | public function write($messages, $newline = true)
67 | {
68 | }
69 |
70 | /**
71 | * {@inheritDoc}
72 | */
73 | public function writeError($messages, $newline = true)
74 | {
75 | }
76 |
77 | /**
78 | * {@inheritDoc}
79 | */
80 | public function overwrite($messages, $newline = true, $size = 80)
81 | {
82 | }
83 |
84 | /**
85 | * {@inheritDoc}
86 | */
87 | public function overwriteError($messages, $newline = true, $size = 80)
88 | {
89 | }
90 |
91 | /**
92 | * {@inheritDoc}
93 | */
94 | public function ask($question, $default = null)
95 | {
96 | return $default;
97 | }
98 |
99 | /**
100 | * {@inheritDoc}
101 | */
102 | public function askConfirmation($question, $default = true)
103 | {
104 | return $default;
105 | }
106 |
107 | /**
108 | * {@inheritDoc}
109 | */
110 | public function askAndValidate($question, $validator, $attempts = false, $default = null)
111 | {
112 | return $default;
113 | }
114 |
115 | /**
116 | * {@inheritDoc}
117 | */
118 | public function askAndHideAnswer($question)
119 | {
120 | return null;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/Installer/Installer.php:
--------------------------------------------------------------------------------
1 | getComposerCommand();
25 |
26 | if (null === $composerCmd || !$system->checkIfCommandExists($composerCmd)) {
27 | throw new \RuntimeException('Unable to find the composer executable.');
28 | }
29 |
30 | if ($system instanceof LinuxSystem) {
31 | return new LinuxInstaller($system, $composerCmd);
32 | } elseif ($system instanceof MacSystem) {
33 | return new MacInstaller($system, $composerCmd);
34 | } elseif ($system instanceof UnixSystem) {
35 | // Fallback for BSD systems
36 | return new LinuxInstaller($system, $composerCmd);
37 | } elseif ($system instanceof WindowsSystem) {
38 | return new WindowsInstaller($system, $composerCmd);
39 | } else {
40 | throw new \RuntimeException('This platform is unknown for the installer');
41 | }
42 | }
43 |
44 | public function install(string $installPath = null, bool $beVerbose = false)
45 | {
46 | $installPath = (null !== $installPath) ? $installPath : $this->getInstallPath();
47 | if (null !== $installPath && !$this->system->validatePath($installPath)) {
48 | throw new \RuntimeException('Invalid install path.');
49 | }
50 |
51 | $this->system->ensurePath($installPath);
52 | $this->executeComposerCommand($installPath, $beVerbose);
53 |
54 | $this->installKernel();
55 | }
56 |
57 | protected function getInstallPath(): string
58 | {
59 | return ($this->system->isRunningAsAdmin())
60 | ? $this->getAdminInstallPath()
61 | : $this->getUserInstallPath();
62 | }
63 |
64 | protected abstract function getAdminInstallPath(): string;
65 |
66 | protected abstract function getUserInstallPath(): string;
67 |
68 | protected function installKernel()
69 | {
70 | $kernelDef = json_encode([
71 | 'argv' => [
72 | 'php',
73 | $this->getKernelEntrypointPath(),
74 | '{connection_file}'
75 | ],
76 | 'display_name' => 'PHP',
77 | 'language' => 'php',
78 | 'env' => new \stdClass
79 | ]);
80 |
81 | $kernelSpecPath = ($this->system->isRunningAsAdmin())
82 | ? $this->getJupyterKernelsMetadataAdminPath()
83 | : $this->getJupyterKernelsMetadatUserPath();
84 |
85 | $this->system->ensurePath($kernelSpecPath);
86 | file_put_contents($kernelSpecPath.'/kernel.json', $kernelDef);
87 | }
88 |
89 | protected abstract function getKernelEntryPointPath(): string;
90 |
91 | protected abstract function getJupyterKernelsMetadataAdminPath(): string;
92 |
93 | protected abstract function getJupyterKernelsMetadatUserPath(): string;
94 |
95 | protected function executeComposerCommand(string $installPath, bool $beVerbose = false)
96 | {
97 | $composerStatus = 0;
98 |
99 | $pkgsDir = $installPath.DIRECTORY_SEPARATOR.'pkgs';
100 | $this->preparePackagesDir($pkgsDir);
101 |
102 | if ($beVerbose) {
103 | echo "\n";
104 | passthru(
105 | $this->system->wrapCommandToAttachEnvironmentVariable(
106 | 'PATH', getenv('PATH'),
107 | $this->getComposerInitCommand($pkgsDir) . ' && ' .
108 | $this->getComposerInstallCommand($pkgsDir)
109 | ),
110 |
111 | $composerStatus
112 | );
113 | echo "\n";
114 | } else {
115 | $composerStatus = $this->executeSilentComposerCommand($pkgsDir);
116 | }
117 |
118 | if (0 !== $composerStatus) {
119 | throw new \RuntimeException('Error while trying to download Jupyter-PHP dependencies with Composer.');
120 | }
121 | }
122 |
123 | protected function executeSilentComposerCommand(string $pkgsDir)
124 | {
125 | $composerOutputLines = [];
126 |
127 | exec(
128 | $this->system->wrapCommandToAttachEnvironmentVariable(
129 | 'PATH', getenv('PATH'),
130 | $this->getComposerInitCommand($pkgsDir, true) . ' && ' .
131 | $this->getComposerInstallCommand($pkgsDir, true)
132 | ),
133 |
134 | $composerOutputLines,
135 | $composerStatus
136 | );
137 |
138 | return $composerStatus;
139 | }
140 |
141 | private function getComposerInitCommand(string $pkgsDir, bool $silent = false): string
142 | {
143 | $cmd = (
144 | $this->composerCmd . ' init ' .
145 | ' --no-interaction ' .
146 | ' --name=jupyter-php-instance ' .
147 | ' --type=project ' .
148 | ' --working-dir="' . $pkgsDir . '" ' .
149 | ' --require=litipk/jupyter-php=0.* '
150 | );
151 |
152 | return ($silent)
153 | ? $this->system->wrapCommandToNullifyItsOutput($cmd)
154 | : $cmd;
155 | }
156 |
157 | private function getComposerInstallCommand(string $pkgsDir, bool $silent = false): string
158 | {
159 | $cmd = (
160 | $this->composerCmd . ' install ' .
161 | ' --no-interaction ' .
162 | ' --no-progress ' .
163 | ' --prefer-dist ' .
164 | ' --optimize-autoloader ' .
165 | ' --working-dir="' . $pkgsDir . '" '
166 | );
167 |
168 | return ($silent)
169 | ? $this->system->wrapCommandToNullifyItsOutput($cmd . ' --no-progress ')
170 | : $cmd;
171 | }
172 |
173 | protected function __construct(System $system, string $composerCmd)
174 | {
175 | $this->system = $system;
176 | $this->composerCmd = $composerCmd;
177 | }
178 |
179 | protected function preparePackagesDir(string $pkgsDir)
180 | {
181 | if (file_exists($pkgsDir)) {
182 | foreach (
183 | new \RecursiveIteratorIterator(
184 | new \RecursiveDirectoryIterator($pkgsDir, \FilesystemIterator::SKIP_DOTS),
185 | \RecursiveIteratorIterator::CHILD_FIRST
186 | ) as $path
187 | ) {
188 | $path->isDir() && !$path->isLink() ? rmdir($path->getPathname()) : unlink($path->getPathname());
189 | }
190 | rmdir($pkgsDir);
191 | }
192 | mkdir($pkgsDir);
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/src/Installer/LinuxInstaller.php:
--------------------------------------------------------------------------------
1 | system->getCurrentUserHome().'/.jupyter-php';
30 | }
31 |
32 | protected function getJupyterKernelsMetadatUserPath(): string
33 | {
34 | return $this->system->getCurrentUserHome().'/.local/share/jupyter/kernels/jupyter-php';
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Installer/MacInstaller.php:
--------------------------------------------------------------------------------
1 | system->getCurrentUserHome().'/Library/jupyter-php';
25 | }
26 |
27 | protected function getJupyterKernelsMetadatUserPath(): string
28 | {
29 | return $this->system->getCurrentUserHome().'/Library/Jupyter/kernels/jupyter-php';
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Installer/UnixInstaller.php:
--------------------------------------------------------------------------------
1 | getInstallPath() . '/pkgs/vendor/litipk/jupyter-php/src/kernel.php';
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Installer/WindowsInstaller.php:
--------------------------------------------------------------------------------
1 | system->getProgramDataPath() . '\jupyter-php';
26 | }
27 |
28 | protected function getUserInstallPath(): string
29 | {
30 | return $this->system->getCurrentUserHome() . '\.jupyter-php';
31 | }
32 |
33 | protected function getKernelEntryPointPath(): string
34 | {
35 | return $this->getInstallPath() . '\pkgs\vendor\litipk\jupyter-php\src\kernel.php';
36 | }
37 |
38 | protected function getJupyterKernelsMetadataAdminPath(): string
39 | {
40 | return $this->system->getProgramDataPath() . '\jupyter\kernels\jupyter-php';
41 | }
42 |
43 | protected function getJupyterKernelsMetadatUserPath(): string
44 | {
45 | return $this->system->getAppDataPath() . '\jupyter\kernels\jupyter-php';
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/System/BsdSystem.php:
--------------------------------------------------------------------------------
1 | getCurrentUser() === $this->getAdminUser());
37 | }
38 |
39 | public abstract function getOperativeSystem(): int;
40 |
41 | public abstract function getCurrentUser(): string;
42 |
43 | public abstract function getAdminUser(): string;
44 |
45 | public abstract function getCurrentUserHome(): string;
46 |
47 | public abstract function checkIfCommandExists(string $cmdName): bool;
48 |
49 | /** @return string|null */
50 | public abstract function getComposerCommand();
51 |
52 | /**
53 | * Returns true if the path is a "valid" path and is writable (event if the complete path does not yet exist).
54 | */
55 | public abstract function validatePath(string $path): bool;
56 |
57 | /**
58 | * @param string $path
59 | * @return string The "absolute path" version of $path.
60 | */
61 | public abstract function ensurePath(string $path): string;
62 |
63 | public abstract function wrapCommandToNullifyItsOutput(string $command): string;
64 |
65 | public abstract function wrapCommandToAttachEnvironmentVariable(string $varName, string $varValue, string $command);
66 |
67 | protected abstract function isAbsolutePath(string $path): bool;
68 |
69 | protected abstract function getAbsolutePath(string $path): string;
70 |
71 | private static function guessOperativeSystem(): int
72 | {
73 | $phpOS = strtolower(PHP_OS);
74 |
75 | if ('linux' === $phpOS) {
76 | return self::OS_LINUX;
77 | } elseif ('darwin' === $phpOS) {
78 | return self::OS_OSX;
79 | } elseif (in_array($phpOS, ['windows', 'winnt', 'win32'])) {
80 | return self::OS_WIN;
81 | } elseif (in_array($phpOS, ['freebsd', 'netbsd', 'openbsd'])) {
82 | return self::OS_BSD;
83 | } else {
84 | return self::OS_UNKNOWN;
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/System/UnixSystem.php:
--------------------------------------------------------------------------------
1 | checkIfCommandExists('whoami')) {
15 | return exec('whoami');
16 | } else {
17 | throw new \RuntimeException('Unable to obtain the current username.');
18 | }
19 | }
20 |
21 | public function getAdminUser(): string
22 | {
23 | return 'root';
24 | }
25 |
26 | public function getCurrentUserHome(): string
27 | {
28 | if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
29 | $pwuData = posix_getpwuid(posix_geteuid());
30 | return $pwuData['dir'];
31 | } elseif (function_exists('getenv') && false !== getenv('HOME')) {
32 | return getenv('HOME');
33 | } else {
34 | throw new \RuntimeException('Unable to obtain the current user home directory.');
35 | }
36 | }
37 |
38 | public function checkIfCommandExists(string $cmdName): bool
39 | {
40 | if (!function_exists('exec')) {
41 | return false;
42 | }
43 |
44 | $sysResponse = exec(
45 | 'PATH='.getenv('PATH').'; '.
46 | "if command -v ".$cmdName." >/dev/null 2>&1; then echo \"true\"; else echo \"false\"; fi;"
47 | );
48 |
49 | return filter_var($sysResponse, FILTER_VALIDATE_BOOLEAN);
50 | }
51 |
52 | /** @return string|null */
53 | public function getComposerCommand()
54 | {
55 | $potentialCommands = [
56 | 'composer', 'composer.phar', './composer.phar', './composer', './bin/composer', './bin/composer.phar',
57 | './vendor/bin/composer', './vendor/bin/composer.phar', '../vendor/bin/composer',
58 | '../vendor/bin/composer.phar', '../../vendor/bin/composer', '../../vendor/bin/composer.phar'
59 | ];
60 |
61 | foreach ($potentialCommands as $potentialCommand) {
62 | if ($this->checkIfCommandExists($potentialCommand)) {
63 | return $potentialCommand;
64 | }
65 | }
66 |
67 | return null;
68 | }
69 |
70 | /**
71 | * Returns true if the path is a "valid" path and is writable (even if the complete path does not yet exist).
72 | */
73 | public function validatePath(string $path): bool
74 | {
75 | $absPath = $this->getAbsolutePath($path);
76 | $absPathParts = preg_split('/\//', preg_replace('/(^\/|\/$)/', '', $absPath));
77 | $nSteps = count($absPathParts);
78 |
79 | $tmpPath = '';
80 | $prevReadable = false;
81 | $prevWritable = false;
82 |
83 | for ($i=0; $i<$nSteps; $i++) {
84 | $tmpPath .= '/' . $absPathParts[$i];
85 |
86 | if (file_exists($tmpPath)) {
87 | if (!is_dir($tmpPath)) {
88 | if (is_link($tmpPath)) {
89 | $linkPath = readlink($tmpPath);
90 | if (false === $linkPath || !is_dir($linkPath)) {
91 | return false;
92 | }
93 | $tmpPath = $linkPath;
94 | } else {
95 | return false;
96 | }
97 | }
98 |
99 | $prevReadable = is_readable($tmpPath);
100 | $prevWritable = is_writable($tmpPath);
101 | } else {
102 | return ($prevReadable && $prevWritable);
103 | }
104 | }
105 |
106 | return true;
107 | }
108 |
109 | /**
110 | * @param string $path
111 | * @return string The "absolute path" version of $path.
112 | */
113 | public function ensurePath(string $path): string
114 | {
115 | $absPath = $this->getAbsolutePath($path);
116 |
117 | if (!file_exists($absPath) && false === mkdir($absPath, 0755, true)) {
118 | throw new \RuntimeException('Unable to create the specified directory ('.$absPath.').');
119 | }
120 |
121 | return $absPath;
122 | }
123 |
124 | public function wrapCommandToNullifyItsOutput(string $command): string
125 | {
126 | return $command . ' > /dev/null 2>&1 ';
127 | }
128 |
129 | public function wrapCommandToAttachEnvironmentVariable(string $varName, string $varValue, string $command)
130 | {
131 | return ' ' . $varName . '=' . $varValue . ' && ' . $command;
132 | }
133 |
134 | protected function isAbsolutePath(string $path): bool
135 | {
136 | return (1 === preg_match('#^/#', $path));
137 | }
138 |
139 | protected function getAbsolutePath(string $path): string
140 | {
141 | return $this->isAbsolutePath($path) ? $path : (getcwd() . DIRECTORY_SEPARATOR . $path);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/System/WindowsSystem.php:
--------------------------------------------------------------------------------
1 | nul 2>&1 && echo true");
44 |
45 | return filter_var($sysResponse, FILTER_VALIDATE_BOOLEAN);
46 | }
47 |
48 | public function getComposerCommand(): string
49 | {
50 | return 'composer';
51 | }
52 |
53 | /**
54 | * Returns true if the path is a "valid" path and is writable (event if the complete path does not yet exist).
55 | */
56 | public function validatePath(string $path): bool
57 | {
58 | $absPath = $this->getAbsolutePath($path);
59 | $absPathParts = explode(DIRECTORY_SEPARATOR, $absPath);
60 | $nSteps = count($absPathParts);
61 |
62 | $tmpPath = $absPathParts[0];
63 | $prevReadable = false;
64 | $prevWritable = false;
65 |
66 | for ($i = 1; $i < $nSteps; $i++) {
67 | $tmpPath .= DIRECTORY_SEPARATOR . $absPathParts[$i];
68 |
69 | if (file_exists($tmpPath)) {
70 | if (!is_dir($tmpPath)) {
71 | if (is_link($tmpPath)) {
72 | $linkPath = readlink($tmpPath);
73 | if (false === $linkPath || !is_dir($linkPath)) {
74 | return false;
75 | }
76 | $tmpPath = $linkPath;
77 | } else {
78 | return false;
79 | }
80 | }
81 |
82 | $prevReadable = is_readable($tmpPath);
83 | $prevWritable = is_writable($tmpPath);
84 | } else {
85 | return ($prevReadable && $prevWritable);
86 | }
87 | }
88 |
89 | return true;
90 | }
91 |
92 | /**
93 | * @param string $path
94 | * @return string The "absolute path" version of $path.
95 | */
96 | public function ensurePath(string $path): string
97 | {
98 | $absPath = $this->getAbsolutePath($path);
99 |
100 | if (!file_exists($absPath) && false === mkdir($absPath, 0755, true)) {
101 | throw new \RuntimeException('Unable to create the specified directory (' . $absPath . ').');
102 | }
103 |
104 | return $absPath;
105 | }
106 |
107 | public function wrapCommandToNullifyItsOutput(string $command): string
108 | {
109 | return $command . ' > nul 2>&1 ';
110 | }
111 |
112 | public function wrapCommandToAttachEnvironmentVariable(string $varName, string $varValue, string $command)
113 | {
114 | return ' set ' . $varName . '=' . $varValue . ' && ' . $command;
115 | }
116 |
117 | public function getProgramDataPath(): string
118 | {
119 | if (function_exists('getenv') && false !== getenv('PROGRAMDATA')) {
120 | return getenv('PROGRAMDATA');
121 | } else {
122 | throw new \RuntimeException('Unable to obtain the program data directory.');
123 | }
124 | }
125 |
126 | public function getAppDataPath(): string
127 | {
128 | if (function_exists('getenv') && false !== getenv('APPDATA')) {
129 | return getenv('APPDATA');
130 | } else {
131 | throw new \RuntimeException('Unable to obtain the app data directory.');
132 | }
133 | }
134 |
135 | protected function isAbsolutePath(string $path): bool
136 | {
137 | return preg_match('/^[a-z]\:/i', $path) === 1;
138 | }
139 |
140 | protected function getAbsolutePath(string $path): string
141 | {
142 | $path = $this->isAbsolutePath($path) ? $path : (getcwd() . DIRECTORY_SEPARATOR . $path);
143 |
144 | // Normalise directory separators
145 | $path = preg_replace('/[\/\\\\]/u', DIRECTORY_SEPARATOR, $path);
146 |
147 | return $path;
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/Util/ErrorHandler.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | * Andres Correa
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 |
15 | namespace Litipk\JupyterPhpInstaller\Util;
16 |
17 |
18 | use Litipk\JupyterPhpInstaller\IO\IOInterface;
19 |
20 |
21 | /**
22 | * Convert PHP errors into exceptions
23 | *
24 | * @author Artem Lopata
25 | * @author Andres Correa
26 | */
27 | class ErrorHandler
28 | {
29 | /** @var IOInterface */
30 | private static $io;
31 |
32 | /**
33 | * Error handler
34 | *
35 | * @param int $level Level of the error raised
36 | * @param string $message Error message
37 | * @param string $file Filename that the error was raised in
38 | * @param int $line Line number the error was raised at
39 | *
40 | * @static
41 | * @throws \ErrorException
42 | */
43 | public static function handle($level, $message, $file, $line)
44 | {
45 | // respect error_reporting being disabled
46 | if (!error_reporting()) {
47 | return;
48 | }
49 |
50 | if (ini_get('xdebug.scream')) {
51 | $message .= "\n\nWarning: You have xdebug.scream enabled, the warning above may be".
52 | "\na legitimately suppressed error that you were not supposed to see.";
53 | }
54 |
55 | if ($level !== E_DEPRECATED && $level !== E_USER_DEPRECATED) {
56 | throw new \ErrorException($message, 0, $level, $file, $line);
57 | }
58 |
59 | if (self::$io) {
60 | self::$io->writeError('Deprecation Notice: '.$message.' in '.$file.':'.$line.'');
61 | if (self::$io->isVerbose()) {
62 | self::$io->writeError('Stack trace:');
63 | self::$io->writeError(array_filter(array_map(function ($a) {
64 | if (isset($a['line'], $a['file'])) {
65 | return ' '.$a['file'].':'.$a['line'].'';
66 | }
67 |
68 | return null;
69 | }, array_slice(debug_backtrace(), 2))));
70 | }
71 | }
72 | }
73 |
74 | /**
75 | * Register error handler
76 | *
77 | * @static
78 | * @param IOInterface|null $io
79 | */
80 | public static function register(IOInterface $io = null)
81 | {
82 | set_error_handler(array(__CLASS__, 'handle'));
83 | self::$io = $io;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/tests/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Coder-Spirit/Jupyter-PHP-Installer/ac86a042b6db8fd196062775836831bfe675b0a7/tests/.gitkeep
--------------------------------------------------------------------------------