Self-hosted service
fishros/install avatar
fishros/install

The documented install command fetches a script over plain HTTP and sources it into your shell

一键安装程序,欢迎大家提交代码和小鱼一起一键安装停止浪费生命

3,216 stars292 forksPythonLicense varies

At a glance

What is it?
A Chinese-language one-click installer, mostly aimed at robotics software and developer tooling on Ubuntu, built as a plugin system where each tool is one Python file. It declares no licence, its Dockerfile serves the installer itself as a static site, and both of its container examples end with a dangling command separator.
Who is it for?
This suits a robotics developer on Ubuntu who wants the framework, its dependency tool and a handful of common utilities installed the way the project maintainer installs them, and who is comfortable replaying a recorded answer file in a container build. It does not suit anyone who needs to know what a script will do before it runs with their privileges.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 121 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 5, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The documented command pipes a downloaded script into your shell

There is one usage line in this readme, and it is worth reading as a security statement rather than as an installation instruction.

It fetches the installer from the project's own domain with a downloader that suppresses progress output, and pipes the result into your shell as a process substitution, which means the shell executes it directly in your current session rather than saving it for you to read.

Two properties follow, and neither is hidden. The transport is plain HTTP, not encrypted, so whatever answers that request is what runs. And the execution is immediate and unsandboxed, at whatever privileges your current shell has, which on a robotics workstation is frequently root because installing system packages requires it.

This is a deliberate design choice rather than an oversight. The project exists to remove exactly this step, and a one-liner you can paste is the product. The same pattern appears again in both of the project's own container examples, which fetch the same URL with the same protocol and then run the downloaded file with bash:

