diff --git a/COPYING b/COPYING index 3490ab98d67..b6ffe7a42c5 100644 --- a/COPYING +++ b/COPYING @@ -4,6 +4,15 @@ The Geographic Resources Analysis and Support System (GRASS) Geographic Information System (GIS) is Copyright by members of the GRASS Development Team. +Copyright notices in individual source files use SPDX tags, for example: + + SPDX-FileCopyrightText: 1999-2022 Jane Doe + SPDX-FileCopyrightText: Other GRASS authors + SPDX-License-Identifier: GPL-2.0-or-later + +Other GRASS authors denotes the authors of a file who are not named +individually in it. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your diff --git a/doc/development/style_guide.md b/doc/development/style_guide.md index 1d69d479877..bc6ad4e85cc 100644 --- a/doc/development/style_guide.md +++ b/doc/development/style_guide.md @@ -768,12 +768,19 @@ Use the following header in your source code. # # PURPOSE: Provide short description of module here... # -# COPYRIGHT: (C) 2024 by John Doe and the GRASS Development Team -# +# SPDX-FileCopyrightText: 2024 John Doe +# SPDX-FileCopyrightText: Other GRASS authors # SPDX-License-Identifier: GPL-2.0-or-later ############################################################################## ``` +Each copyright holder gets one `SPDX-FileCopyrightText` line carrying the years +of their own contributions. Add a line for yourself when you make a substantial +contribution, the same threshold as an `AUTHOR(S)` entry, and leave other +people's lines alone. The line `SPDX-FileCopyrightText: Other GRASS authors` +comes last and covers everyone not named individually; the `COPYING` file +defines it. The `SPDX-License-Identifier` line follows all copyright lines. + #### Use Standard Options in Interface GRASS tools must use the GRASS parser to handle its command line parameters. To @@ -960,8 +967,7 @@ Please use the following docstring template: Classes: - example::ExampleClass -(C) 2024 by the GRASS Development Team - +SPDX-FileCopyrightText: 2024 Other GRASS authors SPDX-License-Identifier: GPL-2.0-or-later @author First Author @@ -1078,8 +1084,8 @@ original work remains, it must be properly cited. * MODULE: g.foo * AUTHOR(S): John Doe * PURPOSE: Provide short description of module here... - * COPYRIGHT: (C) 2010 by John Doe, and the GRASS Development Team - * + * SPDX-FileCopyrightText: 2010 John Doe + * SPDX-FileCopyrightText: Other GRASS authors * SPDX-License-Identifier: GPL-2.0-or-later * *****************************************************************************/ diff --git a/general/g.parser/g.parser.html b/general/g.parser/g.parser.html index e6329a46517..e395a977afc 100644 --- a/general/g.parser/g.parser.html +++ b/general/g.parser/g.parser.html @@ -565,17 +565,9 @@

Easy creation of a script

