SecBSD's official ports repository

This commit is contained in:
purplerain 2023-08-16 22:26:55 +00:00
commit 2c0afcbbf3
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
64331 changed files with 5339189 additions and 0 deletions

View file

@ -0,0 +1,66 @@
CATEGORIES = databases
V = 7.39
DISTNAME = sqlports-$V
DISTFILES =
COMMENT-main = sqlite database of ports
COMMENT-list = full list of pkgpaths in ports
MAINTAINER = Marc Espie <espie@openbsd.org>
PKGNAME-list = portslist-$V
PERMIT_PACKAGE = Yes
MULTI_PACKAGES = -main -list
DBNAME = sqlports
SQLCACHE = ${DBNAME}_cache.sql
SQLVIEWS = ${DBNAME}_views.sql
DBS = ${DBNAME}.list ${DBNAME} ports-INDEX ${SQLCACHE}
BUILD_DEPENDS = databases/p5-DBD-SQLite \
databases/sqlite3
RUN_DEPENDS-main = databases/sqlite3
FLAVORS = nonstrict
FLAVOR =
.if ${FLAVOR:Mnonstrict}
STRICT =
.else
STRICT =-s
.endif
# for debugging the ports tree purposes, start at this dir
#STARTDIR = -S games/stepmania
SCRIPTS = print-ports-index show-reverse-deps rebuild-sqlports-cache
MANS = show-reverse-deps.1 sqlports.5
do-build:
@PORTSDIR=${PORTSDIR} ${MAKE_ENV} perl ${FILESDIR}/mksqlitedb -v -V $V -p ${WRKBUILD}/ouch ${STRICT} -C ${WRKBUILD}/${SQLCACHE} -w ${WRKBUILD}/${SQLVIEWS} ${STARTDIR} ${WRKBUILD}/${DBNAME}
@if test -s ${WRKBUILD}/ouch; then \
cat ${WRKBUILD}/ouch; \
exit 1; \
fi
cd ${WRKBUILD} && sqlite3 <${SQLCACHE} ${DBNAME}
alter-tables:
@${MAKE_ENV} ${SUDO} -u ${BUILD_USER} perl ${FILESDIR}/rebuild_schema -v -V $V ${WRKBUILD/${DBNAME}
@${SUDO} -u ${BUILD_USER} ${MAKE} post-build
post-build:
@cd ${WRKBUILD} && ${LOCALBASE}/bin/sqlite3 ${DBNAME} 'select min(_paths.fullpkgpath) from _paths join _ports on _paths.id=_ports.fullpkgpath where _ports.static_plist=1 group by fullpkgname order by _paths.fullpkgpath' >${DBNAME}.list
@cd ${WRKBUILD} && sh ${FILESDIR}/scripts/print-ports-index ${DBNAME} >ports-INDEX
do-install:
if [[ `wc -l < ${WRKBUILD}/ports-INDEX` -le 666 ]]; then echo "Unexpectedly short file."; exit 1; fi
${INSTALL_PROGRAM_DIR} ${PREFIX}/bin
.for s in ${SCRIPTS}
@${SUBST_PROGRAM} ${FILESDIR}/scripts/$s ${PREFIX}/bin/$s
.endfor
.for s in ${MANS}
@${SUBST_MAN} ${FILESDIR}/man/$s ${PREFIX}/man/man${s:E}/$s
.endfor
@for i in ${DBS}; do \
${INSTALL_DATA} ${WRKBUILD}/$$i ${PREFIX}/share; \
done
NO_TEST = Yes
NO_CHECKSUM = Yes
.include <bsd.port.mk>

View file

@ -0,0 +1,176 @@
# $OpenBSD: Info.pm,v 1.38 2023/06/16 04:54:20 espie Exp $
#
# Copyright (c) 2012 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# example script that shows how to store all variable values into a
# database, using SQLite for that purpose.
#
# usage: cd /usr/ports && make dump-vars |mksqlitedb
use v5.36;
use Var;
package Info;
our $vars = {
AUTOCONF_VERSION => 'AutoVersionVar',
AUTOMAKE_VERSION => 'AutoVersionVar',
BROKEN => 'BrokenVar',
BUILD_DEPENDS => 'BuildDependsVar',
CATEGORIES => 'CategoriesVar',
COMES_WITH => 'DefinedVar',
COMMENT => 'AnyVar',
COMPILER_LINKS => 'CompilerLinksVar',
CONFIGURE_ARGS => 'ConfigureArgsVar',
CONFIGURE_STYLE => 'ConfigureVar',
DEBUG_CONFIGURE_ARGS => 'DebugConfigureArgsVar',
DEBUG_PACKAGES => 'DebugPackagesVar',
DESCR => 'DescrVar',
DISTFILES => 'SupdistfilesVar',
DPB_PROPERTIES => 'DPBPropertiesVar',
PATCHFILES => 'PatchfilesVar',
DISTNAME => 'AnyVar',
DIST_SUBDIR => 'DefinedVar',
EPOCH => 'AnyVar',
FLAVORS => 'FlavorsVar',
FULLPKGNAME => 'FullpkgnameVar',
GH_ACCOUNT => 'DefinedVar',
GH_COMMIT => 'DefinedVar',
GH_PROJECT => 'DefinedVar',
GH_TAGNAME => 'DefinedVar',
HOMEPAGE => 'AnyVar',
IGNORE => 'DefinedVar',
IS_INTERACTIVE => 'AnyVar',
LIB_DEPENDS => 'LibDependsVar',
MAINTAINER=> 'EmailVar',
MAKEFILE_LIST => 'MakefilesListVar',
MASTER_SITES => 'MasterSitesVar',
MASTER_SITES0 => 'MasterSitesVar',
MASTER_SITES1 => 'MasterSitesVar',
MASTER_SITES2 => 'MasterSitesVar',
MASTER_SITES3 => 'MasterSitesVar',
MASTER_SITES4=> 'MasterSitesVar',
MASTER_SITES5 => 'MasterSitesVar',
MASTER_SITES6 => 'MasterSitesVar',
MASTER_SITES7 => 'MasterSitesVar',
MASTER_SITES8 => 'MasterSitesVar',
MASTER_SITES9=> 'MasterSitesVar',
MODULES => 'ModulesVar',
MULTI_PACKAGES => 'MultiVar',
NO_BUILD => 'YesNoVar',
NO_TEST => 'YesNoVar',
NOT_FOR_ARCHS => 'NotForArchListVar',
ONLY_FOR_ARCHS => 'OnlyForArchListVar',
PERMIT_DISTFILES=> 'YesKeyVar',
PERMIT_PACKAGE=> 'YesKeyVar',
PKGNAME => 'AnyVar',
PKGSPEC => 'AnyVar',
PKGSTEM => 'AnyVar',
PREFIX => 'PrefixKeyVar',
PKG_ARCH => 'ArchKeyVar',
PORTROACH => 'DefinedVar',
PORTROACH_COMMENT => 'DefinedVar',
PSEUDO_FLAVOR => 'AnyVar',
PSEUDO_FLAVORS => 'PseudoFlavorsVar',
TEST_DEPENDS => 'TestDependsVar',
TEST_IS_INTERACTIVE => 'AnyVar',
REVISION => 'AnyVar',
README => 'ReadmeVar',
RUN_DEPENDS => 'RunDependsVar',
SEPARATE_BUILD => 'YesKeyVar',
SHARED_LIBS => 'SharedLibsVar',
STATIC_PLIST => 'StaticPlistVar',
SUBPACKAGE => 'DefinedVar',
SUBST_VARS => 'SubstVar',
SUPDISTFILES => 'SupdistfilesVar',
TARGETS => 'TargetsVar',
UPDATE_PLIST_ARGS => 'DefinedVar',
USE_GMAKE => 'YesNoVar',
USE_GROFF => 'YesNoVar',
USE_LIBTOOL => 'YesNoGnuVar',
USE_NOBTCFI => 'YesNoVar',
USE_NOEXECONLY => 'YesNoVar',
USE_WXNEEDED => 'YesNoSpecialVar',
COMPILER => 'DefinedVar',
COMPILER_LANGS => 'DefinedVar',
WANTLIB => 'WantlibVar',
FIX_EXTRACT_PERMISSIONS => 'YesNoVar',
USE_LLD => 'YesNoVar',
PKGPATHS => 'PkgPathsVar',
# XXX those variables are part of the dump for dpb, but really should
# not end up in sqlports. But make sure we know about them.
BUILD_PACKAGES => 'IgnoredVar',
CHECKSUM_FILE => 'IgnoredVar',
FETCH_MANUALLY => 'IgnoredVar',
FLAVOR => 'IgnoredVar',
MISSING_FILES => 'IgnoredVar',
FIX_CRLF_FILES => 'CRLFFiles',
};
my @indexed = qw(FULLPKGNAME RUN_DEPENDS LIB_DEPENDS IGNORE
COMMENT PKGNAME ONLY_FOR_ARCHS NOT_FOR_ARCHS PKGSPEC PKGSTEM PREFIX
PERMIT_PACKAGE_FTP PERMIT_PACKAGE_CDROM WANTLIB CATEGORIES DESCR
EPOCH REVISION STATIC_PLIST PKG_ARCH);
my $indexed = {map {($_, 1)} @indexed};
our $unknown = {};
sub is_indexed($class, $name)
{
return $indexed->{$name};
}
sub new($class, $p)
{
bless {path => $p, vars => {}}, $class;
}
sub create($self, $var, $value, $arch, $path)
{
my $k = $var;
if (defined $arch) {
$k .= "-$arch";
}
if (defined $vars->{$var}) {
$self->{vars}{$k} = $vars->{$var}->new($var, $value, $arch,
$path);
} else {
$unknown->{$k} //= $path;
}
}
sub variables($self)
{
return values %{$self->{vars}};
}
sub value($self, $name)
{
if (defined $self->{vars}{$name}) {
return $self->{vars}{$name}->value;
} else {
return "";
}
}
sub reclaim($self)
{
my $n = {};
for my $k (qw(SUBPACKAGE FLAVOR)) {
$n->{$k} = $self->{vars}{$k};
}
$self->{vars} = $n;
}
1;

View file

@ -0,0 +1,306 @@
#! /usr/bin/perl
# $OpenBSD: Inserter.pm,v 1.42 2023/06/16 04:54:20 espie Exp $
#
# Copyright (c) 2006-2010 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use v5.36;
use Sql;
package Inserter;
# this is the object to use to put stuff into the db...
sub new($class, $db, $i, $verbose, $create)
{
$db->do("PRAGMA foreign_keys=ON");
bless {
db => $db,
transaction => 0,
threshold => $i,
vars => {},
created => {},
create => $create,
errors => [],
done => {},
todo => {},
verbose => $verbose,
}, $class;
}
# $self->add_error($msg)
sub add_error($, $)
{
}
sub current_path($self)
{
return $self->{current_path};
}
sub create_tables($self, $vars)
{
my $t = $self->{ports_table} = Sql::Create::Table->new("_Ports");
my $v = $self->{ports_view} = Sql::Create::View->new("Ports",
origin => '_Ports');
$self->create_path_table;
# XXX sort it
for my $i (sort keys %$vars) {
$vars->{$i}->prepare_tables($self, $i);
}
$t->sort;
$self->{varlist} = [$t->column_names];
$t->prepend(AnyVar->fullpkgpath);
$v->sort;
$v->prepend(AnyVar->pathref);
$self->create_meta;
$self->create_schema;
print '-'x50, "\n" if $self->{verbose};
}
sub add_to_ports_table($self, @column)
{
$self->{ports_table}->add(@column);
}
sub add_to_ports_view($self, @o)
{
$self->{ports_view}->add(@o);
}
sub make_ordered_view($self, $class)
{
my $view = $self->view_name($class->table."_ordered");
my @subselect = $class->subselect;
my @select = (Sql::Column::View->new('FullPkgPath')->group_by,
Sql::Column::View::Concat->new("Value"), $class->select);
Sql::Create::View->new($view, origin => 'o')->add(
Sql::With->new('o', origin => $self->table_name($class->table))
->add(@subselect),
@select);
}
sub set($self, $ref)
{
$self->{ref} = $ref;
}
sub db($self)
{
return $self->{db};
}
sub last_id($self)
{
return $self->db->func('last_insert_rowid');
}
sub insert_done($self)
{
$self->{transaction}++;
}
sub new_sql($self, $sql)
{
my $n = $sql->name;
return if defined $self->{created}{$n};
$self->{created}{$n} = 1;
my $drop = $sql->drop;
# print "$drop\n" if $self->{verbose};
$self->db->do($drop);
my $request = $sql->stringize;
print "$request\n" if $self->{verbose};
$self->db->do($request);
}
sub create_schema($self)
{
if ($self->{create}) {
for my $t (Sql::Create->all_tables) {
$self->new_sql($t);
}
for my $t (Sql::Create->all_tables) {
my $i = $t->inserter;
print $i, "\n";
$self->{insert}{$t->name} = $self->prepare($i);
}
for my $i (Sql::Create->all_indices) {
$self->new_sql($i);
}
}
for my $v (Sql::Create->all_views) {
$self->new_sql($v);
}
$self->commit_to_db;
}
sub prepare($self, $s)
{
return $self->db->prepare($s);
}
sub finish_port($self)
{
my @values = ($self->ref);
for my $i (@{$self->{varlist}}) {
push(@values, $self->{vars}{$i});
}
$self->insert('_Ports', @values);
$self->{vars} = {};
if ($self->{transaction} >= $self->{threshold}) {
$self->commit_to_db;
$self->{transaction} = 0;
}
}
sub add_to_port($self, $var, $value)
{
$self->{vars}{$var} = $value;
}
sub ref($self)
{
return $self->{ref};
}
sub insert($self, $table, @p)
{
$self->{insert}{$table}->execute(@p);
$self->insert_done;
}
sub add_var($self, $v)
{
$v->add($self);
}
sub create_canonical_depends($self, $class)
{
my $t = $self->table_name($class->table);
my $p = $self->table_name("Paths");
Sql::Create::View->new("_canonical_depends", origin=>$t)->add(
Sql::Column::View->new("FullPkgPath", origin=>"Id")
->join(Sql::Join->new($p)
->add(Sql::Equal->new("Canonical", "FullPkgPath"))),
Sql::Column::View->new("DependsPath", origin=>"Canonical")
->join(Sql::Join->new($p)
->add(Sql::Equal->new("Id", "DependsPath"))),
Sql::Column::View->new("Type"));
Sql::Create::View->new("canonical_depends", origin=>$t)->add(
Sql::Column::View->new("FullPkgPath")
->join(Sql::Join->new($p)
->add(Sql::Equal->new("Canonical", "FullPkgPath"))),
Sql::Column::View->new("DependsPath", origin=>"FullPkgPath")
->join(Sql::Join->new($p)
->add(Sql::Equal->new("Id", "DependsPath")),
Sql::Join->new($p)
->add(Sql::Equal->new("Id", "canonical"))),
Sql::Column::View->new("Type"));
}
sub commit_to_db($self)
{
$self->db->commit;
}
sub table_name($class, $name)
{
return "_$name";
}
sub view_name($class, $name)
{
return $name;
}
sub adjust($self)
{
return $self->{adjust} //= $self->prepare("UPDATE _Paths set Canonical=? where Id=?");
}
sub create_meta($)
{
Sql::Create::Table->new("Meta")->add(
Sql::Column::Text->new("SchemaVersion"),
Sql::Column::Text->new("Hash"),
Sql::Column::CurrentDate->new("CreationDate"));
}
sub create_path_table($)
{
my $t = "_Paths";
my $v = "Paths";
Sql::Create::Table->new($t)->add(
Sql::Column::Key->new("Id")->noautoincrement,
Sql::Column::Text->new("FullPkgPath")->notnull->unique,
Sql::Column::Integer->new("PkgPath")->references($t),
Sql::Column::Integer->new("Canonical")->references($t)->indexed);
Sql::Create::View->new($v, origin => $t)->add(
Sql::Column::View->new("PathId", origin => "Id"),
Sql::Column::View->new("FullPkgPath"),
Sql::Column::View->new("PkgPath", origin => "FullPkgPath")
->join(Sql::Join->new($t)->add(
Sql::Equal->new("Id", "PkgPath"))),
Sql::Column::View->new("Canonical", origin => "FullPkgPath")
->join(Sql::Join->new($t)->add(
Sql::Equal->new("Id", "Canonical")))
);
}
my $path_cache = {};
my $newid = 1;
sub find_pathkey($self, $key)
{
if (!defined $key or $key eq '') {
say STDERR "Empty pathkey";
return 0;
}
if (defined $path_cache->{$key}) {
return $path_cache->{$key};
}
# if none, we create one
my $path = $key;
$path =~ s/\,.*//;
if ($path ne $key) {
$path = $self->find_pathkey($path);
} else {
$path = $newid;
}
$self->insert('_Paths', $newid, $key, $path, $newid);
my $r = $self->last_id;
$path_cache->{$key} = $r;
$newid++;
return $r;
}
sub add_path($self, $key, $alias)
{
$self->adjust->execute($path_cache->{$alias}, $path_cache->{$key});
}
sub set_newkey($self, $key)
{
$self->set($self->find_pathkey($key));
$self->{current_path} = $key;
}
# $self->write_log($fh)
sub write_log($, $)
{
}
1;

View file

@ -0,0 +1,86 @@
# ex:ts=8 sw=4:
# $OpenBSD: PkgPath.pm,v 1.7 2023/06/15 12:53:07 espie Exp $
#
# Copyright (c) 2012 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use v5.36;
my $ports1;
BEGIN {
$ports1 = $ENV{PORTSDIR} || '/usr/ports';
}
use lib ("$ports1/infrastructure/lib");
use DPB::BasePkgPath;
package PkgPath;
our @ISA = qw(DPB::BasePkgPath);
use Info;
sub init($)
{
}
sub clone_properties($n, $o)
{
$n->{info} //= $o->{info};
}
sub subpackage($self)
{
return $self->{info}->value('SUBPACKAGE');
}
sub flavor($self)
{
my $value = $self->{info}->value('FLAVOR');
$value =~ s/^\s+//;
$value =~ s/\s+$//;
my @l = split(/\s+/, $value);
my %values = map {($_,1)} @l;
return \%values;
}
# $class->equates($hash)
sub equates($, $)
{
}
sub simplifies_to($self, $simpler, $walker)
{
$walker->{equivs}{$self->fullpkgpath} = $simpler->fullpkgpath;
}
sub change_multi($path, $multi)
{
# make a tmp copy, non registered
my $tmp = ref($path)->create($path->fullpkgpath);
if ($multi eq '-main') {
$tmp->{m} = undef;
} else {
$tmp->{m} = $multi;
}
return $tmp->normalize;
}
sub break($path, $message)
{
$path->{parent} //= '?';
say STDERR $path->fullpkgpath, "(", $path->{parent}, "):", $message;
}
1;

View file

@ -0,0 +1,977 @@
#! /usr/bin/perl
# $OpenBSD: Sql.pm,v 1.36 2023/06/15 14:33:13 espie Exp $
#
# Copyright (c) 2018 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# This does implement objects for an Sql Tree.
use v5.36;
package Sql::Object;
sub new($class, $name, %rest)
{
my $o = \%rest;
$o->{name} = $name;
bless $o, $class;
}
sub indent($self, $string, $plus)
{
$self->{level} //= 0;
return ' 'x(($self->{level}+$plus)).$string;
}
sub name($self)
{
return $self->{name};
}
sub drop($self)
{
return "DROP ".$self->type." IF EXISTS ".$self->name;
}
sub dump($self)
{
say $self->stringize;
}
sub add($self, @p)
{
for my $o (@p) {
$o->add_to($self);
}
return $self;
}
sub add_to($o, $c)
{
$o->{parent} = $c;
push(@{$c->{$o->category}}, $o);
}
sub prepend($self, @p)
{
for my $o (reverse @p) {
$o->prepend_to($self);
}
return $self;
}
sub prepend_to($o, $c)
{
$o->{parent} = $c;
unshift(@{$c->{$o->category}}, $o);
}
sub is_table($)
{
0
}
sub origin($self)
{
return $self->{origin};
}
sub normalize($self, $v)
{
$v =~ tr/A-Z/a-z/;
return $v;
}
sub identify($self)
{
my $string = "object ".ref($self)." named ".$self->name;
if (exists $self->{origin}) {
$string .= " (from $self->{origin})";
}
if (defined $self->{parent}) {
$string .= "(parent ".$self->{parent}->identify.")";
}
return $string;
}
sub is_view($)
{
0
}
sub is_index($)
{
0
}
package Sql::Create;
our @ISA = qw(Sql::Object);
my $register;
sub stringize($self)
{
return "CREATE ".($self->{temp} ? "TEMP ": "").$self->type.
" ".$self->name." ".join("\n", $self->contents);
}
sub sort($self)
{
$self->{columns} = [ sort {$a->name cmp $b->name} @{$self->{columns}}];
return $self;
}
sub all_tables($class)
{
return grep {$_->is_table} (sort {$a->name cmp $b->name} values %$register);
}
sub all_views($class)
{
return grep {$_->is_view} (sort {$a->name cmp $b->name} values %$register);
}
sub all_indices($class)
{
return grep {$_->is_index} (sort {$a->name cmp $b->name} values %$register);
}
sub key($class, $name)
{
return $class->find($name)->{key};
}
sub find($class, $name)
{
return $register->{$class->normalize($name)};
}
sub dump_all($class)
{
for my $v (values %$register) {
$v->dump;
}
}
sub register($self)
{
$register->{$self->normalize($self->name)} = $self;
return $self;
}
sub add_column_names($self, $name)
{
my $o = $self->find($name);
if (!defined $o) {
# print STDERR $name, "\n";
return;
}
$self->add_column_names_from($o);
}
sub add_column_names_from($self, $o)
{
for my $c ($o->columns) {
$self->{column_names}{$self->normalize($c->name)}++;
}
}
sub known_column($self, $name)
{
$name = $self->normalize($name);
for my $c ($self->columns) {
if ($self->normalize($c->name) eq $name) {
return 1;
}
}
return 0;
}
sub is_table_column($self, $table, $name)
{
my $t = $self->find($table);
if (defined $t) {
return $t->known_column($name);
} else {
return 0;
}
}
sub columns($self)
{
return @{$self->{columns}};
}
sub column_names($self)
{
my @names;
for my $c ($self->columns) {
next if $c->is_key;
push(@names, $c->name);
}
return @names;
}
sub temp($self)
{
$self->{temp} = 1;
return $self;
}
package Sql::Create::Table;
our @ISA = qw(Sql::Create);
sub type($)
{
"TABLE"
}
sub is_table($)
{
1
}
sub contents($self)
{
my @c;
my @d;
for my $col (@{$self->{columns}}) {
if ($col->{want_index}) {
Sql::Create::Index->new($self, $col);
}
push(@c, $col->stringize);
if ($col->{is_constraint}) {
push(@d, $col->name);
}
}
if (@d > 0) {
push(@c, "UNIQUE(".join(", ", @d). ")");
}
return "(". join(', ', @c).")";
}
sub inserter($self)
{
my (@names, @placeholders);
my $alt = $self->{ignore} ? " OR IGNORE" :
($self->{noreplace} ? "" : " OR REPLACE");
for my $c ($self->columns) {
next if $c->is_key;
push @names, $c->name;
push @placeholders, $c->placeholder;
}
return "INSERT$alt INTO ".$self->name." (".
join(', ', @names).") VALUES (".join(', ', @placeholders).")";
}
sub noreplace($self)
{
$self->{noreplace} = 1;
return $self;
}
sub ignore($self)
{
$self->{ignore} = 1;
return $self;
}
sub new($class, @p)
{
$class->SUPER::new(@p)->register;
}
package Sql::Create::View;
our @ISA = qw(Sql::Create);
sub type($)
{
"VIEW"
}
sub is_view($)
{
1
}
sub new($class, @p)
{
my $o = $class->SUPER::new(@p);
my $a = "T0001";
$o->{alias} = \$a;
$o->{select} = Sql::Select->new(@p);
$o->register;
}
sub cache($self, $name = $self->name."_Cache")
{
return "CREATE TABLE $name (". $self->{select}->cache. ")";
}
sub contents($self)
{
my @parts = ();
$self->{select}{level} = ($self->{level}//0)+4;
$self->{select}{alias} = $self->{alias};
return ("AS", $self->{select}->contents);
}
sub columns($self)
{
if (!defined $self->{select}{columns}) {
die $self->identify, " has no columns";
}
return @{$self->{select}{columns}};
}
sub add($self, @p)
{
$self->{select}->add(@p);
return $self;
}
sub prepend($self, @p)
{
$self->{select}->prepend(@p);
return $self;
}
sub sort($self)
{
$self->{select}->sort;
return $self;
}
package Sql::Select;
our @ISA = qw(Sql::Create);
sub contents($self)
{
my @parts = ();
# compute the joins
my $joins = {};
my @joins = ();
# figure out used tables
my $tables = {};
if (!defined $self->{origin}) {
die "Missing origin in ", $self->identify;
}
# and column names
$self->{column_names} = {};
for my $w (@{$self->{with}}) {
$w->{alias} = $self->{alias};
# this stuff should use double dispatch
$self->add_column_names_from($w);
push(@parts, $self->indent("WITH ".$w->name." AS", 0));
my @c = $w->contents;
my $one = shift @c;
my $last = pop @c;
push(@parts, $self->indent("($one", 4));
for my $c (@c) {
push(@parts, $self->indent($c, 5));
}
push(@parts, $self->indent("$last)", 5));
}
# this stuff should use double dispatch
$self->add_column_names($self->origin);
$tables->{$self->normalize($self->origin)}++;
for my $c (@{$self->{columns}}) {
my $j = $c->{join};
while (defined $j) {
if (!defined $joins->{$j}) {
# this stuff should use double dispatch
$self->add_column_names($j->name);
push(@joins, $j);
$joins->{$j} = $j;
if (++$tables->{$self->normalize($j->name)} == 1) {
delete $j->{alias};
} else {
$j->{alias} = ${$self->{alias}}++;
}
}
$j = $j->{join};
}
}
push(@parts, $self->indent("SELECT", 0));
my @c = @{$self->{columns}};
while (@c != 0) {
my $c = shift @c;
my $sep = @c == 0 ? '' : ',';
my @lines = split /\n/, $c->stringize;
while (@lines > 1) {
push(@parts, $self->indent(shift @lines, 4));
}
push(@parts, $self->indent(shift @lines, 4).$sep);
}
push(@parts, $self->indent("FROM ".$self->origin, 0));
for my $j (@joins) {
push(@parts, $self->indent($j->join_part, 4));
# next if $j->is_natural;
my @p = $j->on_part($self);
if (@p > 0) {
push(@parts, $self->indent("ON ".join(" AND ", @p), 8));
}
}
if (defined $self->{group}) {
push(@parts, $self->indent("GROUP BY ".
join(", ", map {$_->name} @{$self->{group}}), 4));
}
if (defined $self->{order}) {
push(@parts, $self->indent("ORDER BY ".
join(", ", map {$_->name} @{$self->{order}}), 4));
}
return @parts;
}
sub is_unique_name($self, $name)
{
my $c = $self->{column_names}{$self->normalize($name)};
if (!defined $c) {
die "$name not registed in ", $self->identify;
}
return $c == 1;
}
sub cache($self)
{
my @c;
my $base = Sql::Create->find($self->origin);
for my $c (@{$self->{columns}}) {
my $type = "TEXT";
if (defined $c->{join}) {
my $t = Sql::Create->find($c->{join}->name);
for my $c2 (@{$t->{columns}}) {
if ($c2->name eq $c->origin) {
$type = $c2->type;
last;
}
}
} else {
for my $c2 (@{$base->{columns}}) {
if ($c2->name eq $c->origin) {
$type = $c2->type;
last;
}
}
}
push @c, $c->name." ".$type;
}
return join(', ', @c);
}
package Sql::With;
our @ISA = qw(Sql::Object);
sub category($)
{
"with"
}
sub new($class, @p)
{
my $o = $class->SUPER::new(@p);
$o->{select} = Sql::Select->new(@p);
return $o;
}
sub contents($self)
{
return $self->{select}->contents;
}
sub add($self, @p)
{
$self->{select}->add(@p);
return $self;
}
sub prepend($self, @p)
{
$self->{select}->prepend(@p);
return $self;
}
sub columns($self)
{
return $self->{select}->columns;
}
package Sql::Order;
our @ISA = qw(Sql::Object);
sub category($)
{
"order"
}
package Sql::Group;
our @ISA = qw(Sql::Object);
sub category($)
{
"group"
}
package Sql::Column;
our @ISA = qw(Sql::Object);
sub category($)
{
"columns"
}
sub notnull($self)
{
$self->{notnull} = 1;
return $self;
}
sub null($self)
{
delete $self->{notnull};
return $self;
}
sub unique($self)
{
$self->{unique} = 1;
return $self;
}
sub indexed($self)
{
$self->{want_index} = 1;
return $self;
}
sub stringize($self)
{
my @c = ($self->name, $self->type);
if ($self->{notnull}) {
push(@c, "NOT NULL");
}
if ($self->{unique}) {
push(@c, "UNIQUE");
}
if ($self->{references}) {
push(@c, "REFERENCES $self->{references}{table}(".
$self->reference_field.")");
}
return join(" ", @c);
}
sub placeholder($)
{
'?';
}
sub is_key($)
{
0
}
sub constraint($self)
{
$self->{is_constraint} = 1;
return $self;
}
package Sql::Column::Integer;
our @ISA = qw(Sql::Column);
sub type($)
{
"INTEGER"
}
sub reference_field($self)
{
if (defined $self->{references}{field}) {
return $self->{references}{field};
} else {
my $table = $self->{references}{table};
my $k = Sql::Create::Table->key($table);
if (defined $k) {
return $k->name;
} else {
my $parent = "???";
if (defined $self->{parent}) {
$parent = $self->{parent}->name;
}
die "Can't reference $table from field ",$self->name,
" in $parent";
}
}
}
sub may_reference($self, $table, $field = undef)
{
$self->{references}{table} = $table;
$self->{references}{field} = $field if defined $field;
return $self;
}
sub references($self, $table, $field = undef)
{
return $self->may_reference($table, $field)->notnull;
}
sub placeholder($self)
{
if (!defined $self->{references}) {
return '?';
}
my $table = $self->{references}{table};
my ($key, $value);
for my $c (Sql::Create->find($table)->columns) {
if ($c->is_key) {
$key = $c->name;
} elsif (defined $value) {
return '?'; # can't match multiple fields
} else {
$value = $c->name;
}
}
if (defined $key && defined $value) {
return "(SELECT $key FROM $table WHERE $value=?)";
} else {
return '?';
}
}
package Sql::Column::View;
our @ISA = qw(Sql::Column);
# this is the code I need to rewrite to provide column names based on the
# container or the join
sub stringize($self)
{
if ($self->{parent}->is_unique_name($self->origin)) {
if ($self->origin eq $self->name) {
return $self->name;
} else {
return $self->origin." AS ".$self->name;
}
} else {
return $self->stringize_with_alias;
}
}
sub stringize_with_alias($self)
{
return $self->expr." AS ".$self->name;
}
sub expr($self, @p)
{
return $self->column(@p);
}
sub column($self, $name = $self->origin)
{
if ($self->{parent}->is_unique_name($name)) {
return $name;
}
if (defined $self->{join} &&
Sql::Create->is_table_column($self->{join}->name, $name)) {
return $self->{join}->join_table.".".$name;
} else {
return $self->{parent}->origin.".".$name;
}
}
sub group_by($self)
{
$self->{group_by} = 1;
return $self;
}
sub join_table($self)
{
return $self->{parent}->origin;
}
sub join($self, @j)
{
my $subject = $self;
for my $j (@j) {
$subject->{join} = $j;
$j->{previous} = $subject;
$subject = $j;
}
return $self;
}
sub left($self)
{
if (defined $self->{join}) {
$self->{join}->left;
}
return $self;
}
sub new($class, @p)
{
my $o = $class->SUPER::new(@p);
$o->{origin} //= $o->name;
return $o;
}
sub add_to($self, $container)
{
$self->SUPER::add_to($container);
if ($self->{group_by}) {
push(@{$container->{group}}, $self);
}
}
sub prepend_to($self, $container)
{
$self->SUPER::prepend_to($container);
if ($self->{group_by}) {
unshift(@{$container->{group}}, $self);
}
}
package Sql::Column::View::Expr;
our @ISA = qw(Sql::Column::View);
sub stringize($self)
{
return $self->stringize_with_alias;
}
package Sql::Column::View::Concat;
our @ISA = qw(Sql::Column::View::Expr);
sub new($class, @p)
{
my $o = $class->SUPER::new(@p);
$o->{separator} //= ' ';
return $o;
}
sub expr($self)
{
return "group_concat(".$self->column.", '".$self->{separator}."')";
}
package Sql::Column::Text;
our @ISA = qw(Sql::Column);
sub type($)
{
"TEXT";
}
package Sql::Column::CurrentDate;
our @ISA = qw(Sql::Column::Text);
sub placeholder($)
{
"CURRENT_DATE";
}
package Sql::Column::Key;
our @ISA = qw(Sql::Column::Integer);
sub new($class, @p)
{
my $o = $class->SUPER::new(@p);
$o->{autoincrement} = 1;
return $o;
}
sub is_key($self)
{
return $self->{autoincrement};
}
sub add_to($self, $c)
{
$c->{key} = $self;
$self->SUPER::add_to($c);
}
sub prepend_to($self, $c)
{
$c->{key} = $self;
$self->SUPER::prepend_to($c);
}
sub noautoincrement($self)
{
$self->{autoincrement} = 0;
return $self;
}
sub type($self)
{
if ($self->{autoincrement}) {
return "INTEGER PRIMARY KEY AUTOINCREMENT";
} else {
return "INTEGER PRIMARY KEY";
}
}
package Sql::Join;
our @ISA = qw(Sql::Object);
sub category($)
{
"joins"
}
sub join_part($self)
{
my $s = "JOIN ".$self->name;
if (defined $self->{alias}) {
$s .= " ".$self->{alias};
}
if ($self->{left}) {
$s = "LEFT ".$s;
}
# if ($self->is_natural) {
# $s = "NATURAL ".$s;
# }
return $s;
}
sub join_table($self)
{
return $self->{alias} // $self->name;
}
sub on_part($self, $view)
{
return map {$_->equation($self, $view)} @{$self->{equals}};
}
sub is_natural($self)
{
for my $e (@{$self->{equals}}) {
return 0 if !$e->is_natural;
}
return 1;
}
sub left($self)
{
$self->{left} = 1;
return $self;
}
package Sql::Equal;
our @ISA = qw(Sql::Object);
sub new($class, $a, $b)
{
bless {a => $a, b => $b}, $class;
}
sub category($)
{
"equals"
}
sub equation($self, $join, $view)
{
my $a = $self->{a};
my $b = $self->{b};
if (!$view->is_unique_name($a)) {
$a = $join->join_table.".".$a;
}
if (!$view->is_unique_name($b)) {
$b = $join->{previous}->join_table.".".$b;
}
return "$a=$b";
}
sub is_natural($self)
{
return $self->{a} eq $self->{b};
}
package Sql::EqualConstant;
our @ISA = qw(Sql::Equal);
sub equation($self, $join, $view)
{
my $a = $self->{a};
if (!$view->is_unique_name($a)) {
$a = $join->join_table.".".$a;
}
return "$a=$self->{b}";
}
sub is_natural($)
{
0
}
package Sql::IsNull;
our @ISA = qw(Sql::Equal);
# :IsNull is a "kind of" equal but it has only one single value
# it's okay because everything referencing b is overriden.
sub new($class, $a)
{
bless {a => $a}, $class;
}
sub equation($self, $join, $view)
{
my $a = $self->{a};
if (!$view->is_unique_name($a)) {
$a = $join->join_table.".".$a;
}
return "$a IS NULL";
}
sub is_natural($)
{
0
}
package Sql::Create::Index;
our @ISA = qw(Sql::Create);
sub type($)
{
"INDEX"
}
sub is_index($)
{
1
}
sub new($class, $table, $col)
{
my $name = $table->name."_".$col->name;
my $o = bless { name => $name, table => $table, col => $col}, $class;
$o->register;
}
sub contents($self)
{
return "ON ". $self->{table}->name."(".$self->{col}->name.")";
}
1;

View file

@ -0,0 +1,91 @@
# ex:ts=8 sw=4:
# $OpenBSD: Trace.pm,v 1.2 2023/06/16 04:17:56 espie Exp $
#
# Copyright (c) 2015-2018 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use v5.36;
package Trace;
# inspired by Carp::Always
sub trace_message()
{
my $msg = '';
my $x = 1;
while (1) {
my @c;
{
package DB;
our @args;
@c = caller($x+1);
}
last if !@c;
$msg .= "$c[3](".
join(', ', map {
if (!defined $_) {
'<undef>';
} else {
my $string;
eval { $string = $_->debug_dump };
if (defined $string) {
"$_($string)";
} else {
$_;
}
}
} @DB::args).
") called at $c[1] line $c[2]\n";
$x++;
}
return $msg;
}
my ($sig, $olddie, $oldwarn);
sub setup($class, $sig)
{
$olddie = $SIG{__DIE__};
$oldwarn = $SIG{__WARN__};
$sig->{__WARN__} = sub {
$sig->{__WARN__} = $oldwarn;
my $a = pop @_;
$a =~ s/(.*)( at .*? line .*?)\n$/$1$2/s;
push @_, $a;
my $msg = join("\n", @_, &trace_message());
warn $msg;
};
$sig->{__DIE__} = sub {
die @_ if $^S;
$sig->{__DIE__} = $olddie;
my $a = pop @_;
$a =~ s/(.*)( at .*? line .*?)\n$/$1$2/s;
push @_, $a;
my $msg = join("\n", @_, &trace_message());
die $msg;
};
$sig->{INFO} = sub {
print "Trace:\n", &trace_message();
sleep 1;
};
}
END {
$sig->{__DIE__} = $olddie;
$sig->{__WARN__} = $oldwarn;
}
1;

View file

@ -0,0 +1,152 @@
#! /usr/bin/perl
# $OpenBSD: TreeWalker.pm,v 1.18 2023/06/15 12:53:07 espie Exp $
#
# Copyright (c) 2006-2013 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use v5.36;
use warnings;
package TreeWalker;
use PkgPath;
sub new($class, $strict, $startdir)
{
return bless { strict => $strict, startdir => $startdir }, $class;
}
sub subdirlist($self, $list)
{
return join(' ', sort keys %$list);
}
sub dump_dirs($self, $subdirs = undef)
{
my ($pid, $fd);
unless (defined($pid = open($fd, "-|"))) {
die "can't fork : $!";
}
if ($pid) {
$self->parse_dump($fd, $subdirs);
close $fd || die $!;
} else {
my %myenv = ();
my $portsdir = $ENV{PORTSDIR};
if (defined $subdirs) {
$myenv{'SUBDIR'} = $self->subdirlist($subdirs);
} elsif (defined $ENV{SUBDIRLIST}) {
$myenv{'SUBDIRLIST'} = $ENV{SUBDIRLIST};
} elsif (defined $self->{startdir}) {
$myenv{'STARTDIR'} = $self->{startdir};
}
$myenv{'NO_IGNORE'} = 'Yes';
$myenv{PORTSDIR} = $portsdir;
close STDERR;
open STDERR, '>&STDOUT';
chdir $portsdir;
%ENV = %myenv;
my @vars = ('LIBECXX=$${LIBECXX}',
'COMPILER_LIBCXX=$${COMPILER_LIBCXX}');
if (!$self->{strict}) {
push(@vars, "PORTSDIR_PATH=$portsdir");
}
exec {'make'} ("make", "dump-vars", @vars);
die $!;
}
}
sub parse_dump($self, $fd, $subdirs)
{
my $h = {};
my $seen = {};
my $subdir;
my $reset = sub() {
$h = PkgPath->handle_equivalences($self, $h, $subdirs);
for my $pkgpath (sort values %$h) {
$self->handle_path($pkgpath, $self->{equivs});
}
$h = {};
};
while (<$fd>) {
chomp;
# kill noise
if (m/^\=\=\=\>\s*Exiting (.*) with an error$/) {
my $dir = PkgPath->new($1);
$dir->break("exiting with an error");
$h->{$dir} = $dir;
$h = {};
next;
}
if (m/^\=\=\=\>\s*(.*)/) {
$subdir = PkgPath->new($1);
&$reset();
} elsif (my ($pkgpath, $var, $arch, $value) =
m/^(.*?)\.([A-Z][A-Z_0-9]*)(?:\-([a-z0-9]+))?\=\s*(.*)\s*$/) {
if ($value =~ m/^\"(.*)\"$/) {
$value = $1;
}
my $o = PkgPath->compose($pkgpath, $subdir);
$h->{$o} = $o;
$self->handle_value($o, $var, $value, $arch);
# Note we did it !
} elsif (m/^\>\>\s*Broken dependency:\s*(.*?)\s*non existent/) {
my $dir = PkgPath->new($1);
$dir->break("broken dependency");
$h->{$dir} = $dir;
$h= {};
}
}
&$reset();
}
# $self->handle_value($o, $var, $value, $arch)
sub handle_value($, $, $, $, $)
{
}
# $self->handle_path($pkgpath, $equivs)
sub handle_path($, $, $)
{
}
sub dump_all_dirs($self)
{
$self->dump_dirs;
my $i = 1;
while (1) {
my $subdirlist = {};
for my $v (PkgPath->seen) {
if (defined $v->{info}) {
delete $v->{tried};
if (defined $v->{want}) {
delete $v->{want};
}
next;
}
if (defined $v->{tried}) {
} elsif ($v->{want}) {
$v->add_to_subdirlist($subdirlist);
$v->{tried} = 1;
}
}
last if (keys %$subdirlist) == 0;
$i++;
say "pass #$i";
$self->dump_dirs($subdirlist);
}
}
1;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,58 @@
.\" $OpenBSD: show-reverse-deps.1,v 1.3 2020/06/11 19:55:15 espie Exp $
.\"
.\" Copyright (c) 2020 Marc Espie <espie@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: June 11 2020 $
.Dt SHOW-REVERSE-DEPS 1
.Os
.Sh NAME
.Nm show-reverse-deps
.Nd show reverse dependencies for a given port
.Sh SYNOPSIS
.Nm show-reverse-deps
.Op Fl ftv
.Op Fl d Ar database
.Ar pkgpath
.Sh DESCRIPTION
.Nm
quickly computes all ports dependent on a given port through a recursive sql
query to
.Pa sqlports .
.Pp
The
.Ar pkgpath
parameter should normally be the fullpkgpath of the port to depend on.
.Pp
Options are as follows:
.Bl -tag -width flagdatabase
.It Fl d Ar database
Choose an sqlite3 database other than the default
.Pa ${TRUEPREFIX}/share/sqlports .
.It Fl f
Fuzzy matching, show dependencies for any path which contains the
.Ar pkgpath
parameter.
.It Fl t
Also include test dependencies.
By default, only other types of dependencies are considered.
.It Fl v
Show verbose results: instead of a list of pkgpath, show every
dependency in the form "fullpkgpath|dependspath|TYPE", where TYPE
is one of
.Ev LIB_DEPENDS , RUN_DEPENDS , BUILD_DEPENDS , TEST_DEPENDS .
Results can be rather large!
.El
.Sh SEE ALSO
.Xr sqlite3 1

View file

@ -0,0 +1,287 @@
.\" $OpenBSD: sqlports.5,v 1.8 2023/08/08 11:12:06 espie Exp $
.\"
.\" Copyright (c) 2020 Marc Espie <espie@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: August 8 2023 $
.Dt SQLPORTS 5
.Os
.Sh NAME
.Nm sqlports
.Nd sqlite database for ports meta information
.Sh DESCRIPTION
.Nm
is built as a port by parsing the output of
.Li make dump-vars
over the full ports tree.
.Pp
The database contains tables for automated tools, along with nice views
for human consumption.
.Pp
Table names are prefixed with underscore, .e.g,
.Sq _Ports
contrary to views, e.g.,
.Sq Paths .
.Pp
The special table
.Sq Meta
contains only one entry, detailing the current database.
.Bl -tag -offset indent -width keyword
.It Meta (SchemaVersion, Hash, CurrentDate)
SchemaVersion follows the usual major.minor rules as shared libraries,
Hash is unique to each generated database,
CurrentDate is the date the database was generated.
.El
.Pp
Other tables are as follows:
.Bl -tag -offset indent -width keyword
.It _Paths (ID, FULLPKGPATH, PKGPATH, CANONICAL)
PKGPATH points to a PATHS entry corresponding to the stripped down version of
FULLPKGPATH, without flavors or subpackage markers, or is null if FULLPKGPATH
is already stripped.
Every other FULLPKGPATH, PKGPATH, DEPENDSPATH entry
in the database points to this table.
The FULLPKGPATH is complete, including flavors and pseudo flavors markers.
For every port with MULTI_PACKAGES settings, one entry is written
for each SUBPACKAGE.
CANONICAL points to the actual ID to use as an entry in other tables, for
FULLPKGPATH which don't have their own entry.
.It _Ports(FULLPKGPATH, ...)
holds all the information retrieved through various variables that is not
stored in specialized tables, e.g.,:
.Bl -tag -width AUTOMAKE_VERSION -offset indent -compact
.It AUTOCONF_VERSION
.It AUTOMAKE_VERSION
.It COMES_WITH
.It COMMENT
.It COMPILER
.It COMPILER_LANGS
.It DISTFILES
.It DISTNAME
.It DIST_SUBDIR
.It EPOCH
.It FIX_EXTRACT_PERMISSIONS
.It FULLPKGNAME
.It GH_*
.It HOMEPAGE
.It IGNORE
.It IS_INTERACTIVE
.It MAINTAINER
.It NO_*
.It PERMIT_*
.It PKGNAME
.It PKGSPEC
.It PKGSTEM
.It PKG_ARCH
.It PORTROACH
.It PORTROACH_COMMENT
.It PREFIX
.It PSEUDO_FLAVOR
.It REVISION
.It SEPARATE_BUILD
.It STATIC_PLIST
.It SUBPACKAGE
.It SUPDISTFILES
.It TEST_IS_INTERACTIVE
.It UPDATE_PLIST_ARGS
.It USE_*
.El
Some of this information is stored as indexes in keyword tables,
and Yes/No variables have been replaced with 1/0.
Variables not present in a given port are left undefined.
.Pp
Specifically, AUTOCONF_VERSION and AUTOMAKE_VERSION reference _AutoVersion,
MAINTAINER references _EMail, PERMIT_DISTFILES and SEPARATE_BUILD
reference _Keywords2, PKG_ARCH references _Arch, and PREFIX references _Prefix.
Note that USE_LIBTOOL is 3-valued: 2 is gnu, 1 is yes, undef is no.
Note that USE_WXNEEDED is 3-valued: 2 is special, 1 is yes, undef is no.
.Pp
MULTI_PACKAGES ports hold several entries with corresponding FULLPKGPATH
(after canonicalisation).
.It _Flavors(FULLPKGPATH, VALUE, N)
.It _PseudoFlavors(FULLPKGPATH, VALUE, N)
.It _Categories(FULLPKGPATH, VALUE, N)
.It _Multi(FULLPKGPATH, VALUE, SUBPKGPATH, N)
No values are stored for SUBPKGPATH=-.
.It _Modules(FULLPKGPATH, VALUE, N)
.It _Configure(FULLPKGPATH, VALUE, N)
Corresponds to CONFIGURE_STYLE
.It _ConfigureArgs(FULLPKGPATH, VALUE, N, QUOTETYPE)
.It _DebugConfigureArgs(FULLPKGPATH, VALUE, N, QUOTETYPE)
.It _MasterSites(FULLPKGPATH, N, VALUE)
.It _Makefiles(FULLPKGPATH, VALUE, N)
This tables contains only Makefiles from MAKE_FILE_LIST that are not
.Sq default values
(always included makefiles).
.It _FixCRLFFiles(FULLPKGPATH, VALUE, N)
.It _NotForArch(FULLPKGPATH, VALUE, N)
.It _OnlyForArch(FULLPKGPATH, VALUE, N)
All of these variable values are actually ordered lists (hence the N).
.Pp
Each keyword table follows the same scheme
TABLENAME(KEYREF, VALUE)
.It _Depends(FULLPKGPATH, FULLDEPENDS, PKGSPEC, REST, DEPENDSPATH, TYPE, N)
All depends are stored in a single table, the type is
.Bl -tag -width 10 -offset indent -compact
.It 0
LIB_DEPENDS
.It 1
RUN_DEPENDS
.It 2
BUILD_DEPENDS
.It 3
TEST_DEPENDS
.El
FULLDEPENDS is the full text of the dependency, which parses as DEPENDSPATH,
the actual PKGPATH we depend upon, PKGSPEC, the spec we depend upon
(if explicit), and REST the remainder of the text (things like :configure and
such).
.It _Distfiles(FULLPKGPATH, VALUE, N, Type)
All distfiles/patchfiles/supdistfiles are stored in a single table, with Type
.Bl -tag -width 10 -offset indent -compact
.It 0
distfiles
.It 1
patchfiles
.It 2
supdistfiles
.El
Note that N is :N from mastersites, those are not considered ordered lists.
.It _DPBProperties (FULLPKGPATH, VALUE, N)
.It _Wantlib(FULLPKGPATH, VALUE, EXTRA)
All the libraries the FULLPKGPATH depends upon, with optional version
number specification stored in EXTRA
coming from the WANTLIB variable.
.It _Multi(FULLPKGPATH, VALUE, SUBPKGPATH, N)
also contains the normalized pkgpath for the corresponding subpackage.
.It _DebugPackages(FULLPKGPATH, VALUE, SUBPKGPATH, N)
contrary to _Multi, also contains
.Sq -
entries for packages without subpackages which have debug packages.
.It _PkgPaths(FULLPKGPATH, Value, N)
all build_packages associated to a fullpkgpath.
.It _Broken(FULLPKGPATH, ARCH, TEXT)
.It _Shared_Libs(FULLPKGPATH, LIBNAME, VERSION)
.It _SubstVars(FULLPKGPATH, VALUE, N)
.It _TARGETS(FULLPKGPATH, VALUE)
.El
Some information, both in the main table and in secondary tables
is stored as keyword references to other tables:
.Bl -tag -width AUTOMAKE_VERSIONblablabla -offset indent -compact
.It AUTOCONF_VERSION , AUTOMAKE_VERSION
_AUTOVERSION
.It FixCRLFFiles
_FILENAME2
.It _DPBProperties.value
_DPBKeys
.It MAINTAINER
_EMAIL
.It CATEGORIES
_CATEGORYKEYS
.It CONFIGURE
_CONFIGURE_KEYS
.It MAKEFILES
_FILENAME
.It MODULES
_MODULEKEYS
.It PREFIX
_PREFIX
.It _WANTLIB.VALUE , _SHARED_LIBS.LIBNAME
_LIBRARY
.It PERMIT_* , SEPARATE_BUILD
_KEYWORDS2
.It FLAVORS , PSEUDO_FLAVORS
_KEYWORDS
.It NOT_FOR_ARCHS , ONLY_FOR_ARCHS , PKG_ARCH
_ARCH
.It _SubstVars.value
_substvarskey
.It TARGETS
_TARGETKEYS
.It _Distfiles.value
_Fetchfiles
.El
A few views are provided for convenience while building complex requests.
.Bl -bullet -offset indent
.It
Ports:
contains all info from _ports and from secondary tables with indices
replaced with text values.
.It
* Depends_ordered, Categories_ordered, CompilerLinks_Ordered,
Configureargs_ordered, Configure_ordered, DebugConfigureArgs_Ordered,
DPBProperties_ordered,
Flavors_ordered, Makefiles_ordered, Modules_ordered, NotForArch_ordered,
OnlyforArch_ordered, PkgPaths_ordered, PseudoFlavors_ordered,
SubstVars_ordered, Targets_ordered, distfiles_ordered, wantlib_ordered:
reconstituted lists of text values as a single string from the
corresponding table.
.It
each "keyword" list also has a corresponding view, e.g.,
_BROKEN -> BROKEN (PathId, FULLPKGPATH, Arch, Value)
with text fields, and PathId still the index entry for the fullpkgpath,
suitable for further joins.
.It
canonical_depends: fullpkgpath/dependspath/dependstype from _depends but
normalized as canonical paths.
.El
.Pp
The database also contains a caching table named
.Sq PortsQ
that contains the actual data from the
.Sq Ports
view.
.Sh EXAMPLES
Looking at the details of a view:
.Bd -literal -offset indent
sqlite> .schema depends
CREATE VIEW Depends AS
SELECT
_Paths.Id AS PathId,
_Paths.FullPkgPath AS FullPkgPath,
FullDepends,
PkgSpec,
Rest,
T0001.FullPkgpath AS DependsPath,
Type,
N
FROM _Depends
JOIN _Paths
ON _Paths.Canonical=_Depends.FullPkgPath
JOIN _Paths T0001
ON T0001.Canonical=DependsPath
/* Depends(PathId,FullPkgPath,FullDepends,PkgSpec,Rest,DependsPath,Type,N) */;
.Ed
List the fullpkgpaths of leaf ports (not a dependency of anything):
.Bd -literal -offset indent
sqlite> select distinct fullpkgpath from _paths where pkgpath not in
(select pkgpath from _paths
join _depends on _depends.dependspath=_paths.id);
.Ed
.Sh BUGS AND LIMITATIONS
The optimizer in
.Xr sqlite 1
doesn't care for non-standard constructs such as
.Sq group_concat
and doesn't optimize left joins away when it should,
so even if you don't ask for agregated columns in the
.Sq Ports
view, it will compute them irregardless.
Hence the
.Sq PortsQ
cache.
.Sh FILES
.Pa ${TRUEPREFIX}/share/sqlports
.Sh SEE ALSO
.Xr sqlite3 1

View file

@ -0,0 +1,174 @@
#! /usr/bin/perl
# $OpenBSD: mksqlitedb,v 1.60 2023/06/16 04:54:20 espie Exp $
#
# Copyright (c) 2006-2010 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# example script that shows how to store all variable values into a
# database, using SQLite for that purpose.
#
# usage: cd /usr/ports && mksqlitedb
use v5.36;
use FindBin;
use lib $FindBin::Bin;
use Getopt::Std;
use Var;
use Inserter;
use DBI;
use PkgPath;
use Info;
use TreeWalker;
use Trace;
package MyTreeWalker;
our @ISA = (qw(TreeWalker));
sub new($class, $inserter, @r)
{
my $o = $class->SUPER::new(@r);
$o->{inserter} = $inserter;
return $o;
}
sub inserter($self)
{
return $self->{inserter};
}
sub handle_value($self, $o, $var, $value, $arch)
{
$o->{info} //= Info->new($o);
$o->{info}->create($var, $value, $arch, $o);
}
sub parse_dump($self, $fd, $subdirs)
{
$self->SUPER::parse_dump($fd, $subdirs);
$self->inserter->commit_to_db;
}
sub create_missing_vars($self, $o)
{
for my $name (qw(SHARED_LIBS TARGETS)) {
if (!defined $o->{info}->{vars}{$name}) {
$o->{info}->create($name, '', undef, $o);
}
}
}
sub handle_path($self, $pkgpath, $equivs)
{
$self->create_missing_vars($pkgpath);
my $key = $pkgpath->fullpkgpath;
while (defined $equivs->{$key}) {
$key = $equivs->{$key};
}
if ($pkgpath->{info}{done}) {
print "--- $key (already done)\n";
return;
}
print "+++ $key\n";
$self->inserter->set_newkey($key);
for my $var ($pkgpath->{info}->variables) {
$self->inserter->add_var($var);
}
$pkgpath->{info}->reclaim;
$pkgpath->{info}{done} = 1;
$pkgpath->{done} = 1;
$self->inserter->finish_port;
}
package main;
use Digest::SHA;
use MIME::Base64;
sub digest($filename)
{
my $d = Digest::SHA->new(256);
$d->addfile($filename);
return encode_base64($d->digest, '');
}
our ($opt_v, $opt_q, $opt_p, $opt_V, $opt_C, $opt_w, $opt_s, $opt_S);
Trace->setup(\%SIG);
getopts('svq:p:V:C:w:S:');
my $dbname;
if (@ARGV == 1) {
$dbname = shift;
} elsif (@ARGV == 0) {
$dbname = 'sqlports';
} else {
exit 1;
}
my $db = DBI->connect("dbi:SQLite:dbname=$dbname", '', '', {AutoCommit => 0});
my $inserter = Inserter->new($db, 1000, $opt_v, 1);
$inserter->create_tables($Info::vars);
if ($opt_p) {
$ENV{'REPORT_PROBLEM_LOGFILE'}= $opt_p;
}
my $walker = MyTreeWalker->new($inserter, $opt_s, $opt_S);
if (defined $opt_C) {
open(my $f, '>', $opt_C) or die;
my $cache = "PortsQ";
say $f "DROP TABLE if exists $cache;";
say $f Sql::Create->find('ports')->cache($cache), ";";
say $f "INSERT INTO $cache select * from Ports;";
say $f "ANALYZE;";
close $f;
}
if (defined $opt_w) {
open(my $f, '>', $opt_w) or die;
for my $v (Sql::Create->all_views) {
say $f $v->drop, ";";
say $f $v->stringize, ";";
}
close $f;
}
$walker->dump_all_dirs;
# Create aliases, we have to sort the keys so that they are
# created in the right pkgpath order
for my $p (sort keys %{$walker->{equivs}}) {
my $a = $p;
while (defined $walker->{equivs}{$a}) {
$a = $walker->{equivs}{$a};
}
$walker->inserter->add_path($p, $a);
}
$walker->inserter->commit_to_db;
$walker->inserter->insert("Meta", $opt_V, digest($dbname));
$walker->inserter->commit_to_db;
$db->disconnect;
while (my ($k, $v) = each %$Info::unknown) {
say STDERR "Unknown variable $k in ", $v->fullpkgpath;
}
if (defined $opt_q) {
open(my $log, ">", $opt_q) or die $!;
$walker->inserter->write_log($log);
} else {
$walker->inserter->write_log(\*STDERR);
}

View file

@ -0,0 +1,60 @@
#! /usr/bin/perl
# $OpenBSD: rebuild_schema,v 1.3 2019/03/15 11:29:53 espie Exp $
#
# Copyright (c) 2018 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# example script that shows how to store all variable values into a
# database, using SQLite for that purpose.
#
# usage: cd /usr/ports && mksqlitedb
use strict;
use warnings;
use FindBin;
use lib $FindBin::Bin;
use Getopt::Std;
use Var;
use Inserter;
use DBI;
use PkgPath;
use Info;
use Trace;
package main;
our ($opt_v, $opt_q, $opt_p, $opt_V);
Trace->setup(\%SIG);
getopts('vq:p:V:');
my $dbname;
if (@ARGV == 1) {
$dbname = shift;
} elsif (@ARGV == 0) {
$dbname = 'sqlports';
} else {
exit 1;
}
my $db = DBI->connect("dbi:SQLite:dbname=$dbname", '', '', {AutoCommit => 0});
my $inserter = Inserter->new($db, 1000, $opt_v, 0);
$inserter->create_tables($Info::vars);
my $stmt = $db->prepare("UPDATE Meta set SchemaVersion=?");
$stmt->execute($opt_V);
$inserter->commit_to_db;

View file

@ -0,0 +1,37 @@
#! /usr/bin/perl
# a small script that takes a sqlite3 schema and creates
# a normalized version (zaps extraneous spaces, rewrites
# everything as lowercase, sorts by table/view name)
use v5.36;
my ($object, $comment);
my $stmt = '';
while(<STDIN>) {
chomp;
$stmt .= " ".lc($_);
if (m/\;/) {
$stmt =~ s/\s+/ /g;
$stmt =~ s/^\s//;
$stmt =~ s/\s?\(\s?/\(/g;
$stmt =~ s/\s?\)\s?/\)/g;
if ($stmt =~ m/^create table (\S+)/) {
$object->{$1} = $stmt;
} elsif ($stmt =~ m/^create view (\S+)/) {
$object->{$1} = $stmt;
} else {
say $stmt;
}
$stmt = '';
}
}
for my $k (sort keys %$object) {
if ($object->{$k} =~ m,\s/\*,) {
say "$`\n/*$'\n";
} else {
say $object->{$k}, "\n";
}
}

View file

@ -0,0 +1,64 @@
#! /bin/sh
# $OpenBSD: print-ports-index,v 1.12 2019/07/14 11:27:19 espie Exp $
#
# Copyright (c) 2018 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# recreate index file, identical to /usr/ports/INDEX
set -e
if [ $# -ge 1 ]
then
file=$1
else
file=${TRUEPREFIX}/share/sqlports
fi
cat <<'EOSQL' |sqlite3 $file
-- in order for group_concat to sort, you must do it in two steps
with
d1 (d, p, t) as
(select
distinct((case pkgspec when '' then '' else pkgspec||":" end)||_paths.fullpkgpath) as fd,
_depends.fullpkgpath, type
from _depends join _paths on _Paths.Id=_depends.dependspath order by fd),
-- and now the part that's going to be used 3 times in the main request
d2 as
(select group_concat(d, ' ') as dlist, p, t
from d1 group by p, t)
select fullpkgname, ports.fullpkgpath,
(case prefix when '/usr/local' THEN "" else prefix end),
comment,descr, maintainer,categories,
libd.dlist, buildd.dlist, rund.dlist,
case 1
when only_for_archs is null then
case 1
when not_for_archs is null
then 'any'
else '!'||not_for_archs
end
else only_for_archs
end,
'?',
(case lower(PERMIT_PACKAGE) when "yes" then "y" else "n" end),
(case lower(PERMIT_DISTFILES) when "yes" then "y" else "n" end)
from ports
left join d2 as libd on libd.p=ports.pathid and libd.t=0
left join d2 as buildd on buildd.p=ports.pathid and buildd.t=2
left join d2 as rund on rund.p=ports.pathid and rund.t=1
where ports.pathid in (select distinct canonical from _paths)
group by ports.fullpkgpath
order by ports.fullpkgpath;
EOSQL

View file

@ -0,0 +1,25 @@
#! /bin/sh
# $OpenBSD: rebuild-sqlports-cache,v 1.2 2019/06/04 16:05:52 espie Exp $
#
# Copyright (c) 2019 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
set -e
if [ $# -ge 1 ]
then
file=$1
else
file=${TRUEPREFIX}/share/sqlports
fi
sqlite3 $file <${TRUEPREFIX}/share/sqlports_cache.sql

View file

@ -0,0 +1,106 @@
#! /bin/sh
# $OpenBSD: show-reverse-deps,v 1.10 2020/06/11 19:55:15 espie Exp $
#
# Copyright (c) 2018 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# compute reverse dependencies
# XXX this is not perfect yet! it *does* require collating lib-depends over
# multi-packages setup, which this is NOT doing yet, but it is close to
# actually doing it.
# we just require a few more views for that.
usage="Usage: show-reverse-deps [-ftv] [-d sqlite_db] pkgpath"
args=`getopt d:ftv $*`
if [ $? -ne 0 ]
then
echo 2>&1 $usage
fi
set -e
db=${TRUEPREFIX}/share/sqlports
type_root="root.type!=3"
type_child="child.type!=3"
fuzzy=false
verbose=false
set -- $args
while [ $# -ne 0 ]
do
case "$1" in
-d)
db="$2"
shift
shift
;;
-f)
fuzzy=true
shift
;;
-t)
type_root=true
type_child=true
shift
;;
-v)
verbose=true
shift
;;
--)
shift
break
;;
esac
done
if [ $# -ne 1 ]
then
echo 2>&1 $usage
exit 1
fi
if $fuzzy
then
query="p2.fullpkgpath like \"%$1%\""
else
query="p2.fullpkgpath=\"$1\""
fi
if $verbose
then
adj=", _paths2.fullpkgpath, case d.type when 0 then 'LIB_DEPENDS' when 1 then 'RUN_DEPENDS' when 2 then 'BUILD_DEPENDS' when 3 then 'TEST_DEPENDS' end"
join_adj="join _paths _paths2 on _paths2.id=d.dependspath"
else
adj=""
join_adj=""
fi
sqlite3 "$db" <<EOSQL
with recursive d (fullpkgpath, dependspath, type) as
(select root.fullpkgpath, root.dependspath, root.type
from _canonical_depends root
join _paths
on root.dependspath=_paths.canonical
join _paths p2
on $query and p2.id=_paths.pkgpath
where $type_root
union
select child.fullpkgpath, child.dependspath, child.type
from d parent, _canonical_depends child
where parent.fullpkgpath=child.dependspath and $type_child)
select distinct _paths.fullpkgpath $adj from d
join _paths
on _paths.id=d.fullpkgpath
$join_adj
order by _paths.fullpkgpath $adj;
EOSQL

View file

@ -0,0 +1,3 @@
Reduced list of every fullpkgpath reachable in the ports tree, with
duplicate pkgnames removed, and with ports without static plists taken
out.

View file

@ -0,0 +1,12 @@
SQLite database of every port in the system. This can be queried through
e.g., sqlitebrowser, or any kind of programming interface.
This schema is mostly optimized for tools, and cumbersome to query by
hand.
Human users are strongly advised to mostly use views on those tables.
The default flavor only looks in PORTSDIR, use nonstrict to heed
PORTSDIR_PATH fully.
The database scheme is documented in sqlports(5)

View file

@ -0,0 +1,3 @@
@option always-update
share/ports-INDEX
share/sqlports.list

View file

@ -0,0 +1,10 @@
@option always-update
@conflict sqlports-compact-<7.0
@pkgpath databases/sqlports,-compact
bin/print-ports-index
bin/rebuild-sqlports-cache
bin/show-reverse-deps
@man man/man1/show-reverse-deps.1
@man man/man5/sqlports.5
share/sqlports
share/sqlports_cache.sql