[v4] devtools: add new SPDX license compliance checker

Message ID 20200224210130.672-1-stephen@networkplumber.org (mailing list archive)
State Superseded, archived
Headers
Series [v4] devtools: add new SPDX license compliance checker |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/iol-testing success Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/Intel-compilation success Compilation OK
ci/travis-robot success Travis build: passed

Commit Message

Stephen Hemminger Feb. 24, 2020, 9:01 p.m. UTC
  Simple script to look for drivers and scripts that
are missing requires SPDX header.

Update the contribution guidelines to indicate that SPDX license
identfier is required for this project.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
v4 - add MAINTAINERS entry
     update coding style document
     change name of script

 MAINTAINERS                              |  1 +
 devtools/check-spdx-tag.sh               | 77 ++++++++++++++++++++++++
 doc/guides/contributing/coding_style.rst |  9 ++-
 3 files changed, 85 insertions(+), 2 deletions(-)
 create mode 100755 devtools/check-spdx-tag.sh
  

Comments

Stephen Hemminger April 28, 2020, 8:15 p.m. UTC | #1
On Mon, 24 Feb 2020 13:01:30 -0800
Stephen Hemminger <stephen@networkplumber.org> wrote:

> Simple script to look for drivers and scripts that
> are missing requires SPDX header.
> 
> Update the contribution guidelines to indicate that SPDX license
> identfier is required for this project.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> v4 - add MAINTAINERS entry
>      update coding style document
>      change name of script
> 
>  MAINTAINERS                              |  1 +
>  devtools/check-spdx-tag.sh               | 77 ++++++++++++++++++++++++
>  doc/guides/contributing/coding_style.rst |  9 ++-
>  3 files changed, 85 insertions(+), 2 deletions(-)
>  create mode 100755 devtools/check-spdx-tag.sh

Still waiting for this script all requested changes were done months ago.

Current output is:
$ ./devtools/check-spdx-tag.sh -v
Files without SPDX License
--------------------------


Files with redundant license text
---------------------------------
app/test/test_timer_racecond.c
lib/librte_ethdev/rte_ethdev_pci.h
lib/librte_ethdev/rte_ethdev_vdev.h

total: 0 errors, 3 warnings
  
Stephen Hemminger June 11, 2020, 6:46 p.m. UTC | #2
On Mon, 24 Feb 2020 13:01:30 -0800
Stephen Hemminger <stephen@networkplumber.org> wrote:

> Simple script to look for drivers and scripts that
> are missing requires SPDX header.
> 
> Update the contribution guidelines to indicate that SPDX license
> identfier is required for this project.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> v4 - add MAINTAINERS entry
>      update coding style document
>      change name of script
> 
>  MAINTAINERS                              |  1 +
>  devtools/check-spdx-tag.sh               | 77 ++++++++++++++++++++++++
>  doc/guides/contributing/coding_style.rst |  9 ++-
>  3 files changed, 85 insertions(+), 2 deletions(-)
>  create mode 100755 devtools/check-spdx-tag.sh
>

Going through the patch backlog.

Why is this not merged yet?
Why is not in DPDK 20.05?
  
Thomas Monjalon June 11, 2020, 9:32 p.m. UTC | #3
11/06/2020 20:46, Stephen Hemminger:
> On Mon, 24 Feb 2020 13:01:30 -0800
> Stephen Hemminger <stephen@networkplumber.org> wrote:
> 
> > Simple script to look for drivers and scripts that
> > are missing requires SPDX header.
> > 
> > Update the contribution guidelines to indicate that SPDX license
> > identfier is required for this project.
> > 
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> 
> Going through the patch backlog.
> 
> Why is this not merged yet?
> Why is not in DPDK 20.05?

I would like to see some reviews on such patch
which looks like a policy.
  
Thomas Monjalon June 11, 2020, 9:39 p.m. UTC | #4
24/02/2020 22:01, Stephen Hemminger:
> +tmpfile=$(mktemp)

Please check how other temp files are created in other scripts
for consitency.

