Initial commit
Test / test (push) Successful in 7m5s
Release / gates (push) Successful in 7m28s
Release / build (amd64, freebsd) (push) Successful in 2m52s
Release / build (amd64, linux) (push) Successful in 2m46s
Release / build (arm64, freebsd) (push) Successful in 2m22s
Release / build (arm64, linux) (push) Successful in 2m38s
Release / build (loong64, linux) (push) Successful in 2m7s
Release / build (riscv64, linux) (push) Successful in 2m17s
Release / release (push) Successful in 1m0s
Test / test (push) Successful in 7m5s
Release / gates (push) Successful in 7m28s
Release / build (amd64, freebsd) (push) Successful in 2m52s
Release / build (amd64, linux) (push) Successful in 2m46s
Release / build (arm64, freebsd) (push) Successful in 2m22s
Release / build (arm64, linux) (push) Successful in 2m38s
Release / build (loong64, linux) (push) Successful in 2m7s
Release / build (riscv64, linux) (push) Successful in 2m17s
Release / release (push) Successful in 1m0s
Assisted-by: GLM 5.3
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env perl
|
||||
# notices.pl writes NOTICE.md in the repository root: the full licence text of
|
||||
# every Go module the binary is compiled from, and the terms of the artwork and
|
||||
# the fonts embedded in it. The repository is the record, so the file lives in
|
||||
# the tree and travels with every source archive rather than being attached to
|
||||
# a release. The rows are ordered by provenance, not alphabet: the owner's own
|
||||
# modules on the forge first, then golang.org, then every other source.
|
||||
#
|
||||
# Copy this file to scripts/notices.pl, edit the configuration block, and run:
|
||||
#
|
||||
# perl scripts/notices.pl
|
||||
#
|
||||
# The rule that decides whether the project has the file at all: a notice
|
||||
# exists to reproduce somebody else's terms. A project whose every embedded
|
||||
# thing is the owner's own modules, artwork and code has nobody to notice and
|
||||
# carries no NOTICE.md; the script says so and writes nothing.
|
||||
#
|
||||
# Perl builtins only. The one external binary is the Go toolchain, driven in
|
||||
# list form so that no path is word-split or globbed, and every failure names
|
||||
# what was being attempted.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configuration. Replace the values; everything below the block is the
|
||||
# standard script and is identical in every repository.
|
||||
# ---------------------------------------------------------------------------
|
||||
my $binary = "volumen";
|
||||
|
||||
# Directories whose files ship inside the binary, relative to the repository
|
||||
# root. A directory the project does not have simply adds no section.
|
||||
my $artwork_dir = "internal/web/static";
|
||||
my $fonts_dir = "internal/web/static/fonts";
|
||||
|
||||
# The faces the fonts directory carries, when it carries third-party ones.
|
||||
my $faces_note = <<'FACES';
|
||||
Ubuntu and Ubuntu Mono (latin and latin-ext subsets), the interface faces of
|
||||
the admin. Copyright 2010, 2011 Canonical Ltd, with the reserved font names
|
||||
"Ubuntu" and "Ubuntu Mono"; distributed under the
|
||||
[Ubuntu Font Licence 1.0](https://ubuntu.com/legal/font-licence), whose terms
|
||||
follow the SIL Open Font Licence 1.1.
|
||||
FACES
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
(my $script_dir = $0) =~ s{/[^/]*$}{};
|
||||
# Run as `perl notices.pl` and $0 carries no slash: the substitution is a
|
||||
# no-op, and the script's own directory is the working directory.
|
||||
$script_dir = '.' if !length($script_dir) || $0 !~ m{/};
|
||||
my $root = -f "$script_dir/../go.mod" ? "$script_dir/.." : $script_dir;-f "$root/go.mod" or die "no go.mod in $root, so this is not the module root\n";
|
||||
my $out_path = "$root/NOTICE.md";
|
||||
|
||||
sub slurp {
|
||||
my ($path) = @_;
|
||||
open my $fh, '<', $path or die "cannot read $path: $!\n";
|
||||
my $text = do { local $/; <$fh> };
|
||||
close $fh;
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub spew {
|
||||
my ($path, $text) = @_;
|
||||
open my $fh, '>', $path or die "cannot write $path: $!\n";
|
||||
print $fh $text;
|
||||
close $fh or die "cannot flush $path: $!\n";
|
||||
}
|
||||
|
||||
# licence_files returns the licence texts a module directory carries, in a
|
||||
# stable order, and dies when there are none: a dependency whose terms cannot
|
||||
# be reproduced cannot ship.
|
||||
sub licence_files {
|
||||
my ($dir) = @_;
|
||||
my @found;
|
||||
for my $subdir ('', 'LICENSES/', 'licenses/') {
|
||||
my $at = length $subdir ? "$dir/$subdir" : $dir;
|
||||
next unless -d $at;
|
||||
opendir my $dh, $at or die "cannot list $at: $!\n";
|
||||
my @names = grep { m{^(?:LICEN[CS]E|COPYING|COPYRIGHT|NOTICE|UNLICENSE)}i && -f "$at/$_" } readdir $dh;
|
||||
closedir $dh;
|
||||
push @found, map { "$at/$_" } sort @names;
|
||||
}
|
||||
return @found;
|
||||
}
|
||||
|
||||
# provenance orders the modules: the owner's own forge first, golang.org next,
|
||||
# every other source last; alphabetical inside each group.
|
||||
sub provenance {
|
||||
my ($path) = @_;
|
||||
return 0 if $path =~ m{^sourcedock\.dev/};
|
||||
return 1 if $path =~ m{^golang\.org/};
|
||||
return 2;
|
||||
}
|
||||
|
||||
# The modules the binary is built from: the modules that provide the packages
|
||||
# the program imports, which is the same list the toolchain records in the
|
||||
# binary. The build list is wider, because it also holds modules that no
|
||||
# package of this program compiles, and those need no notice.
|
||||
my $main = do {
|
||||
open my $m, '-|', qw{go -C}, $root, qw{list -m -f}, '{{.Path}}'
|
||||
or die "cannot run go list -m: $!\n";
|
||||
my $line = <$m>;
|
||||
close $m or die "go list -m failed\n";
|
||||
defined $line or die "go list -m named no main module\n";
|
||||
chomp $line;
|
||||
$line;
|
||||
};
|
||||
length $main or die "go list -m named no main module\n";
|
||||
|
||||
my @lines;
|
||||
open my $go, '-|', qw{go -C}, $root, qw{list -deps -f}, "{{if .Module}}{{.Module.Path}}\t{{.Module.Version}}\t{{.Module.Dir}}{{end}}", "./cmd/$binary"
|
||||
or die "cannot run go list: $!\n";
|
||||
while (my $line = <$go>) { push @lines, $line }
|
||||
close $go or die "go list -deps failed\n";
|
||||
|
||||
my (%seen, @modules);
|
||||
for my $line (sort @lines) {
|
||||
chomp $line;
|
||||
next unless length $line;
|
||||
my ($path, $version, $dir) = split /\t/, $line, 3;
|
||||
$path = '' unless defined $path;
|
||||
$version = '' unless defined $version;
|
||||
$dir = '' unless defined $dir;
|
||||
next if $path eq $main;
|
||||
next if $seen{$path}++;
|
||||
length $dir or die "no module directory for $path, run go mod download all first\n";
|
||||
-d $dir or die "module directory $dir for $path does not exist\n";
|
||||
push @modules, { path => $path, version => $version, dir => $dir };
|
||||
}
|
||||
|
||||
my @faces;
|
||||
if (opendir my $dh, "$root/$fonts_dir") {
|
||||
@faces = sort grep { /\.woff2?\z/ } readdir $dh;
|
||||
closedir $dh;
|
||||
}
|
||||
|
||||
# The exemption: everything the artefact carries is the owner's own. The
|
||||
# owner's modules (provenance 0) and the owner's artwork need no notice, and a
|
||||
# project with nothing else has no file. The script writes nothing, and says
|
||||
# why; delete a NOTICE.md left over from a heavier dependency set by hand.
|
||||
my @external = grep { provenance($_->{path}) != 0 } @modules;
|
||||
if (!@external && !@faces) {
|
||||
print "NOTICE.md not needed: every dependency of ./cmd/$binary is the owner's own\n";
|
||||
print "and an old NOTICE.md should be removed\n" if -f $out_path;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
@modules = sort { provenance($a->{path}) <=> provenance($b->{path}) || $a->{path} cmp $b->{path} } @modules;
|
||||
|
||||
my $licence_url = {
|
||||
'PolyForm-Noncommercial-1.0.0' => 'https://polyformproject.org/licenses/noncommercial/1.0.0',
|
||||
'CC-BY-NC-4.0' => 'https://creativecommons.org/licenses/by-nc/4.0/',
|
||||
'MIT' => 'https://opensource.org/license/mit',
|
||||
};
|
||||
|
||||
my @t = gmtime;
|
||||
my $stamp = sprintf '%04d-%02d-%02d', $t[5] + 1900, $t[4] + 1, $t[3];
|
||||
|
||||
my $out = <<'HEAD';
|
||||
# Third-party notices
|
||||
|
||||
The project is under the licence in [LICENSE](LICENSE). Everything else that
|
||||
a built binary carries is here: the Go modules it is compiled from, with each
|
||||
licence reproduced verbatim, and the terms of the artwork and the fonts
|
||||
embedded in it. The owner's own modules come first, golang.org next, every
|
||||
other source last. Every licence text below is quoted inside a code block, so
|
||||
a Markdown renderer cannot reflow it.
|
||||
|
||||
HEAD
|
||||
|
||||
$out .= <<"HEAD";
|
||||
Generated on $stamp by `perl scripts/notices.pl`, which takes the module list
|
||||
from \`go list -deps ./cmd/$binary\`, so it names what the toolchain actually
|
||||
links rather than the wider build list. Run it again after a dependency changes.
|
||||
|
||||
HEAD
|
||||
|
||||
for my $module (@modules) {
|
||||
my @files = licence_files($module->{dir});
|
||||
@files or die "no licence file found for $module->{path} in $module->{dir}\n";
|
||||
my $name = length $module->{version}
|
||||
? "$module->{path} $module->{version}"
|
||||
: $module->{path};
|
||||
$out .= "## $name\n\n";
|
||||
for my $file (@files) {
|
||||
if (@files > 1) {
|
||||
(my $label = $file) =~ s{^\Q$module->{dir}\E/?}{};
|
||||
$out .= "**$label**\n\n";
|
||||
}
|
||||
my $text = slurp($file);
|
||||
$text =~ s/\s+\z//;
|
||||
$out .= "```text\n$text\n```\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
my @svgs;
|
||||
if (opendir my $ah, "$root/$artwork_dir") {
|
||||
@svgs = sort grep { /\.svg\z/ } readdir $ah;
|
||||
closedir $ah;
|
||||
}
|
||||
if (@svgs) {
|
||||
$out .= "## Artwork embedded in the binary\n\n";
|
||||
for my $name (@svgs) {
|
||||
my $head = slurp("$root/$artwork_dir/$name");
|
||||
my ($copy) = $head =~ m{^<!--\s*(Copyright.*?)\s*-->\s*$}m;
|
||||
my ($spdx) = $head =~ m{^<!--\s*SPDX-License-Identifier:\s*(\S+)\s*-->$}m;
|
||||
defined $copy or die "no copyright line in $artwork_dir/$name\n";
|
||||
defined $spdx or die "no SPDX line in $artwork_dir/$name\n";
|
||||
my $url = $licence_url->{$spdx} or die "no licence URL known for $spdx\n";
|
||||
$out .= "### $name\n\n$copy\n\n[$spdx]($url)\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (@faces) {
|
||||
$out .= "## Fonts embedded in the binary\n\n";
|
||||
(my $note = $faces_note) =~ s/\s+\z//;
|
||||
$out .= "$note\n\nThe files carried:\n\n";
|
||||
$out .= "- $_\n" for @faces;
|
||||
$out .= "\n";
|
||||
}
|
||||
|
||||
spew($out_path, $out);
|
||||
printf "wrote NOTICE.md (%d module(s), %d artwork file(s), %d font file(s))\n",
|
||||
scalar @modules, scalar @svgs, scalar @faces;
|
||||
Reference in New Issue
Block a user