Git Product home page Git Product logo

stowsh's Introduction

stowsh

A shell script to install and uninstall dotfiles using symlinks. stow written in bash, in other words.

Installation

Put stowsh in your path.

Dependencies

stowsh strives for minimal dependencies, but it currently depends on the GNU coreutils implementation of realpath and GNU findutils.

These are already installed on most Linux systems. On macOS you can install them with brew install findutils coreutils.

I would welcome PRs to remove these dependencies and replace them with POSIX shell commands!

Quickstart

Create a package (a directory of dotfiles, ~/.dotfiles in this example):

$ cd
$ tree -a
.
└── .dotfiles
    ├── .bash_profile
    └── .vimrc

Install the package (create symlinks in the current directory) using stowsh

$ stowsh ~/.dotfiles
$ tree -a
.
├── .bash_profile -> .dotfiles/.bash_profile
├── .dotfiles
│   ├── .bash_profile
│   └── .vimrc
└── .vimrc -> .dotfiles/.vimrc

Uninstall the package (delete symlinks) using stowsh

$ stowsh -D ~/.dotfiles

Details and options

A package is a directory containing related configuration files. stowsh symlinks the package's contents to the corresponding locations in the current directory, creating subdirectories as necessary.

$ stowsh -h
Usage: stowsh [-D] [-n] [-s] [-g] [-v[v]] [-t TARGET] PACKAGES...

TARGET is the destination directory (current directory by default).

  • -D uninstall package(s)
  • -n dry-run (print what would happen, but don't do anything)
  • -v verbose (-vv is even more verbose)
  • -g ignore files that are not tracked by git (uses git ls-files)
  • -s skip (skip errors rather than abort)

When installing a package stowsh will never overwrite existing files. When uninstalling a package stowsh will never delete files that are not symlinks to the expected place in the package.

By default stowsh will abort without making any changes if either of these errors occurs. This is done to avoid being left with a broken half installed configuration. The -s flag can be used to force stowsh to skip these errors and install/uninstall as much as possible.

One important consequence of the fact that stowsh does not delete files that aren't symlinks to the right place is (deep breath!): if you install a package, delete a file from the package, then uninstall the package, your target directory will be left with a broken symlink to the deleted file.

Use as a dotfiles manager

You can put your dotfiles in one package and install that with stowsh directly.

Or you may prefer to have multiple orthogonal packages that get installed by a script that uses stowsh. This allows you to install packages only if certain conditions are met. Here's an example install script that uses stowsh.

If your needs go beyond this, there are many fully-featured dotfiles managers.

Subdirectories

stowsh will only create links to files and links. It does not create links to directories.

If a package contains directories, and the corresponding directories do not exist in the target, stowsh will create real directories (not links).

This choice allows two packages to install files in the same subdirectory, and files that don't belong in your dotfiles repo (e.g. caches) to be added to those subdirectories without also being added to your dotfiles repo or its .gitignore file.

$ tree -a
.
├── .conf
│   └── conf.cache
└── .dotfiles
    ├── pkg1
    │   ├── .conf
    │   │   ├── a.conf
    │   │   ├── b.conf
    │   │   └── c.conf
    │   └── bin
    │       └── script1
    └── pkg2
        └── bin
            └── script2
$ stowsh .dotfiles/pkg1 .dotfiles/pkg2
$ tree -a -I '.dotfiles'  # exclude ./.dotfiles from tree listing
.
├── .conf
│   ├── a.conf -> ../.dotfiles/pkg1/.conf/a.conf
│   ├── b.conf -> ../.dotfiles/pkg1/.conf/b.conf
│   ├── c.conf -> ../.dotfiles/pkg1/.conf/c.conf
│   └── conf.cache
└── bin
    ├── script1 -> ../.dotfiles/pkg1/bin/script1
    └── script2 -> ../.dotfiles/pkg2/bin/script2

Things to note here:

  • ~/bin was created by stowsh. It's a real directory, not a link.
  • both pkg1 and pkg2 install files into ~/bin
  • the directory .conf existed before pkg1 was installed
  • conf.cache is a real file that exists alongside the symlinks installed by stowsh

When uninstalling a package, subdirectories will only be deleted if they are empty. So:

$ stowsh -D .dotfiles/pkg1 .dotfiles/pkg2
$ tree -a -I '.dotfiles'
.
└── .conf
    └── conf.cache

What's wrong with GNU stow?

stowsh is a short, cross-platform bash script without dependencies. stow is implemented as a Perl module. I'm not smart enough to install Perl modules, and I'd rather not have Perl as a dependency.

Author

Mike Lee Williams. Issues and PRs welcome.

stowsh's People

Contributors

alexisspacegirl avatar cinghiopinghio avatar mikepqr avatar mynameisfiber avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

stowsh's Issues

Make better tests

Current tests (which verify the two scenarios in the README) are performed by diffing the output of tree before and after stowsh.

My code is bad and I feel bad.

This should be better.

Require coreutils and findutils (or remove dependencies)

stowsh currently expects realpath and find to be the GNU versions. This is fine for me as I brew install them on macOS (and add /usr/local/opt/coreutils/libexec/gnubin to my PATH to use them without a g prefix).

But at the least we should

  • test if realpath and path are the GNU versions (how)?
  • look for g-prefixed binaries with the same name if not, and use them if found
  • refuse to run if those are not found
  • add coreutils and findutils as dependencies in the README

Ideally we should remove these dependencies and workaround the crappy BSD versions on macOS.

Using the functions directly changes callers directory

If you source the script then run the functions directly, stowsh can change the directory of the caller. This is bad.

When run as a regular script the cds all run in a subshell so do no harm.

Protect all the cds with subshells or get rid of them.

Add tests

Write tests to test

  • filenames with spaces
  • symlinks in packages
  • verbose option
  • skip option

Support --long-options

stowsh currently only supports short options -D, -n, etc. It should also support long versions of these options.

Remove GNU findutils and coreutils dependenices

It should be possible to remove these dependencies so stowsh can run on BSD systems (including macOS). See #13.

I don't personally have a need to fix this issue, but contributions welcome.

Some difficulties:

  • we need a way to construct the relative path from an existing file to a non-existing file. We currently do this with realpath foo --relative-to=bar --canonicalize-missing. This script may work, but introduces a readlink dependency. (BSD readlink doesn't do the right thing for our use case.)
  • BSD find complains on uninstall. Have not investigated why.

feature request: add --ignore option

It would be cool to add an --ignore cli option to ignore some files or directories.
The main use case is to ignore the README.md (or LICENCE etc.).

One can either hardcode those filenames or add some sort of filtering.

If you agree I can try to code it.

Add dry-run option and do nothing if any file would be skipped

shtow currently links or deletes as many files as possible. A more cautious approach less likely to result in a broken half-installed package would be to check all the proposed changes are possible, and make them only if they are. This would also make a dry-run option possible.

Use git ls-files to enumerate files to be linked

If the package is in a git directory, get the list of files to be linked using git ls-files. This will ensure we don't link in ignored stuff.

Consider making this behavior optional and whether to support non-git-directories.

stowsh doesn't make symbolic links for directories only for files

Dotfiles.d
    ├── fish
    │   ├── .config
    │   │   ├── fish
    │   │    |   ├── config.fish
    │   │    |   └── functions
    |     |     |    |    |── func.fish
    └── tmux
        └── .tmux.conf

so when I install fish configuration like:

~ $ stowsh Dotfiles.d/fish

stowsh will mkdir ~/.config/fish and mkdir ~/.config/fish/functions` instead make a symbolic link of fish.

This will cause problem, if I create a new file inside fish or functions directory like

~ $ touch ~/.config/fish/abc # or touch ~/.config/fish/functions/abc

since fish or functions are not a symbolic links, the abc file I created will not be put into ~/Dotfiles.d/fish/.config/fish or ~/Dotfiles.d/fish/.config/fish/functions

When I tried to sync my Dotfiles.d to server, it will not show the new added files in ~/Dotfiles.d repo.

Add tests for claims about existing files in README

Add tests to check this claim remains true:

When installing a package stowsh will never overwrite existing files. When unsintalling a package stowsh will never delete files that are not symlinks to the expected place in the package.

stowsh doesn't work if executing it inside the dotfiles.d directory

For example:

my Dotfiles.d contains multiple directory for different program such as fish, tmux

Dotfiles.d
    ├── fish
    │   ├── .config
    │   │   ├── fish
    │   │    |   ├── config.fish
    │   │    |   └── functions
    |     |     |    |    |── xxx
    └── tmux
        └── .tmux.conf

If I use stow like this, it works

~/Dotfiles.d $ stow ./tmux

it will link ~/Dotfiled.s/tmux/.tmux.conf to ~/.tmux.conf

but it doesn't work if I use stowsh like stow, I have to use

~/ $ stowsh Dotfiles.d/tmux

which executes stowsh outside of dotfiles.d

Issues on Debian

Hey!

I have been using stowsh on my old laptop and it worked great (debian 8)

now updating to the latest debian 9.0, i installed coreutils & findutils with apt,
but i still get the "you need the GNU coreutils" error,

is there something i still need to get?

my install was done from the netinstall so a lot of packages are not included by default, halp!

Ignore .gitignored files

stowsh should (optionally) ignore .gitignored files in git repos (i.e. the source of file lists should be git ls-files).

Use stderr

Errors are currently written to stdout (also they're not treated as errors, see #1).

Add force option

This should force the creation of symlinks on install.

It should delete whatever file is in the expected location on uninstall.

It should probably not delete non-empty directories on uninstall.

No need to discuss/test Ubuntu 14.04

The Travis CI job is set up to build coreutils from scratch so that stowsh works on Ubuntu 14.04. The README has a long section explaining why.

Travis CI now uses 16.04, so there's no need to build coreutils. And the README section is not worth keeping given there have been two LTS releases since 14.04.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.