Einrichten eines lokalen Spiegels für Composer-Pakete mit Satis
German (Deutsch) translation by Władysław Łucyszyn (you can also view the original English article)
Die Installation all Ihrer PHP-Bibliotheken mit Composer ist eine großartige Möglichkeit, Zeit zu sparen. Bei größeren Projekten, die bei jedem Commit für Ihr SVC-System (Software Version Control) automatisch getestet und ausgeführt werden, dauert es jedoch lange, bis alle erforderlichen Pakete aus dem Internet installiert sind. Sie möchten Ihre Tests so schnell wie möglich über Ihr CI-System (Continuous Integration) ausführen, damit Sie schnelles Feedback und schnelle Reaktionen auf Fehler erhalten. In diesem Tutorial richten wir einen lokalen Spiegel ein, um alle in der Datei composer.json Ihres Projekts erforderlichen Pakete zu vertreten. Dadurch arbeitet unser CI viel schneller, die Pakete werden über das lokale Netzwerk installiert oder sogar auf demselben Computer gehostet, und es wird sichergestellt, dass die spezifischen Versionen der Pakete immer verfügbar sind.
Was ist Satis?
Satis ist der Name der Anwendung, mit der wir die verschiedenen Repositorys für unser Projekt spiegeln. Es dient als Proxy zwischen dem Internet und Ihrem Komponisten. Unsere Lösung erstellt einen lokalen Spiegel einiger Pakete und weist unseren Komponisten an, diese anstelle der im Internet gefundenen Quellen zu verwenden.
Hier ist ein Bild, das mehr als tausend Worte sagt.



