Skip to content

Commit

Permalink
Refactoring (#22)
Browse files Browse the repository at this point in the history
* refactoring
* More stuff
* Tests stuff
* code style
  • Loading branch information
fmizzell authored Mar 19, 2021
1 parent 54deed9 commit 258a26e
Show file tree
Hide file tree
Showing 15 changed files with 694 additions and 248 deletions.
15 changes: 9 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
version: 2.0
jobs:
build:
machine:
image: ubuntu-2004:202010-01
environment:
CC_TEST_REPORTER_ID: 05b97154cabfafb769fb0afb99744dca1b5b1bdc6436657c0ac32887cfa599da
docker:
- image: circleci/php:7-cli-node-browsers-legacy
working_directory: ~/repo
steps:
- checkout
- run:
name: Setup dependencies
name: Setup DDEV
command: |
sudo composer self-update
composer install -n --prefer-dist
curl -LO https://raw.githubusercontent.com/drud/ddev/master/scripts/install_ddev.sh && bash install_ddev.sh
- run:
name: Setup Code Climate test-reporter
command: |
Expand All @@ -21,6 +20,10 @@ jobs:
- run:
name: Run tests
command: |
ddev start
ddev xdebug
ddev composer install
./cc-test-reporter before-build
vendor/bin/phpunit --testsuite all --coverage-clover clover.xml
ddev exec ./vendor/bin/phpunit --testsuite all --coverage-clover clover.xml
sed -i 's+/var/www/html/+/home/circleci/repo/+g' clover.xml
./cc-test-reporter after-build --coverage-input-type clover --exit-code $?
171 changes: 171 additions & 0 deletions .ddev/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: file-fetcher
type: php
docroot: ""
php_version: "7.3"
webserver_type: nginx-fpm
router_http_port: "80"
router_https_port: "443"
xdebug_enabled: false
additional_hostnames: []
additional_fqdns: []
mariadb_version: "10.2"
mysql_version: ""
provider: default
use_dns_when_possible: true
composer_version: ""


# This config.yaml was created with ddev version v1.16.5
# webimage: drud/ddev-webserver:v1.16.3
# dbimage: drud/ddev-dbserver-mariadb-10.2:v1.16.0
# dbaimage: phpmyadmin:5
# However we do not recommend explicitly wiring these images into the
# config.yaml as they may break future versions of ddev.
# You can update this config.yaml using 'ddev config'.

# Key features of ddev's config.yaml:

# name: <projectname> # Name of the project, automatically provides
# http://projectname.ddev.site and https://projectname.ddev.site

# type: <projecttype> # drupal6/7/8, backdrop, typo3, wordpress, php

# docroot: <relative_path> # Relative path to the directory containing index.php.

# php_version: "7.3" # PHP version to use, "5.6", "7.0", "7.1", "7.2", "7.3", "7.4" "8.0"

# You can explicitly specify the webimage, dbimage, dbaimage lines but this
# is not recommended, as the images are often closely tied to ddev's' behavior,
# so this can break upgrades.

# webimage: <docker_image> # nginx/php docker image.
# dbimage: <docker_image> # mariadb docker image.
# dbaimage: <docker_image>

# mariadb_version and mysql_version
# ddev can use many versions of mariadb and mysql
# However these directives are mutually exclusive
# mariadb_version: 10.2
# mysql_version: 8.0

# router_http_port: <port> # Port to be used for http (defaults to port 80)
# router_https_port: <port> # Port for https (defaults to 443)

# xdebug_enabled: false # Set to true to enable xdebug and "ddev start" or "ddev restart"
# Note that for most people the commands
# "ddev xdebug" to enable xdebug and "ddev xdebug off" to disable it work better,
# as leaving xdebug enabled all the time is a big performance hit.

# webserver_type: nginx-fpm # or apache-fpm

# timezone: Europe/Berlin
# This is the timezone used in the containers and by PHP;
# it can be set to any valid timezone,
# see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# For example Europe/Dublin or MST7MDT

# composer_version: "2"
# if composer_version:"" it will use the current ddev default composer release.
# It can also be set to "1", to get most recent composer v1
# or "2" for most recent composer v2.
# It can be set to any existing specific composer version.
# After first project 'ddev start' this will not be updated until it changes

# additional_hostnames:
# - somename
# - someothername
# would provide http and https URLs for "somename.ddev.site"
# and "someothername.ddev.site".

# additional_fqdns:
# - example.com
# - sub1.example.com
# would provide http and https URLs for "example.com" and "sub1.example.com"
# Please take care with this because it can cause great confusion.

# upload_dir: custom/upload/dir
# would set the destination path for ddev import-files to custom/upload/dir.

# working_dir:
# web: /var/www/html
# db: /home
# would set the default working directory for the web and db services.
# These values specify the destination directory for ddev ssh and the
# directory in which commands passed into ddev exec are run.

# omit_containers: [db, dba, ddev-ssh-agent]
# Currently only these containers are supported. Some containers can also be
# omitted globally in the ~/.ddev/global_config.yaml. Note that if you omit
# the "db" container, several standard features of ddev that access the
# database container will be unusable.

# nfs_mount_enabled: false
# Great performance improvement but requires host configuration first.
# See https://ddev.readthedocs.io/en/stable/users/performance/#using-nfs-to-mount-the-project-into-the-container

# host_https_port: "59002"
# The host port binding for https can be explicitly specified. It is
# dynamic unless otherwise specified.
# This is not used by most people, most people use the *router* instead
# of the localhost port.

# host_webserver_port: "59001"
# The host port binding for the ddev-webserver can be explicitly specified. It is
# dynamic unless otherwise specified.
# This is not used by most people, most people use the *router* instead
# of the localhost port.

# host_db_port: "59002"
# The host port binding for the ddev-dbserver can be explicitly specified. It is dynamic
# unless explicitly specified.

# phpmyadmin_port: "8036"
# phpmyadmin_https_port: "8037"
# The PHPMyAdmin ports can be changed from the default 8036 and 8037

# mailhog_port: "8025"
# mailhog_https_port: "8026"
# The MailHog ports can be changed from the default 8025 and 8026

# webimage_extra_packages: [php7.3-tidy, php-bcmath]
# Extra Debian packages that are needed in the webimage can be added here

# dbimage_extra_packages: [telnet,netcat]
# Extra Debian packages that are needed in the dbimage can be added here

# use_dns_when_possible: true
# If the host has internet access and the domain configured can
# successfully be looked up, DNS will be used for hostname resolution
# instead of editing /etc/hosts
# Defaults to true

# project_tld: ddev.site
# The top-level domain used for project URLs
# The default "ddev.site" allows DNS lookup via a wildcard
# If you prefer you can change this to "ddev.local" to preserve
# pre-v1.9 behavior.

# ngrok_args: --subdomain mysite --auth username:pass
# Provide extra flags to the "ngrok http" command, see
# https://ngrok.com/docs#http or run "ngrok http -h"

# disable_settings_management: false
# If true, ddev will not create CMS-specific settings files like
# Drupal's settings.php/settings.ddev.php or TYPO3's AdditionalSettings.php
# In this case the user must provide all such settings.

# no_project_mount: false
# (Experimental) If true, ddev will not mount the project into the web container;
# the user is responsible for mounting it manually or via a script.
# This is to enable experimentation with alternate file mounting strategies.
# For advanced users only!

# provider: default # Currently either "default" or "pantheon"
#
# Many ddev commands can be extended to run tasks before or after the
# ddev command is executed, for example "post-start", "post-import-db",
# "pre-composer", "post-composer"
# See https://ddev.readthedocs.io/en/stable/users/extending-commands/ for more
# information on the commands that can be extended and the tasks you can define
# for them. Example:
#hooks:
5 changes: 5 additions & 0 deletions .ddev/docker-compose.environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
services:
web:
environment:
XDEBUG_MODE: 'coverage'
PHP_IDE_CONFIG: 'serverName=myproject.ddev.local'
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"license": "GPL-3.0-only",
"minimum-stability": "dev",
"require-dev": {
"phpunit/phpunit": "^8.2"
"phpunit/phpunit": "^8.2",
"badoo/soft-mocks": "dev-master",
"getdkan/mock-chain": "dev-master"
},
"authors": [
{
Expand All @@ -15,7 +17,7 @@
"autoload": {
"psr-4": {
"FileFetcher\\": "src/",
"FileFetcherTest\\": "test/"
"FileFetcherTests\\": "test/"
}
},
"require": {
Expand Down
24 changes: 24 additions & 0 deletions src/PhpFunctionsBridge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace FileFetcher;

/**
* Intercept calls to PHP functions.
*/

class PhpFunctionsBridge
{
/**
* Magic call to intercept any function pass to it.
*
* @param string $func The function to call.
*
* @param array $args Arguments passed to the function.
*
* @return mixed The result of the function call.
*/
public function __call($func, $args)
{
return call_user_func_array($func, $args);
}
}
21 changes: 21 additions & 0 deletions src/PhpFunctionsBridgeTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace FileFetcher;

trait PhpFunctionsBridgeTrait
{
/**
* @var PhpFunctionsBridge
*/
protected $php;

private function initializePhpFunctionsBridge()
{
$this->php = new PhpFunctionsBridge();
}

public function setPhpFunctionsBridge(PhpFunctionsBridge $bridge)
{
$this->php = $bridge;
}
}
106 changes: 106 additions & 0 deletions src/Processor/AbstractChunkedProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

namespace FileFetcher\Processor;

use FileFetcher\PhpFunctionsBridgeTrait;
use FileFetcher\TemporaryFilePathFromUrl;
use Procrastinator\Result;

abstract class AbstractChunkedProcessor implements ProcessorInterface
{
use PhpFunctionsBridgeTrait;
use TemporaryFilePathFromUrl;

abstract public function isServerCompatible(array $state): bool;
abstract protected function getFileSize(string $filePath): int;
abstract protected function getChunk(string $filePath, int $start, int $end);
/**
* Constructor.
*/
public function __construct()
{
$this->initializePhpFunctionsBridge();
}


public function setupState(array $state): array
{
$state['destination'] = $this->getTemporaryFilePath($state);
$state['temporary'] = true;
$state['total_bytes'] = $this->getFileSize($state['source']);

if (file_exists($state['destination'])) {
clearstatcache();
$state['total_bytes_copied'] = filesize($state['destination']);
}

return $state;
}

public function isTimeLimitIncompatible(): bool
{
return false;
}

public function copy(array $state, Result $result, int $timeLimit = PHP_INT_MAX): array
{
$destinationFile = $state['destination'];
$total = $state['total_bytes_copied'];

$expiration = time() + $timeLimit;

while ($chunk = $this->getTheChunk($state)) {
$bytesWritten = $this->createOrAppend($destinationFile, $chunk);

if ($bytesWritten !== strlen($chunk)) {
throw new \RuntimeException(
"Unable to fetch {$state['source']}. " .
" Reason: Failed to write to destination " . $destinationFile,
0
);
}

$total += $bytesWritten;
$state['total_bytes_copied'] = $total;

$currentTime = time();
if ($currentTime > $expiration) {
$result->setStatus(Result::STOPPED);
return ['state' => $state, 'result' => $result];
}
}

$result->setStatus(Result::DONE);
return ['state' => $state, 'result' => $result];
}

private function createOrAppend($filePath, $chunk)
{
if (!file_exists($filePath)) {
$bytesWritten = file_put_contents($filePath, $chunk);
} else {
$bytesWritten = file_put_contents($filePath, $chunk, FILE_APPEND);
}
return $bytesWritten;
}

private function getTheChunk(array $state)
{
// 10 MB.
$bytesToRead = 10 * 1000 * 1000;

$filePath = $state['source'];
$start = $state['total_bytes_copied'];
$end = $start + $bytesToRead;

if ($end > $state['total_bytes']) {
$end = $state['total_bytes'];
}

if ($start == $end) {
return false;
}

return $this->getChunk($filePath, $start, $end);
}
}
Loading

0 comments on commit 258a26e

Please sign in to comment.