diff --git a/doc/reverse-build-depends.1 b/doc/reverse-build-depends.1 deleted file mode 100644 index 3fcdc0d..0000000 --- a/doc/reverse-build-depends.1 +++ /dev/null @@ -1,172 +0,0 @@ -.\" Automatically generated by Pod::Man 2.1801 (Pod::Simple 3.05) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "BUILD-RDEPS 1" -.TH BUILD-RDEPS 1 "2008-08-14" "Debian Utilities" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -build\-rdeps \- find packages that depend on a specific package to build (reverse build depends) -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBubuild-rdeps\fR \fIpackage\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fBubuild-rdeps\fR searches for all packages that build-depend on the specified package. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-u\fR \fB\-\-update\fR" 4 -.IX Item "-u --update" -Run apt-get update before searching for build-depends. -.IP "\fB\-s\fR \fB\-\-sudo\fR" 4 -.IX Item "-s --sudo" -Use sudo when running apt-get update. Has no effect if \-u is omitted. -.IP "\fB\-\-distribution\fR" 4 -.IX Item "--distribution" -Select another distribution, which is searched for build-depends. -.IP "\fB\-m\fR \fB\-\-print\-maintainer\fR" 4 -.IX Item "-m --print-maintainer" -Print the value of the maintainer field for each package. -.IP "\fB\-d\fR \fB\-\-debug\fR" 4 -.IX Item "-d --debug" -Run the debug mode -.IP "\fB\-\-help\fR" 4 -.IX Item "--help" -Show the usage information. -.IP "\fB\-\-version\fR" 4 -.IX Item "--version" -Show the version information. -.SH "LICENSE" -.IX Header "LICENSE" -This code is copyright by Patrick Schoenfeld -, all rights reserved. -This program comes with \s-1ABSOLUTELEY\s0 \s-1NO\s0 \s-1WARRANTY\s0. -You are free to redistribute this code under the terms of the -\&\s-1GNU\s0 General Public License, version 2 or later. -.SH "AUTHOR" -.IX Header "AUTHOR" -Patrick Schoenfeld diff --git a/reverse-build-depends b/reverse-build-depends deleted file mode 100755 index 8b66be9..0000000 --- a/reverse-build-depends +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/perl -# Copyright (C) Patrick Schoenfeld -# Copyright (C) 2009 Ryan Kavanagh -# -# 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. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -=head1 NAME - -build-rdeps - find packages that depend on a specific package to build (reverse build depends) - -=head1 SYNOPSIS - -B I - -=head1 DESCRIPTION - -B searches for all packages that build-depend on the specified package. - -=head1 OPTIONS - -=over 4 - -=item B<-u> B<--update> - -Run apt-get update before searching for build-depends. - -=item B<-s> B<--sudo> - -Use sudo when running apt-get update. Has no effect if -u is omitted. - -=item B<--distribution> - -Select another distribution, which is searched for build-depends. - -=item B<-m> B<--print-maintainer> - -Print the value of the maintainer field for each package. - -=item B<-d> B<--debug> - -Run the debug mode - -=item B<--help> - -Show the usage information. - -=item B<--version> - -Show the version information. - -=back - -=cut - -use warnings; -use strict; -use File::Basename; -use File::Find; -use Getopt::Long; -use Pod::Usage; -use Data::Dumper; -my $progname = basename($0); -my $version = '1.0'; -my $default_distribution = `ubuntu-distro-info --devel`; -chomp($default_distribution); -my $dctrl = "/usr/bin/grep-dctrl"; -my $sources_path = "/var/lib/apt/lists/"; -my $source_pattern = ".*_dists_${default_distribution}_.*Sources\$"; -my @source_files; -my $sources_count=0; -my $opt_debug; -my $opt_update; -my $opt_sudo; -my $opt_maintainer; -my $opt_mainonly; -my $opt_distribution; - -if (!(-x $dctrl)) { - die "$progname: Fatal error. grep-dctrl is not available.\nPlease install the 'dctrl-tools' package.\n"; -} - -sub version { - print <<"EOT"; -This is $progname $version, from the Debian devscripts package, v. ###VERSION### -This code is copyright by Patrick Schoenfeld, all rights reserved. -It comes with ABSOLUTELY NO WARRANTY. You are free to redistribute this code -under the terms of the GNU General Public License, version 2 or later. -EOT -exit (0); -} - -sub usage { - print <<"EOT"; -usage: $progname packagename - $progname --help - $progname --version - -Searches for all packages that build-depend on the specified package. - -Options: - -u, --update Run apt-get update before searching for build-depends. - (needs root privileges) - -s, --sudo Use sudo when running apt-get update - (has no effect when -u is omitted) - -d, --debug Enable the debug mode - -m, --print-maintainer Print the maintainer information (experimental) - --distribution distribution Select a distribution to search for build-depends - (Default: $default_distribution) - --only-main Ignore universe and multiverse - -EOT -version; -} - -sub findsources { - if (/$source_pattern/ and $sources_count <= 3) { - unless ($opt_mainonly and /(universe|multiverse)/) { - push(@source_files, $_); - $sources_count+=1; - print STDERR "DEBUG: Added source file: $_ (#$sources_count)\n" if ($opt_debug); - } - } -} - -sub findreversebuilddeps { - my ($package, $source_file) = @_; - my %packages; - my $depending_package; - my $count=0; - my $maintainer_info=''; - - open(PACKAGES, "$dctrl -F Build-Depends,Build-Depends-Indep $package -s Package,Build-Depends,Build-Depends-Indep,Maintainer $source_file|"); - - while() { - chomp; - print STDERR "$_\n" if ($opt_debug); - if (/Package: (.*)$/) { - $depending_package = $1; - $packages{$depending_package}->{'Build-Depends'} = 0; - } - - if (/Maintainer: (.*)$/) { - if ($depending_package) { - $packages{$depending_package}->{'Maintainer'} = $1; - } - } - - if (/Build-Depends: (.*)$/ or /Build-Depends-Indep: (.*)$/) { - if ($depending_package) { - print STDERR "$1\n" if ($opt_debug); - if ($1 =~ /^(.*\s)?$package([\s,]|$)/) { - $packages{$depending_package}->{'Build-Depends'} = 1; - } - } - - } - } - - while($depending_package = each(%packages)) { - if ($packages{$depending_package}->{'Build-Depends'} != 1) { - print STDERR "Ignoring package $depending_package because its not really build depending on $package.\n" if ($opt_debug); - next; - } - if ($opt_maintainer) { - $maintainer_info = "($packages{$depending_package}->{'Maintainer'})"; - } - - $count+=1; - print "$depending_package $maintainer_info \n"; - - } - - if ($count == 0) { - print "No reverse build-depends found for $package.\n\n" - } - else { - print "\nFound a total of $count reverse build-depend(s) for $package.\n\n"; - } -} - -if ($#ARGV < 0) { usage; exit(0); } - - -Getopt::Long::Configure('bundling'); -GetOptions( - "u|update" => \$opt_update, - "s|sudo" => \$opt_sudo, - "m|print-maintainer" => \$opt_maintainer, - "distribution=s" => \$opt_distribution, - "only-main" => \$opt_mainonly, - "d|debug" => \$opt_debug, - "h|help" => sub { usage; }, - "v|version" => sub { version; } -); - -my $package = shift; - -if (!$package) { - die "$progname: missing argument. expecting packagename\n"; -} - -print STDERR "DEBUG: Package => $package\n" if ($opt_debug); - -if ($opt_update) { - print STDERR "DEBUG: Updating apt-cache before search\n" if ($opt_debug); - my @cmd; - if ($opt_sudo) { - print STDERR "DEBUG: Using sudo to become root\n" if ($opt_debug); - push(@cmd, 'sudo'); - } - push(@cmd, 'apt-get', 'update'); - system @cmd; -} - -if ($opt_distribution) { - print STDERR "DEBUG: Setting distribution to $opt_distribution" if ($opt_debug); - $source_pattern = ".*_dists_" . $opt_distribution . "_.*Sources\$"; -} - -# Find sources files -find(\&findsources, $sources_path); - -if (($#source_files+1) <= 0) { - die "$progname: unable to find sources files.\nDid you forget to run apt-get update (or add --update to this command)?"; -} - -foreach my $source_file (@source_files) { - if ($source_file =~ /main/) { - print "Reverse Build-depends in main:\n"; - print "------------------------------\n\n"; - findreversebuilddeps($package, "$sources_path/$source_file"); - } - - if ($source_file =~ /universe/) { - print "Reverse Build-depends in universe:\n"; - print "---------------------------------\n\n"; - findreversebuilddeps($package, "$sources_path/$source_file"); - } - - if ($source_file =~ /multiverse/) { - print "Reverse Build-depends in multiverse:\n"; - print "----------------------------------\n\n"; - findreversebuilddeps($package, "$sources_path/$source_file"); - } -} - -=head1 LICENSE - -This code is copyright by Patrick Schoenfeld -, all rights reserved. -This program comes with ABSOLUTELEY NO WARRANTY. -You are free to redistribute this code under the terms of the -GNU General Public License, version 2 or later. - -=head1 AUTHOR - -Patrick Schoenfeld - -=cut diff --git a/reverse-depends b/reverse-depends new file mode 100755 index 0000000..a2ffd61 --- /dev/null +++ b/reverse-depends @@ -0,0 +1,65 @@ +#!/usr/bin/python +# +# Copyright (C) 2011, Stefano Rivera +# +# Permission to use, copy, modify, and/or 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. + +import optparse + +from distro_info import UbuntuDistroInfo + +from ubuntutools.rdepends import rdepends + +def main(): + parser = optparse.OptionParser('%progname [options] package') + parser.add_option('-r', '--release', metavar='RELEASE', + default=UbuntuDistroInfo().devel(), + help='Query dependencies in RELEASE. Default: devel') + parser.add_option('-R', '--without-recommends', + action='store_false', dest='recommends', default=True, + help='Only examine Depends relationships, ' + 'not Recommends.') + parser.add_option('-s', '--with-suggests', + action='store_true', dest='suggests', default=False, + help='Also consider Suggests relationships.') + parser.add_option('-b', '--build-depends', + action='store_const', dest='arch', const='source', + help='Query build dependencies (synonym for ' + '--arch=source') + parser.add_option('-a', '--arch', metavar='ARCH', default='i386', + help='Query dependencies in ARCH' + '(default: i386)') + parser.add_option('-u', '--service-url', metavar='URL', + dest='server', default=None, + help='Reverse Depedencies webservice URL' + '(default: UbuntuWire)') + + options, args = parser.parse_args() + + if len(args) != 1: + parser.error("One (and only one) package must be specified") + package = args[0] + + opts = { + 'recommends': options.recommends, + 'suggests': options.suggests, + } + if options.server is not None: + opts['server'] = options.server + + result = rdepends(package, options.release, options.arch, **opts) + result.sort() + print u'\n'.join(result) + +if __name__ == '__main__': + main() diff --git a/ubuntutools/rdepends.py b/ubuntutools/rdepends.py new file mode 100644 index 0000000..49e7f38 --- /dev/null +++ b/ubuntutools/rdepends.py @@ -0,0 +1,45 @@ +# Copyright (C) 2011, Stefano Rivera +# +# Permission to use, copy, modify, and/or 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. + +import json +import os +import urllib2 + + +def rdepends(package, release, arch, recommends=True, suggests=False, + server='http://qa.ubuntuwire.org/rdepends'): + """Look up a packages reverse-dependencies on the Ubuntuwire + Reverse- webservice + """ + url = os.path.join(server, 'v1', release, arch, package) + try: + data = json.load(urllib2.urlopen(url)) + except urllib2.HTTPError, e: + if e.code == 404: + return [] + raise + + if arch == 'source': + fields = ('Build-Depends', 'Build-Depends-Indep') + else: + fields = ['Depends'] + if recommends: + fields.append('Recommends') + if suggests: + fields.append('Suggests') + + result = set() + for field in fields: + result.update(data.get(field, [])) + return list(result) diff --git a/ubuntutools/test/test_rdepends.py b/ubuntutools/test/test_rdepends.py new file mode 100644 index 0000000..52d09b5 --- /dev/null +++ b/ubuntutools/test/test_rdepends.py @@ -0,0 +1,98 @@ +# test_rdepends.py - Test suite for ubuntutools.rdepends +# +# Copyright (C) 2011, Stefano Rivera +# +# Permission to use, copy, modify, and/or 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. + +import BaseHTTPServer +import SocketServer +import re +import threading + +from ubuntutools.rdepends import rdepends +from ubuntutools.test import unittest + +responses = { + '/v1/precise/source/python-beautifulsoup': + """{"Build-Depends-Indep": ["episoder"], + "Build-Depends": ["pyth", "wikkid", "calibre", "ibid", + "linaro-image-tools"]}""", + '/v1/precise/i386/python-beautifulsoup': + """{"Suggests": ["python-formalchemy", "python-pysolr", "chm2pdf", + "foxtrotgps", "python-html5lib"], + "Depends": ["python-btsutils", "python-pyth", "nagstamon", + "python-deliciousapi", "ibid", "python-freevo", "anki", + "archmage", "calibre", "creepy", "w3af-console", + "screenlets", "episoder", "uicilibris", + "totem-plugins-extra", "python-nodebox-web", "wikkid", + "python-bzutils", "wxbanker", "linaro-image-tools"], + "Recommends": ["sugar-read-activity-0.84", "webcheck", + "sugar-read-activity-0.86", "python-webtest", + "planet-venus"]}""", +} + +class FakeServer(BaseHTTPServer.BaseHTTPRequestHandler): + def do_GET(self): + if self.path in responses: + self.send_response(200) + self.end_headers() + self.wfile.write(responses[self.path]) + else: + self.send_response(404) + self.end_headers() + +class RdependsTestCase(unittest.TestCase): + def setUp(self): + self.fake_server = SocketServer.TCPServer(("127.0.0.1", 0), FakeServer) + self.fake_server.server_activate() + self.server_url = ('http://127.0.0.1:%i' + % self.fake_server.server_address[1]) + + self.server_thread = threading.Thread( + target=self.fake_server.serve_forever) + self.server_thread.start() + + def tearDown(self): + self.fake_server.shutdown() + + def test_source(self): + result = rdepends('python-beautifulsoup', 'precise', 'source', + server=self.server_url) + self.assertIn('ibid', result) + self.assertIn('episoder', result) + + def test_depends(self): + result = rdepends('python-beautifulsoup', 'precise', 'i386', + recommends=False, server=self.server_url) + self.assertIn('ibid', result) + self.assertNotIn('webcheck', result) + self.assertNotIn('chm2pdf', result) + + def test_recommends(self): + result = rdepends('python-beautifulsoup', 'precise', 'i386', + server=self.server_url) + self.assertIn('ibid', result) + self.assertIn('webcheck', result) + self.assertNotIn('chm2pdf', result) + + def test_suggests(self): + result = rdepends('python-beautifulsoup', 'precise', 'i386', + suggests=True, server=self.server_url) + self.assertIn('ibid', result) + self.assertIn('webcheck', result) + self.assertIn('chm2pdf', result) + + def test_empty(self): + result = rdepends('ibid', 'precise', 'source', + suggests=True, server=self.server_url) + self.assertEqual(result, [])