Move pisi-1.0_alpha2 tag

This commit is contained in:
Fatih Aşıcı
2009-10-27 10:12:48 +00:00
parent 70663a75ba
commit 2ce1296005
124 changed files with 0 additions and 14457 deletions
-75
View File
@@ -1,75 +0,0 @@
Like every serious project, there are guidelines.
Oooooo. "Coding Standards".
Guidelines
----------
1. When using dirnames, don't expect the dir to end
with a trailing slash, and please use the dirnames
in pisiconfig
2. Python indentation is usually 4 chars.
3. Follow python philosophy of 'batteries included'
4. Don't make the code have runtime dependencies on
a particular distribution (as much as possible)
5. Don't assume narrow use cases.
6. If you are changing something, check if that change
breaks anything and fix breakage. For instance a
name. Running the tests is not always enough!
Unit testing
------------
Unit tests are located in unittests directory. Running the tests is
trivial. But you must synchronize your code and data with the test
code, which can be a tedious work if you lose discipline.
Sample data files are located in the same directory with test modules.
For running the entire test suite, use the following command:
$ ./unittests/run.py
If you know what you are doing, you can run the tests seperately. But
keep in your mind that tests can depend on each other. (?) The unit test
system doesn't know about that. The following command will run tests
in specfiletests and archivetests in unittests dir:
$ ./unittests/run.py specfile archive
Misc. Suggestions
-----------------
1. Demeter's Law
In OO programming, try to invoke Demeter's law.
One of the "rules" there is not directly accessing any
objects that are further than, 2/3 refs, away. So the
following code is OK.
destroy_system(a.system().name())
but the following isn't as robust
destroy_system(object_store.root().a.system.name())
As you can tell, this introduces too many implementation
dependencies. The rule of thumb is that, in these cases
this statement must have been elsewhere.... It may be a
good idea to not count the object scope in this case,
so in Python self.a means only one level of reference,
not two.
One quibble with this: it may be preferable not to insist
on this where it would be inefficient. So if everything
is neatly packed into one object contained in another
object, why replicate everything in the upper level? If
the semantics prevents dependency changes, then chains
of 3 or even 4 could be acceptable.
OTOH, in Python and C++, it's not always good to implement
accessor/modifier pairs for every property of an object.
It would be much simpler if you are not doing any special
processing on the property (e.g. if what the type system
does is sufficient).
The main rule of thumb in Demeter's Law is avoiding
putting more than, say, 10 methods in a class. That works
really well in practice, forcing refactoring every now
and then.
-346
View File
@@ -1,346 +0,0 @@
NOTE! The GPL below is copyrighted by the Free Software Foundation, but
the instance of code that it refers to (the kde programs) are copyrighted
by the authors who actually wrote it.
---------------------------------------------------------------------------
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
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
-4
View File
@@ -1,4 +0,0 @@
recursive-include tests *.py
recursive-include doc *
recursive-include spec *
recursive-include samples *
-12
View File
@@ -1,12 +0,0 @@
PISI - Packages Installed Succesfully as Intented
PISI is a new package manager implemented in python for the PARDUS
distribution.
Main features
- Implemented in python.
- All specification and intermediate data is in an XML format.
- Fast database access implemented with berkeley DB.
- Integrates both low-level and high-level package operations.
-159
View File
@@ -1,159 +0,0 @@
PiSi TODO List
==============
A list of tasks to accomplish, organized into priority sections
Legend:
- Todo
? Not determined if/how we have to do
/ In progress
+ Accomplished
1. Pre-Alpha
+ reading spec file
+ writing
+ files
+ metadata
+ Actions API framework
+ sample api modules (autotools)
+ unit test
+ source building
+ package module
+ extraction
+ add file / compression
+ package creation
+ install database
+ package database
+ command line interface
+ pisi-build
+ pisi-install
+ pisi-index
+ pisi-updatedb
+ single repository index
+ simple dependency checking
+ Package/Files
2. Alpha
+ multi-package dependency analysis (eray)
+ design a package operation planner
+ install/remove operations (eray)
+ command line interface:
+ pisi remove
+ svn-like CLI
+ configuration file
+ define the format of the configuration file
+ extend Config module (config.py) accordingly
+ define configuration keys (baris - meren)
+ query
+ list of installed packages (eray)
+ refactor actionsAPI (caglar)
+ fix xml indentation (meren)
+ define file types (doc, executable, conf, etc...) (baris - meren)
+ write specfile (eray)
+ file locking for database access [not tested!] (eray)
+ implement file uri
+ extend the modules dealing with files accordingly
+ ui module improvements
+ methods for interaction (yes, no questions, etc.)
+ implement source database (eray)
+ easy package preparation
+ convert ebuild to pisi
+ COMAR interface
+ what do we need to specify in a package.
+ package install: register config script
+ package remove: unregister config script
+ internet installation
+ support URI's whereever a filename is supported
+ http server
+ pisi updatedb over internet
3. Beta
- configure-pending (eray)
/ autoxml: automated xml processing (eray)
+ design
+ basic types
/ list type
- class type
/ localtext type
/ components (eray)
+ requirements
- xml format
- query components: list of components/packages in a component
- install/remove components
/ API: we even have application users (eray)
/ multiple package repository (eray)
+ decide how to implement
+ support repo order
- support medium types
- internet: http/ftp
- local repository: file://
- removable media: media://
/ i18n support
/ UI
? pyqt UI class to interface
- PISIMAT
/ pykde GUI (cartman)
+ improve interface
+ refactor UI, reintroduce base class
+ add an ack interface, start cleaning up a bit
+ cli
+ ask alternatives to choose from (eray)
+ eliminate \n's from infos, what's the point?
+ metaclass coolness for CLI command framework (eray)
/ overhaul installdb (try to merge its use with packagedb) (eray)
- partial caching and automatic resume for file download (meren)
- use a separate "partial/" subdir like urpmi
/ exception handling (baris)
/ better/more sensible exception hierarchy (eray)
? recovery from exceptions where necessary
/ query
- comar OM information (Provides)
+ package by name, summary/description
- files (rpm -ql)
/ actionsAPI documentation, unittests (caglar - meren)
/ versioning information document
/ verify metodlari
+ SpecFile
+ MetaData
+ Files
- Index (o kadar onemli degil)
? non-interactive use (baris)
+ implement missing unit tests
+ sourcedb
+ package (baris)
+ configuration file (baris)
+ upgrade (eray)
+ upgrade operation
+ test upgrade op
+ system-wide upgrade (upgrade-all) komutu
+ incremental build (eray)
+ generate binary release number by comparing MD5s (eray)
+ keep track of successfully completed configure, make, install
steps (necessary for large-scale builds?) (meren)
+ database locking bugs (eray)
+ provide a library interface for users outside (YALI, TASMA). "import pisi" (baris)
4. Release (bug fix, guzellestirme vs.)
5. Post Release
- a database of components: faster access
- more support for categories:
- put categories into a database
- fast query for categories
/ make a package and sourcedb for each repo
+ packagedb
- sourceb
- transaction stuff for database (eray)
- multi-architecture support (baris, caglar)
/ design decisions
/ extend XML specs to support that
- cross-platform building support
- incremental build/fetch for repository index (pisi-index.xml)
- diffsets (caglar)
-79
View File
@@ -1,79 +0,0 @@
% ALGORITHM STYLE -- Released 8 April 1996
% for LaTeX-2e
% Copyright -- 1994 Peter Williams
% E-mail Peter.Williams@dsto.defence.gov.au
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{algorithm}
\typeout{Document Style `algorithm' - floating environment}
\RequirePackage{float}
\RequirePackage{ifthen}
\newcommand{\ALG@within}{nothing}
\newboolean{ALG@within}
\setboolean{ALG@within}{false}
\newcommand{\ALG@floatstyle}{ruled}
\newcommand{\ALG@name}{Algorithm}
\newcommand{\listalgorithmname}{List of \ALG@name s}
% Declare Options
% first appearance
\DeclareOption{plain}{
\renewcommand{\ALG@floatstyle}{plain}
}
\DeclareOption{ruled}{
\renewcommand{\ALG@floatstyle}{ruled}
}
\DeclareOption{boxed}{
\renewcommand{\ALG@floatstyle}{boxed}
}
% then numbering convention
\DeclareOption{part}{
\renewcommand{\ALG@within}{part}
\setboolean{ALG@within}{true}
}
\DeclareOption{chapter}{
\renewcommand{\ALG@within}{chapter}
\setboolean{ALG@within}{true}
}
\DeclareOption{section}{
\renewcommand{\ALG@within}{section}
\setboolean{ALG@within}{true}
}
\DeclareOption{subsection}{
\renewcommand{\ALG@within}{subsection}
\setboolean{ALG@within}{true}
}
\DeclareOption{subsubsection}{
\renewcommand{\ALG@within}{subsubsection}
\setboolean{ALG@within}{true}
}
\DeclareOption{nothing}{
\renewcommand{\ALG@within}{nothing}
\setboolean{ALG@within}{true}
}
\DeclareOption*{\edef\ALG@name{\CurrentOption}}
% ALGORITHM
%
\ProcessOptions
\floatstyle{\ALG@floatstyle}
\ifthenelse{\boolean{ALG@within}}{
\ifthenelse{\equal{\ALG@within}{part}}
{\newfloat{algorithm}{htbp}{loa}[part]}{}
\ifthenelse{\equal{\ALG@within}{chapter}}
{\newfloat{algorithm}{htbp}{loa}[chapter]}{}
\ifthenelse{\equal{\ALG@within}{section}}
{\newfloat{algorithm}{htbp}{loa}[section]}{}
\ifthenelse{\equal{\ALG@within}{subsection}}
{\newfloat{algorithm}{htbp}{loa}[subsection]}{}
\ifthenelse{\equal{\ALG@within}{subsubsection}}
{\newfloat{algorithm}{htbp}{loa}[subsubsection]}{}
\ifthenelse{\equal{\ALG@within}{nothing}}
{\newfloat{algorithm}{htbp}{loa}}{}
}{
\newfloat{algorithm}{htbp}{loa}
}
\floatname{algorithm}{\ALG@name}
\newcommand{\listofalgorithms}{\listof{algorithm}{\listalgorithmname}}
-158
View File
@@ -1,158 +0,0 @@
% ALGORITHMIC STYLE -- Released 8 APRIL 1996
% for LaTeX version 2e
% Copyright -- 1994 Peter Williams
% E-mail PeterWilliams@dsto.defence.gov.au
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{algorithmic}
\typeout{Document Style `algorithmic' - environment}
%
\RequirePackage{ifthen}
\RequirePackage{calc}
\newboolean{ALC@noend}
\setboolean{ALC@noend}{false}
\newcounter{ALC@line}
\newcounter{ALC@rem}
\newlength{\ALC@tlm}
%
\DeclareOption{noend}{\setboolean{ALC@noend}{true}}
%
\ProcessOptions
%
% ALGORITHMIC
\newcommand{\algorithmicrequire}{\textbf{Require:}}
\newcommand{\algorithmicensure}{\textbf{Ensure:}}
\newcommand{\algorithmiccomment}[1]{\{#1\}}
\newcommand{\algorithmicend}{\textbf{end}}
\newcommand{\algorithmicif}{\textbf{if}}
\newcommand{\algorithmicthen}{\textbf{then}}
\newcommand{\algorithmicelse}{\textbf{else}}
\newcommand{\algorithmicelsif}{\algorithmicelse\ \algorithmicif}
\newcommand{\algorithmicendif}{\algorithmicend\ \algorithmicif}
\newcommand{\algorithmicfor}{\textbf{for}}
\newcommand{\algorithmicforall}{\textbf{for all}}
\newcommand{\algorithmicdo}{\textbf{do}}
\newcommand{\algorithmicendfor}{\algorithmicend\ \algorithmicfor}
\newcommand{\algorithmicwhile}{\textbf{while}}
\newcommand{\algorithmicendwhile}{\algorithmicend\ \algorithmicwhile}
\newcommand{\algorithmicloop}{\textbf{loop}}
\newcommand{\algorithmicendloop}{\algorithmicend\ \algorithmicloop}
\newcommand{\algorithmicrepeat}{\textbf{repeat}}
\newcommand{\algorithmicuntil}{\textbf{until}}
\def\ALC@item[#1]{%
\if@noparitem \@donoparitem
\else \if@inlabel \indent \par \fi
\ifhmode \unskip\unskip \par \fi
\if@newlist \if@nobreak \@nbitem \else
\addpenalty\@beginparpenalty
\addvspace\@topsep \addvspace{-\parskip}\fi
\else \addpenalty\@itempenalty \addvspace\itemsep
\fi
\global\@inlabeltrue
\fi
\everypar{\global\@minipagefalse\global\@newlistfalse
\if@inlabel\global\@inlabelfalse \hskip -\parindent \box\@labels
\penalty\z@ \fi
\everypar{}}\global\@nobreakfalse
\if@noitemarg \@noitemargfalse \if@nmbrlist \refstepcounter{\@listctr}\fi \fi
\sbox\@tempboxa{\makelabel{#1}}%
\global\setbox\@labels
\hbox{\unhbox\@labels \hskip \itemindent
\hskip -\labelwidth \hskip -\ALC@tlm
\ifdim \wd\@tempboxa >\labelwidth
\box\@tempboxa
\else \hbox to\labelwidth {\unhbox\@tempboxa}\fi
\hskip \ALC@tlm}\ignorespaces}
%
\newenvironment{algorithmic}[1][0]{
\let\@item\ALC@item
\newcommand{\ALC@lno}{%
\ifthenelse{\equal{\arabic{ALC@rem}}{0}}
{{\footnotesize \arabic{ALC@line}:}}{}%
}
\let\@listii\@listi
\let\@listiii\@listi
\let\@listiv\@listi
\let\@listv\@listi
\let\@listvi\@listi
\let\@listvii\@listi
\newenvironment{ALC@g}{
\begin{list}{\ALC@lno}{ \itemsep\z@ \itemindent\z@
\listparindent\z@ \rightmargin\z@
\topsep\z@ \partopsep\z@ \parskip\z@\parsep\z@
\leftmargin 1em
\addtolength{\ALC@tlm}{\leftmargin}
}
}
{\end{list}}
\newcommand{\ALC@it}{\addtocounter{ALC@line}{1}\addtocounter{ALC@rem}{1}\ifthenelse{\equal{\arabic{ALC@rem}}{#1}}{\setcounter{ALC@rem}{0}}{}\item}
\newcommand{\ALC@com}[1]{\ifthenelse{\equal{##1}{default}}%
{}{\ \algorithmiccomment{##1}}}
\newcommand{\REQUIRE}{\item[\algorithmicrequire]}
\newcommand{\ENSURE}{\item[\algorithmicensure]}
\newcommand{\STATE}{\ALC@it}
\newcommand{\COMMENT}[1]{\algorithmiccomment{##1}}
\newenvironment{ALC@if}{\begin{ALC@g}}{\end{ALC@g}}
\newenvironment{ALC@for}{\begin{ALC@g}}{\end{ALC@g}}
\newenvironment{ALC@whl}{\begin{ALC@g}}{\end{ALC@g}}
\newenvironment{ALC@loop}{\begin{ALC@g}}{\end{ALC@g}}
\newenvironment{ALC@rpt}{\begin{ALC@g}}{\end{ALC@g}}
\renewcommand{\\}{\@centercr}
\newcommand{\IF}[2][default]{\ALC@it\algorithmicif\ ##2\ \algorithmicthen%
\ALC@com{##1}\begin{ALC@if}}
\newcommand{\ELSE}[1][default]{\end{ALC@if}\ALC@it\algorithmicelse%
\ALC@com{##1}\begin{ALC@if}}
\newcommand{\ELSIF}[2][default]%
{\end{ALC@if}\ALC@it\algorithmicelsif\ ##2\ \algorithmicthen%
\ALC@com{##1}\begin{ALC@if}}
\newcommand{\FOR}[2][default]{\ALC@it\algorithmicfor\ ##2\ \algorithmicdo%
\ALC@com{##1}\begin{ALC@for}}
\newcommand{\FORALL}[2][default]{\ALC@it\algorithmicforall\ ##2\ %
\algorithmicdo%
\ALC@com{##1}\begin{ALC@for}}
\newcommand{\WHILE}[2][default]{\ALC@it\algorithmicwhile\ ##2\ %
\algorithmicdo%
\ALC@com{##1}\begin{ALC@whl}}
\newcommand{\LOOP}[1][default]{\ALC@it\algorithmicloop%
\ALC@com{##1}\begin{ALC@loop}}
\newcommand{\REPEAT}[1][default]{\ALC@it\algorithmicrepeat%
\ALC@com{##1}\begin{ALC@rpt}}
\newcommand{\UNTIL}[1]{\end{ALC@rpt}\ALC@it\algorithmicuntil\ ##1}
\ifthenelse{\boolean{ALC@noend}}{
\newcommand{\ENDIF}{\end{ALC@if}}
\newcommand{\ENDFOR}{\end{ALC@for}}
\newcommand{\ENDWHILE}{\end{ALC@whl}}
\newcommand{\ENDLOOP}{\end{ALC@loop}}
}{
\newcommand{\ENDIF}{\end{ALC@if}\ALC@it\algorithmicendif}
\newcommand{\ENDFOR}{\end{ALC@for}\ALC@it\algorithmicendfor}
\newcommand{\ENDWHILE}{\end{ALC@whl}\ALC@it\algorithmicendwhile}
\newcommand{\ENDLOOP}{\end{ALC@loop}\ALC@it\algorithmicendloop}
}
\renewcommand{\@toodeep}{}
\begin{list}{\ALC@lno}{\setcounter{ALC@line}{0}\setcounter{ALC@rem}{0}%
\itemsep\z@ \itemindent\z@ \listparindent\z@%
\partopsep\z@ \parskip\z@ \parsep\z@%
\labelsep 0.5em \topsep 0.2em%
\ifthenelse{\equal{#1}{0}}
{\labelwidth 0.5em }
{\labelwidth 1.2em }
\leftmargin\labelwidth \addtolength{\leftmargin}{\labelsep}
\ALC@tlm\labelsep
}
}
{\end{list}}
-381
View File
@@ -1,381 +0,0 @@
%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End:
\documentclass[a4paper,11pt]{article}
\usepackage{graphicx}
\usepackage{algorithm}
\usepackage{algorithmic}
\usepackage{amsmath}
\usepackage{amstext}
\usepackage{amsfonts}
\usepackage{amsbsy}
\usepackage{amsthm}
\usepackage{prettyref}
%\newrefformat{alg}{Algorithm~\ref{#1}}
%\newrefformat{eq}{Equation~\ref{#1}}
%\newrefformat{lem}{Lemma~\ref{#1}}
%\newrefformat{thm}{Theorem~\ref{#1}}
%\newrefformat{chp}{Chapter~\ref{#1}}
%\newrefformat{sec}{Section~\ref{#1}}
%\newrefformat{apx}{Appendix~\ref{#1}}
%\newrefformat{tab}{Table~\ref{#1}}
%\newrefformat{fig}{Figure~\ref{#1}}
%usepackage[active]{srcltx}
\title{ Dependency Resolution in PISI}
\author{Eray \"{O}zkural}
\date{\today}
\begin{document}
\maketitle
\section{Introduction}
Dependency resolution in package management systems have a
significance in that they are the key to providing system stability
and internet upgrades. The scale of package databases requires the
dependency resolution mechanism to be efficient and correct,
motivating a closer look at the theory.
\section{Review}
Dependency resolution has been taken in the most general setting as
the famous SAT problem of propositional logic. If we consider a system
$D$ of dependency statements $D_i$, each statement can be taken as a
proposition in propositional logic which states, for instance:
$D_i$: if package $a$ is installed or package $b$ is installed, then
package $i$ is installable.\\
...
The system is thus understood as the conjunction of such facts, giving
us a logical programming formulation to determine installation
conditions. Note that for simplicity we do not consider the nuances in
upgrade and remove operations at the moment.
However, using a SAT solver for this operation may be shooting a fly
with a bazooka. We observe that only certain forms of propositions
will be necessary for a dependency system. Furthermore, as we shall
see further constraints and optimizations may be required of the
system that are not modelled well with the SAT problem.
We use a graph theoretic approach instead. A directed graph (digraph)
$G=(V,E)$ is formally a set of vertices $V$ and a set of edges $E$
where each edge $(u,v)$ represents an edge from a vertex to another.
Accessor functions $V(G)$ and $E(G)$ yield the vertex and edge set of
the graph $G$. Topological sort of a graph gives a total ordering of
the vertices in which there are only forward edges. A vertex induced
subgraph of $G$ by vertex set $A$ contains only the vertex set $A$ and
edges incident to members of $A$.
\section{Package operation planning}
The dependency resolution problem may be viewed as a simple forward
chaining problem, where we would like to begin from an initial state
$S_0$ and by following allowable system transitions $t_i: S \to S$,
arrive at a desired system state $S_f$ (where $S$ is the set of all states).
A system state $S_i$ is defined as the set of installed packages on
the system together with their versions, i.e. $S_i = \{ (x,v) : x
\text{ is installed}, v=version(x)\} $. An atomic system transition
$t_i$ chains one system state into another, making one ACID change on
the system. The usual atomic transitions are the single package
install, remove and reinstall (upgrade or downgrade) operations found
in low-level package management code of PISI. Note that in PISI, an
upgrade operation is identical to a remove operation followed by an
install operation (which sets it apart from some other packaging
systems).
A package operation plan is thus naturally conceived of as a sequence
of atomic system transitions. Given an initial state and a final
state, the job of the package operation planner is to determine
whether there is a plan, and if so find the "best" one.
Where there are no versions involved (e.g. upgrade/downgrade), we will
replace the pair $(x,v)$ with $x$ in the definitions for simplicity.
\subsection{System consistency}
It is worth mentioning here the concept of system consistency. As in a
database transaction, it is not acceptable that the system violates an
invariant afterwards. In the context of PISI, system consistency is
composed of two conditions for the current set of installed packages.
\begin{enumerate}
\item All package dependencies are satisfied (we may call this a
closed system)
\item No package conflicts are present.
\end{enumerate}
Therefore, by atomic transition we also mean one that does not corrupt
system consistency. The system is thus never in an inconsistent
state. We will explain the conflicts later, for the present let us
look at the dependency condition.
\subsection{Solving the simplest case with topological sorting}
We will now concentrate on a simple form of the problem which can be
solved with topological sorting. This form is not concerned with
versions. Neither do we consider remote repositories. From an initial
set of packages $S_0$, we would like to install in addition a new set
$A$ of packages obtaining $S_f = S_0 \cup A$, for a static set of package
relations.
The only relations considered are of the form: $a$ Depends on $b$, or
more briefly $aDb$. The graph of all such simple dependency relations
is a digraph $G$. For each dependency relation $aDb$, there is an
edge $a \to b$ in $G$. Accessing graph $G$ usually requires a database
operation and is therefore expensive.
We now consider the digraph $G_A$ of the minimal set of simple
dependency relations which contains all information required to
construct a plan to install packages $A$. $G_A$ is a vertex induced
graph such that the fringe of $A$, e.g. vertices with out-degree $0$
depend only on packages that are already installed (or none). Vertices
of $G_A$ are taken from $S_f$. First, let us explain the labelling
scheme. Already installed vertices are labelled with 'i'. Packages to
be added are labelled with 'a', and packages to be installed due to
dependencies are labelled with 'd'. We construct the graph as follows
\begin{algorithm}
\caption{$\textsc{Make-}G_A(G, A)$}
\label{alg:cons-graph}
\begin{algorithmic}[1]
\STATE $G_A \gets$ vertex induced subgraph of $G$ by $A$ labelled with 'a'
\REPEAT
\STATE done $\gets$ true
\FOR{each $u \in V(G_A)$ with out-degree $0$}
\FOR{ $v \in adj(u) $ of $G$}
\IF{$v \notin V(G_A)$}
\STATE done $\gets$ false
\IF{$v$ is installed}
\STATE label $v$ with 'i'
\ELSE
\STATE label $v$ with 'd'
\ENDIF
\STATE add $(u,v)$ to $G_A$
\ENDIF
\ENDFOR
\ENDFOR
\UNTIL{done}
\end{algorithmic}
\end{algorithm}
By this iterative expansion, we do a minimum number of database
accesses to $G$ and construct a dependency graph in memory. If the
$G_A$'s fringe has vertices with non 'i'-labels, then $A$ cannot be
installed. Otherwise, we find a topological sort $L$ of $G_A$, and in
the reverse order, install packages for vertices labelled with
'a' or 'd'. Observe that, by definition of a topological sort,
installing packages in the reverse order of a topological sort
guarantees that no package is installed before all of its dependencies
are installed. Thus, this yields a consistency-preserving plan.
\subsection{Dependency conditions}
In the PISI specification, we allow a dependency to specify a local
condition, for instance a program may require a dependency on
\texttt{libx} with pardus source release $3$ or greater. Another
program may require a dependency on a particular source release. These
conditions are local because they can be computed over the elements of
system state $S_i$, e.g. package (name, version) pairs. Let us denote this
condition by a predicate $P(b)$ such that $aDb$ iff $P(b)$. The
predicate $P$ for the dependency $aDb$ can be stored as edge data for
$(u,v)$ on the graph.
% thus when we say $P(u,v)$, this means the predicate stored on
%$(u,v)$ edge for vertex $v$.
In this case, the vertices of the package dependency graph $G$ and the
planning graph $G_A$ retain the version information along with the
package name. The dependency relation thus holds between two pairs
$(p_1,v_1)$ and $(p_2,v_2)$, satisfying a given predicate
$P(p_2,v_2)$. When constructing the graph, we therefore take this
predicate into account and admit a new edge $(u,v)$, and thus a new
vertex $v$ into $G_A$ if and only if the target vertex satisfies
$P(v)$.
\subsection{Conflicts and COMAR dependencies}
The tags \texttt{Conflicts} and \texttt{Provides} in PISI are
inherited from Debian distribution. A conflict between two packages
($a$ conflicts with $b$) is a symmetric relation that prevents the
packages $a,b$ from being installed simultaneously (It is
sufficient that only one direction of the relation is declared, the
other direction is inferred). Provision in the form of $a$ provides $A$
denotes that $a$ implements a virtual package abstraction $A$.
In PISI, a package can provide an object of a COMAR Object Model (OM),
and is currently the only model of a ``virtual package''. In the
following example, let $a_1,a_2,\ldots,a_n$ provide the OM $A$. A package
can depend on another package's OM, for instance $b$ comar-depends on
$A$ (or in short form $bDA$) (Currently, conditions on virtual
dependencies are not supported). In this case, it is sufficient that
only one of the $a_i$ are installed. To resolve this, the user is
asked to choose from a list of alternatives immediately, since
otherwise there is unavoidable combinatorial explosion (in the form of
having to consider $\Pi_{bDA}num(A)$ graphs in the worst case where
$num(A)$ is the number of alternatives for comar OM $A$; the problem
is that there seems to be no simple solution to solve satisfiability
with arbitrary disjunctions in package dependency, short of a $SAT$
solver).
The resolution of conflicts to maintain system consistency condition
$2$ is easier to achieve. This can be satisfied by disallowing
installation of a package that would violate the condition, or
removing currently installed packages which conflict with the newly
installed package and its dependencies. In most package managers, the
second option is confirmed by the user for making it easier. In the
install operation, after constructing the partial dependency graph
$G_A$, we merely have to check whether any conflict appears among the
vertices of $G_A$. If so, then the operation is untenable, since $G_A$
shows the future state of the installed system. Since a conflict is
symmetric, it is represented as a bidirectional edge $a \leftrightarrow b$. To
distinguish dependencies from conflicts, the edges would have to be
labelled in this case, for instance with 'd' and 'c'. The removal
option can be implemented by invoking a multi-package remove operation
on the packages in conflict.
\subsection{Remove operation}
Dependency resolution for remove operation is similar to install. The
only significant difference is that we remove the packages in the
topological order rather than installing packages in the reverse
topological order.
\section{Remote repositories and upgrade operation}
The upgrade operation is more complicated. First of all, the system
has to distinguish between the current relation graph (e.g.
dependencies and conflicts), and the future relation graph which may
be different in rather important aspects. In theory, we allow any
dependency and conflict to change. Therefore, we have a $G_0$ which
represents the current relations (among installed packages) in the
system, and a $G_f$ which is probably taken from a remote package
repository. We begin by noting that $G_0$ and $G_f$ have to be
compatible. That is, to say, if a package $(p_1,v_1)$ is shared across
two graphs, then the declarations made by the package are one and the
same.
$G_0$ can be calculated from the package information (e.g. metadata)
of the installed packages and is stored by PISI in a dedicated
database. $G_f$ is most likely constructed from a PISI Index file
corresponding to a particular package repository. Accessing both of
these entities is expensive and we should take care to minimize access
as in the previous section.
To preserve consistency during individual transitions, the planner can
choose to remove a minimum number of packages from the system to bring
it to a clean state, and then install the new versions of these
packages in the correct order. Let us assume that it is indeed
possible to achieve this ``clean state''. Apparently, this is not
always possible because other packages may depend on the package(s) to
upgrade. At any rate, to achieve this, first we need to
calculate subgraphs of $G_0$ and $G_f$. We can calculate alternative
plans from these subgraphs if need be.
Let $A$ be the set of packages to be upgraded from a given repository.
$G_{A,0}$ is the subgraph of $G_{0}$ induced by the ``upgrade
closure'' of $A$. The ``upgrade closure'' of a set $A$ of packages is
defined as a minimal set of packages $B \supseteq A$ such that there is no
package in $B$ that requires an upgrade for $A$ to be upgraded. This
is found by assuming that the current system state $S_0$ is
consistent, and by constructing a relation graph of the future state
of the system to detect the dependencies that have changed.
Obviously, to make a plan, we must first know the goal state. In a
multi-package upgrade, the exact details of the goal state depend on
the graph $G_f$ of the repository. Thus, we construct a graph
$G_{A,f}$ that is a vertex-induced subgraph of $G_f$ such that it
contains all information relevant to upgrading packages $A$. We begin
by a vertex induced subgraph of $G_f$ by $A$. These are the packages
that will be upgraded in any case. Then, we make a pass on the
vertices, and look at all the outgoing edges, we compare whether this
edge has changed in any substantial way from the previous version. In
particular, we are interested in whether the predicate of the edge is
valid for the version of the same package in our current system. Every
compared vertex in this manner is marked done, and the edges not valid
for the current system pull new unmarked vertices into $G_f$, this
continues until there are no unmarked vertices left. Hence, the
vertices of $G_f$ are the packages that must be upgraded.
To actually carry out the upgrade a strategy is to upgrade all the
packages in $G_{A,f}$ in some order. A good order is again the reverse
topological order order, in fact, the upgrade operation is merely a
special case of a multi-package installation code that can install
from a remote repository, since a multi-package installation can
contain upgrades in addition to new packages. However, in case no
package depends on the packages to be upgraded, then we can carry out
a completely consistency-preserving plan as discussed above. The
conflicts are resolved in the usual fashion, by removing those
packages in conflict with new packages that are installed. This can be
accomplished by invoking a remove operation prior to the upgrade
operation.
\section{Examples}
\subsection{A single package upgrade}
goal: upgrade $(a,1)$ to $(a,2)$\\
\\
rules:\\
$(a,1)$ depends on $(b,1), (c,1)$ \\
$(a,1)$ conflicts with $(d,1)$\\
$(a,2)$ depends on $(c,3), (d,2)$\\
$(a,2)$ conflicts with $(b,1)$\\
\\
initial state:\\
$(a,1), (b,1), (c,1)$ installed \\
In this case, we can find a consistency-preserving plan in terms of
install and remove operations.
\\
plan:\\
remove $(a,1)$\\
remove $(b,1)$\\
remove $(c,1)$\\
install $(c,3)$\\
install $(d,2)$\\
install $(a,2)$\\
\subsection{Another upgrade}
goal: upgrade $(b,1) \to (b,2)$\\
\\
current dep: $(a,1) \to[=1] (b,1) \to[=1] (c,1) \to[=1] (d,1)$\\
repo dep: \nobreakspace{} \nobreakspace$(a,1) \to[=2] (b,2) \to[=2] (c,2) \to[=1] (d,1)$\\
In this case, we cannot remove $(b,1)$ because it's locked in the
chain. In fact, here there is no consistency-preserving plan in terms
of atomic single package transitions: install, remove, upgrade. In
these cases, it seems best to resort to upgrade in place, and in the
reverse topological order of dependencies.
\\
plan:\\
upgrade $(c,1) \to (c,2)$\\
upgrade $(b,1) \to (b,2)$\\
\subsection{A multi package remove}
goal: remove $(a,2), (b,3), (c,2)$\\
\\
rules:\\
$(c,2)$ depends $(a,2)$\\
$(d,2)$ depends on $(b,3), (c,2)$\\
$(e,1)$ depends on $(a,2)$\\
$(f,2)$ depends on $(e,1)$\\
$(g,2)$ depends on $(e,1)$\\\\
plan:\\
remove $(f,2)$\\
remove $(g,2)$\\
remove $(e,1)$\\
remove $(d,2)$\\
remove $(b,3)$\\
remove $(c,2)$\\
remove $(a,2)$\\
\end{document}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

-37
View File
@@ -1,37 +0,0 @@
%%
%% This is file `prettyref.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% prettyref.dtx (with options: `style')
%%
%% Copyright (c) 1995 Kevin Ruland
%%
%%
%% prettyref v3.0
%%
%% Copyright 1995,1998. by Kevin Ruland kevin@rodin.wustl.edu
%%
\ProvidesPackage{prettyref}[1998/07/09 v3.0]
\def\newrefformat#1#2{%
\@namedef{pr@#1}##1{#2}}
\newrefformat{eq}{\textup{(\ref{#1})}}
\newrefformat{lem}{Lemma \ref{#1}}
\newrefformat{thm}{Theorem \ref{#1}}
\newrefformat{cha}{Chapter \ref{#1}}
\newrefformat{sec}{Section \ref{#1}}
\newrefformat{tab}{Table \ref{#1} on page \pageref{#1}}
\newrefformat{fig}{Figure \ref{#1} on page \pageref{#1}}
\def\prettyref#1{\@prettyref#1:}
\def\@prettyref#1:#2:{%
\expandafter\ifx\csname pr@#1\endcsname\relax%
\PackageWarning{prettyref}{Reference format #1\space undefined}%
\ref{#1:#2}%
\else%
\csname pr@#1\endcsname{#1:#2}%
\fi%
}
\endinput
%%
%% End of file `prettyref.sty'.
-54
View File
@@ -1,54 +0,0 @@
#!/usr/bin/python
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import sys
import gettext
__trans = gettext.translation('pisi', fallback=True)
_ = __trans.ugettext
from pisi.cli.pisicli import PisiCLI
def handle_exception(exception, value, tb):
import traceback
import exceptions
import pisi.ui
from pisi.xmlext import XmlError
ui = pisi.cli.CLI()
if exception == exceptions.KeyboardInterrupt:
ui.error(_("\nKeyboardInterrupt: Exiting...\n"))
sys.exit(1)
elif exception == XmlError:
ui.error(str(value))
sys.exit(1)
ui.error(_("""
Internal PISI Error:
Please file a bug report! (http://bugs.uludag.org.tr)
"""))
ui.error("%s" %exception)
ui.error("%s\n" %value)
ui.info(_("Traceback:"))
traceback.print_tb(tb)
sys.exit(1)
if __name__ == "__main__":
sys.excepthook = handle_exception
cli = PisiCLI()
cli.run_command()
-351
View File
@@ -1,351 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-3.8.dtd">
<!-- Project file for project pisi -->
<!-- Saved: 2005-09-20, 22:00:02 -->
<!-- Copyright (C) 2005 PiSi Development Team, -->
<Project version="3.8">
<ProgLanguage mixed="0">Python</ProgLanguage>
<UIType>Qt</UIType>
<Description>The package management software of Pardus distribution.
</Description>
<Author>PiSi Development Team</Author>
<Email></Email>
<Sources>
<Source>
<Dir>tools</Dir>
<Name>ebuild2pisi.py</Name>
</Source>
<Source>
<Dir>tools</Dir>
<Name>cat-db.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Dir>popt</Dir>
<Name>actions.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Dir>zip</Dir>
<Name>actions.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Dir>unzip</Dir>
<Name>actions.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>configfiletests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>sourcedbtests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>utiltests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>installdbtests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>run.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>metadatatests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>constantstests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>fetchertests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>archivetests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>versiontests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>actionsapitests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>specfiletests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>packagetests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>packagedbtests.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>graphtests.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>get.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>shelltools.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>variables.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>autotools.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>pisitools.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>kde.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>__init__.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>libtools.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>coreutils.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>cli</Dir>
<Name>pisicli.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>cli</Dir>
<Name>__init__.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>cli</Dir>
<Name>commands.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>lockeddbshelve.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>specfile.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>package.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>__init__.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>build.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>xmlfile.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>packagedb.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>files.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>config.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>index.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>repodb.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>ui.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>util.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>dependency.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>metadata.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>pgraph.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>operations.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>context.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>sourcefetcher.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>graph.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>sourcearchive.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>configfile.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>sourcedb.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>install.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>installdb.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>constants.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>fetcher.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>archive.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>xmlext.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>version.py</Name>
</Source>
<Source>
<Name>setup.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Dir>actionsapi</Dir>
<Name>pisitoolsfunctions.py</Name>
</Source>
<Source>
<Dir>tools</Dir>
<Name>repostats.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>uri.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>api.py</Name>
</Source>
<Source>
<Dir>tests</Dir>
<Name>xmlfiletests.py</Name>
</Source>
<Source>
<Dir>pisi</Dir>
<Name>specfilenew.py</Name>
</Source>
<Source>
<Name>TODO</Name>
</Source>
</Sources>
<Forms>
</Forms>
<Translations>
</Translations>
<Interfaces>
</Interfaces>
<Others>
<Other>
<Name>pisi-cli</Name>
</Other>
<Other>
<Dir>tests</Dir>
<Name>beta-light.sh</Name>
</Other>
<Other>
<Dir>tests</Dir>
<Name>beta-upgrade.sh</Name>
</Other>
<Other>
<Dir>tests</Dir>
<Name>beta.sh</Name>
</Other>
<Other>
<Dir>tests</Dir>
<Name>sandbox</Name>
</Other>
</Others>
<MainScript>
<Name>pisi-cli</Name>
</MainScript>
<Vcs>
<VcsType>Subversion</VcsType>
<VcsOptions>{'status': [], 'log': [], 'global': [], 'update': [], 'remove': [], 'add': [], 'tag': [], 'export': [], 'diff': [], 'commit': [], 'checkout': [], 'history': []}</VcsOptions>
<VcsOtherData>{'standardLayout': 1}</VcsOtherData>
</Vcs>
<FiletypeAssociations>
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
<FiletypeAssociation pattern="*.ui" type="FORMS" />
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
<FiletypeAssociation pattern="*.py" type="SOURCES" />
</FiletypeAssociations>
</Project>
-26
View File
@@ -1,26 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# PiSi version
__version__ = "1.0_alpha2"
__all__ = [ 'api', 'packagedb', 'installdb' ]
class Error(Exception):
"""Class of exceptions that lead to program termination"""
pass
class Exception(Exception):
"""Class of exceptions that must be caught and handled within PISI"""
pass
# FIXME: can't do this due to name clashes in config and other singletons booo
#from pisi.api import *
-11
View File
@@ -1,11 +0,0 @@
ReFactor ActionsAPI:
pisitools.py - %90
autotools.py - %100
get.py - %75
kde.py - %75
libtools.py - %90
pisitoolsfunctions.py - %75
shelltools.py - %75
variables.py - %100
coreutils.py - %100
@@ -1,20 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# pisi.actionsapi version
__version__ = '1.0_alpha2'
import pisi
class Error(pisi.Error):
pass
class Exception(pisi.Exception):
pass
@@ -1,142 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Standard Python Modules
import os
# Pisi Modules
import pisi.context as ctx
# ActionsAPI Modules
import pisi.actionsapi
import pisi.actionsapi.get as get
from pisi.actionsapi.shelltools import system
from pisi.actionsapi.shelltools import can_access_file
from pisi.actionsapi.libtools import gnuconfig_update
class ConfigureError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
if can_access_file('config.log'):
ctx.ui.error('\n!!! Please attach the config.log to your bug report:\n%s/config.log\n' % os.getcwd())
class MakeError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
class InstallError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
class RunTimeError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
def configure(parameters = ''):
'''configure source with given parameters = "--with-nls --with-libusb --with-something-usefull"'''
if can_access_file('configure'):
gnuconfig_update()
args = './configure \
--prefix=/%s \
--host=%s \
--mandir=/%s \
--infodir=/%s \
--datadir=/%s \
--sysconfdir=/%s \
--localstatedir=/%s \
%s' % (get.defaultprefixDIR(), \
get.HOST(), get.manDIR(), \
get.infoDIR(), get.dataDIR(), \
get.confDIR(), get.localstateDIR(), parameters)
if system(args):
raise ConfigureError('!!! Configure failed...\n')
else:
raise ConfigureError('!!! No configure script found...\n')
def rawConfigure(parameters = ''):
'''configure source with given parameters = "--prefix=/usr --libdir=/usr/lib --with-nls"'''
if can_access_file('configure'):
gnuconfig_update()
if system('./configure %s' % parameters):
raise ConfigureError('!!! Configure failed...\n')
else:
raise ConfigureError('!!! No configure script found...\n')
def compile(parameters = ''):
#FIXME: Only one package uses this until now, hmmm
system('%s %s %s' % (get.GCC(), get.CFLAGS(), parameters))
def make(parameters = ''):
'''make source with given parameters = "all" || "doc" etc.'''
if system('make %s' % parameters):
raise MakeError('!!! Make failed...\n')
def install(parameters = '', argument = 'install'):
'''install source into install directory with given parameters'''
if can_access_file('makefile') or can_access_file('Makefile') or can_access_file('GNUmakefile'):
args = 'make prefix=%(prefix)s/%(defaultprefix)s \
datadir=%(prefix)s/%(data)s \
infodir=%(prefix)s/%(info)s \
localstatedir=%(prefix)s/%(localstate)s \
mandir=%(prefix)s/%(man)s \
sysconfdir=%(prefix)s/%(conf)s \
%(parameters)s \
%(argument)s' % {'prefix': get.installDIR(),
'defaultprefix': get.defaultprefixDIR(),
'man': get.manDIR(),
'info': get.infoDIR(),
'localstate': get.localstateDIR(),
'conf': get.confDIR(),
'data': get.dataDIR(),
'parameters': parameters,
'argument':argument}
if system(args):
raise InstallError('!!! Install failed...\n')
else:
raise InstallError('!!! No Makefile found...\n')
def rawInstall(parameters = '', argument = 'install'):
'''install source into install directory with given parameters = PREFIX=%s % get.installDIR()'''
if can_access_file('makefile') or can_access_file('Makefile') or can_access_file('GNUmakefile'):
if system('make %s %s' % (parameters, argument)):
raise InstallError('!!! Install failed...\n')
else:
raise InstallError('!!! No Makefile found...\n')
def aclocal(parameters = ''):
'''generates an aclocal.m4 based on the contents of configure.in.'''
if system('aclocal %s' % parameters):
raise RunTimeError('!!! Running aclocal failed...')
def autoconf(parameters = ''):
'''generates a configure script'''
if system('autoconf %s' % parameters):
raise RunTimeError('!!! Running autoconf failed...')
def autoreconf(parameters = ''):
'''re-generates a configure script'''
if system('autoreconf %s' % parameters):
raise RunTimeError('!!! Running autoconf failed...')
def automake(parameters = ''):
'''generates a makefile'''
if system('automake %s' % parameters):
raise RunTimeError('!!! Running automake failed...')
def autoheader(parameters = ''):
'''generates templates for configure'''
if system('autoheader %s' % parameters):
raise RunTimeError('!!! Running autoheader failed...')
@@ -1,77 +0,0 @@
#!/usr/bin/python
#-*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Standard Python Modules
import sys
import re
from itertools import izip, imap, count, ifilter, ifilterfalse
# ActionsAPI
import pisi.actionsapi
def cat(filename):
return file(filename).xreadlines()
class grep:
'''keep only lines that match the regexp'''
def __init__(self, pat, flags = 0):
self.fun = re.compile(pat, flags).match
def __ror__(self, input):
return ifilter(self.fun, input)
class tr:
'''apply arbitrary transform to each sequence element'''
def __init__(self, transform):
self.tr = transform
def __ror__(self, input):
return imap(self.tr, input)
class printto:
'''print sequence elements one per line'''
def __init__(self, out = sys.stdout):
self.out = out
def __ror__(self,input):
for line in input:
print >> self.out, line
printlines = printto(sys.stdout)
class terminator:
def __init__(self,method):
self.process = method
def __ror__(self,input):
return self.process(input)
aslist = terminator(list)
asdict = terminator(dict)
astuple = terminator(tuple)
join = terminator(''.join)
enum = terminator(enumerate)
class sort:
def __ror__(self,input):
ll = list(input)
ll.sort()
return ll
sort = sort()
class uniq:
def __ror__(self,input):
for i in input:
try:
if i == prev:
continue
except NameError:
pass
prev = i
yield i
uniq = uniq()
-155
View File
@@ -1,155 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Standart Python Modules
import os
# PISI Modules
import pisi.actionsapi
import pisi.context as ctx
# ActionsAPI Modules
from variables import glb
class BinutilsError(pisi.actionsapi.Error):
pass
env = glb.env
dirs = glb.dirs
def curDIR():
return os.getcwd()
def ENV(environ):
return os.environ[environ];
# variables.Env
def pkgDIR():
return env.pkg_dir
def workDIR():
return env.work_dir
def installDIR():
return env.install_dir
def srcNAME():
return env.src_name
def srcVERSION():
return env.src_version
def srcRELEASE():
return env.src_release
def srcTAG():
return env.src_name + '-' + env.src_version + '-' + env.src_release
def srcDIR():
return env.src_name + '-' + env.src_version
def HOST():
return env.host
def CFLAGS():
return env.cflags
def CXXFLAGS():
return env.cxxflags
def LDFLAGS():
return env.ldflags
# variables.Dirs
def docDIR():
return dirs.doc
def sbinDIR():
return dirs.sbin
def infoDIR():
return dirs.info
def manDIR():
return dirs.man
def dataDIR():
return dirs.data
def confDIR():
return dirs.conf
def localstateDIR():
return dirs.localstate
def defaultprefixDIR():
return dirs.defaultprefix
def kdeDIR():
return dirs.kde
def qtDIR():
return dirs.qt
def qtLIBDIR():
return '%s/lib/' % qtDIR()
# Binutils Variables
def exists_binary(bin):
# determine if path has binary
path = os.environ['PATH'].split(':')
for directory in path:
if os.path.exists(os.path.join(directory, bin) ):
return True
return False
def getBinutilsInfo(util):
cross_build_name = '%s-%s' % (HOST(), util)
if not exists_binary(cross_build_name):
if not exists_binary(util):
raise BinutilsError('util %s cannot be found' % util)
else:
ctx.ui.debug('Warning: %s does not exist, using plain name %s' \
% (cross_build_name, util))
return util
else:
return cross_build_name
def AR():
return getBinutilsInfo('ar')
def AS():
return getBinutilsInfo('as')
def CC():
return getBinutilsInfo('gcc')
def CXX():
return getBinutilsInfo('g++')
def LD():
return getBinutilsInfo('ld')
def NM():
return getBinutilsInfo('nm')
def RANLIB():
return getBinutilsInfo('ranlib')
def F77():
return getBinutilsInfo('f77')
def GCJ():
return getBinutilsInfo('gcj')
@@ -1,72 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# standard python modules
import os
# Pisi Modules
import pisi.context as ctx
# ActionsAPI Modules
import pisi.actionsapi
import pisi.actionsapi.get as get
from pisi.actionsapi.shelltools import system, can_access_file
class ConfigureError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
if can_access_file('config.log'):
ctx.ui.error('\n!!! Please attach the config.log to your bug report:\n%s/config.log' % os.getcwd())
class MakeError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
class InstallError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
def configure(parameters = ''):
''' parameters = '--with-nls --with-libusb --with-something-usefull '''
if can_access_file('configure'):
args = './configure \
--prefix=%s \
--host=%s \
--with-x \
--enable-mitshm \
--with-xinerama \
--with-qt-dir=%s \
--enable-mt \
--with-qt-libraries=%s \
--enable-final \
--disable-dependency-tracking \
--disable-debug \
%s' % (get.kdeDIR(), get.HOST(), get.qtDIR(), get.qtLIBDIR(), parameters)
if system(args):
raise ConfigureError('!!! Configure failed...\n')
else:
raise ConfigureError('!!! No configure script found...\n')
def make(parameters = ''):
'''make source with given parameters = "all" || "doc" etc.'''
if system('make %s' % parameters):
raise MakeError('!!! Make failed...\n')
def install(parameters = 'install'):
if can_access_file('Makefile'):
args = 'make DESTDIR=%s destdir=%s %s' % (get.installDIR(), get.installDIR(), parameters)
if system(args):
raise InstallError('!!! Install failed...\n')
else:
raise InstallError('!!! No Makefile found...\n')
@@ -1,66 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Standard Python Modules
import os
# Pisi-Core Modules
import pisi.context as ctx
# ActionsAPI Modules
import pisi.actionsapi
from pisi.actionsapi.shelltools import *
import pisi.actionsapi.get as get
class RunTimeError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
def preplib(sourceDirectory = '/usr/lib'):
sourceDirectory = get.installDIR() + sourceDirectory
if can_access_directory(sourceDirectory):
if system('/sbin/ldconfig -n -N %s' % sourceDirectory):
raise RunTimeError('!!! Running ldconfig failed...')
def preplib_so(sourceDirectory):
pass
def gnuconfig_update():
''' copy newest config.* onto source\'s '''
for root, dirs, files in os.walk(os.getcwd()):
for file in files:
if file in ['config.sub', 'config.guess']:
copy('/usr/share/gnuconfig/%s' % file, os.path.join(root, file))
ctx.ui.info('GNU Config Update Finished.')
def libtoolize(parameters = ''):
if system('/usr/bin/libtoolize %s' % parameters):
raise RunTimeError('Running libtoolize failed...')
def gen_usr_ldscript(dynamicLib):
makedirs('%s/usr/lib' % get.installDIR())
destinationFile = open('%s/usr/lib/%s' % (get.installDIR(), dynamicLib), 'w')
content = '''
/* GNU ld script
Since Pardus has critical dynamic libraries
in /lib, and the static versions in /usr/lib,
we need to have a "fake" dynamic lib in /usr/lib,
otherwise we run into linking problems.
*/
GROUP ( /lib/%s )
''' % dynamicLib
destinationFile.write(content)
destinationFile.close()
chmod('%s/usr/lib/%s' % (get.installDIR(), dynamicLib))
@@ -1,219 +0,0 @@
#!/usr/bin/python
#-*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Standart Python Modules
import os
import glob
import sys
import fileinput
import re
# Pisi Modules
import pisi.context as ctx
# ActionsAPI Modules
import pisi.actionsapi
import pisi.actionsapi.get as get
from pisi.actionsapi.pisitoolsfunctions import *
from pisi.actionsapi.shelltools import *
def dobin(sourceFile, destinationDirectory = '/usr/bin'):
'''insert a executable file into /bin or /usr/bin'''
''' example call: pisitools.dobin("bin/xloadimage", "/bin", "xload") '''
executable_insinto(get.installDIR() + destinationDirectory, sourceFile)
def dodir(destinationDirectory):
'''creates a directory tree'''
makedirs(get.installDIR() + destinationDirectory)
def dodoc(*sourceFiles):
'''inserts the files in the list of files into /usr/share/doc/PACKAGE'''
readable_insinto(get.installDIR() + os.path.join('/usr/share/doc', get.srcTAG()), *sourceFiles)
def doexe(sourceFile, destinationDirectory):
'''insert a executable file into destination directory'''
''' example call: pisitools.doexe("kde-3.4.sh", "/etc/X11/Sessions")'''
executable_insinto(get.installDIR() + destinationDirectory, sourceFile)
def dohard(sourceFile, destinationFile):
'''creates hard link between sourceFile and destinationFile'''
#FIXME: How can i use hard-links in Python?
pass
def dohtml(*sourceFiles):
'''inserts the files in the list of files into /usr/share/doc/PACKAGE/html'''
''' example call: pisitools.dohtml("doc/doxygen/html/*")'''
destionationDirectory = os.path.join(get.installDIR(), 'usr/share/doc' ,get.srcTAG(), 'html')
if not can_access_directory(destionationDirectory):
makedirs(destionationDirectory)
allowed_extensions = ['.png', '.gif', '.html', '.htm', '.jpg', '.css', '.js']
disallowed_directories = ['CVS']
for sourceFile in sourceFiles:
for source in glob.glob(sourceFile):
if os.path.isfile(source) and os.path.splitext(source)[1] in allowed_extensions:
system('install -m0644 %s %s' % ('"' + source + '"', destionationDirectory))
if os.path.isdir(source) and os.path.basename(source) not in disallowed_directories:
for root, dirs, files in os.walk(source):
for source in files:
if os.path.splitext(source)[1] in allowed_extensions:
makedirs(destionationDirectory)
system('install -m0644 %s %s' % (os.path.join(root, source), destionationDirectory))
def doinfo(*sourceFiles):
'''inserts the into files in the list of files into /usr/share/info'''
readable_insinto(os.path.join(get.installDIR(), get.infoDIR()), *sourceFiles)
def dojar():
'''installs jar files into /usr/share/PACKAGE/lib, and adds to /usr/share/PACKAGE/classpath.env'''
pass
def dolib(sourceFile, destinationDirectory = '/usr/lib'):
'''insert the library into /usr/lib'''
'''example call: pisitools.dolib_a("libz.a")'''
'''example call: pisitools.dolib_a("libz.so")'''
sourceFile = os.path.join(os.getcwd(), sourceFile)
destinationDirectory = get.installDIR() + destinationDirectory
lib_insinto(sourceFile, destinationDirectory, 755)
def dolib_a(sourceFile, destinationDirectory = '/usr/lib'):
'''insert the static library into /usr/lib with permission 0644'''
'''example call: pisitools.dolib_a("staticlib/libvga.a")'''
sourceFile = os.path.join(os.getcwd(), sourceFile)
destinationDirectory = get.installDIR() + destinationDirectory
lib_insinto(sourceFile, destinationDirectory, 644)
def dolib_so(sourceFile, destinationDirectory = '/usr/lib'):
'''insert the static library into /usr/lib with permission 0755'''
'''example call: pisitools.dolib_so("pppd/plugins/minconn.so")'''
sourceFile = os.path.join(os.getcwd(), sourceFile)
destinationDirectory = get.installDIR() + destinationDirectory
lib_insinto(sourceFile, destinationDirectory, 755)
def doman(*sourceFiles):
'''inserts the man pages in the list of files into /usr/share/man/'''
'''example call: pisitools.doman("man.1", "pardus.*")'''
manDIR = os.path.join(get.installDIR(), get.manDIR())
if not can_access_directory(manDIR):
makedirs(manDIR)
for sourceFile in sourceFiles:
for source in glob.glob(sourceFile):
try:
pageName, pageDirectory = source[:source.rindex('.')], \
source[source.rindex('.')+1:]
except ValueError:
ctx.ui.error('\n!!! ActionsAPI [doman]: Wrong man page file...')
makedirs(manDIR + '/man%s' % pageDirectory)
system('install -m0644 %s %s' % (source, manDIR + '/man%s' % pageDirectory))
def domo(sourceFile, locale, destinationFile ):
'''inserts the mo files in the list of files into /usr/share/locale/LOCALE/LC_MESSAGES'''
'''example call: pisitools.domo("po/tr.po", "tr", "pam_login.mo")'''
system('msgfmt %s' % sourceFile)
makedirs('%s/usr/share/locale/%s/LC_MESSAGES/' % (get.installDIR(), locale))
move('messages.mo', '%s/usr/share/locale/%s/LC_MESSAGES/%s' % (get.installDIR(), locale, destinationFile))
def domove(sourceFile, destination, destinationFile = ''):
'''moves sourceFile/Directory into destinationFile/Directory'''
''' example call: pisitools.domove("/usr/bin/bash", "/bin/bash")'''
''' example call: pisitools.domove("/usr/bin/", "/usr/sbin")'''
makedirs(get.installDIR() + destination)
for file in glob.glob(get.installDIR() + sourceFile):
if not destinationFile:
move(file, get.installDIR() + os.path.join(destination, os.path.basename(file)))
else:
move(file, get.installDIR() + os.path.join(destination, destinationFile))
def dopython():
'''FIXME: What the hell is this?'''
pass
def dosed(sourceFile, findPattern, replacePattern = ''):
'''replaces patterns in sourceFile'''
''' example call: pisitools.dosed("/etc/passwd", "caglar", "cem")'''
''' example call: pisitools.dosym("/etc/passwd", "caglar")'''
''' example call: pisitools.dosym("Makefile", "(?m)^(HAVE_PAM=.*)no", r"\1yes")'''
if can_access_file(sourceFile):
for line in fileinput.input(sourceFile, inplace = 1):
#FIXME: In-place filtering is disabled when standard input is read
line = re.sub(findPattern, replacePattern, line)
sys.stdout.write(line)
else:
raise FileError('File doesn\'t exists or permission denied...')
def dosbin(sourceFile, destinationDirectory = '/usr/sbin'):
'''insert a executable file into /sbin or /usr/sbin'''
''' example call: pisitools.dobin("bin/xloadimage", "/sbin") '''
executable_insinto(get.installDIR() + destinationDirectory, sourceFile)
def dosym(sourceFile, destinationFile):
'''creates soft link between sourceFile and destinationFile'''
''' example call: pisitools.dosym("/usr/bin/bash", "/bin/bash")'''
makedirs(get.installDIR() + os.path.dirname(destinationFile))
try:
os.symlink(sourceFile, get.installDIR() + destinationFile)
except OSError:
ctx.ui.error('\n!!! ActionsAPI [dosym]: File exists...')
def insinto(destinationDirectory, sourceFile, destinationFile = ''):
'''insert a sourceFile into destinationDirectory as a destinationFile with same uid/guid/permissions'''
makedirs(get.installDIR() + destinationDirectory)
if not destinationFile:
for file in glob.glob(sourceFile):
if can_access_file(file):
copy(file, get.installDIR() + os.path.join(destinationDirectory, os.path.basename(file)))
else:
copy(sourceFile, get.installDIR() + os.path.join(destinationDirectory, destinationFile))
def newdoc(sourceFile, destinationFile):
'''inserts a sourceFile into /usr/share/doc/PACKAGE/ directory as a destinationFile'''
move(sourceFile, destinationFile)
readable_insinto(os.path.join(get.installDIR(), 'usr/share/doc', get.srcTAG()), destinationFile)
def newman(sourceFile, destinationFile):
'''inserts a sourceFile into /usr/share/man/manPREFIX/ directory as a destinationFile'''
move(sourceFile, destinationFile)
doman(destinationFile)
def remove(sourceFile):
'''removes sourceFile'''
for file in glob.glob(get.installDIR() + sourceFile):
unlink(file)
def removeDir(destinationDirectory):
'''removes destinationDirectory and its subtrees'''
for directory in glob.glob(get.installDIR() + destinationDirectory):
unlinkDir(directory)
@@ -1,72 +0,0 @@
#!/usr/bin/python
#-*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Generic functions for common usage of pisitools #
# Standart Python Modules
import os
import glob
# Pisi Modules
import pisi.context as ctx
# ActionsAPI Modules
import pisi.actionsapi
from pisi.actionsapi.shelltools import *
class FileError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
class ArgumentError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
def executable_insinto(destinationDirectory, *sourceFiles):
'''insert a executable file into destinationDirectory'''
if not sourceFiles or not destinationDirectory:
raise ArgumentError('Insufficient arguments...')
if not can_access_directory(destinationDirectory):
makedirs(destinationDirectory)
for sourceFile in sourceFiles:
for source in glob.glob(sourceFile):
system('install -m0755 -o root -g root %s %s' % (source, destinationDirectory))
def readable_insinto(destinationDirectory, *sourceFiles):
'''inserts file list into destinationDirectory'''
if not sourceFiles or not destinationDirectory:
raise ArgumentError('Insufficient arguments...')
if not can_access_directory(destinationDirectory):
makedirs(destinationDirectory)
for sourceFile in sourceFiles:
for source in glob.glob(sourceFile):
system('install -m0644 %s %s' % (source, destinationDirectory))
def lib_insinto(sourceFile, destinationDirectory, permission = 0644):
'''inserts a library fileinto destinationDirectory with given permission'''
if not sourceFile or not destinationDirectory:
raise ArgumentError('Insufficient arguments...')
if not can_access_directory(destinationDirectory):
makedirs(destinationDirectory)
if os.path.islink(sourceFile):
os.symlink(os.path.realpath(sourceFile), os.path.join(destinationDirectory, sourceFile))
else:
system('install -m%s %s %s' % (permission, sourceFile, destinationDirectory))
@@ -1,57 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# standard python modules
import os
# Pisi Modules
import pisi.context as ctx
# ActionsAPI Modules
import pisi.actionsapi
import pisi.actionsapi.get as get
from pisi.actionsapi.shelltools import system, can_access_file
from pisi.actionsapi.pisitools import dodoc
class CompileError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
class InstallError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
class RunTimeError(pisi.actionsapi.Error):
def __init__(self, Exception):
ctx.ui.error(Exception)
def compile(parameters = ''):
'''compile source with given parameters.'''
if system('python setup.py build %s' % (get.installDIR(), parameters)):
raise CompileError('!!! Make failed...\n')
def install(parameters = ''):
'''does python setup.py install'''
if system('python setup.py install --root=%s --no-compile %s' % (get.installDIR(), parameters)):
raise InstallError('!!! Install failed...\n')
DDOCS = 'CHANGELOG COPYRIGHT KNOWN_BUGS MAINTAINERS PKG-INFO \
CONTRIBUTORS LICENSE COPYING* Change* MANIFEST* README*'
for doc in DDOCS:
if can_access_file(doc):
pisitools.dodoc(doc)
def run(parameters = ''):
'''executes parameters with python'''
if system('python %s' % (parameters)):
raise RunTimeError('!!! Running %s failed...\n' % parameters)
@@ -1,198 +0,0 @@
#!/usr/bin/python
#-*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Standart Python Modules
import os
import glob
import shutil
# Pisi Modules
import pisi.context as ctx
# ActionsAPI Modules
import pisi.actionsapi
import pisi.actionsapi.get
def can_access_file(sourceFile):
'''test the existence of file'''
return os.access(sourceFile, os.F_OK)
def can_access_directory(destinationDirectory):
'''test readability, writability and executablility of directory'''
return os.access(destinationDirectory, os.R_OK | os.W_OK | os.X_OK)
def makedirs(destinationDirectory):
'''recursive directory creation function'''
try:
os.makedirs(destinationDirectory)
except OSError:
pass
def echo(destionationFile, content):
try:
f = open(destionationFile, 'a')
f.write("%s\n" % content)
f.close()
except IOError:
ctx.ui.error(' ActionsAPI [echo]: Can\'t append to file...')
def chmod(sourceFile, mode = 0755):
'''change the mode of sourceFile to the mode'''
for file in glob.glob(sourceFile):
if can_access_file(file):
try:
os.chmod(file, mode)
except OSError:
ctx.ui.error(' ActionsAPI [chmod]: Operation not permitted...')
else:
ctx.ui.error(' ActionsAPI [chmod]: File doesn\'t exists...')
def chown(sourceFile, uid = 0, gid = 0):
'''change the owner and group id of sourceFile to the numeric uid and gid'''
if can_access_file(sourceFile):
try:
os.chown(sourceFile, uid, gid)
except OSError:
ctx.ui.error(' ActionsAPI [chown]: Operation not permitted...')
else:
ctx.ui.error(' ActionsAPI [chown]: File doesn\'t exists...')
def sym(sourceFile, destinationFile):
'''creates symbolic link'''
try:
os.symlink(sourceFile, destinationFile)
except OSError:
ctx.ui.error(' ActionsAPI [sym]: Permission denied...')
def unlink(sourceFile):
'''remove the file path'''
if isFile(sourceFile) or isLink(sourceFile):
try:
os.unlink(sourceFile)
except OSError:
ctx.ui.error(' ActionsAPI [unlink]: Permission denied.')
elif isDirectory(sourceFile):
pass
else:
ctx.ui.error(' ActionsAPI [unlink]: File doesn\'t exists.')
def unlinkDir(sourceDirectory):
'''delete an entire directory tree'''
if isDirectory(sourceDirectory) or isLink(sourceDirectory):
try:
shutil.rmtree(sourceDirectory)
except OSError:
ctx.ui.error(' ActionsAPI [unlinkDir]: Operation not permitted.')
elif isFile(sourceDirectory):
pass
else:
ctx.ui.error(' ActionsAPI [unlinkDir]: Directory doesn\'t exists.')
def move(sourceFile, destinationFile):
'''recursively move a sourceFile or directory to destinationFile'''
for file in glob.glob(sourceFile):
if isFile(file) or isLink(file) or isDirectory(file):
try:
shutil.move(file, destinationFile)
except OSError:
ctx.ui.error(' ActionsAPI [move]: Permission denied.')
else:
ctx.ui.error(' ActionsAPI [move]: File doesn\'t exists.')
def copy(sourceFile, destinationFile):
'''recursively copy a sourceFile or directory to destinationFile'''
for file in glob.glob(sourceFile):
if isFile(file) or isLink(file):
try:
shutil.copy(file, destinationFile)
except IOError:
ctx.ui.error(' ActionsAPI [copy]: Permission denied.')
else:
ctx.ui.error(' ActionsAPI [copy]: File doesn\'t exists.')
def copytree(source, destination, sym = False):
'''recursively copy an entire directory tree rooted at source'''
if isDirectory(source) or isLink(source):
try:
shutil.copytree(source, destination, sym)
except OSError:
ctx.ui.error(' ActionsAPI [copytree]: Permission denied.')
else:
ctx.ui.error(' ActionsAPI [copytree]: Directory doesn\'t exists.')
def touch(sourceFile):
'''changes the access time of the 'sourceFile', or creates it if it is not exist'''
if glob.glob(sourceFile):
for file in glob.glob(sourceFile):
os.utime(file, None)
else:
try:
f = open(sourceFile, 'w')
f.close()
except IOError:
ctx.ui.error(' ActionsAPI [touch]: Permission denied.')
def cd(directoryName = ''):
'''change directory'''
current = os.getcwd()
if directoryName:
os.chdir(directoryName)
else:
os.chdir(os.path.dirname(current))
def ls(source):
'''listdir'''
if os.path.isdir(source):
return os.listdir(source)
else:
return glob.glob(source)
def export(key, value):
'''export environ variable'''
os.environ[key] = value
def isLink(sourceFile):
'''return True if sourceFile refers to a symbolic link'''
return os.path.islink(sourceFile)
def isFile(sourceFile):
'''return True if sourceFile is an existing regular file'''
return os.path.isfile(sourceFile)
def isDirectory(sourceDirectory):
'''Return True if sourceFile is an existing directory'''
return os.path.isdir(sourceDirectory)
def realPath(sourceFile):
'''return the canonical path of the specified filename, eliminating any symbolic links encountered in the path'''
return os.path.realpath(sourceFile)
def baseName(sourceFile):
'''return the base name of pathname sourceFile'''
return os.path.basename(sourceFile)
def dirName(sourceFile):
'''return the directory name of pathname path'''
return os.path.dirname(sourceFile)
def system(command):
#FIXME: String formatting
command = command.replace(" ", " ")
ctx.ui.debug('executing %s' % command)
p = os.popen(command)
while 1:
line = p.readline()
if not line:
break
ctx.ui.debug(line[0:len(line)-1])
return p.close()
@@ -1,82 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Standard Python Modules
from os import getenv, environ
# Pisi-Core Modules
import pisi.context as ctx
# Set individual information, that are generally needed for ActionsAPI
def exportFlags():
'''General flags used in actions API.'''
# Build systems depend on these environment variables. That is why
# we export them instead of using as (instance) variables.
values = ctx.config.values
environ['HOST'] = values.build.host
environ['CFLAGS'] = values.build.cflags
environ['CXXFLAGS'] = values.build.cxxflags
environ['LDFLAGS'] = values.build.ldflags
class Env(object):
'''General environment variables used in actions API'''
def __init__(self):
exportFlags()
self.__vars = {
'pkg_dir': 'PKG_DIR',
'work_dir': 'WORK_DIR',
'install_dir': 'INSTALL_DIR',
'src_name': 'SRC_NAME',
'src_version': 'SRC_VERSION',
'src_release': 'SRC_RELEASE',
'host': 'HOST',
'cflags': 'CFLAGS',
'cxxflags': 'CXXFLAGS',
'ldflags': 'LDFLAGS'
}
def __getattr__(self, attr):
# Using environment variables is somewhat tricky. Each time
# you need them you need to check for their value.
if self.__vars.has_key(attr):
return getenv(self.__vars[attr])
else:
return None
class Dirs:
'''General directories used in actions API.'''
# TODO: Eventually we should consider getting these from a/the
# configuration file
doc = 'usr/share/doc'
sbin = 'usr/sbin'
man = 'usr/share/man'
info = 'usr/share/info'
data = 'usr/share'
conf = 'etc'
localstate = 'var/lib'
defaultprefix = 'usr'
#FIXME: Get these from config or somewhere else!
kde = '/usr/kde/3.4'
qt = '/usr/qt/3'
def initVariables():
ctx.env = Env()
ctx.dirs = Dirs()
return ctx
glb = initVariables()
-589
View File
@@ -1,589 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr>
"""Top level PISI interfaces. a facade to the entire PISI system"""
import os
import sys
ver = sys.version_info
if ver[0] <= 2 and ver[1] < 4:
from sets import Set as set
import pisi
import pisi.context as ctx
from pisi.uri import URI
import pisi.util as util
import pisi.dependency as dependency
import pisi.pgraph as pgraph
import pisi.operations as operations
import pisi.packagedb as packagedb
import pisi.repodb
import pisi.installdb
from pisi.index import Index
import pisi.cli
class Error(pisi.Error):
pass
def init(database = True, options = None, ui = None ):
"""Initialize PiSi subsystem"""
import pisi.config
ctx.config = pisi.config.Config(options)
if ui is None:
if options:
pisi.context.ui = pisi.cli.CLI(options.debug)
else:
pisi.context.ui = pisi.cli.CLI()
else:
pisi.context.ui = ui
# initialize repository databases
if database:
ctx.repodb = pisi.repodb.init()
ctx.installdb = pisi.installdb.init()
# TODO: bunun da ctx'de olmasi gerek, global hesabi
packagedb.init()
# import pisi.sourcedb
# pisi.sourcedb.init()
def install(packages):
"""install a list of packages (either files/urls, or names)"""
# FIXME: this function name "install" makes impossible to import
# and use install module directly.
from install import InstallError
try:
# determine if this is a list of files/urls or names
if packages[0].endswith(ctx.const.package_prefix): # they all have to!
return install_pkg_files(packages)
else:
return install_pkg_names(packages)
#FIXME: As Gurer warns, something's fishy with this exception proc.
except InstallError, e:
ctx.ui.error("InstallError:%s" % e)
except packagedb.Error, e:
ctx.ui.error("PackageDBError: (%s)" % e)
ctx.ui.error("Package is not installable.")
#except Exception, e:
# print e
# ctx.ui.error("Error: %s" % e)
def install_pkg_files(package_URIs):
"""install a number of pisi package files"""
from package import Package
ctx.ui.debug('A = %s' % str(package_URIs))
for x in package_URIs:
if not x.endswith(ctx.const.package_prefix):
ctx.ui.error('Mixing file names and package names not supported YET.\n')
return False
# read the package information into memory first
# regardless of which distribution they come from
d_t = {}
dfn = {}
for x in package_URIs:
package = Package(x)
package.read()
name = str(package.metadata.package.name)
d_t[name] = package.metadata.package
dfn[name] = x
def satisfiesDep(dep):
return dependency.installed_satisfies_dep(dep) \
or dependency.dict_satisfies_dep(d_t, dep)
# for this case, we have to determine the dependencies
# that aren't already satisfied and try to install them
# from the repository
dep_unsatis = []
for name in d_t.keys():
pkg = d_t[name]
deps = pkg.runtimeDeps
for dep in deps:
if not satisfiesDep(dep):
dep_unsatis.append(dep)
# now determine if these unsatisfied dependencies could
# be satisfied by installing packages from the repo
# if so, then invoke install_pkg_names
extra_packages = [x.package for x in dep_unsatis]
if (extra_packages and install_pkg_names(extra_packages)) or \
(not extra_packages):
class PackageDB:
def __init__(self):
self.d = d_t
def get_package(self, key):
return d_t[str(key)]
packagedb = PackageDB()
A = d_t.keys()
if len(A)==0:
ctx.ui.info('No packages to install.')
return True
# try to construct a pisi graph of packages to
# install / reinstall
G_f = pgraph.PGraph(packagedb) # construct G_f
# find the "install closure" graph of G_f by package
# set A using packagedb
print A
for x in A:
G_f.add_package(x)
B = A
#state = {}
while len(B) > 0:
Bp = set()
for x in B:
pkg = packagedb.get_package(x)
print pkg
for dep in pkg.runtimeDeps:
print 'checking ', dep
if dependency.dict_satisfies_dep(d_t, dep):
if not dep.package in G_f.vertices():
Bp.add(str(dep.package))
G_f.add_dep(x, dep)
B = Bp
G_f.write_graphviz(sys.stdout)
order = G_f.topological_sort()
order.reverse()
print order
for x in order:
operations.install_single_file(dfn[x])
else:
raise Error('External dependencies not satisfied')
return True # everything went OK.
def install_pkg_names(A):
"""This is the real thing. It installs packages from
the repository, trying to perform a minimum number of
installs"""
ctx.ui.debug('A = %s' % str(A))
if len(A)==0:
ctx.ui.info('No packages to install.')
return True
# try to construct a pisi graph of packages to
# install / reinstall
G_f = pgraph.PGraph(packagedb) # construct G_f
# find the "install closure" graph of G_f by package
# set A using packagedb
print A
for x in A:
G_f.add_package(x)
B = A
#state = {}
while len(B) > 0:
Bp = set()
for x in B:
pkg = packagedb.get_package(x)
print pkg
for dep in pkg.runtimeDeps:
print 'checking ', dep
# we don't deal with already *satisfied* dependencies
if not dependency.installed_satisfies_dep(dep):
if not dep.package in G_f.vertices():
Bp.add(str(dep.package))
G_f.add_dep(x, dep)
B = Bp
G_f.write_graphviz(sys.stdout)
order = G_f.topological_sort()
order.reverse()
print order
for x in order:
operations.install_single_name(x)
return True # everything went OK :)
def package_graph(A):
"""Construct a package relations graph, containing
all dependencies of packages A"""
ctx.ui.debug('A = %s' % str(A))
# try to construct a pisi graph of packages to
# install / reinstall
G_f = pgraph.PGraph(packagedb) # construct G_f
# find the "install closure" graph of G_f by package
# set A using packagedb
for x in A:
G_f.add_package(x)
B = A
#state = {}
while len(B) > 0:
Bp = set()
for x in B:
pkg = packagedb.get_package(x)
print pkg
for dep in pkg.runtimeDeps:
# we don't deal with already *satisfied* dependencies
if not dep.package in G_f.vertices():
Bp.add(str(dep.package))
G_f.add_dep(x, dep)
# if not dependency.installed_satisfies_dep(dep):
# if not dep.package in G_f.vertices():
# Bp.add(str(dep.package))
# G_f.add_dep(x, dep)
B = Bp
return G_f
def upgrade(A):
upgrade_pkg_names(A)
def upgrade_pkg_names(A):
"""Re-installs packages from the repository, trying to perform
a maximum number of upgrades."""
ignore_build = ctx.config.options and ctx.config.options.ignore_build_no
# filter packages that are not upgradable
Ap = []
for x in A:
if not ctx.installdb.is_installed(x):
ctx.ui.info('Package %s is not installed.' % x)
continue
(version, release, build) = ctx.installdb.get_version(x)
pkg = packagedb.get_package(x)
if ignore_build or (not build):
if release < pkg.release:
Ap.append(x)
elif build < pkg.build:
Ap.append(x)
else:
#ctx.ui.info('Package %s cannot be upgraded. ' % x)
ctx.ui.info('Package %s is already at its latest version %s,\
release %s, build %s.'
% (x, pkg.version, pkg.release, pkg.build))
A = Ap
if len(A)==0:
ctx.ui.info('No packages to upgrade.')
return True
ctx.ui.debug('A = %s' % str(A))
# try to construct a pisi graph of packages to
# install / reinstall
G_f = pgraph.PGraph(packagedb) # construct G_f
# find the "install closure" graph of G_f by package
# set A using packagedb
for x in A:
G_f.add_package(x)
B = A
#state = {}
while len(B) > 0:
Bp = set()
for x in B:
pkg = packagedb.get_package(x)
print pkg
for dep in pkg.runtimeDeps:
print 'checking ', dep
# add packages that can be upgraded
if dependency.repo_satisfies_dep(dep):
if ctx.installdb.is_installed(dep.package):
(v,r,b) = ctx.installdb.get_version(dep.package)
rep_pkg = packagedb.get_package(dep.package)
(vp,rp,bp) = (rep_pkg.version, rep_pkg.release,
rep_pkg.build)
if ignore_build or (not b) or (not bp):
# if we can't look at build
if r >= rp: # installed already new
continue
elif b and bp and b >= bp:
continue
if not dep.package in G_f.vertices():
Bp.add(str(dep.package))
G_f.add_dep(x, dep)
B = Bp
G_f.write_graphviz(sys.stdout)
order = G_f.topological_sort()
order.reverse()
print order
for x in order:
operations.install_single_name(x, True)
return True # everything went OK :)
def list_upgradable():
ignore_build = ctx.config.options and ctx.config.options.ignore_build_no
A = ctx.installdb.list_installed()
# filter packages that are not upgradable
Ap = []
for x in A:
if not ctx.installdb.is_installed(x):
continue
(version, release, build) = ctx.installdb.get_version(x)
pkg = packagedb.get_package(x)
if ignore_build or (not build):
if release < pkg.release:
Ap.append(x)
elif build < pkg.build:
Ap.append(x)
else:
pass
#ctx.ui.info('Package %s cannot be upgraded. ' % x)
return Ap
def remove(A):
"""remove set A of packages from system (A is a list of package names)"""
# filter packages that are not installed
Ap = []
for x in A:
if ctx.installdb.is_installed(x):
Ap.append(x)
else:
ctx.ui.info('Package %s does not exist. Cannot remove.' % x)
A = Ap
if len(A)==0:
ctx.ui.info('No packages to remove.')
return True
# try to construct a pisi graph of packages to
# install / reinstall
G_f = pgraph.PGraph(packagedb) # construct G_f
# find the (install closure) graph of G_f by package
# set A using packagedb
print A
for x in A:
G_f.add_package(x)
B = A
#state = {}
while len(B) > 0:
Bp = set()
for x in B:
pkg = packagedb.get_package(x)
print 'processing', pkg.name
rev_deps = packagedb.get_rev_deps(x)
for (rev_dep, depinfo) in rev_deps:
print 'checking ', rev_dep
# we don't deal with unsatisfied dependencies
if dependency.installed_satisfies_dep(depinfo):
if not rev_dep in G_f.vertices():
Bp.add(rev_dep)
G_f.add_plain_dep(rev_dep, x)
B = Bp
G_f.write_graphviz(sys.stdout)
order = G_f.topological_sort()
print order
for x in order:
if ctx.installdb.is_installed(x):
operations.remove_single(x)
else:
ctx.ui.info('Package %s is not installed. Cannot remove.' % x)
return True # everything went OK :)
def configure_pending():
# TODO: not coded yet
# start with pending packages
# configure them in reverse topological order of configuration dependency
pass
def info(package):
if package.endswith(ctx.const.package_prefix):
return info_file(package)
else:
return info_name(package)
def info_file(package):
from package import Package
if not os.path.exists(package):
raise Error ('File %s not found' % package)
package = Package(package)
package.read()
return package.metadata, package.files
def info_name(package_name):
"""fetch package information for a package"""
if packagedb.has_package(package_name):
package = packagedb.get_package(package_name)
from pisi.metadata import MetaData
metadata = MetaData()
metadata.package = package
#FIXME: get it from sourcedb
metadata.source = None
#TODO: fetch the files from server if possible
if ctx.installdb.is_installed(package.name):
files = ctx.installdb.files(package.name)
else:
files = None
return metadata, files
else:
raise Error('Package %s not found' % package_name)
def index(repo_dir = '.'):
ctx.ui.info('* Building index of PISI files under %s' % repo_dir)
index = Index()
index.index(repo_dir)
index.write(ctx.const.pisi_index)
ctx.ui.info('* Index file written')
def add_repo(name, indexuri):
repo = pisi.repodb.Repo(URI(indexuri))
ctx.repodb.add_repo(name, repo)
def remove_repo(name):
if ctx.repodb.has_repo(name):
ctx.repodb.remove_repo(name)
else:
ctx.ui.error('* Repository %s does not exist. Cannot remove.'
% name)
def update_repo(repo):
ctx.ui.info('* Updating repository: %s' % repo)
index = Index()
index.read(ctx.repodb.get_repo(repo).indexuri.get_uri(), repo)
index.update_db(repo)
ctx.ui.info('* Package database updated.')
# build functions...
def prepare_for_build(pspecfile, authInfo=None):
# FIXME: there is a function named "build" in this module which
# makes it impossible to use build module directly.
from build import PisiBuild
url = URI(pspecfile)
if url.is_remote_file():
from sourcefetcher import SourceFetcher
fs = SourceFetcher(url, authInfo)
url.uri = fs.fetch_all()
pb = PisiBuild(url.uri)
# find out the build dependencies that are not satisfied...
dep_unsatis = []
for dep in pb.spec.source.buildDeps:
if not dependency.installed_satisfies_dep(dep):
dep_unsatis.append(dep)
# FIXME: take care of the required buildDeps...
# For now just report an error!
if dep_unsatis:
ctx.ui.error("Unsatisfied Build Dependencies:")
for dep in dep_unsatis:
ctx.ui.error(dep.package)
# FIXME: Don't exit for now! It's annoying to test on a system that
# doesn't has all packages made with pisi.
# Will be enabled on the full-pisi system.
# sys.exit(1)
return pb
def build(pspecfile, authInfo=None):
pb = prepare_for_build(pspecfile, authInfo)
pb.build()
order = {"none": 0,
"unpack": 1,
"setupaction": 2,
"buildaction": 3,
"installaction": 4,
"buildpackages": 5}
def __buildState_unpack(pb):
# unpack is the first state to run.
pb.fetch_source_archive()
pb.unpack_source_archive()
pb.apply_patches()
def __buildState_setupaction(pb, last):
if order[last] < order["unpack"]:
__buildState_unpack(pb)
pb.run_setup_action()
def __buildState_buildaction(pb, last):
if order[last] < order["setupaction"]:
__buildState_setupaction(pb, last)
pb.run_build_action()
def __buildState_installaction(pb, last):
if order[last] < order["buildaction"]:
__buildState_buildaction(pb, last)
pb.run_install_action()
def __buildState_buildpackages(pb, last):
if order[last] < order["installaction"]:
__buildState_installaction(pb, last)
pb.build_packages()
def build_until(pspecfile, state, authInfo=None):
pb = prepare_for_build(pspecfile, authInfo)
pb.compile_action_script()
last = pb.get_state()
ctx.ui.info("Last state was %s"%last)
if not last: last = "none"
if state == "unpack":
__buildState_unpack(pb)
return
if state == "setupaction":
__buildState_setupaction(pb, last)
return
if state == "buildaction":
__buildState_buildaction(pb, last)
return
if state == "installaction":
__buildState_installaction(pb, last)
return
__buildState_buildpackages(pb, last)
-213
View File
@@ -1,213 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Archive module provides access to regular archive file types.
# maintainer baris and meren
# standard library modules
import os
import tarfile
import zipfile
# PiSi modules
import pisi
import pisi.util as util
class ArchiveError(pisi.Error):
pass
class ArchiveBase(object):
"""Base class for Archive classes."""
def __init__(self, file_path, atype):
self.file_path = file_path
self.type = atype
def unpack(self, target_dir, clean_dir = False):
self.target_dir = target_dir
# first we check if we need to clean-up our working env.
if os.path.exists(self.target_dir) and clean_dir:
util.clean_dir(self.target_dir)
os.makedirs(self.target_dir)
class ArchiveTar(ArchiveBase):
"""ArchiveTar handles tar archives depending on the compression
type. Provides access to tar, tar.gz and tar.bz2 files.
This class provides the unpack magic for tar archives."""
def __init__(self, file_path, arch_type = "tar"):
super(ArchiveTar, self).__init__(file_path, arch_type)
def unpack(self, target_dir, clean_dir = False):
"""Unpack tar archive to a given target directory(target_dir)."""
super(ArchiveTar, self).unpack(target_dir, clean_dir)
rmode = ""
if self.type == 'tar':
rmode = 'r:'
elif self.type == 'targz':
rmode = 'r:gz'
elif self.type == 'tarbz2':
rmode = 'r:bz2'
else:
raise ArchiveError("Archive type not recognized")
tar = tarfile.open(self.file_path, rmode)
oldwd = os.getcwd()
os.chdir(self.target_dir)
for tarinfo in tar:
tar.extract(tarinfo)
os.chdir(oldwd)
tar.close()
class ArchiveZip(ArchiveBase):
"""ArchiveZip handles zip archives.
Being a zip archive PISI packages also use this class
extensively. This class provides unpacking and packing magic for
zip archives."""
symmagic = 2716663808 #long of hex val '0xA1ED0000L'
def __init__(self, file_path, arch_type = "zip", mode = 'r'):
super(ArchiveZip, self).__init__(file_path, arch_type)
self.zip_obj = zipfile.ZipFile(self.file_path, mode)
def close(self):
"""Close the zip archive."""
self.zip_obj.close()
def add_to_archive(self, file_name):
"""Add file or directory path to the zip file"""
# It's a pity that zipfile can't handle unicode strings. Grrr!
file_name = str(file_name)
if os.path.isdir(file_name) and not os.path.islink(file_name):
self.zip_obj.writestr(file_name + '/', '')
for f in os.listdir(file_name):
self.add_to_archive(os.path.join(file_name, f))
else:
if os.path.islink(file_name):
dest = os.readlink(file_name)
attr = zipfile.ZipInfo()
attr.filename = file_name
attr.create_system = 3
attr.external_attr = self.symmagic
self.zip_obj.writestr(attr, dest)
else:
self.zip_obj.write(file_name, file_name, zipfile.ZIP_DEFLATED)
def add_basename_to_archive(self, file_name):
"""Add only the basepath to the zip file. For example; if the given
file_name parameter is /usr/local/bin/somedir, this function
will create only the base directory/file somedir in the
archive."""
cwd = os.getcwd()
path_name = os.path.dirname(file_name)
file_name = os.path.basename(file_name)
if path_name:
os.chdir(path_name)
self.add_to_archive(file_name)
os.chdir(cwd)
def unpack_file_cond(self, pred, target_dir, archive_root = ''):
"""Unpack/Extract a file according to predicate function filename ->
bool"""
zip_obj = self.zip_obj
for info in zip_obj.infolist():
if pred(info.filename): # check if condition holds
# below code removes that, so we find it here
is_dir = info.filename.endswith('/')
# calculate output file name
if archive_root == '':
outpath = info.filename
else:
# change archive_root
if util.subpath(archive_root, info.filename):
outpath = util.removepathprefix(archive_root,
info.filename)
else:
continue # don't extract if not under
ofile = os.path.join(target_dir, outpath)
if is_dir: # this is a directory
d = os.path.join(target_dir, outpath)
if not os.path.isdir(d):
os.makedirs(d)
continue
# check that output dir is present
util.check_dir(os.path.dirname(ofile))
# remove output file we might be overwriting
if os.path.exists(ofile):
os.remove(ofile)
if info.external_attr == self.symmagic:
target = zip_obj.read(info.filename)
os.symlink(target, ofile)
else:
perm = info.external_attr
perm &= 0x00FF0000
perm >>= 16
perm |= 0x00000100
buff = open (ofile, 'wb')
file_content = zip_obj.read(info.filename)
buff.write(file_content)
buff.close()
os.chmod(ofile, perm)
def unpack_files(self, paths, target_dir):
self.unpack_file_cond(lambda f:f in paths, target_dir)
def unpack_dir(self, path, target_dir):
self.unpack_file_cond(lambda f:util.subpath(path, f), target_dir)
def unpack_dir_flat(self, path, target_dir):
self.unpack_file_cond(lambda f:util.subpath(path, f), target_dir, path)
def unpack(self, target_dir, clean_dir=False):
super(ArchiveZip, self).unpack(target_dir, clean_dir)
self.unpack_file_cond(lambda f: True, target_dir)
self.close()
return
class Archive:
"""Archive is the main factory for ArchiveClasses, regarding the
Abstract Factory Pattern :)."""
def __init__(self, file_path, arch_type):
"""accepted archive types:
targz, tarbz2, zip, tar"""
handlers = {
'targz': ArchiveTar,
'tarbz2': ArchiveTar,
'tar': ArchiveTar,
'zip': ArchiveZip
}
self.archive = handlers.get(arch_type)(file_path, arch_type)
def unpack(self, target_dir, clean_dir = False):
self.archive.unpack(target_dir, clean_dir)
def unpack_files(self, files, target_dir):
self.archive.unpack_files(files, target_dir)
-466
View File
@@ -1,466 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# package bulding stuff
# maintainer: baris and meren
# python standard library
import os
import sys
import gettext
__trans = gettext.translation('pisi', fallback=True)
_ = __trans.ugettext
import pisi
import pisi.util as util
import pisi.context as ctx
from pisi.sourcearchive import SourceArchive
from pisi.files import Files, FileInfo
from pisi.metadata import MetaData
from pisi.package import Package
class Error(pisi.Error):
pass
# Helper Functions
def get_file_type(path, pinfoList):
"""Return the file type of a path according to the given PathInfo
list"""
# The usage of depth is somewhat confusing. It is used for finding
# the best match to paths(in pinfolist). For an example, if paths
# contain ['/usr/share','/usr/share/doc'] and path is
# /usr/share/doc/filename our iteration over paths should match
# the second item.
depth = 0
ftype = ""
path = "/"+path # we need a real path.
for pinfo in pinfoList:
if util.subpath(pinfo.pathname, path):
length = len(pinfo.pathname)
if depth < length:
depth = length
ftype = pinfo.fileType
return ftype
def check_path_collision(package, pkgList):
"""This function will check for collision of paths in a package with
the paths of packages in pkgList. The return value will be the
list containing the paths that collide."""
collisions = []
for pinfo in package.paths:
for pkg in pkgList:
if pkg is package:
continue
for path in pkg.paths:
# if pinfo.pathname is a subpath of path.pathname like
# the example below. path.patname is marked as a
# collide. Exp:
# pinfo.pathname: /usr/share
# path.pathname: /usr/share/doc
if util.subpath(pinfo.pathname, path.pathname):
collisions.append(path.pathname)
ctx.ui.error(_('Path %s belongs in multiple packages') %
path.pathname)
return collisions
# a dynamic build context
from pisi.specfile import SpecFile
class BuildContext(object):
"""Build Context Singleton"""
def __init__(self, pspecfile):
super(BuildContext, self).__init__()
self.set_spec_file(pspecfile)
def set_spec_file(self, pspecfile):
self.pspecfile = pspecfile
spec = SpecFile()
spec.read(pspecfile)
# FIXME: following checks the integrity but does nothing when it is wrong
# -gurer
#spec.verify() # check pspec integrity
self.spec = spec
# directory accessor functions
# pkg_x_dir: per package directory for storing info type x
def pkg_dir(self):
"package build directory"
packageDir = self.spec.source.name + '-' + \
self.spec.source.version + '-' + self.spec.source.release
return ctx.config.destdir + ctx.config.values.dirs.tmp_dir \
+ '/' + packageDir
def pkg_work_dir(self):
return self.pkg_dir() + ctx.const.work_dir_suffix
def pkg_install_dir(self):
return self.pkg_dir() + ctx.const.install_dir_suffix
class PisiBuild:
"""PisiBuild class, provides the package build and creation routines"""
def __init__(self, pspec):
self.bctx = BuildContext(pspec)
self.pspecDir = os.path.dirname(os.path.realpath(self.bctx.pspecfile))
self.spec = self.bctx.spec
self.sourceArchive = SourceArchive(self.bctx)
self.set_environment_vars()
self.actionLocals = None
self.actionGlobals = None
self.srcDir = None
def set_state(self, state):
stateFile = os.path.join(self.bctx.pkg_work_dir(), "pisiBuildState")
open(stateFile, "w").write(state)
def get_state(self):
stateFile = os.path.join(self.bctx.pkg_work_dir(), "pisiBuildState")
if not os.path.exists(stateFile): # no state
return None
return open(stateFile, "r").read()
def build(self):
"""Build the package in one shot."""
ctx.ui.info(_("Building PISI source package: %s") % self.spec.source.name)
util.xterm_title(_("Building PISI source package: %s\n") % self.spec.source.name)
self.compile_action_script()
# check if all patch files exists, if there are missing no need to unpack!
self.patch_exists()
self.fetch_source_archive()
self.unpack_source_archive()
self.solve_build_dependencies()
# apply the patches and prepare a source directory for build.
self.apply_patches()
self.run_setup_action()
self.run_build_action()
self.run_install_action()
# after all, we are ready to build/prepare the packages
self.build_packages()
def set_environment_vars(self):
"""Sets the environment variables for actions API to use"""
evn = {
"PKG_DIR": self.bctx.pkg_dir(),
"WORK_DIR": self.bctx.pkg_work_dir(),
"INSTALL_DIR": self.bctx.pkg_install_dir(),
"SRC_NAME": self.spec.source.name,
"SRC_VERSION": self.spec.source.version,
"SRC_RELEASE": self.spec.source.release
}
os.environ.update(evn)
def fetch_source_archive(self):
ctx.ui.info(_("Fetching source from: %s") % self.spec.source.archiveUri)
self.sourceArchive.fetch()
ctx.ui.info(_("Source archive is stored: %s/%s")
%(ctx.config.archives_dir(), self.spec.source.archiveName))
def unpack_source_archive(self):
ctx.ui.info(_("Unpacking archive..."))
self.sourceArchive.unpack()
ctx.ui.info(_(" unpacked (%s)") % self.bctx.pkg_work_dir())
self.set_state("unpack")
def run_setup_action(self):
# Run configure, build and install phase
ctx.ui.action(_("Setting up source..."))
self.run_action_function(ctx.const.setup_func)
self.set_state("setupaction")
def run_build_action(self):
ctx.ui.action(_("Building source..."))
self.run_action_function(ctx.const.build_func)
self.set_state("buildaction")
def run_install_action(self):
ctx.ui.action(_("Installing..."))
# Before install make sure install_dir is clean
if os.path.exists(self.bctx.pkg_install_dir()):
util.clean_dir(self.bctx.pkg_install_dir())
# install function is mandatory!
self.run_action_function(ctx.const.install_func, True)
self.set_state("installaction")
def compile_action_script(self):
"""Compiles actions.py and sets the actionLocals and actionGlobals"""
specdir = os.path.dirname(self.bctx.pspecfile)
scriptfile = os.path.join(specdir, ctx.const.actions_file)
try:
localSymbols = globalSymbols = {}
buf = open(scriptfile).read()
exec compile(buf, "error", "exec") in localSymbols, globalSymbols
except IOError, e:
ctx.ui.error(_("Unable to read Action Script (%s): %s") %(scriptfile,e))
sys.exit(1)
except SyntaxError, e:
ctx.ui.error (_("SyntaxError in Action Script (%s): %s") %(scriptfile,e))
sys.exit(1)
self.actionLocals = localSymbols
self.actionGlobals = globalSymbols
self.srcDir = self.pkg_src_dir()
def pkg_src_dir(self):
"""Returns the real path of WorkDir for an unpacked archive."""
try:
workdir = self.actionGlobals['WorkDir']
except KeyError:
workdir = self.spec.source.name + "-" + self.spec.source.version
return os.path.join(self.bctx.pkg_work_dir(), workdir)
def run_action_function(self, func, mandatory=False):
"""Calls the corresponding function in actions.py.
If mandatory parameter is True, and function is not present in
actionLocals pisi.build.Error will be raised."""
# we'll need our working directory after actionscript
# finished its work in the archive source directory.
curDir = os.getcwd()
os.chdir(self.srcDir)
if func in self.actionLocals:
self.actionLocals[func]()
else:
if mandatory:
Error, _("unable to call function from actions: %s") %func
os.chdir(curDir)
def solve_build_dependencies(self):
"""fail if dependencies not satisfied"""
#TODO: we'll have to do better than plugging a fxn here
pass
def patch_exists(self):
"""check existence of patch files declared in PSPEC"""
files_dir = os.path.abspath(os.path.join(self.pspecDir,
ctx.const.files_dir))
for patch in self.spec.source.patches:
patchFile = os.path.join(files_dir, patch.filename)
if not os.access(patchFile, os.F_OK):
raise Error(_("Patch file is missing: %s\n") % patch.filename)
def apply_patches(self):
files_dir = os.path.abspath(os.path.join(self.pspecDir,
ctx.const.files_dir))
for patch in self.spec.source.patches:
patchFile = os.path.join(files_dir, patch.filename)
if patch.compressionType:
patchFile = util.uncompress(patchFile,
compressType=patch.compressionType,
targetDir=ctx.config.tmp_dir())
ctx.ui.action(_("* Applying patch: %s") % patch.filename)
util.do_patch(self.srcDir, patchFile, level=patch.level, target=patch.target)
def gen_metadata_xml(self, package):
"""Generate the metadata.xml file for build source.
metadata.xml is composed of the information from specfile plus
some additional information."""
metadata = MetaData()
metadata.from_spec(self.spec.source, package)
metadata.package.distribution = ctx.config.values.general.distribution
metadata.package.distributionRelease = ctx.config.values.general.distribution_release
metadata.package.architecture = "Any"
# FIXME: Bu hatalı. installsize'ı almak için tüm
# pkg_install_dir()'ın boyutunu hesaplayamayız. Bir source
# birden fazla kaynak üretebilir. package.paths ile
# karşılaştırarak file listesinden boyutları hesaplatmalıyız.
d = self.bctx.pkg_install_dir()
size = util.dir_size(d)
metadata.package.installedSize = str(size)
# build no
if ctx.config.options.ignore_build_no:
metadata.package.build = None # means, build no information n/a
ctx.ui.warning('build number is not available.')
else:
metadata.package.build = self.calc_build_no(metadata.package.name)
metadata.write(os.path.join(self.bctx.pkg_dir(), ctx.const.metadata_xml))
self.metadata = metadata
def gen_files_xml(self, package):
"""Generetes files.xml using the path definitions in specfile and
generated files by the build system."""
files = Files()
install_dir = self.bctx.pkg_install_dir()
collisions = check_path_collision(package,
self.spec.packages)
if collisions:
raise Error(_('Path collisions detected'))
d = {}
for pinfo in package.paths:
path = install_dir + pinfo.pathname
for fpath, fhash in util.get_file_hashes(path, collisions, install_dir):
frpath = util.removepathprefix(install_dir, fpath) # relative path
ftype = get_file_type(frpath, package.paths)
try: # broken links can cause problem
fsize = str(os.path.getsize(fpath))
except OSError:
fsize = "0"
d[frpath] = FileInfo(frpath, ftype, fsize, fhash)
for (p, fileinfo) in d.iteritems():
files.append(fileinfo)
files.write(os.path.join(self.bctx.pkg_dir(), ctx.const.files_xml))
self.files = files
def calc_build_no(self, package_name):
"""Calculate build number"""
# find previous build in ctx.config.options.output_dir
found = []
for root, dirs, files in os.walk(ctx.config.options.output_dir):
for fn in files:
fn = fn.decode('utf-8')
if fn.startswith(package_name + '-') and \
fn.endswith(ctx.const.package_prefix):
old_package_fn = os.path.join(root, fn)
ctx.ui.info('(found old version %s)' % old_package_fn)
old_pkg = Package(old_package_fn, 'r')
old_pkg.read(os.path.join(ctx.config.tmp_dir(), 'oldpkg'))
old_build = old_pkg.metadata.package.build
found.append( (old_package_fn, old_build) )
if not found:
return 0
ctx.ui.warning('(no previous build found, setting build no to 0.)')
else:
a = filter(lambda (x,y): y != None, found)
if a:
a.sort(lambda x,y : cmp(x[1],y[1]))
old_package_fn = a[0][0]
old_build = a[0][1]
else:
old_build = None
# compare old files.xml with the new one..
old_pkg = Package(old_package_fn, 'r')
old_pkg.read(os.path.join(ctx.config.tmp_dir(), 'oldpkg'))
# FIXME: TAKE INTO ACCOUNT MINOR CHANGES IN METADATA
changed = False
fnew = self.files.list
fold = old_pkg.files.list
fold.sort(lambda x,y : cmp(x.path,y.path))
fnew.sort(lambda x,y : cmp(x.path,y.path))
if len(fnew) != len(fold):
changed = True
else:
for i in range(len(fold)):
fo = fold.pop(0)
fn = fnew.pop(0)
if fo.path != fn.path:
changed = True
break
else:
if fo.hash != fn.hash:
changed = True
break
# set build number
if old_build is None:
ctx.ui.warning('(old package lacks a build no, setting build no to 0.)')
return 0
elif changed:
return old_build + 1
else:
return old_build
def build_packages(self):
"""Build each package defined in PSPEC file. After this process there
will be .pisi files hanging around, AS INTENDED ;)"""
for package in self.spec.packages:
# store additional files
c = os.getcwd()
os.chdir(self.pspecDir)
install_dir = self.bctx.pkg_dir() + ctx.const.install_dir_suffix
for afile in package.additionalFiles:
src = os.path.join(ctx.const.files_dir, afile.filename)
dest = os.path.join(install_dir + os.path.dirname(afile.target), os.path.basename(afile.target))
util.copy_file(src, dest)
if afile.permission:
# mode is octal!
os.chmod(dest, int(afile.permission, 8))
os.chdir(c)
name = util.package_name(package.name,
self.spec.source.version,
self.spec.source.release)
ctx.ui.action(_("** Building package %s") % package.name);
ctx.ui.action(_("Generating %s...") % ctx.const.files_xml)
self.gen_files_xml(package)
ctx.ui.info(_(" done."))
ctx.ui.action(_("Generating %s...") % ctx.const.metadata_xml)
self.gen_metadata_xml(package)
ctx.ui.info(_(" done."))
ctx.ui.action(_("Creating PISI package %s") % name)
pkg = Package(name, 'w')
# add comar files to package
os.chdir(self.pspecDir)
for pcomar in package.providesComar:
fname = os.path.join(ctx.const.comar_dir,
pcomar.script)
pkg.add_to_package(fname)
# add xmls and files
os.chdir(self.bctx.pkg_dir())
pkg.add_to_package(ctx.const.metadata_xml)
pkg.add_to_package(ctx.const.files_xml)
# Now it is time to add files to the packages using newly
# created files.xml
files = Files()
files.read(ctx.const.files_xml)
for finfo in files.list:
pkg.add_to_package("install/" + finfo.path)
pkg.close()
os.chdir(c)
self.set_state("buildpackages")
util.xterm_title_reset()
-23
View File
@@ -1,23 +0,0 @@
Writing commands:
-----------------
TODO: this is a *bit* out of date now.
Subclass from Command.
Be careful not to import PiSi modules before Command is run, e.g.
do it in run() method. This is necessary to prevent an obscure
initialization error.
We used to import pisi.operations in pisi.cli
This prevented pisi.operations from having the current global
pisi.ui.ui because it's loaded before the UI is set! So, despite
what you might understand from the python FAQ 1.2.3
http://www.python.org/doc/faq/programming.html#how-do-i-share-global-variables-across-modules
you have to be careful about the initialization order when using
singleton modules.
Another way to solve this is to ensure that the global module is
always imported again in every function it is called (see
ui.CLI.confirm() ) but this is more expensive.
-85
View File
@@ -1,85 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# pisi.cli package version
__version__ = "1.0_alpha2"
import sys
import pisi
import pisi.context as ctx
from pisi.ui import UI
from pisi.cli.colors import colorize
class Error(pisi.Error):
pass
class Exception(pisi.Exception):
pass
class CLI(UI):
"Command Line Interface"
def __init__(self, show_debug = False, show_verbose = False):
super(CLI, self).__init__(show_debug, show_verbose)
def output(self, str):
sys.stdout.write(str)
sys.stdout.flush()
def info(self, msg, verbose = False):
# TODO: need to look at more kinds of info messages
# let's cheat from KDE :)
if verbose and self.show_verbose:
self.output(msg + '\n')
elif not verbose:
self.output(msg + '\n')
def warning(self,msg):
self.output(colorize('Warning:' + msg + '\n', 'purple'))
def error(self,msg):
self.output(colorize('Error:' + msg + '\n', 'red'))
def action(self,msg):
#TODO: this seems quite redundant?
self.output(colorize(msg + '\n', 'green'))
def choose(self, msg, opts):
print msg
for i in range(0,len(opts)):
print i + 1, opts(i)
while True:
s = raw_input(msg + colorize('1-%d' % len(opts), 'red'))
try:
opt = int(s)
if 1 <= opt and opt <= len(opts):
return opts(opt-1)
except (Exception,e):
pass
def confirm(self, msg):
if ctx.config.options and ctx.config.options.yes_all:
return True
while True:
s = raw_input(msg + colorize('(yes/no)', 'red'))
if s.startswith('y') or s.startswith('Y'):
return True
if s.startswith('n') or s.startswith('N'):
return False
def display_progress(self, pd):
out = '\r%-30.30s %3d%% %12.2f %s' % \
(pd['filename'], pd['percent'], pd['rate'], pd['symbol'])
self.output(out)
-60
View File
@@ -1,60 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Colors module provides some color codes for console output.
colors = {'black' : "\033[30m",
'red' : "\033[31m",
'green' : "\033[32m",
'yellow' : "\033[33m",
'blue' : "\033[34m",
'purple' : "\033[35m",
'cyan' : "\033[36m",
'white' : "\033[37m",
'brightblack' : "\033[01;30m",
'brightred' : "\033[01;31m",
'brightgreen' : "\033[01;32m",
'brightyellow' : "\033[01;33m",
'brightblue' : "\033[01;34m",
'brightmagenta' : "\033[01;35m",
'brightcyan' : "\033[01;36m",
'brightwhite' : "\033[01;37m",
'underlineblack' : "\033[04;30m",
'underlinered' : "\033[04;31m",
'underlinegreen' : "\033[04;32m",
'underlineyellow' : "\033[04;33m",
'underlineblue' : "\033[04;34m",
'underlinemagenta' : "\033[04;35m",
'underlinecyan' : "\033[04;36m",
'underlinewhite' : "\033[04;37m",
'blinkingblack' : "\033[05;30m",
'blinkingred' : "\033[05;31m",
'blinkinggreen' : "\033[05;32m",
'blinkingyellow' : "\033[05;33m",
'blinkingblue' : "\033[05;34m",
'blinkingmagenta' : "\033[05;35m",
'blinkingcyan' : "\033[05;36m",
'blinkingwhite' : "\033[05;37m",
'backgroundblack' : "\033[07;30m",
'backgroundred' : "\033[07;31m",
'backgroundgreen' : "\033[07;32m",
'backgroundyellow' : "\033[07;33m",
'backgroundblue' : "\033[07;34m",
'backgroundmagenta' : "\033[07;35m",
'backgroundcyan' : "\033[07;36m",
'backgroundwhite' : "\033[07;37m",
'default' : "\033[0m" }
def colorize(msg, color):
"""Colorize the given message for console output"""
if colors.has_key(color):
return colors[color] + msg + colors['default']
else:
return msg
-952
View File
@@ -1,952 +0,0 @@
# -*- coding:utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import sys
from optparse import OptionParser
import pisi
import pisi.cli
import pisi.context as ctx
from pisi.uri import URI
class Command(object):
"""generic help string for any command"""
# class variables
cmd = []
cmd_dict = {}
def commands_string():
s = ''
list = [x.name[0] for x in Command.cmd]
list.sort()
for x in list:
s += x + '\n'
return s
commands_string = staticmethod(commands_string)
def get_command(cmd, fail=False):
if Command.cmd_dict.has_key(cmd):
return Command.cmd_dict[cmd]()
if fail:
print "Unrecognized command: ", cmd
sys.exit(1)
else:
return None
get_command = staticmethod(get_command)
# instance variabes
def __init__(self):
# now for the real parser
import pisi
self.parser = OptionParser(usage=getattr(self, "__doc__"),
version="%prog " + pisi.__version__)
self.options()
self.commonopts()
(self.options, self.args) = self.parser.parse_args()
self.args.pop(0) # exclude command arg
self.check_auth_info()
def commonopts(self):
'''common options'''
p = self.parser
p.add_option("-D", "--destdir", action="store")
p.add_option("", "--yes-all", action="store_true",
default=False, help = "assume yes in all yes/no queries")
p.add_option("-u", "--username", action="store")
p.add_option("-p", "--password", action="store")
p.add_option("-P", action="store_true", dest="getpass", default=False,
help="Get password from the command line")
p.add_option("-v", "--verbose", action="store_true",
dest="verbose", default=False,
help="detailed output")
p.add_option("-d", "--debug", action="store_true",
default=True, help="show debugging information")
p.add_option("-n", "--dry-run", action="store_true", default=False,
help = "do not perform any action, just show what\
would be done")
return p
def options(self):
"""This is a fall back function. If the implementer module provides an
options function it will be called"""
pass
def check_auth_info(self):
username = self.options.username
password = self.options.password
# TODO: We'll get the username, password pair from a configuration
# file from users home directory. Currently we need user to
# give it from the user interface.
# if not username and not password:
# if someauthconfig.username and someauthconfig.password:
# self.authInfo = (someauthconfig.username,
# someauthconfig.password)
# return
if username and password:
self.authInfo = (username, password)
return
if username and self.options.getpass:
from getpass import getpass
password = getpass("Password: ")
self.authInfo = (username, password)
else:
self.authInfo = None
def init(self, database = True):
"""initialize PiSi components"""
# NB: command imports here or in the command class run fxns
import pisi.api
pisi.api.init(database, self.options)
def finalize(self):
"""do cleanup work for PiSi components"""
pass
def get_name(self):
return self.__class__.name
def format_name(self):
(name, shortname) = self.get_name()
if shortname:
return "%s (%s)" % (name, shortname)
else:
return name
def help(self):
"""print help for the command"""
ctx.ui.info(self.format_name() + ': ')
print getattr(self, "__doc__")
print self.parser.format_option_help()
def die(self):
"""exit program"""
print 'Program terminated abnormally.'
sys.exit(-1)
class autocommand(type):
def __init__(cls, name, bases, dict):
super(autocommand, cls).__init__(name, bases, dict)
Command.cmd.append(cls)
name = getattr(cls, 'name', None)
if name is None:
raise pisi.cli.Error('command lacks name')
longname, shortname = name
def add_cmd(cmd):
if Command.cmd_dict.has_key(cmd):
raise pisi.cli.Error('duplicate command %s' % cmd)
else:
Command.cmd_dict[cmd] = cls
add_cmd(longname)
if shortname:
add_cmd(shortname)
class Help(Command):
"""Prints help for given commands.
Usage: help [ <command1> <command2> ... <commandn> ]
If run without parameters, it prints the general help."""
__metaclass__ = autocommand
def __init__(self):
#TODO? Discard Help's own usage doc in favor of general usage doc
#self.__doc__ = usage_text
#self.__doc__ += commands_string()
super(Help, self).__init__()
name = ("help", "h")
def run(self):
if not self.args:
self.parser.set_usage(usage_text)
self.parser.print_help()
return
self.init()
for arg in self.args:
obj = Command.get_command(arg, True)
obj.help()
print
self.finalize()
class Clean(Command):
"""Clean stale locks."""
__metaclass__ = autocommand
def __init__(self):
super(Clean, self).__init__()
name = ("clean", None)
def run(self):
self.init()
pisi.util.clean_locks()
self.finalize()
class Graph(Command):
"""Graph package relations.
Usage: graph <package1> <package2> ...
Write a graph of package relations, tracking dependency and
conflicts relations starting from given packages.
"""
__metaclass__ = autocommand
def __init__(self):
super(Graph, self).__init__()
name = ("graph", None)
def run(self):
self.init()
if self.args:
g = pisi.api.package_graph(self.args)
g.write_graphviz(file('pgraph.dot', 'w'))
self.finalize()
def buildno_opts(self):
self.parser.add_option("", "--ignore-build-no", action="store_true",
default=False,
help="do not take build no into account.")
class Build(Command):
"""Build a PISI package using a pspec.xml file
Usage: build <pspec.xml>
You can give a URI of the pspec.xml file. PISI will
fetch all necessary files and build the package for you.
"""
__metaclass__ = autocommand
def __init__(self):
super(Build, self).__init__()
name = ("build", "bi")
def options(self):
buildno_opts(self)
self.parser.add_option("-O", "--output-dir", action="store", default=".",
help="output directory for produced packages")
def run(self):
if not self.args:
self.help()
return
self.init()
ctx.ui.info('Output directory: %s\n' % ctx.config.options.output_dir)
for arg in self.args:
pisi.api.build(arg, self.authInfo)
self.finalize()
class PackageOp(Command):
"""Abstract package operation command"""
def __init__(self):
super(PackageOp, self).__init__()
def options(self):
self.parser.add_option("", "--ignore-comar", action="store_true",
default=False, help="bypass comar configuration agent")
## self.parser.add_option("", "--ignore-dependency",
## action="store_true",
## default=False, help="death")
def init(self):
super(PackageOp, self).init(True)
import pisi
if not self.options.ignore_comar:
import comar
try:
ctx.comard = comar.Link() # context
except comar.Error:
ctx.ui.error('Comar error encountered\n')
self.die()
def finalize(self):
#self.finalize_db()
if not self.options.ignore_comar:
pass
#try:
# pisi.comariface.finalize()
#except pisi.comariface.ComarError:
# ui.error('Comar error encountered\n')
class Install(PackageOp):
"""Install PISI packages
Usage: install <package1> <package2> ... <packagen>
You may use filenames, URIs or package names for packages. If you have
specified a package name, it should exist in a specified repository.
"""
__metaclass__ = autocommand
def __init__(self):
super(Install, self).__init__()
name = "install", "it"
def options(self):
super(Install, self).options()
buildno_opts(self)
def run(self):
if not self.args:
self.help()
return
self.init()
pisi.api.install(self.args)
self.finalize()
class Upgrade(PackageOp):
"""Upgrade PISI packages
Usage: Upgrade <package1> <package2> ... <packagen>
You may use filenames, URIs or package names for packages. If you have
specified a package name, it should exist in a specified repository.
"""
__metaclass__ = autocommand
def __init__(self):
super(Upgrade, self).__init__()
name = ("upgrade", "up")
def options(self):
super(Upgrade, self).options()
buildno_opts(self)
def run(self):
if not self.args:
self.help()
return
self.init()
pisi.api.upgrade(self.args)
self.finalize()
class Remove(PackageOp):
"""Remove PISI packages
Usage: remove <package1> <package2> ... <packagen>
Remove package(s) from your system. Just give the package names to remove.
"""
__metaclass__ = autocommand
def __init__(self):
super(Remove, self).__init__()
name = ("remove", "rm")
def run(self):
if not self.args:
self.help()
return
self.init()
pisi.api.remove(self.args)
self.finalize()
class UpgradeAll(PackageOp):
"""Upgrade system
Usage: Upgrade
Upgrade the entire system.
"""
__metaclass__ = autocommand
def __init__(self):
super(UpgradeAll, self).__init__()
name = ("upgrade-all", None)
def options(self):
super(UpgradeAll, self).options()
buildno_opts(self)
def run(self):
if self.args:
self.help()
return
self.init()
pisi.api.upgrade(ctx.installdb.list_installed())
self.finalize()
class ConfigurePending(PackageOp):
"""configure pending packages
"""
__metaclass__ = autocommand
def __init__(self):
super(ConfigurePending, self).__init__()
name = ("configure-pending", "cp")
def run(self):
self.init()
pisi.api.configure_pending()
self.finalize()
class Info(Command):
"""Display package information
Usage: info <package1> <package2> ... <packagen>
"""
__metaclass__ = autocommand
def __init__(self):
super(Info, self).__init__()
name = ("info", "i")
def options(self):
self.parser.add_option("-f", "--files", action="store_true",
default=False,
help="Show a list of package files.")
self.parser.add_option("-F", "--files-path", action="store_true",
default=False,
help="Show only paths.")
def run(self):
if not self.args:
self.help()
return
self.init(True)
for arg in self.args:
self.printinfo(arg)
self.finalize()
def printinfo(self, arg):
import os.path
metadata, files = pisi.api.info(arg)
print metadata.package
if self.options.files or self.options.files_path:
if files:
print
print 'Files:'
for fileinfo in files.list:
if self.options.files:
print fileinfo
else:
print fileinfo.path
else:
print 'File information not available'
class Index(Command):
"""Index PISI files in a given directory
Usage: index <directory>
This command searches for all PiSi files in a directory, collects PiSi
tags from them and accumulates the information in an output XML file,
named by default 'pisi-index.xml'. In particular, it indexes both
source and binary packages.
"""
__metaclass__ = autocommand
def __init__(self):
super(Index, self).__init__()
name = ("index", "ix")
def options(self):
self.parser.add_option("-a", "--absolute-uris", action="store_true",
default=False,
help="store absolute links for indexed files.")
def run(self):
self.init()
from pisi.api import index
if len(self.args)==1:
index(self.args[0])
elif len(self.args)==0:
print 'Indexing current directory.'
index()
else:
print 'Indexing only a single directory supported.'
return
self.finalize()
class ListInstalled(Command):
"""Print the list of all installed packages
Usage: list-installed
"""
__metaclass__ = autocommand
def __init__(self):
super(ListInstalled, self).__init__()
name = ("list-installed", "li")
def options(self):
self.parser.add_option("-l", "--long", action="store_true",
default=False, help="show in long format")
self.parser.add_option("-i", "--install-info", action="store_true",
default=False, help="show detailed install info")
def run(self):
self.init(True)
list = ctx.installdb.list_installed()
list.sort()
if self.options.install_info:
print 'Package Name |St| Version| Rel.| Build| Distro| Date'
print '========================================================================'
for pkg in list:
package = pisi.packagedb.inst_packagedb.get_package(pkg)
inst_info = ctx.installdb.get_info(pkg)
if self.options.long:
print package
print inst_info
elif self.options.install_info:
print '%-15s | %s ' % (package.name, inst_info.one_liner())
else:
print '%15s - %s ' % (package.name, package.summary)
self.finalize()
class UpdateRepo(Command):
"""Update repository databases
Usage: update-repo <repo1> <repo2> ... <repon>
<repoi>: repository name
Synchronizes the PiSi databases with the current repository.
"""
__metaclass__ = autocommand
def __init__(self):
super(UpdateRepo, self).__init__()
name = ("update-repo", "ur")
def run(self):
if not self.args:
self.help()
return
self.init(True)
for repo in self.args:
pisi.api.update_repo(repo)
self.finalize()
class AddRepo(Command):
"""Add a repository
Usage: add-repo <repo> <indexuri>
<repo>: name of repository to add
<indexuri>: URI of index file
NB: We support only local files (e.g., /a/b/c) and http:// URIs at the moment
"""
__metaclass__ = autocommand
def __init__(self):
super(AddRepo, self).__init__()
name = ("add-repo", "ar")
def run(self):
if len(self.args)>=2:
self.init()
name = self.args[0]
indexuri = self.args[1]
pisi.api.add_repo(name, indexuri)
self.init()
else:
self.help()
return
class RemoveRepo(Command):
"""Remove repositories
Usage: remove-repo <repo1> <repo2> ... <repon>
Remove all repository information from the system.
"""
__metaclass__ = autocommand
def __init__(self):
super(RemoveRepo, self).__init__()
name = ("remove-repo", "rr")
def run(self):
if len(self.args)>=1:
self.init()
for repo in self.args:
pisi.api.remove_repo(repo)
self.finalize()
else:
self.help()
return
class ListRepo(Command):
"""List repositories
Usage: list-repo
Lists currently tracked repositories.
"""
__metaclass__ = autocommand
def __init__(self):
super(ListRepo, self).__init__()
name = ("list-repo", "lr")
def run(self):
self.init()
for repo in ctx.repodb.list():
print repo
print ' ', ctx.repodb.get_repo(repo).indexuri.get_uri()
self.finalize()
class ListAvailable(Command):
"""List available packages in the repositories
Usage: list-available [ <repo1> <repo2> ... repon ]
Gives a brief list of PiSi components published in the repository.
"""
__metaclass__ = autocommand
def __init__(self):
super(ListAvailable, self).__init__()
name = ("list-available", "la")
def run(self):
self.init(True)
if self.args:
for arg in self.args:
self.print_packages(arg)
else:
# print for all repos
for repo in ctx.repodb.list():
ctx.ui.info("Repository : %s\n" % repo)
self.print_packages(repo)
self.finalize()
def print_packages(self, repo):
from pisi import packagedb
from colors import colorize
pkg_db = packagedb.get_db(repo)
list = pkg_db.list_packages()
installed_list = ctx.installdb.list_installed()
list.sort()
for p in list:
if p in installed_list:
print colorize(p, "cyan")
else:
print p
class ListUpgrades(Command):
"""List packages to be upgraded
Usage: list-upgrades [ <repo1> <repo2> ... repon ]
"""
__metaclass__ = autocommand
def __init__(self):
super(ListUpgrades, self).__init__()
name = ("list-upgrades", "lu")
def options(self):
self.parser.add_option("-l", "--long", action="store_true",
default=False, help="show in long format")
self.parser.add_option("-i", "--install-info", action="store_true",
default=False, help="show detailed install info")
buildno_opts(self)
def run(self):
self.init(True)
list = pisi.api.list_upgradable()
list.sort()
if self.options.install_info:
print 'Package Name |St| Version| Rel.| Build| Distro| Date'
print '========================================================================'
for pkg in list:
package = pisi.packagedb.inst_packagedb.get_package(pkg)
inst_info = ctx.installdb.get_info(pkg)
if self.options.long:
print package
print inst_info
elif self.options.install_info:
print '%-15s | %s ' % (package.name, inst_info.one_liner())
else:
print '%15s - %s ' % (package.name, package.summary)
self.finalize()
class ListPending(Command):
"""List pending packages"""
__metaclass__ = autocommand
def __init__(self):
super(ListPending, self).__init__()
name = ("list-pending", "lp")
def run(self):
self.init(True)
list = ctx.installdb.list_pending()
list.sort()
for p in list:
print p
self.finalize()
class SearchAvailable(Command):
"""Search in available packages
Usage: search-available <search pattern>
FIXME: this is bogus
"""
pass
# Partial build commands
class BuildUntil(Build):
"""Run the build process partially
Usage: -sStateName build-until <pspec file>
where states are:
unpack, setupaction, buildaction, installaction, buildpackages
You can give an URI of the pspec.xml file. PISI will fetch all
necessary files and unpack the source and prepare a source directory
for you.
"""
__metaclass__ = autocommand
def __init__(self):
super(BuildUntil, self).__init__()
name = ("build-until", "bu")
def options(self):
super(BuildUntil, self).options()
self.parser.add_option("-s", action="store", dest="state")
def run(self):
if not self.args:
self.help()
return
self.init()
state = self.options.state
for arg in self.args:
pisi.api.build_until(arg, state, self.authInfo)
self.finalize()
class BuildUnpack(Build):
"""Unpack the source archive
Usage: build-unpack <pspec file>
TODO: desc.
"""
__metaclass__ = autocommand
def __init__(self):
super(BuildUnpack, self).__init__()
name = ("build-unpack", "biu")
def run(self):
if not self.args:
self.help()
return
self.init()
for arg in self.args:
pisi.api.build_until(arg, "unpack", self.authInfo)
self.finalize()
class BuildSetup(Build):
"""Setup the source
Usage: build-setup <pspec file>
TODO: desc.
"""
__metaclass__ = autocommand
def __init__(self):
super(BuildSetup, self).__init__()
name = ("build-setup", "bis")
def run(self):
if not self.args:
self.help()
return
self.init()
for arg in self.args:
pisi.api.build_until(arg, "setupaction",
self.authInfo)
self.finalize()
class BuildBuild(Command):
"""Setup the source
Usage: build-build <pspec file>
TODO: desc.
"""
__metaclass__ = autocommand
def __init__(self):
super(BuildBuild, self).__init__()
name = ("build-build", "bib")
def run(self):
if not self.args:
self.help()
return
self.init()
for arg in self.args:
pisi.api.build_until(arg, "buildaction", self.authInfo)
self.finalize()
class BuildInstall(Build):
"""Install to the sandbox
Usage: build-install <pspec file>
TODO: desc.
"""
__metaclass__ = autocommand
def __init__(self):
super(BuildInstall, self).__init__()
name = ("build-install", "bii")
def run(self):
if not self.args:
self.help()
return
self.init()
for arg in self.args:
pisi.api.build_until(arg, "installaction",
self.authInfo)
self.finalize()
class BuildPackage(Build):
"""Setup the source
Usage: build-build <pspec file>
TODO: desc.
"""
__metaclass__ = autocommand
def __init__(self):
super(BuildPackage, self).__init__()
name = ("build-package", "bip")
def run(self):
if not self.args:
self.help()
return
self.init()
for arg in self.args:
pisi.api.build_until(arg, "buildpackages", self.authInfo)
self.finalize()
usage_text1 = """%prog [options] <command> [arguments]
where <command> is one of:
"""
usage_text2 = """
Use \"%prog help <command>\" for help on a specific command.
"""
usage_text = (usage_text1 + Command.commands_string() + usage_text2)
-96
View File
@@ -1,96 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import sys
from optparse import OptionParser
import pisi
from pisi.uri import URI
from pisi.cli.commands import *
class ParserError(Exception):
pass
class PreParser(OptionParser):
"""consumes any options, and finds arguments from command line"""
def __init__(self, version):
OptionParser.__init__(self, usage=usage_text, version=version)
def error(self, msg):
raise ParserError, msg
def parse_args(self, args=None):
self.rargs = self._get_args(args)
self._process_args()
return self.args
def _process_args(self):
args = []
rargs = self.rargs
if not self.allow_interspersed_args:
first_arg = False
while rargs:
arg = rargs[0]
def option():
if not self.allow_interspersed_args and first_arg:
self.error('Options must precede non-option arguments')
del rargs[0]
return
# We handle bare "--" explicitly, and bare "-" is handled by the
# standard arg handler since the short arg case ensures that the
# len of the opt string is greater than 1.
if arg == "--":
del rargs[0]
break
elif arg[0:2] == "--":
# process a single long option (possibly with value(s))
option()
elif arg[:1] == "-" and len(arg) > 1:
# process a cluster of short options (possibly with
# value(s) for the last one only)
option()
else: # then it must be an argument
args.append(arg)
del rargs[0]
self.args = args
class PisiCLI(object):
def __init__(self):
# first construct a parser for common options
# this is really dummy
self.parser = PreParser(version="%prog " + pisi.__version__)
try:
args = self.parser.parse_args()
if len(args)==0: # more explicit than using IndexError
print 'No command given'
self.die()
cmd_name = args[0]
except ParserError:
print 'Command line parsing error'
self.die()
self.command = Command.get_command(cmd_name)
if not self.command:
print "Unrecognized command: ", cmd
self.die()
def die(self):
self.parser.print_help()
sys.exit(1)
def run_command(self):
self.command.run()
-61
View File
@@ -1,61 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# PISI Configuration module is used for gathering and providing
# regular PISI configurations.
# Authors: Baris Metin <baris@uludag.org.tr
# Eray Ozkural <eray@uludag.org.tr>
import pisi
import pisi.context as ctx
from pisi.configfile import ConfigurationFile
class Config(object):
"""Config Singleton"""
def __init__(self, options = None):
self.options = options
self.values = ConfigurationFile("/etc/pisi/pisi.conf")
self.destdir = self.values.general.destinationdirectory
# directory accessor functions
# here is how it goes
# x_dir: system wide directory for storing info type x
# pkg_x_dir: per package directory for storing info type x
def lib_dir(self):
return self.destdir + self.values.dirs.lib_dir
def db_dir(self):
return self.destdir + self.values.dirs.db_dir
def archives_dir(self):
return self.destdir + self.values.dirs.archives_dir
def packages_dir(self):
return self.destdir + self.values.dirs.packages_dir
def index_dir(self):
return self.destdir + self.values.dirs.index_dir
def tmp_dir(self):
return self.destdir + self.values.dirs.tmp_dir
# bu dizini neden kullanıyoruz? Yalnızca index.py içerisinde
# kullanılıyor ama /var/tmp/pisi/install gibi bir dizine niye
# ihtiyacımız var? (baris)
def install_dir(self):
return self.tmp_dir() + ctx.const.install_dir_suffix
#TODO: remove this
config = Config()
-132
View File
@@ -1,132 +0,0 @@
# -*- conding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# PISI Configuration File module, obviously, is used to read from the
# configuration file. Module also defines default values for
# configuration parameters.
#
# Configuration file is located in /etc/pisi/pisi.conf by default,
# having an INI like format like below.
#
#[general]
#destinationdirectory = /tmp
#
#[build]
#host = i686-pc-linux-gnu
#CFLAGS= -mcpu=i686 -O2 -pipe -fomit-frame-pointer
#CXXFLAGS= -mcpu=i686 -O2 -pipe -fomit-frame-pointer
#LDFLAGS=
#
#[directories]
#lib_dir = /var/lib/pisi
#db_dir = /var/db/pisi
#archives_dir = /var/cache/pisi/archives
#packages_dir = /var/cache/pisi/packages
#index_dir = /var/cache/pisi/index
#tmp_dir = /var/tmp/pisi
#icon_theme_dir = /usr/share/icons/Tulliana-1.0
import os
from ConfigParser import ConfigParser, NoSectionError
class ConfigException(Exception):
pass
class GeneralDefaults:
"""Default values for [general] section"""
destinationdirectory = os.getcwd() + "/tmp" # FOR ALPHA
distribution = "Pardus"
distribution_release = "0.1"
class BuildDefaults:
"""Default values for [build] section"""
host = "i686-pc-linux-gnu"
CFLAGS = "-mcpu=i686 -O2 -pipe -fomit-frame-pointer"
CXXFLAGS = "-mcpu=i686 -O2 -pipe -fomit-frame-pointer"
LDFLAGS = ""
class DirsDefaults:
"Default values for [directories] section"
lib_dir = "/var/lib/pisi"
db_dir = "/var/db/pisi"
archives_dir = "/var/cache/pisi/archives"
packages_dir = "/var/cache/pisi/packages"
index_dir = "/var/cache/pisi/index"
tmp_dir = "/var/tmp/pisi"
icon_theme_dir = "/usr/share/icons/Tulliana-1.0"
class ConfigurationSection(object):
"""ConfigurationSection class defines a section in the configuration
file, using defaults (above) as a fallback."""
def __init__(self, section, items=[]):
self.items = items
if section == "general":
self.defaults = GeneralDefaults
elif section == "build":
self.defaults = BuildDefaults
elif section == "directories":
self.defaults = DirsDefaults
else:
e = "No section by name '%s'" % section
raise ConfigException, e
self.section = section
def __getattr__(self, attr):
# first search for attribute in the items provided in the
# configuration file.
if self.items:
for item in self.items:
if item[0] == attr:
return item[1]
# then fall back to defaults
if hasattr(self.defaults, attr):
return getattr(self.defaults, attr)
return ""
# We'll need to access configuration keys by their names as a
# string. Like; ["default"]...
def __getitem__(self, key):
return self.__getattr__(key)
class ConfigurationFile(object):
"""Parse and get configuration values from the configuration file"""
def __init__(self, filePath):
parser = ConfigParser()
self.filePath = filePath
parser.read(self.filePath)
try:
generalitems = parser.items("general")
except NoSectionError:
generalitems = []
self.general = ConfigurationSection("general", generalitems)
try:
builditems = parser.items("build")
except NoSectionError:
builditems = []
self.build = ConfigurationSection("build", builditems)
try:
dirsitems = parser.items("directories")
except NoSectionError:
dirsitems = []
self.dirs = ConfigurationSection("directories", dirsitems)
-90
View File
@@ -1,90 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# PISI constants.
# If you have a "magic" constant value this is where it should be
# defined.
# Author: Baris Metin <baris@uludag.org.tr
import pisi
class _constant:
"Constant members implementation"
class ConstError(TypeError):
pass
def __setattr__(self, name, value):
if self.__dict__.has_key(name):
raise self.ConstError, "Can't rebind constant: %s" % name
# Binding an attribute once to a const is available
self.__dict__[name] = value
def __delattr__(self, name):
if self.__dict__.has_key(name):
raise self.ConstError, "Can't unbind constant: %s" % name
# we don't have an attribute by this name
raise NameError, name
class Constants:
"Pisi Constants Singleton"
__c = _constant()
def __init__(self):
# prefix for package names
self.__c.package_prefix = ".pisi"
# directory suffixes for build
self.__c.work_dir_suffix = "/work"
self.__c.install_dir_suffix = "/install"
# directory suffixes for intall. We'll use these directories
# for storing files related to the packages. Each package will
# have its own directory under lib_dir with has these
# sub-directories.
self.__c.comar_dir_suffix = "/comar"
self.__c.files_dir_suffix = "/files"
self.__c.metadata_dir_suffix = "/metadata"
# file/directory names
self.__c.actions_file = "actions.py"
self.__c.files_dir = "files"
self.__c.comar_dir = "comar"
self.__c.files_xml = "files.xml"
self.__c.metadata_xml = "metadata.xml"
self.__c.pisi_index = "pisi-index.xml"
# functions in actions_file
self.__c.setup_func = "setup"
self.__c.build_func = "build"
self.__c.install_func = "install"
# file types
self.__c.doc = "doc"
self.__c.man = "man"
self.__c.info = "info"
self.__c.conf = "config"
self.__c.header = "header"
self.__c.library = "library"
self.__c.executable = "executable"
self.__c.data = "data"
self.__c.localedata = "localedata"
def __getattr__(self, attr):
return getattr(self.__c, attr)
def __setattr__(self, attr, value):
setattr(self.__c, attr, value)
def __delattr__(self, attr):
delattr(self.__c, attr)
-36
View File
@@ -1,36 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Context module.
# Authors: Baris Metin <baris@uludag.org.tr
# Eray Ozkural <eray@uludag.org.tr>
# global variables here
import pisi.constants
const = pisi.constants.Constants()
config = None
# default UI is CLI
ui = None # not now
installdb = None
repodb = None
comard = None
#def register(_impl):
# """ Register a UI implementation"""
# ui = _impl
-134
View File
@@ -1,134 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# dependency analyzer
# Author: Eray Ozkural <eray@uludag.org.tr>
#import pisi.db as db
import pisi.context as ctx
import pisi.packagedb as packagedb
from pisi.version import Version
from pisi.xmlext import *
from pisi.xmlfile import XmlFile
from pisi.util import Checks
class DepInfo:
def __init__(self, node = None):
if node:
self.package = getNodeText(node).strip()
self.versionFrom = getNodeAttribute(node, "versionFrom")
self.versionTo = getNodeAttribute(node, "versionTo")
self.releaseFrom = getNodeAttribute(node, "releaseFrom")
self.releaseTo = getNodeAttribute(node, "releaseTo")
else:
self.versionFrom = self.versionTo = None
self.releaseFrom = self.releaseFrom = None
def elt(self, xml):
node = xml.newNode("Dependency")
xml.addText(node, self.package)
if self.versionFrom:
node.setAttribute("versionFrom", self.versionFrom)
if self.versionTo:
node.setAttribute("versionTo", self.versionTo)
if self.releaseFrom:
node.setAttribute("releaseFrom", self.versionFrom)
if self.releaseTo:
node.setAttribute("releaseTo", self.versionTo)
return node
def has_errors(self):
if not self.package:
return [ "Dependency should have a package string" ]
return None
def satisfies(self, pkg_name, version, release):
"""determine if a package ver. satisfies given dependency spec"""
ret = True
from version import Version
if self.versionFrom:
ret &= Version(version) >= Version(self.versionFrom)
if self.versionTo:
ret &= Version(version) <= Version(self.versionTo)
if self.releaseFrom:
ret &= Version(release) <= Version(self.releaseFrom)
if self.releaseTo:
ret &= Version(release) <= Version(self.releaseTo)
return ret
def __str__(self):
s = self.package
if self.versionFrom:
s += 'ver >= ' + self.versionFrom
if self.versionTo:
s += 'ver <= ' + self.versionTo
if self.releaseFrom:
s += 'rel >= ' + self.releaseFrom
if self.releaseTo:
s += 'rel <= ' + self.releaseTo
return s
def dict_satisfies_dep(dict, depinfo):
"""determine if a package in a dictionary satisfies given dependency spec"""
pkg_name = depinfo.package
if not dict.has_key(pkg_name):
return False
else:
pkg = dict[pkg_name]
(version, release) = (pkg.version, pkg.release)
return depinfo.satisfies(pkg_name, version, release)
def installed_satisfies_dep(depinfo):
"""determine if a package in *repository* satisfies given
dependency spec"""
pkg_name = depinfo.package
if not ctx.installdb.is_installed(pkg_name):
return False
else:
pkg = packagedb.inst_packagedb.get_package(pkg_name)
(version, release) = (pkg.version, pkg.release)
return depinfo.satisfies(pkg_name, version, release)
def repo_satisfies_dep(depinfo):
"""determine if a package in *repository* satisfies given
dependency spec"""
pkg_name = depinfo.package
if not packagedb.has_package(pkg_name):
return False
else:
pkg = packagedb.get_package(pkg_name)
(version, release) = (pkg.version, pkg.release)
return depinfo.satisfies(pkg_name, version, release)
def satisfies_dependencies(pkg, deps, sat = installed_satisfies_dep):
for dep in deps:
if not sat(dep):
ctx.ui.error('Package %s does not satisfy dependency %s' %
(pkg,dep))
return False
return True
def satisfies_runtime_deps(pkg):
deps = packagedb.get_package(pkg).runtimeDeps
return satisfies_dependencies(pkg, deps)
def installable(pkg):
"""calculate if pkg is installable currently
which means it has to satisfy both install and runtime dependencies"""
if not packagedb.has_package(pkg):
ctx.ui.info("Package " + pkg + " is not present in the package database");
return False
elif satisfies_runtime_deps(pkg):
return True
else:
#ctx.ui.info("package " + pkg + " does not satisfy dependencies\n");
return False
-154
View File
@@ -1,154 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Yet another Pisi module for fetching files from various sources. Of
# course, this is not limited to just fetching source files. We fetch
# all kinds of things: source tarballs, index files, packages, and God
# knows what.
# python standard library modules
import urllib2
import os
from base64 import encodestring
# pisi modules
import pisi
import pisi.util as util
import pisi.context as ctx
from pisi.uri import URI
class FetchError(pisi.Error):
pass
# helper functions
def fetch_url(url, dest, progress=None):
fetch = Fetcher(url, dest)
fetch.progress = progress
fetch.fetch()
if progress:
pass
#ctx.ui.info('\n')
class Fetcher:
"""Fetcher can fetch a file from various sources using various
protocols."""
def __init__(self, url, dest):
if not isinstance(url, URI):
url = URI(url)
self.url = url
self.filedest = dest
util.check_dir(self.filedest)
self.percent = 0
self.rate = 0.0
self.progress = None
def fetch (self):
"""Return value: Fetched file's full path.."""
if not self.url.filename():
self.err("filename error")
if not os.access(self.filedest, os.W_OK):
self.err("no perm to write to dest dir")
if self.url.is_local_file():
self.fetchLocalFile()
else:
self.fetchRemoteFile()
return os.path.join(self.filedest, self.url.filename())
def _do_grab(self, fileURI, dest, totalsize):
symbols = [' B/s', 'KB/s', 'MB/s', 'GB/s']
from time import time
tt, oldsize = int(time()), 0
bs, size = 1024, 0
symbol, depth = "B/s", 0
st = time()
chunk = fileURI.read(bs)
size = size + len(chunk)
if self.progress:
p = self.progress(totalsize)
self.percent = p.update(size)
while chunk:
dest.write(chunk)
chunk = fileURI.read(bs)
size = size + len(chunk)
ct = time()
if int(tt) != int(ct):
self.rate = size / (ct - st)
while self.rate > 1000 and depth < 3:
self.rate /= 1024
depth += 1
symbol, depth = symbols[depth], 0
oldsize, tt = size, time()
if self.progress:
if p.update(size):
self.percent = p.percent
retval = {'filename': self.url.filename(),
'percent' : self.percent,
'rate': self.rate,
'symbol': symbol}
ctx.ui.display_progress(retval)
dest.close()
def fetchLocalFile (self):
url = self.url
if not os.access(url.path(), os.F_OK):
self.err("no such file or no perm to read")
dest = open(os.path.join(self.filedest, url.filename()) , "w")
totalsize = os.path.getsize(url.path())
fileObj = open(url.path())
self._do_grab(fileObj, dest, totalsize)
def fetchRemoteFile (self):
from httplib import HTTPException
try:
fileObj = urllib2.urlopen(self.formatRequest\
(urllib2.Request(self.url.uri)))
headers = fileObj.info()
except ValueError, e:
self.err('%s' % (e, ))
except IOError, e:
self.err('%s' % (e, ))
except OSError, e:
self.err('%s' % (e, ))
except HTTPException, e:
self.err(('(%s): %s') % (e.__class__.__name__, e))
try:
totalsize = int(headers['Content-Length'])
except:
totalsize = 0
dest = open(os.path.join(self.filedest, self.url.filename()) , "w")
self._do_grab(fileObj, dest, totalsize)
def formatRequest(self, request):
authinfo = self.url.auth_info()
if authinfo:
enc = encodestring("%s:%s" % authinfo)
request.add_header('Authorization', 'Basic %s' % enc)
return request
def err (self, error):
raise FetchError(error)
-97
View File
@@ -1,97 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Files module provides access to files.xml. files.xml is genarated
# during the build process of a package and used in installation.
# Authors: Eray Ozkural <eray@uludag.org.tr>
from pisi.xmlext import *
from pisi.xmlfile import XmlFile
from pisi.util import Checks
class FileInfo:
"""FileInfo holds the information for a File node/tag in files.xml"""
def __init__(self, _path = "", _type = "", _size = "", _hash = ""):
self.path = _path
self.type = _type
self.size = _size
self.hash = _hash
def readnew(node):
f = FileInfo()
f.read(node)
return f
readnew = staticmethod(readnew)
def read(self, node):
self.path = getNodeText(getNode(node, "Path"))
self.type = getNodeText(getNode(node, "Type"))
self.size = getNodeText(getNode(node, "Size"))
self.hash = getNodeText(getNode(node, "SHA1Sum"))
def elt(self, dom):
## FIXME: looking for a better way to do it
## could apparently use helper functions to do this shorter
elt = dom.createElement("File")
pathElt = dom.createElement("Path")
pathElt.appendChild(dom.createTextNode(self.path))
typeElt = dom.createElement("Type")
typeElt.appendChild(dom.createTextNode(self.type))
sizeElt = dom.createElement("Size")
sizeElt.appendChild(dom.createTextNode(self.size))
hashElt = dom.createElement("SHA1Sum")
hashElt.appendChild(dom.createTextNode(self.hash))
elt.appendChild(pathElt)
elt.appendChild(typeElt)
elt.appendChild(sizeElt)
elt.appendChild(hashElt)
return elt
def has_errors(self):
err = Checks()
err.has_tag(self.path, "File", "Path")
err.has_tag(self.type, "File", "Type")
err.has_tag(self.size, "File", "Size")
err.has_tag(self.hash, "File", "SHA1Sum")
return err.list
def __str__(self):
s = "%s, type: %s, size: %s, sha1sum: %s" % (self.path, self.type,
self.size, self.hash)
return s
class Files(XmlFile):
def __init__(self):
XmlFile.__init__(self, "Files")
self.list = []
def append(self, fileinfo):
self.list.append(fileinfo)
def read(self, filename):
self.readxml(filename)
fileElts = self.getAllNodes("File")
self.list = [FileInfo.readnew(x) for x in fileElts]
def write(self, filename):
self.newDOM()
document = self.dom.documentElement
for x in self.list:
document.appendChild(x.elt(self.dom))
self.writexml(filename)
def has_errors(self):
err = Checks()
for finfo in self.list:
err.join(finfo.has_errors())
return err.list
-159
View File
@@ -1,159 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# the most simple minded digraph class ever
# for python 2.3 compatibility
import sys
ver = sys.version_info
if ver[0] <= 2 and ver[1] < 4:
from sets import Set as set
import pisi
# not an error!
class CycleException(pisi.Exception):
pass
class Digraph(object):
def __init__(self):
self.__v = set()
self.__adj = {}
self.__vdata = {}
self.__edata = {}
def vertices(self):
"return set of vertex descriptors"
return self.__v
def edges(self):
"return a list of edge descriptors"
list = []
for u in self.__v:
for v in self.__u:
list.append( (u,v) )
return list
def from_list(self, el):
"convert a list of edges (u,v) to graph"
for (u,v) in el:
self.add_edge(u,v)
def add_vertex(self, u, data = None):
"add vertex u, optionally with data"
assert not u in self.__v
self.__v.add(u)
self.__adj[u] = set()
if data:
self.__vdata[u] = data
self.__edata[u] = {}
def add_edge(self, u, v, edata = None, udata = None, vdata = None):
"add edge u -> v"
if not u in self.__v:
self.add_vertex(u, udata)
if not v in self.__v:
self.add_vertex(v, vdata)
self.__adj[u].add(v)
if edata != None:
self.__edata[u][v] = edata
def add_biedge(self, u, v, edata = None):
self.add_edge(u, v, edata)
self.add_edge(v, u, edata)
def set_vertex_data(self, u, data):
self.__vdata[u] = data
def vertex_data(self, u):
return self.__vdata[u]
def edge_data(self, u, v):
return self.__edata[u][v]
def has_vertex(self, u):
return u in self.__v
def has_edge(self, u,v):
if u in self.__v:
return v in self.__adj[u]
else:
return False
def adj(self, u):
return self.__adj[u]
def dfs(self, finish_hook = None):
self.color = {}
self.p = {}
self.d = {}
self.f = {}
for u in self.__v:
self.color[u] = 'w' # mark white (unexplored)
self.p[u] = None
self.time = 0
for u in self.__v:
if self.color[u] == 'w':
self.dfs_visit(u, finish_hook)
def dfs_visit(self, u, finish_hook):
self.color[u] = 'g' # mark green (discovered)
self.d[u] = self.time = self.time + 1
for v in self.adj(u):
if self.color[v] == 'w': # explore unexplored vertices
self.p[v] = u
self.dfs_visit(v, finish_hook)
elif self.color[v] == 'g': # cycle detected
raise CycleException
self.color[u] = 'b' # mark black (completed)
if finish_hook:
finish_hook(u)
self.f[u] = self.time = self.time + 1
def cycle_free(self):
try:
self.dfs()
return True
except CycleException:
return False
def topological_sort(self):
list = []
self.dfs(lambda u: list.append(u))
list.reverse()
return list
def id_str(self, u):
s = str(u)
return s.replace('-', '_')
def write_graphviz(self, f):
f.write('digraph G {\n')
for u in self.vertices():
f.write(self.id_str(u))
self.write_graphviz_vlabel(f, u)
f.write(';\n')
f.write('\n')
for u in self.vertices():
for v in self.adj(u):
f.write( self.id_str(u) + ' -> ' + self.id_str(v))
self.write_graphviz_elabel(f, u, v)
f.write(';\n')
f.write('\n')
f.write('}\n')
def write_graphviz_vlabel(self, f, u):
pass
def write_graphviz_elabel(self, f, u, v):
pass
-98
View File
@@ -1,98 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# PISI source/package index
# Author: Eray Ozkural <eray@uludag.org.tr>
import os
import pisi.context as ctx
import pisi.metadata as metadata
import pisi.packagedb as packagedb
import pisi.util as util
from pisi.package import Package
from pisi.xmlfile import XmlFile
from pisi.uri import URI
class Index(XmlFile):
def __init__(self):
XmlFile.__init__(self,"PISI")
self.sources = []
self.packages = []
def read(self, filename, repo = None):
"""Read PSPEC file"""
self.filepath = filename
url = URI(filename)
if url.is_remote_file():
from fetcher import fetch_url
dest = os.path.join(ctx.config.index_dir(), repo)
if not os.path.exists(dest):
os.makedirs(dest)
fetch_url(url, dest, ctx.ui.Progress)
self.filepath = os.path.join(dest, url.filename())
self.readxml(self.filepath)
# find all binary packages
packageElts = self.getAllNodes("Package")
self.packages = [metadata.PackageInfo(p) for p in packageElts]
self.unlink()
def write(self, filename):
"""Write index file"""
self.newDOM()
for pkg in self.packages:
self.addChild(pkg.elt(self))
self.writexml(filename)
self.unlink()
def index(self, repo_uri):
self.repo_dir = repo_uri
for root, dirs, files in os.walk(repo_uri):
for fn in files:
if fn.endswith(ctx.const.package_prefix):
ctx.ui.info('Adding ' + fn + ' to package index')
self.add_package(os.path.join(root, fn), repo_uri)
def update_db(self, repo):
pkgdb = packagedb.get_db(repo)
pkgdb.clear()
for pkg in self.packages:
pkgdb.add_package(pkg)
def add_package(self, path, repo_uri):
package = Package(path, 'r')
# extract control files
util.clean_dir(ctx.config.install_dir())
package.extract_PISI_files(ctx.config.install_dir())
md = metadata.MetaData()
md.read(os.path.join(ctx.config.install_dir(), ctx.const.metadata_xml))
if ctx.config.options and ctx.config.options.absolute_uris:
md.package.packageURI = os.path.realpath(path)
else: # create relative path by default
# TODO: in the future we'll do all of this with purl/pfile/&helpers
# After that, we'll remove the ugly repo_uri parameter from this
# function.
md.package.packageURI = util.removepathprefix(repo_uri, path)
# check package semantics
if md.has_errors():
ctx.ui.error('Package ' + md.package.name + ': metadata corrupt')
else:
self.packages.append(md.package)
-182
View File
@@ -1,182 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Package install operation
# Author: Eray Ozkural <eray@uludag.org.tr>
import os
import pisi
import pisi.context as ctx
import pisi.packagedb as packagedb
import pisi.dependency as dependency
import pisi.operations as operations
from pisi.specfile import *
from pisi.package import Package
from pisi.metadata import MetaData
#import conflicts
class InstallError(pisi.Error):
pass
class Installer:
"Installer class, provides install routines for pisi packages"
def __init__(self, package_fname):
"initialize from a file name"
self.package = Package(package_fname)
self.package.read()
self.metadata = self.package.metadata
self.files = self.package.files
self.pkginfo = self.metadata.package
def install(self, ask_reinstall = True):
"entry point"
ctx.ui.info('Installing %s, version %s, release %s, build %s' %
(self.pkginfo.name, self.pkginfo.version,
self.pkginfo.release, self.pkginfo.build))
self.ask_reinstall = ask_reinstall
self.check_requirements()
self.check_relations()
self.reinstall()
self.extract_install()
self.store_pisi_files()
self.register_comar_scripts()
self.update_databases()
def check_requirements(self):
"""check system requirements"""
#TODO: IS THERE ENOUGH SPACE?
# what to do if / is split into /usr, /var, etc.
pass
def check_relations(self):
# check if package is in database
# If it is not, put it into 3rd party packagedb
if not packagedb.has_package(self.pkginfo.name):
db = packagedb.thirdparty_packagedb
db.add_package(self.pkginfo)
# check conflicts
for pkg in self.metadata.package.conflicts:
if ctx.installdb.is_installed(self.pkginfo):
raise InstallError("Package conflicts " + pkg)
# check dependencies
if not dependency.installable(self.pkginfo.name):
ctx.ui.error('Dependencies for ' + self.pkginfo.name +
' not satisfied')
raise InstallError("Package not installable")
def reinstall(self):
"check reinstall, confirm action, and remove package if reinstall"
pkg = self.pkginfo
if ctx.installdb.is_installed(pkg.name): # is this a reinstallation?
(iversion, irelease, ibuild) = ctx.installdb.get_version(pkg.name)
# determine if same version
same_ver = False
ignore_build = ctx.config.options and ctx.config.options.ignore_build_no
if (not ibuild) or (not pkg.build) or ignore_build:
# we don't look at builds to compare two package versions
if pkg.version == iversion and pkg.release == irelease:
same_ver = True
else:
if pkg.build == ibuild:
same_ver = True
if same_ver:
if self.ask_reinstall:
if not ctx.ui.confirm('Re-install same version package?'):
raise InstallError('Package re-install declined')
else:
upgrade = False
# is this an upgrade?
# determine and report the kind of upgrade: version, release, build
if pkg.version > iversion:
ctx.ui.info('Upgrading to new upstream version')
upgrade = True
elif pkg.release > irelease:
ctx.ui.info('Upgrading to new distribution release')
upgrade = True
elif ((not ignore_build) and ibuild and pkg.build
and pkg.build > ibuild):
ctx.ui.info('Upgrading to new distribution build')
upgrade = True
# is this a downgrade? confirm this action.
if self.ask_reinstall and (not upgrade):
if pkg.version < iversion:
x = 'Downgrade to old upstream version?'
elif pkg.release < irelease:
x = 'Downgrade to old distribution release?'
else:
x = 'Downgrade to old distribution build?'
if not ctx.ui.confirm(x):
raise InstallError('Package downgrade declined')
# remove old package then
operations.remove_single(pkg.name)
def extract_install(self):
"unzip package in place"
ctx.ui.info('Extracting files,')
self.package.extract_dir_flat('install', ctx.config.destdir)
def store_pisi_files(self):
"""put files.xml, metadata.xml, actions.py and COMAR scripts
somewhere in the file system. We'll need these in future..."""
ctx.ui.info('Storing %s, ' % ctx.const.files_xml)
self.package.extract_file(ctx.const.files_xml, self.package.pkg_dir())
ctx.ui.info('%s.' % ctx.const.metadata_xml)
self.package.extract_file(ctx.const.metadata_xml, self.package.pkg_dir())
for pcomar in self.metadata.package.providesComar:
fpath = os.path.join(ctx.const.comar_dir, pcomar.script)
# comar prefix is added to the pkg_dir while extracting comar
# script file. so we'll use pkg_dir as destination.
ctx.ui.info('Storing %s' % fpath)
self.package.extract_file(fpath, self.package.pkg_dir())
def register_comar_scripts(self):
"register COMAR scripts"
for pcomar in self.metadata.package.providesComar:
scriptPath = os.path.join(self.package.comar_dir(),pcomar.script)
ctx.ui.info("Registering COMAR script %s" % pcomar.script)
# FIXME: We must check the result of the command (possibly
# with id?)
if comard:
comard.register(pcomar.om,
self.metadata.package.name,
scriptPath)
def update_databases(self):
"update databases"
# installdb
ctx.installdb.install(self.metadata.package.name,
self.metadata.package.version,
self.metadata.package.release,
self.metadata.package.build,
self.metadata.package.distribution)
# installed packages
packagedb.inst_packagedb.add_package(self.pkginfo)
-165
View File
@@ -1,165 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
#
# installation database
#
# Author: Eray Ozkural <eray@uludag.org.tr>
# System
import os
import fcntl
# PiSi
import pisi
import pisi.context as ctx
import pisi.lockeddbshelve as shelve
from pisi.files import Files
import pisi.util as util
class InstallDBError(pisi.Error):
pass
class InstallInfo:
# some data is replicated from packagedb.inst_packagedb
# we store as an object, hey, we can waste O(1) space.
# this is also easier to modify in the future, without
# requiring database upgrades! wow!
def __init__(self, state, version, release, build, distribution):
self.state = state
self.version = version
self.release = release
self.build = build
self.distribution = distribution
import time
self.time = time.localtime()
def one_liner(self):
import time
time_str = time.strftime("%d %b %Y %H:%M", self.time)
s = '%2s|%10s|%6s|%6s|%8s|%12s' % (self.state, self.version, self.release,
self.build, self.distribution,
time_str)
return s
state_map = { 'i': 'installed', 'ip':'installed-pending', 'r:removed'
'p': 'purged' }
def __str__(self):
s = "State: %s\nVersion: %s, Release: %s, Build: %s\n" % \
(InstallInfo.state_map[self.state], self.version,
self.release, self.build)
import time
time_str = time.strftime("%d %b %Y %H:%M", self.time)
s += 'Distribution: %s, Install Time: %s\n' % (self.distribution,
time_str)
return s
class InstallDB:
def __init__(self):
from os.path import join
self.d = shelve.LockedDBShelf('install')
self.dp = shelve.LockedDBShelf('configpending')
self.files_dir = os.path.join(ctx.config.db_dir(), 'files')
def files_name(self, pkg, version, release):
from os.path import join
pkg_dir = join(ctx.config.lib_dir(), pkg + '-' + version + '-' + release)
return join(pkg_dir, ctx.const.files_xml)
def files(self, pkg):
pkg = str(pkg)
pkginfo = self.d[pkg]
files = Files()
files.read(self.files_name(pkg,pkginfo.version,pkginfo.release))
return files
def is_recorded(self, pkg):
pkg = str(pkg)
return self.d.has_key(pkg)
def is_installed(self, pkg):
pkg = str(pkg)
if self.is_recorded(pkg):
info = self.d[pkg]
return info.state=='i' or info.state=='ip'
else:
return False
def list_installed(self):
list = []
for (pkg, info) in self.d.iteritems():
if info.state=='i' or info.state=='ip':
list.append(pkg)
return list
def list_pending(self):
list = []
for (pkg, x) in self.dp.iteritems():
list.append(pkg)
return list
def get_info(self, pkg):
pkg = str(pkg)
return self.d[pkg]
def get_version(self, pkg):
pkg = str(pkg)
info = self.d[pkg]
return (info.version, info.release, info.build)
def is_removed(self, pkg):
pkg = str(pkg)
if self.is_recorded(pkg):
info = self.d[pkg]
return info.state=='r'
else:
return False
def install(self, pkg, version, release, build, distro = ""):
"""install package with specific version, release, build"""
pkg = str(pkg)
if self.is_installed(pkg):
raise InstallDBError("already installed")
if ctx.config.options and ctx.config.options.ignore_comar:
state = 'ip'
self.dp[pkg] = True
else:
state = 'i'
self.d[pkg] = InstallInfo(state, version, release, build, distro)
def remove(self, pkg):
pkg = str(pkg)
info = self.d[pkg]
info.state = 'r'
self.d[pkg] = info
def purge(self, pkg):
pkg = str(pkg)
if self.d.has_key(pkg):
del self.d[pkg]
db = None
def init():
global db
if db:
return db
db = InstallDB()
return db
@@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# A simple wrapper to implement locking for bsddb's dbshelf
#
# Authors: Eray Ozkural <eray@uludag.org.tr>
import bsddb.dbshelve as shelve
import bsddb.db as db
import os
import fcntl
import pisi
import pisi.context
class LockedDBShelf(shelve.DBShelf):
def __init__(self, dbname, flags=db.DB_CREATE, mode=0660,
filetype=db.DB_HASH, dbenv=None):
shelve.DBShelf.__init__(self, dbenv)
if type(flags) == type(''):
sflag = flags
if sflag == 'r':
flags = db.DB_RDONLY
elif sflag == 'rw':
flags = 0
elif sflag == 'w':
flags = db.DB_CREATE
elif sflag == 'c':
flags = db.DB_CREATE
elif sflag == 'n':
flags = db.DB_TRUNCATE | db.DB_CREATE
else:
raise error, "flags should be one of 'r', 'w', 'c' or 'n' or use the bsddb.db.DB_* flags"
filename = os.path.join( pisi.context.config.db_dir(), dbname + '.bdb')
self.open(filename, dbname, filetype, flags, mode)
def open(self, filename, dbname, filetype, flags, mode):
pisi.util.check_dir(pisi.context.config.db_dir())
self.lockfile = file(filename + '.lock', 'w')
try:
fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
import sys
pisi.context.ui.error("Another instance of PISI is running. Try later!")
sys.exit(1)
return self.db.open(filename, dbname, filetype, flags, mode)
def close(self):
self.db.close()
self.lockfile.close()
-150
View File
@@ -1,150 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Metadata module provides access to metadata.xml. metadata.xml is
# generated during the build process of a package and used in the
# installation. Package repository also uses metadata.xml for building
# a package index.
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr
import pisi.context as ctx
import pisi.specfile as specfile
from pisi.xmlfile import *
from pisi.util import Checks
class SourceInfo:
def __init__(self, node=None):
if node:
self.name = getNodeText(node, "Name")
self.homepage = getNodeText(node, "HomePage")
self.packager = specfile.PackagerInfo(getNode(node, "Packager"))
else:
self.homepage = None
def elt(self, xml):
node = xml.newNode("Source")
xml.addTextNodeUnder(node, "Name", self.name)
if self.homepage:
xml.addTextNodeUnder(node, "Homepage", self.homepage)
node.appendChild(self.packager.elt(xml))
return node
def has_errors(self):
if not self.name:
return [ "SourceInfo should have a Name" ]
return None
class PackageInfo(specfile.PackageInfo):
def __init__(self, node = None):
if node:
specfile.PackageInfo.__init__(self, node)
self.version = getNodeText(node, "History/Update/Version")
self.release = getNodeText(node, "History/Update/Release")
build_ = getNodeText(node, "History/Update/Build")
if build_ != None:
self.build = int(build_)
else:
self.build = None
self.distribution = getNodeText(node, "Distribution")
self.distributionRelease = getNodeText(node, "DistributionRelease")
self.architecture = getNodeText(node, "Architecture")
self.installedSize = int(getNodeText(node, "InstalledSize"))
self.packageURI = getNodeText(node, "PackageURI")
else:
self.packageURI = None
def elt(self, xml):
node = specfile.PackageInfo.elt(self, xml)
if self.build != None:
xml.addTextNodeUnder(node, "Build", str(self.build))
xml.addTextNodeUnder(node, "Distribution", self.distribution)
xml.addTextNodeUnder(node, "DistributionRelease", self.distributionRelease)
xml.addTextNodeUnder(node, "Architecture", self.architecture)
xml.addTextNodeUnder(node, "InstalledSize", str(self.installedSize))
if self.packageURI:
xml.addTextNodeUnder(node, "PackageURI", str(self.packageURI))
return node
def has_errors(self):
# FIXME: there should be real error msgs
# and comment the logic here please, it isn't very clear -gurer
ret = (specfile.PackageInfo.has_errors(self) == None)
ret = ret and self.distribution!=None
ret = ret and self.distributionRelease!=None
ret = ret and self.architecture!=None and self.installedSize!=None
if ret:
return None
return [ "Some error in package metadata" ]
def __str__(self):
s = specfile.PackageInfo.__str__(self)
return s
class MetaData(XmlFile):
"""Package metadata. Metadata is composed of Specfile and various
other information. A metadata has two parts, Source and Package."""
def __init__(self):
XmlFile.__init__(self, "PISI")
def from_spec(self, src, pkg):
self.source = SourceInfo()
self.source.name = src.name
self.source.homepage = src.homepage
self.source.packager = src.packager
self.package = PackageInfo()
self.package.name = pkg.name
self.package.summary = pkg.summary
self.package.description = pkg.description
self.package.icon = pkg.icon
self.package.isa = pkg.isa
self.package.partof = pkg.partof
self.package.license = pkg.license
self.package.runtimeDeps = pkg.runtimeDeps
self.package.paths = pkg.paths
self.package.history = src.history # FIXME
self.package.conflicts = pkg.conflicts
self.package.providesComar = pkg.providesComar
self.package.requiresComar = pkg.requiresComar
self.package.additionalFiles = pkg.additionalFiles
# FIXME: right way to do it?
self.source.version = src.version
self.source.release = src.release
self.package.version = src.version
self.package.release = src.release
def read(self, filename):
self.readxml(filename)
self.source = SourceInfo(self.getNode("Source"))
self.package = PackageInfo(self.getNode("Package"))
def write(self, filename):
self.newDOM()
self.addChild(self.source.elt(self))
self.addChild(self.package.elt(self))
self.writexml(filename)
def has_errors(self):
err = Checks()
# FIXME: is this an internal error?? -gurer
if not hasattr(self, 'source'):
err.add("Metadata should have source")
err.join(self.source.has_errors())
if not self.package:
err.add("Metadata should have a package")
err.join(self.package.has_errors())
return err.list
-105
View File
@@ -1,105 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
#
"Package Operations: install/remove/upgrade"
import os
import pisi
import pisi.context as ctx
import pisi.util as util
import pisi.packagedb as packagedb
from pisi.uri import URI
# single package operations
def remove_single(package_name):
"""Remove a single package"""
inst_packagedb = packagedb.inst_packagedb
#TODO: check dependencies
ctx.ui.info('Removing package %s' % package_name)
if not ctx.installdb.is_installed(package_name):
raise Exception('Trying to remove nonexistent package '
+ package_name)
if ctx.comard:
ctx.comard.remove(package_name)
ctx.comard.call("System.Package", "preremove")
for fileinfo in ctx.installdb.files(package_name).list:
fpath = os.path.join(ctx.config.destdir, fileinfo.path)
# TODO: We have to store configuration files for futher
# usage. Currently we'are doing it like rpm does, saving
# with a prefix and leaving the user to edit it. In the future
# we'll have a plan for these configuration files.
if fileinfo.type == ctx.const.conf:
if os.path.isfile(fpath):
os.rename(fpath, fpath + ".pisi")
else:
# check if file is removed manually.
# And we don't remove directories!
# FIXME: should give a warning if it is...
if os.path.isfile(fpath):
os.unlink(fpath)
ctx.installdb.remove(package_name)
packagedb.remove_package(package_name)
def install_single(pkg, upgrade = False):
"""install a single package from URI or ID"""
url = URI(pkg)
# Check if we are dealing with a remote file or a real path of
# package filename. Otherwise we'll try installing a package from
# the package repository.
if url.is_remote_file() or os.path.exists(url.uri):
install_single_file(pkg, upgrade)
else:
install_single_name(pkg, upgrade)
# FIXME: Here and elsewhere pkg_location must be a URI
def install_single_file(pkg_location, upgrade = False):
"""install a package file"""
from install import Installer
Installer(pkg_location).install(not upgrade)
def install_single_name(name, upgrade = False):
"""install a single package from ID"""
# find package in repository
repo = packagedb.which_repo(name)
if repo:
repo = ctx.repodb.get_repo(repo)
pkg = packagedb.get_package(name)
# FIXME: let pkg.packageURI be stored as URI type rather than string
pkg_uri = URI(pkg.packageURI)
if pkg_uri.is_absolute_path():
pkg_path = str(pkg.packageURI)
else:
pkg_path = os.path.join(os.path.dirname(repo.indexuri.get_uri()),
str(pkg_uri.path()))
ctx.ui.debug("Package URI: %s" % pkg_path)
# Package will handle remote file for us!
install_single_file(pkg_path, upgrade)
else:
ctx.ui.error("Package %s not found in any active repository." % pkg)
# deneme, don't remove ulan
class AtomicOperation(object):
def __init__(self, package, ignore_dep = False):
self.package = package
self.ignore_dep = ignore_dep
def run(self, package):
"perform an atomic package operation"
pass
-114
View File
@@ -1,114 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# package abstraction
# provides methods to add/remove files, extract control files
# maintainer: baris and meren
from os.path import join, exists
import pisi
import pisi.context as ctx
import pisi.archive as archive
from pisi.uri import URI
from pisi.metadata import MetaData
from pisi.files import Files
class PackageError(pisi.Error):
pass
class Package:
"""PISI Package Class provides access to a pisi package (.pisi
file)."""
def __init__(self, packagefn, mode='r'):
self.filepath = packagefn
url = URI(packagefn)
if url.is_remote_file():
from fetcher import fetch_url
dest = ctx.config.packages_dir()
self.filepath = join(dest, url.filename())
# FIXME: exists is not enough, also sha1sum check needed \
# when implemented in pisi-index.xml
if not exists(self.filepath):
fetch_url(url, dest, ctx.ui.Progress)
else:
ctx.ui.info('%s [cached]' % url.filename())
self.impl = archive.ArchiveZip(self.filepath, 'zip', mode)
def add_to_package(self, fn):
"""Add a file or directory to package"""
self.impl.add_to_archive(fn)
def close(self):
"""Close the package archive"""
self.impl.close()
def extract(self, outdir):
"""Extract entire package contents to directory"""
self.extract_dir('', outdir) # means package root
def extract_files(self, paths, outdir):
"""Extract paths to outdir"""
self.impl.unpack_files(paths, outdir)
def extract_file(self, path, outdir):
"""Extract file with path to outdir"""
self.extract_files([path], outdir)
def extract_dir(self, dir, outdir):
"""Extract directory recursively, this function
copies the directory archiveroot/dir to outdir"""
self.impl.unpack_dir(dir, outdir)
def extract_dir_flat(self, dir, outdir):
"""Extract directory recursively, this function
unpacks the *contents* of directory archiveroot/dir inside outdir
this is the function used by the installer"""
self.impl.unpack_dir_flat(dir, outdir)
def extract_PISI_files(self, outdir):
"""Extract PISI control files: metadata.xml, files.xml,
action scripts, etc."""
self.extract_files([ctx.const.metadata_xml, ctx.const.files_xml], outdir)
self.extract_dir('config', outdir)
def read(self, outdir = None):
if not outdir:
outdir = ctx.config.tmp_dir()
# extract control files
self.extract_PISI_files(outdir)
self.metadata = MetaData()
self.metadata.read( join(outdir, ctx.const.metadata_xml) )
if self.metadata.has_errors():
raise PackageError, "MetaData format wrong"
self.files = Files()
self.files.read( join(outdir, ctx.const.files_xml) )
if self.files.has_errors():
raise PackageError, "invalid %s" % ctx.const.files_xml
def pkg_dir(self):
packageDir = self.metadata.package.name + '-' \
+ self.metadata.package.version + '-' \
+ self.metadata.package.release
return join( ctx.config.lib_dir(), packageDir)
def comar_dir(self):
return self.pkg_dir() + ctx.const.comar_dir_suffix
-161
View File
@@ -1,161 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# package database
# interface for update/query to local package repository
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr>
# we basically store everything in PackageInfo class
# yes, we are cheap
import bsddb.dbshelve as shelve
import os, fcntl
from bsddb import db
import pisi
import pisi.util as util
import pisi.context as ctx
class Error(pisi.Error):
pass
class PackageDB(object):
"""PackageDB class provides an interface to the package database with
a delegated dbshelve object"""
def __init__(self, id):
util.check_dir(ctx.config.db_dir())
self.fname = os.path.join(ctx.config.db_dir(), 'package-%s.bdb' % id )
self.fname2 = os.path.join(ctx.config.db_dir(), 'revdep-%s.bdb' % id )
self.lockfile = file(self.fname + '.lock', 'w')
try:
fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError, e:
import sys
ctx.ui.error("PackageDB: %s" % e)
sys.exit(1)
self.d = shelve.open(self.fname)
self.dr = shelve.open(self.fname2)
def __del__(self):
pass
#self.d.close()
#self.dr.close()
#self.lockfile.close()
def has_package(self, name):
name = str(name)
return self.d.has_key(name)
def get_package(self, name):
name = str(name)
return self.d[name]
def get_rev_deps(self, name):
name = str(name)
if self.dr.has_key(name):
return self.dr[name]
else:
return []
def list_packages(self):
list = []
for (pkg, x) in self.d.iteritems():
list.append(pkg)
return list
#TODO: list_upgrades?
def add_package(self, package_info):
name = str(package_info.name)
self.d[name] = package_info
for dep in package_info.runtimeDeps:
dep_name = str(dep.package)
if self.dr.has_key(dep_name):
self.dr[dep_name].append( (name, dep) )
else:
self.dr[dep_name] = [ (name, dep) ]
def clear(self):
self.d.clear()
def remove_package(self, name):
name = str(name)
del self.d[name]
packagedbs = {}
def add_db(name):
packagedbs[name] = PackageDB('repo-' + name)
def get_db(name):
return packagedbs[name]
def remove_db(name):
del packagedbs[name]
#erase database file
def has_package(name):
repo = which_repo(name)
if repo or thirdparty_packagedb.has_package(name) or inst_packagedb.has_package(name):
return True
return False
def which_repo(name):
import pisi.repodb
for repo in pisi.repodb.db.list():
if get_db(repo).has_package(name):
return repo
return None
def get_package(name):
repo = which_repo(name)
if repo:
return get_db(repo).get_package(name)
if thirdparty_packagedb.has_package(name):
return thirdparty_packagedb.get_package(name)
if inst_packagedb.has_package(name):
return inst_packagedb.get_package(name)
raise Error('get_package: package %s not found' % name)
def get_rev_deps(name):
repo = which_repo(name)
if repo:
return get_db(repo).get_rev_deps(name)
if thirdparty_packagedb.has_package(name):
return thirdparty_packagedb.get_rev_deps(name)
if inst_packagedb.has_package(name):
return inst_packagedb.get_rev_deps(name)
return None
def remove_package(name):
# remove the guy from the tracking databases
inst_packagedb.remove_package(name)
if thirdparty_packagedb.has_package(name):
thirdparty_packagedb.remove_package(name)
# tracking databases for non-repository information
thirdparty_packagedb = None
inst_packagedb = None
def init():
global thirdparty_packagedb
global inst_packagedb
if not thirdparty_packagedb:
thirdparty_packagedb = PackageDB('thirdparty')
if not inst_packagedb:
inst_packagedb = PackageDB('installed')
-79
View File
@@ -1,79 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# PISI package relation graph that represents the state of packagedb
from graph import *
# Cache the results from packagedb queries in a graph
class PGraph(Digraph):
def __init__(self, packagedb):
super(PGraph, self).__init__()
self.packagedb = packagedb
def add_package(self, pkg):
pkg1 = self.packagedb.get_package(pkg)
self.add_vertex(str(pkg), (pkg1.version, pkg1.release))
def add_plain_dep(self, pkg1name, pkg2name):
pkg1data = None
if not pkg1name in self.vertices():
pkg1 = self.packagedb.get_package(pkg1name)
pkg1data = (pkg1.version, pkg1.release)
pkg2data = None
if not pkg2name in self.vertices():
pkg2 = self.packagedb.get_package(pkg2name)
pkg2data = (pkg2.version, pkg2.release)
self.add_edge(str(pkg1name), str(pkg2name), ('d', None),
pkg1data, pkg2data )
def add_dep(self, pkg, depinfo):
pkg1data = None
if not pkg in self.vertices():
pkg1 = self.packagedb.get_package(pkg)
pkg1data = (pkg1.version, pkg1.release)
pkg2data = None
if not depinfo.package in self.vertices():
pkg2 = self.packagedb.get_package(depinfo.package)
pkg2data = (pkg2.version, pkg2.release)
self.add_edge(str(pkg), str(depinfo.package), ('d', depinfo),
pkg1data, pkg2data )
def add_rev_dep(self, depinfo, pkg):
pkg1data = None
if not pkg in self.vertices():
pkg1 = self.packagedb.get_package(depinfo.package)
pkg1data = (pkg1.version, pkg1.release)
pkg2data = None
if not depinfo.package in self.vertices():
pkg2 = self.packagedb.get_package(pkg)
pkg2data = (pkg2.version, pkg2.release)
self.add_edge(str(depinfo.package), str(pkg), ('d', depinfo),
pkg1data, pkg2data )
def add_conflict(self, pkg, conflinfo):
pkg1data = None
if not pkg in self.vertices():
pkg1 = self.packagedb.get_package(pkg)
pkg1data = (pkg1.version, pkg1.release)
pkg2data = None
if not pkg in self.vertices():
pkg2 = self.packagedb.get_package(conflinfo.package)
pkg2data = (pkg2.version, pkg2.release)
self.add_biedge(str(pkg), str(conflinfo.package), ('c', conflinfo)
, pkg1data, pkg2data )
def write_graphviz_vlabel(self, f, u):
(v, r) = self.vertex_data(u)
f.write('[ label = \"' + str(u) + '(' + str(v) + ',' + str(r) + ')\" ]')
-105
View File
@@ -1,105 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Author: Eray Ozkural
from bsddb import db
import os, fcntl
import pisi
import pisi.lockeddbshelve as shelve
import pisi.context as ctx
import pisi.packagedb as packagedb
import pisi.util as util
from pisi.uri import URI
class Error(pisi.Error):
pass
class Repo:
def __init__(self, indexuri):
self.indexuri = indexuri
#class HttpRepo
#class FtpRepo
#class RemovableRepo
class RepoDB(object):
"""RepoDB maps repo ids to repository information"""
def __init__(self):
self.d = shelve.LockedDBShelf("repo")
if not self.d.has_key("order"):
self.d["order"] = []
def init_dbs(self):
# initialize package/source dbs
for x in self.list():
packagedb.add_db(x)
def __del__(self):
self.d.close()
def repo_name(self, ix):
l = self.list()
return l[ix]
def swap(self, x,y):
l = d["order"]
t = l[x]
l[x] = l[y]
l[y] = t
d["order"] = l
def has_repo(self, name):
name = str(name)
return self.d.has_key("repo-" + name)
def get_repo(self, name):
name = str(name)
return self.d["repo-" + name]
def add_repo(self, name, repo_info):
if self.d.has_key("repo-" + name):
raise Error('Repository %s already exists' % name)
self.d["repo-" + name] = repo_info
order = self.d["order"]
order.append(name)
self.d["order"] = order
packagedb.add_db(name)
def list(self):
return self.d["order"]
def clear(self):
self.d.clear()
def remove_repo(self, name):
name = str(name)
del self.d["repo-" + name]
l = self.d["order"]
l.remove(name)
self.d["order"] = l
db = None
def init():
global db
if db:
return db
db = RepoDB()
db.init_dbs()
return db
@@ -1,69 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Authors: Baris Metin <baris@uludag.org.tr>
# Eray Ozkural <eray@uludag.org.tr>
# python standard library
from os.path import join
from os import access, R_OK
# pisi modules
import pisi
import pisi.util as util
import pisi.context as ctx
from pisi.archive import Archive
from pisi.uri import URI
from pisi.fetcher import fetch_url
class SourceArchiveError(pisi.Error):
pass
class SourceArchive:
"""source archive. this is a class responsible for fetching
and unpacking a source archive"""
def __init__(self, bctx):
self.url = URI(bctx.spec.source.archiveUri)
self.archiveFile = join(ctx.config.archives_dir(), self.url.filename())
self.archiveName = bctx.spec.source.archiveName
self.archiveType = bctx.spec.source.archiveType
self.archiveSHA1 = bctx.spec.source.archiveSHA1
self.bctx = bctx
def fetch(self, interactive=True):
if not self.is_cached(interactive):
if interactive:
progress = ctx.ui.Progress
else: progress = None
fetch_url(self.url, ctx.config.archives_dir(), progress)
def is_cached(self, interactive=True):
if not access(self.archiveFile, R_OK):
return False
# check hash
if util.check_file_hash(self.archiveFile, self.archiveSHA1):
if interactive:
ctx.ui.info('%s [cached]' % self.archiveName)
return True
return False
def unpack(self, cleanDir=True):
# check archive file's integrity
if not util.check_file_hash(self.archiveFile, self.archiveSHA1):
raise SourceArchiveError, "unpack: check_file_hash failed"
archive = Archive(self.archiveFile, self.archiveType)
archive.unpack(self.bctx.pkg_work_dir(), cleanDir)
-71
View File
@@ -1,71 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# package source database
# interface for update/query to local package repository
# Author: Eray Ozkural <eray@uludag.org.tr>
# we basically store everything in sourceinfo class
# yes, we are cheap
import bsddb.dbshelve as shelve
import os
import fcntl
from bsddb import db
import pisi.util as util
import pisi.context as ctx
class SourceDB(object):
def __init__(self):
util.check_dir(ctx.config.db_dir())
self.filename = os.path.join(ctx.config.db_dir(), 'source.bdb')
self.d = shelve.open(self.filename)
self.fdummy = file(self.filename + '.lock', 'w')
fcntl.flock(self.fdummy, fcntl.LOCK_EX)
def __del__(self):
#fcntl.flock(self.fdummy, fcntl.LOCK_UN)
self.fdummy.close()
#os.unlink(self.filename + '.lock')
def has_source(self, name):
name = str(name)
return self.d.has_key(name)
def get_source(self, name):
name = str(name)
return self.d[name]
def add_source(self, source_info):
# FIXME: how can you make a negative assertion -gurer
# and yes i'm not very clever :)
# assert source_info.has_errors()
name = str(source_info.name)
self.d[name] = source_info
def remove_source(self, name):
name = str(name)
del self.d[name]
sourcedb = None
def init():
global sourcedb
if sourcedb:
return sourcedb
sourcedb = SourceDB()
return sourcedb
@@ -1,80 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
from os.path import basename, dirname, join
import pisi.context as ctx
from pisi.uri import URI
from pisi.specfile import SpecFile
class SourceFetcher(object):
def __init__(self, url, authInfo=None):
self.url = url
if authInfo:
self.url.set_auth_info(authInfo)
self.location = dirname(self.url.uri)
pkgname = basename(dirname(self.url.path()))
self.dest = join(ctx.config.tmp_dir(), pkgname)
def fetch_all(self):
# fetch pspec file
self.fetch()
pspec = join(self.dest, self.url.filename())
self.spec = SpecFile()
self.spec.read(pspec)
self.fetch_actionsfile()
self.fetch_patches()
self.fetch_comarfiles()
self.fetch_additionalFiles()
return pspec
def fetch_actionsfile(self):
actionsuri = join(self.location, ctx.const.actions_file)
self.url.uri = actionsuri
self.fetch()
def fetch_patches(self):
spec = self.spec
for patch in spec.source.patches:
patchuri = join(self.location,
ctx.const.files_dir, patch.filename)
self.url.uri = patchuri
self.fetch(ctx.const.files_dir)
def fetch_comarfiles(self):
spec = self.spec
for package in spec.packages:
for pcomar in package.providesComar:
comaruri = join(self.location,
ctx.const.comar_dir, pcomar.script)
self.url.uri = comaruri
self.fetch(ctx.const.comar_dir)
def fetch_additionalFiles(self):
spec = self.spec
for pkg in spec.packages:
for afile in pkg.additionalFiles:
afileuri = join(self.location,
ctx.const.files_dir, afile.filename)
self.url.uri = afileuri
self.fetch(ctx.const.files_dir)
def fetch(self, appendDest=""):
from fetcher import fetch_url
ctx.ui.info("Fetching %s" % self.url.uri)
dest = join(self.dest, appendDest)
fetch_url(self.url, dest)
-471
View File
@@ -1,471 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Gurer Ozen <gurer@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr>
# History:
# Baris wrote the first version, then Baris and Eray did
# several revisions of it. It was rewritten in accordance
# with Gurer's observations.
"""Specfile module is our handler for PSPEC files. PSPEC (PISI SPEC)
files are specification files for PISI source packages. This module
provides read and write access to PSPEC files."""
# standard python modules
from os.path import basename
# pisi modules
import pisi
from pisi.xmlext import *
from pisi.xmlfile import XmlFile
from pisi.dependency import DepInfo
from pisi.util import Checks
#class Packager:
# __metaclass__ = xmlfile.autoxml
class PackagerInfo:
def __init__(self, node = None):
if node:
self.name = getNodeText(getNode(node, "Name"))
self.email = getNodeText(getNode(node, "Email"))
else:
self.name = None
self.email = None
def elt(self, xml):
node = xml.newNode("Packager")
xml.addTextNodeUnder(node, "Name", self.name)
xml.addTextNodeUnder(node, "Email", self.email)
return node
def has_errors(self):
err = Checks()
err.has_tag(self.name, "Packager", "Name")
err.has_tag(self.email, "Packager", "Email")
return err.list
def __str__(self):
s = "%s <%s>" % (self.name, self.email)
return s
class AdditionalFileInfo:
def __init__(self, node = None):
if node:
self.filename = getNodeText(node)
self.target = getNodeAttribute(node, "target")
self.permission = getNodeAttribute(node, "permission")
def elt(self, xml):
node = xml.newNode("AdditionalFile")
xml.addText(node, self.filename)
node.setAttribute("target", self.target)
if self.permission:
node.setAttribute("permission", self.permission)
def has_errors(self):
err = Checks()
if not self.filename:
err.add("AdditionalFile should have file name string")
if not self.target:
err.add("AdditionalFile should have a target attribute")
return err.list
def __str__(self):
s = "->".join(self.filename, self.target)
s += s + '(' + self.permission + ')'
return s
class PatchInfo:
def __init__(self, node = None):
if node:
self.filename = getNodeText(node)
self.compressionType = getNodeAttribute(node, "compressionType")
self.level = getNodeAttribute(node, "level")
self.target = getNodeAttribute(node, "target")
else:
self.compressionType = None
if not self.level:
self.level = 0
else:
self.level = int(self.level)
if not self.target:
self.target = ''
def elt(self, xml):
node = xml.newNode("Patch")
xml.addText(node, self.filename)
if self.compressionType:
node.setAttribute("compressionType", self.compressionType)
if self.level:
node.setAttribute("level", str(self.level))
if self.target:
node.setAttribute("target", self.target)
return node
def has_errors(self):
if not self.filename:
return [ "Patch should have a filename string" ]
return None
def __str__(self):
s = self.filename
s += ' (' + self.compressionType + ')'
s += ' level:' + self.level
return s
class UpdateInfo:
def __init__(self, node = None):
if node:
self.date = getNodeText(getNode(node, "Date"))
self.version = getNodeText(getNode(node, "Version"))
self.release = getNodeText(getNode(node, "Release"))
self.type = getNodeText(getNode(node, "Type"))
else:
self.type = None
def elt(self, xml):
node = xml.newNode("Update")
xml.addTextNodeUnder(node, "Date", self.date)
xml.addTextNodeUnder(node, "Version", self.version)
xml.addTextNodeUnder(node, "Release", self.release)
if self.type:
xml.addTextNodeUnder(node, "Type", self.type)
return node
def has_errors(self):
err = Checks()
err.has_tag(self.date, "Update", "Date")
err.has_tag(self.version, "Update", "Version")
err.has_tag(self.release, "Update", "Release")
return err.list
def __str__(self):
s = self.date
s += ", ver=" + self.version
s += ", rel=" + self.release
s += ", type=" + self.type
return s
class PathInfo:
def __init__(self, node = None):
if node:
self.pathname = getNodeText(node)
self.fileType = getNodeAttribute(node, "fileType")
if not self.fileType:
self.fileType = "other"
def elt(self, xml):
node = xml.newNode("Path")
xml.addText(node, self.pathname)
node.setAttribute("fileType", self.fileType)
return node
def has_errors(self):
if not self.pathname:
return [ "Path tag should have a name string" ]
return None
def __str__(self):
s = self.pathname
s += ", type=" + self.fileType
return s
class ComarProvide:
def __init__(self, node = None):
if node:
self.om = getNodeText(node)
self.script=getNodeAttribute(node, "script")
def elt(self, xml):
node = xml.newNode("COMAR")
xml.addText(node, self.om)
node.setAttribute("script", self.script)
return node
def has_errors(self):
if not self.om or not self.script:
return [ "COMAR provide should have something :)" ]
return None
def __str__(self):
s = self.script
s += ' (' + self.om + ')'
return s
class SourceInfo:
"""A structure to hold source information. Source information is
located under <Source> tag in PSPEC file."""
def __init__(self, node = None):
if node:
self.name = getNodeText(node, "Name")
self.homepage = getNodeText(node, "HomePage")
self.packager = PackagerInfo(getNode(node, "Packager"))
self.summary = getNodeText(node, "Summary")
self.description = getNodeText(node, "Description")
self.license = map(getNodeText, getAllNodes(node, "License"))
self.icon = getNodeText(node, "Icon")
self.isa = map(getNodeText, getAllNodes(node, "IsA"))
self.partof = getNodeText(node, "PartOf")
archiveNode = getNode(node, "Archive")
self.archiveUri = getNodeText(archiveNode).strip()
self.archiveName = basename(self.archiveUri)
self.archiveType = getNodeAttribute(archiveNode, "type")
self.archiveSHA1 = getNodeAttribute(archiveNode,
"sha1sum")
patchElts = getAllNodes(node, "Patches/Patch")
self.patches = [PatchInfo(p) for p in patchElts]
buildDepElts = getAllNodes(node,
"BuildDependencies/Dependency")
self.buildDeps = [DepInfo(d) for d in buildDepElts]
historyElts = getAllNodes(node, "History/Update")
self.history = [UpdateInfo(x) for x in historyElts]
def elt(self, xml):
node = xml.newNode("Source")
xml.addTextNodeUnder(node, "Name", self.name)
if self.homepage:
xml.addTextNodeUnder(node, "Homepage", self.homepage)
node.appendChild(self.packager.elt(xml))
xml.addTextNodeUnder(node, "Summary", self.summary)
xml.addTextNodeUnder(node, "Description", self.description)
if self.icon:
xml.addTextNodeUnder(node, "Icon", self.icon)
for lic in self.license:
xml.addTextNodeUnder(node, "License", lic)
for isa in self.isa:
xml.addTextNodeUnder(node, "IsA", isa)
xml.addTextNodeUnder(node, "PartOf", self.partof)
archiveNode = xml.addNodeUnder(node, "Archive")
archiveNode.setAttribute("type", self.archiveType)
archiveNode.setAttribute("sha1sum", self.archiveSHA1)
for patch in self.patches:
xml.addNodeUnder(node, "Patches", patch.elt(xml))
for dep in self.buildDeps:
xml.addNodeUnder(node, "BuildDependencies", dep.elt(xml))
for update in self.history:
xml.addNodeUnder(node, "History", update.elt(xml))
return node
def has_errors(self):
err = Checks()
err.has_tag(self.name, "Source", "Name")
err.has_tag(self.description, "Source", "Description")
err.has_tag(self.summary, "Source", "Summary")
err.has_tag(self.packager, "Source", "Packager")
err.has_tag(self.license, "Source", "License")
if (not self.archiveUri) or (not self.archiveType):
err.add("Source archive URI and type should be given")
if not self.archiveSHA1:
errd.add("Source archive should have a SHA1 sum")
if len(self.history) <= 0:
err.add("Source needs some education about History :)")
err.join(self.packager.has_errors())
for update in self.history:
err.join(update.has_errors())
for patch in self.patches:
err.join(patch.has_errors())
for dep in self.buildDeps:
err.join(dep.has_errors())
return err.list
class PackageInfo:
"""A structure to hold package information. Package information is
located under <Package> tag in PSPEC file. Opposite to Source each
PSPEC file can have more than one Package tag."""
def __init__(self, node = None):
if node:
self.name = getNodeText(node, "Name")
self.summary = getNodeText(node, "Summary")
self.description = getNodeText(node, "Description")
self.isa = map(getNodeText, getAllNodes(node, "IsA"))
self.partof = getNodeText(node, "PartOf")
self.license = map(getNodeText, getAllNodes(node, "License"))
self.icon = getNodeText(node, "Icon")
rtDepElts = getAllNodes(node, "RuntimeDependencies/Dependency")
self.runtimeDeps = [DepInfo(x) for x in rtDepElts]
self.paths = [PathInfo(x) for x in getAllNodes(node, "Files/Path")]
historyElts = getAllNodes(node, "History/Update")
self.history = [UpdateInfo(x) for x in historyElts]
conflElts = getAllNodes(node, "Conflicts/Package")
self.conflicts = map(getNodeText, conflElts)
provComarElts = getAllNodes(node, "Provides/COMAR")
self.providesComar = [ComarProvide(x) for x in provComarElts]
reqComarElts = getAllNodes(node, "Requires/COMAR")
self.requiresComar = map(getNodeText, reqComarElts)
aFilesElts = getAllNodes(node, "AdditionalFiles/AdditionalFile")
self.additionalFiles = [AdditionalFileInfo(f) for f in aFilesElts]
def elt(self, xml):
node = xml.newNode("Package")
xml.addTextNodeUnder(node, "Name", self.name)
xml.addTextNodeUnder(node, "Summary", self.summary)
xml.addTextNodeUnder(node, "Description", self.description)
if self.icon:
xml.addTextNodeUnder(node, "Icon", self.icon)
for lic in self.license:
xml.addTextNodeUnder(node, "License", lic)
for isa in self.isa:
xml.addTextNodeUnder(node, "IsA", isa)
if self.partof:
xml.addTextNodeUnder(node, "PartOf", self.partof)
for dep in self.runtimeDeps:
xml.addNodeUnder(node, "RuntimeDependencies", dep.elt(xml))
for path in self.paths:
xml.addNodeUnder(node, "Files", path.elt(xml))
for update in self.history:
xml.addNodeUnder(node, "History", update.elt(xml))
for conflict in self.conflicts:
xml.addTextNodeUnder(node, "Conflicts/Package", conflict)
for pcomar in self.providesComar:
xml.addNodeUnder(node, "Provides", pcomar.elt(xml))
for rcomar in self.requiresComar:
xml.addTextNodeUnder(node, "Requires/COMAR", rcomar)
for afile in self.additionalFiles:
xml.addNodeUnder(node, "AdditionalFiles", afile.elt(xml))
return node
def has_errors(self):
err = Checks()
err.has_tag(self.name, "Package", "Name")
err.has_tag(self.summary, "Package", "Summary")
err.has_tag(self.description, "Package", "Description")
err.has_tag(self.license, "Package", "License")
if len(self.paths) <= 0:
err.add("Package should have some files")
for path in self.paths:
err.join(path.has_errors())
for dep in self.runtimeDeps:
err.join(dep.has_errors())
for afile in self.additionalFiles:
err.join(afile.has_errors())
return err.list
def __str__(self):
s = 'Name: ' + self.name
s += '\nSummary: ' + self.summary
s += '\nDescription: ' + self.description
return s
def pkg_dir(self):
packageDir = self.name + '-' \
+ self.version + '-' \
+ self.release
return join( config.lib_dir(), packageDir)
class SpecFile(XmlFile):
"""A class for reading/writing from/to a PSPEC (PISI SPEC) file."""
def __init__(self):
XmlFile.__init__(self,"PISI")
def read(self, filename):
"""Read PSPEC file"""
self.readxml(filename)
self.source = SourceInfo(self.getNode("Source"))
# As we have no Source/Version tag we need to get
# the last version and release information
# from the first child of History/Update. And it works :)
self.source.version = self.source.history[0].version
self.source.release = self.source.history[0].release
# find all binary packages
packageElts = self.getAllNodes("Package")
self.packages = [PackageInfo(p) for p in packageElts]
self.merge_tags()
self.override_tags()
self.unlink()
errs = self.has_errors()
if errs:
e = ""
for x in errs:
e += x + "\n"
raise XmlError("File '%s' has errors:\n%s" % (filename, e))
def override_tags(self):
"""Override tags from Source in Packages. Some tags in Packages
overrides the tags from Source. There is a more detailed
description in documents."""
tmp = []
for pkg in self.packages:
if not pkg.summary:
pkg.summary = self.source.summary
if not pkg.description:
pkg.description = self.source.description
if not pkg.partof:
pkg.partof = self.source.partof
if not pkg.license:
pkg.license = self.source.license
if not pkg.icon:
pkg.icon = self.source.icon
tmp.append(pkg)
self.packages = tmp
def merge_tags(self):
"""Merge tags from Source in Packages. Some tags in Packages merged
with the tags from Source. There is a more detailed
description in documents."""
tmp = []
for pkg in self.packages:
if pkg.isa and self.source.isa:
pkg.isa.append(self.source.isa)
elif not pkg.isa and self.source.isa:
pkg.isa = self.source.isa
tmp.append(pkg)
self.packages = tmp
def has_errors(self):
"""Return errors of the PSPEC file if there are any."""
#FIXME: has_errors name is misleading for a function that does
#not just return a boolean value. check() would be better - exa
err = Checks()
err.join(self.source.has_errors())
if len(self.packages) <= 0:
errs.add("There should be at least one Package section")
for p in self.packages:
err.join(p.has_errors())
return err.list
def write(self, filename):
"""Write PSPEC file"""
self.newDOM()
self.addChild(self.source.elt(self))
for pkg in self.packages:
self.addChild(pkg.elt(self))
self.writexml(filename)
-149
View File
@@ -1,149 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr>
"""
Specfile module is our handler for PSPEC files. PSPEC (PISI SPEC)
files are specification files for PISI source packages. This module
provides read and write routines for PSPEC files.
"""
# standard python modules
from os.path import basename
# pisi modules
from pisi.xmlext import *
import pisi.xmlfile as xmlfile
from pisi.xmlfile import XmlFile
from pisi.ui import ui
from pisi.dependency import DepInfo
from pisi.util import Checks
__metaclass__ = xmlfile.autoxml
class Packager:
t_Name = [types.StringType, xmlfile.mandatory]
t_Email = [types.StringType, xmlfile.mandatory]
def __str__(self):
s = "%s <%s>" % (self.name, self.email)
return s
class AdditionalFileInfo:
s_Filename = xmlfile.mandatory
a_Target = [types.StringType, xmlfile.mandatory]
a_Permission = [types.StringType, xmlfile.optional]
def __str__(self):
s = "%s -> %s " % (self.filename, self.target)
if self.permission:
s += '(%s)' % self.permission
return s
class Patch:
s_Filename = xmlfile.mandatory
a_compressionType = [types.StringType, xmlfile.optional]
a_level = [types.StringType, xmlfile.optional]
a_target = [types.StringType, xmlfile.optional]
def __str__(self):
s = self.filename
if self.compressionType:
s += ' (' + self.compressionType + ')'
if self.level:
s += ' level:' + self.level
if self.target:
s += ' target:' + self.target
return s
class Update:
t_Date = [types.StringType, xmlfile.mandatory]
t_Version = [types.StringType, xmlfile.mandatory]
t_Release = [types.StringType, xmlfile.mandatory]
t_Type = [types.StringType, xmlfile.optional]
def __str__(self):
s = self.date
s += ", ver=" + self.version
s += ", rel=" + self.release
if self.type:
s += ", type=" + self.type
return s
class Path:
s_Path = xmlfile.mandatory
a_fileType = [types.StringType, xmlfile.optional]
def __str__(self):
s = self.pathname
s += ", type=" + self.fileType
return s
class ComarProvide:
s_om = [types.StringType, xmlfile.mandatory]
a_script = [types.StringType, xmlfile.mandatory]
def __str__(self):
# FIXME: descriptive enough?
s = self.script
s += ' (' + self.om + ')'
return s
class Archive:
s_uri = [ types.StringType, xmlfile.mandatory ]
a_type =[ types.StringType, xmlfile.mandatory ]
a_sha1sum =[ types.StringType, xmlfile.mandatory ]
def decode_post(self):
self.name = basename(self.uri)
class Source:
t_Name = [types.StringType, xmlfile.mandatory]
t_HomePage = [types.StringType, xmlfile.mandatory]
t_Packager = [Packager, xmlfile.mandatory]
t_Summary = [types.StringType, xmlfile.mandatory]
t_Description = [types.StringType, xmlfile.mandatory]
t_License = [ [types.StringType], xmlfile.mandatory]
t_IsA = [ [types.StringType], xmlfile.mandatory]
t_PartOf = [types.StringType, xmlfile.mandatory]
t_Archive = [Archive, xmlfile.mandatory ]
t_Patch = [ [Patch], xmlfile.mandatory, "Patches/Patch"]
t_BuildDep = [ [Dependency], xmlfile.mandatory, "BuildDependencies/Dependency"]
t_History = [ [Update], xmlfile.mandatory, "History/Update"]
class Package:
t_Name = [ types.StringType, xmlfile.mandatory ]
t_Summary = [ types.StringType, xmlfile.mandatory ]
t_Description = [ types.StringType, xmlfile.mandatory ]
t_IsA = [ [types.StringType], xmlfile.mandatory]
t_PartOf = [types.StringType, xmlfile.mandatory]
t_History = [ [Update], xmlfile.mandatory, "History/Update"]
t_Conflicts = [ [types.StringType], xmlfile.mandatory, "Conflicts/Package"]
t_ProvidesComar = [ [ComarProvide], xmlfile.mandatory, "Provides/COMAR"]
t_RequriesComar = [ [types.StringType], xmlfile.mandatory, "Requires/COMAR"]
t_AdditionalFiles = [ [AdditionalFile], xmlfile.mandatory, "AdditionalFiles/AdditionalFile"]
-84
View File
@@ -1,84 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# generic user interface
#
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Murat Eren <meren@uludag.org.tr>
import sys
import pisi
import pisi.context as ctx
class UI(object):
"Abstract class for UI operations, derive from this."
class Progress:
def __init__(self, totalsize):
self.totalsize = totalsize
self.percent = 0
def update(self, size):
if not self.totalsize:
return 100
percent = (size * 100) / self.totalsize
if percent and self.percent is not percent:
self.percent = percent
return percent
else:
return 0
def __init__(self, debuggy = False, verbose = False):
self.show_debug = debuggy
self.show_verbose = verbose
def set_verbose(self, flag):
self.show_verbose = flag
def set_debug(self, flag):
self.show_debug = flag
def info(self, msg, verbose = False):
"give an informative message"
pass
def ack(self, msg):
"inform the user of an important event and wait for acknowledgement"
pass
def debug(self, msg):
"show debugging info"
if self.show_debug:
self.info('DEBUG: ' + msg)
def warning(self,msg):
"warn the user"
pass
def error(self,msg):
"inform a (possibly fatal) error"
pass
def action(self,msg):
"uh?"
pass
def choose(self, msg, list):
"ask the user to choose from a list of alternatives"
pass
def confirm(self, msg):
"ask a yes/no question"
pass
def display_progress(self, pd):
"display progress"
pass
-102
View File
@@ -1,102 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Simplifies working with URLs, purl module provides common URL
# parsing and processing
from urlparse import urlparse
from os.path import basename
import pisi.util as util
class URI(object):
"""URI class provides a URL parser and simplifies working with
URLs."""
def __init__(self, uri=None):
if uri:
self.set_uri(uri)
else:
self.__scheme = None
self.__location = None
self.__path = None
self.__filename = None
self.__params = None
self.__query = None
self.__fragment = None
self.__uri = None
self.__authinfo = None
def get_uri(self):
if self.__uri:
return self.__uri
return None
def set_uri(self, uri):
# (scheme, location, path, params, query, fragment)
u = urlparse(uri, "file")
self.__scheme = u[0]
self.__location = u[1]
self.__path = u[2]
self.__filename = basename(self.__path)
self.__params = u[3]
self.__query = u[4]
self.__fragment = u[5]
self.__uri = uri
def is_local_file(self):
if self.scheme() == "file":
return True
else:
return False
def is_remote_file(self):
return not self.is_local_file()
def is_absolute_path(self):
return util.absolute_path(self.__path)
def is_relative_path(self):
return not self.is_absolute_path()
def set_auth_info(self, authTuple):
if not isinstance(authTuple, tuple):
raise Exception, "setAuthInfo needs a tuple (user, pass)"
self.__authinfo = authTuple
def auth_info(self):
return self.__authinfo
def scheme(self):
return self.__scheme
def location(self):
return self.__location
def path(self):
return self.__path
def filename(self):
return self.__filename
def params(self):
return self.__params
def query(self):
return self.__query
def fragment(self):
return self.__fragment
def __str__(self):
return self.get_uri()
uri = property(get_uri, set_uri)
-374
View File
@@ -1,374 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# misc. utility functions, including process and file utils
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr>
# S. Caglar Onur <caglar@uludag.org.tr>
# A. Murat Eren <meren@uludag.org.tr>
# standard python modules
import os
import sys
import sha
import shutil
import statvfs
# pisi modules
import pisi
import pisi.context as ctx
class FileError(pisi.Error):
pass
class UtilError(pisi.Error):
pass
#########################
# spec validation utility #
#########################
class Checks:
def __init__(self):
self.list = None
def add(self, err):
if not self.list:
self.list = []
self.list.append(err)
def join(self, list):
if list != None:
if not self.list:
self.list = []
self.list.extend(list)
def has_tag(self, var, section, name):
if not var:
if not self.list:
self.list = []
self.list.append("%s section should have a '%s' tag" % (section, name))
#########################
# string/list functions #
#########################
def unzip(seq):
return zip(*seq)
def concat(l):
'''concatenate a list of lists'''
return reduce( lambda x,y: x+y, l )
def strlist(l):
"""concatenate string reps of l's elements"""
return "".join(map(lambda x: str(x) + ' ', l))
def multisplit(str, chars):
""" split str with any of chars"""
l = [str]
for c in chars:
l = concat(map(lambda x:x.split(c), l))
return l
def same(l):
'''check if all elements of a sequence are equal'''
if len(l)==0:
return True
else:
last = l.pop()
for x in l:
if x!=last:
return False
return True
def prefix(a, b):
'''check if sequence a is a prefix of sequence b'''
if len(a)>len(b):
return False
for i in range(0,len(a)):
if a[i]!=b[i]:
return False
return True
def remove_prefix(a,b):
"remove prefix a from sequence b"
assert prefix(a,b)
return b[len(a):]
##############################
# Process Releated Functions #
##############################
def run_batch(cmd):
"""run command non-interactively and report return value and output"""
ui.info('running ' + cmd)
a = os.popen(cmd)
lines = a.readlines()
ret = a.close()
ui.debug('return value ' + ret)
successful = ret == None
if not successful:
ui.error('ERROR: executing command: ' + cmd + '\n' + strlist(lines))
return (successful,lines)
def xterm_title(message):
"""sets message as a console window's title"""
if os.environ.has_key("TERM") and sys.stderr.isatty():
terminalType = os.environ["TERM"]
for term in ["xterm", "Eterm", "aterm", "rxvt", "screen", "kterm", "rxvt-unicode"]:
if terminalType.startswith(term):
sys.stderr.write("\x1b]2;"+str(message)+"\x07")
sys.stderr.flush()
break
def xterm_title_reset():
"""resets console window's title"""
if os.environ.has_key("TERM"):
terminalType = os.environ["TERM"]
xterm_title(os.environ["TERM"])
#############################
# Path Processing Functions #
#############################
def splitpath(a):
"""split path into components and return as a list
os.path.split doesn't do what I want like removing trailing /"""
comps = a.split(os.path.sep)
if comps[len(comps)-1]=='':
comps.pop()
return comps
# I'm not sure how necessary this is. Ahem.
def commonprefix(l):
"""an improved version of os.path.commonprefix,
returns a list of path components"""
common = []
comps = map(splitpath, l)
for i in range(0, min(len,l)):
compi = map(lambda x: x[i], comps) # get ith slice
if same(compi):
common.append(compi[0])
return common
# but this one is necessary
def subpath(a, b):
"find if path a is before b in the directory tree"
return prefix(splitpath(a), splitpath(b))
def removepathprefix(prefix, path):
"remove path prefix a from b, finding the pathname rooted at a"
comps = remove_prefix(splitpath(prefix), splitpath(path))
if len(comps) > 0:
return os.path.join(*tuple(comps))
else:
return ""
def absolute_path(path):
"determine if given @path is absolute"
comps = splitpath(path)
return comps[0] == ''
####################################
# File/Directory Related Functions #
####################################
def check_file(file, mode = os.F_OK):
"shorthand to check if a file exists"
if not os.access(file, mode):
raise FileError("File " + file + " not found")
return True
def check_dir(dir):
"""check if directory exists, and create if it doesn't.
works recursively"""
dir = dir.strip().rstrip("/")
if not os.access(dir, os.F_OK):
os.makedirs(dir)
def clean_dir(path):
"Remove all content of a directory (top)"
# don't reimplement the wheel
if os.path.exists(path):
shutil.rmtree(path)
def dir_size(dir):
""" calculate the size of files under a dir
based on the os module example"""
# It's really hard to give an approximate value for package's
# installed size. Gettin a sum of all files' sizes if far from
# being true. Using 'du' command (like Debian does) can be a
# better solution :(.
getsize = os.path.getsize
join = os.path.join
islink = os.path.islink
def sizes():
for root, dirs, files in os.walk(dir):
yield sum([getsize(join(root, name)) for name in files if not islink(join(root,name))])
return sum( sizes() )
def copy_file(src,dest):
"""copy source file to destination file"""
check_file(src)
check_dir(os.path.dirname(dest))
shutil.copyfile(src, dest)
def get_file_hashes(top, exclude_prefix=None, removePrefix=None):
"""Generator function iterates over a toplevel path and returns the
(filePath, sha1Hash) tuple for all files. If excludePrefixes list
is given as a parameter, function will exclude the filePaths
matching those prefixes. The removePrefix string parameter will be
used to remove prefix from filePath while matching excludes, if
given."""
# also handle single files
if os.path.isfile(top):
yield (top, sha1_file(top))
return
def has_excluded_prefix(filename):
if exclude_prefix and removePrefix:
tempfnam = remove_prefix(removePrefix, filename)
for p in exclude_prefix:
if tempfnam.startswith(p):
return 1
else:
return 0
return 0
for root, dirs, files in os.walk(top, topdown=False):
#bug 339
if os.path.islink(root) and not has_excluded_prefix(root):
#yield the symlink..
#bug 373
yield (root, sha1_data(os.readlink(root)))
exclude_prefix.append(remove_prefix(removePrefix, root) + "/")
continue
#bug 397
for dir in dirs:
d = os.path.join(root, dir)
if os.path.islink(d) and not has_excluded_prefix(d):
yield (d, sha1_data(os.readlink(d)))
exclude_prefix.append(remove_prefix(removePrefix, d) + "/")
#bug 340
if os.path.isdir(root) and not has_excluded_prefix(root):
parent, r, d, f = root, '', '', ''
for r, d, f in os.walk(parent, topdown=False): pass
if not f and not d:
yield (parent, sha1_file(parent))
for fname in files:
f = os.path.join(root, fname)
if has_excluded_prefix(f):
continue
#bug 373
elif os.path.islink(f):
yield (f, sha1_data(os.readlink(f)))
else:
yield (f, sha1_file(f))
def copy_dir(src, dest):
"""copy source dir to destination dir recursively"""
shutil.copytree(src, dest)
def check_file_hash(filename, hash):
"""Check the files integrity with a given hash"""
if sha1_file(filename) == hash:
return True
return False
def sha1_file(filename):
"""calculate sha1 hash of filename"""
# Broken links can cause problem!
try:
m = sha.new()
f = file(filename, 'rb')
for line in f:
m.update(line)
return m.hexdigest()
except IOError:
return "0"
def sha1_data(data):
"""calculate sha1 hash of given data"""
try:
m = sha.new()
m.update(data)
return m.hexdigest()
except:
return "0"
def uncompress(patchFile, compressType="gz", targetDir=None):
"""uncompresses a file and returns the path of the uncompressed
file"""
if targetDir:
filePath = os.path.join(targetDir,
os.path.basename(patchFile))
else:
filePath = os.path.basename(patchFile)
if compressType == "gz":
from gzip import GzipFile
obj = GzipFile(patchFile)
elif compressType == "bz2":
from bz2 import BZ2File
obj = BZ2File(patchFile)
open(filePath, "w").write(obj.read())
return filePath
def do_patch(sourceDir, patchFile, level, target = ''):
"""simple function to apply patches.."""
cwd = os.getcwd()
os.chdir(sourceDir)
check_file(patchFile)
level = int(level)
cmd = "patch -p%d %s< %s" % (level, target, patchFile)
p = os.popen(cmd)
o = p.readlines()
retval = p.close()
if retval:
raise UtilError("ERROR: patch (%s) failed: %s" % (patchFile,
strlist (o)))
os.chdir(cwd)
def partition_freespace(directory):
""" returns free space of given directory's partition """
st = os.statvfs(directory)
return st[statvfs.F_BSIZE] * st[statvfs.F_BFREE]
def clean_locks(top = '.'):
for root, dirs, files in os.walk(top):
for fn in files:
if fn.endswith('.lock'):
path = os.path.join(root, fn)
ctx.ui.info('Removing lock %s', path)
os.unlink(path)
########################################
# Package/Repository Related Functions #
########################################
def package_name(name, version, release):
return name + '-' + version + '-' + release + ctx.const.package_prefix
-161
View File
@@ -1,161 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# version structure
# Authors: Eray Ozkural <eray@uludag.org.tr>
import re
import pisi.util as util
# Basic rule is:
# p > (no suffix) > rc > pre > beta > alpha
keywords = {"alpha": 0,
"beta" : 1,
"pre" : 2,
"rc" : 3,
"NOKEY" : 4,
"p" : 5}
# helper functions
def has_keyword(versionitem):
if versionitem._keyword != "NOKEY":
return True
return False
class VersionItem:
_keyword = "NOKEY"
_value = 0
def __init__(self, itemstring):
for keyword in keywords.keys():
if itemstring.startswith(keyword):
if self._keyword == "NOKEY":
self._keyword = keyword
else:
# longer match is correct
if len(keyword) > len(self._keyword):
self._keyword = keyword
if self._keyword == "NOKEY":
self._value = itemstring
else:
# rest is the version item's value. And each must have
# one!
self._value = itemstring[len(self._keyword):]
def __lt__(self,rhs):
l = keywords[self._keyword]
r = keywords[rhs._keyword]
if l < r:
return True
elif l == r:
return self._value < rhs._value
else: # l > r
return False
def __le__(self,rhs):
l = keywords[self._keyword]
r = keywords[rhs._keyword]
if l < r:
return True
elif l == r:
return self._value <= rhs._value
else: # l > r
return False
def __gt__(self,rhs):
l = keywords[self._keyword]
r = keywords[rhs._keyword]
if l > r:
return True
elif l == r:
return self._value > rhs._value
else: # l < r
return False
def __ge__(self,rhs):
l = keywords[self._keyword]
r = keywords[rhs._keyword]
if l > r:
return True
elif l == r:
return self._value >= rhs._value
else: # l < r
return False
class Version:
def __init__(self, verstring):
self.comps = []
for i in util.multisplit(verstring,'.-_'):
# some version strings can contain ascii chars at the
# back. As an example: 2.11a
# We split '11a' as two items like '11' and 'a'
s = re.compile("[a-z-A-Z]$").search(i)
if s:
head = i[:s.start()]
tail = s.group()
self.comps.append(VersionItem(head))
self.comps.append(VersionItem(tail))
else:
self.comps.append(VersionItem(i))
self.verstring = verstring
def string(self):
return self.verstring
def pred(self, rhs, pred):
loop = len(self.comps)
if len(rhs.comps) > loop:
loop = len(rhs.comps)
for i in range(0, loop):
try:
litem = self.comps[i]
except IndexError:
litem = VersionItem("")
try:
ritem = rhs.comps[i]
except IndexError:
ritem = VersionItem("")
if pred(litem, ritem):
return True
else:
return False
def __lt__(self,rhs):
return self.pred(rhs, lambda x,y: x<y)
def __le__(self,rhs):
return self.pred(rhs, lambda x,y: x<=y)
def __gt__(self,rhs):
return self.pred(rhs, lambda x,y: x>y)
def __ge__(self,rhs):
return self.pred(rhs, lambda x,y: x>=y)
-163
View File
@@ -1,163 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr
"""
some helper functions for using minidom
function names are mixedCase for compatibility with minidom,
an old library
"""
import pisi
class XmlError(pisi.Error):
"named this way because the class if mostly used with an import *"
pass
def getNodeAttribute(node, attrname):
"""get named attribute from DOM node"""
if not node.hasAttribute(attrname):
return None
return node.getAttribute(attrname)
def getTagByName(parent, childName):
return [x for x in parent.childNodes
if x.nodeType == x.ELEMENT_NODE if x.tagName == childName]
def getNodeText(node, tagpath = ""):
"""get the first child and expect it to be text!"""
if tagpath!="":
node = getNode(node, tagpath)
try:
child = node.childNodes[0]
except IndexError:
return None
except AttributeError: # no node by that name
return None
if child.nodeType == child.TEXT_NODE:
# in any case, strip whitespaces...
return child.data.strip()
else:
raise XmlError("getNodeText: Expected text node, got something else!")
def getChildText(node_s, tagpath):
"""get the text of a child at the end of a tag path"""
node = getNode(node_s, tagpath)
if not node:
return None
return getNodeText(node)
def getChildElts(node):
"""get only child elements"""
return filter(lambda x:x.nodeType == x.ELEMENT_NODE, node.childNodes)
def getNode(node, tagpath):
"""returns the *first* matching node for given tag path."""
assert type(tagpath)==str
tags = tagpath.split('/')
assert len(tags)>0
# iterative code to search for the path
# get DOM for top node
nodeList = getTagByName(node, tags[0])
if len(nodeList) == 0:
return None # not found
node = nodeList[0] # discard other matches
for tag in tags[1:]:
nodeList = getTagByName(node, tag)
if len(nodeList) == 0:
return None
else:
node = nodeList[0]
return node
def getAllNodes(node, tagPath):
"""retrieve all nodes that match a given tag path."""
tags = tagPath.split('/')
if len(tags) == 0:
return []
nodeList = getTagByName(node, tags[0])
if len(nodeList) == 0:
return []
for tag in tags[1:]:
results = map(lambda x: getTagByName(x, tag), nodeList)
nodeList = []
for x in results:
nodeList.extend(x)
pass # emacs indentation error, keep it here
if len(nodeList) == 0:
return []
return nodeList
def createTagPath(dom, node, tags):
"""create new child at the end of a tag chain starting from node
no matter what"""
if len(tags)==0:
return node
for tag in tags:
node = node.appendChild(dom.createElement(tag))
return node
def addTagPath(dom, node, tags, newnode=None):
"""add newnode at the end of a tag chain, smart one"""
node = createTagPath(dom, node, tags)
if newnode: # node to add specified
node.appendChild(newnode)
return node
def addNode(dom, node, tagpath, newnode = None):
"""add a new node at the end of the tree"""
assert type(tagpath)==str
tags = []
if tagpath != "":
tags = tagpath.split('/') # tag chain
else:
addTagPath(dom, node, [], newnode)
return node
assert len(tags)>0 # we want a chain
# iterative code to search for the path
# get DOM for top node
nodeList = getTagByName(node, tags[0])
if len(nodeList) == 0:
return addTagPath(dom, node, tags, newnode)
node = nodeList[len(nodeList)-1] # discard other matches
tags.pop(0)
while len(tags)>0:
tag = tags.pop(0)
nodeList = getTagByName(node, tag)
if len(nodeList) == 0: # couldn't find
tags.insert(0, tag) # put it back in
return addTagPath(dom, node, tags, newnode)
else:
node = nodeList[len(nodeList)-1]
else:
# had only one tag..
return addTagPath(dom, node, tags, newnode)
return node
-595
View File
@@ -1,595 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
#
# Authors: Eray Ozkural <eray@uludag.org.tr>
# Gurer Ozen <gurer@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr>
"""
xmlfile is a helper module for accessing XML files using
xml.dom.minidom.
XmlFile class further abstracts a dom object using the
high-level dom functions provided in xmlext module (and sorely lacking
in xml.dom :( )
autoxml is a metaclass for automatic XML translation, using
a miniature type system. (w00t!) This is based on an excellent
high-level XML processing prototype that Gurer prepared.
Method names are mixedCase for compatibility with minidom,
an old library.
"""
# System
import xml.dom.minidom as mdom
from xml.parsers.expat import ExpatError
import codecs
import types
# PiSi
import pisi
from pisi.xmlext import *
import pisi.context as ctx
class Error(pisi.Error):
pass
mandatory, optional = range(2) # poor man's enum
# basic types
Text = types.StringType
Integer = types.IntType
class LocalText(object):
"""Handles XML tags/attributes with localized text"""
def __init__():
locs = {}
def decode(nodes, req):
# flags, tag name, instance attribute
if not nodes:
if req == mandatory:
pass
#errs.append("Tag '%s' should have at least one '%s' tag\n" % (parent.tagName, d[2]))
else:
for node in nodes:
lang = getAttribute(node, "xml:lang")
c = getText(node)
if not c:
#errs.append("Tag '%s' should have some text data\n" % node.tagName)
break
# FIXME: check for dups and 'en'
if not lang:
lang = 'en'
self.locs[lang] = c
# FIXME: return full list too
L = language
if not locs.has_key(L):
L = 'en'
if not locs.has_key(L):
#errs.append("Tag '%s' should have an English version\n" % d[2])
return ""
return locs[L]
class autoxml(type):
"""High-level automatic XML transformation interface for xmlfile.
The idea is to declare a class for each XML tag. Inside the
class the tags and attributes nested in the tag are further
elaborated. A simple example follows:
class Employee:
__metaclass__ = autoxml
t_Name = [xmlfile.Text, xmlfile.mandatory]
a_Type = [xmlfile.Integer, xmlfile.optional]
This class defines a tag and an attribute nested in Employee
class. Name is a string and type is an integer, called basic
types.
While the tag is mandatory, the attribute may be left out.
Other basic types supported are: xmlfile.Float, xmlfile.Double
and (not implemented yet): xmlfile.Binary
By default, the class name is taken as the corresponding tag,
which may be overridden by defining a tag attribute. Thus,
the same tag may also be written as:
class EmployeeXML:
...
tag = 'Employee'
...
In addition to basic types, we allow for two kinds of complex
types: class types and list types.
A declared class can be nested in another class as follows
class Position:
__metaclass__ = autoxml
t_Name = [xmlfile.Text, xmlfile.mandatory]
t_Description = [xmlfile.Text, xmlfile.optional]
which we can add to our Employee class.
class Employee:
__metaclass__ = autoxml
t_Name = [xmlfile.Text, xmlfile.mandatory]
a_Type = [xmlfile.Integer, xmlfile.optional]
t_Position = [Position, xmlfile.mandatory]
Note some unfortunate redundancy here with Position; this is
justified by the implementation (kidding). Still, you might
want to assign a different name than the class name that
goes in there, which may be fully qualified.
There is more! Suppose we want to define a company, with
of course many employees.
class Company:
__metaclass__ = autoxml
t_Employees = [ [Employee], xmlfile.mandatory, 'Employee']
Logically, inside the Company/Employees tag, we will have several
Employes tags, which are inserted to the Employees instance variable of
Company in order of appearance.
The mandatory flag here asserts that at least one such record
is to be found.
You see, it works like magic, when it works of course. All of it
done without a single brain exploding.
"""
def __init__(cls, name, bases, dict):
"""entry point for metaclass code"""
print 'generating class', name
# add XmlFile as one of the superclasses, we're smart
bases = list(bases)
if not XmlFile in bases:
bases.append(XmlFile)
# standard initialization
super(autoxml, cls).__init__(name, bases, dict)
#TODO: initialize class attribute __xml_tags
#setattr(cls, 'xml_variables', [])
# default class tag is class name
if not dict.has_key('tag'):
cls.tag = name
# generate helper routines, for each XML component
inits = []
decoders = []
encoders = []
formatters = []
for var in dict:
if var.startswith('t_') or var.startswith('a_'):
name = var[2:]
print 'generating member', name
if var.startswith('a_'):
x = autoxml.gen_attr_member(cls, name)
elif var.startswith('t_'):
x = autoxml.gen_tag_member(cls, name)
(init, decoder, encoder, formatter) = x
inits.append(init)
decoders.append(decoder)
encoders.append(encoder)
formatters.append(formatter)
# generate top-level helper functions
cls.initializers = inits
def initialize(self):
# XmlFile.__init__(self, cls.tag)
for init in self.__class__.initializers:
init(self)
cls.__init__ = initialize
cls.decoders = decoders
def decode(self, node):
for decode_member in self.__class__.decoders:
decode_member(self, node)
cls.decode = decode
cls.encoders = encoders
def encode(self, xml):
node = xml.newNode(cls.tag)
for encode_member in self.__class__.encoders:
encode_member(self, xml, node)
xml.dom.documentElement = node
return node
cls.encode = encode
cls.formatters = formatters
def format(self):
string = ''
for formatter in self.__class__.formatters:
string += formatter(self)
return string
cls.format = format
if not dict.has_key('__str__'):
cls.__str__ = format
def gen_attr_member(cls, attr):
"""generate readers and writers for an attribute member"""
print 'attr:', attr
spec = getattr(cls, 'a_' + attr)
tag_type = spec[0]
assert type(tag_type) == type(type)
def readtext(node, attr):
return getNodeAttribute(node, attr)
def createnode(xml, attr_name):
return xml.newAttribute(attr_name) # create an attribute node
def writetext(xml, attr, nil, text):
attr.value = text
anonfuns = cls.gen_anon_basic(attr, spec, readtext, createnode, writetext)
def mergetext(node, attr):
node.setAttributeNode(attr)
return cls.gen_named_comp(attr, spec, anonfuns, mergetext)
def gen_tag_member(cls, tag):
"""generate helper funs for tag member of class"""
spec = getattr(cls, 't_' + tag)
anonfuns = cls.gen_tag(tag, spec)
def mergetext(node, newnode):
print 'mergenode', node, newnode
node.appendChild(newnode)
return cls.gen_named_comp(tag, spec, anonfuns, mergetext)
def gen_tag(cls, tag, spec):
"""generate readers and writers for the tag"""
tag_type = spec[0]
if type(tag_type) is types.TypeType:
def readtext(node, tagpath):
return getNodeText(node, tagpath)
def createnode(xml, tag):
return xml.newNode(tag)
def writetext(xml, node, tagpath, text):
xml.addTextNodeUnder(node, tagpath, text)
return cls.gen_anon_basic(tag, spec, readtext,
createnode, writetext)
elif type(tag_type) is types.ListType:
return cls.gen_list_tag(tag, spec)
elif type(tag_type) is autoxml or type(tag_type) is types.ClassType:
return cls.gen_class_tag(tag, spec)
def gen_named_comp(cls, token, spec, anonfuns, mergetext):
"""generate a named component tag/attr. a decoration of
anonymous functions that do not bind to variable names"""
name = cls.mixed_case(token)
token_type = spec[0]
req = spec[1]
(init_a, decode_a, encode_a, format_a) = anonfuns
def init(self):
"""initialize component"""
setattr(self, name, init_a())
def decode(self, node):
"""decode component from DOM node"""
setattr(self, name, decode_a(node))
def encode(self, xml, node):
"""encode self inside, possibly new, DOM node using xml"""
if hasattr(self, name):
value = getattr(self, name)
else:
value = None
newnode = encode_a(xml, value)
if newnode:
mergetext(node, newnode)
def format(self):
if hasattr(self, name):
value = getattr(self,name)
return '%s: %s\n' % (token, format_a(value))
else:
if req == mandatory:
raise Error('Mandatory variable %s not available' % name)
return ''
return (init, decode, encode, format)
def mixed_case(cls, identifier):
"""helper function to turn token name into mixed case"""
if identifier is "":
return ""
else:
return identifier[0].lower() + identifier[1:]
def tagpath_head_last(cls, tagpath):
"returns split of the tag path into last tag and the rest"
try:
lastsep = tagpath.rindex('/')
except ValueError, e:
return ('', tagpath)
return (tagpath[:lastsep], tagpath[lastsep+1:])
def parse_spec(cls, token, spec):
"""decompose member specification"""
name = cls.mixed_case(token)
token_type = spec[0]
req = spec[1]
if len(spec)>=3:
path = spec[2] # an alternative path specified
else:
path = token # otherwise it's the same name as
# the token
return name, token_type, req, path
def gen_anon_basic(cls, token, spec, readtext, createnode, writetext):
"""Generate a tag or attribute with one of the basic
types like integer. This has got to be pretty generic
so that we can invoke it from the complex types such as Class
and List. The readtext and writetext arguments achieve
the DOM text access for this datatype."""
name, token_type, req, tagpath = cls.parse_spec(token, spec)
def initialize():
"""default value for all basic types is None"""
return None
def decode(node):
"""decode from DOM node, the value, watching the spec"""
text = readtext(node, token)
print 'read text ', text
if text:
try:
value = autoxml.basic_cons_map[token_type](text)
except Error:
raise Error('Type mismatch: read text cannot be decoded')
return value
else:
if req == mandatory:
raise Error('Mandatory token %s not available' % token)
else:
return None
def encode(xml, value):
"""encode given value inside DOM node"""
if value:
node = createnode(xml, token)
writetext(xml, node, token, str(value))
return node
else:
if req == mandatory:
raise Error('Mandatory argument not available')
def format(value):
"""format value for pretty printing"""
return str(value)
return initialize, decode, encode, format
def gen_class_tag(cls, tag, spec):
"""generate a class datatype"""
name, tag_type, req, path = cls.parse_spec(tag, spec)
def make_object():
return tag_type.__new__(tag_type)
def init():
return make_object()
def decode(node):
node = getNode(node, tag)
if node:
try:
obj = make_object()
obj.decode(node)
return obj
except Error:
raise Error('Type mismatch: DOM cannot be decoded')
else:
if req == mandatory:
raise Error('Mandatory argument not available')
else:
return None
def encode(xml, obj):
if obj:
try:
node = obj.encode(xml)
#FIXME: change node's tag?
return
except Error:
raise Error('Object cannot be encoded')
else:
if req == mandatory:
raise Error('Mandatory argument not available')
def format(obj):
return obj.format()
return (init, decode, encode, format)
def gen_list_tag(cls, tag, spec):
"""generate a list datatype. stores comps in tag/comp_tag"""
name, tag_type, req, comp_tag = cls.parse_spec(tag, spec)
#head, last = cls.tagpath_head_last(path)
if len(tag_type) != 1:
raise Error('List type must contain only one element')
x = cls.gen_tag(comp_tag, [tag_type[0], mandatory])
(init_item, decode_item, encode_item, format_item) = x
def init():
return []
def decode(node):
l = []
nodes = getAllNodes(node, tag + '/' + comp_tag)
print node, tag + '/' + comp_tag
print 'F U', nodes
if len(nodes) is 0 and req is mandatory:
raise Error('Mandatory list empty')
for node in nodes:
dummy = node.ownerDocument.createElement("Dummy")
dummy.appendChild(node)
l.append(decode_item(dummy))
return l
def encode(xml, l):
dummy = xml.newNode("Dummy")
if len(l) > 0:
for item in l:
item_node = encode_item(xml, item)
xml.addNodeUnder(dummy, comp_tag, item_node)
return getNode(dummy, "Dummy")
else:
if req is mandatory:
raise Error('Mandatory list empty')
def format(l):
#print 'format:', name
s = ''
for ix in range(len(l)):
s += str(ix+1) + ': ' + format_item(l[ix])
if ix != len(l)-1:
s += ', '
return s
return (init, decode, encode, format)
basic_cons_map = {
types.StringType : str,
types.IntType : int
}
class XmlFile(object):
"""A class to help reading and writing an XML file"""
def __init__(self, rootTag):
self.rootTag = rootTag
self.newDOM()
def newDOM(self):
"""clear DOM"""
impl = mdom.getDOMImplementation()
self.dom = impl.createDocument(None, self.rootTag, None)
def unlink(self):
"""deallocate DOM structure"""
self.dom.unlink()
def readxml(self, fileName):
try:
self.dom = mdom.parse(fileName)
except ExpatError, inst:
raise Error("File '%s' has invalid XML: %s\n" % (fileName,
str(inst)))
def writexml(self, fileName):
f = codecs.open(fileName,'w', "utf-8")
f.write(self.dom.toprettyxml())
f.close()
def verifyRootTag(self):
actual_roottag = self.dom.documentElement.tagName
if actual_roottag != self.rootTag:
raise Error("Root tagname %s not identical to %s as expected " %
(actual_roottag, self.rootTag) )
# construction helpers
def newNode(self, tag):
return self.dom.createElement(tag)
def newTextNode(self, text):
return self.dom.createTextNode(text)
def newAttribute(self, attr):
return self.dom.createAttribute(attr)
# read helpers
def getNode(self, tagPath = ""):
"""returns the *first* matching node for given tag path."""
self.verifyRootTag()
return getNode(self.dom.documentElement, tagPath)
def getNodeText(self, tagPath):
"""returns the text of *first* matching node for given tag path."""
node = self.getNode(tagPath)
if not node:
return None
return getNodeText(node)
def getAllNodes(self, tagPath):
"""returns all nodes matching a given tag path."""
self.verifyRootTag()
return getAllNodes(self.dom.documentElement, tagPath)
def getChildren(self, tagpath):
""" returns the children of the given path"""
node = self.getNode(tagpath)
return node.childNodes
# get only elements of a given type
#FIXME: this doesn't work
def getChildrenWithType(self, tagpath, type):
""" returns the children of the given path, only with given type """
node = self.getNode(tagpath)
return filter(lambda x:x.nodeType == type, node.childNodes)
# get only child elements
def getChildElts(self, tagpath):
""" returns the children of the given path, only with given type """
node = self.getNode(tagpath)
try:
return filter(lambda x:x.nodeType == x.ELEMENT_NODE,
node.childNodes)
except AttributeError:
return None
# write helpers
def addNode(self, tagPath, newnode = None):
"this adds the newnode under given tag path"
self.verifyRootTag()
return addNode(self.dom, self.dom.documentElement, tagPath,
newnode)
def addNodeUnder(self, node, tagPath, newnode = None):
"this adds the new stuff under node and then following tag path"
self.verifyRootTag()
return addNode(self.dom, node, tagPath, newnode)
def addChild(self, newnode):
"add a new child node right under root element document"
self.dom.documentElement.appendChild(newnode)
def addText(self, node, text):
"add text to node"
node.appendChild(self.newTextNode(text))
def addTextNode(self, tagPath, text):
"add a text node with given tag path"
node = self.addNode(tagPath, self.newTextNode(text))
return node
def addTextNodeUnder(self, node, tagPath, text):
"add a text node under given node with tag path (phew)"
return self.addNodeUnder(node, tagPath, self.newTextNode(text))
-52
View File
@@ -1,52 +0,0 @@
#!/usr/bin/env python
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
# Install script for tengis.
#
from distutils.core import setup
PISI_VERSION = "0.1"
def getRevision():
import os
try:
p = os.popen("svn info 2> /dev/null")
for line in p.readlines():
line = line.strip()
if line.startswith("Revision:"):
return line.split(":")[1].strip()
except:
pass
# doesn't working in a Subversion directory
return None
def getVersion():
rev = getRevision()
if rev:
return "-r".join([PISI_VERSION, rev])
else:
return PISI_VERSION
setup(name="pisi",
version= getVersion(),
description="PISI (Packages Installed Successfully as Intended)",
long_description="PISI is the package management system of Pardus Linux.",
license="GNU GPL2",
author="Pardus Developers",
author_email="pisi@uludag.org.tr",
url="http://www.uludag.org.tr/eng/pisi/",
package_dir = {'': ''},
packages = ['pisi', 'pisi.cli', 'pisi.actionsapi'],
scripts = ['pisi-cli']
)
-10
View File
@@ -1,10 +0,0 @@
PISI test suite
---------------
There are python unit tests and shell scripts in this directory.
Shell scripts use the CLIs to perform package operations.
For this there must be a symlink "packages" to the PISI package repository
until we can find a few sample packages to put here.
-23
View File
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<A href="http://www.cs.bilkent.edu.tr/~erayo">
<Name>Eray Ozkural</Name>
<Number>868</Number>
<Description>Lazy Tin</Description>
<Description xml:lang="tr">Tembel Teneke</Description>
<Projects>
<Project>pisi</Project>
<Project>noatun</Project>
<Project>kdevelop</Project>
</Projects>
<OtherInfo>
<BirthDate>18071976</BirthDate>
<Interest>AI</Interest>
<CodesWith>
<Person>Baris</Person>
<Person>Gurer</Person>
<Person>Caglar</Person>
<Person>Meren</Person>
</CodesWith>
</OtherInfo>
</A>
@@ -1,51 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
import unittest
import zipfile
class ActionsAPITestCase(unittest.TestCase):
def setUp(self):
self.f = zipfile.ZipFile("helloworld-0.1-1.pisi", "r")
self.filelist = []
for file in self.f.namelist():
self.filelist.append(file)
def testFileList(self):
fileContent = ["files.xml", \
"install/bin/helloworld", \
"install/opt/PARDUS", \
"install/opt/helloworld/helloworld", \
"install/opt/uludag", \
"install/sbin/helloworld", \
"install/sys/PARDUS", \
"install/sys/uludag", \
"install/usr/bin/goodbye", \
"install/usr/bin/helloworld", \
"install/usr/lib/helloworld.o", \
"install/usr/sbin/goodbye", \
"install/usr/sbin/helloworld", \
"install/usr/share/doc/helloworld-0.1-1/Makefile.am", \
"install/usr/share/doc/helloworld-0.1-1/goodbyeworld.cpp", \
"install/usr/share/info/Makefile.am", \
"install/usr/share/info/Makefile.cvs", \
"install/usr/share/info/Makefile.in", \
"install/var/goodbye", \
"install/var/hello", \
"metadata.xml"]
'''check number of files in package'''
self.assertEqual(fileContent.__len__(), self.filelist.__len__())
'''check file content'''
for file in self.filelist:
self.assert_(fileContent.__contains__(file))
suite = unittest.makeSuite(ActionsAPITestCase)
-116
View File
@@ -1,116 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
from os.path import exists as pathexists
from os.path import basename, islink, join
import pisi.context as ctx
import pisi.api
from pisi import archive
from pisi import sourcearchive
from pisi import fetcher
from pisi import util
from pisi.build import BuildContext
from pisi.config import config
from pisi import uri
class ArchiveFileTestCase(unittest.TestCase):
def setUp(self):
pisi.api.init()
def testUnpackTar(self):
bctx = BuildContext("tests/popt/pspec.xml")
achv = sourcearchive.SourceArchive(bctx)
assert bctx.spec.source.archiveType == "targz"
# skip fetching and directly unpack the previously fetched (by
# fetchertests) archive
if not achv.is_cached(interactive=False):
achv.fetch(interactive=False)
achv.unpack()
targetDir = bctx.pkg_work_dir()
# but testing is hard
# "var/tmp/pisi/popt-1.7-3/work" (targetDir)
assert pathexists(targetDir + "/popt-1.7")
testfile = targetDir + "/popt-1.7/Makefile.am"
assert pathexists(testfile)
# check file integrity
self.assertEqual(util.sha1_file(testfile),
"5af9dd7d754f788cf511c57ce0af3d555fed009d")
def testUnpackZip(self):
bctx = BuildContext("tests/pccts/pspec.xml")
assert bctx.spec.source.archiveType == "zip"
achv = sourcearchive.SourceArchive(bctx)
achv.fetch(interactive=False)
achv.unpack(cleanDir=True)
targetDir = bctx.pkg_work_dir()
assert pathexists(targetDir + "/pccts")
testfile = targetDir + "/pccts/history.txt"
assert pathexists(testfile)
# check file integrity
self.assertEqual(util.sha1_file(testfile),
"f2be0f9783e84e98fe4e2b8201a8f506fcc07a4d")
# TODO: no link file in pccts package. Need to find a ZIP file
# containing a symlink
# check for symbolic links
# testfile = targetDir + "/sandbox/testdir/link1"
# assert islink(testfile)
def testMakeZip(self):
# first unpack our dear sandbox.zip
bctx = BuildContext("tests/pccts/pspec.xml")
targetDir = bctx.pkg_work_dir()
achv = sourcearchive.SourceArchive(bctx)
achv.fetch(interactive=False)
achv.unpack(cleanDir=True)
del achv
newZip = targetDir + "/new.zip"
zip = archive.ArchiveZip(newZip, 'zip', 'w')
sourceDir = targetDir + "/pccts"
zip.add_to_archive(sourceDir)
zip.close()
#TODO: do some more work to test the integrity of new zip file
def testUnpackZipCond(self):
bctx = BuildContext("tests/pccts/pspec.xml")
url = uri.URI(bctx.spec.source.archiveUri)
targetDir = bctx.pkg_work_dir()
filePath = join(config.archives_dir(), url.filename())
# check cached
if util.sha1_file(filePath) != bctx.spec.source.archiveSHA1:
fetch = fetcher.Fetcher(bctx.spec.source.archiveUri, targetDir)
fetch.fetch()
assert bctx.spec.source.archiveType == "zip"
achv = archive.Archive(filePath, bctx.spec.source.archiveType)
achv.unpack_files(["pccts/history.txt"], targetDir)
assert pathexists(targetDir + "/pccts")
testfile = targetDir + "/pccts/history.txt"
assert pathexists(testfile)
suite = unittest.makeSuite(ArchiveFileTestCase)
-20
View File
@@ -1,20 +0,0 @@
#!/bin/sh
pwd
PATH=$PATH:.
set -x
pisi-cli --ignore-comar remove unzip
set -e
pisi-cli --ignore-build-no build tests/zip/pspec.xml tests/unzip/pspec.xml
pisi-cli index .
pisi-cli add-repo repo1 pisi-index.xml
pisi-cli list-repo
pisi-cli update-repo repo1
pisi-cli list-available
pisi-cli --ignore-comar install zip
pisi-cli list-installed
pisi-cli --ignore-comar remove unzip
pisi-cli info zip*.pisi
pisi-cli --ignore-comar install zip*.pisi
pisi-cli list-pending
pisi-cli configure-pending
@@ -1,25 +0,0 @@
#!/bin/sh
export PATH=$PATH:.
set -x # xtrace
set -e # errexit
echo "beta functionality test script for testing remote repos"
echo "working directory:" `pwd`
echo "cleaning destination dir: tmp"
rm -rf tmp
#echo "*** repository tests"
pisi-cli add-repo pardus ftp://ftp.uludag.org.tr/pub/pisi/binary/system/base/pisi-index.xml
pisi-cli update-repo pardus
pisi-cli list-repo
#echo "*** package ops"
pisi-cli list-available
pisi-cli info python
pisi-cli install python
echo "*** database contents"
for x in `find tmp -iname '*.bdb'`; do
echo "contents of database " $x;
tools/cat-db.py $x;
done
@@ -1,23 +0,0 @@
#!/bin/sh
pwd
PATH=$PATH:.
set -x -e
pisi-cli --ignore-build-no build tests/zip/pspec.xml tests/unzip/pspec.xml
pisi-cli --yes-all --ignore-comar install unzip-5.50-1.pisi zip-2.3-1.pisi
mkdir -p myrepo
cd myrepo
../pisi-cli --ignore-build-no build ../tests/zip2/pspec.xml ../tests/unzip2/pspec.xml
cd ..
pisi-cli --absolute-uris index myrepo
pisi-cli remove-repo repo1
pisi-cli add-repo repo1 pisi-index.xml
pisi-cli list-repo
pisi-cli update-repo repo1
pisi-cli list-available
pisi-cli --install-info list-installed
pisi-cli list-upgrades
pisi-cli --ignore-comar upgrade zip
pisi-cli --install-info list-installed
-45
View File
@@ -1,45 +0,0 @@
#!/bin/sh
echo "beta functionality test script"
echo "working directory:" `pwd`
echo "cleaning destination dir: tmp"
PATH=$PATH:.
set -x # xtrace
set -e # errexit
rm -rf tmp
#echo "*** build tests"
pisi-cli build https://svn.uludag.org.tr/pisi/trunk/system/base/zip/pspec.xml \
https://svn.uludag.org.tr/pisi/trunk/system/base/unzip/pspec.xml
#partial-builds
pisi-cli build-setup https://svn.uludag.org.tr/pisi/trunk/system/base/hdparm/pspec.xml
pisi-cli build-build https://svn.uludag.org.tr/pisi/trunk/system/base/hdparm/pspec.xml
pisi-cli build-install https://svn.uludag.org.tr/pisi/trunk/system/base/hdparm/pspec.xml
pisi-cli build-package https://svn.uludag.org.tr/pisi/trunk/system/base/hdparm/pspec.xml
#echo "*** repository tests"
pisi-cli index .
pisi-cli add-repo repo1 pisi-index.xml
pisi-cli update-repo repo1
pisi-cli list-repo
pisi-cli build https://svn.uludag.org.tr/pisi/trunk/system/base/grep/pspec.xml \
https://svn.uludag.org.tr/pisi/trunk/system/base/flex/pspec.xml
#echo "*** package ops"
pisi-cli info *.pisi
# pisi-cli list-available
pisi-cli install --ignore-comar zip
pisi-cli list-installed
pisi-cli remove --ignore-comar unzip
pisi-cli install --ignore-comar zip*.pisi
pisi-cli install --ignore-comar hdparm*.pisi flex*.pisi grep*.pisi
pisi-cli remove-repo repo1
# pisi-cli list-available
echo "*** database contents"
for x in `find tmp -iname '*.bdb'`; do
echo "contents of database " $x;
tools/cat-db.py $x;
done
@@ -1,45 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
from pisi.configfile import ConfigurationFile
class ConfigFileTestCase(unittest.TestCase):
def setUp(self):
self.cf = ConfigurationFile("tests/pisi.conf")
def testSections(self):
cf = self.cf
if not cf.general:
self.fail("No 'general' section found in ConfigurationFile")
if not cf.build:
self.fail("No 'build' section found in ConfigurationFile")
if not cf.dirs:
self.fail("No 'dirs' section found in ConfigurationFile")
def testValues(self):
cf = self.cf
# test values from pisi.conf file
self.assertEqual(cf.general.destinationdirectory, "/testing")
self.assertEqual(cf.dirs.archives_dir, "/disk2/pisi/archives")
# test default values
self.assertEqual(cf.dirs.tmp_dir, "/var/tmp/pisi")
def testAccessMethods(self):
cf = self.cf
self.assertEqual(cf.build.host, cf.build["host"])
self.assertEqual(cf.dirs.index_dir, cf.dirs["index_dir"])
suite = unittest.makeSuite(ConfigFileTestCase)
@@ -1,67 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import pisi.context as ctx
class ContextTestCase(unittest.TestCase):
def testConstness(self):
const = ctx.const
# test if we can get a const attribute?
try:
test = const.package_prefix
self.assertNotEqual(test, "")
except AttributeError:
self.fail("Couldn't get const attribute")
# test binding a new constant
const.test = "test binding"
# test re-binding (which is illegal)
try:
const.test = "test rebinding"
# we shouldn't reach here
self.fail("Rebinding a constant works. Something is wrong!")
except:
# we achived our goal with this error. infact, this is a
# ConstError but we can't catch it directly here
pass
# test unbinding (which is also illegal)
try:
del const.test
# we shouldn't reach here
self.fail("Unbinding a constant works. Something is wrong!")
except:
# we achived our goal with this error. infact, this is a
# ConstError but we can't catch it directly here
pass
def testConstValues(self):
const = ctx.const
constDict = {
"actions_file": "actions.py",
"setup_func": "setup",
"metadata_xml": "metadata.xml"
}
for k in constDict.keys():
if hasattr(const, k):
value = getattr(const, k)
self.assertEqual(value, constDict[k])
else:
self.fail("Constants does not have an attribute named %s" % k)
suite = unittest.makeSuite(ContextTestCase)
@@ -1,38 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
import pisi.context as ctx
import pisi.api
from pisi.specfile import SpecFile
from pisi import fetcher
from pisi import util
from pisi import uri
class FetcherTestCase(unittest.TestCase):
def setUp(self):
pisi.api.init()
self.spec = SpecFile()
self.spec.read("tests/popt/pspec.xml")
self.url = uri.URI(self.spec.source.archiveUri)
self.destpath = ctx.config.archives_dir()
self.fetch = fetcher.Fetcher(self.url, self.destpath)
def testFetch(self):
self.fetch.fetch()
fetchedFile = os.path.join(self.destpath, self.url.filename())
if os.access(fetchedFile, os.R_OK):
self.assertEqual(util.sha1_file(fetchedFile),
self.spec.source.archiveSHA1)
suite = unittest.makeSuite(FetcherTestCase)
-34
View File
@@ -1,34 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
from pisi import graph
from pisi.config import config
class GraphTestCase(unittest.TestCase):
def setUp(self):
self.g0 = graph.Digraph()
self.g0.from_list([ (1,2), (1,3), (2,3), (3,4), (4, 5), (4,1)])
self.g1 = graph.Digraph()
self.g1.from_list([ (0,2), (0,3), (3,4), (2,4), (0,5), (5,4) ])
def testCycle(self):
self.assert_(not self.g0.cycle_free())
self.assert_(self.g1.cycle_free())
def testTopologicalSort(self):
order = self.g1.topological_sort()
self.assertEqual(order[0], 0)
self.assertEqual(order[len(order)-1], 4)
suite = unittest.makeSuite(GraphTestCase)
@@ -1,102 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
from pisi.actionsapi import autotools
from pisi.actionsapi import pisitools
from pisi.actionsapi import shelltools
from pisi.actionsapi import libtools
from pisi.actionsapi import get
WorkDir = "helloworld"
def setup():
autotools.configure()
def build():
autotools.make()
def install():
autotools.install()
'''/opt/helloworld/'''
pisitools.dodir("/opt/helloworld")
'''/usr/share/doc/helloworld-0.1-1/Makefile.am'''
pisitools.dodoc("Makefile.am")
'''/opt/helloworld/helloworld'''
pisitools.doexe("src/helloworld", "/opt/helloworld")
'''/usr/share/info/Makefile.am'''
'''/usr/share/info/Makefile.cvs'''
'''/usr/share/info/Makefile.in'''
pisitools.doinfo("Makefile.*")
'''/usr/lib/helloworld.o'''
pisitools.dolib("src/helloworld.o")
'''/opt/hello'''
pisitools.insinto("/opt/", "src/helloworld", "hello")
'''/opt/hi'''
pisitools.insinto("/opt/", "src/helloworld", "hi")
'''/opt/hello -> /var/hello'''
pisitools.domove("/opt/hello", "/var/")
'''/opt/hi -> /var/goodbye'''
pisitools.domove("/opt/hi", "/var/", "goodbye")
'''/usr/bin/helloworld'''
pisitools.dobin("src/helloworld")
'''/bin/helloworld'''
pisitools.dobin("src/helloworld", "/bin")
'''/usr/sbin/helloworld'''
pisitools.dosbin("src/helloworld")
'''/sbin/helloworld'''
pisitools.dosbin("src/helloworld", "/sbin")
'''Hello, world! -> Goodbye, world!'''
pisitools.dosed("src/helloworld.cpp", "Hello, world!", "Goodbye, world!")
'''/usr/sbin/goodbye --> helloworld'''
pisitools.dosym("helloworld", "/usr/sbin/goodbye")
'''/usr/bin/goodbye --> helloworld'''
pisitools.dosym("helloworld", "/usr/bin/goodbye")
'''/home/pardus/'''
pisitools.dodir("/home/pardus")
'''delete pardus'''
pisitools.removeDir("/home/pardus")
'''delete home'''
pisitools.removeDir("/home")
'''src/helloworld.cpp --> /usr/share/doc/helloworld-0.1-1/goodbyeworld.cpp'''
pisitools.newdoc("src/helloworld.cpp", "goodbyeworld.cpp")
'''/opt/pardus'''
shelltools.touch("%s/opt/pardus" % get.installDIR())
'''/opt/pardus --> /opt/uludag'''
shelltools.copy("%s/opt/pardus" % get.installDIR(), "%s/opt/uludag" % get.installDIR())
'''/opt/pardus --> /opt/Pardus'''
shelltools.move("%s/opt/pardus" % get.installDIR(), "%s/opt/PARDUS" % get.installDIR())
'''/opt/ --> /sys/'''
shelltools.copytree("%s/opt/" % get.installDIR(), "%s/sys/" % get.installDIR())
'''delete /sys/helloworld/helloworld'''
shelltools.unlink("%s/sys/helloworld/helloworld" % get.installDIR())
'''delete /sys/helloworld'''
shelltools.unlinkDir("%s/sys/helloworld" % get.installDIR())
'''generate /usr/lib/helloworld.o'''
libtools.gen_usr_ldscript("helloworld.o")
@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE PISI SYSTEM "http://www.uludag.org.tr/projeler/pisi/pisi-spec.dtd">
<PISI>
<Source>
<Name>helloworld</Name>
<Homepage>http://www.uludag.org.tr</Homepage>
<Packager>
<Name>S.Çağlar Onur</Name>
<Email>caglar@uludag.org.tr</Email>
</Packager>
<License>GPL-2</License>
<IsA>category</IsA>
<PartOf>component</PartOf>
<Summary xml:lang="en">Dummy HelloWorld for testing ActionsAPI</Summary>
<Description xml:lang="en">Dummy HelloWorld for testing ActionsAPI</Description>
<Archive type="targz" sha1sum="6242681ee0bceb820eb6e8544ad1bb3d0ba3ee78">http://cekirdek.uludag.org.tr/~caglar/helloworld.tar.gz</Archive>
<History>
<Update>
<Date>2005-08-21</Date>
<Version>0.1</Version>
<Release>1</Release>
</Update>
</History>
</Source>
<Package>
<Name>helloworld</Name>
<Files>
<Path fileType="binary">/</Path>
</Files>
</Package>
</PISI>
@@ -1,41 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
import pisi.context as ctx
import pisi.api
import pisi.installdb
from pisi import util
class InstallDBTestCase(unittest.TestCase):
def setUp(self):
pisi.api.init()
self.installdb = ctx.installdb
def testRemoveDummy(self):
self.installdb.remove('installtest')
self.assert_(not self.installdb.is_installed('installtest'))
def testInstall(self):
self.installdb.purge('installtest')
self.installdb.install('installtest', '0.1', '2', '3')
def testRemovePurge(self):
self.installdb.install('installtest', '0.1', '2', '3')
self.assert_(self.installdb.is_installed('installtest'))
self.installdb.remove('installtest')
self.assert_(self.installdb.is_removed('installtest'))
self.installdb.purge('installtest')
self.assert_(not self.installdb.is_recorded('installtest'))
suite = unittest.makeSuite(InstallDBTestCase)
@@ -1,43 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
from pisi import metadata
from pisi import util
from pisi.config import config
class MetaDataTestCase(unittest.TestCase):
def setUp(self):
pass
def testRead(self):
md = metadata.MetaData()
md.read('tests/popt/metadata.xml')
self.assertEqual(md.package.license, ["As-Is"])
self.assertEqual(md.package.version, "1.7")
self.assertEqual(md.package.installedSize, 149691)
return md
def testWrite(self):
md = self.testRead()
md.write(os.path.join(config.tmp_dir(),'metadata-test.xml' ))
def testVerify(self):
md = self.testRead()
if md.has_errors():
self.fail("Couldn't verify!")
suite = unittest.makeSuite(MetaDataTestCase)
@@ -1,43 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
import pisi.context as ctx
import pisi.api
from pisi.packagedb import PackageDB
from pisi import util
from pisi.specfile import SpecFile
class PackageDBTestCase(unittest.TestCase):
def setUp(self):
# setUp will be called for each test individually
pisi.api.init()
self.spec = SpecFile()
self.spec.read('tests/popt/pspec.xml')
self.pdb = PackageDB('testdb')
def testAdd(self):
self.pdb.add_package(self.spec.packages[0])
self.assert_(self.pdb.has_package('popt-libs'))
# close the database and remove lock
del self.pdb
def testRemove(self):
self.pdb.remove_package('popt-libs')
self.assert_(not self.pdb.has_package('popt-libs'))
del self.pdb
suite = unittest.makeSuite(PackageDBTestCase)
@@ -1,49 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
from pisi import util
from pisi.config import config
from pisi import package
class PackageTestCase(unittest.TestCase):
def setUp(self):
self.pkgName = util.package_name("testing",
"5.1",
"2")
def testAddExtract(self):
cur = os.getcwd()
tmpdir = config.tmp_dir()
testdir = os.path.join(cur, "tests/popt")
pkg_path = os.path.join(tmpdir, self.pkgName)
pkg = package.Package(pkg_path, "w")
os.chdir(testdir)
pkg.add_to_package("files.xml")
pkg.add_to_package("metadata.xml")
os.chdir(cur)
pkg.close()
pkg = package.Package(pkg_path)
pkg.extract_file("files.xml", cur)
if not os.path.exists("files.xml"):
self.fail("Package extract error")
os.remove("files.xml")
os.remove(pkg_path)
suite = unittest.makeSuite(PackageTestCase)
@@ -1,53 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
# Timu EREN <selamtux@gmail.com>
from pisi.actionsapi import autotools
from pisi.actionsapi import get
from pisi.actionsapi import pisitools
from pisi.actionsapi import shelltools
WorkDir = "pccts"
def setup():
shelltools.export("COPT", get.CFLAGS())
def build():
# autotools.make("COPT=%s" % (get.CFLAGS()))
autotools.make()
def install():
#autotools.install("")
pisitools.dobin("bin/antlr")
pisitools.dobin("bin/dlg")
pisitools.dobin("bin/genmk")
pisitools.dobin("bin/sor")
pisitools.insinto("/usr/include/pccts","h/*.h")
pisitools.insinto("/usr/include/pccts","h/*.c")
pisitools.insinto("/usr/include/pccts","h/*.cpp")
pisitools.insinto("/usr/include/pccts/sorcerer","sorcerer/h/*.h")
pisitools.insinto("/usr/include/pccts/sorcerer","sorcerer/h/*.c")
pisitools.insinto("/usr/include/pccts/sorcerer","sorcerer/h/*.cpp")
pisitools.insinto("/usr/include/pccts/sorcerer/lib","sorcerer/lib/*.h")
pisitools.insinto("/usr/include/pccts/sorcerer/lib","sorcerer/lib/*.c")
pisitools.insinto("/usr/include/pccts/sorcerer/lib","sorcerer/lib/*.cpp")
pisitools.dodoc("CHANGES*", "KNOWN_PROBLEMS*", "README", "RIGHTS", "history.txt", "history.ps")
pisitools.dodoc("sorcerer/README", "sorcerer/UPDATES")
pisitools.doman("dlg/dlg.1", "antlr/antlr.1")
@@ -1,69 +0,0 @@
--- pccts-1.33.33/support/genmk/genmk.c Fri Aug 3 17:12:51 2001
+++ pccts-1.33.33/support/genmk/genmk-gentoo.c Fri Aug 3 17:12:14 2001
@@ -7,6 +7,11 @@
* U of MN
*/
+/* modified 20010803 by Peter Kadau
+ * for better fhs-compliance
+ * i.e. from "none" to "hmmm soso" ;-)
+ */
+
#include <stdio.h>
#include <string.h>
#include "pcctscfg.h" /* be sensitive to what ANTLR/DLG call the files */
@@ -65,7 +70,7 @@
static int nondef_comp = 0; /* 1=compiler is non default */
static char *compilerCCC="CC";
static char *compilerCC="cc";
-static char *pccts_path="/usr/local/pccts";
+static char *pccts_path="/usr/include/pccts";
#ifdef __STDC__
void help(void);
@@ -356,7 +361,7 @@
{ "-cfiles",1,pCFiles, "Additional files in C or C++ to compile"},
{ "-sor",0,pSor, "Start of sorcerer group"},
{ "-pccts_path",1,ppccts_path,
- "Path for $PCCTS directory (default is /usr/local/pccts)"},
+ "Path for $PCCTS directory (default is /usr/include/pccts)"},
{ "-compiler",1,pCompiler,
"Default compiler (default is CC/cc)"},
{ "*", 0,pFile, "" }, /* anything else is a file */
@@ -495,13 +500,13 @@
else printf("SCAN = %s%s\n", DIR(), dlg_class);
printf("PCCTS = %s\n",pccts_path);
- printf("ANTLR_H = $(PCCTS)%sh\n", DirectorySymbol);
+ printf("ANTLR_H = $(PCCTS)\n");
if (num_sors>0) {
- printf("SOR_H = $(PCCTS)%ssorcerer%sh\n", DirectorySymbol, DirectorySymbol);
+ printf("SOR_H = $(PCCTS)%ssorcerer\n", DirectorySymbol);
printf("SOR_LIB = $(PCCTS)%ssorcerer%slib\n",
DirectorySymbol, DirectorySymbol);
}
- printf("BIN = $(PCCTS)%sbin\n", DirectorySymbol);
+ printf("BIN = %susr%sbin\n", DirectorySymbol, DirectorySymbol);
printf("ANTLR = $(BIN)%santlr\n", DirectorySymbol);
printf("DLG = $(BIN)%sdlg\n", DirectorySymbol);
if (num_sors>0) printf("SOR = $(BIN)%ssor\n", DirectorySymbol);
--- pccts-1.33.33/sorcerer/lib/sorlist.c 1999-06-30 03:15:56.000000000 +0200
+++ pccts-1.33.33/sorcerer/lib/sorlist.c.new 2003-05-23 11:11:09.000000000 +0200
@@ -28,6 +28,7 @@
*/
#include <stdio.h>
#include <setjmp.h>
+#include "pcctscfg.h"
#ifdef PCCTS_USE_STDARG
#include <stdarg.h>
--- pccts-1.33.33/sorcerer/lib/sintstack.c 1999-06-30 15:08:06.000000000 +0200
+++ pccts-1.33.33/sorcerer/lib/sintstack.c.new 2003-05-23 12:54:26.000000000 +0200
@@ -28,6 +28,7 @@
*/
#include <stdio.h>
#include <setjmp.h>
+#include "pcctscfg.h"
#ifdef PCCTS_USE_STDARG
#include <stdarg.h>
@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE PISI SYSTEM "http://www.uludag.org.tr/projeler/pisi/pisi-spec.dtd">
<PISI>
<Source>
<Name>pccts</Name>
<Homepage>http://www.polhode.com</Homepage>
<Packager>
<Name>Timu EREN</Name>
<Email>selamtux@gmail.com</Email>
</Packager>
<License>BSD</License>
<IsA>category</IsA>
<PartOf>component</PartOf>
<Summary xml:lang="en">Purdue Compiler Construction Tool Set is an embedded C/C++ parser generator</Summary>
<Description xml:lang="en">Purdue Compiler Construction Tool Set is an embedded C/C++ parser generator</Description>
<Archive type="zip" sha1sum="5b3417efd5f537434b568114bcda853b4975d851">http://www.polhode.com/pccts133mr33.zip</Archive>
<Patches>
<Patch level="1">pccts-1.33.33-gentoo.diff</Patch>
</Patches>
<BuildDependencies>
<Dependency>unzip</Dependency>
<Dependency>patch</Dependency>
</BuildDependencies>
<History>
<Update>
<Date>2005-09-16</Date>
<Version>1.33.33</Version>
<Release>1</Release>
</Update>
</History>
</Source>
<Package>
<Name>pccts</Name>
<Files>
<Path fileType="header">/usr/include</Path>
<Path fileType="doc">/usr/share/doc</Path>
<Path fileType="executable">/usr/bin</Path>
<Path fileType="man">/usr/share/man</Path>
</Files>
</Package>
</PISI>
-6
View File
@@ -1,6 +0,0 @@
[general]
destinationdirectory = /testing
[directories]
archives_dir = /disk2/pisi/archives
@@ -1,25 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
from pisi.actionsapi import autotools
WorkDir='popt-1.7'
def setup():
autotools.configure( '--with-nls' )
def build():
autotools.make()
def install():
autotools.install()
-507
View File
@@ -1,507 +0,0 @@
<?xml version="1.0" ?>
<Files>
<File>
<Path>
usr/share/locale/es/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1593
</Size>
<SHA1Sum>
29481dbd4051e5c6a0f000436664ba00e47572ae
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/de/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/is/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1793
</Size>
<SHA1Sum>
edbcbb430b122626216ea9f6bba268d5de8454b6
</SHA1Sum>
</File>
<File>
<Path>
usr/lib/libpopt.la
</Path>
<Type>
sharedLib
</Type>
<Size>
699
</Size>
<SHA1Sum>
04bac6fce89f2c84d4bb1c5adced729f7d312980
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/sl/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
514
</Size>
<SHA1Sum>
2031bdefffcf57121e46f3f68f0747fe6b7f1fcc
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/fr/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/it/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/eu_ES/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/da/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1599
</Size>
<SHA1Sum>
3ae14880a8bc2cddd9dd0a03861a55d663ac8b0d
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/ko/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1916
</Size>
<SHA1Sum>
2079233b9e3284c866e5d17e5aca001f678d4c23
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/ja/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/pt/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1870
</Size>
<SHA1Sum>
7db5d457fa3cc169fea2f747f25ba0353ed5fb69
</SHA1Sum>
</File>
<File>
<Path>
usr/lib/libpopt.so
</Path>
<Type>
sharedLib
</Type>
<Size>
38532
</Size>
<SHA1Sum>
617c2afa4e79faee954cb95715470f875c044e5a
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/no/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1800
</Size>
<SHA1Sum>
b33d41a1fbde6b879f0cce06cf2d8395012cc0ec
</SHA1Sum>
</File>
<File>
<Path>
usr/lib/libpopt.a
</Path>
<Type>
sharedLib
</Type>
<Size>
36100
</Size>
<SHA1Sum>
f067421ebdb9a68f89c90526feb64a70763c95cf
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/wa/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
517
</Size>
<SHA1Sum>
92f1f582ae24dbf5631fee1ace8bfc99cb5c1b66
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/tr/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1601
</Size>
<SHA1Sum>
16e3e8e12af497102c75ccbb52edf8d1783545c3
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/zh/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/id/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/ro/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1150
</Size>
<SHA1Sum>
914729e4200d68e5c55d114e6a083c74e692707b
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/sr/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/hu/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
496
</Size>
<SHA1Sum>
236bf8c1fea44a5a93c6e18e0c88b3dae1762264
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/pt_BR/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/sv/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1844
</Size>
<SHA1Sum>
63517df43bd74c84496441d8894f2b67533c6060
</SHA1Sum>
</File>
<File>
<Path>
usr/lib/libpopt.so.0.0.0
</Path>
<Type>
sharedLib
</Type>
<Size>
38532
</Size>
<SHA1Sum>
1f2d3c41ba8e4d6b1c4979225cdf2dd97d4a0aea
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/ru/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1955
</Size>
<SHA1Sum>
4742785bd5235eb437922f76a9faa30ec314d09b
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/zh_CN.GB2312/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
468
</Size>
<SHA1Sum>
5e0a688794619278a452c851a3fc86b50b7f781e
</SHA1Sum>
</File>
<File>
<Path>
usr/lib/libpopt.so.0
</Path>
<Type>
sharedLib
</Type>
<Size>
38532
</Size>
<SHA1Sum>
617c2afa4e79faee954cb95715470f875c044e5a
</SHA1Sum>
</File>
<File>
<Path>
usr/include/popt.h
</Path>
<Type>
header
</Type>
<Size>
15982
</Size>
<SHA1Sum>
091692391fd1c539b19298f30e8ae074e3210459
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/sk/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
510
</Size>
<SHA1Sum>
f7e081a22577eb5429809b7ce999b8b1e2b1f9b3
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/pl/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/uk/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
504
</Size>
<SHA1Sum>
f91c695161926679401201fdaf3edcef4664f6ca
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/cs/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1806
</Size>
<SHA1Sum>
920f5b99199361f1d169430bf13d2bfac1a02fab
</SHA1Sum>
</File>
<File>
<Path>
usr/share/man/man3/popt.3
</Path>
<Type>
doc
</Type>
<Size>
31011
</Size>
<SHA1Sum>
5c0014442b4ef38d71733c952884573071978328
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/gl/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
1636
</Size>
<SHA1Sum>
8486430a6ecbb006b5d374cbcb109e8303c7d5f8
</SHA1Sum>
</File>
<File>
<Path>
usr/share/locale/fi/LC_MESSAGES/popt.mo
</Path>
<Type>
localedata
</Type>
<Size>
345
</Size>
<SHA1Sum>
6ceb513b02af4f612a20b49e5d615c158fdcee31
</SHA1Sum>
</File>
</Files>
@@ -1,108 +0,0 @@
<?xml version="1.0" ?>
<PISI>
<Source>
<Name>
popt
</Name>
<Packager>
<Name>
Kırmızı kafalar
</Name>
<Email>
hotmail@redhat.com
</Email>
</Packager>
</Source>
<Package>
<Name>
popt-libs
</Name>
<Summary>
Command line option parsing library
</Summary>
<Description>
library files for popt
</Description>
<License>
As-Is
</License>
<IsA>
library:util:optparser
</IsA>
<PartOf>
rpm:archive
</PartOf>
<RuntimeDependencies>
<Dependency>
gettext
</Dependency>
</RuntimeDependencies>
<Files>
<Path fileType="sharedLib">
/usr/lib
</Path>
<Path fileType="doc">
/usr/share/doc
</Path>
<Path fileType="doc">
/usr/share/man
</Path>
<Path fileType="localedata">
/usr/share/locale
</Path>
<Path fileType="header">
/usr/include/popt.h
</Path>
</Files>
<History>
<Update>
<Date>
06/14/2005
</Date>
<Version>
1.7
</Version>
<Release>
3
</Release>
</Update>
<Update>
<Date>
06/10/2005
</Date>
<Version>
1.7
</Version>
<Release>
2
</Release>
</Update>
<Update>
<Date>
05/05/2005
</Date>
<Version>
1.7
</Version>
<Release>
1
</Release>
</Update>
</History>
<Build>
0
</Build>
<Distribution>
Pardus
</Distribution>
<DistributionRelease>
0.1
</DistributionRelease>
<Architecture>
Any
</Architecture>
<InstalledSize>
149691
</InstalledSize>
</Package>
</PISI>
-80
View File
@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE PSPEC SYSTEM
"http://www.uludag.org.tr/projeler/pisi/pisi-spec.dtd">
<PISI>
<Source>
<Name>popt</Name>
<Homepage>http://www.rpm.org/</Homepage>
<Packager>
<Name>Kırmızı kafalar</Name>
<Email>hotmail@redhat.com</Email>
</Packager>
<License>As-Is</License>
<IsA>library:util:optparser</IsA>
<PartOf>rpm:archive</PartOf>
<Summary>Popt command line option parser</Summary>
<Description>Command line option parsing library.
While it is similiar to getopt(3), it contains a number of enhancements, including:
1) popt is fully reentrant
2) popt can parse arbitrary argv[] style arrays while
getopt(2) makes this quite difficult
3) popt allows users to alias command line arguments
4) popt provides convience functions for parsing strings
into argv[] style arrays
</Description>
<Archive type="targz" sha1sum="66f3c77b87a160951b180447f4a6dce68ad2f71b">
ftp://ftp.rpm.org/pub/rpm/dist/rpm-4.1.x/popt-1.7.tar.gz
</Archive>
<Patches>
<Patch compressionType="gz" level="1">popt-1.7-uclibc.patch.gz</Patch>
</Patches>
<BuildDependencies>
<Dependency versionFrom="1.8"> make </Dependency>
</BuildDependencies>
<History>
<Update>
<Date>06/14/2005</Date>
<Version>1.7</Version>
<Release>3</Release>
</Update>
<Update>
<Date>06/10/2005</Date>
<Version>1.7</Version>
<Release>2</Release>
</Update>
<Update>
<Date>05/05/2005</Date>
<Version>1.7</Version>
<Release>1</Release>
</Update>
</History>
</Source>
<Package>
<Name>popt-libs</Name>
<Summary xml:lang="en">Command line option parsing library</Summary>
<Summary xml:lang="tr">Komut satırı seçenekleri işleme kütüphanesi</Summary>
<RuntimeDependencies>
<Dependency>gettext</Dependency>
</RuntimeDependencies>
<Description>library files for popt</Description>
<Files>
<Path fileType="sharedLib">/usr/lib</Path>
<Path fileType="doc">/usr/share/doc</Path>
<Path fileType="doc">/usr/share/man</Path>
<Path fileType="localedata">/usr/share/locale</Path>
<Path fileType="header">/usr/include/popt.h</Path>
</Files>
<History>
<Update>
<Date>06/14/2005</Date>
<Version>1.7</Version>
<Release>2</Release>
</Update>
</History>
</Package>
</PISI>
-71
View File
@@ -1,71 +0,0 @@
#!/usr/bin/python
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import sys
import os
sys.path.append('.')
sys.path.append('..')
runTestSuite = lambda(x): unittest.TextTestRunner(verbosity=2).run(x)
def run_all():
import utiltests
import xmlfiletests
import specfiletests
import metadatatests
import constantstests
import fetchertests
import archivetests
import installdbtests
import sourcedbtests
import packagedbtests
import actionsapitests
import graphtests
import versiontests
import configfiletests
import packagetests
alltests = unittest.TestSuite((
utiltests.suite,
xmlfiletests.suite,
specfiletests.suite,
metadatatests.suite,
constantstests.suite,
fetchertests.suite,
archivetests.suite,
installdbtests.suite,
sourcedbtests.suite,
packagedbtests.suite,
# FIXME: actionsapitests requires tester to run a specific command first.
# actionsapitests.suite,
graphtests.suite,
versiontests.suite,
configfiletests.suite,
packagetests.suite
))
runTestSuite(alltests)
if __name__ == "__main__":
args = sys.argv
if len(args) > 1: # run modules given from the command line
tests = sys.argv[1:]
for test in tests:
module = __import__(test + 'tests')
print "\nRunning tests in '%s'...\n" % (test)
runTestSuite(module.suite)
else: # run all tests
print "\nRunning all tests in order...\n"
run_all()
@@ -1,38 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
import pisi.context as ctx
import pisi.api
import pisi.sourcedb
from pisi import util
from pisi.specfile import SpecFile
class SourceDBTestCase(unittest.TestCase):
def setUp(self):
pisi.api.init()
self.sourcedb = pisi.sourcedb.init()
self.spec = SpecFile()
self.spec.read("tests/popt/pspec.xml")
def testAdd(self):
self.sourcedb.add_source(self.spec.source)
self.assert_(self.sourcedb.has_source("popt"))
def testRemove(self):
self.testAdd()
self.sourcedb.remove_source("popt")
self.assert_(not self.sourcedb.has_source("popt"))
suite = unittest.makeSuite(SourceDBTestCase)
@@ -1,80 +0,0 @@
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import unittest
import os
from pisi import specfile
from pisi.config import config
import pisi.util as util
class SpecFileTestCase(unittest.TestCase):
def setUp(self):
self.spec = specfile.SpecFile()
self.spec.read("tests/popt/pspec.xml")
def testReadSpec(self):
self.assertEqual(self.spec.source.name, "popt")
self.assertEqual(self.spec.source.version, "1.7")
self.assertEqual(self.spec.source.release, "3")
self.assertEqual(self.spec.source.archiveSHA1,
"66f3c77b87a160951b180447f4a6dce68ad2f71b")
patches = self.spec.source.patches
self.assertEqual(len(patches), 1)
patch = patches[0] #get first and the only patch
self.assertEqual(patch.filename, "popt-1.7-uclibc.patch.gz")
self.assertEqual(patch.compressionType, "gz")
packages = self.spec.packages
self.assertEqual(len(packages), 1)
package = packages[0] # get the first and the only package
self.assertEqual(package.name, "popt-libs")
# search for a path in package.paths
pn = "/usr/lib"
matched = [p for p in package.paths if p.pathname == pn]
if not matched:
self.fail("Failed to match pathname: %s" %pn)
def testIsAPartOf(self):
# test existence in Source
if not "library:util:optparser" in self.spec.source.isa:
self.fail("Failed to match IsA in Source")
if not isinstance(self.spec.source.isa, list):
self.fail("source.isa is not a list, but it must be...")
if "rpm:archive" != self.spec.source.partof:
self.fail("Failed to match PartOf in Source")
# test existence in Package
pkg = self.spec.packages[0]
if not "library:util:optparser" in pkg.isa:
self.fail("Failed to match IsA in Package")
if not isinstance(pkg.isa, list):
self.fail("source.isa is not a list, but it must be...")
if "rpm:archive" != pkg.partof:
self.fail("Failed to match PartOf in Package")
def testVerify(self):
if self.spec.has_errors():
self.fail("Failed to verify specfile")
def testCopy(self):
util.check_dir(config.tmp_dir())
self.spec.read("tests/popt/pspec.xml")
self.spec.write(os.path.join(config.tmp_dir(), 'popt-copy.pspec.xml'))
suite = unittest.makeSuite(SpecFileTestCase)
@@ -1,35 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
from pisi.actionsapi import autotools
from pisi.actionsapi import get
from pisi.actionsapi import pisitools
def setup():
pisitools.dosed("unix/Makefile", "-O3", get.CFLAGS())
pisitools.dosed("unix/Makefile", "CC=gcc LD=gcc", "CC=${CC:-gcc} LD=${CC:-gcc}")
pisitools.dosed("unix/Makefile", "-O ", get.CFLAGS())
pass
def build():
autotools.make("-f unix/Makefile linux")
def install():
pisitools.insinto("/usr/bin/", "unzip")
pisitools.insinto("/usr/bin/", "funzip")
pisitools.insinto("/usr/bin/", "unzipsfx")
pisitools.insinto("/usr/bin/", "unix/zipgrep")
pisitools.dosym("/usr/bin/unzip", "/usr/bin/zipinfo")
pisitools.doman("man/*.1")
pisitools.dodoc("BUGS", "History*", "README", "ToDo", "WHERE")
@@ -1,85 +0,0 @@
Only in unzip-5.50-lhh/: cscope.files
Only in unzip-5.50-lhh/: cscope.out
diff -ur unzip-5.50/unix/unix.c unzip-5.50-lhh/unix/unix.c
--- unzip-5.50/unix/unix.c 2002-01-21 17:54:42.000000000 -0500
+++ unzip-5.50-lhh/unix/unix.c 2003-06-11 18:35:38.000000000 -0400
@@ -421,7 +421,8 @@
*/
{
char pathcomp[FILNAMSIZ]; /* path-component buffer */
- char *pp, *cp=(char *)NULL; /* character pointers */
+ char *pp, *cp=(char *)NULL, /* character pointers */
+ *dp=(char *)NULL;
char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
#ifdef ACORN_FTYPE_NFS
char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */
@@ -429,6 +430,7 @@
#endif
int quote = FALSE; /* flags */
int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
+ int snarf_ddot = FALSE; /* Is set while scanning for "../" */
int error = MPN_OK;
register unsigned workch; /* hold the character being tested */
@@ -467,6 +469,9 @@
while ((workch = (uch)*cp++) != 0) {
if (quote) { /* if character quoted, */
+ if ((pp == pathcomp) && (workch == '.'))
+ /* Oh no you don't... */
+ goto ddot_hack;
*pp++ = (char)workch; /* include it literally */
quote = FALSE;
} else
@@ -481,15 +486,44 @@
break;
case '.':
- if (pp == pathcomp) { /* nothing appended yet... */
+ if (pp == pathcomp) {
+ddot_hack:
+ /* nothing appended yet... */
if (*cp == '/') { /* don't bother appending "./" to */
++cp; /* the path: skip behind the '/' */
break;
- } else if (!uO.ddotflag && *cp == '.' && cp[1] == '/') {
- /* "../" dir traversal detected */
- cp += 2; /* skip over behind the '/' */
- killed_ddot = TRUE; /* set "show message" flag */
- break;
+ } else if (!uO.ddotflag) {
+
+ /*
+ * SECURITY: Skip past control characters if the user
+ * didn't OK use of absolute pathnames. lhh - this is
+ * a very quick, ugly, inefficient fix.
+ */
+ dp = cp;
+ do {
+ workch = (uch)(*dp);
+ if (workch == '/' && snarf_ddot) {
+ /* "../" dir traversal detected */
+ cp = dp + 1; /* skip past the '/' */
+ killed_ddot = TRUE; /* set "show msg" flag */
+ break;
+ } else if (workch == '.' && !snarf_ddot) {
+ snarf_ddot = TRUE;
+ } else if (isprint(workch) ||
+ ((workch > 127) && (workch <= 254))) {
+ /*
+ * Since we found a printable, non-ctrl char,
+ * we can stop looking for '../', the amount
+ * in ../!
+ */
+ break;
+ }
+
+ dp++;
+ } while (*dp != 0);
+
+ if (killed_ddot)
+ break;
}
}
*pp++ = '.';
Only in unzip-5.50-lhh/unix: .unix.c.swp

Some files were not shown because too many files have changed in this diff Show More