> +    git grep -L SPDX-License-Identifier -- \
> +	':^.git*' ':^.ci/*' ':^.travis.yml' \
> +	':^README' ':^MAINTAINERS' ':^VERSION' ':^ABI_VERSION' \
> +	':^*/Kbuild' ':^*/README' \
> +	':^license/' ':^doc/' ':^config/' ':^buildtools/' \

I think doc/ should be part of the license check,
same for buildtools/.

> +	':^*.cocci' ':^*.abignore' \
> +	':^*.def' ':^*.map' ':^*.ini' ':^*.data' ':^*.cfg' ':^*.txt' \
> +	> $tmpfile
> +
> +    errors=0
> +    while read -r line
> +    do $quiet || echo $line
> +       errors=$((errors + 1))

I'm surprised this works for you.
In general, "while" creates a subshell which makes impossible
updating a variable.
I recommend using "for" with IFS=$'\n'.

> +    done < $tmpfile
> +}
> +
> +check_boilerplate() {
> +    if $verbose ; then
> +	echo
> +	echo "Files with redundant license text"
> +	echo "---------------------------------"
> +    fi
> +
> +    git grep -l Redistribution -- \
> +	':^license/' ':^/devtools/check-spdx-tag.sh' |
> +	while read line
> +	do $quiet || echo $line
> +	   warnings=$((warnings + 1))
> +	done

Same comment about "while" subshell.

> +
> +    warnings=0
> +    while read -r line
> +    do $quiet || echo $line
> +       warnings=$((errors + 1))

Here too

> +    done < $tmpfile
> +}

[...]
> +Each file must begin with a special comment containing the
> +`Software Package Data Exchange (SPDX) License Identfier <https://spdx.org/using-spdx-license-identifier>`_.

Typo: Identifier

> +
> +Generally this is the BSD License, except for code granted special exceptions.

Is a verb missing?

> +The SPDX licences identifier is sufficient, a file should not contain
> +an additional text version of the license (boilerplate).
  
Gaëtan Rivet June 12, 2020, 8:36 a.m. UTC | #5
Hi Thomas, Stephen,

On 11/06/20 23:39 +0200, Thomas Monjalon wrote:
> 24/02/2020 22:01, Stephen Hemminger:
> > +tmpfile=$(mktemp)
> 
> Please check how other temp files are created in other scripts
> for consitency.
> 
> > +    git grep -L SPDX-License-Identifier -- \
> > +	':^.git*' ':^.ci/*' ':^.travis.yml' \
> > +	':^README' ':^MAINTAINERS' ':^VERSION' ':^ABI_VERSION' \
> > +	':^*/Kbuild' ':^*/README' \
> > +	':^license/' ':^doc/' ':^config/' ':^buildtools/' \
> 
> I think doc/ should be part of the license check,
> same for buildtools/.
> 
> > +	':^*.cocci' ':^*.abignore' \
> > +	':^*.def' ':^*.map' ':^*.ini' ':^*.data' ':^*.cfg' ':^*.txt' \
> > +	> $tmpfile
> > +
> > +    errors=0
> > +    while read -r line
> > +    do $quiet || echo $line
> > +       errors=$((errors + 1))
> 
> I'm surprised this works for you.
> In general, "while" creates a subshell which makes impossible
> updating a variable.
> I recommend using "for" with IFS=$'\n'.
> 

No it should work, while will only spawn a subshell if you use a pipe with it.
Ex:

   err=0; while true; do err=$((err + 1)); done            # $err changes

   err=0; yes | while read -r y; do err=$((err + 1)); done # $err is always 0

Using for could be an issue, as you are then limited by the number of
parameters allowed. Additionally, the script is written for POSIX shell,
using $'\n' is forbidden and the POSIX equivalent is very ugly:

   IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n