# MODULE: v.what.rast_wrapper # AUTHOR(S): username # PURPOSE: Wrapper for v.what.rast -# COPYRIGHT: (C) 2017 by username, and the GRASS Development Team -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# SPDX-FileCopyrightText: 2017 username +# SPDX-FileCopyrightText: Other GRASS authors +# SPDX-License-Identifier: GPL-2.0-or-later # ############################################################################ diff --git a/general/g.parser/g.parser.md b/general/g.parser/g.parser.md index d690724ea2d..58bcd83ad70 100644 --- a/general/g.parser/g.parser.md +++ b/general/g.parser/g.parser.md @@ -556,17 +556,9 @@ v.what.rast --script # MODULE: v.what.rast_wrapper # AUTHOR(S): username # PURPOSE: Wrapper for v.what.rast -# COPYRIGHT: (C) 2017 by username, and the GRASS Development Team -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# SPDX-FileCopyrightText: 2017 username +# SPDX-FileCopyrightText: Other GRASS authors +# SPDX-License-Identifier: GPL-2.0-or-later # ############################################################################ diff --git a/general/g.parser/tests/g_parser_script_test.py b/general/g.parser/tests/g_parser_script_test.py new file mode 100644 index 00000000000..c1eda170970 --- /dev/null +++ b/general/g.parser/tests/g_parser_script_test.py @@ -0,0 +1,63 @@ +"""Tests of the header emitted by g.parser --script + +The header is produced by G__script() in lib/gis/parser_script.c. +""" + +import os +import re + +import pytest + +import grass.script as gs +from grass.tools import Tools + +TOOL = "v.what.rast" + + +@pytest.fixture(scope="module") +def session(tmp_path_factory): + """Set up a GRASS session for the tests.""" + tmp_path = tmp_path_factory.mktemp("grass_session") + project = "test_project" + gs.create_project(tmp_path, project) + with gs.setup.init(tmp_path / project, env=os.environ.copy()) as session: + yield session + + +@pytest.fixture(scope="module") +def script(session): + """Return the script generated by TOOL --script.""" + tools = Tools(session=session) + return tools.run_cmd([TOOL, "--script"]).stdout + + +def test_script_header_has_no_obsolete_license_text(script): + """The generated header carries no COPYRIGHT field and no GPL paragraph.""" + for obsolete in ("COPYRIGHT:", "free software", "GNU General Public License"): + assert obsolete not in script, ( + f"Generated script still contains obsolete license text: {obsolete!r}" + ) + + +def test_script_header_has_one_holder_per_line(script): + """Each copyright line names one holder, and the collective one comes last.""" + lines = script.splitlines() + copyright_lines = [ + i for i, line in enumerate(lines) if "SPDX-FileCopyrightText:" in line + ] + identifiers = [ + i for i, line in enumerate(lines) if "SPDX-License-Identifier:" in line + ] + + assert len(identifiers) == 1, "Expected exactly one SPDX-License-Identifier line." + assert copyright_lines, "Expected at least one SPDX-FileCopyrightText line." + assert max(copyright_lines) < identifiers[0], ( + "All SPDX-FileCopyrightText lines must precede SPDX-License-Identifier." + ) + assert ( + lines[max(copyright_lines)] == "# SPDX-FileCopyrightText: Other GRASS authors" + ), "The last copyright line must be the collective line." + for i in copyright_lines: + assert not re.search(r",\s+and\s|\sand\sthe\s", lines[i]), ( + f"Copyright line names more than one holder: {lines[i]!r}" + ) diff --git a/lib/gis/parser_script.c b/lib/gis/parser_script.c index 5b3dfa8eefd..e495a30b1a8 100644 --- a/lib/gis/parser_script.c +++ b/lib/gis/parser_script.c @@ -3,10 +3,8 @@ \brief GIS Library - Argument parsing functions (script) - (C) 2001-2009, 2011 by the GRASS Development Team - - This program is free software under the GNU General Public License - (>=v2). Read the file COPYING that comes with GRASS for details. + SPDX-FileCopyrightText: 2001-2009, 2011 Other GRASS authors + SPDX-License-Identifier: GPL-2.0-or-later \author Original author CERL \author Soeren Gebbert added Dec. 2009 WPS process_description document @@ -33,28 +31,10 @@ void G__script(void) fprintf(fp, "# MODULE: %s_wrapper\n", G_program_name()); fprintf(fp, "# AUTHOR(S): %s\n", G_whoami()); fprintf(fp, "# PURPOSE: Wrapper for %s\n", G_program_name()); - fprintf(fp, - "# COPYRIGHT: (C) %s by %s, and the GRASS Development Team\n", - GRASS_VERSION_DATE, G_whoami()); - fprintf(fp, "#\n"); - fprintf(fp, "# This program is free software; you can redistribute it " - "and/or modify\n"); - fprintf(fp, "# it under the terms of the GNU General Public License as " - "published by\n"); - fprintf(fp, "# the Free Software Foundation; either version 2 of the " - "License, or\n"); - fprintf(fp, "# (at your option) any later version.\n"); - fprintf(fp, "#\n"); - fprintf( - fp, - "# This program is distributed in the hope that it will be useful,\n"); - fprintf( - fp, - "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); - fprintf( - fp, - "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); - fprintf(fp, "# GNU General Public License for more details.\n"); + fprintf(fp, "# SPDX-FileCopyrightText: %s %s\n", GRASS_VERSION_DATE, + G_whoami()); + fprintf(fp, "# SPDX-FileCopyrightText: Other GRASS authors\n"); + fprintf(fp, "# SPDX-License-Identifier: GPL-2.0-or-later\n"); fprintf(fp, "#\n"); fprintf(fp, "##############################################################" "##############\n\n"); diff --git a/utils/copywrite.pl b/utils/copywrite.pl deleted file mode 100755 index 6cebce8e140..00000000000 --- a/utils/copywrite.pl +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/perl - -## Script to easily add missing copyright statements in -## GRASS source code files -## 2006, written by Schuyler Erle -## -## COPYRIGHT: (C) 2006 by the GRASS Development Team -## -## This program is free software under the GNU General Public -## License (>=v2). Read the file COPYING that comes with GRASS -## for details. -## -## The script searches and opens sequentially all files -## which lack the word "copyright". Additionally the local -## ChangeLog is fetched and contributor names are extracted. -## Then a new header is inserted containing the GPL statement, -## purpose template and authors. -## -## Please run from top source code directory. -## For usage details, see below. - -use File::Find; -use File::Basename; -use strict; -use warnings; -use Cwd; -use File::Basename; - -#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-# -# edit this, and edit the bottom of the file after __END__ - -# my $editor = "vi -o"; -# my $editor = "nedit"; -my $editor = "xemacs"; - -# don't forget to get a copy of -# http://www.red-bean.com/cvs2cl/cvs2cl.pl -# and put it in the same directory as this script -# -# run this script as: -# perl copywrite.pl contributors.csv -# committer identities can be provided in a file on the commandline -# the format of the file should be "username,identity", one per line -# The contributors.csv is already in the main directory of the GRASS -# source code, so it should be found. - -#### -# to work offline: -# $ export PATH=$PATH:$(pwd) -# $ find . -name main.c | while read i; do \ -# echo $i; (cd `dirname $i`; cvs2cl.pl -f ChangeLog.tmp main.c); done -# -# to clean up after: -# $ find -name ChangeLog.tmp | xargs rm -# -# otherwise, this script will assume you are online and fetch -# the ChangeLogs on the fly (and remove them automatically). -# -#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-#-=-# - -my $ChangeLog = "ChangeLog.tmp"; -my $cvs2cl = getcwd . "/cvs2cl.pl -f $ChangeLog"; -my $template = do {local $/; }; -my %identity; - -sub evaluate_file { - my $name = do { no warnings; $File::Find::name }; - - # only process main.c - return unless $_ eq 'main.c'; - - warn "+ Reading $name\n"; - - # slurp main.c - my $main_c = do {local $/; open my $F, '<', $_ or die "reading $name: $!"; <$F>}; - - # continue if main.c is 25 lines or longer - return unless ($main_c =~ y/\n/\n/) >= 25; - - # continue if main.c doesn't mention "copyright" - return if $main_c =~ /\(?c\)?opyright/gios; - - # run cvs2cl - warn "+ Checking CVS log $name\n"; - my $fetched_ChangeLog = 0; - unless (-f $ChangeLog) { - system "$cvs2cl $_" and die "$cvs2cl $_: $!"; - $fetched_ChangeLog++; - } - - # get the list of contributors - my (%username, %year, $user); - my $original_author = ""; - { - # Read whole paras at once - local $/ = ""; - open my $LOG, '<', $ChangeLog or die "$ChangeLog: $!"; - while (my $line = $LOG) { - - # Hack out the pretty printing - $line =~ s/\s+/ /gos; - - # And drop trailing spaces - $line =~ s/\s+$//gos; - - # Match individual check ins - if ($line =~ /^(\d{4})-\d\d-\d\d\s+\d\d:\d\d\s+(.+)$/gos) { - $year{$1}++; - $user = $2; - $username{$user}++; - } - - # Note when a user did the initial check in - # if ($line =~ /^\s+\*\s+[^:]+:\s+(?:initial|new$)/gios) { - # $original_author = $user; - # } - $original_author = $user; - - # Note when a contributor submitted code - if ($line =~ /:\s+([^:<]+\s*<[^>]+>)\s*:/gos) { - $username{$1}++; - } - } - } - - # don't duplicate the original author - delete $username{$original_author} if $original_author; - - #figure out module name - my $fullname = $name; - my $mymodule = basename(dirname($fullname)); - - # append the list of contributors - my @years = sort map {$_ + 0} keys %year; - my @authors = sort keys %username; - - # map committers to identities - @authors = map { exists( $identity{$_} ) ? $identity{$_} : $_ } @authors; - $original_author = $identity{$original_author} - if exists $identity{$original_author}; - - # execute the template - { - local $" = ", "; - $main_c = eval{ - "<', $_ or die "writing $name: $!"; - print F $main_c; - close F; - - # load it up in an editor for vetting - system "$editor $_ $ChangeLog description.html" and die "$editor $_ $ChangeLog: $!"; - - # delete the ChangeLog after *only* if this script created it - unlink $ChangeLog if $fetched_ChangeLog; -} - -# committer identities can be provided in a file on the commandline -# the format of the file should be "username,identity", one per line -# -if ($ARGV[0]) { - while (<>) { - chomp; - next unless /^[a-z]/ios; - my ($user, $id) = split(",", $_, 2); - $identity{$user} = $id; - } -} - -find( \&evaluate_file, "." ); - -### edit the template after __END__ -__END__ -/**************************************************************************** - * - * MODULE: $mymodule - * AUTHOR(S): $original_author (original contributor) - * @authors - * PURPOSE: - * COPYRIGHT: (C) $years[0]-$years[-1] by the GRASS Development Team - * - * This program is free software under the GNU General Public - * License (>=v2). Read the file COPYING that comes with GRASS - * for details. - * - *****************************************************************************/ -$main_c