Show More
@@ -8,7 +8,7 b'' | |||||
8 | from node import * |
|
8 | from node import * | |
9 | from i18n import _ |
|
9 | from i18n import _ | |
10 | import os, sys, bisect, stat |
|
10 | import os, sys, bisect, stat | |
11 | import mdiff, bdiff, util, templater, patch |
|
11 | import mdiff, bdiff, util, templater, patch, errno | |
12 |
|
12 | |||
13 | revrangesep = ':' |
|
13 | revrangesep = ':' | |
14 |
|
14 | |||
@@ -286,6 +286,204 b' def addremove(repo, pats=[], opts={}, dr' | |||||
286 | if not dry_run: |
|
286 | if not dry_run: | |
287 | repo.copy(old, new) |
|
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 | def service(opts, parentfn=None, initfn=None, runfn=None): |
|
487 | def service(opts, parentfn=None, initfn=None, runfn=None): | |
290 | '''Run a command as a service.''' |
|
488 | '''Run a command as a service.''' | |
291 |
|
489 |
@@ -438,204 +438,6 b' def commit(ui, repo, *pats, **opts):' | |||||
438 | force_editor=opts.get('force_editor')) |
|
438 | force_editor=opts.get('force_editor')) | |
439 | cmdutil.commit(ui, repo, commitfunc, pats, opts) |
|
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 | def copy(ui, repo, *pats, **opts): |
|
441 | def copy(ui, repo, *pats, **opts): | |
640 | """mark files as copied for the next commit |
|
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 | wlock = repo.wlock(False) |
|
455 | wlock = repo.wlock(False) | |
654 | try: |
|
456 | try: | |
655 |
errs, copied = |
|
457 | errs, copied = cmdutil.copy(ui, repo, pats, opts) | |
656 | finally: |
|
458 | finally: | |
657 | del wlock |
|
459 | del wlock | |
658 | return errs |
|
460 | return errs | |
@@ -2260,7 +2062,7 b' def rename(ui, repo, *pats, **opts):' | |||||
2260 | """ |
|
2062 | """ | |
2261 | wlock = repo.wlock(False) |
|
2063 | wlock = repo.wlock(False) | |
2262 | try: |
|
2064 | try: | |
2263 |
errs, copied = |
|
2065 | errs, copied = cmdutil.copy(ui, repo, pats, opts) | |
2264 | names = [] |
|
2066 | names = [] | |
2265 | for abs, rel, exact in copied: |
|
2067 | for abs, rel, exact in copied: | |
2266 | if ui.verbose or not exact: |
|
2068 | if ui.verbose or not exact: |
General Comments 0
You need to be logged in to leave comments.
Login now