> > +    done < $tmpfile
> > +}
> > +
> > +check_boilerplate() {
> > +    if $verbose ; then
> > +	echo
> > +	echo "Files with redundant license text"
> > +	echo "---------------------------------"
> > +    fi
> > +
> > +    git grep -l Redistribution -- \
> > +	':^license/' ':^/devtools/check-spdx-tag.sh' |
> > +	while read line

Missing a -r to read here: https://www.shellcheck.net/wiki/SC2162
Generally, best to use shellcheck when writing a script, especially if
using /bin/sh.

> > +	do $quiet || echo $line
> > +	   warnings=$((warnings + 1))
> > +	done
> 
> Same comment about "while" subshell.
> 
> > +
> > +    warnings=0
> > +    while read -r line
> > +    do $quiet || echo $line
> > +       warnings=$((errors + 1))
> 
> Here too
> 
> > +    done < $tmpfile
> > +}
> 
> [...]
> > +Each file must begin with a special comment containing the
> > +`Software Package Data Exchange (SPDX) License Identfier <https://spdx.org/using-spdx-license-identifier>`_.
> 
> Typo: Identifier
> 
> > +
> > +Generally this is the BSD License, except for code granted special exceptions.
> 
> Is a verb missing?
> 
> > +The SPDX licences identifier is sufficient, a file should not contain
> > +an additional text version of the license (boilerplate).
> 
> 
>
  
Gaëtan Rivet June 12, 2020, 9:05 a.m. UTC | #6
On 24/02/20 13:01 -0800, Stephen Hemminger wrote:
> Simple script to look for drivers and scripts that
> are missing requires SPDX header.
> 
> Update the contribution guidelines to indicate that SPDX license
> identfier is required for this project.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> v4 - add MAINTAINERS entry
>      update coding style document
>      change name of script
> 
>  MAINTAINERS                              |  1 +
>  devtools/check-spdx-tag.sh               | 77 ++++++++++++++++++++++++
>  doc/guides/contributing/coding_style.rst |  9 ++-
>  3 files changed, 85 insertions(+), 2 deletions(-)
>  create mode 100755 devtools/check-spdx-tag.sh
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3d5e8d1104b2..6b0e042c5fbb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -96,6 +96,7 @@ F: devtools/check-maintainers.sh
>  F: devtools/check-forbidden-tokens.awk
>  F: devtools/check-git-log.sh
>  F: devtools/check-includes.sh
> +F: devtools/check-spdx-tag.sh
>  F: devtools/check-symbol-maps.sh
>  F: devtools/checkpatches.sh
>  F: devtools/get-maintainer.sh
> diff --git a/devtools/check-spdx-tag.sh b/devtools/check-spdx-tag.sh
> new file mode 100755
> index 000000000000..b1b8cdba4e4e
> --- /dev/null
> +++ b/devtools/check-spdx-tag.sh
> @@ -0,0 +1,77 @@
> +#! /bin/sh
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright (c) 2019 Microsoft Corporation
> +#
> +# Produce a list of files with incorrect license tags
> +
> +print_usage () {
> +    echo "usage: $(basename $0) [-q] [-v]"
> +    exit 1
> +}
> +
> +check_spdx() {
> +    if  $verbose;  then
> +	echo "Files without SPDX License"
> +	echo "--------------------------"
> +    fi
> +    git grep -L SPDX-License-Identifier -- \
> +	':^.git*' ':^.ci/*' ':^.travis.yml' \
> +	':^README' ':^MAINTAINERS' ':^VERSION' ':^ABI_VERSION' \
> +	':^*/Kbuild' ':^*/README' \
> +	':^license/' ':^doc/' ':^config/' ':^buildtools/' \
> +	':^*.cocci' ':^*.abignore' \
> +	':^*.def' ':^*.map' ':^*.ini' ':^*.data' ':^*.cfg' ':^*.txt' \
> +	> $tmpfile

I find it easier to maintain an exclude list by setting a variable and
generating the relevant parameters:

    excludes='.git* .ci/* .travis.yml */Kbuild */README'
    exclude_opt=""
    set -f
    for pattern in $excludes; do
        exclude_opt="$exclude_opt ':^${pattern}'"
    done
    set +f
    printf "\"%s\"\n" "$exclude_opt"

However I recognize that means dealing with contrarian globbing issues in shells,
so it comes at a price. But I find changing the exclude list much easier that way.

> +
> +    errors=0
> +    while read -r line
> +    do $quiet || echo $line
> +       errors=$((errors + 1))
> +    done < $tmpfile
> +}
> +
> +check_boilerplate() {
> +    if $verbose ; then
> +	echo
> +	echo "Files with redundant license text"
> +	echo "---------------------------------"
> +    fi
> +
> +    git grep -l Redistribution -- \
> +	':^license/' ':^/devtools/check-spdx-tag.sh' |
> +	while read line
> +	do $quiet || echo $line
> +	   warnings=$((warnings + 1))
> +	done
> +
> +    warnings=0
> +    while read -r line
> +    do $quiet || echo $line
> +       warnings=$((errors + 1))
> +    done < $tmpfile
> +}
> +
> +quiet=false
> +verbose=false
> +
> +while getopts qvh ARG ; do
> +	case $ARG in
> +		q ) quiet=true ;;
> +		v ) verbose=true ;;
> +		h ) print_usage ; exit 0 ;;
> +		? ) print_usage ; exit 1 ;;
> +	esac
> +done
> +shift $(($OPTIND - 1))
> +
> +tmpfile=$(mktemp)
> +trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
> +
> +check_spdx
> +$quiet || echo
> +
> +check_boilerplate
> +
> +$quiet || echo
> +echo "total: $errors errors, $warnings warnings"
> +exit $errors
> diff --git a/doc/guides/contributing/coding_style.rst b/doc/guides/contributing/coding_style.rst
> index 841ef6d5c829..04626667dc18 100644
> --- a/doc/guides/contributing/coding_style.rst
> +++ b/doc/guides/contributing/coding_style.rst
> @@ -54,8 +54,13 @@ To document a public API, a doxygen-like format must be used: refer to :ref:`dox
>  License Header
>  ~~~~~~~~~~~~~~
>  
> -Each file should begin with a special comment containing the appropriate copyright and license for the file.
> -Generally this is the BSD License, except for code for Linux Kernel modules.
> +Each file must begin with a special comment containing the
> +`Software Package Data Exchange (SPDX) License Identfier <https://spdx.org/using-spdx-license-identifier>`_.
> +
> +Generally this is the BSD License, except for code granted special exceptions.
> +The SPDX licences identifier is sufficient, a file should not contain
> +an additional text version of the license (boilerplate).
> +
>  After any copyright header, a blank line should be left before any other contents, e.g. include statements in a C file.
>  
>  C Preprocessor Directives
> -- 
> 2.20.1
>
  
