def generate_info_config(self, from_id=None, prefix=None, project=None): """Generate a metomi.rose.config.ConfigNode for a rose-suite.info. This is suitable for passing into the create method of this class. If from_id is defined, copy items from it. Return the metomi.rose.config.ConfigNode instance. """ from_project = None from_title = None if from_id is not None: from_info_url = "%s/%s/rose-suite.info@%s" % ( from_id.to_origin(), from_id.branch, from_id.revision, ) out_data = self.popen("svn", "cat", from_info_url)[0] from_config = metomi.rose.config.load(StringIO(out_data)) res_loc = ResourceLocator.default() older_config = None info_config = metomi.rose.config.ConfigNode() # Determine project if given as a command-line option on create if from_id is None and project is not None: info_config.set(["project"], project) # Set the compulsory fields and use the project and metadata if # available. meta_config = load_meta_config( info_config, config_type=metomi.rose.INFO_CONFIG_NAME) if from_id is None and project is not None: for node_keys, node in meta_config.walk(no_ignore=True): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value sect = sect.translate(None, "=") if key == "compulsory" and value == "true": info_config.set([sect], "") info_config.set(["project"], project) else: if from_project is None: info_config.set(["project"], "") if from_title is None: info_config.set(["title"], "") # Determine prefix if prefix is None: if from_id is None: prefix = SuiteId.get_prefix_default() else: prefix = from_id.prefix # Determine owner: # 1. From user configuration [rosie-id]prefix-username # 2. From username of a matching group in [groups] in # ~/.subversion/servers # 3. Current user ID owner = res_loc.get_conf().get_value( ["rosie-id", "prefix-username." + prefix]) if not owner and self.subversion_servers_conf: servers_conf = metomi.rose.config.load( self.subversion_servers_conf) groups_node = servers_conf.get(["groups"]) if groups_node is not None: prefix_loc = SuiteId.get_prefix_location(prefix) prefix_host = urlparse(prefix_loc).hostname for key, node in groups_node.value.items(): if fnmatch(prefix_host, node.value): owner = servers_conf.get_value([key, "username"]) break if not owner: owner = pwd.getpwuid(os.getuid())[0] info_config.set(["owner"], owner) # Copy description try: from_id.to_string_with_version() info_config.set( ["description"], "Copy of %s" % (from_id.to_string_with_version()), ) except AttributeError: pass # Copy fields provided by the user try: from_config.walk(no_ignore=False) for node_keys, node in from_config.walk(no_ignore=False): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value if key in [ "description", "owner", "access-list" ] or (key == "project" and from_project is not None): pass else: info_config.set([key], value) except UnboundLocalError: pass # Determine access list access_list_str = res_loc.get_conf().get_value( ["rosie-vc", "access-list-default"]) if access_list_str: info_config.set(["access-list"], access_list_str) if from_id is None and project is not None: for node_keys, node in meta_config.walk(no_ignore=True): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value sect = sect.translate(None, "=") if key == "value-hints" or key == "values": reminder = ("please remove all commented hints/lines " + "in the main/top section before saving.") info_config.set( [sect], metomi.rose.variable.array_split(value)[0], comments=[value, reminder], ) if older_config is not None: for node_keys, node in older_config.walk(no_ignore=True): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value info_config.set([key], value) return info_config
def create(): """CLI function: create and copy.""" opt_parser = RoseOptionParser( usage=('rosie create [OPTIONS]' '\n rosie copy [OPTIONS] ID-OF-EXISTING-SUITE'), description=''' rosie create: Create a new suite rosie copy : Create a new suite and copy content from an existing one. Assign a new `ID` and create the directory structure in the central repository for a new suite. The location of the repository for the new suite is determined in order of preference: 1. `--prefix=PREFIX` option 2. prefix of the `ID-OF-EXISTING-SUITE` 3. `[rosie-id]prefix-default` option in the site/user configuration. If `ID-OF-EXISTING-SUITE` is specified, copy items from the existing suite `ID-OF-EXISTING-SUITE` when the suite is created. It is worth noting that revision history of the copied items can only be preserved if `ID-OF-EXISTING-SUITE` is in the same repository of the new suite The syntax of the ID-OF-EXISTING-SUITE is PREFIX-xxNNN[/BRANCH][@REV] (e.g. my-su173, my-su173/trunk, my-su173/trunk@HEAD). If REV is not specified, the last changed revision of the branch is used. If BRANCH is not specified, "trunk" is used. NOTE: ID-OF-EXISTING-SUITE is _not_ a filepath. ''', ) opt_parser.add_my_options( "checkout_mode", "info_file", "meta_suite_mode", "non_interactive", "prefix", "project", ) opts, args = opt_parser.parse_args() verbosity = opts.verbosity - opts.quietness client = RosieVCClient(event_handler=Reporter(verbosity)) SuiteId.svn.event_handler = client.event_handler from_id = None if args: from_id = SuiteId(id_text=args[0]) if from_id.branch is None: from_id.branch = from_id.BRANCH_TRUNK if from_id.revision is None: from_id.revision = from_id.REV_HEAD from_id = SuiteId(id_text=from_id.to_string_with_version()) interactive_mode = not opts.non_interactive if opts.info_file is None: info_config = client.generate_info_config(from_id, opts.prefix, opts.project) if from_id is not None: meta_config = load_meta_config( info_config, directory=None, config_type=metomi.rose.INFO_CONFIG_NAME, error_handler=None, ignore_meta_error=False, ) for node_keys, node in meta_config.walk(no_ignore=True): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value sect = sect.replace("=", "") if key == "copy-mode" and value == "clear": info_config.set([sect], "") if key == "copy-mode" and value == "never": info_config.unset([sect]) info_config = _edit_info_config(opts, client, info_config) else: file_ = opts.info_file if opts.info_file == "-": file_ = sys.stdin info_config = metomi.rose.config.load(file_) info_config = _validate_info_config(opts, client, info_config) if interactive_mode: prefix = opts.prefix if from_id: if not prefix: prefix = from_id.prefix question = PROMPT_COPY % (from_id.to_string_with_version(), prefix) else: if not prefix: prefix = SuiteId.get_prefix_default() question = PROMPT_CREATE % prefix try: response = input(question) except EOFError: sys.exit(1) if response != YES: sys.exit(1) try: id_ = client.create(info_config, from_id, opts.prefix, opts.meta_suite_mode) except (RosePopenError, SuiteIdOverflowError) as exc: client.event_handler(exc) sys.exit(1) if opts.checkout_mode: try: client.checkout(id_) except (FileExistError, RosePopenError) as exc: client.event_handler(exc) sys.exit(1)
def create(argv): """CLI function: create and copy.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("checkout_mode", "info_file", "meta_suite_mode", "non_interactive", "prefix", "project") opts, args = opt_parser.parse_args(argv) verbosity = opts.verbosity - opts.quietness client = RosieVCClient(event_handler=Reporter(verbosity)) SuiteId.svn.event_handler = client.event_handler from_id = None if args: from_id = SuiteId(id_text=args[0]) if from_id.branch is None: from_id.branch = from_id.BRANCH_TRUNK if from_id.revision is None: from_id.revision = from_id.REV_HEAD from_id = SuiteId(id_text=from_id.to_string_with_version()) interactive_mode = not opts.non_interactive if opts.info_file is None: info_config = client.generate_info_config(from_id, opts.prefix, opts.project) if from_id is not None: meta_config = load_meta_config( info_config, directory=None, config_type=metomi.rose.INFO_CONFIG_NAME, error_handler=None, ignore_meta_error=False) for node_keys, node in meta_config.walk(no_ignore=True): if isinstance(node.value, dict): continue sect, key = node_keys value = node.value sect = sect.replace("=", "") if key == "copy-mode" and value == "clear": info_config.set([sect], "") if key == "copy-mode" and value == "never": info_config.unset([sect]) info_config = _edit_info_config(opts, client, info_config) else: file_ = opts.info_file if opts.info_file == "-": file_ = sys.stdin info_config = metomi.rose.config.load(file_) info_config = _validate_info_config(opts, client, info_config) if interactive_mode: prefix = opts.prefix if from_id: if not prefix: prefix = from_id.prefix question = PROMPT_COPY % (from_id.to_string_with_version(), prefix) else: if not prefix: prefix = SuiteId.get_prefix_default() question = PROMPT_CREATE % prefix try: response = input(question) except EOFError: sys.exit(1) if response != YES: sys.exit(1) try: id_ = client.create(info_config, from_id, opts.prefix, opts.meta_suite_mode) except (RosePopenError, SuiteIdOverflowError) as exc: client.event_handler(exc) sys.exit(1) if opts.checkout_mode: try: client.checkout(id_) except (FileExistError, RosePopenError) as exc: client.event_handler(exc) sys.exit(1)