hgext/clonebundles.py
changeset 50711 40638610c6ee
parent 50710 1299525832d0
child 50713 ddc55fb220ba
equal deleted inserted replaced
50710:1299525832d0 50711:40638610c6ee
   252 
   252 
   253     [clone-bundles]
   253     [clone-bundles]
   254     auto-generate.on-change=yes
   254     auto-generate.on-change=yes
   255     auto-generate.formats= zstd-v2, gzip-v2
   255     auto-generate.formats= zstd-v2, gzip-v2
   256 
   256 
       
   257 Automatic Inline serving
       
   258 ........................
       
   259 
       
   260 The simplest way to serve the generated bundle is through the Mercurial
       
   261 protocol. However it is not the most efficient as request will still be served
       
   262 by that main server. It is useful in case where authentication is complexe or
       
   263 when an efficient mirror system is already in use anyway. See the `inline
       
   264 clonebundles` section above for details about inline clonebundles
       
   265 
       
   266 To automatically serve generated bundle through inline clonebundle, simply set
       
   267 the following option::
       
   268 
       
   269     auto-generate.serve-inline=yes
       
   270 
       
   271 Enabling this option disable the managed upload and serving explained below.
       
   272 
   257 Bundles Upload and Serving:
   273 Bundles Upload and Serving:
   258 ...........................
   274 ...........................
       
   275 
       
   276 This is the most efficient way to serve automatically generated clone bundles,
       
   277 but requires some setup.
   259 
   278 
   260 The generated bundles need to be made available to users through a "public" URL.
   279 The generated bundles need to be made available to users through a "public" URL.
   261 This should be donne through `clone-bundles.upload-command` configuration. The
   280 This should be donne through `clone-bundles.upload-command` configuration. The
   262 value of this command should be a shell command. It will have access to the
   281 value of this command should be a shell command. It will have access to the
   263 bundle file path through the `$HGCB_BUNDLE_PATH` variable. And the expected
   282 bundle file path through the `$HGCB_BUNDLE_PATH` variable. And the expected
   342 cmdtable = {}
   361 cmdtable = {}
   343 command = registrar.command(cmdtable)
   362 command = registrar.command(cmdtable)
   344 
   363 
   345 configitem(b'clone-bundles', b'auto-generate.on-change', default=False)
   364 configitem(b'clone-bundles', b'auto-generate.on-change', default=False)
   346 configitem(b'clone-bundles', b'auto-generate.formats', default=list)
   365 configitem(b'clone-bundles', b'auto-generate.formats', default=list)
       
   366 configitem(b'clone-bundles', b'auto-generate.serve-inline', default=False)
   347 configitem(b'clone-bundles', b'trigger.below-bundled-ratio', default=0.95)
   367 configitem(b'clone-bundles', b'trigger.below-bundled-ratio', default=0.95)
   348 configitem(b'clone-bundles', b'trigger.revs', default=1000)
   368 configitem(b'clone-bundles', b'trigger.revs', default=1000)
   349 
   369 
   350 configitem(b'clone-bundles', b'upload-command', default=None)
   370 configitem(b'clone-bundles', b'upload-command', default=None)
   351 
   371 
   751 def upload_bundle(repo, bundle):
   771 def upload_bundle(repo, bundle):
   752     """upload the result of a GeneratingBundle and return a GeneratedBundle
   772     """upload the result of a GeneratingBundle and return a GeneratedBundle
   753 
   773 
   754     The upload is done using the `clone-bundles.upload-command`
   774     The upload is done using the `clone-bundles.upload-command`
   755     """
   775     """
   756     cmd = repo.ui.config(b'clone-bundles', b'upload-command')
   776     inline = repo.ui.config(b'clone-bundles', b'auto-generate.serve-inline')
   757     url = repo.ui.config(b'clone-bundles', b'url-template')
       
   758     basename = repo.vfs.basename(bundle.filepath)
   777     basename = repo.vfs.basename(bundle.filepath)
   759     filepath = procutil.shellquote(bundle.filepath)
   778     if inline:
   760     variables = {
   779         dest_dir = repo.vfs.join(bundlecaches.BUNDLE_CACHE_DIR)
   761         b'HGCB_BUNDLE_PATH': filepath,
   780         repo.vfs.makedirs(dest_dir)
   762         b'HGCB_BUNDLE_BASENAME': basename,
   781         dest = repo.vfs.join(dest_dir, basename)
   763     }
   782         util.copyfiles(bundle.filepath, dest, hardlink=True)
   764     env = procutil.shellenviron(environ=variables)
   783         url = bundlecaches.CLONEBUNDLESCHEME + basename
   765     ret = repo.ui.system(cmd, environ=env)
   784         return bundle.uploaded(url, basename)
   766     if ret:
   785     else:
   767         raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
   786         cmd = repo.ui.config(b'clone-bundles', b'upload-command')
   768     url = (
   787         url = repo.ui.config(b'clone-bundles', b'url-template')
   769         url.decode('utf8')
   788         filepath = procutil.shellquote(bundle.filepath)
   770         .format(basename=basename.decode('utf8'))
   789         variables = {
   771         .encode('utf8')
   790             b'HGCB_BUNDLE_PATH': filepath,
   772     )
   791             b'HGCB_BUNDLE_BASENAME': basename,
   773     return bundle.uploaded(url, basename)
   792         }
       
   793         env = procutil.shellenviron(environ=variables)
       
   794         ret = repo.ui.system(cmd, environ=env)
       
   795         if ret:
       
   796             raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
       
   797         url = (
       
   798             url.decode('utf8')
       
   799             .format(basename=basename.decode('utf8'))
       
   800             .encode('utf8')
       
   801         )
       
   802         return bundle.uploaded(url, basename)
   774 
   803 
   775 
   804 
   776 def delete_bundle(repo, bundle):
   805 def delete_bundle(repo, bundle):
   777     """delete a bundle from storage"""
   806     """delete a bundle from storage"""
   778     assert bundle.ready
   807     assert bundle.ready
   779     msg = b'clone-bundles: deleting bundle %s\n'
   808 
       
   809     inline = bundle.file_url.startswith(bundlecaches.CLONEBUNDLESCHEME)
       
   810 
       
   811     if inline:
       
   812         msg = b'clone-bundles: deleting inline bundle %s\n'
       
   813     else:
       
   814         msg = b'clone-bundles: deleting bundle %s\n'
   780     msg %= bundle.basename
   815     msg %= bundle.basename
   781     if repo.ui.configbool(b'devel', b'debug.clonebundles'):
   816     if repo.ui.configbool(b'devel', b'debug.clonebundles'):
   782         repo.ui.write(msg)
   817         repo.ui.write(msg)
   783     else:
   818     else:
   784         repo.ui.debug(msg)
   819         repo.ui.debug(msg)
   785 
   820 
   786     cmd = repo.ui.config(b'clone-bundles', b'delete-command')
   821     if inline:
   787     variables = {
   822         inline_path = repo.vfs.join(
   788         b'HGCB_BUNDLE_URL': bundle.file_url,
   823             bundlecaches.BUNDLE_CACHE_DIR,
   789         b'HGCB_BASENAME': bundle.basename,
   824             bundle.basename,
   790     }
   825         )
   791     env = procutil.shellenviron(environ=variables)
   826         util.tryunlink(inline_path)
   792     ret = repo.ui.system(cmd, environ=env)
   827     else:
   793     if ret:
   828         cmd = repo.ui.config(b'clone-bundles', b'delete-command')
   794         raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
   829         variables = {
       
   830             b'HGCB_BUNDLE_URL': bundle.file_url,
       
   831             b'HGCB_BASENAME': bundle.basename,
       
   832         }
       
   833         env = procutil.shellenviron(environ=variables)
       
   834         ret = repo.ui.system(cmd, environ=env)
       
   835         if ret:
       
   836             raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
   795 
   837 
   796 
   838 
   797 def auto_bundle_needed_actions(repo, bundles, op_id):
   839 def auto_bundle_needed_actions(repo, bundles, op_id):
   798     """find the list of bundles that need action
   840     """find the list of bundles that need action
   799 
   841