public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: Troy Dack <troy@tkdack.com>
To: gentoo-dev@gentoo.org
Subject: [gentoo-dev] Portage http interface
Date: 16 Nov 2002 02:26:15 +1100	[thread overview]
Message-ID: <1037373976.32414.9.camel@waterhouse.internal.lan> (raw)

[-- Attachment #1: Type: text/plain, Size: 666 bytes --]

Hi all,
	I've just started playing with/learning about python and while reading
the docs noticed that it had a http server module.  So I thought I'd
have a bash at throwing together a webmin type front end for portage.

Th results are attached.  It's not very functional at the moment, but I
thought I'd share it and get peoples opinions.

Installation is simple:

1. Save the attachment somewhere comfortable as: portageserver.py
2. make it executable (chmod o+x portageserver.py)
3. run it /path/to/portageserver.py

Usage is even easier, just point your browser @ http://localhost:9000

Let me know what you think.

Thanks
-- 
	Troy Dack
	http://linux.tkdack.com

[-- Attachment #2: portageserver.py --]
[-- Type: text/x-python, Size: 5578 bytes --]

#!/usr/bin/env python2.2

import SocketServer
import BaseHTTPServer
import sys
import os
import cgi
import socket
import urllib
import portage
from string import *


class ClientAbortedException(Exception):
	pass

class PortageServer(BaseHTTPServer.HTTPServer):
	def __init__(self):
		SocketServer.TCPServer.__init__(
			self,
			('127.0.0.1', 9000),
			PortageRequestHandler)

	def server_bind(self):
		# set SO_REUSEADDR (if available on this platform)
		if hasattr(socket, 'SOL_SOCKET') and hasattr(socket, 'SO_REUSEADDR'):
			self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		BaseHTTPServer.HTTPServer.server_bind(self)

class PortageRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

	VERSION_SHORT=1
	VERSION_RELEASE=2
	
	installcache = portage.db["/"]["vartree"]

	PortageTree = {}

	for node in portage.portdb.cp_all():
		if not PortageTree.has_key(split(node, "/")[0]):
			# need to make a new key first
			PortageTree[split(node, "/")[0]] = []
		# add the package to the list for this category
		PortageTree[split(node, "/")[0]].append(split(node, "/")[1])
	categories = PortageTree.keys()
	categories.sort()

	def do_GET(self):
		try:
			self._perform_GET()
		except ClientAbortedException:
        		pass

	def _perform_GET(self):
		path = self.translate_path()
		if path is None:
        		self.send_error(400, 'Illegal URL construction')
                if len(path) == 0:
		        self._rootdir()
		elif (len(path) == 2) and (path[0] == 'category'):
		        self._categorydir(path[1])
                return

	def _rootdir(self):
		self.send_response(200)
		self.send_header("Content-Type", 'text/html')
		self.end_headers()

		self.wfile.write("""
<html>
        <head>
	        <title>Gentoo Portage</title>
        </head>
        <body>
	        <h1>Categories</h1>
		<p><b>""" + str(len(self.PortageTree)) + """</b> Categories</p>\n""")

		for category in self.categories:
		        self.wfile.write("""
			<a href="/category/""" + category + """">""" + category + "</a> ( " + str(len(self.PortageTree[category])) + " ) </br>")
		self.wfile.write("""
        </body>
</html>""")
		return

	def _categorydir(self, category):
		self.send_response(200)
		self.send_header("Content-Type", 'text/html')
		self.end_headers()
		self.wfile.write("""
<html>
        <head>
	        <title>Gentoo Portage - """ + category + """</title>
        </head>
        <body>
	        <h1>Packages in: """ + category + """ </h1>
		<p><b>""" + str(len(self.PortageTree[category])) + """</b> Packages</p>
	        <a href="/">Back</a>
		<table>
			<tr>
			        <td style="text-align: center">
				        Emerge?
			        </td>
			        <td>
				        Package Name
			        </td>
			        <td>
				        Latest Available
			        </td>
				<td>
				        Latest Installed
				</td>
				<td>
				        Description
				</td>
			</tr>""")
		i = 0
		for app in self.PortageTree[category]:
			if i % 2 == 0:
			        rowcolor = "white"
			else:
			        rowcolor = "light grey"
		        match = category + "/" + app
			masked = ""
			full_package = portage.portdb.xmatch("bestmatch-visible",match)
			if not full_package:
				#no match found; we don't want to query description
				full_package=portage.best(portage.portdb.xmatch("match-all",match))
				if not full_package:
					continue
				else:
					masked = """</br><span style="color: red;">** Masked **</span>"""
					rowcolor = "pink"
			try:
				full_desc = portage.portdb.aux_get(full_package,["DESCRIPTION"])[0]
			except KeyError:
				print "emerge: search: aux_get() failed, skipping"
				continue
			myver = self.getVersion(full_package, self.VERSION_RELEASE)
			i += 1
		        self.wfile.write("""
			<tr style="background-color: """ + rowcolor + """;">
			        <td style="text-align: center">
				        <input type="checkbox">
			        </td>
				<td>
				        """ + app + """
			        </td>
			        <td>
				        """ + myver + """
			        </td>
				<td>
				        """ + self.getInstallationStatus(match) + masked + """
				</td>
				<td>
				        """ + full_desc + """
			        </td>
			</tr>""")
		self.wfile.write("""
		</table>
        </body>
</html>""")
		return

	def getVersion(self,full_package,detail):
		if len(full_package) > 1:
			package_parts = portage.catpkgsplit(full_package)
			if detail == self.VERSION_RELEASE and package_parts[3] != 'r0':
				result = package_parts[2]+ "-" + package_parts[3]
			else:
				result = package_parts[2]
		else:
			result = ""
		return result

	def getInstallationStatus(self,package):
		installed_package = portage.portdb.xmatch("bestmatch-visible", package)
		result = ""
		version = self.getVersion(installed_package,self.VERSION_RELEASE)
		if len(version) > 0:
			result = version
		else:
			result = "Not Installed"
		return result
	
	def translate_path(self):
		parts = split(urllib.unquote(self.path), '/')
		parts = filter(None, parts)
		while 1:
			try:
				parts.remove('.')
			except ValueError:
				break
		while 1:
			try:
			        idx = parts.index('..')
			except ValueError:
				break
			if idx == 0:
				# illegal path: the '..' attempted to go above the root
				return None
			del parts[idx-1:idx+1]
		return parts

# Main Program
if __name__ == '__main__':

	svr = PortageServer()

	print "Portage Server: serving on port 8080..."
	svr.serve_forever()


[-- Attachment #3: Type: text/plain, Size: 37 bytes --]

--
gentoo-dev@gentoo.org mailing list

             reply	other threads:[~2002-11-15 15:27 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-11-15 15:26 Troy Dack [this message]
2002-11-16  8:49 ` [gentoo-dev] Portage http interface Peter Ruskin
2002-11-16  9:39   ` Troy Dack
2002-11-16 10:36     ` Peter Ruskin
2002-11-16 11:43       ` Troy Dack
2002-11-16 12:49         ` Peter Ruskin
2002-11-16 11:47       ` José Fonseca
2002-11-16 12:55         ` Peter Ruskin
2002-11-19 19:55       ` Per Wigren
2002-11-16 13:42 ` Alexander Futasz
2002-11-16 14:10 ` Troy Dack
2002-11-16 14:39   ` Johannes Findeisen
2002-11-16 15:22     ` Troy Dack

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1037373976.32414.9.camel@waterhouse.internal.lan \
    --to=troy@tkdack.com \
    --cc=gentoo-dev@gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox