Show More
@@ -58,10 +58,9 b' def link(src, dest):' | |||||
58 | util.oslink(src, dest) |
|
58 | util.oslink(src, dest) | |
59 | except OSError: |
|
59 | except OSError: | |
60 | # if hardlinks fail, fallback on atomic copy |
|
60 | # if hardlinks fail, fallback on atomic copy | |
61 | with open(src, 'rb') as srcf: |
|
61 | with open(src, 'rb') as srcf, util.atomictempfile(dest) as dstf: | |
62 | with util.atomictempfile(dest) as dstf: |
|
62 | for chunk in util.filechunkiter(srcf): | |
63 | for chunk in util.filechunkiter(srcf): |
|
63 | dstf.write(chunk) | |
64 | dstf.write(chunk) |
|
|||
65 | os.chmod(dest, os.stat(src).st_mode) |
|
64 | os.chmod(dest, os.stat(src).st_mode) | |
66 |
|
65 | |||
67 | def usercachepath(ui, hash): |
|
66 | def usercachepath(ui, hash): | |
@@ -236,10 +235,9 b' def copyfromcache(repo, hash, filename):' | |||||
236 | wvfs.makedirs(wvfs.dirname(wvfs.join(filename))) |
|
235 | wvfs.makedirs(wvfs.dirname(wvfs.join(filename))) | |
237 | # The write may fail before the file is fully written, but we |
|
236 | # The write may fail before the file is fully written, but we | |
238 | # don't use atomic writes in the working copy. |
|
237 | # don't use atomic writes in the working copy. | |
239 | with open(path, 'rb') as srcfd: |
|
238 | with open(path, 'rb') as srcfd, wvfs(filename, 'wb') as destfd: | |
240 | with wvfs(filename, 'wb') as destfd: |
|
239 | gothash = copyandhash( | |
241 | gothash = copyandhash( |
|
240 | util.filechunkiter(srcfd), destfd) | |
242 | util.filechunkiter(srcfd), destfd) |
|
|||
243 | if gothash != hash: |
|
241 | if gothash != hash: | |
244 | repo.ui.warn(_('%s: data corruption in %s with hash %s\n') |
|
242 | repo.ui.warn(_('%s: data corruption in %s with hash %s\n') | |
245 | % (filename, path, gothash)) |
|
243 | % (filename, path, gothash)) |
@@ -2750,148 +2750,147 b' def amend(ui, repo, commitfunc, old, ext' | |||||
2750 | base = old.p1() |
|
2750 | base = old.p1() | |
2751 |
|
2751 | |||
2752 | newid = None |
|
2752 | newid = None | |
2753 | with repo.wlock(), repo.lock(): |
|
2753 | with repo.wlock(), repo.lock(), repo.transaction('amend') as tr: | |
2754 | with repo.transaction('amend') as tr: |
|
2754 | # See if we got a message from -m or -l, if not, open the editor | |
2755 | # See if we got a message from -m or -l, if not, open the editor |
|
2755 | # with the message of the changeset to amend | |
2756 | # with the message of the changeset to amend |
|
2756 | message = logmessage(ui, opts) | |
2757 | message = logmessage(ui, opts) |
|
2757 | # ensure logfile does not conflict with later enforcement of the | |
2758 | # ensure logfile does not conflict with later enforcement of the |
|
2758 | # message. potential logfile content has been processed by | |
2759 | # message. potential logfile content has been processed by |
|
2759 | # `logmessage` anyway. | |
2760 | # `logmessage` anyway. |
|
2760 | opts.pop('logfile') | |
2761 | opts.pop('logfile') |
|
2761 | # First, do a regular commit to record all changes in the working | |
2762 | # First, do a regular commit to record all changes in the working |
|
2762 | # directory (if there are any) | |
2763 | # directory (if there are any) |
|
2763 | ui.callhooks = False | |
2764 | ui.callhooks = False |
|
2764 | activebookmark = repo._bookmarks.active | |
2765 | activebookmark = repo._bookmarks.active |
|
2765 | try: | |
2766 | try: |
|
2766 | repo._bookmarks.active = None | |
2767 | repo._bookmarks.active = None |
|
2767 | opts['message'] = 'temporary amend commit for %s' % old | |
2768 | opts['message'] = 'temporary amend commit for %s' % old |
|
2768 | node = commit(ui, repo, commitfunc, pats, opts) | |
2769 | node = commit(ui, repo, commitfunc, pats, opts) |
|
2769 | finally: | |
2770 | finally: |
|
2770 | repo._bookmarks.active = activebookmark | |
2771 |
|
|
2771 | repo._bookmarks.recordchange(tr) | |
2772 | repo._bookmarks.recordchange(tr) |
|
2772 | ui.callhooks = True | |
2773 | ui.callhooks = True |
|
2773 | ctx = repo[node] | |
2774 | ctx = repo[node] |
|
2774 | ||
2775 |
|
2775 | # Participating changesets: | ||
2776 | # Participating changesets: |
|
2776 | # | |
|
2777 | # node/ctx o - new (intermediate) commit that contains changes | |||
|
2778 | # | from working dir to go into amending commit | |||
|
2779 | # | (or a workingctx if there were no changes) | |||
|
2780 | # | | |||
|
2781 | # old o - changeset to amend | |||
|
2782 | # | | |||
|
2783 | # base o - parent of amending changeset | |||
|
2784 | ||||
|
2785 | # Update extra dict from amended commit (e.g. to preserve graft | |||
|
2786 | # source) | |||
|
2787 | extra.update(old.extra()) | |||
|
2788 | ||||
|
2789 | # Also update it from the intermediate commit or from the wctx | |||
|
2790 | extra.update(ctx.extra()) | |||
|
2791 | ||||
|
2792 | if len(old.parents()) > 1: | |||
|
2793 | # ctx.files() isn't reliable for merges, so fall back to the | |||
|
2794 | # slower repo.status() method | |||
|
2795 | files = set([fn for st in repo.status(base, old)[:3] | |||
|
2796 | for fn in st]) | |||
|
2797 | else: | |||
|
2798 | files = set(old.files()) | |||
|
2799 | ||||
|
2800 | # Second, we use either the commit we just did, or if there were no | |||
|
2801 | # changes the parent of the working directory as the version of the | |||
|
2802 | # files in the final amend commit | |||
|
2803 | if node: | |||
|
2804 | ui.note(_('copying changeset %s to %s\n') % (ctx, base)) | |||
|
2805 | ||||
|
2806 | user = ctx.user() | |||
|
2807 | date = ctx.date() | |||
|
2808 | # Recompute copies (avoid recording a -> b -> a) | |||
|
2809 | copied = copies.pathcopies(base, ctx) | |||
|
2810 | if old.p2: | |||
|
2811 | copied.update(copies.pathcopies(old.p2(), ctx)) | |||
|
2812 | ||||
|
2813 | # Prune files which were reverted by the updates: if old | |||
|
2814 | # introduced file X and our intermediate commit, node, | |||
|
2815 | # renamed that file, then those two files are the same and | |||
|
2816 | # we can discard X from our list of files. Likewise if X | |||
|
2817 | # was deleted, it's no longer relevant | |||
|
2818 | files.update(ctx.files()) | |||
|
2819 | files = [f for f in files if not samefile(f, ctx, base)] | |||
|
2820 | ||||
|
2821 | def filectxfn(repo, ctx_, path): | |||
|
2822 | try: | |||
|
2823 | fctx = ctx[path] | |||
|
2824 | flags = fctx.flags() | |||
|
2825 | mctx = context.memfilectx(repo, | |||
|
2826 | fctx.path(), fctx.data(), | |||
|
2827 | islink='l' in flags, | |||
|
2828 | isexec='x' in flags, | |||
|
2829 | copied=copied.get(path)) | |||
|
2830 | return mctx | |||
|
2831 | except KeyError: | |||
|
2832 | return None | |||
|
2833 | else: | |||
|
2834 | ui.note(_('copying changeset %s to %s\n') % (old, base)) | |||
|
2835 | ||||
|
2836 | # Use version of files as in the old cset | |||
|
2837 | def filectxfn(repo, ctx_, path): | |||
|
2838 | try: | |||
|
2839 | return old.filectx(path) | |||
|
2840 | except KeyError: | |||
|
2841 | return None | |||
|
2842 | ||||
|
2843 | user = opts.get('user') or old.user() | |||
|
2844 | date = opts.get('date') or old.date() | |||
|
2845 | editform = mergeeditform(old, 'commit.amend') | |||
|
2846 | editor = getcommiteditor(editform=editform, | |||
|
2847 | **pycompat.strkwargs(opts)) | |||
|
2848 | if not message: | |||
|
2849 | editor = getcommiteditor(edit=True, editform=editform) | |||
|
2850 | message = old.description() | |||
|
2851 | ||||
|
2852 | pureextra = extra.copy() | |||
|
2853 | extra['amend_source'] = old.hex() | |||
|
2854 | ||||
|
2855 | new = context.memctx(repo, | |||
|
2856 | parents=[base.node(), old.p2().node()], | |||
|
2857 | text=message, | |||
|
2858 | files=files, | |||
|
2859 | filectxfn=filectxfn, | |||
|
2860 | user=user, | |||
|
2861 | date=date, | |||
|
2862 | extra=extra, | |||
|
2863 | editor=editor) | |||
|
2864 | ||||
|
2865 | newdesc = changelog.stripdesc(new.description()) | |||
|
2866 | if ((not node) | |||
|
2867 | and newdesc == old.description() | |||
|
2868 | and user == old.user() | |||
|
2869 | and date == old.date() | |||
|
2870 | and pureextra == old.extra()): | |||
|
2871 | # nothing changed. continuing here would create a new node | |||
|
2872 | # anyway because of the amend_source noise. | |||
2777 | # |
|
2873 | # | |
2778 | # node/ctx o - new (intermediate) commit that contains changes |
|
2874 | # This not what we expect from amend. | |
2779 | # | from working dir to go into amending commit |
|
2875 | return old.node() | |
2780 | # | (or a workingctx if there were no changes) |
|
2876 | ||
2781 | # | |
|
2877 | ph = repo.ui.config('phases', 'new-commit', phases.draft) | |
2782 | # old o - changeset to amend |
|
2878 | try: | |
2783 | # | |
|
2879 | if opts.get('secret'): | |
2784 | # base o - parent of amending changeset |
|
2880 | commitphase = 'secret' | |
2785 |
|
||||
2786 | # Update extra dict from amended commit (e.g. to preserve graft |
|
|||
2787 | # source) |
|
|||
2788 | extra.update(old.extra()) |
|
|||
2789 |
|
||||
2790 | # Also update it from the intermediate commit or from the wctx |
|
|||
2791 | extra.update(ctx.extra()) |
|
|||
2792 |
|
||||
2793 | if len(old.parents()) > 1: |
|
|||
2794 | # ctx.files() isn't reliable for merges, so fall back to the |
|
|||
2795 | # slower repo.status() method |
|
|||
2796 | files = set([fn for st in repo.status(base, old)[:3] |
|
|||
2797 | for fn in st]) |
|
|||
2798 | else: |
|
2881 | else: | |
2799 |
|
|
2882 | commitphase = old.phase() | |
2800 |
|
2883 | repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend') | ||
2801 | # Second, we use either the commit we just did, or if there were no |
|
2884 | newid = repo.commitctx(new) | |
2802 | # changes the parent of the working directory as the version of the |
|
2885 | finally: | |
2803 | # files in the final amend commit |
|
2886 | repo.ui.setconfig('phases', 'new-commit', ph, 'amend') | |
|
2887 | if newid != old.node(): | |||
|
2888 | # Reroute the working copy parent to the new changeset | |||
|
2889 | repo.setparents(newid, nullid) | |||
|
2890 | mapping = {old.node(): (newid,)} | |||
2804 | if node: |
|
2891 | if node: | |
2805 | ui.note(_('copying changeset %s to %s\n') % (ctx, base)) |
|
2892 | mapping[node] = () | |
2806 |
|
2893 | scmutil.cleanupnodes(repo, mapping, 'amend') | ||
2807 | user = ctx.user() |
|
|||
2808 | date = ctx.date() |
|
|||
2809 | # Recompute copies (avoid recording a -> b -> a) |
|
|||
2810 | copied = copies.pathcopies(base, ctx) |
|
|||
2811 | if old.p2: |
|
|||
2812 | copied.update(copies.pathcopies(old.p2(), ctx)) |
|
|||
2813 |
|
||||
2814 | # Prune files which were reverted by the updates: if old |
|
|||
2815 | # introduced file X and our intermediate commit, node, |
|
|||
2816 | # renamed that file, then those two files are the same and |
|
|||
2817 | # we can discard X from our list of files. Likewise if X |
|
|||
2818 | # was deleted, it's no longer relevant |
|
|||
2819 | files.update(ctx.files()) |
|
|||
2820 | files = [f for f in files if not samefile(f, ctx, base)] |
|
|||
2821 |
|
||||
2822 | def filectxfn(repo, ctx_, path): |
|
|||
2823 | try: |
|
|||
2824 | fctx = ctx[path] |
|
|||
2825 | flags = fctx.flags() |
|
|||
2826 | mctx = context.memfilectx(repo, |
|
|||
2827 | fctx.path(), fctx.data(), |
|
|||
2828 | islink='l' in flags, |
|
|||
2829 | isexec='x' in flags, |
|
|||
2830 | copied=copied.get(path)) |
|
|||
2831 | return mctx |
|
|||
2832 | except KeyError: |
|
|||
2833 | return None |
|
|||
2834 | else: |
|
|||
2835 | ui.note(_('copying changeset %s to %s\n') % (old, base)) |
|
|||
2836 |
|
||||
2837 | # Use version of files as in the old cset |
|
|||
2838 | def filectxfn(repo, ctx_, path): |
|
|||
2839 | try: |
|
|||
2840 | return old.filectx(path) |
|
|||
2841 | except KeyError: |
|
|||
2842 | return None |
|
|||
2843 |
|
||||
2844 | user = opts.get('user') or old.user() |
|
|||
2845 | date = opts.get('date') or old.date() |
|
|||
2846 | editform = mergeeditform(old, 'commit.amend') |
|
|||
2847 | editor = getcommiteditor(editform=editform, |
|
|||
2848 | **pycompat.strkwargs(opts)) |
|
|||
2849 | if not message: |
|
|||
2850 | editor = getcommiteditor(edit=True, editform=editform) |
|
|||
2851 | message = old.description() |
|
|||
2852 |
|
||||
2853 | pureextra = extra.copy() |
|
|||
2854 | extra['amend_source'] = old.hex() |
|
|||
2855 |
|
||||
2856 | new = context.memctx(repo, |
|
|||
2857 | parents=[base.node(), old.p2().node()], |
|
|||
2858 | text=message, |
|
|||
2859 | files=files, |
|
|||
2860 | filectxfn=filectxfn, |
|
|||
2861 | user=user, |
|
|||
2862 | date=date, |
|
|||
2863 | extra=extra, |
|
|||
2864 | editor=editor) |
|
|||
2865 |
|
||||
2866 | newdesc = changelog.stripdesc(new.description()) |
|
|||
2867 | if ((not node) |
|
|||
2868 | and newdesc == old.description() |
|
|||
2869 | and user == old.user() |
|
|||
2870 | and date == old.date() |
|
|||
2871 | and pureextra == old.extra()): |
|
|||
2872 | # nothing changed. continuing here would create a new node |
|
|||
2873 | # anyway because of the amend_source noise. |
|
|||
2874 | # |
|
|||
2875 | # This not what we expect from amend. |
|
|||
2876 | return old.node() |
|
|||
2877 |
|
||||
2878 | ph = repo.ui.config('phases', 'new-commit', phases.draft) |
|
|||
2879 | try: |
|
|||
2880 | if opts.get('secret'): |
|
|||
2881 | commitphase = 'secret' |
|
|||
2882 | else: |
|
|||
2883 | commitphase = old.phase() |
|
|||
2884 | repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend') |
|
|||
2885 | newid = repo.commitctx(new) |
|
|||
2886 | finally: |
|
|||
2887 | repo.ui.setconfig('phases', 'new-commit', ph, 'amend') |
|
|||
2888 | if newid != old.node(): |
|
|||
2889 | # Reroute the working copy parent to the new changeset |
|
|||
2890 | repo.setparents(newid, nullid) |
|
|||
2891 | mapping = {old.node(): (newid,)} |
|
|||
2892 | if node: |
|
|||
2893 | mapping[node] = () |
|
|||
2894 | scmutil.cleanupnodes(repo, mapping, 'amend') |
|
|||
2895 | return newid |
|
2894 | return newid | |
2896 |
|
2895 | |||
2897 | def commiteditor(repo, ctx, subs, editform=''): |
|
2896 | def commiteditor(repo, ctx, subs, editform=''): |
@@ -2177,9 +2177,8 b' def debugtemplate(ui, repo, tmpl, **opts' | |||||
2177 | @command('debugupdatecaches', []) |
|
2177 | @command('debugupdatecaches', []) | |
2178 | def debugupdatecaches(ui, repo, *pats, **opts): |
|
2178 | def debugupdatecaches(ui, repo, *pats, **opts): | |
2179 | """warm all known caches in the repository""" |
|
2179 | """warm all known caches in the repository""" | |
2180 | with repo.wlock(): |
|
2180 | with repo.wlock(), repo.lock(): | |
2181 |
|
|
2181 | repo.updatecaches() | |
2182 | repo.updatecaches() |
|
|||
2183 |
|
2182 | |||
2184 | @command('debugupgraderepo', [ |
|
2183 | @command('debugupgraderepo', [ | |
2185 | ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')), |
|
2184 | ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')), |
@@ -792,35 +792,33 b' def upgraderepo(ui, repo, run=False, opt' | |||||
792 | upgradeactions = [a.name for a in actions] |
|
792 | upgradeactions = [a.name for a in actions] | |
793 |
|
793 | |||
794 | ui.write(_('beginning upgrade...\n')) |
|
794 | ui.write(_('beginning upgrade...\n')) | |
795 | with repo.wlock(): |
|
795 | with repo.wlock(), repo.lock(): | |
796 | with repo.lock(): |
|
796 | ui.write(_('repository locked and read-only\n')) | |
797 | ui.write(_('repository locked and read-only\n')) |
|
797 | # Our strategy for upgrading the repository is to create a new, | |
798 | # Our strategy for upgrading the repository is to create a new, |
|
798 | # temporary repository, write data to it, then do a swap of the | |
799 | # temporary repository, write data to it, then do a swap of the |
|
799 | # data. There are less heavyweight ways to do this, but it is easier | |
800 | # data. There are less heavyweight ways to do this, but it is easier |
|
800 | # to create a new repo object than to instantiate all the components | |
801 | # to create a new repo object than to instantiate all the components |
|
801 | # (like the store) separately. | |
802 | # (like the store) separately. |
|
802 | tmppath = tempfile.mkdtemp(prefix='upgrade.', dir=repo.path) | |
803 | tmppath = tempfile.mkdtemp(prefix='upgrade.', dir=repo.path) |
|
803 | backuppath = None | |
804 | backuppath = None |
|
804 | try: | |
805 | try: |
|
805 | ui.write(_('creating temporary repository to stage migrated ' | |
806 | ui.write(_('creating temporary repository to stage migrated ' |
|
806 | 'data: %s\n') % tmppath) | |
807 | 'data: %s\n') % tmppath) |
|
807 | dstrepo = localrepo.localrepository(repo.baseui, | |
808 | dstrepo = localrepo.localrepository(repo.baseui, |
|
808 | path=tmppath, | |
809 |
|
|
809 | create=True) | |
810 | create=True) |
|
|||
811 |
|
810 | |||
812 |
|
|
811 | with dstrepo.wlock(), dstrepo.lock(): | |
813 | with dstrepo.lock(): |
|
812 | backuppath = _upgraderepo(ui, repo, dstrepo, newreqs, | |
814 | backuppath = _upgraderepo(ui, repo, dstrepo, newreqs, |
|
813 | upgradeactions) | |
815 | upgradeactions) |
|
|||
816 |
|
814 | |||
817 |
|
|
815 | finally: | |
818 |
|
|
816 | ui.write(_('removing temporary repository %s\n') % tmppath) | |
819 |
|
|
817 | repo.vfs.rmtree(tmppath, forcibly=True) | |
820 |
|
818 | |||
821 |
|
|
819 | if backuppath: | |
822 |
|
|
820 | ui.warn(_('copy of old repository backed up at %s\n') % | |
823 |
|
|
821 | backuppath) | |
824 |
|
|
822 | ui.warn(_('the old repository will not be deleted; remove ' | |
825 |
|
|
823 | 'it to free up disk space once the upgraded ' | |
826 |
|
|
824 | 'repository is verified\n')) |
General Comments 0
You need to be logged in to leave comments.
Login now