Skip to content
This repository has been archived by the owner on Dec 12, 2023. It is now read-only.

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
* develop:
  add missing use statements
  add readme
  test .env override real variables
  enable debug profiler when url provided
  enable silent cartographer by default
  add method to load .env from a config folder
  add method to provide the commands
  add hello world application
  add basic repo files
  • Loading branch information
Baptouuuu committed Apr 14, 2020
2 parents 8067039 + 8ee96f0 commit 0a0abc3
Show file tree
Hide file tree
Showing 11 changed files with 900 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitattributes
@@ -0,0 +1,5 @@
/.gitattributes export-ignore
/.gitignore export-ignore
/phpunit.xml.dist export-ignore
/psalm.xml export-ignore
/tests export-ignore
65 changes: 65 additions & 0 deletions .github/workflows/ci.yml
@@ -0,0 +1,65 @@
name: CI

on: [push]

jobs:
phpunit:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
php-version: ['7.4']
name: 'PHPUnit - PHP/${{ matrix.php-version }} - OS/${{ matrix.os }}'
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Setup PHP
uses: shivammathur/setup-php@v1
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl
coverage: xdebug
ini-values: xdebug.max_nesting_level=2048
- name: Get Composer Cache Directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Dependencies
run: composer install --no-progress
- name: PHPUnit
run: vendor/bin/phpunit --coverage-clover=coverage.clover
- uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
psalm:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4']
name: 'Psalm - PHP/${{ matrix.php-version }}'
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Setup PHP
uses: shivammathur/setup-php@v1
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl
- name: Get Composer Cache Directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Dependencies
run: composer install --no-progress
- name: Psalm
run: vendor/bin/psalm --shepherd
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
/composer.lock
/vendor
/.phpunit.result.cache
43 changes: 43 additions & 0 deletions README.md
@@ -0,0 +1,43 @@
# CLI Framework

