Can I use macros/variables in a `.gitignore` script? - bash

Is there any way to use macros or variables (à la bash) in a .gitignore script? The gitignore docs don't mention anything along those lines, but I figured I'd ask just in case there's some undocumented features and/or cool workarounds. A few people have asked about using environment variables in a .gitignore, but I want to know if there's any support whatsoever for macro-like or var-like anything.
use case
I have a repository which has been undergoing a refactoring of its directory structure/paths. Certain paths are used in multiple patterns in my .gitignore script, so it would be nice to be able to have something in there along the lines of:
# set a variable
UNSTABLE_PATH=foo/bar
# use the variable in some patterns
$UNSTABLE_PATH/test_data
$UNSTABLE_PATH/test_output
And yes, before you say it, I'm aware that clever use of glob and/or recursive glob could probably cover my use case. It would just be nice if there was some simple variable support as well. Though come to think of it I would also settle for a way to make the git mv command rewrite matching paths in the .gitignore.

Well, I'll just jump to the end of the semantics debate in the comments and leave it at this:
.gitignore is not a script, it's a list of patterns. As you would then expect, it has no support for variables.
If you really need this ability, I would take a cue from the likes of sass or less: Write your own file of "ignore rules with extended syntax" and write a script to boil that down into a proper .gitignore file.
But if you want my two cents, this looks like another case that would be resolved by moving some stuff outside your work tree, so that the work tree can just be a work tree.

Related

Why don't makefiles behave more like shell scripts within recipes?

I find makefiles very useful, and the header of each recipe
<target> : [dependencies]
is helpful. Within a recipe, the prefixes # and - are useful, as well as the automatically-defined variables like $# and $?. However, besides that, I find the way of coding the actual recipe to be strange and unhelpful. There are so many questions on StackOverflow along the lines of "how to do this in a makefile" for something that's simple (or at least more familiar) to do in bash.
Is there a reason why the recipe contents are not just interpreted as a regular shell script? Reading the manual pages, there seems to be many tools with equivalent functionality to a shell script but with different syntax. I end up specifying .ONESHELL and escaping $ with $$, or sometimes just call a script from the recipe when I can't figure out how to make it work in a makefile. My question is whether this is just unfortunate design, or are there are important features of makefiles that force them to be designed this way?
I don't really know how to answer your question. Probably that means it's not really appropriate for StackOverflow.
The requirement for using $$ instead of $ is obvious. The reasoning for using a separate shell for each logical line of a makefile instead of passing the entire recipe to a single shell, is less clear. It could have worked either way, and this is the way it was chosen.
There is one advantage to the way it works now, although maybe most people don't care about it: you only have to indent the first recipe line with TAB, if you use backslash newline to continue each line. If you don't use backslash newline, then every line has to be indented with TAB else you don't know where the recipe ends.
If your question is, could Stuart Feldman have made very different syntax decisions that would have made it easier to write long/complex recipes in makefiles, then sure. Choosing a more obscure character than $ as a variable introducer would reduce the amount of escaping (although, shell scripting uses pretty much every special character somewhere so "reduce" is the best you can do). Choosing an explicit "start/stop" character sequence for recipes would make it simpler to write long recipes, possibly at the expense of some readability.
But that's not how it was done.

How can I add built-in rules to make?

