8 Commits

4 changed files with 102 additions and 28 deletions

View File

@@ -23,12 +23,11 @@ These formats are supported for now: `http`, `curl`, `wget`.
## Planned features ## Planned features
- support as many as possible/necessary of authentication kinds (_currently no ones_); - support as many as possible/necessary of authentication kinds (_currently no ones_);
- support as many as possible/necessary of body formats (_currently json and formdata_); - support as many as possible/necessary of body formats (_currently only `json` and `formdata`_);
- documentation generation support (markdown) with responce examples (if present); - documentation generation support (markdown) with responce examples (if present);
- maybe some another convert formats (like httpie or something...); - maybe some another convert formats (like httpie or something...);
- replace `{{vars}}` from folder; - replace `{{vars}}` from folder;
- replace `{{vars}}` from environment; - replace `{{vars}}` from environment;
- performance measurement;
- better logging; - better logging;
- tests, phpcs, psalm, etc.; - tests, phpcs, psalm, etc.;
- web version. - web version.

View File

@@ -21,7 +21,7 @@ foreach ($paths as $path) {
is_null($file) && throw new RuntimeException('Unable to locate autoload.php file.'); is_null($file) && throw new RuntimeException('Unable to locate autoload.php file.');
try { try {
(new Processor($argv))->start(); (new Processor($argv))->convert();
} catch (Exception $e) { } catch (Exception $e) {
fwrite(STDERR, sprintf('ERROR: %s%s', $e->getMessage(), PHP_EOL)); fwrite(STDERR, sprintf('ERROR: %s%s', $e->getMessage(), PHP_EOL));
die(1); die(1);

View File

@@ -10,8 +10,17 @@ use PmConverter\Exceptions\{
DirectoryIsNotWriteableException, DirectoryIsNotWriteableException,
DirectoryNotExistsException}; DirectoryNotExistsException};
/**
* Helper class to work with files and directories
*/
class FileSystem class FileSystem
{ {
/**
* Normalizes a given path
*
* @param string $path
* @return string
*/
public static function normalizePath(string $path): string public static function normalizePath(string $path): string
{ {
$path = str_replace('~', $_SERVER['HOME'], $path); $path = str_replace('~', $_SERVER['HOME'], $path);
@@ -19,6 +28,8 @@ class FileSystem
} }
/** /**
* Recursively creates a new directory by given path
*
* @param string $path * @param string $path
* @return string * @return string
* @throws CannotCreateDirectoryException * @throws CannotCreateDirectoryException
@@ -38,6 +49,8 @@ class FileSystem
} }
/** /**
* Recursively removes a given directory
*
* @param string $path * @param string $path
* @return void * @return void
* @throws DirectoryIsNotReadableException * @throws DirectoryIsNotReadableException
@@ -65,23 +78,22 @@ class FileSystem
{ {
$path = static::normalizePath($path); $path = static::normalizePath($path);
if (!file_exists($path)) { if (!file_exists($path)) {
throw new DirectoryNotExistsException("output directory is not exist: $path"); throw new DirectoryNotExistsException("directory does not exist: $path");
} }
if (!is_readable($path)) { if (!is_readable($path)) {
throw new DirectoryIsNotReadableException("output directory permissions are not valid: $path"); throw new DirectoryIsNotReadableException("directory permissions are not valid: $path");
} }
if (!is_writable($path)) { if (!is_writable($path)) {
throw new DirectoryIsNotWriteableException("output directory permissions are not valid: $path"); throw new DirectoryIsNotWriteableException("directory permissions are not valid: $path");
} }
return true; return true;
} }
/** /**
* Returns content of given directory path
*
* @param string $path * @param string $path
* @return array * @return array
* @throws DirectoryIsNotReadableException
* @throws DirectoryIsNotWriteableException
* @throws DirectoryNotExistsException
*/ */
public static function dirContents(string $path): array public static function dirContents(string $path): array
{ {
@@ -92,4 +104,22 @@ class FileSystem
} }
return $records; return $records;
} }
/**
* Checks if a given file is a valid collection json file
*
* @param string $path
* @return bool
*/
public static function isCollectionFile(string $path): bool
{
$path = static::normalizePath($path);
return !empty($path = trim($path))
&& str_ends_with($path, '.postman_collection.json')
&& file_exists($path)
&& is_readable($path)
&& ($json = json_decode(file_get_contents($path), true))
&& json_last_error() === JSON_ERROR_NONE
&& isset($json['collection']['info']['name']);
}
} }

View File

