Skip to content

Commit

Permalink
Add a command to split a HAR file #16
Browse files Browse the repository at this point in the history
  • Loading branch information
deviantintegral authored Sep 4, 2019
2 parents 15b5531 + 8b4170a commit c235e64
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 4 deletions.
65 changes: 64 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ test: &test
php composer-setup.php --quiet --install-dir /usr/local/bin --filename composer
- run: docker-php-ext-install bcmath

- run: composer update -n --prefer-dist $COMPOSER_FLAGS

- save_cache:
Expand Down Expand Up @@ -75,6 +77,8 @@ test_and_cover: &test_and_cover
php composer-setup.php --quiet --install-dir /usr/local/bin --filename composer
- run: docker-php-ext-install bcmath

- run: composer update -n --prefer-dist

- run: |
Expand Down Expand Up @@ -125,6 +129,8 @@ code_fixer: &code_fixer
php composer-setup.php --quiet --install-dir /usr/local/bin --filename composer
- run: docker-php-ext-install bcmath

- run: composer update -n --prefer-dist

- save_cache:
Expand All @@ -135,6 +141,49 @@ code_fixer: &code_fixer
# run tests!
- run: vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run --using-cache=no --path-mode=intersection -- src tests

build_phar: &build_phar
steps:
- checkout

# Download and cache dependencies
- restore_cache:
keys:
- v2-test-dependencies-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }}-{{ checksum ".circleci/config.yml" }}
# fallback to using the latest cache if no exact match is found
- v2-test-dependencies-

# php:* has no zip extension and the CLI is faster to install.
- run: apt-get update -y && apt-get install unzip -y

- run: |
EXPECTED_SIGNATURE=$(curl -L https://composer.github.io/installer.sig)
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_SIGNATURE=$(php -r "echo hash_file('SHA384', 'composer-setup.php');")
if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
then
>&2 echo 'ERROR: Invalid installer signature'
rm composer-setup.php
exit 1
fi
php composer-setup.php --quiet --install-dir /usr/local/bin --filename composer
- run: docker-php-ext-install bcmath

- run: composer update -n --prefer-dist

- save_cache:
paths:
- /root/.composer/cache/files
key: v2-test-dependencies-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }}-{{ checksum ".circleci/config.yml" }}

# Build the phar!
- run: composer build-phar

- store_artifacts:
path: ./har.phar

jobs:
build_php73:
docker:
Expand All @@ -157,12 +206,20 @@ jobs:

code_fixer:
docker:
- image: php:7.2
- image: php:7.3

working_directory: ~/repo

<<: *code_fixer

build_phar:
docker:
- image: php:7.3

working_directory: ~/repo

<<: *build_phar

workflows:
version: 2

Expand All @@ -172,6 +229,9 @@ workflows:
- build_php72
- build_php73
- code_fixer
- build_phar:
requires:
- build_php73

nightly:
triggers:
Expand All @@ -186,3 +246,6 @@ workflows:
- build_php72
- build_php73
- code_fixer
- build_phar:
requires:
- build_php73
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ build
.phpunit.result.cache
vendor
.php_cs.cache
har.phar
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Features include:
* Writing a `\Deviantintegral\Har\Har` back out into a HAR JSON string.
* Adapters for PSR-7 Request and Response interfaces.
* An interface and `\Deviantintegral\Har\HarRepository` class to load HARs from a filesystem or other backend.
* A CLI tool to split a HAR file into single files per request / response pair.

## Example

Expand Down
16 changes: 16 additions & 0 deletions bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

use Deviantintegral\Har\Command\SplitCommand;

require_once __DIR__ . '/../vendor/autoload.php';

// Create the Application
$application = new Symfony\Component\Console\Application;

$application->add(new SplitCommand());