Make(1) has built-in rules, such that for simple tasks you don't need a makefile at all. I can type make prog and if the current directory has a prog.c, make will do something useful.
I have a number of rules like this (e.g., how to make .pdf from .html) that apply in many projects. If I have a makefile in a directory, I can simply include my rules from a file. Is there a way to tell make to use this file always? Like a dot file that make would always include before doing anything else.
Make's rules are truly built-in, not read from a file. This has advantages (the entirety of make is one executable and you can copy it and install it anywhere and get identical behavior) and disadvantages (you can't modify the default rules without modifying the source code and recompiling--if you want to do that it's easy to do, though: see the default.c file in the sources).
You can specify an extra makefile (or makefiles) that should be parsed before the usual ones using an environment variable, though, so you can create a makefile with some extra rules, then (in your ~/.bashrc or whatever) set the MAKEFILES environment variable to the name of that file (or files) containing these extra rules (don't forget to export it).
Now every make invocation will load these rules as well.
You may discover, though, that this isn't quite what you'd hoped, because it could cause other makefiles to fail or act in bizarre ways (for example if you download open source packages and want to build them locally, etc.) If you do this just remember you did it, so in a few months if you run into issues you'll remember to try undoing it and see if it helps :-)

Check for wildcard in fish shell arguments

In writing a function for fish shell I want to know if a lone wildcard (not part of a bigger expression) was used in the command arguments. Fish does the wildcard expansion before passing arguments to my function, so there is no easy way that I can see to do that, aside from check whether the arguments are the same as the output of ls. The inefficiency of that method makes me sad, though. Is there a better way to do this, without going into fish's source code?
EDIT:
Thanks for the input. Specifically, I am looking to add some functionality like zshell has for warning if there is a * in the arguments of rm. I know that there was an issue opened on GitHub specifically about this but I couldn't find the link again. I have typod, for example, rm * .o instead of rm *.o, and accidentally deleted all my code (... which I brought back from git, but still).
EDIT 2:
Here is the issue on GitHub: https://github.com/fish-shell/fish-shell/issues/1511
No, there's no way for a function to tell where its arguments came from. Maybe if you give more details about what you're really trying to accomplish, we can give another suggestion.

syntax-check a VimL script

I have a sizable vim script (a .vim file, in viml syntax). I'd like to check (but not execute!) the file for simple syntax errors.
How do I accomplish this?
I just want a very rough syntax check. Something along the lines of perl -c or pyflakes.
Here is a syntax checker for VimL.
https://github.com/syngan/vim-vimlint/
I don't think (I'm relatively sure, as much as one can be) one exists. VimL is an internal language of Vim (and only Vim), and there aren't many tools developed for it.
I tried searching on vim.org and several other places, with no luck. Not suprising, because I've never heard of one either.
So you're either stuck with running the script, or switching to an outside language like Python, Perl or Ruby.
https://github.com/osyo-manga/vim-watchdogs
vim-watchdogs, apparently, is a syntax checker for vim, it says that it supports many languages, including vimL
if you use vundle, you can just drop this into your vimrc:
Plugin 'git://github.com/osyo-manga/vim-watchdogs.git'
..and then run:
:PluginInstall
..to set it up (vundle is a very nifty plugin manager) If you have syntastic, you might want to be careful and disable it first, and then see if it is an adequate replacement (since it says it supports all those languages anyway).
It is a safe bet that when you have multiple syntax checkers going, you will need to put your "dogs on a leash", so to speak; by configuring one to check languages that the other one does not, and vice-versa. If you do not, there will be at best collisions, duplications, or misdirections. At worst, you will have all of the above and more.
Make sure that you always backup your ~/.vim directory (or your VIMRUNTIME directory if you install things on a global level), you will be glad you did. Hope that helped you or someone else out, good luck! Sorry you had to wait 7.5 months for a response, heh :)
There's now a second option: vim-lint (as opposed to vimlint)

how to not forget to delete debug lines in code

This seems to me to be a novel idea (since i haven't found any solutions or anyone having implemented it)...
A shell script that automatically runs whenever you git commit or whatever that will let you know if you forgot to delete any debugging or development env specific lines of code in your project.
For example:
Often times (in my Ruby projects) I'll leave lines of code to output variables like
puts params.inspect
or
raise params.inspect
Also, sometimes I'll use different methods so I can easily see the effects such as in cases like using delayed_job where I'd rather call the method without a delay during development.
The problem is sometimes I forget to change those methods back or forget to delete a call to raise params.inspect and I'll inadvertently push that code.
So I thought maybe the simplest solution was to add a comment to any such debugging line such as
raise params.inspect #debug
In essence flagging that line as a development only/debug line. Then in a shell script that runs before some other command like git commit it can use awk or grep to search through all the latest modified files for that #debug comment and stop execution and alert you. However i don't know much about shell scripting so I thought I'd ask for help :)
Although I whole-heartedly recommend following cdeszaq'a advice and discourage doing this sort of thing, it is pretty easy to write a git hook that will prevent you from committing any lines with a particular string. For simplicity, I'm not showing the git rev-parse --verify HEAD that you should use to make this hook work on an initial commit, but if you simply put the following in .git/hooks/pre-commit (and make it executable), you will not be able to commit any lines of code that contain the string '#debug':
#!/bin/sh
if git diff-index -p -M --cached HEAD | grep '#debug' > /dev/null; then
echo 'debug lines found in commit. Aborting' >&2
exit 1
fi
Rather than having to remember to do additional work (removing lines of code) only to have to do more work later when things break again (re-adding that code), why not put in sensible debugging statements from the beginning?
Most languages have fairly expressive and often cheap logging libraries that will allow you to write out various levels of information (error, info, debug, trace) to a number of different locations (a file, a database). Many of these libraries will even let you adjust the logging level for a specific chunk of the code at runtime or even while the program is running.
So, rather than try to bandage up brute-force debugging by scripting away the problem, why not do yourself, and the rest of the world that has to use what you produce, a favor and use an actual logging framework for logging?
As I said in my comment, you can use any programming language you feel comfortable with.
Anyway, searching for other commit hooks, I think this one could be a good one to start with. It basically looks for some words in your files and can be customized just changing the checks array in the top of the file.
#cdeszaq is correct about the logging part.
For behaviour that differs depending on environment, the common way to achieve this is to make the behaviour configurable. delayed_job should read a value from the config file to decide how long to delay. For production environments the config would have one value and for development environments the config would have a different value.

Resources