decopy - Automatic debian/copyright generator
decopy [options] [files or dirs]
Decopy is a tool that automates creating and updating the debian/copyright files. It does this by parsing all files in a source tree, figuring out the copyright attribution and license for each file (when possible) and then structuring the output in the copyright format 1.0.
Simply running decopy in the source tree that needs to be parsed will process
all files in the tree, group them by license, wildcard those groups and generate
the proper output to be written to the debian/copyright file.
If the source tree already includes a debian/copyright file, it will be used as input for files where the license could not be inferred, for the copyright of the debian directory and for the license snippets. The license texts for well known licenses are filled in automatically (see --fill-licenses); any that are not recognised need to be filled in manually.
The files or directories specified as positional arguments can be used to limit the processing to the indicated subset instead of processing the complete source tree.
On top of the simple decopy usage, these examples show some of the most common
usecases. Please see the following sections for detailed explanations of what
each of the parameters do.
decopy --root src/hello-1.0/ --output src/hello-1.0/debian/copyrightdecopy --mode partial src/3rdparty/ninjasrc/3rdparty/ninja directory. Only that directory is analyzed and the
output includes only files contained in it.decopy --group-by copyrightdecopy src--mode <mode>--changed--since <ref>--output <file>, -o <file>
--root <path>--spdx, --no-spdx
LicenseRef-<name> (and an exception as
AdditionRef-<name>), as the SPDX expression syntax requires. The default
is --no-spdx, which uses the DEP-5 names.--fill-licenses, --no-fill-licenses
/usr/share/common-licenses for the licenses shipped there, or
the full text for other well known licenses. With --no-fill-licenses the
license text is left as a TODO placeholder to be filled in manually.--list-license-files, --no-list-license-files
COPYING*, COPYRIGHT,
LICENSE*) get an entry of their own in the generated output. Such a file
carries a license text but is not itself licensed under it, so listing it is
redundant (lintian reports license-file-listed-in-debian-copyright). The
default is --no-list-license-files, which drops those entries, both the
ones decopy would generate and the ones an existing debian/copyright
already has. The licenses found in them are still used for the directory
that holds them.Instead of regenerating debian/copyright, decopy can report what is out of date in the existing file, which is useful as a check (e.g. in CI).
--explainThe report also lists, as advice that does not change the exit status, the directories whose license comes from a package manifest (see PACKAGE METADATA), and the manifests that declare a license other than the one in the license file next to them.
The generated output will always create separate paragraphs for groups of files with different licenses, additionally, it can also split paragraphs according to the following grouping options.
--group-by <criteria>--split-on-license--no-split-on-license--split-debian--no-split-debianArchive files (tar, zip and similar) found in the source tree are expanded and their contents are parsed as if they were regular files, so that licenses and copyright holders embedded inside archives are detected.
--expand-archives, --no-expand-archives
--max-archive-depth <n>--max-archive-member-size <bytes>Images frequently state their author and license only in embedded metadata
rather than in a comment: SVG files carry an RDF block written by the drawing
program, and raster images carry the equivalent XMP or PNG text chunks. Decopy
reads the authorship fields of both (dc:creator and dc:rights in RDF,
Author, Artist and Creator in raster metadata) and uses them as the
copyright holder when the file states none anywhere else. A holder found in the
file itself is always preferred, so the metadata only fills a gap.
No year is taken from the metadata: the date fields images carry are re-save timestamps far more often than authorship years, and a wrong year in a copyright notice is worse than no year at all.
Rights and copyright fields are treated with more suspicion than authorship ones, because the tools that write them are routinely pointed at a license instead: a value that names a license is reported as the license and not as a copyright holder.
Reading raster metadata requires exiftool. Without it those files fall back to the plain text reader, which skips binary files, so no holder or license is reported for them at all. SVG needs no external tool.
A directory without a license file of its own normally inherits the license of
its parent. When it holds a package manifest that declares a license, that
declaration is used instead, which gives vendored packages (a
node_modules/foo/ with only a package.json, a bundled Python module) their
own license. The manifests read, and the field read in each, are:
package.json, composer.json: license (or npm's older licenses).Cargo.toml: license in [package]; a crate declaring
license.workspace = true takes the [workspace.package] license of the
nearest workspace root above it.pyproject.toml: license in [project] (or [tool.poetry]),
else its License :: classifiers.setup.py, setup.cfg: the license of setup() (only when it is a
literal string: the file is parsed, never run) or of [metadata], else
the License :: classifiers.PKG-INFO, METADATA: License-Expression, else License, else the
classifiers.meson.build: the license of the project() call.DESCRIPTION (R): License, in R's own syntax (GPL (>= 2),
MIT + file LICENSE).META.json, META.yml (Perl CPAN): license, CPAN's own keys
(perl_5, apache_2_0, ...; open_source and unknown name no license).*.gemspec: the license or licenses a Gem::Specification
assigns, when the value is a string, an array of strings or a %w[] list
(the file is Ruby code and is not run).Only the license field of a manifest is read. Lockfiles (package-lock.json,
Cargo.lock, ...) list the licenses of the dependencies, not of the
directory, and are never read; neither are the manifests in debian/. A
value that names no license (UNLICENSED, SEE LICENSE IN ..., a vague
BSD) is ignored, and so is a declaration that can only be read in part.
The more specific source wins: a license notice in a file applies to that
file, a license file in the directory beats a manifest next to it, and a
manifest beats the license inherited from a parent directory. A deprecated
SPDX identifier such as GPL-2.0, which was written meaning either "only" or
"or later", is read as the "or later" version when the directory already has
it. A manifest that declares what the directory inherits anyway changes
nothing. Otherwise the paragraph's comment names the manifest and its value,
like node_modules/foo/package.json (MIT). Unlike a license file, a
manifest does not give its directory a paragraph of its own under
--split-on-license: its files are grouped with the other files under the
same license.
The default logging shows WARN and ERROR messages. It can be modified with the following flags:
--debug--verbose, -v
--quiet, -q
--copyright-file <filename>debian/copyright
--text, -a
--jobs <n>, -j <n>
--glob, --no-glob
Files: field
of the generated output. Globbing is enabled by default (--glob).--progress, --no-progress
--exclude <regex>, -X <regex>
-X 'doc/' excludes a top-level
doc/ but not src/doc/, and matching an extension needs a leading .*
(-X '.*\.jpg$'). The option is repeatable and every pattern given
applies, so unrelated exclusions need not be folded into one alternation
(-X '^build/' -X '^po/'). Each pattern matching no file is reported as a
warning, naming that pattern. As a special case, debian/copyright and
debian/changelog are always excluded.--gitignore, --no-gitignore
.gitignore and .git/info/exclude)
while walking the tree, so ignored files are not parsed. This is enabled by
default (--gitignore); use --no-gitignore to parse ignored files too.
This requires the pathspec module; without it the option has no effect.
The Files-Excluded patterns from the header of an existing
debian/copyright file are always honoured, regardless of this option.Decopy was inspired by previous copyright helpers like copyright-helper by Modestas Vainius, licensecheck(1) by Jonas Smedegaard, or the copyright helper shipped with debmake(1), written by Osamu Aoki.
The main difference with all of them, is that decopy aims to detects as many licenses as possible, including many more that those in the other helpers, as well as the fact that it's capable of processing more than just plain text files.
Additionally, while it is possible to use it for the creation of the copyright file, its main usecase is to keep the copyright file updated with any changes that are done to the source tree as time passes.
Decopy was written by Maximiliano Curia. The debian packaging and this manpage were created by Margarita Manterola.
Decopy and all the associated code and documentation are released under the ISC license.