Composer, Satis, Satisfy: Fremdbibliotheken von Composer, Packagist und Github entkoppeln

In der heutigen Webentwicklung müssen wir das Rad nicht ständig neu erfinden. Es gibt eine Vielzahl von Bibliotheken – sowohl server- als auch clientseitig – die einem das Entwicklerleben vereinfachen. Damit wir aber nicht bei sämtlichen Fremdbibliotheken regelmäßig nachprüfen müssen, ob es eine neue Version gibt, gibt es Paketverwaltungen. Im PHP-Bereich ist Composer der Quasi-Standard für diese Aufgabe.
Dieser Beitrag beschreibt, wie wir mit Composer komfortabel (= inkl. Version Constraints) auch Bibliotheken einbinden können, die:

  • nicht auf Packagist zu finden sind (z.B. private Bibliotheken) und / oder
  • keine composer.json haben oder in früheren Versionen nicht hatten

Die meisten PHP-Bibliotheken sind bei Packagist (dem Standard-Repository von Composer) gelistet und können dadurch ohne weitere Einstellungen in der composer.json unter „require“ angegeben werden.

Bei Bibliotheken, die nicht bei Packagist gelistet sind, müssen wir Composer mitteilen, wo es die Pakete finden kann: Wir müssen die Repositorys selbst definieren.
Für die Einbindung über Github haben wir dann z.B. viele Blöcke wie z.B. folgenden:

"repositories": [
    {
      "type": "package",
      "package": {
        "name": "sciactive/pnotify",
        "version": "2.0.0",
        "source": {
          "url": "https://github.com/sciactive/pnotify",
          "type": "git",
          "reference": "v2.0.0"
        }
      }
    }
]

Die hier angegebene Versionsnummer 2.0.0 basiert auf den Git-Tags der Bibliothek.

Das Problem ist, dass wir die Version fest definiert haben. Composer würde uns immer nur genau diese Version liefern. Wir müssten uns demzufolge selbst darum kümmern, zu gucken, ob es eine neue Version der Bibliothek gibt und dann das Composer-Repository ggf. anpassen. Viel schöner wäre es ja aber, wenn man Bugfix-Releases (und manchmal auch Minor-Releases) automatisch beim Composer Update bekäme.
Leider kann man bei der Definition der Composer-Repositorys aber die Version nicht durch ein Sternchen setzen, sondern dort wird immer ein existierendes Tag (oder ein Branch oder Commit) erwartet.

Und hier kommt Satis ins Spiel. Satis stellt ein Composer-Repository zur Verfügung, ähnlich wie Packagist, mit dem Unterschied, dass es auf unseren Servern läuft und wir selbst bestimmen können, welche Bibliotheken darin enthalten sein sollen (und welche Versionen).
Satis hat dadurch einige Vorteile:

  • Einbindung von nicht öffentlichen Repositorys
  • Einbindung von Bibliotheken, die nicht bei Packagist gelistet sind
  • Nutzung von Bibliotheken, die keine Composer.json haben (mit Satisfy, dazu weiter unten mehr)
  • Unabhängigkeit von Github und Packagist während des Builds (falls diese Seiten mal offline sind oder man selbst kein Internet hat)

Um Satis einzurichten müssen wir zuerst Satis als eigenes Composer-Projekt herunterladen:

php composer.phar create-project composer/satis --stability=dev

Anschließend erstellen wir eine grundlegende Konfiguration (satis.json) innerhalb des gerade erstellten Projektes:

{
    "name": "Our Satis repository",
    "homepage": "http://localhost/satis",
    "require-all": true
}

Dies definiert, lediglich, wie unser Repository heißt (name) und wie man es über den Browser aufrufen kann (homepage).
require-all bedeutet, dass Satis sämtliche Versionen der Bibliotheken laden soll – dies ist die Standardeinstellung, denn schließlich soll ja in der composer.json des eigentlichen Projektes später die genaue Version festgelegt werden können.

Nun müssen wir Satis noch mitteilen, welche Bibliotheken wir benötigen. Für Repositorys, die eine composer.json haben, kann dies direkt in der satis.json definiert werden.

"repositories": [
    { 
        "type": "composer", 
        "url": "https://URL-of-private-Gitlab-Repository" 
    }
]

Projekte, die keine composer.json haben (wie viele JS-Bibliotheken, weil Client-Entwickler wiederum einen eigenen Paketmanager haben) können mittels Satisfy hinzugefügt werden. Satisfy analysiert dazu alle Git-Tags der definierten Bibliotheken und erstellt dafür einzelne Einträge in der Satis-Konfigurationsdatei.

Damit Satisfy weiß, welche Git-Repositories es einlesen soll, benötigen wir eine packagelist.json:

