wajig/0000755000000000000000000000000012266756533007064 5ustar wajig/bash-completion0000644000000000000000000001170112252405302012047 0ustar have grep-status && { _comp_dpkg_installed_packages() { grep-status -P -e "^$1" -a -FStatus 'install ok installed' -n -s Package } } || { _comp_dpkg_installed_packages() { command grep -A 1 "Package: $1" /var/lib/dpkg/status | \ command grep -B 1 -Ee "ok installed|half-installed|unpacked| \ half-configured" \ -Ee "^Essential: yes" | \ command grep "Package: $1" | cut -d\ -f2 } } have grep-status && { _comp_dpkg_hold_packages() { grep-status -P -e "^$1" -a -FStatus 'hold' -n -s Package } } || { _comp_dpkg_hold_packages() { command grep -B 2 'hold' /var/lib/dpkg/status | \ command grep "Package: $1" | cut -d\ -f2 } } have wajig && _wajig() { local cur dashoptions prev special i COMPREPLY=() _get_comp_words_by_ref cur prev dashoptions='-h --help -V --version' for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do if [[ ${COMP_WORDS[i]} == \ @(addcdrom|addrepo|aptlog|auto-alts|auto-clean|auto-download|autoremove|build| build-deps|changelog|clean|contents|daily-upgrade|dependents|describe| describe-new|details|dist-upgrade|download|editsources|extract| fix-configure|fix-install|fix-missing|force|hold|info|init|install| install-suggested|integrity|large|lastupdate|list-alternatives| list-cache|list-commands|list-daemons|list-files|list-hold|list-installed| list-log|list-names|list-packages|list-scripts|list-section|list-sections| list-status|madison|move|new|new-detail|news|new-upgrades|nonfree| orphans|policy|purge|purge-orphans|purge-removed|rbuilddeps|readme| rec-download|recommended|reconfigure|reinstall|reload|remove| remove-orphans|repackage|reportbug|restart|rpm2deb|rpminstall| search|searchapt|show|sizes|snapshot|source|start|status|status-match| stop|tasksel|todo|toupgrade|tutorial|unhold|unofficial| update|update-alternatives|update-pci-ids|update-usb-ids|upgrade| upgrade-security|verify|versions|which-package) ]]; then special=${COMP_WORDS[i]} fi done if [[ -n "$special" ]]; then case $special in install|distupgrade|download|show|changelog|builddeps|dependents|describe|details|policy|recdownload) COMPREPLY=( $( apt-cache pkgnames $cur 2> /dev/null ) ) if [[ "$special" == "install" ]]; then _filedir fi return 0 ;; purge|remove|reinstall|listinstalled|hold|news|readme|recommended|reconfigure|reload|repackage|*start|status|stop|todo|verify) COMPREPLY=( $( _comp_dpkg_installed_packages "$cur" ) ) return 0 ;; unhold) COMPREPLY=( $( _comp_dpkg_hold_packages "$cur" ) ) return 0 ;; contents|extract|info|rpm2deb|rpminstall) _filedir ;; esac fi case $prev in # don't complete anything if these options are found autoclean|clean|search|upgrade|update) return 0 ;; -S) _filedir return 0 ;; esac if [[ "$cur" == -* ]]; then COMPREPLY=( $( compgen -W "$dashoptions" -- "$cur" ) ) elif [[ -z "$special" ]]; then commands=(addcdrom addrepo aptlog auto-alts auto-clean auto-download auto-remove build build-deps changelog clean contents daily-upgrade dependents describe describe-new details dist-upgrade download editsources extract fix-configure fix-install fix-missing force hold info init install install-suggested integrity large lastupdate list-alternatives list-cache list-commands list-daemons list-files list-hold list-installed list-log list-names list-packages list-scripts list-section list-sections list-status madison move new new-detail news new-upgrades nonfree orphans policy purge purge-orphans purge-removed rbuilddeps readme rec-download recommended reconfigure reinstall reload remove remove-orphans repackage reportbug restart rpm2deb rpminstall search searchapt show sizes snapshot source start status status-match stop tasksel todo toupgrade tutorial unhold unofficial update update-alternatives update-pci-ids update-usb-ids upgrade upgrade-security verify versions which-package) local option oldNoCaseMatch=$(shopt -p nocasematch) shopt -s nocasematch COMPREPLY=( $( for command in "${commands[@]}"; do [[ ${command:0:${#cur}} == "$cur" ]] && printf '%s\n' $command done ) ) eval "$oldNoCaseMatch" 2> /dev/null fi return 0 } complete -F _wajig wajig # Local variables: # mode: shell-script # sh-basic-offset: 4 # sh-indent-comment: t # indent-tabs-mode: nil # End: # ex: ts=4 sw=4 et filetype=sh wajig/debian/0000755000000000000000000000000012266756664010313 5ustar wajig/debian/wajig.docs0000644000000000000000000000002412253101611012226 0ustar README.rst TUTORIAL wajig/debian/copyright0000644000000000000000000000210112252405302012207 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: wajig Source: https://bitbucket.org/tshepang/wajig/src Files: * Copyright: Copyright 2001-2013 Graham J Williams License: GPL-2+ 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 package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. wajig/debian/rules0000755000000000000000000000010012252406736011345 0ustar #!/usr/bin/make -f # -*- makefile -*- %: dh $@ --with python3 wajig/debian/control0000644000000000000000000000232312252406762011700 0ustar Source: wajig Maintainer: Graham Williams Uploaders: Tshepang Lekhonkhobe Section: admin Priority: optional Build-Depends: debhelper (>= 9), dh-python, python3, python3-apt X-Python3-Version: >= 3.3 Standards-Version: 3.9.5 Vcs-Browser: https://bitbucket.org/tshepang/wajig/src Vcs-Hg: https://bitbucket.org/tshepang/wajig Homepage: http://wajig.togaware.com Package: wajig Architecture: all Depends: ${misc:Depends}, ${python3:Depends}, apt, python3-apt (>= 0.8.9), aptitude, dpkg (>= 1.16.2) Suggests: debconf, reportbug, apt-move, dpkg-repack, alien, fakeroot, apt-file, locales, deborphan, vrms, sudo, apt-show-versions, dctrl-tools, debsums, netselect-apt, dpkg-dev, debtags Description: unified package management front-end for Debian A command-line wrapper around apt, apt-cache, dpkg, aptitude, and more. It's goal is to ease package management by unifying the main functions of these tools from one interface. . For a short guide, run this command: $ wajig help wajig/debian/dirs0000644000000000000000000000005612155054044011154 0ustar usr/bin usr/share/wajig etc/bash_completion.d wajig/debian/compat0000644000000000000000000000000212155054044011465 0ustar 9 wajig/debian/changelog0000644000000000000000000016341612266755367012177 0ustar wajig (2.13) unstable; urgency=medium * Remove unit tests... only had 5 tests, and the code isn't really ready for it without 'too' much effort; Closes: #735821 -- Tshepang Lekhonkhobe Sun, 19 Jan 2014 15:59:53 +0200 wajig (2.12) unstable; urgency=low * bump Standards-Version to 3.9.5: no changes needed * README: also read /usr/share/doc//README.rst files * modernise packaging... use dh-python; work done by Sergey Romanov * LIST-SCRIPTS: fix Py3k conversion error; no one saw/reported this since it was introduced in version 2.2, until Sergey Romanov, who also submitted a fix -- Tshepang Lekhonkhobe Sat, 14 Dec 2013 19:11:33 +0200 wajig (2.11) unstable; urgency=low * UPGRADE: Use the new --with-new-pkgs option of 'apt-get upgrade' * EDITSOURCES: Select $VISUAL or $EDITOR (in that order of preference) if defined, else use 'sensible-editor'; Closes: #729585 -- Tshepang Lekhonkhobe Mon, 02 Dec 2013 22:23:31 +0200 wajig (2.10) unstable; urgency=low * LIST-COMMANDS: accept an optional argument to filter the output; this is equivalent to 'wajig list-commands | grep ' -- Tshepang Lekhonkhobe Sun, 13 Oct 2013 08:21:30 +0200 wajig (2.9) unstable; urgency=low * bump Standards-Version to 3.9.4: no changes needed * minimum version for python-apt is now 0.8.9+, due to python3.3 support * restore dashes in subcommands in bash completion; suggestion and initial patch by Reuben Thomas * LIST-LOG: restore wajig log; Karl Schmidt insisted very strongly * LIST-COMMANDS: make it one-line per command as it was before; Karl insisted strongly on this one too -- Tshepang Lekhonkhobe Sun, 11 Aug 2013 00:10:06 +0200 wajig (2.8) unstable; urgency=low * UPDATE: fix performance issue (patch by Robert Luberda); Closes: #705241 * improve package description: - simpler - less boastful - add a pointer to a guide - tis 'wajig', not 'Wajig' * SEARCH: - make -v|--verbose match short package descriptions in addition to package names - add -vv, which also searches long package descriptions and displays them; the former was available as -v, and the latter is new; this functionality was suggested by Reuben Thomas - add debtags search; this happens if the string '::' is in the search term * SEARCH, INSTALL: fix weird bugs where package '0ad' could not be searched for or installed; LP #1182264 * update TUTORIAL to reflect that allowing any case for commands has since been removed; LP #1033536 * PURGEORPHANS, REMOVEORPHANS: - remove --teach option + it would need to be too complex in order to be accurate since it runs 2 commands, the second one using output of the first + this also gets rid of an ugly (and broken) workaround * PURGEORPHANS: remove --noauth option; it doesn't make sense here * REMOVEORPHANS: add --yes option, for consistency with PURGEORPHANS * replace internal function with a more thorough stdlib shutil.which() for checking if a particular executable exists; this bumps minimum Python dependency to 3.3 * LISTLOG: add APTLOG as synonym, in place of an erroneously-added SYSLOG -- Tshepang Lekhonkhobe Tue, 28 May 2013 14:35:05 +0200 wajig (2.7.3) unstable; urgency=low * NEWUPGRADES: a bug introduced in 2.5 made this subcommand illegal; Closes: #681309 * STATUSSEARCH: same case as above -- Tshepang Lekhonkhobe Thu, 12 Jul 2012 12:11:46 +0200 wajig (2.7.2) unstable; urgency=low * For some reason, some temp/build files ended up in the source package :( Thanks to RM, Adam D. Barratt, for noticing. -- Tshepang Lekhonkhobe Tue, 03 Jul 2012 21:03:25 +0200 wajig (2.7.1) unstable; urgency=low * NEW, NEWDESCRIBE: fix an exception that occurs if package exists only for configured foreign architectures; Closes: #679969 * DESCRIBE: if package does not exist for native architecture, check if it does for configured foreign ones before giving up; this is closely related to the above-mentioned fix * Specify a minimum dpkg version (1.16.2), due to the use of --print-foreign-architectures option introduced as a result of the above-mentioned fixes -- Tshepang Lekhonkhobe Mon, 02 Jul 2012 21:04:43 +0200 wajig (2.7) unstable; urgency=low * NEW, DETAILNEW, and DESCRIBENEW: - make them do as the commands imply; Closes: #670687 - do not quit if a package is not found in APT cache; Closes: #667068 -- Tshepang Lekhonkhobe Tue, 19 Jun 2012 04:31:23 +0200 wajig (2.6.1) unstable; urgency=low * DISTUPGRADE: fix an exception triggered by specifying the --dist option -- Tshepang Lekhonkhobe Sat, 16 Jun 2012 07:43:15 +0200 wajig (2.6) unstable; urgency=low * stop converting COMMANDS to uppercase... be like everyone else * polish bash auto-completion, by only auto-completing: - names of installed packages where no other name makes sense - names of all packages where no other name makes sense - names of files/directories where no other name makes sense for every other COMMAND, do not auto-complete at all (Reuben Thomas helped with this one) -- Tshepang Lekhonkhobe Wed, 23 May 2012 22:19:10 +0200 wajig (2.5.1) unstable; urgency=low * make licence DEP-5 compliant * DEPENDENTS: fix an exception that occurs when the sources.list only has Wheezy in it. -- Tshepang Lekhonkhobe Fri, 20 Apr 2012 14:05:30 +0200 wajig (2.5) unstable; urgency=low IMPROVEMENTS * improve bash completion, thanks again to Reuben Thomas; Closes: #597721 * avoid displaying a stack trace when quitting an operation (Ctrl+C) * the --simulate and --teaching options now display the commands in bold; they now also have consistent spacing (single space) between non-whitespace characters * REMOVEORPHANS, PURGEORPHANS: for the sake of consistency with REMOVE and PURGE subcommands, use the --auto-remove option of apt-get; Closes: #444150 * INSTALL, INSTALLSUGGESTED, NEWUPGRADES, AUTODOWNLOAD: use --auto-remove option. Seems a more sane way to have that as default, and leads to a less-surprising REMOVE/PURGE experience (whereby it would remove packages that are not related to packages being removed). * INSTALL: when installing using the url method, do keep the downloaded file; it will be found in "~/.wajig/$HOSTNAME/" BUGS FIXED * INSTALLSUGGESTED: don't fail when one of the Suggested dependencies is a virtual package, but instead install one the Providers of that virtual package. * {REMOVE,PURGE}ORPHANS: fix exception that happened with --simulate option * AUTODOWNLOAD, TOUPGRADE, NEWDETAIL: fix an exception that occurs when ~/.wajig dir is removed * fix 'displays incorrect new and upgradeable package count'; patch by Graeme Hewson; LP #892410 * fix '"wajig status" gives warning message about stdin not sorted'; patch by Graeme Hewson; LP #978172 RESTORED FUNCTIONALITY (Closes: #667856) * LISTALL: this was mistakenly removed, so restore it * LIST{CACHE,NAMES,PACKAGES,STATUS,INSTALLED}: restore ability to filter on a pattern; some people complained about the removal of the feature (in 2.3) * TOUPGRADE: sort the list, again * restore ability to have multiple-word commands to be separated with dashes, e.g. an alias for LISTINSTALLED is LIST-INSTALLED MISC * remove the (Suggests) dependencies on fping and wget; Python stdlib is capable enough * README: improve setup instructions, thanking Graeme Hewson (from LP #892410) * NEWUPGRADES: doesn't seem to provide much more than TOUGPRADE, so alias it * AUTODOWNLOAD, NEW: get rid of --install option; it's overkill * PURGEREMOVE: remove --teaching and --simulate options; they display incomplete output * UNOFFICIAL: simply open the search results page with a web browser instead of scanning it and displaying suitable lines for "/etc/apt/sources.list"; that feature was broken (and nobody complained) -- Tshepang Lekhonkhobe Wed, 11 Apr 2012 13:52:52 +0200 wajig (2.4.1) unstable; urgency=low * 2.4 made an assumption that a user that isn't in 'sudo' group is not a sudoer. That's not the case (and it's a bad assumption). -- Tshepang Lekhonkhobe Tue, 27 Mar 2012 16:07:31 +0200 wajig (2.4) unstable; urgency=low * README, TODO, NEWS: if doc path (/usr/share/doc/) for a given package isn't found, check if such a package even exists. * INSTALL, INSTALLSUGGESTED: make --recommends and --norecommends options conflict. * INSTALL: one can now specify a mixture of installables: * deb files * url files * normal packages Previously, only one of these types could be installed at a time * make bash completer also complete lower-case COMMANDS; patch by "Reuben Thomas" * Reinstate --simulate and --teaching options: - the --simulate option implies that the epilogs of the --help option are now redundant so they are now removed. All they did was state what commands would be ran. - the --teaching option is renamed to --teach (for sake of consistency) - Closes: #665729 * LOCALUPGRADE remove: - [ole] wajig LOCALUPGRADE - [new] wajig UPGRADE --local * LOCALDISTUPGRADE remove: - [ole] wajig LOCALDISTUPGRADE - [new] wajig DISTUPGRADE --local * Fix an (embarassing) exception; Closes: #665887 -- Tshepang Lekhonkhobe Tue, 27 Mar 2012 12:51:44 +0200 wajig (2.3) unstable; urgency=low NEW * TODO: new command that reads package TODO files UI CHANGES * Optional arguments should be available only to COMMANDS that use them: - [ole] wajig --verbose install - [new] wajig install --verbose * FILEINSTALL: removed in favor of INSTALL option, -f|--fileinput: - [ole] wajig FILEINSTALL - [new] wajig INSTALL --fileinput Note that with this new option, one can specify multiple files and packages on the command line. * FILEREMOVE: applies to REMOVE as FILEINSTALL applies to INSTALL (see above) * FILEDOWNLOAD: applies to DOWNLOAD as... (see above) * PURGE: for sake of consistency, give this -f|--fileinput option too * REMOVE, PURGE: add --noauth option, to avoid cases where a package would be downloaded when there's an unauthenticated version available; this happens in a case where removing/purging a package leaves a void where APT want to be smart/convenient, and install a replacement. * Improve usability by limiting verbosity to either True or False. * Rename LISTRECOMMENDED --> RECOMMENDED * Remove the sanitation of wajig COMMANS, e.g. where 'LISTcommands', 'list-commands', and 'li-st_COMMA-nds' would be translated to 'listcommands'; it's too much magic (and too much work to get it to work with argparse) * LISTCACHE: remove ability to filter output; user can always run grep themselves * LISTNAMES: also remove filtering ability * LISTPACKAGES: also remove filtering ability * LISTSTATUS: also remove filtering ability * LISTINSTALLED: also remove filtering ability * NEW: 'wajig new --install' replaces the less elegant 'wajig new install' * NEWUPGRADES: 'wajig NEWUPGRADES --install' replaces the less elegant 'wajig NEWUPGRADES install' * RELOAD: if this fails, try FORCE-RELOAD DOC CHANGES: * DOWNLOAD: improve description. (Closes: #627173) * DESCRIBE: Last character in short description missing; LP: #923041 * DEPENDENTS: improve output REMOVED * The "--pager" option is really excess, considering that user can simply do "wajig COMMAND | pager" by herself * The "--pause" option was only useful for gjig (IIRC) to avoid windows from closing up automatically, in order to allow one to read the output; this was only applicable when wajig used to have a GUI, gjig * All "--quiet" option did was redirect output to /dev/null; when the option is used, if there is, for example, a Yes/No prompt, it won't be seen and it will appear like wajig is stuck; user can easily do own redirection (wajig COMMAND > /dev/null), so let's reduce the bloat - this change accidentally fixed an exception; Closes: #661269 * Ability to specify backup directory; requires too much work in order to make it work with argparse * Me wonders if the mini-tutorial was useful to anyone * The "--simulate" and "--teaching" options: - they don't apply to a lot wajig commands - they display ugly output - I doubt if anyone will miss them * SETUP: it's an alias of EDITSOURCES and it appears that it was added since it was the name of a long-removed Debian tool, 'apt-setup' * LISTWIDE: it's basically the same as LIST command * LISTALL: it's exactly the same as LIST command (future note: not true) * VERSION: it's already provided by 'wajig --version' * a file named COMMANDS: the content is now generated dynamically * AUTOINSTALL: - [ole] wajig AUTOINSTALL - [ole] wajig INSTALL --yes * INSTALLWITHDIST: * [ole] wajig INSTALLWITHDIST/ * [new] wajig INSTALL --dist * FILE{INSTALL,REMOVE,DOWNLOAD}: see UI CHANGES section * SHOWDISTUPGRADE: all it does is simulate DISTUPGRADE * SHOWUPGRADE: all it does is simulate UPGRADE * SHOWINSTALL: all it does is simulate INSTALL * SHOWREMOVE: all it does is simulate REMOVE BUGS FIXED * INSTALLS/SUGGESTS: specifying multiple packages was broken, and too much so work to fix, so limit to just one * LIST-SCRIPTS: fix brokenness which was a result of porting to Py3k. * MADISON: get rid of duplicates from output, if any. * RECONFIGURE: remove dependency on gkdebconf; the implementation was so broken that gkdebconf never got invoked * Don't run "su -c" when root (patch by Francesco Poli); Closes: #664231 MISC * Bump minimum required Python version to 3.2 due to new dependency on argparse (which replaces the less featureful getopt) * Update to debhelper compat level 9 * Fix some lintian warnings -- Tshepang Lekhonkhobe Thu, 22 Mar 2012 22:21:45 +0200 wajig (2.2) unstable; urgency=low * port to Python 3 (Closes: #600059, by making it irrelevant) * AVAILABLE: add back to bash auto completion * WHICHPACKAGE: use apt-file and dpkg instead of custom implementation to search for package content * local implementation could not use path as search term if package is not installed * it could also not work offline if the package is not installed Closes: #422500, LP: #141520 * INSTALL: when installing a DEB file, install its dependencies too * UPDATE: rm dependency on dselect; use apt-get instead -- Tshepang Lekhonkhobe Mon, 09 May 2011 22:06:02 +0200 wajig (2.1) unstable; urgency=low [ Tshepang Lekhonkhobe ] * Change versioning from 3 digits to 2. There wasn't much meaning there. * Remove gjig; it was more an experiment than a serious app, and: - more complete alternatives exist (e.g. synaptic and software-center) - UI is cranky and weird * Remove deps that were needed by gjig: - python-gtk2, python-glade2, python-gnome2, and gnome-terminal * INSTALLR, INSTALLRS: 'apt-get install' now installs Recommends by default, making these options redundant. * INSTALL, INSTALLS: add -r|--recommends and -R|--norecommends options. * INSTALLS: add -n|--noauth and -y|--yes options. * Add meself to Uploaders field in debian/control. * CHANGELOG: change -x to -P; it's a more meaningful short option for --pager * POLICY: more than one person has complained about removal of the alias of this command, AVAILABLE; I put it back. * SHOW: add -f|--fast to offer apt-cache's much faster implementation * INSTALL/DIST: fix brokenness, fixes LP: #540740. * SOURCE: don't run the command unless 'dpkg-dev' is installed, fixes LP: #662018 * BUILD, BUILDDEP: add -y|--yes and -n|--noauth options. * AUTOREMOVE: add back after more than one request. (Closes: #590089) * Add --dist, an alias for apt-get -t|--target-release. * Slightly simplify the build: getting rid of dynamic bash completion generator. * Fix a Lintian complaint (add dependency on python). -- Tshepang Lekhonkhobe Wed, 27 Apr 2011 12:13:21 +0200 wajig (2.0.50.1) unstable; urgency=low * Fix (an embarassing) exception exposed by LIST-COMMANDS, DOCUMENTATION, ... -- Tshepang Lekhonkhobe Wed, 13 Oct 2010 16:15:59 +0200 wajig (2.0.50) unstable; urgency=low [ Tshepang Lekhonkhobe ] * VERIFY: Add a check for debsums before running the command, and add a Suggests on it. * PURGE: use apt-get instead of dpkg, in order to get a yes/no prompt. * LIST-LOG: Remove custom logging implementation - was fragile: sometimes info was lost during a run - was expensive: checked system cache both before and after the operation to determine what happened; it also did this for commands which didn't even change the system cache - did not log cache changes when they were done by other tools (apt, aptitude, & synaptic) - APT log looks much better * SHOW: use aptitude instead of apt-cache - the output is prettier - better virtual package handling; it displays real packages that provide the functionality implied by that virtual package, instead of just vomiting "package not found!" - only displays info on the installed version; else, the latest available; apt-get showed all available versions - the trade-off is that the command is slower, but what's the rush :) * LIST-RECOMMENDED: new command that displays packages which are auto-installed via Recommends, and are without installed dependencies. (Closes: #482147) * PURGE: also purge packages that were installed via a Recommends and have nothing depending on them; this makes PURGE-DEPEND reduntant. * REMOVE: also remove packages that were installed via a Recommends and have nothing depending on them; this makes REMOVE-DEPEND reduntant. * AUTO-REMOVE: Made reduntant by above REMOVE change, so removed. * AUTO-INSTALL: Deprecated in favour of "--yes INSTALL", so removed from docs. * NEWS: 'new' command that displays package NEWS file(s). * AVAILABLE: removed a badly-named and redundant command; POLICY command does the same thing. * INSTALL: accept -y|--yes option, an alias for apt-get's --assume-yes. * UPGRADE: accept -y|--yes option, too. * FIX-INSTALL: accept -n|--noauth option. * FIX-MISSING: accept -n|--noauth option, too. * REINSTALL: accept -n|--noauth and -y|--yes option. * HELP: introduce the convenient "wajig HELP COMMAND" functionality. * Remove supression of error messages; Not a good idea. * Add dependency on aptitude; It must have been forgotten. * Cleanse packaging, drastically :-) * Stop using python-support; There was no need for it. -- Graham Williams Wed, 16 Sep 2010 17:22:16 +1000 wajig (2.0.49) unstable; urgency=low [ Tshepang Lekhonkhobe ] * UPGRADE: Don't automatically do an "apt-get update" with the backup option; the behaviour is not standard, and is not so-damn-fast. * UPGRADE: Add command line argument for --backup to specify target directory. * Was "wajig --backup upgrade BKDIR". * Now is "wajig --backup=BKDIR upgrade". * UPGRADE: Proceed to upgrade after using -b|--backup option. * UPGRADE: Remove the option to install listed packages. This helps reduce code complexity. * CHANGELOG: Now only displays uninstalled entries by default. This makes the hacky NEWS command redundant, which is therefore removed. (Closes: #424668). * CHANGELOG: Add -v|--verbose=1 option to display the whole thing. This was the default option, but suggestion offered in #424668 is more sane. * CHANGELOG: Add -x|--pager option to allow scrolling. This also implies -v|--verbose=1 (see above). * DIST-UPGRADE: Add -b|--backup=BKDIR option to allow backing up of packages before dist-upgrade. * BUILD: Now uses sudo instead of fakeroot to avoid permission-related. build failures for some packages (EG, fakeroot & cdbs). (Closes: #464003). * Fix a parsing bug where "wajig changelog libgtk2.0-0" didn't work. * Switch to dpkg-source 3.0 (native) format * RBUILDDEPS: New option allowing one to determine which packages build-depends on a particular package. The long form command is "reverse-build-depends", else just use "wajig rbuilddeps pkgname". (Closes: #335240). * SEARCH: Make apt-cache's "--names-only" default. Use "-v" option to get old behaviour. -- Graham Williams Wed, 15 Sep 2010 17:22:16 +1000 wajig (2.0.48) unstable; urgency=low [ Tshepang Lekhonkhobe ] * ADDEPO: new command USED to add a Launchpad PPA. Uses add-apt-repository. * UPGRADE: Add -b (backup) option so it is easier to revert to a previous state if problems arises. Uses dpkg-repack. * Cleanups: debian meta data, code, remove deprecated usage of 'string' module, and improve readability. * Add unit-testing. * Show downgraded packages in 'wajig list-log'. (Closes: #366796). * Remove the unavailable gnome-tasksel from Suggested. (Closes: #549574). [ Graham Williams ] * Tidy up the list of commands from the "list-commands" command. (Closes: #582252). -- Graham Williams Tue, 24 Aug 2010 20:53:48 +1000 wajig (2.0.47) unstable; urgency=low * Use apt-get remove --auto-remove to implement remove-depend. This is simpler than making wajig do the dependency checking, and runs much faster. (Closes: #579419). -- Graham Williams Wed, 19 May 2010 20:16:10 +1000 wajig (2.0.46) unstable; urgency=low * Change installr to use aptitude -r so that we get recursive install of recommended packages. (Closes: #477921). * Patch from Julian Klode and Dirk Eddelbuettel for new API - apply patches but no longer works on Ubuntu - assume works on Debian. (Closes: #571766). -- Graham Williams Wed, 17 Mar 2010 06:27:07 +1100 wajig (2.0.45) unstable; urgency=low * Update web search interface call for whichpkg and remove extraneous link information from the call to lynx - Bernat Arlandis i Mañó. (Closes: #565666). -- Grham Williams Mon, 18 Jan 2010 09:08:41 +1100 wajig (2.0.44) unstable; urgency=low * the describe/detail commands should handle installed but no longer available packages - Reuben Thomas. (Closes: #432266) * ensure all old tmp files removed - Robert Luberda. (Closes: #563573) -- Graham Williams Mon, 4 Jan 2010 08:30:43 +1100 wajig (2.0.43) unstable; urgency=low * revert untested code from Reuben Thomas causing issues with "new" -- Graham Williams Mon, 1 May 2009 11:46:27 +1000 wajig (2.0.42) unstable; urgency=low * update purgeremoved as suggested by Reuben Thomas. (Closes: #477921) * some debian control updates provided by Dirk. -- Graham Williams Mon, 30 Apr 2009 07:44:46 +0700 wajig (2.0.41) unstable; urgency=low * Allow commas in list of packages so can copy from other programs * Ensure join uses langC=True - new coretuils join complains otherwise. -- Graham Williams Mon, 25 Apr 2009 08:46:45 +1100 wajig (2.0.40) unstable; urgency=low * Add noauth to autoinstall reported by Leslie Viljoen. (Closes: #506795) * Allow commas in list of packages so can copy from other programs -- Graham Williams Mon, 30 Nov 2008 17:27:23 +1000 wajig (2.0.39) unstable; urgency=low * Add purge-removed command requested by Reuben Thomas. (Closes: #477921) -- Graham Williams Mon, 2 Jun 2008 05:41:50 +1000 wajig (2.0.38) unstable; urgency=low * Don't use invoke-rc.d as this is really meant for package maintainers, not interactive user usage, and there are cases where it won't work. Bug reported by William Xu. (Closes: #426969) * Ensure auto-remove is in the auto completion list. Reported by Reuben Thomas. (Closes: #445713) * Fix problem with change of HTML format for WHICH-PKG query. Bug reported by Alex Malinovich and David Liontooth. (Closes: #443593 #442169) * Add INFO, CONTENTS, and EXTRACT commands to run dpkg --info, dpkg --contents, and dpkg --extract to list info or contents or to extract the contents of a package file. * For LISTFILES support the listing of the contents of a .deb file. (Suggested by Roland.Baudin). * Fix documentation pointing to sarovar. (Closes: #442168) -- Graham Williams Thu, 4 Nov 2007 16:41:11 +1100 wajig (2.0.37) unstable; urgency=low * Add AUTO-REMOVE command to run apt-get autoremove, to remove any packages that were automatically installed through dependencies, and are no longer required. (Closes: #430457) -- Graham Williams Sun, 1 Jul 2007 17:50:35 +1000 wajig (2.0.36) unstable; urgency=high * Fix grave bug on moving to using pycentral - needed XS-Python-Version and XB-Python-Version, otherwise pycentral is crashing. Reported by Laurent Bonnaud and Anthony Campbell. If you get an error like package has no field Python-Version, then remove /var/lib/dpkg/info/wajig.prerm, and reinstall wajig. (Closes: #422596) -- Graham Williams Mon, 7 Mar 2007 22:06:10 +1000 wajig (2.0.35) unstable; urgency=low [Graham Williams] * LOCATE is a synonym for FIND-FILE (suggested by Alexandre Girao). * CHANGELOG query was not correctly stripping off version numbers. Bug reported by Reuben Thomas. (Closes: #385612) * VERIFY introduced to check the md5sums of an installed packages. Suggested by Francesco Potorti. (Closes: #386658) * Considered removing bash_completion.py. It is redundant, but does no harm. (Closes: #396698) * Replace depend on superseded base-config with locales. Suggested by Michael Gilbert. (Closes: #415378) * Depend on dselect because at least the update command depends on it. Suggested by Chris AtLee. (Closes: #415365) [Dirk Eddelbuettel] * debian/rules: Change dh_python to dh_pycentral * debian/control: Added Build-Depends-Indep: on 'python-central (>= 0.5)' -- Graham Williams Mon, 7 Mar 2007 06:44:28 +1000 wajig (2.0.34) unstable; urgency=low * Update to python 2.4 and new python policy. (Closes: #375591) -- Graham Williams Thu, 29 May 2006 18:11:34 +1000 wajig (2.0.33) unstable; urgency=low * MADISON command added to directly call apt-cache madison. Suggested by Dirk Eddelbuettel. * SHOW, DESCRIBE, LISTSECTIONS, LISTSECTION, DEPENDENTS, INSTALLS all stopped working with new version of Python apt_pkg which uses mmap for ParseTagFile and so could no longer handle pipes. Fixed by saving dumpavail output to temporary file. Bug reported by Anthony Campbell, with suggested fix using new apt from Michael Vogt. (Closes: #366678) -- Graham Williams Sun, 25 May 2006 08:56:11 +1000 wajig (2.0.32) unstable; urgency=low * EDITSOURCES now calls the editor rather than apt-setup because the latter is now in a udeb and not generally available. * Introduce the --noauth option, which for a DISTUPGRADE will use the --allow-unauthenticated option. This is particularly for the case where an archive you trust has no signed Release file, but you want that archive to supply packages ahead of those that are formally signed. E.g., a local package archive you maintain. The option applies to specific commands (not checked): INSTALL, DISTUPGRADE, UPGRADE. * NEWS has been fixed to extract latest changelog from the changelog archive since old news source has disappeared. * PURGE now using dpkg --purge rather than apt-get purge. The latter no longer works for removed packages. Reported by David Lionthooth (Closes: #362632) * CHANGELOG and NEWS updated to use the http://packages.debian.org/changelog:pkg as suggested by David Liontooth. (Closes: #364227) -- Graham Williams Sun, 23 Apr 2006 07:53:11 +1000 wajig (2.0.31) unstable; urgency=low * In BUILD two commands are run, but if first fails or is aborted then second was still being run. Fix it by test result. Bug reported by John V. Belmonte. (Closes: #337587) * bash_completion now works on multiple package name arguments. Bug reported by Kamaraju Kusumanchi. (Closes: #318048) * Add UPDATE-PCI-IDS and UPDATE-USB-IDS commands to call update-pciids and update-usbids, as suggested by Karl Schmidt. * The use of "+/-N" in tail is deprecated. Using "-n +/-N" instead. Bug reported by Yves-Alexis Perez. (Closes: #339010) -- Graham Williams Tue, 15 Nov 2005 06:48:22 +1000 wajig (2.0.30) unstable; urgency=low * In glutil.py (used by gjig) fix gnome __init__ call to pass args without names since the names seem to have changed. Also replace deprecated mainloop and mainquit with main and main_quit. * Extended the VERSION command and introduced VERSIONS as a near synonym to list the version available and the source distribution of the package. Suggested by John V. Belmonte. (Closes: #317584) * Introduce the --yes option to ask apt-get to assume yes to questions. Requested by Jason Lewis. * Do sudo -v before any sudo commands with pipes to avoid issues with pipes and multiple password requests. Bug reported by Karl Chen. (Closes: #320126) * Add extra information in documentation about NETSELECT-APT writing a candidate sources.list to the current directory, not to the system file. Reported by David Fedoruk. (Closes: #332822) * Revert behaviour of SOURCE to not do a BUILDDEPEND. Requested by John Belmonte. (Closes: #337588) * Ensure wajig.completions is updated each make. Reported by John V. Belmonte. (Closes: #330473) * debian/control: Standards-Version increased to 3.6.2 -- Graham Williams Sat, 5 Nov 2005 15:35:13 +1000 wajig (2.0.29) unstable; urgency=low * In query through wget to packages.debian.org replace + with %2B. Bug reported by John V. Belmonte. (Closes: #315082) -- Graham Williams Tue, 21 Jun 2005 21:05:25 +1000 wajig (2.0.28) unstable; urgency=low * Add new option to NEW and NEWUPGRADES to INSTALL the packages. Suggested by David Liontooth. (Closes: #314730) -- Graham Williams Sat, 18 Jun 2005 16:25:25 +1000 wajig (2.0.27) unstable; urgency=low * Allow DIST-UPGRADE to have an optional argument to identify a distribution to upgrade to. Suggested by August Mayer. (Closes: #311543) -- Graham Williams Thu, 2 Jun 2005 05:54:36 +1000 wajig (2.0.26) unstable; urgency=low * BUILD and SOURCE will also now call apt-get build-dep first to ensure dependent packages for the build are installed. * LIST-LOG takes an optional argument to filter the output on. * LIST-LOG filters output to make the reading of the timestamp more pleasant. (Closes: #304435) * DEPENDENTS output now indicates the dependency: d=depend, s=suggest, r=recommend, p=replaces, c=conflict, o=other. (Closes: #306221) * STATUS-SEARCH calls to perform.execute all use langC to avoid LOCALE problems with sort. (Closes: #302648) * LIST-SCRIPTS will display the contents of the package script files to the screen. Suggested by Jerry Quinn. (Closes: #306222) -- Graham Williams Wed, 27 Apr 2005 20:24:36 +1100 wajig (2.0.25) unstable; urgency=low * Extend LIST-ALL with optional argument to filter output on. Requested by Karl Schmidt. * Start implementing logging of install/remove/update. Suggested by Karl Schmidt (Closes: #297461). * New command LIST-LOG will simply list the contents of the log file. * LIST-WIDE removes extra space to list as compact as possible. Suggested by Karl Schmidt * PURGE-DEPEND now only checks installed packages. Suggested by Manuel Hernandez. -- Graham Williams Sat, 5 Mar 2005 06:51:36 +1100 wajig (2.0.24) unstable; urgency=low * Add DOC back into wajig. Suggested by Francesco Potorti. (Closes Bug#295806). * Use langC for grep when doing apt-cache dumpavail and count_upgrades since grep is very slow on other locales. Fix suggested by Reuben Thomas in relation to Bug#295022. (Closes: #295022). * Add LIST-SECTION(S) to the documentation. Reported by David Liontooth. (Closes: #295923). -- Graham Williams Sun, 20 Feb 2005 10:01:06 +1100 wajig (2.0.23) unstable; urgency=low * Change plurality of a message * Fix problem with CHANGLOG when the source package is not an installable package, as in libgtk2.0-dev and source gtk+2.0. Bug reported by Matthew Hawkins (Closes: #295455). -- Graham Williams Fri, 18 Feb 2005 18:17:37 +1100 wajig (2.0.22) unstable; urgency=low * New commands LISTSECTION and LISTSECTIONS. -- Graham Williams Sun, 6 Feb 2005 19:47:37 +1100 wajig (2.0.21) unstable; urgency=low * New upstream release - Exit with status 1 if LISTNAMES returns no results. Bug reported by A Costa (Closes: #292581). -- Graham Williams Tue, 1 Feb 2005 19:43:47 +1100 wajig (2.0.20-1) unstable; urgency=low * New maintainer (== upstream author), with the previous maintainer as sponsor * Regenerate Graham's debian package build. - Fix a locale problem where LC_ALL was being set to C by wajig for all external system calls. Only needed for STATUS? Bug reported by Serge Matveev (Closes: #288852). - Fix bug in getting username when USER not define, reported by Dirk Eddelbuettel - Fix typo reported by A Costa (Closes: #292456) - LISTALTS should ignore the README Reported by A Costa (Closes: #292457) - Fix change of DEPENDEES to DEPENDENTS Reported by A Costa (Closes: #292469) -- Graham Williams Sat, 29 Jan 2005 21:41:43 +1100 wajig (2.0.19-2) unstable; urgency=low * Applied two small fixes suggested by Graham to address issues when running as root (Closes: #290286): - src/perform.py: Use getpass.getuser() for root test - src/commands.py: Escape quotes in quietopt assignment - src/wajig.py: Idem in filter_str assignment -- Dirk Eddelbuettel Thu, 13 Jan 2005 06:25:43 -0600 wajig (2.0.19-1) unstable; urgency=low * New upstream release: - Fix problem when using sudo, and running wajig as root - if root was not in sudoers file then wajig could not run. root did not need to be in the sudoers file to run wajig - added a check for root running wajig and if so, don't use sudo if sudo is installed. Bug reported by Serge Matveev (Closes: #288849). - Fix bug with PURGE-ORPHANS whereby sudo was being doubly used and causing problems if root was not in sudoers. Bug reported by Serge Matveev (Closes: #288847) - Continue work on command interpreter completion. Only command complete the first "word" not all "words" in the command line. - REC-DOWNLOAD has been renamed RECURSIVE (but kept for compatibility) -- Dirk Eddelbuettel Fri, 7 Jan 2005 20:19:41 -0600 wajig (2.0.18-1) unstable; urgency=low * New upstream release: - Without any arguments wajig will start a command interpreter. The command interpreter accepts any wajig command, with completion. Suggested by Lorenzo Prince (Closes: #288041). -- Dirk Eddelbuettel Mon, 3 Jan 2005 06:24:04 -0600 wajig (2.0.17-1) unstable; urgency=low * New upstream release: - DETAILS now allows DEB files as arguments. Calls dpkg-deb --info. - CHANGELOG now tries harder to get most recent changelog. Rather than relying on http://changelogs.debian.net/, use http:// packages.debian.org/changelogs/pool/..../_/changelog. Delay in the updating of changelogs.debian.net links pointed out by Matthew Hawkins (and puts full closure on #286580). -- Dirk Eddelbuettel Wed, 29 Dec 2004 21:19:41 -0600 wajig (2.0.16-1) unstable; urgency=low * New upstream release: - Add new command SNAPSHOT which prints each package installed and its version number in the "package=version" format. Saving this to file will allow a Debian system to be restored to just this collection of packages at some later stage with the RESTORE command (yet to be implemented). Suggested by Dirk Eddelbuettel. - Update README command to report missing READMEs and missing doc directory. Suggested by Gintautas Miliauskas. - Remove remaining TABS from files to avoid mixing tabs and space. (Closes: #283335) -- Dirk Eddelbuettel Sun, 28 Nov 2004 15:07:14 -0600 wajig (2.0.15-1) unstable; urgency=low * New upstream release: - Move the main documentation out of wajig into the Survival Guide. - Improve README to show all documentation files found. - Add second argument completion for bash (Closes: #283307) -- Dirk Eddelbuettel Sat, 27 Nov 2004 22:34:05 -0600 wajig (2.0.14-1) unstable; urgency=low * New upstream release -- Dirk Eddelbuettel Wed, 17 Nov 2004 07:01:04 -0600 wajig (2.0.13-1) unstable; urgency=low * New upstream release with fixes for the three outstanding bugs: - Update documentation of DEPENDENTS (Closes: #280163) - Documentation updates from Gintautas Miliauskas (Closes: #280486) - HOLD/UNHOLD work when `sudo' is not installed (Closes: #280305) -- Dirk Eddelbuettel Sat, 13 Nov 2004 22:59:59 -0600 wajig (2.0.12-1) unstable; urgency=low * New upstream release with fixes for all outstanding bugs: - option to upgrade packages with the same version number (Closes: #253392) - wajig: download error (Closes: #271620) - wajig changelog wajig fails (Closes: #276862) - "wajig dependees" should be "wajig dependents" (Closes: #277186) -- Dirk Eddelbuettel Fri, 5 Nov 2004 23:15:50 -0600 wajig (2.0.11-4) unstable; urgency=low * The (hopefully) final revision, with special thanks to Matthias Klose for clarifications on the Python Policy in a series of helpful emails. * Partial reversal of some of the changes in the 2.0.11-{2,3} revisions: - debian/rules: Back to removing the .pyo/.pyc files generated by Make - debian/dirs: Remove usr/lib/wajig entry - {wajig.sh.in,gjig.sh.in}: Reverse change using /usr/lib/wajig - {wajig.sh.in,gjig.sh.in}: Add -O to Python call - debian/postrm: Remove as in Martin's patch as files are re-created * Also revert back to Architecture: all - debian/control: Updated accordingly - debian/rules: Switched back to using binary-independent section -- Dirk Eddelbuettel Sun, 17 Oct 2004 09:58:39 -0500 wajig (2.0.11-3) unstable; urgency=low * Bug fix upload to complement previous patch: - {wajig.sh.in,gjig.sh.in}: Need to override @datadir@ substitution; calling configure with --datadir=/usr/lib creates other problems -- Dirk Eddelbuettel Thu, 14 Oct 2004 21:22:39 -0500 wajig (2.0.11-2) unstable; urgency=low * Bug fix upload based on two patches provided by Martin F. Krafft: - src/wajig.py: Use invoke-rc.d, not /etc/init.d, (Closes: #276538) - debian/rules: Move python modules from /usr/share to /usr/lib to satisfy the Debian Python Policy (Closes: #276537) - debian/rules: Use dh_python - debian/rules: Use DESTDIR, not prefix - {Makefile.in, src/Makefile.in}: Use DESTDIR -- Dirk Eddelbuettel Thu, 14 Oct 2004 20:51:01 -0500 wajig (2.0.11-1) unstable; urgency=low * New upstream release: - the 'force' command now works if the package has not yet been downloaded (Closes: #252600) - the 'changelog' command handles source packages with different (but specified) version numbers. (Closes: #248549) * debian/control: Standards-Version increased to 3.6.1.1 -- Dirk Eddelbuettel Sun, 15 Aug 2004 21:41:34 -0500 wajig (2.0.10-1) unstable; urgency=low * New upstream release: - new commands listwide (Closes: #249091), liststatus, fileremove * debian/control: s/deborphans/deborphan/ (Closes: #247610) -- Dirk Eddelbuettel Mon, 24 May 2004 20:57:37 -0500 wajig (2.0.9-2) unstable; urgency=low * Makefile.in: Don't install bash_completion file (Closes: #247410) -- Dirk Eddelbuettel Tue, 4 May 2004 19:15:49 -0500 wajig (2.0.9-1) unstable; urgency=low * New upstream release: - reimplement status-match (Closes: #240359, #240403) - modified policy command (Closes: #246931) - see upstream changelog for more changes * debian/control: Added 'deborphans, vrms' to Suggests (Closes: #238313) -- Dirk Eddelbuettel Tue, 4 May 2004 06:54:27 -0500 wajig (2.0.7-1) unstable; urgency=low * New upstream release with new command tasksel, enhancements to hold/unhold commands, and updates to listcache and status (Closes: #235064) * debian/rules: Added gnome-tasksel to Suggests per Graham's suggestion -- Dirk Eddelbuettel Tue, 2 Mar 2004 22:00:17 -0600 wajig (2.0.6-3) unstable; urgency=low * debian/rules: Activate binary-arch which was still commented out from when this was an 'Architecture: all' package -- Dirk Eddelbuettel Mon, 23 Feb 2004 13:24:44 -0600 wajig (2.0.6-2) unstable; urgency=low * debian/control: Added python-dev to Build-Depends (Closes: #234372) -- Dirk Eddelbuettel Mon, 23 Feb 2004 09:58:08 -0600 wajig (2.0.6-1) unstable; urgency=low * New upstream version released today * debian/control: Added 'base-config' to Suggests as the apt-setup command is used by the wajig commands setup/editsources (Closes: #232536) -- Dirk Eddelbuettel Sun, 15 Feb 2004 17:12:39 -0600 wajig (2.0.5-1) unstable; urgency=low * New upstream version released today * The package is now again an Architecture: any package as we are depending on a particular Python version anyway * debian/control: Switched to Architecture: any, and Build-Depends: * debian/rules: No longer purge *.pyo files * debian/control: Added Suggests: gnome-terminal -- Dirk Eddelbuettel Mon, 9 Feb 2004 19:11:26 -0600 wajig (2.0.4-1) unstable; urgency=low * New upstream version released today * Upstream version number jumped as both a new Gui (gjig) and some new features were; minor revision .4 is the first public release Graham sent me. As usual, see his changelog for the full details. * The new gjig gui requires python-gtk2, python-glade2, and python-gnome2 which implies another, larger set of other packages -- so that for now, we only Suggests: these gui components as to not force a whole new set of packages onto systems which would use only the tried and tested command line version of wajig. Long term, maybe gjig should be in its own package and depend on wajig. Or maybe I'm going overboard here. * This also implies a Depends on the actual version supplying the default gtk2, glade and gnome modules, so we now Depend on the default Python version and conflict with the next one up as per Python Policy. * Upstream fix for 'apt-cache show run as root' (Closes:# 229330) * debian/control: Depends on python now 'python (>= 2.2)' (Closes: #228778) -- Dirk Eddelbuettel Sun, 8 Feb 2004 16:39:10 -0600 wajig (1.0.2-1) unstable; urgency=low * New upstream version released today - Fix typo in documentation. (Closes: Bug#217411) - Reimplement PURGE/DEPEND and REMOVE/DEPEND - no longer rely on aptitude (since it didn't work - only if you use aptitude to also install). Both commands now remove pkg plus any it requires/suggests which are not required by anything else. (Closes: Bug#211211) -- Dirk Eddelbuettel Sun, 26 Oct 2003 19:08:14 -0600 wajig (1.0.1-1) unstable; urgency=low * New upstream version released today - CHANGELOG to list the change log of a package. Useful to check to see if you want to install the package without downloading it. - FINDPKG and UNOFFICIAL to search for an unofficial Debian package at apt-get.org. - SHOW-INSTALL and SHOW-REMOVE to list the steps that would be taken for the install or removal. Also document SHOW-UPGRADE and SHOW-DIST-UPGRADE which had been overlooked. (Closes: #215835) -- Dirk Eddelbuettel Thu, 23 Oct 2003 20:23:36 -0500 wajig (1.0.0-1) unstable; urgency=low * New upstream version released today: - Fix NEWS to check Source package. Reported by John Belmonte. (Closes: #211130) - INSTALL/DIST will choose the distribution DIST (Closes: #209385) - "/" added as command meta character - UPGRADE/SECURITY will do security upgrade. Suggested by Markus Hegland. - Outstanding issue with REMOVE-DEPEND under review. -- Dirk Eddelbuettel Wed, 1 Oct 2003 07:10:00 -0500 wajig (0.3.30-1) unstable; urgency=low * New upstream version released moments ago: - Fixes WHICHPKG - it did not handle diversions (Closes: #210499) -- Dirk Eddelbuettel Fri, 12 Sep 2003 19:35:33 -0500 wajig (0.3.29-1) unstable; urgency=low * New upstream version released today: - New command PURGE-DEPEND to purge pkg and dependees (Closes: #209383) - Update NEWS to handle HTML entities using lynx (Closes: #208632 * debian/control: Add lynx to Suggests: -- Dirk Eddelbuettel Tue, 9 Sep 2003 23:32:48 -0500 wajig (0.3.28-1) unstable; urgency=low * New upstream version released today: - New command UNHOLD to remove the hold flag on packages. - Update NEWS to handle some HTML sequences (Closes: #208632) - Update DEPENDEES to not use grep-dctrl * debian/control: Removed grep-dctrl from Suggests: * Internal disk usage has been reduced since 0.3.27 (Closes: #206662) -- Dirk Eddelbuettel Tue, 9 Sep 2003 06:33:32 -0500 wajig (0.3.27-2) unstable; urgency=low * src/{commands,documentation,wajig}.py: Wrote small patch for new 'unhold' command functionality; derived from 'hold' command -- Dirk Eddelbuettel Wed, 3 Sep 2003 20:17:31 -0500 wajig (0.3.27-1) unstable; urgency=low * New upstream version released today: - Remove redundant (and large) Packages cache - Remove the Installed packages cache - Note version 0.3.26 not released -- Dirk Eddelbuettel Sat, 23 Aug 2003 10:02:21 -0500 wajig (0.3.25-1) unstable; urgency=low * New upstream version released today (whereas 0.3.24 never made it) - new 'recdownload' command - download package and dependees - fix available list problem - cache the list - new 'size', 'sizes', 'large' commands - print size of packages * debian/control: Standards-Version increased to 3.6.0.1 -- Dirk Eddelbuettel Thu, 21 Aug 2003 20:58:59 -0500 wajig (0.3.23-1) unstable; urgency=low * New upstream version released today: - strip space from Available file (Closes: #192861) - 'lastupdate' works even if no 'update' performed (Closes: #192862) - 'removedepend' added using 'aptitude' (Closes: #192685) - new commands: 'news' and 'avail' -- Dirk Eddelbuettel Sat, 17 May 2003 17:53:35 -0500 wajig (0.3.22-1) unstable; urgency=low * New upstream version released today: - 'download' command improved (Closes: #192123) - 'localupgrade' command added -- Dirk Eddelbuettel Tue, 6 May 2003 07:16:43 -0500 wajig (0.3.21-1) unstable; urgency=low * New upstream version released today: - better 'remove-orphans' when no orphans present (Closes: #191670) - added 'purge-orphans' -- Dirk Eddelbuettel Tue, 6 May 2003 06:21:18 -0500 wajig (0.3.20-1) unstable; urgency=low * New upstream version released today: - 'wajig purge' now uses dpkg (Closes: #189301) - New commands 'showupgrade', 'showdistupgrade' (Closes: #189923) -- Dirk Eddelbuettel Wed, 23 Apr 2003 21:36:14 -0500 wajig (0.3.19-1) unstable; urgency=low * New upstream version released today (Closes: #187437) -- Dirk Eddelbuettel Thu, 3 Apr 2003 14:37:06 -0600 wajig (0.3.18-1) unstable; urgency=low * New upstream version released today * debian/copyright: Updated upstream location -- Dirk Eddelbuettel Sat, 22 Mar 2003 01:16:49 -0600 wajig (0.3.17-1) unstable; urgency=low * Upgraded to new upstream release 0.3.17; 0.3.16 was also released today -- Dirk Eddelbuettel Tue, 11 Feb 2003 20:05:14 -0600 wajig (0.3.15-1) unstable; urgency=low * Upgraded to new upstream release 0.3.15 (Closes: #174011, #174948) -- Dirk Eddelbuettel Thu, 30 Jan 2003 19:28:32 -0600 wajig (0.3.14-2) unstable; urgency=low * debian/control: Added grep-dctrl to Suggests (Closes: #175707) -- Dirk Eddelbuettel Tue, 7 Jan 2003 20:10:27 -0600 wajig (0.3.14-1) unstable; urgency=low * Upgraded to new upstream release 0.3.14 -- Dirk Eddelbuettel Sat, 9 Nov 2002 08:09:00 -0600 wajig (0.3.13-3) unstable; urgency=low * debian/control: Build-Depends on python (Closes: #164072) -- Dirk Eddelbuettel Fri, 11 Oct 2002 22:44:59 -0500 wajig (0.3.13-2) unstable; urgency=low * debian/control: Depends changed to python (>= 1.5) -- we do not need versioned Depends as .py[co] file are not shipped (anymore), and differences between Python versions should be fine (Closes: #159208) * debian/control: Similarly, no longer Build-Depends on python-dev -- Dirk Eddelbuettel Thu, 5 Sep 2002 19:44:26 -0500 wajig (0.3.13-1) unstable; urgency=low * Upgraded to new upstream release 0.3.13 (Closes: #150015, #150308) -- Dirk Eddelbuettel Sat, 29 Jun 2002 07:07:32 -0500 wajig (0.3.11-1) unstable; urgency=low * Upgraded to new upstream release 0.3.11 (Closes: #139157) -- Dirk Eddelbuettel Thu, 6 Jun 2002 22:27:22 -0500 wajig (0.3.10-1) unstable; urgency=low * Upgraded to new upstream release 0.3.10 (Closes: #148723) -- Dirk Eddelbuettel Sat, 1 Jun 2002 08:28:25 -0500 wajig (0.3.9-1) unstable; urgency=low * Upgraded to new upstream release 0.3.9 (Closes: #145902) -- Dirk Eddelbuettel Thu, 30 May 2002 22:02:31 -0500 wajig (0.3.7-1) unstable; urgency=low * Upgraded to new upstream release 0.3.7 (Closes: #144524, #144527)) -- Dirk Eddelbuettel Sun, 28 Apr 2002 07:23:05 -0500 wajig (0.3.5-3) unstable; urgency=low * wajig.py: Ooops, apply the fix for 0.3.5-2 at the right spot. -- Dirk Eddelbuettel Tue, 16 Apr 2002 22:02:44 -0500 wajig (0.3.5-2) unstable; urgency=low * wajig.py: For 'wajig source', do not call 'apt-get source' as root. Thanks to Christian Steigies for finding the bug, and testing the the suggested fix (Closes: #142763) -- Dirk Eddelbuettel Sun, 14 Apr 2002 13:49:37 -0500 wajig (0.3.5-1) unstable; urgency=low * Upgraded to new upstream release 0.3.5 * This release adds a host of new features as e.g. support for .rpm packages using alien(1) and fixes a few minor bugs (Closes: #139001) * debian/control: Added Suggests: alien, fping -- Dirk Eddelbuettel Sun, 31 Mar 2002 19:52:17 -0600 wajig (0.3.1-1) unstable; urgency=low * Upgraded to new upstream release 0.3.1 following interim releases 0.2.13 and 0.3.0 all from this weekend. * This new upstream release fixes several bugs, adds a few new commands and uses python-apt for good measure (Closes: #119900, #136439, #136280) * debian/control: Depends and Build-Depends on Python 2.1 with double relation python (>= 2.1), python (<< 2.2) * debian/control: Also added Depends on python-apt -- Dirk Eddelbuettel Sun, 3 Mar 2002 09:23:17 -0600 wajig (0.2.12-2) unstable; urgency=low * debian/rules: Remove .pyo,.pyc files (Closes: #128957) * debian/control: Architecture: all (Closes: #128911) * debian/rules: Corresponding changes for Arch: all * The net effect of these two changes is that wajig will run slower, but this is bound to make the FHS Policy happy. -- Dirk Eddelbuettel Sun, 13 Jan 2002 10:57:52 -0600 wajig (0.2.12-1) unstable; urgency=low * Upgraded to new upstream release (Closes: #128431) -- Dirk Eddelbuettel Fri, 11 Jan 2002 09:06:06 -0600 wajig (0.2.11-1) unstable; urgency=low * Upgraded to new upstream release -- Dirk Eddelbuettel Mon, 7 Jan 2002 19:47:42 -0600 wajig (0.2.10-1) unstable; urgency=low * Upgraded to new upstream release -- Dirk Eddelbuettel Wed, 5 Dec 2001 23:07:53 -0600 wajig (0.2.9-1) unstable; urgency=low * Upgraded to new upstream release * debian/control: Rewrote Depends: and Suggests: with upstream author -- Dirk Eddelbuettel Wed, 5 Dec 2001 20:29:40 -0600 wajig (0.2.8-2) unstable; urgency=low * Adapted Python Policy (as of version 0.3.7) * debian/control: Unversioned Depends on python (Closes: #118916) * debian/control: Added Build-Depends on python-dev (Closes: #119009) * debian/control: Clarified/rewrote Description (Closes: #119139) -- Dirk Eddelbuettel Mon, 12 Nov 2001 09:54:22 -0600 wajig (0.2.8-1) unstable; urgency=low * Initial Debian release following WNPP head's up (Closes: #115474) * The release is made with the understanding that Graham will maintain his wajig package once he has cleared the New Maintainer process. -- Dirk Eddelbuettel Mon, 5 Nov 2001 21:54:58 -0600 wajig (0.2.7-1) unstable; urgency=low * New upstream release: Minor documentation update -- Graham Williams Sat, 13 Oct 2001 09:56:37 +1000 wajig (0.2.6-1) unstable; urgency=low * New upstream release: Serious bug fix -- Graham Williams Sat, 6 Oct 2001 21:43:11 +1000 wajig (0.2.5-1) unstable; urgency=low * New upstream release: Wajig in shared /home environment -- Graham Williams Wed, 3 Oct 2001 08:24:11 +1000 wajig (0.2.4-1) unstable; urgency=low * New upstream release: Fix su problem with hold command -- Graham Williams Tue, 2 Oct 2001 13:16:05 +1000 wajig (0.2.3-1) unstable; urgency=low * New upstream release: Added reload command. -- Graham Williams Fri, 28 Sep 2001 11:25:08 +1000 wajig (0.2.2-1) unstable; urgency=low * New upstream release Fix problem with removing non-existent temp files. * Add wget as a dependency. -- Graham Williams Mon, 24 Sep 2001 11:19:57 +1000 wajig (0.2.1-1) unstable; urgency=low * New upstream release: Address some temp problems. Add new commands updatealts, listalts, lastupdate. -- Graham Williams Thu, 20 Sep 2001 14:04:35 +1000 wajig (0.2.0-1) unstable; urgency=low * New upstream release: All old wajig commands now implemented. Ready for release. -- Graham Williams Mon, 17 Sep 2001 14:00:23 +1000 wajig (0.1.10-1) unstable; urgency=low * New upstream release: Added force and hold. Improved status output. -- Graham Williams Sat, 15 Sep 2001 22:35:10 +1000 wajig (0.1.9-1) unstable; urgency=low * New upstream release -- Graham Williams Fri, 14 Sep 2001 12:38:44 +1000 wajig (0.1.8-1) unstable; urgency=low * New upstream release -- Graham Williams Fri, 14 Sep 2001 10:26:21 +1000 wajig (0.1.7-1) unstable; urgency=low * New upstream release adding new commands -- Graham Williams Thu, 13 Sep 2001 10:12:13 +1000 wajig (0.1.6-1) unstable; urgency=low * New upstream release -- Graham Williams Wed, 12 Sep 2001 19:40:47 +1000 wajig (0.1.5-1) unstable; urgency=low * New upstream release -- Graham Williams Wed, 12 Sep 2001 13:37:47 +1000 wajig (0.1.4-1) unstable; urgency=low * New upstream release -- Graham Williams Tue, 11 Sep 2001 20:19:08 +1000 wajig (0.1.3-3) unstable; urgency=low * Remove INSTALL from doc. * Fix Upstream Author in copyright -- Graham Williams Tue, 11 Sep 2001 20:11:53 +1000 wajig (0.1.3-2) unstable; urgency=low * Add dh_installdocs to get docs installed. -- Graham Williams Tue, 11 Sep 2001 20:03:41 +1000 wajig (0.1.3-1) unstable; urgency=low * New upstream release -- Graham Williams Tue, 11 Sep 2001 19:44:22 +1000 wajig (0.1.2-2) unstable; urgency=low * Fix some of the debian files. -- Graham Williams Tue, 11 Sep 2001 19:26:34 +1000 wajig (0.1.2-1) unstable; urgency=low * New upstream release -- Graham Williams Tue, 11 Sep 2001 19:16:47 +1000 wajig (0.1.1-1) unstable; urgency=low * New upstream release -- Graham Williams Tue, 11 Sep 2001 15:12:39 +1000 wajig (0.1.0-1) unstable; urgency=low * Initial Release of rewritten Python version -- Graham Williams Fri, 7 Sep 2001 13:44:54 +1000 wajig/debian/source/0000755000000000000000000000000012155054044011567 5ustar wajig/debian/source/format0000644000000000000000000000001512155054044012776 0ustar 3.0 (native) wajig/wajig.sh0000755000000000000000000000005212266756103010512 0ustar #!/bin/sh /usr/share/wajig/wajig.py "$@" wajig/TUTORIAL0000644000000000000000000007152712252405302010242 0ustar wajig is a Debian tool that attempts to unify Debian packagement. wajig commands are entered as the first argument to wajig. For example: "wajig INSTALL gnome". The word JIG has a couple of meanings, as WordNet and Webster's 1913 Dictionary will confirm. It is a small machine or handy tool used to guide other tools. It is also a quick dance, generally an old rustic dance involving kicking and leaping, as well as a light, humorous piece of writing, especially in rhyme, a farce in verse, or a ballad. "A jig shall be clapped at, and every rhyme praised and applauded." For wajig, 'wa' is Japanese, indicating 'harmony' and 'team spirit and unity'. Development of wajig was historically sponsored and supported by Togaware, an Australian based Debian GNU/Linux company. Written in Python, wajig uses traditional Debian administration and user tools including apt-get, aptitude, dpkg, apt-cache, and others. wajig has evolved over many years and was rewritten from its original shell script to be a Python program. As wajig is simply a frontend to various other commands, the goal of this tutorial is more than simply demonstrating how to manage your system with wajig. wajig may not be the answer you are looking for and that is fine. Wherever I illustrate a procedure with wajig I will often indicate the underlying commands that are being used to effect the wajig command. You can then use these underlying commands directly if you prefer. Online information about wajig is at http://wajig.togaware.com. wajig is hosted on Bitbucket at https://bitbucket.org/tshepang/wajig/src. Tshepang Lekhonkhobe is the current active developer, but rather send your queries to wajig@googlegroups.com. HISTORY: MOTIVATIONS FOR wajig If you've tried to remember all the different commands to get different information about different aspects of Debian package management and then used other commands to install and remove packages then you'll know that it can become a little too much. Swapping between dselect, aptitude, apt-get, dpkg, apt-cache, and so on is interesting but cumbersome. Plus personally I find dselect, and aptitude confusing and even though I've spent hours understanding each of them, I don't think the time was particularly well spent. This Python script simply collects together what I have learnt over the years about various commands! Clearly I have yet to learn all there is. INSTALLING wajig wajig is available in the Debian distribution. As root: # apt-get install wajig Alternatively, if you already have sudo configured: $ sudo apt-get install wajig THE BASIC DEBIAN TOOLS The Debian package apt-howto is a good place to start with understanding the APT (for Advanced Packaging Tools) suite of tools. Once installed browse this file: /usr/share/doc/apt-howto/en/index.html Also, see the Debian FAQ at http://www.debian.org/doc/FAQ/. In particular, Section 6 deals with the Packaging system. APT is the recommended way of managing packages under Debian. To learn how to work with APT off-line, see: /usr/share/doc/apt/offline.html/index.html wajig OVERVIEW wajig is designed to run in such a way as to suit the system it is running on and the policies of the system administrators. It can be run as a normal user, but once a privileged command is required it will use either su and ask for the root user's password, or else it can use sudo and rely on the normal user's password. It can also be run directly as root without any extra setup (i.e., without the need for sudo or regularly supplying passwords). Using sudo requires a little setting (see below). Try the help command for a list of common commands provided by wajig: $ wajig help Examples commands include: $ wajig update (= apt-get update) $ wajig install less (= apt-get install less) $ wajig new (list new packages since last update) $ wajig newupgrades (list packages upgraded since last update) $ wajig updatealts editor (update the default "editor") $ wajig restart apache (restart the apache daemon) $ wajig listfiles less (list the files supplied by the "less" pkg) $ wajig whichpkg stdio.h (what package supplies this header file) $ wajig whatis rats (one line description of the package "rats") $ wajig orphans (list libraries not required by other pkgs) For a complete list of available commands, 'wajig list-commands'. In most cases, wajig expects a command and will call upon other Debian tools to perform the command. GETTING STARTED WITH SUDO The aim of wajig is to operate as much as possible as a user command and to do super user privileged commands only when necessary (if that is how the system administrator wishes to allow a user to maintain their system). The easiest way to do this is to use the sudo package which will ask you for your password and then run the command as the super user. If you don't have sudo installed then wajig will use `su' to run as super user, but you will need to enter the super user password frequently. If `sudo' is installed but not set up for you to access the appropriate apt-get commands you will see a permission denied message. In order to allow your user to use sudo, run this command as root: # adduser sudo The change will take effect after logging out and in again. AVAILABLE PACKAGES The Debian packaging system relies on your local system having some idea of what packages are available. This is initialised when you install your system. You will generally need to update this list of packages with what is currently available from the Debian archives for downloading. If you are staying with the stable release you generally only need to update the list of available packages once. The following command is used to update the information about what is available for downloading: $ wajig update (apt-get update) (In brackets after the wajig command is the underlying command that wajig calls upon to perform the operation.) This uses entries in the file /etc/apt/sources.list to know where to get the list of available packages from and which release of Debian you wish to follow. You can edit this file with: $ wajig editsources ( /etc/apt/sources.list) It will check if $VISUAL and $EDITOR are defined, and use the editors defined there. If not, it will simply use /usr/bin/sensible-editor. You need to understand the format of the file /etc/apt/sources.list as explained in the manual page: $ man sources.list It is pretty straightforward and we will see examples in the next section. If you have a Debian CD-ROM or DVD-ROM then you can tell apt what is available on it using: $ wajig addcdrom To add a Launchpad PPA (Personal Package Archive) repository (used by Ubuntu) the ADD-REPO command can be used. For example, to add the daily builds of Google's Chromium browser, do the following: $ wajig addrepo ppa:chromium-daily If you want to check when you last did an update then: $ wajig lastupdate There are quite a few archives available and you can test for a good connection to one with: $ wajig searchapt This will write a candidate sources.list in the current directory, which you can then review and add to the system sources.list, if you wish, with $ wajig editsources FINDING PACKAGES To search for a particular packages, use: $ wajig search (apt-cache --names-only) This will only match a particular string with package names. If you want a more comprehensive search, one that also searches for package descriptions, use the "-v|--verbose" options. To display the list of newly-available packages (after a cache update), use: $ wajig new Note that after the first time you use update all packages will be considered new! But after the next update the new packages are those that were not in the available list from the previous update. Some (and often many) of the packages that you already have installed on your Debian system may have been upgraded in the archive since the last time you performed an update. The following command will list these packages: $ wajig newupgrades For a complete list of the packages you have installed but for which there are newer versions available on the archive use: $ wajig toupgrade To check the version of any installed package and also the version available from the archive previously (i.e., the last time, but one, you performed an upgrade) and now (based on the last time you performed an update), and to also see the so called Desired and Status flags of the package, use: $ wajig status (similar to dpkg -l) Without a list of package names all installed packages will be listed. A variation is to list the status of all packages with a given string in their name: $ wajig statussearch To check for a particular package for which you might guess at part of its name you can use: $ wajig listnames (apt-cache pkgnames) Without the string argument all known package names will be listed. To list the names and current install status of all installed packages then use: $ wajig list You can also list just the names of the packages installed with: $ wajig list-installed And if you are looking for a particular installed package with a name containing a particular string then use: $ wajig list-installed To generate a list of packages, with version numbers, which you might save to file, and then restore a system to just this list of packages at a later stage, use: $ wajig snapshot > snapshop-12dec04 Each package installs some collection of files in different places on your system (e.g., in /usr/bin/, /usr/man/man1/ and usr/doc/). Sometimes you like to see where those files go or even just view the list of files installed. The command to use is: $ wajig listfiles (dpkg --listfiles ) To list a one line dscription for a package use: $ wajig whatis And to find which package supplies a given file use: $ wajig whichpkg and for a command (e.g., most): $ wajig whichpkg $(which -p most) For unofficial packages (i.e., you came across a package but it doesn't seem to be in Debian yet) search for a site with: $ wajig searchpkg The more detailed description of a package is available with: $ wajig detail Here, the package name can be replaced with a specific deb file. The Debian changelog can be retrieved with: $ wajig changelog This command only displays changelog entries for upgradable packages. If you want to display the entire changelog, use: $ wajig changelog --verbose It may be more practical to run the output through a pager: $ wajig changelog --verbose | pager INSTALLING PACKAGES To install a new package (or even to update an already installed package) all you need do is: $ wajig install (apt-get install) (Instead of install you could equivalently say update.) You can list multiple packages to install with the one command. The install command will also accept a .deb file. So, for example, if you have downloaded a Debian package file (with the .deb extension) you can install it with: $ wajig install <.deb file> (dpkg -i) The .deb file will be searched for in both the current directory and in the apt archive at /var/cache/apt/archive/. You can list multiple .deb files to install. If the .deb package file you wish to install is available on the internet you can give its address and wajig will download then install it: $ wajig install http://samfundet.no/debian/dists/woody/css/xine-dvd-css.deb Sometimes you may want to install many packages by listing them in a file, one per line. You can do this with: $ wajig install --fileinput The file of packages to install can conveniently be created from the list of installed packages on another system with: $ wajig listinstalled > (dpkg --get-selections) UPGRADING PACKAGES You can upgrade all installed packages with: $ wajig upgrade (apt-get -u upgrade) And you can upgrade all installed packages, remove those packages that need to be removed (for various reasons, including issues to do with dependencies) and install all newly required packages in the distribution with: $ wajig distupgrade (apt-get -u dist-upgrade) Note that a dist-upgrade will potentially remove packages where dependency checking indicates this is necessary. Important packages (determined by the Priority specification which can be found using the details command) will be upgraded even at the cost of downgrading other (less important) packages. If this is an issue for you then you should use the upgrade command rather than dist-upgrade. This command will never remove or downgrade a package. To upgrade to a specific distribution (e.g., experimental) you can use: # wajig distupgrade --dist experimental Note that the mentioned distribution must also be mentioned in your /etc/apt/sources.list file. A neat trick with wajig is the ability to upgrade a collection of packages all with the same version number to another common version number: $ wajig status | grep 3.2.3-2 | grep 3.3.0-1 | cut -f1 > list $ wajig installfile list REMOVING PACKAGES Once a package is installed you can remove it with: $ wajig remove (apt-get remove) Once again, you can list multiple packages to remove with the one command. A remove will not remove configuration files (in case you have done some configuration of the package and later re-install the package). To get rid of the configuation files as well use: $ wajig purge (apt-get --purge remove) DISPLAYING APT LOG Whenever a package is installed, removed, upgraded, or downgraded with either apt, aptitude, or synaptic, a log found at /var/log/apt/history.log is updated. To display it, run: $ wajig list-log (cat /var/log/apt/history.log) CHECKING WHAT'S CHANGED BEFORE INSTALLING When you install an updated package it is sometimes useful to know what's changed. The apt-listchanges package provides a mechanism whereby when updating packages you will be given a chance to review the changelog of the package and then decide whether to continue with the upgrade. Simply install the apt-listchanges package to turn this feature on. INSTALLING ALIEN (RedHat/Fedora/CentOS) PACKAGES RedHat has quite an installed base of users. Some packages (particularly commercial packages) are available as RedHat packages (with the rpm extension). These can usually be installed in Debian with little effort. The alien package is required to convert the rpm into deb format which can then be installed. This is taken care of by wajig: $ wajig rpminstall gmyclient-0.0.91b-1.i386.rpm PUTTING PACKAGES ON HOLD Occasionally, and particularly if you are following the unstable release, some packages are broken for various reasons. This was the case with the package cdrecord in unstable. This package was compiled with kernel 2.4.n and had some kernel specific issues that were done differently with kernel 2.2.n. At compile time one or the other options was chosen (but not both!). Thus the newer binary versions of cdrecord would not run on a system using kernel 2.2.n. One solution is to build a Debian package of cdrecord using the wajig build command. Another is to reinstall an older version that worked and then place the package on hold with: $ wajig hold cdrecord A wajig upgrade would not try to upgrade this package. BUILDING PACKAGES Sometimes the binary distribution of the package is configured or compiled with options that don't suit you. Or it may be compiled for a more recent release than that which you are using and does not work for your release. Normally you would then be left on your own to retrieve the source of the package, configure and compile it, then install it into /usr/local/. This is then outside of the Debian package management system, which is just fine. But there are better solutions. One is to tune a specific source package and build a Debian package from it. The second is to specify general configuration options for your system and then rebuild many packages with these options. BUILDING PACKAGES FROM SOURCE You can download the source code for any Debian package from the Debian archive. You can then modify it and generate your own .deb file for installation. To download the source of a Debian package you will need deb-src lines in your /etc/apt/sources.list file, such as the following: deb-src http://ftp.debian.org/debian unstable main contrib non-free Generally you can add the '-src' to copies of pre-existing 'deb' lines. To retrieve and unpack a source Debian package use: $ wajig source (apt-get source) Note that you can list several packages and grab all of their sources. The source command downloads a .tar.gz file and a .dsc file for the package. The .tar.gz file contains the source code and associated files. The .dsc file contains test information that is used by the packaging system. The source command will also extract the contents of the .tar.gz archive into a subdirectory consisting of the package name and version. To go one step further and also configure, compile and generate a default Debian .deb package from source code (useful if you need to compile a package for your setup specifically) then use instead: $ wajig build This conveniently installs the needed build-dependencies for you. If you need to modify the source in some way and rebuild a package: $ wajig update $ wajig build ncftp $ dpkg-source -x ncftp_3.0.2-3.dsc $ cd ncftp-3.0.2 $ fakeroot dpkg-buildpackage -b -u Note that for some packages, you will get permission-related build errors. Replace 'fakeroot' with 'sudo' in such cases. BUILD ARCHITECTURE-OPTIMISED PACKAGES The apt-build package, a front-end to apt-get, provides a general solution to build Debian packages tuned (or optimised) for your architecture. $ wajig install apt-build You will be asked for some options, and these go into /etc/apt/apt-build.conf: build-dir = /var/cache/apt-build/build repository-dir = /var/cache/apt-build/repository Olevel = -O2 march = -march=pentium4 mcpu = -mcpu=pentium4 options = " " The built packages will be placed into /var/cache/apt-build/repository, an can be accessed with the standard Debian package tools by adding the following line to the top of /etc/apt/sources.list (which can be done during the installation of apt-build: deb file:/var/cache/apt-build/repository apt-build main You will need deb-src entries in your /etc/apt/sources.list file to be able to obtain the source packages. Being a front-end to apt-get, your first apt-build command might be to update the list of known available packages (particularly if you have just added a deb-src entry to /etc/apt/sources.list), although the following is equivalent: $ wajig update You can then start building packages: $ sudo apt-build install most You can manage a collection of packages to be recompiled and installed instead of obtaining the default compiled versions. Create the file /etc/apt/apt-build.list to contain a list of such packages and then: $ sudo apt-build world One way to get a full list of installed packages is: # dpkg --get-selections | awk '{if ($2 == "install") print $1' \\ > /etc/apt/apt-build.list Be sure to edit the list to remove, for example, gcc! Then a: $ sudo apt-build world will recompile and optimise all packages. PINNING DISTRIBUTIONS With the Debian packaging system you can specify that your packages come by default from one distribution but you can override this with packages from other distributions. The concept is called pinning and after it is set up you can have, for example, testing as your default release and then include unstable in /etc/apt/sources.list and install cdrecord from unstable with: # apt-get install cdrecord/unstable The following /etc/apt/preferences makes apt-get use testing unless it is overridden, even though there are entries for unstable in /etc/apt/sources.list: Package: * Pin: release a=testing Pin-Priority: 900 Package: * Pin: release o=Debian Pin-Priority: -10 RECONFIGURE PACKAGES $ wajig reconfigure debconf (dpkg-reconfigure debconf) An alternative where you can specify a particular front end to use for the configurator is: # dpkg-reconfigure --frontend=dialog debconf SETTING DEFAULT APPLICATIONS Debian has a system of alternatives for various commands (or functionalities). For example, the editor command could be nano or nvi, or one of a large number of alternative editors. You can update the default for this command with: $ wajig updatealts editor (update-alternatives --config editor) Another common alternative is x-window-manager. You can get a list of all alternatives with: $ wajig listalts (ls /etc/alternatives/) The information is maintained in the directory /etc/alternatives/. BUGS If you find a problem with your system and think it might be a bug, use: $ wajig bug (reportbug) This will allow you to view bugs recorded against packages and also allow you to add a new bug report to the Debian bug reporting system. Otherwise visit the Debian email lists at http://lists.debian.org/ and search for the problem there. The advice one gets here is generally of high quality. MANAGING DAEMONS OR SERVICES In addition to managing the installed packages wajig also allows you to start, stop, reload, and restart services (which are often provided by so called daemons---processes that run on your computer in the background performing various functions on an on-going basis). The commands all follow the same pattern: $ wajig restart (/etc/init.d/ restart) The start and stop commands are obvious. The restart command generally performs a stop followed by a start. The reload command will ask the daemon to reload its configuration files generally without stopping the daemon, if this is possible. The services you can specifiy here depend on what you have installed. Common services include: apache Web server cron Regular task scheduler exim Email delivery system gdm The Gnome Windows Display Manager (for logging on) ssh The Secure Shell daemon Generally, daemons are started at system boot time automatically. ALTERNATIVE APPLICATIONS Debian has a mechanism for dealing with applications that provide the same functionality. We describe here how this mechanism works and how you can use it to tune your installation. If you have more than one variant of emacs installed (e.g., emacs19, emacs20, and xemacs) then you can configure which one you get by default with: $ wajig updatealts emacs You will be asked to choose from a list of alternatives. To specify which window manager to use as the system default: $ wajig updatealts x-window-manager Suppose the window-manager you want to use as the default is not listed as available. You can install it with: # update-alternatives --install /usr/bin/x-window-manager \\ x-window-manager /usr/bin/mywm PRIORITY Where PRIORITY is a number higher than the highest existing priority for the x-window-manager alternative. You can get a list of priorities with: # update-alternatives --display x-window-manager To remove a Window Manager: # update-alternatives --remove x-window-manager /usr/bin/mywm PACKAGE ARCHIVES Local Cache When packages are installed from the Debian Archives the corresponding deb files are stored in /var/cache/apt/archive. This can become quite populated with older versions of packages and we can clean out these older versions with: $ wajig autoclean (apt-get autoclean) Warning: It is sometimes useful to have older versions of packages hanging around if you are tracking the unstable release. Sometimes the newer versions of packages are broken and you need to revert to an older version which may not be available from the Debian archives, but might be in your local download archive. If you get short of disk space then you might want to remove all the downloaded deb files (not just the older versions of downloaded files) with: $ wajig clean (apt-get clean) To remove files immediately after they have been installed edit /etc/apt/apt.conf: // Things that effect the APT dselect method DSelect { Clean "auto"; // always|auto|prompt|never ; Historic Packages To obtain any package version that might have appeared in the archive include http://snapshot.debian.net in your package sources list and the name of the package you are interested in. To update your sources list run: $ wajig editsources to add the following line: deb http://snapshot.debian.net/archive pool sed Then you can do, for example: $ wajig available sed $ wajig install sed=4.1.2-1 MAINTAINING A DISTRIBUTION ARCHIVE Downloaded Debian packages are placed into /var/cache/apt/archive. You can have the files moved into a local hierarchy that mirrors a standard Debian distribution hierarchy. Then you can point the /etc/apt/sources.list to this local archive by using the file:// format. To set up a local machine as a local (partial) mirror of the Debian archive, wajig will use the apt-move package. Edit /etc/apt-move.conf to set the DIST to match your system (default is stable): DIST=unstable The wajig command move will then move any packages in your /var/cache/apt/archives into the Debian mirror being created: $ wajig move You can actually create a complete mirror with: # apt-move mirror These commands place the packages into /mirrors/debian. To make it available on your web server simply: # cd /var/www # ln -s /mirrors pub The file /etc/apt/sources.list can then be updated to point to the new archive as the first place to check for packages (place this lines first in the file): deb http://athens/pub/debian unstable main contrib non-free All of this might happen on your server (called athens in this example) and other machines on your local network can then access the local archive by adding the above line to /etc/apt/sources.list. If your server is not the most up to date machine (since you may not want to run the risk of your server becoming unstable), you can rsync all packages in /var/cache/apt/archives on other machines to the server and then run the move command on the server: # rsync -vr friend:/var/cache/apt/archives/ /var/cache/apt/archives/ # ssh friend wajig clean (apt-get clean) # wajig move (apt-move update) In fact, on your server you could use the following Python script saved to file /root/apt-archive.py to automate this for each of the hosts on the network: #!/usr/bin/env python import os hosts = ['friend', 'cargo'] archive = '/var/cache/apt/archives/' for h in hosts: os.system('rsync -vr %s:%s %s' % (h, archive, archive)) os.system('ssh %s wajig clean' % h) os.system('wajig move') Then set the script up to run: # chmod u+x apt-archive.py and run it as required: # ./apt-archive.py Depending on how you have ssh set up this may ask for your password for each connection. To avoid this, you can use public/private keys with no passphrase, and then the script could be run automatically using cron each morning by copying the executable script to /etc/cron.daily/apt-archive. (Scripts in /etc/cron.daily with a py extension are not run, so be sure to rename the file as suggested here.) Local Debian Package Cache To set up a local Debian cache of deb files that you've created or downloaded separately: # mkdir -p /usr/local/cache/dists/local/local/binary-i386 # cp *.deb /usr/local/cache/dists/local/local/binary-i386 # cd /usr/local/cache # dpkg-scanpackages dists/local/local/binary-i386 /dev/null \\ $ dists/local/local/binary-i386/Packages Then add the following line to /etc/apt/sources.list: deb file:/usr/local/cache local local OTHER COMMANDS These may work their way into wajig. You can use the apt-get --download-only option of apt-get to download the files for an install without actually unpacking and setting up the packages. For example: # wajig update # apt-get --download-only dist-upgrade In this way you are able to leave the download unattended and when you are ready you can monitor the unpacking and setup. If things go wrong somewhere then apt may be able to help: # apt-get --fix-broken dist-upgrade but if things still don't work, you may need to use dpkg directly to remove and isntall packages. Synchronising Two Installations The package system maintains a list of all packages installed (and de-installed). You can access this list, save it to a file, and use it to mark those same packages for installation (or deinstallation) on anther machine: # dpkg --get-selections > dpkg-selections # dpkg --set-selections < dpkg-selections # apt-get dselect-upgrade wajig/Makefile0000644000000000000000000000107012266755412010515 0ustar # modified from a version found at: # savetheions.com/2010/01/20/packaging-python-applicationsmodules-for-debian/ LIBDIR = $(DESTDIR)/usr/share/wajig BINDIR = $(DESTDIR)/usr/bin MANDIR = $(DESTDIR)/usr/share/man/man1 CMPDIR = $(DESTDIR)/etc/bash_completion.d clean: rm -rf src/__pycache__ install: install -d $(LIBDIR) $(MANDIR) $(CMPDIR) cp src/*.py $(LIBDIR)/ cp wajig.1 $(MANDIR)/ install -D wajig.sh $(BINDIR)/wajig cp bash-completion $(CMPDIR)/wajig uninstall: rm -rf $(LIBDIR) rm -f $(MANDIR)/wajig.1 rm -f $(BINDIR)/wajig rm -f $(CMPDIR)/wajig wajig/src/0000755000000000000000000000000012266756462007654 5ustar wajig/src/debfile-deps.py0000644000000000000000000000304312252405302012524 0ustar #!/usr/bin/python3 # This file is part of wajig. The copyright file is at debian/copyright. import sys import apt from apt.debfile import DebPackage def show_dependencies(debfile): install, remove, unauthenticated = debfile.required_changes prefix = "In order to allow installation of" if unauthenticated: # me not know what should happen here # awaiting bug report :) print ("The following are UNAUTHENTICATED: ", end="") for package_name in unauthenticated: print(package_name + " ", end=" ") print() if remove: print ("{} {}, the following is to be REMOVED: ".format( prefix, debfile.pkgname), end="") for package_name in remove: print(package_name + " ", end=" ") print() if install: print ("{} {}, the following is to be INSTALLED: ".format( prefix, debfile.pkgname), end="") for package_name in install: print(package_name, end=" ") print() def main(package): cache = apt.Cache() debfile = DebPackage(package, cache=cache) if debfile.check(): show_dependencies(debfile) prompt = "Do you want to continue [Y/n]? " choice = input(prompt) if "y" == choice.lower() or not choice: try: cache.commit(apt.progress.text.AcquireProgress()) except apt.cache.FetchFailedException as e: print(e) else: print("Abort.") if __name__ == "__main__": main(sys.argv[1]) wajig/src/debfile.py0000644000000000000000000000230312252405302011571 0ustar #!/usr/bin/python3 # This file is part of wajig. The copyright file is at debian/copyright. """ Primitive (no error handling) script to install a DEB file and its dependencies. It can be called via wajig or directly: $ wajig install $ python3 /path/to/debfile.py """ import os import sys import perform def install(package_list, args=False): """Some gymnastics to try install local DEB files""" non_existent = list() for package in package_list: if not os.path.exists(package): non_existent.append(package) if non_existent: print("File(s) not found: " + " ".join(non_existent)) return 1 packages = " ".join(package_list) cmd_install = "dpkg --install {}".format(packages) cmd_configure = "dpkg --configure --pending" if perform.execute(cmd_install, root=True): curdir = os.path.dirname(__file__) script = os.path.join(curdir, "debfile-deps.py") for package in package_list: command = "{} {} {}".format(sys.executable, script, package) perform.execute(command, root=True) perform.execute(cmd_configure, root=True) if __name__ == "__main__": install(sys.argv[1:]) wajig/src/perform.py0000644000000000000000000000765512266755472011715 0ustar # This file is part of wajig. The copyright file is at debian/copyright. import os import subprocess SIMULATE = False TEACH = False def highlight(text): return "\x1b[1m{}\x1b[0m".format(text) output = subprocess.check_output("dpkg --get-selections".split()) output = output.decode().split() if "sudo" in output and os.getuid(): setroot = "/usr/bin/sudo" # In case someone is using the non-default install of sudo on # Debian (the default install uses a default root path for sudo # which includes sbin) or have added this user to the sudo group # (which has the effect of also using the user's path rather than # the root path), add the sbin directories to the PATH. os.environ['PATH'] = os.environ['PATH'] + ":/sbin:/usr/sbin" else: setroot = "/bin/su" def execute(command, root=False, pipe=False, langC=False, getoutput=False, log=False): """Ask the operating system to perform a command. Arguments: COMMAND A string containing the command and command line options ROOT If True, root access is required to execute command PIPE If True then return a file-like object. LANGC If LC_TYPE=C is needed (as in join in status command) Returns either the status of the command or a file-like object if PIPE is True.""" if root: if setroot == "/usr/bin/sudo": # # Bug #320126. Karl suggested that we use -v to preset the # password, which also avoids mixing password failure # with command failure but this causes password to be # asked for even if the sudoers file indicates a password # is not required. But this happens in only a few cases, # like listnames (in user has no access to sources.list), # hold, unhold. So should be sufferable. # if '|' in command and subprocess.call(setroot + " -v", shell=True): raise SystemExit("sudo authentication failed.") # # Bug #320126 noted the following is not good as is since # the password is asked for multiple times in a pipe # before it is cached. It captures the case where the # command contains a pipe, and requires root. Then each # part is done as sudo. TODO: It's not always true that # root is required for each part! E.g. HOLD doesn't need # it: echo package hold | dpkg --set-selections # command = setroot + " " + command.replace("|", "| %s " % setroot) elif os.getuid(): print("Using `su' and requiring root password. Install `sudo' " "to support user passwords. See wajig documentation " "(wajig doc) for details.") command = "{} -c '{}'".format(setroot, command) # This worked a long time until Bug#288852 from Serge Matveev # reported that locale is not handled - # which is correct and according to the fix of Bug#119899 the # language was specifially put to be C to make the join work in # the status command. So the fix now is to not touch the locale # except if the cammand asks for it through the langC flag. # if langC: command = "LC_ALL=C; export LC_ALL; " + command elif SIMULATE: print(highlight(" ".join(command.split()))) return if TEACH: print(highlight(" ".join(command.split()))) if pipe: return os.popen(command) elif getoutput: return subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT) else: if log: import tempfile import util temp = tempfile.mkstemp(dir='/tmp', prefix='wajig_')[1] util.start_log(temp) result = subprocess.call(command, shell=True) if log: util.finish_log(temp) return result wajig/src/wajig.py0000755000000000000000000010634712266756462011345 0ustar #!/usr/bin/python3 # # wajig - Debian Command Line System Administrator # # Copyright (c) Graham.Williams@togaware.com # # 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. See the file LICENSE. # # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # import argparse import sys import commands import perform VERSION = "2.13" def main(): # without arguments, run a wajig shell (interactive mode) if len(sys.argv) == 1: import subprocess command = "python3 /usr/share/wajig/shell.py" subprocess.call(command.split()) return parser = argparse.ArgumentParser( prog="wajig", description="unified package management front-end for Debian", epilog=("'wajig commands' displays available commands\n" "'wajig doc' displays a tutorial\n" "'wajig@googlegroups.com' is where your queries should go"), formatter_class=argparse.RawDescriptionHelpFormatter ) parser_backup = argparse.ArgumentParser(add_help=False) message = "backup currently installed packages before replacing them" parser_backup.add_argument("-b", "--backup", action='store_true', help=message) parser_teach = argparse.ArgumentParser(add_help=False) group = parser_teach.add_mutually_exclusive_group() group.add_argument("-s", "--simulate", action='store_true', help="simulate command execution") group.add_argument("-t", "--teach", action='store_true', help="display commands to be executed, before actual execution") parser_verbose = argparse.ArgumentParser(add_help=False) message = "turn on verbose output" parser_verbose.add_argument("-v", "--verbose", action="store_true", help=message) parser_fast = argparse.ArgumentParser(add_help=False) message = ("uses the faster apt-cache instead of the slower (but more " "advanced) aptitude to display package info") parser_fast.add_argument("-f", "--fast", action='store_true', help=message) parser_recommends = argparse.ArgumentParser(add_help=False) group = parser_recommends.add_mutually_exclusive_group() message = "install Recommend dependencies (Debian default)" group.add_argument("-r", "--recommends", action='store_true', help=message) message = "do not install Recommend dependencies" group.add_argument("-R", "--norecommends", action='store_true', help=message) parser_yesno = argparse.ArgumentParser(add_help=False) message = "skip 'Yes/No' confirmation prompts; use with care!" parser_yesno.add_argument("-y", "--yes", action='store_true', help=message) parser_auth = argparse.ArgumentParser(add_help=False) parser_auth.add_argument("-n", "--noauth", action='store_true', help="do not authenticate packages before installation") parser_dist = argparse.ArgumentParser(add_help=False) message = "specify a distribution to use (e.g. testing or experimental)" parser_dist.add_argument("-d", "--dist", help=message) parser_fileinput = argparse.ArgumentParser(add_help=False) parser_fileinput.add_argument("-f", "--fileinput", action="store_true", help=("if any of the arguments are files, assume their contents to " "be packages names")) parser_local = argparse.ArgumentParser(add_help=False) parser_local.add_argument("-l", "--local", action="store_true", help="use packages from local cache; don't download anything") parser_grep = argparse.ArgumentParser(add_help=False) parser_grep.add_argument("pattern", nargs="?", help="filter output, somewhat like grep") message = "show wajig version" parser.add_argument("-V", "--version", action="version", help=message, version="%(prog)s " + VERSION) subparsers = parser.add_subparsers(title='subcommands', help=argparse.SUPPRESS) def help(args): args.parser.print_help() parser_help = subparsers.add_parser("help") parser_help.set_defaults(func=help, parser=parser) function = commands.addcdrom parser_addcdrom = subparsers.add_parser("addcdrom", aliases=["add-cdrom"], parents=[parser_teach], description=function.__doc__) parser_addcdrom.set_defaults(func=function) function = commands.addrepo parser_addrepo = subparsers.add_parser("addrepo", parents=[parser_teach], description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_addrepo.add_argument("ppa") parser_addrepo.set_defaults(func=function) function = commands.autoalts parser_autoalts = subparsers.add_parser("autoalts", parents=[parser_teach], aliases="autoalternatives auto-alternatives auto-alts".split(), description=function.__doc__) parser_autoalts.add_argument("alternative") parser_autoalts.set_defaults(func=function) function = commands.autoclean parser_autoclean = subparsers.add_parser("autoclean", parents=[parser_teach], aliases=["auto-clean"], description=function.__doc__) parser_autoclean.set_defaults(func=function) function = commands.autodownload parser_autodownload = subparsers.add_parser("autodownload", aliases=["auto-download"], parents=[parser_verbose, parser_yesno, parser_auth, parser_teach], description=function.__doc__) parser_autodownload.set_defaults(func=function) function = commands.autoremove parser_autoremove = subparsers.add_parser("autoremove", aliases=["auto-remove"], parents=[parser_teach], description=function.__doc__) parser_autoremove.set_defaults(func=function) function = commands.build parser_build = subparsers.add_parser("build", parents=[parser_yesno, parser_auth, parser_teach], description=function.__doc__) parser_build.add_argument("packages", nargs="+") parser_build.set_defaults(func=function) function = commands.builddeps parser_builddeps = subparsers.add_parser("builddeps", parents=[parser_yesno, parser_auth, parser_teach], aliases="builddepend builddepends build-deps".split(), description=function.__doc__) parser_builddeps.add_argument("packages", nargs="+") parser_builddeps.set_defaults(func=function) function = commands.changelog parser_changelog = subparsers.add_parser("changelog", parents=[parser_verbose, parser_teach], description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_changelog.add_argument("package") parser_changelog.set_defaults(func=function) function = commands.clean parser_clean = subparsers.add_parser("clean", parents=[parser_teach], description=function.__doc__) parser_clean.set_defaults(func=function) function = commands.contents parser_contents = subparsers.add_parser("contents", parents=[parser_teach], description=function.__doc__) parser_contents.add_argument("debfile") parser_contents.set_defaults(func=function) function = commands.dailyupgrade parser_dailyupgrade = subparsers.add_parser("dailyupgrade", aliases=["daily-upgrade"], parents=[parser_teach], description=function.__doc__) parser_dailyupgrade.set_defaults(func=function) function = commands.dependents parser_dependents = subparsers.add_parser("dependents", description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_dependents.add_argument("package") parser_dependents.set_defaults(func=function) function = commands.describe parser_describe = subparsers.add_parser("describe", parents=[parser_verbose, parser_teach], description=function.__doc__) parser_describe.add_argument("packages", nargs="+") parser_describe.set_defaults(func=function) function = commands.describenew parser_describenew = subparsers.add_parser("describenew", aliases="newdescribe new-describe describe-new".split(), description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_describenew.set_defaults(func=function) function = commands.distupgrade parser_distupgrade = subparsers.add_parser("distupgrade", aliases=["dist-upgrade"], parents=[parser_backup, parser_yesno, parser_auth, parser_teach, parser_local, parser_dist], formatter_class=argparse.RawDescriptionHelpFormatter, description=function.__doc__) help = "distribution/suite to upgrade to (e.g. unstable)" parser_distupgrade.set_defaults(func=function) function = commands.download parser_download = subparsers.add_parser("download", parents=[parser_fileinput, parser_teach], description=function.__doc__) parser_download.add_argument("packages", nargs="+") parser_download.set_defaults(func=function) function = commands.editsources parser_editsources = subparsers.add_parser("editsources", aliases=["edit-sources"], parents=[parser_teach], description=function.__doc__) parser_editsources.set_defaults(func=function) function = commands.extract parser_extract = subparsers.add_parser("extract", parents=[parser_teach], description=function.__doc__) parser_extract.add_argument("debfile") parser_extract.add_argument("destination_directory") parser_extract.set_defaults(func=function) function = commands.fixconfigure parser_fixconfigure = subparsers.add_parser("fixconfigure", aliases=["fix-configure"], parents=[parser_teach], description=function.__doc__) parser_fixconfigure.set_defaults(func=function) function = commands.fixinstall parser_fixinstall = subparsers.add_parser("fixinstall", aliases=["fix-install"], parents=[parser_yesno, parser_auth, parser_teach], description=function.__doc__) parser_fixinstall.set_defaults(func=function) function = commands.fixmissing parser_fixmissing = subparsers.add_parser("fixmissing", aliases=["fix-missing"], parents=[parser_yesno, parser_auth, parser_teach], description=function.__doc__) parser_fixmissing.set_defaults(func=function) function = commands.force parser_force = subparsers.add_parser("force", parents=[parser_teach], description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_force.add_argument("packages", nargs="+") parser_force.set_defaults(func=function) function = commands.hold parser_hold = subparsers.add_parser("hold", parents=[parser_teach], description=function.__doc__) parser_hold.add_argument("packages", nargs="+") parser_hold.set_defaults(func=function) function = commands.info parser_info = subparsers.add_parser("info", parents=[parser_teach], description=function.__doc__) parser_info.add_argument("package") parser_info.set_defaults(func=function) function = commands.init parser_init = subparsers.add_parser("init", description=function.__doc__) parser_init.set_defaults(func=function) function = commands.install parser_install = subparsers.add_parser("install", parents=[parser_recommends, parser_yesno, parser_auth, parser_dist, parser_fileinput, parser_teach], aliases="isntall autoinstall".split(), description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_install.add_argument("packages", nargs="+") parser_install.set_defaults(func=function) function = commands.installsuggested parser_installsuggested = subparsers.add_parser("installsuggested", parents=[parser_recommends, parser_yesno, parser_auth, parser_dist, parser_teach], aliases="installs suggested install-suggested".split(), description=function.__doc__) parser_installsuggested.add_argument("package") parser_installsuggested.set_defaults(func=function) function = commands.integrity parser_integrity = subparsers.add_parser("integrity", parents=[parser_teach], description=function.__doc__) parser_integrity.set_defaults(func=function) function = commands.large parser_large = subparsers.add_parser("large", description=function.__doc__) parser_large.set_defaults(func=function) function = commands.lastupdate parser_lastupdate = subparsers.add_parser("lastupdate", aliases=["last-update"], parents=[parser_teach], description=function.__doc__) parser_lastupdate.set_defaults(func=function) function = commands.listalternatives parser_listalternatives = subparsers.add_parser("listalternatives", parents=[parser_teach], aliases="listalts list-alternatives".split(), description=function.__doc__) parser_listalternatives.set_defaults(func=function) function = commands.listall parser_listall = subparsers.add_parser("listall", aliases=["list-all"], parents=[parser_teach, parser_grep], description=function.__doc__) parser_listall.set_defaults(func=function) function = commands.listcache parser_listcache = subparsers.add_parser("listcache", aliases=["list-cache"], parents=[parser_teach, parser_grep], description=function.__doc__) parser_listcache.set_defaults(func=function) function = commands.listcommands parser_commands = subparsers.add_parser("listcommands", aliases="commands list-commands".split(), parents=[parser_grep], description=function.__doc__) parser_commands.set_defaults(func=function) function = commands.listdaemons parser_listdaemons = subparsers.add_parser("listdaemons", aliases=["list-daemons"], parents=[parser_teach], description=function.__doc__) parser_listdaemons.set_defaults(func=function) function = commands.listfiles parser_listfiles = subparsers.add_parser("listfiles", aliases=["list-files"], parents=[parser_teach], description=function.__doc__) parser_listfiles.add_argument("package") parser_listfiles.set_defaults(func=function) function = commands.listhold parser_listhold = subparsers.add_parser("listhold", aliases=["list-hold"], description=function.__doc__) parser_listhold.set_defaults(func=function) function = commands.listinstalled parser_listinstalled = subparsers.add_parser("listinstalled", aliases=["list-installed"], parents=[parser_teach, parser_grep], description=function.__doc__) parser_listinstalled.set_defaults(func=function) function = commands.listnames parser_listnames = subparsers.add_parser("listnames", aliases=["list-names"], parents=[parser_teach, parser_grep], description=function.__doc__) parser_listnames.set_defaults(func=function) function = commands.listpackages parser_listpackages = subparsers.add_parser("listpackages", parents=[parser_teach, parser_grep], aliases="list list-packages".split(), description=function.__doc__) parser_listpackages.set_defaults(func=function) function = commands.listscripts parser_listscripts = subparsers.add_parser("listscripts", aliases=["list-scripts"], parents=[parser_teach], description=function.__doc__) parser_listscripts.add_argument("debfile") parser_listscripts.set_defaults(func=function) function = commands.listsection parser_listsection = subparsers.add_parser("listsection", aliases=["list-section"], description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_listsection.add_argument("section") parser_listsection.set_defaults(func=function) function = commands.listsections parser_listsections = subparsers.add_parser("listsections", aliases=["list-sections"], description=function.__doc__) parser_listsections.set_defaults(func=function) function = commands.liststatus parser_liststatus = subparsers.add_parser("liststatus", aliases=["list-status"], parents=[parser_teach, parser_grep], description=function.__doc__) parser_liststatus.set_defaults(func=function) function = commands.madison parser_madison = subparsers.add_parser("madison", parents=[parser_teach], description=function.__doc__) parser_madison.add_argument("packages", nargs="+") parser_madison.set_defaults(func=function) function = commands.move parser_move = subparsers.add_parser("move", parents=[parser_teach], description=function.__doc__) parser_move.set_defaults(func=function) function = commands.new parser_new = subparsers.add_parser("new", parents=[parser_verbose], description=function.__doc__) parser_new.set_defaults(func=function) function = commands.newdetail parser_newdetail = subparsers.add_parser("newdetail", aliases="detailnew detail-new new-detail".split(), description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_newdetail.set_defaults(func=function) function = commands.news parser_news = subparsers.add_parser("news", parents=[parser_teach], description=function.__doc__) parser_news.add_argument("package") parser_news.set_defaults(func=function) function = commands.nonfree parser_nonfree = subparsers.add_parser("nonfree", aliases=["non-free"], parents=[parser_teach], description=function.__doc__) parser_nonfree.set_defaults(func=function) function = commands.orphans parser_orphans = subparsers.add_parser("orphans", parents=[parser_teach], aliases="orphaned listorphaned listorphans".split(), description=function.__doc__) parser_orphans.set_defaults(func=function) function = commands.policy parser_policy = subparsers.add_parser("policy", parents=[parser_teach], aliases=["available"], description=function.__doc__) parser_policy.add_argument("packages", nargs="+") parser_policy.set_defaults(func=function) function = commands.purge parser_purge = subparsers.add_parser("purge", aliases=["purgedepend"], parents=[parser_yesno, parser_auth, parser_fileinput, parser_teach], description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_purge.add_argument("packages", nargs="+") parser_purge.set_defaults(func=function) function = commands.purgeorphans parser_purgeorphans = subparsers.add_parser("purgeorphans", aliases=["purge-orphans"], parents=[parser_yesno], description=function.__doc__) parser_purgeorphans.set_defaults(func=function) function = commands.purgeremoved parser_purgeremoved = subparsers.add_parser("purgeremoved", aliases=["purge-removed"], description=function.__doc__) parser_purgeremoved.set_defaults(func=function) function = commands.rbuilddeps parser_rbuilddeps = subparsers.add_parser("rbuilddeps", parents=[parser_teach], aliases="rbuilddep reversebuilddeps reverse-build-deps".split(), description=function.__doc__) parser_rbuilddeps.add_argument("package") parser_rbuilddeps.set_defaults(func=function) function = commands.readme parser_readme = subparsers.add_parser("readme", parents=[parser_teach], formatter_class=argparse.RawDescriptionHelpFormatter, description=function.__doc__) parser_readme.add_argument("package") parser_readme.set_defaults(func=function) function = commands.recdownload parser_recdownload = subparsers.add_parser("recdownload", parents=[parser_auth, parser_teach], aliases="recursive rec-download".split(), description=function.__doc__) parser_recdownload.add_argument("packages", nargs="+") parser_recdownload.set_defaults(func=function) function = commands.recommended parser_recommended = subparsers.add_parser("recommended", parents=[parser_teach], description=function.__doc__) parser_recommended.set_defaults(func=function) function = commands.reconfigure parser_reconfigure = subparsers.add_parser("reconfigure", parents=[parser_teach], description=function.__doc__) parser_reconfigure.add_argument("packages", nargs="+") parser_reconfigure.set_defaults(func=function) function = commands.reinstall parser_reinstall = subparsers.add_parser("reinstall", aliases=["re-install"], parents=[parser_yesno, parser_auth, parser_teach], description=function.__doc__) parser_reinstall.add_argument("packages", nargs="+") parser_reinstall.set_defaults(func=function) function = commands.reload parser_reload = subparsers.add_parser("reload", parents=[parser_teach], description=function.__doc__) parser_reload.add_argument("daemon") parser_reload.set_defaults(func=function) function = commands.remove parser_remove = subparsers.add_parser("remove", parents=[parser_yesno, parser_auth, parser_fileinput, parser_teach], description=function.__doc__) parser_remove.add_argument("packages", nargs="+") parser_remove.set_defaults(func=function) function = commands.removeorphans parser_removeorphans = subparsers.add_parser("removeorphans", aliases=["remove-orphans"], parents=[parser_yesno], description=function.__doc__) parser_removeorphans.set_defaults(func=function) function = commands.repackage parser_repackage = subparsers.add_parser("repackage", parents=[parser_teach], aliases=["package"], description=function.__doc__) parser_repackage.add_argument("package") parser_repackage.set_defaults(func=function) function = commands.reportbug parser_reportbug = subparsers.add_parser("reportbug", parents=[parser_teach], aliases="bug bugreport".split(), description=function.__doc__) parser_reportbug.add_argument("package") parser_reportbug.set_defaults(func=function) function = commands.restart parser_restart = subparsers.add_parser("restart", parents=[parser_teach], description=function.__doc__) parser_restart.add_argument("daemon") parser_restart.set_defaults(func=function) function = commands.rpm2deb parser_rpm2deb = subparsers.add_parser("rpm2deb", parents=[parser_teach], aliases=["rpmtodeb"], description=function.__doc__) parser_rpm2deb.add_argument("rpm") parser_rpm2deb.set_defaults(func=function) function = commands.rpminstall parser_rpminstall = subparsers.add_parser("rpminstall", aliases=["rpm-install"], parents=[parser_teach], description=function.__doc__) parser_rpminstall.add_argument("rpm") parser_rpminstall.set_defaults(func=function) function = commands.search parser_search = subparsers.add_parser("search", parents=[parser_teach], description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_search.add_argument("patterns", nargs="+") help=("'-v' will also search short package desciption; " "'-vv' will also search the short and long decription") parser_search.add_argument("-v", "--verbose", action="count", help=help) parser_search.set_defaults(func=function) function = commands.searchapt parser_searchapt = subparsers.add_parser("searchapt", parents=[parser_teach], aliases=["search-apt"], description=function.__doc__) parser_searchapt.add_argument("dist") parser_searchapt.set_defaults(func=function) function = commands.show parser_show = subparsers.add_parser("show", parents=[parser_fast, parser_teach], aliases="detail details".split(), description=function.__doc__) parser_show.add_argument("packages", nargs="+") parser_show.set_defaults(func=function) function = commands.sizes parser_sizes = subparsers.add_parser("sizes", parents=[parser_teach], aliases=["size"], description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_sizes.add_argument("packages", nargs="*") parser_sizes.set_defaults(func=function) function = commands.snapshot parser_snapshot = subparsers.add_parser("snapshot", parents=[parser_teach], description=function.__doc__) parser_snapshot.set_defaults(func=function) function = commands.source parser_source = subparsers.add_parser("source", parents=[parser_teach], description=function.__doc__) parser_source.add_argument("packages", nargs="+") parser_source.set_defaults(func=function) function = commands.start parser_start = subparsers.add_parser("start", parents=[parser_teach], description=function.__doc__) parser_start.add_argument("daemon") parser_start.set_defaults(func=function) function = commands.status parser_status = subparsers.add_parser("status", parents=[parser_teach], description=function.__doc__) parser_status.add_argument("packages", nargs="+") parser_status.set_defaults(func=function) function = commands.statusmatch parser_statusmatch = subparsers.add_parser("statusmatch", parents=[parser_teach], aliases="statussearch status-search status-match".split(), description=function.__doc__) parser_statusmatch.add_argument("pattern") parser_statusmatch.set_defaults(func=function) function = commands.stop parser_stop = subparsers.add_parser("stop", parents=[parser_teach], description=function.__doc__) parser_stop.add_argument("daemon") parser_stop.set_defaults(func=function) function = commands.aptlog parser_aptlog = subparsers.add_parser("aptlog", parents=[parser_teach], description=function.__doc__) parser_aptlog.set_defaults(func=function) function = commands.listlog parser_listlog = subparsers.add_parser("listlog", aliases=["list-log"], parents=[parser_teach], description=function.__doc__) parser_listlog.set_defaults(func=function) function = commands.tasksel parser_tasksel = subparsers.add_parser("tasksel", parents=[parser_teach], description=function.__doc__) parser_tasksel.set_defaults(func=function) function = commands.todo parser_todo = subparsers.add_parser("todo", parents=[parser_teach], description=function.__doc__) parser_todo.add_argument("package") parser_todo.set_defaults(func=function) function = commands.toupgrade parser_toupgrade = subparsers.add_parser("toupgrade", aliases="newupgrades new-upgrades to-upgrade".split(), description=function.__doc__) parser_toupgrade.set_defaults(func=function) function = commands.tutorial parser_tutorial = subparsers.add_parser("tutorial", aliases="doc docs documentation".split(), description=function.__doc__) parser_tutorial.set_defaults(func=function) function = commands.unhold parser_unhold = subparsers.add_parser("unhold", parents=[parser_teach], description=function.__doc__) parser_unhold.add_argument("packages", nargs="+") parser_unhold.set_defaults(func=function) function = commands.unofficial parser_unofficial = subparsers.add_parser("unofficial", parents=[parser_teach], aliases="findpkg findpackage".split(), description=function.__doc__) parser_unofficial.add_argument("package") parser_unofficial.set_defaults(func=function) function = commands.update parser_update = subparsers.add_parser("update", parents=[parser_teach], description=function.__doc__) parser_update.set_defaults(func=function) function = commands.updatealternatives parser_updatealternatives = subparsers.add_parser("updatealternatives", parents=[parser_teach], aliases=("updatealts update-alts setalts set-alts setalternatives" "set-alternatives update-alternatives").split(), description=function.__doc__) parser_updatealternatives.add_argument("alternative") parser_updatealternatives.set_defaults(func=function) function = commands.updatepciids parser_updatepciids = subparsers.add_parser("updatepciids", aliases="update-pciids update-pci-ids".split(), parents=[parser_teach], description=function.__doc__) parser_updatepciids.set_defaults(func=function) function = commands.updateusbids parser_updateusbids = subparsers.add_parser("updateusbids", aliases="update-usbids update-usb-ids".split(), parents=[parser_teach], description=function.__doc__) parser_updateusbids.set_defaults(func=function) function = commands.upgrade parser_upgrade = subparsers.add_parser("upgrade", parents=[parser_backup, parser_yesno, parser_auth, parser_teach, parser_local], formatter_class=argparse.RawDescriptionHelpFormatter, description=function.__doc__) parser_upgrade.set_defaults(func=function) function = commands.upgradesecurity parser_upgradesecurity = subparsers.add_parser("upgradesecurity", aliases=["upgrade-security"], parents=[parser_teach], description=function.__doc__) parser_upgradesecurity.set_defaults(func=function) function = commands.verify parser_verify = subparsers.add_parser("verify", parents=[parser_teach], description=function.__doc__) parser_verify.add_argument("package") parser_verify.set_defaults(func=function) function = commands.versions parser_versions = subparsers.add_parser("versions", parents=[parser_teach], description=function.__doc__) parser_versions.add_argument("packages", nargs="*") parser_versions.set_defaults(func=function) function = commands.whichpackage parser_whichpackage = subparsers.add_parser("whichpackage", parents=[parser_teach], aliases=("findfile find-file locate filesearch file-search whichpkg " "which-package").split(), description=function.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser_whichpackage.add_argument("pattern", help="partial/full file path") parser_whichpackage.set_defaults(func=function) result = parser.parse_args() try: result.recommends = "--install-recommends" if result.recommends else "" except AttributeError: pass try: result.local = "--no-download --ignore-missing" if result.local else "" except AttributeError: pass try: result.recommends = "--no-install-recommends" if result.norecommends else "" except AttributeError: pass try: if not result.dist: result.dist = "" except AttributeError: pass try: result.noauth = " --allow-unauthenticated " if result.noauth else "" except AttributeError: pass try: result.yes = " --yes " if result.yes else "" except AttributeError: pass try: if result.simulate: perform.SIMULATE = True except AttributeError: pass try: if result.teach: perform.TEACH = True except AttributeError: pass result.func(result) if __name__ == '__main__': try: main() except KeyboardInterrupt: pass wajig/src/shell.py0000755000000000000000000000137512252410415011322 0ustar #!/usr/bin/python3 # # This file is part of wajig. The copyright file is at debian/copyright. import subprocess import readline import os import atexit HISTFILE = os.path.join(os.environ["HOME"], ".wajig", ".wajig-history") def main(): try: readline.read_history_file(HISTFILE) except IOError: pass readline.parse_and_bind('tab: complete') while True: command_line = input("wajig> ") if command_line in "exit quit bye".split(): return if command_line: command = "wajig " + command_line subprocess.call(command.split()) if __name__ == "__main__": try: main() except EOFError: print() atexit.register(readline.write_history_file, HISTFILE) wajig/src/util.py0000644000000000000000000004527512266755606011217 0ustar # This file is part of wajig. The copyright file is at debian/copyright. "Contains miscellaneous utilities." import os import sys import tempfile import re import socket from datetime import datetime import time import apt import apt_pkg import perform #------------------------------------------------------------------------ # # LOCATIONS # # init_dir # # Wajig can be run on several machines sharing the same home # directories (often through NFS) so we need to have host specific # status files. Make sure the directories exist. # #------------------------------------------------------------------------ init_dir = os.path.expanduser("~/.wajig/") + socket.gethostname() if not os.path.exists(init_dir): os.makedirs(init_dir) # # Temporarily, remove old files from .wajig # After a few versions remove this code. # tmp_dir = os.path.expanduser("~/.wajig") if os.path.exists(tmp_dir + "/Available"): os.rename(tmp_dir + "/Available", init_dir + "/Available") if os.path.exists(tmp_dir + "/Available.prv"): os.rename(tmp_dir + "/Available.prv", init_dir + "/Available.prv") if os.path.exists(tmp_dir + "/Installed"): os.rename(tmp_dir + "/Installed", init_dir + "/Installed") # 100104 Remove any old tmp files. Bug#563573 perform.execute("rm -f " + init_dir + "/tmp*") # TODO 23 Aug 2003 # # Perhaps the only file that wajig needs to cache itself is # Available.prv - the other two can be generated dynamically. # Installed is now like this. Available can be done. # This would mean essentially half the space usage (Installed # is quite small at 30K, while Available and Available.prv # were 280K). This is significant for a user who manages # many hosts. # # If this is the case, then don't worry about creating a host # subdirectory in ~/.wajig. Simply use host in filename, # unless init_dir is used elsewhere?????? Perhaps keep as folder # since tempfiles are created there. # # TODO Work to use bzip2 files for available and previous. # Then bunzip2 to temporary files when needed! # Disk usage goes from 274K to 83K. new_file = init_dir + "/New" if not os.path.exists(new_file): with open(new_file, 'w'): pass available_file = init_dir + "/Available" previous_file = init_dir + "/Available.prv" # Set the temporary directory to the init_dir. # Large files are not generally written there so should be okay. tempfile.tempdir = init_dir def newly_available(verbose=False): """display brand-new packages.. technically new package names""" with open(new_file) as f: packages = f.readlines() if verbose: for package in packages: perform.execute('aptitude show ' + package) else: do_describe([package.strip() for package in packages], die=False) def update_available(noreport=False): """Generate current list of available packages, backing up the old list """ if not os.path.exists(available_file): f = open(available_file, "w") f.close() temporary_file = tempfile.mkstemp()[1] os.rename(available_file, temporary_file) # sort --unique so packages with more that one architecture are included # only once. This makes the count shown by "update" consistent with the # output of "toupgrade", though not necessarily with the list shown # by "upgrade" (really "apt-get --show-upgraded upgrade"), which might # show amd64 and i386 versions. command = ("apt-cache dumpavail " "| egrep '^(Package|Version):' " "| tr '\n' ' '" "| perl -p -e 's|Package: |\n|g; s|Version: ||g'" "| sort -u -k 1b,1 | tail -n +2 | sed 's| $||' > ") \ + available_file # Use langC in the following since it uses a grep. perform.execute(command, langC=True) # root is not required. os.rename(temporary_file, previous_file) available_packages = open(available_file).readlines() previous_packages = open(previous_file).readlines() diff = len(available_packages) - len(previous_packages) temporary_file = tempfile.mkstemp()[1] # 090425 Use langC=True to work with change from coreutils 6.10 to 7.2 command = "join -v 1 -t' ' {0} {1} | cut -d' ' -f 1 | tee {2} | wc -l" command = command.format(available_file, previous_file, temporary_file) newest = perform.execute(command, pipe=True, langC=True) newest = newest.readlines()[0].strip() if newest != "0": os.rename(temporary_file, new_file) else: os.remove(temporary_file) if not noreport: if diff < 0: direction = str(0 - diff) + " down on" elif diff == 0: direction = "the same as" else: direction = str(diff) + " up on" print("This is " + direction + " the previous count", end=' ') print("with " + newest + " new", end=' ') if newest == "1": print("package.") else: print("packages.") def gen_installed_command_str(): """Generate command to list installed packages and their status.""" # Use sort --unique. See comment in update_available(). command = ("cat /var/lib/dpkg/status | " "egrep '^(Package|Status|Version):' | " "awk '/^Package: / {pkg=$2} " " /^Status: / {s1=$2;s2=$3;s3=$4}" " /^Version: / {print pkg,$2,s1,s2,s3}' | " "grep 'ok installed' | awk '{print $1,$2}' | sort -u -k 1b,1") return command def count_upgrades(): """Return as a string the number of new upgrades since last update.""" ifile = tempfile.mkstemp()[1] # Use langC in the following since it uses a grep. perform.execute(gen_installed_command_str() + " > " + ifile, langC=True) command = ("join %s %s |" "awk '$2 != $3 {print}' | sort -k 1b,1 | join - %s |" "awk '$4 != $3 {print}' | wc -l | awk '{print $1}' ") % \ (previous_file, available_file, ifile) # 090425 Use langC=True to work with change from coreutils 6.10 to 7.2 count = perform.execute(command, pipe=True, langC=True).read().split()[0] if os.path.exists(ifile): os.remove(ifile) return count def reset_files(): if os.path.exists(available_file): os.remove(available_file) if os.path.exists(previous_file): os.remove(previous_file) update_available(noreport=True) def ensure_initialised(): """Create the init_dir and files if they don't exist.""" if not os.path.exists(available_file): reset_files() def backup_before_upgrade(packages, distupgrade=False): """Backup packages before a (dist)upgrade. This optional functionality helps recovery in case of trouble caused by the newly-installed packages. The packages are by default stored in a directory named like ~/.wajig/hostname/backups/2010-09-21_09h21.""" date = time.strftime("%Y-%m-%d_%Hh%M", time.localtime()) target = os.path.join(init_dir, "backups", date) if not os.path.exists(target): os.makedirs(target) os.chdir(target) print("The packages will saved in", target) for package in packages: command = "fakeroot -u dpkg-repack " + package perform.execute(command) def requires_package(package, path=None): import shutil if not path: path = package if shutil.which(path): return True print("This command depends on '{}' being installed".format(package)) sys.exit(1) def package_exists(cache, package, ignore_virtual_packages=False): try: if cache.is_virtual_package(package) and not ignore_virtual_packages: return cache.get_providing_packages(package)[0] return cache[package] except KeyError as error: print(error.args[0]) sys.exit(1) def upgradable(distupgrade=False, get_names_only=True): "Checks if the system is upgradable." cache = apt.Cache() cache.upgrade(distupgrade) if get_names_only: packages = [package.name for package in cache.get_changes()] else: packages = [package for package in cache.get_changes()] return packages def local_changelog(package, tmp): """Retrieve Debian changelog from local installation.""" changelog = "/usr/share/doc/" + package + "/changelog.Debian.gz" changelog_native = "/usr/share/doc/" + package + "/changelog.gz" if os.path.exists(changelog): return "zcat {0} >> {1}".format(changelog, tmp) elif os.path.exists(changelog_native): return "zcat {0} >> {1}".format(changelog_native, tmp) else: print("Package", package, "is likely broken (changelog not found)!") def extract_dependencies(package, dependency_type="Depends"): """Produce all Dependencies of a particular type""" if not package.candidate: return for dependency_list in package.candidate.get_dependencies(dependency_type): for dependency in dependency_list.or_dependencies: yield dependency.name def do_describe(packages, verbose=False, die=True): """Display package description(s)""" package_files = [package for package in packages if package.endswith(".deb")] package_names = [package for package in packages if not package.endswith(".deb")] if package_files: for package_file in package_files: perform.execute("dpkg-deb --info " + package_file) print("="*72) sys.stdout.flush() if package_names: packages = package_names else: return if not packages: print("No packages found from those known to be available/installed.") else: packageversions = list() cache = apt.cache.Cache() for package in packages: try: package = cache[package] except KeyError as e: import subprocess command = 'dpkg --print-foreign-architectures'.split() output = subprocess.check_output(command) for arch in output.decode().split(): try: package = cache["{}:{}".format(package, arch)] # to avoid noise, only consider the 1st match break except KeyError: pass if not isinstance(package, apt.package.Package) and die: print(str(e).strip('"')) return 1 packageversion = package.installed if not packageversion: # if package is not installed... packageversion = package.candidate packageversions.append((package.shortname, packageversion.summary, packageversion.description)) packageversions = set(packageversions) if verbose: for packageversion in packageversions: print("{}: {}\n{}\n".format(packageversion[0], packageversion[1], packageversion[2])) else: print("{0:24} {1}".format("Package", "Description")) print("="*24 + "-" + "="*51) for packageversion in packageversions: print("%-24s %s" % (packageversion[0], packageversion[1])) def show_package_versions(): packages = upgradable(get_names_only=False) if packages: print("{:<24} {:<24} {}".format("Package", "Available", "Installed")) print("="*24 + "-" + "="*24 + "-" + "="*24) for package in sorted(packages): print("{:<24} {:<24} {}".format(package.name, package.candidate.version, package.installed.version)) return packages def display_sys_docs(package, filenames): """This services README and NEWS commands""" docpath = os.path.join("/usr/share/doc", package) if not os.path.exists(docpath): if package_exists(apt.Cache(), package): print("'{}' is not installed".format(package)) return found = False for filename in filenames: path = os.path.join(docpath, filename) cat = "cat" if not os.path.exists(path): path += ".gz" cat = "zcat" if os.path.exists(path): found = True print("{0:=^72}".format(" {0} ".format(filename))) sys.stdout.flush() perform.execute(cat + " " + path) if not found: print("File not found") def do_status(packages, snapshot=False): """List status of the packages identified""" if not snapshot: print("%-23s %-15s %-15s %-15s %s" % \ ("Package", "Installed", "Previous", "Now", "State")) print("="*23 + "-" + "="*15 + "-" + "="*15 + "-" + "="*15 + "-" + "="*5) sys.stdout.flush() # Generate a temporary file of installed packages. ifile = tempfile.mkstemp()[1] perform.execute(gen_installed_command_str() + " > " + ifile, langC=True) # Build the command to list the status of installed packages. command = "dpkg --get-selections | sort | join - " + ifile + " | " +\ "join -a 1 - " + previous_file + " | " +\ "awk 'NF==3 {print $0, \"N/A\"; next}{print}' | " +\ "join -a 1 - " + available_file + " | " +\ "awk 'NF==4 {print $0, \"N/A\"; next}{print}' | " if len(packages) > 0: # Use grep, not egrep, otherwise g++ gets lost, for example! command = command + "grep '^\($" for i in packages: command = command + " \|" + i command = command + " \)' |" command = command +\ "awk '{printf(\"%-20s\\t%-15s\\t%-15s\\t%-15s\\t%-2s\\n\", " +\ "$1, $3, $4, $5, $2)}'" if snapshot: fobj = perform.execute(command, pipe=True) for l in fobj: print("=".join(l.split()[0:2])) else: perform.execute(command, langC=True) # Check whether the package is not in the installed list, and if not # list its status appropriately. for i in packages: if perform.execute("egrep '^" + i + " ' " + ifile + " >/dev/null"): # Package is not installed. command = \ "join -a 2 " + previous_file + " " + available_file + " | " +\ "awk 'NF==2 {print $1, \"N/A\", $2; next}{print}' | " +\ "egrep '^" + i + " '" command = command +\ " | awk '{printf(\"%-20s\\t%-15s\\t%-15s\\t%-15s\\n\", " +\ "$1, \"N/A\", $2, $3)}'" perform.execute(command, langC=True) # Tidy up - remove the "installed file" if os.path.exists(ifile): os.remove(ifile) def do_listnames(pattern=False, pipe=False): # If user can't access /etc/apt/sources.list then must do this with # sudo or else most packages will not be found. needsudo = not os.access("/etc/apt/sources.list", os.R_OK) if pattern: command = "apt-cache pkgnames | grep -- " + pattern \ + " | sort -k 1b,1" else: command = "apt-cache pkgnames | sort -k 1b,1" # Start fix for Bug #292581 - pre-run command to check for no output results = perform.execute(command, root=needsudo, pipe=True) if results: lines = results.readlines() if lines: return perform.execute(command, root=needsudo, pipe=pipe) else: sys.exit(1) def do_update(simulate=False): if not perform.execute("apt-get update", root=True): if not simulate: update_available() print("There are {} new upgrades".format(count_upgrades())) def get_deps_recursively(cache, package, packages): if not package in packages: packages.append(package) for package_name in \ extract_dependencies(package_exists(cache, package)): if package_name not in packages: packages.append(package_name) get_deps_recursively(cache, package_name, packages) return packages def consolidate_package_names(args): packages = list() filelist = list() if args.fileinput: for path in args.packages: if os.path.isfile(path): with open(path) as f: packages.extend(f.read().split()) filelist.append(path) packages.extend(args.packages) # filenames are not package names; this feels like a hack for filename in filelist: packages.remove(filename) return set(packages) def sizes(packages=None, size=0): status = apt_pkg.TagFile(open("/var/lib/dpkg/status", "r")) size_list = dict() status_list = dict() for section in status: package_name = section.get("Package") package_size = section.get("Installed-Size") package_status = re.split(" ", section.get("Status"))[2] if package_size and int(package_size) > size: if package_name not in size_list: size_list[package_name] = package_size status_list[package_name] = package_status packages = list(size_list) packages.sort(key=lambda x: int(size_list[x])) # sort by size if packages: print("{:<33} {:^10} {:>12}".format("Package", "Size (KB)", "Status")) print("{}-{}-{}".format("="*33, "="*10, "="*12)) for package in packages: message = "{:<33} {:^10} {:>12}".format(package, format(int(size_list[package]), ',d'), status_list[package]) print(message) else: print("No packages of >10MB size found") log_file = os.path.join(init_dir, 'Log') def start_log(old_log): "Write a list of installed packages to a tmp file." perform.execute(gen_installed_command_str() + " > " + old_log, langC=True) def finish_log(old_log): ts = datetime.strftime(datetime.now(), '%Y-%m-%dT%H:%M:%S') # Generate new list of installed and compare to old lf = open(log_file, "a") new_iter = perform.execute(gen_installed_command_str(), langC=True, pipe=True) old_iter = open(old_log) for o in old_iter: o = o.strip().split(" ") n = new_iter.__next__().strip().split(" ") while o[0] != n[0]: if o[0] < n[0]: lf.write("{0} {1} {2} {3}\n".format(ts, "remove", o[0], o[1])) o = old_iter.__next__().strip().split(" ") elif o[0] > n[0]: lf.write("{0} {1} {2} {3}\n".format(ts, "install", n[0], n[1])) n = new_iter.__next__().strip().split(" ") if o[1] != n[1]: old_version = o[1].split(".") # for a more accurate comparison new_version = n[1].split(".") # same if old_version > new_version: lf.write("{0} {1} {2} {3}\n".format(ts, "downgrade", n[0], n[1])) else: lf.write("{0} {1} {2} {3}\n".format(ts, "upgrade", n[0], n[1])) os.remove(old_log) wajig/src/commands.py0000644000000000000000000010452112253102272012006 0ustar # This file is part of wajig. The copyright file is at debian/copyright. """Implementation of all COMMANDs""" # Do not include any function in here that does not correspond to a COMMAND import os import sys import inspect import tempfile import subprocess import urllib.request import webbrowser import apt # wajig modules import perform import util import debfile # before we do any other command make sure the right files exist util.ensure_initialised() def addcdrom(args): """Add a Debian CD/DVD to APT's list of available sources""" perform.execute("/usr/bin/apt-cdrom add", root=True) def addrepo(args): """Add a Launchpad PPA (Personal Package Archive) repository An example that shows how to add the daily builds of Google's Chromium browser: $ wajig addrepo ppa:chromium-daily""" util.requires_package("add-apt-repository") perform.execute("/usr/bin/add-apt-repository " + args.ppa, root=True) def aptlog(args): """Display APT log file""" perform.execute("cat /var/log/apt/history.log") def autoalts(args): """Mark the Alternative to be auto-set (using set priorities)""" perform.execute("/usr/sbin/update-alternatives --auto " + args.alternative, root=True) def autodownload(args): """Do an update followed by a download of all updated packages""" util.do_update(args.simulate) command = ("/usr/bin/apt-get --download-only --show-upgraded --assume-yes " "--force-yes dist-upgrade") perform.execute(command, root=True) if not args.simulate: upgradable_packages = util.upgradable() if upgradable_packages: util.do_describe(upgradable_packages, verbose) else: print("no upgradable packages") util.show_package_versions() def autoclean(args): """Remove no-longer-downloadable .deb files from the download cache""" perform.execute("/usr/bin/apt-get autoclean", root=True) def autoremove(args): """Remove unused dependency packages""" perform.execute("/usr/bin/apt-get autoremove", root=True, log=True) def build(args): """Get source packages, unpack them, and build binary packages from them. This also installs the needed build-dependencies if needed.""" util.requires_package("sudo") # First make sure dependencies are met if not builddeps(args): command = "apt-get {} source --build " + " ".join(args.packages) command = command.format(args.noauth) perform.execute(command) def builddeps(args): """Install build-dependencies for given packages""" command = "/usr/bin/apt-get {} {} build-dep " + " ".join(args.packages) command = command.format(args.yes, args.noauth) return perform.execute(command, root=True, log=True) def changelog(args): """Display Debian changelog of a package network on: changelog - if there's newer entries, display them -v changelog - if there's newer entries, display them, and proceed to display complete local changelog network off: changelog - if there's newer entries, mention failure to retrieve -v changelog - if there's newer entries, mention failure to retrieve, and proceed to display complete local changelog""" package = util.package_exists(apt.Cache(), args.package) changelog = "{:=^79}\n".format(" {} ".format(args.package)) # header try: changelog += package.get_changelog() except AttributeError as e: # This is caught so as to avoid an ugly python-apt trace; it's a bug # that surfaces when: # 1. The package is not available in the default Debian suite # 2. The suite the package belongs to is set to a pin of < 0 print("If this package is not on your default Debian suite, " \ "ensure that its APT pinning isn't less than 0.") return help_message = "\nTo display the local changelog, run:\n" \ "wajig changelog --verbose " + args.package if "Failed to download the list of changes" in changelog: if not args.verbose: changelog += help_message else: changelog += "\n" elif changelog.endswith("The list of changes is not available"): changelog += ".\nYou are likely running the latest version.\n" if not args.verbose: changelog += help_message if not args.verbose: print(changelog) else: tmp = tempfile.mkstemp()[1] with open(tmp, "w") as f: if package.is_installed: changelog += "{:=^79}\n".format(" local changelog ") f.write(changelog) if package.is_installed: command = util.local_changelog(args.package, tmp) if not command: return perform.execute(command) with open(tmp) as f: for line in f: print(line, end="") def clean(args): """Remove all deb files from the download cache""" perform.execute("/usr/bin/apt-get clean", root=True) def contents(args): """List the contents of a package file (.deb)""" perform.execute("dpkg --contents " + args.debfile) def dailyupgrade(args): """Perform an update then a dist-upgrade""" util.do_update(args.simulate) perform.execute("/usr/bin/apt-get --show-upgraded dist-upgrade", root=True, log=True) def dependents(args): """Display packages which have some form of dependency on the given package Types of dependencies: * Depends * Recommends * Suggests * Replaces * Enhances""" DEPENDENCY_TYPES = [ "Depends", "Recommends", "Suggests", "Replaces", "Enhances", ] cache = apt.cache.Cache() package = util.package_exists(cache, args.package) dependents = { name : [] for name in DEPENDENCY_TYPES } for key in cache.keys(): other_package = cache[key] for dependency_type, specific_dependents in dependents.items(): if package.shortname in \ util.extract_dependencies(other_package, dependency_type): specific_dependents.append(other_package.shortname) for dependency_type, specific_dependents in dependents.items(): if specific_dependents: output = dependency_type.upper(), " ".join(specific_dependents) print("{}: {}".format(*output)) def describe(args): """Display one-line descriptions for the given packages""" util.do_describe(args.packages, args.verbose) def describenew(args): """Display one-line descriptions of newly-available packages This produces the same output as 'wajig new'""" util.newly_available() def distupgrade(args): """Comprehensive system upgrade This may remove some packages in order to ensure no package is left stale. Use the more conservative 'upgrade' command to avoid that. """ packages = util.upgradable(distupgrade=True) if not packages and not args.dist: print('No upgrades. Did you run "wajig update" beforehand?') return if args.backup: util.requires_package("dpkg-repack") util.requires_package("fakeroot") util.backup_before_upgrade(packages, distupgrade=True) cmd = "/usr/bin/apt-get --show-upgraded {} {} {} ".format(args.local, args.yes, args.noauth) if args.dist: cmd += "--target-release " + args.dist + " " cmd += "dist-upgrade" perform.execute(cmd, root=True, log=True) def download(args): """Download one or more packages without installing them""" print("Packages being downloaded to /var/cache/apt/archives/") command = "/usr/bin/apt-get --reinstall --download-only install " packages = util.consolidate_package_names(args) command = command + " ".join(packages) perform.execute(command, root=True) def editsources(args): """Edit list of Debian repository locations for packages""" editor = ( os.environ.get('VISUAL') or os.environ.get('EDITOR') or '/usr/bin/sensible-editor' ) perform.execute(editor + ' /etc/apt/sources.list', root=True) def extract(args): """Extract the files from a package file to a directory""" command = "dpkg --extract {} {}" command = command.format(args.debfile, args.destination_directory) perform.execute(command) def fixconfigure(args): """Fix an interrupted install""" perform.execute("/usr/bin/dpkg --configure --pending", root=True) def fixinstall(args): """Fix an install interrupted by broken dependencies""" command = "/usr/bin/apt-get --fix-broken {} install".format(args.noauth) perform.execute(command, root=True, log=True) def fixmissing(args): """Fix and install even though there are missing dependencies""" command = "/usr/bin/apt-get --ignore-missing {} upgrade".format(args.noauth) perform.execute(command, root=True, log=True) def force(args): """Install packages and ignore file overwrites and depends note: This is useful when there is a conflict of the same file from multiple packages or when a dependency is not installed for whatever reason""" command = "/usr/bin/dpkg --install --force overwrite --force depends " archives = "/var/cache/apt/archives/" # For a .deb file we simply force install it. if args.packages[0].endswith(".deb"): for package in args.packages: if os.path.exists(package): command += "'" + package + "' " elif os.path.exists(archives + package): command += "'" + archives + package + "' " else: message = ("File {} not found. " "Searched current directory and {}." "Please confirm the location and try again.") print(message.format(package, archives)) return() else: # Package names rather than a specific deb package archive # is expected. for package in args.packages: # Identify the latest version of the package available in # the download archive, if there is any there. lscmd = "ls " + archives lscmd += " | grep -E '^" + package + "_' | sort -k 1b,1 | tail -n -1" matches = perform.execute(lscmd, pipe=True) debpkg = matches.readline().strip() if not debpkg: dlcmd = "apt-get --quiet=2 --reinstall --download-only " dlcmd += "install '" + package + "'" perform.execute(dlcmd, root=1) matches = perform.execute(lscmd, pipe=True) debpkg = matches.readline().strip() # Force install the package from the download archive. command += "'" + archives + debpkg + "' " perform.execute(command, root=True, log=True) def hold(args): """Place packages on hold (so they will not be upgraded)""" for package in args.packages: # The dpkg needs sudo but not the echo. # Do all of it as root then! command = "/bin/echo \"" + package + " hold\" | /usr/bin/dpkg --set-selections" perform.execute(command, root=True) print("The following packages are on hold:") perform.execute("dpkg --get-selections | grep -E 'hold$' | cut -f1") def info(args): """List the information contained in a package file""" perform.execute("dpkg --info " + args.package) def init(args): """Initialise or reset wajig archive files""" util.reset_files() def install(args): """Package installer notes: * specifying a .deb file will also try to satisfy that deb's dependencies; * one can specify multiple files with --fileinput option * specifying a url will try fetch the file from the internet, and keep it in "~/.wajig/$HOSTNAME" example: $ wajig install a b_1.0_all.deb http://example.com/c_1.0_all.deb Assuming there's no errors, the command will install 3 packages named 'a', 'b', and 'c''""" packages = util.consolidate_package_names(args) online_files = [package for package in packages if package.startswith(("http://", "ftp://"))] deb_files = list() for package in online_files: if not package.endswith(".deb"): print("A valied .deb file should have a '.deb' extension") continue filename = os.path.join(util.init_dir, package.split("/")[-1]) try: response = urllib.request.urlopen(package) except urllib.error.HTTPError as error: print("{}; is '{}' the correct url?".format(error.reason, package)) else: with open(filename, "wb") as f: f.write(response.read()) deb_files.append(filename) deb_files.extend([package for package in packages if package.endswith(".deb") and os.path.exists(package)]) if deb_files: debfile.install(deb_files, args) packages = packages.difference(online_files, deb_files) if packages: if args.dist: args.dist = "--target-release " + args.dist command = "/usr/bin/apt-get {} {} {} {} --auto-remove install " command += " ".join(packages) command = command.format(args.yes, args.noauth, args.recommends, args.dist) perform.execute(command, root=True, log=True) def installsuggested(args): """Install a package and its Suggests dependencies""" cache = apt.cache.Cache() package = util.package_exists(cache, args.package, ignore_virtual_packages=True) dependencies = list(util.extract_dependencies(package, "Suggests")) for n, dependency in enumerate(dependencies): dependencies[n] = util.package_exists(cache, dependency).shortname dependencies = " ".join(dependencies) command = "/usr/bin/apt-get {} {} {} --auto-remove install {} {}" command = command.format(args.recommends, args.yes, args.noauth, dependencies, args.package) perform.execute(command, root=True, log=True) def integrity(args): """Check the integrity of installed packages (through checksums)""" perform.execute("debsums --all --silent") def large(args): """List size of all large (>10MB) installed packages""" util.sizes(size=10000) def lastupdate(args): """Identify when an update was last performed""" command = ("ls -l --full-time " + util.available_file + " 2> " "/dev/null | awk '{printf \"Last update was %s %s %s\\n\"" ", $6, $7, $8}' | sed 's|\.000000000||'") perform.execute(command) def listall(args): """List one line descriptions for all packages""" command = ("apt-cache dumpavail |" "grep -E \"^(Package|Description): \" |" "awk '/^Package: /{pkg=$2} /^Description: /" "{printf(\"%-24s %s\\n\", pkg," "substr($0,13))}' | sort -u -k 1b,1") if args.pattern: command = "{} | grep -E '{}'".format(command, args.pattern) perform.execute(command) def listcache(args): """List the contents of the download cache""" command = "printf 'Found %d files %s in the cache.\n\n'\ $(ls /var/cache/apt/archives/ | wc -l) \ $(ls -sh /var/cache/apt/archives/ | head -1 | awk '{print $2}')" perform.execute(command) command = "ls /var/cache/apt/archives/" if args.pattern: command = "{} | grep -E '{}'".format(command, args.pattern) perform.execute(command) def listalternatives(args): """List the objects that can have alternatives configured""" command = ("ls /etc/alternatives/ | " "grep -E -v '(\.1|\.1\.gz|\.8|\.8\.gz|README)$'") perform.execute(command) def listcommands(args): """Display all wajig commands""" for name, value in sorted(globals().items()): if inspect.isfunction(value): summary = value.__doc__.split('\n')[0] if args.pattern: if args.pattern not in summary and \ args.pattern not in name: continue print("{:<18} {}".format(name, summary)) def listdaemons(args): """List the daemons that wajig can start, stop, restart, or reload""" command = ("printf 'Found %d daemons in /etc/init.d.\n\n' " "$(ls /etc/init.d/ | " "grep -E -v '(~$|README|-(old|dist)|\.[0-9]*$)' | wc -l)") perform.execute(command) command = ("ls /etc/init.d/ | " "grep -E -v '(~$|README|-(old|dist)|\.[0-9]*$)' |" "pr --columns=3 --omit-header") perform.execute(command) def listfiles(args): """List the files that are supplied by the named package""" if args.package.endswith("deb"): perform.execute("dpkg --contents " + args.package) else: perform.execute("dpkg --listfiles " + args.package) def listhold(args): """List packages that are on hold (i.e. those that won't be upgraded)""" perform.execute("dpkg --get-selections | grep -E 'hold$' | cut -f1") def listinstalled(args): """List installed packages""" command = "dpkg --get-selections | cut -f1" if args.pattern: command += " | grep -E '{}' | sort -k 1b,1".format(args.pattern) perform.execute(command) def listlog(args): """Display wajig log file""" perform.execute("cat " + util.log_file) def listnames(args): """List all known packages; optionally filter the list with a pattern""" util.do_listnames(args.pattern) def listpackages(args): """List the status, version, and description of installed packages""" command = "dpkg --list '*' | grep -E -v 'no description avail'" if args.pattern: command += " | grep -E '{}' | sort -k 1b,1".format(args.pattern) perform.execute(command) def listscripts(args): """List the control scripts of the package of deb file""" package = args.debfile scripts = ["preinst", "postinst", "prerm", "postrm"] if package.endswith(".deb"): command = "ar p " + package + " control.tar.gz | tar ztvf -" pkgScripts = perform.execute(command, pipe=True).readlines() for script in scripts: if "./" + script in "".join(pkgScripts): nlen = int((72 - len(script)) / 2) print(">"*nlen, script, "<"*nlen) command = "ar p " + package + " control.tar.gz |" +\ "tar zxvf - -O ./" + script +\ " 2>/dev/null" perform.execute(command) else: root = "/var/lib/dpkg/info/" for script in scripts: fname = root + package + "." + script if os.path.exists(fname): nlen = int((72 - len(script))/2) print(">"*nlen, script, "<"*nlen) perform.execute("cat " + fname) def listsection(args): """List packages that belong to a specific section note: Use the LISTSECTIONS command for a list of Debian Sections""" section = args.section cache = apt.cache.Cache() for package in cache.keys(): package = cache[package] if(package.section == args.section): print(package.name) def listsections(args): """List all available sections""" cache = apt.cache.Cache() sections = list() for package in cache.keys(): package = cache[package] sections.append(package.section) sections = set(sections) for section in sections: print(section) def liststatus(args): """Same as list but only prints first two columns, not truncated""" command = "COLUMNS=400 " command += "dpkg --list '*' | grep -E -v 'no description avail'" command += " | awk '{print $1,$2}'" if args.pattern: command += " | grep -E '{}' | sort -k 1b,1".format(args.pattern) perform.execute(command) def localdistupgrade(args): """Dist-upgrade using only packages that are already downloaded""" command = ("/usr/bin/apt-get --no-download --ignore-missing --show-upgraded " "dist-upgrade") perform.execute(command, root=True, log=True) def localupgrade(args): """Upgrade using only packages that are already downloaded""" command = "/usr/bin/apt-get --no-download --ignore-missing --show-upgraded upgrade" perform.execute(command, root=True, log=True) def madison(args): """Runs the madison command of apt-cache""" command = "apt-cache madison " + " ".join(set(args.packages)) perform.execute(command) def move(args): """Move packages in the download cache to a local Debian mirror (apt-move)""" perform.execute("/usr/bin/apt-move update", root=True) def new(args): """Display newly-available packages""" util.newly_available(args.verbose) def newdetail(args): """Display detailed descriptions of newly-available packages This produces the same output as 'wajig new --verbose'""" util.newly_available(verbose=True) def news(args): """Display the NEWS file of a given package""" util.display_sys_docs(args.package, "NEWS.Debian NEWS".split()) def nonfree(args): """List packages that don't meet the Debian Free Software Guidelines""" util.requires_package("vrms") perform.execute("vrms") def orphans(args): """List libraries not required by any installed package """ util.requires_package("deborphan") perform.execute("deborphan") def policy(args): """From preferences file show priorities/policy (available)""" perform.execute("apt-cache policy " + " ".join(args.packages)) def purge(args): """Remove one or more packages and their configuration files""" packages = util.consolidate_package_names(args) command = "/usr/bin/apt-get {} {} --auto-remove purge " command = command.format(args.yes, args.noauth) command = command + " ".join(packages) perform.execute(command, root=True, log=True) def purgeorphans(args): """Purge orphaned libraries (not required by installed packages)""" # Deborphans does not require root, but dpkg does, # so build up the orphans list first, then pass that to dpkg. util.requires_package("deborphan") packages = "" for package in perform.execute("deborphan", pipe=True): packages += " " + package.strip() if packages: command = "/usr/bin/apt-get --auto-remove purge {} {}" command = command.format(args.yes, packages) perform.execute(command, root=True, log=True) def purgeremoved(args): """Purge all packages marked as deinstall""" packages = "" cmd = ("dpkg-query --show --showformat='${Package}\t${Status}\n' | " "grep -E \"deinstall ok config-files\" | cut -f 1 ") packages = perform.execute(cmd, pipe=True) if packages: packages = " ".join(packages) packages = " ".join(packages.split()) perform.execute("/usr/bin/apt-get purge " + packages, root=True, log=True) def rbuilddeps(args): """Display the packages which build-depend on the given package""" util.requires_package("grep-dctrl") command = "grep-available -sPackage -FBuild-Depends,Build-Depends-Indep " command = command + args.package + " /var/lib/apt/lists/*Sources" perform.execute(command) def readme(args): """Display the README file(s) of a given package This will display README, README.Debian, README.rst, and USAGE files of a package. It will also decompress them if they are postfixed with .gz. """ matches = 'README README.Debian README.rst USAGE' util.display_sys_docs(args.package, matches.split()) def recdownload(args): """Download a package and all its dependencies""" package_names = list() cache = apt.cache.Cache() for package in args.packages: util.package_exists(cache, package) print("Calculating all dependencies...") for package in args.packages: package_names.extend(util.get_deps_recursively(cache, package, [])) print("Packages to download to /var/cache/apt/archives:") for package in package_names: # We do this because apt-get install dont list the packages to # reinstall if they don't need to be upgraded print(package, end=' ') print() command = "/usr/bin/apt-get --download-only --reinstall -u install " + args.noauth command += " ".join(package_names) perform.execute(command, root=True) def reconfigure(args): """Reconfigure package""" command = "/usr/sbin/dpkg-reconfigure " + " ".join(args.packages) perform.execute(command, root=True) def recommended(args): """Display packages installed as Recommends and have no dependents""" command = ("aptitude search '" "?and( ?automatic(?reverse-recommends(?installed)), " "?not(?automatic(?reverse-depends(?installed))) )'") perform.execute(command) def reinstall(args): """Reinstall the given packages""" command = "/usr/bin/apt-get install --reinstall {} {} " + " ".join(args.packages) command = command.format(args.noauth, args.yes) perform.execute(command, root=True, log=True) def reload(args): """Reload system daemons (see LIST-DAEMONS for available daemons)""" command = "/usr/sbin/service {} reload".format(args.daemon) if perform.execute(command, root=True): print("attempt FORCE-RELOAD instead") command = "/usr/sbin/service {} force-reload ".format(args.daemon) perform.execute(command, root=True) def remove(args): """Remove packages (see also PURGE command)""" packages = util.consolidate_package_names(args) command = "/usr/bin/apt-get {} {}--auto-remove remove " + " ".join(packages) command = command.format(args.yes, args.noauth) perform.execute(command, root=True, log=True) def removeorphans(args): """Remove orphaned libraries""" util.requires_package("deborphan") packages = "" for package in perform.execute("deborphan", pipe=True): packages += " " + package.strip() if packages: command = "/usr/bin/apt-get --auto-remove remove {} {}" command = command.format(args.yes, packages) perform.execute(command, root=True, log=True) def repackage(args): """Generate a .deb file from an installed package""" util.requires_package("dpkg-repack") util.requires_package("fakeroot") command = "fakeroot --unknown-is-real dpkg-repack " + args.package perform.execute(command) def reportbug(args): """Report a bug in a package using Debian BTS (Bug Tracking System)""" util.requires_package("reportbug", "/usr/bin/reportbug") perform.execute("reportbug " + args.package) def restart(args): """Restart system daemons (see LIST-DAEMONS for available daemons)""" command = "/usr/sbin/service {} restart".format(args.daemon) perform.execute(command, root=True) def rpm2deb(args): """Convert an .rpm file to a Debian .deb file""" command = "alien " + args.rpm perform.execute(command) def rpminstall(args): """Install an .rpm package file""" command = "/usr/bin/alien --install " + args.rpm perform.execute(command, root=True, log=True) def search(args): """Search for package names containing the given pattern If '::' is found in the search term, use a debtags search; example: $ wajig search implemented-in::python balazar - adventure/action game Balazar -- Arkanae II, reforged scepters compizconfig-settings-manager - Compizconfig Settings Manager ... """ if len(args.patterns) == 1 and '::' in args.patterns[0]: util.requires_package('debtags') command = 'debtags search ' + args.patterns[0] if args.verbose: command += ' --full' elif not args.verbose: command = "apt-cache --names-only search {}" command = command.format(" ".join(args.patterns)) elif args.verbose == 1: import shlex args.patterns = [shlex.quote(pattern) for pattern in args.patterns] command = "apt-cache search {} | grep -E --ignore-case '{}'" command = command.format(" ".join(args.patterns), "\|".join(args.patterns)) else: command = "apt-cache search --full " + " ".join(args.patterns) perform.execute(command) def searchapt(args): """Find nearby Debian package repositories""" util.requires_package("netselect-apt") command = "netselect-apt " + args.dist perform.execute(command) def show(args): """Provide a detailed description of package""" package_names = " ".join(set(args.packages)) tool = "apt-cache" if args.fast else "aptitude" command = "{} show {}".format(tool, package_names) perform.execute(command) def start(args): """Start system daemons (see LIST-DAEMONS for available daemons)""" command = "/usr/sbin/service {} start".format(args.daemon) perform.execute(command, root=True) def stop(args): """Stop system daemons (see LISTDAEMONS for available daemons)""" command = "/usr/sbin/service {} stop".format(args.daemon) perform.execute(command, root=True) def sizes(args): """Display installed sizes of given packages $ wajig sizes [] Display installed sizes of all packages $ wajig sizes""" util.sizes(args.packages) def snapshot(args): """Generates a list of package=version for all installed packages""" util.do_status([], snapshot=True) def source(args): """Retrieve and unpack sources for the named packages""" util.requires_package("dpkg-source") perform.execute("apt-get source " + " ".join(args.packages)) def status(args): """Show the version and available versions of packages""" util.do_status(args.packages) def statusmatch(args): """Show the version and available versions of matching packages""" try: packages = [s.strip() for s in util.do_listnames(args.pattern, pipe=True).readlines()] except AttributeError: print("No packages found matching '{}'".format(args.pattern)) else: util.do_status(packages) def tasksel(args): """Run the task selector to install groups of packages""" util.requires_package("tasksel") perform.execute("/usr/bin/tasksel", root=True, log=True) def todo(args): """Display the TODO file of a given package""" util.display_sys_docs(args.package, ["TODO"]) def toupgrade(args): """List versions of upgradable packages""" if not util.show_package_versions(): print("No upgradeable packages") def tutorial(args): """Display wajig tutorial""" perform.execute('zcat /usr/share/doc/wajig/TUTORIAL') def unhold(args): """Remove listed packages from hold so they are again upgradeable""" for package in args.packages: # The dpkg needs sudo but not the echo. # Do all of it as root then. command = "echo \"" + package + " install\" | dpkg --set-selections" perform.execute(command, root=1) print("The following packages are still on hold:") perform.execute("dpkg --get-selections | grep -E 'hold$' | cut -f1") def unofficial(args): """Search for an unofficial Debian package at apt-get.org""" aptget_org = "http://www.apt-get.org" try: urllib.request.urlopen(aptget_org) except urllib.error.URLError as error: print("'{}' is unreachable".format(aptget_org)) else: url = aptget_org + "/search/?query=" + args.package webbrowser.open(url) def update(args): """Update the list of new and updated packages""" util.do_update(args.simulate) def updatealternatives(args): """Update default alternative for things like x-window-manager""" command = "/usr/sbin/update-alternatives --config " + args.alternative perform.execute(command, root=True) def updatepciids(args): """Updates the local list of PCI ids from the internet master list""" util.requires_package("pciutils", path="/usr/bin/update-pciids") perform.execute("/usr/bin/update-pciids", root=True) def updateusbids(args): """Updates the local list of USB ids from the internet master list""" util.requires_package("usbutils", path="/usr/sbin/update-usbids") perform.execute("/usr/sbin/update-usbids", root=True) def upgrade(args): """Conservative system upgrade This will not go as far remove packages in order to fulfill the upgrade, so may leave stale packages around. Use 'dist-upgrade' to avoid that. """ packages = util.upgradable() if packages: if args.backup: util.requires_package("dpkg-repack") util.requires_package("fakeroot") util.backup_before_upgrade(packages) command = "/usr/bin/apt-get {} {} {} --show-upgraded --with-new-pkgs upgrade" command = command.format(args.local, args.yes, args.noauth) perform.execute(command, root=True, log=True) else: print('No upgradeable packages. Did you run "wajig update" first?') def upgradesecurity(args): """Do a security upgrade""" sources_list = tempfile.mkstemp(".security", "wajig.", "/tmp")[1] sources_file = open(sources_list, "w") # check dist sources_file.write("deb http://security.debian.org/ " +\ "testing/updates main contrib non-free\n") sources_file.close() command = ("/usr/bin/apt-get --no-list-cleanup --option Dir::Etc::SourceList=" "{} update") command = command.format(sources_list) perform.execute(command, root=True) command = "/usr/bin/apt-get --option Dir::Etc::SourceList={} upgrade" command = command.format(sources_list) perform.execute(command, root=True, log=True) if os.path.exists(sources_list): os.remove(sources_list) def verify(args): """Check package's md5sum""" util.requires_package("debsums") perform.execute("debsums " + args.package) def versions(args): """List version and distribution of given packages""" util.requires_package("apt-show-versions") if args.packages: for package in args.packages: perform.execute("apt-show-versions " + package) else: perform.execute("apt-show-versions") def whichpackage(args): """Search for files matching a given pattern within packages Note: if no match is found, the apt-file repository is checked""" try: out = perform.execute("dpkg --search " + args.pattern, getoutput=True) except subprocess.CalledProcessError: util.requires_package("apt-file") perform.execute("apt-file search " + args.pattern) else: try: print(out.decode().strip()) # will get here when on --simulate mode except AttributeError: pass wajig/wajig.10000644000000000000000000000361612155054044010236 0ustar .\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH wajig 1 "March, 2012" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME wajig \- Simplified command line administrator for Debian .SH SYNOPSIS .B wajig .RI [ options ] " commands" ... .SH DESCRIPTION This manual page briefly documents the .B wajig command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBwajig\fP packages into one tool many commands useful for managing a Debian system. Instead of having to remember whether to use dpkg or apt-get or apt-cache, etc, wajig does the selection of the appropriate tool for you. .PP \fBwajig\fP is a user command but will use \fBsudo\fP to run commands requiring super user permissions. .PP The primary documentation is available from http://www.togaware.com/wajig. .SH OPTIONS This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options to get you started is included below. For more details see \fBwajig tutorial\fP and \fBwajig commands\fP. .TP .B \-h, \-\-help Show summary. .TP .B \-V, \-\-version Show version of program. .SH AUTHOR This manual page was written by Graham Williams , for the Debian GNU/Linux system (but may be used by others). wajig/README.rst0000644000000000000000000000230712253075313010537 0ustar wajig has evolved over several years of using and maintaining Debian systems. It attempts to capture in a single command line tool various things I commonly do that relate to managing the system. Many of the commands supported by wajig have been gleemed from hints and gossip on the mailing lists, and sometimes nuggets of useful information from the documentation. Online documentation is available at http://wajig.togaware.com. Dirk Eddelbuettel has also been incredibly helpful in sponsoring wajig for inclusion in Debian and in suggesting new commands. Also, many thanks to other users of wajig who have made suggestions over the years. --> words by Graham Williams & updated/fixed by Tshepang Lekhonkhobe hacking ------- * Setup:: wajig install devscripts debhelper debcheckout wajig cd wajig * Build:: debuild -us -uc * Install:: sudo debi * Ensure that user-visible changes are mentioned in ``debian/changelog``; use ``/usr/bin/debchange`` from within the project root directory and do your changes there howto release ------------- * Ensure that version string on ``src/wajig.py`` matches that of latest changelog * Ensure that debuild does not emit any lintian errors/warnings