Show More
@@ -8,7 +8,7 b'' | |||
|
8 | 8 | from node import * |
|
9 | 9 | from i18n import _ |
|
10 | 10 | import os, sys, bisect, stat |
|
11 | import mdiff, bdiff, util, templater, patch | |
|
11 | import mdiff, bdiff, util, templater, patch, errno | |
|
12 | 12 | |
|
13 | 13 | revrangesep = ':' |
|
14 | 14 | |
@@ -286,6 +286,204 b' def addremove(repo, pats=[], opts={}, dr' | |||
|
286 | 286 | if not dry_run: |
|
287 | 287 | repo.copy(old, new) |
|
288 | 288 | |
|
289 | def copy(ui, repo, pats, opts): | |
|
290 | # called with the repo lock held | |
|
291 | # | |
|
292 | # hgsep => pathname that uses "/" to separate directories | |
|
293 | # ossep => pathname that uses os.sep to separate directories | |
|
294 | cwd = repo.getcwd() | |
|
295 | errors = 0 | |
|
296 | copied = [] | |
|
297 | targets = {} | |
|
298 | ||
|
299 | # abs: hgsep | |
|
300 | # rel: ossep | |
|
301 | # return: hgsep | |
|
302 | def okaytocopy(abs, rel, exact): | |
|
303 | reasons = {'?': _('is not managed'), | |
|
304 | 'r': _('has been marked for remove')} | |
|
305 | state = repo.dirstate[abs] | |
|
306 | reason = reasons.get(state) | |
|
307 | if reason: | |
|
308 | if exact: | |
|
309 | ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) | |
|
310 | else: | |
|
311 | if state == 'a': | |
|
312 | origsrc = repo.dirstate.copied(abs) | |
|
313 | if origsrc is not None: | |
|
314 | return origsrc | |
|
315 | return abs | |
|
316 | ||
|
317 | # origsrc: hgsep | |
|
318 | # abssrc: hgsep | |
|
319 | # relsrc: ossep | |
|
320 | # otarget: ossep | |
|
321 | def copy(origsrc, abssrc, relsrc, otarget, exact): | |
|
322 | abstarget = util.canonpath(repo.root, cwd, otarget) | |
|
323 | reltarget = repo.pathto(abstarget, cwd) | |
|
324 | prevsrc = targets.get(abstarget) | |
|
325 | src = repo.wjoin(abssrc) | |
|
326 | target = repo.wjoin(abstarget) | |
|
327 | if prevsrc is not None: | |
|
328 | ui.warn(_('%s: not overwriting - %s collides with %s\n') % | |
|
329 | (reltarget, repo.pathto(abssrc, cwd), | |
|
330 | repo.pathto(prevsrc, cwd))) | |
|
331 | return | |
|
332 | if (not opts['after'] and os.path.exists(target) or | |
|
333 | opts['after'] and repo.dirstate[abstarget] in 'mn'): | |
|
334 | if not opts['force']: | |
|
335 | ui.warn(_('%s: not overwriting - file exists\n') % | |
|
336 | reltarget) | |
|
337 | return | |
|
338 | if not opts['after'] and not opts.get('dry_run'): | |
|
339 | os.unlink(target) | |
|
340 | if opts['after']: | |
|
341 | if not os.path.exists(target): | |
|
342 | return | |
|
343 | else: | |
|
344 | targetdir = os.path.dirname(target) or '.' | |
|
345 | if not os.path.isdir(targetdir) and not opts.get('dry_run'): | |
|
346 | os.makedirs(targetdir) | |
|
347 | try: | |
|
348 | restore = repo.dirstate[abstarget] == 'r' | |
|
349 | if restore and not opts.get('dry_run'): | |
|
350 | repo.undelete([abstarget]) | |
|
351 | try: | |
|
352 | if not opts.get('dry_run'): | |
|
353 | util.copyfile(src, target) | |
|
354 | restore = False | |
|
355 | finally: | |
|
356 | if restore: | |
|
357 | repo.remove([abstarget]) | |
|
358 | except IOError, inst: | |
|
359 | if inst.errno == errno.ENOENT: | |
|
360 | ui.warn(_('%s: deleted in working copy\n') % relsrc) | |
|
361 | else: | |
|
362 | ui.warn(_('%s: cannot copy - %s\n') % | |
|
363 | (relsrc, inst.strerror)) | |
|
364 | errors += 1 | |
|
365 | return | |
|
366 | if ui.verbose or not exact: | |
|
367 | ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) | |
|
368 | targets[abstarget] = abssrc | |
|
369 | if abstarget != origsrc: | |
|
370 | if repo.dirstate[origsrc] == 'a': | |
|
371 | if not ui.quiet: | |
|
372 | ui.warn(_("%s has not been committed yet, so no copy " | |
|
373 | "data will be stored for %s.\n") | |
|
374 | % (repo.pathto(origsrc, cwd), reltarget)) | |
|
375 | if abstarget not in repo.dirstate and not opts.get('dry_run'): | |
|
376 | repo.add([abstarget]) | |
|
377 | elif not opts.get('dry_run'): | |
|
378 | repo.copy(origsrc, abstarget) | |
|
379 | copied.append((abssrc, relsrc, exact)) | |
|
380 | ||
|
381 | # pat: ossep | |
|
382 | # dest ossep | |
|
383 | # srcs: list of (hgsep, hgsep, ossep, bool) | |
|
384 | # return: function that takes hgsep and returns ossep | |
|
385 | def targetpathfn(pat, dest, srcs): | |
|
386 | if os.path.isdir(pat): | |
|
387 | abspfx = util.canonpath(repo.root, cwd, pat) | |
|
388 | abspfx = util.localpath(abspfx) | |
|
389 | if destdirexists: | |
|
390 | striplen = len(os.path.split(abspfx)[0]) | |
|
391 | else: | |
|
392 | striplen = len(abspfx) | |
|
393 | if striplen: | |
|
394 | striplen += len(os.sep) | |
|
395 | res = lambda p: os.path.join(dest, util.localpath(p)[striplen:]) | |
|
396 | elif destdirexists: | |
|
397 | res = lambda p: os.path.join(dest, | |
|
398 | os.path.basename(util.localpath(p))) | |
|
399 | else: | |
|
400 | res = lambda p: dest | |
|
401 | return res | |
|
402 | ||
|
403 | # pat: ossep | |
|
404 | # dest ossep | |
|
405 | # srcs: list of (hgsep, hgsep, ossep, bool) | |
|
406 | # return: function that takes hgsep and returns ossep | |
|
407 | def targetpathafterfn(pat, dest, srcs): | |
|
408 | if util.patkind(pat, None)[0]: | |
|
409 | # a mercurial pattern | |
|
410 | res = lambda p: os.path.join(dest, | |
|
411 | os.path.basename(util.localpath(p))) | |
|
412 | else: | |
|
413 | abspfx = util.canonpath(repo.root, cwd, pat) | |
|
414 | if len(abspfx) < len(srcs[0][0]): | |
|
415 | # A directory. Either the target path contains the last | |
|
416 | # component of the source path or it does not. | |
|
417 | def evalpath(striplen): | |
|
418 | score = 0 | |
|
419 | for s in srcs: | |
|
420 | t = os.path.join(dest, util.localpath(s[0])[striplen:]) | |
|
421 | if os.path.exists(t): | |
|
422 | score += 1 | |
|
423 | return score | |
|
424 | ||
|
425 | abspfx = util.localpath(abspfx) | |
|
426 | striplen = len(abspfx) | |
|
427 | if striplen: | |
|
428 | striplen += len(os.sep) | |
|
429 | if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])): | |
|
430 | score = evalpath(striplen) | |
|
431 | striplen1 = len(os.path.split(abspfx)[0]) | |
|
432 | if striplen1: | |
|
433 | striplen1 += len(os.sep) | |
|
434 | if evalpath(striplen1) > score: | |
|
435 | striplen = striplen1 | |
|
436 | res = lambda p: os.path.join(dest, | |
|
437 | util.localpath(p)[striplen:]) | |
|
438 | else: | |
|
439 | # a file | |
|
440 | if destdirexists: | |
|
441 | res = lambda p: os.path.join(dest, | |
|
442 | os.path.basename(util.localpath(p))) | |
|
443 | else: | |
|
444 | res = lambda p: dest | |
|
445 | return res | |
|
446 | ||
|
447 | ||
|
448 | pats = util.expand_glob(pats) | |
|
449 | if not pats: | |
|
450 | raise util.Abort(_('no source or destination specified')) | |
|
451 | if len(pats) == 1: | |
|
452 | raise util.Abort(_('no destination specified')) | |
|
453 | dest = pats.pop() | |
|
454 | destdirexists = os.path.isdir(dest) | |
|
455 | if not destdirexists: | |
|
456 | if len(pats) > 1 or util.patkind(pats[0], None)[0]: | |
|
457 | raise util.Abort(_('with multiple sources, destination must be an ' | |
|
458 | 'existing directory')) | |
|
459 | if dest.endswith(os.sep) or os.altsep and dest.endswith(os.altsep): | |
|
460 | raise util.Abort(_('destination %s is not a directory') % dest) | |
|
461 | if opts['after']: | |
|
462 | tfn = targetpathafterfn | |
|
463 | else: | |
|
464 | tfn = targetpathfn | |
|
465 | copylist = [] | |
|
466 | for pat in pats: | |
|
467 | srcs = [] | |
|
468 | for tag, abssrc, relsrc, exact in walk(repo, [pat], opts, | |
|
469 | globbed=True): | |
|
470 | origsrc = okaytocopy(abssrc, relsrc, exact) | |
|
471 | if origsrc: | |
|
472 | srcs.append((origsrc, abssrc, relsrc, exact)) | |
|
473 | if not srcs: | |
|
474 | continue | |
|
475 | copylist.append((tfn(pat, dest, srcs), srcs)) | |
|
476 | if not copylist: | |
|
477 | raise util.Abort(_('no files to copy')) | |
|
478 | ||
|
479 | for targetpath, srcs in copylist: | |
|
480 | for origsrc, abssrc, relsrc, exact in srcs: | |
|
481 | copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact) | |
|
482 | ||
|
483 | if errors: | |
|
484 | ui.warn(_('(consider using --after)\n')) | |
|
485 | return errors, copied | |
|
486 | ||
|
289 | 487 | def service(opts, parentfn=None, initfn=None, runfn=None): |
|
290 | 488 | '''Run a command as a service.''' |
|
291 | 489 |
@@ -438,204 +438,6 b' def commit(ui, repo, *pats, **opts):' | |||
|
438 | 438 | force_editor=opts.get('force_editor')) |
|
439 | 439 | cmdutil.commit(ui, repo, commitfunc, pats, opts) |
|
440 | 440 | |
|
441 | def docopy(ui, repo, pats, opts): | |
|
442 | # called with the repo lock held | |
|
443 | # | |
|
444 | # hgsep => pathname that uses "/" to separate directories | |
|
445 | # ossep => pathname that uses os.sep to separate directories | |
|
446 | cwd = repo.getcwd() | |
|
447 | errors = 0 | |
|
448 | copied = [] | |
|
449 | targets = {} | |
|
450 | ||
|
451 | # abs: hgsep | |
|
452 | # rel: ossep | |
|
453 | # return: hgsep | |
|
454 | def okaytocopy(abs, rel, exact): | |
|
455 | reasons = {'?': _('is not managed'), | |
|
456 | 'r': _('has been marked for remove')} | |
|
457 | state = repo.dirstate[abs] | |
|
458 | reason = reasons.get(state) | |
|
459 | if reason: | |
|
460 | if exact: | |
|
461 | ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) | |
|
462 | else: | |
|
463 | if state == 'a': | |
|
464 | origsrc = repo.dirstate.copied(abs) | |
|
465 | if origsrc is not None: | |
|
466 | return origsrc | |
|
467 | return abs | |
|
468 | ||
|
469 | # origsrc: hgsep | |
|
470 | # abssrc: hgsep | |
|
471 | # relsrc: ossep | |
|
472 | # otarget: ossep | |
|
473 | def copy(origsrc, abssrc, relsrc, otarget, exact): | |
|
474 | abstarget = util.canonpath(repo.root, cwd, otarget) | |
|
475 | reltarget = repo.pathto(abstarget, cwd) | |
|
476 | prevsrc = targets.get(abstarget) | |
|
477 | src = repo.wjoin(abssrc) | |
|
478 | target = repo.wjoin(abstarget) | |
|
479 | if prevsrc is not None: | |
|
480 | ui.warn(_('%s: not overwriting - %s collides with %s\n') % | |
|
481 | (reltarget, repo.pathto(abssrc, cwd), | |
|
482 | repo.pathto(prevsrc, cwd))) | |
|
483 | return | |
|
484 | if (not opts['after'] and os.path.exists(target) or | |
|
485 | opts['after'] and repo.dirstate[abstarget] in 'mn'): | |
|
486 | if not opts['force']: | |
|
487 | ui.warn(_('%s: not overwriting - file exists\n') % | |
|
488 | reltarget) | |
|
489 | return | |
|
490 | if not opts['after'] and not opts.get('dry_run'): | |
|
491 | os.unlink(target) | |
|
492 | if opts['after']: | |
|
493 | if not os.path.exists(target): | |
|
494 | return | |
|
495 | else: | |
|
496 | targetdir = os.path.dirname(target) or '.' | |
|
497 | if not os.path.isdir(targetdir) and not opts.get('dry_run'): | |
|
498 | os.makedirs(targetdir) | |
|
499 | try: | |
|
500 | restore = repo.dirstate[abstarget] == 'r' | |
|
501 | if restore and not opts.get('dry_run'): | |
|
502 | repo.undelete([abstarget]) | |
|
503 | try: | |
|
504 | if not opts.get('dry_run'): | |
|
505 | util.copyfile(src, target) | |
|
506 | restore = False | |
|
507 | finally: | |
|
508 | if restore: | |
|
509 | repo.remove([abstarget]) | |
|
510 | except IOError, inst: | |
|
511 | if inst.errno == errno.ENOENT: | |
|
512 | ui.warn(_('%s: deleted in working copy\n') % relsrc) | |
|
513 | else: | |
|
514 | ui.warn(_('%s: cannot copy - %s\n') % | |
|
515 | (relsrc, inst.strerror)) | |
|
516 | errors += 1 | |
|
517 | return | |
|
518 | if ui.verbose or not exact: | |
|
519 | ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) | |
|
520 | targets[abstarget] = abssrc | |
|
521 | if abstarget != origsrc: | |
|
522 | if repo.dirstate[origsrc] == 'a': | |
|
523 | if not ui.quiet: | |
|
524 | ui.warn(_("%s has not been committed yet, so no copy " | |
|
525 | "data will be stored for %s.\n") | |
|
526 | % (repo.pathto(origsrc, cwd), reltarget)) | |
|
527 | if abstarget not in repo.dirstate and not opts.get('dry_run'): | |
|
528 | repo.add([abstarget]) | |
|
529 | elif not opts.get('dry_run'): | |
|
530 | repo.copy(origsrc, abstarget) | |
|
531 | copied.append((abssrc, relsrc, exact)) | |
|
532 | ||
|
533 | # pat: ossep | |
|
534 | # dest ossep | |
|
535 | # srcs: list of (hgsep, hgsep, ossep, bool) | |
|
536 | # return: function that takes hgsep and returns ossep | |
|
537 | def targetpathfn(pat, dest, srcs): | |
|
538 | if os.path.isdir(pat): | |
|
539 | abspfx = util.canonpath(repo.root, cwd, pat) | |
|
540 | abspfx = util.localpath(abspfx) | |
|
541 | if destdirexists: | |
|
542 | striplen = len(os.path.split(abspfx)[0]) | |
|
543 | else: | |
|
544 | striplen = len(abspfx) | |
|
545 | if striplen: | |
|
546 | striplen += len(os.sep) | |
|
547 | res = lambda p: os.path.join(dest, util.localpath(p)[striplen:]) | |
|
548 | elif destdirexists: | |
|
549 | res = lambda p: os.path.join(dest, | |
|
550 | os.path.basename(util.localpath(p))) | |
|
551 | else: | |
|
552 | res = lambda p: dest | |
|
553 | return res | |
|
554 | ||
|
555 | # pat: ossep | |
|
556 | # dest ossep | |
|
557 | # srcs: list of (hgsep, hgsep, ossep, bool) | |
|
558 | # return: function that takes hgsep and returns ossep | |
|
559 | def targetpathafterfn(pat, dest, srcs): | |
|
560 | if util.patkind(pat, None)[0]: | |
|
561 | # a mercurial pattern | |
|
562 | res = lambda p: os.path.join(dest, | |
|
563 | os.path.basename(util.localpath(p))) | |
|
564 | else: | |
|
565 | abspfx = util.canonpath(repo.root, cwd, pat) | |
|
566 | if len(abspfx) < len(srcs[0][0]): | |
|
567 | # A directory. Either the target path contains the last | |
|
568 | # component of the source path or it does not. | |
|
569 | def evalpath(striplen): | |
|
570 | score = 0 | |
|
571 | for s in srcs: | |
|
572 | t = os.path.join(dest, util.localpath(s[0])[striplen:]) | |
|
573 | if os.path.exists(t): | |
|
574 | score += 1 | |
|
575 | return score | |
|
576 | ||
|
577 | abspfx = util.localpath(abspfx) | |
|
578 | striplen = len(abspfx) | |
|
579 | if striplen: | |
|
580 | striplen += len(os.sep) | |
|
581 | if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])): | |
|
582 | score = evalpath(striplen) | |
|
583 | striplen1 = len(os.path.split(abspfx)[0]) | |
|
584 | if striplen1: | |
|
585 | striplen1 += len(os.sep) | |
|
586 | if evalpath(striplen1) > score: | |
|
587 | striplen = striplen1 | |
|
588 | res = lambda p: os.path.join(dest, | |
|
589 | util.localpath(p)[striplen:]) | |
|
590 | else: | |
|
591 | # a file | |
|
592 | if destdirexists: | |
|
593 | res = lambda p: os.path.join(dest, | |
|
594 | os.path.basename(util.localpath(p))) | |
|
595 | else: | |
|
596 | res = lambda p: dest | |
|
597 | return res | |
|
598 | ||
|
599 | ||
|
600 | pats = util.expand_glob(pats) | |
|
601 | if not pats: | |
|
602 | raise util.Abort(_('no source or destination specified')) | |
|
603 | if len(pats) == 1: | |
|
604 | raise util.Abort(_('no destination specified')) | |
|
605 | dest = pats.pop() | |
|
606 | destdirexists = os.path.isdir(dest) | |
|
607 | if not destdirexists: | |
|
608 | if len(pats) > 1 or util.patkind(pats[0], None)[0]: | |
|
609 | raise util.Abort(_('with multiple sources, destination must be an ' | |
|
610 | 'existing directory')) | |
|
611 | if dest.endswith(os.sep) or os.altsep and dest.endswith(os.altsep): | |
|
612 | raise util.Abort(_('destination %s is not a directory') % dest) | |
|
613 | if opts['after']: | |
|
614 | tfn = targetpathafterfn | |
|
615 | else: | |
|
616 | tfn = targetpathfn | |
|
617 | copylist = [] | |
|
618 | for pat in pats: | |
|
619 | srcs = [] | |
|
620 | for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts, | |
|
621 | globbed=True): | |
|
622 | origsrc = okaytocopy(abssrc, relsrc, exact) | |
|
623 | if origsrc: | |
|
624 | srcs.append((origsrc, abssrc, relsrc, exact)) | |
|
625 | if not srcs: | |
|
626 | continue | |
|
627 | copylist.append((tfn(pat, dest, srcs), srcs)) | |
|
628 | if not copylist: | |
|
629 | raise util.Abort(_('no files to copy')) | |
|
630 | ||
|
631 | for targetpath, srcs in copylist: | |
|
632 | for origsrc, abssrc, relsrc, exact in srcs: | |
|
633 | copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact) | |
|
634 | ||
|
635 | if errors: | |
|
636 | ui.warn(_('(consider using --after)\n')) | |
|
637 | return errors, copied | |
|
638 | ||
|
639 | 441 | def copy(ui, repo, *pats, **opts): |
|
640 | 442 | """mark files as copied for the next commit |
|
641 | 443 | |
@@ -652,7 +454,7 b' def copy(ui, repo, *pats, **opts):' | |||
|
652 | 454 | """ |
|
653 | 455 | wlock = repo.wlock(False) |
|
654 | 456 | try: |
|
655 |
errs, copied = |
|
|
457 | errs, copied = cmdutil.copy(ui, repo, pats, opts) | |
|
656 | 458 | finally: |
|
657 | 459 | del wlock |
|
658 | 460 | return errs |
@@ -2260,7 +2062,7 b' def rename(ui, repo, *pats, **opts):' | |||
|
2260 | 2062 | """ |
|
2261 | 2063 | wlock = repo.wlock(False) |
|
2262 | 2064 | try: |
|
2263 |
errs, copied = |
|
|
2065 | errs, copied = cmdutil.copy(ui, repo, pats, opts) | |
|
2264 | 2066 | names = [] |
|
2265 | 2067 | for abs, rel, exact in copied: |
|
2266 | 2068 | if ui.verbose or not exact: |
General Comments 0
You need to be logged in to leave comments.
Login now