Unser Projekt wird wie gewohnt Komponisten verwenden. Es wird so konfiguriert, dass der lokale Satis-Server als primäre Quelle verwendet wird. Wenn dort ein Paket gefunden wird, wird es von dort installiert. Wenn nicht, lassen wir den Komponisten das Standardpaket packagist.org verwenden, um das Paket abzurufen.
Satis bekommen
Satis ist über Composer erhältlich, daher ist die Installation sehr einfach. Im angehängten Quellcodearchiv finden Sie Satis im Ordner Sources/Satis installiert. Zuerst werden wir den Komponisten selbst installieren.
1 |
$ curl -sS https://getcomposer.org/installer | php |
2 |
#!/usr/bin/env php All settings correct for using Composer Downloading...
|
3 |
Composer successfully installed to: /home/csaba/Personal/Programming/NetTuts/Setting up a local mirror for Composer packages with Satis/Sources/Satis/composer.phar Use it: php composer.phar |
Dann werden wir Satis installieren.
1 |
$ php composer.phar create-project composer/satis --stability=dev --keep-vcs Installing composer/satis (dev-master eddb78d52e8f7ea772436f2320d6625e18d5daf5) |
2 |
- Installing composer/satis (dev-master master) |
3 |
Cloning master |
4 |
Created project in /home/csaba/Personal/Programming/NetTuts/Setting up a local mirror for Composer packages with Satis/Sources/Satis/satis Loading composer repositories with package information Installing dependencies (including require-dev) from lock file |
5 |
- Installing symfony/process (dev-master 27b0fc6) |
6 |
Cloning 27b0fc645a557b2fc7bc7735cfb05505de9351be |
7 |
|
8 |
- Installing symfony/finder (v2.4.0-BETA1) |
9 |
Downloading: 100% |
10 |
|
11 |
- Installing symfony/console (dev-master f44cc6f) |
12 |
Cloning f44cc6fabdaa853335d7f54f1b86c99622db518a |
13 |
|
14 |
- Installing seld/jsonlint (1.1.1) |
15 |
Downloading: 100% |
16 |
|
17 |
- Installing justinrainbow/json-schema (1.1.0) |
18 |
Downloading: 100% |
19 |
|
20 |
- Installing composer/composer (dev-master f8be812) |
21 |
Cloning f8be812a496886c84918d6dd1b50db5c16da3cc3 |
22 |
|
23 |
- Installing twig/twig (v1.14.1) |
24 |
Downloading: 100% |
25 |
symfony/console suggests installing symfony/event-dispatcher () Generating autoload files
|
Satis konfigurieren
Satis wird durch eine JSON-Datei konfiguriert, die dem Composer sehr ähnlich ist. Sie können einen beliebigen Namen für Ihre Datei verwenden und ihn zur späteren Verwendung angeben. Wir werden "mirrored-packages.conf" verwenden.
1 |
{
|
2 |
"name": "NetTuts Composer Mirror", |
3 |
"homepage": "https://localhost:4680", |
4 |
|
5 |
"repositories": [ |
6 |
{ "type": "vcs", "url": "https://github.com/SynetoNet/monolog" }, |
7 |
{ "type": "composer", "url": "https://packagist.org" } |
8 |
],
|
9 |
|
10 |
"require": { |
11 |
"monolog/monolog": "syneto-dev", |
12 |
"mockery/mockery": "*", |
13 |
"phpunit/phpunit": "*" |
14 |
},
|
15 |
"require-dependencies": true |
16 |
}
|
Lassen Sie uns diese Konfigurationsdatei analysieren.
-
name- steht für eine Zeichenfolge, die auf der Weboberfläche unseres Spiegels angezeigt wird. -
homepage- ist die Webadresse, unter der unsere Pakete aufbewahrt werden. Dies weist unseren Webserver nicht an, diese Adresse und diesen Port zu verwenden, sondern ist lediglich eine Information über eine funktionierende Konfiguration. Wir werden den Zugriff darauf später auf dieser Adresse und diesem Port einrichten. -
repositories- Eine Liste der nach Präferenzen geordneten Repositorys. In unserem Beispiel ist das erste Repository eine Github-Verzweigung der Monolog-Protokollierungsbibliotheken. Es hat einige Modifikationen und wir möchten diese spezielle Gabel bei der Installation von Monolog verwenden. Der Typ dieses Repositorys ist "vcs". Das zweite Repository ist vom Typ "composer". Die URL ist die Standardwebsite von packagist.org. -
require- listet die Pakete auf, die gespiegelt werden sollen. Es kann ein bestimmtes Paket mit einer bestimmten Version oder einem bestimmten Zweig oder eine beliebige Version für diese Angelegenheit darstellen. Es verwendet dieselbe Syntax wie "require" oder "require-dev" in Ihrercomposer.json. -
require-dependencies- ist die letzte Option in unserem Beispiel. Satis wird angewiesen, nicht nur die Pakete zu spiegeln, die wir im Abschnitt "require" angegeben haben, sondern auch alle ihre Abhängigkeiten.
Um unsere Einstellungen schnell auszuprobieren, müssen wir Satis zunächst anweisen, die Spiegel zu erstellen. Führen Sie diesen Befehl in dem Ordner aus, in dem Sie Satis installiert haben.
1 |
$ php ./satis/bin/satis build ./mirrored-packages.conf ./packages-mirror Scanning packages Writing packages.json Writing web view
|
Während des Vorgangs sehen Sie, wie Satis jede gefundene Version der erforderlichen Pakete spiegelt. Seien Sie geduldig, es kann eine Weile dauern, bis alle diese Pakete erstellt sind.
Satis verlangt, dass date.timezone in der Datei php.ini angegeben wird. Stellen Sie daher sicher, dass dies der Fall ist, und stellen Sie Ihre lokale Zeitzone ein. Andernfalls wird ein Fehler angezeigt.
1 |
[Twig_Error_Runtime]
|
2 |
An exception has been thrown during the rendering of a template |
3 |
("date_default_timezone_get(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set) function. |
Dann können wir eine PHP-Serverinstanz in unserer Konsole ausführen, die auf das kürzlich erstellte Repository verweist. PHP 5.4 oder neuer ist erforderlich.
1 |
$ php -S localhost:4680 -t ./packages-mirror/ PHP 5.4.22-pl0-gentoo Development Server started at Sun Dec 8 14:47:48 2013 Listening on http://localhost:4680 Document root is /home/csaba/Personal/Programming/NetTuts/Setting up a local mirror for Composer packages with Satis/Sources/Satis/packages-mirror Press Ctrl-C to quit. |
2 |
[Sun Dec 8 14:48:09 2013] 127.0.0.1:56999 [200]: / |
3 |
[Sun Dec 8 14:48:09 2013] 127.0.0.1:57000 [404]: /favicon.ico - No such file or directory |
Und wir können jetzt unsere gespiegelten Pakete durchsuchen und sogar nach bestimmten suchen, indem wir unseren Webbrowser auf http://localhost:4680: verweisen.



Lassen Sie es uns auf Apache hosten
Wenn Sie einen laufenden Apache zur Hand haben, ist das Erstellen eines virtuellen Hosts für Satis ganz einfach.
1 |
Listen 4680 |
2 |
|
3 |
<Directory "/path/to/your/packages-mirror"> Options -Indexes FollowSymLinks AllowOverride all Order allow,deny Allow from all |
4 |
</Directory> |
5 |
|
6 |
<VirtualHost *:4680> DocumentRoot "/path/to/your/packages-mirror" ServerName 127.0.0.1:4680 ServerAdmin admin@example.com |
7 |
ErrorLog syslog:user |
8 |
|
9 |
</VirtualHost> |
Wir verwenden einfach eine solche .conf-Datei, die im Ordner conf.d von Apache abgelegt wird, normalerweise /etc/apache2/conf.d. Es erstellt einen virtuellen Host am 4680-Port und verweist ihn auf unseren Ordner. Natürlich können Sie jeden gewünschten Port verwenden.
Aktualisierung unserer Spiegel
Satis kann die Spiegel nur dann automatisch aktualisieren, wenn wir es mitteilen. Der einfachste Weg auf einem UNIX-ähnlichen System besteht darin, Ihrem System einfach einen Cron-Job hinzuzufügen. Das wäre sehr einfach und nur ein einfaches Skript, um unseren Update-Befehl auszuführen.
1 |
#!/bin/bash php /full/path/to/satis/bin/satis build \
|
2 |
/full/path/to/mirrored-packages.conf \
|
3 |
/full/path/to/packages-mirror |
Der Nachteil dieser Lösung ist, dass sie statisch ist. Wir müssen die mirrored-package.conf jedes Mal manuell aktualisieren, wenn wir der composer.json unseres Projekts ein weiteres Paket hinzufügen. Wenn Sie Teil eines Teams in einem Unternehmen mit einem großen Projekt und einem Server für die kontinuierliche Integration sind, können Sie sich nicht darauf verlassen, dass Benutzer daran denken, die Pakete auf dem Server hinzuzufügen. Sie haben möglicherweise nicht einmal die Berechtigung, auf die CI-Infrastruktur zuzugreifen.
Dynamische Aktualisierung der Satis-Konfiguration
Es ist Zeit für eine PHP TDD-Übung. Wenn Sie nur möchten, dass Ihr Code bereit und ausgeführt wird, lesen Sie den Quellcode, der diesem Tutorial beigefügt ist.
1 |
require_once __DIR__ . '/../../../../vendor/autoload.php'; |
2 |
class SatisUpdaterTest extends PHPUnit_Framework_TestCase { |
3 |
function testBehavior() { |
4 |
$this->assertTrue(true); |
5 |
}
|
6 |
}
|
Wie üblich beginnen wir mit einem degenerativen Test, gerade genug, um sicherzustellen, dass wir ein funktionierendes Test-Framework haben. Möglicherweise stellen Sie fest, dass ich eine ziemlich seltsam aussehende require_once-Zeile habe. Dies liegt daran, dass ich vermeiden möchte, PHPUnit und Mockery für jedes kleine Projekt neu installieren zu müssen. Ich habe sie also in einem vendor ordner im Stammverzeichnis meiner NetTuts. Sie sollten sie einfach mit Composer installieren und die Zeile require_once ganz löschen.
1 |
class SatisUpdaterTest extends PHPUnit_Framework_TestCase { |
2 |
function testDefaultConfigFile() { |
3 |
$expected = '{ |
4 |
"name": "NetTuts Composer Mirror",
|
5 |
"homepage": "http://localhost:4680",
|
6 |
|
7 |
"repositories": [
|
8 |
{ "type": "vcs", "url": "https://github.com/SynetoNet/monolog" },
|
9 |
{ "type": "composer", "url": "https://packagist.org" }
|
10 |
],
|
11 |
|
12 |
"require": {
|
13 |
},
|
14 |
"require-dependencies": true
|
15 |
}'; |
16 |
$actual = $this->parseComposerConf(''); |
17 |
$this->assertEquals($expected, $actual); |
18 |
}
|
19 |
}
|
Das sieht ungefähr richtig aus. Alle Felder außer "require" sind statisch. Wir müssen nur die Pakete generieren. Die Repositories verweisen auf unsere privaten Git-Klone und auf Packagist nach Bedarf. Das Verwalten dieser Aufgaben ist eher ein Systemadministratorjob als der eines Softwareentwicklers.
Dies schlägt natürlich fehl mit:
1 |
PHP Fatal error: Call to undefined method SatisUpdaterTest::parseComposerConf()
|
Das zu beheben ist einfach.
1 |
private function parseComposerConf($string) { |
2 |
}
|
Ich habe unserer Testklasse gerade eine leere Methode mit dem erforderlichen Namen als privat hinzugefügt. Cool, aber jetzt haben wir einen anderen Fehler.
1 |
PHPUnit_Framework_ExpectationFailedException : Failed asserting that null matches expected '{ ... }'
|
Daher stimmt null nicht mit unserer Zeichenfolge überein, die die gesamte Standardkonfiguration enthält.
1 |
private function parseComposerConf($string) { |
2 |
return '{ |
3 |
"name": "NetTuts Composer Mirror",
|
4 |
"homepage": "http://localhost:4680",
|
5 |
|
6 |
"repositories": [
|
7 |
{ "type": "vcs", "url": "https://github.com/SynetoNet/monolog" },
|
8 |
{ "type": "composer", "url": "https://packagist.org" }
|
9 |
],
|
10 |
|
11 |
"require": {
|
12 |
},
|
13 |
"require-dependencies": true
|
14 |
}'; |
15 |
}
|
OK, das funktioniert. Alle Tests bestehen.
1 |
PHPUnit 3.7.28 by Sebastian Bergmann. Time: 15 ms, Memory: 2.50Mb OK (1 test, 1 assertion) |
Aber wir haben eine schreckliche Vervielfältigung eingeführt. All dieser statische Text an zwei Stellen, Zeichen für Zeichen an zwei verschiedenen Stellen geschrieben. Lassen Sie es uns beheben:
1 |
class SatisUpdaterTest extends PHPUnit_Framework_TestCase { |
2 |
static $DEFAULT_CONFIG = '{ |
3 |
"name": "NetTuts Composer Mirror",
|
4 |
"homepage": "http://localhost:4680",
|
5 |
|
6 |
"repositories": [
|
7 |
{ "type": "vcs", "url": "https://github.com/SynetoNet/monolog" },
|
8 |
{ "type": "composer", "url": "https://packagist.org" }
|
9 |
],
|
10 |
|
11 |
"require": {
|
12 |
},
|
13 |
"require-dependencies": true
|
14 |
}'; |
15 |
|
16 |
function testDefaultConfigFile() { |
17 |
$expected = self::$DEFAULT_CONFIG; |
18 |
|
19 |
$actual = $this->parseComposerConf(''); |
20 |
$this->assertEquals($expected, $actual); |
21 |
}
|
22 |
|
23 |
private function parseComposerConf($string) { |
24 |
return self::$DEFAULT_CONFIG; |
25 |
}
|
26 |
}
|
Ähhh! Das ist besser.
1 |
function testEmptyRequiredPackagesInComposerJsonWillProduceDefaultConfiguration() { |
2 |
$expected = self::$DEFAULT_CONFIG; |
3 |
|
4 |
$actual = $this->parseComposerConf('{"require": {}}'); |
5 |
$this->assertEquals($expected, $actual); |
6 |
}
|
Gut. Das geht auch vorbei. Es werden aber auch einige Überschneidungen und nutzlose Zuordnungen hervorgehoben.
1 |
function testDefaultConfigFile() { |
2 |
$actual = $this->parseComposerConf(''); |
3 |
$this->assertEquals(self::$DEFAULT_CONFIG, $actual); |
4 |
}
|
5 |
function testEmptyRequiredPackagesInComposerJsonWillProduceDefaultConfiguration() { |
6 |
$actual = $this->parseComposerConf('{"require": {}}'); |
7 |
$this->assertEquals(self::$DEFAULT_CONFIG, $actual); |
8 |
}
|
Wir haben die erwartete Variable $expected. $actual könnte auch inline sein, aber ich mag es auf diese Weise besser. Der Fokus bleibt auf dem, was getestet wird.
Jetzt haben wir ein anderes Problem. Der nächste Test, den ich schreiben möchte, würde folgendermaßen aussehen:
1 |
function testARequiredPackageInComposerWillBeInSatisAlso() { |
2 |
$actual = $this->parseComposerConf( |
3 |
'{"require": {
|
4 |
"Mockery/Mockery": ">=0.7.2"
|
5 |
}}'); |
6 |
$this->assertContains('"Mockery/Mockery": ">=0.7.2"', $actual); |
7 |
}
|
Nach dem Schreiben der einfachen Implementierung werden wir jedoch feststellen, dass dafür json_decode() und json_encode() erforderlich sind. Und natürlich werden diese Funktionen unsere Zeichenfolge neu formatieren und passende Zeichenfolgen werden bestenfalls schwierig sein. Wir müssen einen Schritt zurücktreten.
1 |
function testDefaultConfigFile() { |
2 |
$actual = $this->parseComposerConf(''); |
3 |
$this->assertJsonStringEqualsJsonString($this->jsonRecode(self::$DEFAULT_CONFIG), $actual); |
4 |
}
|
5 |
function testEmptyRequiredPackagesInComposerJsonWillProduceDefaultConfiguration() { |
6 |
$actual = $this->parseComposerConf('{"require": {}}'); |
7 |
$this->assertJsonStringEqualsJsonString($this->jsonRecode(self::$DEFAULT_CONFIG), $actual); |
8 |
}
|
9 |
private function parseComposerConf($jsonConfig) { |
10 |
return $this->jsonRecode(self::$DEFAULT_CONFIG); |
11 |
}
|
12 |
private function jsonRecode($json) { |
13 |
return json_encode(json_decode($json, true)); |
14 |
}
|
Wir haben unsere Assertionsmethode geändert, um JSON-Zeichenfolgen zu vergleichen, und wir haben auch unsere Variable $actual neu codiert. ParseComposerConf() wurde ebenfalls geändert, um diese Methode zu verwenden. Sie werden gleich sehen, wie es uns hilft. Unser nächster Test wird JSON-spezifischer.
1 |
function testARequiredPackageInComposerWillBeInSatisAlso() { |
2 |
$actual = $this->parseComposerConf( |
3 |
'{"require": {
|
4 |
"Mockery/Mockery": ">=0.7.2"
|
5 |
}}'); |
6 |
$this->assertEquals('>=0.7.2', json_decode($actual, true)['require']['Mockery/Mockery']); |
7 |
}
|
Und es ist wieder ganz einfach, diesen Test zusammen mit den anderen Tests zu bestehen.
1 |
private function parseComposerConf($jsonConfig) { |
2 |
$addedConfig = json_decode($jsonConfig, true); |
3 |
$config = json_decode(self::$DEFAULT_CONFIG, true); |
4 |
if (isset($addedConfig['require'])) { |
5 |
$config['require'] = $addedConfig['require']; |
6 |
}
|
7 |
return json_encode($config); |
8 |
}
|
Wir nehmen die eingegebene JSON-Zeichenfolge, dekodieren sie und verwenden sie stattdessen in unserer Satis-Konfigurationsdatei, wenn sie ein "require" -Feld enthält. Möglicherweise möchten wir jedoch alle Versionen eines Pakets spiegeln, nicht nur die letzte. Vielleicht möchten wir unseren Test ändern, um zu überprüfen, ob die Version in Satis "*" ist, unabhängig davon, welche genaue Version in composer.json enthalten ist.
1 |
function testARequiredPackageInComposerWillBeInSatisAlso() { |
2 |
$actual = $this->parseComposerConf( |
3 |
'{"require": {
|
4 |
"Mockery/Mockery": ">=0.7.2"
|
5 |
}}'); |
6 |
$this->assertEquals('*', json_decode($actual, true)['require']['Mockery/Mockery']); |
7 |
}
|
Das scheitert offensichtlich mit einer coolen Nachricht:
1 |
PHPUnit_Framework_ExpectationFailedException : Failed asserting that two strings are equal. Expected :* Actual :>=0.7.2 |
Jetzt müssen wir unseren JSON tatsächlich bearbeiten, bevor wir ihn neu codieren können.
1 |
private function parseComposerConf($jsonConfig) { |
2 |
$addedConfig = json_decode($jsonConfig, true); |
3 |
$config = json_decode(self::$DEFAULT_CONFIG, true); |
4 |
$config = $this->addNewRequires($addedConfig, $config); |
5 |
return json_encode($config); |
6 |
}
|
7 |
private function toAllVersions($config) { |
8 |
foreach ($config['require'] as $package => $version) { |
9 |
$config['require'][$package] = '*'; |
10 |
}
|
11 |
return $config; |
12 |
}
|
13 |
private function addNewRequires($addedConfig, $config) { |
14 |
if (isset($addedConfig['require'])) { |
15 |
$config['require'] = $addedConfig['require']; |
16 |
$config = $this->toAllVersions($config); |
17 |
}
|
18 |
return $config; |
19 |
}
|
Um den Test zu bestehen, müssen wir jedes Element des erforderlichen Paketarrays durchlaufen und ihre Version auf '*' setzen. Weitere Informationen finden Sie unter Methode toAllVersion(). Um dieses Tutorial ein wenig zu beschleunigen, haben wir im selben Schritt auch einige private Methoden extrahiert. Auf diese Weise wird parseComoserConf() sehr beschreibend und leicht verständlich. Wir könnten $config auch in die Argumente von addNewRequires() einbinden, aber aus ästhetischen Gründen habe ich es in zwei Zeilen belassen.
Aber was ist mit "require-dev" in composer.json?
1 |
function testARquiredDevPackageInComposerWillBeInSatisAlso() { |
2 |
$actual = $this->parseComposerConf( |
3 |
'{"require-dev": {
|
4 |
"Mockery/Mockery": ">=0.7.2",
|
5 |
"phpunit/phpunit": "3.7.28"
|
6 |
}}'); |
7 |
$this->assertEquals('*', json_decode($actual, true)['require']['Mockery/Mockery']); |
8 |
$this->assertEquals('*', json_decode($actual, true)['require']['phpunit/phpunit']); |
9 |
}
|
Das scheitert offensichtlich. Wir können es schaffen, indem wir einfach unsere if-Bedingung in addNewRequires() kopieren/einfügen:
1 |
private function addNewRequires($addedConfig, $config) { |
2 |
if (isset($addedConfig['require'])) { |
3 |
$config['require'] = $addedConfig['require']; |
4 |
$config = $this->toAllVersions($config); |
5 |
}
|
6 |
if (isset($addedConfig['require-dev'])) { |
7 |
$config['require'] = $addedConfig['require-dev']; |
8 |
$config = $this->toAllVersions($config); |
9 |
}
|
10 |
return $config; |
11 |
}
|
Ja, das macht es pass, aber die duplizierten, wenn Aussagen böse aussehen. Beschäftigen wir uns mit ihnen.
1 |
private function addNewRequires($addedConfig, $config) { |
2 |
$config = $this->addRequire($addedConfig, 'require', $config); |
3 |
$config = $this->addRequire($addedConfig, 'require-dev', $config); |
4 |
return $config; |
5 |
}
|
6 |
private function addRequire($addedConfig, $string, $config) { |
7 |
if (isset($addedConfig[$string])) { |
8 |
$config['require'] = $addedConfig[$string]; |
9 |
$config = $this->toAllVersions($config); |
10 |
}
|
11 |
return $config; |
12 |
}
|
Wir können wieder glücklich sein, die Tests sind grün und wir haben unseren Code überarbeitet. Ich denke, es bleibt nur noch ein Test zu schreiben. Was ist, wenn wir in composer.json sowohl die Abschnitte "require" als auch "require-dev" haben?
1 |
function testItCanParseComposerJsonWithBothSections() { |
2 |
$actual = $this->parseComposerConf( |
3 |
'{"require": {
|
4 |
"Mockery/Mockery": ">=0.7.2"
|
5 |
},
|
6 |
"require-dev": {
|
7 |
"phpunit/phpunit": "3.7.28"
|
8 |
}}'); |
9 |
$this->assertEquals('*', json_decode($actual, true)['require']['Mockery/Mockery']); |
10 |
$this->assertEquals('*', json_decode($actual, true)['require']['phpunit/phpunit']); |
11 |
}
|
Dies schlägt fehl, da die von "require-dev" festgelegten Pakete die von "require" überschreiben und ein Fehler auftritt:
1 |
Undefined index: Mockery/Mockery |
Fügen Sie einfach ein Pluszeichen hinzu, um die Arrays zusammenzuführen, und wir sind fertig.
1 |
private function addRequire($addedConfig, $string, $config) { |
2 |
if (isset($addedConfig[$string])) { |
3 |
$config['require'] += $addedConfig[$string]; |
4 |
$config = $this->toAllVersions($config); |
5 |
}
|
6 |
return $config; |
7 |
}
|
Tests bestehen. Unsere Logik ist beendet. Wir müssen nur noch die Methoden in ihre eigene Datei und Klasse extrahieren. Die endgültige Version der Tests und die SatisUpdater-Klasse finden Sie im angehängten Quellcode.
Wir können jetzt unser Cron-Skript ändern, um unseren Parser zu laden und auf unserer composer.json auszuführen. Dies ist spezifisch für die jeweiligen Ordner Ihrer Projekte. Hier ist ein Beispiel, das Sie an Ihr System anpassen können.
1 |
#!/usr/local/bin/php
|
2 |
|
3 |
<?php require_once __DIR__ . '/Configuration.php'; |
4 |
|
5 |
$outputDir = '/path/to/your/packages-mirror'; |
6 |
$composerJsonFile = '/path/to/your/projects/composer.json'; |
7 |
$satisConf = '/path/to/your/mirrored-packages.conf'; |
8 |
|
9 |
$satisUpdater = new SatisUpdater(); |
10 |
$conf = $satisUpdater->parseComposerConf(file_get_contents($composerJsonFile)); file_put_contents($satisConf, $conf); |
11 |
system(sprintf('/path/to/satis/bin/satis build %s %s', $satisConf, $outputDir), $retval); exit($retval); |
Verwenden des Spiegels für Ihr Projekt
Wir haben in diesem Artikel über viele Dinge gesprochen, aber wir haben nicht erwähnt, wie wir unser Projekt anweisen werden, den Spiegel anstelle des Internets zu verwenden. Sie wissen, die Standardeinstellung ist packagist.org? Es sei denn, wir machen so etwas:
1 |
"repositories": [ |
2 |
{
|
3 |
"type": "composer", |
4 |
"url": "http://your-mirror-server:4680" |
5 |
}
|
6 |
],
|
Das macht Ihren Spiegel zur ersten Wahl für Komponisten. Wenn Sie jedoch genau das in composer.json Ihres Projekts einfügen, wird der Zugriff auf packagist.org nicht deaktiviert. Wenn ein Paket nicht im lokalen Spiegel gefunden werden kann, wird es aus dem Internet heruntergeladen. Wenn Sie diese Funktion blockieren möchten, möchten Sie möglicherweise auch die folgende Zeile zum obigen Abschnitt "Repositorys" hinzufügen:
1 |
"packagist": false |
Abschließende Gedanken
Das ist es. Lokaler Spiegel mit automatischer Anpassung und Aktualisierung von Paketen. Ihre Kollegen müssen nie lange warten, während sie oder der CI-Server alle Anforderungen Ihrer Projekte installieren. Habe Spaß.