Stephen Hemminger June 12, 2020, 2:53 p.m. UTC | #7
On Thu, 11 Jun 2020 23:39:55 +0200
Thomas Monjalon <thomas@monjalon.net> wrote:

> 24/02/2020 22:01, Stephen Hemminger:
> > +tmpfile=$(mktemp)  
> 
> Please check how other temp files are created in other scripts
> for consitency.
> 
> > +    git grep -L SPDX-License-Identifier -- \
> > +	':^.git*' ':^.ci/*' ':^.travis.yml' \
> > +	':^README' ':^MAINTAINERS' ':^VERSION' ':^ABI_VERSION' \
> > +	':^*/Kbuild' ':^*/README' \
> > +	':^license/' ':^doc/' ':^config/' ':^buildtools/' \  
> 
> I think doc/ should be part of the license check,
> same for buildtools/.
> 
> > +	':^*.cocci' ':^*.abignore' \
> > +	':^*.def' ':^*.map' ':^*.ini' ':^*.data' ':^*.cfg' ':^*.txt' \
> > +	> $tmpfile
> > +
> > +    errors=0
> > +    while read -r line
> > +    do $quiet || echo $line
> > +       errors=$((errors + 1))  
> 
> I'm surprised this works for you.
> In general, "while" creates a subshell which makes impossible
> updating a variable.
> I recommend using "for" with IFS=$'\n'.
> 
> > +    done < $tmpfile
> > +}
> > +
> > +check_boilerplate() {
> > +    if $verbose ; then
> > +	echo
> > +	echo "Files with redundant license text"
> > +	echo "---------------------------------"
> > +    fi
> > +
> > +    git grep -l Redistribution -- \
> > +	':^license/' ':^/devtools/check-spdx-tag.sh' |
> > +	while read line
> > +	do $quiet || echo $line
> > +	   warnings=$((warnings + 1))
> > +	done  
> 
> Same comment about "while" subshell.
> 
> > +
> > +    warnings=0
> > +    while read -r line
> > +    do $quiet || echo $line
> > +       warnings=$((errors + 1))  
> 
> Here too
> 
> > +    done < $tmpfile
> > +}  
> 
> [...]
> > +Each file must begin with a special comment containing the
> > +`Software Package Data Exchange (SPDX) License Identfier <https://spdx.org/using-spdx-license-identifier>`_.  
> 
> Typo: Identifier
> 
> > +
> > +Generally this is the BSD License, except for code granted special exceptions.  
> 
> Is a verb missing?
> 
> > +The SPDX licences identifier is sufficient, a file should not contain
> > +an additional text version of the license (boilerplate).  

