diff options
Diffstat (limited to 'bitbake-dev/lib')
-rw-r--r-- | bitbake-dev/lib/bb/command.py | 1 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/cooker.py | 10 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/fetch/__init__.py | 50 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/fetch/git.py | 42 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/providers.py | 2 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/server/__init__.py | 1 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/server/none.py (renamed from bitbake-dev/lib/bb/xmlrpcserver.py) | 0 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/server/xmlrpc.py | 145 | ||||
-rw-r--r-- | bitbake-dev/lib/bb/utils.py | 16 |
9 files changed, 225 insertions, 42 deletions
diff --git a/bitbake-dev/lib/bb/command.py b/bitbake-dev/lib/bb/command.py index e7c3770ffc..1a1bf00b33 100644 --- a/bitbake-dev/lib/bb/command.py +++ b/bitbake-dev/lib/bb/command.py | |||
@@ -57,7 +57,6 @@ class Command: | |||
57 | async_cmds[command] = (method) | 57 | async_cmds[command] = (method) |
58 | 58 | ||
59 | def runCommand(self, commandline): | 59 | def runCommand(self, commandline): |
60 | bb.debug("Running command %s" % commandline) | ||
61 | try: | 60 | try: |
62 | command = commandline.pop(0) | 61 | command = commandline.pop(0) |
63 | if command in CommandsSync.__dict__: | 62 | if command in CommandsSync.__dict__: |
diff --git a/bitbake-dev/lib/bb/cooker.py b/bitbake-dev/lib/bb/cooker.py index b2b237b4c7..1bf7d4bd14 100644 --- a/bitbake-dev/lib/bb/cooker.py +++ b/bitbake-dev/lib/bb/cooker.py | |||
@@ -25,7 +25,8 @@ | |||
25 | import sys, os, getopt, glob, copy, os.path, re, time | 25 | import sys, os, getopt, glob, copy, os.path, re, time |
26 | import bb | 26 | import bb |
27 | from bb import utils, data, parse, event, cache, providers, taskdata, runqueue | 27 | from bb import utils, data, parse, event, cache, providers, taskdata, runqueue |
28 | from bb import xmlrpcserver, command | 28 | from bb import command |
29 | import bb.server.xmlrpc | ||
29 | import itertools, sre_constants | 30 | import itertools, sre_constants |
30 | 31 | ||
31 | class MultipleMatches(Exception): | 32 | class MultipleMatches(Exception): |
@@ -62,14 +63,13 @@ class BBCooker: | |||
62 | Manages one bitbake build run | 63 | Manages one bitbake build run |
63 | """ | 64 | """ |
64 | 65 | ||
65 | def __init__(self, configuration): | 66 | def __init__(self, configuration, server): |
66 | self.status = None | 67 | self.status = None |
67 | 68 | ||
68 | self.cache = None | 69 | self.cache = None |
69 | self.bb_cache = None | 70 | self.bb_cache = None |
70 | 71 | ||
71 | self.server = bb.xmlrpcserver.BitBakeXMLRPCServer(self) | 72 | self.server = server.BitBakeServer(self) |
72 | #self.server.register_function(self.showEnvironment) | ||
73 | 73 | ||
74 | self.configuration = configuration | 74 | self.configuration = configuration |
75 | 75 | ||
@@ -680,7 +680,7 @@ class BBCooker: | |||
680 | retval = False | 680 | retval = False |
681 | if not retval: | 681 | if not retval: |
682 | self.command.finishAsyncCommand() | 682 | self.command.finishAsyncCommand() |
683 | bb.event.fire(bb.event.BuildCompleted(buildname, targets, self.configuration.event_data, failures)) | 683 | bb.event.fire(bb.event.BuildCompleted(buildname, item, self.configuration.event_data, failures)) |
684 | return False | 684 | return False |
685 | return 0.5 | 685 | return 0.5 |
686 | 686 | ||
diff --git a/bitbake-dev/lib/bb/fetch/__init__.py b/bitbake-dev/lib/bb/fetch/__init__.py index b8a00107e2..ab4658bc3b 100644 --- a/bitbake-dev/lib/bb/fetch/__init__.py +++ b/bitbake-dev/lib/bb/fetch/__init__.py | |||
@@ -99,6 +99,11 @@ def fetcher_init(d): | |||
99 | pd.delDomain("BB_URI_HEADREVS") | 99 | pd.delDomain("BB_URI_HEADREVS") |
100 | else: | 100 | else: |
101 | bb.msg.fatal(bb.msg.domain.Fetcher, "Invalid SRCREV cache policy of: %s" % srcrev_policy) | 101 | bb.msg.fatal(bb.msg.domain.Fetcher, "Invalid SRCREV cache policy of: %s" % srcrev_policy) |
102 | |||
103 | for m in methods: | ||
104 | if hasattr(m, "init"): | ||
105 | m.init(d) | ||
106 | |||
102 | # Make sure our domains exist | 107 | # Make sure our domains exist |
103 | pd.addDomain("BB_URI_HEADREVS") | 108 | pd.addDomain("BB_URI_HEADREVS") |
104 | pd.addDomain("BB_URI_LOCALCOUNT") | 109 | pd.addDomain("BB_URI_LOCALCOUNT") |
@@ -147,14 +152,16 @@ def init(urls, d, setup = True): | |||
147 | urldata_cache[fn] = urldata | 152 | urldata_cache[fn] = urldata |
148 | return urldata | 153 | return urldata |
149 | 154 | ||
150 | def go(d): | 155 | def go(d, urls = None): |
151 | """ | 156 | """ |
152 | Fetch all urls | 157 | Fetch all urls |
153 | init must have previously been called | 158 | init must have previously been called |
154 | """ | 159 | """ |
155 | urldata = init([], d, True) | 160 | if not urls: |
161 | urls = d.getVar("SRC_URI", 1).split() | ||
162 | urldata = init(urls, d, True) | ||
156 | 163 | ||
157 | for u in urldata: | 164 | for u in urls: |
158 | ud = urldata[u] | 165 | ud = urldata[u] |
159 | m = ud.method | 166 | m = ud.method |
160 | if ud.localfile: | 167 | if ud.localfile: |
@@ -465,6 +472,23 @@ class Fetch(object): | |||
465 | 472 | ||
466 | srcrev_internal_helper = staticmethod(srcrev_internal_helper) | 473 | srcrev_internal_helper = staticmethod(srcrev_internal_helper) |
467 | 474 | ||
475 | def localcount_internal_helper(ud, d): | ||
476 | """ | ||
477 | Return: | ||
478 | a) a locked localcount if specified | ||
479 | b) None otherwise | ||
480 | """ | ||
481 | |||
482 | localcount= None | ||
483 | if 'name' in ud.parm: | ||
484 | pn = data.getVar("PN", d, 1) | ||
485 | localcount = data.getVar("LOCALCOUNT_" + ud.parm['name'], d, 1) | ||
486 | if not localcount: | ||
487 | localcount = data.getVar("LOCALCOUNT", d, 1) | ||
488 | return localcount | ||
489 | |||
490 | localcount_internal_helper = staticmethod(localcount_internal_helper) | ||
491 | |||
468 | def try_mirror(d, tarfn): | 492 | def try_mirror(d, tarfn): |
469 | """ | 493 | """ |
470 | Try to use a mirrored version of the sources. We do this | 494 | Try to use a mirrored version of the sources. We do this |
@@ -553,12 +577,7 @@ class Fetch(object): | |||
553 | """ | 577 | """ |
554 | 578 | ||
555 | """ | 579 | """ |
556 | has_sortable_valid = hasattr(self, "_sortable_revision_valid") | 580 | if hasattr(self, "_sortable_revision"): |
557 | has_sortable = hasattr(self, "_sortable_revision") | ||
558 | |||
559 | if has_sortable and not has_sortable_valid: | ||
560 | return self._sortable_revision(url, ud, d) | ||
561 | elif has_sortable and self._sortable_revision_valid(url, ud, d): | ||
562 | return self._sortable_revision(url, ud, d) | 581 | return self._sortable_revision(url, ud, d) |
563 | 582 | ||
564 | pd = persist_data.PersistData(d) | 583 | pd = persist_data.PersistData(d) |
@@ -566,13 +585,24 @@ class Fetch(object): | |||
566 | 585 | ||
567 | latest_rev = self._build_revision(url, ud, d) | 586 | latest_rev = self._build_revision(url, ud, d) |
568 | last_rev = pd.getValue("BB_URI_LOCALCOUNT", key + "_rev") | 587 | last_rev = pd.getValue("BB_URI_LOCALCOUNT", key + "_rev") |
569 | count = pd.getValue("BB_URI_LOCALCOUNT", key + "_count") | 588 | uselocalcount = bb.data.getVar("BB_LOCALCOUNT_OVERRIDE", d, True) or False |
589 | count = None | ||
590 | if uselocalcount: | ||
591 | count = Fetch.localcount_internal_helper(ud, d) | ||
592 | if count is None: | ||
593 | count = pd.getValue("BB_URI_LOCALCOUNT", key + "_count") | ||
570 | 594 | ||
571 | if last_rev == latest_rev: | 595 | if last_rev == latest_rev: |
572 | return str(count + "+" + latest_rev) | 596 | return str(count + "+" + latest_rev) |
573 | 597 | ||
598 | buildindex_provided = hasattr(self, "_sortable_buildindex") | ||
599 | if buildindex_provided: | ||
600 | count = self._sortable_buildindex(url, ud, d, latest_rev) | ||
601 | |||
574 | if count is None: | 602 | if count is None: |
575 | count = "0" | 603 | count = "0" |
604 | elif uselocalcount or buildindex_provided: | ||
605 | count = str(count) | ||
576 | else: | 606 | else: |
577 | count = str(int(count) + 1) | 607 | count = str(int(count) + 1) |
578 | 608 | ||
diff --git a/bitbake-dev/lib/bb/fetch/git.py b/bitbake-dev/lib/bb/fetch/git.py index 911c5e437f..43053d6c46 100644 --- a/bitbake-dev/lib/bb/fetch/git.py +++ b/bitbake-dev/lib/bb/fetch/git.py | |||
@@ -28,6 +28,12 @@ from bb.fetch import runfetchcmd | |||
28 | 28 | ||
29 | class Git(Fetch): | 29 | class Git(Fetch): |
30 | """Class to fetch a module or modules from git repositories""" | 30 | """Class to fetch a module or modules from git repositories""" |
31 | def init(self, d): | ||
32 | # | ||
33 | # Only enable _sortable revision if the key is set | ||
34 | # | ||
35 | if bb.data.getVar("BB_GIT_CLONE_FOR_SRCREV", d, True): | ||
36 | self._sortable_buildindex = self._sortable_buildindex_disabled | ||
31 | def supports(self, url, ud, d): | 37 | def supports(self, url, ud, d): |
32 | """ | 38 | """ |
33 | Check to see if a given url can be fetched with git. | 39 | Check to see if a given url can be fetched with git. |
@@ -145,44 +151,32 @@ class Git(Fetch): | |||
145 | def _build_revision(self, url, ud, d): | 151 | def _build_revision(self, url, ud, d): |
146 | return ud.tag | 152 | return ud.tag |
147 | 153 | ||
148 | def _sortable_revision_valid(self, url, ud, d): | 154 | def _sortable_buildindex_disabled(self, url, ud, d, rev): |
149 | return bb.data.getVar("BB_GIT_CLONE_FOR_SRCREV", d, True) or False | ||
150 | |||
151 | def _sortable_revision(self, url, ud, d): | ||
152 | """ | 155 | """ |
153 | This is only called when _sortable_revision_valid called true | 156 | Return a suitable buildindex for the revision specified. This is done by counting revisions |
154 | 157 | using "git rev-list" which may or may not work in different circumstances. | |
155 | We will have to get the updated revision. | ||
156 | """ | 158 | """ |
157 | gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.')) | 159 | gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.')) |
158 | repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname) | 160 | repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname) |
159 | 161 | ||
160 | key = "GIT_CACHED_REVISION-%s-%s" % (gitsrcname, ud.tag) | ||
161 | if bb.data.getVar(key, d): | ||
162 | return bb.data.getVar(key, d) | ||
163 | |||
164 | |||
165 | # Runtime warning on wrongly configured sources | ||
166 | if ud.tag == "1": | ||
167 | bb.msg.error(1, bb.msg.domain.Fetcher, "SRCREV is '1'. This indicates a configuration error of %s" % url) | ||
168 | return "0+1" | ||
169 | |||
170 | cwd = os.getcwd() | 162 | cwd = os.getcwd() |
171 | 163 | ||
172 | # Check if we have the rev already | 164 | # Check if we have the rev already |
173 | if not os.path.exists(repodir): | 165 | if not os.path.exists(repodir): |
174 | print "no repo" | ||
175 | self.go(None, ud, d) | 166 | self.go(None, ud, d) |
167 | if not os.path.exists(repodir): | ||
168 | bb.msg.error(bb.msg.domain.Fetcher, "GIT repository for %s doesn't exist in %s, cannot get sortable buildnumber, using old value" % (url, repodir)) | ||
169 | return None | ||
170 | |||
176 | 171 | ||
177 | os.chdir(repodir) | 172 | os.chdir(repodir) |
178 | if not self._contains_ref(ud.tag, d): | 173 | if not self._contains_ref(rev, d): |
179 | self.go(None, ud, d) | 174 | self.go(None, ud, d) |
180 | 175 | ||
181 | output = runfetchcmd("git rev-list %s -- 2> /dev/null | wc -l" % ud.tag, d, quiet=True) | 176 | output = runfetchcmd("git rev-list %s -- 2> /dev/null | wc -l" % rev, d, quiet=True) |
182 | os.chdir(cwd) | 177 | os.chdir(cwd) |
183 | 178 | ||
184 | sortable_revision = "%s+%s" % (output.split()[0], ud.tag) | 179 | buildindex = "%s" % output.split()[0] |
185 | bb.data.setVar(key, sortable_revision, d) | 180 | bb.msg.debug(1, bb.msg.domain.Fetcher, "GIT repository for %s in %s is returning %s revisions in rev-list before %s" % (url, repodir, buildindex, rev)) |
186 | return sortable_revision | 181 | return buildindex |
187 | |||
188 | 182 | ||
diff --git a/bitbake-dev/lib/bb/providers.py b/bitbake-dev/lib/bb/providers.py index 8970fb3be1..6c1cf78eb3 100644 --- a/bitbake-dev/lib/bb/providers.py +++ b/bitbake-dev/lib/bb/providers.py | |||
@@ -191,7 +191,7 @@ def _filterProviders(providers, item, cfgData, dataCache): | |||
191 | eligible.append(preferred_versions[pn][1]) | 191 | eligible.append(preferred_versions[pn][1]) |
192 | 192 | ||
193 | # Now add latest verisons | 193 | # Now add latest verisons |
194 | for pn in pkg_pn.keys(): | 194 | for pn in sortpkg_pn.keys(): |
195 | if pn in preferred_versions and preferred_versions[pn][1]: | 195 | if pn in preferred_versions and preferred_versions[pn][1]: |
196 | continue | 196 | continue |
197 | preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0]) | 197 | preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0]) |
diff --git a/bitbake-dev/lib/bb/server/__init__.py b/bitbake-dev/lib/bb/server/__init__.py new file mode 100644 index 0000000000..0dd04cf724 --- /dev/null +++ b/bitbake-dev/lib/bb/server/__init__.py | |||
@@ -0,0 +1 @@ | |||
import xmlrpc | |||
diff --git a/bitbake-dev/lib/bb/xmlrpcserver.py b/bitbake-dev/lib/bb/server/none.py index ef061bc5dd..ef061bc5dd 100644 --- a/bitbake-dev/lib/bb/xmlrpcserver.py +++ b/bitbake-dev/lib/bb/server/none.py | |||
diff --git a/bitbake-dev/lib/bb/server/xmlrpc.py b/bitbake-dev/lib/bb/server/xmlrpc.py new file mode 100644 index 0000000000..c5937abd66 --- /dev/null +++ b/bitbake-dev/lib/bb/server/xmlrpc.py | |||
@@ -0,0 +1,145 @@ | |||
1 | # | ||
2 | # BitBake XMLRPC Server | ||
3 | # | ||
4 | # Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer | ||
5 | # Copyright (C) 2006 - 2008 Richard Purdie | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License version 2 as | ||
9 | # published by the Free Software Foundation. | ||
10 | # | ||
11 | # This program is distributed in the hope that it will be useful, | ||
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | # GNU General Public License for more details. | ||
15 | # | ||
16 | # You should have received a copy of the GNU General Public License along | ||
17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | |||
20 | """ | ||
21 | This module implements an xmlrpc server for BitBake. | ||
22 | |||
23 | Use this by deriving a class from BitBakeXMLRPCServer and then adding | ||
24 | methods which you want to "export" via XMLRPC. If the methods have the | ||
25 | prefix xmlrpc_, then registering those function will happen automatically, | ||
26 | if not, you need to call register_function. | ||
27 | |||
28 | Use register_idle_function() to add a function which the xmlrpc server | ||
29 | calls from within server_forever when no requests are pending. Make sure | ||
30 | that those functions are non-blocking or else you will introduce latency | ||
31 | in the server's main loop. | ||
32 | """ | ||
33 | |||
34 | import bb | ||
35 | import xmlrpclib | ||
36 | |||
37 | DEBUG = False | ||
38 | |||
39 | from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler | ||
40 | import inspect, select | ||
41 | |||
42 | class BitBakeServerCommands(): | ||
43 | def __init__(self, server, cooker): | ||
44 | self.cooker = cooker | ||
45 | self.server = server | ||
46 | |||
47 | def registerEventHandler(self, host, port): | ||
48 | """ | ||
49 | Register a remote UI Event Handler | ||
50 | """ | ||
51 | s = xmlrpclib.Server("http://%s:%d" % (host, port), allow_none=True) | ||
52 | return bb.event.register_UIHhandler(s) | ||
53 | |||
54 | def unregisterEventHandler(self, handlerNum): | ||
55 | """ | ||
56 | Unregister a remote UI Event Handler | ||
57 | """ | ||
58 | return bb.event.unregister_UIHhandler(handlerNum) | ||
59 | |||
60 | def runCommand(self, command): | ||
61 | """ | ||
62 | Run a cooker command on the server | ||
63 | """ | ||
64 | return self.cooker.command.runCommand(command) | ||
65 | |||
66 | def terminateServer(self): | ||
67 | """ | ||
68 | Trigger the server to quit | ||
69 | """ | ||
70 | self.server.quit = True | ||
71 | print "Server (cooker) exitting" | ||
72 | return | ||
73 | |||
74 | def ping(self): | ||
75 | """ | ||
76 | Dummy method which can be used to check the server is still alive | ||
77 | """ | ||
78 | return True | ||
79 | |||
80 | class BitBakeServer(SimpleXMLRPCServer): | ||
81 | # remove this when you're done with debugging | ||
82 | # allow_reuse_address = True | ||
83 | |||
84 | def __init__(self, cooker, interface = ("localhost", 0)): | ||
85 | """ | ||
86 | Constructor | ||
87 | """ | ||
88 | SimpleXMLRPCServer.__init__(self, interface, | ||
89 | requestHandler=SimpleXMLRPCRequestHandler, | ||
90 | logRequests=False, allow_none=True) | ||
91 | self._idlefuns = {} | ||
92 | self.host, self.port = self.socket.getsockname() | ||
93 | #self.register_introspection_functions() | ||
94 | commands = BitBakeServerCommands(self, cooker) | ||
95 | self.autoregister_all_functions(commands, "") | ||
96 | |||
97 | def autoregister_all_functions(self, context, prefix): | ||
98 | """ | ||
99 | Convenience method for registering all functions in the scope | ||
100 | of this class that start with a common prefix | ||
101 | """ | ||
102 | methodlist = inspect.getmembers(context, inspect.ismethod) | ||
103 | for name, method in methodlist: | ||
104 | if name.startswith(prefix): | ||
105 | self.register_function(method, name[len(prefix):]) | ||
106 | |||
107 | def register_idle_function(self, function, data): | ||
108 | """Register a function to be called while the server is idle""" | ||
109 | assert callable(function) | ||
110 | self._idlefuns[function] = data | ||
111 | |||
112 | def serve_forever(self): | ||
113 | """ | ||
114 | Serve Requests. Overloaded to honor a quit command | ||
115 | """ | ||
116 | self.quit = False | ||
117 | while not self.quit: | ||
118 | #print "Idle queue length %s" % len(self._idlefuns) | ||
119 | if len(self._idlefuns) == 0: | ||
120 | self.timeout = None | ||
121 | else: | ||
122 | self.timeout = 0 | ||
123 | self.handle_request() | ||
124 | #print "Idle timeout, running idle functions" | ||
125 | for function, data in self._idlefuns.items(): | ||
126 | try: | ||
127 | retval = function(self, data, False) | ||
128 | if not retval: | ||
129 | del self._idlefuns[function] | ||
130 | except SystemExit: | ||
131 | raise | ||
132 | except: | ||
133 | import traceback | ||
134 | traceback.print_exc() | ||
135 | pass | ||
136 | |||
137 | # Tell idle functions we're exiting | ||
138 | for function, data in self._idlefuns.items(): | ||
139 | try: | ||
140 | retval = function(self, data, True) | ||
141 | except: | ||
142 | pass | ||
143 | |||
144 | self.server_close() | ||
145 | return | ||
diff --git a/bitbake-dev/lib/bb/utils.py b/bitbake-dev/lib/bb/utils.py index 603c926422..5b0aaba4a7 100644 --- a/bitbake-dev/lib/bb/utils.py +++ b/bitbake-dev/lib/bb/utils.py | |||
@@ -21,8 +21,9 @@ BitBake Utility Functions | |||
21 | 21 | ||
22 | digits = "0123456789" | 22 | digits = "0123456789" |
23 | ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | 23 | ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" |
24 | separators = ".-" | ||
24 | 25 | ||
25 | import re, fcntl, os | 26 | import re, fcntl, os, types |
26 | 27 | ||
27 | def explode_version(s): | 28 | def explode_version(s): |
28 | r = [] | 29 | r = [] |
@@ -39,12 +40,15 @@ def explode_version(s): | |||
39 | r.append(m.group(1)) | 40 | r.append(m.group(1)) |
40 | s = m.group(2) | 41 | s = m.group(2) |
41 | continue | 42 | continue |
43 | r.append(s[0]) | ||
42 | s = s[1:] | 44 | s = s[1:] |
43 | return r | 45 | return r |
44 | 46 | ||
45 | def vercmp_part(a, b): | 47 | def vercmp_part(a, b): |
46 | va = explode_version(a) | 48 | va = explode_version(a) |
47 | vb = explode_version(b) | 49 | vb = explode_version(b) |
50 | sa = False | ||
51 | sb = False | ||
48 | while True: | 52 | while True: |
49 | if va == []: | 53 | if va == []: |
50 | ca = None | 54 | ca = None |
@@ -56,6 +60,16 @@ def vercmp_part(a, b): | |||
56 | cb = vb.pop(0) | 60 | cb = vb.pop(0) |
57 | if ca == None and cb == None: | 61 | if ca == None and cb == None: |
58 | return 0 | 62 | return 0 |
63 | |||
64 | if type(ca) is types.StringType: | ||
65 | sa = ca in separators | ||
66 | if type(cb) is types.StringType: | ||
67 | sb = cb in separators | ||
68 | if sa and not sb: | ||
69 | return -1 | ||
70 | if not sa and sb: | ||
71 | return 1 | ||
72 | |||
59 | if ca > cb: | 73 | if ca > cb: |
60 | return 1 | 74 | return 1 |
61 | if ca < cb: | 75 | if ca < cb: |