Show More
@@ -209,7 +209,8 b' It is possible to set Mercurial to autom' | |||||
209 | new content is available. |
|
209 | new content is available. | |
210 |
|
210 | |||
211 | Mercurial will take care of the process asynchronously. The defined list of |
|
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 | Bundles Generation: |
|
215 | Bundles Generation: | |
215 | ................... |
|
216 | ................... | |
@@ -235,11 +236,26 b' basename in the "public" URL is accessib' | |||||
235 | upload-command=sftp put $HGCB_BUNDLE_PATH \ |
|
236 | upload-command=sftp put $HGCB_BUNDLE_PATH \ | |
236 | sftp://bundles.host/clone-bundles/$HGCB_BUNDLE_BASENAME |
|
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 | After upload, the file should be available at an url defined by |
|
241 | After upload, the file should be available at an url defined by | |
239 | `clone-bundles.url-template`. |
|
242 | `clone-bundles.url-template`. | |
240 |
|
243 | |||
241 | [clone-bundles] |
|
244 | [clone-bundles] | |
242 | url-template=https://bundles.host/cache/clone-bundles/{basename} |
|
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 | configitem(b'clone-bundles', b'upload-command', default=None) |
|
316 | configitem(b'clone-bundles', b'upload-command', default=None) | |
301 |
|
317 | |||
|
318 | configitem(b'clone-bundles', b'delete-command', default=None) | |||
|
319 | ||||
302 | configitem(b'clone-bundles', b'url-template', default=None) |
|
320 | configitem(b'clone-bundles', b'url-template', default=None) | |
303 |
|
321 | |||
304 | configitem(b'devel', b'debug.clonebundles', default=False) |
|
322 | configitem(b'devel', b'debug.clonebundles', default=False) | |
@@ -666,6 +684,34 b' def finalize_one_bundle(repo, target):' | |||||
666 | cleanup_tmp_bundle(repo, target) |
|
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 | def upload_bundle(repo, bundle): |
|
715 | def upload_bundle(repo, bundle): | |
670 | """upload the result of a GeneratingBundle and return a GeneratedBundle |
|
716 | """upload the result of a GeneratingBundle and return a GeneratedBundle | |
671 |
|
717 | |||
@@ -691,12 +737,34 b' def upload_bundle(repo, bundle):' | |||||
691 | return bundle.uploaded(url, basename) |
|
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 | def auto_bundle_needed_actions(repo, bundles, op_id): |
|
761 | def auto_bundle_needed_actions(repo, bundles, op_id): | |
695 | """find the list of bundles that need action |
|
762 | """find the list of bundles that need action | |
696 |
|
763 | |||
697 | returns a list of RequestedBundle objects that need to be generated and |
|
764 | returns a list of RequestedBundle objects that need to be generated and | |
698 | uploaded.""" |
|
765 | uploaded.""" | |
699 | create_bundles = [] |
|
766 | create_bundles = [] | |
|
767 | delete_bundles = [] | |||
700 | repo = repo.filtered(b"immutable") |
|
768 | repo = repo.filtered(b"immutable") | |
701 | targets = repo.ui.configlist(b'clone-bundles', b'auto-generate.formats') |
|
769 | targets = repo.ui.configlist(b'clone-bundles', b'auto-generate.formats') | |
702 | revs = len(repo.changelog) |
|
770 | revs = len(repo.changelog) | |
@@ -712,7 +780,8 b' def auto_bundle_needed_actions(repo, bun' | |||||
712 | data['bundle_type'] = t |
|
780 | data['bundle_type'] = t | |
713 | b = RequestedBundle(**data) |
|
781 | b = RequestedBundle(**data) | |
714 | create_bundles.append(b) |
|
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 | def start_one_bundle(repo, bundle): |
|
787 | def start_one_bundle(repo, bundle): | |
@@ -759,6 +828,8 b' def debugmakeclonebundles(ui, repo):' | |||||
759 | requested_bundle = util.pickle.load(procutil.stdin) |
|
828 | requested_bundle = util.pickle.load(procutil.stdin) | |
760 | procutil.stdin.close() |
|
829 | procutil.stdin.close() | |
761 |
|
830 | |||
|
831 | collect_garbage(repo) | |||
|
832 | ||||
762 | fname = requested_bundle.suggested_filename |
|
833 | fname = requested_bundle.suggested_filename | |
763 | fpath = repo.vfs.makedirs(b'tmp-bundles') |
|
834 | fpath = repo.vfs.makedirs(b'tmp-bundles') | |
764 | fpath = repo.vfs.join(b'tmp-bundles', fname) |
|
835 | fpath = repo.vfs.join(b'tmp-bundles', fname) | |
@@ -778,7 +849,7 b' def make_auto_bundler(source_repo):' | |||||
778 | repo = reporef() |
|
849 | repo = reporef() | |
779 | assert repo is not None |
|
850 | assert repo is not None | |
780 | bundles = read_auto_gen(repo) |
|
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 | for data in new: |
|
853 | for data in new: | |
783 | start_one_bundle(repo, data) |
|
854 | start_one_bundle(repo, data) | |
784 | return None |
|
855 | return None |
@@ -11,6 +11,7 b' initial setup' | |||||
11 | > [clone-bundles] |
|
11 | > [clone-bundles] | |
12 | > auto-generate.formats = v2 |
|
12 | > auto-generate.formats = v2 | |
13 | > upload-command = cp "\$HGCB_BUNDLE_PATH" "$TESTTMP"/final-upload/ |
|
13 | > upload-command = cp "\$HGCB_BUNDLE_PATH" "$TESTTMP"/final-upload/ | |
|
14 | > delete-command = rm -f "$TESTTMP/final-upload/\$HGCB_BASENAME" | |||
14 | > url-template = file://$TESTTMP/final-upload/{basename} |
|
15 | > url-template = file://$TESTTMP/final-upload/{basename} | |
15 | > |
|
16 | > | |
16 | > [devel] |
|
17 | > [devel] | |
@@ -68,3 +69,28 b' Newer bundles are generated with more pu' | |||||
68 | full-v2-2_revs-aaff8d2ffbbf_tip-*_txn.hg (glob) |
|
69 | full-v2-2_revs-aaff8d2ffbbf_tip-*_txn.hg (glob) | |
69 | full-v2-4_revs-6427147b985a_tip-*_txn.hg (glob) |
|
70 | full-v2-4_revs-6427147b985a_tip-*_txn.hg (glob) | |
70 | $ ls -1 ../server/.hg/tmp-bundles |
|
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