{
    "sciactive/pnotify": {
        "url": "https://github.com/sciactive/pnotify",
        "minversion": "2.0"
    },
    ...
}

Aus der ursprünglichen satis.json und aus der packagelist.json kann Satisfy nun eine erweiterte Satis-Konfiguration erstellen:

satisfy --repofile satis.json --packagefile packagelist.json --output satis.expanded.json

Die entstehende satis.expanded.json enthält sämtliche Git-Tags aller angegebenen Git-Repositorys als einzelne Satis-Repositorys:

"repositories": [
    {
      "type": "package",
      "package": {
        "name": "sciactive/pnotify",
        "version": "2.0.0",
        "source": {
          "url": "https://github.com/sciactive/pnotify",
          "type": "git",
          "reference": "v2.0.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "sciactive/pnotify",
        "version": "2.0.1",
        "source": {
          "url": "https://github.com/sciactive/pnotify",
          "type": "git",
          "reference": "v2.0.1"
        }
      }
    }
...
]

Nun müssen wir Satis nur noch anweisen, die satis.expanded.json einzulesen:

php satis build satis.expanded.json <per HTTP erreichbares Verzeichnis>

Angenommen, wir nutzen Apache und haben einen Link namens „satis“ auf das per HTTP erreichbare Verzeichnis erstellt, können wir im Browser http://localhost/satis aufrufen und sehen eine Übersicht über sämtliche Bibliotheken und deren Versionen, die nun zur Verfügung stehen (so ähnlich wie auf Packagist). Natürlich macht es mehr Sinn Satis auf einen zentralen Server zu packen, damit alle darauf zugreifen können, aber für Testzwecke reicht auch erstmal eine lokale Installation.

Nun können wir die composer.json unseres Projektes öffnen und auf unser Satis-Repository verweisen:

"repositories":[
    {
      "type": "composer",
      "url": "http://localhost/satis"
      }
    },
    {
        "packagist": false
    }
]

Das "packagist": false bewirkt, dass Composer bei fehlenden Paketen nicht auf Packagist nachsieht. Dadurch hat man die komplette Kontrolle über alle eingebundenen Fremdbibliotheken, wenn Satis sinnvollerweise das einzige Composer-Repository ist.

Nun können wir auf sämtliche Bibliotheken und Versionen, die unter http://localhost/satis aufgelistet sind, im require-Block zugreifen:

"require": {
    "sciactive/pnotify": "2.*"
}

Man beachte das Sternchen bei der Versionsangabe. Obwohl die JS-Bibliothek PNotify keine composer.json hat und auch nicht bei Packagist gelistet ist, können wir die Version Constraints von Composer nutzen. Es funktioniert natürlich genauso für Bibliotheken, die eine composer.json haben und trotzdem nicht bei Packagist sind.

Einen weiteren Vorteil hat die Nutzung von Satis noch: Es könnte vorkommen, dass man gerade eine neue Version bauen möchte, aber Github oder Packagist gerade nicht erreichbar sind. In diesem Fall können wir keine neue Version erstellen, was unter Umständen teuer sein kann.
Satis kann als Proxy für Github und Packagist fungieren, indem es per Cronjob regelmäßig die Github-Repositorys überprüft und neue Versionen herunterlädt. Wird später eine bestimmte Version per Composer angefordert, kann auf die zwischengespeicherte Version zurückgegriffen werden und man ist somit unabhängig von Github oder Packagist.

Für die Archivierung von Versionen ist folgende Ergänzung in der satis.json nötig:

{
    "name": "Our Satis repository",
    "homepage": "http://localhost/satis",
    "require-all": true,
    "require-dependencies": true,
    "require-dev-dependencies": true,
    "archive": {
        "directory": "dist",
        "format": "tar",
        "skip-dev": true
    }
}

require-dependencies und require-dev-dependencies sorgen dafür, dass auch sämtliche Bibliotheken archiviert werden, von denen unsere benötigten Bibliotheken abhängig sind.
directory ist das Verzeichnis, in dem Satis die heruntergeladenen Versionen speichert
skip-dev legt fest, ob auch Branches heruntergeladen werden (true) sollen oder nur Tags (false).

Ist das eingestellt, archiviert Satis die Bibliotheken beim nächsten

php satis build satis.expanded.json <per HTTP erreichbares Verzeichnis>

PS: Ich habe in diesem Fall stets Github erwähnt. Satisfy kann natürlich auch auf andere Dienste zugreifen, solange Git zugrunde liegt, z.B. BitBucket, Gitlab usw.

Dieser Beitrag wurde in   PHP veröffentlicht.
Fügen Sie ein Lesezeichen für den   permanenten Link hinzu.

Jan hat 152 Beiträge geschrieben

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>