// Run it
$application->run();
20 changes: 17 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"type": "library",
"license": "GPL-2.0+",
"minimum-stability": "dev",
"prefer-stable": true,
"authors": [
{
"name": "Andrew Berry",
Expand All @@ -17,13 +18,14 @@
"doctrine/annotations": "^1.7",
"guzzlehttp/psr7": "^1.6",
"deviantintegral/jms-serializer-uri-handler": "^1.0",
"deviantintegral/null-date-time": "^0.1.0"
"deviantintegral/null-date-time": "^0.1.0",
"symfony/console": "^4.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.15",
"phpunit/phpunit": "^8.3",
"symfony/console": "^4.3",
"guzzlehttp/guzzle": "^6.3"
"guzzlehttp/guzzle": "^6.3",
"macfja/phar-builder": "^0.2.8"
},
"autoload": {
"psr-4": {
Expand All @@ -34,5 +36,17 @@
"psr-4": {
"Deviantintegral\\Har\\Tests\\": "tests/src"
}
},
"scripts": {
"build-phar": "php -dphar.readonly=0 vendor/bin/phar-builder package composer.json && chmod +x har.phar"
},
"extra": {
"phar-builder": {
"compression": "gzip",
"name": "har.phar",
"output-dir": "./",
"entry-point": "bin/console",
"include": []
}
}
}
90 changes: 90 additions & 0 deletions src/Command/SplitCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace Deviantintegral\Har\Command;

use Deviantintegral\Har\Serializer;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
* Command to split a HAR file into multiple files.
*/
class SplitCommand extends Command
{
protected function configure()
{
parent::configure();
$this->setName('har:split')
->setDescription('Split a HAR file into one file per entry')
->setHelp('Each entry in the supplied HAR will be split into a single file.')
->addArgument('har', InputArgument::REQUIRED, 'The source HAR file to split.')
->addArgument('destination', InputArgument::OPTIONAL, 'The source directory to save the split files to. Defaults to the current directory.')
->addOption('md5', null, InputOption::VALUE_NONE, 'Save split files with an MD5 hash of the request URL instead of a numeric index.')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Overwrite destination files that already exist.');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$source = $input->getArgument('har');
$contents = file_get_contents($source);
$serializer = new Serializer();
$har = $serializer->deserializeHar($contents);

$io->text(sprintf('Splitting %s into one file per entry',
$source
));
$io->progressStart(\count($har->getLog()->getEntries()));

foreach ($har->splitLogEntries() as $index => $cloned) {
$destination = $this->getSplitDestination(
$index,
$input->getOption('md5'),
$cloned,
$input->getArgument('destination') ?: getcwd()
);

if ($input->getOption('force') || !file_exists($destination)) {
if (false === file_put_contents($destination, $serializer->serializeHar($cloned))) {
throw new \RuntimeException(sprintf('Unable to write to %s.', $destination));
}
} else {
throw new \RuntimeException(sprintf('%s exists. Use --force to overwrite it and all other existing files', $destination));
}
$io->progressAdvance();
}
$io->progressFinish();
}

/**
* @param $index
* @param $md5
* @param \Deviantintegral\Har\Har $cloned
* @param string $destination_path
*
* @return string
*/
private function getSplitDestination(
$index,
$md5,
\Deviantintegral\Har\Har $cloned,
string $destination_path
): string {
$filename = $index + 1 .'.har';
if ($md5) {
$filename = md5(
(string) $cloned->getLog()->getEntries()[0]->getRequest()
->getUrl()
).'.har';
}
$destination = $destination_path."/$filename";

return $destination;
}
}
14 changes: 14 additions & 0 deletions src/Har.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,18 @@ public function setLog(Log $log): self

return $this;
}

/**
* Return a generator that returns cloned HARs with one per HAR entry.
*
* @return \Deviantintegral\Har\Har[]
*/
public function splitLogEntries(): \Generator
{
foreach ($this->getLog()->getEntries() as $index => $entry) {
$cloned = clone $this;
$cloned->getLog()->setEntries([$entry]);
yield $index => $cloned;
}
}
}

0 comments on commit c235e64

Please sign in to comment.