{"id":20425253,"url":"https://github.com/catseye/shelf","last_synced_at":"2025-10-08T20:36:35.105Z","repository":{"id":19320322,"uuid":"77549846","full_name":"catseye/shelf","owner":"catseye","description":"MIRROR of https://codeberg.org/catseye/shelf : A package installer which neither packages nor installs","archived":false,"fork":false,"pushed_at":"2023-10-27T13:17:41.000Z","size":51,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-25T19:02:34.384Z","etag":null,"topics":["installer","link-farm","package-manager","packager","shell-functions"],"latest_commit_sha":null,"homepage":"https://catseye.tc/node/shelf","language":"Shell","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/catseye.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-12-28T17:30:47.000Z","updated_at":"2023-10-26T20:44:06.000Z","dependencies_parsed_at":"2023-01-11T20:25:22.021Z","dependency_job_id":"93015475-3a77-408d-ab23-e87373dc76ef","html_url":"https://github.com/catseye/shelf","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/catseye/shelf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catseye%2Fshelf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catseye%2Fshelf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catseye%2Fshelf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catseye%2Fshelf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/catseye","download_url":"https://codeload.github.com/catseye/shelf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catseye%2Fshelf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000639,"owners_count":26082818,"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","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["installer","link-farm","package-manager","packager","shell-functions"],"created_at":"2024-11-15T07:12:42.078Z","updated_at":"2025-10-08T20:36:35.090Z","avatar_url":"https://github.com/catseye.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"`shelf`\n=======\n\n_Version 0.7_\n| _Entry_ [@ catseye.tc](https://catseye.tc/node/shelf)\n| _See also:_ [ellsync](https://codeberg.org/catseye/ellsync#ellsync)\n∘ [tagfarm](https://codeberg.org/catseye/tagfarm#tagfarm)\n∘ [yastasoti](https://codeberg.org/catseye/yastasoti#yastasoti)\n\n- - - -\n\nCat's Eye Technologies' **shelf** is \"a package installer which\nneither packages nor installs\".  It aims to be a replacement for\n[toolshelf](https://catseye.tc/node/toolshelf), implemented as a\nset of Bourne shell functions.\n\nQuick Start\n-----------\n\nDownload the file `shelf.sh` and put it somewhere, say `$HOME/shelf.sh`.\n\nOr better, clone this repo as `$HOME/.shelf`; then the file `shelf.sh`\nwill be at `$HOME/.shelf/shelf.sh`, and you can pull the latest changes\nwith `cd $HOME/.shelf \u0026\u0026 git pull origin master`.\n\nThen add these four lines to the end of your shell startup script\n(`.bashrc`, `.bash_profile`, or whatever):\n\n    . $HOME/.shelf/shelf.sh\n    export SHELF_FARMBASE=$HOME/.local                   # see below\n    export SHELF_PATH=$HOME/checkout1:$HOME/checkout2    # see below\n    shelf_init\n\nThen start a new shell for it to take effect.\n\n`SHELF_FARMBASE` is the directory where the link farms will be created.\nOn some OSes `$HOME/.local` has a similar purpose, so it can be used here\ntoo.  (Although note, the wisdom of doing that has not been fully vetted.)\n\n`SHELF_PATH` should be a colon-separated list of directories where you\nwill be keeping the source directories you wish to manage using shelf.\n\nIf you are using `bash`, you can also configure some nicer tab-completion\nby sourcing `shelf_tabcomplete.sh`, i.e. you can also add\n\n    . $HOME/.shelf/shelf_tabcomplete.sh\n\nto your startup script.\n\nUsage\n-----\n\nThe following shell functions are defined by `shelf.sh` and available for use:\n\n*   `shelf_link` *DIR* [*DIR* ...]\n    \n    Create links to the relevant files in *DIR*, in the appropriate link farm.\n    One or more *DIR*s may be given.\n\n*   `shelf_unlink` *DIR* [*DIR* ...]\n    \n    Remove, from all link farms, any links to any files found in *DIR*.\n    One or more *DIR*s may be given.\n\n*   `shelf_unlink_broken`\n    \n    Remove, from all link farms, any links that are broken.\n\n*   `shelf_build` *DIR* [*DIR* ...]\n    \n    Make a best-effort guess at how to build the sources in *DIR*, and try to\n    build them using that method.  One or more *DIR*s may be given.\n\n*   `shelf_test` *DIR* [*DIR* ...]\n    \n    Make a best-effort guess at how to run tests for the project in *DIR*, then\n    run the tests using that method.  One or more *DIR*s may be given.\n\n*   `shelf_pwd` *NAME*\n    \n    Print out the full path of the first directory on `SHELF_PATH` with name\n    *NAME*, if one exists, else print nothing and return an error code 1.\n\n*   `shelf_cd` *NAME*\n    \n    Change directory to the first directory on `SHELF_PATH` with name *NAME*,\n    if one exists, else display an error message and return an error code 1.\n\n*   `shelf_which` *NAME*\n    \n    Essentially the same as `command -v` but, if the found file is a symbolic\n    link, the link destination is output instead.  Thus, if *NAME* is\n    an executable in your link farm, the file in the originating project\n    will be shown.\n\n*   `shelf_dockgh` *USER/PROJECT*\n    \n    Convenience command which, given the user (or organization) and repository\n    name of a repository on Github, clones that repository using `git`, then\n    runs `shelf_build` and `shelf_link` on the clone's directory.  This makes\n    the most sense if the current directory is on the `SHELF_PATH`, but no\n    check is made.\n\n*   `shelf_push` *DEST* *DIR* [*DIR* ...]\n    \n    Pushes changes from the project in *DIR* to the project of the same basename\n    in *DEST*.  Currently only supports git repos.  Always pushes the changes to\n    a branch in *DEST* whose name is the name of the current branch in *DIR; if\n    there is no such branch configured in *DEST*, it will be fetched first.\n    *DEST* should be a directory on the `SHELF_PATH`.\n\n*   `shelf_fanout` *DIR* [*DIR* ...]\n    \n    Executes a `shelf_push` to every directory on the `SHELF_PATH` that contains\n    a project directory that has the same basename as *DIR*.\n\n### Catalog files\n\nIn the context of shelf, a _catalog file_ is a text file with one entry per line.\nEach entry consists of a directory name, optionally followed by an `@` symbol\nfollowed by a tag name.\n\nSeveral commands operate on catalog files, which are usually supplied via\nstandard input.  Some of these commands ignore the tag names.\n\n*   `shelf_populate_from_distfiles` *DIR* \u003c *CATALOG*\n    \n    Given a directory *DIR* containing tarballs of the project listed in\n    *CATALOG*, extract each of those tarballs to a directory of the same\n    name in the current directory.\n    \n    The current directory is assumed to be on `SHELF_PATH`.\n\n*   `shelf_populate_from_git` *PREFIX* \u003c *CATALOG*\n    \n    For each of the projects listed in *CATALOG*, prefix *PREFIX* to its\n    name and, if a corresponding directory exists in the current directory,\n    update the repository in that corresponding directory using `git pull`,\n    otherwise attempt to `git clone` the repository to that corresponding\n    directory in the current directory.\n    \n    The current directory is assumed to be on `SHELF_PATH`.\n\n*   `shelf_mirror_from_git` *PREFIX* \u003c *CATALOG*\n    \n    The same as `shelf_populate_from_git`, but uses `git clone --mirror` to\n    clone each new repo directory, and `git remote update` to update it.\n\n*   `shelf_cast` *DIR* \u003c *CATALOG*\n    \n    When executed from a directory containing repositories listed in *CATALOG*,\n    create a non-version-controlled directory in *DIR* from each of the listed\n    repositories, at the tag or branch given by its tag name.\n\n    Two environment variables affect the operation of `shelf_cast`:\n\n    `SHELF_LOWERCASE`, if set, causes the casted directory to be created as\n    the lower-cased version of the catalog entry name.\n\n    `SHELF_CAST_REF`, if set, overrides the tag given in the catalog entry.\n\n*   `shelf_pin` \u003c *CATALOG*\n    \n    When executed from a directory containing repositories listed in *CATALOG*,\n    checks out each repository named in the catalog at the tag or branch given\n    by its tag name.\n\n*   `shelf_unpin` \u003c *CATALOG*\n    \n    When executed from a directory containing repositories listed in *CATALOG*,\n    checks out each repository named in the catalog at the tip of its `master`\n    branch.\n\n### Environment variables\n\n*   `SHELF_VERBOSE`\n    \n    If this environment variable is set to any non-empty value, the `shelf_*`\n    functions will produce verbose messages on standard output about what they\n    are doing, which can be useful for troubleshooting.\n\n*   `SHELF_DRYRUN`\n    \n    If this environment variable is set to any non-empty value, the `shelf_*`\n    functions will not make significant changes to the state of the\n    filesystem (for example, running commands like `ln` and `rm`) and instead\n    will only report that such changes would be made.\n\n### TODO\n\n*   Make a `shelf_pull` to complement `shelf_push`.\n*   Make a `shelf_fanin` to complement `shelf_fanout`.\n*   Make a `shelf_populate_from_shelf` (`shelf_replicate`?)\n*   Would a `shelf_pwd_all` be helpful?  It's in my notes, but I don't know why.\n*   Configure list of dirs to skip when linking, in an env var\n\n### History\n\n#### 0.7\n\n*   Fixed a bug in `shelf_link` where links were not being correctly\n    made to files with spaces in their pathnames.\n\n#### 0.6\n\n*   `shelf_cast`, by default, now casts the version of the source\n    repository at the tag given in each catalog entry, instead of\n    always casting `HEAD`.  Setting the environment variable\n    `SHELF_CAST_REF` to `HEAD` can override this new behaviour.\n*   Made `shelf_populate_from_git` and `shelf_pin` record a list of\n    directories which they failed to process, and fail themselves at the\n    end of procssing if that list is not empty.\n\n#### 0.5\n\n*   Changed `shelf_which` to [not use the which command][] and to produce\n    cleaner output (only show the target executable file).\n*   Introduced `shelf_mirror_from_git`.\n*   Commands which work on catalog files output the name of each directory\n    just before they process it, making the output more sensible to read.\n\n#### 0.4\n\n*   Fixed a bug where it was trying to link `.git` directories and other\n    inappropriate files because a pattern wasn't being correctly applied.\n*   `venv` (Python virtualenv directory) and `.hg` (Mercurial directory)\n    are now skipped when finding files to link.\n\n#### 0.3\n\n*   Added tab completion for bash.\n*   Made `shelf_push` and `shelf_fanout` fetch the branch first, so new branches\n    can be pushed to repositories that don't have them yet.\n*   `shelf_fanout` is able to process multiple project directories.\n\n#### 0.2\n\n*   Added `shelf_test`, `shelf_dockgh`, `shelf_push`, `shelf_fanout`,\n    `shelf_populate_from_distfiles`, `shelf_populate_from_git`, `shelf_cast`,\n    `shelf_pin`, and `shelf_unpin`.\n*   `shelf_build` is able to process multiple sources.\n*   Fixed bug where `shelf_build` exited immediately on the first error.\n\n#### 0.1\n\n*   Initial version.\n\n[not use the which command]: https://unix.stackexchange.com/questions/85249/why-not-use-which-what-to-use-then\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcatseye%2Fshelf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcatseye%2Fshelf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcatseye%2Fshelf/lists"}