Show More
@@ -209,7 +209,8 b' It is possible to set Mercurial to autom' | |||
|
209 | 209 | new content is available. |
|
210 | 210 | |
|
211 | 211 | Mercurial will take care of the process asynchronously. The defined list of |
|
212 |
bundle |
|
|
212 | bundle-type will be generated, uploaded, and advertised. Older bundles will get | |
|
213 | decommissioned as newer ones replace them. | |
|
213 | 214 | |
|
214 | 215 | Bundles Generation: |
|
215 | 216 | ................... |
@@ -235,11 +236,26 b' basename in the "public" URL is accessib' | |||
|
235 | 236 | upload-command=sftp put $HGCB_BUNDLE_PATH \ |
|
236 | 237 | sftp://bundles.host/clone-bundles/$HGCB_BUNDLE_BASENAME |
|
237 | 238 | |
|
239 | If the file was already uploaded, the command must still succeed. | |
|
240 | ||
|
238 | 241 | After upload, the file should be available at an url defined by |
|
239 | 242 | `clone-bundles.url-template`. |
|
240 | 243 | |
|
241 | 244 | [clone-bundles] |
|
242 | 245 | url-template=https://bundles.host/cache/clone-bundles/{basename} |
|
246 | ||
|
247 | Old bundles cleanup: | |
|
248 | .................... | |
|
249 | ||
|
250 | When new bundles are generated, the older ones are no longer necessary and can | |
|
251 | be removed from storage. This is done through the `clone-bundles.delete-command` | |
|
252 | configuration. The command is given the url of the artifact to delete through | |
|
253 | the `$HGCB_BUNDLE_URL` environment variable. | |
|
254 | ||
|
255 | [clone-bundles] | |
|
256 | delete-command=sftp rm sftp://bundles.host/clone-bundles/$HGCB_BUNDLE_BASENAME | |
|
257 | ||
|
258 | If the file was already deleted, the command must still succeed. | |
|
243 | 259 | """ |
|
244 | 260 | |
|
245 | 261 | |
@@ -299,6 +315,8 b" configitem(b'clone-bundles', b'auto-gene" | |||
|
299 | 315 | |
|
300 | 316 | configitem(b'clone-bundles', b'upload-command', default=None) |
|
301 | 317 | |
|
318 | configitem(b'clone-bundles', b'delete-command', default=None) | |
|
319 | ||
|
302 | 320 | configitem(b'clone-bundles', b'url-template', default=None) |
|
303 | 321 | |
|
304 | 322 | configitem(b'devel', b'debug.clonebundles', default=False) |
@@ -666,6 +684,34 b' def finalize_one_bundle(repo, target):' | |||
|
666 | 684 | cleanup_tmp_bundle(repo, target) |
|
667 | 685 | |
|
668 | 686 | |
|
687 | def find_outdated_bundles(repo, bundles): | |
|
688 | """finds outdated bundles""" | |
|
689 | olds = [] | |
|
690 | per_types = {} | |
|
691 | for b in bundles: | |
|
692 | if not b.valid_for(repo): | |
|
693 | olds.append(b) | |
|
694 | continue | |
|
695 | l = per_types.setdefault(b.bundle_type, []) | |
|
696 | l.append(b) | |
|
697 | for key in sorted(per_types): | |
|
698 | all = per_types[key] | |
|
699 | if len(all) > 1: | |
|
700 | all.sort(key=lambda b: b.revs, reverse=True) | |
|
701 | olds.extend(all[1:]) | |
|
702 | return olds | |
|
703 | ||
|
704 | ||
|
705 | def collect_garbage(repo): | |
|
706 | """finds outdated bundles and get them deleted""" | |
|
707 | with repo.clonebundles_lock(): | |
|
708 | bundles = read_auto_gen(repo) | |
|
709 | olds = find_outdated_bundles(repo, bundles) | |
|
710 | for o in olds: | |
|
711 | delete_bundle(repo, o) | |
|
712 | update_bundle_list(repo, del_bundles=olds) | |
|
713 | ||
|
714 | ||
|
669 | 715 | def upload_bundle(repo, bundle): |
|
670 | 716 | """upload the result of a GeneratingBundle and return a GeneratedBundle |
|
671 | 717 | |
@@ -691,12 +737,34 b' def upload_bundle(repo, bundle):' | |||
|
691 | 737 | return bundle.uploaded(url, basename) |
|
692 | 738 | |
|
693 | 739 | |
|
740 | def delete_bundle(repo, bundle): | |
|
741 | """delete a bundle from storage""" | |
|
742 | assert bundle.ready | |
|
743 | msg = b'clone-bundles: deleting bundle %s\n' | |
|
744 | msg %= bundle.basename | |
|
745 | if repo.ui.configbool(b'devel', b'debug.clonebundles'): | |
|
746 | repo.ui.write(msg) | |
|
747 | else: | |
|
748 | repo.ui.debug(msg) | |
|
749 | ||
|
750 | cmd = repo.ui.config(b'clone-bundles', b'delete-command') | |
|
751 | variables = { | |
|
752 | b'HGCB_BUNDLE_URL': bundle.file_url, | |
|
753 | b'HGCB_BASENAME': bundle.basename, | |
|
754 | } | |
|
755 | env = procutil.shellenviron(environ=variables) | |
|
756 | ret = repo.ui.system(cmd, environ=env) | |
|
757 | if ret: | |
|
758 | raise error.Abort(b"command returned status %d: %s" % (ret, cmd)) | |
|
759 | ||
|
760 | ||
|
694 | 761 | def auto_bundle_needed_actions(repo, bundles, op_id): |
|
695 | 762 | """find the list of bundles that need action |
|
696 | 763 | |
|
697 | 764 | returns a list of RequestedBundle objects that need to be generated and |
|
698 | 765 | uploaded.""" |
|
699 | 766 | create_bundles = [] |
|
767 | delete_bundles = [] | |
|
700 | 768 | repo = repo.filtered(b"immutable") |
|
701 | 769 | targets = repo.ui.configlist(b'clone-bundles', b'auto-generate.formats') |
|
702 | 770 | revs = len(repo.changelog) |
@@ -712,7 +780,8 b' def auto_bundle_needed_actions(repo, bun' | |||
|
712 | 780 | data['bundle_type'] = t |
|
713 | 781 | b = RequestedBundle(**data) |
|
714 | 782 | create_bundles.append(b) |
|
715 | return create_bundles | |
|
783 | delete_bundles.extend(find_outdated_bundles(repo, bundles)) | |
|
784 | return create_bundles, delete_bundles | |
|
716 | 785 | |
|
717 | 786 | |
|
718 | 787 | def start_one_bundle(repo, bundle): |
@@ -759,6 +828,8 b' def debugmakeclonebundles(ui, repo):' | |||
|
759 | 828 | requested_bundle = util.pickle.load(procutil.stdin) |
|
760 | 829 | procutil.stdin.close() |
|
761 | 830 | |
|
831 | collect_garbage(repo) | |
|
832 | ||
|
762 | 833 | fname = requested_bundle.suggested_filename |
|
763 | 834 | fpath = repo.vfs.makedirs(b'tmp-bundles') |
|
764 | 835 | fpath = repo.vfs.join(b'tmp-bundles', fname) |
@@ -778,7 +849,7 b' def make_auto_bundler(source_repo):' | |||
|
778 | 849 | repo = reporef() |
|
779 | 850 | assert repo is not None |
|
780 | 851 | bundles = read_auto_gen(repo) |
|
781 | new = auto_bundle_needed_actions(repo, bundles, b"%d_txn" % id(tr)) | |
|
852 | new, __ = auto_bundle_needed_actions(repo, bundles, b"%d_txn" % id(tr)) | |
|
782 | 853 | for data in new: |
|
783 | 854 | start_one_bundle(repo, data) |
|
784 | 855 | return None |
@@ -11,6 +11,7 b' initial setup' | |||
|
11 | 11 | > [clone-bundles] |
|
12 | 12 | > auto-generate.formats = v2 |
|
13 | 13 | > upload-command = cp "\$HGCB_BUNDLE_PATH" "$TESTTMP"/final-upload/ |
|
14 | > delete-command = rm -f "$TESTTMP/final-upload/\$HGCB_BASENAME" | |
|
14 | 15 | > url-template = file://$TESTTMP/final-upload/{basename} |
|
15 | 16 | > |
|
16 | 17 | > [devel] |
@@ -68,3 +69,28 b' Newer bundles are generated with more pu' | |||
|
68 | 69 | full-v2-2_revs-aaff8d2ffbbf_tip-*_txn.hg (glob) |
|
69 | 70 | full-v2-4_revs-6427147b985a_tip-*_txn.hg (glob) |
|
70 | 71 | $ ls -1 ../server/.hg/tmp-bundles |
|
72 | ||
|
73 | Older bundles are cleaned up with more pushes | |
|
74 | --------------------------------------------- | |
|
75 | ||
|
76 | $ touch faz | |
|
77 | $ hg -q commit -A -m 'add faz' | |
|
78 | $ touch fuz | |
|
79 | $ hg -q commit -A -m 'add fuz' | |
|
80 | $ hg push | |
|
81 | pushing to $TESTTMP/server | |
|
82 | searching for changes | |
|
83 | adding changesets | |
|
84 | adding manifests | |
|
85 | adding file changes | |
|
86 | clone-bundles: deleting bundle full-v2-2_revs-aaff8d2ffbbf_tip-*_txn.hg (glob) | |
|
87 | 6 changesets found | |
|
88 | added 2 changesets with 2 changes to 2 files | |
|
89 | clone-bundles: starting bundle generation: v2 | |
|
90 | ||
|
91 | $ cat ../server/.hg/clonebundles.manifest | |
|
92 | file:/*/$TESTTMP/final-upload/full-v2-6_revs-b1010e95ea00_tip-*_txn.hg BUNDLESPEC=v2 REQUIRESNI=true (glob) | |
|
93 | $ ls -1 ../final-upload | |
|
94 | full-v2-4_revs-6427147b985a_tip-*_txn.hg (glob) | |
|
95 | full-v2-6_revs-b1010e95ea00_tip-*_txn.hg (glob) | |
|
96 | $ ls -1 ../server/.hg/tmp-bundles |
General Comments 0
You need to be logged in to leave comments.
Login now