{"id":16569978,"url":"https://github.com/andygrunwald/perseus","last_synced_at":"2025-10-29T01:30:18.151Z","repository":{"id":57523983,"uuid":"77749681","full_name":"andygrunwald/perseus","owner":"andygrunwald","description":"Local git mirror for your PHP (composer) project dependencies that works together with Satis.","archived":false,"fork":false,"pushed_at":"2021-06-25T15:17:06.000Z","size":394,"stargazers_count":4,"open_issues_count":4,"forks_count":1,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-02-01T20:51:12.200Z","etag":null,"topics":["composer","medusa","mirroring","packagist","php","php-package-server","satis"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andygrunwald.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"andygrunwald","custom":"https://paypal.me/andygrunwald"}},"created_at":"2016-12-31T17:22:52.000Z","updated_at":"2021-06-25T15:17:08.000Z","dependencies_parsed_at":"2022-09-16T16:33:52.436Z","dependency_job_id":null,"html_url":"https://github.com/andygrunwald/perseus","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andygrunwald%2Fperseus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andygrunwald%2Fperseus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andygrunwald%2Fperseus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andygrunwald%2Fperseus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andygrunwald","download_url":"https://codeload.github.com/andygrunwald/perseus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238751732,"owners_count":19524627,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["composer","medusa","mirroring","packagist","php","php-package-server","satis"],"created_at":"2024-10-11T21:16:10.509Z","updated_at":"2025-10-29T01:30:17.689Z","avatar_url":"https://github.com/andygrunwald.png","language":"Go","funding_links":["https://github.com/sponsors/andygrunwald","https://paypal.me/andygrunwald"],"categories":[],"sub_categories":[],"readme":"![perseus logo](assets/perseus_logo.png)\n\n--------------------------------------------\n\n[![Build Status](https://travis-ci.org/andygrunwald/perseus.svg?branch=master)](https://travis-ci.org/andygrunwald/perseus)\n[![Go Report Card](https://goreportcard.com/badge/github.com/andygrunwald/perseus)](https://goreportcard.com/report/github.com/andygrunwald/perseus)\n[![GoDoc](https://godoc.org/github.com/andygrunwald/perseus?status.svg)](https://godoc.org/github.com/andygrunwald/perseus)\n\nLocal git mirror for your PHP ([composer](https://getcomposer.org/)) project dependencies that works together with [Satis](https://github.com/composer/satis).\n\n*perseus* is a successor out of and drop-in replacement for [Medusa](https://github.com/instaclick/medusa).\n\n## Table of contents\n\n- [Whats wrong with Medusa?](#whats-wrong-with-medusa)\n- [Features](#features)\n- [Installation](#installation)\n\t- [From binary](#from-binary)\n\t- [From docker image](#from-docker-image)\n\t- [From source](#from-source)\n- [Usage](#usage)\n\t- [Add a new package](#add-a-new-package)\n\t- [Mirror all packages](#mirror-all-packages)\n\t- [Update all mirrored packages](#update-all-mirrored-packages)\n\t- [Show me the version of perseus](#show-me-the-version-of-perseus)\n- [Configuration](#configuration)\n\t- [Command line flags](#command-line-flags)\n\t- [`medusa.json` configuration file](#medusajson-configuration-file)\n- [Drop-in replacement](#drop-in-replacement)\n- [Development](#development)\n\t- [Build](#build)\n\t- [Build the docker image](#build-the-docker-image)\n\t- [Unit tests](#unit-tests)\n\t- [Release a new version](#release-a-new-version)\n- [Project background](#project-background)\n\t- [The name \"*perseus*\"](#the-name-perseus)\n- [Credits](#credits)\n\n## Whats wrong with Medusa?\n\nNothing. Really.\n[Medusa](https://github.com/instaclick/medusa) is a great software.\nIt works well for many people and companies.\nThanks to [Sebastien Armand](https://github.com/khepin), [Instaclick Inc.](https://github.com/instaclick) and all others who have helped and contributed to this project.\nBut it has its limitations, flaws and disadvantages like:\n\n* Very poor documentation (as mentioned in the readme)\n* Nearly no error handling (for API requests to [Packagist](https://packagist.org/), system commands like triggering git, etc.)\n* Long mirror/update runs, due to sequential procedure and single threaded nature (long runtimes can ruin a fast development workflow)\n* Stops the complete mirror/update run, if one package/url/composer.json is faulty and stops updating other packaging in the list\n* Need to implement auxiliary processes to make it work in a bigger engineering team like self-service to add new or remove old packages, monitoring and reliabilities\n\n*perseus* was born out of the motivation to eliminate these points.\n\n## Features\n\n* **Drop-in replacement** for [Medusa](https://github.com/instaclick/medusa)\n* Fully documented\n* Concurrency and usage of multiple threads for faster mirror/update runs\n* Serious error handling\n* Reporting of faulty packages or packages that can't be processed\n\n## Installation\n\n### From binary\n\nWe offer pre-compiled binaries of *perseus* for easy usage.\n\n1. Checkout our [Releases page](https://github.com/andygrunwald/perseus/releases) and choose the latest release\n2. Select your system architecture and operating system of your choice\n3. Download and extract the archive\n4. Switch to the extracted directory and fire a `perseus version`\n5. Have fun\n\n### From docker image\n\n*perseus* is available as Docker image at [andygrunwald/perseus](https://hub.docker.com/r/andygrunwald/perseus/). To download the image, fire:\n\n```sh\n$ docker pull andygrunwald/perseus\n```\n\nCommands can be executed like a normal installation in the format:\n\n```sh\n$ docker run andygrunwald/perseus \u003cCommand-Name\u003e [Flags] \u003cParameter\u003e\n```\n\nE.g. the `add` command:\n\n```sh\n$ docker run andygrunwald/perseus add --with-deps symfony/console /var/config/medusa-small.json\n```\n\nInside the container, example *medusa* and *satis* configurations from the [.docker](./.docker/) folder are available in the path `/var/config`.\nThose can be used to play around.\n\n### From source\n\nTo install *perseus* from source, a running [Golang installation](https://golang.org/doc/install) is required.\n\n```sh\n$ go get github.com/andygrunwald/perseus\n$ cd $GOPATH/src/github.com/andygrunwald/perseus\n$ go get ./...\n$ make install\n$ $GOPATH/bin/perseus\n```\n\n## Usage\n\n### Add a new package\n\nThe `add` command will mirror the given *\u003cPackage-Name\u003e* down to disk (with dependencies if requested) and adds the package into the configured Satis.json file.\n\nUsage:\n\n```sh\n$ perseus add \u003cPackage-Name\u003e [Config-File]\n```\n\nExamples:\n\n```sh\n$ perseus add \"twig/twig\"\n$ perseus add --with-deps \"symfony/console\"\n$ perseus add --with-deps \"guzzlehttp/guzzle\" /var/config/medusa.json\n```\n\n### Mirror all packages\n\nThe `mirror` command will mirror all configured packages from `medusa.json` down to disk (incl. dependencies) and adds all packages into the configured `satis.json` file.\n\nUsage:\n\n```sh\n$ perseus mirror [Config-File]\n```\n\nExamples:\n\n```sh\n$ perseus mirror\n$ perseus mirror /var/config/medusa.json\n```\n\n### Update all mirrored packages\n\nThe `update` command will update all mirrored packages that are located at disk and update them to the latest state. To find all packages it will do a search in the path configured at `repodir`.\n\nUsage:\n\n```sh\n$ perseus update [Config-File]\n```\n\nExamples:\n\n```sh\n$ perseus update\n$ perseus update /var/config/medusa.json\n```\n\n### Show me the version of perseus\n\nPrint the version number incl. build details of perseus.\n\nUsage:\n\n```sh\n$ perseus version\n```\n\nExamples:\n\n```sh\n$ perseus version\nperseus v0.1.0-Alpha-4C8098CE24FA56AC7DFD512EA756F95AD9D941EB darwin/amd64 BuildDate: 2017-05-09T16:35:17Z\n```\n\n## Configuration\n\n*perseus* has two different kinds of configurations:\n\n1. Process settings (via command line flags)\n2. `medusa.json` configuration file\n\n### Command line flags\n\nSeveral settings can be set by command line flags:\n\n* Flag `--config`: Path to the *medusa.json* configuration (default: `medusa.json`)\n* Flag `--numOfWorkers`: Number of worker used, when a concurrent process is started (default: number of available CPUs)\n\n### `medusa.json` configuration file\n\n*Perseus* is mainly configured with a JSON file (like Medusa).\nHere is a minimalistic example:\n\n```json\n{\n    \"repositories\": [\n        {\n            \"name\": \"myvendor/package\",\n            \"url\": \"git@othervcs:myvendor/package.git\"\n        },\n        ...\n    ],\n    \"require\": [\n        \"symfony/symfony\",\n        \"monolog/monolog\",\n        ...\n    ],\n    \"repodir\": \"/tmp/perseus/git-mirror\",\n    \"satisurl\": \"http://php.pkg.company.tld/git-mirror\",\n    \"satisconfig\": \"./satis.json\"\n}\n```\n\nIn the next sections an explaination of the single configuration parts can be found.\n\n#### `repositories`\n\nA list of custom packages that are not available on the configured https://packagist.org/.\nPer each repository, a name and a url must be given.\n\n#### `require`\n\nA list of repositories to mirror down to disk.\n\nThe packages will be searched on the given Packagist instance.\nPer default the standard instance https://packagist.org/ will be used.\n\n#### `repodir`\n\nDirectory to write all repositories to.\n\nThis directory needs to be writable.\n\n#### `satisurl`\n\nURL of the future satis installation.\n\nThis URL will be used to prefix all package URLs in the final satis configuration.\n\n#### `satisconfig`\n\nAt the end of the run, *perseus* write a valid [satis](https://getcomposer.org/doc/articles/handling-private-packages-with-satis.md#satis) configuration file.\nIn this setting a valid path to a writeable satis configuration is expected.\nFurther more the file needs to be exists before and it needs to be a valid satis configuration.\n\n*preseus* itself will only touch and edit the `repositories` section in this satis configuration.\nAll other parts of the file will be untouched.\n\n##### Example `satis.json`\n\n```json\n{\n    \"archive\": {\n        \"directory\": \"dist\",\n        \"format\": \"tar\",\n        \"prefix-url\": \"http://php.pkg.company.tld/packages/\",\n        \"skip-dev\": true\n    },\n    \"homepage\": \"http://php.pkg.company.tld/packages/\",\n    \"name\": \"private php package repositories\",\n    \"providers\": true,\n    \"repositories\": [\n        {\n            \"type\": \"git\",\n            \"url\": \"http://php.pkg.company.tld/git-mirror/symfony/debug.git\"\n        },\n        ...\n    ],\n    \"require-all\": true\n}\n```\n\n## Drop-in replacement\n\nWe are a Drop-in replacement for [Medusa](https://github.com/instaclick/medusa).\nWe have the same command structure and functionality.\n\nBut in one point we are not compatible: Logging.\nWe log way more information during the process as the original Medusa.\n\nBe aware: If you parse the logs of the original Medusa process, you might have to adjust your scripts.\n\n## Development\n\n### Build\n\nTo build the application, fire\n\n```sh\n$ make build\n```\n\nA binary, called `perseus` should appear in the same directory.\n\n### Build the docker image\n\nTo build the docker image on your own machine, fire\n\n```sh\n$ docker build -t andygrunwald/perseus .\n```\n\n### Unit tests\n\nA running go installation is required to execute unit tests.\nTo execute them, run:\n\n```sh\n$ make test\n```\n\nTip: If you plan to contribute via a Pull Request, the use of unit tests is encouraged.\n\n### Release a new version\n\nWe use [goreleaser](https://github.com/goreleaser/goreleaser) to build and ship our releases. Further more we follow [semantic versioning](http://semver.org/).\nHere is how you create and ship a ner version:\n\n1. Export a `GITHUB_TOKEN` environment variable with the `repo` scope selected. This will be used to deploy releases to your GitHub repository. Create yours [here](https://github.com/settings/tokens/new).\n\n\t```sh\n\t$ export GITHUB_TOKEN=\"YOUR_TOKEN\"\n\t```\n\n2. GoReleaser uses the latest [Git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) of your repository.\nCreate a tag:\n\n\t```console\n\t$ git tag -a v0.1.0 -m \"First release\"\n\t```\n\n\tIf you don't want to create a tag yet but instead simply create a package based on the latest commit, then you can also use the `--snapshot` flag.\n\n3. Now you can run GoReleaser at the root of your repository:\n\n\t```sh\n\t$ goreleaser\n\t```\n\n4. That's it! Check your GitHub project's release page.\n\n## Project background\n\n### The name \"*perseus*\"\n\nNaming projects is hard.\nI often struggle with this.\nThe name needs to be simple, \"catchy\" and easy to remember.\n\nIn this case it was easy.\n[Medusa](https://en.wikipedia.org/wiki/Medusa) was part of the greek mythology.\nI started looking in this direction and found *Perseus*.\nCheckout [Perseus with the Head of Medusa](https://en.wikipedia.org/wiki/Perseus_with_the_Head_of_Medusa) for more details..\n\n## Credits\n\nThe perseus logo was created by [@mre](https://github.com/mre).  \nThe original Gopher was designed by [Renee French](http://reneefrench.blogspot.com/).  \nGo Gopher vector illustration by [Hugo Arganda](http://about.me/argandas) ([@argandas](https://github.com/argandas))  \nHosted at the [gopher-vector repository](https://github.com/golang-samples/gopher-vector).  \nThe Medusa vector art was adjusted from [Amanda Downs](https://thenounproject.com/search/?q=medusa\u0026i=22849) work from the Noun Project.  \nThe perseus font is called [Dalek](http://www.dafont.com/de/dalek.font) created by [K-Type](http://www.k-type.com/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandygrunwald%2Fperseus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandygrunwald%2Fperseus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandygrunwald%2Fperseus/lists"}