Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
garveen committed Jan 6, 2016
0 parents commit 0cd5099
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
vendor/
composer.lock

public/*
!public/index.php
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## Imagist

Image the packagist

### Introduction

Due to the Internet connection may not so stable, you want to have a cached `packagist` for using `composer`.

### Installation

#### Installer

```
composer global require acabin/imagist
```

You may have put the `~/.composer/vendor/bin` directory in your PATH. If not, do so.

Once installed, the `imagist new` command can be used for create your own site.

```
imagist new my_packagist
```

#### Composer

```
composer require composer/composer:^1.0@alpha acabin/imagist
```

### Usage

1. Now you have a `public` directory in your site. You can set up a web server as usual, just by using the `public` as root.

2. Set up a `crontab` job to update the packages.json:

```
*/5 * * * * php /path/to/public/index.php packages.json >/dev/null 2>&1
```

3. Configure your `composer` to use this amazing site:

```
composer config [--global] repo.packagist composer https://yoursite
```

Notice: You should **NOT** use `imagist` globally on the machine which you run it.
27 changes: 27 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "acabin/imagist",
"description": "Image the packagist",
"keywords": ["image", "proxy", "packagist", "composer"],
"config": {
"bin-dir": "public"
},
"authors": [
{
"name": "Gavin",
"email": "acabin@live.com"
}
],
"require": {
"symfony/console": "~2.3|~3.0",
"symfony/process": "~2.3|~3.0",
"symfony/http-foundation": "~2.3|~3.0",
"composer/composer": "^1.0@alpha"
},
"autoload": {
"psr-4": {
"Acabin\\Imagist\\": "src/"
}
},
"bin": ["imagist"],
"license": "GPL-2.0"
}
11 changes: 11 additions & 0 deletions imagist
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env php
<?php
if (file_exists(__DIR__.'/../../autoload.php')) {
require __DIR__.'/../../autoload.php';
} else {
require __DIR__.'/vendor/autoload.php';
}
define('ROOT_PATH', __DIR__);
$app = new Symfony\Component\Console\Application('imagist');
$app->add(new Acabin\Imagist\Console\NewCommand);
$app->run();
23 changes: 23 additions & 0 deletions public/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

if (file_exists(__DIR__.'/../../autoload.php')) {
require __DIR__.'/../../autoload.php';
} else {
require __DIR__.'/../vendor/autoload.php';
}
define('ROOT_PATH', __DIR__);

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

if(PHP_SAPI == 'cli') {
$argv[0] = '';
$request = Request::create(implode('/', $argv));
} else {
$request = Request::createFromGlobals();
}

$response = new Response;
$imagist = new Acabin\Imagist\Http\Imagist($request, $response);
$imagist->run();

84 changes: 84 additions & 0 deletions src/Console/NewCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
namespace Acabin\Imagist\Console;

use RuntimeException;
use Symfony\Component\Process\Process;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class NewCommand extends Command
{
/**
* Configure the command options.
*
* @return void
*/
protected function configure()
{
$this
->setName('new')
->setDescription('Create a new Imagist application.')
->addArgument('name', InputArgument::REQUIRED);
}
/**
* Execute the command.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->verifyApplicationDoesntExist(
$directory = getcwd() . '/' . $input->getArgument('name'),
$output
);

mkdir($directory, 0755, true);
$composer = $this->findComposer();
$commands = [
"$composer require composer/composer:^1.0@alpha acabin/imagist",
];
if(!empty($commands)) {
$this->process($commands, $directory, $output);
}
mkdir($directory . "/public", 0755, true);
copy(ROOT_PATH . '/index.php', $directory . "/public/index.php");

$output->writeln('<comment>Here we are! Now you can have a cached composer!</comment>');

}
protected function process($commands, $directory, $output)
{
$process = new Process(implode(' && ', $commands), $directory, null, null, null);
$process->run(function ($type, $line) use ($output) {
$output->write($line);
});
}
/**
* Verify that the application does not already exist.
*
* @param string $directory
* @return void
*/
protected function verifyApplicationDoesntExist($directory, OutputInterface $output)
{
if (is_dir($directory)) {
throw new RuntimeException('Application already exists!');
}
}
/**
* Get the composer command for the environment.
*
* @return string
*/
protected function findComposer()
{
if (file_exists(getcwd() . '/composer.phar')) {
return '"' . PHP_BINARY . '" composer.phar';
}
return 'composer';
}
}
164 changes: 164 additions & 0 deletions src/Http/Imagist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?php

namespace Acabin\Imagist\Http;

use Illuminate\Http\Request;

use Composer\Console\Application;
use Composer\IO\ConsoleIO;
use Symfony\Component\Console\Helper\HelperSet;
use Composer\Factory;
use Composer\Repository\CompositeRepository;

use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Composer\DependencyResolver\Pool;

class Imagist
{
protected $request;
protected $response;
protected $pathinfo;
public function __construct($request, $response)
{
$this->request = $request;
$this->response = $response;
$this->pathinfo = $request->getPathInfo();

}

public function run()
{
$pathinfo = rawurldecode($this->pathinfo);
switch (true) {
case preg_match('{^/packages.json$}i', $pathinfo):
$output = $this->generate();
break;
case preg_match('{^/p/(?<name>.*)\$(?<hash>.*)\.json$}i', $pathinfo, $matches):
$output = $this->package($matches);
break;
default:
echo $pathinfo;exit;
}
if (isset($output)) {
if (is_string($output)) {
echo $output;
return;
} elseif (is_object($output)) {
if (is_callable([$output, '__toString'])) {
echo $output->__toString();
return;
}
}
echo json_encode($output);
}
}

protected function generate()
{
$packages = [
'packages' => [],
'notify' => 'https://packagist.org/downloads/%package%',
'notify-batch' => 'https://packagist.org/downloads/',
'providers-url' => '/p/%package%$%hash%.json',
'search' => 'https://packagist.org/search.json?q=%query%',
'provider-includes' => [
],

'sync-time' => date('c'),
];

$repos = $this->getRepos();
foreach ($repos as $repo) {
$repoName = $repo->name;
if (!is_callable([$repo, 'getProviderNames'])) {
continue;
}
$repo->getProviderNames();
// do some hack
$ref = new \ReflectionProperty($repo, 'providerListing');
$ref->setAccessible(true);
$all = $ref->getValue($repo);

$json = json_encode(['providers' => $all]);
$sha256 = hash('sha256', $json);
$path = "p/{$repoName}";
$file = "{$path}/all\${$sha256}.json";

mkdir($path, 0755, true);

file_put_contents($file, $json);

$packages['provider-includes'][$file] = ['sha256' => $sha256];
}

file_put_contents("packages.json", json_encode($packages));
return $packages;
}

protected function package($matches)
{

$hash = $matches['hash'];
$name = $matches['name'];
$filename = 'p/hash/' . substr($hash, 0, 2) . '/' . substr($hash, 2, 2) . '/' . $hash . hash('md5', $hash . $name) . '.json';
if (!file_exists($filename)) {
$repos = $this->getRepos();
$pool = new Pool('dev');
foreach ($repos as $repo) {
try {
$pool->addRepository($repo);
} catch (\RuntimeException $e) {}

}
$matches = $pool->whatProvides($name, null);
if (!$matches) {
return '{}';
} else {
$match = $matches[0];
$repo = $match->getRepository();

$ref = new \ReflectionProperty($repo, 'cache');
$ref->setAccessible(true);
$cache = $ref->getValue($repo);

$cacheKey = 'provider-' . strtr($name, '/', '$') . '.json';
$packages = $cache->read($cacheKey);
if (empty($packages)) {
throw new \Exception("Cache should exists, please report this issue on github", 1);
}
mkdir(dirname($filename), 0755, true);
file_put_contents($filename, $packages);
}

}
return file_get_contents($filename);
}

protected function getRepos()
{
$input = new StringInput('');
$output = new BufferedOutput;
$helperSet = new HelperSet;

$io = new ConsoleIO($input, $output, $helperSet);
if (!file_exists('composer.json')) {
putenv('COMPOSER=../composer.json');
}

$composer = Factory::create($io);
$config = $composer->getConfig();
$repos = $config->getRepositories();

foreach ($repos as &$repo) {
$type = ucfirst($repo['type']);
$type = "Composer\\Repository\\{$type}Repository";
$repo = new $type($repo, $io, $config);
$ref = new \ReflectionProperty($repo, 'url');
$ref->setAccessible(true);
$url = $ref->getValue($repo);
$repo->name = preg_replace(['{^https?://}i', '{[^a-z0-9._]}i'], ['', '-'], $url);
}
return $repos;
}
}

0 comments on commit 0cd5099

Please sign in to comment.