I created a make target which fetches a list of files from git ls-files and passes them to phpcs, a coding standards utility.
The problem is that I don't want to run it if no files are returned. (because it then tries to analyze the entire codebase)
phpcs:
FS=$$(git ls-files -om --exclude-standard '*.php'); \
vendor/bin/phpcs --encoding=utf-8 --extensions=php $$FS
How would I exit if $FS (which is set in the first line) is empty?
I'm running the default gnu-make which comes with OSX. (3.8.1)
This isn't really a makefile question. You are using shell commands to perform these operations so you have to come up with a shell solution for your problem: make doesn't enter into it.
You can do something like this:
phpcs:
FS=$$(git ls-files -om --exclude-standard '*.php'); \
test -z "$$FS" || vendor/bin/phpcs --encoding=utf-8 --extensions=php $$FS
PS. There's no such release as GNU make 3.8.1. You mean, I assume, GNU make 3.81.
Related
Background
I am well aware of how git status works, and even about git ls-files. Usually git status is all I need and want, it perfectly answers the question: "What is my status, and what files need my attention?"
However, I have been unable to find a quick command that answers the following question: "What files do I have, and what is their respective status?" So, I need a full listing of the directory (like ls -la) with a column that shows the status of each file/directory.
What I have tried
git status -s --ignored comes quite close to the output format that I want, but it just won't list the files that are unchanged between HEAD, index, and working directory. Also, it will recurse into directories.
git ls-files seems to be able to provide all the required info in scriptable form, but I've been unable to stop it from recursive listing the contents of all directories.
Obviously, I could hack something together that takes the output of these two commands and provides the view I would like to have. However, I would hate to reinvent the wheel if there is already some usable command out there.
Question
Is there some way of listing all files in a directory with their respective git status?
I want a full listing showing exactly the same files that ls would show.
Notes
This other question does not answer mine, because I definitely want an ls equivalent. Including unmodified, ignored, and untracked files, but excluding directory contents.
To restrict the paths Git inspects to just the current directory, use its Unix glob pathspecs. Since git status does a lot of checking against the index and against HEAD, use that, and to fill in the rest of the files ls would show you, use ls, just munge its output to have the same format as git status's output and take only the ones git status didn't already list.
( git status -s -- ':(glob)*'; ls -A --file-type | awk '{print " "$0}' ) \
| sort -t$'\n' -usk1.4
:(glob) tells Git the rest of the pathspec's a Unix glob, i.e. that * should match only one level, just like a (dotglob-enabled) shell wildcard¹.
The -t$'\n' tells sort that the field separator is a newline, i.e. it's all one big field, and -usk1.4 says uniquify, only take the first of a run, stable, preserve input order where it doesn't violate sort key order (which is a little slower so you have to ask for that specifically), k1.4 says the key starts at the first field, the fourth character in that field, with no end given so from there to the end.
¹ Why they decided to make pathspecs match neither like shell specs nor like gitignore specs by default, I might never bother learning, since I so much prefer ignorantly disapproving of their annoying choice.
Because output of git status -s is enough, let's just make a bash routine around this function! Then for unchanged files we could to echo the proper signaling manually. Following the specification we might use two symbols of space ' ' for this purpose either some another symbol. E.g. for directories, which are not tracked by Git anyway, selected symbol '_' as status code:
for FILE in *
do
if [[ -f $FILE ]]
then
if ! [[ $(git status -s $FILE) ]]
then
# first two simbols below is a two-letter status code
echo " $FILE"
else
git status -s "$FILE"
fi
fi
if [[ -d $FILE ]]
then
# first two symbols just selected as status code for directories
echo "__ $FILE"
fi
done
The script works in the same manner as ls. It can be written in one line using ; as well.
I'm trying to put together a Makefile that will create a folder and clone repositories from GIT
I'm having trouble putting it all together so I'm starting with a generic Makefile
My makefile:
$(shell mkdir -p myDir)
$(shell git.sh)
The shell script that I am trying to get to invoke
#!/bin/sh
REPOSRC="my bitbucket repo URL"
LOCALREPO="myDir"
# We do it this way so that we can abstract if from just git later on
LOCALREPO_VC_DIR=$LOCALREPO/.git
if [ ! -d $LOCALREPO_VC_DIR ]
then
git clone $REPOSRC $LOCALREPO
else
cd $LOCALREPO
git pull $REPOSRC
fi
# End
When I run make I'm getting the following error:
Makefile:2: *** missing separator. Stop.
Also, is this the correct way to go about this task?
What you have is not a makefile. It's really a shell script written in makefile syntax (and, as you've discovered from the errors, not correct makefile syntax).
Make is a tool that allows commands to be run to update a set of target files, or not run if any of the target files don't need to be updated, based on comparing timestamps of the target files and their prerequisite files. These dependency relationships can be chained.
That's all that make is for.
To prototypical example is compiling a program: if any of the source files have been modified then you need to recompile the object files for those sources; if object files are updated then libraries might need to be re-created; if object or library files are updated then programs might need to be re-linked.
If your problem space doesn't map, or can't be made to map, to that mechanism, then make and makefiles are not the correct tool for the job you have in mind. Based on your description of your problem, make is not the right tool for this job.
You should just write a shell script, as you've basically done here already, and move forward.
If you do want to write a makefile you should spend some time understanding the syntax of makefiles and how they work, rather than just searching on Stack Overflow and trying to put together a makefile based on the answers. For example, try reading at least the introduction of the GNU make manual.
With $(shell ...) construct you substitute shell command output into the makefile. Of course after calling mkdir or invoking git the output is not a valid makefile.
Your makefile should be like this
all:
mkdir -p myDir
./git.sh
note that indentation after all: has to be done with tabs.
And it looks like you don't need make for your task. Just shell script would be enough.
I know nothing about shell scripting but something has come up and I need to be able to understand what two lines of code do so that I can modify a project I am working on
SDKROOT= make -C $TEMP_DIR -f $PROJECT_DIR/greg/Makefile VPATH=$PROJECT_DIR/greg || exit $?
$TEMP_DIR/greg -o $DERIVED_FILES_DIR/${INPUT_FILE_BASE}.m $INPUT_FILE_PATH
will you please explain what these two lines of code do... I know what the variables are and the path names but the rest of the syntax is confusing and foreign. Please help.
The first line:
SDKROOT= make -C $TEMP_DIR -f $PROJECT_DIR/greg/Makefile VPATH=$PROJECT_DIR/greg || exit $?
SDKROOT= sets the environment variable SDKROOT to nothing for the execution of the make command.
make is the build tool, and it's being run with the following options:
-C $TEMP_DIR: means run make in the directory $TEMP_DIR
-f $PROJECT_DIR/greg/Makefile specifies to make to use the Makefile in $PROJECT_DIR/greg
VPATH=$PROJECT_DIR/greg sets another variable, VPATH to $PROJECT_DIR/greg. VPATH specifies to make a search path for prerequisits.
|| exit $? means that if the make command fails the script should exit with the same error code as make, as $? means the return code of the last run program/command.
The second line:
$TEMP_DIR/greg -o $DERIVED_FILES_DIR/${INPUT_FILE_BASE}.m $INPUT_FILE_PATH
appears to be running the command $TEMP_DIR/greg with the option -o $DERIVED_FILES_DIR/${INPUT_FILE_BASE}.m and with some input from $INPUT_FILE_PATH. This looks like the program which may have been built from the previous line's make command, so it's hard to know exactly what it does.
EDIT
The SDKROOT is an environment variable used by XCode to say where the SDK it's using is installed. It will be a path like /Developer/SDKs/MacOSX"${HOST_VERSION}".sdk/ for instance. The value should be setup somewhere in XCode I imagine (I don't used xcode so can't be more helpful than that.). By doing SDKROOT= at the beginning of the command the value of SDKROOT will be nothing/blank. The reason for this is that the code being compiled will use resources which exist in the SDKROOT, rather than local ones; such resources may be classes, config or libraries for example.
Let's say I added two lines to the file hello.rb.
# this is a comment
puts "hello world"
If I do git diff, it will show that I added two lines.
I don't want git to show any line which is a Ruby comment. I tried using git diff -G <regular expression>, but it didn't work for me. How do I do git diff so that it won't show any Ruby comments?
One possibility would be (ab)using git's textconv filters which are applied before the diff is created, so you can even transform binary formats to get a human-readable diff.
You can use any script that reads from a file and writes to stdout, such as this one which strips all lines starting with #:
#!/bin/sh
grep -v "^\s*#" "$1" || test $? = 1
(test $? = 1 corrects the exit code of grep, see https://stackoverflow.com/a/49627999/4085967 for details.)
For C, there is a sed script to remove comments, which I will use in the following example. Download the script:
cd ~/install
wget http://sed.sourceforge.net/grabbag/scripts/remccoms3.sed
chmod +x remccoms3.sed
Add it to your ~/.gitconfig:
[diff "strip-comments"]
textconv=~/install/remccoms3.sed
Add it to the repository's .gitattributes to enable it for certain filetypes:
*.cpp diff=strip-comments
*.c diff=strip-comments
*.h diff=strip-comments
The main downside is that this will be always enabled by default, you can disable it with --no-textconv.
Git cares a lot about the data that you give to it, and tries really hard not to lose any information. For Git, it doesn't make sense to treat some lines as if they haven't changed if they had.
I think that the only reasonable way to do this is to post-process Git output, as Dogbert had already shown in his comment.
I see that this is the same question as
Making cmake print commands before executing
But that answer doesn't work for me. I'm guessing that answer only works with cmake. What options work without cmake?
Note tried these
make VERBOSE=1 target
make target VERBOSE=1
VERBOSE=1 make target
make V=1 target
make target V=1
V=1 make target
make -V target
make -v target
none of them worked.
make -v returns
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
By default, make does print every command before executing it. This printing can be suppressed by one of the following mechanisms:
on a case-by-case basis, by adding # at the beginning of the command
globally, by adding the .SILENT built-in target.
somewhere along the make process, by invoking sub-make(s) with one of the flags -s, --silent or --quiet, as in $(MAKE) --silent -C someDir, for example. From that moment on, command echoing is suppressed in the sub-make.
If your makefile does not print the commands, then it is probably using one of these three mechanisms, and you have to actually inspect the makefile(s) to figure out which.
As a workaround to avoid these echo-suppressing mechanisms, you could re-define the shell to be used to use a debug mode, for example like make SHELL="/bin/bash -x" target. Other shells have similar options. With that approach, it is not make printing the commands, but the shell itself.
If you use the flag -n or --just-print, the echo-suppressing mechanisms will be ignored and you will always see all commands that make thinks should be executed -- but they are not actually executed, just printed. That might be a good way to figure out what you can actually expect to see.
The VERBOSE variable has no standard meaning for make, but only if your makefile interprets it.
For my version of make, I found BOTH paramters -n and -d helped.
GNU Make 3.80 Copyright (C) 2002 Free Software Foundation, Inc
-d Print lots of debugging information.
-n, --just-print, --dry-run, --recon
Don't actually run any commands; just print them.
When a bunch of makefile fragments are included, the line numbers don't make sense without this key debug flag.
CreateProcess(....exe,...)
Reading makefile `../../../../build/Makefile.options' (search path) (don't care) (no ~ expansion)...
Makefile:361: Extraneous text after `else' directive
Makefile:368: Extraneous text after `else' directive
Makefile:368: *** only one `else' per conditional. Stop.
in my case i was able to suppress commands in output by setting up below variable in top my make file
# Use `make V=1` to print commands.
$(V).SILENT:
add the above line in top of you make file and when you call any target it wont print
Before :
muhasan#admins-MacBook-Pro fx.identitymanagement % make dockerstatus
cd identity.API/ && docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------
identityapi_backend_1 dotnet Identity.API.dll Up 0.0.0.0:5000->80/tcp
identityapi_db_1 docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
muhasan#admins-MacBook-Pro fx.identitymanagement %
After :
muhasan#admins-MacBook-Pro fx.identitymanagement % make dockerstatus
Name Command State Ports
--------------------------------------------------------------------------------------
identityapi_backend_1 dotnet Identity.API.dll Up 0.0.0.0:5000->80/tcp
identityapi_db_1 docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
muhasan#admins-MacBook-Pro fx.identitymanagement %
My Makefile
# Use `make V=1` to print commands.
$(V).SILENT:
Path = identity.API
builddocker:
cd devops && cp -rv Dockerfile docker-compose.yml ../${Path}/ && cd ..
installdocker:
cd ${Path}/ && docker-compose up -d
dockerstatus:
cd ${Path}/ && docker-compose ps
I think this is what you want:
make MAKE_VERBOSE=1 target