[![codecov](https://codecov.io/gh/Innmind/CLIFramework/branch/develop/graph/badge.svg)](https://codecov.io/gh/Innmind/CLIFramework)
[![Build Status](https://github.com/Innmind/CLIFramework/workflows/CI/badge.svg)](https://github.com/Innmind/CLIFramework/actions?query=workflow%3ACI)
[![Type Coverage](https://shepherd.dev/github/Innmind/CLIFramework/coverage.svg)](https://shepherd.dev/github/Innmind/CLIFramework)

Small library on top of [`innmind/cli`](https://github.com/innmind/cli) to automatically enable some features.

## Installation

```sh
composer require innmind/cli-framework
```

## Usage

```php
use Innmind\CLI\{
Environment,
Command,
};
use Innmind\CLI\Framework\Application;
use Innmind\OperatingSystem\OperatingSystem;
use Innmind\Url\Path;

new class extends Main {
protected function main(Environment $env, OperatingSystem $os): void
{
Application::of($env, $os)
->configAt(Path::of('/path/to/config/directory/'))
->commands(fn(Environment $env, OperatingSystem $os): array => [
// a list of objects implementing Command
])
->run();
}
}
```

This simple example will try to locate a file named `.env` in the directory provided and will add the variables to the map returned by `$env->variables()` in the `commands` callable.

By default it enables the usage of [`innmind/silent-cartographer`](https://github.com/innmind/silentcartographer), but can be disabled by calling `->disableSilentCartographer()`.

When a `PROFILER` environment variable is declared it will enable [`innmind/debug`](https://github.com/innmind/debug), you can disable specific sections of the profiler by calling `->disableProfilerSection(...$sectionsClassNameToDisable)`.
38 changes: 38 additions & 0 deletions composer.json
@@ -0,0 +1,38 @@
{
"name": "innmind/cli-framework",
"type": "library",
"description": "CLI framework",
"keywords": ["assistant"],
"homepage": "http://github.com/Innmind/CLIFramework",
"license": "MIT",
"authors": [
{
"name": "Baptiste Langlade",
"email": "langlade.baptiste@gmail.com"
}
],
"support": {
"issues": "http://github.com/Innmind/CLIFramework/issues"
},
"require": {
"php": "~7.4",
"innmind/cli": "~2.0",
"symfony/dotenv": "^5.0",
"innmind/silent-cartographer": "^2.0",
"innmind/debug": "^2.0"
},
"autoload": {
"psr-4": {
"Innmind\\CLI\\Framework\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\Innmind\\CLI\\Framework\\": "tests/"
}
},
"require-dev": {
"phpunit/phpunit": "~8.0",
"vimeo/psalm": "^3.7"
}
}
19 changes: 19 additions & 0 deletions phpunit.xml.dist
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit colors="true" bootstrap="vendor/autoload.php">
<testsuites>
<testsuite name="Test suite">
<directory>./tests</directory>
</testsuite>
</testsuites>

<filter>
<whitelist>
<directory>.</directory>
<exclude>
<directory>./tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
16 changes: 16 additions & 0 deletions psalm.xml
@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<psalm
totallyTyped="true"
errorLevel="1"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>
168 changes: 168 additions & 0 deletions src/Application.php
@@ -0,0 +1,168 @@
<?php
declare(strict_types = 1);

namespace Innmind\CLI\Framework;

use Innmind\CLI\{
Environment,
Command,
Commands,
};
use Innmind\OperatingSystem\OperatingSystem;
use Innmind\Debug\Profiler\Section;
use Innmind\Url\{
Path,
Url,
};
use Innmind\Immutable\Set;
use function Innmind\SilentCartographer\bootstrap as cartographer;
use function Innmind\Debug\bootstrap as debug;
use function Innmind\Immutable\unwrap;

final class Application
{
private Environment $env;
private OperatingSystem $os;
/** @var \Closure(Environment, OperatingSystem): list<Command> */
private \Closure $commands;
/** @var \Closure(Environment, OperatingSystem): Environment */
private \Closure $loadDotEnv;
/** @var \Closure(Environment, OperatingSystem): OperatingSystem */
private \Closure $enableSilentCartographer;
/** @var list<class-string<Section>> */
private array $disabledSections;

/**
* @param callable(Environment, OperatingSystem): list<Command> $commands
* @param callable(Environment, OperatingSystem): Environment $loadDotEnv
* @param callable(Environment, OperatingSystem): OperatingSystem $enableSilentCartographer
* @param list<class-string<Section>> $disabledSections
*/
private function __construct(
Environment $env,
OperatingSystem $os,
callable $commands,
callable $loadDotEnv,
callable $enableSilentCartographer,
array $disabledSections
) {
$this->env = $env;
$this->os = $os;
$this->commands = \Closure::fromCallable($commands);
$this->loadDotEnv = \Closure::fromCallable($loadDotEnv);
$this->enableSilentCartographer = \Closure::fromCallable($enableSilentCartographer);
$this->disabledSections = $disabledSections;
}

public static function of(Environment $env, OperatingSystem $os): self
{
return new self(
$env,
$os,
static fn(): array => [],
static fn(Environment $env): Environment => $env,
static fn(Environment $env, OperatingSystem $os): OperatingSystem => cartographer($os)['cli'](
Url::of('/')->withPath(
$env->workingDirectory(),
),
),
[],
);
}

/**
* @param callable(Environment, OperatingSystem): list<Command> $commands
*/
public function commands(callable $commands): self
{
return new self(
$this->env,
$this->os,
fn(Environment $env, OperatingSystem $os): array => \array_merge(
($this->commands)($env, $os),
$commands($env, $os),
),
$this->loadDotEnv,
$this->enableSilentCartographer,
[],
);
}

public function configAt(Path $path): self
{
return new self(
$this->env,
$this->os,
$this->commands,
static fn(Environment $env, OperatingSystem $os): Environment => new DotEnvAware(
$env,
$os->filesystem(),
$path,
),
$this->enableSilentCartographer,
[],
);
}

public function disableSilentCartographer(): self
{
return new self(
$this->env,
$this->os,
$this->commands,
$this->loadDotEnv,
static fn(Environment $env, OperatingSystem $os): OperatingSystem => $os,
[],
);
}

/**
* @param list<class-string<Section>> $sections
*/
public function disableProfilerSection(string ...$sections): self
{
return new self(
$this->env,
$this->os,
$this->commands,
$this->loadDotEnv,
$this->enableSilentCartographer,
\array_merge(
$this->disabledSections,
$sections,
),
);
}

public function run(): void
{
$os = ($this->enableSilentCartographer)($this->env, $this->os);
$env = ($this->loadDotEnv)($this->env, $os);
$debugEnabled = $env->variables()->contains('PROFILER');
$wrapCommands = static fn(Command ...$commands): array => $commands;

if ($debugEnabled) {
$debug = debug(
$os,
Url::of($env->variables()->get('PROFILER')),
$env->variables(),
null,
Set::strings(...$this->disabledSections),
);
$os = $debug['os']();
$wrapCommands = static fn(Command ...$commands): array => unwrap(
$debug['cli'](...$commands),
);
}

$commands = ($this->commands)($env, $os);
$commands = \count($commands) === 0 ? [new HelloWorld] : $commands;

if ($debugEnabled) {
$commands = $wrapCommands(...$commands);
}

$run = new Commands(...$commands);
$run($env);
}
}

0 comments on commit 0a0abc3

Please sign in to comment.