summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/utils.py')
-rw-r--r--bitbake/lib/bb/utils.py185
1 files changed, 93 insertions, 92 deletions
diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py
index 5015ee440a..93c158c604 100644
--- a/bitbake/lib/bb/utils.py
+++ b/bitbake/lib/bb/utils.py
@@ -19,11 +19,12 @@ BitBake Utility Functions
19# with this program; if not, write to the Free Software Foundation, Inc., 19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 21
22separators = ".-"
23
24import re, fcntl, os, types, bb, string, stat, shutil, time 22import re, fcntl, os, types, bb, string, stat, shutil, time
25from commands import getstatusoutput 23from commands import getstatusoutput
26 24
25# Version comparison
26separators = ".-"
27
27# Context used in better_exec, eval 28# Context used in better_exec, eval
28_context = { 29_context = {
29 "os": os, 30 "os": os,
@@ -92,19 +93,19 @@ def vercmp(ta, tb):
92 r = vercmp_part(ra, rb) 93 r = vercmp_part(ra, rb)
93 return r 94 return r
94 95
95_package_weights_ = {"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} # dicts are unordered 96_package_weights_ = {"pre":-2, "p":0, "alpha":-4, "beta":-3, "rc":-1} # dicts are unordered
96_package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list 97_package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list
97 98
98def relparse(myver): 99def relparse(myver):
99 """Parses the last elements of a version number into a triplet, that can 100 """Parses the last elements of a version number into a triplet, that can
100 later be compared. 101 later be compared.
101 """ 102 """
102 103
103 number = 0 104 number = 0
104 p1 = 0 105 p1 = 0
105 p2 = 0 106 p2 = 0
106 mynewver = myver.split('_') 107 mynewver = myver.split('_')
107 if len(mynewver)==2: 108 if len(mynewver) == 2:
108 # an _package_weights_ 109 # an _package_weights_
109 number = float(mynewver[0]) 110 number = float(mynewver[0])
110 match = 0 111 match = 0
@@ -132,15 +133,15 @@ def relparse(myver):
132 divider = len(myver)-1 133 divider = len(myver)-1
133 if myver[divider:] not in "1234567890": 134 if myver[divider:] not in "1234567890":
134 #letter at end 135 #letter at end
135 p1 = ord(myver[divider:]) 136 p1 = ord(myver[divider:])
136 number = float(myver[0:divider]) 137 number = float(myver[0:divider])
137 else: 138 else:
138 number = float(myver) 139 number = float(myver)
139 return [number,p1,p2] 140 return [number, p1, p2]
140 141
141__vercmp_cache__ = {} 142__vercmp_cache__ = {}
142 143
143def vercmp_string(val1,val2): 144def vercmp_string(val1, val2):
144 """This takes two version strings and returns an integer to tell you whether 145 """This takes two version strings and returns an integer to tell you whether
145 the versions are the same, val1>val2 or val2>val1. 146 the versions are the same, val1>val2 or val2>val1.
146 """ 147 """
@@ -148,13 +149,13 @@ def vercmp_string(val1,val2):
148 # quick short-circuit 149 # quick short-circuit
149 if val1 == val2: 150 if val1 == val2:
150 return 0 151 return 0
151 valkey = val1+" "+val2 152 valkey = val1 + " " + val2
152 153
153 # cache lookup 154 # cache lookup
154 try: 155 try:
155 return __vercmp_cache__[valkey] 156 return __vercmp_cache__[valkey]
156 try: 157 try:
157 return - __vercmp_cache__[val2+" "+val1] 158 return - __vercmp_cache__[val2 + " " + val1]
158 except KeyError: 159 except KeyError:
159 pass 160 pass
160 except KeyError: 161 except KeyError:
@@ -175,21 +176,21 @@ def vercmp_string(val1,val2):
175 # replace '-' by '.' 176 # replace '-' by '.'
176 # FIXME: Is it needed? can val1/2 contain '-'? 177 # FIXME: Is it needed? can val1/2 contain '-'?
177 178
178 val1 = string.split(val1,'-') 179 val1 = val1.split("-")
179 if len(val1) == 2: 180 if len(val1) == 2:
180 val1[0] = val1[0] +"."+ val1[1] 181 val1[0] = val1[0] + "." + val1[1]
181 val2 = string.split(val2,'-') 182 val2 = val2.split("-")
182 if len(val2) == 2: 183 if len(val2) == 2:
183 val2[0] = val2[0] +"."+ val2[1] 184 val2[0] = val2[0] + "." + val2[1]
184 185
185 val1 = string.split(val1[0],'.') 186 val1 = val1[0].split('.')
186 val2 = string.split(val2[0],'.') 187 val2 = val2[0].split('.')
187 188
188 # add back decimal point so that .03 does not become "3" ! 189 # add back decimal point so that .03 does not become "3" !
189 for x in range(1,len(val1)): 190 for x in range(1, len(val1)):
190 if val1[x][0] == '0' : 191 if val1[x][0] == '0' :
191 val1[x] = '.' + val1[x] 192 val1[x] = '.' + val1[x]
192 for x in range(1,len(val2)): 193 for x in range(1, len(val2)):
193 if val2[x][0] == '0' : 194 if val2[x][0] == '0' :
194 val2[x] = '.' + val2[x] 195 val2[x] = '.' + val2[x]
195 196
@@ -206,10 +207,10 @@ def vercmp_string(val1,val2):
206 val2[-1] += '_' + val2_prepart 207 val2[-1] += '_' + val2_prepart
207 # The above code will extend version numbers out so they 208 # The above code will extend version numbers out so they
208 # have the same number of digits. 209 # have the same number of digits.
209 for x in range(0,len(val1)): 210 for x in range(0, len(val1)):
210 cmp1 = relparse(val1[x]) 211 cmp1 = relparse(val1[x])
211 cmp2 = relparse(val2[x]) 212 cmp2 = relparse(val2[x])
212 for y in range(0,3): 213 for y in range(0, 3):
213 myret = cmp1[y] - cmp2[y] 214 myret = cmp1[y] - cmp2[y]
214 if myret != 0: 215 if myret != 0:
215 __vercmp_cache__[valkey] = myret 216 __vercmp_cache__[valkey] = myret
@@ -290,9 +291,9 @@ def _print_trace(body, line):
290 291
291 # print the environment of the method 292 # print the environment of the method
292 bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function") 293 bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function")
293 min_line = max(1,line-4) 294 min_line = max(1, line-4)
294 max_line = min(line+4,len(body)-1) 295 max_line = min(line + 4, len(body)-1)
295 for i in range(min_line,max_line+1): 296 for i in range(min_line, max_line + 1):
296 bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) ) 297 bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) )
297 298
298 299
@@ -304,7 +305,7 @@ def better_compile(text, file, realfile, mode = "exec"):
304 try: 305 try:
305 return compile(text, file, mode) 306 return compile(text, file, mode)
306 except Exception, e: 307 except Exception, e:
307 import bb,sys 308 import bb, sys
308 309
309 # split the text into lines again 310 # split the text into lines again
310 body = text.split('\n') 311 body = text.split('\n')
@@ -323,18 +324,18 @@ def better_exec(code, context, text, realfile):
323 print the lines that are responsible for the 324 print the lines that are responsible for the
324 error. 325 error.
325 """ 326 """
326 import bb,sys 327 import bb, sys
327 try: 328 try:
328 exec code in _context, context 329 exec code in _context, context
329 except: 330 except:
330 (t,value,tb) = sys.exc_info() 331 (t, value, tb) = sys.exc_info()
331 332
332 if t in [bb.parse.SkipPackage, bb.build.FuncFailed]: 333 if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
333 raise 334 raise
334 335
335 # print the Header of the Error Message 336 # print the Header of the Error Message
336 bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: %s" % realfile) 337 bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: %s" % realfile)
337 bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t,value) ) 338 bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t, value))
338 339
339 # let us find the line number now 340 # let us find the line number now
340 while tb.tb_next: 341 while tb.tb_next:
@@ -344,7 +345,7 @@ def better_exec(code, context, text, realfile):
344 line = traceback.tb_lineno(tb) 345 line = traceback.tb_lineno(tb)
345 346
346 _print_trace( text.split('\n'), line ) 347 _print_trace( text.split('\n'), line )
347 348
348 raise 349 raise
349 350
350def simple_exec(code, context): 351def simple_exec(code, context):
@@ -367,22 +368,22 @@ def lockfile(name):
367 while True: 368 while True:
368 # If we leave the lockfiles lying around there is no problem 369 # If we leave the lockfiles lying around there is no problem
369 # but we should clean up after ourselves. This gives potential 370 # but we should clean up after ourselves. This gives potential
370 # for races though. To work around this, when we acquire the lock 371 # for races though. To work around this, when we acquire the lock
371 # we check the file we locked was still the lock file on disk. 372 # we check the file we locked was still the lock file on disk.
372 # by comparing inode numbers. If they don't match or the lockfile 373 # by comparing inode numbers. If they don't match or the lockfile
373 # no longer exists, we start again. 374 # no longer exists, we start again.
374 375
375 # This implementation is unfair since the last person to request the 376 # This implementation is unfair since the last person to request the
376 # lock is the most likely to win it. 377 # lock is the most likely to win it.
377 378
378 try: 379 try:
379 lf = open(name, "a+") 380 lf = open(name, "a + ")
380 fcntl.flock(lf.fileno(), fcntl.LOCK_EX) 381 fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
381 statinfo = os.fstat(lf.fileno()) 382 statinfo = os.fstat(lf.fileno())
382 if os.path.exists(lf.name): 383 if os.path.exists(lf.name):
383 statinfo2 = os.stat(lf.name) 384 statinfo2 = os.stat(lf.name)
384 if statinfo.st_ino == statinfo2.st_ino: 385 if statinfo.st_ino == statinfo2.st_ino:
385 return lf 386 return lf
386 # File no longer exists or changed, retry 387 # File no longer exists or changed, retry
387 lf.close 388 lf.close
388 except Exception, e: 389 except Exception, e:
@@ -390,7 +391,7 @@ def lockfile(name):
390 391
391def unlockfile(lf): 392def unlockfile(lf):
392 """ 393 """
393 Unlock a file locked using lockfile() 394 Unlock a file locked using lockfile()
394 """ 395 """
395 os.unlink(lf.name) 396 os.unlink(lf.name)
396 fcntl.flock(lf.fileno(), fcntl.LOCK_UN) 397 fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
@@ -406,7 +407,7 @@ def md5_file(filename):
406 except ImportError: 407 except ImportError:
407 import md5 408 import md5
408 m = md5.new() 409 m = md5.new()
409 410
410 for line in open(filename): 411 for line in open(filename):
411 m.update(line) 412 m.update(line)
412 return m.hexdigest() 413 return m.hexdigest()
@@ -472,7 +473,7 @@ def filter_environment(good_vars):
472 for key in os.environ.keys(): 473 for key in os.environ.keys():
473 if key in good_vars: 474 if key in good_vars:
474 continue 475 continue
475 476
476 removed_vars.append(key) 477 removed_vars.append(key)
477 os.unsetenv(key) 478 os.unsetenv(key)
478 del os.environ[key] 479 del os.environ[key]
@@ -517,7 +518,7 @@ def build_environment(d):
517def prunedir(topdir): 518def prunedir(topdir):
518 # Delete everything reachable from the directory named in 'topdir'. 519 # Delete everything reachable from the directory named in 'topdir'.
519 # CAUTION: This is dangerous! 520 # CAUTION: This is dangerous!
520 for root, dirs, files in os.walk(topdir, topdown=False): 521 for root, dirs, files in os.walk(topdir, topdown = False):
521 for name in files: 522 for name in files:
522 os.remove(os.path.join(root, name)) 523 os.remove(os.path.join(root, name))
523 for name in dirs: 524 for name in dirs:
@@ -532,7 +533,7 @@ def prunedir(topdir):
532# but thats possibly insane and suffixes is probably going to be small 533# but thats possibly insane and suffixes is probably going to be small
533# 534#
534def prune_suffix(var, suffixes, d): 535def prune_suffix(var, suffixes, d):
535 # See if var ends with any of the suffixes listed and 536 # See if var ends with any of the suffixes listed and
536 # remove it if found 537 # remove it if found
537 for suffix in suffixes: 538 for suffix in suffixes:
538 if var.endswith(suffix): 539 if var.endswith(suffix):
@@ -553,42 +554,42 @@ def mkdirhier(dir):
553 554
554import stat 555import stat
555 556
556def movefile(src,dest,newmtime=None,sstat=None): 557def movefile(src, dest, newmtime = None, sstat = None):
557 """Moves a file from src to dest, preserving all permissions and 558 """Moves a file from src to dest, preserving all permissions and
558 attributes; mtime will be preserved even when moving across 559 attributes; mtime will be preserved even when moving across
559 filesystems. Returns true on success and false on failure. Move is 560 filesystems. Returns true on success and false on failure. Move is
560 atomic. 561 atomic.
561 """ 562 """
562 563
563 #print "movefile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" 564 #print "movefile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
564 try: 565 try:
565 if not sstat: 566 if not sstat:
566 sstat=os.lstat(src) 567 sstat = os.lstat(src)
567 except Exception, e: 568 except Exception, e:
568 print "movefile: Stating source file failed...", e 569 print "movefile: Stating source file failed...", e
569 return None 570 return None
570 571
571 destexists=1 572 destexists = 1
572 try: 573 try:
573 dstat=os.lstat(dest) 574 dstat = os.lstat(dest)
574 except: 575 except:
575 dstat=os.lstat(os.path.dirname(dest)) 576 dstat = os.lstat(os.path.dirname(dest))
576 destexists=0 577 destexists = 0
577 578
578 if destexists: 579 if destexists:
579 if stat.S_ISLNK(dstat[stat.ST_MODE]): 580 if stat.S_ISLNK(dstat[stat.ST_MODE]):
580 try: 581 try:
581 os.unlink(dest) 582 os.unlink(dest)
582 destexists=0 583 destexists = 0
583 except Exception, e: 584 except Exception, e:
584 pass 585 pass
585 586
586 if stat.S_ISLNK(sstat[stat.ST_MODE]): 587 if stat.S_ISLNK(sstat[stat.ST_MODE]):
587 try: 588 try:
588 target=os.readlink(src) 589 target = os.readlink(src)
589 if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): 590 if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
590 os.unlink(dest) 591 os.unlink(dest)
591 os.symlink(target,dest) 592 os.symlink(target, dest)
592 #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) 593 #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
593 os.unlink(src) 594 os.unlink(src)
594 return os.lstat(dest) 595 return os.lstat(dest)
@@ -596,38 +597,38 @@ def movefile(src,dest,newmtime=None,sstat=None):
596 print "movefile: failed to properly create symlink:", dest, "->", target, e 597 print "movefile: failed to properly create symlink:", dest, "->", target, e
597 return None 598 return None
598 599
599 renamefailed=1 600 renamefailed = 1
600 if sstat[stat.ST_DEV]==dstat[stat.ST_DEV]: 601 if sstat[stat.ST_DEV] == dstat[stat.ST_DEV]:
601 try: 602 try:
602 ret=os.rename(src,dest) 603 ret = os.rename(src, dest)
603 renamefailed=0 604 renamefailed = 0
604 except Exception, e: 605 except Exception, e:
605 import errno 606 import errno
606 if e[0]!=errno.EXDEV: 607 if e[0] != errno.EXDEV:
607 # Some random error. 608 # Some random error.
608 print "movefile: Failed to move", src, "to", dest, e 609 print "movefile: Failed to move", src, "to", dest, e
609 return None 610 return None
610 # Invalid cross-device-link 'bind' mounted or actually Cross-Device 611 # Invalid cross-device-link 'bind' mounted or actually Cross-Device
611 612
612 if renamefailed: 613 if renamefailed:
613 didcopy=0 614 didcopy = 0
614 if stat.S_ISREG(sstat[stat.ST_MODE]): 615 if stat.S_ISREG(sstat[stat.ST_MODE]):
615 try: # For safety copy then move it over. 616 try: # For safety copy then move it over.
616 shutil.copyfile(src,dest+"#new") 617 shutil.copyfile(src, dest + "#new")
617 os.rename(dest+"#new",dest) 618 os.rename(dest + "#new", dest)
618 didcopy=1 619 didcopy = 1
619 except Exception, e: 620 except Exception, e:
620 print 'movefile: copy', src, '->', dest, 'failed.', e 621 print 'movefile: copy', src, '->', dest, 'failed.', e
621 return None 622 return None
622 else: 623 else:
623 #we don't yet handle special, so we need to fall back to /bin/mv 624 #we don't yet handle special, so we need to fall back to /bin/mv
624 a=getstatusoutput("/bin/mv -f "+"'"+src+"' '"+dest+"'") 625 a = getstatusoutput("/bin/mv -f " + "'" + src + "' '" + dest + "'")
625 if a[0]!=0: 626 if a[0] != 0:
626 print "movefile: Failed to move special file:" + src + "' to '" + dest + "'", a 627 print "movefile: Failed to move special file:" + src + "' to '" + dest + "'", a
627 return None # failure 628 return None # failure
628 try: 629 try:
629 if didcopy: 630 if didcopy:
630 os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) 631 os.lchown(dest, sstat[stat.ST_UID], sstat[stat.ST_GID])
631 os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown 632 os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
632 os.unlink(src) 633 os.unlink(src)
633 except Exception, e: 634 except Exception, e:
@@ -635,47 +636,47 @@ def movefile(src,dest,newmtime=None,sstat=None):
635 return None 636 return None
636 637
637 if newmtime: 638 if newmtime:
638 os.utime(dest,(newmtime,newmtime)) 639 os.utime(dest, (newmtime, newmtime))
639 else: 640 else:
640 os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) 641 os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
641 newmtime=sstat[stat.ST_MTIME] 642 newmtime = sstat[stat.ST_MTIME]
642 return newmtime 643 return newmtime
643 644
644def copyfile(src,dest,newmtime=None,sstat=None): 645def copyfile(src, dest, newmtime = None, sstat = None):
645 """ 646 """
646 Copies a file from src to dest, preserving all permissions and 647 Copies a file from src to dest, preserving all permissions and
647 attributes; mtime will be preserved even when moving across 648 attributes; mtime will be preserved even when moving across
648 filesystems. Returns true on success and false on failure. 649 filesystems. Returns true on success and false on failure.
649 """ 650 """
650 #print "copyfile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" 651 #print "copyfile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
651 try: 652 try:
652 if not sstat: 653 if not sstat:
653 sstat=os.lstat(src) 654 sstat = os.lstat(src)
654 except Exception, e: 655 except Exception, e:
655 print "copyfile: Stating source file failed...", e 656 print "copyfile: Stating source file failed...", e
656 return False 657 return False
657 658
658 destexists=1 659 destexists = 1
659 try: 660 try:
660 dstat=os.lstat(dest) 661 dstat = os.lstat(dest)
661 except: 662 except:
662 dstat=os.lstat(os.path.dirname(dest)) 663 dstat = os.lstat(os.path.dirname(dest))
663 destexists=0 664 destexists = 0
664 665
665 if destexists: 666 if destexists:
666 if stat.S_ISLNK(dstat[stat.ST_MODE]): 667 if stat.S_ISLNK(dstat[stat.ST_MODE]):
667 try: 668 try:
668 os.unlink(dest) 669 os.unlink(dest)
669 destexists=0 670 destexists = 0
670 except Exception, e: 671 except Exception, e:
671 pass 672 pass
672 673
673 if stat.S_ISLNK(sstat[stat.ST_MODE]): 674 if stat.S_ISLNK(sstat[stat.ST_MODE]):
674 try: 675 try:
675 target=os.readlink(src) 676 target = os.readlink(src)
676 if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): 677 if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
677 os.unlink(dest) 678 os.unlink(dest)
678 os.symlink(target,dest) 679 os.symlink(target, dest)
679 #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) 680 #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
680 return os.lstat(dest) 681 return os.lstat(dest)
681 except Exception, e: 682 except Exception, e:
@@ -683,30 +684,30 @@ def copyfile(src,dest,newmtime=None,sstat=None):
683 return False 684 return False
684 685
685 if stat.S_ISREG(sstat[stat.ST_MODE]): 686 if stat.S_ISREG(sstat[stat.ST_MODE]):
686 try: # For safety copy then move it over. 687 try: # For safety copy then move it over.
687 shutil.copyfile(src,dest+"#new") 688 shutil.copyfile(src, dest + "#new")
688 os.rename(dest+"#new",dest) 689 os.rename(dest + "#new", dest)
689 except Exception, e: 690 except Exception, e:
690 print 'copyfile: copy', src, '->', dest, 'failed.', e 691 print 'copyfile: copy', src, '->', dest, 'failed.', e
691 return False 692 return False
692 else: 693 else:
693 #we don't yet handle special, so we need to fall back to /bin/mv 694 #we don't yet handle special, so we need to fall back to /bin/mv
694 a=getstatusoutput("/bin/cp -f "+"'"+src+"' '"+dest+"'") 695 a = getstatusoutput("/bin/cp -f " + "'" + src + "' '" + dest + "'")
695 if a[0]!=0: 696 if a[0] != 0:
696 print "copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a 697 print "copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a
697 return False # failure 698 return False # failure
698 try: 699 try:
699 os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) 700 os.lchown(dest, sstat[stat.ST_UID], sstat[stat.ST_GID])
700 os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown 701 os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
701 except Exception, e: 702 except Exception, e:
702 print "copyfile: Failed to chown/chmod/unlink", dest, e 703 print "copyfile: Failed to chown/chmod/unlink", dest, e
703 return False 704 return False
704 705
705 if newmtime: 706 if newmtime:
706 os.utime(dest,(newmtime,newmtime)) 707 os.utime(dest, (newmtime, newmtime))
707 else: 708 else:
708 os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) 709 os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
709 newmtime=sstat[stat.ST_MTIME] 710 newmtime = sstat[stat.ST_MTIME]
710 return newmtime 711 return newmtime
711 712
712def which(path, item, direction = 0): 713def which(path, item, direction = 0):