Giter Site home page Giter Site logo

assimilate's Introduction

Assimilate

A rust binary and shell function to make exporting/aliasing less painful

Motivation

How often do you need to export something or make an alias and decide you really want that globally available? If you are like me, you do this quite often, but are just too lazy to add it to your alias or export file after you have it working in your shell. With Assimilate you can alias/export to your current shell and/or directly to your alias/export file.

Usage

Assimilate is comprised of two parts, a rust binary and a shell function. The rust binary handles all the heavy lifting and provides the nice cli interface, while the shell function enables you to alias/export to the current shell. You can use just the rust binary, but you will not be able to alias/export to the current shell.

$> assimilate_bin --help
> USAGE:
      assimilate_bin [FLAGS] --name <name> [item]...
  
  FLAGS:
      -a, --alias
      -e, --export
          --help       Prints help information
      -h, --here
      -s, --save
      -V, --version    Prints version information
  
  OPTIONS:
      -n, --name <name>
  
  ARGS:
      <item>...

The default behavior is to export and you must provide either -h or -s for any action to be taken.

Additionally, if you want to --save to your alias/export file, you will need to have already exported one or both of the following ...

EXPORT_FILE=<path to export file>
ALIAS_FILE=<path to alias file>

Examples

$> assimilate -ahn foo echo bar
# --> result: alias foo='echo bar'

$> assimilate -ehn MY_OTHER_HOME '$HOME/subdir'
# --> result: export MY_OTHER_HOME='$HOME/subdir'

$> assimilate -ehn EXPANDED_HOME $HOME/subdir
# --> result: export EXPANDED_HOME='<path_to_your_$HOME>/subdir'
# see discussion subsection Shell Expansion

$> dig +short myip.opendns.com @resolver1.opendns.com -4
# <your ip address>
$> assimilate -asn myip "!!"
# alternatively: assimilate -asn myip -- !!
# see discussion subsection Shell Expansion
# --> result alias myip='dig +short myip.opendns.com @resolver1.opendns.com -4'

Caveats

Because you are specifying arguments on the command line you will want to pay attention to shell expansion.

Be aware that the shell function utilizes eval in order to alias/export in the current shell.

Installation

Currently you must clone and build from source ...

$> git clone https://github.com/fvhockney/assimilate.git
$> cd assimilate
# Make sure you have a rust toolchain installed
$> cargo build --release
# make sure that target/release/assimilate_bin is in your $PATH

if you want to use the shell function ...

--- in someplace which will run on shell startup
source <path to assimilate git dir>

alternatively if you want to just use the rust binary

$> ln -s assimilate_bin /usr/sbin/assimilate

Discussion

Why a binary and a function

This boils down to three issues:

First is Process context. If you want to alias/export in the current shell, you must perform that opertion within the context of that shell. Running the command in a seperate binary causes a subprocess which can not affect the parent/starting process. However, executing alias/export from within a shell function is successful because it is running in the same process context.

Second is Process pollution. Writing everything within the shell function is certainly feasible (in fact, I did just this in one iteration), but this leads very easily to polluting the running process with lots of variables/functions. Sure, I could probably get around the function problem by using declarative programming, but functions are just sooooo much better. The variable problem is much more insidious, you need variables for parsing the command line arguments plus quite a number of holder variables. Cleaning them up with unset is generally possible, but since you are in a function, you can't really utilize traps to capture errors and ensure clean up. Additionally, unsetting varialbes from a sourced function is tricky as they may not reliably be re-instantiated when the function is called again. Putting the bulk of the work load in a seperate binary prevents a great deal of process pollution.

Third is Modularity. Maybe you don't care about setting it in the current process. Fine, you can just use the binary and not worry about sourcing the shell function.

Third the second, Portablity. The shell function is, to the best of my abilities, POSIX compliant. Writing the whole shebang (pun intended) in a POSIX manner without requiring the user to install any dependencies (ok, fine, most people probably have sed, tr, cut and the like already installed), is quite the challenge. Plus, I would really like to expand this to allow history navigation and other functionality which would have just been a nightmare in pure shell. Git* et al pipelines coupled with releases and packaging files makes it easy for users to install and use, even without having to install the rust toolchain.

Why eval

I really don't like eval. It's kind of like seeing unsafe. Even if it is safe, something just turns in my stomach, but alas, because of items 1 and 2, I could find no other way of handling this problem. Essentially, if the rust binary exits with 0, then the shell function evals the result. If it exits with anything else, it echos the result and returns with the original exit code. This means we only have to save two variables in the current scope (__assimilate_exit_code and __assimilate_output).

Shell Expansion ...

will get you every time. Know how shell expansion works on your shell and don't let it bite you in the rear. The rust binary will always ' the right hand side of the expression so that the eval statement does not expand if you did not want it to.

TODO

  • interactive history lookup
  • parse option to handle commands like export foo='bar'; assimilate -se "!!"
  • tests of binary
  • package (if there is enough interest)
  • CI/CD with releases
  • better help documentation
  • man pages?

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.