@@ -22,12 +22,12 @@ class Processor
/** /**
* Converter version * Converter version
*/ */
public const VERSION = '1.0.0'; public const VERSION = '1.1.1';
/** /**
* @var string[] Paths to collection files * @var string[] Paths to collection files
*/ */
protected array $collectionPaths; protected array $collectionPaths = [];
/** /**
* @var string Output path where to put results in * @var string Output path where to put results in
@@ -52,7 +52,17 @@ class Processor
/** /**
* @var object[] Collections that will be converted into choosen formats * @var object[] Collections that will be converted into choosen formats
*/ */
protected array $collections; protected array $collections = [];
/**
* @var int Initial timestamp
*/
protected int $init_time;
/**
* @var int Initial RAM usage
*/
protected int $init_ram;
/** /**
* Constructor * Constructor
@@ -61,6 +71,8 @@ class Processor
*/ */
public function __construct(protected array $argv) public function __construct(protected array $argv)
{ {
$this->init_time = hrtime(true);
$this->init_ram = memory_get_usage(true);
} }
/** /**
@@ -80,54 +92,66 @@ class Processor
switch ($arg) { switch ($arg) {
case '-f': case '-f':
case '--file': case '--file':
$path = $this->argv[$idx + 1]; $rawpath = $this->argv[$idx + 1];
if (empty($path) || !str_ends_with($path, '.json') || !file_exists($path) || !is_readable($path)) { $normpath = FileSystem::normalizePath($rawpath);
throw new InvalidArgumentException('a valid json-file path is expected for -f (--file)'); if (!FileSystem::isCollectionFile($normpath)) {
throw new InvalidArgumentException(
sprintf("this is not a valid collection file:%s\t%s %s", PHP_EOL, $arg, $rawpath)
);
} }
$this->collectionPaths[] = $this->argv[$idx + 1]; $this->collectionPaths[] = $this->argv[$idx + 1];
break; break;
case '-o': case '-o':
case '--output': case '--output':
if (empty($this->argv[$idx + 1])) { if (empty($this->argv[$idx + 1])) {
throw new InvalidArgumentException('-o expected'); throw new InvalidArgumentException('-o is required');
} }
$this->outputPath = $this->argv[$idx + 1]; $this->outputPath = $this->argv[$idx + 1];
break; break;
case '-d': case '-d':
case '--dir': case '--dir':
if (empty($this->argv[$idx + 1])) { if (empty($this->argv[$idx + 1])) {
throw new InvalidArgumentException('a directory path is expected for -d (--dir)'); throw new InvalidArgumentException('a directory path is expected for -d (--dir)');
} }
$path = $this->argv[$idx + 1]; $normpath = $this->argv[$idx + 1];
if (FileSystem::checkDir($path)) { $files = array_filter(
$files = array_filter( FileSystem::dirContents($normpath),
FileSystem::dirContents($path), static fn($filename) => FileSystem::isCollectionFile($filename)
static fn($filename) => str_ends_with($filename, '.json') );
); $this->collectionPaths = array_unique(array_merge($this?->collectionPaths ?? [], $files));
$this->collectionPaths = array_unique(array_merge($this?->collectionPaths ?? [], $files));
}
break; break;
case '-p': case '-p':
case '--preserve': case '--preserve':
$this->preserveOutput = true; $this->preserveOutput = true;
break; break;
case '--http': case '--http':
$this->formats[ConvertFormat::Http->name] = ConvertFormat::Http; $this->formats[ConvertFormat::Http->name] = ConvertFormat::Http;
break; break;
case '--curl': case '--curl':
$this->formats[ConvertFormat::Curl->name] = ConvertFormat::Curl; $this->formats[ConvertFormat::Curl->name] = ConvertFormat::Curl;
break; break;
case '--wget': case '--wget':
$this->formats[ConvertFormat::Wget->name] = ConvertFormat::Wget; $this->formats[ConvertFormat::Wget->name] = ConvertFormat::Wget;
break; break;
case '-v': case '-v':
case '--version': case '--version':
die(implode(PHP_EOL, $this->version()) . PHP_EOL); die(implode(PHP_EOL, $this->version()) . PHP_EOL);
case '-h': case '-h':
case '--help': case '--help':
die(implode(PHP_EOL, $this->usage()) . PHP_EOL); die(implode(PHP_EOL, $this->usage()) . PHP_EOL);
} }
} }
if (empty($this->collectionPaths)) {
throw new InvalidArgumentException('there are no collections to convert');
}
if (empty($this->formats)) { if (empty($this->formats)) {
$this->formats = [ConvertFormat::Http->name => ConvertFormat::Http]; $this->formats = [ConvertFormat::Http->name => ConvertFormat::Http];
} }
@@ -180,22 +204,43 @@ class Processor
* *
* @throws Exception * @throws Exception
*/ */
public function start(): void public function convert(): void
{ {
$this->parseArgs(); $this->parseArgs();
$this->initOutputDirectory(); $this->initOutputDirectory();
$this->initConverters(); $this->initConverters();
$this->initCollections(); $this->initCollections();
$count = count($this->collections);
$current = 0;
$success = 0;
print(implode(PHP_EOL, array_merge($this->version(), $this->copyright())) . PHP_EOL . PHP_EOL); print(implode(PHP_EOL, array_merge($this->version(), $this->copyright())) . PHP_EOL . PHP_EOL);
foreach ($this->collections as $collectionName => $collection) { foreach ($this->collections as $collectionName => $collection) {
print("Converting '$collectionName':" . PHP_EOL); ++$current;
printf("Converting '%s' (%d/%d):%s", $collectionName, $current, $count, PHP_EOL);
foreach ($this->converters as $type => $exporter) { foreach ($this->converters as $type => $exporter) {
print("\t-> " . strtolower($type)); printf(' > %s', strtolower($type));
$outputPath = sprintf('%s%s%s', $this->outputPath, DIRECTORY_SEPARATOR, $collectionName); $outputPath = sprintf('%s%s%s', $this->outputPath, DIRECTORY_SEPARATOR, $collectionName);
$exporter->convert($collection, $outputPath); $exporter->convert($collection, $outputPath);
printf("\t- OK: %s%s", $exporter->getOutputPath(), PHP_EOL); printf(' - OK: %s%s', $exporter->getOutputPath(), PHP_EOL);
} }
print(PHP_EOL);
++$success;
} }
$this->printStats($success, $current);
}
/**
* Outputs some statistics
*
* @param int $success
* @param int $count
* @return void
*/
protected function printStats(int $success, int $count): void
{
$time = (hrtime(true) - $this->init_time) / 1_000_000;
$ram = (memory_get_peak_usage(true) - $this->init_ram) / 1024 / 1024;
printf('Converted %d of %d in %.3f ms using %.3f MiB RAM', $success, $count, $time, $ram);
} }
/** /**