summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore9
-rw-r--r--.svn.ignore2
-rw-r--r--AUTHORS44
-rw-r--r--CHANGES258
-rw-r--r--COPYING280
-rw-r--r--ChangeLog1959
-rw-r--r--HACKING68
-rw-r--r--INSTALL72
-rw-r--r--MANIFEST.in14
-rw-r--r--Makefile15
-rw-r--r--README66
-rw-r--r--README.api57
-rw-r--r--RELEASE_NOTES26
-rw-r--r--TODO19
-rwxr-xr-xbin/layman37
-rw-r--r--doc/.svn.ignore3
-rw-r--r--doc/Makefile38
-rw-r--r--doc/asciidoc.conf3
-rw-r--r--doc/layman.8.txt473
-rw-r--r--etc/Makefile4
-rw-r--r--etc/cache-private.xml25
-rw-r--r--etc/cache.xml531
-rw-r--r--etc/layman.cfg164
-rw-r--r--layman/.svn.ignore1
-rw-r--r--layman/__init__.py47
-rwxr-xr-xlayman/api.py556
-rw-r--r--layman/argsparser.py362
-rw-r--r--layman/cli.py342
-rw-r--r--layman/compatibility.py29
-rw-r--r--layman/config.py305
-rw-r--r--layman/constants.py55
-rw-r--r--layman/db.py482
-rw-r--r--layman/dbbase.py329
-rw-r--r--layman/debug.py399
-rw-r--r--layman/makeconf.py296
-rw-r--r--layman/output.py205
-rw-r--r--layman/overlays/.svn.ignore1
-rw-r--r--layman/overlays/__init__.py1
-rw-r--r--layman/overlays/bzr.py92
-rw-r--r--layman/overlays/cvs.py117
-rw-r--r--layman/overlays/darcs.py93
-rw-r--r--layman/overlays/g_common.py88
-rw-r--r--layman/overlays/git.py99
-rw-r--r--layman/overlays/mercurial.py93
-rwxr-xr-xlayman/overlays/overlay.py565
-rw-r--r--layman/overlays/rsync.py89
-rw-r--r--layman/overlays/source.py218
-rw-r--r--layman/overlays/svn.py116
-rw-r--r--layman/overlays/tar.py224
-rwxr-xr-xlayman/tests/dtest.py93
-rwxr-xr-xlayman/tests/external.py140
-rw-r--r--layman/tests/pylintrc19
-rw-r--r--layman/tests/testfiles/global-overlays.xml30
-rw-r--r--layman/tests/testfiles/layman-test.tar.bz2bin0 -> 845 bytes
-rw-r--r--layman/tests/testfiles/make.conf345
-rw-r--r--layman/tests/testfiles/overlays_bug_184449.xml19
-rw-r--r--layman/tests/testfiles/overlays_bug_286290.xml13
-rw-r--r--layman/tests/testfiles/subpath-1.xml19
-rw-r--r--layman/tests/testfiles/subpath-2.xml22
-rw-r--r--layman/utils.py214
-rw-r--r--layman/version.py28
-rwxr-xr-xsetup.py22
-rw-r--r--testpath.example17
-rwxr-xr-xtestsuite.sh13
64 files changed, 10365 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..464dd72
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*~
+*.pyc
+/doc/layman.8
+/doc/layman.8.html
+/doc/docbook-xsl.css
+/dist
+/MANIFEST
+*.patch
+testpath
diff --git a/.svn.ignore b/.svn.ignore
new file mode 100644
index 0000000..eaea68a
--- /dev/null
+++ b/.svn.ignore
@@ -0,0 +1,2 @@
+MANIFEST
+dist
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..0f2b329
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,44 @@
+AUTHORS
+-------
+
+Originally Written by
+
+ Gunnar Wrobel (wrobel@gentoo.org)
+
+Currently developed and maintained by:
+
+Brian Dolbec (brian.dolbec@gmail.com)
+
+
+Contributors:
+~~~~~~~~~~~~~
+
+Stefan Schweizer (genstef@gentoo.org) - git overlay support
+Adrian Perez (moebius@connectical.net) - bzr overlay support
+Andres Loeh (kosmikus@gentoo.org) - darcs overlay support
+Samuel Tardieu (sam@rfc1149.net) - mercurial overlay support
+Mike Auty (ikelos@gentoo.org) - Updates for python-2.6
+A. F. T. Arahesis (arfrever.fta@gmail.com) - Quieten the VC systems
+ - Better locale support.
+Donnie Berkholz (dberkholz@gentoo.org) - git support fixes
+Martin von Gagern (Martin.vGagern@gmx.net) - Better list format.
+Sebastian Pipping (sebastian@pipping.org) - repositories.xml support
+ - ElementTree migration
+ - docbook migration
+Christian Groschupp (christian@groschupp.org) - ElementTree migration
+
+Brian Dolbec (brian.dolbec@gmail.com) - New high level api,
+ - mid-level api enhancements,
+ - new message class,
+ - extend config options,
+ - code cleanup,
+ - new cli connections to
+ the new api,
+ - per repo type add, sync options
+ - per repo type post sync command
+ hooks,
+ - plug-in style repository.xml
+ lists
+ - new dictionary repo definition
+ support
+Auke Booij (auke@tulcod.com) - new g-common overlay support
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..1a80c84
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,258 @@
+CHANGES
+-------
+Version 2.0.0_rc2 - Released 2011-08-10
+=======================================
+
+ - fix success mistracking
+ - change raising an exception to outputing the error
+ - fix --list --verbose functionality, bug 375779
+ - update manpage
+ - add overlay_defs option to layman.cfg
+ - fix existing tests. add new tests for new classes
+ update all tests to pass
+ - fix undefined 'subpath'
+ - fix setting the timestamp from the remote server, bug # 376601
+ - fix the overly noisy output for unsupported overlay types
+ - add supported_types() to the api
+ - add --debug-level to cli options and code Message.debug()
+ - fix broken UnknownOverlayException
+ - fix error reporting in the api, refactor action & error processing/tracking.
+ - add a space before the * in the output func()'s as per "Etal"'s forum request
+ - fix a bug causing it to not get the correct config path
+ - fix typo causing traceback in bug 377401 comment # 31
+ - clean out some dead code.
+ - fix task spacing for running multiple tasks
+ - eliminate a duped error output
+ - run "svn cleanup..." for keyboard interrupts, bug 377035
+ - fix bug 378097. unofficial installed overlays not printing
+ - make it EPREFIX ready
+ - restore python 2.5 compatibility
+
+-------
+Version 2.0.0_rc1 - Released 2011-06-06
+=======================================
+
+ - major rewrite of the api's, extensions,
+ new cli-api connections, other enhancements...
+
+
+Version 1.4.2-r2 - Released 2011-04-28
+======================================
+
+ - fix bug 363797 python-2.5 test errors.
+
+ - fix broken *args for python 2.5 and 2.6+
+
+
+Version 1.4.2 - Released 2011-02-08
+===================================
+
+ - Fixed: Ignore case when sorting data for layman -l|-L
+
+ - Fixed: Improve documentation on option nocheck (bug #267686)
+
+
+Version 1.4.1 - Released 2010-07-09
+===================================
+
+ - Fixed: Catch keyboard interrupts (Ctrl+C) while
+ running child processes properly
+
+ - Fixed: doctest error in tar overlay code (bug #327491)
+ Thanks to David Abbott for reporting!
+
+
+Version 1.4.0 - Released 2010-07-08
+===================================
+
+ - Handle command line calls "layman" and "layman foo" better.
+ Former now shows a usage summary while latter now reports
+ an error. Both of them kept quiet before.
+
+ - Replace os.system() by subprocess.Popen()
+
+ - Close stdin of child processes when run in quiet mode
+ to avoid running into infinite and blindly interactive sessions.
+
+
+Version 1.3.4 - Released 2010-07-05
+===================================
+
+ - Propagate move of cvs and subversion from
+ dev-util/* to dev-vcs/* (bug #311419, bug #307849)
+
+
+Version 1.3.3 - Released 2010-04-08
+===================================
+
+ - Fix syncing of SVN overlays for users of SVN <1.6.5 (bug #313303)
+
+ - Fix handling of empty XML entities (bug #309617)
+
+ - Fix missing import (bug #306143)
+
+ - Extend in-config docs on proxy handling (bug #300651)
+
+ - Propagate move of bzr, darcs, git, mercurial from
+ dev-util/* to dev-vcs/* (bug #311419)
+
+
+Version 1.3.2 - Released 2010-02-20
+===================================
+
+ - Fix syncing of tar overlays (bug #304547)
+
+ - Hint about broken overlay catalog (bug #304781)
+
+
+Version 1.3.1 - Released 2010-02-05
+===================================
+
+ - Fix handling of CVS overlays (bug #301689)
+ Thanks for the patch to Dmitry Karasik!
+
+ - Fix handling of non-existing overlays (bug #301612)
+
+ - Now delete empty overlay directories (bug #301612) ..
+ - on deletion of a non-existing overlay and
+ - after failed addition of an overlay.
+
+
+Version 1.3.0 - Released 2010-01-19
+===================================
+
+ - Move storage default from /usr/local/portage/layman
+ to /var/lib/layman (fixes bug #253725)
+
+ - Syncing failed for overlays that no longer exist in the remote
+ lists without need to (bug #301174)
+
+ - No longer treat sync warnings like errors (bug #301327)
+
+ - Fix faults introduced at refactoring (bug #301253)
+
+
+Version 1.3.0_rc1 - Released 2010-01-15
+=======================================
+
+ - Add support for several sources per overlay (also fixes #280472)
+ When adding an overlay all sources will be probed until a working
+ one is found. This should help Layman through some firewalls.
+
+ - Display related directory when deleting overlays
+
+ - Improve overlay info display (i.e. layman -i):
+ - Add quality indicator (keep in mind: no guarantee)
+ - Add feed URIs
+ - Fix whitespace handling for description field
+
+ - Improve layman usage display
+
+
+Version 1.2.6 - Released 2010-01-12
+===================================
+
+ - Warn on lack of write permissions (fixes #260218)
+
+ - Migrate to GNU tar's compression format auto-detection
+ which adds potential support for more types of compressed
+ tar archives (LZMA, xz or Z) as a side-effect
+ (Requires GNU tar 1.15 or later, released in 2005)
+
+ - Drop support for broken tar overlays with missing category level
+ (and missing profiles/repo_name as a consequence)
+
+ - Make missing overlay directory not fail removal of that overlay
+ from the local list
+
+ - Start shipping doc sources and release notes with release archives
+
+ - Start shipping test suite files missing from the 1.2.5 release
+
+
+Version 1.2.5 - Released 2010-01-04
+===================================
+
+ - Allow overriding of VCS commands
+
+ - Migrate XML handling from minidom to ElementTree (also fixes #261666)
+
+ - Allow running VCS from PATH (fixes #280539)
+
+ - Fix handling of Subversion overlays whose name contains
+ one or more '@' characters (#295018)
+
+ - Fix handling of non-ASCII characters (#286290)
+
+
+Version 1.2.4 - Released 2009-12-05
+===================================
+
+ - Add option "-d" to calls of "cvs update" so it checks out new
+ directories properly (#278807)
+
+ - Fix reading of CDATA sections
+
+ - Add support for repositories.xml database format
+
+ - Substitute path "/usr/portage/local/layman" by "/usr/local/portage/layman"
+ in the documentation (#271457)
+
+ - Fix grammar errors in program output (#259188)
+
+
+Version 1.2.3 - Released 2009-01-01
+===================================
+
+ - Support setting the terminal screen width (also fixes #253016)
+
+ - layman -S fetches each overlay twice (#253241)
+
+
+Version 1.2.2 - Released 2008-12-28
+===================================
+
+ - layman -L: better use of screen real estate for source URLs
+ (#251032)
+
+ - Execute subprocesses in a shell. Fixes app-portage/layman-1.2.1:
+ --quietness=2 is broken (#247792)
+
+ - app-portage/layman - 'layman -S --quiet' yields "git: 'pull-q' is
+ not a git-command." (#247964)
+
+
+Version 1.2.1 - Released 2008-11-15
+===================================
+
+ - Pass --quiet flag down to the version control
+ system (#236165).
+
+ - Fixes for python-2.6 (#237625)
+
+ - Better locale support (#235165)
+
+ - Handle git+ssh://, ssh:// correctly (#230702)
+
+ - Do not remove directories if adding an
+ overlay failed (#236945)
+
+
+Version 1.2.0 - Released 2008-06-02
+===================================
+
+ - Fixed --info call (#198483)
+
+ - Added umask setting (#186819)
+
+ - Switched default storage location from
+
+ /usr/portage/local/layman
+
+ to
+
+ /usr/local/portage/layman
+
+ (#219786)
+
+ - Added optional version control useflags (#168203)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5a965fb
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..5ce8fce
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,1959 @@
+commit c0fff99f7ae0168900eeea30dc27fc240caa9240
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Tue May 17 22:19:39 2011 -0700
+
+ fix the success result when adding already installed overlays
+
+commit 50b971a3724c2b5637d1ce3fc6587d6e3325f2ca
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Tue May 17 22:12:50 2011 -0700
+
+ fix a false -d success for non-existent overlay. fix a couple error messages.
+ fix a long line
+
+commit 6dbd30b42a513437e4219446f34997610b351353
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sat May 14 06:06:17 2011 -0700
+
+ fix /var/lib/layman/make.conf not being updated when adding an overlay
+
+commit e15707648c5024274bd91b9348dad8cc85b0a497
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Thu May 5 02:43:11 2011 -0700
+
+ quiet the "Fetching" output for locally defined overlays.
+
+commit e55554e5b5c6a9c95bb8ad56aab195df1fb35817
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Thu May 5 02:42:07 2011 -0700
+
+ fix a regression for the old xml format.
+ improve the Exception messages with the function name it originated in.
+
+commit 2812cf483e10b3f3a1dddc6f931192509dbbd36c
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sun May 1 22:07:10 2011 -0700
+
+ fix bug 363797 python-2.5 test errors cherypicked from 1.4.x branch
+
+commit b3c8fd83c0db1f8a38c59386452128b9bd04b7c9
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sun May 1 21:54:27 2011 -0700
+
+ set VERSION and set the 'User-Agent' header to use it.
+
+commit db3e6ddad1edf4b984abd49b23c35715614e733d
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sat Apr 30 19:18:21 2011 -0700
+
+ fix --quiet option.
+
+commit fa6bee894b2259941b2ca233fee1c07fed487d73
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sat Apr 30 17:53:35 2011 -0700
+
+ Add the timestamp and url to the RemoteDB.cache() outputs.
+
+commit d1520e65968d61eb100133ab1248e00bc79ac3e9
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sat Apr 30 17:26:06 2011 -0700
+
+ fix the wrong return value for sync() move an ouptut to .debug
+
+commit cfa618287cf94f5ba4b295aeadf8168e90374533
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sat Apr 30 15:37:21 2011 -0700
+
+ improve the output a bit.
+
+commit fcd35daad6e84fdaab69f4bd0c969b80daee590d
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sat Apr 30 15:36:54 2011 -0700
+
+ Add checks and code to fetch the new list using 'If-Modified-Since' protocol.
+ adds saving the 'last-modified' date of the same filename with a .timestamp extension.
+
+commit 1b94f151b74219541f87c8ec29b381c63075d07d
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Sat Apr 30 00:01:30 2011 -0700
+
+ start moving to debug message types.
+
+commit e3bee4b35df8cc63e84a54a512020ee895ae5dfe
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Fri Apr 29 23:36:40 2011 -0700
+
+ Add the module and function to the error message for better tracking of the problem.
+
+commit 51424bf1f0aa7734dfc45672a5c6ae9ef10cbb6e
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Fri Apr 29 23:35:32 2011 -0700
+
+ Fix supported() use to return 1 if it is not supported.
+ This is a continuation of the move away from raising exceptions for everything.
+
+commit b44b5484afd1386a17021cee2922b1330ece5f63
+Author: dol-sen <brian.dolbec@gmail.com>
+Date: Fri Apr 29 23:32:38 2011 -0700
+
+ Add empty add, sync and postsync options to the defaults so they are defined.
+ Fixes sync not working due to the addition of them in the code.
+
+commit 97c96c8f6d616889bf9dcc423f27675c11af4af8
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Mar 27 19:52:48 2011 -0700
+
+ migrate to using explicit checks.
+
+commit 58530ac4e610f8eb9952ba8ee7ca920d400915db
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Mar 27 19:50:10 2011 -0700
+
+ fix double output for info sent to output.error() due to callback.
+
+commit eab52f261bda8aef53675271357b3ca742f865ad
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Mar 27 00:14:16 2011 -0700
+
+ migrate to explicit if check
+
+commit 34d7a5444ee72a7b6ca9193c2dc5975d0b894a8a
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Mar 27 00:13:32 2011 -0700
+
+ migrate to print()
+
+commit 0cd786b5d016d3b08dc8dbb1843ed04b5ce910a0
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Mar 26 23:37:19 2011 -0700
+
+ fix a missed change in error handling.
+
+commit d0339cb228c16eb491d489a2276e254bacb41c81
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Mar 26 20:39:37 2011 -0700
+
+ migrate except ... as
+
+commit e14906b88ec2da99dba82d565d88ed5ca1d40099
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Mar 26 20:24:26 2011 -0700
+
+ migrate to print()
+
+commit d73b5dacce0927e727db5aebb9384a6fd2bb1cd5
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Mar 26 20:23:02 2011 -0700
+
+ fix missed parameter.
+
+commit 50833d06b407b6028d6b6ec66e938bc26cc23141
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Thu Mar 17 21:17:23 2011 -0700
+
+ remove no longer used action.py
+
+commit 0a82306f384ab032a30cce35513a7a4a7c194991
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Feb 25 18:46:44 2011 -0800
+
+ replace more exception raising with error reporting and proper return values.
+ some long line cleanup.
+
+commit d9de33168cfe46be2e269d04ec52afe003f7ba6d
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 23:42:42 2011 -0800
+
+ add being able to set the OptionConfig defaults as well
+
+commit 336d0c4b675dff698455cc9df91b71de78347fa7
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 23:17:06 2011 -0800
+
+ make add_from_dict() private.
+
+commit a160cc7323338779f8f96e4b63da3e22742d9063
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 23:05:45 2011 -0800
+
+ remove unused import.
+ change an exception into an output.error message.
+ set more functions to return True/False
+
+commit bc8019e52ba29b30b528d31aa46180576e7d9dcb
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 22:38:03 2011 -0800
+
+ clean out excessive use of try: except pairs
+
+commit f0f43429d260c9afa4bdda394e86a9b258e29150
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 22:17:00 2011 -0800
+
+ create a new create_overlay_dict() to assist in using a python dictionary for overlay definitions
+
+commit a9fe3d3dc2794ab46af1b68728aa7a12f0733f49
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 22:15:06 2011 -0800
+
+ fix whitespace, change the version
+
+commit fcadf2247b0982bc0449e65116bd7fd9a76bd789
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 22:14:18 2011 -0800
+
+ add a new OptionConfig subclass.
+ improve some debug messages.
+
+commit 091147c6abb9bdfa814a8fc571b6cad85669fa46
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 22:13:04 2011 -0800
+
+ remove a few raise Exception()'s and replace them with self.output.error messages.
+ wrap the make_Conf in a config check.
+
+commit 4c51f94ca343338c0d266fae5c5ab6500df5e258
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 22:10:33 2011 -0800
+
+ add 2 new functions, add_new & add_from_dict.
+ Modify the __init__ params a bit
+ whitespace additions between functions.
+
+commit ba5f0cd5c948bb7a65ab21008c940caf0fbe38e7
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Feb 23 21:58:49 2011 -0800
+
+ removal of xml from the vcs class parameters.
+
+commit e4cbd7af207a2f21df967a080af5bb61c6c782d7
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Feb 21 03:41:16 2011 -0800
+
+ set output's error callback to the api's _error().
+ update the overlay's info dictionary.
+
+commit 89455e5de82d644e5b034642bacaac8338e8987a
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Feb 21 03:38:41 2011 -0800
+
+ add an error callback function ability to pass errors to.
+
+commit b68a9eaead31e08460460a13d999444118784a59
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Feb 21 03:37:13 2011 -0800
+
+ Change most exceptions raised to output.errors().
+ set functions to return True/False.
+
+ Signed-off-by: Brian Dolbec <brian.dolbec@gmail.com>
+
+commit a79acc064e4bf9ba97e33b6fd66329f2fee9014d
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 19 10:08:14 2011 -0800
+
+ separate out ArgsParser to it's own file and subclass BareConfig
+
+commit 990e967e10ec6511aa8e58beacdc9c3a5a029fcc
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 19 03:01:30 2011 -0800
+
+ Create a new single import high level Layman class
+
+commit 3097da00099de860894ddde8f7b3df9722ec6734
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 19 02:45:50 2011 -0800
+
+ remove no longer needed imports and OUT variable
+
+commit 9df5b23e5b71d6f35302572162239f3d23732e33
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 19 02:45:03 2011 -0800
+
+ import Message directly add all options to BareConfig for easy instantiation with teh desired options.
+
+commit 7a970a992bfc1fea6c37ef96378c2fd4bfbc8b17
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 19 02:43:11 2011 -0800
+
+ eliminate the need to import Message, cleanup some stale comments.
+
+commit bf5a704ebca23f917911c73994c708a1fa45d78d
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Feb 18 20:49:33 2011 -0800
+
+ missed another typo
+
+commit 762d63a6bd055092ce2033c21bd70871c1c8d234
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Feb 18 20:46:57 2011 -0800
+
+ fix typos
+
+commit a54b7138d76dacf2c8e3ba9b550d7619790a9010
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Feb 18 20:10:18 2011 -0800
+
+ fix missed colon
+
+commit f2dd98035ee2c90bb01174d6f816a4866b1c0f7d
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Feb 18 20:06:51 2011 -0800
+
+ add nocolr to BareConfig and improve quiet/quietness handling
+
+commit 3eaca0340384122c5d83e0aa2d0a8b6dc1165487
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Thu Feb 17 21:19:08 2011 -0800
+
+ Add per repo type postsync options.
+ Some minor long lines cleanup.
+
+commit 4872509aab4693638c957fcd8e9d38af06357769
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Thu Feb 17 13:52:44 2011 -0800
+
+ make the BareConfig more comparable with the ArgsParser.
+ Separate out a True/False function for config option string conversion.
+
+commit 6d023e32aa94c42f6307f2263ac49a6f09d7680e
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Thu Feb 17 13:49:28 2011 -0800
+
+ shorten long lines
+
+commit af55bea519642b9742135498e5fddaececab7d1f
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Thu Feb 17 13:48:54 2011 -0800
+
+ add per repo type config options
+
+commit cc15f2551e105540850101572ccba275a6fc1ace
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 13 16:53:33 2011 -0800
+
+ fix the incorrect exit code settings which are opposite the True/False that the api returns
+
+commit 69ca817b92d78e91b03ee3e327b9e369c8f26e5a
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 13 16:52:19 2011 -0800
+
+ Split out MessageBase class, more code reduction/cleanup
+
+commit d308b929d9fb4a0c69d331079f9a8b3ebbb2164a
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 13 16:50:45 2011 -0800
+
+ more DebugMessage class cleanup/transition to subclassing Message
+
+commit 503c1586ac80109089f0bf6d0a1a0a579a19a6d7
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 13 16:49:30 2011 -0800
+
+ fix a missed color_off(), add myself to the copyright, whitespace cleaning
+
+commit ac8a52948f107265718dabe97e144a7cc4a70091
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 13 16:47:14 2011 -0800
+
+ fix a long line, clean an unused import, fix the sync return value better
+
+commit 6a85b05289ae2bb9f5da1748985322e83d064f60
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 13 01:31:54 2011 -0800
+
+ simplify debug.py to subclass the simplified Message class
+
+commit 306b419af140c6e1eb41a2114005b20b82a5332c
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 13 01:30:24 2011 -0800
+
+ further simplify, reduce the number of functions
+
+commit badca544dbd7e151e27b4f004962b139aa450ac3
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 12 19:24:37 2011 -0800
+
+ output more info to the trial for adding an overlay
+
+commit 429281392d97880cb075456d85e878dc077e7d51
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 6 15:40:15 2011 -0800
+
+ use the new message class and fix the error recording and output
+
+commit 43d5d08711fb4170b85505e3ec7edffc64cbf8e6
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 6 15:38:49 2011 -0800
+
+ new simplified message class
+
+commit b9635c0d5a2b99263ba361bf957d31ac0907c5a0
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 6 15:37:30 2011 -0800
+
+ rename Overlay's __str__(). split out UnknownOverlayMessage() from the exception class
+
+commit 8f3c12a02768bea0cf1ceed02b27886cdac3f2af
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Feb 6 15:34:36 2011 -0800
+
+ add the ability to plugin repository definition xml files without editing the config file
+
+commit 6c2ae66cf246a34fa4b3129df4cd01aa2ee47641
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 5 10:35:27 2011 -0800
+
+ add an example testpath for testing the git checkout
+
+commit f91a4b9045933174384f558bd89aeb24a2579bef
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Feb 5 10:34:28 2011 -0800
+
+ add an irc data element to the overlay xml
+
+commit 2dd23d2be98537bebe647340a6ba6c6f88578300
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Jan 17 23:58:04 2011 -0800
+
+ add a list_ids() and use the it
+
+commit 6780f08f787642bb3e1620a0909d96a7e43abb0d
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Jan 17 23:57:18 2011 -0800
+
+ add missing output statements, debug all the new actions
+
+commit da083d70887673dbb3e26c28f4a796355f47b00e
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Jan 17 20:48:38 2011 -0800
+
+ minor word change
+
+commit 3da3a059d7e0c251e457a3b803752dd517acf726
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Jan 17 20:06:37 2011 -0800
+
+ add missing output messages
+
+commit 92298c7aa198f0492655d365fd8bb11f2d883869
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Mon Jan 17 20:05:48 2011 -0800
+
+ add a generator for source types the same as source uris.
+ use the generator in get_all_info().
+ pylint cleanup.
+
+commit f00559c0ae7d5abe8197c8e9a1052c02cdd0a273
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 23:50:16 2011 -0800
+
+ add a few more files to ignore
+
+commit 7aa228d25d1fb1f1343f9cddb187a84bc1cd5a50
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:57:58 2011 -0800
+
+ create a new cli interface to use the new api
+
+commit cf439af88990de7f7e0ef68faca1581e0480a458
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:56:06 2011 -0800
+
+ overhaul the api, add several functions, delay loading of the db's, etc
+
+commit c551ad652c54eaccc974c1bb87e8c7582adacbae
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:52:52 2011 -0800
+
+ move utility functions out of the Overlay class
+
+commit d7510f1f7ee5c5bec7bdba68a310c1ce17444821
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:50:08 2011 -0800
+
+ add a linefeed to the hint message for better output separation
+
+commit 3ae0e5c0768081314183e66f589b57a13f271af5
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:49:16 2011 -0800
+
+ fix long lines and a typo, minor code improvements
+
+commit b214cd3e79ee70aec597262f5bb9bbaf6fdc74e5
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:46:38 2011 -0800
+
+ Move color codes to a new file.
+ Add some message string constants
+
+commit 4fbff6fc56d92aaba151bf2a02d27464425f1644
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:41:32 2011 -0800
+
+ add optional repo list limiter to the list function
+
+commit 5e5809bd76bcdab37a6f270a47aa57f5900d4723
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jan 16 22:39:47 2011 -0800
+
+ slight code change to my modified base.
+ whitespace cleanup
+
+commit ae654d7a403eb2d018543a9034a408689f26484c
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Nov 14 16:25:36 2010 -0800
+
+ update to using basestring instead of str.
+ Otherwise assume it is an iterable.
+
+commit 5c08a86e2c65c99a98bcfddf6f1f0d2b0c199a8c
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Aug 7 08:33:52 2010 -0700
+
+ Apply tulcod's g-common support changes.
+
+commit 3f0553996ab99a1923bc35e609efc42008c6d4cd
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Jul 16 23:02:01 2010 -0700
+
+ some docstring updates
+
+commit 8802626d9ca6c325213f3d19b7da696892c6c1fe
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Jul 16 14:04:24 2010 -0700
+
+ remove the extra comma that wrapped the dict in a tuple.
+
+commit 11ba6a09a61778dbe873246d9c4bcfb875f351d9
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Fri Jul 16 07:10:49 2010 -0700
+
+ change add_repo and delete_repo to add_repos,
+ delete_repos to reflect they can take a list.
+ fix the dumb error in get_errors().
+ change get_info() to get_info_str() and code get_all_info()
+ that returns data instead of the string representation of it.
+
+commit 5609d5d6f73b4e15477a4851c1f9701866b5a3c2
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Thu Jul 15 17:52:54 2010 -0700
+
+ fix the docstrings to match current input types.
+
+commit 63789af9d74191578d21159f0b19af524134eb9f
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jul 11 15:21:56 2010 -0700
+
+ make the sync_results saved every time rather than conditional.
+
+commit 5a949d21c92aa729490bd9aa268354c5c08844ee
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jul 11 14:04:57 2010 -0700
+
+ fix some typos, copy/paste errors, and debug/fix some changes to the api.
+
+commit e4b3560bf8b8dbce3c992086a5697fea7aefa200
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sun Jul 11 01:54:22 2010 -0700
+
+ Remove the Output class as it is not needed, was used for initial testing only.
+
+commit bb446c2f548b08ad745ff8b608383314e76a9224
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Jul 10 21:22:40 2010 -0700
+
+ Add a get_option function as a convenience function for option retrieval instead of using the class instance as a dictionary.
+
+commit af8c821f1b6c1a48b5ce2f6ba328ba9ff8807a9d
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Sat Jul 10 21:20:44 2010 -0700
+
+ Modify the API to be more compatible with a c interface.
+ Make all main repo functions accept either a string or a list of strings.
+ Change most functions to return True/False for success/failure and save error messages for separate retrieval.
+ Change other functions to return a dictionary instead of tuples or lists.
+ Add a get_errors() for retrieving and resetting error messages.
+ Change sync to either save or print the success, warnings, fatals info.
+
+commit a11c61f22f3df968f4c00f9a8f8b996e6a143df7
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Wed Jul 7 19:18:34 2010 -0700
+
+ Separate out the configs from the args parsing code. This will allow basic configs for api consumers that are changeable.
+
+commit 61135ce4b04e52855e0ce320777ec671cccf710c
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 19:53:29 2010 -0700
+
+ change the shebang because it would not run in my test environment
+
+commit eeea37f1f26e26794df88ea60f48881b1e9ad5d7
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 19:32:09 2010 -0700
+
+ create a new readme to explain a bit how to use the new api
+
+commit 423dda9923eef331670ab3e79266e5d0ca19a699
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 18:42:53 2010 -0700
+
+ fix results tracking
+
+commit b0fec599217155459e26aba627f3297a7e857a09
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 18:20:56 2010 -0700
+
+ add new layman API file and class to be used by api consumers, but could also be used by the cli if they desire to migrate to it. That would eliminate the duplication in hte action.py file. Unfortunately, the action classes were not suitable for api consumers. They worked efficiently as one time cli use only. I also have subclassed the debug.py's Message class to override some print statements for data capture instead. This may not survive when the api is completed. create_fd() is handy for creating opened file descriptors to use for output re-direction.
+
+commit 3731e182e0577165ede11e95d4bd447354ce3786
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 18:08:46 2010 -0700
+
+ Change the remaining modules to use the config['output'] variable so re-direction is possible for all output.
+
+commit c387c4eff9eb13ece3108cf1b5818d0ba6551f1f
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 18:07:41 2010 -0700
+
+ Add an output parameter to Message class and change the prints that weren't already re-directed to re-direct to it
+
+commit 8d5c2c9f9a64dd99f65bf3791cb88ca400339c45
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 17:36:22 2010 -0700
+
+ change to use the config['output'] variable
+
+commit 8c0b76134494339ff75bb5c3e8332c69f257838a
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 17:21:17 2010 -0700
+
+ Add an input parameter, 'output' to delete_empty_directory so that it can be overriden if desired
+
+commit 3b6f983f8d764e974c38ae4b4eccbfd63553ff2d
+Author: Brian Dolbec <brian.dolbec@gmail.com>
+Date: Tue Jul 6 17:17:34 2010 -0700
+
+ add new __init__ input parameters, output (replaces OUT import), stdout, stdin, stderr. These are then added to the config dictionary for all other modules to use. This creates a single point to assign them and makes it possible to re-assign them from the defaults in the case of API consumers.
+
+commit 08c7aed2adc6ab162388b39074267ef8d3ffbab4
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 8 04:55:13 2011 +0100
+
+ Extend .gitignore
+
+commit 440993c99ed2094d07a9d623ee12adb12ba0ad5f
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 8 04:40:48 2011 +0100
+
+ MANIFEST.in: Ship file doc/docbook-xsl.css
+
+commit 2cf5b4e6ce1a89492ce0f343ce409de6ca19e76b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 8 04:36:08 2011 +0100
+
+ Prepare release of 1.4.2 (set release date, sync release notes)
+
+commit 1d1a3a78111f6204f60649119d53856f27da8ae3
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 8 04:30:06 2011 +0100
+
+ Makefile: Extract version from layman/version.py (was hardcoded before)
+
+commit 52140908a6b046af3e28071eb1129e578b6ff6c8
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 8 04:16:32 2011 +0100
+
+ Makefile: Add target "website" to ease uploading the latest man page to layman.sf.net
+
+commit c309635e0357b825531ca44df6e9019bb69d3a73
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 8 04:15:33 2011 +0100
+
+ Makefile: Remove target "www"
+
+commit 73780463a727edd844a16f59abb321f89e0fd2c0
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Nov 7 02:09:21 2010 +0100
+
+ Add missing asciidoc.conf
+
+commit 46fb83877a68c5ddc1841e93695248772c500168
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Nov 7 00:58:39 2010 +0100
+
+ Improve documentation on option nocheck (bug #267686)
+
+commit 72042f2bc3d3f920753fddd68900a7ec057af813
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Nov 7 00:08:14 2010 +0100
+
+ man page: Add "=" to long options
+
+commit d6bb0aa46b32b9675f3aab6e9b870f9184d416cb
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Nov 7 00:06:18 2010 +0100
+
+ man page: Fix logic in synopsis
+
+commit eda4ea7cecaadc6ab2c4923efe8c65410ae91f5d
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Nov 7 00:01:23 2010 +0100
+
+ man page: Uppercase parameter variables and fix their style in synopsis
+
+commit cd8893c95b7fb6d7bd28c998b4c6d472674035b7
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Nov 6 23:57:53 2010 +0100
+
+ man page: Improve style
+
+commit ecc3c7b6b629ff4a62e359c2796dc71abaf3bb9d
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Nov 6 23:47:00 2010 +0100
+
+ man page: Improve style
+
+commit 652f873d575efb014be62eef26e0f1c8b1183751
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Nov 6 23:44:23 2010 +0100
+
+ man page: Introduce see also section
+
+commit 2288a74dd0a90c92bcf04da7d455e72cdd74c875
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Nov 6 23:44:09 2010 +0100
+
+ man page: Add note on gpo.zugaina.org
+
+commit 835ede6a4cbdb69985400648f87523310eaf83a6
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Nov 6 23:39:36 2010 +0100
+
+ man page: Replace PORTAGE_OVERLAYS by PORTDIR_OVERLAY
+
+commit a8eee022c6dc2085d4e37e838ffb45404f77242b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Nov 6 23:34:00 2010 +0100
+
+ Migrate documentation from DocBook to Asciidoc
+
+commit 467251b6cd44f146907dddb513b98ed0abbef364
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Oct 23 00:44:35 2010 +0200
+
+ Ignore case when sorting data for layman -l|-L
+
+commit 224ed4d1b2f96b22756fcb72240356382d2705d0
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jul 9 20:43:17 2010 +0200
+
+ Prepare release of 1.4.1 (set release date, sync release notes)
+
+commit dd968998a2a3bba484b6387ee844d214c6774a75
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jul 8 18:08:47 2010 +0200
+
+ Add script to ease up test suite invocation
+
+commit 2024dd0c9337f91a676ec821bfca59246501ffae
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jul 8 17:47:43 2010 +0200
+
+ Fix doctest error reported by dabbott
+
+commit 3eac51fa7beb8e7cae657c394c2de52f3f47ef12
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jul 8 17:14:20 2010 +0200
+
+ Catch keyboard interrupts (Ctrl+C)
+
+commit 41155ede79c5a1f770f510e0f8e6fdd70c440b39
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jul 8 13:19:15 2010 +0200
+
+ Rename make target "release" to "dist"
+
+commit d8567e2059259f69918285eac1d720efc62132d8
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jul 8 13:17:02 2010 +0200
+
+ Prepare release of 1.4.0 (set release date, sync release notes)
+
+commit a2cc62702fb5d6b54aa68c4a4ed2bf300e582b31
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jul 7 21:40:51 2010 +0200
+
+ Close stdin of child processes in quiet mode
+
+commit 8eff1545b83aafba80074951829f6325199a5b25
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jul 7 21:20:56 2010 +0200
+
+ Replace os.system() by subprocess.Popen()
+
+commit a80e2f67c49d372397f96cf89ac1087b2c0f78d1
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jul 7 18:19:29 2010 +0200
+
+ Improve command line API cases "layman" and "layman foo"
+
+commit aa11838f38b40f4e34987cf12cb911d6633450db
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jul 7 17:46:29 2010 +0200
+
+ Tune usage summary display
+
+commit 995476bfa8af27b3f77c1ef8b6ec655d2156998b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jul 5 16:41:51 2010 +0200
+
+ Prepare release of 1.3.4 (set release date, sync release notes)
+
+commit 108731312e8e6f682aa138bd63ddd1850fc5f29e
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jul 5 16:39:21 2010 +0200
+
+ Add make target "doc" to main Makefile
+
+commit afe5dd06a8c05efbef4936dcb9f3e68495832055
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jul 5 16:32:37 2010 +0200
+
+ No longer store generated file www/index.html
+
+commit 7a762a654c78a71cba8db860f74f584a5692498a
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jul 5 16:28:59 2010 +0200
+
+ Change date format in change log from YYYY/MM/DD to YYYY-MM-DD
+
+commit 3adaa2d12d66291232a45dafce1e869efe78b92d
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jul 5 15:35:21 2010 +0200
+
+ Propagate move of CVS and Subversion
+
+commit 18c03d4ce91370fe040af969f8bbb597ddc977af
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Apr 8 20:27:07 2010 +0200
+
+ Prepare release of 1.3.3 (set release date, sync release notes, update website)
+
+commit bcc193c6e2a30ad8b22c6bdb239f63187b10151c
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Apr 8 10:09:18 2010 +0200
+
+ Fix syncing of SVN overlays for users of SVN <1.6.5 (bug #313303)
+
+commit 3e3202109cf033b56a54917510cd338f7389a8e5
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Apr 8 10:13:32 2010 +0200
+
+ Extend change log for bug #311419
+
+commit 8fb19064802856bc5700d0ac27a50590f252a1bf
+Author: Ondrej Sukup <mimi.vx@gmail.com>
+Date: Fri Mar 26 09:54:23 2010 +0100
+
+ dev-util category changed to dev-vcs for bzr, darcs, git, mercurial
+
+commit fcf9411b7b44d1c1f6f575d49777bdb0579b09d8
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Mar 15 23:26:51 2010 +0100
+
+ Update ChangeLog
+
+commit b3d326a19454ddd00b9f5fc8400f926123bd13db
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Mar 15 23:21:22 2010 +0100
+
+ Fix handling of empty XML entities (bug #309617)
+
+commit ff2e47c9682bbd07e821110a34a67861cce2168e
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Feb 27 00:45:57 2010 +0100
+
+ Extend in-config docs on proxy (suggested by James Broadhead)
+
+commit 92efbc0a73df31655597895c9526e8b80d3e7bef
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Feb 26 20:25:07 2010 +0100
+
+ Move code from ListLocal/ListRemote up to List
+
+commit 10f33da79d6c99d0360bd2c1d3365af4d7fc991c
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Feb 26 20:08:13 2010 +0100
+
+ Rename class List to ListRemote, make ListRemote and ListLocal derive from a new class List
+
+commit 83ea95d35bbbe3300ca09b755e38d316b015afe6
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Feb 21 17:19:37 2010 +0100
+
+ pylint: Resolve redefinition of variable by renaming
+
+commit c7ad6d9e87954b1248a0bc01e31afa4fe59d5781
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Feb 21 17:16:14 2010 +0100
+
+ pylint: Resolve unused import
+
+commit 806b99591eaab8f398988dfc4f2a2452738dd622
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Feb 21 17:02:24 2010 +0100
+
+ Fix missing import
+
+commit 4b16c82ce4d7d78d943f81ea536f4407a7caf4bb
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Feb 20 22:02:43 2010 +0100
+
+ Prepare release of 1.3.2 (set release date, sync release notes, update website)
+
+commit 15607e2a960e046a9d1cf23bbc04f30c505c5600
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Feb 18 06:27:01 2010 +0100
+
+ Hint about broken overlay catalog
+
+commit b3c281c1c5060f4d28e83680dbbc3f2819f0bd42
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Feb 18 05:42:00 2010 +0100
+
+ Move safe op out of try-except block, extend code doc
+
+commit 8c4ac69b03fbeae655e448fadf0d896ed8b2fb56
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Feb 18 05:36:31 2010 +0100
+
+ No longer read same XML file twice
+
+commit 0920b37df448fda795a77a698fb82e23fdfdb20d
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Feb 18 05:29:02 2010 +0100
+
+ Move MakeConf class to dedicated file
+
+commit 8990dad4eb192d342545589c66555faae88e8301
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Feb 18 05:12:43 2010 +0100
+
+ Resolve Actions class, allow custom sys.argv for Config class
+
+commit f32f4851f604ff3e96d47f58a2044d3ca71a21b2
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 22:43:44 2010 +0100
+
+ Add pylint config
+
+commit 2661aa7e6ef777d7fcf3909c1bb181a3cf50449d
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 22:35:51 2010 +0100
+
+ pylint: Fix dangerous/mutable default value
+
+commit 46b5e63dda2b5bef24f5a4803c920a6637c5b56b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 22:11:13 2010 +0100
+
+ pylint: Resolve redefinition of variable by renaming
+
+commit fd91a63d0a91a6d232f9345ae247d76d84e1a1a6
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 22:08:49 2010 +0100
+
+ pylint: Remove unused variable
+
+commit e404a75383b8b70e8d39f419ed77cbcc75918747
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 22:08:03 2010 +0100
+
+ pylint: Add child-only attribute to parent, too
+
+commit c043fc0b8fe9d1f2bc554769ecae40756b4546bb
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 22:05:15 2010 +0100
+
+ pylint: Resolve unused import
+
+commit e2b872c7c60d3935b99c12aaecba85f5190df6df
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 22:02:11 2010 +0100
+
+ pylint: Resolve use of blacklisted built-in funtions
+
+commit c5064d16abd462db1c5a9c65cc69ce2a3bd2298e
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 21:59:01 2010 +0100
+
+ pylint: Resolve re-import
+
+commit db48cf95e47649aa68bc70c39c88d49c3fb523c7
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 21:56:06 2010 +0100
+
+ pylint: Fix bad indentation
+
+commit d6313993a6559a752a13e8826fa95c1afb39b9cd
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 21:53:06 2010 +0100
+
+ pylint: Resolve method overriding with different arguments
+
+commit 3b5e998d2ad91d992cd9764bf8b3a3e00916ebf9
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Feb 17 00:26:51 2010 +0100
+
+ Make fail of tar sync not leave temp files
+
+commit d7425a8bfc7d18a7f5b7e682f65cb8f8d7db4abe
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 16 05:35:50 2010 +0100
+
+ Fix syncing of tar overlays (bug #304547)
+
+commit 44bfd48309633feaf0cec67d337945c1c41b1b65
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Feb 16 21:58:11 2010 +0100
+
+ Add test case for syncing of tar overlays (bug #304547)
+
+commit 2403aa7ea58f46b7113a5eac0cc52973748da411
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Feb 5 02:12:47 2010 +0100
+
+ Prepare release of 1.3.1 (set release date, sync release notes, update website)
+
+commit e321b1c0abca64e2e3615a9e1a321b47a6adbbed
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 28 01:10:45 2010 +0100
+
+ Rename layman.overlay.Overlays to layman.dbbase.DbBase
+
+commit 7a4e280313f57f714c499aed2566c93744d60851
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 28 00:49:55 2010 +0100
+
+ Delete empty overlay directories
+
+commit c654e79fd18adb0e9f1cae6b783f8c81b39dda61
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 28 00:47:32 2010 +0100
+
+ Fix handling of non-existing overlays
+
+commit a223dc2c467cc05932aa5e42bdd905dd6aa83037
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Jan 24 00:22:56 2010 +0100
+
+ Fix handling of CVS overlays
+
+commit 2de3c57b0f31249260943d93e6860913c03f37a8
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 19 18:20:45 2010 +0100
+
+ Prepare release of 1.3.0 (set release date, sync release notes, update website)
+
+commit 218e6a12ceb1808e0f5544eaec933e1172762551
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 19 01:16:58 2010 +0100
+
+ Move storage default to /var/lib/layman
+
+commit 8467497542c0b41e5361a9741d914a0ea2f42c39
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 18 02:38:45 2010 +0100
+
+ No longer treat sync warnings like errors
+
+commit 35b801214aabd8d4a06bcd501a21601827ea2256
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sun Jan 17 17:02:02 2010 +0100
+
+ Fix refactoring faults
+
+commit 6c7d833b16fbe0c4d39af665e76fa47811edcad2
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Jan 16 18:21:25 2010 +0100
+
+ Fix syncing of overlays gone from remote lists
+
+commit 8d8f7a47dd95ad6a69b8058888cb7aaae9430c76
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 19:02:31 2010 +0100
+
+ Prepare release of 1.3.0_rc1 (set release date, sync release notes, update website)
+
+commit 7ba4169637a767bfcf2c99e167c78df97c940a8f
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 18:50:19 2010 +0100
+
+ Fix Overlay and OverlaySource equality check
+
+commit 0b95d4b85c1d968060a28e762564a532d4c262f1
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 18:32:01 2010 +0100
+
+ Display related directory when deleting overlays
+
+commit 6db71f043212980cd590ced1790c0c91b7b8a553
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 01:54:48 2010 +0100
+
+ Fix whitspace handling for description field (with layman -i)
+
+commit e7773dee5669e65afbecc9f3f0a14497e7d6d5a5
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 01:38:13 2010 +0100
+
+ Include quality indicator in overlay info display
+
+commit f3c4dc76ff8c950f39dfff80bd47144e1ba2420f
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 01:18:56 2010 +0100
+
+ Include feed URIs in overlay info display
+
+commit d1e69d954ea403eb7f5d76c73ed80c248ac24bb3
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 01:10:34 2010 +0100
+
+ Remove format and category data from test case XML
+
+commit 9c8e55a689bc8938f3b3dcb0cd3b4e6df740b898
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 00:54:54 2010 +0100
+
+ Bump version to 1.3.0_rc1
+
+commit 4a7ed6990d142aed4b0773576b4375f208f8ee59
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 15 00:53:38 2010 +0100
+
+ Fix another test case
+
+commit c9e4f93f884564732b7cbb3961f01c1fb80f8093
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 14 23:57:08 2010 +0100
+
+ Make "layman -L" display as many source URIs as fit (not just one)
+
+commit f0306ea946d3f838c92c1127b0c0b825e7302f70
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 14 23:45:00 2010 +0100
+
+ Fix output for command "layman -L |& less"
+
+commit 71d8076d56646ab92f777d6090a388f86c1fe7e7
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 14 23:20:32 2010 +0100
+
+ Improve usage display
+
+commit 0939294c9265abb78e00124789ee86d9191f3d99
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 14 23:11:16 2010 +0100
+
+ Fix test case in TarOverlay
+
+commit 54a53d5aa0302d6c97a25de21c797cbc607770de
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 14 20:45:21 2010 +0100
+
+ Fix wrong(?) test cases
+
+commit 100390d0bd4253c4fb6eed8a5430bfabd03d6f07
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 14 20:37:51 2010 +0100
+
+ Fix test cases by using new Overlay.source_uris() generator
+
+commit 7cf05fe5c4fb83340d9927ee03df4172cb0b8605
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Thu Jan 14 20:32:02 2010 +0100
+
+ Fix display of overlay type
+
+commit 2a14ba6689f6104601533d0677fb9211a35c96e0
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jan 13 02:38:44 2010 +0100
+
+ Add support for multiple sources per overlay
+
+commit 82643d91c7814033626885285ee51ac06e66cbe9
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jan 13 00:29:03 2010 +0100
+
+ Move a few methods down from Overlay to OverlaySource
+
+commit 3f95bfa1f070876ee9f355c7a31d2cd03b089977
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jan 13 00:25:05 2010 +0100
+
+ Inject OverlaySource class into hierarchy
+
+commit b6f7eed0d97ebcdcb35ad38a1fc61b7544e5a69f
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jan 13 00:31:09 2010 +0100
+
+ Resolve method Overlay._set_source()
+
+commit 4ab9ad6868e63115ccf7259a152c9fa67fbee2c9
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jan 13 00:17:23 2010 +0100
+
+ Migrate overlay classes to using super()
+
+commit c0d50a487033ad63f342e2e73e9305cd0696386f
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 12 22:48:48 2010 +0100
+
+ Prepare release of 1.2.6 (set release date, sync release notes, update website)
+
+commit 900903c2085f118a24786a5f4ac5d9fd4d0dde1e
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 12 22:37:04 2010 +0100
+
+ Start shipping doc sources and release notes
+
+commit 8b36cd2f4838662a75cd252d81736ba984dde6a9
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 12 22:32:35 2010 +0100
+
+ Improve release process
+
+commit 3004cad75da1af98f50c9f457bc43fc3aeda1a7a
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 12 16:56:39 2010 +0100
+
+ New fail-logic on removal of an overlay
+
+commit 18d5ccac39d9c5a813331959f54a7961e83174ce
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 12 03:09:43 2010 +0100
+
+ Make .tar.noidea extension for tar archives with unknown compression
+
+commit 38b8f5873f774202e9d9b47a1e702804cdeaee9e
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 12 03:08:32 2010 +0100
+
+ Document arrival of support for .tar.lzma and friends
+
+commit 553ea1d895e3b9b74f9b6232bf0ca99fe9adc77b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 12 03:03:52 2010 +0100
+
+ Drop support for broken tar overlays
+
+commit b513cf5ddd0eae89a6ba7454a033586efb18e94e
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 11 04:32:45 2010 +0100
+
+ Migrate to GNU tar's compression format auto-detection
+
+commit 3df0bb5425b5988f1439a462bb5ff9484b1cd63c
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Wed Jan 6 07:06:17 2010 +0100
+
+ Fix and further improve write permission checks
+
+commit 6d6663f5519b400982037721a807528ea0b03202
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 5 16:00:02 2010 +0100
+
+ Sync CHANGES
+
+commit 58fa6a3bf2600b8cb6338158c32d306a99658236
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 5 15:56:57 2010 +0100
+
+ Add hint on not being root
+
+commit 07ebab92cbd300853e12c2e2ea3b405e31a8e6cc
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Jan 5 15:53:26 2010 +0100
+
+ No longer fetch twice
+
+commit a977b9542d18da2cde5ce03cb75e403c6630f5e2
+Author: Bjoern Tropf <asym@gentoo.org>
+Date: Tue Jan 5 15:52:15 2010 +0100
+
+ Check write permission before fetching the list of overlays
+
+commit dbc4f712fa892bb067996f45821f8d3aeda5e2fc
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 21:05:30 2010 +0100
+
+ Prepare release of 1.2.5 (set release date, sync release notes, update website)
+
+commit acf9ef9a4b3b9aedbc9b1a6f9fec26fa0fe19afa
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 05:48:22 2010 +0100
+
+ Mute warnings from external test suite
+
+commit 3dd1f818e2e004c96f630e0aea77cded1b018b14
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 05:48:51 2010 +0100
+
+ Add test suite for format/subpath/category
+
+commit e54bec19b0a5e29df79b35d0f90574e22db538da
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 05:47:18 2010 +0100
+
+ Add reading of format/subpath/category from repositories.xml format
+
+commit 21f0e3ccbe47993cb8851aa62aab4e015da74e39
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 05:38:34 2010 +0100
+
+ Notify subclasses of Overlay which <source> is selected
+
+commit fb57193767a3b52ca6eafda31f2f7e4e33730458
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 05:44:57 2010 +0100
+
+ Bring back writing of format/subpath/category
+
+commit 836dea135b73c2b0e802888702c6b67c86f2bea4
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 05:36:34 2010 +0100
+
+ Introduce equality and inequality tests
+
+commit 4cfd62c88c855c90f56db1a60ef2e438b13ca3d6
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 05:31:15 2010 +0100
+
+ Make Overlay derive from object so we can use super() in subclasses
+
+commit 9c520cc5bfd77769ba989b11ce90372c8206b44b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon Jan 4 00:52:17 2010 +0100
+
+ Handle sys.stdout.encoding being None
+
+commit a4ce3e5d2076528950155069999873a92b87833e
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Jan 2 04:23:56 2010 +0100
+
+ Fix handling of non-ASCII characters
+
+commit 13b8a3969b3fcba55b25d2b593c78abf708fec06
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Jan 1 01:39:33 2010 +0100
+
+ Fix handling of names containing '@' for Subversion overlays
+
+commit 04a856b8773f0838dcf0fd595b3869402cde769b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 15:33:10 2009 +0100
+
+ Bump version to 1.2.5
+
+commit 1d2c84df69f450318b2632ef5710ce392ef2802d
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 15:32:03 2009 +0100
+
+ Rename Overlay.to_minidom to to_xml (as it no longer uses minidom)
+
+commit f70906f907df33672da506a178e00a726be41952
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 15:28:35 2009 +0100
+
+ Fix post-1.2.4 whitespace-stripping bug
+
+commit 08c83772f69aaa7edf6c4809365809e8144cce3b
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 14:50:25 2009 +0100
+
+ Allow running VCS from PATH
+
+commit 1fffa93607c68947ae4eea18bf22f95e0d514a66
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 14:22:06 2009 +0100
+
+ Allow overriding VCS commands
+
+commit 4e5db6241219e5daf79ac20967aef03097d70bb8
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 13:35:33 2009 +0100
+
+ Pass config down to Overlay instances
+
+commit 3ef674c91931a22a51bcdeb840897147c35e1db5
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 13:33:52 2009 +0100
+
+ Migrate ElementTree imports to Python >=2.5
+
+commit ba638979c483a371e5be70ba4d5fc641089c45ad
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 02:32:40 2009 +0100
+
+ Sync CHANGES and AUTHORS
+
+commit 42deac2d731c7ead984bc7cca79cf001e8ca387c
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 02:01:31 2009 +0100
+
+ Indent XML when writing to disk
+
+commit a4499de57c1a71e29beda6320dfeb79286668799
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 02:00:17 2009 +0100
+
+ Migrate ElementTree imports to Python >=2.5
+
+commit e0e15fa5177023b9d82569d9de0e8561bf83f128
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Tue Dec 29 01:59:05 2009 +0100
+
+ Fix license headers
+
+commit 507e8f4451e53de613228761b9bbf1a5d82f25cb
+Author: Christian Groschupp <christian@groschupp.org>
+Date: Mon Dec 28 01:43:18 2009 +0100
+
+ Migrate XML handling to ElementTree
+
+commit 63b1dff9da3df8a63708a4ecb5f646af6951ecfd
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Dec 5 03:16:43 2009 +0100
+
+ Update website to reflect release 1.2.4
+
+commit 38b74db5d5e29b360834f525a2d07444e30ba213
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Dec 5 03:15:11 2009 +0100
+
+ Remove subversion'ess from helper Makefile
+
+commit e9279ed990f591d662c914a7d57c0c56b3c02679
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Dec 4 21:38:15 2009 +0100
+
+ Prepare release 1.2.4 (sync change log and release notes, bump version)
+
+commit 8349b28317031a4ff45755079a0e4d47ade1768c
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Dec 4 21:01:04 2009 +0100
+
+ Add support for repositories.xml database format
+
+commit 9c9f1661c23c96e97079eefa81f667cde38208f1
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Dec 4 23:55:26 2009 +0100
+
+ Fix reading of CDATA sections
+
+commit a04926356ba19a23afc4f166f20e7edccfa350f7
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Dec 4 22:03:09 2009 +0100
+
+ Introduce .gitignore
+
+commit 7008879fe154908916891bdf7e07ef4805e3c9c8
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Sat Dec 5 00:15:20 2009 +0100
+
+ Remove file uploading from helper Makefile
+
+commit 664c15b1f51339d5640f492abdab5c70c4612eb0
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri Dec 4 22:05:28 2009 +0100
+
+ Remove layman ebuild (as it went to the Gentoo tree)
+
+2009-10-12 Gunnar Wrobel <p@rdus.de>
+
+ * layman/overlays/cvs.py (CvsOverlay.sync): app-portage/layman cvs
+ update command needs to include -d or it dosn't checkout new
+ directorys (#278807)
+ http://bugs.gentoo.org/show_bug.cgi?id=278807
+
+ * doc/layman.8.xml: Old layman path in new documentation (#271457)
+ http://bugs.gentoo.org/show_bug.cgi?id=271457
+
+ * layman/db.py (DB.add): app-portage/layman:output grammar
+ error (#259188)
+ http://bugs.gentoo.org/show_bug.cgi?id=259188
+
+2009-01-01 Gunnar Wrobel <p@rdus.de>
+
+ * layman/version.py (VERSION): Bump to 1.2.3.
+
+ * layman/overlays/overlay.py (Overlay.short_list): Support setting
+ the terminal screen width (also fixes #253016)
+ http://bugs.gentoo.org/show_bug.cgi?id=253016
+
+ * layman/action.py (Sync.run): layman -S fetches each overlay
+ twice (#253241)
+ http://bugs.gentoo.org/show_bug.cgi?id=253241
+
+2008-12-28 Gunnar Wrobel <p@rdus.de>
+
+ * layman/version.py (VERSION): Bump to 1.2.2.
+
+ * layman/overlays/overlay.py (Overlay.short_list.terminal_width):
+ layman -L: better use of screen real estate for source
+ URLs (#251032).
+ Submitted by Martin von Gagern <Martin.vGagern@gmx.net>.
+ https://bugs.gentoo.org/show_bug.cgi?id=251032
+
+2008-12-03 Gunnar Wrobel <p@rdus.de>
+
+ * layman/overlays/overlay.py (Overlay.cmd): Execute subprocesses
+ in a shell. Fixes app-portage/layman-1.2.1: --quietness=2 is
+ broken (#247792).
+ http://bugs.gentoo.org/show_bug.cgi?id=247792
+
+ * layman/overlays/git.py (GitOverlay.sync): app-portage/layman -
+ 'layman -S --quiet' yields "git: 'pull-q' is not a
+ git-command." (#247964)
+ http://bugs.gentoo.org/show_bug.cgi?id=247964
+
+2008-11-15 Gunnar Wrobel <p@rdus.de>
+
+ * layman/version.py (VERSION): Bump to 1.2.1.
+
+2008-11-14 Gunnar Wrobel <p@rdus.de>
+
+ * layman/*: layman: pass --quiet flag down to the version control
+ system (#236165).
+ Submitted by A. F. T. Arahesis <arfrever.fta@gmail.com>.
+ http://bugs.gentoo.org/show_bug.cgi?id=236165
+
+ * layman/db.py (RemoteDB.path): Use the hashlib library (#237625).
+ Submitted by Mike Auty <ikelos@gentoo.org>.
+ http://bugs.gentoo.org/show_bug.cgi?id=237625
+
+ * layman/overlays/overlay.py (Overlay.cmd): Use the subprocess
+ module (#237625).
+ Submitted by Mike Auty <ikelos@gentoo.org>.
+ http://bugs.gentoo.org/show_bug.cgi?id=237625
+
+ * layman/overlays/git.py (GitOverlay.add): layman git: handle
+ git+ssh://, ssh:// correctly (#230702)
+ Submitted by Donnie Berkholz <dberkholz@gentoo.org>
+ http://bugs.gentoo.org/show_bug.cgi?id=230702
+
+ * layman/overlays/overlay.py: layman-1.2.0-r1, TR locale
+ error (#235165)
+ Submitted by A. F. T. Arahesis <arfrever.fta@gmail.com>.
+ http://bugs.gentoo.org/show_bug.cgi?id=235165
+
+ * layman/action.py: layman-1.2.0-r1, TR locale error (#235165)
+ Submitted by A. F. T. Arahesis <arfrever.fta@gmail.com>.
+ http://bugs.gentoo.org/show_bug.cgi?id=235165
+
+ * layman/db.py (DB.add): Do not remove directories if adding an
+ overlay failed (#236945)
+ http://bugs.gentoo.org/show_bug.cgi?id=236945
+
+2008-06-02 Gunnar Wrobel <p@rdus.de>
+
+ * ebuild/layman-1.2.0.ebuild: Ebuild for 1.2.0
+
+ * etc/layman.cfg (nocheck): Set nocheck to yes.
+
+ * layman/version.py: Mark version 1.2.0
+
+ * layman/config.py: Implement a umask setting (#186819)
+ http://bugs.gentoo.org/show_bug.cgi?id=186819
+
+ * INSTALL: Fix the documentation.
+
+ * README: Updated project links.
+
+ * doc/layman.8.xml: Update the link section.
+
+2007-11-08 Gunnar Wrobel <p@rdus.de>
+
+ * layman/action.py (Info.run):
+
+ Catch non-existing overlay when calling --info
+ http://bugs.gentoo.org/show_bug.cgi?id=198483
+
+2007-09-12 Gunnar Wrobel <p@rdus.de>
+
+ * layman/version.py:
+
+ Version 1.1.1
+
+ * layman/action.py (Sync.__init__):
+
+ Fixed --sync-all (#192190)
+ http://bugs.gentoo.org/show_bug.cgi?id=192190
+
+2007-09-11 Gunnar Wrobel <p@rdus.de>
+
+ * layman/config.py (Config.__init__):
+ * doc/layman.8.xml:
+
+ Add "nocolor" option (#183364)
+ http://bugs.gentoo.org/show_bug.cgi?id=183364
+
+ * layman/db.py:
+ * layman/debug.py:
+
+ Fixes for unicode bug #184449
+ http://bugs.gentoo.org/show_bug.cgi?id=184449
+
+ * layman/overlays/rsync.py (RsyncOverlay.sync):
+
+ Fix bug #177045
+ http://bugs.gentoo.org/show_bug.cgi?id=177045
+
+ * doc/layman.8.xml:
+
+ Improve the man page concerning the --overlays flag (#180107)
+ http://bugs.gentoo.org/show_bug.cgi?id=180107
+
+ * layman/db.py (DB.add):
+ * layman/overlays/overlay.py (Overlay.set_priority):
+
+ Correctly handle the priority setting (#185142)
+ http://bugs.gentoo.org/show_bug.cgi?id=185142
+
+ * layman/config.py (Config.__init__):
+
+ Finally fix the default for "nocheck"
+
+ * layman/version.py:
+
+ Update to version 1.1.
+
+ * layman/config.py (Config.__init__):
+ * layman/action.py (Info.run):
+ * doc/layman.8.xml:
+
+ Add the new "--info" option (bug #188000)
+ http://bugs.gentoo.org/show_bug.cgi?id=188000
+
+ * doc/layman.8.xml:
+
+ Description of the verbose switch (partial fix
+ for #188004).
+ http://bugs.gentoo.org/show_bug.cgi?id=188004
+
+ * layman/config.py (Config.__init__):
+
+ Add the output options into the list of documented
+ cli switches (partial fix for #188004).
+ http://bugs.gentoo.org/show_bug.cgi?id=188004
+
+2007-01-09 Gunnar Wrobel <wrobel@pardus.de>
+
+ * layman/version.py:
+
+ Update to version 1.0.10
+
+2007-01-08 Gunnar Wrobel <wrobel@pardus.de>
+
+ * layman/db.py (DB.add, MakeConf.write):
+
+ Added support for the --priority flag.
+
+ Modified order of entries in PORTDIR_OVERLAY.
+
+ * layman/config.py (Config.__init__):
+
+ Added --priority flag.
+
+ * doc/layman.8.xml:
+
+ Added documentation for --priority switch.
+
+2007-01-05 Gunnar Wrobel <wrobel@pardus.de>
+
+ * layman/db.py:
+
+ Fixed doc tests.
+
+ * layman/config.py:
+
+ Fixed doc tests.
+
+ * layman/action.py:
+
+ Fixed doc tests.
+
+ * layman/overlays/tar.py:
+
+ Fixed doc tests.
+
+2006-12-30 Gunnar Wrobel <wrobel@pardus.de>
+
+ * layman/config.py (Config.__init__):
+
+ Fixed quietness option.
+
+ * layman/overlays/tar.py (TarOverlay.__init__):
+
+ Fixed default values.
+
+ * layman/overlays/cvs.py (CvsOverlay.__init__):
+
+ Fixed default values.
+
+ * layman/action.py:
+
+ Add support for --quiet/--quietness
+
+ * layman/overlay.py (Overlays.__init__):
+
+ Add support for --quiet/--quietness
+
+ * layman/overlays/overlay.py (Overlay.__init__, Overlay.cmd):
+
+ Add support for --quiet/--quietness
+
+ * layman/db.py (DB.__init__):
+
+ Add support for --quiet/--quietness
+
+ * layman/version.py:
+
+ This will be version 1.0.9
+
+ * doc/layman.8.xml:
+
+ Added documentation for --quiet/--quietness
+
+2006-12-29 Gunnar Wrobel <wrobel@pardus.de>
+
+ * layman/config.py (Config):
+
+ Added quietness and modified OUT.info / OUT.warn calls
+ accordingly (bug #151965)
+
+ * layman/db.py (DB.sync, DB.add):
+
+ Catching error when syncing fails (bugs #148698 and #159051).
+
+ * ebuild/layman-1.0.8.ebuild:
+
+ Fixed postinstall instructions for layman (bug #149867)
+
+ Added subversion "nowebdav" check by cardoe into repository.
+
+2006-09-23 <post@gunnarwrobel.de>
+
+ * layman/version.py: Update to 1.0.8
+
+2006-09-22 <post@gunnarwrobel.de>
+
+ * layman/overlays/cvs.py (CvsOverlay.sync): CVS support
+
+2006-09-05 <post@gunnarwrobel.de>
+
+ * layman/*: Generic pylint and cleanup fixes
+
+ * layman/config.py (Config.__init__): Modified to allow switching
+ strict checking off.
+
+2006-08-08 <post@gunnarwrobel.de>
+
+ * layman/overlays/tar.py (TarOverlay.add): Support for explicit
+ file format of a tar package.
+
+2006-08-01 <post@gunnarwrobel.de>
+
+ * layman/action.py (Sync.run): Print successes and warning at the
+ end of the run.
+ (List.run): List only official overlays when not running verbose.
+
+ * layman/db.py (MakeConf.write.prio_sort): Sort overlays by
+ priority when writing make.conf
+
+ * layman/overlay.py (Overlays.list): Support for marking overlays
+ as official.
+ (Overlays.read): Only warn on invalid overlay definitions and do
+ not add them.
+
+ * layman/overlays/bzr.py: Allow whitespace.
+
+ * layman/overlays/darcs.py: Allow whitespace.
+
+ * layman/overlays/git.py: Allow whitespace.
+
+ * layman/overlays/mercurial.py: Allow whitespace.
+
+ * layman/overlays/rsync.py: Allow whitespace.
+
+ * layman/overlays/svn.py: Allow whitespace.
+
+ * layman/overlays/tar.py: Allow whitespace.
+
+ * layman/overlays/overlay.py (Overlay.__init__): Required contact,
+ description. Added support for status and priority.
+ (Overlay.__str__): Modified display according to changes given
+ above.
+ (Overlay.is_official): Added new function for official overlays.
+
+ * layman/overlay.py: Added mercurial support thanks to
+ Andres Loeh <kosmikus@gentoo.org>
+
+ * layman/overlays/mercurial.py: Added mercurial support thanks to
+ Andres Loeh <kosmikus@gentoo.org>
+
+2006-07-25 <post@gunnarwrobel.de>
+
+ * layman/config.py (Config.__init__): Fixed error introduced in
+ changeset 204. Config file gets read again.
+
+2006-07-18 <post@gunnarwrobel.de>
+
+ * layman/version.py: version bump to 1.0.5
+
+ * layman/config.py (Config.__getitem__): Fixed handling of overlays
+ specified on the command line.
+
+ * layman/db.py (RemoteDB.cache): Fixed handling of downloaded
+ overlay list.
+
+ * layman/overlay.py: Added darcs module.
+
+2006-07-17 <post@gunnarwrobel.de>
+
+ * layman/config.py (Config.__init__): Fixed some config defaults.
+
+ * layman/action.py (Actions.__init__): Reduced actions for which
+ the remote lists will be implicitely fetched.
+
+ * doc/layman.8.xml: Updated documentation for implicit fetch.
+
+ * layman/action.py (Actions.__init__): Run fetch implicitely
+ only on specific actions.
+
+ * layman/db.py (RemoteDB.cache): Modified download code for
+ improved handling of fetch problems.
+
+ * layman/action.py (Sync.__init__): Added --sync-all support.
+
+ * doc/layman.8.xml: Added --sync-all documentation.
+
+ * layman/db.py (RemoteDB.__init__): Added proxy support.
+
+ * etc/layman.cfg (make_conf): Added local file syntax example.
+ (overlays): Added proxy variable.
+
+ * doc/layman.8.xml: Added documentation about local overlay
+ definitions.
+ Added proxy documentation.
+
+2006-06-28 <post@gunnarwrobel.de>
+
+ * layman/version.py: Version bump to 1.0.4
+
+ * layman/action.py (Sync.run): Fixed src check.
+
+2006-06-27 <post@gunnarwrobel.de>
+
+ * layman/action.py (ListLocal.run): Fixed code for listing.
+
+ * doc/layman.8.xml: Fixed documentation for new nofetch option.
+
+ * layman/action.py (Actions.__init__): Made fetching the default
+ if nofetch is NOT set.
+ (Sync.run): Added source path comparison for overlay location changes.
+ (List.run): Modified output to differentiate between supported and
+ unsupported overlays.
+
+ * layman/config.py (Config.__init__): Added nofetch option.
+
+ * layman/overlay.py: Added bzr support. Thanks to Adrian Perez.
+
+ * layman/overlays/bzr.py: Added bzr support. Thanks to Adrian Perez.
+
+ * layman/overlays/overlay.py (Overlay.short_list): Fixed length
+ of short listing.
+ (Overlay.supported): Fixed check for supported overlay types.
+
+2006-06-05 <post@gunnarwrobel.de>
+
+ * layman/overlays/overlay.py (Overlay): Forgot to add a check
+ if the overlay type is actually supported. -> 1.0.2
+
+ * layman/overlay.py: genstef@gentoo.org provided support for
+ git based overlays. -> released 1.0.1
+
+2006-05-27 <post@gunnarwrobel.de>
+
+ * doc/layman.8.xml: Updated docs to multi list support
+
+ * layman/version.py: Version bump to 1.0.0
+
+ * etc/layman.cfg (overlays): Adapted configuration for change
+ in global list url and multiple list support.
+
+ * layman/config.py (Config.__init__): Fixed link for global
+ overlay list.
+
+ * layman/db.py: Added support for multiple overlay lists.
+
+ * layman/overlay.py: Added support for mutliple overlay lists.
+
+2006-05-01 <post@gunnarwrobel.de>
+
+ * layman/version.py: Version bump to 0.9.2
+
+ * layman/tests/dtest.py (test_suite): Added utils.py test
+
+ * layman/overlays/tar.py (TarOverlay): Fixed testing results.
+
+2006-04-14 <post@gunnarwrobel.de>
+
+ * layman/version.py: Version 0.9.1
+
+ * layman/overlays/tar.py (TarOverlay.__init__): Added
+ category support to packaged overlays. Could/Should
+ also allow this for other overlay types.
+
+2006-03-12 <post@gunnarwrobel.de>
+
+ * layman/db.py (RemoteDB.cache): Create storage
+ dir if it is missing.
+ (MakeConf.write): Add $PORTDIR_OVERLAY to include
+ manual PORTDIR_OVERLAY variable.
+ (MakeConf.read): Disregard PORTDIR_OVERLAY variable
+ as overlay name.
+
+ * layman/action.py (Fetch.run): Added error handling
+ for fetch problems.
+
+ * doc/layman.8.xml: Fixes to the man page.
+
+ * layman/version.py: Version bump to 0.9
+
+ * layman/action.py (Add.run): Added warning if
+ overlay is unkown.
+
+ * etc/cache.xml: Added kolab2 and xgloverlays.
+
+ * layman/overlays/overlay.py (Overlay.short_list): Added
+ shortened overlay listing
+
+ * layman/overlay.py: Added tar support.
+
+ * layman/overlays/tar.py: Added tar support.
+
+2006-02-04 <post@gunnarwrobel.de>
+
+ * etc/cache-private.xml: Added private overlay locations.
+
+ * layman/db.py (MakeConf.read): Allowed for a missing
+ make.conf. This now allows to source an external file
+ into the original make.conf
+
+ * etc/layman.cfg (cache): Fixed location of cache and
+ overlay list
+
+ * layman/config.py (Config.__init__): Fixed description of
+ layman usage.
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..600c92e
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,68 @@
+=================
+DEVELOPMENT NOTES
+=================
+
+:Last update: $Date: 2007-12-18 14:32:42 +0100 (Di, 18 Dez 2007) $
+:Revision: $Revision: 8 $
+:Contact: p@rdus.de
+
+Changes
+-------
+
+ 1) Any change should get a short ChangeLog entry.
+
+ 2) Bigger changes, feature enhancements and closed bugs go into
+ CHANGES
+
+ 3) The RELEASE_NOTES should contain a summary for the current release
+ as well as a list of enhancements and closed bugs.
+
+
+Versions
+--------
+
+ The version number is being recorded in layman/version.py.
+
+ The version number for release packages has three numbers.
+
+ SVN versions should have the date of the last commit appended.
+
+
+Authors
+-------
+
+ Please do not forget to add new authors or contributors within
+ AUTHORS.
+
+
+Release management
+------------------
+
+ No instructions yet.
+
+
+Branches
+--------
+
+ No branches yet.
+
+
+Documentation
+-------------
+
+ The documentation can be found as man page in layman/doc. The source
+ file layman/doc/layman.8.xml is in DocBook format.
+
+
+Testing
+-------
+
+The central testing script is llayman/tests/dtest.py
+
+To run the tests, move into the layman root directory and run
+
+ PYTHONPATH="." python layman/tests/dtest.py
+
+The tests should not fail.
+
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..824ab74
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,72 @@
+====================
+INSTALL instructions
+====================
+
+:Last update: $Date: 2007-12-18 14:32:42 +0100 (Di, 18 Dez 2007) $
+:Revision: $Revision: 10 $
+:Contact: p@rdus.de
+
+Obtaining the software
+----------------------
+
+Download the software at
+
+ http://sourceforge.net/project/showfiles.php?group_id=195416
+
+
+Prerequisites
+-------------
+
+ layman requires the following to work:
+
+ - >=python-2.5 (http://www.python.org)
+
+
+ In addition you will need to install the different version control /
+ file management systems that layman should support.
+
+ layman can support the following systems:
+
+ - bzr
+ - cvs
+ - darcs
+ - git
+ - mercurial
+ - rsync
+ - svn
+ - tar
+ - g-common (g-cran)
+
+
+Installing the software
+-----------------------
+
+ Download the package, unpack it and use the Python setup.py to build
+ and install the software:
+
+ python setup.py build
+ python setup.py install
+
+
+Configuring the software
+------------------------
+
+ The basic configuration can be found in /etc/layman/layman.cfg.
+
+ If you are using layman for overlay management on Gentoo you should
+ follow the configuration instructions provided after installing the
+ tool.
+
+
+Upgrading the software
+----------------------
+
+ Simply download and install a newer version following the
+ instructions given above.
+
+
+Obtaining support
+-----------------
+
+ Post a bug report at http://bugs.gentoo.org
+
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..df2a997
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,14 @@
+include AUTHORS
+include CHANGES
+include COPYING
+include INSTALL
+include README
+include README.api
+include RELEASE_NOTES
+include etc/layman.cfg
+include doc/asciidoc.conf
+include doc/docbook-xsl.css
+include doc/layman.8
+include doc/layman.8.html
+include doc/layman.8.txt
+recursive-include layman/tests *
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1b09206
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+.PHONY: doc
+doc:
+ $(MAKE) -C doc
+
+.PHONY: dist
+dist: doc
+ rm -rf dist MANIFEST
+ ./setup.py sdist
+
+.PHONY: website
+website: doc
+ # Upload HTML version of the man page to http://layman.sf.net/
+ # Please run this for each release
+ # https://sourceforge.net/apps/trac/sourceforge/wiki/Project%20web#ConnectionSettings
+ scp doc/docbook-xsl.css doc/layman.8.html dol-sen,layman@web.sourceforge.net:/home/groups/l/la/layman/htdocs/
diff --git a/README b/README
new file mode 100644
index 0000000..ff3fe25
--- /dev/null
+++ b/README
@@ -0,0 +1,66 @@
+======
+README
+======
+
+:Last update: Date: 2011-08-08
+:Revision:
+:Contact: brian.dolbec@gmail.com
+
+
+About
+-----
+
+layman is the Gentoo overlay manager and allows to integrate
+experimental software packages into the main distribution. It can also
+be used as a manager for version control repositories.
+
+
+Links
+-----
+
+Primary project web site:
+
+ - http://layman.sourceforge.net/
+
+Project site on SourceForge:
+
+ - http://sourceforge.net/projects/layman
+
+Project summary on Ohloh:
+
+ - http://ohloh.net/projects/layman/
+
+Project summary on Freshmeat:
+
+ - http://freshmeat.net/projects/layman/
+
+Bug tracker:
+
+ - http://bugs.gentoo.org
+
+Wiki:
+
+ - http://gentoo-wiki.com/Portage_Overlay_Listing#Layman
+
+Combined RSS feed:
+
+ - http://www.google.com/reader/shared/user/02645926629531261525/label/%5Bproject%5D%20layman
+
+Git repository:
+ - http://git.overlays.gentoo.org/gitweb/?p=proj/layman.git;a=summary
+
+
+File description
+----------------
+
+AUTHORS : The developers of this project
+ChangeLog : A detailed change log
+CHANGES : A summary of the project changes
+COPYING : Licensing information
+HACKING : Developers notes for the project
+INSTALL : Installation instructions
+MANIFEST.in : The listing of files that get included into the python
+ package.
+README : This file.
+RELEASE_NOTES: Release notes for the latest version
+TODO : Task list for the project
diff --git a/README.api b/README.api
new file mode 100644
index 0000000..976006d
--- /dev/null
+++ b/README.api
@@ -0,0 +1,57 @@
+New layman API readme:
+
+
+To use the new LaymanAPI class, so far this is what I've come up with.
+
+big_daddy layman # python
+Python 2.6.5 (release26-maint, May 15 2010, 18:26:37)
+[GCC 4.4.3] on linux2
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import layman;from layman.api import LaymanAPI, create_fd;from layman.config import BareConfig
+>>> e=create_fd();o=create_fd();from layman.debug import Message;M=Message(module='layman',out=o[1], err=e[1]);c=BareConfig(output=M, stdout=o[1], stderr=e[1])
+
+
+>>> # connect the e[0] and o[0] file descriptors to where you want to capture/direct the output #
+...
+
+
+>>> l=LaymanAPI(config=c, output=M)
+>>> avail=l.get_available()
+>>> avail
+[u'DuPol', u'THE', u'akoya', u'alexcepoi', u'alexxy', u'amielke-overlay', u'anarchy', u'and3k-sunrise', u'arcon', u'armagetron', u'aross', u'bangert', u'bazaar', u'belak', u'benf', u'berkano', u'betagarden', u'betelgeuse', u'bibletime', u'calculate', u'cell', u'centerim', u'chtekk-apps', u'crg', u'd', u'dagger', u'dberkholz', u'deathwing00', u'dertobi123', u'desktop-effects', u'dev-zero', u'devnull', u'dilfridge', u'dirtyepic', u'dotnet', u'dottout', u'drizzt-overlay', u'eatnumber1', u'efika', u'emacs', u'embedded-cross', u'enlightenment', u'eva', u'eyolfson', u'falco', u'ferringb', u'finnish', u'flameeyes-overlay', u'foo-overlay', u'freevo', u'gamerlay', u'games', u'gcc-porting', u'gechi', u'genstef', u'gentoo-arm', u'gentoo-bsd', u'gentoo-china', u'gentoo-quebec', u'gentoo-taiwan', u'gentoojp', u'gnome', u'gnome-live', u'gnr', u'gnustep', u'gpe', u'graaff', u'halcy0n', u'hanno', u'hardened-development', u'haskell', u'hawking', u'hollow', u'hwoarang', u'iElectric', u'ibormuth', u'ikelos', u'init6', u'initng', u'interactive-fiction', u'iwlwifi', u'jasiu', u'java-overlay', u'je_fro', u'jensp', u'jmbsvicetto', u'jokey', u'jyujin', u'kde', u'kde-sunset', u'kerberos', u'keruspe', u'kolab', u'kvm', u'laurentb', u'leio', u'lila-theme', u'liquidx', u'lisp', u'loki_val', u'loongson', u'lordvan', u'lorelei', u'ltsp', u'lu_zero', u'luke-jr', u'lxde', u'm68k', u'maekke', u'maggu2810-overlay', u'mamona', u'marineam-xen', u'matsuu', u'mozilla', u'mpd', u'mrpouet', u'multilib', u'multimedia', u'mv', u'mysql', u'n4g', u'n4g-experimental', u'n8x0', u'nelchael', u'neurogeek', u'neuvoo', u'nirbheek', u'njw', u'nx', u'ohnobinki', u'openmoko', u'openoffice-geki', u'openrc', u'oss-overlay', u'otih', u'pchrist', u'pcsx2', u'pd-overlay', u'pda', u'pentoo', u'perl-experimental', u'php', u'php-4', u'piczu', u'pioto-overlay', u'plan9', u'portato', u'postgresql-experimental', u'postgresql-testing', u'powerman', u'powerpc', u'pro-audio', u'purak', u'pure-funtoo', u'python', u'pythonhead', u'qting-edge', u'rafaelmartins', u'ramereth', u'raw', u'rbu', u'remi', u'rion', u'robbat2', u'roslin', u'rostov', u'rox', u'rubenqba', u'ruby', u's3d', u'sabayon', u'sage-on-gentoo', u'sattvik', u'scarabeus', u'science', u'secondlife', u'seemant', u'serkan-overlay', u'sipx', u'sochotnicky', u'soor-overlay', u'sping', u'steev', u'stormfront', u'stuge', u'sugar', u'suka', u'sunrise', u'swegener', u'tante', u'tcl-8.6', u'tcl-multislot', u'thousand-parsec', u'toolchain', u'trapni', u'trauma', u'tryton', u'turbogears2', u'ub0rlay', u'vdr-devel', u'vdr-testing', u'vdr-xine', u'verlihub', u'vmware', u'voip', u'voyageur', u'vps', u'webapps-experimental', u'wirelay', u'wish', u'wolf31o2', u'wrobel', u'wschlich', u'wschlich-testing', u'x11', u'xemacs', u'xen', u'xfce-dev', u'xgr', u'xhub', u'xmms-zombie', u'xwing', u'zugaina']
+>>> inst=l.get_installed()
+>>> inst
+[u'bazaar', u'hardened-development', u'oss-overlay', u'sping', u'sunrise']
+>>> results = l.sync(['sunrise'])
+>>> results
+([], [('sunrise', 'Successfully synchronized overlay "sunrise".')], [])
+# results are a tuple of (warnings, successes, errors)
+>>> l.get_info(['sunrise'])
+[('sunrise\n~~~~~~~\nSource : svn://overlays.gentoo.org/proj/sunrise/reviewed/\nContact : sunrise@gentoo.org\nType : Subversion; Priority: 50\nQuality : experimental\n\nDescription:\n Ebuilds for bugs assigned to maintainer-wanted\n\nLink:\n http://overlays.gentoo.org/proj/sunrise\n\nFeed:\n http://overlays.gentoo.org/proj/sunrise/timeline\n', True, True)]
+>>> l.fetch_remote_list()
+True
+>>> avail = l.get_available()
+>>> avail
+[u'DuPol', u'THE', u'akoya', u'alexcepoi', u'alexxy', u'amielke-overlay', u'anarchy', u'and3k-sunrise', u'arcon', u'armagetron', u'aross', u'bangert', u'bazaar', u'belak', u'benf', u'berkano', u'betagarden', u'betelgeuse', u'bibletime', u'calculate', u'cell', u'centerim', u'chtekk-apps', u'crg', u'd', u'dagger', u'dberkholz', u'deathwing00', u'dertobi123', u'desktop-effects', u'dev-zero', u'devnull', u'dilfridge', u'dirtyepic', u'dotnet', u'dottout', u'drizzt-overlay', u'eatnumber1', u'efika', u'emacs', u'embedded-cross', u'enlightenment', u'eva', u'eyolfson', u'falco', u'ferringb', u'finnish', u'flameeyes-overlay', u'foo-overlay', u'freevo', u'gamerlay', u'games', u'gcc-porting', u'gechi', u'genstef', u'gentoo-arm', u'gentoo-bsd', u'gentoo-china', u'gentoo-quebec', u'gentoo-taiwan', u'gentoojp', u'gnome', u'gnome-live', u'gnr', u'gnustep', u'gpe', u'graaff', u'halcy0n', u'hanno', u'hardened-development', u'haskell', u'hawking', u'hollow', u'hwoarang', u'iElectric', u'ibormuth', u'ikelos', u'init6', u'initng', u'interactive-fiction', u'iwlwifi', u'jasiu', u'java-overlay', u'je_fro', u'jensp', u'jmbsvicetto', u'jokey', u'jyujin', u'kde', u'kde-sunset', u'kerberos', u'keruspe', u'kolab', u'kvm', u'laurentb', u'leio', u'lila-theme', u'liquidx', u'lisp', u'loki_val', u'loongson', u'lordvan', u'lorelei', u'ltsp', u'lu_zero', u'luke-jr', u'lxde', u'm68k', u'maekke', u'maggu2810-overlay', u'mamona', u'marineam-xen', u'matsuu', u'mozilla', u'mpd', u'mrpouet', u'multilib', u'multimedia', u'mv', u'mysql', u'n4g', u'n4g-experimental', u'n8x0', u'nelchael', u'neurogeek', u'neuvoo', u'nirbheek', u'njw', u'nx', u'ohnobinki', u'openmoko', u'openoffice-geki', u'openrc', u'oss-overlay', u'otih', u'pchrist', u'pcsx2', u'pd-overlay', u'pda', u'pentoo', u'perl-experimental', u'php', u'php-4', u'piczu', u'pioto-overlay', u'plan9', u'portato', u'postgresql-experimental', u'postgresql-testing', u'powerman', u'powerpc', u'pro-audio', u'purak', u'pure-funtoo', u'python', u'pythonhead', u'qting-edge', u'rafaelmartins', u'ramereth', u'raw', u'rbu', u'remi', u'rion', u'robbat2', u'roslin', u'rostov', u'rox', u'rubenqba', u'ruby', u's3d', u'sabayon', u'sage-on-gentoo', u'sattvik', u'scarabeus', u'science', u'secondlife', u'seemant', u'serkan-overlay', u'sipx', u'sochotnicky', u'soor-overlay', u'sping', u'steev', u'stormfront', u'stuge', u'sugar', u'suka', u'sunrise', u'swegener', u'tante', u'tcl-8.6', u'tcl-multislot', u'thousand-parsec', u'toolchain', u'trapni', u'trauma', u'tryton', u'turbogears2', u'ub0rlay', u'vdr-devel', u'vdr-testing', u'vdr-xine', u'verlihub', u'vmware', u'voip', u'voyageur', u'vps', u'webapps-experimental', u'wirelay', u'wish', u'wolf31o2', u'wrobel', u'wschlich', u'wschlich-testing', u'x11', u'xemacs', u'xen', u'xfce-dev', u'xgr', u'xhub', u'xmms-zombie', u'xwing', u'zugaina']
+>> results=l.get_info(['sunrise'])
+>>> results[0]
+('sunrise\n~~~~~~~\nSource : svn://overlays.gentoo.org/proj/sunrise/reviewed/\nContact : sunrise@gentoo.org\nType : Subversion; Priority: 50\nQuality : experimental\n\nDescription:\n Ebuilds for bugs assigned to maintainer-wanted\n\nLink:\n http://overlays.gentoo.org/proj/sunrise\n\nFeed:\n http://overlays.gentoo.org/proj/sunrise/timeline\n', True, True)
+>>> info,official,supported=results[0]
+>>> info
+'sunrise\n~~~~~~~\nSource : svn://overlays.gentoo.org/proj/sunrise/reviewed/\nContact : sunrise@gentoo.org\nType : Subversion; Priority: 50\nQuality : experimental\n\nDescription:\n Ebuilds for bugs assigned to maintainer-wanted\n\nLink:\n http://overlays.gentoo.org/proj/sunrise\n\nFeed:\n http://overlays.gentoo.org/proj/sunrise/timeline\n'
+>>> official
+True
+>>> supported
+True
+>>>
+>>> results=l.get_info(['sunrise', 'sping'])
+>>> len(results)
+2
+>>> info,official,supported=results[1]
+>>> info
+'sping\n~~~~~\nSource : git://git.goodpoint.de/overlay-sping.git\nContact : Sebastian Pipping <sping@gentoo.org>\nType : Git; Priority: 50\nQuality : experimental\n\nDescription:\n Gentoo overlay of Sebastian Pipping\n\nLink:\n http://git.goodpoint.de/?p=overlay-sping.git;a=summary\n\nFeed:\n http://git.goodpoint.de/?p=overlay-sping.git;a=atom\n'
+>>> official
+False
+>>> supported
+True
+>>>
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
new file mode 100644
index 0000000..821ccf6
--- /dev/null
+++ b/RELEASE_NOTES
@@ -0,0 +1,26 @@
+Version 2.0.0_rc1 - Released 2011-06-06
+=======================================
+
+ - major rewrite of the api's, extensions,
+ new cli-api connections, other enhancements...
+
+
+FRESHMEAT
+=========
+
+# Release focus. Possible values:
+# 0 - N/A
+# 1 - Initial freshmeat announcement
+# 2 - Documentation
+# 3 - Code cleanup
+# 4 - Minor feature enhancements
+# 5 - Major feature enhancements
+# 6 - Minor bugfixes
+# 7 - Major bugfixes
+# 8 - Minor security fixes
+# 9 - Major security fixes
+
+focus:
+name:
+project:
+branch:
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..1af34ac
--- /dev/null
+++ b/TODO
@@ -0,0 +1,19 @@
+=========
+TODO List
+=========
+
+:Last update: $Date: 2007-12-18 14:32:42 +0100 (Di, 18 Dez 2007) $
+:Revision: $Revision: 10 $
+:Contact: p@rdus.de
+
+Open bugs
+---------
+
+
+Required enhancements
+---------------------
+
+
+Plans
+-----
+
diff --git a/bin/layman b/bin/layman
new file mode 100755
index 0000000..6299d34
--- /dev/null
+++ b/bin/layman
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+################################################################################
+# LAYMAN - A UTILITY TO SELECT AND UPDATE GENTOO OVERLAYS
+################################################################################
+# Distributed under the terms of the GNU General Public License v2
+#
+# Copyright:
+# (c) 2005 Gunnar Wrobel
+# (c) 2009 Sebastian Pipping
+# (c) 2011 Brian Dolbec
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Sebastian Pipping <sebastian@pipping.org>
+# Brian Dolbec <brian.dolbec@gmail.com>
+#
+
+__version__ = "0.2"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+from layman.argsparser import ArgsParser
+from layman.cli import Main
+
+#===============================================================================
+#
+# MAIN
+#
+#-------------------------------------------------------------------------------
+
+main = Main(ArgsParser())
+main()
diff --git a/doc/.svn.ignore b/doc/.svn.ignore
new file mode 100644
index 0000000..ff0e9f9
--- /dev/null
+++ b/doc/.svn.ignore
@@ -0,0 +1,3 @@
+*.html
+*.8
+semantic.cache
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..b5dbaf3
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,38 @@
+#
+# layman/doc/Makefile
+# Simple Makefile to rebuild the documentation from the
+# docbook XML sources
+#
+# Copyright (c) 1999-2005 Gentoo Foundation
+# Released under v2 of the GNU GPL
+#
+# Author(s) Stuart Herbert <stuart@gentoo.org>
+# Renat Lumpau <rl03@gentoo.org>
+# Gunnar Wrobel <php@gunnarwrobel.de>
+#
+# ========================================================================
+
+MAN_PAGES = layman.8
+HTML_PAGES = layman.8.html
+
+TMPFILE=./layman.man
+
+PACKAGE_VERSION = `fgrep "VERSION = " ../layman/version.py | sed 's|^VERSION = '"'"'\(.\+\)'"'"'$$|\1|'`
+
+all: man html
+
+html: $(HTML_PAGES)
+
+man: $(MAN_PAGES)
+
+clean:
+ rm -f $(MAN_PAGES)
+ rm -f $(HTML_PAGES)
+
+%.html: %.txt ../layman/version.py
+ @echo HTML $@
+ a2x --conf-file=asciidoc.conf --attribute="laymanversion=$(PACKAGE_VERSION)" --format=xhtml "$<"
+
+%: %.txt ../layman/version.py
+ @echo MAN $@
+ a2x --conf-file=asciidoc.conf --attribute="laymanversion=$(PACKAGE_VERSION)" --format=manpage "$<"
diff --git a/doc/asciidoc.conf b/doc/asciidoc.conf
new file mode 100644
index 0000000..e1c1d52
--- /dev/null
+++ b/doc/asciidoc.conf
@@ -0,0 +1,3 @@
+#
+# asciidoc.conf for layman's man page
+#
diff --git a/doc/layman.8.txt b/doc/layman.8.txt
new file mode 100644
index 0000000..0558b67
--- /dev/null
+++ b/doc/layman.8.txt
@@ -0,0 +1,473 @@
+LAYMAN(8)
+=========
+:man source: layman {laymanversion}
+:man manual: layman {laymanversion}
+Gunnar Wrobel <wrobel@gentoo.org>
+
+
+NAME
+----
+layman - manage your local repository of Gentoo overlays
+
+
+SYNOPSIS
+--------
+*layman* (*-a*|*--add*) (*ALL*|'OVERLAY')
+
+*layman* (*-d*|*--delete*) (*ALL*|'OVERLAY')
+
+*layman* (*-s*|*--sync*) (*ALL*|'OVERLAY')
+
+*layman* (*-i*|*--info*) (*ALL*|'OVERLAY')
+
+*layman* (*-S*|*--sync-all*)
+
+*layman* (*-L*|*--list*)
+
+*layman* (*-l*|*--list-local*)
+
+*layman* (*-f*|*--fetch*)
+
+
+DESCRIPTION
+-----------
+*layman* is a script that allows you to add, remove and update
+Gentoo overlays from a variety of sources.
+
+WARNING
+~~~~~~~
+*layman* makes it easy to retrieve and update overlays for Gentoo.
+In addition it makes it TRIVIAL to break your system.
+
+The Gentoo main tree provides you with high quality ebuilds that
+are all maintained by Gentoo developers. This will not be the case
+for most of the overlays you can get by using *layman*. Thus you
+are removing the security shield that the standard tree provides
+for you. You should keep that in mind when installing ebuilds from
+an overlay.
+
+To ensure the security of your system you MUST read the source of
+the ebuild you are about to install.
+
+
+OPTIONS
+-------
+
+ACTIONS
+~~~~~~~
+List of possible *layman* actions.
+
+*-f*, *--fetch*::
+ Fetches the remote list of overlays. You will usually NOT need
+to explicitly specify this option. The fetch operation will be
+performed automatically once you run the sync, sync-all, or list action.
+You can prevent this automatic fetching using the *--nofetch* option.
+
+*-a* 'OVERLAY', *--add*='OVERLAY'::
+ Add the given overlay from the cached remote list to your
+ locally installed overlays. Specify "ALL" to add all overlays
+ from the remote list.
+
+*-d* 'OVERLAY', *--delete*='OVERLAY'::
+ Remove the given overlay from your locally installed overlays.
+ Specify "ALL" to remove all overlays
+
+*-s* 'OVERLAY', *--sync*='OVERLAY'::
+ Update the specified overlay. Use "ALL" as parameter to
+ synchronize all overlays
+
+*-i* 'OVERLAY', *--info*='OVERLAY'::
+ Display all available information about the specified overlay.
+
+*-S*, *--sync-all*::
+ Update all overlays. Shortcut for *-s ALL*.
+
+*-L*, *--list*::
+ List the contents of the remote list.
+
+*-l*, *--list-local*::
+ List the locally installed overlays.
+
+
+OTHER OPTIONS
+~~~~~~~~~~~~~
+List of other available *layman* options.
+
+*-c* 'PATH', *--config*='PATH'::
+ Path to an alternative configuration file.
+
+*-o* 'URL', *--overlays*='URL'::
+ Specifies the location of additional overlay lists. You can use
+ this flag several times and the specified URLs will get temporarily
+ appended to the list of URLs you specified in your config file.
+ You may also specify local file URLs by prepending the path with
+ 'file://'. This option will only append the URL for this specific
+ *layman* run - edit your config file to add a URL permanently.
+ So this is useful for testing purposes.
+
+*-n*, *--nofetch*::
+ Prevents *layman* from automatically fetching the remote lists
+ of overlays. The default behavior for *layman* is to update all
+ remote lists if you run the sync, list or fetch operation.
+
+*-k*, *--nocheck*::
+- When listing remote overlays (using *-L* or *--list*) *layman*
+ no longer hides overlays, for which you lack the tools to use.
+ By default, *layman* hides Git repositories if you do not have Git
+ installed. Same applies to Subversion, CVS and so forth.
+
+- Prevents *layman* from checking the remote lists of overlays for
+ complete overlay definitions. The default behavior for *layman* is
+ to reject overlays that do not provide a description or a contact
+ attribute.
+
+
+*-q*, *--quiet*::
+ Makes *layman* completely quiet. In quiet mode child processes
+ will be run with stdin closed to avoid running into infinite and
+ blindly interactive sessions. Thus a child process may abort once
+ it runs into an situation with need for human interaction.
+ For example this might happen if your overlay resides in Subversion
+ and the SSL certificate of the server needs manual acceptance.
+
+*-v*, *--verbose*::
+ Makes *layman* more verbose and you will receive a description of
+ the overlays you can download.
+
+*-N*, *--nocolor*::
+ Remove color codes from the *layman* output.
+
+*-Q* 'LEVEL', *--quietness*='LEVEL'::
+ Makes *layman* less verbose. Choose a value between 0 and 4
+ with 0 being completely quiet. Once you set this below 3,
+ the same warning as given for *--quiet* applies.
+
+*-p* 'LEVEL', *--priority*='LEVEL'::
+ Use this option in combination with the *--add*. It will modify
+ the priority of the added overlay and thus influence the order
+ of entries in the make.conf file. The lower the priority,
+ the earlier in the list the entry will be mentioned. Use a value
+ between 0 and 100. The default value is 50.
+
+
+CONFIGURATION
+-------------
+*layman* reads configuration parameters from the file
+'/etc/layman/layman.cfg' by default. This file provides seven possible
+settings.
+
+storage::
+ Directory that will be used to store the overlays and all
+ additional data *layman* needs. The default is '/var/lib/layman'.
+ *layman* uses a location within the '/usr/portage' hierarchy
+ instead of '/var' in order to store its data. This decision has
+ been made to support network file systems. If you have your
+ Gentoo tree on NFS or a similar file system and several
+ machines access the same ebuild repository over the net it
+ will be necessary to also provide all necessary *layman* data
+ within the hierarchy of the tree. This way the overlays will
+ also have to be synced at one location only.
+
+cache::
+ *layman* will store the downloaded global list of overlays here.
+ The default is '%(storage)s/cache.xml'.
+
+installed::
+ *layman* will store the list of installed overlays here.
+ The default is '%(storage)s/installed.xml'.
+
+make.conf::
+ This is the *portage* configuration file that *layman* will
+ modify in order to make the new overlays available within
+ *portage*. The default is '%(storage)s/make.conf'. You could
+ also specify '/etc/make.conf' directly. But that would mean
+ that you have an external program trying to automatically
+ set variables within this very central configuration file.
+ Since I consider that dangerous I prefer having a very small
+ external file that only contains the setting for
+ *PORTDIR_OVERLAY*. This file is then sourced at the end of
+ '/etc/make.conf'. This is the reason why *layman* suggests running
+ the following *after* it has been installed.
+
+ echo 'source /var/lib/layman/make.conf' >> /etc/make.conf
+
+
+
+
+overlays::
+ Specifies the URL for the remote list of all available overlays.
+ The default is 'http://www.gentoo.org/proj/en/overlays/repositories.xml'.
+ You can specify several URLs here (one per line). The contents will
+ get merged to a single list of overlays. This allows to add a personal
+ collection of overlays that are not present in the global list.
+
+proxy::
+ Specify your proxy in case you have to use one.
+
+nocheck::
+ Set to "yes" if *layman* should stop worrying about overlays
+ with missing a contact address or the description.
+
+*NEW* Per repository type Add, Sync options.
+
+bzr_addopts::
+bzr_syncopts::
+cvs_addopts::
+cvs_syncopts::
+...::
+ These are command options to include in the commands sent to perform
+ the desired action.
+
+*NEW* Per repository type Post Add, Sync hooks.
+
+bzr_postsync::
+cvs_postsync::
+darcs_postsync::
+git_postsync::
+...::
+ These are commands that are run after each add, sync operation if they
+ are defined.
+
+
+
+HANDLING OVERLAYS
+-----------------
+*layman* intends to provide easy maintenance of Gentoo overlays
+while not requiring any configuration.
+
+
+OVERLAY LISTS
+~~~~~~~~~~~~~
+*layman* allows you to fetch an overlay without the need to modify
+any configuration files. In order for this to be possible the script
+needs an external list of possible overlay sources. There is a
+centralized list available at
+'http://www.gentoo.org/proj/en/overlays/repositories.xml'
+but nothing will prevent you from using or publishing your own
+list of overlays. The location of the remote lists can also be
+modified using the *--overlays* option when running *layman*.
+
+To get a new overlay added to the central list provided for *layman*,
+send a mail to <overlays@gentoo.org>. Gentoo developers may add their
+overlay entries directly into the list which can be accessed over the
+CVS repository for the Gentoo website.
+
+You can also use several lists at the same time. Just add one URL per
+line to the overlays variable in your configuration file. *layman*
+will merge the contents of all lists.
+
+*layman* also allows you to define local files in this list.
+Just make sure you prepend these path names in standard URL notation with 'file://'.
+*New* is the ability to just add an overlay definition to /etc/layman/overlays/
+ some-overlay.xml and it will be automatically available for actions such as
+ add, delete, info... (see below for file format details)
+
+If you need to use a proxy for access to the Internet, you can use
+the corresponding variable in the *layman* configuration file.
+*layman* will also respect the *http_proxy* environment variable in case you set it.
+
+
+LOCAL CACHE
+~~~~~~~~~~~
+*layman* stores a local copy of the fetched remote list.
+It will be stored in '/var/lib/layman/cache.xml' by default.
+There exists only one such cache file and it will be overwritten
+every time you run *layman*.
+
+
+HANDLING /ETC/MAKE.CONF
+~~~~~~~~~~~~~~~~~~~~~~~
+Since *layman* is designed to automatically handle the inclusion of
+overlays into your system it needs to be able to modify the
+*PORTDIR_OVERLAY* variable in your '/etc/make.conf' file.
+But '/etc/make.conf' is a very central and essential configuration
+file for a Gentoo system. Automatically modifying this file would
+be somewhat dangerous. You can allow *layman* to do this by
+setting the make_conf variable in the configuration file to
+'/etc/make.conf'.
+
+A much safer and in fact recommended solution to the problem is
+to let *layman* handle an external file that only contains the
+*PORTDIR_OVERLAY* variable and is sourced within the standard
+'/etc/make.conf' file. Just add the following line to the end of
+your '/etc/make.conf' file:
+
+-------------------------------------------
+source /var/lib/layman/make.conf
+-------------------------------------------
+
+'/var/lib/layman/make.conf' is the default provided in the *layman*
+configuration. Change this file name in case you decide to store
+it somewhere else.
+
+The file does not necessarily need to exist at the beginning.
+If it is missing, *layman* will create it for you.
+
+There is also no need to remove the original *PORTDIR_OVERLAY*
+variable from the make.conf file. Layman will simply add new overlays
+to this variable and all your old entries will remain in there.
+
+
+ADDING, REMOVING AND UPDATING OVERLAYS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Once a remote list of overlays has been fetched, *layman* allows
+to add overlays from the remote list to your system. The script
+will try to fetch the overlay. If this is successful the overlay
+information will be copied from the cache to the list of locally
+installed overlays. In addition *layman* will modify the
+*PORTDIR_OVERLAY* variable to include the new overlay path.
+
+Removing the overlay with *layman* will delete the overlay without
+leaving any traces behind.
+
+In order to update all overlays managed by *layman* you can run
+the script with the *--sync ALL* option or the *--sync-all* flag.
+
+
+LIST OVERLAYS
+~~~~~~~~~~~~~
+*layman* provides the *--list* and *--list-local* options to print
+a list of available respectively installed overlays.
+
+Listing will prepend all fully supported overlays with a green
+asterisk, all non-official overlays with a yellow asterisk and
+all overlays that you will not be able to use since you do not
+have the necessary tools installed with a red asterisk.
+
+In the default mode *layman* will be strict about listing overlays
+and only present you with overlays that are fully supported.
+In addition it will complain about overlays that are missing
+a description field or a contact attribute. This type of behavior
+has been added with *layman* 1.0.7 and if you'd like to return to
+the old behavior you may use the k option flag or set the nocheck
+option in the configuration file.
+
+
+SEARCHING EBUILDS IN OVERLAYS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can search through the ebuilds available in the overlays on
+'http://overlays.gentoo.org/' by using *eix*. Emerge the package and
+run:
+
+ update-eix-remote update
+
+Alternatively, you can browse overlays that you have not installed
+on 'http://gpo.zugaina.org/'.
+
+
+OVERLAY TYPES
+~~~~~~~~~~~~~
+Currently *layman* supports overlays that are exported via *rsync*,
+*CVS*, *subversion*, *bzr*, *darcs*, *git*, *mercurial* or provided as *tar*
+packages. It also supports the generated overlay type *g-common* installed
+with the g-cran package (at time of this writing, only available in the science
+ overlay).
+
+
+OVERLAY LISTS
+-------------
+
+OVERLAY LIST FORMAT
+~~~~~~~~~~~~~~~~~~~
+Layman uses a central list of overlays in XML format. The file looks
+like this:
+
+Example 1. An example overlays.xml file
+
+-------------------------------------------
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE repositories SYSTEM "/dtd/repositories.dtd">
+<repositories xmlns="" version="1.0">
+<repo quality="experimental" status="official">
+ <name>gnome</name>
+ <description>experimental gnome ebuilds</description>
+ <homepage>http://git.overlays.gentoo.org/gitweb/?p=proj/gnome.git;a=summary</homepage>
+ <owner type="project">
+ <email>gnome@gentoo.org</email>
+ <name>GNOME herd</name>
+ </owner>
+ <source type="git">git://git.overlays.gentoo.org/proj/gnome.git</source>
+ <source type="git">http://git.overlays.gentoo.org/gitroot/proj/gnome.git</source>
+ <source type="git">git+ssh://git@git.overlays.gentoo.org/proj/gnome.git</source>
+ <feed>http://git.overlays.gentoo.org/gitweb/?p=proj/gnome.git;a=atom</feed>
+ <feed>http://git.overlays.gentoo.org/gitweb/?p=proj/gnome.git;a=rss</feed>
+</repo>
+</repositories>
+-------------------------------------------
+
+
+ADDING AN OVERLAY LOCALLY
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Simply create an overlay list in the format described above and run
+*layman* with the -o switch. You need to prepend local file URLs
+with 'file://'. *New* is the ability to just add an overlay definition like
+ the above to /etc/layman/overlays/some-overlay.xml and it will be
+ automatically available for actions such as add, delete, info...
+
+
+ADDING AN OVERLAY GLOBALLY
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+The global list of overlays used by *layman* lies at
+'http://www.gentoo.org/proj/en/overlays/repositories.xml'.
+
+All Gentoo developers have access to this location via CVS and
+can modify the list of overlays.
+
+If you are not a Gentoo developer but wish to get your overlay
+listed you should contact the Gentoo Overlays team at
+<overlays@gentoo.org>. You can also join *#gentoo-overlays* on
+irc.freenode.net.
+
+
+EXAMPLES
+--------
+
+INSTALLING AN OVERLAY
+~~~~~~~~~~~~~~~~~~~~~
+-------------------------------------------
+layman -f -a wrobel
+-------------------------------------------
+
+This would add the overlay with the id wrobel to your list of
+installed overlays.
+
+
+SYNCING YOUR OVERLAYS
+~~~~~~~~~~~~~~~~~~~~~
+-------------------------------------------
+layman -s ALL
+-------------------------------------------
+
+This updates all overlays
+
+
+PERFORMING SEVERAL ACTIONS AT THE SAME TIME
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-------------------------------------------
+layman -f -a wrobel -a webapps-experimental
+-------------------------------------------
+
+This fetches the remote list and immediately adds two overlays
+
+
+FILES
+-----
+'/etc/layman/layman.cfg'::
+ Configuration file, holding the defaults for *layman*
+
+
+AUTHORS
+-------
+- Gunnar Wrobel <wrobel@gentoo.org>
+- Sebastian Pipping <sping@gentoo.org>
+- Brian Dolbec <brian.dolbec@gmail.com>
+
+
+REPORTING BUGS
+--------------
+Please report bugs you might find at 'http://bugs.gentoo.org/'. Thank you!
+
+
+SEE ALSO
+--------
+make.conf(5), eix(1)
diff --git a/etc/Makefile b/etc/Makefile
new file mode 100644
index 0000000..4a8c01a
--- /dev/null
+++ b/etc/Makefile
@@ -0,0 +1,4 @@
+list:
+ scp cache-private.xml root@build.pardus.de:/var/www/localhost/htdocs/downloads/private-overlays.xml
+
+.PHONY: list
diff --git a/etc/cache-private.xml b/etc/cache-private.xml
new file mode 100644
index 0000000..d1bf56a
--- /dev/null
+++ b/etc/cache-private.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" ?>
+<layman>
+
+ <overlay
+ type = "svn"
+ src = "http://overlays.gentoo.org/svn/dev/wrobel/stable"
+ name = "wrobel-stable"/>
+ <overlay
+ type = "svn"
+ src = "http://overlays.gentoo.org/svn/dev/wrobel/testing"
+ name = "wrobel-testing"/>
+ <overlay
+ type = "svn"
+ src = "http://overlays.gentoo.org/svn/dev/wrobel/broken"
+ name = "wrobel-broken"/>
+ <overlay
+ type = "svn"
+ src = "https://www.gunnarwrobel.de/svn/kolab/ebuilds"
+ name = "kolab2"/>
+ <overlay
+ type = "svn"
+ src = "https://www.gunnarwrobel.de/svn/kolab-pardus/ebuilds"
+ name = "kolab-pardus"/>
+
+</layman>
diff --git a/etc/cache.xml b/etc/cache.xml
new file mode 100644
index 0000000..2f4759d
--- /dev/null
+++ b/etc/cache.xml
@@ -0,0 +1,531 @@
+<?xml version="1.0" ?>
+<layman>
+
+ <overlay
+ type = "svn"
+ src = "https://gentopia.gentooexperimental.org/svn/overlay/"
+ name = "gentopia">
+
+ <link>
+ http://gentopia.gentooexperimental.org/
+ </link>
+
+ <description>
+ Purpose
+
+ To provide a smooth, seamlessly functional and enjoyable Gentoo
+ Desktop experience by following the mantra of "Just Works".
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "tar"
+ src = "http://svn.gnqs.org/downloads/gentoo-php-overlay.tar.gz"
+ name = "php">
+
+ <link>
+ http://svn.gnqs.org/projects/gentoo-php-overlay/
+ </link>
+
+ <description>
+ The Gentoo PHP Overlay is our testbed for new and improved PHP
+ packages for Gentoo21. It's a place where Gentoo developers and
+ users alike can work together on providing Gentoo Linux with the
+ very best PHP support that there is, for any platform.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "https://gentooscience.org/svn/overlay"
+ name = "science">
+
+ <link>
+ https://gentooscience.org/
+ </link>
+
+ <description>
+ The Gentoo Science Overlay is intended as a place to work
+ outside of the main portage tree on experimental ebuilds. Our
+ aim is to increase the rate of development of scientific
+ packages for Gentoo, but ebuilds in this repository are by their
+ very nature more experimental. If you wish to use them you
+ should be willing to help test and report bugs.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "https://nemesis.fprintf.net/svn/gnome-experimental/"
+ name = "gnome-experimental">
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://rsync.breakmygentoo.net/bmg-main"
+ name = "break-my-gentoo-main">
+
+ <link>
+ http://www.breakmygentoo.net
+ </link>
+
+ <description>
+ Nevertheless the name seems to be standing for something other,
+ "Break My Gentoo" is not just a project to help you destroying your
+ fine Gentoo-installation. It could, but this is not the main purpose.
+ We want to provide unstable ebuilds, which have no chance to get into
+ portage. We want to give technology previews especially focused on
+ GNOME.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://rsync.gentoo.de/gentoo-de-ebuilds"
+ name = "gentoo-de">
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "http://redeeman.kaspersandberg.com/fluidportage/trunk"
+ name = "fluidportage">
+
+ <description>
+ Contains A LOT of *-cvs packages for many things, read the
+ readme file for more information.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "http://catmur.co.uk/svn/repos/gentoo/tree"
+ name = "ecatmur">
+
+ <link>
+ http://catmur.co.uk/gentoo/
+ </link>
+
+ <description>
+ ecatmurs overlay contains a variety of ebuilds: cool applications,
+ various fixes, version bumps, bleeding-edge code grabs.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://download.berlios.de/genkdesvn_ftp/stable"
+ name = "kde-stable">
+
+ <link>
+ http://genkdesvn.berlios.de/wiki/index.php/Main_Page
+ </link>
+
+ <description>
+ This wiki has been provided as a central place for information
+ regarding the kde-svn ebuilds.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://download.berlios.de/genkdesvn_ftp/playground"
+ name = "kde-experimental">
+
+ <link>
+ http://genkdesvn.berlios.de/wiki/index.php/Main_Page
+ </link>
+
+ <description>
+ This wiki has been provided as a central place for information
+ regarding the kde-svn ebuilds.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://gentoo.zugaina.org/zugaina-portage"
+ name = "zugaina">
+
+ <link>
+ http://gentoo.zugaina.org/
+ </link>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://gentoo.xwing.info/xwing-overlay"
+ name = "xwing">
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://rsync.ebuildexchange.org/ebuildexchange"
+ name = "ebuild-exchange">
+
+ <link>
+ http://www.ebuildexchange.org/
+ </link>
+
+ <description>
+ This site tries to provide a new medium of distributing Ebuilds
+ for the Gentoo Linux Distribution.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://erazor-zone.de/portage/"
+ name = "erazor">
+
+ <link>
+ http://wiki.erazor-zone.de/wiki:projects:linux:gentoo
+ </link>
+
+ <description>
+ erazor provides some ebuilds here. At this point, most of them
+ are newer that the ones in portage, but be warned, they have not
+ been tested much and there is no warranty at all.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "https://fantoo.ru/svn"
+ name = "fantoo">
+
+ <link>
+ http://fantoo.org/
+ </link>
+
+ <description>
+ Portage Overlay tree of new gentoo based distibution called
+ Fantoo Linux. Fantoo Linux aims to be bleeding edge and bugfixes
+ in gentoo upstream.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "http://svn.gnqs.org/svn/gentoo-webapps-overlay/experimental"
+ name = "webapps-experimental">
+
+ <link>
+ http://svn.gnqs.org/projects/gentoo-webapps-overlay/
+ </link>
+
+ <description>
+ This is the home of Gentoo's wider collection of ebuilds for
+ web-based applications. This is where we collect all the ebuilds
+ submitted to Bugzilla by our users, and make them available in
+ an easy-to-use overlay for wider testing.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://gunnarwrobel.de/wrobel-stable"
+ name = "wrobel-stable">
+
+ <link>
+ http://projects.gunnarwrobel.de/ebuilds/wiki/WikiStart
+ </link>
+
+ <description>
+ A collection of stable ebuilds from Gunnar Wrobel [wrobel@gentoo.org].
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://gunnarwrobel.de/wrobel-testing"
+ name = "wrobel-experimental">
+
+ <link>
+ http://projects.gunnarwrobel.de/ebuilds/wiki/WikiStart
+ </link>
+
+ <description>
+ A collection of experimental ebuilds from Gunnar Wrobel [wrobel@gentoo.org].
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://gunnarwrobel.de/kolab2"
+ name = "kolab2">
+
+ <link>
+ http://projects.gunnarwrobel.de/kolab/wiki
+ </link>
+
+ <description>
+ Project to allow running Kolab2 on Gentoo.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "http://svn.xgl-coffee.org/xgl-coffee/trunk/"
+ name = "portage-xgl">
+
+ <link>
+ http://gentoo-wiki.com/XGL#Checkout_An_Overlay
+ </link>
+
+ <description>
+ Xgl is an Xserver that uses OpenGL for its drawing
+ operations. Together with compiz, an opengl compositing and
+ window manager, it allows for some cool desktop effects.
+
+ This is the XGL overlay from Hanno Boeck (http://www.hboeck.de)
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://svn.netdomination.org/gentoo-voip"
+ name = "voip">
+
+ <link>
+ http://svn.netdomination.org/gentoo-voip
+ </link>
+
+ <description>
+ Voice over IP related ebuilds.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://kpex.no-ip.org/kpex-media"
+ name = "kpex-media">
+
+ <link>
+ https://kpex.no-ip.org/kpex-media.html
+ </link>
+
+ <description>
+ A series of unsupported multimedia ebuilds for Gentoo
+ portage that are either updated versions, live CVS/SVN
+ packages, or have updated features not included in the
+ official portage tree.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "https://svn.initng.org/portage/gentoo"
+ name = "initng">
+
+ <link>
+ http://www.initng.org
+ </link>
+
+ <description>
+ Initng is a full replacement of the old and in many ways
+ deprecated sysvinit tool. It is designed with speed in mind
+ because it does as much as possible asynchronously. In other
+ words: It will boot your unix-system much faster, and give you
+ more control and statistics over your system.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "tar"
+ src = "http://snigel.no-ip.com/~nxsty/linux/glibc-overlay.tar.bz2"
+ name = "nxsty-glibc"
+ category = "sys-libs">
+
+ <link>
+ http://forums.gentoo.org/viewtopic-t-435659-start-0-postdays-0-postorder-asc-highlight-nxsty+glibc.html
+ </link>
+
+ <description>
+ This overlay provides an enhanced glibc 2.4 ebuild.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "tar"
+ src = "http://snigel.no-ip.com/~nxsty/linux/binutils-overlay.tar.bz2"
+ name = "nxsty-binutils"
+ category = "sys-devel">
+
+ <link>
+ http://forums.gentoo.org/viewtopic-t-435659-start-0-postdays-0-postorder-asc-highlight-nxsty+glibc.html
+ </link>
+
+ <description>
+ This overlay provides a supplemental binutils ebuild to the nxsty-glibc overlay.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "http://svn.gnqs.org/svn/gentoo-nx-overlay/testing"
+ name = "nx">
+
+ <link>
+ http://svn.gnqs.org/projects/gentoo-nx-overlay/timeline
+ </link>
+
+ <description>
+ Overlay for the NX/FreeNX packages for Gentoo.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "svn://svn.tuxfamily.org/svnroot/ckpp/proaudio"
+ name = "pro-audio">
+
+ <link>
+ http://forums.gentoo.org/viewtopic-t-427211.html
+ </link>
+
+ <description>
+ Evermind's overlay with ebuilds for a lot of pro-audio production
+ software.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "http://svn.italpro.biz/catalyst-portage"
+ name = "catalystframework">
+
+ <link>
+ http://gentoo-wiki.com/HOWTO_Catalyst_Framework
+ </link>
+
+ <description>
+ This project tries to provide ebuilds for the great Catalyst MVC
+ Framework and many of the related Perl modules, plugins, etc.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "http://callisto.cs.kun.nl:81/svn/trees/vmware/"
+ name = "vmware">
+
+ <link>
+ http://bugs.gentoo.org/show_bug.cgi?id=122500
+ </link>
+
+ <description>
+ Testing ground for vmware-server and vmware-server-console
+ ebuilds until they can eventually be committed into portage.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "https://www.gentooexperimental.org/svn/java/migration/"
+ name = "java-migration">
+
+ <link>
+ https://projects.gentooexperimental.org/expj/wiki
+ </link>
+
+ <description>
+ The current focus of this overlay is on migration to a new build
+ system which will ultimately allow us to unmask Java 1.5, and be
+ able to support Java 1.6 when it is released.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "https://www.gentooexperimental.org/svn/java/gentoo-java-experimental/"
+ name = "java-experimental">
+
+ <link>
+ https://projects.gentooexperimental.org/expj/wiki
+ </link>
+
+ <description>
+ This is the experimental Portage tree for the Gentoo Java
+ Team. Half-baked ebuilds in-progress will reside it here during
+ development time, before they are included into the
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ src = "svn://juffo.org/musicbrainz-overlay"
+ name = "musicbrainz">
+
+ <link>
+ http://juffo.org/proj/musicbrainz-overlay/README.html
+ </link>
+
+ <description>
+ This is the Gentoo Portage overlay for the most recent
+ MusicBrainz packages.
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ name = "liferea_overlay"
+ src = "https://82.224.45.203/svn/liferea_overlay" >
+
+ <link>
+ http://liferea.sourceforge.net/
+ </link>
+
+ <description>
+ Updated ebuilds for newer versions of Liferea
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "svn"
+ name = "yao"
+ src = "svn://svn.berlios.de/yao/trunk" >
+
+ <link>
+ http://developer.berlios.de/projects/yao/
+ </link>
+
+ <description>
+ Yet Another Overlay aims to provide ebuilds for light
+ applications to allow Gentoo users to maintain a light desktop
+ without being restricted to the small amount of apps which don't
+ depend on GNOME or KDE libraries.
+ </description>
+
+ </overlay>
+
+</layman>
diff --git a/etc/layman.cfg b/etc/layman.cfg
new file mode 100644
index 0000000..1b74f96
--- /dev/null
+++ b/etc/layman.cfg
@@ -0,0 +1,164 @@
+[MAIN]
+#-----------------------------------------------------------
+# Defines the directory where overlays should be installed
+
+storage : @GENTOO_PORTAGE_EPREFIX@/var/lib/layman
+
+#-----------------------------------------------------------
+# Remote overlay lists will be stored here
+# layman will append _md5(url).xml to each filename
+
+cache : %(storage)s/cache
+
+#-----------------------------------------------------------
+# The list of locally installed overlays
+
+installed: %(storage)s/installed.xml
+
+# This has been renamed from the following
+# old name : value use it for updating to new one above
+# local_list: %(storage)s/overlays.xml
+# either rename the overlays.xml file to installed.xml
+# or edit the value above to the current name of your
+# installed overlay(s) file.
+
+#-----------------------------------------------------------
+# Path to the make.conf file that should be modified by
+# layman
+
+make_conf : %(storage)s/make.conf
+
+#-----------------------------------------------------------
+# URLs of the remote lists of overlays (one per line) or
+# local overlay definitions
+#
+#overlays : http://www.gentoo.org/proj/en/overlays/repositories.xml
+# http://dev.gentoo.org/~wrobel/layman/global-overlays.xml
+# http://mydomain.org/my-layman-list.xml
+# file:///var/lib/layman/my-list.xml
+
+overlays : http://www.gentoo.org/proj/en/overlays/repositories.xml
+
+#-----------------------------------------------------------
+# The directory to scan for xml overlay definition files to include
+# in the list of available overlays. They are automatically added to the
+# "overlays" parameter above. Use either method, but do not add the same
+# definition in both.
+#
+
+#overlay_defs : /etc/layman/overlays
+
+#-----------------------------------------------------------
+# Proxy support
+# If unset, layman will use the http_proxy environment variable.
+#
+#proxy : http://[user:pass@]www.my-proxy.org:3128
+
+#-----------------------------------------------------------
+# Strict checking of overlay definitions
+#
+# The nocheck option is a bit confusing, for historical reasons.
+# Hopefully this description eases the double negation trouble:
+#
+# nocheck : yes
+# - Accepts complete overlay entries without warnings
+# - Lists overlays of type foo (say Git) even with no foo installed
+#
+# nocheck : no
+# - Checks overlay entries for missing description or contact
+# information and issue warnings as needed
+# - Hides overlays of type foo (say Git) if foo not not installed
+#
+nocheck : yes
+
+#-----------------------------------------------------------
+# Umask settings
+#
+# layman should usually work with a umask of 0022. You should
+# only change this setting if you are absolutely certain that
+# you know what you are doing.
+#
+#umask : 0022
+
+#-----------------------------------------------------------
+# Command overrides
+#
+# You can have commands point to either a binary at a different
+# location, e.g.
+#
+# /home/you/local/bin/git
+#
+# or just the command, e.g.
+#
+# git
+#
+# to use PATH-based resolution of the binary to call.
+#
+#bzr_command : /usr/bin/bzr
+#cvs_command : /usr/bin/cvs
+#darcs_command : /usr/bin/darcs
+#git_command : /usr/bin/git
+#mercurial_command : /usr/bin/hg
+#rsync_command : /usr/bin/rsync
+#svn_command : /usr/bin/svn
+#tar_command : /bin/tar
+#g-common_command : /usr/bin/g-common
+
+
+#-----------------------------------------------------------
+# Command additional options
+#
+# These commnad options will be added to the above commands
+# when the overlay is added or synced.
+#
+# note: there are some options hardcoded in the backend
+# scripts already. All VCS types listed here are
+# for general consistency. Options may not be available
+# or recommended for all VCS types and/or add/sync operations.
+# Any options defined here are deemed:
+# "Use at your own risk"
+# and are not supported.
+#
+# eg:
+# svn_addopts : --config-option=config:miscellany:use-commit-times=yes
+#
+
+#bzr_addopts :
+#bzr_syncopts :
+#cvs_addopts :
+#cvs_syncopts :
+#darcs_addopts :
+#darcs_syncopts :
+#git_addopts :
+#git_syncopts :
+#mercurial_addopts :
+#mercurial_syncopts :
+#rsync_syncopts :
+#svn_addopts :
+#svn_syncopts :
+#g-common_generateopts :
+#g-common_syncopts :
+
+
+#-----------------------------------------------------------
+# Per VCS Post Sync/Add hooks
+#
+# The listed commands will be run after every add/sync operation.
+# All on one line If the repo path is needed, use a %cwd= in
+# where you want the path substituted in. It will be detected
+# and replaced with the correct path.
+#
+# eg: git_postsync : git-set-file-times
+# eg: git_postsync : git-set-file-times %cwd=
+# eg: git_postsync : git-set-file-times path=%cwd=
+#
+#bzr_postsync :
+#cvs_postsync :
+#darcs_postsync :
+#git_postsync :
+#mercurial_postsync :
+#rsync_postsync :
+#svn_postsync :
+#tar_postsync :
+#g-common_postsync :
+
diff --git a/layman/.svn.ignore b/layman/.svn.ignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/layman/.svn.ignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/layman/__init__.py b/layman/__init__.py
new file mode 100644
index 0000000..9eeff49
--- /dev/null
+++ b/layman/__init__.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""Layman is a complete library for the operation and maintainance
+on all gentoo repositories and overlays
+"""
+
+try:
+ from layman.api import LaymanAPI
+ from layman.config import BareConfig
+ from layman.output import Message
+except ImportError:
+ import sys
+ sys.stderr.write("!!! Layman API import failed.")
+
+
+
+class Layman(LaymanAPI):
+ """A complete high level interface capable of performing all
+ overlay repository actions."""
+
+ def __init__(self, stdout=None, stdin=None, stderr=None,
+ config=None, read_configfile=True, quiet=False, quietness=4,
+ verbose=False, nocolor=False, width=0
+ ):
+ """Input parameters are optional to override the defaults.
+ sets up our LaymanAPI with defaults or passed in values
+ and returns an instance of it"""
+ self.message = Message(out=stdout, err=stderr)
+ self.config = BareConfig(
+ output=self.message,
+ stdout=stdout,
+ stdin=stdin,
+ stderr=stderr,
+ config=config,
+ read_configfile=read_configfile,
+ quiet=quiet,
+ quietness=quietness,
+ verbose=verbose,
+ nocolor=nocolor,
+ width=width
+ )
+ LaymanAPI.__init__(self, self.config,
+ report_errors=True,
+ output=self.config['output']
+ )
+ return
diff --git a/layman/api.py b/layman/api.py
new file mode 100755
index 0000000..3005c3f
--- /dev/null
+++ b/layman/api.py
@@ -0,0 +1,556 @@
+#!python
+# -*- coding: utf-8 -*-
+#######################################################################
+# LAYMAN - A UTILITY TO SELECT AND UPDATE GENTOO OVERLAYS
+#######################################################################
+# Distributed under the terms of the GNU General Public License v2
+#
+# Copyright:
+# (c) 2010 Brian Dolbec
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Brian Dolbec <dol-sen@sourceforge.net>
+#
+
+from sys import stderr
+import os
+
+from layman.config import BareConfig
+
+from layman.dbbase import UnknownOverlayException, UnknownOverlayMessage
+from layman.db import DB, RemoteDB
+from layman.overlays.source import require_supported
+#from layman.utils import path, delete_empty_directory
+from layman.compatibility import encode, fileopen
+
+
+UNKNOWN_REPO_ID = "Repo ID '%s' " + \
+ "is not listed in the current available overlays list"
+
+
+class LaymanAPI(object):
+ """class to hold and run a layman instance for use by API consumer apps, guis, etc.
+ """
+ ## hell, even the current cli should probably be converted to use this one.
+ ## It is a near duplicate of the actions classes.
+
+ def __init__(self, config=None, report_errors=False, output=None):
+ """
+ @param configfile: optional config file to use instead of the default.
+ can be a BareConfig or ArgsParser config class.
+ default is BareConfig(output=output)
+ @param report_errors: optional bool to silence some error reporting to stdout
+ default is False
+ @param output: optional Message class instance created with your settings.
+ default is Message(module='layman') other params are defaults.
+ """
+
+ self.config = config if config is not None else BareConfig(output=output)
+
+ self.output = self.config['output']
+
+ self.report_errors = report_errors
+
+ # add our error recording function to output
+ self.output.error_callback = self._error
+
+ # get installed and available dbs
+ self._installed_db = None
+ self._installed_ids = None
+ self._available_db = None
+ self._available_ids = None
+ self._error_messages = []
+ self.sync_results = []
+
+
+ def is_repo(self, ovl):
+ """validates that the ovl given is a known repo id
+
+ @param ovl: repo id
+ @type ovl: str
+ @rtype boolean
+ """
+ return ovl in self.get_available()
+
+
+ def is_installed(self, ovl):
+ """checks that ovl is a known installed repo id
+
+ @param ovl: repo id
+ @type ovl: str
+ @rtype boolean
+ """
+ return ovl in self.get_installed()
+
+
+ @staticmethod
+ def _check_repo_type( repos, caller):
+ """internal function that validates the repos parameter,
+ converting a string to a list[string] if it is not already a list.
+ produces and error message if it is any other type
+ returns repos as list always"""
+ if isinstance(repos, basestring):
+ repos = [repos]
+ # else assume it is an iterable, if not it will error
+ return [encode(i) for i in repos]
+
+
+ def delete_repos(self, repos):
+ """delete the selected repo from the system
+
+ @type repos: list of strings or string
+ @param repos: ['repo-id1', ...] or 'repo-id'
+ @param output: method to handle output if desired
+ @rtype dict
+ """
+ repos = self._check_repo_type(repos, "delete_repo")
+ results = []
+ for ovl in repos:
+ if not self.is_installed(ovl):
+ self.output.error("Repository '"+ovl+"' was not installed")
+ results.append(False)
+ continue
+ success = False
+ try:
+ self._get_installed_db().delete(
+ self._get_installed_db().select(ovl))
+ except Exception, e:
+ self._error(
+ "Exception caught disabling repository '"+ovl+
+ "':\n"+str(e))
+ results.append(success)
+ self.get_installed(dbreload=True)
+ if False in results:
+ return False
+ return True
+
+
+ def add_repos(self, repos):
+ """installs the seleted repo id
+
+ @type repos: list of strings or string
+ @param repos: ['repo-id', ...] or 'repo-id'
+ @param output: method to handle output if desired
+ @rtype dict
+ """
+ repos = self._check_repo_type(repos, "add_repo")
+ results = []
+ for ovl in repos:
+ if self.is_installed(ovl):
+ self.output.error("Repository '"+ovl+"' was already installed")
+ results.append(False)
+ continue
+ if not self.is_repo(ovl):
+ self.output.error(UnknownOverlayMessage(ovl))
+ results.append(False)
+ continue
+ success = False
+ try:
+ success = self._get_installed_db().add(
+ self._get_remote_db().select(ovl))
+ except Exception, e:
+ self._error("Exception caught enabling repository '"+ovl+
+ "' : "+str(e))
+ results.append(success)
+ self.get_installed(dbreload=True)
+ if False in results:
+ return False
+ return True
+
+
+ def get_all_info(self, repos, local=False):
+ """retrieves the recorded information about the repo(s)
+ specified by repo-id
+
+ @type repos: list of strings or string
+ @param repos: ['repo-id1', ...] or 'repo-id'
+ @rtype list of tuples [(str, bool, bool),...]
+ @return: dictionary of dictionaries
+ {'ovl1':
+ {'name': str,
+ 'owner_name': str,
+ 'owner_email': str,
+ ' homepage': str,
+ 'description': str,
+ 'src_uris': list of str ['uri1',...]
+ 'src_type': str,
+ 'priority': int,
+ 'quality': str
+ 'status':,
+ 'official': bool,
+ 'supported': bool,
+ },
+ 'ovl2': {...}
+ }
+ """
+
+ repos = self._check_repo_type(repos, "get_info")
+ result = {}
+
+ if local:
+ db = self._get_installed_db()
+ else:
+ db = self._get_remote_db()
+
+ for ovl in repos:
+ if not self.is_repo(ovl):
+ self.output.error(UnknownOverlayMessage(ovl))
+ result[ovl] = ('', False, False)
+ continue
+ try:
+ overlay = db.select(ovl)
+ except UnknownOverlayException, error:
+ self._error(error)
+ result[ovl] = ('', False, False)
+ else:
+ result[ovl] = {
+ 'name': overlay.name,
+ 'owner_name': overlay.owner_name,
+ 'owner_email': overlay.owner_email,
+ 'homepage': overlay.homepage,
+ 'irc': overlay.irc,
+ 'description': overlay.description,
+ 'feeds': overlay.feeds,
+ 'sources': [(e.src, e.type, e.subpath) \
+ for e in overlay.sources],
+ #'src_uris': [e.src for e in overlay.sources],
+ 'src_uris': overlay.source_uris(),
+ 'src_types': overlay.source_types(),
+ #'src_types': [e.type for e in overlay.sources],
+ 'priority': overlay.priority,
+ 'quality': overlay.quality,
+ 'status': overlay.status,
+ 'official': overlay.is_official(),
+ 'supported': overlay.is_supported(),
+ }
+
+ return result
+
+
+ def get_info_str(self, repos, local=True, verbose=False, width=0):
+ """retrieves the string representation of the recorded information
+ about the repo(s) specified by ovl
+
+ @type repos: list of strings or string
+ @param repos: ['repo-id1', ...] or 'repo-id'
+ @rtype list of tuples [(str, bool, bool),...]
+ @return: dictionary {'repo-id': (info string, official, supported)}
+ """
+ repos = self._check_repo_type(repos, "get_info")
+ result = {}
+
+ if local:
+ db = self._get_installed_db()
+ else:
+ db = self._get_remote_db()
+
+ for ovl in repos:
+ if not self.is_repo(ovl):
+ self.output.error(UnknownOverlayMessage(ovl))
+ result[ovl] = ('', False, False)
+ continue
+ try:
+ overlay = db.select(ovl)
+ #print "overlay = ", ovl
+ #print "!!!", overlay
+ except UnknownOverlayException, error:
+ #print "ERRORS", str(error)
+ self._error(error)
+ result[ovl] = ('', False, False)
+ else:
+ # Is the overlay supported?
+ if verbose:
+ info = overlay.get_infostr()
+ else:
+ info = overlay.short_list(width)
+ official = overlay.is_official()
+ supported = overlay.is_supported()
+ result[ovl] = (info, official, supported)
+
+ return result
+
+ def get_info_list(self, local=True, verbose=False, width=0):
+ """retrieves the string representation of the recorded information
+ about the repo(s)
+
+ @param local: bool (defaults to True)
+ @param verbose: bool(defaults to False)
+ @param width: int (defaults to 0)
+ @rtype list of tuples [(str, bool, bool),...]
+ @return: list [(info string, official, supported),...]
+ """
+
+ if local:
+ return self._get_installed_db().list(verbose=verbose, width=width)
+ else:
+ return self._get_remote_db().list(verbose=verbose, width=width)
+
+
+ def sync(self, repos, output_results=True):
+ """syncs the specified repo(s) specified by repos
+
+ @type repos: list of strings or string
+ @param repos: ['repo-id1', ...] or 'repo-id'
+ @rtype bool or {'repo-id': bool,...}
+ """
+ self.output.debug("API.sync(); repos to sync = %s" % ', '.join(repos), 5)
+ fatals = []
+ warnings = []
+ success = []
+ repos = self._check_repo_type(repos, "sync")
+ db = self._get_installed_db()
+
+ self.output.debug("API.sync(); starting ovl loop", 5)
+ for ovl in repos:
+ self.output.debug("API.sync(); starting ovl = %s" %ovl, 5)
+ try:
+ #self.output.debug("API.sync(); selecting %s, db = %s" % (ovl, str(db)), 5)
+ odb = db.select(ovl)
+ self.output.debug("API.sync(); %s now selected" %ovl, 5)
+ except UnknownOverlayException, error:
+ #self.output.debug("API.sync(); UnknownOverlayException selecting %s" %ovl, 5)
+ #self._error(str(error))
+ fatals.append((ovl,
+ 'Failed to select overlay "' + ovl + '".\nError was: '
+ + str(error)))
+ self.output.debug("API.sync(); UnknownOverlayException "
+ "selecting %s. continuing to next ovl..." %ovl, 5)
+ continue
+
+ try:
+ self.output.debug("API.sync(); try: self._get_remote_db().select(ovl)", 5)
+ ordb = self._get_remote_db().select(ovl)
+ except UnknownOverlayException:
+ message = 'Overlay "%s" could not be found in the remote lists.\n' \
+ 'Please check if it has been renamed and re-add if necessary.' % ovl
+ warnings.append((ovl, message))
+ else:
+ self.output.debug("API.sync(); else: self._get_remote_db().select(ovl)", 5)
+ current_src = odb.sources[0].src
+ available_srcs = set(e.src for e in ordb.sources)
+ if ordb and odb and not current_src in available_srcs:
+ if len(available_srcs) == 1:
+ plural = ''
+ candidates = ' %s' % tuple(available_srcs)[0]
+ else:
+ plural = 's'
+ candidates = '\n'.join((' %d. %s' % (ovl + 1, v)) \
+ for ovl, v in enumerate(available_srcs))
+
+ warnings.append((ovl,
+ 'The source of the overlay "%(repo_name)s" seems to have changed.\n'
+ 'You currently sync from\n'
+ '\n'
+ ' %(current_src)s\n'
+ '\n'
+ 'while the remote lists report\n'
+ '\n'
+ '%(candidates)s\n'
+ '\n'
+ 'as correct location%(plural)s.\n'
+ 'Please consider removing and re-adding the overlay.' %
+ {
+ 'repo_name':ovl,
+ 'current_src':current_src,
+ 'candidates':candidates,
+ 'plural':plural,
+ }))
+
+ try:
+ self.output.debug("API.sync(); starting db.sync(ovl)", 5)
+ db.sync(ovl)
+ success.append((ovl,'Successfully synchronized overlay "' + ovl + '".'))
+ except Exception, error:
+ fatals.append((ovl,
+ 'Failed to sync overlay "' + ovl + '".\nError was: '
+ + str(error)))
+
+ if output_results:
+ if success:
+ message = '\nSucceeded:\n------\n'
+ for ovl, result in success:
+ message += result + '\n'
+ self.output.info(message, 3)
+
+ if warnings:
+ message = '\nWarnings:\n------\n'
+ for ovl, result in warnings:
+ message += result + '\n'
+ self.output.warn(message, 2)
+
+ if fatals:
+ message = '\nErrors:\n------\n'
+ for ovl, result in fatals:
+ message += result + '\n'
+ self.output.error(message)
+
+ self.sync_results = (success, warnings, fatals)
+
+ return fatals == []
+
+
+ def fetch_remote_list(self):
+ """Fetches the latest remote overlay list
+
+
+ >>> import os
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> cache = os.path.join(tmpdir, 'cache')
+ >>> from layman.config import OptionConfig
+ >>> opts = {'overlays' :
+ ... ['file://' + here + '/tests/testfiles/global-overlays.xml'],
+ ... 'cache' : cache,
+ ... 'nocheck' : 'yes',
+ ... 'proxy' : None,
+ ... 'svn_command':'/usr/bin/svn',
+ ... 'rsync_command':'/usr/bin/rsync'}
+ >>> config = OptionConfig(opts)
+ >>> config.set_option('quietness', 3)
+ >>> api = LaymanAPI(config)
+ >>> api.fetch_remote_list()
+ True
+ >>> api.get_errors()
+ []
+ >>> filename = api._get_remote_db().filepath(config['overlays'])+'.xml'
+ >>> b = fileopen(filename, 'r')
+ >>> b.readlines()[24]
+ ' A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].\\n'
+
+ >>> b.close()
+
+ >>> api.get_available()
+ [u'wrobel', u'wrobel-stable']
+ >>> all = api.get_all_info(u'wrobel')
+ >>> info = all['wrobel']
+ >>> info['status']
+ u'official'
+ >>> info['description']
+ u'Test'
+ >>> info['sources']
+ [(u'https://overlays.gentoo.org/svn/dev/wrobel', 'Subversion', None)]
+
+ #{u'wrobel': {'status': u'official',
+ #'owner_name': None, 'description': u'Test',
+ #'src_uris': <generator object source_uris at 0x167c3c0>,
+ #'owner_email': u'nobody@gentoo.org',
+ #'quality': u'experimental', 'name': u'wrobel', 'supported': True,
+ #'src_types': <generator object source_types at 0x167c370>,
+ #'official': True,
+ #'priority': 10, 'feeds': [], 'irc': None, 'homepage': None}}
+
+ >>> os.unlink(filename)
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ """
+
+ try:
+ dbreload, succeeded = self._get_remote_db().cache()
+ self.output.debug(
+ 'LaymanAPI.fetch_remote_list(); cache updated = %s'
+ % str(dbreload),8)
+ except Exception, error:
+ self.output.error('Failed to fetch overlay list!\n Original Error was: '
+ + str(error))
+ return False
+ self.get_available(dbreload)
+ return succeeded
+
+
+ def get_available(self, dbreload=False):
+ """returns the list of available overlays"""
+ self.output.debug('LaymanAPI.get_available() dbreload = %s'
+ % str(dbreload), 8)
+ if self._available_ids is None or dbreload:
+ self._available_ids = self._get_remote_db(dbreload).list_ids()
+ return self._available_ids[:] or ['None']
+
+
+ def get_installed(self, dbreload=False):
+ """returns the list of installed overlays"""
+ if self._installed_ids is None or dbreload:
+ self._installed_ids = self._get_installed_db(dbreload).list_ids()
+ return self._installed_ids[:]
+
+
+ def _get_installed_db(self, dbreload=False):
+ """returns the list of installed overlays"""
+ if not self._installed_db or dbreload:
+ self._installed_db = DB(self.config)
+ self.output.debug("API._get_installed_db; len(installed) = %s, %s"
+ %(len(self._installed_db.list_ids()), self._installed_db.list_ids()), 5)
+ return self._installed_db
+
+
+ def _get_remote_db(self, dbreload=False):
+ """returns the list of installed overlays"""
+ if self._available_db is None or dbreload:
+ self._available_db = RemoteDB(self.config)
+ return self._available_db
+
+
+ def reload(self):
+ """reloads the installed and remote db's to the data on disk"""
+ result = self.get_available(dbreload=True)
+ result = self.get_installed(dbreload=True)
+
+
+ def _error(self, message):
+ """outputs the error to the pre-determined output
+ defaults to stderr. This method may be removed, is here for now
+ due to code taken from the packagekit backend.
+ """
+ self._error_messages.append(message)
+ self.output.debug("API._error(); _error_messages = %s" % str(self._error_messages), 4)
+ if self.report_errors:
+ print >>self.config['stderr'], message
+
+
+ def get_errors(self):
+ """returns any warning or fatal messages that occurred during
+ an operation and resets it back to None
+
+ @rtype: list
+ @return: list of error strings
+ """
+ self.output.debug("API.get_errors(); _error_messages = %s" % str(self._error_messages), 4)
+ if len(self._error_messages):
+ messages = self._error_messages[:]
+ self._error_messages = []
+ return messages
+ return []
+
+ def supported_types(self):
+ """returns a dictionary of all repository types,
+ with boolean values"""
+ cmds = [x for x in self.config.keys() if '_command' in x]
+ supported = {}
+ for cmd in cmds:
+ type_key = cmd.split('_')[0]
+ supported[type_key] = require_supported(
+ [(self.config[cmd],type_key, '')], self.output.warn)
+ return supported
+
+
+def create_fd():
+ """creates file descriptor pairs an opens them ready for
+ use in place of stdin, stdout, stderr.
+ """
+ fd_r, fd_w = os.pipe()
+ write = os.fdopen(fd_w, 'w')
+ rread = os.fdopen(fd_r, 'r')
+ return (read, write, fd_r, fd_w)
+
+
+if __name__ == '__main__':
+ import doctest, sys
+
+ # Ignore warnings here. We are just testing
+ from warnings import filterwarnings, resetwarnings
+ filterwarnings('ignore')
+
+ doctest.testmod(sys.modules[__name__])
+
+ resetwarnings()
diff --git a/layman/argsparser.py b/layman/argsparser.py
new file mode 100644
index 0000000..e1703ac
--- /dev/null
+++ b/layman/argsparser.py
@@ -0,0 +1,362 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN CONFIGURATION
+#################################################################################
+# File: argsparser.py
+#
+# Handles layman command line interface configuration
+#
+# Copyright:
+# (c) 2005 - 2009 Gunnar Wrobel
+# (c) 2009 Sebastian Pipping
+# (c) 2010 - 2011 Brian Dolbec
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Sebastian Pipping <sebastian@pipping.org>
+# Brian Dolbec <brian.dolbec@gmail.com>
+#
+'''Defines the configuration options and provides parsing functionality.'''
+
+
+__version__ = "$Id: config.py 286 2007-01-09 17:48:23Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import sys
+
+from optparse import OptionParser, OptionGroup
+
+from layman.config import BareConfig
+from layman.constants import OFF
+from layman.version import VERSION
+
+
+_USAGE = """
+ layman (-a|-d|-s|-i) (OVERLAY|ALL)
+ layman -f [-o URL]
+ layman (-l|-L|-S)"""
+
+
+class ArgsParser(BareConfig):
+ '''Handles the configuration and option parser.'''
+
+ def __init__(self, args=None, stdout=None, stdin=None, stderr=None):
+ '''
+ Creates and describes all possible polymeraZe options and creates
+ a Message object.
+
+ >>> import os.path
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> sys.argv.append('--config')
+ >>> sys.argv.append(here + '/../etc/layman.cfg')
+ >>> sys.argv.append('--overlay_defs')
+ >>> sys.argv.append('')
+ >>> a = ArgsParser()
+ >>> a['overlays']
+ '\\nhttp://www.gentoo.org/proj/en/overlays/repositories.xml'
+ >>> sorted(a.keys())
+ ['bzr_addopts', 'bzr_command', 'bzr_postsync', 'bzr_syncopts', 'cache', 'config', 'configdir', 'cvs_addopts', 'cvs_command', 'cvs_postsync', 'cvs_syncopts', 'darcs_addopts', 'darcs_command', 'darcs_postsync', 'darcs_syncopts', 'g-common_command', 'g-common_generateopts', 'g-common_postsync', 'g-common_syncopts', 'git_addopts', 'git_command', 'git_postsync', 'git_syncopts', 'installed', 'local_list', 'make_conf', 'mercurial_addopts', 'mercurial_command', 'mercurial_postsync', 'mercurial_syncopts', 'nocheck', 'overlay_defs', 'overlays', 'proxy', 'quietness', 'rsync_command', 'rsync_postsync', 'rsync_syncopts', 'storage', 'svn_addopts', 'svn_command', 'svn_postsync', 'svn_syncopts', 't/f_options', 'tar_command', 'tar_postsync', 'umask', 'width']
+ '''
+
+ BareConfig.__init__(self, stdout=stdout, stderr=stderr, stdin=stdin)
+ if args == None:
+ args = sys.argv
+
+ # get a couple BareConfig items
+ self.defaults = self.get_defaults()
+ self.output = self.get_option('output')
+
+ self.parser = OptionParser(
+ usage = _USAGE,
+ version = VERSION)
+
+ #-----------------------------------------------------------------
+ # Main Options
+
+ group = OptionGroup(self.parser,
+ '<Actions>')
+
+ group.add_option('-a',
+ '--add',
+ action = 'append',
+ help = 'Add the given overlay from the cached remote li'
+ 'st to your locally installed overlays.. Specify "ALL" '
+ 'to add all overlays from the remote list.')
+
+ group.add_option('-d',
+ '--delete',
+ action = 'append',
+ help = 'Remove the given overlay from your locally inst'
+ 'alled overlays. Specify "ALL" to remove all overlays')
+
+ group.add_option('-s',
+ '--sync',
+ action = 'append',
+ help = 'Update the specified overlay. Use "ALL" as para'
+ 'meter to synchronize all overlays')
+
+ group.add_option('-i',
+ '--info',
+ action = 'append',
+ help = 'Display information about the specified overlay'
+ '.')
+
+ group.add_option('-S',
+ '--sync-all',
+ action = 'store_true',
+ help = 'Update all overlays.')
+
+ group.add_option('-L',
+ '--list',
+ action = 'store_true',
+ help = 'List the contents of the remote list.')
+
+ group.add_option('-l',
+ '--list-local',
+ action = 'store_true',
+ help = 'List the locally installed overlays.')
+
+ group.add_option('-f',
+ '--fetch',
+ action = 'store_true',
+ help = 'Fetch a remote list of overlays. This option is'
+ ' deprecated. The fetch operation will be performed by '
+ 'default when you run sync, sync-all, or list.')
+
+ group.add_option('-n',
+ '--nofetch',
+ action = 'store_true',
+ help = 'Do not fetch a remote list of overlays.')
+
+ group.add_option('-p',
+ '--priority',
+ action = 'store',
+ help = 'Use this with the --add switch to set the prior'
+ 'ity of the added overlay. This will influence the sort'
+ 'ing order of the overlays in the PORTDIR_OVERLAY varia'
+ 'ble.')
+
+ self.parser.add_option_group(group)
+
+ #-----------------------------------------------------------------
+ # Additional Options
+
+ group = OptionGroup(self.parser,
+ '<Path options>')
+
+ group.add_option('-c',
+ '--config',
+ action = 'store',
+ help = 'Path to the config file [default: ' \
+ + self.defaults['config'] + '].')
+
+ group.add_option('-O',
+ '--overlay_defs',
+ action = 'store',
+ help = 'Path to aditional overlay.xml files [default: '\
+ + self.defaults['overlay_defs'] + '].')
+
+ group.add_option('-o',
+ '--overlays',
+ action = 'append',
+ help = 'The list of overlays [default: ' \
+ + self.defaults['overlays'] + '].')
+
+ self.parser.add_option_group(group)
+
+ #-----------------------------------------------------------------
+ # Output Options
+
+ group = OptionGroup(self.parser,
+ '<Output options>')
+
+ group.add_option('-v',
+ '--verbose',
+ action = 'store_true',
+ help = 'Increase the amount of output and describe the '
+ 'overlays.')
+
+ group.add_option('-q',
+ '--quiet',
+ action = 'store_true',
+ help = 'Yield no output. Please be careful with this op'
+ 'tion: If the processes spawned by layman when adding o'
+ 'r synchronizing overlays require any input layman will'
+ ' hang without telling you why. This might happen for e'
+ 'xample if your overlay resides in subversion and the S'
+ 'SL certificate of the server needs acceptance.')
+
+ group.add_option('-N',
+ '--nocolor',
+ action = 'store_true',
+ help = 'Remove color codes from the layman output.')
+
+ group.add_option('-Q',
+ '--quietness',
+ action = 'store',
+ type = 'int',
+ default = '4',
+ help = 'Set the level of output (0-4). Default: 4. Once'
+ ' you set this below 2 the same warning as given for --'
+ 'quiet applies! ')
+
+ group.add_option('-W',
+ '--width',
+ action = 'store',
+ type = 'int',
+ default = '0',
+ help = 'Sets the screen width. This setting is usually '
+ 'not required as layman is capable of detecting the '
+ 'available number of columns automatically.')
+
+ group.add_option('-k',
+ '--nocheck',
+ action = 'store_true',
+ help = 'Do not check overlay definitions and do not i'
+ 'ssue a warning if description or contact information'
+ ' are missing.')
+
+ group.add_option('--debug-level',
+ action = 'store',
+ type = 'int',
+ help = 'A value between 0 and 10. 0 means no debugging '
+ 'messages will be selected, 10 selects all debugging me'
+ 'ssages. Default is "4".')
+
+
+ self.parser.add_option_group(group)
+
+ #-----------------------------------------------------------------
+ # Debug Options
+
+ #self.output.cli_opts(self.parser)
+
+ # Parse the command line first since we need to get the config
+ # file option.
+ if len(args) == 1:
+ self.output.notice('Usage:%s' % _USAGE)
+ sys.exit(0)
+
+ (self.options, remain_args) = self.parser.parse_args(args)
+ # remain_args starts with something like "bin/layman" ...
+ if len(remain_args) > 1:
+ self.parser.error("ArgsParser(): Unhandled parameters: %s"
+ % ', '.join(('"%s"' % e) for e in remain_args[1:]))
+
+ # handle debugging
+ #self.output.cli_handle(self.options)
+
+ if (self.options.__dict__.has_key('debug_level') and
+ self.options.__dict__['debug_level']):
+ dbglvl = int(self.options.__dict__['debug_level'])
+ if dbglvl < 0:
+ dbglvl = 0
+ if dbglvl > 10:
+ dbglvl = 10
+ self.output.set_debug_level(dbglvl)
+
+ if self.options.__dict__['nocolor']:
+ self.output.set_colorize(OFF)
+
+ # Set only alternate config settings from the options
+ if self.options.__dict__['config'] is not None:
+ self.defaults['config'] = self.options.__dict__['config']
+ self.output.debug('ARGSPARSER: Got config file at ' + \
+ self.defaults['config'], 8)
+ else: # fix the config path
+ self.defaults['config'] = self.defaults['config'] \
+ % {'configdir': self.defaults['configdir']}
+ if self.options.__dict__['overlay_defs'] is not None:
+ self.defaults['overlay_defs'] = self.options.__dict__['overlay_defs']
+ self.output.debug('ARGSPARSER: Got overlay_defs location at ' + \
+ self.defaults['overlay_defs'], 8)
+
+ # Now parse the config file
+ self.output.debug('ARGSPARSER: Reading config file at ' + \
+ self.defaults['config'], 8)
+ self.read_config(self.defaults)
+
+ # handle quietness
+ if self.options.__dict__['quiet']:
+ self.set_option('quiet', True)
+ elif self.options.__dict__['quietness']:
+ self.set_option('quietness', self.options.__dict__['quietness'])
+
+
+ def __getitem__(self, key):
+
+ if key == 'overlays':
+ overlays = ''
+ if (key in self.options.__dict__.keys()
+ and not self.options.__dict__[key] is None):
+ overlays = '\n'.join(self.options.__dict__[key])
+ if self.config.has_option('MAIN', 'overlays'):
+ overlays += '\n' + self.config.get('MAIN', 'overlays')
+ if len(overlays):
+ return overlays
+
+ self.output.debug('ARGSPARSER: Retrieving options option: %s' % key, 9)
+
+ if (key in self.options.__dict__.keys()
+ and not self.options.__dict__[key] is None):
+ return self.options.__dict__[key]
+
+ self.output.debug('ARGSPARSER: Retrieving config option: %s' % key, 9)
+
+ if self.config.has_option('MAIN', key):
+ if key in self._defaults['t/f_options']:
+ return self.t_f_check(self.config.get('MAIN', key))
+ return self.config.get('MAIN', key)
+
+ self.output.debug('ARGSPARSER: Retrieving option: %s' % key, 9)
+
+ if key in self._options.keys():
+ return self._options[key]
+
+ if key in self.defaults.keys():
+ return self.defaults[key]
+
+ self.output.debug('ARGSPARSER: Retrieving option failed. returning None', 9)
+
+ return None
+
+
+ def keys(self):
+ '''Special handler for the configuration keys.'''
+
+ self.output.debug('ARGSPARSER: Retrieving keys', 9)
+
+ keys = [i for i in self.options.__dict__.keys()
+ if not self.options.__dict__[i] is None]
+
+ self.output.debug('ARGSPARSER: Retrieving keys 2', 9)
+
+ keys += [name for name, _ in self.config.items('MAIN')
+ if not name in keys]
+
+ self.output.debug('ARGSPARSER: Retrieving keys 3', 9)
+
+ keys += [i for i in self.defaults.keys()
+ if not i in keys]
+
+ self.output.debug('ARGSPARSER: Returning keys', 9)
+
+ return keys
+
+
+#===============================================================================
+#
+# Testing
+#
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod(sys.modules[__name__])
diff --git a/layman/cli.py b/layman/cli.py
new file mode 100644
index 0000000..95ec858
--- /dev/null
+++ b/layman/cli.py
@@ -0,0 +1,342 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN ACTIONS
+#################################################################################
+# File: cli.py
+#
+# Handles layman actions via the command line interface.
+#
+# Copyright:
+# (c) 2010 - 2011
+# Gunnar Wrobel
+# Brian Dolbec
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Brian Dolbec <brian.dolbec@gmail.com
+#
+''' Provides the command line actions that can be performed by layman.'''
+
+__version__ = "$Id: cli.py 2011-01-15 23:52 PST Brian Dolbec$"
+
+
+import os, sys
+
+from layman.api import LaymanAPI
+from layman.utils import (decode_selection, encoder, get_encoding,
+ pad, terminal_width)
+from layman.constants import (NOT_OFFICIAL_MSG, NOT_SUPPORTED_MSG,
+ FAILURE, SUCCEED)
+
+
+
+class ListPrinter(object):
+ def __init__(self, config):
+ self.config = config
+ self.output = self.config['output']
+ if not self.config['width']:
+ self.width = terminal_width()-1
+ else:
+ self.width = self.config['width']
+ self.srclen = self.width - 43
+ self._encoding_ = get_encoding(self.output)
+ if config['verbose']:
+ self.my_lister = self.short_list # self.long_list
+ else:
+ self.my_lister = self.short_list
+
+ def print_shortdict(self, info, complain):
+ #print "ListPrinter.print_shortdict()",info, "\n\n"
+ overlays = sorted(info)
+ #print "ids =======>", overlays, "\n"
+ for ovl in overlays:
+ overlay = info[ovl]
+ #print "overlay =", overlay
+ summary, supported, official = overlay
+ self.print_overlay(summary, supported, official, complain)
+
+ def print_shortlist(self, info, complain):
+ for summary, supported, official in info:
+ self.print_overlay(summary, supported, official, complain)
+
+
+ def print_fulldict(self, info, complain):
+ ids = sorted(info)
+ #print "ids =======>", ids, "\n"
+ for ovl in ids:
+ overlay = info[ovl]
+ #print overlay
+ self.print_overlay(self.my_lister(overlay),
+ overlay['supported'],
+ overlay['official'],
+ complain)
+
+
+ def print_overlay(self, summary, supported, official, complain):
+ # Is the overlay supported?
+ if supported:
+ # Is this an official overlay?
+ if official:
+ self.output.info(summary, 1)
+ # Unofficial overlays will only be listed if we are not
+ # checking or listing verbose
+ elif complain:
+ # Give a reason why this is marked yellow if it is a verbose
+ # listing
+ if self.config['verbose']:
+ self.output.warn(NOT_OFFICIAL_MSG, 1)
+ self.output.warn(summary, 1)
+ # Unsupported overlays will only be listed if we are not checking
+ # or listing verbose
+ elif complain:
+ # Give a reason why this is marked red if it is a verbose
+ # listing
+ prev_state = self.output.block_callback
+ self.output.block_callback = True
+ if self.config['verbose']:
+ self.output.error(NOT_SUPPORTED_MSG)
+ self.output.error(summary)
+ self.output.block_callback = prev_state
+
+
+ def short_list(self, overlay):
+ '''
+ >>> print short_list(overlay)
+ wrobel [Subversion] (https://o.g.o/svn/dev/wrobel )
+ '''
+ name = pad(overlay['name'], 25)
+
+ if len(set(e for e in overlay['src_types'])) == 1:
+ _type = overlay['src_types'][0]
+ else:
+ _type = '%s/..' % overlay['src_type'][0]
+ mtype = ' [' + pad(_type, 10) + ']'
+
+ source = ', '.join(overlay['src_uris'])
+
+ if len(source) > self.srclen:
+ source = source.replace("overlays.gentoo.org", "o.g.o")
+ source = ' (' + pad(source, self.srclen) + ')'
+
+ return encoder(name + mtype + source, self._encoding_)
+
+
+class Main(object):
+ '''Performs the actions the user selected.
+ '''
+
+ def __init__(self, config):
+ self.config = config
+ #print "config.keys()", config.keys()
+ self.output = config['output']
+ self.api = LaymanAPI(config,
+ report_errors=False,
+ output=config.output)
+ # Given in order of precedence
+ self.actions = [('fetch', 'Fetch'),
+ ('add', 'Add'),
+ ('sync', 'Sync'),
+ ('info', 'Info'),
+ ('sync_all', 'Sync'),
+ ('delete', 'Delete'),
+ ('list', 'ListRemote'),
+ ('list_local', 'ListLocal'),]
+
+ def __call__(self):
+ self.output.debug("CLI.__call__(): self.config.keys()"
+ " %s" % str(self.config.keys()), 6)
+ # blank newline -- no " *"
+ self.output.notice('')
+ # Make fetching the overlay list a default action
+ if not 'nofetch' in self.config.keys():
+ # Actions that implicitely call the fetch operation before
+ fetch_actions = ['sync', 'sync_all', 'list']
+ for i in fetch_actions:
+ if i in self.config.keys():
+ # Implicitely call fetch, break loop
+ self.Fetch()
+ break
+
+ result = 0
+
+ # Set the umask
+ umask = self.config['umask']
+ try:
+ new_umask = int(umask, 8)
+ old_umask = os.umask(new_umask)
+ except Exception, error:
+ self.output.die('Failed setting to umask "' + umask +
+ '"!\nError was: ' + str(error))
+
+ action_errors = []
+ results = []
+ act=set([x[0] for x in self.actions])
+ k=set([x for x in self.config.keys()])
+ a=act.intersection(k)
+ self.output.debug('Actions = %s' % str(a), 4)
+ for action in self.actions:
+
+ self.output.debug('Checking for action %s' % action[0], 4)
+
+ if action[0] in self.config.keys():
+ result += getattr(self, action[1])()
+ _errors = self.api.get_errors()
+ if _errors:
+ self.output.debug("CLI: found errors performing "
+ "action %s" % action[0], 2)
+ action_errors.append((action[0], _errors))
+ result = -1 # So it cannot remain 0, i.e. success
+ results.append(result)
+ self.output.debug('Completed action %s, result %s'
+ % (action[0], result==0), 4)
+
+ self.output.debug('Checking for action errors', 4)
+ if action_errors:
+ for action, _errors in action_errors:
+ self.output.warn("CLI: Errors occured processing action"
+ " %s" % action)
+ for _error in _errors:
+ self.output.error(_error)
+ self.output.notice("")
+
+ # Reset umask
+ os.umask(old_umask)
+
+ if -1 in results:
+ sys.exit(FAILURE)
+ else:
+ sys.exit(SUCCEED)
+
+
+ def Fetch(self):
+ ''' Fetches the overlay listing.
+ '''
+ self.output.info("Fetching remote list,...", 2)
+ result = self.api.fetch_remote_list()
+ if result:
+ self.output.info('Fetch Ok', 2)
+ # blank newline -- no " *"
+ self.output.notice('')
+ return result
+
+
+ def Add(self):
+ ''' Adds the selected overlays.
+ '''
+ self.output.info("Adding overlay,...", 2)
+ selection = decode_selection(self.config['add'])
+ if 'ALL' in selection:
+ selection = self.api.get_available()
+ self.output.debug('Adding selected overlays', 6)
+ result = self.api.add_repos(selection)
+ if result:
+ self.output.info('Successfully added overlay(s) '+\
+ ', '.join(selection) +'.', 2)
+ # blank newline -- no " *"
+ self.output.notice('')
+ return result
+
+
+
+ def Sync(self):
+ ''' Syncs the selected overlays.
+ '''
+ self.output.info("Syncing selected overlays,...", 2)
+ # Note api.sync() defaults to printing results
+ selection = decode_selection(self.config['sync'])
+ if self.config['sync_all'] or 'ALL' in selection:
+ selection = self.api.get_installed()
+ self.output.debug('Updating selected overlays', 6)
+ result = self.api.sync(selection)
+ # blank newline -- no " *"
+ self.output.notice('')
+ return result
+
+
+ def Delete(self):
+ ''' Deletes the selected overlays.
+ '''
+ self.output.info('Deleting selected overlays,...', 2)
+ selection = decode_selection(self.config['delete'])
+ if 'ALL' in selection:
+ selection = self.api.get_installed()
+ result = self.api.delete_repos(selection)
+ if result:
+ self.output.info('Successfully deleted overlay(s) ' +\
+ ', '.join(selection) + '.', 2)
+ # blank newline -- no " *"
+ self.output.notice('')
+ return result
+
+
+ def Info(self):
+ ''' Print information about the specified overlays.
+ '''
+ selection = decode_selection(self.config['info'])
+ if 'ALL' in selection:
+ selection = self.api.get_available()
+
+ list_printer = ListPrinter(self.config)
+ _complain = self.config['nocheck'] or self.config['verbose']
+
+ info = self.api.get_info_str(selection, local=False,
+ verbose=True, width=list_printer.width)
+ list_printer.print_shortdict(info, complain=_complain)
+ # blank newline -- no " *"
+ self.output.notice('')
+ return info != {}
+
+
+ def ListRemote(self):
+ ''' Lists the available overlays.
+ '''
+
+ self.output.debug('Printing remote overlays.', 6)
+ list_printer = ListPrinter(self.config)
+
+ _complain = self.config['nocheck'] or self.config['verbose']
+ info = self.api.get_info_list(local=False,
+ verbose=self.config['verbose'], width=list_printer.width)
+ list_printer.print_shortlist(info, complain=_complain)
+ # blank newline -- no " *"
+ self.output.notice('')
+
+ return info != {}
+
+
+ def ListLocal(self):
+ ''' Lists the local overlays.
+ '''
+ #print "ListLocal()"
+ self.output.debug('Printing installed overlays.', 6)
+ list_printer = ListPrinter(self.config)
+
+ #
+ # fast way
+ info = self.api.get_info_list(verbose=self.config['verbose'],
+ width=list_printer.width)
+ #self.output.debug('CLI: ListLocal() info = %s' % len(info), 4)
+ #self.output.debug('\n'.join([ str(x) for x in info]), 4)
+ list_printer.print_shortlist(info, complain=True)
+ #
+ # slow way
+ #info = self.api.get_all_info(self.api.get_installed(), local=True)
+ #list_printer.print_fulldict(info, complain=_complain)
+
+ # blank newline -- no " *"
+ self.output.notice('')
+ return info != {}
+
+
+if __name__ == '__main__':
+ import doctest
+
+ # Ignore warnings here. We are just testing
+ from warnings import filterwarnings, resetwarnings
+ filterwarnings('ignore')
+
+ doctest.testmod(sys.modules[__name__])
+
+ resetwarnings()
diff --git a/layman/compatibility.py b/layman/compatibility.py
new file mode 100644
index 0000000..b71a8af
--- /dev/null
+++ b/layman/compatibility.py
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" Copyright 2005 - 2008 Gunnar Wrobel
+ 2011 - Brian Dolbec
+ Distributed under the terms of the GNU General Public License v2
+"""
+
+import sys, types
+
+
+def encode(text, enc="UTF-8"):
+ """py2, py3 compatibility function"""
+ if hasattr(text, 'decode'):
+ try:
+ return text.decode(enc)
+ except UnicodeEncodeError:
+ return unicode(text)
+ return str(text)
+
+
+def fileopen(path, mode='r', enc="UTF-8"):
+ """py2, py3 compatibility function"""
+ try:
+ f = open(path, mode, encoding=enc)
+ except TypeError:
+ f = open(path, mode)
+ return f
+
diff --git a/layman/config.py b/layman/config.py
new file mode 100644
index 0000000..2af4069
--- /dev/null
+++ b/layman/config.py
@@ -0,0 +1,305 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+ LAYMAN CONFIGURATION
+
+ File: config.py
+
+ Handles Basic layman configuration
+
+ Copyright:
+ (c) 2005 - 2009 Gunnar Wrobel
+ (c) 2009 Sebastian Pipping
+ (c) 2010 - 2011 Brian Dolbec
+ Distributed under the terms of the GNU General Public License v2
+
+ Author(s):
+ Gunnar Wrobel <wrobel@gentoo.org>
+ Sebastian Pipping <sebastian@pipping.org>
+ Brian Dolbec <brian.dolbec@gmail.com>
+"""
+
+'''Defines the configuration options.'''
+
+__version__ = "0.2"
+
+
+
+import sys
+import os
+import ConfigParser
+
+from layman.output import Message
+
+
+def read_layman_config(config=None, defaults=None):
+ """reads the config file defined in defaults['config']
+ and updates the config
+
+ @param config: ConfigParser.ConfigParser(self.defaults) instance
+ @param defaults: dict
+ @modifies config['MAIN']['overlays']
+ """
+ config.read(defaults['config'])
+ if config.get('MAIN', 'overlay_defs'):
+ try:
+ filelist = os.listdir(config.get('MAIN', 'overlay_defs'))
+ except OSError:
+ return
+ filelist = [f for f in filelist if f.endswith('.xml')]
+ overlays = set(config.get('MAIN', 'overlays').split('\n'))
+ for _file in filelist:
+ path = os.path.join(config.get('MAIN', 'overlay_defs'), _file)
+ if os.path.isfile(path):
+ overlays.update(["file://" + path])
+ config.set('MAIN', 'overlays', '\n'.join(overlays))
+
+
+# establish the eprefix, initially set so eprefixify can
+# set it on install
+EPREFIX = "@GENTOO_PORTAGE_EPREFIX@"
+
+# check and set it if it wasn't
+if "GENTOO_PORTAGE_EPREFIX" in EPREFIX:
+ EPREFIX = ''
+
+
+class BareConfig(object):
+ '''Handles the configuration only.'''
+
+ def __init__(self, output=None, stdout=None, stdin=None, stderr=None,
+ config=None, read_configfile=False, quiet=False, quietness=4,
+ verbose=False, nocolor=False, width=0
+ ):
+ '''
+ Creates a bare config with defaults and a few output options.
+
+ >>> a = BareConfig()
+ >>> a['overlays']
+ 'http://www.gentoo.org/proj/en/overlays/repositories.xml'
+ >>> sorted(a.keys())
+ ['bzr_addopts', 'bzr_command', 'bzr_postsync', 'bzr_syncopts', 'cache', 'config', 'configdir', 'cvs_addopts', 'cvs_command', 'cvs_postsync', 'cvs_syncopts', 'darcs_addopts', 'darcs_command', 'darcs_postsync', 'darcs_syncopts', 'g-common_command', 'g-common_generateopts', 'g-common_postsync', 'g-common_syncopts', 'git_addopts', 'git_command', 'git_postsync', 'git_syncopts', 'installed', 'local_list', 'make_conf', 'mercurial_addopts', 'mercurial_command', 'mercurial_postsync', 'mercurial_syncopts', 'nocheck', 'nocolor', 'output', 'overlay_defs', 'overlays', 'proxy', 'quiet', 'quietness', 'rsync_command', 'rsync_postsync', 'rsync_syncopts', 'stderr', 'stdin', 'stdout', 'storage', 'svn_addopts', 'svn_command', 'svn_postsync', 'svn_syncopts', 't/f_options', 'tar_command', 'tar_postsync', 'umask', 'verbose', 'width']
+ >>> a.get_option('nocheck')
+ True
+ '''
+
+ self._defaults = {
+ 'configdir': EPREFIX + '/etc/layman',
+ 'config' : '%(configdir)s/layman.cfg',
+ 'storage' : EPREFIX + '/var/lib/layman',
+ 'cache' : '%(storage)s/cache',
+ 'local_list': '%(storage)s/overlays.xml',
+ 'installed': '%(storage)s/installed.xml',
+ 'make_conf' : '%(storage)s/make.conf',
+ 'nocheck' : 'yes',
+ 'proxy' : '',
+ 'umask' : '0022',
+ 'overlays' :
+ 'http://www.gentoo.org/proj/en/overlays/repositories.xml',
+ 'overlay_defs': '%(configdir)s/overlays',
+ 'bzr_command': EPREFIX +'/usr/bin/bzr',
+ 'cvs_command': EPREFIX +'/usr/bin/cvs',
+ 'darcs_command': EPREFIX +'/usr/bin/darcs',
+ 'git_command': EPREFIX +'/usr/bin/git',
+ 'g-common_command': EPREFIX +'/usr/bin/g-common',
+ 'mercurial_command': EPREFIX +'/usr/bin/hg',
+ 'rsync_command': EPREFIX +'/usr/bin/rsync',
+ 'svn_command': EPREFIX +'/usr/bin/svn',
+ 'tar_command': EPREFIX +'/bin/tar',
+ 't/f_options': ['nocheck'],
+ 'bzr_addopts' : '',
+ 'bzr_syncopts' : '',
+ 'cvs_addopts' : '',
+ 'cvs_syncopts' : '',
+ 'darcs_addopts' : '',
+ 'darcs_syncopts' : '',
+ 'git_addopts' : '',
+ 'git_syncopts' : '',
+ 'mercurial_addopts' : '',
+ 'mercurial_syncopts' : '',
+ 'rsync_syncopts' : '',
+ 'svn_addopts' : '',
+ 'svn_syncopts' : '',
+ 'g-common_generateopts' : '',
+ 'g-common_syncopts' : '',
+ 'bzr_postsync' : '',
+ 'cvs_postsync' : '',
+ 'darcs_postsync' : '',
+ 'git_postsync' : '',
+ 'mercurial_postsync' : '',
+ 'rsync_postsync' : '',
+ 'svn_postsync' : '',
+ 'tar_postsync' : '',
+ 'g-common_postsync' : '',
+ }
+ self._options = {
+ 'config': config if config else self._defaults['config'],
+ 'stdout': stdout if stdout else sys.stdout,
+ 'stdin': stdin if stdin else sys.stdin,
+ 'stderr': stderr if stderr else sys.stderr,
+ 'output': output if output else Message(),
+ 'quietness': quietness,
+ 'nocolor': nocolor,
+ 'width': width,
+ 'verbose': verbose,
+ 'quiet': quiet,
+ }
+ self._set_quietness(quietness)
+ self.config = None
+ if read_configfile:
+ self.read_config(self.get_defaults())
+
+
+ def read_config(self, defaults):
+ self.config = ConfigParser.ConfigParser(defaults)
+ self.config.add_section('MAIN')
+ read_layman_config(self.config, defaults)
+
+
+ def keys(self):
+ '''Special handler for the configuration keys.
+ '''
+ self._options['output'].debug(
+ 'Retrieving %s options' % self.__class__.__name__, 9)
+ keys = [i for i in self._options]
+ self._options['output'].debug(
+ 'Retrieving %s defaults' % self.__class__.__name__, 9)
+ keys += [i for i in self._defaults
+ if not i in keys]
+ self._options['output'].debug(
+ 'Retrieving %s done...' % self.__class__.__name__, 9)
+ return keys
+
+
+ def get_defaults(self):
+ """returns our defaults dictionary"""
+ _defaults = self._defaults.copy()
+ _defaults['config'] = self._options['config']
+ return _defaults
+
+
+ def get_option(self, key):
+ """returns the current option's value"""
+ return self._get_(key)
+
+
+ def set_option(self, option, value):
+ """Sets an option to the value """
+ self._options[option] = value
+ # handle quietness
+ if option == 'quiet':
+ if self._options['quiet']:
+ self._set_quietness(1)
+ self._options['quietness'] = 1
+ else:
+ self._set_quietness(4)
+ if option == 'quietness':
+ self._set_quietness(value)
+
+ def _set_quietness(self, value):
+ self._options['output'].set_info_level(value)
+ self._options['output'].set_warn_level(value)
+
+ def __getitem__(self, key):
+ return self._get_(key)
+
+ def _get_(self, key):
+ self._options['output'].debug(
+ 'Retrieving %s option: %s' % (self.__class__.__name__, key), 9)
+ if key == 'overlays':
+ overlays = ''
+ if (key in self._options
+ and not self._options[key] is None):
+ overlays = '\n'.join(self._options[key])
+ if self.config and self.config.has_option('MAIN', 'overlays'):
+ overlays += '\n' + self.config.get('MAIN', 'overlays')
+ if overlays:
+ return overlays
+ if (key in self._options
+ and not self._options[key] is None):
+ return self._options[key]
+ if self.config and self.config.has_option('MAIN', key):
+ if key in self._defaults['t/f_options']:
+ return self.t_f_check(self.config.get('MAIN', key))
+ return self.config.get('MAIN', key)
+ self._options['output'].debug('Retrieving BareConfig default', 9)
+ if key in self._defaults['t/f_options']:
+ return self.t_f_check(self._defaults[key])
+ if key in self._defaults:
+ if '%(storage)s' in self._defaults[key]:
+ return self._defaults[key] %{'storage': self._defaults['storage']}
+ return self._defaults[key]
+ return None
+
+ @staticmethod
+ def t_f_check(option):
+ """evaluates the option and returns
+ True or False
+ """
+ return option.lower() in ['yes', 'true', 'y', 't']
+
+
+class OptionConfig(BareConfig):
+ """This subclasses BareCongig adding functions to make overriding
+ or resetting defaults and/or setting options much easier
+ by using dictionaries.
+ """
+
+ def __init__(self, options=None, defaults=None):
+ """
+ @param options: dictionary of {'option': value, ...}
+ @rtype OptionConfig class instance.
+
+ >>> options = {"overlays": ["http://www.gentoo-overlays.org/repositories.xml"]}
+ >>> new_defaults = {"configdir": "/etc/test-dir"}
+ >>> a = OptionConfig(options=options, defaults=new_defaults)
+ >>> a['overlays']
+ 'http://www.gentoo-overlays.org/repositories.xml'
+ >>> a["configdir"]
+ '/etc/test-dir'
+ >>> sorted(a.keys())
+ ['bzr_addopts', 'bzr_command', 'bzr_postsync', 'bzr_syncopts', 'cache', 'config', 'configdir', 'cvs_addopts', 'cvs_command', 'cvs_postsync', 'cvs_syncopts', 'darcs_addopts', 'darcs_command', 'darcs_postsync', 'darcs_syncopts', 'g-common_command', 'g-common_generateopts', 'g-common_postsync', 'g-common_syncopts', 'git_addopts', 'git_command', 'git_postsync', 'git_syncopts', 'installed', 'local_list', 'make_conf', 'mercurial_addopts', 'mercurial_command', 'mercurial_postsync', 'mercurial_syncopts', 'nocheck', 'nocolor', 'output', 'overlay_defs', 'overlays', 'proxy', 'quiet', 'quietness', 'rsync_command', 'rsync_postsync', 'rsync_syncopts', 'stderr', 'stdin', 'stdout', 'storage', 'svn_addopts', 'svn_command', 'svn_postsync', 'svn_syncopts', 't/f_options', 'tar_command', 'tar_postsync', 'umask', 'verbose', 'width']
+ """
+ BareConfig.__init__(self)
+
+ self.update_defaults(defaults)
+
+ self.update(options)
+
+ return
+
+ def update(self, options):
+ """update the options with new values passed in via options
+
+ @param options
+ """
+ if options is not None:
+ keys = sorted(options)
+ if 'quiet' in keys:
+ self.set_option('quiet', options['quiet'])
+ options.pop('quiet')
+ if 'quietness' in keys and not options['quiet']:
+ self._set_quietness(options['quietness'])
+ options.pop('quietness')
+ self._options.update(options)
+ return
+
+ def update_defaults(self, new_defaults):
+ """update the options with new values passed in via options
+
+ @param options
+ """
+ if new_defaults is not None:
+ self._defaults.update(new_defaults)
+ return
+
+#===============================================================================
+#
+# Testing
+#
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod(sys.modules[__name__])
diff --git a/layman/constants.py b/layman/constants.py
new file mode 100644
index 0000000..6f53de3
--- /dev/null
+++ b/layman/constants.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN CONSTANTS
+#################################################################################
+# File: constants.py
+#
+# Handles layman actions via the command line interface.
+#
+# Copyright:
+# (c) 2010 - 2011
+# Gunnar Wrobel
+# Brian Dolbec
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Brian Dolbec <brian.dolbec@gmail.com
+#
+''' Provides the command line actions that can be performed by layman.'''
+
+__version__ = "$Id: constants.py 2011-01-16 23:52 PST Brian Dolbec$"
+
+
+
+
+#################################################################################
+##
+## Color codes (taken from portage)
+##
+#################################################################################
+
+esc_seq = '\x1b['
+
+codes = {}
+codes['reset'] = esc_seq + '39;49;00m'
+codes['red'] = esc_seq + '31;01m'
+codes['green'] = esc_seq + '32;01m'
+codes['yellow'] = esc_seq + '33;01m'
+codes['turquoise'] = esc_seq + '36;01m'
+
+
+NOT_OFFICIAL_MSG = '*** This is not an official gentoo overlay ***\n'
+NOT_SUPPORTED_MSG = '*** You are lacking the necessary tools' +\
+ ' to install this overlay ***\n'
+
+
+OFF = 0
+WARN_LEVEL = 4
+INFO_LEVEL = 4
+DEBUG_LEVEL = 4
+DEBUG_VERBOSITY = 2
+
+FAILURE = 1
+SUCCEED = 0
diff --git a/layman/db.py b/layman/db.py
new file mode 100644
index 0000000..cca257b
--- /dev/null
+++ b/layman/db.py
@@ -0,0 +1,482 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN OVERLAY DB
+#################################################################################
+# File: db.py
+#
+# Access to the db of overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+'''Handles different storage files.'''
+
+from __future__ import with_statement
+
+__version__ = "$Id: db.py 309 2007-04-09 16:23:38Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import os, os.path
+import urllib2
+import hashlib
+
+from layman.utils import path, delete_empty_directory, encoder
+from layman.dbbase import DbBase
+from layman.makeconf import MakeConf
+from layman.version import VERSION
+from layman.compatibility import fileopen
+
+#from layman.debug import OUT
+
+#===============================================================================
+#
+# Class DB
+#
+#-------------------------------------------------------------------------------
+
+class DB(DbBase):
+ ''' Handle the list of installed overlays.'''
+
+ def __init__(self, config):
+
+ self.config = config
+ self.output = config['output']
+
+ self.path = config['installed']
+ self.output.debug("DB.__init__(): config['installed'] = %s" % self.path, 3)
+
+ if config['nocheck']:
+ ignore = 2
+ else:
+ ignore = 1
+
+ # check and handle the name change
+ #if not os.access(self.path, os.F_OK):
+ # self.rename_db()
+
+ DbBase.__init__(self,
+ config,
+ paths=[config['installed'], ],
+ ignore=ignore,
+ )
+
+ self.output.debug('DB handler initiated', 6)
+
+
+ def rename_db(self):
+ """small upgarde function to handle the name change
+ for the installed xml file"""
+ if os.access(self.config['local_list'], os.F_OK):
+ self.output.info("Automatic db rename, old name was: %s"
+ % self.config['local_list'],2)
+ try:
+ os.rename(self.config['local_list'], self.path)
+ self.output.info("Automatic db rename, new installed db "
+ "name is: %s" %self.path, 2)
+ self.output.notice('')
+ return
+ except OSError, err:
+ self.output.error("Automatic db rename failed:\n%s" %str(err))
+ else:
+ self.output.info("Automatic db rename, failed access to: %s"
+ % self.config['local_list'],2)
+ self.output.die("Please check that /etc/layman.cfg is up"
+ " to date\nThen try running layman again.\n"
+ "You may need to rename the old 'local_list' config setting"
+ " to\nthe new 'installed' config setting's filename.\n")
+
+
+ # overrider
+ def _broken_catalog_hint(self):
+ return ''
+
+ def add(self, overlay):
+ '''
+ Add an overlay to the local list of overlays.
+
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> write = os.path.join(tmpdir, 'installed.xml')
+ >>> write2 = os.path.join(tmpdir, 'make.conf')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> from layman.config import OptionConfig
+ >>> myoptions = {'installed' :
+ ... here + '/tests/testfiles/global-overlays.xml',
+ ... 'make_conf' : write2,
+ ... 'nocheck' : 'yes',
+ ... 'storage' : tmpdir}
+
+ >>> config = OptionConfig(myoptions)
+ >>> config.set_option('quietness', 3)
+ >>> a = DB(config)
+ >>> config.set_option('installed', write)
+ >>> b = DB(config)
+ >>> config['output'].set_colorize(False)
+
+ >>> m = MakeConf(config, b.overlays)
+ >>> m.path = write2
+ >>> success = m.write()
+ >>> success
+ True
+
+ # Commented out since it needs network access:
+
+ # >>> b.add(a.select('wrobel-stable')) #doctest: +ELLIPSIS
+ # * Running command "/usr/bin/rsync -rlptDvz --progress --delete --delete-after --timeout=180 --exclude="distfiles/*" --exclude="local/*" --exclude="packages/*" "rsync://gunnarwrobel.de/wrobel-stable/*" "/tmp/file.../wrobel-stable""...
+ # >>> c = DbBase([write, ], dict())
+ # >>> c.overlays.keys()
+ # [u'wrobel-stable']
+
+ # >>> m = MakeConf(config, b.overlays)
+ # >>> [i.name for i in m.overlays] #doctest: +ELLIPSIS
+ # [u'wrobel-stable']
+
+ # >>> os.unlink(write)
+ >>> os.unlink(write2)
+
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ '''
+
+ if overlay.name not in self.overlays.keys():
+ result = overlay.add(self.config['storage'])
+ if result == 0:
+ if 'priority' in self.config.keys():
+ overlay.set_priority(self.config['priority'])
+ self.overlays[overlay.name] = overlay
+ self.write(self.path)
+ if self.config['make_conf']:
+ make_conf = MakeConf(self.config, self.overlays)
+ make_ok = make_conf.add(overlay)
+ return make_ok
+ return True
+ else:
+ mdir = path([self.config['storage'], overlay.name])
+ delete_empty_directory(mdir, self.output)
+ if os.path.exists(mdir):
+ self.output.error('Adding repository "%s" failed!'
+ ' Possible remains of the operation have NOT'
+ ' been removed and may be left at "%s".'
+ ' Please remove them manually if required.' \
+ % (overlay.name, mdir))
+ return False
+ else:
+ self.output.error(
+ 'Adding repository "%s" failed!' % overlay.name)
+ return False
+ else:
+ self.output.error('Repository "' + overlay.name +
+ '" already in the local (installed) list!')
+ return False
+
+
+ def delete(self, overlay):
+ '''
+ Add an overlay to the local list of overlays.
+
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> write = os.path.join(tmpdir, 'installed.xml')
+ >>> write2 = os.path.join(tmpdir, 'make.conf')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> from layman.config import OptionConfig
+ >>> myoptions = {'installed' :
+ ... here + '/tests/testfiles/global-overlays.xml',
+ ... 'make_conf' : write2,
+ ... 'nocheck' : 'yes',
+ ... 'storage' : tmpdir}
+
+ >>> config = OptionConfig(myoptions)
+ >>> config.set_option('quietness', 3)
+ >>> a = DB(config)
+ >>> config.set_option('installed', write)
+ >>> b = DB(config)
+ >>> config['output'].set_colorize(False)
+
+ >>> m = MakeConf(config, b.overlays)
+ >>> m.path = here + '/tests/testfiles/make.conf'
+ >>> m.read()
+ True
+
+ >>> m.path = write2
+ >>> m.write()
+ True
+
+ # >>> b.add(a.select('wrobel-stable')) #doctest: +ELLIPSIS
+ # * Running command "/usr/bin/rsync -rlptDvz --progress --delete --delete-after --timeout=180 --exclude="distfiles/*" --exclude="local/*" --exclude="packages/*" "rsync://gunnarwrobel.de/wrobel-stable/*" "/tmp/file.../wrobel-stable""...
+ # >>> b.add(a.select('wrobel')) #doctest: +ELLIPSIS
+ # * Running command "/usr/bin/svn co "https://overlays.gentoo.org/svn/dev/wrobel/" "/tmp/file.../wrobel""...
+ # >>> c = DbBase([write, ], dict())
+ # >>> c.overlays.keys()
+ # [u'wrobel', u'wrobel-stable']
+
+ # >>> b.delete(b.select('wrobel'))
+ # >>> c = DbBase([write, ], dict())
+ # >>> c.overlays.keys()
+ # [u'wrobel-stable']
+
+ # >>> m = MakeConf(config, b.overlays)
+ # >>> [i.name for i in m.overlays] #doctest: +ELLIPSIS
+ # [u'wrobel-stable']
+
+ # >>> os.unlink(write)
+ >>> os.unlink(write2)
+
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ '''
+
+ if overlay.name in self.overlays.keys():
+ make_conf = MakeConf(self.config, self.overlays)
+ overlay.delete(self.config['storage'])
+ del self.overlays[overlay.name]
+ self.write(self.path)
+ make_conf.delete(overlay)
+ else:
+ self.output.error('No local overlay named "' + overlay.name + '"!')
+ return False
+ return True
+
+ def sync(self, overlay_name):
+ '''Synchronize the given overlay.'''
+
+ overlay = self.select(overlay_name)
+ result = overlay.sync(self.config['storage'])
+ if result:
+ raise Exception('Syncing overlay "' + overlay_name +
+ '" returned status ' + str(result) + '!' +
+ '\ndb.sync()')
+
+#===============================================================================
+#
+# Class RemoteDB
+#
+#-------------------------------------------------------------------------------
+
+class RemoteDB(DbBase):
+ '''Handles fetching the remote overlay list.'''
+
+ def __init__(self, config, ignore_init_read_errors=False):
+
+ self.config = config
+ self.output = config['output']
+
+ self.proxies = {}
+
+ if config['proxy']:
+ self.proxies['http'] = config['proxy']
+ elif os.getenv('http_proxy'):
+ self.proxies['http'] = os.getenv('http_proxy')
+
+ if self.proxies:
+ proxy_handler = urllib2.ProxyHandler(self.proxies)
+ opener = urllib2.build_opener(proxy_handler)
+ urllib2.install_opener(opener)
+
+ self.urls = [i.strip() for i in config['overlays'].split('\n') if len(i)]
+
+ paths = [self.filepath(i) + '.xml' for i in self.urls]
+
+ if config['nocheck']:
+ ignore = 2
+ else:
+ ignore = 0
+
+ #quiet = int(config['quietness']) < 3
+
+ DbBase.__init__(self, config, paths=paths, ignore=ignore,
+ ignore_init_read_errors=ignore_init_read_errors)
+
+ # overrider
+ def _broken_catalog_hint(self):
+ return 'Try running "sudo layman -f" to re-fetch that file'
+
+ def cache(self):
+ '''
+ Copy the remote overlay list to the local cache.
+
+ >>> import tempfile
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> cache = os.path.join(tmpdir, 'cache')
+ >>> myoptions = {'overlays' :
+ ... ['file://' + here + '/tests/testfiles/global-overlays.xml'],
+ ... 'cache' : cache,
+ ... 'nocheck' : 'yes',
+ ... 'proxy' : None}
+ >>> from layman.config import OptionConfig
+ >>> config = OptionConfig(myoptions)
+ >>> config.set_option('quietness', 3)
+ >>> a = RemoteDB(config)
+ >>> a.cache()
+ (True, True)
+ >>> b = fileopen(a.filepath(config['overlays'])+'.xml')
+ >>> b.readlines()[24]
+ ' A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].\\n'
+
+ >>> b.close()
+ >>> os.unlink(a.filepath(config['overlays'])+'.xml')
+
+ >>> a.overlays.keys()
+ [u'wrobel', u'wrobel-stable']
+
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ '''
+ has_updates = False
+ # succeeded reset when a failure is detected
+ succeeded = True
+ for url in self.urls:
+
+ filepath = self.filepath(url)
+ mpath = filepath + '.xml'
+ tpath = filepath + '.timestamp'
+
+ # check when the cache was last updated
+ # and don't re-fetch it unless it has changed
+ request = urllib2.Request(url)
+ opener = urllib2.build_opener()
+ opener.addheaders = [('User-Agent', 'Layman-' + VERSION)]
+
+ if os.path.exists(tpath):
+ with fileopen(tpath,'r') as previous:
+ timestamp = previous.read()
+ request.add_header('If-Modified-Since', timestamp)
+
+ if not self.check_path([mpath]):
+ continue
+
+ try:
+ connection = opener.open(request)
+ # py2, py3 compatibility, since only py2 returns keys as lower()
+ headers = dict((x.lower(), x) for x in connection.headers.keys())
+ if 'last-modified' in headers:
+ timestamp = connection.headers[headers['last-modified']]
+ elif 'date' in headers:
+ timestamp = connection.headers[headers['date']]
+ else:
+ timestamp = None
+ except urllib2.HTTPError, e:
+ if e.code == 304:
+ self.output.info('Remote list already up to date: %s'
+ % url, 4)
+ self.output.info('Last-modified: %s' % timestamp, 4)
+ else:
+ self.output.error('RemoteDB.cache(); HTTPError was:\n'
+ 'url: %s\n%s'
+ % (url, str(e)))
+ succeeded = False
+ continue
+ except IOError, error:
+ self.output.error('RemoteDB.cache(); Failed to update the '
+ 'overlay list from: %s\nIOError was:%s\n'
+ % (url, str(error)))
+ succeeded = False
+ continue
+ else:
+ if url.startswith('file://'):
+ quieter = 1
+ else:
+ quieter = 0
+ self.output.info('Fetching new list... %s' % url, 4 + quieter)
+ if timestamp is not None:
+ self.output.info('Last-modified: %s' % timestamp, 4 + quieter)
+ # Fetch the remote list
+ olist = connection.read()
+
+ # Create our storage directory if it is missing
+ if not os.path.exists(os.path.dirname(mpath)):
+ try:
+ os.makedirs(os.path.dirname(mpath))
+ except OSError, error:
+ raise OSError('Failed to create layman storage direct'
+ + 'ory ' + os.path.dirname(mpath) + '\n'
+ + 'Error was:' + str(error))
+
+ # Before we overwrite the old cache, check that the downloaded
+ # file is intact and can be parsed
+ try:
+ self.read(olist, origin=url)
+ except Exception, error:
+ raise IOError('Failed to parse the overlays list fetched fr'
+ 'om ' + url + '\nThis means that the download'
+ 'ed file is somehow corrupt or there was a pr'
+ 'oblem with the webserver. Check the content '
+ 'of the file. Error was:\n' + str(error))
+
+ # Ok, now we can overwrite the old cache
+ try:
+ out_file = fileopen(mpath, 'w')
+ if hasattr(olist, 'decode'):
+ olist = olist.decode("UTF-8")
+ out_file.write(olist)
+ out_file.close()
+
+ if timestamp is not None:
+ out_file = fileopen(tpath, 'w')
+ out_file.write(str(timestamp))
+ out_file.close()
+
+ has_updates = True
+
+ except Exception, error:
+ raise IOError('Failed to temporarily cache overlays list in'
+ ' ' + mpath + '\nError was:\n' + str(error))
+ self.output.debug("RemoteDB.cache() returning: has_updates, succeeded"
+ " %s, %s" % (str(has_updates), str(succeeded)), 4)
+ return has_updates, succeeded
+
+
+ def filepath(self, url):
+ '''Return a unique file name for the url.'''
+
+ base = self.config['cache']
+
+ self.output.debug('Generating cache path.', 6)
+ url_encoded = encoder(url, "UTF-8")
+
+ return base + '_' + hashlib.md5(url_encoded).hexdigest()
+
+
+ def check_path(self, paths, hint=True):
+ '''Check for sufficient privileges'''
+ self.output.debug('RemoteDB.check_path; paths = ' + str(paths), 8)
+ is_ok = True
+ for path in paths:
+ if os.path.exists(path) and not os.access(path, os.W_OK):
+ if hint:
+ self.output.warn(
+ 'You do not have permission to update the cache (%s).'
+ % path)
+ import getpass
+ if getpass.getuser() != 'root':
+ self.output.warn('Hint: You are not root.\n')
+ is_ok = False
+ return is_ok
+
+#===============================================================================
+#
+# Testing
+#
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ import doctest, sys
+
+ # Ignore warnings here. We are just testing
+ from warnings import filterwarnings, resetwarnings
+ filterwarnings('ignore')
+
+ doctest.testmod(sys.modules[__name__])
+
+ resetwarnings()
diff --git a/layman/dbbase.py b/layman/dbbase.py
new file mode 100644
index 0000000..461038b
--- /dev/null
+++ b/layman/dbbase.py
@@ -0,0 +1,329 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN OVERLAY HANDLER
+#################################################################################
+# File: overlay.py
+#
+# Access to an xml list of overlays
+#
+# Copyright:
+# (c) 2005 - 2009 Gunnar Wrobel
+# (c) 2009 Sebastian Pipping
+# (c) 2009 Christian Groschupp
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Sebastian Pipping <sebastian@pipping.org>
+# Christian Groschupp <christian@groschupp.org>
+#
+'''Main handler for overlays.'''
+
+__version__ = "$Id: overlay.py 273 2006-12-30 15:54:50Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import sys, os, os.path
+import xml
+import xml.etree.ElementTree as ET # Python 2.5
+
+#from layman.debug import OUT
+from layman.utils import indent
+from layman.compatibility import fileopen
+from layman.overlays.overlay import Overlay
+
+#===============================================================================
+#
+# Class UnknownOverlayException
+#
+#-------------------------------------------------------------------------------
+def UnknownOverlayMessage(ovl):
+ return 'Exception: Overlay "%s" does not exist.' % ovl
+
+class UnknownOverlayException(Exception):
+ def __init__(self, repo_name):
+ self.repo_name = repo_name
+
+ def __str__(self):
+ return UnknownOverlayMessage(self.repo_name)
+
+#===============================================================================
+#
+# Class BrokenOverlayCatalog
+#
+#-------------------------------------------------------------------------------
+
+class BrokenOverlayCatalog(ValueError):
+ def __init__(self, origin, expat_error, hint=None):
+ if hint == None:
+ hint = ''
+ else:
+ hint = '\nHint: %s' % hint
+
+ super(BrokenOverlayCatalog, self).__init__(
+ 'XML parsing failed for "%(origin)s" (line %(line)d, column %(column)d)%(hint)s' % \
+ {'line':expat_error.lineno, 'column':expat_error.offset + 1, 'origin':origin, 'hint':hint})
+
+
+#===============================================================================
+#
+# Class DbBase
+#
+#-------------------------------------------------------------------------------
+
+class DbBase(object):
+ ''' Handle a list of overlays.'''
+
+ def __init__(self, config, paths=None, ignore = 0,
+ ignore_init_read_errors=False
+ ):
+
+ self.config = config
+ self.paths = paths
+ self.ignore = ignore
+ self.output = config['output']
+ self.ignore_init_read_errors = ignore_init_read_errors
+
+ self.overlays = {}
+
+ self.output.debug('Initializing overlay list handler', 8)
+
+ for path in self.paths:
+ if not os.path.exists(path):
+ continue
+
+ self.read_file(path)
+
+
+ def __eq__(self, other):
+ for key in set(self.overlays.keys() + other.overlays.keys()):
+ if self.overlays[key] != other.overlays[key]:
+ return False
+ return True
+
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+ def read_file(self, path):
+ '''Read the overlay definition file.'''
+
+ try:
+ df = fileopen(path, 'r')
+ document = df.read()
+
+ except Exception, error:
+ if not self.ignore_init_read_errors:
+ self.output.error('Failed to read the overlay list at ("'
+ + path + '")')
+ raise error
+
+ self.read(document, origin=path)
+
+
+ def _broken_catalog_hint(self):
+ this_function_name = sys._getframe().f_code.co_name
+ raise NotImplementedError('Method "%s.%s" not implemented' % \
+ (self.__class__.__name__, this_function_name))
+
+
+ def read(self, text, origin):
+ '''
+ Read an xml list of overlays (adding to and potentially overwriting existing entries)
+
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> from layman.output import Message
+ >>> output = Message()
+ >>> config = {'output': output, 'svn_command': '/usr/bin/svn', 'rsync_command':'/usr/bin/rsync'}
+ >>> a = DbBase(config, [here + '/tests/testfiles/global-overlays.xml', ])
+ >>> a.overlays.keys()
+ [u'wrobel', u'wrobel-stable']
+
+ >>> list(a.overlays['wrobel-stable'].source_uris())
+ [u'rsync://gunnarwrobel.de/wrobel-stable']
+ '''
+ try:
+ document = ET.fromstring(text)
+ except xml.parsers.expat.ExpatError, error:
+ raise BrokenOverlayCatalog(origin, error, self._broken_catalog_hint())
+
+ overlays = document.findall('overlay') + \
+ document.findall('repo')
+
+ for overlay in overlays:
+ self.output.debug('Parsing overlay: %s' % overlay, 9)
+ ovl = Overlay(config=self.config, xml=overlay,
+ ignore=self.ignore)
+ self.overlays[ovl.name] = ovl
+ return
+
+
+ def add_new(self, xml=None, origin=None, from_dict=None):
+ '''Reads xml text and dictionary definitions and adds
+ them to the db.
+ '''
+ if xml is not None:
+ self.read(xml, origin)
+ if from_dict is not None:
+ self.output.info("DbBase: add_new() from_dict")
+ if isinstance(from_dict, dict):
+ from_dict = [from_dict]
+ self._add_from_dict(from_dict)
+
+ return
+
+
+ def _add_from_dict(self, overlays=None):
+ """Add a new overlay from a list of dictionary values
+ """
+ self.output.info("DbBase: add_from_dict()")
+ for overlay in overlays:
+ self.output.debug('Parsing overlay entry', 8)
+ ovl = Overlay(self.config, ovl_dict=overlay,
+ ignore=self.ignore)
+ self.overlays[ovl.name] = ovl
+ return
+
+
+ def write(self, path):
+ '''
+ Write the list of overlays to a file.
+
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> write = os.path.join(tmpdir, 'test.xml')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> from layman.config import BareConfig
+ >>> config = BareConfig()
+ >>> a = DbBase(config, [here + '/tests/testfiles/global-overlays.xml', ])
+ >>> from layman.output import Message
+ >>> b = DbBase({"output": Message() }, [write,])
+ >>> b.overlays['wrobel-stable'] = a.overlays['wrobel-stable']
+ >>> b.write(write)
+ >>> c = DbBase({"output": Message() }, [write,])
+ >>> c.overlays.keys()
+ [u'wrobel-stable']
+
+ >>> os.unlink(write)
+ >>> os.rmdir(tmpdir)
+ '''
+
+ tree = ET.Element('repositories', version="1.0")
+ tree[:] = [e.to_xml() for e in self.overlays.values()]
+ indent(tree)
+ tree = ET.ElementTree(tree)
+ try:
+ f = fileopen(path, 'w')
+ f.write("""\
+<?xml version="1.0" encoding="UTF-8"?>
+""")
+ tree.write(f, encoding='utf-8')
+ f.close()
+ except Exception, error:
+ raise Exception('Failed to write to local overlays file: '
+ + path + '\nError was:\n' + str(error))
+
+ def select(self, overlay):
+ '''
+ Select an overlay from the list.
+
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> from layman.output import Message
+ >>> output = Message()
+ >>> config = {'output': output, 'svn_command': '/usr/bin/svn', 'rsync_command':'/usr/bin/rsync'}
+ >>> a = DbBase(config, [here + '/tests/testfiles/global-overlays.xml', ])
+ >>> list(a.select('wrobel-stable').source_uris())
+ [u'rsync://gunnarwrobel.de/wrobel-stable']
+ '''
+ self.output.debug("DbBase.select(), overlay = %s" % overlay, 5)
+ if not overlay in self.overlays.keys():
+ self.output.debug("DbBase.select(), unknown overlay = %s"
+ % overlay, 4)
+ self.output.debug("DbBase.select(), known overlays = %s"
+ % ', '.join(self.overlays.keys()), 4)
+ raise UnknownOverlayException(overlay)
+ return self.overlays[overlay]
+
+ def list(self, repos=None, verbose = False, width = 0):
+ '''
+ List all overlays.
+
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> from layman.output import Message
+ >>> output = Message()
+ >>> config = {'output': output, 'svn_command': '/usr/bin/svn', 'rsync_command':'/usr/bin/rsync'}
+ >>> a = DbBase(config, [here + '/tests/testfiles/global-overlays.xml', ])
+ >>> for i in a.list(verbose=True):
+ ... print i[0]
+ wrobel
+ ~~~~~~
+ Source : https://overlays.gentoo.org/svn/dev/wrobel
+ Contact : nobody@gentoo.org
+ Type : Subversion; Priority: 10
+ Quality : experimental
+ <BLANKLINE>
+ Description:
+ Test
+ <BLANKLINE>
+ wrobel-stable
+ ~~~~~~~~~~~~~
+ Source : rsync://gunnarwrobel.de/wrobel-stable
+ Contact : nobody@gentoo.org
+ Type : Rsync; Priority: 50
+ Quality : experimental
+ <BLANKLINE>
+ Description:
+ A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].
+ <BLANKLINE>
+
+ >>> for i in a.list(verbose=False, width=80):
+ ... print i[0]
+ wrobel [Subversion] (https://o.g.o/svn/dev/wrobel )
+ wrobel-stable [Rsync ] (rsync://gunnarwrobel.de/wrobel-stable)
+ '''
+ result = []
+
+ selection = [overlay for (a, overlay) in self.overlays.items()]
+ if repos is not None:
+ selection = [overlay for overlay in selection if overlay.name in repos]
+
+ for overlay in selection:
+ if verbose:
+ result.append((overlay.get_infostr(), overlay.is_supported(),
+ overlay.is_official()))
+ else:
+ result.append((overlay.short_list(width), overlay.is_supported(),
+ overlay.is_official()))
+
+ result = sorted(result, key=lambda (summary, supported, official): summary.lower())
+
+ return result
+
+ def list_ids(self):
+ """returns a list of the overlay names
+ """
+ return sorted(self.overlays)
+
+
+#===============================================================================
+#
+# Testing
+#
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ import doctest
+
+ # Ignore warnings here. We are just testing
+ from warnings import filterwarnings, resetwarnings
+ filterwarnings('ignore')
+
+ doctest.testmod(sys.modules[__name__])
+
+ resetwarnings()
diff --git a/layman/debug.py b/layman/debug.py
new file mode 100644
index 0000000..f5c247b
--- /dev/null
+++ b/layman/debug.py
@@ -0,0 +1,399 @@
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN - DEBUGGING FUNCTIONS
+#################################################################################
+# debug.py -- Utility function for debugging
+# Copyright 2005 - 2008 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+
+__version__ = "$Id: debug.py 153 2006-06-05 06:03:16Z wrobel $"
+
+#################################################################################
+##
+## Dependancies
+##
+#################################################################################
+
+import sys, inspect, types
+
+from optparse import OptionGroup
+
+from layman.constants import (codes, DEBUG_LEVEL, DEBUG_VERBOSITY,
+ INFO_LEVEL, WARN_LEVEL, OFF)
+
+from output import Message
+
+
+class DebugMessage(Message):
+ """fully Debug enabled subclass of output.py's Message
+ """
+ #FIXME: Think about some simple doctests before you modify this class the
+ # next time.
+
+ def __init__(self, module = '',
+ out = sys.stdout,
+ err = sys.stderr,
+ dbg = sys.stderr,
+ debug_level = DEBUG_LEVEL,
+ debug_verbosity = DEBUG_VERBOSITY,
+ info_level = INFO_LEVEL,
+ warn_level = WARN_LEVEL,
+ col = True,
+ mth = None,
+ obj = None,
+ var = None):
+
+ if mth == None: mth = ['*']
+ if obj == None: obj = ['*']
+ if var == None: var = ['*']
+
+ Message.__init__(self)
+
+ # A description of the module that is being debugged
+ self.debug_env = module
+
+ # Where should the debugging output go? This can also be a file
+ self.debug_out = dbg
+
+ # Where should the error output go? This can also be a file
+ #self.error_out = err
+
+ # Where should the normal output go? This can also be a file
+ #self.std_out = out
+
+ # The higher the level the more information you will get
+ #self.warn_lev = warn_level
+
+ # The higher the level the more information you will get
+ #self.info_lev = info_level
+
+ # The highest level of debugging messages acceptable for output
+ # The higher the level the more output you will get
+ #self.debug_lev = debugging_level
+
+ # The debugging output can range from very verbose (3) to
+ # very compressed (1)
+ self.debug_vrb = debug_verbosity
+
+ # Which methods should actually be debugged?
+ # Use '*' to indicate 'All methods'
+ self.debug_mth = mth
+
+ # Which objects should actually be debugged?
+ # Use '*' to indicate 'All objects'
+ self.debug_obj = obj
+
+ # Which variables should actually be debugged?
+ # Use '*' to indicate 'All variables'
+ self.debug_var = var
+
+ # Exclude class variables by default
+ self.show_class_variables = False
+
+ # Should the output be colored?
+ #self.use_color = col
+
+ #self.has_error = False
+
+
+ ############################################################################
+ # Add command line options
+
+ def cli_opts(self, parser):
+
+ #print "Parsing debug opts"
+
+ group = OptionGroup(parser,
+ '<Debugging options>',
+ 'Control the debugging features of '
+ + self.debug_env)
+
+ group.add_option('--debug',
+ action = 'store_true',
+ help = 'Activates debugging features.')
+
+ group.add_option('--debug-level',
+ action = 'store',
+ type = 'int',
+ help = 'A value between 0 and 10. 0 means no debugging '
+ 'messages will be selected, 10 selects all debugging me'
+ 'ssages. Default is "4".')
+
+ group.add_option('--debug-verbose',
+ action = 'store',
+ type = 'int',
+ help = 'A value between 1 and 3. Lower values yield les'
+ 's verbose debugging output. Default is "2".')
+
+ group.add_option('--debug-methods',
+ action = 'store',
+ help = 'Limits the methods that will return debugging o'
+ 'utput. The function name is sufficient and there is no'
+ 'difference between class methods or general functions.'
+ ' Several methods can be specified by seperating them w'
+ ' with a comma. Default is "*" which specifies all meth'
+ 'ods.')
+
+ group.add_option('--debug-classes',
+ action = 'store',
+ help = 'Limits the classes that will return debugging o'
+ 'utput. Specify only the class name not including the m'
+ 'odules in which the class is defined (e.g. MyModule.ma'
+ 'in.Main should only be represented by "Main"). Several'
+ 'classes can be specified by seperating them with a com'
+ 'ma. Default is "*" which specifies all classes.')
+
+ group.add_option('--debug-variables',
+ action = 'store',
+ help = 'Limits the variables that will return debugging'
+ ' output. Several variables can be specified by seperat'
+ 'ing them with a comma. Default is "*" which specifies '
+ 'all variables.')
+
+ group.add_option('--debug-class-vars',
+ action = 'store_true',
+ help = 'In default mode the debugging code will only re'
+ 'turn information on the local variable which does not '
+ 'include the class variables. Use this switch to add al'
+ 'l values that are provided by "self".')
+
+ group.add_option('--debug-nocolor',
+ action = 'store_true',
+ help = 'Deactivates colors in the debugging output.')
+
+ parser.add_option_group(group)
+
+
+ #############################################################################
+ # Handle command line options
+
+ def cli_handle(self, options):
+
+ if (options.__dict__.has_key('debug')
+ and options.__dict__['debug']):
+ self.set_debug_level(DEBUG_LEVEL)
+ else:
+ self.set_debug_level(OFF)
+ return
+
+ if (options.__dict__.has_key('debug_class_vars')
+ and options.__dict__['debug_class_vars']):
+ self.class_variables_on()
+ else:
+ self.class_variables_off()
+
+ if (options.__dict__.has_key('debug_nocolor')
+ and options.__dict__['debug_nocolor']):
+ self.set_colorize(False)
+ else:
+ self.set_colorize(True)
+
+ if (options.__dict__.has_key('debug_level') and
+ options.__dict__['debug_level']):
+ dbglvl = int(options.__dict__['debug_level'])
+ if dbglvl < 0:
+ dbglvl = 0
+ if dbglvl > 10:
+ dbglvl = 10
+ self.set_debug_level(dbglvl)
+
+ if (options.__dict__.has_key('debug_verbose') and
+ options.__dict__['debug_verbose']):
+ dbgvrb = int(options.__dict__['debug_verbose'])
+ if dbgvrb < 1:
+ dbgvrb = 1
+ if dbgvrb > 3:
+ dbgvrb = 3
+ self.set_debug_verbosity(dbgvrb)
+
+ for i in [('debug_methods', self.set_debug_methods),
+ ('debug_classes', self.set_debug_classes),
+ ('debug_variables', self.set_debug_variables),]:
+
+ if (options.__dict__.has_key(i[0]) and
+ options.__dict__[i[0]]):
+ i[1](options.__dict__[i[0]])
+
+
+ #############################################################################
+ ## Helper Functions
+
+ def set_module(self, module):
+
+ self.debug_env = module
+
+ def set_debug_methods(self, methods):
+
+ methods = methods.split(',')
+
+ if methods:
+ self.debug_mth = methods
+
+ def set_debug_classes(self, classes):
+
+ classes = classes.split(',')
+
+ if classes:
+ self.debug_obj = classes
+
+ def set_debug_variables(self, variables):
+
+ variables = variables.split(',')
+
+ if variables:
+ self.debug_var = variables
+
+
+ def set_debug_verbosity(self, debugging_verbosity = DEBUG_VERBOSITY):
+ self.debug_vrb = debugging_verbosity
+
+
+ def class_variables_off(self):
+ self.show_class_variables = False
+
+ def class_variables_on(self):
+ self.show_class_variables = True
+
+ #############################################################################
+ ## Output Functions
+
+ def debug (self, message, level = DEBUG_LEVEL):
+ '''
+ This is a generic debugging method.
+ '''
+ ## Check the debug level first. This is the most inexpensive check.
+ if level > self.debug_lev:
+ return
+
+ ## Maybe this should be debugged. So get the stack first.
+ stack = inspect.stack()
+
+ ## This can probably never happen but does not harm to check
+ ## that there is actually something calling this function
+ if len(stack) < 2:
+ return
+
+ ## Get the stack length to determine indentation of the debugging output
+ stacklength = len(stack)
+ ls = ' ' * stacklength
+
+ ## Get the information about the caller
+ caller = stack[1]
+
+ ## The function name of the calling frame is the fourth item in the list
+ callermethod = caller[3]
+
+ ## Is this actually one of the methods that should be debugged?
+ if not '*' in self.debug_mth and not callermethod in self.debug_mth:
+ return
+
+ ## Still looks like this should be debugged. So retrieve the dictionary
+ ## of local variables from the caller
+ callerlocals = inspect.getargvalues(caller[0])[3]
+
+ ## Is the caller an obejct? If so he provides 'self'
+ if 'self' in callerlocals.keys():
+ callerobject = callerlocals['self']
+ del callerlocals['self']
+ if self.show_class_variables:
+ cv = inspect.getmembers(callerobject,
+ lambda x: not inspect.ismethod(x))
+ callerlocals.sync(cv)
+ else:
+ callerobject = None
+
+ # Remove variables not requested
+ if not '*' in self.debug_var:
+ callerlocals = dict([i for i in callerlocals.items()
+ if i[0] in self.debug_var])
+
+ ## Is the object among the list of objects to debug?
+ if (not '*' in self.debug_obj and
+ not str(callerobject.__class__.__name__) in self.debug_obj):
+ return
+
+ if type(message) not in types.StringTypes:
+ message = str(message)
+
+ def breaklines(x):
+ '''
+ Helper function to keep width of the debugging output.
+
+ This may look ugly for arrays but it is acceptable and not
+ breaking the line would break the output format
+ '''
+ ## Get the number of lines we need (rounded down)
+ lines = len(x) // 60
+ if lines > 0:
+ for j in range(lines):
+ ## Print line with continuation marker
+ print >> self.debug_out, ls + '// ' + x[0:60] + ' \\'
+ ## Remove printed characters from output
+ x = x[60:]
+ ## Print final line
+ print >> self.debug_out, ls + '// ' + x
+
+ if self.debug_vrb == 1:
+ # Top line indicates class and method
+ c = ''
+ if callerobject:
+ c += 'Class: ' + str(callerobject.__class__.__name__) + ' | '
+ if callermethod:
+ c += 'Method: ' + str(callermethod)
+ print >> self.debug_out, '// ' + c
+ # Selected variables follow
+ if callerlocals:
+ for i,j in callerlocals.items():
+ print >> self.debug_out, '// ' \
+ + self.maybe_color('turquoise', str(i)) + ':' + str(j)
+ # Finally the message
+ print >> self.debug_out, self.maybe_color('yellow', message)
+ return
+
+ if self.debug_vrb == 3:
+ print >> self.debug_out, ls + '/////////////////////////////////' + \
+ '////////////////////////////////'
+
+ # General information about what is being debugged
+ #(module name or similar)
+ print >> self.debug_out, ls + '// ' + self.debug_env
+ print >> self.debug_out, ls + '//-----------------------------------' + \
+ '----------------------------'
+
+ ## If the caller is a class print the name here
+ if callerobject:
+ print >> self.debug_out, ls + \
+ '// Object Class: ' + str(callerobject.__class__.__name__)
+
+ ## If the method has been extracted print it here
+ if callermethod:
+ print >> self.debug_out, ls + '// ' \
+ + self.maybe_color('green', 'Method: ') + str(callermethod)
+ if self.debug_vrb == 3:
+ print >> self.debug_out, ls + '//---------------------------' + \
+ '------------------------------------'
+
+ ## Print the information on all available local variables
+ if callerlocals:
+ if self.debug_vrb == 3:
+ print >> self.debug_out, ls + '//'
+ print >> self.debug_out, ls + '// VALUES '
+ for i,j in callerlocals.items():
+ print >> self.debug_out, ls + '// ------------------> ' \
+ + self.maybe_color('turquoise', str(i)) + ':'
+ breaklines(str(j))
+ if self.debug_vrb == 3:
+ print >> self.debug_out, ls + '//------------------------------'\
+ '---------------------------------'
+
+ # Finally print the message
+ breaklines(self.maybe_color('yellow', message))
+
+ if self.debug_vrb == 3:
+ print >> self.debug_out, ls + '//-------------------------------' + \
+ '--------------------------------'
+ print >> self.debug_out, ls + '/////////////////////////////////' + \
+ '////////////////////////////////'
+
+## gloabal message handler
+OUT = Message('layman')
diff --git a/layman/makeconf.py b/layman/makeconf.py
new file mode 100644
index 0000000..7eca2cd
--- /dev/null
+++ b/layman/makeconf.py
@@ -0,0 +1,296 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# MAKE-DOT-CONF HANDLING
+#################################################################################
+# File: makeconf.py
+#
+# Handles modifications to /etc/make.conf
+#
+# Copyright:
+# (c) 2005 - 2009 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+
+import os
+import codecs
+import re
+
+from layman.utils import path
+
+#===============================================================================
+#
+# Helper class MakeConf
+#
+#-------------------------------------------------------------------------------
+
+class MakeConf:
+ '''
+ Handles modifications to /etc/make.conf
+
+ Check that an add/remove cycle does not modify the make.conf:
+
+ >>> import hashlib
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> write = os.path.join(tmpdir, 'make.conf')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> config = {'installed' :
+ ... here + '/tests/testfiles/global-overlays.xml',
+ ... 'make_conf' : here + '/tests/testfiles/make.conf',
+ ... 'nocheck' : True,
+ ... 'storage' : '/var/lib/layman',
+ ... 'quietness':3}
+ >>> b = DB(config)
+ >>> a = MakeConf(config, b.overlays)
+ >>> o_md5 = str(hashlib.md5(open(here + '/tests/testfiles/make.conf').read()).hexdigest())
+ >>> a.path = write
+ >>> a.add(b.overlays['wrobel-stable'])
+ >>> [i.name for i in a.overlays]
+ [u'wrobel-stable', u'wrobel-stable']
+ >>> a.add(b.overlays['wrobel'])
+ >>> [i.name for i in a.overlays]
+ [u'wrobel', u'wrobel-stable', u'wrobel-stable']
+ >>> a.delete(b.overlays['wrobel-stable'])
+ >>> [i.name for i in a.overlays]
+ [u'wrobel']
+ >>> a.add(b.overlays['wrobel-stable'])
+ >>> [i.name for i in a.overlays]
+ [u'wrobel', u'wrobel-stable']
+ >>> a.delete(b.overlays['wrobel'])
+ >>> n_md5 = str(hashlib.md5(open(write).read()).hexdigest())
+ >>> o_md5 == n_md5
+ True
+ >>> os.unlink(write)
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ '''
+
+ my_re = re.compile('PORTDIR_OVERLAY\s*=\s*"([^"]*)"')
+
+ def __init__(self, config, overlays):
+
+ self.config = config
+ self.path = config['make_conf']
+ self.storage = config['storage']
+ self.data = ''
+ self.db = overlays
+ self.overlays = []
+ self.extra = []
+ self.output = config['output']
+
+ self.read(True)
+
+ def add(self, overlay):
+ '''
+ Add an overlay to make.conf.
+
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> write = os.path.join(tmpdir, 'make.conf')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> config = {'installed' :
+ ... here + '/tests/testfiles/global-overlays.xml',
+ ... 'make_conf' : here + '/tests/testfiles/make.conf',
+ ... 'nocheck' : True,
+ ... 'storage' : '/var/lib/layman',
+ ... 'quietness':3}
+ >>> c = DB(config)
+ >>> a = MakeConf(config, c.overlays)
+ >>> a.path = write
+ >>> a.add(c.select('wrobel'))
+ >>> config['make_conf'] = write
+ >>> b = MakeConf(config, c.overlays)
+ >>> [i.name for i in b.overlays]
+ [u'wrobel', u'wrobel-stable']
+ >>> b.extra
+ [u'/usr/local/portage/ebuilds/testing', u'/usr/local/portage/ebuilds/stable', u'/usr/local/portage/kolab2', u'/usr/local/portage/gentoo-webapps-overlay/experimental', u'/usr/local/portage/gentoo-webapps-overlay/production-ready']
+
+ >>> os.unlink(write)
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ '''
+ self.overlays.append(overlay)
+ return self.write()
+
+ def delete(self, overlay):
+ '''
+ Delete an overlay from make.conf.
+
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> write = os.path.join(tmpdir, 'make.conf')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> config = {'installed' :
+ ... here + '/tests/testfiles/global-overlays.xml',
+ ... 'make_conf' : here + '/tests/testfiles/make.conf',
+ ... 'nocheck' : True,
+ ... 'storage' : '/var/lib/layman',
+ ... 'quietness':3}
+ >>> c = DB(config)
+ >>> a = MakeConf(config, c.overlays)
+ >>> a.path = write
+ >>> a.delete(c.select('wrobel-stable'))
+ >>> config['make_conf'] = write
+ >>> b = MakeConf(config, c.overlays)
+ >>> [i.name for i in b.overlays]
+ []
+ >>> b.extra
+ [u'/usr/local/portage/ebuilds/testing', u'/usr/local/portage/ebuilds/stable', u'/usr/local/portage/kolab2', u'/usr/local/portage/gentoo-webapps-overlay/experimental', u'/usr/local/portage/gentoo-webapps-overlay/production-ready']
+
+ >>> os.unlink(write)
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ '''
+ self.overlays = [i
+ for i in self.overlays
+ if i.name != overlay.name]
+ return self.write()
+
+ def read(self, raise_error=False):
+ '''
+ Read the list of registered overlays from /etc/make.conf.
+
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> config = {'installed' :
+ ... here + '/tests/testfiles/global-overlays.xml',
+ ... 'make_conf' : here + '/tests/testfiles/make.conf',
+ ... 'nocheck' : True,
+ ... 'storage' : '/var/lib/layman',
+ ... 'quietness':3}
+ >>> c = DB(config)
+ >>> a = MakeConf(config, c.overlays)
+ >>> [i.name for i in a.overlays]
+ [u'wrobel-stable']
+ >>> a.extra
+ [u'/usr/local/portage/ebuilds/testing', u'/usr/local/portage/ebuilds/stable', u'/usr/local/portage/kolab2', u'/usr/local/portage/gentoo-webapps-overlay/experimental', u'/usr/local/portage/gentoo-webapps-overlay/production-ready']
+ '''
+ if os.path.isfile(self.path):
+ self.content()
+
+ overlays = self.my_re.search(self.data)
+
+ if not overlays:
+ msg = 'MakeConf: read(); Did not find a ' + \
+ 'PORTDIR_OVERLAY entry in file ' + \
+ self.path +'! Did you specify the correct file?'
+ if raise_error:
+ raise Exception(msg)
+ self.output.error(msg)
+ return False
+
+ overlays = [i.strip()
+ for i in overlays.group(1).split('\n')
+ if i.strip()]
+
+ for i in overlays:
+ if i[:len(self.storage)] == self.storage:
+ oname = os.path.basename(i)
+ if oname in self.db.keys():
+ self.overlays.append(self.db[oname])
+ else:
+ # These are additional overlays that we dont know
+ # anything about. The user probably added them manually
+ self.extra.append(i)
+ else:
+ # These are additional overlays that we dont know anything
+ # about. The user probably added them manually
+ self.extra.append(i)
+
+ else:
+ self.overlays = []
+ self.data = 'PORTDIR_OVERLAY="\n"\n'
+
+ self.extra = [i for i in self.extra
+ if (i != '$PORTDIR_OVERLAY'
+ and i != '${PORTDIR_OVERLAY}')]
+ return True
+
+ def write(self):
+ '''
+ Write the list of registered overlays to /etc/make.conf.
+
+ >>> import tempfile
+ >>> tmpdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> os.path.join(tmpdir, 'make.conf')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> config = {'installed' :
+ ... here + '/tests/testfiles/global-overlays.xml',
+ ... 'make_conf' : here + '/tests/testfiles/make.conf',
+ ... 'nocheck' : True,
+ ... 'storage' : '/var/lib/layman',
+ ... 'quietness':3}
+ >>> c = DB(config)
+ >>> a = MakeConf(config, c.overlays)
+ >>> a.path = write
+ >>> a.write()
+ >>> config['make_conf'] = write
+ >>> b = MakeConf(config, c.overlays)
+ >>> [i.name for i in b.overlays]
+ [u'wrobel-stable']
+ >>> b.extra
+ [u'/usr/local/portage/ebuilds/testing', u'/usr/local/portage/ebuilds/stable', u'/usr/local/portage/kolab2', u'/usr/local/portage/gentoo-webapps-overlay/experimental', u'/usr/local/portage/gentoo-webapps-overlay/production-ready']
+
+ >>> os.unlink(write)
+ >>> import shutil
+ >>> shutil.rmtree(tmpdir)
+ '''
+ def prio_sort(a, b):
+ '''Sort by priority.'''
+ if a.priority < b.priority:
+ return -1
+ elif a.priority > b.priority:
+ return 1
+ return 0
+
+ self.overlays.sort(prio_sort)
+
+ paths = []
+ for i in self.overlays:
+ paths.append(path((self.storage, i.name, )))
+
+ overlays = 'PORTDIR_OVERLAY="\n'
+ overlays += '\n'.join(paths) + '\n'
+ overlays += '$PORTDIR_OVERLAY\n'
+ overlays += '\n'.join(self.extra)
+ overlays += '"'
+
+ content = self.my_re.sub(overlays, self.data)
+
+ if not self.my_re.search(content):
+ self.output.error('MakeConf: write(); Oops, failed to set a '
+ 'proper PORTDIR_OVERLAY entry in file '
+ + self.path +'! Did not overwrite the file.')
+ return False
+
+ try:
+ make_conf = codecs.open(self.path, 'w', 'utf-8')
+
+ make_conf.write(content)
+
+ make_conf.close()
+
+ except Exception, error:
+ self.output.error('MakeConf: write(); Failed to write "'
+ + self.path + '".\nError was:\n' + str(error))
+ return False
+ return True
+
+ def content(self):
+ '''
+ Returns the content of the /etc/make.conf file.
+ '''
+ try:
+ make_conf = codecs.open(self.path, 'r', 'utf-8')
+
+ self.data = make_conf.read()
+
+ make_conf.close()
+
+ except Exception, error:
+ self.output.error('MakeConf: content(); Failed to read "' +
+ self.path + '".\nError was:\n' + str(error))
+ raise error
diff --git a/layman/output.py b/layman/output.py
new file mode 100644
index 0000000..7b42b81
--- /dev/null
+++ b/layman/output.py
@@ -0,0 +1,205 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" Copyright 2005 - 2008 Gunnar Wrobel
+ 2011 - Brian Dolbec
+ Distributed under the terms of the GNU General Public License v2
+"""
+
+
+__version__ = "0.1"
+
+
+import sys, types
+
+from layman.constants import codes, INFO_LEVEL, WARN_LEVEL, DEBUG_LEVEL, OFF
+from layman.compatibility import encode
+
+
+class MessageBase(object):
+ """Base Message class helper functions and variables
+ """
+
+ def __init__(self,
+ out = sys.stdout,
+ err = sys.stderr,
+ info_level = INFO_LEVEL,
+ warn_level = WARN_LEVEL,
+ col = True,
+ error_callback=None
+ ):
+ # Where should the error output go? This can also be a file
+ self.error_out = err
+
+ # Where should the normal output go? This can also be a file
+ self.std_out = out
+
+ # The higher the level the more information you will get
+ self.warn_lev = warn_level
+
+ # The higher the level the more information you will get
+ self.info_lev = info_level
+
+ # Should the output be colored?
+ self.color_func = None
+ self.set_colorize(col)
+
+ self.debug_lev = OFF
+
+ # callback function that gets passed any error messages
+ # that have shown up.
+ self.error_callback = error_callback
+ self.block_callback = False
+
+
+ def _color (self, col, text):
+ return codes[col] + text + codes['reset']
+
+
+ def _no_color (self, col, text):
+ return text
+
+
+ def set_colorize(self, state):
+ if state:
+ self.color_func = self._color
+ else:
+ self.color_func = self._no_color
+
+
+ def set_info_level(self, info_level = INFO_LEVEL):
+ self.info_lev = info_level
+
+
+ def set_warn_level(self, warn_level = WARN_LEVEL):
+ self.warn_lev = warn_level
+
+
+ def set_debug_level(self, debugging_level = DEBUG_LEVEL):
+ self.debug_lev = debugging_level
+
+ def do_error_callback(self, error):
+ """runs the error_callback function with the error
+ that occurred
+ """
+ if self.error_callback is not None and not self.block_callback:
+ self.error_callback(error)
+
+
+class Message(MessageBase):
+ """Primary Message output methods
+ """
+ #FIXME: Think about some simple doctests before you modify this class the
+ # next time.
+
+ def __init__(self,
+ out = sys.stdout,
+ err = sys.stderr,
+ info_level = INFO_LEVEL,
+ warn_level = WARN_LEVEL,
+ col = True,
+ error_callback = None
+ ):
+
+ MessageBase.__init__(self, out, err, info_level, warn_level,
+ col, error_callback)
+
+
+ ## Output Functions
+
+ def debug(self, info, level = OFF):
+ """empty debug function, does nothing,
+ declared here for compatibility with DebugMessage
+ """
+ if type(info) != str:#not in types.StringTypes:
+ info = encode(info)
+
+ if level > self.debug_lev:
+ return
+
+ for i in info.split('\n'):
+ print >> self.std_out, self.color_func('yellow', 'DEBUG: ') + i
+
+
+ def notice (self, note):
+ print >> self.std_out, note
+
+
+ def info (self, info, level = INFO_LEVEL):
+
+ if type(info) != str:#not in types.StringTypes:
+ info = encode(info)
+
+ if level > self.info_lev:
+ return
+
+ for i in info.split('\n'):
+ print >> self.std_out, self.color_func('green', ' * ') + i
+
+
+ def status (self, message, status, info = 'ignored'):
+
+ if type(message) != str:#not in types.StringTypes:
+ message = encode(message)
+
+ lines = message.split('\n')
+
+ if not len(lines):
+ return
+
+ for i in lines[0:-1]:
+ print >> self.std_out, self.color_func('green', ' * ') + i
+
+ i = lines[-1]
+
+ if len(i) > 58:
+ i = i[0:57]
+
+ if status == 1:
+ result = '[' + self.color_func('green', 'ok') + ']'
+ elif status == 0:
+ result = '[' + self.color_func('red', 'failed') + ']'
+ else:
+ result = '[' + self.color_func('yellow', info) + ']'
+
+ print >> self.color_func('green', ' * ') + i + ' ' + \
+ '.' * (58 - len(i)) + ' ' + result
+
+
+ def warn (self, warn, level = WARN_LEVEL):
+
+ if type(warn) != str:#not in types.StringTypes:
+ warn = encode(warn)
+
+ if level > self.warn_lev:
+ return
+
+ for i in warn.split('\n'):
+ print >> self.std_out, self.color_func('yellow', ' * ') + i
+
+
+ def error (self, error):
+
+ if type(error) != str:#not in types.StringTypes:
+ error = encode(error)
+
+ for i in error.split('\n'):
+ # NOTE: Forced flushing ensures that stdout and stderr
+ # stay in nice order. This is a workaround for calls like
+ # "layman -L |& less".
+ sys.stdout.flush()
+ self.error_out.flush()
+ print >> self.std_out, self.color_func('red', ' * ') + i
+ sys.stdout.flush()
+ self.do_error_callback(error)
+
+
+ def die (self, error):
+
+ if type(error) != str:#not in types.StringTypes:
+ error = encode(error)
+
+ for i in error.split('\n'):
+ self.error(self.color_func('red', 'Fatal error: ') + i)
+ self.error(self.color_func('red', 'Fatal error(s) - aborting'))
+ sys.exit(1)
diff --git a/layman/overlays/.svn.ignore b/layman/overlays/.svn.ignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/layman/overlays/.svn.ignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/layman/overlays/__init__.py b/layman/overlays/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/layman/overlays/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/layman/overlays/bzr.py b/layman/overlays/bzr.py
new file mode 100644
index 0000000..fb1fb24
--- /dev/null
+++ b/layman/overlays/bzr.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN BZR OVERLAY HANDLER
+#################################################################################
+# File: bzr.py
+#
+# Handles bzr overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Adrian Perez, Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Adrian Perez <moebius@connectical.net>
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+'''Should work with any version of Bzr equal to or better than 0.7 --
+ caution: tested only with 0.8 and 0.8.2...'''
+
+__version__ = "$Id: bzr.py 236 2006-09-05 20:39:37Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class BzrOverlay
+#
+#-------------------------------------------------------------------------------
+
+class BzrOverlay(OverlaySource):
+ ''' Handles bzr overlays.'''
+
+ type = 'Bzr'
+ type_key = 'bzr'
+
+ def __init__(self, parent, config, _location, ignore = 0):
+
+ super(BzrOverlay, self).__init__(parent,
+ config, _location, ignore)
+ self.subpath = None
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["bzr_addopts"]
+ target = path([base, self.parent.name])
+
+ # bzr get SOURCE TARGET
+ if len(cfg_opts):
+ args = ['branch', cfg_opts,
+ self.src + '/', target]
+ else:
+ args = ['branch', self.src + '/', target]
+ return self.postsync(
+ self.run_command(self.command(), args, cmd=self.type),
+ cwd=target)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["bzr_syncopts"]
+ target = path([base, self.parent.name])
+
+ # bzr pull --overwrite SOURCE
+ if len(cfg_opts):
+ args = ['pull', cfg_opts, '--overwrite', self.src]
+ else:
+ args = ['pull', '--overwrite', self.src]
+ return self.postsync(
+ self.run_command(self.command(), args, cwd=target, cmd=self.type),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'bzr', 'dev-vcs/bzr'),],
+ self.output.warn)
diff --git a/layman/overlays/cvs.py b/layman/overlays/cvs.py
new file mode 100644
index 0000000..2bb6791
--- /dev/null
+++ b/layman/overlays/cvs.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN CVS OVERLAY HANDLER
+#################################################################################
+# File: cvs.py
+#
+# Handles cvs overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+''' Cvs overlay support.'''
+
+__version__ = "$Id$"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import xml.etree.ElementTree as ET # Python 2.5
+
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class CvsOverlay
+#
+#-------------------------------------------------------------------------------
+
+class CvsOverlay(OverlaySource):
+ ''' Handles cvs overlays.'''
+
+ type = 'cvs'
+ type_key = 'cvs'
+
+ def __init__(self, parent, config, _location, ignore = 0):
+
+ super(CvsOverlay, self).__init__(parent, config, _location, ignore)
+ self.subpath = None
+
+
+ def __eq__(self, other):
+ res = super(CvsOverlay, self).__eq__(other) \
+ and self.subpath == other.subpath
+ return res
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ # overrider
+ def to_xml_hook(self, repo_elem):
+ if self.subpath:
+ _subpath = ET.Element('subpath')
+ _subpath.text = self.subpath
+ repo_elem.append(_subpath)
+ del _subpath
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["cvs_addopts"]
+ target = path([base, self.parent.name])
+
+ # cvs [-q] co -d SOURCE SCOPE
+ args = []
+ if self.config['quiet']:
+ args.append('-q')
+ args.append('co')
+ args.append('-d')
+ if len(cfg_opts):
+ args.append(cfg_opts)
+ args.append(self.parent.name)
+ args.append(self.subpath)
+
+ return self.postsync(
+ self.run_command(self.command(), args, cwd=base,
+ env=dict(CVSROOT=self.src), cmd=self.type),
+ cwd=target)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["cvs_syncopts"]
+ target = path([base, self.parent.name])
+
+ # cvs [-q] update -d
+ args = []
+ if self.config['quiet']:
+ args.append('-q')
+ args.append('update')
+ args.append('-d')
+ if len(cfg_opts):
+ args.append(cfg_opts)
+ return self.postsync(
+ self.run_command(self.command(), args, cwd=target, cmd=self.type),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'cvs', 'dev-vcs/cvs'),],
+ self.output.warn)
diff --git a/layman/overlays/darcs.py b/layman/overlays/darcs.py
new file mode 100644
index 0000000..d3eec6a
--- /dev/null
+++ b/layman/overlays/darcs.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN DARCS OVERLAY HANDLER
+#################################################################################
+# File: darcs.py
+#
+# Handles darcs overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel, Andres Loeh
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Andres Loeh <kosmikus@gentoo.org>
+#
+''' Darcs overlay support.'''
+
+__version__ = "$Id: darcs.py 236 2006-09-05 20:39:37Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class BzrOverlay
+#
+#-------------------------------------------------------------------------------
+
+class DarcsOverlay(OverlaySource):
+ ''' Handles darcs overlays.'''
+
+ type = 'Darcs'
+ type_key = 'darcs'
+
+ def __init__(self, parent, config, _location, ignore = 0):
+
+ super(DarcsOverlay, self).__init__(parent, config,
+ _location, ignore)
+ self.subpath = None
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["darcs_addopts"]
+ target = path([base, self.parent.name])
+
+ # darcs get --partial SOURCE TARGET
+ if len(cfg_opts):
+ args = ['get', '--partial', cfg_opts,
+ self.src + '/', target]
+ else:
+ args = ['get', '--partial',
+ self.src + '/', target]
+
+ return self.postsync(
+ self.run_command(self.command(), args, cmd=self.type),
+ cwd=target)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["darcs_addopts"]
+ target = path([base, self.parent.name])
+
+ # darcs pull --all SOURCE
+ if len(cfg_opts):
+ args = ['pull', '--all', cfg_opts, self.src]
+ else:
+ args = ['pull', '--all', self.src]
+ return self.postsync(
+ self.run_command(self.command(), args, cwd=target, cmd=self.type),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'darcs', 'dev-vcs/darcs'),],
+ self.output.warn)
diff --git a/layman/overlays/g_common.py b/layman/overlays/g_common.py
new file mode 100644
index 0000000..5f0e9bc
--- /dev/null
+++ b/layman/overlays/g_common.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN G-COMMON OVERLAY HANDLER
+#################################################################################
+# File: g_common.py
+#
+# Handles g-common-style repositories
+#
+# Copyright:
+# (c) 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Auke Booij <auke@tulcod.com>
+#
+''' G-common repository support.'''
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import os
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class GCommonOverlay
+#
+#-------------------------------------------------------------------------------
+
+class GCommonOverlay(OverlaySource):
+ ''' Handles g-common-style repositories.'''
+
+ type = 'g-common'
+ type_key = 'g-common'
+
+ def __init__(self, parent, config, _location, ignore = 0):
+ super(GCommonOverlay, self).__init__(parent, config,
+ _location, ignore)
+ #split source into driver and remote uri.
+ self.driver=self.src[:self.src.find(' ')]
+ self.remote_uri=self.src[self.src.find(' ')+1:]
+ self.subpath = None
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ target = path([base, self.parent.name])
+
+ os.makedirs(target)
+
+ return self.sync(base)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ target = path([base, self.parent.name])
+
+ args = [target, 'sync', self.driver, self.remote_uri]
+ returncode = self.run_command(self.command(), args, cwd=target)
+ if returncode:
+ return returncode
+ args = [target, 'generate-tree']
+ return self.postsync(
+ self.run_command(self.command(), args, cwd=target, cmd=self.type),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(),
+ 'g-common',
+ 'app-portage/g-common'),
+ ('/usr/share/g-common/drivers/'+self.driver+'.cfg',
+ 'g-common for '+self.driver,
+ 'app-portage/g-'+self.driver),],
+ self.output.warn)
diff --git a/layman/overlays/git.py b/layman/overlays/git.py
new file mode 100644
index 0000000..3cdc21e
--- /dev/null
+++ b/layman/overlays/git.py
@@ -0,0 +1,99 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN GIT OVERLAY HANDLER
+#################################################################################
+# File: git.py
+#
+# Handles git overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel, Stefan Schweizer
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Stefan Schweizer <genstef@gentoo.org>
+''' Git overlay support.'''
+
+__version__ = "$Id: git.py 146 2006-05-27 09:52:36Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class GitOverlay
+#
+#-------------------------------------------------------------------------------
+
+class GitOverlay(OverlaySource):
+ ''' Handles git overlays.'''
+
+ type = 'Git'
+ type_key = 'git'
+
+ def __init__(self, parent, config, _location, ignore = 0):
+ super(GitOverlay, self).__init__(parent, config,
+ _location, ignore)
+ self.subpath = None
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ def fix_git_source(source):
+ # http:// should get trailing slash, other protocols shouldn't
+ if source.split(':')[0] == 'http':
+ return source + '/'
+ return source
+
+ cfg_opts = self.config["git_addopts"]
+ target = path([base, self.parent.name])
+
+ # git clone [-q] SOURCE TARGET
+ args = ['clone']
+ if self.config['quiet']:
+ args.append('-q')
+ if len(cfg_opts):
+ args.append(cfg_opts)
+ args.append(fix_git_source(self.src))
+ args.append(target)
+ return self.postsync(
+ self.run_command(self.command(), args, cmd=self.type),
+ cwd=target)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ self.output.debug("git.sync(); starting...%s" % self.parent.name, 6)
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["git_syncopts"]
+ target = path([base, self.parent.name])
+
+ args = ['pull']
+ if self.config['quiet']:
+ args.append('-q')
+ if len(cfg_opts):
+ args.append(cfg_opts)
+
+ return self.postsync(
+ self.run_command(self.command(), args, cwd=target, cmd=self.type),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'git', 'dev-vcs/git'),],
+ self.output.warn)
diff --git a/layman/overlays/mercurial.py b/layman/overlays/mercurial.py
new file mode 100644
index 0000000..0d8250e
--- /dev/null
+++ b/layman/overlays/mercurial.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN MERCURIAL OVERLAY HANDLER
+#################################################################################
+# File: darcs.py
+#
+# Handles darcs overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel, Andres Loeh
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Andres Loeh <kosmikus@gentoo.org>
+#
+''' Mercurial overlay support.'''
+
+__version__ = "$Id: mercurial.py 236 2006-09-05 20:39:37Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class MercurialOverlay
+#
+#-------------------------------------------------------------------------------
+
+class MercurialOverlay(OverlaySource):
+ ''' Handles mercurial overlays.'''
+
+ type = 'Mercurial'
+ type_key = 'mercurial'
+
+ def __init__(self, parent, config,
+ _location, ignore = 0):
+
+ super(MercurialOverlay, self).__init__(parent,
+ config, _location, ignore)
+ self.subpath = None
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["mercurial_addopts"]
+ target = path([base, self.parent.name])
+
+ # hg clone SOURCE TARGET
+ if len(cfg_opts):
+ args = ['clone', cfg_opts, self.src + '/', target]
+ else:
+ args = ['clone', self.src + '/', target]
+
+ return self.postsync(
+ self.run_command(self.command(), args, cmd=self.type),
+ cwd=target)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ cfg_opts = self.config["mercurial_syncopts"]
+ target = path([base, self.parent.name])
+
+ # hg pull -u SOURCE
+ if len(cfg_opts):
+ args = ['pull', '-u', cfg_opts, self.src]
+ else:
+ args = ['pull', '-u', self.src]
+
+ return self.postsync(
+ self.run_command(self.command(), args, cwd=target, cmd=self.type),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'mercurial', 'dev-vcs/mercurial'),],
+ self.output.warn)
diff --git a/layman/overlays/overlay.py b/layman/overlays/overlay.py
new file mode 100755
index 0000000..8eb0870
--- /dev/null
+++ b/layman/overlays/overlay.py
@@ -0,0 +1,565 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+################################################################################
+# LAYMAN OVERLAY BASE CLASS
+################################################################################
+# File: overlay.py
+#
+# Base class for the different overlay types.
+#
+# Copyright:
+# (c) 2005 - 2009 Gunnar Wrobel
+# (c) 2009 Sebastian Pipping
+# (c) 2009 Christian Groschupp
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Sebastian Pipping <sebastian@pipping.org>
+# Christian Groschupp <christian@groschupp.org>
+#
+''' Basic overlay class.'''
+
+__version__ = "0.2"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import sys, re, os, os.path
+import codecs
+import locale
+import xml.etree.ElementTree as ET # Python 2.5
+
+from layman.utils import pad, terminal_width, get_encoding, encoder
+from layman.compatibility import encode
+
+from layman.overlays.bzr import BzrOverlay
+from layman.overlays.darcs import DarcsOverlay
+from layman.overlays.git import GitOverlay
+from layman.overlays.g_common import GCommonOverlay
+from layman.overlays.mercurial import MercurialOverlay
+from layman.overlays.cvs import CvsOverlay
+from layman.overlays.svn import SvnOverlay
+from layman.overlays.rsync import RsyncOverlay
+from layman.overlays.tar import TarOverlay
+
+#===============================================================================
+#
+# Constants
+#
+#-------------------------------------------------------------------------------
+
+OVERLAY_TYPES = dict((e.type_key, e) for e in (
+ GitOverlay,
+ GCommonOverlay,
+ CvsOverlay,
+ SvnOverlay,
+ RsyncOverlay,
+ TarOverlay,
+ BzrOverlay,
+ MercurialOverlay,
+ DarcsOverlay
+))
+
+QUALITY_LEVELS = 'core|stable|testing|experimental|graveyard'.split('|')
+
+WHITESPACE_REGEX = re.compile('\s+')
+
+
+class Overlay(object):
+ ''' Derive the real implementations from this.'''
+
+ def __init__(self, config, xml=None, ovl_dict=None,
+ ignore = 0):
+ '''
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> import xml.etree.ElementTree as ET # Python 2.5
+ >>> document =ET.parse(here + '/../tests/testfiles/global-overlays.xml')
+ >>> overlays = document.findall('overlay') + document.findall('repo')
+ >>> from layman.output import Message
+ >>> output = Message()
+ >>> a = Overlay({'output': output}, overlays[0])
+ >>> a.name
+ u'wrobel'
+ >>> a.is_official()
+ True
+ >>> list(a.source_uris())
+ [u'https://overlays.gentoo.org/svn/dev/wrobel']
+ >>> a.owner_email
+ u'nobody@gentoo.org'
+ >>> a.description
+ u'Test'
+ >>> a.priority
+ 10
+ >>> b = Overlay({'output': output}, overlays[1])
+ >>> b.is_official()
+ False
+ '''
+ self.config = config
+ self.output = config['output']
+ self._encoding_ = get_encoding(self.output)
+
+ if xml is not None:
+ self.from_xml(xml, ignore)
+ elif ovl_dict is not None:
+ self.from_dict(ovl_dict, ignore)
+
+
+ def from_xml(self, xml, ignore):
+ """Process an xml overlay definition
+ """
+ def strip_text(node):
+ res = node.text
+ if res is None:
+ return ''
+ return res.strip()
+
+ _name = xml.find('name')
+ if _name != None:
+ self.name = encode(strip_text(_name))
+ elif 'name' in xml.attrib:
+ self.name = encode(xml.attrib['name'])
+ else:
+ raise Exception('Overlay from_xml(), "' + self.name + \
+ 'is missing a "name" entry!')
+
+ _sources = xml.findall('source')
+ # new xml format
+ if _sources != []:
+ _sources = [e for e in _sources if 'type' in e.attrib]
+ #old xml format
+ elif ('src' in xml.attrib) and ('type' in xml.attrib):
+ s = ET.Element('source', type=xml.attrib['type'])
+ s.text = xml.attrib['src']
+ _sources = [s]
+ del s
+
+ def create_overlay_source(source_elem):
+ _type = source_elem.attrib['type']
+ try:
+ _class = OVERLAY_TYPES[_type]
+ except KeyError:
+ raise Exception('Overlay from_xml(), "' + self.name + \
+ 'Unknown overlay type "%s"!' % _type)
+ _location = encode(strip_text(source_elem))
+ return _class(parent=self, config=self.config,
+ _location=_location, ignore=ignore)
+
+ if not len(_sources):
+ raise Exception('Overlay from_xml(), "' + self.name + \
+ '" is missing a "source" entry!')
+
+ self.sources = [create_overlay_source(e) for e in _sources]
+
+ _subpath = xml.find('subpath')
+ if _subpath != None:
+ self.subpath = encode(_subpath.text.strip())
+ elif 'subpath' in xml.attrib:
+ self.subpath = encode(xml.attrib['subpath'])
+ else:
+ self.subpath = ''
+
+ _owner = xml.find('owner')
+ if _owner == None:
+ _email = None
+ else:
+ _email = _owner.find('email')
+ if _owner != None and _email != None:
+ self.owner_email = encode(strip_text(_email))
+ _name = _owner.find('name')
+ if _name != None:
+ self.owner_name = encode(strip_text(_name))
+ else:
+ self.owner_name = None
+ elif 'contact' in xml.attrib:
+ self.owner_email = encode(xml.attrib['contact'])
+ self.owner_name = None
+ else:
+ self.owner_email = ''
+ self.owner_name = None
+ if not ignore:
+ raise Exception('Overlay from_xml(), "' + self.name + \
+ '" is missing an "owner.email" entry!')
+ elif ignore == 1:
+ self.output.warn('Overlay "' + self.name + '" is missing a '
+ '"owner.email" entry!', 4)
+
+ _desc = xml.find('description')
+ if _desc != None:
+ d = WHITESPACE_REGEX.sub(' ', strip_text(_desc))
+ self.description = encode(d)
+ del d
+ else:
+ self.description = ''
+ if not ignore:
+ raise Exception('Overlay from_xml(), "' + self.name + \
+ '" is missing a description" entry!')
+ elif ignore == 1:
+ self.output.warn('Overlay "' + self.name + '" is missing a '
+ '"description" entry!', 4)
+
+ if 'status' in xml.attrib:
+ self.status = encode(xml.attrib['status'])
+ else:
+ self.status = None
+
+ self.quality = u'experimental'
+ if 'quality' in xml.attrib:
+ if xml.attrib['quality'] in set(QUALITY_LEVELS):
+ self.quality = encode(xml.attrib['quality'])
+
+ if 'priority' in xml.attrib:
+ self.priority = int(xml.attrib['priority'])
+ else:
+ self.priority = 50
+
+ h = xml.find('homepage')
+ l = xml.find('link')
+ if h != None:
+ self.homepage = encode(strip_text(h))
+ elif l != None:
+ self.homepage = encode(strip_text(l))
+ else:
+ self.homepage = None
+
+ self.feeds = [encode(strip_text(e)) \
+ for e in xml.findall('feed')]
+
+ _irc = xml.find('irc')
+ if _irc != None:
+ self.irc = encode(strip_text(_irc))
+ else:
+ self.irc = None
+
+
+ def from_dict(self, overlay, ignore):
+ """Process an xml overlay definition
+ """
+ self.output.debug("Overlay from_dict(); overlay" + str(overlay))
+ _name = overlay['name']
+ if _name != None:
+ self.name = encode(_name)
+ else:
+ raise Exception('Overlay from_dict(), "' + self.name +
+ 'is missing a "name" entry!')
+
+ _sources = overlay['sources']
+
+ if _sources == None:
+ raise Exception('Overlay from_dict(), "' + self.name +
+ '" is missing a "source" entry!')
+
+ def create_dict_overlay_source(source_):
+ _src, _type, _sub = source_
+ try:
+ _class = OVERLAY_TYPES[_type]
+ except KeyError:
+ raise Exception('Overlay from_dict(), "' + self.name +
+ 'Unknown overlay type "%s"!' % _type)
+ _location = encode(_src)
+ return _class(parent=self, config=self.config,
+ _location=_location, ignore=ignore)
+
+ self.sources = [create_dict_overlay_source(e) for e in _sources]
+
+ _owner = overlay['owner_name']
+ if _owner == None:
+ self.owner_name = None
+ _email = None
+ else:
+ self.owner_name = encode(_owner)
+ _email = overlay['owner_email']
+ if _email != None:
+ self.owner_email = encode(_email)
+ else:
+ self.owner_email = None
+ if not ignore:
+ raise Exception('Overlay from_dict(), "' + self.name +
+ '" is missing an "owner.email" entry!')
+ elif ignore == 1:
+ self.output.warn('Overlay from_dict(), "' + self.name +
+ '" is missing an "owner.email" entry!', 4)
+
+ _desc = overlay['description']
+ if _desc != None:
+ d = WHITESPACE_REGEX.sub(' ', _desc)
+ self.description = encode(d)
+ del d
+ else:
+ self.description = ''
+ if not ignore:
+ raise Exception('Overlay from_dict(), "' + self.name +
+ '" is missing a "description" entry!')
+ elif ignore == 1:
+ self.output.warn('Overlay from_dict(), "' + self.name +
+ '" is missing a "description" entry!', 4)
+
+ if overlay['status']:
+ self.status = encode(overlay['status'])
+ else:
+ self.status = None
+
+ self.quality = u'experimental'
+ if len(overlay['quality']):
+ if overlay['quality'] in set(QUALITY_LEVELS):
+ self.quality = encode(overlay['quality'])
+
+ if overlay['priority']:
+ self.priority = int(overlay['priority'])
+ else:
+ self.priority = 50
+
+ h = overlay['homepage']
+ if h != None:
+ self.homepage = encode(h)
+ else:
+ self.homepage = None
+
+ self.feeds = [encode(e) \
+ for e in overlay['feeds']]
+
+ _irc = overlay['irc']
+ if _irc != None:
+ self.irc = encode(_irc)
+ else:
+ self.irc = None
+
+ #xml = self.to_xml()
+ # end of from_dict
+
+
+ def __eq__(self, other):
+ for i in ('description', 'homepage', 'name', 'owner_email',
+ 'owner_name', 'priority', 'status'):
+ if getattr(self, i) != getattr(other, i):
+ return False
+ for i in self.sources + other.sources:
+ if not i in self.sources:
+ return False
+ if not i in other.sources:
+ return False
+ return True
+
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+ def set_priority(self, priority):
+ '''Set the priority of this overlay.'''
+ self.priority = int(priority)
+
+
+ def to_xml(self):
+ '''Convert to xml.'''
+ repo = ET.Element('repo')
+ if self.status != None:
+ repo.attrib['status'] = self.status
+ repo.attrib['quality'] = self.quality
+ repo.attrib['priority'] = str(self.priority)
+ name = ET.Element('name')
+ name.text = self.name
+ repo.append(name)
+ desc = ET.Element('description')
+ desc.text = self.description
+ repo.append(desc)
+ if self.homepage != None:
+ homepage = ET.Element('homepage')
+ homepage.text = self.homepage
+ repo.append(homepage)
+ if self.irc != None:
+ irc = ET.Element('irc')
+ irc.text = self.irc
+ repo.append(irc)
+ owner = ET.Element('owner')
+ repo.append(owner)
+ owner_email = ET.Element('email')
+ owner_email.text = self.owner_email
+ owner.append(owner_email)
+ if self.owner_name != None:
+ owner_name = ET.Element('name')
+ owner_name.text = self.owner_name
+ owner.append(owner_name)
+ for i in self.sources:
+ source = ET.Element('source', type=i.__class__.type_key)
+ source.text = i.src
+ repo.append(source)
+ del source
+ for i in self.sources:
+ # NOTE: Two loops on purpose so the
+ # hooks are called with all sources in
+ i.to_xml_hook(repo)
+ for i in self.feeds:
+ feed = ET.Element('feed')
+ feed.text = i
+ repo.append(feed)
+ del feed
+ return repo
+
+
+ def add(self, base):
+ res = 1
+ first_s = True
+ for s in self.sources:
+ if not first_s:
+ self.output.info("\nTrying next source of listed sources...", 4)
+ try:
+ res = s.add(base)
+ if res == 0:
+ # Worked, throw other sources away
+ self.sources = [s]
+ break
+ except Exception, error:
+ self.output.warn(str(error), 4)
+ first_s = False
+ return res
+
+
+ def sync(self, base):
+ self.output.debug("overlay.sync(); name = %s" % self.name, 4)
+ assert len(self.sources) == 1
+ return self.sources[0].sync(base)
+
+
+ def delete(self, base):
+ assert len(self.sources) == 1
+ return self.sources[0].delete(base)
+
+
+ def get_infostr(self):
+ '''
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> import xml.etree.ElementTree as ET # Python 2.5
+ >>> document =ET.parse(here + '/../tests/testfiles/global-overlays.xml')
+ >>> overlays = document.findall('overlay') + document.findall('repo')
+ >>> from layman.output import Message
+ >>> output = Message()
+ >>> a = Overlay({'output': output}, overlays[0])
+ >>> print a.get_infostr()
+ wrobel
+ ~~~~~~
+ Source : https://overlays.gentoo.org/svn/dev/wrobel
+ Contact : nobody@gentoo.org
+ Type : Subversion; Priority: 10
+ Quality : experimental
+ <BLANKLINE>
+ Description:
+ Test
+ <BLANKLINE>
+ '''
+
+ result = u''
+
+ result += self.name + u'\n' + (len(self.name) * u'~')
+
+ if len(self.sources) == 1:
+ result += u'\nSource : ' + self.sources[0].src
+ else:
+ result += u'\nSources:'
+ for i, v in enumerate(self.sources):
+ result += '\n %d. %s' % (i + 1, v.src)
+ result += '\n'
+
+ if self.owner_name != None:
+ result += u'\nContact : %s <%s>' \
+ % (self.owner_name, self.owner_email)
+ else:
+ result += u'\nContact : ' + self.owner_email
+ if len(self.sources) == 1:
+ result += u'\nType : ' + self.sources[0].type
+ else:
+ result += u'\nType : ' + '/'.join(
+ sorted(set(e.type for e in self.sources)))
+ result += u'; Priority: ' + str(self.priority) + u'\n'
+ result += u'Quality : ' + self.quality + u'\n'
+
+
+ description = self.description
+ description = re.compile(u' +').sub(u' ', description)
+ description = re.compile(u'\n ').sub(u'\n', description)
+ result += u'\nDescription:'
+ result += u'\n '.join((u'\n' + description).split(u'\n'))
+ result += u'\n'
+
+ if self.homepage != None:
+ link = self.homepage
+ link = re.compile(u' +').sub(u' ', link)
+ link = re.compile(u'\n ').sub(u'\n', link)
+ result += u'\nLink:'
+ result += u'\n '.join((u'\n' + link).split(u'\n'))
+ result += u'\n'
+
+ if self.irc != None:
+ result += u'\nIRC : ' + self.irc + u'\n'
+
+ if len(self.feeds):
+ result += u'\n%s:' % ((len(self.feeds) == 1) and "Feed" or "Feeds")
+ for i in self.feeds:
+ result += u'\n %s' % i
+ result += u'\n'
+
+ return encoder(result, self._encoding_)
+
+
+ def short_list(self, width = 0):
+ '''
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> import xml.etree.ElementTree as ET # Python 2.5
+ >>> document =ET.parse(here + '/../tests/testfiles/global-overlays.xml')
+ >>> overlays = document.findall('repo') + document.findall('overlay')
+ >>> from layman.output import Message
+ >>> output = Message()
+ >>> a = Overlay({'output': output}, overlays[0])
+ >>> print a.short_list(80)
+ wrobel [Subversion] (https://o.g.o/svn/dev/wrobel )
+ '''
+ name = pad(self.name, 25)
+
+ if len(set(e.type for e in self.sources)) == 1:
+ _type = self.sources[0].type
+ else:
+ _type = '%s/..' % self.sources[0].type
+
+ mtype = ' [' + pad(_type, 10) + ']'
+ if not width:
+ width = terminal_width()-1
+ srclen = width - 43
+ source = ', '.join(self.source_uris())
+ if len(source) > srclen:
+ source = source.replace("overlays.gentoo.org", "o.g.o")
+ source = ' (' + pad(source, srclen) + ')'
+
+ return encoder(name + mtype + source, self._encoding_)
+
+
+ def is_official(self):
+ '''Is the overlay official?'''
+ return self.status == 'official'
+
+
+ def is_supported(self):
+ return any(e.is_supported() for e in self.sources)
+
+
+ def source_uris(self):
+ for i in self.sources:
+ yield i.src
+
+
+ def source_types(self):
+ for i in self.sources:
+ yield i.type
+
+
+#==============================================================================
+#
+# Testing
+#
+#------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod(sys.modules[__name__])
diff --git a/layman/overlays/rsync.py b/layman/overlays/rsync.py
new file mode 100644
index 0000000..f87a7e0
--- /dev/null
+++ b/layman/overlays/rsync.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN RSYNC OVERLAY HANDLER
+#################################################################################
+# File: rsync.py
+#
+# Handles rsync overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+''' Rsync overlay support.'''
+
+__version__ = "$Id: rsync.py 236 2006-09-05 20:39:37Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class RsyncOverlay
+#
+#-------------------------------------------------------------------------------
+
+class RsyncOverlay(OverlaySource):
+ ''' Handles rsync overlays.'''
+
+ type = 'Rsync'
+ type_key = 'rsync'
+
+
+ def __init__(self, parent, config, _location, ignore = 0):
+
+ super(RsyncOverlay, self).__init__(parent, config,
+ _location, ignore)
+ self.subpath = None
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ super(RsyncOverlay, self).add(base)
+
+ return self.sync(base)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ # rsync OPTIONS [-q] SOURCE TARGET
+ args = ['-rlptDvz', '--progress', '--delete', '--delete-after',
+ '--timeout=180', '--exclude=distfiles/*', '--exclude=local/*',
+ '--exclude=packages/*']
+
+ cfg_opts = self.config["rsync_syncopts"]
+ target = path([base, self.parent.name])
+
+ if self.config['quiet']:
+ args.append('-q')
+ if len(cfg_opts):
+ args.append(cfg_opts)
+ args.append(self.src + '/')
+ args.append(target)
+
+ return self.postsync(
+ self.run_command(self.command(), args, cmd=self.type),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'rsync', 'net-misc/rsync'),],
+ self.output.warn)
diff --git a/layman/overlays/source.py b/layman/overlays/source.py
new file mode 100644
index 0000000..843edf4
--- /dev/null
+++ b/layman/overlays/source.py
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+# LAYMAN OVERLAY SOURCE BASE CLASS
+###############################################################################
+# File: source.py
+#
+# Base class for the different overlay types.
+#
+# Copyright:
+# (c) 2010 Sebastian Pipping
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Sebastian Pipping <sebastian@pipping.org>
+
+import os
+import copy
+import sys
+import shutil
+import subprocess
+from layman.utils import path
+
+supported_cache = {}
+
+def _supported(key, check_supported=None):
+ """internal caching function that checks tracks any
+ un-supported/supported repo types."""
+ if key is None:
+ return False
+ if key not in supported_cache:
+ supported_cache[key] = check_supported()
+ return supported_cache[key]
+
+def _resolve_command(command, _output):
+ if os.path.isabs(command):
+ if not os.path.exists(command):
+ _output('Program "%s" not found' % command, 6)
+ return ('File', None)
+ return ('File', command)
+ else:
+ kind = 'Command'
+ env_path = os.environ['PATH']
+ for d in env_path.split(os.pathsep):
+ f = os.path.join(d, command)
+ if os.path.exists(f):
+ return ('Command', f)
+ _output('Cound not resolve command ' +\
+ '"%s" based on PATH "%s"' % (command, env_path), 6)
+ return ('Command', None)
+
+
+def require_supported(binaries, _output):
+ for command, mtype, package in binaries:
+ kind, path = _resolve_command(command, _output)
+ if not path:
+ if _output:
+ _output(kind + ' ' + command + ' seems to be missing!'
+ ' Overlay type "' + mtype + '" not support'
+ 'ed. Did you emerge ' + package + '?', 6)
+ return False
+ return True
+
+
+class OverlaySource(object):
+
+ type_key = None
+
+ def __init__(self, parent, config, _location,
+ ignore = 0):
+ self.parent = parent
+ self.src = _location
+ self.config = config
+ self.ignore = ignore
+
+ self.output = config['output']
+
+ def __eq__(self, other):
+ return self.src == other.src
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def add(self, base):
+ '''Add the overlay.'''
+
+ mdir = path([base, self.parent.name])
+
+ if os.path.exists(mdir):
+ self.output.error('Directory ' + mdir +
+ ' already exists. Will not overwrite its contents!')
+ return False
+
+ os.makedirs(mdir)
+ return True
+
+ def sync(self, base):
+ '''Sync the overlay.'''
+ pass
+
+ def delete(self, base):
+ '''Delete the overlay.'''
+ mdir = path([base, self.parent.name])
+
+ if not os.path.exists(mdir):
+ self.output.warn('Directory ' + mdir + \
+ ' did not exist, no files deleted.')
+ return False
+
+ self.output.info('Deleting directory "%s"' % mdir, 2)
+ shutil.rmtree(mdir)
+ return True
+
+ def supported(self):
+ '''Is the overlay type supported?'''
+ return True
+
+ def is_supported(self):
+ '''Is the overlay type supported?'''
+ return _supported(self.get_type_key(), self.supported)
+
+ def get_type_key(self):
+ return '%s' % self.__class__.type_key
+
+ def command(self):
+ return self.config['%s_command' % self.__class__.type_key]
+
+ def run_command(self, command, args, **kwargs):
+ self.output.debug("OverlaySource.run_command(): " + command, 6)
+ file_to_run = _resolve_command(command, self.output.error)[1]
+ args = [file_to_run] + args
+ assert('pwd' not in kwargs) # Bug detector
+
+ self.output.debug("OverlaySource.run_command(): cleared 'assert'", 7)
+ cwd = kwargs.get('cwd', None)
+ env = None
+ env_updates = None
+ if 'env' in kwargs:
+ # Build actual env from surrounding plus updates
+ env_updates = kwargs['env']
+ env = copy.copy(os.environ)
+ env.update(env_updates)
+
+ command_repr = ' '.join(args)
+ if env_updates is not None:
+ command_repr = '%s %s' % (' '.join('%s=%s' % (k, v) for (k, v)
+ in sorted(env_updates.items())), command_repr)
+ if cwd is not None:
+ command_repr = '( cd %s && %s )' % (cwd, command_repr)
+
+ cmd = kwargs.get('cmd', '')
+ self.output.info('Running %s... # %s' % (cmd, command_repr), 2)
+
+ if self.config['quiet']:
+
+ input_source = subprocess.PIPE
+ output_target = open('/dev/null', 'w')
+ else:
+ # Re-use parent file descriptors
+ input_source = None
+ output_target = None
+
+ proc = subprocess.Popen(args,
+ stdin=input_source,
+ stdout=output_target,
+ stderr=self.config['stderr'],
+ cwd=cwd,
+ env=env)
+
+ if self.config['quiet']:
+ # Make child non-interactive
+ proc.stdin.close()
+
+ try:
+ result = proc.wait()
+ except KeyboardInterrupt:
+ self.output.info('Interrupted manually', 2)
+ self.output.warn("Checking for cleanup actions to perform", 4)
+ self.cleanup()
+ result = 1
+ except Exception, err:
+ self.output.error(
+ 'Unknown exception running command: %s' % command_repr)
+ self.output.error('Original error was: %s' % str(err))
+ result = 1
+
+ if self.config['quiet']:
+ output_target.close()
+
+ if result:
+ self.output.info('Failure result returned from %s' % cmd , 2)
+
+ return result
+
+ def postsync(self, failed_sync, **kwargs):
+ """Runs any repo specific postsync operations
+ """
+ # check if the add/sync operation succeeded
+ if failed_sync:
+ return failed_sync
+ # good to continue
+ postsync_opt = self.config['%s_postsync' % self.__class__.type_key]
+ if len(postsync_opt):
+ # repalce "%cwd=" while it's still a string'
+ _opt = postsync_opt.replace('%cwd=',
+ kwargs.get('cwd', '')).split()
+ command = _opt[0]
+ args = _opt[1:]
+ return self.run_command(command, args,
+ cmd='%s_postsync' % self.__class__.type_key)
+ return failed_sync
+
+ def to_xml_hook(self, repo_elem):
+ pass
+
+ def cleanup(self):
+ '''cleanup a failed/interrupted process
+ overridden in subclass if it is needed.'''
+ pass
diff --git a/layman/overlays/svn.py b/layman/overlays/svn.py
new file mode 100644
index 0000000..3e5497c
--- /dev/null
+++ b/layman/overlays/svn.py
@@ -0,0 +1,116 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+###############################################################################
+# LAYMAN SVN OVERLAY HANDLER
+###############################################################################
+# File: svn.py
+#
+# Handles subversion overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+''' Subversion overlay support.'''
+
+__version__ = "$Id: svn.py 236 2006-09-05 20:39:37Z wrobel $"
+
+#==============================================================================
+#
+# Dependencies
+#
+#------------------------------------------------------------------------------
+
+from layman.utils import path
+from layman.overlays.source import OverlaySource, require_supported
+
+#==============================================================================
+#
+# Class SvnOverlay
+#
+#------------------------------------------------------------------------------
+
+class SvnOverlay(OverlaySource):
+ ''' Handles subversion overlays.'''
+
+ type = 'Subversion'
+ type_key = 'svn'
+
+ def __init__(self, parent, config, _location,
+ ignore = 0):
+
+ super(SvnOverlay, self).__init__(
+ parent, config, _location, ignore)
+ self.subpath = None
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ super(SvnOverlay, self).add(base)
+
+ cfg_opts = self.config["svn_addopts"]
+ self.target = path([base, self.parent.name])
+
+ args = ['co']
+ if self.config['quiet']:
+ args.append('-q')
+ if len(cfg_opts):
+ args.append(cfg_opts)
+ args.append(self.src + '/@')
+ args.append(self.target)
+
+ return self.postsync(
+ self.run_command(self.command(), args, cmd=self.type),
+ cwd=self.target)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ def checkout_location():
+ # Append '@' iff needed
+ # Keeps users of SVN <1.6.5 happy in more cases (bug #313303)
+ repo_part = self.parent.name
+ if self.parent.name.find('@') != -1:
+ repo_part = repo_part + '@'
+ return path([base, repo_part])
+
+ cfg_opts = self.config["svn_syncopts"]
+ self.target = checkout_location()
+
+ # svn up [-q] TARGET
+ args = ['up']
+ if self.config['quiet']:
+ args.append('-q')
+ if len(cfg_opts):
+ args.append(cfg_opts)
+ args.append(self.target)
+
+ return self.postsync(
+ self.run_command(self.command(), args, cmd=self.type),
+ cwd=self.target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'svn','dev-vcs/subversion'),],
+ self.output.warn)
+
+ def cleanup(self):
+ '''Code to run in the event of a keyboard interrupt.
+ runs svn cleanup
+ '''
+ self.output.warn("SVN: preparing to run cleanup()", 2)
+ args = ["cleanup"]
+ args.append(self.target)
+ cleanup = self.run_command(self.command(), args, cmd="svn cleanup")
+ return
diff --git a/layman/overlays/tar.py b/layman/overlays/tar.py
new file mode 100644
index 0000000..c6f2443
--- /dev/null
+++ b/layman/overlays/tar.py
@@ -0,0 +1,224 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN TAR OVERLAY HANDLER
+#################################################################################
+# File: tar.py
+#
+# Handles tar overlays
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+''' Tar overlay support.'''
+
+__version__ = "$Id: tar.py 310 2007-04-09 16:30:40Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import os, os.path, sys, urllib2, shutil, tempfile
+import xml.etree.ElementTree as ET # Python 2.5
+
+from layman.utils import path
+#from layman.debug import OUT
+from layman.overlays.source import OverlaySource, require_supported
+
+#===============================================================================
+#
+# Class TarOverlay
+#
+#-------------------------------------------------------------------------------
+
+class TarOverlay(OverlaySource):
+ ''' Handles tar overlays.
+
+ >>> from layman.output import Message
+ >>> import xml.etree.ElementTree as ET # Python 2.5
+ >>> repo = ET.Element('repo')
+ >>> repo_name = ET.Element('name')
+ >>> repo_name.text = 'dummy'
+ >>> desc = ET.Element('description')
+ >>> desc.text = 'Dummy description'
+ >>> owner = ET.Element('owner')
+ >>> owner_email = ET.Element('email')
+ >>> owner_email.text = 'dummy@example.org'
+ >>> owner[:] = [owner_email]
+ >>> source = ET.Element('source', type='tar')
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> source.text = 'file://' + here + '/../tests/testfiles/layman-test.tar.bz2'
+ >>> subpath = ET.Element('subpath')
+ >>> subpath.text = 'layman-test'
+ >>> repo[:] = [repo_name, desc, owner, source, subpath]
+ >>> from layman.config import BareConfig
+ >>> config = BareConfig()
+ >>> import tempfile
+ >>> testdir = tempfile.mkdtemp(prefix="laymantmp_")
+ >>> from layman.overlays.overlay import Overlay
+ >>> a = Overlay(config, repo)
+ >>> config['output'].set_colorize(False)
+ >>> a.add(testdir)
+ 0
+ >>> os.listdir(testdir + '/dummy/')
+ ['layman-test']
+ >>> sorted(os.listdir(testdir + '/dummy/layman-test/'))
+ ['app-admin', 'app-portage']
+ >>> shutil.rmtree(testdir)
+ '''
+
+ type = 'Tar'
+ type_key = 'tar'
+
+ def __init__(self, parent, config, _location, ignore = 0):
+
+ super(TarOverlay, self).__init__(parent,
+ config, _location, ignore)
+
+ self.output = config['output']
+ self.subpath = None
+
+ def __eq__(self, other):
+ res = super(TarOverlay, self).__eq__(other) \
+ and self.subpath == other.subpath
+ return res
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ # overrider
+ def to_xml_hook(self, repo_elem):
+ if self.subpath:
+ _subpath = ET.Element('subpath')
+ _subpath.text = self.subpath
+ repo_elem.append(_subpath)
+ del _subpath
+
+ def _extract(self, base, tar_url, dest_dir):
+ ext = '.tar.noidea'
+ for i in [('tar.%s' % e) for e in ('bz2', 'gz', 'lzma', 'xz', 'Z')] \
+ + ['tgz', 'tbz', 'taz', 'tlz', 'txz']:
+ candidate_ext = '.%s' % i
+ if self.src.endswith(candidate_ext):
+ ext = candidate_ext
+ break
+
+ try:
+ tar = urllib2.urlopen(tar_url).read()
+ except Exception, error:
+ raise Exception('Failed to fetch the tar package from: '
+ + self.src + '\nError was:' + str(error))
+
+ pkg = path([base, self.parent.name + ext])
+
+ try:
+ out_file = open(pkg, 'w+b')
+ out_file.write(tar)
+ out_file.close()
+ except Exception, error:
+ raise Exception('Failed to store tar package in '
+ + pkg + '\nError was:' + str(error))
+
+ # tar -v -x -f SOURCE -C TARGET
+ args = ['-v', '-x', '-f', pkg, '-C', dest_dir]
+ result = self.run_command(self.command(), args, cmd=self.type)
+
+ os.unlink(pkg)
+ return result
+
+ def _add_unchecked(self, base):
+ def try_to_wipe(folder):
+ if not os.path.exists(folder):
+ return
+
+ try:
+ self.output.info('Deleting directory "%s"' % folder, 2)
+ shutil.rmtree(folder)
+ except Exception, error:
+ raise Exception('Failed to remove unnecessary tar structure "'
+ + folder + '"\nError was:' + str(error))
+
+ final_path = path([base, self.parent.name])
+ temp_path = tempfile.mkdtemp(dir=base)
+ try:
+ result = self._extract(base=base, tar_url=self.src,
+ dest_dir=temp_path)
+ except Exception, error:
+ try_to_wipe(temp_path)
+ raise error
+
+ if result == 0:
+ if self.subpath:
+ source = temp_path + '/' + self.subpath
+ else:
+ source = temp_path
+
+ if os.path.exists(source):
+ if os.path.exists(final_path):
+ self.delete(base)
+
+ try:
+ os.rename(source, final_path)
+ except Exception, error:
+ raise Exception('Failed to rename tar subdirectory ' +
+ source + ' to ' + final_path +
+ '\nError was:' + str(error))
+ os.chmod(final_path, 0755)
+ else:
+ raise Exception('Given subpath "' + source + '" does not exist '
+ ' in the tar package!')
+
+ try_to_wipe(temp_path)
+ return result
+
+ def add(self, base):
+ '''Add overlay.'''
+
+ if not self.supported():
+ return 1
+
+ target = path([base, self.parent.name])
+
+ if os.path.exists(target):
+ raise Exception('Directory ' + target + ' already exists.' +\
+ ' Will not overwrite its contents!')
+
+ return self.postsync(
+ self._add_unchecked(base),
+ cwd=target)
+
+ def sync(self, base):
+ '''Sync overlay.'''
+
+ if not self.supported():
+ return 1
+
+ target = path([base, self.parent.name])
+
+ return self.postsync(
+ self._add_unchecked(base),
+ cwd=target)
+
+ def supported(self):
+ '''Overlay type supported?'''
+
+ return require_supported(
+ [(self.command(), 'tar', 'app-arch/tar'), ],
+ self.output.warn)
+
+if __name__ == '__main__':
+ import doctest
+
+ # Ignore warnings here. We are just testing
+ from warnings import filterwarnings, resetwarnings
+ filterwarnings('ignore')
+
+ doctest.testmod(sys.modules[__name__])
+
+ resetwarnings()
diff --git a/layman/tests/dtest.py b/layman/tests/dtest.py
new file mode 100755
index 0000000..fe973d9
--- /dev/null
+++ b/layman/tests/dtest.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN DOCTEST AGGREGATOR
+#################################################################################
+# File: dtest.py
+#
+# Combines the doctests that are available for the different modules
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+#
+'''Aggregates doctests from all modules that provide such tests.'''
+
+__version__ = '$Id: dtest.py 237 2006-09-05 21:18:54Z wrobel $'
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import unittest, doctest
+
+# On module creation:
+
+# 1.) Check header section (copyright notice)
+# 2.) Add module doc string
+# 3.) Add version string
+# 4.) Add testing handler at bottom of module
+# 5.) Add module into tests/dtest.py. Check that tests run through
+# 6.) Run pylint over the code. Fix any reasonable complaints.
+# 7.) Whitespace clean the buffer.
+# 8.) Add svn:keywords "Id" to file.
+
+# On module change:
+
+# 1.) Check header section (copyright notice)
+# 5.) Check that tests run through
+# 6.) Run pylint over the code. Fix any reasonable complaints.
+# 7.) Whitespace clean the buffer.
+
+# clean modules : CT
+# not yet clean : UT
+# clean but no testing : CN
+# unclean but no testing: UN
+
+import layman.api #CT
+import layman.argsparser #CT
+import layman.cli #CT
+import layman.config #CT
+import layman.db #CT
+import layman.dbbase #CT
+import layman.utils #CT
+import layman.overlays.overlay #CT
+import layman.overlays.tar #CT
+
+#===============================================================================
+#
+# Test Suite
+#
+#-------------------------------------------------------------------------------
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocTestSuite(layman.api),
+ doctest.DocTestSuite(layman.config),
+ doctest.DocTestSuite(layman.argsparser),
+ doctest.DocTestSuite(layman.db),
+ doctest.DocTestSuite(layman.dbbase),
+ doctest.DocTestSuite(layman.utils),
+ doctest.DocTestSuite(layman.overlays.overlay),
+ doctest.DocTestSuite(layman.overlays.tar),
+ ))
+
+#===============================================================================
+#
+# Run Testing
+#
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ # Ignore warnings here. We are just testing
+ from warnings import filterwarnings, resetwarnings
+ filterwarnings('ignore')
+
+ unittest.main(defaultTest='test_suite')
+
+ resetwarnings()
diff --git a/layman/tests/external.py b/layman/tests/external.py
new file mode 100755
index 0000000..00e4a82
--- /dev/null
+++ b/layman/tests/external.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+#################################################################################
+# EXTENRAL LAYMAN TESTS
+#################################################################################
+# File: external.py
+#
+# Runs external (non-doctest) test cases.
+#
+# Copyright:
+# (c) 2009 Sebastian Pipping
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Sebastian Pipping <sebastian@pipping.org>
+#
+'''Runs external (non-doctest) test cases.'''
+
+import unittest
+import os
+import tempfile
+import shutil
+import urllib
+from layman.dbbase import DbBase
+from layman.output import Message
+from layman.config import BareConfig
+from warnings import filterwarnings, resetwarnings
+
+HERE = os.path.dirname(os.path.realpath(__file__))
+
+
+class Unicode(unittest.TestCase):
+ def _overlays_bug(self, number):
+ config = BareConfig()
+ filename = os.path.join(HERE, 'testfiles', 'overlays_bug_%d.xml' % number)
+ o = DbBase(config, [filename])
+ for verbose in (True, False):
+ for t in o.list(verbose=verbose):
+ print t[0]
+ print
+
+ def test_184449(self):
+ self._overlays_bug(184449)
+
+ def test_286290(self):
+ self._overlays_bug(286290)
+
+
+class FormatSubpathCategory(unittest.TestCase):
+ def _run(self, number):
+ #config = {'output': Message()}
+ config = BareConfig()
+ filename1 = os.path.join(HERE, 'testfiles',
+ 'subpath-%d.xml' % number)
+
+ # Read, write, re-read, compare
+ os1 = DbBase(config, [filename1])
+ filename2 = tempfile.mkstemp()[1]
+ os1.write(filename2)
+ os2 = DbBase(config, [filename2])
+ os.unlink(filename2)
+ self.assertTrue(os1 == os2)
+
+ # Pass original overlays
+ return os1
+
+ def test(self):
+ os1 = self._run(1)
+ os2 = self._run(2)
+
+ # Same content from old/layman-global.txt
+ # and new/repositories.xml format?
+ self.assertTrue(os1 == os2)
+
+
+# http://bugs.gentoo.org/show_bug.cgi?id=304547
+class TarAddRemoveSync(unittest.TestCase):
+ def test(self):
+ repo_name = 'tar-test-overlay'
+ tar_source_path = os.path.join(HERE, 'testfiles', 'layman-test.tar.bz2')
+
+ # Duplicate test tarball (so we have it deletable for later)
+ (_, temp_tarball_path) = tempfile.mkstemp()
+ shutil.copyfile(tar_source_path, temp_tarball_path)
+
+ # Write overlay collection XML
+ xml_text = """\
+<?xml version="1.0" encoding="UTF-8"?>
+<repositories xmlns="" version="1.0">
+ <repo quality="experimental" status="unofficial">
+ <name>%(repo_name)s</name>
+ <description>XXXXXXXXXXX</description>
+ <owner>
+ <email>foo@exmaple.org</email>
+ </owner>
+ <source type="tar">file://%(temp_tarball_url)s</source>
+ </repo>
+</repositories>
+""" % { 'temp_tarball_url':urllib.pathname2url(temp_tarball_path),
+ 'repo_name':repo_name}
+ (fd, temp_collection_path) = tempfile.mkstemp()
+ f = os.fdopen(fd, 'w')
+ f.write(xml_text)
+ f.close()
+
+ # Make playground directory
+ temp_dir_path = tempfile.mkdtemp()
+
+ # Make DB from it
+ #config = {'output': Message(), 'tar_command':'/bin/tar'}
+ config = BareConfig()
+ db = DbBase(config, [temp_collection_path])
+
+ specific_overlay_path = os.path.join(temp_dir_path, repo_name)
+ o = db.select('tar-test-overlay')
+
+ # Actual testcase
+ o.add(temp_dir_path)
+ self.assertTrue(os.path.exists(specific_overlay_path))
+ # (1/2) Sync with source available
+ o.sync(temp_dir_path)
+ self.assertTrue(os.path.exists(specific_overlay_path))
+ os.unlink(temp_tarball_path)
+ try:
+ # (2/2) Sync with source _not_ available
+ o.sync(temp_dir_path)
+ except:
+ pass
+ self.assertTrue(os.path.exists(specific_overlay_path))
+ o.delete(temp_dir_path)
+ self.assertFalse(os.path.exists(specific_overlay_path))
+
+ # Cleanup
+ os.unlink(temp_collection_path)
+ os.rmdir(temp_dir_path)
+
+
+if __name__ == '__main__':
+ filterwarnings('ignore')
+ unittest.main()
+ resetwarnings()
diff --git a/layman/tests/pylintrc b/layman/tests/pylintrc
new file mode 100644
index 0000000..b05498a
--- /dev/null
+++ b/layman/tests/pylintrc
@@ -0,0 +1,19 @@
+[MESSAGES CONTROL]
+
+# Disable all messages in the listed categories (IRCWEF).
+disable-msg-cat=IRC
+
+# Disable the message(s) with the given id(s).
+# :W0613: *Unused argument %r*
+# :W0702: *No exception type(s) specified*
+# :W0703: *Catch "Exception"*
+disable-msg=W0613,W0702,W0703
+
+
+[REPORTS]
+
+# Include message's id in output
+include-ids=yes
+
+# Tells whether to display a full report or only the messages
+reports=no
diff --git a/layman/tests/testfiles/global-overlays.xml b/layman/tests/testfiles/global-overlays.xml
new file mode 100644
index 0000000..d770692
--- /dev/null
+++ b/layman/tests/testfiles/global-overlays.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" ?>
+<layman>
+
+ <overlay
+ type = "svn"
+ src = "https://overlays.gentoo.org/svn/dev/wrobel"
+ contact = "nobody@gentoo.org"
+ name = "wrobel"
+ status = "official"
+ priority = "10">
+
+ <description>
+ Test
+ </description>
+
+ </overlay>
+
+ <overlay
+ type = "rsync"
+ src = "rsync://gunnarwrobel.de/wrobel-stable"
+ contact = "nobody@gentoo.org"
+ name = "wrobel-stable">
+
+ <description>
+ A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].
+ </description>
+
+ </overlay>
+
+</layman>
diff --git a/layman/tests/testfiles/layman-test.tar.bz2 b/layman/tests/testfiles/layman-test.tar.bz2
new file mode 100644
index 0000000..85ee7fd
--- /dev/null
+++ b/layman/tests/testfiles/layman-test.tar.bz2
Binary files differ
diff --git a/layman/tests/testfiles/make.conf b/layman/tests/testfiles/make.conf
new file mode 100644
index 0000000..9a8aac6
--- /dev/null
+++ b/layman/tests/testfiles/make.conf
@@ -0,0 +1,345 @@
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-src/portage/cnf/make.conf.x86,v 1.5.2.5 2005/04/13 15:28:38 jstubbs Exp $
+# Contains local system settings for Portage system
+
+# Please review 'man make.conf' for more information.
+
+# Build-time functionality
+# ========================
+#
+# The USE variable is used to enable optional build-time functionality. For
+# example, quite a few packages have optional X, gtk or GNOME functionality
+# that can only be enabled or disabled at compile-time. Gentoo Linux has a
+# very extensive set of USE variables described in our USE variable HOWTO at
+# http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=2&chap=1
+#
+# The available list of use flags with descriptions is in your portage tree.
+# Use 'less' to view them: --> less /usr/portage/profiles/use.desc <--
+#
+# 'ufed' is an ncurses/dialog interface available in portage to make handling
+# useflags for you. 'emerge app-portage/ufed'
+#
+# Example:
+
+# Use flags will be handled by polymeraZe
+USE="-*"
+
+# Host Setting
+# ============
+#
+# DO NOT CHANGE THIS SETTING UNLESS YOU ARE USING STAGE1!
+# Change this line as appropriate (i686, i586, i486 or i386).
+# All modern systems (even Athlons) should use "i686-pc-linux-gnu".
+# All K6's are i586.
+CHOST="i686-pc-linux-gnu"
+
+# Host and optimization settings
+# ==============================
+#
+# For optimal performance, enable a CFLAGS setting appropriate for your CPU.
+#
+# Please note that if you experience strange issues with a package, it may be
+# due to gcc's optimizations interacting in a strange way. Please test the
+# package (and in some cases the libraries it uses) at default optimizations
+# before reporting errors to developers.
+#
+# -mcpu=<cpu-type> means optimize code for the particular type of CPU without
+# breaking compatibility with other CPUs.
+#
+# -march=<cpu-type> means to take full advantage of the ABI and instructions
+# for the particular CPU; this will break compatibility with older CPUs (for
+# example, -march=athlon-xp code will not run on a regular Athlon, and
+# -march=i686 code will not run on a Pentium Classic.
+#
+# CPU types supported in gcc-3.2 and higher: athlon-xp, athlon-mp,
+# athlon-tbird, athlon, k6, k6-2, k6-3, i386, i486, i586 (Pentium), i686
+# (PentiumPro), pentium, pentium-mmx, pentiumpro, pentium2 (Celeron),
+# pentium3, and pentium4.
+#
+# Note that Gentoo Linux 1.4 and higher include at least gcc-3.2.
+#
+# CPU types supported in gcc-2.95*: k6, i386, i486, i586 (Pentium), i686
+# (Pentium Pro), pentium, pentiumpro Gentoo Linux 1.2 and below use gcc-2.95*
+#
+# CRITICAL WARNINGS: ****************************************************** #
+# K6 markings are deceptive. Avoid setting -march for them. See Bug #24379. #
+# Pentium-M CPU's should not enable sse2 until at least gcc-3.4. Bug 50616. #
+# ************************************************************************* #
+#
+# Decent examples:
+#
+#CFLAGS="-mcpu=athlon-xp -O3 -pipe"
+
+CFLAGS="-march=athlon-xp -O3 -pipe"
+
+
+# If you set a CFLAGS above, then this line will set your default C++ flags to
+# the same settings.
+CXXFLAGS="${CFLAGS}"
+
+# Advanced Masking
+# ================
+#
+# Gentoo is using a new masking system to allow for easier stability testing
+# on packages. KEYWORDS are used in ebuilds to mask and unmask packages based
+# on the platform they are set for. A special form has been added that
+# indicates packages and revisions that are expected to work, but have not yet
+# been approved for the stable set. '~arch' is a superset of 'arch' which
+# includes the unstable, in testing, packages. Users of the 'x86' architecture
+# would add '~x86' to ACCEPT_KEYWORDS to enable unstable/testing packages.
+# '~ppc', '~sparc' are the unstable KEYWORDS for their respective platforms.
+#
+# Please note that this is not for development, alpha, beta, nor cvs release
+# packages. "Broken" packages will not be added to testing and should not be
+# requested to be added. Alternative routes are available to developers
+# for experimental packages, and it is at their discretion to use them.
+#
+# DO NOT PUT ANYTHING BUT YOUR SPECIFIC ~ARCHITECTURE IN THE LIST.
+# IF YOU ARE UNSURE OF YOUR ARCH, OR THE IMPLICATIONS, DO NOT MODIFY THIS.
+#
+
+ACCEPT_KEYWORDS="x86"
+
+
+# Portage Directories
+# ===================
+#
+# Each of these settings controls an aspect of portage's storage and file
+# system usage. If you change any of these, be sure it is available when
+# you try to use portage. *** DO NOT INCLUDE A TRAILING "/" ***
+#
+# PORTAGE_TMPDIR is the location portage will use for compilations and
+# temporary storage of data. This can get VERY large depending upon
+# the application being installed.
+PORTAGE_TMPDIR=/var/tmp
+#
+# PORTDIR is the location of the portage tree. This is the repository
+# for all profile information as well as all ebuilds. If you change
+# this, you must update your /etc/make.profile symlink accordingly.
+PORTDIR=/usr/portage
+#
+# DISTDIR is where all of the source code tarballs will be placed for
+# emerges. The source code is maintained here unless you delete
+# it. The entire repository of tarballs for gentoo is 9G. This is
+# considerably more than any user will ever download. 2-3G is
+# a large DISTDIR.
+DISTDIR=/usr/distfiles
+#
+# PKGDIR is the location of binary packages that you can have created
+# with '--buildpkg' or '-b' while emerging a package. This can get
+# upto several hundred megs, or even a few gigs.
+#PKGDIR=${PORTDIR}/packages
+#
+# PORT_LOGDIR is the location where portage will store all the logs it
+# creates from each individual merge. They are stored as NNNN-$PF.log
+# in the directory specified. This is disabled until you enable it by
+# providing a directory. Permissions will be modified as needed IF the
+# directory exists, otherwise logging will be disabled. NNNN is the
+# increment at the time the log is created. Logs are thus sequential.
+PORT_LOGDIR=/var/log/services/portage.d
+#
+# PORTDIR_OVERLAY is a directory where local ebuilds may be stored without
+# concern that they will be deleted by rsync updates. Default is not
+# defined.
+PORTDIR_OVERLAY="
+/var/lib/layman/wrobel-stable
+$PORTDIR_OVERLAY
+/usr/local/portage/ebuilds/testing
+/usr/local/portage/ebuilds/stable
+/usr/local/portage/kolab2
+/usr/local/portage/gentoo-webapps-overlay/experimental
+/usr/local/portage/gentoo-webapps-overlay/production-ready"
+
+# Fetching files
+# ==============
+#
+# If you need to set a proxy for wget or lukemftp, add the appropriate "export
+# ftp_proxy=<proxy>" and "export http_proxy=<proxy>" lines to /etc/profile if
+# all users on your system should use them.
+#
+# Portage uses wget by default. Here are some settings for some alternate
+# downloaders -- note that you need to merge these programs first before they
+# will be available.
+#
+# Default fetch command (5 tries, passive ftp for firewall compatibility)
+#FETCHCOMMAND="/usr/bin/wget -t 5 --passive-ftp \${URI} -P \${DISTDIR}"
+#RESUMECOMMAND="/usr/bin/wget -c -t 5 --passive-ftp \${URI} -P \${DISTDIR}"
+#
+# Using wget, ratelimiting downloads
+#FETCHCOMMAND="/usr/bin/wget -t 5 --passive-ftp --limit-rate=200k \${URI} -P \${DISTDIR}"
+#RESUMECOMMAND="/usr/bin/wget -c -t 5 --passive-ftp --limit-rate=200k \${URI} -P \${DISTDIR}"
+#
+# Lukemftp (BSD ftp):
+#FETCHCOMMAND="/usr/bin/lukemftp -s -a -o \${DISTDIR}/\${FILE} \${URI}"
+#RESUMECOMMAND="/usr/bin/lukemftp -s -a -R -o \${DISTDIR}/\${FILE} \${URI}"
+#
+
+FETCHCOMMAND="/usr/bin/getdelta.sh \${URI}"
+
+
+# Portage uses GENTOO_MIRRORS to specify mirrors to use for source retrieval.
+# The list is a space separated list which is read left to right. If you use
+# another mirror we highly recommend leaving the default mirror at the end of
+# the list so that portage will fall back to it if the files cannot be found
+# on your specified mirror. We _HIGHLY_ recommend that you change this setting
+# to a nearby mirror by merging and using the 'mirrorselect' tool.
+
+GENTOO_MIRRORS="http://pandemonium.tiscali.de/pub/gentoo/ ftp://pandemonium.tiscali.de/pub/gentoo/ ftp://ftp-stud.fht-esslingen.de/pub/Mirrors/gentoo/ http://mir.zyrianes.net/gentoo/ http://ftp.snt.utwente.nl/pub/os/linux/gentoo http://distfiles.gentoo.org http://www.ibiblio.org/pub/Linux/distributions/gentoo"
+
+#
+# Portage uses PORTAGE_BINHOST to specify mirrors for prebuilt-binary packages.
+# The list is a single entry specifying the full address of the directory
+# serving the tbz2's for your system. Running emerge with either '--getbinpkg'
+# or '--getbinpkgonly' will cause portage to retrieve the metadata from all
+# packages in the directory specified, and use that data to determine what will
+# be downloaded and merged. '-g' or '-gK' are the recommend parameters. Please
+# consult the man pages and 'emerge --help' for more information. For FTP, the
+# default connection is passive -- If you require an active connection, affix
+# an asterisk (*) to the end of the host:port string before the path.
+#PORTAGE_BINHOST="http://grp.mirror.site/gentoo/grp/1.4/i686/athlon-xp/"
+# This ftp connection is passive ftp.
+#PORTAGE_BINHOST="ftp://login:pass@grp.mirror.site/pub/grp/i686/athlon-xp/"
+# This ftp connection is active ftp.
+#PORTAGE_BINHOST="ftp://login:pass@grp.mirror.site:21*/pub/grp/i686/athlon-xp/"
+
+# Synchronizing Portage
+# =====================
+#
+# Each of these settings affects how Gentoo synchronizes your Portage tree.
+# Synchronization is handled by rsync and these settings allow some control
+# over how it is done.
+#
+#
+# SYNC is the server used by rsync to retrieve a localized rsync mirror
+# rotation. This allows you to select servers that are geographically
+# close to you, yet still distribute the load over a number of servers.
+# Please do not single out specific rsync mirrors. Doing so places undue
+# stress on particular mirrors. Instead you may use one of the following
+# continent specific rotations:
+#
+# Default: "rsync://rsync.gentoo.org/gentoo-portage"
+# North America: "rsync://rsync.namerica.gentoo.org/gentoo-portage"
+# South America: "rsync://rsync.samerica.gentoo.org/gentoo-portage"
+# Europe: "rsync://rsync.europe.gentoo.org/gentoo-portage"
+# Asia: "rsync://rsync.asia.gentoo.org/gentoo-portage"
+# Australia: "rsync://rsync.au.gentoo.org/gentoo-portage"
+
+SYNC="rsync://rsync.europe.gentoo.org/gentoo-portage"
+
+#
+# RSYNC_RETRIES sets the number of times portage will attempt to retrieve
+# a current portage tree before it exits with an error. This allows
+# for a more successful retrieval without user intervention most times.
+#RSYNC_RETRIES="3"
+#
+# RSYNC_TIMEOUT sets the length of time rsync will wait before it times out
+# on a connection. Most users will benefit from this setting as it will
+# reduce the amount of 'dead air' they experience when they run across
+# the occasional, unreachable mirror. Dialup users might want to set this
+# value up around the 300 second mark.
+#RSYNC_TIMEOUT=180
+
+# Advanced Features
+# =================
+#
+# MAKEOPTS provides extra options that may be passed to 'make' when a
+# program is compiled. Presently the only use is for specifying
+# the number of parallel makes (-j) to perform. The suggested number
+# for parallel makes is CPUs+1.
+MAKEOPTS="-j2"
+#
+# PORTAGE_NICENESS provides a default increment to emerge's niceness level.
+# Note: This is an increment. Running emerge in a niced environment will
+# reduce it further. Default is unset.
+PORTAGE_NICENESS=3
+#
+# AUTOCLEAN enables portage to automatically clean out older or overlapping
+# packages from the system after every successful merge. This is the
+# same as running 'emerge -c' after every merge. Set with: "yes" or "no".
+# This does not affect the unpacked source. See 'noclean' below.
+AUTOCLEAN="yes"
+#
+# PORTAGE_TMPFS is a location where portage may create temporary files.
+# If specified, portage will use this directory whenever possible
+# for all rapid operations such as lockfiles and transient data.
+# It is _highly_ recommended that this be a tmpfs or ramdisk. Do not
+# set this to anything that does not give a significant performance
+# enhancement and proper FS compliance for locks and read/write.
+# /dev/shm is a glibc mandated tmpfs, and should be a reasonable
+# setting for all linux kernel+glibc based systems.
+#PORTAGE_TMPFS="/dev/shm"
+#
+# FEATURES are settings that affect the functionality of portage. Most of
+# these settings are for developer use, but some are available to non-
+# developers as well.
+#
+# 'autoaddcvs' causes portage to automatically try to add files to cvs
+# that will have to be added later. Done at generation times
+# and only has an effect when 'cvs' is also set.
+# 'buildpkg' causes binary packages to be created of all packages that
+# are being merged.
+# 'ccache' enables ccache support via CC.
+# 'collision-protect'
+# prevents packages from overwriting files that are owned by
+# another package or by no package at all.
+# 'cvs' causes portage to enable all cvs features (commits, adds),
+# and to apply all USE flags in SRC_URI for digests -- for
+# developers only.
+# 'digest' causes digests to be generated for all packages being merged.
+# 'distcc' enables distcc support via CC.
+# 'distlocks' enables distfiles locking using fcntl or hardlinks. This
+# is enabled by default. Tools exist to help clean the locks
+# after crashes: /usr/lib/portage/bin/clean_locks.
+# 'fixpackages' allows portage to fix binary packages that are stored in
+# PKGDIR. This can consume a lot of time. 'fixpackages' is
+# also a script that can be run at any given time to force
+# the same actions.
+# 'gpg' enables basic verification of Manifest files using gpg.
+# This features is UNDER DEVELOPMENT and reacts to features
+# of strict and severe. Heavy use of gpg sigs is coming.
+# 'keeptemp' prevents the clean phase from deleting the temp files ($T)
+# from a merge.
+# 'keepwork' prevents the clean phase from deleting the WORKDIR.
+# 'maketest' causes ebuilds to perform testing phases if they are capable
+# of it. Some packages support this automaticaly via makefiles.
+# 'noauto' causes ebuild to perform only the action requested and
+# not any other required actions like clean or unpack -- for
+# debugging purposes only.
+# 'noclean' prevents portage from removing the source and temporary files
+# after a merge -- for debugging purposes only.
+# 'nostrip' prevents the stripping of binaries.
+# 'notitles' disables xterm titlebar updates (which contain status info).
+# 'sandbox' enables sandboxing when running emerge and ebuild.
+# 'strict' causes portage to react strongly to conditions that are
+# potentially dangerous, like missing/incorrect Manifest files.
+# 'userpriv' allows portage to drop root privileges while it is compiling,
+# as a security measure. As a side effect this can remove
+# sandbox access violations for users.
+# 'usersandbox' enables sandboxing while portage is running under userpriv.
+#FEATURES="sandbox buildpkg ccache distcc userpriv usersandbox notitles noclean noauto cvs keeptemp keepwork autoaddcvs"
+FEATURES="sandbox ccache userprivs distlocks cvs"
+#
+# CCACHE_SIZE sets the space use limitations for ccache. The default size is
+# 2G, and will be set if not defined otherwise and ccache is in features.
+# Portage will set the default ccache dir if it is not present in the
+# user's environment, for userpriv it sets: ${PORTAGE_TMPDIR}/ccache
+# (/var/tmp/ccache), and for regular use the default is /root/.ccache.
+# Sizes are specified with 'G' 'M' or 'K'.
+# '2G' for 2 gigabytes, '2048M' for 2048 megabytes (same as 2G).
+CCACHE_SIZE="1G"
+#
+# DISTCC_DIR sets the temporary space used by distcc.
+#DISTCC_DIR="${PORTAGE_TMPDIR}/.distcc"
+#
+# RSYNC_EXCLUDEFROM is a file that portage will pass to rsync when it updates
+# the portage tree. Specific chunks of the tree may be excluded from
+# consideration. This may cause dependency failures if you are not careful.
+# The file format is one pattern per line, blanks and ';' or '#' lines are
+# comments. See 'man rsync' for more details on the exclude-from format.
+#RSYNC_EXCLUDEFROM=/etc/portage/rsync_excludes
+EBEEP_IGNORE=yes
+
+CONFIG_PROTECT_MASK="/usr/X11R6/lib/X11"
+
+
diff --git a/layman/tests/testfiles/overlays_bug_184449.xml b/layman/tests/testfiles/overlays_bug_184449.xml
new file mode 100644
index 0000000..c8dff2d
--- /dev/null
+++ b/layman/tests/testfiles/overlays_bug_184449.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<layman>
+
+ <overlay
+ type = "svn"
+ src = "https://overlays.gentoo.org/svn/dev/wrobel"
+ contact = "nobody@gentoo.org"
+ name = "wrÖbel"
+ status = "official"
+ priority = "10">
+
+ <description>
+ Test ä
+ </description>
+
+ </overlay>
+
+
+</layman>
diff --git a/layman/tests/testfiles/overlays_bug_286290.xml b/layman/tests/testfiles/overlays_bug_286290.xml
new file mode 100644
index 0000000..1d4bd1b
--- /dev/null
+++ b/layman/tests/testfiles/overlays_bug_286290.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<layman>
+ <overlay contact="media-video@gentoo.org"
+ name="multimedia"
+ src="git://gitorious.org/gentoo-multimedia/gentoo-multimedia.git"
+ status="official"
+ type="git">
+ <link>http://gitorious.org/gentoo-multimedia</link>
+ <description>Repository for development of (mostly bleeding-edge)
+ multimedia packages for Gentoo Linux. This is the official overlay
+ for Gentoo’s media herds.</description>
+ </overlay>
+</layman>
diff --git a/layman/tests/testfiles/subpath-1.xml b/layman/tests/testfiles/subpath-1.xml
new file mode 100644
index 0000000..ddb0e3e
--- /dev/null
+++ b/layman/tests/testfiles/subpath-1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<layman>
+ <overlay
+ name="b_name"
+ contact="b_owner@example.org"
+ type="tar"
+ src="http://example.org/b.tar.gz"
+ subpath="b_path">
+ <description>b_desc</description>
+ </overlay>
+ <overlay
+ name="c_name"
+ contact="c_owner@example.org"
+ type="cvs"
+ src=":pserver:username@example.org:/usr/local/cvs-repository"
+ subpath="c_path">
+ <description>c_desc</description>
+ </overlay>
+</layman>
diff --git a/layman/tests/testfiles/subpath-2.xml b/layman/tests/testfiles/subpath-2.xml
new file mode 100644
index 0000000..aa11497
--- /dev/null
+++ b/layman/tests/testfiles/subpath-2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE repositories SYSTEM "/dtd/repositories.dtd">
+<repositories xmlns="" version="1.0">
+ <repo>
+ <name>b_name</name>
+ <description>b_desc</description>
+ <owner>
+ <email>b_owner@example.org</email>
+ </owner>
+ <source type="tar">http://example.org/b.tar.gz</source>
+ <subpath>b_path</subpath>
+ </repo>
+ <repo>
+ <name>c_name</name>
+ <description>c_desc</description>
+ <owner>
+ <email>c_owner@example.org</email>
+ </owner>
+ <source type="cvs">:pserver:username@example.org:/usr/local/cvs-repository</source>
+ <subpath>c_path</subpath>
+ </repo>
+</repositories>
diff --git a/layman/utils.py b/layman/utils.py
new file mode 100644
index 0000000..9ffdda0
--- /dev/null
+++ b/layman/utils.py
@@ -0,0 +1,214 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# POLYMERAZE XML UTILITIES
+#################################################################################
+# File: xml.py
+#
+# Utilities to deal with xml nodes.
+#
+# Copyright:
+# (c) 2005 - 2008 Gunnar Wrobel
+# (c) 2009 Sebastian Pipping
+# (c) 2009 Christian Groschupp
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Sebastian Pipping <sebastian@pipping.org>
+# Christian Groschupp <christian@groschupp.org>
+#
+
+'''Utility functions to deal with xml nodes. '''
+
+__version__ = '$Id: utils.py 236 2006-09-05 20:39:37Z wrobel $'
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import types, re, os
+import sys
+import locale
+import codecs
+
+from layman.debug import OUT
+
+
+#===============================================================================
+#
+# Helper functions
+#
+#-------------------------------------------------------------------------------
+
+def encoder(text, _encoding_):
+ return codecs.encode(text, _encoding_, 'replace')
+
+
+def decode_selection(selection):
+ '''utility function to decode a list of strings
+ accoring to the filesystem encoding
+ '''
+ # fix None passed in, return an empty list
+ selection = selection or []
+ enc = sys.getfilesystemencoding()
+ if enc is not None:
+ return [encoder(i, enc) for i in selection]
+ return selection
+
+
+def get_encoding(output):
+ if hasattr(output, 'encoding') \
+ and output.encoding != None:
+ return output.encoding
+ else:
+ encoding = locale.getpreferredencoding()
+ # Make sure that python knows the encoding. Bug 350156
+ try:
+ # We don't care about what is returned, we just want to
+ # verify that we can find a codec.
+ codecs.lookup(encoding)
+ except LookupError:
+ # Python does not know the encoding, so use utf-8.
+ encoding = 'utf_8'
+ return encoding
+
+
+def pad(string, length):
+ '''Pad a string with spaces.'''
+ if len(string) <= length:
+ return string + ' ' * (length - len(string))
+ else:
+ return string[:length - 3] + '...'
+
+
+def terminal_width():
+ '''Determine width of terminal window.'''
+ try:
+ width = int(os.environ['COLUMNS'])
+ if width > 0:
+ return width
+ except:
+ pass
+ try:
+ import struct, fcntl, termios
+ query = struct.pack('HHHH', 0, 0, 0, 0)
+ response = fcntl.ioctl(1, termios.TIOCGWINSZ, query)
+ width = struct.unpack('HHHH', response)[1]
+ if width > 0:
+ return width
+ except:
+ pass
+ return 80
+
+
+# From <http://effbot.org/zone/element-lib.htm>
+# BEGIN
+def indent(elem, level=0):
+ i = "\n" + level*" "
+ if len(elem):
+ if not elem.text or not elem.text.strip():
+ elem.text = i + " "
+ if not elem.tail or not elem.tail.strip():
+ elem.tail = i
+ for elem in elem:
+ indent(elem, level+1)
+ if not elem.tail or not elem.tail.strip():
+ elem.tail = i
+ else:
+ if level and (not elem.tail or not elem.tail.strip()):
+ elem.tail = i
+# END
+
+def path(path_elements):
+ '''
+ Concatenate a path from several elements.
+
+ >>> path([])
+ ''
+ >>> path(['a'])
+ 'a'
+ >>> path(['a','b'])
+ 'a/b'
+ >>> path(['a/','b'])
+ 'a/b'
+ >>> path(['/a/','b'])
+ '/a/b'
+ >>> path(['/a/','b/'])
+ '/a/b'
+ >>> path(['/a/','b/'])
+ '/a/b'
+ >>> path(['/a/','/b/'])
+ '/a/b'
+ >>> path(['/a/','/b','c/'])
+ '/a/b/c'
+ '''
+ pathname = ''
+
+ if type(path_elements) in types.StringTypes:
+ path_elements = [path_elements]
+
+ # Concatenate elements and seperate with /
+ for i in path_elements:
+ pathname += i + '/'
+
+ # Replace multiple consecutive slashes
+ pathname = re.compile('/+').sub('/', pathname)
+
+ # Remove the final / if there is one
+ if pathname and pathname[-1] == '/':
+ pathname = pathname[:-1]
+
+ return pathname
+
+def delete_empty_directory(mdir, output=OUT):
+ if os.path.exists(mdir) and not os.listdir(mdir):
+ # Check for sufficient privileges
+ if os.access(mdir, os.W_OK):
+ output.info('Deleting _empty_ directory "%s"' % mdir, 2)
+ try:
+ os.rmdir(mdir)
+ except OSError, error:
+ output.warn(str(error))
+ else:
+ output.warn('Insufficient permissions to delete _empty_ folder "%s".' % mdir)
+ import getpass
+ if getpass.getuser() != 'root':
+ output.warn('Hint: You are not root.')
+
+
+def create_overlay_dict(**kwargs):
+ """Creates a complete empty reository definition.
+ Then fills it with values passed in
+ """
+ result = {
+ 'name': '',
+ 'owner_name': '',
+ 'owner_email': '',
+ 'homepage': '',
+ 'irc': '',
+ 'description': '',
+ 'feeds': [],
+ 'sources': [('','','')],
+ 'priority': 50,
+ 'quality': u'experimental',
+ 'status': '',
+ 'official': False,
+ 'supported': False,
+ }
+ for key in kwargs:
+ result[key] = kwargs[key]
+ return result
+
+
+#===============================================================================
+#
+# Testing
+#
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ import doctest, sys
+ doctest.testmod(sys.modules[__name__])
diff --git a/layman/version.py b/layman/version.py
new file mode 100644
index 0000000..90c7412
--- /dev/null
+++ b/layman/version.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN VERSION
+#################################################################################
+# File: version.py
+#
+# Current version number
+#
+# Copyright:
+# (c) 2005 - 2009 Gunnar Wrobel
+# (c) 2009 Sebastian Pipping
+# (c) 2011 Brian Dolbec
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel <wrobel@gentoo.org>
+# Sebastian Pipping <sebastian@pipping.org>
+# Brian Dolbec <brian.dolbec@gmail.com>
+#
+
+__version__ = "$Id: version.py 309 2007-04-09 16:23:38Z wrobel $"
+
+
+VERSION = '2.0.0-git'
+
+if __name__ == '__main__':
+ print VERSION
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..a8c0457
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+import sys
+
+from distutils.core import setup
+
+# this affects the names of all the directories we do stuff with
+sys.path.insert(0, './')
+from layman.version import VERSION
+
+
+setup(name = 'layman',
+ version = VERSION,
+ description = 'Python script for retrieving gentoo overlays',
+ author = 'Gunnar Wrobel, Brian Dolbec',
+ author_email = 'wrobel@gentoo.org, brian.dolbec@gmail.com',
+ url = 'http://layman.sourceforge.net/, ' +\
+ 'http://git.overlays.gentoo.org/gitweb/?p=proj/layman.git;a=summary',
+ packages = ['layman', 'layman.overlays'],
+ scripts = ['bin/layman'],
+ license = 'GPL',
+ )
diff --git a/testpath.example b/testpath.example
new file mode 100644
index 0000000..8f2d826
--- /dev/null
+++ b/testpath.example
@@ -0,0 +1,17 @@
+# Sample file demonstrating an easy method for running the
+# git sources without the need for installing.
+
+
+# Edit the paths below and save the file as "testpath"
+# the file will be ignored by git.
+
+# Example usage:
+
+# $ cd Dev/git/layman
+# $ source ./testpath
+# $ layman -l
+
+
+export PATH="/home/brian/Dev/git/layman/bin:${PATH}"
+
+export PYTHONPATH="/home/brian/Dev/git/layman/:${PYTHONPATH}"
diff --git a/testsuite.sh b/testsuite.sh
new file mode 100755
index 0000000..ce125d2
--- /dev/null
+++ b/testsuite.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+# Copyright (C) 2010 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under GPLv2
+
+ret=0
+for script in layman/tests/*.py ; do
+ echo "# PYTHONPATH=\"${PWD}\" python \"${script}\""
+ PYTHONPATH="${PWD}" python "${script}" \
+ || ret=1
+done
+
+[[ ${ret} != 0 ]] && echo '!!! FAIL'
+exit ${ret}