(Steve Dougherty)
2013-06-19: Merge ArneBab freenet-scheme. Merge ArneBab freenet-scheme.
diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py --- a/infocalypse/__init__.py +++ b/infocalypse/__init__.py @@ -20,7 +20,7 @@ a running FMS server. For more information on FMS see: USK@0npnMrqZNKRCRoGojZV93UNHCMN-6UU3rRSAmP6jNLE, - ~BG-edFtdCC1cSH4O3BWdeIYa8Sw5DfyrSV-TKdO5ec,AQACAAE/fms/128/ + ~BG-edFtdCC1cSH4O3BWdeIYa8Sw5DfyrSV-TKdO5ec,AQACAAE/fms/106/ ADDING THE EXTENSION: Add the following to your .hgrc/mercurial.ini file. @@ -68,14 +68,10 @@ USAGE EXAMPLES: hg fn-create --uri USK@/test.R1/0 -hg fn-create --wot nickname/test.R1/0 - Inserts the local hg repository into a new USK in Freenet, using the private key in your config file. You can use a full insert URI -value if you want, or --wot for inserting -under a WoT ID. It takes enough of a WoT -nickname required to be unambiguous. +value if you want. hg fn-push --uri USK@/test.R1/0 @@ -162,7 +158,7 @@ 0 = djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqh 2 = test1@SH1BCHw-47oD9~B56SkijxfE35M9XUvqXLX1aYyZNyA|fab7c8bd2fc3 You MUST update the trust map to enable index updating for -repos other than the one this code lives in (c856b1653f0b). +repos other than the one this code lives in (be68e8feccdd). You can edit the config file directly if you want. However, the easiest way to update the trust map is by using the @@ -204,7 +200,7 @@ repository hash. e.g. to pull this code, cd to an empty directory and type: hg init -hg fn-pull --hash c856b1653f0b --aggressive +hg fn-pull --hash be68e8feccdd --aggressive The command: @@ -338,575 +334,16 @@ d kar bott at com cast dot net import os -from binascii import hexlify -from mercurial import commands, util +from commands import * -from infcmds import get_config_info, execute_create, execute_pull, \ - execute_push, execute_setup, execute_copy, execute_reinsert, \ - execute_info +from mercurial import commands, extensions, util, hg, dispatch, discovery +from mercurial.i18n import _ -from fmscmds import execute_fmsread, execute_fmsnotify, get_uri_from_hash, \ - execute_setupfms +import freenetrepo -from sitecmds import execute_putsite, execute_genkey -from wikicmds import execute_wiki, execute_wiki_apply -from arccmds import execute_arc_create, execute_arc_pull, execute_arc_push, \ - execute_arc_reinsert - -from config import read_freesite_cfg, Config -from validate import is_hex_string, is_fms_id - -def set_target_version(ui_, repo, opts, params, msg_fmt): - """ INTERNAL: Update TARGET_VERSION in params. """ - - revs = opts.get('rev') or None - if not revs is None: - for rev in revs: - repo.changectx(rev) # Fail if we don't have the rev. - - params['TO_VERSIONS'] = tuple(revs) - ui_.status(msg_fmt % ' '.join([ver[:12] for ver in revs])) - else: - # REDFLAG: get rid of default versions arguments? - params['TO_VERSIONS'] = tuple([hexlify(head) for head in repo.heads()]) - #print "set_target_version -- using all head" - #print params['TO_VERSIONS'] - -def infocalypse_create(ui_, repo, **opts): - """ Create a new Infocalypse repository in Freenet. """ - params, stored_cfg = get_config_info(ui_, opts) - - insert_uri = '' - attributes = None - if opts['uri'] != '' and opts['wot'] != '': - ui_.warn("Please specify only one of --uri or --wot.\n") - return - elif opts['uri'] != '': - insert_uri = opts['uri'] - elif opts['wot'] != '': - # Expecting wot_id/repo_name.R<redundancy num>/edition/ - wot_id, repo_desc = opts['wot'].split('/', 1) - - import wot - - ui_.status("Querying WoT for local identities.\n") - - attributes = wot.resolve_local_identity(ui_, wot_id) - if attributes is None: - # Something went wrong; the function already printed an error. - return - - ui_.status('Found {0}@{1}\n'.format(attributes['Nickname'], - attributes['Identity'])) - - insert_uri = attributes['InsertURI'] - - # LCWoT returns URIs with a "freenet:" prefix, and WoT does not. The - # rest of Infocalypse does not support the prefix. The local way to fix - # this is to remove it here, but the more flexible way that is also - # more work is to expand support to the rest of Infocalypse. - # TODO: More widespread support for "freenet:" URI prefix. - prefix = "freenet:" - if insert_uri.startswith(prefix): - insert_uri = insert_uri[len(prefix):] - - # URI is USK@key/WebOfTrust/<edition>, but we only want USK@key - insert_uri = insert_uri.split('/', 1)[0] - insert_uri += '/' + repo_desc - - # Add "vcs" context. No-op if the identity already has it. - msg_params = {'Message':'AddContext', - 'Identity': attributes['Identity'], - 'Context': 'vcs'} - - import fcp - node = fcp.FCPNode() - vcs_response =\ - node.fcpPluginMessage(async=False, - plugin_name="plugins.WebOfTrust.WebOfTrust", - plugin_params=msg_params)[0] - - if vcs_response['header'] != 'FCPPluginReply' or\ - 'Replies.Message' not in vcs_response or\ - vcs_response['Replies.Message'] != 'ContextAdded': - ui_.warn("Failed to add context. Got {0}\n.".format(vcs_response)) - return - - # TODO: Would it be friendlier to include the nickname as well? - stored_cfg.set_wot_identity(stored_cfg.get_request_uri(repo.root), - attributes['Identity']) - else: - ui_.warn("Please set the insert key with either --uri or --wot.\n") - - set_target_version(ui_, repo, opts, params, - "Only inserting to version(s): %s\n") - params['INSERT_URI'] = insert_uri - inserted_to = execute_create(ui_, repo, params, stored_cfg) - - # TODO: Move into some function. How to separate local success context? - if inserted_to is not None and attributes is not None and \ - stored_cfg.has_wot_identity(stored_cfg.get_request_uri(repo.root)): - import wot - wot.update_repo_listing(ui_, attributes['Identity']) - -def infocalypse_copy(ui_, repo, **opts): - """ Copy an Infocalypse repository to a new URI. """ - params, stored_cfg = get_config_info(ui_, opts) - - insert_uri = opts['inserturi'] - if insert_uri == '': - # REDFLAG: fix parameter definition so that it is required? - ui_.warn("Please set the insert URI with --inserturi.\n") - return - - request_uri = opts['requesturi'] - if request_uri == '': - request_uri = stored_cfg.get_request_uri(repo.root) - if not request_uri: - ui_.warn("There is no stored request URI for this repo.\n" - "Please set one with the --requesturi option.\n") - return - - params['INSERT_URI'] = insert_uri - params['REQUEST_URI'] = request_uri - execute_copy(ui_, repo, params, stored_cfg) - -def infocalypse_reinsert(ui_, repo, **opts): - """ Reinsert the current version of an Infocalypse repository. """ - params, stored_cfg = get_config_info(ui_, opts) - - request_uri = opts['uri'] - if request_uri == '': - request_uri = stored_cfg.get_request_uri(repo.root) - if not request_uri: - ui_.warn("There is no stored request URI for this repo.\n" - "Do a fn-pull from a repository USK and try again.\n") - return - - level = opts['level'] - if level < 1 or level > 5: - ui_.warn("level must be 1,2,3,4 or 5.\n") - return - - insert_uri = stored_cfg.get_dir_insert_uri(repo.root) - if not insert_uri: - if level == 1 or level == 4: - ui_.warn(("You can't re-insert at level %i without the " - + "insert URI.\n") % level) - return - - ui_.status("No insert URI. Will skip re-insert " - +"of top key.\n") - insert_uri = None - - params['INSERT_URI'] = insert_uri - params['REQUEST_URI'] = request_uri - params['REINSERT_LEVEL'] = level - execute_reinsert(ui_, repo, params, stored_cfg) - -def infocalypse_pull(ui_, repo, **opts): - """ Pull from an Infocalypse repository in Freenet. - """ - params, stored_cfg = get_config_info(ui_, opts) - - if opts['hash']: - # Use FMS to lookup the uri from the repo hash. - if opts['uri'] != '': - ui_.warn("Ignoring --uri because --hash is set!\n") - if len(opts['hash']) != 1: - raise util.Abort("Only one --hash value is allowed.") - params['FMSREAD_HASH'] = opts['hash'][0] - params['FMSREAD_ONLYTRUSTED'] = bool(opts['onlytrusted']) - request_uri = get_uri_from_hash(ui_, repo, params, stored_cfg) - elif opts['wot']: - import wot - if opts['truster']: - truster = opts['truster'] - else : - truster = stored_cfg.get_wot_identity( - stored_cfg.get_dir_insert_uri(repo.root)) - # TODO: Require repo name, not full path as part of the --wot. Look - # it up from the XML. - # TODO: Insert XML. - - # Expecting <id stuff>/reponame - wot_id, repo_name = opts['wot'].split('/', 1) - - # TODO: How to handle redundancy? Does Infocalypse automatically try - # an R0 if an R1 fails? - - repositories = wot.read_repo_listing(ui_, truster, wot_id) - if repo_name not in repositories: - ui_.warn("Could not find repository named \"{0}\".\n".format(repo_name)) - return - - request_uri = repositories[repo_name] - else: - request_uri = opts['uri'] - - if request_uri == '': - request_uri = stored_cfg.get_request_uri(repo.root) - if not request_uri: - ui_.warn("There is no stored request URI for this repo.\n" - "Please set one with the --uri option.\n") - return - - params['REQUEST_URI'] = request_uri - # Hmmmm... can't really implement rev. - execute_pull(ui_, repo, params, stored_cfg) - - -def infocalypse_pull_request(ui, repo, **opts): - if not opts['wot']: - ui.warning("Who do you want to send the pull request to? Set --wot.") - return - - -def infocalypse_push(ui_, repo, **opts): - """ Push to an Infocalypse repository in Freenet. """ - params, stored_cfg = get_config_info(ui_, opts) - insert_uri = opts['uri'] - if insert_uri == '': - insert_uri = stored_cfg.get_dir_insert_uri(repo.root) - if not insert_uri: - ui_.warn("There is no stored insert URI for this repo.\n" - "Please set one with the --uri option.\n") - return - - set_target_version(ui_, repo, opts, params, - "Only pushing to version(s): %s\n") - params['INSERT_URI'] = insert_uri - #if opts['requesturi'] != '': - # # DOESN'T search the insert uri index. - # ui_.status(("Copying from:\n%s\nTo:\n%s\n\nThis is an " - # + "advanced feature. " - # + "I hope you know what you're doing.\n") % - # (opts['requesturi'], insert_uri)) - # params['REQUEST_URI'] = opts['requesturi'] - - inserted_to = execute_push(ui_, repo, params, stored_cfg) - # TODO: Messy. - if inserted_to is not None and stored_cfg.has_wot_identity(stored_cfg - .get_request_uri(repo.root)): - import wot - wot.update_repo_listing(ui_, stored_cfg.get_wot_identity(stored_cfg - .get_request_uri(repo.root))) - -def infocalypse_info(ui_, repo, **opts): - """ Display information about an Infocalypse repository. - """ - # FCP not required. Hmmm... Hack - opts['fcphost'] = '' - opts['fcpport'] = 0 - params, stored_cfg = get_config_info(ui_, opts) - request_uri = opts['uri'] - if request_uri == '': - request_uri = stored_cfg.get_request_uri(repo.root) - if not request_uri: - ui_.warn("There is no stored request URI for this repo.\n" - "Please set one with the --uri option.\n") - return - - params['REQUEST_URI'] = request_uri - execute_info(ui_, repo, params, stored_cfg) - -def parse_trust_args(params, opts): - """ INTERNAL: Helper function to parse --hash and --fmsid. """ - if opts.get('hash', []) == []: - raise util.Abort("Use --hash to set the USK hash.") - if len(opts['hash']) != 1: - raise util.Abort("Only one --hash value is allowed.") - if not is_hex_string(opts['hash'][0]): - raise util.Abort("[%s] doesn't look like a USK hash." % - opts['hash'][0]) - - if opts.get('fmsid', []) == []: - raise util.Abort("Use --fmsid to set the FMS id.") - if len(opts['fmsid']) != 1: - raise util.Abort("Only one --fmsid value is allowed.") - if not is_fms_id(opts['fmsid'][0]): - raise util.Abort("[%s] doesn't look like an FMS id." - % opts['fmsid'][0]) - - params['FMSREAD_HASH'] = opts['hash'][0] - params['FMSREAD_FMSID'] = opts['fmsid'][0] - -def parse_fmsread_subcmd(params, opts): - """ INTERNAL: Parse subcommand for fmsread.""" - if opts['listall']: - params['FMSREAD'] = 'listall' - elif opts['list']: - params['FMSREAD'] = 'list' - elif opts['showtrust']: - params['FMSREAD'] = 'showtrust' - elif opts['trust']: - params['FMSREAD'] = 'trust' - parse_trust_args(params, opts) - elif opts['untrust']: - params['FMSREAD'] = 'untrust' - parse_trust_args(params, opts) - else: - params['FMSREAD'] = 'update' - -def infocalypse_fmsread(ui_, repo, **opts): - """ Read repository update information from fms. - """ - # FCP not required. Hmmm... Hack - opts['fcphost'] = '' - opts['fcpport'] = 0 - params, stored_cfg = get_config_info(ui_, opts) - request_uri = opts['uri'] - if request_uri == '': - request_uri = stored_cfg.get_request_uri(repo.root) - if not request_uri: - ui_.status("There is no stored request URI for this repo.\n") - request_uri = None - parse_fmsread_subcmd(params, opts) - params['DRYRUN'] = opts['dryrun'] - params['REQUEST_URI'] = request_uri - execute_fmsread(ui_, params, stored_cfg) - -def infocalypse_fmsnotify(ui_, repo, **opts): - """ Post a msg with the current repository USK index to fms. - """ - params, stored_cfg = get_config_info(ui_, opts) - insert_uri = stored_cfg.get_dir_insert_uri(repo.root) - if not insert_uri and not (opts['submitbundle'] or - opts['submitwiki']): - ui_.warn("You can't notify because there's no stored " - + "insert URI for this repo.\n" - + "Run from the directory you inserted from.\n") - return - - params['ANNOUNCE'] = opts['announce'] - params['SUBMIT_BUNDLE'] = opts['submitbundle'] - params['SUBMIT_WIKI'] = opts['submitwiki'] - if params['SUBMIT_WIKI'] or params['SUBMIT_BUNDLE']: - request_uri = stored_cfg.get_request_uri(repo.root) - if not request_uri: - ui_.warn("There is no stored request URI for this repo.\n") - raise util.Abort("No request URI.") - params['REQUEST_URI'] = request_uri - - params['DRYRUN'] = opts['dryrun'] - params['INSERT_URI'] = insert_uri - execute_fmsnotify(ui_, repo, params, stored_cfg) - -MSG_BAD_INDEX = 'You must set --index to a value >= 0.' -def infocalypse_putsite(ui_, repo, **opts): - """ Insert an update to a freesite. - """ - - if opts['createconfig']: - if opts['wiki']: - raise util.Abort("Use fn-wiki --createconfig.") - params = {'SITE_CREATE_CONFIG':True} - execute_putsite(ui_, repo, params) - return - - params, stored_cfg = get_config_info(ui_, opts) - if opts['key'] != '': # order important - params['SITE_KEY'] = opts['key'] - if not (params['SITE_KEY'].startswith('SSK') or - params['SITE_KEY'] == 'CHK@'): - raise util.Abort("--key must be a valid SSK " - + "insert key or CHK@.") - - params['ISWIKI'] = opts['wiki'] - read_freesite_cfg(ui_, repo, params, stored_cfg) - - try: - # --index not required for CHK@ - if not params['SITE_KEY'].startswith('CHK'): - params['SITE_INDEX'] = int(opts['index']) - if params['SITE_INDEX'] < 0: - raise ValueError() - else: - params['SITE_INDEX'] = -1 - except ValueError: - raise util.Abort(MSG_BAD_INDEX) - except TypeError: - raise util.Abort(MSG_BAD_INDEX) - - params['DRYRUN'] = opts['dryrun'] - - if not params.get('SITE_KEY', None): - insert_uri = stored_cfg.get_dir_insert_uri(repo.root) - if not insert_uri: - ui_.warn("You don't have the insert URI for this repo.\n" - + "Supply a private key with --key or fn-push " - + "the repo.\n") - return # REDFLAG: hmmm... abort? - params['SITE_KEY'] = 'SSK' + insert_uri.split('/')[0][3:] - - execute_putsite(ui_, repo, params) - -def infocalypse_wiki(ui_, repo, **opts): - """ View and edit the current repository as a wiki. """ - if os.getcwd() != repo.root: - raise util.Abort("You must be in the repository root directory.") - - subcmds = ('run', 'createconfig', 'apply') - required = sum([bool(opts[cmd]) for cmd in subcmds]) - if required == 0: - raise util.Abort("You must specify either --run, " + - "--createconfig, --apply") - if required > 1: - raise util.Abort("Use either --run, --createconfig, or --apply") - - if opts['apply'] != '': - params, stored_cfg = get_config_info(ui_, opts) - params['REQUEST_URI'] = opts['apply'] - execute_wiki_apply(ui_, repo, params, stored_cfg) - return - - if opts['fcphost'] != '' or opts['fcpport'] != 0: - raise util.Abort("--fcphost, --fcpport only for --apply") - - # hmmmm.... useless copy? - params = {'WIKI' : [cmd for cmd in subcmds if opts[cmd]][0], - 'HTTP_PORT': opts['http_port'], - 'HTTP_BIND': opts['http_bind']} - execute_wiki(ui_, repo, params) - -def infocalypse_genkey(ui_, **opts): - """ Print a new SSK key pair. """ - params, dummy = get_config_info(ui_, opts) - execute_genkey(ui_, params) - -def infocalypse_setup(ui_, **opts): - """ Setup the extension for use for the first time. """ - - execute_setup(ui_, - opts['fcphost'], - opts['fcpport'], - opts['tmpdir']) - - if not opts['nofms']: - execute_setupfms(ui_, opts) - else: - ui_.status("Skipped FMS configuration because --nofms was set.\n") - - if not opts['nowot']: - import wot - wot.execute_setup_wot(ui_, opts) - else: - ui_.status("Skipped WoT configuration because --nowot was set.\n") - -def infocalypse_setupfms(ui_, **opts): - """ Setup or modify the fms configuration. """ - # REQUIRES config file. - execute_setupfms(ui_, opts) - - -# TODO: Why ui with trailing underscore? Is there a global "ui" somewhere? -def infocalypse_setupwot(ui_, **opts): - import wot - wot.execute_setup_wot(ui_, opts) - - -# TODO: Should Freemail setup also be part of fn-setup? -# TODO: Should there be per-Identity config? Then each one would have a list -# of repos and optionally a Freemail password. -# Nah, FMS config is global. -def infocalypse_setupfreemail(ui, **opts): - if 'truster' in opts: - identity = opts['truster'] - else: - cfg = Config().from_ui(ui) - identity = cfg.defaults['TRUSTER'] - import wot - # TODO: Should this be part of the normal fn-setup? - wot.execute_setup_freemail(ui, identity) - -#----------------------------------------------------------" -def do_archive_create(ui_, opts, params, stored_cfg): - """ fn-archive --create.""" - insert_uri = opts['uri'] - if insert_uri == '': - raise util.Abort("Please set the insert URI with --uri.") - - params['INSERT_URI'] = insert_uri - params['FROM_DIR'] = os.getcwd() - execute_arc_create(ui_, params, stored_cfg) - -def do_archive_push(ui_, opts, params, stored_cfg): - """ fn-archive --push.""" - insert_uri = opts['uri'] - if insert_uri == '': - insert_uri = ( - stored_cfg.get_dir_insert_uri(params['ARCHIVE_CACHE_DIR'])) - if not insert_uri: - ui_.warn("There is no stored insert URI for this archive.\n" - "Please set one with the --uri option.\n") - raise util.Abort("No Insert URI.") - - params['INSERT_URI'] = insert_uri - params['FROM_DIR'] = os.getcwd() - - execute_arc_push(ui_, params, stored_cfg) - -def do_archive_pull(ui_, opts, params, stored_cfg): - """ fn-archive --pull.""" - request_uri = opts['uri'] - - if request_uri == '': - request_uri = ( - stored_cfg.get_request_uri(params['ARCHIVE_CACHE_DIR'])) - if not request_uri: - ui_.warn("There is no stored request URI for this archive.\n" - "Please set one with the --uri option.\n") - raise util.Abort("No request URI.") - - params['REQUEST_URI'] = request_uri - params['TO_DIR'] = os.getcwd() - execute_arc_pull(ui_, params, stored_cfg) - -ILLEGAL_FOR_REINSERT = ('uri', 'aggressive', 'nosearch') -def do_archive_reinsert(ui_, opts, params, stored_cfg): - """ fn-archive --reinsert.""" - illegal = [value for value in ILLEGAL_FOR_REINSERT - if value in opts and opts[value]] - if illegal: - raise util.Abort("--uri, --aggressive, --nosearch illegal " + - "for reinsert.") - request_uri = stored_cfg.get_request_uri(params['ARCHIVE_CACHE_DIR']) - if request_uri is None: - ui_.warn("There is no stored request URI for this archive.\n" + - "Run fn-archive --pull first!.\n") - raise util.Abort(" No request URI, can't re-insert") - - insert_uri = stored_cfg.get_dir_insert_uri(params['ARCHIVE_CACHE_DIR']) - params['REQUEST_URI'] = request_uri - params['INSERT_URI'] = insert_uri - params['FROM_DIR'] = os.getcwd() # hmmm not used. - params['REINSERT_LEVEL'] = 3 - execute_arc_reinsert(ui_, params, stored_cfg) - -ARCHIVE_SUBCMDS = {'create':do_archive_create, - 'push':do_archive_push, - 'pull':do_archive_pull, - 'reinsert':do_archive_reinsert} -ARCHIVE_CACHE_DIR = '.ARCHIVE_CACHE' -def infocalypse_archive(ui_, **opts): - """ Commands to maintain a non-hg incremental archive.""" - subcmd = [value for value in ARCHIVE_SUBCMDS if opts[value]] - if len(subcmd) > 1: - raise util.Abort("--create, --pull, --push are mutally exclusive. " + - "Only specify one.") - if len(subcmd) > 0: - subcmd = subcmd[0] - else: - subcmd = "pull" - - params, stored_cfg = get_config_info(ui_, opts) - params['ARCHIVE_CACHE_DIR'] = os.path.join(os.getcwd(), ARCHIVE_CACHE_DIR) - - if not subcmd in ARCHIVE_SUBCMDS: - raise util.Abort("Unhandled subcommand: " + subcmd) - - # 2 qt? - ARCHIVE_SUBCMDS[subcmd](ui_, opts, params, stored_cfg) +_freenetschemes = ('freenet', ) +for _scheme in _freenetschemes: + hg.schemes[_scheme] = freenetrepo #----------------------------------------------------------" @@ -928,13 +365,17 @@ NOSEARCH_OPT = [('', 'nosearch', None, ' # Allow mercurial naming convention for command table. # pylint: disable-msg=C0103 +PULL_OPTS = [('', 'hash', [], 'repo hash of repository to pull from'), + ('', 'onlytrusted', None, 'only use repo announcements from ' + + 'known users')] + cmdtable = { "fn-pull": (infocalypse_pull, [('', 'uri', '', 'request URI to pull from'), ('', 'hash', [], 'repo hash of repository to pull from'), - ('', 'wot', '', 'WoT nick@key/repo to pull from'), ('', 'onlytrusted', None, 'only use repo announcements from ' + 'known users')] + + PULL_OPTS + WOT_OPTS + FCP_OPTS + NOSEARCH_OPT diff --git a/infocalypse/commands.py b/infocalypse/commands.py new file mode 100644 --- /dev/null +++ b/infocalypse/commands.py @@ -0,0 +1,445 @@ +from binascii import hexlify +from mercurial import util, hg + +from infcmds import get_config_info, execute_create, execute_pull, \ + execute_push, execute_setup, execute_copy, execute_reinsert, \ + execute_info + +from fmscmds import execute_fmsread, execute_fmsnotify, get_uri_from_hash, \ + execute_setupfms + +from sitecmds import execute_putsite, execute_genkey +from wikicmds import execute_wiki, execute_wiki_apply +from arccmds import execute_arc_create, execute_arc_pull, execute_arc_push, \ + execute_arc_reinsert + +from config import read_freesite_cfg +from validate import is_hex_string, is_fms_id + +def set_target_version(ui_, repo, opts, params, msg_fmt): + """ INTERNAL: Update TARGET_VERSION in params. """ + + revs = opts.get('rev') or None + if not revs is None: + for rev in revs: + repo.changectx(rev) # Fail if we don't have the rev. + + params['TO_VERSIONS'] = tuple(revs) + ui_.status(msg_fmt % ' '.join([ver[:12] for ver in revs])) + else: + # REDFLAG: get rid of default versions arguments? + params['TO_VERSIONS'] = tuple([hexlify(head) for head in repo.heads()]) + #print "set_target_version -- using all head" + #print params['TO_VERSIONS'] + +def infocalypse_create(ui_, repo, **opts): + """ Create a new Infocalypse repository in Freenet. """ + params, stored_cfg = get_config_info(ui_, opts) + + insert_uri = opts['uri'] + if insert_uri == '': + # REDFLAG: fix parameter definition so that it is required? + ui_.warn("Please set the insert URI with --uri.\n") + return + + set_target_version(ui_, repo, opts, params, + "Only inserting to version(s): %s\n") + params['INSERT_URI'] = insert_uri + execute_create(ui_, repo, params, stored_cfg) + +def infocalypse_copy(ui_, repo, **opts): + """ Copy an Infocalypse repository to a new URI. """ + params, stored_cfg = get_config_info(ui_, opts) + + insert_uri = opts['inserturi'] + if insert_uri == '': + # REDFLAG: fix parameter definition so that it is required? + ui_.warn("Please set the insert URI with --inserturi.\n") + return + + request_uri = opts['requesturi'] + if request_uri == '': + request_uri = stored_cfg.get_request_uri(repo.root) + if not request_uri: + ui_.warn("There is no stored request URI for this repo.\n" + "Please set one with the --requesturi option.\n") + return + + params['INSERT_URI'] = insert_uri + params['REQUEST_URI'] = request_uri + execute_copy(ui_, repo, params, stored_cfg) + +def infocalypse_reinsert(ui_, repo, **opts): + """ Reinsert the current version of an Infocalypse repository. """ + params, stored_cfg = get_config_info(ui_, opts) + + request_uri = opts['uri'] + if request_uri == '': + request_uri = stored_cfg.get_request_uri(repo.root) + if not request_uri: + ui_.warn("There is no stored request URI for this repo.\n" + "Do a fn-pull from a repository USK and try again.\n") + return + + level = opts['level'] + if level < 1 or level > 5: + ui_.warn("level must be 1,2,3,4 or 5.\n") + return + + insert_uri = stored_cfg.get_dir_insert_uri(repo.root) + if not insert_uri: + if level == 1 or level == 4: + ui_.warn(("You can't re-insert at level %i without the " + + "insert URI.\n") % level) + return + + ui_.status("No insert URI. Will skip re-insert " + +"of top key.\n") + insert_uri = None + + params['INSERT_URI'] = insert_uri + params['REQUEST_URI'] = request_uri + params['REINSERT_LEVEL'] = level + execute_reinsert(ui_, repo, params, stored_cfg) + +def infocalypse_pull(ui_, repo, **opts): + """ Pull from an Infocalypse repository in Freenet. + """ + params, stored_cfg = get_config_info(ui_, opts) + + if opts['hash']: + # Use FMS to lookup the uri from the repo hash. + if opts['uri'] != '': + ui_.warn("Ignoring --uri because --hash is set!\n") + if len(opts['hash']) != 1: + raise util.Abort("Only one --hash value is allowed.") + params['FMSREAD_HASH'] = opts['hash'][0] + params['FMSREAD_ONLYTRUSTED'] = bool(opts['onlytrusted']) + request_uri = get_uri_from_hash(ui_, repo, params, stored_cfg) + else: + request_uri = opts['uri'] + + if request_uri == '': + request_uri = stored_cfg.get_request_uri(repo.root) + if not request_uri: + ui_.warn("There is no stored request URI for this repo.\n" + "Please set one with the --uri option.\n") + return + + params['REQUEST_URI'] = request_uri + # Hmmmm... can't really implement rev. + execute_pull(ui_, repo, params, stored_cfg) + +def infocalypse_push(ui_, repo, **opts): + """ Push to an Infocalypse repository in Freenet. """ + params, stored_cfg = get_config_info(ui_, opts) + insert_uri = opts['uri'] + if insert_uri == '': + insert_uri = stored_cfg.get_dir_insert_uri(repo.root) + if not insert_uri: + ui_.warn("There is no stored insert URI for this repo.\n" + "Please set one with the --uri option.\n") + return + + set_target_version(ui_, repo, opts, params, + "Only pushing to version(s): %s\n") + params['INSERT_URI'] = insert_uri + #if opts['requesturi'] != '': + # # DOESN'T search the insert uri index. + # ui_.status(("Copying from:\n%s\nTo:\n%s\n\nThis is an " + # + "advanced feature. " + # + "I hope you know what you're doing.\n") % + # (opts['requesturi'], insert_uri)) + # params['REQUEST_URI'] = opts['requesturi'] + + execute_push(ui_, repo, params, stored_cfg) + +def infocalypse_info(ui_, repo, **opts): + """ Display information about an Infocalypse repository. + """ + # FCP not required. Hmmm... Hack + opts['fcphost'] = '' + opts['fcpport'] = 0 + params, stored_cfg = get_config_info(ui_, opts) + request_uri = opts['uri'] + if request_uri == '': + request_uri = stored_cfg.get_request_uri(repo.root) + if not request_uri: + ui_.warn("There is no stored request URI for this repo.\n" + "Please set one with the --uri option.\n") + return + + params['REQUEST_URI'] = request_uri + execute_info(ui_, repo, params, stored_cfg) + +def parse_trust_args(params, opts): + """ INTERNAL: Helper function to parse --hash and --fmsid. """ + if opts.get('hash', []) == []: + raise util.Abort("Use --hash to set the USK hash.") + if len(opts['hash']) != 1: + raise util.Abort("Only one --hash value is allowed.") + if not is_hex_string(opts['hash'][0]): + raise util.Abort("[%s] doesn't look like a USK hash." % + opts['hash'][0]) + + if opts.get('fmsid', []) == []: + raise util.Abort("Use --fmsid to set the FMS id.") + if len(opts['fmsid']) != 1: + raise util.Abort("Only one --fmsid value is allowed.") + if not is_fms_id(opts['fmsid'][0]): + raise util.Abort("[%s] doesn't look like an FMS id." + % opts['fmsid'][0]) + + params['FMSREAD_HASH'] = opts['hash'][0] + params['FMSREAD_FMSID'] = opts['fmsid'][0] + +def parse_fmsread_subcmd(params, opts): + """ INTERNAL: Parse subcommand for fmsread.""" + if opts['listall']: + params['FMSREAD'] = 'listall' + elif opts['list']: + params['FMSREAD'] = 'list' + elif opts['showtrust']: + params['FMSREAD'] = 'showtrust' + elif opts['trust']: + params['FMSREAD'] = 'trust' + parse_trust_args(params, opts) + elif opts['untrust']: + params['FMSREAD'] = 'untrust' + parse_trust_args(params, opts) + else: + params['FMSREAD'] = 'update' + +def infocalypse_fmsread(ui_, repo, **opts): + """ Read repository update information from fms. + """ + # FCP not required. Hmmm... Hack + opts['fcphost'] = '' + opts['fcpport'] = 0 + params, stored_cfg = get_config_info(ui_, opts) + request_uri = opts['uri'] + if request_uri == '': + request_uri = stored_cfg.get_request_uri(repo.root) + if not request_uri: + ui_.status("There is no stored request URI for this repo.\n") + request_uri = None + parse_fmsread_subcmd(params, opts) + params['DRYRUN'] = opts['dryrun'] + params['REQUEST_URI'] = request_uri + execute_fmsread(ui_, params, stored_cfg) + +def infocalypse_fmsnotify(ui_, repo, **opts): + """ Post a msg with the current repository USK index to fms. + """ + params, stored_cfg = get_config_info(ui_, opts) + insert_uri = stored_cfg.get_dir_insert_uri(repo.root) + if not insert_uri and not (opts['submitbundle'] or + opts['submitwiki']): + ui_.warn("You can't notify because there's no stored " + + "insert URI for this repo.\n" + + "Run from the directory you inserted from.\n") + return + + params['ANNOUNCE'] = opts['announce'] + params['SUBMIT_BUNDLE'] = opts['submitbundle'] + params['SUBMIT_WIKI'] = opts['submitwiki'] + if params['SUBMIT_WIKI'] or params['SUBMIT_BUNDLE']: + request_uri = stored_cfg.get_request_uri(repo.root) + if not request_uri: + ui_.warn("There is no stored request URI for this repo.\n") + raise util.Abort("No request URI.") + params['REQUEST_URI'] = request_uri + + params['DRYRUN'] = opts['dryrun'] + params['INSERT_URI'] = insert_uri + execute_fmsnotify(ui_, repo, params, stored_cfg) + +MSG_BAD_INDEX = 'You must set --index to a value >= 0.' +def infocalypse_putsite(ui_, repo, **opts): + """ Insert an update to a freesite. + """ + + if opts['createconfig']: + if opts['wiki']: + raise util.Abort("Use fn-wiki --createconfig.") + params = {'SITE_CREATE_CONFIG':True} + execute_putsite(ui_, repo, params) + return + + params, stored_cfg = get_config_info(ui_, opts) + if opts['key'] != '': # order important + params['SITE_KEY'] = opts['key'] + if not (params['SITE_KEY'].startswith('SSK') or + params['SITE_KEY'] == 'CHK@'): + raise util.Abort("--key must be a valid SSK " + + "insert key or CHK@.") + + params['ISWIKI'] = opts['wiki'] + read_freesite_cfg(ui_, repo, params, stored_cfg) + + try: + # --index not required for CHK@ + if not params['SITE_KEY'].startswith('CHK'): + params['SITE_INDEX'] = int(opts['index']) + if params['SITE_INDEX'] < 0: + raise ValueError() + else: + params['SITE_INDEX'] = -1 + except ValueError: + raise util.Abort(MSG_BAD_INDEX) + except TypeError: + raise util.Abort(MSG_BAD_INDEX) + + params['DRYRUN'] = opts['dryrun'] + + if not params.get('SITE_KEY', None): + insert_uri = stored_cfg.get_dir_insert_uri(repo.root) + if not insert_uri: + ui_.warn("You don't have the insert URI for this repo.\n" + + "Supply a private key with --key or fn-push " + + "the repo.\n") + return # REDFLAG: hmmm... abort? + params['SITE_KEY'] = 'SSK' + insert_uri.split('/')[0][3:] + + execute_putsite(ui_, repo, params) + +def infocalypse_wiki(ui_, repo, **opts): + """ View and edit the current repository as a wiki. """ + if os.getcwd() != repo.root: + raise util.Abort("You must be in the repository root directory.") + + subcmds = ('run', 'createconfig', 'apply') + required = sum([bool(opts[cmd]) for cmd in subcmds]) + if required == 0: + raise util.Abort("You must specify either --run, " + + "--createconfig, --apply") + if required > 1: + raise util.Abort("Use either --run, --createconfig, or --apply") + + if opts['apply'] != '': + params, stored_cfg = get_config_info(ui_, opts) + params['REQUEST_URI'] = opts['apply'] + execute_wiki_apply(ui_, repo, params, stored_cfg) + return + + if opts['fcphost'] != '' or opts['fcpport'] != 0: + raise util.Abort("--fcphost, --fcpport only for --apply") + + # hmmmm.... useless copy? + params = {'WIKI' : [cmd for cmd in subcmds if opts[cmd]][0], + 'HTTP_PORT': opts['http_port'], + 'HTTP_BIND': opts['http_bind']} + execute_wiki(ui_, repo, params) + +def infocalypse_genkey(ui_, **opts): + """ Print a new SSK key pair. """ + params, dummy = get_config_info(ui_, opts) + execute_genkey(ui_, params) + +def infocalypse_setup(ui_, **opts): + """ Setup the extension for use for the first time. """ + + execute_setup(ui_, + opts['fcphost'], + opts['fcpport'], + opts['tmpdir']) + + if not opts['nofms']: + execute_setupfms(ui_, opts) + else: + ui_.status("Skipped FMS configuration because --nofms was set.\n") + +def infocalypse_setupfms(ui_, **opts): + """ Setup or modify the fms configuration. """ + # REQUIRES config file. + execute_setupfms(ui_, opts) + +#----------------------------------------------------------" +def do_archive_create(ui_, opts, params, stored_cfg): + """ fn-archive --create.""" + insert_uri = opts['uri'] + if insert_uri == '': + raise util.Abort("Please set the insert URI with --uri.") + + params['INSERT_URI'] = insert_uri + params['FROM_DIR'] = os.getcwd() + execute_arc_create(ui_, params, stored_cfg) + +def do_archive_push(ui_, opts, params, stored_cfg): + """ fn-archive --push.""" + insert_uri = opts['uri'] + if insert_uri == '': + insert_uri = ( + stored_cfg.get_dir_insert_uri(params['ARCHIVE_CACHE_DIR'])) + if not insert_uri: + ui_.warn("There is no stored insert URI for this archive.\n" + "Please set one with the --uri option.\n") + raise util.Abort("No Insert URI.") + + params['INSERT_URI'] = insert_uri + params['FROM_DIR'] = os.getcwd() + + execute_arc_push(ui_, params, stored_cfg) + +def do_archive_pull(ui_, opts, params, stored_cfg): + """ fn-archive --pull.""" + request_uri = opts['uri'] + + if request_uri == '': + request_uri = ( + stored_cfg.get_request_uri(params['ARCHIVE_CACHE_DIR'])) + if not request_uri: + ui_.warn("There is no stored request URI for this archive.\n" + "Please set one with the --uri option.\n") + raise util.Abort("No request URI.") + + params['REQUEST_URI'] = request_uri + params['TO_DIR'] = os.getcwd() + execute_arc_pull(ui_, params, stored_cfg) + +ILLEGAL_FOR_REINSERT = ('uri', 'aggressive', 'nosearch') +def do_archive_reinsert(ui_, opts, params, stored_cfg): + """ fn-archive --reinsert.""" + illegal = [value for value in ILLEGAL_FOR_REINSERT + if value in opts and opts[value]] + if illegal: + raise util.Abort("--uri, --aggressive, --nosearch illegal " + + "for reinsert.") + request_uri = stored_cfg.get_request_uri(params['ARCHIVE_CACHE_DIR']) + if request_uri is None: + ui_.warn("There is no stored request URI for this archive.\n" + + "Run fn-archive --pull first!.\n") + raise util.Abort(" No request URI, can't re-insert") + + insert_uri = stored_cfg.get_dir_insert_uri(params['ARCHIVE_CACHE_DIR']) + params['REQUEST_URI'] = request_uri + params['INSERT_URI'] = insert_uri + params['FROM_DIR'] = os.getcwd() # hmmm not used. + params['REINSERT_LEVEL'] = 3 + execute_arc_reinsert(ui_, params, stored_cfg) + +ARCHIVE_SUBCMDS = {'create':do_archive_create, + 'push':do_archive_push, + 'pull':do_archive_pull, + 'reinsert':do_archive_reinsert} +ARCHIVE_CACHE_DIR = '.ARCHIVE_CACHE' +def infocalypse_archive(ui_, **opts): + """ Commands to maintain a non-hg incremental archive.""" + subcmd = [value for value in ARCHIVE_SUBCMDS if opts[value]] + if len(subcmd) > 1: + raise util.Abort("--create, --pull, --push are mutally exclusive. " + + "Only specify one.") + if len(subcmd) > 0: + subcmd = subcmd[0] + else: + subcmd = "pull" + + params, stored_cfg = get_config_info(ui_, opts) + params['ARCHIVE_CACHE_DIR'] = os.path.join(os.getcwd(), ARCHIVE_CACHE_DIR) + + if not subcmd in ARCHIVE_SUBCMDS: + raise util.Abort("Unhandled subcommand: " + subcmd) + + # 2 qt? + ARCHIVE_SUBCMDS[subcmd](ui_, opts, params, stored_cfg) + diff --git a/infocalypse/freenetrepo.py b/infocalypse/freenetrepo.py new file mode 100644 --- /dev/null +++ b/infocalypse/freenetrepo.py @@ -0,0 +1,51 @@ +# infocalypse +# +# Copyright 2012 Arne Babenhauserheide <arne_bab at web dot de>, +# though most of this file is taken from hg-git from Scott Chacon +# <schacon at gmail dot com> also some code (and help) borrowed +# from durin42 +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +from mercurial import repo, util +try: + from mercurial.error import RepoError +except ImportError: + from mercurial.repo import RepoError + +class freenetrepo(repo.repository): + capabilities = ['lookup'] + + def __init__(self, ui, path, create): + if create: # pragma: no cover + raise util.Abort('Cannot create a freenet repository, yet.') + self.ui = ui + self.path = path + + def lookup(self, key): + if isinstance(key, str): + return key + + def local(self): + # a freenet repo is never local + raise RepoError + + def heads(self): + return [] + + def listkeys(self, namespace): + return {} + + def pushkey(self, namespace, key, old, new): + return False + + # used by incoming in hg <= 1.6 + def branches(self, nodes): + return [] + +instance = freenetrepo + +def islocal(path): + u = util.url(path) + return not u.scheme or u.scheme == 'file' diff --git a/infocalypse/graph.py b/infocalypse/graph.py --- a/infocalypse/graph.py +++ b/infocalypse/graph.py @@ -52,7 +52,7 @@ FREENET_BLOCK_LEN = 32 * 1024 # Hmmm... arbitrary. MAX_REDUNDANT_LENGTH = 128 * 1024 -# HACK: Approximate multi-level splitfile boundry +# HACK: Approximate multi-level splitfile boundary MAX_METADATA_HACK_LEN = 7 * 1024 * 1024 ############################################################ diff --git a/infocalypse/graphutil.py b/infocalypse/graphutil.py --- a/infocalypse/graphutil.py +++ b/infocalypse/graphutil.py @@ -187,8 +187,8 @@ def should_add_head(repo, version_table, return True # TRICKY: -# You need the repository changset DAG in order to determine -# the base revs. because new changes might have branched from +# You need the repository changeset DAG in order to determine +# the base revs, because new changes might have branched from # a change in the middle of a previous index which doesn't # appear explictly in the graph. # @@ -450,7 +450,7 @@ def get_huge_top_key_edges(graph, extant alternates) that are too big to salt. If extant is True, return existing edges. - If extent is False, return edges that could be added. """ + If extant is False, return edges that could be added. """ ret = [] edges = graph.get_top_key_edges() edges += find_redundant_edges(graph, edges, False)[0] diff --git a/infocalypse/infcmds.py b/infocalypse/infcmds.py --- a/infocalypse/infcmds.py +++ b/infocalypse/infcmds.py @@ -57,16 +57,16 @@ from knownrepos import DEFAULT_TRUST, DE DEFAULT_PARAMS = { # FCP params - 'MaxRetries':3, + 'MaxRetries':6, 'PriorityClass':1, 'DontCompress':True, # hg bundles are already compressed. 'Verbosity':1023, # MUST set this to get progress messages. #'GetCHKOnly':True, # REDFLAG: For testing only. Not sure this still works. # Non-FCP stuff - 'N_CONCURRENT':4, # Maximum number of concurrent FCP requests. - 'CANCEL_TIME_SECS': 20 * 60, # Bound request time. - 'POLL_SECS':0.25, # Time to sleep in the polling loop. + 'N_CONCURRENT':8, # Maximum number of concurrent FCP requests. + 'CANCEL_TIME_SECS': 120 * 60, # Bound request time. + 'POLL_SECS':1.00, # Time to sleep in the polling loop. # Testing HACKs #'TEST_DISABLE_GRAPH': True, # Disable reading the graph. @@ -495,12 +495,8 @@ def is_redundant(uri): ############################################################ # User feedback? success, failure? def execute_create(ui_, repo, params, stored_cfg): - """ - Run the create command. - Return the URIs the repo was inserted to, or None in the case of an error. - """ + """ Run the create command. """ update_sm = None - inserted_to = None try: update_sm = setup(ui_, repo, params, stored_cfg) # REDFLAG: Do better. @@ -520,9 +516,9 @@ def execute_create(ui_, repo, params, st run_until_quiescent(update_sm, params['POLL_SECS']) if update_sm.get_state(QUIESCENT).arrived_from(((FINISHING,))): - inserted_to = update_sm.get_state(INSERTING_URI).get_request_uris() ui_.status("Inserted to:\n%s\n" % - '\n'.join(inserted_to)) + '\n'.join(update_sm.get_state(INSERTING_URI). + get_request_uris())) else: ui_.status("Create failed.\n") @@ -530,8 +526,6 @@ def execute_create(ui_, repo, params, st finally: cleanup(update_sm) - return inserted_to - # REDFLAG: LATER: make this work without a repo? def execute_copy(ui_, repo, params, stored_cfg): """ Run the copy command. """ @@ -612,14 +606,10 @@ def execute_reinsert(ui_, repo, params, cleanup(update_sm) def execute_push(ui_, repo, params, stored_cfg): - """ - Run the push command. - Return the URIs the repo was inserted to if it changed, or None otherwise. - """ + """ Run the push command. """ assert params.get('REQUEST_URI', None) is None update_sm = None - inserted_to = None try: update_sm = setup(ui_, repo, params, stored_cfg) request_uri, is_keypair = do_key_setup(ui_, update_sm, params, @@ -636,9 +626,9 @@ def execute_push(ui_, repo, params, stor run_until_quiescent(update_sm, params['POLL_SECS']) if update_sm.get_state(QUIESCENT).arrived_from(((FINISHING,))): - inserted_to = update_sm.get_state(INSERTING_URI).get_request_uris() ui_.status("Inserted to:\n%s\n" % - '\n'.join(inserted_to)) + '\n'.join(update_sm.get_state(INSERTING_URI). + get_request_uris())) else: extra = '' if update_sm.ctx.get('UP_TO_DATE', False): @@ -649,8 +639,6 @@ def execute_push(ui_, repo, params, stor finally: cleanup(update_sm) - return inserted_to - def execute_pull(ui_, repo, params, stored_cfg): """ Run the pull command. """ update_sm = None diff --git a/infocalypse/sitecmds.py b/infocalypse/sitecmds.py --- a/infocalypse/sitecmds.py +++ b/infocalypse/sitecmds.py @@ -176,13 +176,19 @@ And this is what needs to go into fn-cre %s """ +def genkeypair(fcphost, fcpport): + """ Generate a keypair + + :returns: inserturi, requesturi (strings) + """ + client = FCPClient.connect(fcphost, fcpport) + client.message_callback = lambda x, y : None # silence. + resp = client.generate_ssk() + return resp[1]['InsertURI'], resp[1]['RequestURI'] + def execute_genkey(ui_, params): """ Run the genkey command. """ - client = FCPClient.connect(params['FCP_HOST'], - params['FCP_PORT']) - - client.message_callback = lambda x, y : None # silence. - resp = client.generate_ssk() - ui_.status(MSG_FMT % (resp[1]['InsertURI'], resp[1]['RequestURI'], - resp[1]['InsertURI'].split('/')[0] +'/', - "U" + resp[1]['InsertURI'].split('/')[0][1:] +'/NAME/0')) + insert, request = genkeypair(params['FCP_HOST'], params['FCP_PORT']) + ui_.status(MSG_FMT % (insert, request, + insert.split('/')[0] +'/', + "U" + insert.split('/')[0][1:] +'/NAME.R1/0'))