def checkout(self, id_): """Create a local copy of a suite with the given ID. Return the SuiteId of the suite on success. """ if isinstance(id_, str): id_ = SuiteId(id_text=id_) if id_.revision is None: id_.revision = id_.REV_HEAD if id_.branch is None: id_.branch = id_.BRANCH_TRUNK local_copy = id_.to_local_copy() if os.path.exists(local_copy): id0 = SuiteId(location=local_copy) if id_.to_string_with_version() == id0.to_string_with_version(): self.event_handler(LocalCopyCreateSkipEvent(id_)) return id_ elif self.force_mode: self.fs_util.delete(local_copy) else: raise FileExistError(local_copy) local_copy_dir = os.path.dirname(local_copy) if not os.path.isdir(local_copy_dir): self.fs_util.makedirs(os.path.dirname(local_copy)) origin = "%s/%s@%s" % (id_.to_origin(), id_.branch, id_.revision) self.popen("svn", "checkout", "-q", origin, local_copy) self.event_handler(LocalCopyCreateEvent(id_)) return id_
def delete(self, id, local_only=False): """Delete the local copy and the origin of a suite. It takes the suite ID as an argument. Return the SuiteId of the suite on success. """ if isinstance(id, str): id = SuiteId(id_text=id) local_copy = id.to_local_copy() if os.path.exists(local_copy): if not self.force_mode: status = self.popen("svn", "status", local_copy)[0] if status: raise LocalCopyStatusError(id, status) if os.getcwd() == local_copy: # TODO: Event? os.chdir(os.path.expanduser("~")) shutil.rmtree(local_copy) self.event_handler(FileDeleteEvent(local_copy)) if not local_only: self.popen("svn", "delete", "-q", "-m", "%s: deleted." % str(id), id.to_origin()) self.event_handler(SuiteDeleteEvent(id)) return id
def delete(self, id_, local_only=False): """Delete the local copy and the origin of a suite. It takes the suite ID as an argument. Return the SuiteId of the suite on success. """ if isinstance(id_, str): id_ = SuiteId(id_text=id_) local_copy = id_.to_local_copy() if os.path.exists(local_copy): if not self.force_mode: status = self.popen("svn", "status", local_copy)[0] if status: raise LocalCopyStatusError(id_, status) if os.getcwd() == local_copy: self.fs_util.chdir(os.path.expanduser("~")) self.fs_util.delete(local_copy) if not local_only: self.popen( "svn", "delete", "-q", "-m", self.COMMIT_MESSAGE_DELETE % str(id_), id_.to_origin()) self.event_handler(SuiteDeleteEvent(id_)) return id_
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") opts, args = opt_parser.parse_args(argv) verbosity = opts.verbosity - opts.quietness report = Reporter(verbosity) client = RosieVCClient(event_handler=report) SuiteId.svn.event_handler = client.event_handler # FIXME: ugly? 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()) if opts.info_file is None: try: info_config = client.generate_info_config(from_id, opts.prefix) except (RosePopenError) as e: report(e) sys.exit(1) info_file = tempfile.NamedTemporaryFile(delete=False) try: rose.config.dump(info_config, info_file) info_file.close() command_list = client.popen.get_cmd("editor", info_file.name) client.popen(*command_list, stdout=sys.stdout) info_config = rose.config.load(info_file.name) finally: os.unlink(info_file.name) elif opts.info_file == "-": info_config = rose.config.load(sys.stdin) else: info_config = rose.config.load(opts.info_file) if not opts.non_interactive: try: response = raw_input("Create? y/n (default n) ") except EOFError: sys.exit(1) if response != 'y': sys.exit(1) try: id = client.create(info_config, from_id, opts.prefix, opts.meta_suite_mode) except (RosePopenError, SuiteInfoFieldError, SuiteIdOverflowError) as e: report(e) sys.exit(1) if opts.checkout_mode: try: client.checkout(id) except (FileExistError, RosePopenError) as e: report(e) sys.exit(1)
def create(self, info_config, from_id=None, prefix=None, meta_suite_mode=False): """Create a suite. info_config -- A rose.config.ConfigNode object, which will be used as the content of the "rose-suite.info" file of the new suite. from_id -- If defined, copy items from it. prefix -- If defined, create the suite in the suite repository named by the prefix instead of the default one. meta_suite_mode -- If True, create the special metadata suite. Ignored if from_id is not None. Return the SuiteId of the suite on success. """ for key in ["owner", "project", "title"]: if not info_config.get([key], no_ignore=True): raise SuiteInfoFieldError(key) if from_id is not None: return self._copy(info_config, from_id) new_id = None while new_id is None: if meta_suite_mode: if prefix is None: new_id = SuiteId(id_text="ROSIE") else: idx = SuiteId.FORMAT_IDX % (prefix, "ROSIE") new_id = SuiteId(id_text=idx) else: new_id = SuiteId.get_next(prefix) new_origin = new_id.to_origin() + "/" + new_id.BRANCH_TRUNK dir = self._get_work_dir() rose.config.dump(info_config, os.path.join(dir, "rose-suite.info")) open(os.path.join(dir, "rose-suite.conf"), "w").close() try: self.popen("svn", "import", "-q", "-m", "%s: new suite." % str(new_id), dir, new_origin) self.event_handler(SuiteCreateEvent(new_id)) except RosePopenError as e: try: self.popen("svn", "info", new_origin) if not meta_suite_mode: new_id = None except RosePopenError: raise e finally: self._delete_work_dir() return new_id
def checkout(self, id): """Create a local copy of a suite with the given ID. Return the SuiteId of the suite on success. """ if isinstance(id, str): id = SuiteId(id_text=id) if id.revision is None: id.revision = id.REV_HEAD if id.branch is None: id.branch = id.BRANCH_TRUNK local_copy = id.to_local_copy() if os.path.exists(local_copy): id0 = SuiteId(location=local_copy) if id.to_string_with_version() == id0.to_string_with_version(): self.event_handler(LocalCopyCreateSkipEvent(id)) return id elif self.force_mode: if os.path.isfile(local_copy): unlink(local_copy) else: shutil.rmtree(local_copy) self.event_handler(FileDeleteEvent(local_copy)) else: raise FileExistError(local_copy) local_copy_dir = os.path.dirname(local_copy) if not os.path.isdir(local_copy_dir): os.makedirs(os.path.dirname(local_copy)) self.event_handler(FileCreateEvent(local_copy_dir)) origin = id.to_origin() + "/" + id.branch + "@" + id.revision self.popen("svn", "checkout", "-q", origin, local_copy) self.event_handler(LocalCopyCreateEvent(id)) return id
def update(self): """Get info and communicate any change.""" local_suites = SuiteId.get_checked_out_suite_ids() if local_suites == self.local_suites: return self.local_suites = local_suites self.queue.put(local_suites)
def _render(self, all_revs=0, data=None, filters=None, s=None): """Render return data with a template.""" if data: for item in data: suite_id = SuiteId.from_idx_branch_revision( item["idx"], item["branch"], item["revision"]) item["href"] = suite_id.to_web() item["date"] = str(get_timepoint_from_seconds_since_unix_epoch( item["date"])) tmpl = self.props["template_env"].get_template("prefix-index.html") self.write(tmpl.render( title=self.props["title"], host=self.props["host_name"], rose_version=self.props["rose_version"], script="/static", service_root=self.service_root, prefix=self.prefix, prefix_source_url=self.source_url, known_keys=self.dao.get_known_keys(), query_operators=self.dao.get_query_operators(), all_revs=all_revs, filters=filters, s=s, data=data) )
def query_local_copies(self, user=None): """Returns details of the local suites. As if they had been obtained using a search or query. """ suite_ids = [] for suite_id in SuiteId.get_checked_out_suite_ids(user=user): if suite_id.prefix in self.prefixes: suite_ids.append(suite_id) if not suite_ids: return [] # Simple query results = [] queued_suite_ids = list(suite_ids) while queued_suite_ids: # Batch up queries q_list = [] for _ in range(self.MAX_LOCAL_QUERIES): if not queued_suite_ids: break suite_id = queued_suite_ids.pop() q_list.append("or ( idx eq %s" % suite_id.idx) q_list.append("and branch eq %s )" % suite_id.branch) for data, _ in self.query(q_list): results.extend(data) result_idx_branches = [] for result in results: result_idx_branches.append((result[u"idx"], result[u"branch"])) # A branch may have been deleted - query with all_revs=1. # We only want to use all_revs on demand as it's slow. queued_suite_ids = [] for suite_id in suite_ids: if (suite_id.idx, suite_id.branch) not in result_idx_branches: queued_suite_ids.append(suite_id) if not queued_suite_ids: return results while queued_suite_ids: # Batch up queries q_list = [] for _ in range(self.MAX_LOCAL_QUERIES): if not queued_suite_ids: break suite_id = queued_suite_ids.pop() q_list.append("or ( idx eq %s" % suite_id.idx) q_list.append("and branch eq %s )" % suite_id.branch) more_results = [] for data, _ in self.query(q_list, all_revs=1): more_results.extend(data) new_results = {} for result in more_results: idx_branch = (result[u"idx"], result[u"branch"]) if (idx_branch not in new_results or result[u"revision"] > new_results[idx_branch][u"revision"]): new_results.update({idx_branch: result}) for _, result in sorted(new_results.items()): results.append(result) return results
def __init__(self, root=None, prefix=None): if root is None: config = rose.config.default_node() node = config.get(["rosie-ws-client", "ws-root-default"]) root = node.value self.root = root if prefix is None: prefix = SuiteId.get_prefix_default() self.prefix = prefix
def _copy1(self, info_config, from_id): """Copy a suite from the same repository.""" from_id_url = "%s/%s@%s" % (from_id.to_origin(), from_id.branch, from_id.revision) self.popen("svn", "info", from_id_url) # Die if from_id not exists prefix = from_id.prefix temp_local_copy = os.path.join(self._get_work_dir(), "work") new_id = None # N.B. This is probably the simplest logic to maintain, # but not the most efficient for runtime. Does it matter? while new_id is None: if os.path.exists(temp_local_copy): shutil.rmtree(temp_local_copy) self.popen("svn", "checkout", "-q", "--depth", "empty", SuiteId.get_prefix_location(prefix), temp_local_copy) new_id = SuiteId.get_next(prefix) for i in range(len(new_id.sid)): dir_ = os.path.join( temp_local_copy, os.sep.join(new_id.sid[0:i + 1])) self.popen("svn", "update", "-q", "--depth", "empty", dir_) if not os.path.isdir(dir_): os.mkdir(dir_) self.popen("svn", "add", "-q", dir_) dir_ = os.path.join(temp_local_copy, os.sep.join(new_id.sid)) self.popen( "svn", "cp", "-q", from_id_url, os.path.join(dir_, "trunk")) rose.config.dump( info_config, os.path.join(dir_, "trunk", "rose-suite.info")) message = self.COMMIT_MESSAGE_COPY % ( new_id, from_id.to_string_with_version()) try: self.popen( "svn", "commit", "-q", "-m", message, temp_local_copy) self.event_handler(SuiteCreateEvent(new_id)) self.event_handler(SuiteCopyEvent(new_id, from_id)) except RosePopenError as exc: try: self.popen("svn", "info", new_id.to_origin()) new_id = None except RosePopenError: raise exc finally: self._delete_work_dir() return new_id
def _copy1(self, info_config, from_id): """Copy a suite from the same repository.""" from_id_url = "%s/%s@%s" % (from_id.to_origin(), from_id.branch, from_id.revision) self.popen("svn", "info", from_id_url) # Die if from_id not exists prefix = from_id.prefix temp_local_copy = os.path.join(self._get_work_dir(), "work") new_id = None # N.B. This is probably the simplest logic to maintain, # but not the most efficient for runtime. Does it matter? while new_id is None: if os.path.exists(temp_local_copy): shutil.rmtree(temp_local_copy) self.popen("svn", "checkout", "-q", "--depth", "empty", SuiteId.get_prefix_location(prefix), temp_local_copy) new_id = SuiteId.get_next(prefix) for i in range(len(new_id.sid)): dir_ = os.path.join(temp_local_copy, os.sep.join(new_id.sid[0:i + 1])) self.popen("svn", "update", "-q", "--depth", "empty", dir_) if not os.path.isdir(dir_): os.mkdir(dir_) self.popen("svn", "add", "-q", dir_) dir_ = os.path.join(temp_local_copy, os.sep.join(new_id.sid)) self.popen("svn", "cp", "-q", from_id_url, os.path.join(dir_, "trunk")) rose.config.dump(info_config, os.path.join(dir_, "trunk", "rose-suite.info")) message = self.COMMIT_MESSAGE_COPY % ( new_id, from_id.to_string_with_version()) try: self.popen("svn", "commit", "-q", "-m", message, temp_local_copy) self.event_handler(SuiteCreateEvent(new_id)) self.event_handler(SuiteCopyEvent(new_id, from_id)) except RosePopenError as exc: try: self.popen("svn", "info", new_id.to_origin()) new_id = None except RosePopenError: raise exc finally: self._delete_work_dir() return new_id
def __init__(self, prefix=None): if prefix is None: prefix = SuiteId.get_prefix_default() self.prefix = prefix conf = ResourceLocator.default().get_conf() root = conf.get_value(["rosie-id", "prefix-ws." + self.prefix]) if root is None: raise UnknownRootError(self.prefix) if not root.endswith("/"): root += "/" self.root = root
def add_prefix_choices(self): """Add the prefix choices.""" self.prefixes = SuiteId.get_prefix_locations().keys() self.prefixes.sort() self.prefixes.reverse() for prefix in self.prefixes: search = '<menu action="Source">' repl = search + '<menuitem action="_{0}_"/>'.format(prefix) self.ui_config_string = self.ui_config_string.replace( search, repl, 1) self.radio_action_details.append( ("_{0}_".format(prefix), None, prefix))
def add_prefix_choices(self): """Add the prefix choices.""" self.prefixes = self.ws_client.auth_managers.keys() self.prefixes.sort() self.prefixes.reverse() for prefix in self.prefixes: source = '<menu action="Source">' repl = source + '<menuitem action="_{0}_"/>'.format(prefix) self.ui_config_string = self.ui_config_string.replace( source, repl, 1) label_str = prefix + " - " + SuiteId.get_prefix_location(prefix) self.prefixes_action_details.append( ("_{0}_".format(prefix), None, label_str.replace("_", "__")))
def list_local_suites(argv): """CLI command to list all the locally checked out suites""" opt_parser = RoseOptionParser().add_my_options( "no_headers", "prefixes", "print_format", "reverse", "sort", "user") opts = opt_parser.parse_args(argv)[0] report = Reporter(opts.verbosity - opts.quietness) if opts.user: alternative_roses_dir = SuiteId.get_local_copy_root(opts.user) report(UserSpecificRoses(alternative_roses_dir), prefix=None) ws_client = RosieWSClient(prefixes=opts.prefixes, event_handler=report) _display_maps(opts, ws_client, ws_client.query_local_copies(opts.user))
def add_prefix_choices(self): """Add the prefix choices.""" self.prefixes = self.ws_client.auth_managers.keys() self.prefixes.sort() self.prefixes.reverse() for prefix in self.prefixes: source = '<menu action="Source">' repl = source + '<menuitem action="_{0}_"/>'.format(prefix) self.ui_config_string = self.ui_config_string.replace( source, repl, 1) label_str = prefix + " - " + SuiteId.get_prefix_location(prefix) self.prefixes_action_details.append(( "_{0}_".format(prefix), None, label_str.replace("_", "__")))
def list_local_suites(argv): """CLI command to list all the locally checked out suites""" opt_parser = RoseOptionParser().add_my_options("no_headers", "prefixes", "print_format", "reverse", "sort", "user") opts = opt_parser.parse_args(argv)[0] report = Reporter(opts.verbosity - opts.quietness) if opts.user: alternative_roses_dir = SuiteId.get_local_copy_root(opts.user) report(UserSpecificRoses(alternative_roses_dir), prefix=None) ws_client = RosieWSClient(prefixes=opts.prefixes, event_handler=report) _display_maps(opts, ws_client, ws_client.query_local_copies(opts.user))
def get_local_suites(prefix=None): """Returns a dict of prefixes and id tuples for locally-present suites.""" local_copies = [] local_copy_root = SuiteId.get_local_copy_root() if not os.path.isdir(local_copy_root): return local_copies for path in os.listdir(local_copy_root): location = os.path.join(local_copy_root, path) try: id = SuiteId(location=location) except SuiteIdError as e: continue if prefix is None or id.prefix == prefix: local_copies.append(id) return local_copies
def _render(self, all_revs=0, data=None, filters=None, s=None): """Render return data with a template.""" if data: for item in data: suite_id = SuiteId.from_idx_branch_revision( item["idx"], item["branch"], item["revision"]) item["href"] = suite_id.to_web() template = self.template_env.get_template("prefix-index.html") return template.render(web_prefix=cherrypy.request.script_name, prefix=self.prefix, prefix_source_url=self.source_url, known_keys=self.dao.get_known_keys(), query_operators=self.dao.get_query_operators(), all_revs=all_revs, filters=filters, s=s, data=data)
def _render(self, all_revs=False, data=None, filters=None, s=None): if data: for item in data: suite_id = SuiteId.from_idx_branch_revision( item["idx"], item["branch"], item["revision"]) item["href"] = suite_id.to_web() template = self.template_env.get_template("prefix-index.html") return template.render( web_prefix=cherrypy.request.script_name, prefix=self.prefix, prefix_source_url=self.source_url, known_keys=self.dao.get_known_keys(), query_operators=self.dao.get_query_operators(), all_revs=all_revs, filters=filters, s=s, data=data)
def query_local_copies(self, user=None): """Returns details of the local suites. As if they had been obtained using a search or query. """ suite_ids = [] for suite_id in SuiteId.get_checked_out_suite_ids(user=user): if suite_id.prefix in self.prefixes: suite_ids.append(suite_id) if not suite_ids: return [] q_list = [] for suite_id in suite_ids: q_list.append("or ( idx eq %s" % suite_id.idx) q_list.append("and branch eq %s )" % suite_id.branch) results = [] for data, _ in self.query(q_list): results.extend(data) result_idx_branches = [] for result in results: result_idx_branches.append((result[u"idx"], result[u"branch"])) q_list = [] for suite_id in suite_ids: if (suite_id.idx, suite_id.branch) in result_idx_branches: continue # A branch may have been deleted - we need all_revs=1. # We only want to use all_revs on demand as it's slow. q_list.append("or ( idx eq %s" % suite_id.idx) q_list.append("and branch eq %s )" % suite_id.branch) if q_list: more_results = [] for data, _ in self.query(q_list, all_revs=1): more_results.extend(data) new_results = {} for result in more_results: idx_branch = (result[u"idx"], result[u"branch"]) if (idx_branch not in new_results or result[u"revision"] > new_results[idx_branch][u"revision"]): new_results.update({idx_branch: result}) for _, result in sorted(new_results.items()): results.append(result) return results
def _update_local_status_row(self, model, path, r_iter, data): """Update the status for a row of the treeview""" index_map, local_suites = data[0:2] idx = model.get_value(r_iter, index_map["idx"]) branch = model.get_value(r_iter, index_map["branch"]) revision = int(model.get_value(r_iter, index_map["revision"])) suite_id = SuiteId.from_idx_branch_revision(idx, branch, revision) status = suite_id.get_status() model.set_value(r_iter, index_map["local"], status) suite_id_text = suite_id.to_string_with_version() results = "" for line in self._result_info[idx, branch, revision].splitlines(): if line == suite_id_text or ":" in line or not line: results += line + "\n" else: results += STATUS_TIP[status] + "\n" self._result_info[idx, branch, revision] = results return False
def delete(argv): """CLI function: delete.""" opt_parser = RoseOptionParser().add_my_options("force_mode", "non_interactive", "local_only") opts, args = opt_parser.parse_args(argv) report = Reporter(opts.verbosity - opts.quietness) client = RosieVCClient(event_handler=report, force_mode=opts.force_mode) SuiteId.svn.event_handler = client.event_handler # FIXME if not args: args.append(SuiteId(location=os.getcwd())) interactive_mode = not opts.non_interactive prompt = ("%s: delete local+repository copies? " + "y/n/a (default n, a=yes-to-all) ") if opts.local_only: prompt = "%s: delete local copy? y/n/a (default n, a=yes-to-all) " rc = 0 for arg in args: if interactive_mode: try: response = raw_input(prompt % arg) except EOFError: rc = 1 continue if response == 'a': interactive_mode = False elif response != 'y': rc = 1 continue if opts.debug_mode: client.delete(arg, opts.local_only) else: try: client.delete(arg, opts.local_only) except (LocalCopyStatusError, RosePopenError, SuiteIdPrefixError) as e: client.event_handler(e) rc = 1 if not opts.force_mode: sys.exit(1) if rc: sys.exit(rc)
def delete(argv): """CLI function: delete.""" opt_parser = RoseOptionParser().add_my_options("force_mode", "non_interactive", "local_only") opts, args = opt_parser.parse_args(argv) report = Reporter(opts.verbosity - opts.quietness) client = RosieVCClient(event_handler=report, force_mode=opts.force_mode) SuiteId.svn.event_handler = client.event_handler if not args: args.append(SuiteId(location=os.getcwd())) interactive_mode = not opts.non_interactive prompt = PROMPT_DELETE if opts.local_only: prompt = PROMPT_DELETE_LOCAL ret_code = 0 for arg in args: if interactive_mode: try: response = raw_input(prompt % arg) except EOFError: ret_code = 1 continue if response == YES_TO_ALL: interactive_mode = False elif response != YES: ret_code = 1 continue if opts.debug_mode: client.delete(arg, opts.local_only) else: try: client.delete(arg, opts.local_only) except (LocalCopyStatusError, RosePopenError, SuiteIdPrefixError) as exc: client.event_handler(exc) ret_code = 1 if not opts.force_mode: sys.exit(1) if ret_code: sys.exit(ret_code)
def __init__(self, prefix=None, popen=None, prompt_func=None): if prefix is None: prefix = SuiteId.get_prefix_default() self.prefix = prefix self.auth_manager = RosieWSClientAuthManager(self.prefix, popen=popen, prompt_func=prompt_func) self.root = self.auth_manager.root self.requests_kwargs = {} res_loc = ResourceLocator.default() https_ssl_verify_mode_str = ( res_loc.default().get_conf().get_value(["rosie-id", "prefix-https-ssl-verify." + prefix]) ) if https_ssl_verify_mode_str: https_ssl_verify_mode = ast.literal_eval(https_ssl_verify_mode_str) self.requests_kwargs["verify"] = bool(https_ssl_verify_mode) https_ssl_cert_str = res_loc.default().get_conf().get_value(["rosie-id", "prefix-https-ssl-cert." + prefix]) if https_ssl_cert_str: https_ssl_cert = shlex.split(https_ssl_cert_str) if len(https_ssl_cert) == 1: self.requests_kwargs["cert"] = https_ssl_cert[0] else: self.requests_kwargs["cert"] = tuple(https_ssl_cert[0:2])
def get_local_suites(prefix=None, skip_status=False, user=None): """Returns a dict of prefixes and id tuples for locally-present suites.""" local_copies = [] if user: local_copy_root = os.path.expanduser(user) + "/roses" else: local_copy_root = SuiteId.get_local_copy_root() if not os.path.isdir(local_copy_root): return local_copies for path in os.listdir(local_copy_root): location = os.path.join(local_copy_root, path) try: id_ = SuiteId(location=location, skip_status=skip_status) except SuiteIdError as e: continue if prefix is None or id_.prefix == prefix: if str(id_) == path: local_copies.append(id_) return local_copies
def _render(self, all_revs=0, data=None, filters=None, s=None): """Render return data with a template.""" if data: for item in data: suite_id = SuiteId.from_idx_branch_revision( item["idx"], item["branch"], item["revision"]) item["href"] = suite_id.to_web() item["date"] = str( get_timepoint_from_seconds_since_unix_epoch(item["date"])) tmpl = self.props["template_env"].get_template("prefix-index.html") return tmpl.render(title=self.props["title"], host=self.props["host_name"], rose_version=self.props["rose_version"], script=cherrypy.request.script_name, prefix=self.prefix, prefix_source_url=self.source_url, known_keys=self.dao.get_known_keys(), query_operators=self.dao.get_query_operators(), all_revs=all_revs, filters=filters, s=s, data=data)
def generate_info_config(self, from_id=None, prefix=None, project=None): """Generate a 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 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 = rose.config.load(StringIO(out_data.decode())) res_loc = ResourceLocator.default() older_config = None info_config = 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=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 = 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], 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 _display_maps(opts, ws_client, dict_rows, url=None): """Display returned suite details.""" report = ws_client.event_handler try: terminal_cols = int(ws_client.popen("stty", "size")[0].split()[1]) except (IndexError, RosePopenError, ValueError): terminal_cols = None if terminal_cols == 0: terminal_cols = None if opts.quietness and not opts.print_format: opts.print_format = PRINT_FORMAT_QUIET elif not opts.print_format: opts.print_format = PRINT_FORMAT_DEFAULT all_keys = ws_client.get_known_keys() for dict_row in dict_rows: suite_id = SuiteId.from_idx_branch_revision(dict_row["idx"], dict_row["branch"], dict_row["revision"]) dict_row["suite"] = suite_id.to_string_with_version() if "%local" in opts.print_format: dict_row["local"] = suite_id.get_status(getattr( opts, "user", None)) all_keys += ["suite"] if "%local" in opts.print_format: all_keys += ["local"] more_keys = [] for key in REC_COL_IN_FORMAT.findall(opts.print_format): if key not in all_keys: more_keys.append(key) all_keys += more_keys if opts.sort is None or opts.sort not in all_keys: opts.sort = "revision" dict_rows.sort(lambda x, y: cmp(x[opts.sort], y[opts.sort])) if opts.reverse: dict_rows.reverse() keylist = [] for key in all_keys: if "%" + key in opts.print_format: keylist.append(key) if not opts.no_headers: dummy_row = {} for key in all_keys: dummy_row[key] = key dict_rows.insert(0, dummy_row) dict_rows = _align(dict_rows, keylist) for dict_row in dict_rows: out = opts.print_format for key, value in dict_row.items(): if "%" + key in out: out = unicode(out).replace(u"%" + unicode(key), unicode(value), 1) out = unicode(out.replace("%%", "%").expandtabs().rstrip()) report(SuiteEvent(out.expandtabs() + "\n"), prefix="", clip=terminal_cols) report(SuiteInfo(dict_row), prefix="") if url is not None: report(URLEvent(url + "\n"), prefix="")
def create(self, info_config, from_id=None, prefix=None, meta_suite_mode=False): """Create a suite. info_config -- A rose.config.ConfigNode object, which will be used as the content of the "rose-suite.info" file of the new suite. from_id -- If defined, copy items from it. prefix -- If defined, create the suite in the suite repository named by the prefix instead of the default one. meta_suite_mode -- If True, create the special metadata suite. Ignored if from_id is not None. Return the SuiteId of the suite on success. """ if from_id is not None and (not prefix or from_id.prefix == prefix): return self._copy1(info_config, from_id) dir_ = self._get_work_dir() try: # Create a temporary suite in the file system if from_id: from_id_url = "%s/%s@%s" % ( from_id.to_origin(), from_id.branch, from_id.revision) self.popen("svn", "export", "-q", "--force", from_id_url, dir_) else: open(os.path.join(dir_, "rose-suite.conf"), "w").close() rose.config.dump( info_config, os.path.join(dir_, "rose-suite.info")) # Attempt to import the temporary suite to the repository new_id = None while new_id is None: if meta_suite_mode: if prefix is None: new_id = SuiteId(id_text="ROSIE") else: idx = SuiteId.FORMAT_IDX % (prefix, "ROSIE") new_id = SuiteId(id_text=idx) else: new_id = SuiteId.get_next(prefix) new_origin = new_id.to_origin() + "/" + new_id.BRANCH_TRUNK try: if from_id: message = self.COMMIT_MESSAGE_COPY % ( new_id, from_id.to_string_with_version()) else: message = self.COMMIT_MESSAGE_CREATE % str(new_id) self.popen( "svn", "import", "-q", "-m", message, dir_, new_origin) self.event_handler(SuiteCreateEvent(new_id)) if from_id: self.event_handler(SuiteCopyEvent(new_id, from_id)) except RosePopenError as exc: try: self.popen("svn", "info", new_origin) if not meta_suite_mode: new_id = None except RosePopenError: raise exc return new_id finally: self._delete_work_dir()
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") opts, args = opt_parser.parse_args(argv) verbosity = opts.verbosity - opts.quietness report = Reporter(verbosity) client = RosieVCClient(event_handler=report) SuiteId.svn.event_handler = client.event_handler # FIXME: ugly? 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()) if opts.info_file is None: try: info_config = client.generate_info_config(from_id, opts.prefix) except (RosePopenError) as e: report(e) sys.exit(1) info_file = tempfile.NamedTemporaryFile(delete=False) try: rose.config.dump(info_config, info_file) info_file.write(CREATE_INFO_CONFIG_COMMENT) info_file.close() command_list = client.popen.get_cmd("editor", info_file.name) client.popen(*command_list, stdout=sys.stdout) info_config = rose.config.load(info_file.name) finally: os.unlink(info_file.name) elif opts.info_file == "-": info_config = rose.config.load(sys.stdin) else: info_config = rose.config.load(opts.info_file) if not opts.non_interactive: if from_id: question = "Copy \"%s\"?" % from_id.to_string_with_version() else: prefix = opts.prefix if not prefix: prefix = SuiteId.get_prefix_default() question = "Create suite at \"%s\"?" % prefix try: response = raw_input(question + " y/n (default n) ") except EOFError: sys.exit(1) if response != 'y': sys.exit(1) try: id = client.create(info_config, from_id, opts.prefix, opts.meta_suite_mode) except (RosePopenError, SuiteInfoFieldError, SuiteIdOverflowError) as e: report(e) sys.exit(1) if opts.checkout_mode: try: client.checkout(id) except (FileExistError, RosePopenError) as e: report(e) 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 report = Reporter(verbosity) client = RosieVCClient(event_handler=report) SuiteId.svn.event_handler = client.event_handler # FIXME: ugly? 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()) info_config_new = None interactive_mode = not opts.non_interactive if opts.info_file is None: try: info_config = client.generate_info_config(from_id, opts.prefix, opts.project) except (RosePopenError) as e: report(e) sys.exit(1) info_file = tempfile.NamedTemporaryFile() if args: meta_config = load_meta_config(info_config, directory=None, config_type=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.translate(None, "=") if key == "copy-mode" and value == "clear": info_config.set([sect], "") if key == "copy-mode" and value == "never": info_config.unset([sect]) rose.config.dump(info_config, info_file) info_file.write(CREATE_INFO_CONFIG_COMMENT) info_file.seek(0) command_list = client.popen.get_cmd("editor", info_file.name) client.popen(*command_list, stdout=sys.stdout) info_config = rose.config.load(info_file) try: info_config_new, error_reported = client.check_fields(info_config, interactive_mode, from_id, opts.prefix) except (RosePopenError, SuiteInfoFieldError, SuiteIdOverflowError) as e: report(e) sys.exit(1) while error_reported is True: info_file = tempfile.NamedTemporaryFile() info_config = info_config_new if (info_config.get(["project"]).value is not None and opts.project is None): project = info_config.get(["project"]).value info_config = client.generate_info_config(from_id, opts.prefix, project, info_config) rose.config.dump(info_config, info_file) info_file.write(CREATE_INFO_CONFIG_COMMENT) info_file.seek(0) command_list = client.popen.get_cmd("editor", info_file.name) client.popen(*command_list, stdout=sys.stdout) info_config = rose.config.load(info_file) try: info_config_new, error_reported = client.check_fields( info_config, interactive_mode, from_id, opts.prefix) except (RosePopenError, SuiteInfoFieldError, SuiteIdOverflowError) as e: report(e) sys.exit(1) elif opts.info_file == "-": info_config = rose.config.load(sys.stdin) try: info_config_new, error_reported = client.check_fields(info_config, interactive_mode, from_id, opts.info_file, opts.prefix) except (RosePopenError, SuiteInfoFieldError, SuiteIdOverflowError) as e: report(e) sys.exit(1) else: info_config = rose.config.load(opts.info_file) try: info_config_new, error_reported = client.check_fields(info_config, interactive_mode, from_id, opts.info_file, opts.prefix) except (RosePopenError, SuiteInfoFieldError, SuiteIdOverflowError) as e: report(e) sys.exit(1) if interactive_mode: if from_id: question = "Copy \"%s\"?" % from_id.to_string_with_version() else: prefix = opts.prefix if not prefix: prefix = SuiteId.get_prefix_default() question = "Create suite at \"%s\"?" % prefix try: response = raw_input(question + " y/n (default n) ") except EOFError: sys.exit(1) if response != 'y': sys.exit(1) try: id = client.create(info_config, from_id, opts.prefix, opts.meta_suite_mode) except (RosePopenError, SuiteInfoFieldError, SuiteIdOverflowError) as e: report(e) sys.exit(1) if opts.checkout_mode: try: client.checkout(id) except (FileExistError, RosePopenError) as e: report(e) sys.exit(1)
def create(self, info_config, from_id=None, prefix=None, meta_suite_mode=False): """Create a suite. info_config -- A rose.config.ConfigNode object, which will be used as the content of the "rose-suite.info" file of the new suite. from_id -- If defined, copy items from it. prefix -- If defined, create the suite in the suite repository named by the prefix instead of the default one. meta_suite_mode -- If True, create the special metadata suite. Ignored if from_id is not None. Return the SuiteId of the suite on success. """ if from_id is not None and (not prefix or from_id.prefix == prefix): return self._copy1(info_config, from_id) dir_ = self._get_work_dir() try: # Create a temporary suite in the file system if from_id: from_id_url = "%s/%s@%s" % (from_id.to_origin(), from_id.branch, from_id.revision) self.popen("svn", "export", "-q", "--force", from_id_url, dir_) else: open(os.path.join(dir_, "rose-suite.conf"), "w").close() rose.config.dump(info_config, os.path.join(dir_, "rose-suite.info")) # Attempt to import the temporary suite to the repository new_id = None while new_id is None: if meta_suite_mode: if prefix is None: new_id = SuiteId(id_text="ROSIE") else: idx = SuiteId.FORMAT_IDX % (prefix, "ROSIE") new_id = SuiteId(id_text=idx) else: new_id = SuiteId.get_next(prefix) new_origin = new_id.to_origin() + "/" + new_id.BRANCH_TRUNK try: if from_id: message = self.COMMIT_MESSAGE_COPY % ( new_id, from_id.to_string_with_version()) else: message = self.COMMIT_MESSAGE_CREATE % str(new_id) self.popen("svn", "import", "-q", "-m", message, dir_, new_origin) self.event_handler(SuiteCreateEvent(new_id)) if from_id: self.event_handler(SuiteCopyEvent(new_id, from_id)) except RosePopenError as exc: try: self.popen("svn", "info", new_origin) if not meta_suite_mode: new_id = None except RosePopenError: raise exc return new_id finally: self._delete_work_dir()
def create(self, info_config, from_id=None, prefix=None): """Create a suite. info_config should be a rose.config.ConfigNode object, which will be used as the content of the "rose-suite.info" file of the new suite. If from_id is defined, copy items from it. If prefix is defined, create the suite in the suite repository named by the prefix instead of the default one. Return the SuiteId of the suite on success. """ for key in ["owner", "project", "title"]: if not info_config.get([key], no_ignore=True): raise SuiteInfoFieldError(key) if from_id is not None: prefix = from_id.prefix new_id = None while new_id is None: new_id = SuiteId.get_next(prefix) new_origin = new_id.to_origin() + "/" + new_id.BRANCH_TRUNK dir = self._get_work_dir() rose.config.dump(info_config, os.path.join(dir, "rose-suite.info")) open(os.path.join(dir, "rose-suite.conf"), "w").close() try: self.popen("svn", "import", "-q", "-m", "%s: new suite." % str(new_id), dir, new_origin) self.event_handler(SuiteCreateEvent(new_id)) self._delete_work_dir() except RosePopenError as e: try: self.popen("svn", "info", new_origin) new_id = None except RosePopenError: raise e if from_id is None: return new_id from_origin_base = "%s/%s" % (from_id.to_origin(), from_id.branch) from_origin = "%s@%s" % (from_origin_base, from_id.revision) copy_command_list = ["copy", "-q"] for from_item in self.popen("svn", "ls", from_origin)[0].split(): if from_item not in ["rose-suite.conf", "rose-suite.info"]: item = "%s/%s@%s" % (from_origin_base, from_item, from_id.revision) copy_command_list.append(item) copy_command_list.append(".") log = "%s: copy items from %s" % (str(new_id), from_id.to_string_with_version()) temp_local_copy = os.path.join(self._get_work_dir(), "work") try: self.popen("svn", "checkout", new_origin, temp_local_copy) cwd = os.getcwd() os.chdir(temp_local_copy) self.popen("svn", *copy_command_list) from_conf = "%s/%s@%s" % (from_origin_base, "rose-suite.conf", from_id.revision) f = open("rose-suite.conf", "w") f.write(self.popen("svn", "cat", from_conf)[0]) f.close() self.popen("svn", "commit", "-m", log) self.event_handler(SuiteCopyEvent(new_id, from_id)) finally: os.chdir(cwd) self._delete_work_dir() return new_id
def generate_info_config(self, from_id=None, prefix=None, project=None): """Generate a 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 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 = rose.config.load(StringIO(out_data)) res_loc = ResourceLocator.default() older_config = None info_config = 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=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 = 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], 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(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=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 = 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 generate_info_config(self, from_id=None, prefix=None): """Generate a 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 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 = rose.config.load(StringIO(out_data)) if from_config.get(["project"]) is not None: from_project = from_config.get(["project"]).value if from_config.get(["title"]) is not None: from_title = from_config.get(["title"]).value res_loc = ResourceLocator.default() info_config = rose.config.ConfigNode() # Determine prefix if from_id is not None: prefix = from_id.prefix elif prefix is None: prefix = SuiteId.get_prefix_default() # 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 = rose.config.load(self.subversion_servers_conf) groups_node = servers_conf.get(["groups"]) if groups_node is not None: group = 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) # Determine project and title if from_project: info_config.set(["project"], from_project) else: info_config.set(["project"], "") if from_title: info_config.set(["title"], "Copy of %s: %s" % (from_id.to_string_with_version(), from_title)) else: info_config.set(["title"], "") # 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) return info_config
def generate_info_config(self, from_id=None, prefix=None): """Generate a 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 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 = rose.config.load(StringIO(out_data)) if from_config.get(["project"]) is not None: from_project = from_config.get(["project"]).value if from_config.get(["title"]) is not None: from_title = from_config.get(["title"]).value res_loc = ResourceLocator.default() info_config = rose.config.load( res_loc.locate("rosie-create/rose-suite.info")) if from_id is not None: prefix = from_id.prefix elif prefix is None: prefix = SuiteId.get_prefix_default() # 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 = rose.config.load(self.subversion_servers_conf) groups_node = servers_conf.get(["groups"]) if groups_node is not None: group = 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) if from_project: info_config.set(["project"], from_project) else: info_config.set(["project"], "") if from_title: info_config.set(["title"], "Copy of %s: %s" % (from_id.to_string_with_version(), from_title)) else: info_config.set(["title"], "") return info_config
def _display_maps(opts, ws_client, dict_rows, url=None): """Display returned suite details.""" report = ws_client.event_handler try: terminal_cols = int(ws_client.popen("stty", "size")[0].split()[1]) except (IndexError, RosePopenError, ValueError): terminal_cols = None if terminal_cols == 0: terminal_cols = None if opts.quietness and not opts.print_format: opts.print_format = PRINT_FORMAT_QUIET elif not opts.print_format: opts.print_format = PRINT_FORMAT_DEFAULT all_keys = ws_client.get_known_keys() for dict_row in dict_rows: suite_id = SuiteId.from_idx_branch_revision( dict_row["idx"], dict_row["branch"], dict_row["revision"]) dict_row["suite"] = suite_id.to_string_with_version() if "%local" in opts.print_format: dict_row["local"] = suite_id.get_status( getattr(opts, "user", None)) all_keys += ["suite"] if "%local" in opts.print_format: all_keys += ["local"] more_keys = [] for key in REC_COL_IN_FORMAT.findall(opts.print_format): if key not in all_keys: more_keys.append(key) all_keys += more_keys if opts.sort is None or opts.sort not in all_keys: opts.sort = "revision" dict_rows.sort(lambda x, y: cmp(x[opts.sort], y[opts.sort])) if opts.reverse: dict_rows.reverse() keylist = [] for key in all_keys: if "%" + key in opts.print_format: keylist.append(key) if not opts.no_headers: dummy_row = {} for key in all_keys: dummy_row[key] = key dict_rows.insert(0, dummy_row) dict_rows = _align(dict_rows, keylist) for dict_row in dict_rows: out = opts.print_format for key, value in dict_row.items(): if "%" + key in out: out = out.replace("%" + key, str(value), 1) out = out.replace("%%", "%").expandtabs().rstrip() report(SuiteEvent(out.expandtabs() + "\n"), prefix="", clip=terminal_cols) report(SuiteInfo(dict_row), prefix="") if url is not None: report(URLEvent(url + "\n"), prefix="")
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=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.translate(None, "=") 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 = 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 = raw_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)