bash
source <(wget -qO- http://fishros.com/install)

The alternative the project also offers is not a safer download, it is a recorded answer file, which is the subject of another section here.

The Dockerfile at the root serves the installer over plain HTTP

The Dockerfile in this repository is not the installer. It is a static web server, and what it serves is the installer.

The base image is a web server. It copies the tools directory, the documentation directory, and a file called install into the server's document root, copies the main installer script next to them, exposes one port, and runs the server in the foreground.

So the repository publishes its own installer as a website, and the URL in the usage line is the address of that site. The one-line install command is, structurally, a download from a static copy of this repository.

That closes a loop which is worth seeing clearly. The thing you are told to source is the thing this Dockerfile publishes, served over an unencrypted protocol, with no checksum, no signature and no version pin anywhere in the command.

The rest of the Dockerfile is unremarkable and tells you something else useful: the project considers its documentation and its tool plugins to be part of the same thing worth shipping, which is consistent with a repository whose main artefacts are text rather than a compiled program.

There is also a marker file at the root that disables a static site generator's processing for the hosting, so the documentation publishes as raw files.

No licence file, for a script people run as root

The repository's licensing field carries no licence name, and there is no licence file anywhere in the tree.

That is worth stating plainly because of what the project asks people to do with it. The documented command executes a downloaded script in your shell. Several of the plugins change the system's package source, which is an operation whose blast radius is the whole machine, and one of them installs container and robotics software that typically needs elevated privileges.

There is no licence, and there is no contribution licence agreement either. The contribution guide describes how to add a plugin in five steps and stops at running the tests. It does not say that contributors retain their copyright, and it does not say that they assign it.

For a project whose entire value is convenience, that is a coherent position. It is also the position that leaves a user with the least information about the one artefact they are being asked to run with administrative rights.

The practical guidance is narrow and specific. Read the script before you source it, or run it inside a disposable virtual machine rather than on the machine you work on. The project publishes the installer as a plain text file in its own tree, so reading it does not require anything to be installed.

Your menu answers are recorded to a temp file and replayed in builds

The most interesting mechanism in the project is how it gets past its own interactive prompts.

The installer asks a numbered question at each step and waits for input. For a container image there is nobody to answer, so the project added a mechanism for that: the choices you make are written to a YAML file in the temporary directory as a list of pairs, each with the number you chose and the label of the option you chose.

To use it, you run the installer once by hand, answer as you normally would, and the file is written for you:

bash
cp /tmp/fish_install.yaml ./

You then keep that file in your project. From then on, the installer reads its answers from it instead of prompting, which is what the two container examples do: each builds the file by echoing one line per prompt and then runs the installer, which never asks anything.

That is a well known trick and it is the right one for reproducible images. The detail worth flagging is where the answers are written and where you are told to put them: the temporary directory, and then your project root, which in a Docker build is a layer.

So a recorded decision about which distribution, which framework version and whether to replace the package source ends up committed into an image, and the mechanism that made the prompts skippable is the same mechanism that persists them.

Both Dockerfile examples end in a dangling separator

The two container examples in the readme are the kind of thing you copy, and both are broken in a small way.

The first one installs a downloader and the YAML library, then writes the answer file line by line, then downloads the installer and runs it. Its last line is a command separator with nothing after it, because the line that was meant to follow, described in a comment as the final cleanup, is commented out.

So the example as printed is a command that ends in an operator waiting for its right-hand side. Copy it and the build fails, or you fix it by removing the separator and skipping the cleanup it was gesturing at.

The second example has the mirror-image problem. It joins an install flag and a package name with a line continuation that has no space before it, so the two tokens run together and the package manager reads one long argument.

Both errors are cosmetic rather than conceptual, and both are in the exact place a user is most likely to copy from: the non-interactive setup path.

What is good about both examples is the cleanup in the second one, which removes the answer file, the package manager's cached lists, three temporary directories, and runs two clean commands. That is more care than most example Dockerfiles show.

Nine of ten tools come from one contributor

The tool list credits contributors per entry, and the distribution is worth reading.

Of the ten entries, nine name the same person as the contributor: the robotics framework and its second generation, the code editor, a desktop client for a code hosting site, a node development environment, the dependency configuration tool, the framework environment configuration, the system package source, and a desktop chat client. One entry, the container runtime, names a different person, and one, the localisation library, names two people.

So the bus factor for this project is close to one, with the container runtime being the clearest example of the model working: somebody with a different machine and a different need added the plugin they wanted.

The credit format is also inconsistent in a way that suggests the list grew by hand. Some entries carry a bracketed link after the description, some do not, one has no brackets at all, and one has its description followed by the word for contribution without brackets.

None of that matters for using it. It matters for judging the project: a tool list where one person wrote almost all of it is a tool list that will move quickly when that person loses interest.

Two lists of the same tools, and they do not match

The readme lists the supported tools once near the top and again at the bottom, under a heading for contributors. The two lists disagree.

The top list has ten entries. The bottom list has eight.

The two entries that appear only at the top are the localisation library and the desktop chat client. Nothing appears only at the bottom.

So the contributor roster is a subset of the feature list, and it is missing the two most recently added things, which is exactly what you would expect from a second list appended to the page over time and never reconciled.

There is a third signal in the same area. The top of the page is a heading asking readers to star the repository before leaving, with a joke in it, and immediately below is a link to a wishlist issue where readers can request tools, with a line saying maybe a magician will fulfil the wish.

That combination tells you how the list is maintained: features arrive because one person wanted them, and the roadmap is a public issue anyone can add to. The roster at the bottom is the historical record of who asked for what, not a current index.

The plugin architecture explains why it works that way. Each tool is one file added to a directory and one line registered in the main script, which is a low enough barrier that the list grows by contribution rather than by planning.

Editorial conclusion

This suits a robotics developer on Ubuntu who wants the framework, its dependency tool and a handful of common utilities installed the way the project maintainer installs them, and who is comfortable replaying a recorded answer file in a container build. It does not suit anyone who needs to know what a script will do before it runs with their privileges. Before you run it, check three things: what the script does, since you are being told to pipe a downloaded file straight into your shell as a process substitution over an unencrypted connection; whether you want the system package source changed, which is one of the plugins and is the operation with the widest blast radius; and what the licence is, because the repository declares none and there is no licence file in it.

Frequently asked questions

What is fishros/install?

A Chinese-language one-click installer, written in Python, aimed mostly at Ubuntu systems running robotics software and developer tooling. It ships plugins for a robotics framework and its dependency configuration tool, an environment configuration tool, the system package source, a code editor, a container runtime, a localisation library, a node development environment, a desktop client for a code hosting site, and a desktop chat client.

How do I run the fishros installer?

The documented command fetches the installer from the project's own domain with a downloader and pipes it into your shell as a process substitution, over plain HTTP. The readme also documents a non-interactive path: run it once by hand, and it writes your menu selections to a file in the temporary directory, which you copy into your project so the installer replays those answers instead of prompting.

Does fishros/install have a licence?

None is declared. The repository's licensing field carries no licence name and there is no licence file in the tree, and the contribution guide does not mention a contributor licence agreement. It is worth resolving before running a script that the documentation tells you to pipe into a shell with your own privileges, particularly since one of the plugins changes the system's package source.

How do I add a new tool to fishros/install?

Five steps: fork and clone the project; add a Python file in the local tools directory, named with an install prefix for an installer or a config prefix for a configurator; copy the provided class template, which extends a base class and sets its type, name and author, then implement the run method using the helpers provided for printing, file operations, package management, prompts and command execution; register it in the tools list inside the main install script; and run the tests. The base also exposes system version and architecture information, including three named architectures.

Official sources

  1. fishros/install on GitHub
  2. Issues
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fishros-install.svg)](https://hysenlabs.com/projects/fishros-install)