14
0

- update to 0.6.1

* many new parameters for bugzilla command-line tool like --target_milestone,
  --private, --status, --assignee, et all
  * add support for Bugzilla 36
  * Unicode related fixes
- SUSE specific fixes
  * novell bugzilla support in getBugzillaClassForURL
  * obfuscated password support in oscrc
  * move novell bugzilla to 3.4
  * xmlrpclib changes done in python 2.7 from master [bug#685842]
- create suse branch for stashing SUSE specific changes
  https://gitorious.org/opensuse/python-bugzilla/commits/suse

OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-bugzilla?expand=0&rev=13
This commit is contained in:
2011-05-23 14:05:00 +00:00
committed by Git OBS Bridge
parent 3a8580cbc0
commit b2af480230
11 changed files with 236 additions and 271 deletions

View File

@@ -1,33 +0,0 @@
From 78a52828f8eab7028a3df5613645213ec761aa70 Mon Sep 17 00:00:00 2001
From: Michal Vyskocil <mvyskocil@suse.cz>
Date: Tue, 21 Jul 2009 15:46:07 +0200
Subject: [PATCH 1/2] Use LWPCookieJar by default.
The MozillaCookieJar format is not standard and cannot store
informations about expires necassary for NovellBugzilla. This
patch changes the default loader to LWPCookieJar with fallaback to
MozillaCookieJar if it fails.
---
bugzilla/base.py | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/bugzilla/base.py b/bugzilla/base.py
index 5becb43..56d1faf 100644
--- a/bugzilla/base.py
+++ b/bugzilla/base.py
@@ -140,7 +140,11 @@ class BugzillaBase(object):
del self.cookiefile
self._cookiefile = cookiefile
- cj = cookielib.MozillaCookieJar(self._cookiefile)
+ try:
+ cj = cookielib.LWPCookieJar(self._cookiefile)
+ except LoadError, le:
+ cj = cookielib.MozillaCookieJar(self._cookiefile)
+
if not self._cookiefile:
self._persist_cookie = False
# Create a temporary cookie file
--
1.6.3.3

View File

@@ -1,215 +0,0 @@
From 5347c9d17b0f8bb0430611b687b1389d0620c035 Mon Sep 17 00:00:00 2001
From: Michal Vyskocil <mvyskocil@suse.cz>
Date: Tue, 21 Jul 2009 16:17:21 +0200
Subject: [PATCH 2/2] NovellBugzilla implementation.
The NovellBugzilla implementation - is a subclass of Bugzilla32 with
reimplemented _login and _logoout methods compatible with iChain.
NovellBugzilla don't allow other self.url than bnc, because it should
not be used for any other bugzilla. The url parameters in __init__ and
connect() are overwritten and exists only for compatibility purposes.
It can also read the username/password from ~/.oscrc, which is
common for many SUSE users and contains a same iChain credentials as is
necessary for bugzilla login. So when user use osc he don't need
duplicate login informations to ~/.bugzillarc.
---
bugzilla/__init__.py | 3 +-
bugzilla/nvlbugzilla.py | 164 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 166 insertions(+), 1 deletions(-)
create mode 100644 bugzilla/nvlbugzilla.py
diff --git a/bugzilla/__init__.py b/bugzilla/__init__.py
index 902c996..a871f26 100644
--- a/bugzilla/__init__.py
+++ b/bugzilla/__init__.py
@@ -11,13 +11,14 @@
from bugzilla3 import Bugzilla3, Bugzilla32
from rhbugzilla import RHBugzilla, RHBugzilla3
+from nvlbugzilla import NovellBugzilla
from base import version
import xmlrpclib
import logging
log = logging.getLogger("bugzilla")
# advertised class list
-classlist = ['Bugzilla3', 'Bugzilla32', 'RHBugzilla3']
+classlist = ['Bugzilla3', 'Bugzilla32', 'RHBugzilla3', 'NovellBugzilla']
def getBugzillaClassForURL(url):
log.debug("Choosing subclass for %s" % url)
diff --git a/bugzilla/nvlbugzilla.py b/bugzilla/nvlbugzilla.py
new file mode 100644
index 0000000..027bb19
--- /dev/null
+++ b/bugzilla/nvlbugzilla.py
@@ -0,0 +1,164 @@
+# nvlbugzilla.py - a Python interface to Novell Hat Bugzilla using xmlrpclib.
+#
+# Copyright (C) 2009 Novell Inc.
+# Author: Michal Vyskocil <mvyskocil@suse.cz>
+#
+# 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. See http://www.gnu.org/copyleft/gpl.html for
+# the full text of the license.
+
+#from bugzilla.base import BugzillaError, log
+import bugzilla.base
+from bugzilla import Bugzilla32
+
+import urllib
+import urllib2
+import urlparse
+import cookielib
+import time
+import re
+import os
+
+class NovellBugzilla(Bugzilla32):
+ '''bugzilla.novell.com is a standard bugzilla 3.2 with some extensions, but
+ it uses an proprietary and non-standard IChain login system. This class
+ reimplements a login method which is compatible with iChain.
+
+ Because login process takes relativelly long time, because it needs several
+ HTTP requests, NovellBugzilla caches the session cookies of bugzilla
+ (ZXXXXXXX-bugzilla) and IChain (IPCXXXXXXXXXXXXX) in a self._cookiefile to
+ speedup a repeated connections. To avoid problems with cookie expiration,
+ it set the expiration of cookie to 5 minutes. This expects cookies stored
+ in LWPCookieJar format and login method warn if cookies are in
+ MozillaCookieJar format.
+
+ It can also read a credentials from ~/.oscrc if exists, so it should not
+ be duplicated in /etc/bugzillarc, or ~/.bugzillarc
+ '''
+
+ version = '0.1'
+ user_agent = bugzilla.base.user_agent + ' NovellBugzilla/%s' % version
+
+ bnc_cookie_re = re.compile('^Z.*-bugzilla')
+ ichain_cookie_re = re.compile('^IPC.*')
+ cookie_domain_re = re.compile('.*\.novell\.com$')
+
+ bugzilla_url = 'https://bugzilla.novell.com/xmlrpc.cgi'
+ logout_url = 'https://www.novell.com/cmd/ICSLogout'
+ obs_url = 'https://api.opensuse.org/'
+ #FIXME: is it really necessary to use all those paths???
+ login_path = '/index.cgi?GoAheadAndLogIn=1'
+ auth_path = '/ICSLogin/auth-up'
+ ichainlogin_path = '/ichainlogin.cgi'
+
+ def __init__(self, expires=300, **kwargs):
+ self._expires = expires
+ super(NovellBugzilla, self).__init__(**kwargs)
+ # url argument exists only for backward compatibility, but is always set to same url
+ self._url = self.__class__.bugzilla_url
+
+ def __get_expiration(self):
+ return self._expires
+ def __set_expiration(self, expires):
+ self._expires = expires
+ expires = property(__get_expiration, __set_expiration)
+
+ def _iter_domain_cookies(self):
+ '''Return an generator from all cookies matched a self.__class__.cookie_domain_re'''
+ return (c for c in self._cookiejar if self.__class__.cookie_domain_re.match(c.domain) and not c.is_expired())
+
+ def _is_bugzilla_cookie(self):
+ return len([c for c in self._iter_domain_cookies() if self.__class__.bnc_cookie_re.match(c.name)]) != 0
+
+ def _is_ichain_cookie(self):
+ return len([c for c in self._iter_domain_cookies() if self.__class__.ichain_cookie_re.match(c.name)]) != 0
+
+ def _is_lwp_format(self):
+ return isinstance(self._cookiejar, cookielib.LWPCookieJar)
+
+ def _login(self, user, password):
+ #TODO: IChain is an openID provides - discover an ability of openID login
+
+ # init some basic
+ cls = self.__class__
+ base_url = self.url[:-11] # remove /xmlrpc.cgi
+
+ lwp_format = self._is_lwp_format()
+ if not lwp_format:
+ bugzilla.base.log.warn("""File `%s' is not in LWP format required for NovellBugzilla.
+If you want cache the cookies and speedup the repeated connections, remove it or use an another file for cookies.""" % self._cookiefile)
+
+ #TODO: do some testing what will be if the cookie expires
+ if lwp_format and not self._is_bugzilla_cookie():
+ login_url = urlparse.urljoin(base_url, cls.login_path)
+ bugzilla.base.log.info("GET %s" % login_url)
+ login_resp = self._opener.open(login_url)
+ if login_resp.code != 200:
+ raise BugzillaError("The login failed with code %d" % login_resp.core)
+
+ params = {
+ 'url' : urlparse.urljoin(base_url, cls.ichainlogin_path),
+ 'target' : cls.login_path[1:],
+ 'context' : 'default',
+ 'proxypath' : 'reverse',
+ 'nlogin_submit_btn' : 'Log In',
+ 'username' : user,
+ 'password' : password
+ }
+
+ if lwp_format and not self._is_ichain_cookie():
+ auth_url = urlparse.urljoin(base_url, cls.auth_path)
+ auth_params = urllib.urlencode(params)
+ auth_req = urllib2.Request(auth_url, auth_params)
+ bugzilla.base.log.info("POST %s" % auth_url)
+ auth_resp = self._opener.open(auth_req)
+ if auth_resp.code != 200:
+ raise BugzillaError("The auth failed with code %d" % auth_resp.core)
+
+ if lwp_format:
+ for cookie in self._cookiejar:
+ cookie.expires = time.time() + self._expires # expires cookie in 15 minutes
+ cookie.discard = False
+
+ return super(NovellBugzilla, self)._login(user, password)
+
+ def connect(self, url):
+ # NovellBugzilla should connect only to bnc,
+ return super(NovellBugzilla, self).connect(self.__class__.bugzilla_url)
+
+ def _logout(self):
+ '''Novell bugzilla don't support xmlrpc logout, so let's implemtent it.
+ This method also set all domain cookies as expired.
+ '''
+
+ resp = self._opener.open(self.__class__.logout_url)
+ # expire cookies
+ for cookie in self._iter_domain_cookies():
+ cookie.expires = 0
+
+ def readconfig(self, configpath=None):
+ super(NovellBugzilla, self).readconfig(configpath)
+
+ oscrc=os.path.expanduser('~/.oscrc')
+ if not self.user and not self.password \
+ and os.path.exists(oscrc):
+ from ConfigParser import SafeConfigParser, NoOptionError
+ c = SafeConfigParser()
+ r = c.read(oscrc)
+ if not r:
+ return
+
+ obs_url = self.__class__.obs_url
+ if not c.has_section(obs_url):
+ return
+
+ try:
+ self.user = c.get(obs_url, 'user')
+ self.password = c.get(obs_url, 'pass')
+ bugzilla.base.log.info("Read credentials from ~/.oscrc")
+ except NoOptionError, ne:
+ return
+
+
--
1.6.3.3

View File

@@ -0,0 +1,104 @@
From 120e4196f219ad92358a279c42bb771b3a9aad9e Mon Sep 17 00:00:00 2001
From: Will Woods <wwoods@redhat.com>
Date: Thu, 5 Aug 2010 14:10:46 -0400
Subject: [PATCH 12/19] Fix for httplib/xmlrpclib changes in py2.7
---
bugzilla/base.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/bugzilla/base.py b/bugzilla/base.py
index 7f2bb88..d1a6d61 100644
--- a/bugzilla/base.py
+++ b/bugzilla/base.py
@@ -936,9 +936,9 @@ class CookieTransport(xmlrpclib.Transport):
else:
log.debug("send_cookies(): cookiejar empty. Nothing to send.")
- # This is the same request() method from xmlrpclib.Transport,
+ # This is the same request() method from python 2.6's xmlrpclib.Transport,
# with a couple additions noted below
- def request(self, host, handler, request_body, verbose=0):
+ def request_with_cookies(self, host, handler, request_body, verbose=0):
h = self.make_connection(host)
if verbose:
h.set_debuglevel(1)
@@ -985,10 +985,74 @@ class CookieTransport(xmlrpclib.Transport):
return self._parse_response(h.getfile(), sock)
+ # This is just python 2.7's xmlrpclib.Transport.single_request, with
+ # send additions noted below to send cookies along with the request
+ def single_request_with_cookies(self, host, handler, request_body, verbose=0):
+ h = self.make_connection(host)
+ if verbose:
+ h.set_debuglevel(1)
+
+ # ADDED: construct the URL and Request object for proper cookie handling
+ request_url = "%s://%s%s" % (self.scheme,host,handler)
+ log.debug("request_url is %s" % request_url)
+ cookie_request = urllib2.Request(request_url)
+
+ try:
+ self.send_request(h,handler,request_body)
+ self.send_host(h,host)
+ self.send_cookies(h,cookie_request) # ADDED. creates cookiejar if None.
+ self.send_user_agent(h)
+ self.send_content(h,request_body)
+
+ response = h.getresponse(buffering=True)
+
+ # ADDED: parse headers and get cookies here
+ cookie_response = CookieResponse(response.msg)
+ # Okay, extract the cookies from the headers
+ self.cookiejar.extract_cookies(cookie_response,cookie_request)
+ log.debug("cookiejar now contains: %s" % self.cookiejar._cookies)
+ # And write back any changes
+ if hasattr(self.cookiejar,'save'):
+ try:
+ self.cookiejar.save(self.cookiejar.filename)
+ except Exception, e:
+ log.error("Couldn't write cookiefile %s: %s" % \
+ (self.cookiejar.filename,str(e)))
+
+ if response.status == 200:
+ self.verbose = verbose
+ return self.parse_response(response)
+ except xmlrpclib.Fault:
+ raise
+ except Exception:
+ # All unexpected errors leave connection in
+ # a strange state, so we clear it.
+ self.close()
+ raise
+
+ #discard any response data and raise exception
+ if (response.getheader("content-length", 0)):
+ response.read()
+ raise xmlrpclib.ProtocolError(
+ host + handler,
+ response.status, response.reason,
+ response.msg,
+ )
+
+ # Override the appropriate request method
+ if hasattr(xmlrpclib.Transport, 'single_request'):
+ single_request = single_request_with_cookies # python 2.7+
+ else:
+ request = request_with_cookies # python 2.6 and earlier
+
class SafeCookieTransport(xmlrpclib.SafeTransport,CookieTransport):
'''SafeTransport subclass that supports cookies.'''
scheme = 'https'
- request = CookieTransport.request
+ # Override the appropriate request method
+ if hasattr(xmlrpclib.Transport, 'single_request'):
+ single_request = CookieTransport.single_request_with_cookies
+ else:
+ request = CookieTransport.request_with_cookies
class _User(object):
'''Container object for a bugzilla User.
--
1.7.4.1

View File

@@ -1,7 +1,7 @@
From e286a5be2446a00f91bb498f0feeffae4ec3aa05 Mon Sep 17 00:00:00 2001
From b8de888a2b4aad939ff4373893210334e581f270 Mon Sep 17 00:00:00 2001
From: Michal Vyskocil <mvyskocil@suse.cz>
Date: Wed, 26 Aug 2009 11:08:36 +0200
Subject: [PATCH] obfuscated password support in oscrc
Subject: [PATCH 16/19] obfuscated password support in oscrc
The osc client introduced an obfuscated passwords (not secure, but many
times requested by a community), so this patch to readconfig method adds
@@ -46,5 +46,5 @@ index 35202a4..0d88db1 100644
except NoOptionError, ne:
return
--
1.6.3.3
1.7.4.1

View File

@@ -0,0 +1,25 @@
From 77bbfe33af859cde6a0cf3423aa5f52748dfed50 Mon Sep 17 00:00:00 2001
From: Michal Vyskocil <mvyskocil@suse.cz>
Date: Fri, 4 Sep 2009 09:54:42 +0200
Subject: [PATCH 17/19] fix typo in url argument
---
bugzilla/nvlbugzilla.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/bugzilla/nvlbugzilla.py b/bugzilla/nvlbugzilla.py
index 0d88db1..fe15fd6 100644
--- a/bugzilla/nvlbugzilla.py
+++ b/bugzilla/nvlbugzilla.py
@@ -57,7 +57,7 @@ class NovellBugzilla(Bugzilla32):
self._expires = expires
super(NovellBugzilla, self).__init__(**kwargs)
# url argument exists only for backward compatibility, but is always set to same url
- self._url = self.__class__.bugzilla_url
+ self.url = self.__class__.bugzilla_url
def __get_expiration(self):
return self._expires
--
1.7.4.1

View File

@@ -0,0 +1,26 @@
From ccea238ede22c81100c0456ede42642f2f82947b Mon Sep 17 00:00:00 2001
From: Jan Matejek <jan.matejek@novell.com>
Date: Mon, 23 May 2011 14:20:57 +0200
Subject: [PATCH 18/19] novell bugzilla support in getBugzillaClassForURL
---
bugzilla/__init__.py | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/bugzilla/__init__.py b/bugzilla/__init__.py
index 97d8706..8b26835 100644
--- a/bugzilla/__init__.py
+++ b/bugzilla/__init__.py
@@ -23,6 +23,9 @@ classlist = ['Bugzilla3', 'Bugzilla32', 'Bugzilla34', 'Bugzilla36',
def getBugzillaClassForURL(url):
log.debug("Choosing subclass for %s" % url)
+ if url.startswith('https://bugzilla.novell.com'):
+ return NovellBugzilla
+
s = xmlrpclib.ServerProxy(url)
rhbz = False
bzversion = ''
--
1.7.4.1

View File

@@ -0,0 +1,36 @@
From 82b1b6bdac75814fc94843934d9cfe4fcdef06d4 Mon Sep 17 00:00:00 2001
From: Michal Vyskocil <mvyskocil@suse.cz>
Date: Mon, 23 May 2011 14:24:58 +0200
Subject: [PATCH] novell bugzilla run on 3.4
---
bugzilla/nvlbugzilla.py | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/bugzilla/nvlbugzilla.py b/bugzilla/nvlbugzilla.py
index fe15fd6..4acae00 100644
--- a/bugzilla/nvlbugzilla.py
+++ b/bugzilla/nvlbugzilla.py
@@ -11,7 +11,7 @@
#from bugzilla.base import BugzillaError, log
import bugzilla.base
-from bugzilla import Bugzilla32
+from bugzilla import Bugzilla34
import urllib
import urllib2
@@ -21,8 +21,8 @@ import time
import re
import os
-class NovellBugzilla(Bugzilla32):
- '''bugzilla.novell.com is a standard bugzilla 3.2 with some extensions, but
+class NovellBugzilla(Bugzilla34):
+ '''bugzilla.novell.com is a standard bugzilla 3.4 with some extensions, but
it uses an proprietary and non-standard IChain login system. This class
reimplements a login method which is compatible with iChain.
--
1.7.4.1

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:666684ffbc4ddf6d3b59ae5e21d557747a473434d67e4b53131b38756f267d39
size 35088

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f17e9dad067461d070a27b17c917b7ae20e6bbf1d7db561b2a8608c9aa4a1d03
size 38743

View File

@@ -1,3 +1,24 @@
-------------------------------------------------------------------
Mon May 23 12:36:47 UTC 2011 - mvyskocil@suse.cz
- update to 0.6.1
* many new parameters for bugzilla command-line tool like --target_milestone,
--private, --status, --assignee, et all
* add support for Bugzilla 36
* Unicode related fixes
- SUSE specific fixes
* novell bugzilla support in getBugzillaClassForURL
* obfuscated password support in oscrc
* move novell bugzilla to 3.4
* xmlrpclib changes done in python 2.7 from master [bug#685842]
- create suse branch for stashing SUSE specific changes
https://gitorious.org/opensuse/python-bugzilla/commits/suse
-------------------------------------------------------------------
Thu Jun 17 15:55:51 CEST 2010 - matejcik@suse.cz
- recognize Novell bugzilla in default constructor
-------------------------------------------------------------------
Wed Aug 26 09:18:54 UTC 2009 - mvyskocil@suse.cz

View File

@@ -1,7 +1,7 @@
#
# spec file for package python-bugzilla (Version 0.5)
#
# Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany.
# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,20 +19,24 @@
Name: python-bugzilla
Version: 0.5
Release: 2
Version: 0.6.1
Release: 1
Summary: Python library for bugzilla
Group: Development/Libraries/Python
License: GPL v2 or later
License: GPLv2+
Url: https://fedorahosted.org/python-bugzilla/
#git clone git://git.fedorahosted.org/git/python-bugzilla python-bugzilla-0.5
#tar --exclude-vcs -cjf python-bugzilla-0.5.tar.bz2 python-bugzilla-0.5/
Source: https://fedorahosted.org/releases/p/y/python-bugzilla/%{name}-%{version}.tar.bz2
Patch0: 0001-Use-LWPCookieJar-by-default.patch
Patch1: 0002-NovellBugzilla-implementation.patch
Patch2: 0003-obfuscated-password-support.patch
# generated from python-bugzilla/suse
# https://gitorious.org/opensuse/python-bugzilla/commits/suse
# cherry-picked patches from git format-patch suse...0.6.1
Patch0: 0012-Fix-for-httplib-xmlrpclib-changes-in-py2.7.patch
Patch1: 0016-obfuscated-password-support-in-oscrc.patch
Patch2: 0017-fix-typo-in-url-argument.patch
Patch3: 0018-novell-bugzilla-support-in-getBugzillaClassForURL.patch
Patch4: 0019-novell-bugzilla-run-on-3.4.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: python-devel
BuildArch: noarch
%{py_requires}
%description
@@ -46,16 +50,13 @@ It also includes a 'bugzilla' commandline client which can be used for quick,
ad-hoc bugzilla jiggery-pokery. I guess you could use it in shell scripts too,
but gosh - why not just write something in Python instead?
This package contains a set of patches enabling an access for Novell bugzilla.
AUTHOR
Will Woods <wwoods@redhat.com>, Oct 16 2008
%prep
%setup -q
%patch0 -p1 -b .use-lwpcookiejar-by-default
%patch1 -p1 -b .novellbugzilla-implementation
%patch2 -p1 -b .obfuscated-password
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%build
export CFLAGS="%{optflags}"