Thanks for the feedback.
Text processing is simpler in python, will rewrite in next version?
  
Thomas Monjalon June 12, 2020, 3:42 p.m. UTC | #8
12/06/2020 16:53, Stephen Hemminger:
> On Thu, 11 Jun 2020 23:39:55 +0200
> Thomas Monjalon <thomas@monjalon.net> wrote:
> 
> > 24/02/2020 22:01, Stephen Hemminger:
> > > +tmpfile=$(mktemp)  
> > 
> > Please check how other temp files are created in other scripts
> > for consitency.
> > 
> > > +    git grep -L SPDX-License-Identifier -- \
> > > +	':^.git*' ':^.ci/*' ':^.travis.yml' \
> > > +	':^README' ':^MAINTAINERS' ':^VERSION' ':^ABI_VERSION' \
> > > +	':^*/Kbuild' ':^*/README' \
> > > +	':^license/' ':^doc/' ':^config/' ':^buildtools/' \  
> > 
> > I think doc/ should be part of the license check,
> > same for buildtools/.
> > 
> > > +	':^*.cocci' ':^*.abignore' \
> > > +	':^*.def' ':^*.map' ':^*.ini' ':^*.data' ':^*.cfg' ':^*.txt' \
> > > +	> $tmpfile
> > > +
> > > +    errors=0
> > > +    while read -r line
> > > +    do $quiet || echo $line
> > > +       errors=$((errors + 1))  
> > 
> > I'm surprised this works for you.
> > In general, "while" creates a subshell which makes impossible
> > updating a variable.
> > I recommend using "for" with IFS=$'\n'.
> > 
> > > +    done < $tmpfile
> > > +}
> > > +
> > > +check_boilerplate() {
> > > +    if $verbose ; then
> > > +	echo
> > > +	echo "Files with redundant license text"
> > > +	echo "---------------------------------"
> > > +    fi
> > > +
> > > +    git grep -l Redistribution -- \
> > > +	':^license/' ':^/devtools/check-spdx-tag.sh' |
> > > +	while read line
> > > +	do $quiet || echo $line
> > > +	   warnings=$((warnings + 1))
> > > +	done  
> > 
> > Same comment about "while" subshell.
> > 
> > > +
> > > +    warnings=0
> > > +    while read -r line
> > > +    do $quiet || echo $line
> > > +       warnings=$((errors + 1))  
> > 
> > Here too
> > 
> > > +    done < $tmpfile
> > > +}  
> > 
> > [...]
> > > +Each file must begin with a special comment containing the
> > > +`Software Package Data Exchange (SPDX) License Identfier <https://spdx.org/using-spdx-license-identifier>`_.  
> > 
> > Typo: Identifier
> > 
> > > +
> > > +Generally this is the BSD License, except for code granted special exceptions.  
> > 
> > Is a verb missing?
> > 
> > > +The SPDX licences identifier is sufficient, a file should not contain
> > > +an additional text version of the license (boilerplate).  
> 
> Thanks for the feedback.
> Text processing is simpler in python, will rewrite in next version?

I don't see a need for rewrite.
I think addressing the comments is simpler.
  
Stephen Hemminger July 14, 2020, 11:23 p.m. UTC | #9
On Fri, 12 Jun 2020 11:05:27 +0200
Gaëtan Rivet <grive@u256.net> wrote:

> On 24/02/20 13:01 -0800, Stephen Hemminger wrote:
> > Simple script to look for drivers and scripts that
> > are missing requires SPDX header.
> > 
> > Update the contribution guidelines to indicate that SPDX license
> > identfier is required for this project.
> > 
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > ---
> > v4 - add MAINTAINERS entry
> >      update coding style document
> >      change name of script
> > 
> >  MAINTAINERS                              |  1 +
> >  devtools/check-spdx-tag.sh               | 77 ++++++++++++++++++++++++
> >  doc/guides/contributing/coding_style.rst |  9 ++-
> >  3 files changed, 85 insertions(+), 2 deletions(-)
> >  create mode 100755 devtools/check-spdx-tag.sh
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 3d5e8d1104b2..6b0e042c5fbb 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -96,6 +96,7 @@ F: devtools/check-maintainers.sh
> >  F: devtools/check-forbidden-tokens.awk
> >  F: devtools/check-git-log.sh
> >  F: devtools/check-includes.sh
> > +F: devtools/check-spdx-tag.sh
> >  F: devtools/check-symbol-maps.sh
> >  F: devtools/checkpatches.sh
> >  F: devtools/get-maintainer.sh
> > diff --git a/devtools/check-spdx-tag.sh b/devtools/check-spdx-tag.sh
> > new file mode 100755
> > index 000000000000..b1b8cdba4e4e
> > --- /dev/null
> > +++ b/devtools/check-spdx-tag.sh
> > @@ -0,0 +1,77 @@
> > +#! /bin/sh
> > +# SPDX-License-Identifier: BSD-3-Clause
> > +# Copyright (c) 2019 Microsoft Corporation
> > +#
> > +# Produce a list of files with incorrect license tags
> > +
> > +print_usage () {
> > +    echo "usage: $(basename $0) [-q] [-v]"
> > +    exit 1
> > +}
> > +
> > +check_spdx() {
> > +    if  $verbose;  then
> > +	echo "Files without SPDX License"
> > +	echo "--------------------------"
> > +    fi
> > +    git grep -L SPDX-License-Identifier -- \
> > +	':^.git*' ':^.ci/*' ':^.travis.yml' \
> > +	':^README' ':^MAINTAINERS' ':^VERSION' ':^ABI_VERSION' \
> > +	':^*/Kbuild' ':^*/README' \
> > +	':^license/' ':^doc/' ':^config/' ':^buildtools/' \
> > +	':^*.cocci' ':^*.abignore' \
> > +	':^*.def' ':^*.map' ':^*.ini' ':^*.data' ':^*.cfg' ':^*.txt' \
> > +	> $tmpfile  
> 
> I find it easier to maintain an exclude list by setting a variable and
> generating the relevant parameters:
> 
>     excludes='.git* .ci/* .travis.yml */Kbuild */README'
>     exclude_opt=""
>     set -f
>     for pattern in $excludes; do
>         exclude_opt="$exclude_opt ':^${pattern}'"
>     done
>     set +f
>     printf "\"%s\"\n" "$exclude_opt"
> 
> However I recognize that means dealing with contrarian globbing issues in shells,
> so it comes at a price. But I find changing the exclude list much easier that way.

This is no easier to maintain. Doing more string stuff in shell
is not worth it. If gets to be too much trouble, will consider moving
to python3.
  

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 3d5e8d1104b2..6b0e042c5fbb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -96,6 +96,7 @@  F: devtools/check-maintainers.sh
 F: devtools/check-forbidden-tokens.awk
 F: devtools/check-git-log.sh
 F: devtools/check-includes.sh
+F: devtools/check-spdx-tag.sh
 F: devtools/check-symbol-maps.sh
 F: devtools/checkpatches.sh
 F: devtools/get-maintainer.sh
diff --git a/devtools/check-spdx-tag.sh b/devtools/check-spdx-tag.sh
new file mode 100755
index 000000000000..b1b8cdba4e4e
--- /dev/null
+++ b/devtools/check-spdx-tag.sh
@@ -0,0 +1,77 @@ 
+#! /bin/sh
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2019 Microsoft Corporation
+#
+# Produce a list of files with incorrect license tags
+
+print_usage () {
+    echo "usage: $(basename $0) [-q] [-v]"
+    exit 1
+}
+
+check_spdx() {
+    if  $verbose;  then
+	echo "Files without SPDX License"
+	echo "--------------------------"
+    fi
+    git grep -L SPDX-License-Identifier -- \
+	':^.git*' ':^.ci/*' ':^.travis.yml' \
+	':^README' ':^MAINTAINERS' ':^VERSION' ':^ABI_VERSION' \
+	':^*/Kbuild' ':^*/README' \
+	':^license/' ':^doc/' ':^config/' ':^buildtools/' \
+	':^*.cocci' ':^*.abignore' \
+	':^*.def' ':^*.map' ':^*.ini' ':^*.data' ':^*.cfg' ':^*.txt' \
+	> $tmpfile
+
+    errors=0
+    while read -r line
+    do $quiet || echo $line
+       errors=$((errors + 1))
+    done < $tmpfile
+}
+
+check_boilerplate() {
+    if $verbose ; then
+	echo
+	echo "Files with redundant license text"
+	echo "---------------------------------"
+    fi
+
+    git grep -l Redistribution -- \
+	':^license/' ':^/devtools/check-spdx-tag.sh' |
+	while read line
+	do $quiet || echo $line
+	   warnings=$((warnings + 1))
+	done
+
+    warnings=0
+    while read -r line
+    do $quiet || echo $line
+       warnings=$((errors + 1))
+    done < $tmpfile
+}
+
+quiet=false
+verbose=false
+
+while getopts qvh ARG ; do
+	case $ARG in
+		q ) quiet=true ;;
+		v ) verbose=true ;;
+		h ) print_usage ; exit 0 ;;
+		? ) print_usage ; exit 1 ;;
+	esac
+done
+shift $(($OPTIND - 1))
+
+tmpfile=$(mktemp)
+trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
+
+check_spdx
+$quiet || echo
+
+check_boilerplate
+
+$quiet || echo
+echo "total: $errors errors, $warnings warnings"
+exit $errors
diff --git a/doc/guides/contributing/coding_style.rst b/doc/guides/contributing/coding_style.rst
index 841ef6d5c829..04626667dc18 100644
--- a/doc/guides/contributing/coding_style.rst
+++ b/doc/guides/contributing/coding_style.rst
@@ -54,8 +54,13 @@  To document a public API, a doxygen-like format must be used: refer to :ref:`dox
 License Header
 ~~~~~~~~~~~~~~
 
-Each file should begin with a special comment containing the appropriate copyright and license for the file.
-Generally this is the BSD License, except for code for Linux Kernel modules.
+Each file must begin with a special comment containing the
+`Software Package Data Exchange (SPDX) License Identfier <https://spdx.org/using-spdx-license-identifier>`_.
+
+Generally this is the BSD License, except for code granted special exceptions.
+The SPDX licences identifier is sufficient, a file should not contain
+an additional text version of the license (boilerplate).
+
 After any copyright header, a blank line should be left before any other contents, e.g. include statements in a C file.
 
 C Preprocessor Directives