summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitbake-dev/AUTHORS2
-rw-r--r--bitbake-dev/ChangeLog2
-rwxr-xr-xbitbake-dev/bin/bitbake14
-rw-r--r--bitbake-dev/lib/bb/command.py1
-rw-r--r--bitbake-dev/lib/bb/cooker.py10
-rw-r--r--bitbake-dev/lib/bb/fetch/__init__.py50
-rw-r--r--bitbake-dev/lib/bb/fetch/git.py42
-rw-r--r--bitbake-dev/lib/bb/providers.py2
-rw-r--r--bitbake-dev/lib/bb/server/__init__.py1
-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.py145
-rw-r--r--bitbake-dev/lib/bb/utils.py16
12 files changed, 237 insertions, 48 deletions
diff --git a/bitbake-dev/AUTHORS b/bitbake-dev/AUTHORS
index 9d592608bb..a4014b1e39 100644
--- a/bitbake-dev/AUTHORS
+++ b/bitbake-dev/AUTHORS
@@ -2,7 +2,7 @@ Tim Ansell <mithro@mithis.net>
2Phil Blundell <pb@handhelds.org> 2Phil Blundell <pb@handhelds.org>
3Seb Frankengul <seb@frankengul.org> 3Seb Frankengul <seb@frankengul.org>
4Holger Freyther <zecke@handhelds.org> 4Holger Freyther <zecke@handhelds.org>
5Marcin Juszkiewicz <marcin@haerwu.biz> 5Marcin Juszkiewicz <marcin@juszkiewicz.com.pl>
6Chris Larson <kergoth@handhelds.org> 6Chris Larson <kergoth@handhelds.org>
7Ulrich Luckas <luckas@musoft.de> 7Ulrich Luckas <luckas@musoft.de>
8Mickey Lauer <mickey@Vanille.de> 8Mickey Lauer <mickey@Vanille.de>
diff --git a/bitbake-dev/ChangeLog b/bitbake-dev/ChangeLog
index 65c5e4bf36..22124cb7ea 100644
--- a/bitbake-dev/ChangeLog
+++ b/bitbake-dev/ChangeLog
@@ -176,6 +176,8 @@ Changes in Bitbake 1.9.x:
176 - Set HOME environmental variable when running fetcher commands (from Poky) 176 - Set HOME environmental variable when running fetcher commands (from Poky)
177 - Make sure allowed variables inherited from the environment are exported again (from Poky) 177 - Make sure allowed variables inherited from the environment are exported again (from Poky)
178 - When running a stage task in bbshell, run populate_staging, not the stage task (from Poky) 178 - When running a stage task in bbshell, run populate_staging, not the stage task (from Poky)
179 - Fix + character escaping from PACKAGES_DYNAMIC (thanks Otavio Salvador)
180 - Addition of BBCLASSEXTEND support for allowing one recipe to provide multiple targets (from Poky)
179 181
180Changes in Bitbake 1.8.0: 182Changes in Bitbake 1.8.0:
181 - Release 1.7.x as a stable series 183 - Release 1.7.x as a stable series
diff --git a/bitbake-dev/bin/bitbake b/bitbake-dev/bin/bitbake
index 34c49b8c58..cabdf2b452 100755
--- a/bitbake-dev/bin/bitbake
+++ b/bitbake-dev/bin/bitbake
@@ -144,7 +144,11 @@ Default BBFILES are the .bb files in the current directory.""" )
144 configuration.pkgs_to_build = [] 144 configuration.pkgs_to_build = []
145 configuration.pkgs_to_build.extend(args[1:]) 145 configuration.pkgs_to_build.extend(args[1:])
146 146
147 cooker = bb.cooker.BBCooker(configuration) 147 # Save a logfile for cooker into the current working directory. When the
148 # server is daemonized this logfile will be truncated.
149 cooker_logfile = os.path.join (os.getcwd(), "cooker.log")
150
151 cooker = bb.cooker.BBCooker(configuration, bb.server.xmlrpc)
148 152
149 # Clear away any spurious environment variables. But don't wipe the 153 # Clear away any spurious environment variables. But don't wipe the
150 # environment totally. This is necessary to ensure the correct operation 154 # environment totally. This is necessary to ensure the correct operation
@@ -152,13 +156,13 @@ Default BBFILES are the .bb files in the current directory.""" )
152 bb.utils.clean_environment() 156 bb.utils.clean_environment()
153 157
154 cooker.parseCommandLine() 158 cooker.parseCommandLine()
159
160
161
162
155 host = cooker.server.host 163 host = cooker.server.host
156 port = cooker.server.port 164 port = cooker.server.port
157 165
158 # Save a logfile for cooker into the current working directory. When the
159 # server is daemonized this logfile will be truncated.
160 cooker_logfile = os.path.join (os.getcwd(), "cooker.log")
161
162 daemonize.createDaemon(cooker.serve, cooker_logfile) 166 daemonize.createDaemon(cooker.serve, cooker_logfile)
163 del cooker 167 del cooker
164 168
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 @@
25import sys, os, getopt, glob, copy, os.path, re, time 25import sys, os, getopt, glob, copy, os.path, re, time
26import bb 26import bb
27from bb import utils, data, parse, event, cache, providers, taskdata, runqueue 27from bb import utils, data, parse, event, cache, providers, taskdata, runqueue
28from bb import xmlrpcserver, command 28from bb import command
29import bb.server.xmlrpc
29import itertools, sre_constants 30import itertools, sre_constants
30 31
31class MultipleMatches(Exception): 32class 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
150def go(d): 155def 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
29class Git(Fetch): 29class 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
34import bb
35import xmlrpclib
36
37DEBUG = False
38
39from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
40import inspect, select
41
42class 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
80class 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
22digits = "0123456789" 22digits = "0123456789"
23ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 23ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
24separators = ".-"
24 25
25import re, fcntl, os 26import re, fcntl, os, types
26 27
27def explode_version(s): 28def 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
45def vercmp_part(a, b): 47def 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: