Re: SQL Patch Version 2
Hunter Matthews <[email protected]>
| Newsgroups | gmane.network.up2date.current.devel |
|---|---|
| Message-ID | <1013537255.8851.108.camel@jade> |
On Mon, 2002-02-11 at 20:20, Toby D. Reeves wrote: > Hunter, > > Here is the latest patch for a SQL backend. Toby, a little of this is structure, but most is style, and issues that Current didn't have to deal with before. All, I've reviewed the patch that Toby sent in, and made a number of comments. Some of them are only interesting to Toby and others doing SQL work, but some are style issues - The rules I've marked in Toby's code will be REQUIRED of any and all future patches. If you're thinking about contributing, you want to go through this and see what the rules are. One thing I left out was the 80 column rule - the code goes past it in a couple of places, and esp in patch form, I see why so many projects have a 75 column rule. If you can, keep lines below 76 columns, but 80 is the absolute max. (Yes, I violate it in spots, I'll work on that). Why so hard code on style, even for new files? Several people have remarked they thought the code was "pretty" or well structured and easy to deal with, and I'd like to keep that. Also, the way Toby created the tables initially went pretty far to documenting what everything was. If I could get people to add a couple lines about what tables are and what the columns _mean_, that would be the rest of it. Any other database patches will want to reuse, as much as reasonably possible, the table and column names in this patch. If you really think something should change, you'll definately have to document why. -- Hunter Matthews Unix / Network Administrator Office: BioScience 145/244 Duke Univ. Biology Department Key: F0F88438 / FFB5 34C0 B350 99A4 BB02 9779 A5DB 8B09 F0F8 8438 Never take candy from strangers. Especially on the internet.
current-0.9.4-sql-2.reply
(text/x-patch, 28 KB)
diff -ruNp1 current-0.9.4/CurrentDB.py current-dev/CurrentDB.py
--- current-0.9.4/CurrentDB.py Wed Dec 31 19:00:00 1969
+++ current-dev/CurrentDB.py Mon Feb 11 14:34:26 2002
Uh, packagedb.py/channel.py was an attempt to abstract the relationship
between "the entire collection of rpms and channels that Current knows about"
and "a particular collection of rpms stored in a particular way"
Not having read the rest of the patch, does CurrentDB.py replace BOTH, or
just channel.py?
+_rpm_orphan_sql_statement = """\
+SELECT rpm.rpm_id FROM rpm LEFT JOIN channel_rpm
+ON rpm.rpm_id = channel_rpm.rpm_id
+WHERE channel_rpm.rpm_id IS NULL
+"""
Style complaint: please put the sql at the point you use it - this appears
to only be used once.
+
+#TODO: Might want to move these to misc
+import packagedb
+getCanonArch = packagedb._getCannonArch
+getCompatibleArchs = packagedb._getCompatibleArchs
+scoreArch = packagedb._scoreArch
+compareArchs = packagedb._compareArchs
+del packagedb
This implies that you "replace" packagedb. Would it be possible to make
packagedb truly "portable" between the shelve backend and the sql backend?
Since you suck those functions in, the answer might be "No", which means we'll
move those functions to some other location, so that you don't import
packagedb at all.
+def _centerColumns(items, sep= ' '):
What would people think about the rule "Put private functions at the
end of the module/class"?
+class CurrentDB:
+ """
+ This object manages all channels in the database.
+ """
This looks like you replaced packagedb.py - in that case, we should rename it.
Hmm.....
+ def __init__(self):
+ self.db_name = config.cfg.getItem('db_name')
+ self.db_host = config.cfg.getItem('db_host')
+ self.db_user = config.cfg.getItem('db_user')
+ self.db_password = config.cfg.getItem('db_password')
+ self.dbc=None
The abysmal programming in config.py comes back to haunt me. Sigh.
+ def _connect(self):
+ if self.dbc : return
Absolutely NOT. No patch will be accepted that does this. ':' effectively
ends a line. Fitting everything on one line like that, to me, is a perlism.
if self.dbc:
return
+ r = ''
longer variable names, please. "tmp" or "temp" would be fine here.
spaces between operators and their operands, please.
IE, c=self.... is out, cursor = self.... is in.
+ if channel_id:
+ channel_id = self._getChannelId(channel_id)
+ c=self.dbc.cursor()
cursor = self.dbc.cursor()
+ def _getChannelId(self, channel):
+ """
+ If 'channel' is a String:
+ Get channel_id where channel.name = 'channel'.
+ If that fails, try channel.label = 'channel'.
+
+ If 'channel' is an Int:
+ Return channel_id if successful or None if not successful.
Inside the database, always use the channel label, consistently. The "name"
is just some text for human consumption. The awful config.py kind of mangles
this a little bit, but there's no reason to let that disease spread.
Please seperate the concept of the label and the int used internally. This
one function should not accept both the label string and the int - if you
really need both, write two accessor functions.
+ """
+ c=self.dbc.cursor()
+ if type(channel) is types.StringType:
+ c=self.dbc.cursor()
+ c.execute("""SELECT channel_id FROM channel WHERE name = %s""", (channel,))
+ if c.rowcount : return c.fetchone()[0]
+ c.execute("""SELECT channel_id FROM channel WHERE label = %s""", (channel,))
+ if c.rowcount : return c.fetchone()[0]
+ else:
+ c.execute("""SELECT channel_id FROM channel WHERE channel_id = %d""", (channel,))
+ if c.rowcount : return channel
+ def addRpm(self, pathname, file=None):
+ if file : pathname = os.path.join(pathname,file)
+ else : x,file=os.path.split(pathname)
if file:
stuff
else:
other stuff. spaces after ,
+ c.execute("""INSERT INTO rpm (path, name, version, release, epoch, arch, arch_canon, size, is_src, hash)
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %d, %d, hashbpchar(%s))""",
+ [ pathname,
+ hdr[rpm.RPMTAG_NAME],
+ hdr[rpm.RPMTAG_VERSION],
+ hdr[rpm.RPMTAG_RELEASE],
+ epoch,
+ arch,
+ arch_canon,
+ rpm_size,
+ isSource,
+ file] )
I'm bitching about style in other places, but I like the way you did this
query. Whats hashbpchar()?
+ assert rpm_id != None
Not your fault - it was in the shelve implementation, but someone has
correctly pointed out that a daemon (like Current) cannot just throw
random assertions. If you want, leave this in for now, and when I figure
out what the right thing to do in the shelve implementation is, we can use
the same idea here.
+ log('\t %d files' % len(files), VERBOSE)
+ for f in files:
+ c.execute("""INSERT INTO file (rpm_id, path, hash)
+ VALUES (%d, %s, hashbpchar(%s) )""",
+ [ rpm_id, f, f] )
Either one space (I like that less, Guido hates it) before and after [], or
no spaces at all. Not both on the same line :).
+ # Insert Obsolete
+ # TODO: Not sure if this is needed.
Definately needed. Great that that's here.
+ print 'Database does not contain %s.' % pathname
can printRpm ever be called in Current? Or just cadmin? No code executable
from Current itself can "print" - daemons don't have stdout/stderr.
If this can only called from cadmin, fine, but note that in the comments.
+ c=self.dbc.cursor()
+ c.execute("""DELETE FROM rpm WHERE rpm_id = %d""", (rpm_id,))
+ c.execute("""DELETE FROM file WHERE rpm_id = %d""", (rpm_id,))
+ c.execute("""DELETE FROM provide WHERE rpm_id = %d""", (rpm_id,))
+ c.execute("""DELETE FROM obsolete WHERE rpm_id = %d""", (rpm_id,))
+ c.execute("""DELETE FROM channel_rpm WHERE rpm_id = %d""", (rpm_id,))
Should this be a transaction?
+ def newChannel(self, name, label, arch, os_release, description, parent):
I didn't have this in packagedb/channel, and I like the abstraction.
+ def delChannel(self, name):
+ """
+ Delete every referece to channel 'name' from database.
Again, the database should only know "labels" - name is just a text string
for human consumption.
+ 'channel' can be either a name (string) or an id (long)
Again, pick one type, and use it throughout your code, with an accessor
function for when you absolutely must have the other type. My preference
is to always work by "label", but that might not be the best choice
implementation wise. Does the "id" in the dataase have to an int, would would
the "label" itself work as just as well?
I ask on that one, as I don't know the tradeoffs between "int" and "varchar"
in postgres/sql in general.
+ # Is rpm already in database? If not add it.
+ rpm_id=self._getRpmId(pathname)
See, this is easier - there is no easily definable "label" (NVREA would be as
close as you could get) for rpms themselves.
Does this code cleanly handle having exactly the same RPM in two different
places? (Not even a symlink, but a copy). In my biology install tree, I have
both gromit-2.1.1-1.noarch.rpm in the dulug-7.1-i386 channel and in the
dulug-7.2-i386 channel. I couldn't use a symlink due to nfs mounting issues
at install time.
+ def delRpmFromChannel(self, pathname, channel):
+ """
+ Remove an Rpm from channel. Rpm should be one specified on level 0 (not inherited).
Please explain/document what this comment means. What is an inheirited rpm?
+ def _createListPackagesCache(self, channel):
+ c.execute("""SELECT rpm.name, rpm.version, rpm.release, rpm.epoch, rpm.arch, rpm.size
+ FROM rpm, channel_rpm
+ WHERE channel_rpm.channel_id = %d
+ AND rpm.rpm_id = channel_rpm.rpm_id
+ AND channel_rpm.active = 1""" % (channel_id,))
+
+ for i in range(c.rowcount):
+ name, version, release, epoch, arch, Size = c.fetchone()
+ nlist.append(name, version, release, epoch, arch, Size, label)
+
+ nlist = (nlist,)
+
+ filename = self.getPackageListCache(label)
+ pl_file = gzip.GzipFile(filename, 'wb', 9)
+ str = xmlrpclib.dumps(nlist, methodresponse=1)
+ pl_file.write(str)
+ pl_file.close()
sweet. one query, and long processing task after that. Nice.
+ for r in r2:
DEFINATELY need more descriptive variable names here.
+ c.execute("""
+ SELECT file.rpm_id FROM rpm, file, channel_rpm
+ WHERE channel_rpm.channel_id = %d
+ AND channel_rpm.active = 1
+ AND rpm.rpm_id = channel_rpm.rpm_id
+ AND file.rpm_id = channel_rpm.rpm_id
+ AND file.hash = hashbpchar('%s')
+ AND file.path = '%s'
+ AND channel_rpm.active = 1
+ """ % (channel_id, dep, dep))
Minor quibble, but try indenting the text of the sql statment itself a little.
+ c.execute("""
+ SELECT file.rpm_id FROM rpm, file, channel_rpm
+ WHERE channel_rpm.channel_id = %d
+ AND channel_rpm.active = 1
+ AND rpm.rpm_id = channel_rpm.rpm_id
+ AND file.rpm_id = channel_rpm.rpm_id
+ AND file.hash = hashbpchar('%s')
+ AND file.path = '%s'
+ AND channel_rpm.active = 1
+ """ % (channel_id, dep, dep))
Whether the last line, starting with """ is indented, I'll leave unspec'd.
+ for i in range(c1.rowcount):
This is a good counter-example for where "i" is a perfectly good var name.
+ inactive_rpms = c2.fetchone()[0]
Whats the [0] on these calls specify?
+ #Question: Do you return all parents of a channel or just the "deepest"
+ # What if client is not authorized for deepest?
For now, all database backends should assume a SINGLE parent level for all
children. IE, You can have a parent, but not a grand-parent. Dep checking
will be hard enough with just that.
Siblings may NOT use each other for dependancy checking.
(Yes, this means you dep function above is wrong - I don't see where you
check the parent channel for any deps that a child needs, but in 1.1, thats
good enough)
+# To make up2date.py happy
+class PackageDB(CurrentDB):
+ def __init__(self):
+ CurrentDB.__init__(self)
+
+ def addChannel(self, db_dir):
+ pass
Yuck, but we'll fix this later. I like how your patch just "drops in" to
0.9.4.
--- current-0.9.4/SaferExec.py Wed Dec 31 19:00:00 1969
+++ current-dev/SaferExec.py Mon Feb 11 07:03:27 2002
What the heck is this for?
--- current-0.9.4/auth.py Wed Jan 30 15:41:18 2002
+++ current-dev/auth.py Mon Feb 11 07:02:56 2002
@@ -18,2 +18,3 @@ import config
Why are we patching auth.py?
import ConstructParser
+import SaferExec
from logger import *
@@ -140,3 +141,2 @@ class HeadersId:
self.data['X-RHN-Auth-Channels'] = []
else:
- cp = ConstructParser.ConstructParser(headers[header_attr])
- try:
- tmpHdr = cp.parseIt()
- log ("Header object successfully parsed: %s" % tmpHdr, DEBUG2)
- if not type(tmpHdr[0]) == type([]):
- self.data['X-RHN-Auth-Channels'] = [tmpHdr]
+ #log(pprint.pformat(headers[header_attr]))
+ if 1:
+ # I present an alternative way to do this. Much simple. Should be faster.
+ # Since headers are checksumed to detect tampering, this should be safe.
+ # Except that 'X-RHN-Auth-Channels' is not included in checksum to support
+ # multiple channels.
+ # Does a quick regex to look for "bad" stuff.
+ d=SaferExec.safer_exec(headers[header_attr])
+ log ('d=%s' % `d`)
+ if d:
+ self.data['X-RHN-Auth-Channels']=d
No. If we want a better auth.py mechanism, make that a seperate patch.
I want JUST database stuff for now.
And, based on the python gods on #python, this isn't as safe as the Parser.
(And may not be any faster - auth.py will ALWAYS skew in the direction of
safety, not speed)
+ # We have to handle auth channels as a special case, since for some
+ # reason single channel lists are coming back from the client as a
+ # simple list, instead of a list of lists, as was expected.
+ cp = ConstructParser.ConstructParser(headers[header_attr])
+ try:
+ tmpHdr = cp.parseIt()
+ log ("Header object successfully parsed: %s" % tmpHdr, DEBUG2)
+ if not type(tmpHdr[0]) == type([]):
+ self.data['X-RHN-Auth-Channels'] = [tmpHdr]
+ else:
+ self.data['X-RHN-Auth-Channels'] = tmpHdr
+ except Exception, e:
+ log ("Exception caught: %s" % e, DEBUG2)
+ self.data['X-RHN-Auth-Channels'] = ''
+
+ # we can't print errors from here effectively, so just making
+ # part of the auth data be empty will ensure a neg auth.
@@ -217,5 +231,8 @@ class HeadersId:
- # Can't append a list of lists to a string
- for chan in self.data['X-RHN-Auth-Channels']:
- str = str + chan[0] + ':' + chan[1]
+ # Since it seems the client dinks with this (or I can't
+ # find where it is changed) losen up for testing only. (tdr)
+ if config.cfg.getItem('dangerous_channels') == 0:
+ # Can't append a list of lists to a string
+ for chan in self.data['X-RHN-Auth-Channels']:
+ str = str + chan[0] + ':' + chan[1]
@@ -277,3 +294,2 @@ class HeadersId:
(sum, self.data['X-RHN-Auth']), VERBOSE)
- return 0
@@ -305,2 +321,3 @@ class Authorization:
"""
+ #logfunc(locals())
diff -ruNp1 current-0.9.4/backend.py current-dev/backend.py
--- current-0.9.4/backend.py Wed Dec 31 19:00:00 1969
+++ current-dev/backend.py Mon Feb 11 07:03:27 2002
@@ -0,0 +1,4 @@
+# With backend not necessarily packagedb,
+# Need somewhere to store the chosen backend.
+# This seems a resonable place.
+db = None
The right place would have been packagedb, but its not indenpendant
enough. Let this stand for now.
diff -ruNp1 current-0.9.4/cdbadmin current-dev/cdbadmin
--- current-0.9.4/cdbadmin Wed Dec 31 19:00:00 1969
+++ current-dev/cdbadmin Mon Feb 11 10:11:37 2002
@@ -0,0 +1,33 @@
+#! /usr/bin/python
+
+""" \
+cdbadmin is the administrative program that performs offline tasks
+for the PostgreSQL backend for 'current'.
+Current is an open source implementation of Redhat up2date server.
+
+Note that this program doesn't (nor any other) modify or create the config
+file for you. You must do that. This program prepares the channels
+and other databases, and current itself then uses those databases.
+
+Note also that this program is fragile and poorly documented, right now :(.
+
+Copyright 2001 Hunter Matthews <[email protected]>
+Copyright 2002 Toby D. Reeves <[email protected]>
+
+This software is distributed under the GPL v2, see file "LICENSE"
+
+"""
+
+# Constants and defaults
+# These are replaced by make, so beware
+MODULES_DIR="/usr/share/current"
+
+import sys
+sys.path.insert(0,MODULES_DIR+"/lib")
+sys.path.append(MODULES_DIR)
+
+# I like to have the functions available for other scripts.
+# Thus, this is just a tiny wrapper for the real thing.
+import cdbadmin
+cdbadmin._main()
+
Ick. Whatever.
+# This is written to the Python DB-SIG API.
+# On Redhat 7.2 I'm using stock "postgresql-python-7.1.3-2.i386.rpm".
+
+# Redhat 7.1 uses "postgresql-python-7.0.3-8.i386.rpm".
+# That does not support the DB-SIG API.
+# It probably could be handled with a small imulation layer.
I'm perfectly cool with saying RH 7.2 is required for the postgres backend.
Don't spend any time backporting to 7.0.3 - I'd rather publish the 7.1.4
postgres rpms that I have built for RH 7.1.
+# Redhat 6.2 uses "postgresql-python-6.5.3-6.i386.rpm".
+# That does not support the DB-SIG API.
+# It probably could be handled with a small imulation layer.
I wouldn't support 6.5 anyway.
I was fine to here. (Actually, I'd prefer a single "cadmin", but the original
was so pathetic I don't blame you for doing another one.
However, I think I'd like to see all the "db" code in the backend itself,
and then there could be a single "cadmin" that just
a) pick a backend, based on the config file
b) made backend calls as the user directs.
That could safely wait for 1.1.2 or something.
The following REALLY big script needs to be a file or something?
Comments from other DB'ers here would be nice.
Your tablenames and column names are lowercase. All other sql backends will
need to do the same (I know thats semi-standard, I have seen code that
did otherwise)
+INIT_DATABASE_SCRIPT = """\
+-- This is "Beta". It will change as sql backend matures.
+
+-- DROP DATABASE %(db)s;
+-- CREATE DATABASE %(db)s;
+-- \connect %(db)s
+
+CREATE TABLE rpm (
+ rpm_id SERIAL PRIMARY KEY NOT NULL,
+ path TEXT NOT NULL,
+ name TEXT NOT NULL,
+ version TEXT NOT NULL,
+ release TEXT NOT NULL,
+ epoch TEXT NOT NULL,
+ arch TEXT NOT NULL,
+ arch_canon TEXT NOT NULL,
+ size INT NOT NULL,
+ is_src SMALLINT NOT NULL,
+ created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ hash INT NOT NULL
+);
Line that stuff up.
Postgres question - does smallint buy us anything, or would int work just
as well there?
+
+--GRANT SELECT, INSERT, UPDATE, DELETE ON rpm, rpm_rpm_id_seq TO %(user)s;
+CREATE INDEX rpm_path_idx ON rpm (path);
+CREATE INDEX rpm_hash_idx ON rpm (hash);
+--CREATE INDEX rpm_name_idx ON rpm (name);
+--CREATE INDEX rpm_version_idx ON rpm (version);
+--CREATE INDEX rpm_release_idx ON rpm (release);
+CREATE INDEX rpm_nvr_idx ON rpm (name, version, release);
You commented these out for some reason - could you say why?
+--------------------------------------------------------------------------------
+
+CREATE TABLE file (
+ rpm_id INT NOT NULL,
+ path TEXT NOT NULL,
+ hash INT NOT NULL
+);
Whats the hash for?
+
+--GRANT SELECT, INSERT, UPDATE, DELETE ON file TO %(user)s;
+CREATE INDEX file_rpm_id_idx ON file (rpm_id);
+CREATE INDEX file_hash_path_idx ON file (hash, path);
+--------------------------------------------------------------------------------
+
+CREATE TABLE provide (
+ rpm_id INT NOT NULL,
+ provides TEXT NOT NULL,
+ provide_name TEXT NOT NULL,
+ provide_version TEXT NOT NULL,
+ provide_flags INT NOT NULL
+);
+
+--GRANT SELECT, INSERT, UPDATE, DELETE ON provide TO %(user)s;
+CREATE INDEX provide_rpm_id_idx ON provide (rpm_id);
+CREATE INDEX provide_provides_idx ON provide (provides);
+
+--------------------------------------------------------------------------------
+
+CREATE TABLE obsolete (
+ rpm_id INT NOT NULL,
+ obsoletes TEXT NOT NULL,
+ obsolete_name TEXT NOT NULL,
+ obsolete_version TEXT NOT NULL,
+ obsolete_flags INT NOT NULL
+);
+
+--GRANT SELECT, INSERT, UPDATE, DELETE ON obsolete TO %(user)s;
+CREATE INDEX obsolete_rpm_id ON obsolete (rpm_id);
+
+--------------------------------------------------------------------------------
+
+CREATE TABLE channel (
+ channel_id SERIAL PRIMARY KEY NOT NULL,
+ parent_id INT,
+ name TEXT NOT NULL,
+ label TEXT NOT NULL,
+ arch TEXT NOT NULL,
+ os_release TEXT NOT NULL,
+ description TEXT NOT NULL,
+ created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ computed TIMESTAMP
+);
+
+--GRANT SELECT, INSERT, UPDATE, DELETE ON channel, channel_channel_id_seq TO %(user)s;
+
+--------------------------------------------------------------------------------
+
+CREATE TABLE channel_rpm (
+ channel_id INT NOT NULL,
+ rpm_id INT NOT NULL,
+ level SMALLINT,
+ active SMALLINT
+);
+
+--GRANT SELECT, INSERT, UPDATE, DELETE ON channel_rpm TO %(user)s;
+CREATE INDEX channel_rpm_rpm_id ON channel_rpm (rpm_id);
+CREATE INDEX channel_rpm_channel_id ON channel_rpm (channel_id);
+CREATE INDEX channel_rpm_channel_id_rpm_id ON channel_rpm (channel_id, rpm_id);
+
+--------------------------------------------------------------------------------
+-- This a quick first cut placeholder.
+-- The identifier \'user\' is reserved so I use \'users\' unlike the other tables.
+
+CREATE TABLE users (
+ user_id SERIAL PRIMARY KEY NOT NULL,
+ username TEXT,
+ email TEXT,
+ secret TEXT,
+ created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+--GRANT SELECT, INSERT, UPDATE, DELETE ON users, users_user_id_seq TO %(user)s;
+
+--------------------------------------------------------------------------------
+-- This a quick first cut placeholder.
+
+CREATE TABLE auth (
+ system_id TEXT,
+ user_id INT NOT NULL,
+ type TEXT,
+ checksum TEXT,
+ description TEXT,
+ operating_system TEXT,
+ os_release TEXT,
+ architecture TEXT,
+ profile_name TEXT,
+ created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+--GRANT SELECT, INSERT, UPDATE, DELETE ON auth TO %(user)s;
+
+def thrash_channel(label, count):
+ """\
+Use:
+cdbadmin thrash_channel label count
I see now what it does, but please rename this. That wil scare people :)
Leave the hash marks out. Just put two blank lines between functions/methods/
classes and move on.
+################################################################################
+def headers(label, force):
+ """\
diff -ruNp1 current-0.9.4/config.py current-dev/config.py
--- current-0.9.4/config.py Fri Feb 1 11:24:46 2002
+++ current-dev/config.py Mon Feb 11 09:37:24 2002
@@ -19,3 +19,3 @@ cfg = None
## These are replaced by make, so beware
-VERSION="0.9.4"
+VERSION="0.9.5"
MODULES_DIR="/usr/share/current"
@@ -36,2 +36,3 @@ defaults = {
"pid_file": PID_DIR + "/current.pid",
+ "backend": "packagedb",
"log_level": 55,
@@ -40,2 +41,7 @@ defaults = {
"kill": 0,
+
+ # Used to enable multi-channel client support.
+ # As is, it could be dangerous to enable.
+ # But I don't think so. Mostly to flag Hunter.
+ "dangerous_channels" : 1,
Excellent - Leave this in.
}
@@ -55,2 +61,7 @@ class MissingError(Error):
+class NoConfigFileError(Error):
+ def __init__(self,file):
+ self._s = "The required configuration file '%s' wasn't found." % file
+ def __str__(self):
+ return self._s
@@ -95,2 +106,5 @@ class Config:
file = self._defaults['config_file']
+
+ if not os.path.isfile(file):
+ raise NoConfigFileError(file)
@@ -245,2 +259,3 @@ def _main():
"nodaemon": "1",
+ "backend": "packagedb"
}
-# BUGFIX from Ivan F. Martinez <[email protected]>
+sys.path.insert(0,MODULES_DIR+"/lib")
You keep doing this - why?
I do like the part where you made the backend configurable - leave that
in, please.
+welcome_message = "Welcome to Hunter's up2date server."
+privacy_statement = "Privacy Statement for Hunter's up2date server:
Nobody changes these. :) Not even John.
No patches of this magnitude without documentation will be examined, much
less accepted. Excellent.
--- current-0.9.4/docs/PostgreSQL-Backend.txt Wed Dec 31 19:00:00 1969
+++ current-dev/docs/PostgreSQL-Backend.txt Mon Feb 11 14:03:59 2002
@@ -0,0 +1,180 @@
+********************************************************************************
+ The PostgreSQL Database backend for "current".
+ Development Version (Beta)
+********************************************************************************
+This software is distributed under the GPL v2, see file "../LICENSE".
+Copyright 2002 Toby D. Reeves <[email protected]>
+********************************************************************************
+
+** Installing on Redhat 7.2 **
+
+These instruction are for a stock Redhat 7.2 installation.
+
+I'm using the stock "postgresql-python-7.1.3-2.i386.rpm" which supports
+the Python DB-SIG API.
+
+This version of postgresql-python depends on "mx-2.0.1-1.i386.rpm" which also comes with
+Redhat 7.2.
+
+--------------------------------------------------------------------------------
+This is the sequence to take a stock Red Hat 7.2 machine and get it to run.
+You may need some slightly different commands if your "special".
+
+If you played with the first tarball version of the hack, you need to clean up:
+> su
+> su postgres
+> dropdb currentdb
+> dropuser current
+
+Now, we can begin:
+
+Initialize postgresql and make it start on boot:
+> su
+> /sbin/chkconfig --add postgresql
+> /etc/init.d/postgresql start
+
+You may need to create the file '/var/lib/pgsql/data/postmaster.opts.default' that contains "-i"
+to enable Postgresql to listen to TCP/IP connections. See man page on 'pg_ctl'.
+
+Create the current user in PostgreSQL with these commands:
+> su postgres
+> createuser -A -d -P current
+
+Drop from postgres to root:
+> exit
+
+Now restart postgresql.
+
+> /etc/init.d/postgresql restart
+
+Postgresql has many authentication methods. See /var/lib/pgsql/data/pg_hba.conf.
+The default setup in Postgresql is VERY liberal for connections from the localhost,
+and does not enforce passwords. Thus, the password you entered is NOT USED if you
+do nothing to the pg_hba.conf file.
+
+For now, CurrentDB.py TRIES to use simple "password" authentication.
+
+Drop from root.
+> exit
+
+That should do it for the PostgreSQL server setup.
+--------------------------------------------------------------------------------
I liked this doc.
+Put some sanity checks in as need to verify database to cache and rpm dirs.
+
+Put an option in that disables "file" table use. Most sites will NEVER need this.
+It also happens to be quite expensive in time and resources.
File for dependancy? Think again. Its huge and expensive and I bet 30%
of all dependancies are file dependancies.
REQUIRED.
+Also, "smart" support for multiple canonical architectures (i386, ia64, alpha, ...)
+is not yet done. Have some more thinking to do there.
Good enough for now.
+Someone could do a web interface similiar to RHN, and all the notifications, ect.
+That could be useful if you serve a large campus with several administrators.
+But it is not that useful to me.
Heh. Any takers?
--- current-0.9.4/packagedb.py Thu Jan 24 00:53:05 2002
+++ current-dev/packagedb.py Mon Feb 11 07:03:01 2002
@@ -51,9 +51,4 @@ class PackageDB:
Is this part of the patch required for SQL, or are these seperate
improvements would could add pre-1.0?
If they're seperate, please resend with a description of what you did and
why, and I'll see if it will fit pre-1.0.
If they're not seperate, explain what you're doing here, since its not
obvious how you're using packagedb in the SQL support (other than grabbing
a couple things, which is fine)
- # FIXME: this needs a proper interface
- # just brute force it for now
- # FIXME: we may also need some of the other channel information
- # indexed.
+ # Unique label for eache channel
new_label = tmp.chanInfo['label']
- new_arch = tmp.chanInfo['arch']
- new_rel = tmp.chanInfo['os_release']
@@ -231,2 +210,3 @@ _compat_arches_table = {
"i686" : [ "i386", "i686", "i586", "i486", "i386", "noarch" ],
+ "athlon" : [ "i386", "i486", "i386", "noarch" ], #FIXME
"alpha" : [ "alpha", "alpha", "noarch" ],
actually, athlon support in 7.2 should be
"athlon" : [ "i386", "athlon", "i486", "i386", "noarch" ], I believe.
I hate maintaining this table in Current. Suggestions anyone?
Final note: You mostly reused the existing API so that up2date had to
change fairly little - any other backend must do the same.
Good patch overall.
Great functionality.