apt-forktracer-0.4/0000755000000000000000000000000011672442021011166 5ustar apt-forktracer-0.4/LICENSE0000644000000000000000000004310311110217710012164 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. apt-forktracer-0.4/lib/0000755000000000000000000000000011110217710011724 5ustar apt-forktracer-0.4/lib/apt_forktracer/0000755000000000000000000000000011672435706014756 5ustar apt-forktracer-0.4/lib/apt_forktracer/apt_pkg_adapter.py0000755000000000000000000001010411672417452020452 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class NullProgress: """Makes libapt shut up when passed to Cache().""" def __init__(self, *args, **kwargs): pass def update(self, *args, **kwargs): pass def done(self, *args, **kwargs): pass class AptPkgAdapter: """Wraps the apt_pkg module. The reason for all the *Adapter classes is because the APT API is declared as prone to change. By encapsulating access to the APT API in the adapter classes, we decouple the rest of the codebase from it, hopefully making it easier to port to potential newer incompatible libapt versions. """ def __init__(self, apt_pkg): """apt_pkg is the imported libapt module to wrap.""" self.apt_pkg = apt_pkg self.state_installed = apt_pkg.CURSTATE_INSTALLED self.state_half_installed = apt_pkg.CURSTATE_HALF_INSTALLED self.state_half_configured = apt_pkg.CURSTATE_HALF_CONFIGURED self.state_unpacked = apt_pkg.CURSTATE_UNPACKED self.apt_cache = None self.inited = False def init(self): """Initializes libapt. Must be called before any other method.""" self.apt_pkg.init_config() self.apt_pkg.init_system() self.inited = True def _assert_initialized(self): """Helper method to check whether init() had been called.""" if not self.inited: raise Exception('not initialized') def get_cache_adapter(self, cache_adapter_factory, reporter, progress): """Returns a CacheAdapter object, given a CacheAdapterFactory, a Reporter and libapt progress reporting object. Throws an exception if called before init(). """ self._assert_initialized() self.apt_cache = self.apt_pkg.Cache(progress) return cache_adapter_factory.create_cache_adapter(self.apt_cache, self, reporter) def get_depcache_adapter(self, depcache_adapter_factory): """Returns a DepCacheAdapter object, given a DepCacheAdapterFactory. Must be called after get_cache_adapter() was invoked. Throws an exception if called before init(). """ self._assert_initialized() if not self.apt_cache: raise Exception('you must call get_cache_adapter() earlier') apt_depcache = self.apt_pkg.DepCache(self.apt_cache) return depcache_adapter_factory.create_depcache_adapter(apt_depcache) def version_compare(self, version_a, version_b): """Returns -1, 0 or 1 depending on whether version_a string is considered older, equal to, or newer than version_b string. Throws an exception if either version equals None. Throws an exception if called before init(). """ self._assert_initialized() if version_a == None or version_b == None: raise ValueError('cannot compare a None version string') return self.apt_pkg.version_compare(version_a, version_b) def version_sort(self, versions): """Sorts the given versions list of VersionAdapters in situ and also returns it. Sorted list is in newest to oldest order. Throws an exception if called before init(). """ self._assert_initialized() versions.sort(lambda va,vb: self.version_compare(va.string, vb.string), reverse = True) return versions def version_max(self, versions): """Returns the newest VersionAdapter object in the versions list, or None, if versions is empty. Throws an exception if called before init(). """ self._assert_initialized() max = None for v in versions: if max == None or self.version_compare(v.string, max.string) > 0: max = v return max apt-forktracer-0.4/lib/apt_forktracer/policy.py0000755000000000000000000001357711353737676016656 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import re from apt_forktracer.config_stanza import ConfigStanza class VerbosePolicy: """Just says yes, i.e. "report everything that Checker found to be interesting".""" def should_report(self, something): return True class Policy: """Decides whether to report a given Status object, taking into account default and/or user-defined rules for what should be reported. """ def __init__(self, apt_pkg_adapter, facter, config): self.apt_pkg_adapter = apt_pkg_adapter self.facter = facter self.tilde_stripper = re.compile(r'^(.*)~[^~]+$') self.config = config def base(self, version_string): """Strips off the last tilde and whatever follows it, to get a base version string.""" if version_string == '': return version_string m = self.tilde_stripper.search(version_string) if m: return m.group(1) else: return version_string def _match(self, status, stanza): """Returns True if any of the sources of the status object's candidate version matches accept-origin of the given stanza. """ for file in status.candidate_version.files: if stanza.matches('accept-origin', file.origin): return True return False def stanzas_for_status(self, status): """If there are no config stanzas at all for the given package, returns a set of "default config stanzas". Otherwise returns a (possibly empty) list of stanzas whose accept-origin matches any origin of the candidate version of the package. """ stanzas = self.config.package(status.package_name) if len(stanzas) == 0: return self._create_default_stanzas(status) ret = [] for stanza in stanzas: if self._match(status, stanza): ret.append(stanza) return ret def _create_default_stanza(self, status, base = False): """Creates a stanza used when there is no configuration for a given package. Such Stanza has a matching Package tag, Accept-Origin that matches anything, Track-Origin equal to the distributor ID according to facter, and Track-Version equal to the candidate version (or the base of the candidate version, if base argument is True). """ s = ConfigStanza() s.set('package', status.package_name, 1) s.set('accept-origin', '*', 1) s.set('track-origin', self.facter.distributors_id, 1) if base: v = self.base(status.candidate_version.string) else: v = status.candidate_version.string s.set('track-version', v, 1) return s.finish(1) def _create_default_stanzas(self, status): """Creates stanzas used when there is no configuration for a given package.""" ret = [] ret.append(self._create_default_stanza(status, False)) ret.append(self._create_default_stanza(status, True)) return ret def _track_version(self, stanza, status): """Returns the track-version of a given stanza. The status argument is used to expand values such as =candidate or =candidate-base into an actual version string. """ track_version = stanza.get('track-version') if len(track_version) > 0 and track_version[0] == '=': specifier = track_version[1:] if specifier == 'candidate': track_version = status.candidate_version.string elif specifier == 'candidate-base': track_version = self.base(status.candidate_version.string) else: raise ValueError('invalid version specifier \'%s\'' % specifier) return track_version def _same_version(self, vs, vo): """Returns True only if vs string is the same as the version string of the VersionAdapter object vo. """ return vo and self.apt_pkg_adapter.version_compare(vo.string, vs) == 0 def _should_ignore_according_to_stanza(self, stanza, status): """Returns True if the given config stanza says that the given status should be ignored. This is the case when the version to be tracked is the newest version available from the origin to be tracked. """ origin_to_be_tracked = stanza.get('track-origin') if origin_to_be_tracked == '*': permitted_versions = status.all_available_versions() else: permitted_versions = status.versions_from(origin_to_be_tracked) version_to_be_tracked = self._track_version(stanza, status) return self._same_version(version_to_be_tracked, self.apt_pkg_adapter.version_max(permitted_versions)) def _should_ignore_according_to_any_of_stanzas(self, status, stanzas): """Returns True if ANY of the given stanzas says that the given status should be ignored. """ for stanza in stanzas: if self._should_ignore_according_to_stanza(stanza, status): return True # do not ignore by default return False def should_report(self, status): """Returns True unless the given status should be ignored according to the config or default rules. The default is only considered if there is no configuration for the given package whatsoever. Also returns True if either the candidate or installed version is None. The default rule is as follows: The candidate version or the base of the candidate version is the same as the newest available official version. """ if status.candidate_version == None or status.installed_version == None: return True stanzas = self.stanzas_for_status(status) return not self._should_ignore_according_to_any_of_stanzas(status, stanzas) apt-forktracer-0.4/lib/apt_forktracer/package_adapter.py0000755000000000000000000000530711353712247020425 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from apt_forktracer.version_adapter import VersionAdapter from apt_forktracer.status import Status class PackageAdapterFactory: """Factory for the PackageAdapter objects.""" def __init__(self, depcache_adapter = None): """The depcache_adapter argument is an optional DepCacheAdapter object.""" self.depcache_adapter = depcache_adapter def create_package_adapter(self, apt_package): """Instantiates a new PackageAdapter from the given apt_package object. Sets the candidate_version attribute on the created object, if a DepCacheAdapter was provided when creating the factory. """ pa = PackageAdapter(apt_package) if self.depcache_adapter: pa.candidate_version = self.depcache_adapter.get_candidate_version(pa) return pa class PackageAdapter: """Wrapper for the pkgCache::Package class. See AptPkgAdapter for why it is necessary. """ def __init__(self, apt_package): self.apt_package = apt_package self.name = apt_package.name if apt_package.current_ver: self.current_version = VersionAdapter(apt_package.current_ver) else: self.current_version = None self.candidate_version = None self.versions = [VersionAdapter(v) for v in apt_package.version_list] def get_status(self, facter): """Creates a new Status object based on this one, given a Facter.""" versions_by_origin = {} for version in self.versions: for pfa in version.files: origin = pfa.origin if not origin: continue if versions_by_origin.has_key(origin): versions_by_origin[origin].append(version) else: versions_by_origin[origin] = [version] return Status(self.name, self.current_version, self.candidate_version, versions_by_origin) def __str__(self): """Returns a string which includes the package name and current and candidate versions.""" return '%s >' % (self.name, str(self.current_version), str(self.candidate_version)) __repr__ = __str__ apt-forktracer-0.4/lib/apt_forktracer/depcache_adapter.py0000755000000000000000000000310611353712247020561 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from apt_forktracer.version_adapter import VersionAdapter class DepCacheAdapterFactory: """Factory for DepCacheAdapter objects.""" def create_depcache_adapter(self, apt_dep_cache): return DepCacheAdapter(apt_dep_cache) class DepCacheAdapter: """Wrapper for the pkgDepCache class. See the AptPkgAdapter for why this class is necessary.""" def __init__(self, apt_dep_cache): self.apt_dep_cache = apt_dep_cache def get_candidate_version(self, pkg): """Returns a VersionAdapter object representing the candidate version of the given PackageAdapter object pkg. Returns None if there is no candidate version.""" apt_version = self.apt_dep_cache.get_candidate_ver(pkg.apt_package) if not apt_version: return None else: return VersionAdapter(apt_version) apt-forktracer-0.4/lib/apt_forktracer/facter.py0000755000000000000000000000564411353712247016602 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008-2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import re import subprocess import sys class Facter: """Reports some facts about the system. Currently just the distributor's id (available through the distributors_id attribute). Tries to import the lsb_release Python module, which should be fast and provide most correct information. If that fails, tries to run lsb_release(1) and read its output, which should be functionally equivalent, but not as fast, since it requires a fork/exec. If that fails too, reads /etc/lsb-release directly as the last resort. This might not be correct in all cases, as strictly speaking that file is not required, but just provides a way to override values detected from the system. Throws an exception if all methods fail. The optional attributes are mostly for testing purposes. """ def __init__(self, lsb_release_module = 'lsb_release', lsb_release = 'lsb_release --id --short', file = '/etc/lsb-release'): self.distributors_id = self.get_distrib_id_from_module(lsb_release_module) if not self.distributors_id: self.distributors_id = self.get_distrib_id_from_command(lsb_release) if not self.distributors_id: self.distributors_id = self.get_distrib_id_from_file(file) if not self.distributors_id: raise RuntimeError('Could not obtain distributors id from lsb_release') def get_distrib_id_from_file(self, file_name): p = re.compile(r'DISTRIB_ID\s*=\s*(\S+)') try: f = open(file_name, 'r') for line in f: m = p.search(line) if m: f.close() return m.group(1) except IOError: pass def get_distrib_id_from_command(self, command): try: p = subprocess.Popen(command, stdout = subprocess.PIPE, shell = True) output = p.stdout.readline() p.stdout.close() p.wait() if p.returncode == 0: return output.rstrip('\n') except OSError: pass def get_distrib_id_from_module(self, module_name): try: __import__(module_name) # we need to look up in sys.modules as __import__(name) only returns top-level module if name contains dots module = sys.modules[module_name] distinfo = module.get_distro_information() return distinfo['ID'] except ImportError: pass apt-forktracer-0.4/lib/apt_forktracer/__init__.py0000644000000000000000000000000011110217710017031 0ustar apt-forktracer-0.4/lib/apt_forktracer/checker.py0000755000000000000000000000477411110217710016727 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class Checker: """Checks whether a package is non-standard enough to be reported.""" def __init__(self, facter, verbose_mode = False): """Optional last argument specifies whether this checker should run in verbose mode. By default it is not verbose. """ self.facter = facter self.verbose_mode = verbose_mode def check(self, package_adapter): """Given a PackageAdapter object, determines whether it is sufficiently non-standard (i.e. non-official, or inconsistent state) to be reported. Returns a Status object in such case. Otherwise, returns None. Checks which versions are current, candidate, available and whether they are official. Does not do detailed version string analyses (this is the job of Policy, which also decides whether to ignore any reports). Currently, its algorithm is as follows: In default mode, returns a Status object if there is no candidate version, or if the candidate version is not available from an official source (as determined by the facter). In the verbose mode, additionally returns a Status object if the candidate and current versions are not the same (i.e. an upgrade or downgrade is pending). Raises an exception if current version is None. """ current = package_adapter.current_version candidate = package_adapter.candidate_version if current == None: raise ValueError('Package %s has no current version' % package_adapter) if candidate == None: return package_adapter.get_status(self.facter) if self.verbose_mode and candidate.string != current.string: return package_adapter.get_status(self.facter) if not candidate.is_officially_available(self.facter): return package_adapter.get_status(self.facter) return None apt-forktracer-0.4/lib/apt_forktracer/reporter.py0000755000000000000000000000365411110217710017161 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class Reporter: """Reports a status to the user. Currently just pretty-prints it to standard output. Might syslog or whatever...""" def report(self, status): """Prints a formatted report for a given status to standard output.""" print self.format(status) def format(self, status): """Returns a formatted report for a given status.""" if (not status.installed_version) and (not status.candidate_version): pending_version_info = '' elif not status.installed_version: pending_version_info = '->%s' % status.candidate_version.string elif not status.candidate_version: pending_version_info = '%s->' % status.installed_version.string elif status.installed_version.string == status.candidate_version.string: pending_version_info = status.installed_version.string else: pending_version_info = '%s->%s' % (status.installed_version.string, status.candidate_version.string) version_info = '' for origin,versions in status.versions_by_origin.items(): version_info += ' [%s: %s]' % (origin, ' '.join([v.string for v in versions])) return '%s (%s)' % (status.package_name, pending_version_info) + version_info apt-forktracer-0.4/lib/apt_forktracer/version_checker.py0000755000000000000000000000273311110217710020465 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class VersionChecker: """Given a VersionAdapter object, determines whether it is sufficiently non-standard (i.e. non-official, or inconsistent state) to be reported. Checks whether the version is available and official. Does not do detailed version string analyses (this is the job of Policy, which also decides whether to ignore any reports). See also Checker, which invokes methods of this class.""" def __init__(self, facter): self.facter = facter def analyze(self, version): """Returns True if this version is somehow suspicious. Currently just checks whether a version is officially available.""" return not version.is_officially_available(self.facter) apt-forktracer-0.4/lib/apt_forktracer/config_parser.py0000755000000000000000000000357511110217710020142 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from apt_forktracer.config_stanza import ConfigStanza class ConfigParser: """Parses a text file, producing ConfigStanza objects.""" def __add(self, stanza, lineno, ret, config): """Private method for gathering stanzas.""" if not stanza.is_empty(): ret.append(stanza.finish(lineno)) if config: config.add(stanza) stanza = ConfigStanza() return stanza def load(self, file, config = None): """Parses an open file object, and returns a list of stanzas found. If an optional config argument (a Config object) is provided, it also adds the stanzas to it. Parsing errors are raised as exceptions. """ ret = [] stanza = ConfigStanza() lineno = 0 for line in file: lineno += 1 line = line.strip() if line == '': stanza = self.__add(stanza, lineno, ret, config) continue colon = line.find(':') if colon != -1: key, val = line.split(':', 1) stanza.set(key.strip(), val.strip(), lineno) else: raise ValueError('invalid line %d: %s' % (lineno, repr(line))) stanza = self.__add(stanza, lineno, ret, config) return ret apt-forktracer-0.4/lib/apt_forktracer/cache_adapter.py0000755000000000000000000000356511353712247020101 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class CacheAdapterFactory: """A factory of CacheAdapter objects.""" def create_cache_adapter(self, apt_cache, apt_pkg_adapter, reporter): return _CacheAdapter(apt_cache, apt_pkg_adapter, reporter) class _CacheAdapter: """Wrapper for the pkgCache class. See AptPkgAdapter for why this class is necessary.""" def __init__(self, apt_cache, apt_pkg_adapter, reporter): self.apt_cache = apt_cache self.reporter = reporter self.states_we_check = [ apt_pkg_adapter.state_installed, apt_pkg_adapter.state_half_configured, apt_pkg_adapter.state_half_installed, apt_pkg_adapter.state_unpacked ] def run(self, checker, policy, package_adapter_factory): for package in self.apt_cache.packages: if package.current_state not in self.states_we_check: continue pa = package_adapter_factory.create_package_adapter(package) status = checker.check(pa) if not status: continue if policy.should_report(status): self.reporter.report(status) def __str__(self): return '' % len(self.apt_cache.packages) __repr__ = __str__ apt-forktracer-0.4/lib/apt_forktracer/testlib/0000755000000000000000000000000011672435706016424 5ustar apt-forktracer-0.4/lib/apt_forktracer/testlib/fake_version.py0000755000000000000000000000334211353737676021465 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from apt_forktracer.testlib.fake_package_file import FakePackageFile class FakeVersion(object): """Pretends to be the pkgCache::Version object from apt_pkg. We cannot use the real one, because it is tied to the binary cache, which is difficult to construct and control.""" def __init__(self, version_string = '1.2.3'): self.ver_str = version_string self.file_list = [] def append_package_file(self, package_file): tuple = (package_file,1) self.file_list.append(tuple) def __str__(self): files = '' for f in self.file_list: files += '(%s,%d),' % (str(f[0]), f[1]) return '' % (self.ver_str, files) def _create(string, origins): """Factory method.""" fv = FakeVersion(string) for o in origins: if o == 'dpkg': fv.append_package_file(FakePackageFile(type = 'dpkg')) else: fv.append_package_file(FakePackageFile(origin = o)) return fv _create = staticmethod(_create) apt-forktracer-0.4/lib/apt_forktracer/testlib/test_helper.py0000755000000000000000000001123111353712247021307 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import mox import re from apt_forktracer.facter import Facter def copy_state_constants(to_obj, from_obj): to_obj.CURSTATE_INSTALLED = from_obj.CURSTATE_INSTALLED to_obj.CURSTATE_HALF_CONFIGURED = from_obj.CURSTATE_HALF_CONFIGURED to_obj.CURSTATE_HALF_INSTALLED = from_obj.CURSTATE_HALF_INSTALLED to_obj.CURSTATE_UNPACKED = from_obj.CURSTATE_UNPACKED class Advanced_Version_Comparator: def __init__(self): # tuple: v1, v2, relation # relation == 1 iff v1 << v2 # == 0 iff v1 == v2 # == -1 iff v1 >> v2 self.comparisons = [ ('1', '0', 1), ('1', '1', 0), ('0', '1', -1), ('0.1-1', '0.1-1', 0), ('0.1-1', '0.1-2', -1), ('0.1-2', '0.1-1~sl1', 1), ('0.1-1', '0.1-1~sl1', 1), ('2.6.1-2etch1', '2.6.1-2etch2', -1), ('2.6.1-2etch1', '2.6.1-2etch1', 0), ('2.6.1-2etch2', '2.6.1-2etch2', 0), ('1:1.5.6.3-1.1ubuntu2~mowsiany.1', '1:1.5.6.3-1.1ubuntu2~mowsiany.1', 0), ('0.5-5~sl1', '0.5-5~sl1', 0), ('0.5-5', '0.5-5~sl1', 1), ('0.5-5', '0.5-5', 0), ('1:1.5.2.5-2build1', '1:1.5.2.5-2build1', 0), ('1:1.5.2.5-2build1', '1:1.5.6.3-1.1ubuntu2~mowsiany.1', -1), ('1:1.5.2.5-2build1', '1:1.5.6.3-1.1ubuntu2', -1), ('1.9', '2.0', -1), ('2.0~1', '0', 1), ('2.0~1', '1', 1), ('2.0~1', '2.0~1', 0), ('2.0~1', '2.0', -1), ('2.0', '0', 1), ('2.0', '2.0~1', 1), ('2.0', '2.0~1', 1), ('2.0', '2.0', 0), ('2.0', '2.1~1', -1), ('2.0', '2.1~2', -1), ('2.0', '2.1', -1), ('2.0', '2.2', -1), ('2.1~1', '2.1~1', 0), ('2.1~1', '2.1', -1), ('2.1~2', '2.1~2', 0), ('2.1~2', '2.1', -1), ('2.1', '2.0~1', 1), ('2.1', '2.0', 1), ('2.1', '2.1~1', 1), ('2.1', '2.1~2', 1), ('2.1', '2.1', 0), ('2.1', '2.2~1', -1), ('2.1', '2.2~2', -1), ('2.1', '2.2', -1), ('2.2~2', '2.2~2', 0), ('2.2~2', '2.2', -1), ('2.2', '2.1~1', 1), ('2.2', '2.1~2', 1), ('2.2', '2.1', 1), ('2.2', '2.2~1', 1), ('2.2', '2.2', 0), ] def compare(self, v1, v2): if v1 == v2: return 0 for comparison in self.comparisons: if v1 == comparison[0] and v2 == comparison[1]: return comparison[2] for comparison in self.comparisons: if v1 == comparison[1] and v2 == comparison[0]: return 0 - comparison[2] if v1.find('~') >= 0 or v2.find('~') >= 0: raise ValueError('not attempting to compare %s with %s (tilde found)' % (v1, v2)) return cmp(v1, v2) class MoxTestCase(mox.MoxTestBase): def assertContains(self, haystack, needle): self.assert_(haystack.find(needle) >= 0, 'could not find %s in %s' % (needle, haystack)) def assertNotContains(self, haystack, needle): self.assert_(haystack.find(needle) < 0, 'found "%s" in "%s"' % (needle, haystack)) def assertMatches(self, haystack, regex): self.assert_(re.compile(regex).search(haystack), 'could not match "%s" against "%s"' % (haystack, regex)) def assertRaisesWithMessageContaining(self, exception_class, message_snippet, method, *args, **kwargs): succeeded = False try: method(*args, **kwargs) succeeded = True except exception_class, e: self.assertContains(e.message, message_snippet) except Exception, e: self.fail('%s failed with %s(%s) instead of %s' % (method, type(e), e.message, exception_class)) if succeeded: self.fail('%s did not fail with %s' % (method, exception_class)) def _create_mock_facter(self, id): mock_facter = self.mox.CreateMock(Facter) mock_facter.distributors_id = id return mock_facter def struct(self, **kwargs): class Struct: def __init__(self, **entries): self.__dict__.update(entries) return Struct(**kwargs) def _create_mock_apt_pkg_module(self): mock_apt_pkg_module = self.mox.CreateMockAnything() comparator = Advanced_Version_Comparator() mock_apt_pkg_module.version_compare = lambda x, y: comparator.compare(x, y) mock_apt_pkg_module.init_config = lambda: None mock_apt_pkg_module.init_system = lambda: None return mock_apt_pkg_module apt-forktracer-0.4/lib/apt_forktracer/testlib/__init__.py0000644000000000000000000000000011110217710020477 0ustar apt-forktracer-0.4/lib/apt_forktracer/testlib/fake_cache.py0000755000000000000000000000234711353712247021032 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class FakeCache: """Pretends to be the pkgCache::Header object from apt_pkg. We cannot use the real one, because it is tied to the binary cache file, which is difficult to construct and control.""" def __init__(self): self.packages = [] def append_package(self, package): self.packages.append(package) def __str__(self): pkgs = '' for p in self.packages: pkgs += str(p)+',' return '' % pkgs apt-forktracer-0.4/lib/apt_forktracer/testlib/fake_package.py0000755000000000000000000000302411353712247021353 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import apt_pkg class FakePackage: """Pretends to be the pkgCache::Package object from apt_pkg. We cannot use the real one, because it is tied to the binary cache, which is difficult to construct and control.""" def __init__(self, current_state = apt_pkg.CURSTATE_INSTALLED, name = 'afake'): self.name = name self.version_list = [] self.current_state = current_state self.current_ver = None def append_version(self, version, current = False): self.version_list.append(version) if current: self.current_ver = version def __str__(self): vers = '' for v in self.version_list: vers += str(v) + ',' return '' % (self.current_state, self.name, str(self.current_ver), vers) apt-forktracer-0.4/lib/apt_forktracer/testlib/fake_lsb_release.py0000644000000000000000000000157511212457626022247 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2009 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. def get_distro_information(): return {'ID': 'fake_distributors_id'} apt-forktracer-0.4/lib/apt_forktracer/testlib/fake_package_file.py0000755000000000000000000000410311353712247022351 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from apt_forktracer.package_file_adapter import PackageFileAdapter class FakePackageFile: """Pretends to be the pkgCache::PackageFile object from apt_pkg. We cannot use the real one, because it is tied to the binary cache, which is difficult to construct and control.""" def __init__(self, path = '/a/fake', type = 'normal', origin = 'Debian', archive = 'stable-proposed-updates'): self.filename = path self.archive = archive self.component = 'main' # release version self.version = '1.0' # provider of the archive self.origin = origin # name of the distribution self.label = 'Debian' # apt will not consider taking packages unless told explicitly to do so self.not_automatic = 0 if type == 'normal': self.index_type = PackageFileAdapter.TYPE_PACKAGE_FILE elif type == 'dpkg': self.index_type = PackageFileAdapter.TYPE_DPKG_STATUS self.filename = '/var/lib/dpkg/status' self.archive = 'now' self.component = '' self.version = '' self.origin = '' self.label = '' else: raise ValueError('Unknown type "%s"' % type) def __str__(self): return '' % (self.index_type, self.filename, self.archive, self.component, self.version, self.origin, self.label, self.not_automatic) apt-forktracer-0.4/lib/apt_forktracer/package_file_adapter.py0000755000000000000000000000417611353712247021427 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class PackageFileAdapter: """Wrapper for the aptCache::PackageFile libapt class. See AptPkgAdapter for an explanation of why this is needed.""" TYPE_PACKAGE_FILE = 'Debian Package Index' TYPE_DPKG_STATUS = 'Debian dpkg status file' def __init__(self, apt_package_file): self.name = apt_package_file.filename self.archive = apt_package_file.archive self.component = apt_package_file.component self.version = apt_package_file.version self.origin = apt_package_file.origin self.label = apt_package_file.label self.not_automatic = apt_package_file.not_automatic self.index_type = apt_package_file.index_type def is_official(self, facter): """Returns True if the package file's origin matches distributor's ID according to facter.""" if self.index_type != PackageFileAdapter.TYPE_PACKAGE_FILE: return False else: return self.origin == facter.distributors_id def __str__(self): """Returns a string which includes some attributes of the object.""" if self.index_type == PackageFileAdapter.TYPE_DPKG_STATUS: return '' % (self.name) auto = '' if self.not_automatic: auto = ' NONAUTO' return '' % (self.name, self.archive, self.component, self.version, self.origin, self.label, auto) __repr__ = __str__ apt-forktracer-0.4/lib/apt_forktracer/config_stanza.py0000755000000000000000000000476111353737676020177 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class ConfigStanza: """Represents a single stanza in a configuration file, such as: Package: foo Accept-Origin: O1 Track-Origin: O2 Track-Version: 1.2.3 Tags are on the left of the colons, and their values on the right. """ def __init__(self): self._dict = {} def finish(self, lineno): """Should be called when parser has reached the end of the stanza. Does some integrity checks to make sure the stanza is correct. Any errors are raised as exceptions. lineno is the line number on which the stanza finished - it is used in the error messages. Returns the stanza itself. """ for tag in ['package', 'accept-origin', 'track-origin', 'track-version']: if not self._dict.has_key(tag): raise ValueError('invalid configuration stanza near line %d (missing field %s)' % (lineno, tag)) return self def set(self, tag, value, lineno): """Sets the value of the given tag (overriding any previously set one). Parameter lineno is used in case of an error message. Tag parameter is case-insensitive.""" tag = tag.lower() if tag not in ['package', 'accept-origin', 'track-origin', 'track-version']: raise ValueError('invalid tag %s on line %d' % (tag, lineno)) self._dict[tag] = value def is_empty(self): """Returns True if nothing had been set on this stanza.""" return len(self._dict) == 0 def get(self, tag): """Returns the most-recent set value of the given (case-insensitive) tag.""" return self._dict[tag] def matches(self, tag, value): """Returns True if the currently set value of the given tag is '*' or equal to the value parameter.""" current_value = self.get(tag) if current_value == '*': return True else: return current_value == value apt-forktracer-0.4/lib/apt_forktracer/config_finder.py0000755000000000000000000000405211110217710020104 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os class _ConfigFinderIterator: """Iterator class used by ConfigFinder. See that class for more information.""" def __init__(self, cf): self.cf = cf self.index = 0 self.file = None def __iter__(self): return self def next(self): if len(self.cf.paths) > self.index: path = self.cf.paths[self.index] if self.file: self.file.close() self.file = open(path) self.index += 1 return (path, self.file) else: if self.file: self.file.close() raise StopIteration() class ConfigFinder: """Provides a method to get all config files. Arguments are files or directories to look for. Files are opened, and directories are searched looking for files which end with '.conf' but do not start with a dot. Iterating over this object returns tuples (path, file), where path is the path to a config file, and file is the open file object. """ def __init__(self, *paths): self.paths = [] for path in paths: if not os.path.exists(path): continue if os.path.isdir(path): for name in os.listdir(path): if name and name[0] != '.' and name.endswith('.conf'): self.paths.append(os.path.join(path, name)) else: self.paths.append(path) def __iter__(self): return _ConfigFinderIterator(self) apt-forktracer-0.4/lib/apt_forktracer/status.py0000755000000000000000000000404011110217710016630 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class Status: """Models a potentially interesting piece of information about the status of an installed version of a package, WRT other available versions. """ def __init__(self, package_name, installed_version, candidate_version, versions_by_origin = {}): self.package_name = package_name self.installed_version = installed_version self.candidate_version = candidate_version self.versions_by_origin = versions_by_origin def versions_from(self, origin): """Returns a list of versions available from a given origin.""" if self.versions_by_origin.has_key(origin): return self.versions_by_origin[origin] else: return [] def all_available_versions(self): """Returns a list of all versions available from any source. Does not include the installed or candidate versions, if they are not available from some source.""" ret = [] for a in self.versions_by_origin.values(): ret.extend(a) return ret def __str__(self): version_info = '' for origin,versions in self.versions_by_origin.items(): version_info += '[%s: %s]' % (origin, ','.join([v.string for v in versions])) return '%s %s>' % (self.package_name, self.installed_version, self.candidate_version, version_info) __repr__ = __str__ apt-forktracer-0.4/lib/apt_forktracer/version_adapter.py0000755000000000000000000000300511353737676020525 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from apt_forktracer.package_file_adapter import PackageFileAdapter class VersionAdapter: """Mirror of the aptCache::Version libapt class. See AptPkgAdapter for an explanation of why this is needed.""" def __init__(self, apt_version): self.string = apt_version.ver_str self.files = [PackageFileAdapter(pf[0]) for pf in apt_version.file_list] def is_officially_available(self, facter): """Returns True if any of the files considers itself official.""" for file in self.files: if file.is_official(facter): return True return False def __str__(self): files = '' for f in self.files: files += str(f) + ',' return '' % (self.string, files) __repr__ = __str__ apt-forktracer-0.4/lib/apt_forktracer/tests/0000755000000000000000000000000011672435706016120 5ustar apt-forktracer-0.4/lib/apt_forktracer/tests/test_config.py0000755000000000000000000000367311353677217021013 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.config import Config from apt_forktracer.config_stanza import ConfigStanza class Test_Config(test_helper.MoxTestCase): def setUp(self): super(Test_Config, self).setUp() self.c = Config() def test_addition_and_retrieval(self): foo_stanza1 = self.mox.CreateMock(ConfigStanza) foo_stanza1.get('package').AndReturn('foo') foo_stanza2 = self.mox.CreateMock(ConfigStanza) foo_stanza2.get('package').AndReturn('foo') bar_stanza = self.mox.CreateMock(ConfigStanza) bar_stanza.get('package').AndReturn('bar') self.mox.ReplayAll() self.c.add(foo_stanza1) self.c.add(foo_stanza2) self.c.add(bar_stanza) foo_stanzas = self.c.package('foo') bar_stanzas = self.c.package('bar') baz_stanzas = self.c.package('baz') self.assertEquals(len(foo_stanzas), 2) self.assertEquals(foo_stanzas[0], foo_stanza1) self.assertEquals(foo_stanzas[1], foo_stanza2) self.assertEquals(len(bar_stanzas), 1) self.assertEquals(bar_stanzas[0], bar_stanza) self.assertEquals(len(baz_stanzas), 0) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_package_adapter.py0000755000000000000000000001100311353712247022614 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.apt_pkg_adapter import AptPkgAdapter from apt_forktracer.testlib.fake_package import FakePackage from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.package_adapter import PackageAdapter class TestBasePackageAdapter(test_helper.MoxTestCase): def setUp(self): super(TestBasePackageAdapter, self).setUp() self.fake_package = FakePackage() self.setUp_mangle_fake_package() self.pa = PackageAdapter(self.fake_package) self.setUp_mangle_package_adapter() self.facter = self._create_mock_facter('Debian') self.apt_pkg_adapter = AptPkgAdapter(self._create_mock_apt_pkg_module()) self.apt_pkg_adapter.init() self.status = self.pa.get_status(self.facter) def setUp_mangle_fake_package(self): pass def setUp_mangle_package_adapter(self): pass def testProperties(self): self.assertEquals(self.pa.name, 'afake') self.assertEquals(self.pa.apt_package, self.fake_package) def testLenOfVersionsNonNegative(self): self.assert_(self.pa.versions >= 0) def testBasicStringificationWorks(self): self.assertContains(str(self.pa), 'PackageAdapter') def setUpAddAVersion(self, source = 'NonDebian', version = 'blah'): self.fake_package.append_version(FakeVersion._create(version, [source])) def test_get_status_returns_an_object(self): self.assert_(self.status) self.assertEquals(self.status.package_name, 'afake') self.assertEquals(self.status.installed_version, self.pa.current_version) self.assertEquals(self.status.candidate_version, self.pa.candidate_version) self.assert_(len(self.status.versions_by_origin) >= 0) class TestZeroVersionPackageAdapter(TestBasePackageAdapter): def testEmptyVersions(self): self.assertEquals(self.pa.versions, []) self.assertEquals(len(self.status.versions_by_origin), 0) def testStringificationWorks(self): self.assertContains(str(self.pa), 'v=None->None') class TestOneOfficialVersionPackageAdapter(TestBasePackageAdapter): def setUp_mangle_fake_package(self): self.setUpAddAVersion('Debian') def testOneVersion(self): self.assertEquals(len(self.pa.versions), 1) self.assertEquals(len(self.status.versions_by_origin), 1) class TestOneUnofficialVersionPackageAdapter(TestBasePackageAdapter): def setUp_mangle_fake_package(self): self.setUpAddAVersion() def testOneVersion(self): self.assertEquals(len(self.pa.versions), 1) self.assertEquals(len(self.status.versions_by_origin), 1) class TestFourVersionPackageAdapter(TestBasePackageAdapter): def setUp_mangle_fake_package(self): self.setUpAddAVersion('NonDebian', '0') self.setUpAddAVersion('NonDebian', '4') self.setUpAddAVersion('Debian', '1') self.setUpAddAVersion('Debian', '2') self.setUpAddAVersion('dpkg', '5') def testFourVersions(self): self.assertEquals(len(self.pa.versions), 5) self.assertEquals(len(self.status.versions_by_origin), 2) self.assertEquals(len(self.status.versions_by_origin['Debian']), 2) self.assertEquals(len(self.status.versions_by_origin['NonDebian']), 2) class TestPackageAdapterWithInstalledVersion(TestBasePackageAdapter): def setUp_mangle_fake_package(self): self.setUpAddAVersion() self.fake_package.current_ver = FakeVersion('1.xx.yy') self.official_version = FakeVersion._create('2.3.4', ['Debian']) self.fake_package.append_version(self.official_version) def setUp_mangle_package_adapter(self): self.pa.candidate_version = '2.3.4' def test_versions(self): self.assertEquals(self.pa.current_version.string, '1.xx.yy') self.assertEquals(len(self.status.versions_by_origin), 2) def testStringificationWorks(self): self.assertMatches(str(self.pa), r'VersionAdapter.*1\.xx\.yy.*->2\.3\.4') if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_facter.py0000755000000000000000000000465311353712247021002 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008-2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.facter import Facter class TestFacterWithoutArgs(unittest.TestCase): def setUp(self): self.facter = Facter() def testDistributorsIdReturnsSomething(self): self.assert_(self.facter.distributors_id) class TestFacterWithLSBReleaseModuleArg(unittest.TestCase): def setUp(self): self.facter = Facter(lsb_release_module = 'apt_forktracer.testlib.fake_lsb_release') def testDistributorsIdReturnsFakeDistribursId(self): self.assertEquals(self.facter.distributors_id, 'fake_distributors_id') class TestFacterWithLSBReleaseArg(unittest.TestCase): def setUp(self): self.facter = Facter(lsb_release_module = 'non.existant', lsb_release = 'echo Foobar') def testDistributorsIdReturnsFoobar(self): self.assertEquals(self.facter.distributors_id, 'Foobar') class TestFacterWithBrokenLSBReleaseArgAndValidFileArg(unittest.TestCase): def setUp(self): self.facter = Facter(lsb_release_module = 'non.existant', lsb_release = 'false', file = 'test-data/lsb-release') def testDistributorsIdReturnsUbuntu(self): self.assertEquals(self.facter.distributors_id, 'Ubuntu-in-test-data') class TestFacterReadFirstWord(unittest.TestCase): def setUp(self): self.facter = Facter() def testUsualIssueFile(self): self.assertEquals(self.facter.get_distrib_id_from_file('test-data/lsb-release'), 'Ubuntu-in-test-data') def testEmptyFile(self): self.assertEquals(self.facter.get_distrib_id_from_file('test-data/empty'), None) def testMissingFile(self): self.assertEquals(self.facter.get_distrib_id_from_file('test-data/does_not_exist'), None) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_reporter.py0000755000000000000000000000502411353677217021400 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.reporter import Reporter from apt_forktracer.status import Status class TestReporter(test_helper.MoxTestCase): def setUp(self): super(TestReporter, self).setUp() self.reporter = Reporter() def testFormattingNoCandidateVersion(self): v1 = self.struct() v1.string = '1.2' status = Status('apackage', v1, None) report = self.reporter.format(status) self.assertContains(report, '1.2->)') self.assertNotContains(report, '[') def testFormattingNoCurrentVersion(self): v1 = self.struct() v1.string = '1.2' status = Status('apackage', None, v1) report = self.reporter.format(status) self.assertContains(report, '(->1.2') self.assertNotContains(report, '[') def testFormatting(self): v1 = self.struct() v1.string = '1.2' v2 = self.struct() v2.string = '1.3' v3, v4 = self.struct(), self.struct() v3.string = '1.2.3' v4.string = 'x.y.z' status = Status('apackage', v1, v2, {'Debian': [v3, v4], 'another origin': [v3, v4]}) report = self.reporter.format(status) self.assertContains(report, 'apackage (1.2->1.3) ') self.assertContains(report, ' [Debian: 1.2.3 x.y.z]') self.assertContains(report, ' [another origin: 1.2.3 x.y.z]') def testFormattingSameVersion(self): v = self.struct() v.string = '1.2' status = Status('apackage', v, v) report = self.reporter.format(status) self.assertNotContains(report, '[') self.assertContains(report, 'apackage (1.2)') def testReporting(self): """Since this should print to stdout, we don't call it, just check the method's there.""" mock_status = self.struct() self.assert_(self.reporter.report) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_config_stanza.py0000755000000000000000000000531411353737676022373 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.config_stanza import ConfigStanza class Test_ConfigStanza(test_helper.MoxTestCase): def setUp(self): super(Test_ConfigStanza, self).setUp() self.cs = ConfigStanza() self.assert_(self.cs.is_empty()) def test_empty(self): self.assertRaisesWithMessageContaining(ValueError, 'line 2', self.cs.finish, 2) def test_all_attributes(self): self.cs.set('Package', 'dpkg', 2) self.assert_(not self.cs.is_empty()) self.cs.set('Accept-Origin', 'NonDebian Stuff', 3) self.cs.set('Track-oriGIN', 'Debian', 4) self.cs.set('track-version', '1.2.3', 5) self.assertEquals(self.cs.get('package'), 'dpkg') self.assertEquals(self.cs.get('accept-origin'), 'NonDebian Stuff') self.assert_(self.cs.matches('accept-origin', 'NonDebian Stuff')) self.assert_(not self.cs.matches('accept-origin', 'Debian')) self.assertEquals(self.cs.get('track-origin'), 'Debian') self.assertEquals(self.cs.get('track-version'), '1.2.3') self.assert_(not self.cs.is_empty()) self.assertEquals(self.cs.finish(6), self.cs) def test_invalid_attribute(self): self.assertRaisesWithMessageContaining(ValueError, 'invalid tag', self.cs.set, 'FoO', 'bar', 2) self.assertRaisesWithMessageContaining(ValueError, 'line 2', self.cs.set, 'FoO', 'bar', 2) def test_wildcard_attributes(self): self.cs.set('Package', 'dpkg', 2) self.assert_(not self.cs.is_empty()) self.cs.set('Accept-Origin', '*', 3) self.cs.set('Track-oriGIN', '*', 4) self.cs.set('track-version', '1.2.3', 5) self.assertEquals(self.cs.get('accept-origin'), '*') self.assert_(self.cs.matches('accept-origin', 'whatever')) self.assertEquals(self.cs.get('track-origin'), '*') self.assert_(self.cs.matches('track-origin', 'whatever')) self.assert_(not self.cs.is_empty()) self.assertEquals(self.cs.finish(6), self.cs) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/__init__.py0000755000000000000000000000062511353670600020225 0ustar __all__ = [ 'test_adapters', 'test_apt_pkg_adapter', 'test_cache_adapter', 'test_checker', 'test_config', 'test_config_finder', 'test_config_parser', 'test_config_stanza', 'test_depcache_adapter', 'test_facter', 'test_integration', 'test_package_adapter', 'test_package_file_adapter', 'test_policy', 'test_reporter', 'test_status', 'test_verbose_policy', 'test_version_adapter', 'test_version_checker', ] apt-forktracer-0.4/lib/apt_forktracer/tests/test_verbose_policy.py0000755000000000000000000000214011353677217022556 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.policy import VerbosePolicy class TestVerbosePolicy(unittest.TestCase): def setUp(self): self.policy = VerbosePolicy() def testTrue(self): self.assert_(self.policy.should_report(None)) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_apt_pkg_adapter.py0000755000000000000000000001341111353712247022653 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import apt_pkg from apt_forktracer.testlib import test_helper from apt_forktracer.apt_pkg_adapter import AptPkgAdapter from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.version_adapter import VersionAdapter from apt_forktracer.reporter import Reporter from apt_forktracer.cache_adapter import CacheAdapterFactory from apt_forktracer.depcache_adapter import DepCacheAdapter from apt_forktracer.depcache_adapter import DepCacheAdapterFactory class Base_Apt_Pkg_Adapter_Test(test_helper.MoxTestCase): def setUp(self): super(Base_Apt_Pkg_Adapter_Test, self).setUp() self.create_mock_apt_pkg() self.set_up_mock_apt_pkg() self.apa = AptPkgAdapter(self.mock_apt_pkg) self.set_up_apa() def create_mock_apt_pkg(self): self.mock_apt_pkg = self._create_mock_apt_pkg_module() def set_up_mock_apt_pkg(self): pass def set_up_apa(self): pass class Newer_Apt_Pkg_Adapter_Test(Base_Apt_Pkg_Adapter_Test): def create_mock_apt_pkg(self): self.mock_apt_pkg = apt_pkg def test_states(self): self.mox.ReplayAll() self.assertEquals(self.apa.state_installed, apt_pkg.CURSTATE_INSTALLED) self.assertEquals(self.apa.state_half_installed, apt_pkg.CURSTATE_HALF_INSTALLED) self.assertEquals(self.apa.state_half_configured, apt_pkg.CURSTATE_HALF_CONFIGURED) self.assertEquals(self.apa.state_unpacked, apt_pkg.CURSTATE_UNPACKED) class Uninitialized_Apt_Pkg_Adapter_Test(Base_Apt_Pkg_Adapter_Test): def test_methods_fail_on_uninitialized_adapter(self): self.mox.ReplayAll() self.assertRaisesWithMessageContaining(Exception, 'not initialized', self.apa.get_cache_adapter, 'foo', 'bar', 'baz') self.assertRaisesWithMessageContaining(Exception, 'not initialized', self.apa.get_depcache_adapter, 'foo') self.assertRaisesWithMessageContaining(Exception, 'not initialized', self.apa.version_compare, 'foo', 'bar') self.assertRaisesWithMessageContaining(Exception, 'not initialized', self.apa.version_sort, ['foo', 'bar']) self.assertRaisesWithMessageContaining(Exception, 'not initialized', self.apa.version_max, ['foo', 'bar']) class Initialized_Apt_Pkg_Adapter_Test(Base_Apt_Pkg_Adapter_Test): def set_up_mock_apt_pkg(self): self.mock_apt_pkg.init_config() self.mock_apt_pkg.init_system() def set_up_apa(self): self.apa.init() def test_get_cache_adapters(self): mock_reporter = self.mox.CreateMock(Reporter) mock_progress = self.struct() mock_apt_cache = self.struct() mock_cache_adapter = self.struct() mock_cache_adapter_factory = self.mox.CreateMock(CacheAdapterFactory) mock_apt_depcache = self.struct() mock_depcache_adapter = self.mox.CreateMock(DepCacheAdapter) mock_depcache_adapter_factory = self.mox.CreateMock(DepCacheAdapterFactory) self.mock_apt_pkg.Cache(mock_progress).AndReturn(mock_apt_cache) self.mock_apt_pkg.DepCache(mock_apt_cache).AndReturn(mock_apt_depcache) mock_cache_adapter_factory.create_cache_adapter(mock_apt_cache, self.apa, mock_reporter).AndReturn(mock_cache_adapter) mock_depcache_adapter_factory.create_depcache_adapter(mock_apt_depcache).AndReturn(mock_depcache_adapter) self.mox.ReplayAll() ca = self.apa.get_cache_adapter(mock_cache_adapter_factory, mock_reporter, mock_progress) dca = self.apa.get_depcache_adapter(mock_depcache_adapter_factory) self.assertEquals(ca, mock_cache_adapter) self.assertEquals(dca, mock_depcache_adapter) def test_get_depcache_adapter_fails_without_earlier_get_cache_adapter(self): mock_depcache_adapter_factory = self.mox.CreateMock(DepCacheAdapterFactory) self.mox.ReplayAll() self.assertRaisesWithMessageContaining(Exception, 'must call get_cache_adapter() earlier', self.apa.get_depcache_adapter, mock_depcache_adapter_factory) def test_version_comparison(self): self.mox.ReplayAll() self.assertRaises(ValueError, self.apa.version_compare, None, '1') self.assertRaises(ValueError, self.apa.version_compare, '1', None) self.assertRaises(ValueError, self.apa.version_compare, None, None) self.assert_(self.apa.version_compare('0', '1') < 0) self.assert_(self.apa.version_compare('1', '1') == 0) self.assert_(self.apa.version_compare('1', '0') > 0) def test_version_sort(self): self.mox.ReplayAll() self.assertEquals(self.apa.version_sort([]), []) v1 = VersionAdapter(FakeVersion._create('1', [])) v0 = VersionAdapter(FakeVersion._create('0', [])) v2 = VersionAdapter(FakeVersion._create('2.0', [])) v21 = VersionAdapter(FakeVersion._create('2.0~1', [])) self.assertEquals(self.apa.version_sort([v21]), [v21]) self.assertEquals(self.apa.version_sort([v1, v0, v21, v2]), [v2, v21, v1, v0]) def test_version_max_returns_None_on_empty_list(self): self.mox.ReplayAll() self.assertEquals(self.apa.version_max([]), None) v2 = VersionAdapter(FakeVersion._create('2.0', [])) v21 = VersionAdapter(FakeVersion._create('2.0~1', [])) self.assertEquals(self.apa.version_max([v21]), v21) self.assertEquals(self.apa.version_max([v2, v21]), v2) self.assertEquals(self.apa.version_max([v21, v2]), v2) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_checker.py0000755000000000000000000001533411353712247021140 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.apt_pkg_adapter import AptPkgAdapter from apt_forktracer.checker import Checker from apt_forktracer.testlib.fake_package import FakePackage from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.package_adapter import PackageAdapter from apt_forktracer.version_adapter import VersionAdapter class CheckerCheckTestCase(test_helper.MoxTestCase): """Common plumbing.""" def setUp(self): super(CheckerCheckTestCase, self).setUp() self.fp = FakePackage() self.apt_pkg_adapter = AptPkgAdapter(self._create_mock_apt_pkg_module()) self.apt_pkg_adapter.init() self.setUpChecker() def setUpChecker(self): self.checker = Checker(self._create_mock_facter('Debian')) def _prepare_package_with_candidate_from_official_source_and_current_from_unofficial(self): self.fp.append_version(FakeVersion._create('1.2.2', ['NotDebian']), True) self.fp.append_version(FakeVersion._create('1.2.3', ['Debian'])) pa = PackageAdapter(self.fp) pa.candidate_version = VersionAdapter(FakeVersion._create('1.2.3', ['Debian'])) return pa def _prepare_package_with_candidate_different_from_current(self): self.fp.append_version(FakeVersion._create('1.2.3', ['Debian']), True) pa = PackageAdapter(self.fp) pa.candidate_version = VersionAdapter((FakeVersion._create('1.2.4', ['Debian']))) return pa class GeneralNonVerboseCheckerCheckTest(CheckerCheckTestCase): """Whether a status is returned depends on the CANDIDATE version, not the currently installed one. This is to cut down on noise when machines are behind WRT upgrades.""" def test_aborts_on_package_without_versions(self): pa = PackageAdapter(self.fp) self.assertRaises(ValueError, self.checker.check, pa) def test_aborts_on_package_without_current_version(self): """CacheAdapter should not pass such objects to us. It's better to know in such cases. If there will ever be a need to support this, it can be changed.""" self.fp.append_version(FakeVersion._create('1.2.3', ['Debian']), True) pa = PackageAdapter(self.fp) pa.candidate_version = pa.current_version pa.current_version = None self.assertRaises(ValueError, self.checker.check, pa) def test_does_not_abort_and_returns_a_status_object_on_package_without_candidate_version(self): """Because a candidate version is always reported by apt in normal situations, even when the only known version is installed and not available anywhere else. One case where no candidate version is reported is when there is a pin which cannot be met.""" self.fp.append_version(FakeVersion._create('1.2.3', ['Debian']), True) pa = PackageAdapter(self.fp) pa.candidate_version = None status = self.checker.check(pa) self.assert_(status != None) def test_returns_none_in_common_case(self): """Common case means: package with identical, officially-available current and candidate versions, which is also the newest available version.""" self.fp.append_version(FakeVersion._create('1.2.3', ['Debian']), True) self.fp.append_version(FakeVersion._create('1.2.2', ['Debian'])) pa = PackageAdapter(self.fp) pa.candidate_version = pa.current_version self.assertEquals(self.checker.check(pa), None) def test_returns_none_in_common_case_when_all_versions_available_additionally_from_unofficial_source(self): self.fp.append_version(FakeVersion._create('1.2.3', ['Debian', 'UnOfficial']), True) self.fp.append_version(FakeVersion._create('1.2.2', ['Debian', 'UnOfficial'])) pa = PackageAdapter(self.fp) pa.candidate_version = pa.current_version self.assertEquals(self.checker.check(pa), None) def test_returns_a_status_object_on_package_with_same_current_and_candidate_both_only_locally(self): self.fp.current_ver = FakeVersion._create('1.2.3', ['dpkg']) pa = PackageAdapter(self.fp) pa.candidate_version = pa.current_version self.assert_(self.checker.check(pa) != None) def test_returns_a_status_object_on_package_with_candidate_from_unofficial_source(self): self.fp.append_version(FakeVersion._create('1.2.3', ['Unofficial']), True) self.fp.append_version(FakeVersion._create('1.2', ['Debian'])) pa = PackageAdapter(self.fp) pa.candidate_version = VersionAdapter(FakeVersion._create('1.2.5', ['NonDebian'])) status = self.checker.check(pa) self.assert_(status != None) self.assertEquals(status.package_name, 'afake') self.assertEquals(status.installed_version.string, '1.2.3') self.assertEquals(status.candidate_version.string, '1.2.5') def test_package_without_candidate_version_and_current_unofficial(self): self.fp.current_ver = FakeVersion._create('1.2.2', ['NotDebian']) pa = PackageAdapter(self.fp) pa.candidate_version = None status = self.checker.check(pa) self.assert_(status != None) class NonVerboseCheckerCheckTest(GeneralNonVerboseCheckerCheckTest): def test_returns_none_on_package_with_candidate_from_official_source_and_current_from_unofficial(self): self.assertEquals(self.checker.check(self._prepare_package_with_candidate_from_official_source_and_current_from_unofficial()), None) def test_returns_none_when_candidate_different_from_current(self): pa = self._prepare_package_with_candidate_different_from_current() self.assertEquals(self.checker.check(pa), None) class VerboseCheckerCheckTest(GeneralNonVerboseCheckerCheckTest): """Returns None in less cases than in the non-verbose mode.""" def setUpChecker(self): self.checker = Checker(self._create_mock_facter('Debian'), True) def test_returns_a_status_object_on_package_with_candidate_from_official_source_and_current_from_unofficial(self): status = self.checker.check(self._prepare_package_with_candidate_from_official_source_and_current_from_unofficial()) self.assert_(status != None) def test_returns_a_status_object_when_candidate_different_from_current(self): pa = self._prepare_package_with_candidate_different_from_current() self.assert_(self.checker.check(pa) != None) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_config_finder.py0000755000000000000000000000271111353677217022332 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.config_finder import ConfigFinder class Test_Config_Finder(test_helper.MoxTestCase): def test(self): cf = ConfigFinder('test-data/config', 'test-data/not_exists', 'test-data/config.d') entries = 0 plan = [ ('test-data/config', 4), ('test-data/config.d/sub.conf', 0), ('INVALID ENTRY to catch unexpected files', 0) ] for path, file in cf: self.assertEquals(path, plan[entries][0]) self.assert_(file.readlines() > plan[entries][1]) entries += 1 self.assertEquals(entries, 2) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_policy.py0000755000000000000000000004600411353737676021046 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.apt_pkg_adapter import AptPkgAdapter from apt_forktracer.config_stanza import ConfigStanza from apt_forktracer.testlib.fake_package_file import FakePackageFile from apt_forktracer.package_file_adapter import PackageFileAdapter from apt_forktracer.version_adapter import VersionAdapter from apt_forktracer.policy import Policy from apt_forktracer.status import Status class TestPolicyBase(test_helper.MoxTestCase): def _create_mock_version_adapter(self, version_string): if version_string == None: return None mva = self.mox.CreateMock(VersionAdapter) mva.files = [] if type(version_string) == tuple: mva.string = version_string[0] for o in version_string[1]: mva.files.append(PackageFileAdapter(FakePackageFile(origin = o))) else: mva.string = version_string mva.files.append(PackageFileAdapter(FakePackageFile(origin = 'Debian'))) return mva def _create_mock_status(self, package, current_version, candidate_version, _official_versions, other_versions = {}): official_versions = [self._create_mock_version_adapter(v) for v in _official_versions] vbo = {} vbo['Debian'] = official_versions for o, vers in other_versions.items(): vbo[o] = [self._create_mock_version_adapter((v, o,)) for v in vers] return Status(package, self._create_mock_version_adapter(current_version), self._create_mock_version_adapter(candidate_version), vbo) def _create_mock_config(self, hashes): stanzas = [] for hash in hashes: stanza = ConfigStanza() stanza.set('package', 'apackage', 1) stanza.set('accept-origin', hash['accepted_origin'], 2) stanza.set('track-origin', hash['track_origin'], 3) stanza.set('track-version', hash['track_version'], 4) stanza.finish(4) stanzas.append(stanza) mock_config = self.struct() mock_config.package = lambda name: name == 'apackage' and stanzas or [] return mock_config def setUp(self): super(TestPolicyBase, self).setUp() self.apt_pkg_adapter = AptPkgAdapter(self._create_mock_apt_pkg_module()) self.apt_pkg_adapter.init() self.mock_facter = self._create_mock_facter('Debian') self.set_up_policy_creation() def set_up_policy_creation(self): self.policy = Policy(self.apt_pkg_adapter, self.mock_facter, self._create_mock_config([])) def assert_should_report_yes(self, current_version, candidate_version, official_versions, package = 'apackage', other_versions = {}): s = self._create_mock_status(package, current_version, candidate_version, official_versions, other_versions = other_versions) self.assert_(self.policy.should_report(s)) def assert_should_report_NOT(self, current_version, candidate_version, official_versions, package = 'apackage', other_versions = {}): s = self._create_mock_status(package, current_version, candidate_version, official_versions, other_versions = other_versions) self.assert_(not self.policy.should_report(s)) def test_missing_version(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', None, ['2.1']) self.assert_should_report_yes(None, '2.1~1', ['2.1']) self.assert_should_report_yes('2.1~1', '2.1~1', []) class Test_Policy_Base_Version(TestPolicyBase): def test_base_version(self): self.mox.ReplayAll() self.assertRaises(TypeError, self.policy.base, None) self.assertEquals(self.policy.base(''), '') self.assertEquals(self.policy.base('1'), '1') self.assertEquals(self.policy.base('1~1'), '1') self.assertEquals(self.policy.base('1~1~2'), '1~1') class Test_Policy_Should_Report_With_Same_Candidate_Version_As_Installed(TestPolicyBase): def test_official_not_available(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.1~1', []) def test_candidate_newer_than_available_official(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.1~1', ['2.0']) def test_candidate_same_as_latest_official(self): self.mox.ReplayAll() # This would probably be skipped by Checker, but in case it wasn't, we should not report it. self.assert_should_report_NOT('2.1', '2.1', ['2.1']) self.assert_should_report_NOT('2.1~1', '2.1~1', ['2.1~1']) def test_candidate_derived_directly_from_latest_official(self): self.mox.ReplayAll() self.assert_should_report_NOT('2.1~1', '2.1~1', ['2.1']) def test_candidate_derived_from_previous_official_version(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.1~1', ['2.2', '2.1']) class Test_Policy_Should_Report_With_Newer_Candidate_Version_Than_Installed(TestPolicyBase): """A candidate version newer than the installed one means that an upgrade is pending. If the _candidate_ version is recent enough not to cause a report, then reporting the status based on the _currently_ installed version will cause noise on machines which have not yet been upgraded. Therefore we report what the situation would be _after_ the upgrade, as the system administrator has other tools to notify her when there are pending upgrades. The VerbosePolicy can be used to display all packages identified by Checker.""" # none available def test_official_not_available(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.1~2', []) # newer than available def test_installed_and_candidate_package_newer_than_available_official(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.1~2', ['2.0']) def test_installed_package_derived_directly_from_latest_official_while_candidate_is_even_newer(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.2~2', ['2.1']) # same as or derived from newest available def test_installed_and_candidate_package_derived_directly_from_latest_official(self): self.mox.ReplayAll() self.assert_should_report_NOT('2.1~1', '2.1~2', ['2.1']) self.assert_should_report_NOT('2.1~1', '2.1', ['2.1']) self.assert_should_report_NOT('2.1~1', '2.1~2', ['2.1~2']) def test_installed_package_derived_from_previous_official_version_while_candidate_derived_from_newest_official(self): self.mox.ReplayAll() self.assert_should_report_NOT('2.1~1', '2.2~1', ['2.2', '2.1']) self.assert_should_report_NOT('2.1~1', '2.2', ['2.2', '2.1']) self.assert_should_report_NOT('2.1~1', '2.2~2', ['2.2~2', '2.1']) # older than available def test_both_installed_and_candidate_package_derived_from_previous_official_version(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.1~2', ['2.2', '2.1']) class Test_Policy_Should_Report_With_Older_Candidate_Version_Than_Installed(TestPolicyBase): """An older candidate version means that a downgrade is pending. This calls for the same behaviour as described in Test_Policy_Should_Report_With_Newer_Candidate_Version_Than_Installed.""" # none available def test_official_not_available(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~2', '2.1~1', []) # newer than available def test_both_installed_and_candidate_package_newer_than_available_official(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~2', '2.1~1', ['2.0']) # same as or derived from available def test_both_installed_and_candidate_package_newer_than_available_official(self): self.mox.ReplayAll() self.assert_should_report_NOT('2.1~2', '2.0~1', ['2.0']) self.assert_should_report_NOT('2.1~2', '2.0', ['2.0']) self.assert_should_report_NOT('2.1~2', '2.0~1', ['2.0~1']) # older than available def test_installed_package_derived_directly_from_latest_official_while_candidate(self): self.mox.ReplayAll() self.assert_should_report_yes('2.1~1', '2.0~1', ['2.1']) class Test_Policy_With_Config(TestPolicyBase): def set_up_policy_creation(self): self.policy = Policy(self.apt_pkg_adapter, self.mock_facter, self._create_mock_config([ {'accepted_origin': 'accepted origin', 'track_origin': 'foo', 'track_version': '1.0'}, {'accepted_origin': 'accepted origin', 'track_origin': 'Debian', 'track_version': '2.0'}])) def test_configured_origin_is_ignored(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0']) self.assert_should_report_NOT(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['1.0'], other_versions = {'foo': ['1.0']}) def test_unconfigured_origin_is_not_ignored(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2', ['ANOTHER origin']), ('2.2', ['ANOTHER origin']), ['2.0']) def test_configured_origin_is_not_ignored_if_official_version_does_not_meet_condition(self): self.mox.ReplayAll() # official sources have too new a version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.1']) # official sources have too old version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['1.9']) # official sources have no versions at all self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), []) def test_default_rule_not_referenced_if_config_is_provided_for_a_given_package(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0']) def test_default_rules_are_referenced_for_packages_without_configuration(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2', ['ANOTHER origin']), ('2.2', ['ANOTHER origin']), ['2.0'], package = 'package_without_config') self.assert_should_report_NOT(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0'], package = 'package_without_config') class Test_Policy_With_Config_Track_Candidate_Version(TestPolicyBase): def set_up_policy_creation(self): self.policy = Policy(self.apt_pkg_adapter, self.mock_facter, self._create_mock_config([{'accepted_origin': 'accepted origin', 'track_origin': 'Debian', 'track_version': '=candidate'}])) def test_configured_origin_is_ignored(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.2']) def test_unconfigured_origin_is_not_ignored(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2', ['ANOTHER origin']), ('2.2', ['ANOTHER origin']), ['2.2']) def test_configured_origin_is_not_ignored_if_official_version_does_not_meet_condition(self): self.mox.ReplayAll() # official sources have too new a version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.3']) # official sources have too old version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.1']) # official sources have no versions at all self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), []) def test_default_rule_not_referenced_if_config_is_provided_for_a_given_package(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0']) def test_default_rules_are_referenced_for_packages_without_configuration(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2', ['ANOTHER origin']), ('2.2', ['ANOTHER origin']), ['2.0'], package = 'package_without_config') self.assert_should_report_NOT(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0'], package = 'package_without_config') class Test_Policy_With_Config_Track_Candidate_Base_Version(TestPolicyBase): def set_up_policy_creation(self): self.policy = Policy(self.apt_pkg_adapter, self.mock_facter, self._create_mock_config([{'accepted_origin': 'accepted origin', 'track_origin': 'Debian', 'track_version': '=candidate-base'}])) def test_configured_origin_is_ignored(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.2~1', ['accepted origin']), ('2.2~1', ['accepted origin']), ['2.2']) def test_unconfigured_origin_is_not_ignored(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2~1', ['ANOTHER origin']), ('2.2~1', ['ANOTHER origin']), ['2.2']) def test_configured_origin_is_not_ignored_if_official_version_does_not_meet_condition(self): self.mox.ReplayAll() # official sources have too new a version self.assert_should_report_yes(('2.2~1', ['accepted origin']), ('2.2~1', ['accepted origin']), ['2.3']) # official sources have too old version self.assert_should_report_yes(('2.2~1', ['accepted origin']), ('2.2~1', ['accepted origin']), ['2.1']) # official sources have no versions at all self.assert_should_report_yes(('2.2~1', ['accepted origin']), ('2.2~1', ['accepted origin']), []) def test_default_rule_not_referenced_if_config_is_provided_for_a_given_package(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0']) def test_default_rules_are_referenced_for_packages_without_configuration(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2', ['ANOTHER origin']), ('2.2', ['ANOTHER origin']), ['2.0'], package = 'package_without_config') self.assert_should_report_NOT(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0'], package = 'package_without_config') class Test_Policy_With_Config_For_Non_Debian_Tracked_Origin(TestPolicyBase): def set_up_policy_creation(self): self.policy = Policy(self.apt_pkg_adapter, self.mock_facter, self._create_mock_config([{'accepted_origin': 'accepted origin', 'track_origin': 'tracked origin', 'track_version': '2.0'}])) def test_configured_origin_is_ignored(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0'], other_versions = {'tracked origin': ['2.0']}) def test_only_configured_origin_is_ignored(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2', ['ANOTHER origin']), ('2.2', ['ANOTHER origin']), ['2.0'], other_versions = {'tracked origin': ['2.0']}) def test_origin_is_not_ignored_if_tracked_version_does_not_meet_condition(self): self.mox.ReplayAll() # tracked origin has too new a version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0'], other_versions = {'tracked origin': ['2.1']}) # tracked origin has too old version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0'], other_versions = {'tracked origin': ['1.9']}) # tracked origin has no version at all self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0'], other_versions = {'some other origin': ['2.0']}) self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0'], other_versions = {}) def test_default_rule_not_referenced_if_config_is_provided_for_a_given_package(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0'], other_versions = {'tracked origin': ['2.0']}) def test_default_rule_IS_referenced_for_packages_without_configuration(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0'], package = 'package_without_config', other_versions = {'tracked origin': ['2.0']}) class Test_Policy_With_Config_For_Any_Accepted_Origin(TestPolicyBase): def set_up_policy_creation(self): self.policy = Policy(self.apt_pkg_adapter, self.mock_facter, self._create_mock_config([{'accepted_origin': '*', 'track_origin': 'tracked origin', 'track_version': '2.0'}])) def test_any_origin_is_ignored(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.2', ['accepted origin']), ('2.2', ['whatever origin']), ['2.0'], other_versions = {'tracked origin': ['2.0']}) def test_origin_is_not_ignored_if_tracked_version_does_not_meet_condition(self): self.mox.ReplayAll() # tracked origin has too new a version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['whatever origin']), ['2.0'], other_versions = {'tracked origin': ['2.1']}) # tracked origin has too old version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['whatever origin']), ['2.0'], other_versions = {'tracked origin': ['1.9']}) # tracked origin has no version at all self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['whatever origin']), ['2.0'], other_versions = {'some other origin': ['2.0']}) self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['whatever origin']), ['2.0'], other_versions = {}) def test_default_rule_IS_referenced_for_packages_without_configuration(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0'], package = 'package_without_config', other_versions = {'tracked origin': ['2.0']}) class Test_Policy_With_Config_For_Any_Tracked_Origin(TestPolicyBase): def set_up_policy_creation(self): self.policy = Policy(self.apt_pkg_adapter, self.mock_facter, self._create_mock_config([{'accepted_origin': 'accepted origin', 'track_origin': '*', 'track_version': '2.0'}])) def test_origin_is_ignored_if_ANY_origin_meets_condition(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0'], other_versions = {'whatever origin': ['2.0']}) def test_origin_is_not_ignored_if_NO_origin_meets_version_condition(self): self.mox.ReplayAll() # too new version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.0'], other_versions = {'whatever origin': ['2.1']}) # too old version self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.1'], other_versions = {'whatever origin': ['1.9']}) # no versions at all self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['accepted origin']), ['2.1'], other_versions = {}) def test_unconfigured_origin_is_not_ignored(self): self.mox.ReplayAll() self.assert_should_report_yes(('2.2', ['accepted origin']), ('2.2', ['ANOTHER origin']), ['2.0'], other_versions = {'whatever origin': ['2.0']}) def test_default_rule_IS_referenced_for_packages_without_configuration(self): self.mox.ReplayAll() self.assert_should_report_NOT(('2.0~1', ['ANOTHER origin']), ('2.0~1', ['ANOTHER origin']), ['2.0'], package = 'package_without_config', other_versions = {'tracked origin': ['2.0']}) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_package_file_adapter.py0000755000000000000000000000716211353712247023626 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.testlib.fake_package_file import FakePackageFile from apt_forktracer.package_file_adapter import PackageFileAdapter class BasePFATest(test_helper.MoxTestCase): def setUpPF(self): self.fake_package_file = FakePackageFile() def setUp(self): super(BasePFATest, self).setUp() self.setUpPF() self.pfa = PackageFileAdapter(self.fake_package_file) self.mock_debian_facter = self._create_mock_facter('Debian') self.mock_ubuntu_facter = self._create_mock_facter('Ubuntu') class BasePFATestWithOfficial(BasePFATest): def testIsOfficialTrue(self): self.assert_(self.pfa.is_official(self.mock_debian_facter)) def testIsOfficialFalse(self): self.assert_(not self.pfa.is_official(self.mock_ubuntu_facter)) class TestBasePackageFileAdapter(BasePFATestWithOfficial): def testAttributes(self): self.assertEquals(self.pfa.name, '/a/fake') self.assertEquals(self.pfa.archive, 'stable-proposed-updates') self.assertEquals(self.pfa.component, 'main') self.assertEquals(self.pfa.version, '1.0') self.assertEquals(self.pfa.origin, 'Debian') self.assertEquals(self.pfa.label, 'Debian') self.assertEquals(self.pfa.not_automatic, 0) self.assertEquals(self.pfa.index_type, 'Debian Package Index') def testStringification(self): self.assertMatches(str(self.pfa), '') class TestBasePackageFileAdapterNonAuto(BasePFATestWithOfficial): def setUpPF(self): BasePFATest.setUpPF(self) self.fake_package_file.not_automatic = 1 def testAttributes(self): self.assertEquals(self.pfa.name, '/a/fake') self.assertEquals(self.pfa.archive, 'stable-proposed-updates') self.assertEquals(self.pfa.component, 'main') self.assertEquals(self.pfa.version, '1.0') self.assertEquals(self.pfa.origin, 'Debian') self.assertEquals(self.pfa.label, 'Debian') self.assertEquals(self.pfa.not_automatic, 1) self.assertEquals(self.pfa.index_type, 'Debian Package Index') def testStringification(self): self.assertMatches(str(self.pfa), '') class TestBasePackageFileAdapterDpkgStatus(BasePFATest): def setUpPF(self): self.fake_package_file = FakePackageFile(type = 'dpkg') def testAttributes(self): self.assertEquals(self.pfa.name, '/var/lib/dpkg/status') self.assertEquals(self.pfa.index_type, 'Debian dpkg status file') def testStringification(self): self.assertMatches(str(self.pfa), '') def testIsOfficialFalse(self): self.assert_(not self.pfa.is_official(self.mock_debian_facter)) self.assert_(not self.pfa.is_official(self.mock_ubuntu_facter)) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_adapters.py0000755000000000000000000000767311353712247021346 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import mox import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.testlib.fake_package import FakePackage from apt_forktracer.testlib.fake_package_file import FakePackageFile from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.depcache_adapter import DepCacheAdapter from apt_forktracer.package_adapter import PackageAdapter,PackageAdapterFactory from apt_forktracer.version_adapter import VersionAdapter class Test_Package_And_Version_Reading(test_helper.MoxTestCase): def setUp(self): super(Test_Package_And_Version_Reading, self).setUp() self.fake = FakePackage() v1 = FakeVersion() v1.ver_str = '1.2.3' v1.append_package_file(FakePackageFile()) fpf = FakePackageFile() fpf.not_automatic = 1 v1.append_package_file(fpf) v2 = FakeVersion() v2.ver_str = '4.5.6' self.fake.version_list.append(v1) self.fake.version_list.append(v2) self.fake.current_ver = v1 self.set_up_package_adapter_and_replay_all() def set_up_package_adapter_and_replay_all(self): self.mox.ReplayAll() self.p = PackageAdapter(self.fake) def testPackageAndVersionsReadCorrectly(self): self.assertEquals(self.p.name, 'afake') self.assertEquals(len(self.p.versions), 2) v1 = self.p.versions[0] self.assertEquals(v1.string, '1.2.3') self.assertEquals(len(v1.files), 2) v1pf0 = v1.files[0] self.assertEquals(v1pf0.name, '/a/fake') v1pf1 = v1.files[1] self.assert_(v1pf1.not_automatic) v2 = self.p.versions[1] self.assertEquals(v2.string, '4.5.6') def testStringificationWorks(self): s = str(self.p) self.assertContains(s, 'PackageAdapter') self.assertContains(s, ' afake ') self.assertMatches(s, 'v=<.*1.2.3.*->') vs = str(self.p.versions[0]) self.assertContains(vs, 'VersionAdapter') self.assertContains(vs, '1.2.3') vpfs = str(self.p.versions[0].files[0]) self.assertContains(vpfs, 'PackageFileAdapter') self.assertContains(vpfs, 'path=/a/fake') self.assertContains(vpfs, 'a=stable-proposed-updates') self.assertContains(vpfs, 'c=main') self.assertContains(vpfs, 'v=1.0') self.assertContains(vpfs, 'o=Debian') self.assertContains(vpfs, 'l=Debian') self.assertNotContains(vpfs, 'NONAUTO') vpfs2 = str(self.p.versions[0].files[1]) self.assertContains(vpfs2, 'NONAUTO') class Test_With_Factory_Creation(Test_Package_And_Version_Reading): def set_up_package_adapter_and_replay_all(self): self.mox.ReplayAll() self.p = PackageAdapterFactory().create_package_adapter(self.fake) class Test_With_Factory_Creation_With_Candidate(Test_Package_And_Version_Reading): def set_up_package_adapter_and_replay_all(self): mock_depcache_adapter = self.mox.CreateMock(DepCacheAdapter) self.va = VersionAdapter(FakeVersion._create('1.2.4', [])) mock_depcache_adapter.get_candidate_version(mox.Func(lambda pa: pa.name == 'afake')).AndReturn(self.va) self.mox.ReplayAll() self.p = PackageAdapterFactory(mock_depcache_adapter).create_package_adapter(self.fake) def test_candidate_version(self): self.assertEquals(self.p.candidate_version, self.va) s = str(self.p) self.assertMatches(s, 'v=<.*1.2.3.*->.*<.*1.2.4') if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_cache_adapter.py0000755000000000000000000001770211353712247022300 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import apt_pkg import mox import unittest from apt_forktracer.checker import Checker from apt_forktracer.policy import Policy from apt_forktracer.reporter import Reporter from apt_forktracer.status import Status from apt_forktracer.depcache_adapter import DepCacheAdapter from apt_forktracer.testlib import test_helper from apt_forktracer.apt_pkg_adapter import AptPkgAdapter from apt_forktracer.cache_adapter import CacheAdapterFactory from apt_forktracer.testlib.fake_cache import FakeCache from apt_forktracer.testlib.fake_package import FakePackage from apt_forktracer.package_adapter import PackageAdapterFactory from apt_forktracer.version_adapter import VersionAdapter class Test_Base_Cache_Adapter(test_helper.MoxTestCase): def setUp(self): super(Test_Base_Cache_Adapter, self).setUp() self.set_up_fake_cache() self.mock_policy = self.mox.CreateMock(Policy) self.mock_reporter = self.mox.CreateMock(Reporter) self.mock_depcache_adapter = self.mox.CreateMock(DepCacheAdapter) self.package_adapter_factory = PackageAdapterFactory(self.mock_depcache_adapter) self.set_up_apt_pkg() self.apt_pkg_adapter = AptPkgAdapter(self.fake_apt_pkg_module) self.ca = CacheAdapterFactory().create_cache_adapter(self.fake_cache, self.apt_pkg_adapter, self.mock_reporter) self.mock_checker = self.mox.CreateMock(Checker) self.version_adapter = self.mox.CreateMock(VersionAdapter) self.version_adapter.string = '1.2.3' self.mock_status = self.mox.CreateMock(Status) def set_up_fake_cache(self): self.fake_cache = FakeCache() self.set_up_fake_cache_tweak() def set_up_fake_cache_tweak(self): pass def set_up_apt_pkg(self): self.fake_apt_pkg_module = self._create_mock_apt_pkg_module() test_helper.copy_state_constants(self.fake_apt_pkg_module, apt_pkg) def test_basic_stringification_works(self): self.mox.ReplayAll() self.assertContains(str(self.ca), 'CacheAdapter') def test_states_copied(self): self.mox.ReplayAll() self.assertEquals(self.ca.states_we_check[0], apt_pkg.CURSTATE_INSTALLED) self.assertEquals(self.ca.states_we_check[1], apt_pkg.CURSTATE_HALF_CONFIGURED) self.assertEquals(self.ca.states_we_check[2], apt_pkg.CURSTATE_HALF_INSTALLED) self.assertEquals(self.ca.states_we_check[3], apt_pkg.CURSTATE_UNPACKED) class Test_Empty_Cache_Adapter(Test_Base_Cache_Adapter): def test_stringification_with_empty_cache(self): self.mox.ReplayAll() self.assertContains(str(self.ca), '0 package(s)') def test_invokes_checker_zero_times_with_empty_cache(self): self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) class Test_One_Installed_Package_Cache_Adapter(Test_Base_Cache_Adapter): def set_up_fake_cache_tweak(self): self.fake_cache.append_package(FakePackage()) def test_stringification_with_one_package(self): self.mox.ReplayAll() self.assertContains(str(self.ca), '1 package(s)') def test_invokes_checker_one_time_with_cache_containing_one_package(self): self.mock_depcache_adapter.get_candidate_version(mox.Func(lambda o: o.name == 'afake')).AndReturn(self.version_adapter) self.mock_checker.check(mox.IgnoreArg()).AndReturn(self.mock_status) self.mock_policy.should_report(self.mock_status).AndReturn(True) self.mock_reporter.report(self.mock_status) self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) class Test_Two_Installed_Packages_Cache_Adapter(Test_Base_Cache_Adapter): def set_up_fake_cache_tweak(self): self.fake_cache.append_package(FakePackage(name = 'foo')) self.fake_cache.append_package(FakePackage(name = 'foo')) def test_invokes_checker_two_times_with_cache_containing_one_package(self): self.mock_depcache_adapter.get_candidate_version(mox.Func(lambda o: o.name == 'foo')).AndReturn(self.version_adapter) self.mock_depcache_adapter.get_candidate_version(mox.Func(lambda o: o.name == 'foo')).AndReturn(self.version_adapter) self.mock_checker.check(mox.IgnoreArg()).AndReturn(self.mock_status) self.mock_checker.check(mox.IgnoreArg()).AndReturn(self.mock_status) self.mock_policy.should_report(self.mock_status).AndReturn(True) self.mock_policy.should_report(self.mock_status).AndReturn(True) self.mock_reporter.report(self.mock_status) self.mock_reporter.report(self.mock_status) self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) class Test_One_Not_Installed_Package_Cache_Adapter(Test_Base_Cache_Adapter): def set_up_fake_cache_tweak(self): self.fake_cache.append_package(FakePackage(current_state = apt_pkg.CURSTATE_NOT_INSTALLED)) def test_invokes_checker_zero_times_with_cache_containing_one_not_installed_package(self): self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) class Test_One_Conffiles_Package_Cache_Adapter(Test_Base_Cache_Adapter): def set_up_fake_cache_tweak(self): self.fake_cache.append_package(FakePackage(current_state = apt_pkg.CURSTATE_CONFIG_FILES)) def test_invokes_checker_zero_times_with_cache_containing_one_package_with_just_config_files(self): self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) class Test_One_Half_Configured_Package_Cache_Adapter(Test_Base_Cache_Adapter): def set_up_fake_cache_tweak(self): self.fake_cache.append_package(FakePackage(current_state = apt_pkg.CURSTATE_HALF_CONFIGURED)) def test_invokes_checker_one_time_with_cache_containing_one_package_half_configured(self): self.mock_depcache_adapter.get_candidate_version(mox.Func(lambda o: o.name == 'afake')).AndReturn(self.version_adapter) self.mock_checker.check(mox.IgnoreArg()).AndReturn(self.mock_status) self.mock_policy.should_report(self.mock_status).AndReturn(True) self.mock_reporter.report(self.mock_status) self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) class Test_One_Half_Installed_Package_Cache_Adapter(Test_Base_Cache_Adapter): def set_up_fake_cache_tweak(self): self.fake_cache.append_package(FakePackage(current_state = apt_pkg.CURSTATE_HALF_INSTALLED)) def test_invokes_checker_one_time_with_cache_containing_one_package_half_installed(self): self.mock_depcache_adapter.get_candidate_version(mox.Func(lambda o: o.name == 'afake')).AndReturn(self.version_adapter) self.mock_checker.check(mox.IgnoreArg()).AndReturn(None) self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) class Test_One_Unpacked_Package_Cache_Adapter(Test_Base_Cache_Adapter): def set_up_fake_cache_tweak(self): self.fake_cache.append_package(FakePackage(current_state = apt_pkg.CURSTATE_UNPACKED)) def test_invokes_checker_one_time_with_cache_containing_one_package_half_configured(self): self.mock_depcache_adapter.get_candidate_version(mox.Func(lambda o: o.name == 'afake')).AndReturn(self.version_adapter) self.mock_checker.check(mox.Func(lambda o:o.name == 'afake' and o.candidate_version.string == '1.2.3')).AndReturn(self.mock_status) self.mock_policy.should_report(self.mock_status).AndReturn(False) self.mox.ReplayAll() self.ca.run(self.mock_checker, self.mock_policy, self.package_adapter_factory) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_config_parser.py0000755000000000000000000000412311353677217022356 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import mox import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.config_parser import ConfigParser from apt_forktracer.config import Config class Test_ConfigParser(test_helper.MoxTestCase): def setUp(self): super(Test_ConfigParser, self).setUp() self.cp = ConfigParser() self.c = self.mox.CreateMock(Config) def test_loading_empty_file(self): self.mox.ReplayAll() self.assertEquals(self.cp.load([], self.c), []) def test_loading_invalid_syntax_file(self): fake_file = ['\n', 'invalid line\n'] self.mox.ReplayAll() self.assertRaisesWithMessageContaining(Exception, 'line 2', self.cp.load, fake_file) def test_loading_invalid_stanza_file(self): fake_file = ['\n', 'package:val\n', 'acCepT-OrigiN: val2\n'] self.mox.ReplayAll() self.assertRaisesWithMessageContaining(Exception, 'line 3', self.cp.load, fake_file) def test_loading_valid_file(self): fake_file = ['\n', 'package:val\n', 'acCepT-OrigiN: val2\n', ' track-oriGin : a spaced val \n', 'track-version:foo'] self.c.add(mox.Func(lambda stanza: stanza.get('package') == 'val')) self.mox.ReplayAll() ret = self.cp.load(fake_file, self.c) self.assertEquals(len(ret), 1) self.assertEquals(ret[0].get('package'), 'val') if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_status.py0000755000000000000000000000750711353677217021071 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.testlib.fake_package_file import FakePackageFile from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.status import Status from apt_forktracer.version_adapter import VersionAdapter class TestInstantiation(test_helper.MoxTestCase): def setUp(self): super(TestInstantiation, self).setUp() fv1 = FakeVersion() fv1.append_package_file(FakePackageFile()) installed_version = VersionAdapter(fv1) fv2 = FakeVersion('1.2.4') fv2.append_package_file(FakePackageFile()) candidate_version = VersionAdapter(fv2) self.versions_by_origin = {'Debian': [VersionAdapter(FakeVersion('foo'))], 'Another': [VersionAdapter(FakeVersion('bar')), VersionAdapter(FakeVersion('baz'))]} self.s = Status('foo', installed_version, candidate_version, self.versions_by_origin) def testCorrectness(self): self.assertEquals(self.s.package_name, 'foo') self.assertEquals(self.s.installed_version.string, '1.2.3') self.assertEquals(self.s.candidate_version.string, '1.2.4') installed_ver_pkgs = self.s.installed_version.files self.assertEquals(installed_ver_pkgs[0].origin, 'Debian') self.assertEquals(self.s.versions_from('Debian')[0].string, 'foo') self.assertEquals(self.s.versions_from('Another')[0].string, 'bar') self.assertEquals(self.s.versions_from('Another')[1].string, 'baz') self.assertEquals(self.s.versions_from('nowhere'), []) all = self.s.all_available_versions() self.assertEquals(len(all), 3) all_strings = [v.string for v in all] all_strings.sort() self.assert_('foo' in [v.string for v in all]) self.assert_('bar' in [v.string for v in all]) def testStringification(self): self.assertMatches(str(self.s), r'.*1\.2\.4.*\[Debian: foo\]') self.assertMatches(str(self.s), r'.*1\.2\.4.*\[Another: bar,baz\]') class Test_Instantiation_Without_Official_Versions(test_helper.MoxTestCase): def setUp(self): super(Test_Instantiation_Without_Official_Versions, self).setUp() fv1 = FakeVersion('1.2.5') fv1.append_package_file(FakePackageFile()) installed_version = VersionAdapter(fv1) fv2 = FakeVersion('1.2.6') fv2.append_package_file(FakePackageFile()) candidate_version = VersionAdapter(fv2) self.versions_by_origin = {'NonDebian': [VersionAdapter(FakeVersion('foo'))]} self.s = Status('foo', installed_version, candidate_version, self.versions_by_origin) def testCorrectness(self): self.assertEquals(self.s.package_name, 'foo') self.assertEquals(self.s.installed_version.string, '1.2.5') self.assertEquals(self.s.candidate_version.string, '1.2.6') installed_ver_pkgs = self.s.installed_version.files self.assertEquals(installed_ver_pkgs[0].origin, 'Debian') self.assertEquals(self.s.versions_from('NonDebian')[0].string, 'foo') self.assertEquals(self.s.versions_from('nowhere'), []) def testStringification(self): self.assertMatches(str(self.s), r'.*1\.2\.6.*') if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_version_checker.py0000755000000000000000000000461611353677217022715 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.testlib.fake_package import FakePackage from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.version_adapter import VersionAdapter from apt_forktracer.version_checker import VersionChecker class VersionCheckerTest(test_helper.MoxTestCase): def setUp(self): super(VersionCheckerTest, self).setUp() self.fp = FakePackage() self.facter = self._create_mock_facter('Debian') self.setUpChecker() def setUpChecker(self): self.vchecker = VersionChecker(self.facter) def test_analyze_version_without_sources_returns_true(self): v = VersionAdapter(FakeVersion._create('1.2.3', [])) self.assert_(self.vchecker.analyze(v)) def test_analyze_version_only_in_dpkg_status_file_returns_true(self): v = VersionAdapter(FakeVersion._create('1.2.3', ['dpkg'])) self.assert_(self.vchecker.analyze(v)) def test_analyze_version_in_dpkg_status_file_and_unofficial_source_returns_true(self): v = VersionAdapter(FakeVersion._create('1.2.3', ['dpkg', 'NonDebian'])) self.assert_(self.vchecker.analyze(v)) def test_analyze_version_in_dpkg_status_file_and_official_source_returns_false(self): v = VersionAdapter(FakeVersion._create('1.2.3', ['dpkg', 'Debian'])) self.assert_(not self.vchecker.analyze(v)) def test_analyze_version_in_dpkg_status_file_and_both_official_and_unofficial_source_returns_false(self): v = VersionAdapter(FakeVersion._create('1.2.3', ['dpkg', 'Debian', 'NonDebian'])) self.assert_(not self.vchecker.analyze(v)) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/Makefile0000644000000000000000000000176311110217710017543 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. all: @echo -n '__all__ = [ ' > __init__.py @for f in [a-z]*.py;do n=$$(basename $$f .py); echo -n "'$$n', ";done >> __init__.py @echo ']' >> __init__.py cd ../../.. && ./run_tests.py apt-forktracer-0.4/lib/apt_forktracer/tests/test_integration.py0000755000000000000000000001521411353712247022054 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import apt_pkg import mox import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.apt_pkg_adapter import AptPkgAdapter from apt_forktracer.cache_adapter import CacheAdapterFactory from apt_forktracer.checker import Checker from apt_forktracer.config import Config from apt_forktracer.config_finder import ConfigFinder from apt_forktracer.config_parser import ConfigParser from apt_forktracer.depcache_adapter import DepCacheAdapter from apt_forktracer.testlib.fake_package import FakePackage from apt_forktracer.testlib.fake_package_file import FakePackageFile from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.package_adapter import PackageAdapterFactory from apt_forktracer.policy import Policy, VerbosePolicy from apt_forktracer.reporter import Reporter from apt_forktracer.facter import Facter class TestIntegraton(test_helper.MoxTestCase): def setUp(self): super(TestIntegraton, self).setUp() dpkg_status_file = FakePackageFile(type = 'dpkg') debian_stable_package_file = FakePackageFile(archive = 'stable') debian_proposed_updates_package_file = FakePackageFile(archive = 'stable-proposed-updates') debian_security_package_file = FakePackageFile(archive = 'stable-security') local_package_file = FakePackageFile(origin = 'SnakeOil, Inc.', archive = 'etch') libc6_version = FakeVersion('2.6.1-2etch1') libc6_version.append_package_file(debian_stable_package_file) libc6_version.append_package_file(debian_security_package_file) libc6_updates_version = FakeVersion('2.6.1-2etch2') libc6_updates_version.append_package_file(debian_proposed_updates_package_file) libc6_updates_version.append_package_file(dpkg_status_file) libc6 = FakePackage(name = 'libc6') libc6.append_version(libc6_updates_version, True) libc6.append_version(libc6_version) libspf_version = FakeVersion('0.1-1') libspf_version.append_package_file(debian_stable_package_file) libspf_updates_version = FakeVersion('0.1-2') libspf_updates_version.append_package_file(debian_proposed_updates_package_file) libspf_local_version = FakeVersion('0.1-1~sl1') libspf_local_version.append_package_file(dpkg_status_file) libspf_local_version.append_package_file(local_package_file) libspf = FakePackage(name = 'libspf') libspf.append_version(libspf_version) libspf.append_version(libspf_local_version, True) libspf.append_version(libspf_updates_version) libfoobar_version = FakeVersion('0.5-5') libfoobar_version.append_package_file(debian_stable_package_file) libfoobar_local_version = FakeVersion('0.5-5~sl1') libfoobar_local_version.append_package_file(dpkg_status_file) libfoobar_local_version.append_package_file(local_package_file) libfoobar = FakePackage(name = 'libfoobar') libfoobar.append_version(libfoobar_version) libfoobar.append_version(libfoobar_local_version, True) git_version = FakeVersion('1:1.5.2.5-2build1') git_version.append_package_file(debian_stable_package_file) git_backport_version = FakeVersion('1:1.5.6.3-1.1ubuntu2~mowsiany.1') git_backport_version.append_package_file(dpkg_status_file) git_backport_version.append_package_file(local_package_file) git = FakePackage(name = 'git-core') git.append_version(git_version) git.append_version(git_backport_version, True) self.apt_cache = self.struct() self.apt_cache.packages = [git, libc6, libspf, libfoobar] self.apt_depcache = self.struct() version_table = { 'libc6': libc6_updates_version, 'libspf': libspf_local_version, 'libfoobar': libfoobar_local_version, 'git-core': git_backport_version} self.apt_depcache.get_candidate_ver = lambda o: version_table[o.name] self.reporter = self.mox.CreateMock(Reporter) self.mock_progress = self.struct() self.apt_pkg = self._create_mock_apt_pkg_module() test_helper.copy_state_constants(self.apt_pkg, apt_pkg) self.apt_pkg.Cache(self.mock_progress).AndReturn(self.apt_cache) self.facter = self.mox.CreateMock(Facter) self.facter.distributors_id = 'Debian' def finishSetUp(self): self.apt_pkg_adapter = AptPkgAdapter(self.apt_pkg) self.apt_pkg_adapter.init() cache_adapter_factory = CacheAdapterFactory() self.package_adapter_factory = PackageAdapterFactory(DepCacheAdapter(self.apt_depcache)) self.cache_adapter = self.apt_pkg_adapter.get_cache_adapter(cache_adapter_factory, self.reporter, self.mock_progress) config_finder = ConfigFinder('test-data/config') config_parser = ConfigParser() self.config = Config() for path, file in config_finder: config_parser.load(file, self.config) def test_verbose(self): # lib6 - never self.reporter.report(mox.Func(lambda o: o.package_name == 'libspf')).InAnyOrder() self.reporter.report(mox.Func(lambda o: o.package_name == 'libfoobar')).InAnyOrder() self.reporter.report(mox.Func(lambda o: o.package_name == 'git-core')).InAnyOrder() self.mox.ReplayAll() self.finishSetUp() checker = Checker(self.facter, True) policy = VerbosePolicy() self.cache_adapter.run(checker, policy, self.package_adapter_factory) def test_non_verbose_empty_config(self): # libc6 - never self.reporter.report(mox.Func(lambda o: o.package_name == 'libspf')).InAnyOrder() # libfoobar - never self.reporter.report(mox.Func(lambda o: o.package_name == 'git-core')).InAnyOrder() self.mox.ReplayAll() self.finishSetUp() checker = Checker(self.facter) policy = Policy(self.apt_pkg_adapter, self.facter, Config()) self.cache_adapter.run(checker, policy, self.package_adapter_factory) def test_non_verbose(self): # libc6 - never self.reporter.report(mox.Func(lambda o: o.package_name == 'libspf')) # libfoobar - never # git-core - never self.mox.ReplayAll() self.finishSetUp() checker = Checker(self.facter) policy = Policy(self.apt_pkg_adapter, self.facter, self.config) self.cache_adapter.run(checker, policy, self.package_adapter_factory) if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_version_adapter.py0000755000000000000000000001060311353712247022713 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.testlib.fake_package_file import FakePackageFile from apt_forktracer.testlib.fake_version import FakeVersion from apt_forktracer.version_adapter import VersionAdapter class TestBaseVersionAdapter(test_helper.MoxTestCase): def setUp(self): super(TestBaseVersionAdapter, self).setUp() self.setUpFakeVersion() self.setUpVersionAdapter() def setUpFakeVersion(self): self.fake_version = FakeVersion() def setUpVersionAdapter(self): self.va = VersionAdapter(self.fake_version) def testString(self): self.assertEquals(self.va.string, '1.2.3') def testLenOfFilesListPositive(self): "If there is a version, it must come from at least one file (dpkg status)." self.assert_(self.va.files > 0) def testBasicStringification(self): self.assertMatches(str(self.va), r'') class TestOneFileVersionAdapter(TestBaseVersionAdapter): def setUp(self): super(TestOneFileVersionAdapter, self).setUp() self.setUpFakeVersion() self.setUpAddAFile() self.setUpVersionAdapter() def testFileCount(self): self.assertEquals(len(self.va.files), 1) self.assertEquals(self.va.files[0].name, '/b/lah') def testStringification(self): self.assertMatches(str(self.va), r'') class TestThreeFilesVersionAdapter(TestBaseVersionAdapter): def setUp(self): super(TestThreeFilesVersionAdapter, self).setUp() self.setUpFakeVersion() for i in range(3): self.setUpAddAFile() self.setUpVersionAdapter() def testOneFile(self): self.assertEquals(len(self.va.files), 3) def testStringification(self): self.assertMatches(str(self.va), r'') if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/tests/test_depcache_adapter.py0000755000000000000000000000427411353712247022771 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import apt_pkg import unittest from apt_forktracer.testlib import test_helper from apt_forktracer.depcache_adapter import DepCacheAdapterFactory from apt_forktracer.package_adapter import PackageAdapter from apt_forktracer.testlib.fake_package import FakePackage from apt_forktracer.testlib.fake_package_file import FakePackageFile from apt_forktracer.testlib.fake_version import FakeVersion class TestDepCacheAdapter(test_helper.MoxTestCase): def setUp(self): super(TestDepCacheAdapter, self).setUp() self.mock_depcache = self.mox.CreateMock(apt_pkg.DepCache) self.a_fake_package = FakePackage() self.package_adapter = PackageAdapter(self.a_fake_package) self.dca = DepCacheAdapterFactory().create_depcache_adapter(self.mock_depcache) def testNoCandidate(self): self.mock_depcache.get_candidate_ver(self.a_fake_package).AndReturn(None) self.mox.ReplayAll() version_adapter = self.dca.get_candidate_version(self.package_adapter) self.assertEquals(version_adapter, None) def testWithCandidate(self): fake_version = FakeVersion('1.2') fake_version.append_package_file(FakePackageFile()) self.mock_depcache.get_candidate_ver(self.a_fake_package).AndReturn(fake_version) self.mox.ReplayAll() version_adapter = self.dca.get_candidate_version(self.package_adapter) self.assertEquals(version_adapter.string, '1.2') if __name__ == '__main__': unittest.main() apt-forktracer-0.4/lib/apt_forktracer/forktracer.py0000755000000000000000000000473511110217710017462 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import apt_pkg import getopt from apt_forktracer.apt_pkg_adapter import AptPkgAdapter, NullProgress from apt_forktracer.cache_adapter import CacheAdapterFactory from apt_forktracer.checker import Checker from apt_forktracer.config import Config from apt_forktracer.config_finder import ConfigFinder from apt_forktracer.config_parser import ConfigParser from apt_forktracer.depcache_adapter import DepCacheAdapterFactory from apt_forktracer.facter import Facter from apt_forktracer.package_adapter import PackageAdapterFactory from apt_forktracer.policy import Policy, VerbosePolicy from apt_forktracer.reporter import Reporter def run(verbose): facter = Facter() reporter = Reporter() apt_pkg_adapter = AptPkgAdapter(apt_pkg) apt_pkg_adapter.init() cache_adapter = apt_pkg_adapter.get_cache_adapter(CacheAdapterFactory(), reporter, NullProgress()) apt_depcache_adapter = apt_pkg_adapter.get_depcache_adapter(DepCacheAdapterFactory()) package_adapter_factory = PackageAdapterFactory(apt_depcache_adapter) checker = Checker(facter, verbose) config = Config() config_finder = ConfigFinder('/etc/apt/forktracer.conf', '/etc/apt/forktracer.d') config_parser = ConfigParser() for path, file in config_finder: config_parser.load(file, config) if verbose: policy = VerbosePolicy() else: policy = Policy(apt_pkg_adapter, facter, config) cache_adapter.run(checker, policy, package_adapter_factory) def main(sys): try: opts, args = getopt.getopt(sys.argv[1:], 'v', ['verbose']) except getopt.GetoptError, err: print str(err) sys.exit(1) verbose = False for o, a in opts: if o in ('-v', '--verbose'): verbose = True else: assert False, 'unhandled option' run(verbose) apt-forktracer-0.4/lib/apt_forktracer/config.py0000755000000000000000000000264611110217710016564 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. class Config: """Encapsulates config file information.""" def __init__(self): self._stanzas = [] self._package_map = {} def add(self, stanza): """Adds a given stanza for later retrieval.""" self._stanzas.append(stanza) name = stanza.get('package') if self._package_map.has_key(name): self._package_map[name].append(stanza) else: self._package_map[name] = [ stanza ] def package(self, package_name): """Returns a (potentially empty) list of all stanzas for the given package name.""" if self._package_map.has_key(package_name): return self._package_map[package_name] else: return [] apt-forktracer-0.4/MANIFEST.in0000644000000000000000000000206011110217710012712 0ustar # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. include run_tests.py run_forktracer apt-forktracer setup.py include apt-forktracer.8 forktracer.conf.5 include apt-forktracer.pl.8 forktracer.conf.pl.5 include MANIFEST.in LICENSE recursive-include lib *.py Makefile recursive-include test-data * .* apt-forktracer-0.4/apt-forktracer.pl.80000644000000000000000000001156311111321076014615 0ustar .\" apt-forktracer - a utility for managing package versions .\" Copyright (C) 2008 Marcin Owsiany .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License along .\" with this program; if not, write to the Free Software Foundation, Inc., .\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. .TH APT-FORKTRACER 8 2008-11-16 "Projekt Debian" .SH NAZWA apt-forktracer \- narzędzie wspomagające zarządzanie wersjami pakietów .SH SKŁADNIA .B apt-forktracer [ \-v ] .SH OPIS .SS Wprowadzenie Utrzymanie systemu Debian w wersji stabilnej często wymaga instalacji nieoficjalnych wersji programów: .TP backporty Nowsze wersje pakietów, przystosowane do wersji stabilnej, zawierające nową funkcjonalność niedostępną w danej edycji stabilnej. W tym przypadku wersja pakietu najczęściej jest nowsza niż wersja dostępna w edycji stabilnej. Oznacza to, że teoretycznie nie trzeba "przypinać" pakietu do tej wersji, ponieważ APT wybierze ją domyślnie. .TP lokalne zmiany wersji oficjalnej Najczęściej są to drobne zmiany, więc wystarcza niewielka modyfikacja numeru wersji pakietu. Można to zrobić na dwa sposoby: .sp 1 Spróbować wymyślić taki numer wersji, który byłby nowszy niż obecny oficjalny, ale starszy niż .I następny oficjalny. Sposób ten nie wymaga "przypinania" pakietu, ale w praktyce może łatwo zawieść w nieoczekiwanym momencie \- nigdy nie wiadomo tak naprawdę jaki będzie następny oficjalny numer wersji pakietu \- może okazać się starszy, niż wymyślony przez nas. .sp 1 Drugi sposób polega na takiej modyfikacji numeru wersji, aby była ona starsza od oficjalnej. Bardzo przydatny tutaj jest znak tyldy, który dpkg traktuje w specjalny sposób: wystarczy "doklejenie" do numeru wersji napisu zaczynającego się od tyldy, na przykład .B 1.2 \(-> .BR 1.2~sl.1 . Ten sposób wymaga jednoczesnego "przypięcia" pakietu do danej wersji lub źródła, ale jest bardziej niezawodny, bo działa niezależnie od tego jaka będzie kolejna wersja oficjalna. .PP W obu powyższych przypadkach mamy jednak do czynienia z tym samym problemem: APT nie piśnie ani słówkiem, jeśli pojawi się jakaś nowsza oficjalna wersja pakietu (np. poprawka dotycząca bezpieczeństwa, lub inna poprawka w edycji stabilnej). Oznacza to, że można przegapić jakąś istotną zmianę. .sp 1 .B apt-forktracer to narzędzie ułatwiające śledzenie oficjalnych wersji pakietów, które zainstalowano lokalnie w innej wersji. .SS "Definicja oficjalnej wersji pakietu" Jest to taka wersja pakietu, która jest dostępny ze źródła, którego plik Release zawiera nagłówek Origin o wartości takiej, jak identyfikator dystrybutora systemu, określony przez wynik komendy .B "lsb_release \-\-id" lub przez pole .B DISTRIB_ID w pliku .IR /etc/lsb-release . .SS "Działanie programu" .B apt-forktracer analizuje każdy zainstalowany pakiet z osobna, wypisując na wyjściu te, które są w "niestandardowym" stanie. Znaczenie stanu "niestandardowego" zależy od trybu w jakim działa program: .TP tryb domyślny (nie-gadatliwy) stan ten oznacza pakiety w niepoprawnym stanie (na przykład brak wersji kandydującej), oraz takie, których kandydująca wersja jest inna niż najnowsza dostępna oficjalna wersja. .TP tryb gadatliwy stan ten oznacza dodatkowo pakiety których zainstalowana wersja różni się od kandydującej. .PP W trybie domyślnym dodatkowo czytane są pliki konfiguracyjne, które umożliwiają nakazanie programowi ignorowanie wybranych "niestandardowych" pakietów, o ile spełniają pewne warunki. Jeśli dla danego pakietu nie ma konfiguracji, to obowiązuje dla niego konfiguracja domyślna. Więcej informacji można znaleźć w .BR forktracer.conf (5). .SS "Format komunikatów" Program wypisuje komunikaty takie jak następujący: .sp 1 .nf foobar (1.2.3->1.2.4) [Debian: 1.2.3 1.2.4] [Other origin: 1.2.2] .fi .sp 1 Gdzie: .TP .B foobar nazwa pakietu .TP .B 1.2.3 zainstalowana wersja pakietu .TP .B 1.2.4 kandydująca wersja pakietu - patrz .BR apt-cache (8). .TP .B Debian wartość pola "Origin" jednego ze źródeł pakietu. Po dwukropku są wymienione dostępne z tego źródła wersje. .TP .B "Other origin" nazwa innego źródła. .SH OPCJE .TP .B \-v Włącza tryb "gadatliwy". .SH PLIKI .I /etc/apt/forktracer.conf .br .I /etc/apt/forktracer.d/*.conf .SH "PATRZ TEŻ" .BR forktracer.conf (5), .BR apt_preferences (5), .BR apt-cache (8). apt-forktracer-0.4/debian/0000755000000000000000000000000011672442021012410 5ustar apt-forktracer-0.4/debian/changelog0000644000000000000000000000264611672441763014306 0ustar apt-forktracer (0.4) unstable; urgency=medium * Upgrade lsb-release recommends to depends. (Closes: #651639) * Adjusted apt_pkg_adapter.NullProgress for new pyapt API. (Closes: #625566) * Bumped Standards-Version, no changes needed. * Move to debhelper 8, start using dh. -- Marcin Owsiany Thu, 15 Dec 2011 20:00:06 +0100 apt-forktracer (0.3) unstable; urgency=medium * Updated unit tests to use mox instead of pmock, which is dead. * Updated to use the so-called 0.8 API of python-apt. Setting urgency medium to make sure it migrates to testing before release, getting rid of those ugly deprecation warnings. (closes: #567137) * Added a versioned Recommends on lsb-release. (closes: #532746) * Bumped standards-version to 3.8.4 (no changes needed). * Bumped DH compat version to 7 (as well as DH build-dep version). * Added a debian/source/format file with "3.0 (native)" -- Marcin Owsiany Sun, 28 Mar 2010 21:20:58 +0100 apt-forktracer (0.2) unstable; urgency=low * Added the ability to read LSB distributor's ID by importing lsb_release Python module, that has been recently provided by lsb-release package. -- Marcin Owsiany Sat, 06 Jun 2009 13:31:22 +0100 apt-forktracer (0.1) unstable; urgency=low * Initial release (closes: #506151, the ITP bug) -- Marcin Owsiany Thu, 20 Nov 2008 17:30:15 +0000 apt-forktracer-0.4/debian/source/0000755000000000000000000000000011353737676013733 5ustar apt-forktracer-0.4/debian/source/format0000644000000000000000000000001511353737676015142 0ustar 3.0 (native) apt-forktracer-0.4/debian/control0000644000000000000000000000152011672435007014017 0ustar Source: apt-forktracer Section: admin Priority: optional Maintainer: Marcin Owsiany Build-Depends: debhelper (>= 8), python, python-support (>= 0.3) Standards-Version: 3.9.2 XS-Python-Version: >= 2.4 Package: apt-forktracer Architecture: all Depends: python-apt (>= 0.7.93.2), ${python:Depends}, ${misc:Depends}, lsb-release (>= 3.2-21) XB-Python-Version: ${python:Versions} Description: a utility for tracking non-official package versions apt-forktracer tries to alleviate the problem that APT stops tracking official versions of a package after you pin it or install a newer version. . It displays a list of packages which are in an inconsistent state or have a version other than the newest official installed. You can choose to ignore certain packages - if they match certain criteria - with a configuration file. apt-forktracer-0.4/debian/rules0000755000000000000000000000057311672441451013503 0ustar #!/usr/bin/make -f %: dh $@ # Install the module as private. override_dh_auto_install: python setup.py install --no-compile \ --install-scripts $(CURDIR)/debian/apt-forktracer/usr/bin \ --install-lib $(CURDIR)/debian/apt-forktracer/usr/share/apt-forktracer rm -f $(CURDIR)/debian/apt-forktracer/usr/share/apt-forktracer/apt_forktracer-*.egg-info apt-forktracer-0.4/debian/copyright0000644000000000000000000000206411110363211014333 0ustar This package was written and debianized by Marcin Owsiany in November 2008. The home page is http://marcin.owsiany.pl/apt-forktracer-page apt-forktracer - a utility for managing package versions Copyright (C) 2008 Marcin Owsiany This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. On Debian systems, a copy of the GNU General Public License can be found in /usr/share/common-licenses/GPL. apt-forktracer-0.4/debian/apt-forktracer.manpages0000644000000000000000000000011411672435451017056 0ustar apt-forktracer.pl.8 apt-forktracer.8 forktracer.conf.pl.5 forktracer.conf.5 apt-forktracer-0.4/debian/compat0000644000000000000000000000000211353733634013617 0ustar 7 apt-forktracer-0.4/debian/clean0000644000000000000000000000002511354135673013423 0ustar *.pyc *.pyo MANIFEST apt-forktracer-0.4/debian/pycompat0000644000000000000000000000000211110217710014147 0ustar 2 apt-forktracer-0.4/test-data/0000755000000000000000000000000011353677217013071 5ustar apt-forktracer-0.4/test-data/config.d/0000755000000000000000000000000011110217710014533 5ustar apt-forktracer-0.4/test-data/config.d/.hidden.config0000644000000000000000000000000011110217710017221 0ustar apt-forktracer-0.4/test-data/config.d/config.notreally0000644000000000000000000000000011110217710017721 0ustar apt-forktracer-0.4/test-data/config.d/sub.conf0000644000000000000000000000000111110217710016162 0ustar apt-forktracer-0.4/test-data/empty0000644000000000000000000000000011110217710014113 0ustar apt-forktracer-0.4/test-data/lsb-release0000644000000000000000000000013611353677217015212 0ustar blah blah DISTRIB_WHATEVER=Something blah DISTRIB_ID=Ubuntu-in-test-data DISTRIB_RELEASE=7.10 apt-forktracer-0.4/test-data/config0000644000000000000000000000014711110217710014236 0ustar Package: git-core Accept-Origin: SnakeOil, Inc. Track-Origin: Debian Track-Version: 1:1.5.2.5-2build1 apt-forktracer-0.4/run_tests.py0000755000000000000000000000343511110217710013566 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Runs all tests. # # This script must be run from the directory it is in. # Individual tests may also be executed directly like: ./tests/test_whatever.py from unittest import TestLoader, TextTestRunner import sys sys.path.append('lib') # The following is ugly, but it's the only method I've found of loading all # tests from all subpackages of package 'tests', without hardcoding their names # here. # We have to import both tests and its subpackages, otherwise dir() does not # find subpackages. from apt_forktracer import tests from apt_forktracer.tests import * def run_tests(verbosity): # Filter out special attributes of the package, to get only subpackages. test_names = [n for n in dir(tests) if not n.startswith('__')] # Load and run all tests all_tests = TestLoader().loadTestsFromNames(test_names, tests) TextTestRunner(verbosity=verbosity).run(all_tests) if __name__ == '__main__': if len(sys.argv) == 2: run_tests(int(sys.argv[1])) else: run_tests(1) apt-forktracer-0.4/apt-forktracer.80000644000000000000000000001114311111321076014175 0ustar .\" apt-forktracer - a utility for managing package versions .\" Copyright (C) 2008 Marcin Owsiany .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License along .\" with this program; if not, write to the Free Software Foundation, Inc., .\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. .TH APT-FORKTRACER 8 2008-11-16 "Debian Project" .SH NAME apt-forktracer \- a utility for managing package versions .SH SYNOPSIS .B apt-forktracer [ \-v ] .SH DESCRIPTION .SS Background Maintaining Debian stable systems sometimes requires installation of unofficial versions of packages: .TP backporting newer versions This is necessary, when significant new functionality is required on the system but unavailable in the official version found in the current stable release. In this case, the version string usually sorts as newer than the official stable version string. This means that pinning is not necessary, as APT will select such package version by default. .TP local changes to the official version Usually these are small changes, so a minor modification of the package version string is sufficient. There are two ways to do this: .sp 1 Try to invent a version string newer than the current one, but older than the .I next official one. This way does not require pinning, but is difficult to do reliably. It might turn out, that the next official version string is older than the one invented by you, which would cause the official version to be silently ignored. .sp 1 The other way is to modify the version string in such way that it sorts as older than the official one. The tilde character is very useful here, because dpkg treats it in a special way: it is sufficient to append any string starting with the tilde, to the version string, e.g. .B 1.2 \(-> .BR 1.2~sl.1 . This requires you to "pin" the package to that version, but it is more reliable, because works regardless of what the next official version number will be. .PP In both cases, there is one major drawback: APT will not warn you when newer versions of official packages (point releases, security updates) will appear in the stable release. This means you may miss some important change. .sp 1 .BR apt-forktracer 's job let you track newer official versions of locally overridden packages. .SS "Official package version definition" Official package version is a version which is available from a source, whose Release file's Origin header value is equal to the system distributor identifier, as indicated by the .B "lsb_release \-\-id" command, or by the .B DISTRIB_ID field in the .I /etc/lsb-release file. .SS "Program operation" .B apt-forktracer analyzes each installed package separately, reporting on the standard output these packages which are in a "non-standard" state. What "non-standard" means depends on the mode of program operation: .TP default (non-verbose) mode this state means packages in an incorrect state (e.g. no candidate version) or packages whose candidate version is different than the newest available official version. .TP verbose mode this state also includes packages whose installed version is different from the candidate version .PP In the default mode the program also reads configuration files, which let you ignore some of the "non-standard" packages, as long as they meet certain criteria. If there is no configuration for a given package, then a default configuration is used. More information is available in .BR forktracer.conf (5). .SS "Message format" The program outputs messages such as the following: .sp 1 .nf foobar (1.2.3->1.2.4) [Debian: 1.2.3 1.2.4] [Other origin: 1.2.2] .fi .sp 1 Where: .TP .B foobar package name .TP .B 1.2.3 installed package version .TP .B 1.2.4 candidate package version - see .BR apt-cache (8). .TP .B Debian the value of the "Origin" field of one of the package sources. Versions available from this source are listed after a colon. .TP .B "Other origin" another source origin .SH OPTIONS .TP .B \-v Turns on the verbose mode. .SH FILES .I /etc/apt/forktracer.conf .br .I /etc/apt/forktracer.d/*.conf .SH "SEE ALSO" .BR forktracer.conf (5), .BR apt_preferences (5), .BR apt-cache (8). apt-forktracer-0.4/apt-forktracer0000755000000000000000000000173311110217710014034 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys sys.path.insert(0, '/usr/share/apt-forktracer') from apt_forktracer import forktracer if __name__ == '__main__': forktracer.main(sys) apt-forktracer-0.4/.gitignore0000644000000000000000000000003311110217710013142 0ustar *.pyc *.pyo MANIFEST /dist apt-forktracer-0.4/run_forktracer0000755000000000000000000000170611110217710014136 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys sys.path.insert(0, 'lib') from apt_forktracer import forktracer if __name__ == '__main__': forktracer.main(sys) apt-forktracer-0.4/setup.py0000755000000000000000000000217211353712247012713 0ustar #!/usr/bin/python # apt-forktracer - a utility for managing package versions # Copyright (C) 2008,2010 Marcin Owsiany # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from distutils.core import setup setup(name = 'apt-forktracer', version = '0.3', description = 'Debian packages version tracing utility', author = 'Marcin Owsiany', author_email = 'marcin@owsiany.pl', packages = ['apt_forktracer'], package_dir = {'': 'lib'}, scripts = ['apt-forktracer'] ) apt-forktracer-0.4/forktracer.conf.50000644000000000000000000001454211111321076014342 0ustar .\" apt-forktracer - a utility for managing package versions .\" Copyright (C) 2008 Marcin Owsiany .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License along .\" with this program; if not, write to the Free Software Foundation, Inc., .\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. .TH FORKTRACER.CONF 5 "2008-11-16" "Debian Project" .SH NAME forktracer.conf \- apt-forktracer configuration file .SH DESCRIPTION .B apt-forktracer reports "non-standard" packages which are installed in the system. The configuration files let you ignore (skip reporting) some of them, provided they meet certain criteria. The program reads the .I /etc/apt/forktracer.conf file, as well as .I /etc/apt/forktracer.d/*.conf (skipping hidden files). .PP A config file consists of any number of stanzas, separated with at least one empty lines. A stanza has the following format: .sp 1 .nf Package: package Accept-Origin: origin1 Track-Origin: origin2 Track-Version: version .fi .sp 1 All these lines in a stanza are required, and they have the following meaning: .TP .B package the name of the package to which this stanza applies .TP .B origin1 the value of the Origin field of the source, from which a package should be ignored. A package will be ignored, if its candidate version comes from .BR source1 , and at the same time meets the condition given by the .B Track-* fields. A special value .B "*" means, that a package should be ignored regardless of the source of the candidate version. .TP .B origin2 the value of the Origin field of the source, from which the newest available version should be tracked. A special value .B "*" means, that a generally newest available version should be tracked, regardless of source. .TP .B version is the required version string available from the .B origin2 source. Apart from a literal version string, the following special values may be used: .BR =candidate , which means the current candidate version, and .BR =candidate-base , which means the base version (see below) of the current candidate version. .PP The above stanza would cause .B package to be skipped from program output, as long as its candidate version comes from .BR origin1 , and at the same time its newest version available from .B origin2 equals .BR version . .PP If there is more than one stanza for a given package, then it is omitted from the program output if at least one of them matches the current situation. .SS "Base version definition" A base version is extracted from a given version by stripping from its end the shortest string starting with a tilde character. For example for version .B 1:1.2-3~4~5 the base version is .BR 1:1.2-3~4 . .SS "Default configuration" If for a given package .B package there is no stanza in the configuration, then the program acts as if the following two stanzas existed: .sp 1 .nf Package: package Accept-Origin: * Track-Origin: distributor Track-Version: =candidate Package: package Accept-Origin: * Track-Origin: distributor Track-Version: =candidate-base .fi .sp 1 where .B distributor is the system distributor's identifier, as returned by .B "lsb_release \-\-id" or by the .B DISTRIB_ID field in the .I /etc/lsb-release file. .SH EXAMPLES .SS "Unofficial package" .B apt-forktracer reports packages which are not available from any official source, for example: .sp 1 .nf puppet-softwarelab (0.2) [SoftwareLab: 0.2 0.1] .fi .sp 1 The following stanza makes it skip such packages: .sp 1 .nf Package: puppet-softwarelab Accept-Origin: SoftwareLab Track-Origin: * Track-Version: =candidate .fi .sp 1 If the .B puppet-softwarelab package will be "pinned" to "release o=Softwarelab", then such configuration will make .B apt-forktracer report if .B puppet-softwarelab appears in any source other than .B SoftwareLab in a version newer than the one available from it. .SS Backport Installing a backport has a similar effect to installing an unofficial package: .sp 1 .nf spamc (3.2.3-0.volatile1) [Debian: 3.1.7-2] [volatile.debian.org: 3.2.3-0.volatile1] .fi .sp 1 The following stanza will cause such package to be skipped: .sp 1 .nf Package: spamc Accept-Origin: volatile.debian.org Track-Origin: * Track-Version: =candidate .fi .sp 1 In this situation a small official version string change (for example to 3.1.7-2etch1) will be silently ignored. Such configuration is therefore only suitable for cases where you trust the person providing the backport to carefully track changes in the stable edition and make sure they are incorporated in the backport they are distributing. In other cases, you should probably use the following configuration. .SS "Own modifications" Sometimes there is a situation where you make minor changes to a package, and you would like to know when a new official stable version is released, so that you can update your modified version. .sp 1 .nf policyd-weight (0.1.14-beta-6etch2.0.sl.1) [Debian: 0.1.14-beta-6etch2] [SoftwareLab: 0.1.14-beta-6etch2.0.sl.1] .fi .sp 1 The following configuration is useful in such cases: .sp 1 .nf Package: policyd-weight Accept-Origin: SoftwareLab Track-Origin: Debian Track-Version: 0.1.14-beta-6etch2 .fi .sp 1 It is worth mentioning, that if you apply a certain convention when numbering the modified version, then the .B "Default configuration" described before is sufficient. In this case, if the modified version would have a version number such as .BR 0.1.14-beta-6etch2~sl.1 then the above-mentioned stanza would be unnecessary. What is more, there would be no need to keep any configuration up-to-date in case of new stable version releases, because the default configuration is created dynamically based on the current situation. .SH FILES .I /etc/apt/forktracer.conf .br .I /etc/apt/forktracer.d/*.conf .SH "SEE ALSO" .BR apt\-cache (8), .BR apt\-forktracer (8), .BR apt_preferences (5). apt-forktracer-0.4/forktracer.conf.pl.50000644000000000000000000001505311111321076014752 0ustar .\" apt-forktracer - a utility for managing package versions .\" Copyright (C) 2008 Marcin Owsiany .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License along .\" with this program; if not, write to the Free Software Foundation, Inc., .\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. .TH FORKTRACER.CONF 5 "2008-11-16" "Projekt Debian" .SH NAZWA forktracer.conf \- konfiguracja programu apt-forktracer .SH OPIS Program .B apt-forktracer zgłasza "niestandardowe" pakiety zainstalowane w systemie. Pliki konfiguracyjne tego programu umożliwiają ignorowanie (pominięcie zgłaszania) wybranych z nich, o ile spełniają pewne warunki. Program czyta plik .I /etc/apt/forktracer.conf oraz pliki .I /etc/apt/forktracer.d/*.conf (za wyjątkiem plików ukrytych). Plik konfiguracyjny składa się z dowolnej ilości zwrotek, rozdzielonych jedną lub wieloma pustymi liniami. Format zwrotki jest następujący: .sp 1 .nf Package: pakiet Accept-Origin: źródło1 Track-Origin: źródło2 Track-Version: wersja .fi .sp 1 Wszystkie linie w zwrotce są wymagane, a ich znaczenie jest następujące: .TP .B pakiet nazwa pakietu, którego dotyczy dana zwrotka .TP .B źródło1 wartość pola Origin źródła, z którego należy ignorować dany pakiet. Pakiet zostanie zignorowany, jeśli jego kandydująca wersja pochodzi ze .BR źródła1 , i jednocześnie spełniony jest warunek dany w polach .BR Track-* . Specjalna wartość .B "*" oznacza, że należy ignorować pakiet niezależnie od źródła z którego pochodzi wersja kandydująca. .TP .B źródło2 wartość pola Origin źródła, którego najnowszą wersję należy śledzić. Specjalna wartość .B "*" oznacza, że należy śledzić ogólnie najnowszą dostępną wersję. .TP .B wersja to wymagany numer najnowszej wersji dostępnej ze źródła .BR źródło2 . Oprócz dosłownego numeru wersji, można tu także użyć jednej z dwóch wartości specjalnych: .B =candidate - oznaczająca aktualną wersję kandydującą, oraz .B =candidate-base - oznaczająca wersję podstawową (patrz niżej) aktualnej wersji kandydującej. .PP Powyższa zwrotka powoduje pominięcie pakietu .B pakiet z wyjścia programu, o ile kandydująca wersja pakietu pochodzi ze źródła .BR źródło1 , i jednocześnie najnowsza wersja tegoż pakietu dostępna ze źródła .B źródło2 jest równa .BR wersja . .PP Jeśli dla danego pakietu istnieje więcej niż jedna zwrotka, to jest on pomijany jeśli choć jedna z nich pasuje do obecnej sytuacji. .SS "Definicja wersji podstawowej" Wersję podstawową uzyskuje się poprzez obcięcie z końca danej wersji najkrótszego napisu zaczynającego się od tyldy. Na przykład dla wersji .B 1:1.2-3~4~5 wersja podstawowa to .BR 1:1.2-3~4 . .SS "Konfiguracja domyślna" Jeśli dla pewnego pakietu .B pakiet nie ma żadnej zwrotki w konfiguracji, to program działa tak, jakby istniały następujące dwie zwrotki: .sp 1 .nf Package: pakiet Accept-Origin: * Track-Origin: dystrybutor Track-Version: =candidate Package: pakiet Accept-Origin: * Track-Origin: dystrybutor Track-Version: =candidate-base .fi .sp 1 gdzie .B dystrybutor to identyfikator dystrybutora systemu, określony przez wynik komendy .B "lsb_release \-\-id" lub przez pole .B DISTRIB_ID w pliku .IR /etc/lsb-release . .SH PRZYKŁADY .SS "Nieoficjalny pakiet" .B apt-forktracer zgłasza pakiety niedostępne z żadnego źródła oficjalnego, na przykład: .sp 1 .nf puppet-softwarelab (0.2) [SoftwareLab: 0.2 0.1] .fi .sp 1 Aby tego uniknąć, należy dodać do pliku konfiguracyjnego następującą zwrotkę: .sp 1 .nf Package: puppet-softwarelab Accept-Origin: SoftwareLab Track-Origin: * Track-Version: =candidate .fi .sp 1 Jeśli dodatkowo "przypniemy" pakiet do źródła "release o=Softwarelab", to taka konfiguracja spowoduje, że .B apt-forktracer ostrzeże nas, jeśli w jakimś innym źródle pojawi się taki pakiet w wersji nowszej niż dostępne ze źródła SoftwareLab. .SS Backport Instalacja backportu ma podobny efekt jak instalacja pakietu nieoficjalnego: .sp 1 .nf spamc (3.2.3-0.volatile1) [Debian: 3.1.7-2] [volatile.debian.org: 3.2.3-0.volatile1] .fi .sp 1 Aby wymusić pomijanie tego pakietu, należy dodać analogiczną zwrotkę do konfiguracji: .sp 1 .nf Package: spamc Accept-Origin: volatile.debian.org Track-Origin: * Track-Version: =candidate .fi .sp 1 W tej sytuacji niewielka zmiana wersji pakietu oficjalnego (na przykład na 3.1.7-2etch1) pozostanie niezauważona. Konfiguracja ta nadaje się więc wyłącznie w przypadkach, gdy ufamy, że osoba udostępniająca zainstalowany przez nas backport śledzi zmiany wersji stabilnej i będzie wydawać poprawione backporty, zawierające niezbędne zmiany z edycji stabilnej. Jeśli nie mamy takiego zaufania, należy użyć następującej konfiguracji. .SS "Własne poprawki" Czasami pojawia się sytuacja, gdy wprowadziliśmy do pakietu niewielkie poprawki, i chcemy wiedzieć, gdy pojawi się nowsza wersja oficjalna, aby móc utworzyć nową wersję poprawioną. .sp 1 .nf policyd-weight (0.1.14-beta-6etch2.0.sl.1) [Debian: 0.1.14-beta-6etch2] [SoftwareLab: 0.1.14-beta-6etch2.0.sl.1] .fi .sp 1 Jest wtedy przydatna poniższa konfiguracja: .sp 1 .nf Package: policyd-weight Accept-Origin: SoftwareLab Track-Origin: Debian Track-Version: 0.1.14-beta-6etch2 .fi .sp 1 Warto zauważyć, że jeśli tworząc poprawioną wersję pakietu zastosujemy się do pewnej konwencji numeracji wersji, to do uzyskania tego efektu wystarczy opisana wyżej .BR "Konfiguracja domyślna" . W tym przypadku wystarczyłoby nadać pakietowi wersję .BR 0.1.14-beta-6etch2~sl.1 i powyższa zwrotka konfiguracji stałaby się zbędna. Co ważniejsze, odpada wtedy konieczność aktualizacji konfiguracji przy wydawaniu nowej wersji pakietu, ponieważ konfiguracja domyślna jest generowana automatycznie na podstawie obecnej sytuacji. .SH PLIKI .I /etc/apt/forktracer.conf .br .I /etc/apt/forktracer.d/*.conf .SH "PATRZ TEŻ" .BR apt\-cache (8), .BR apt\-forktracer (8), .BR apt_preferences (5).