def _onlynew(self, msg, id=None, misc=''): """ log an only-new mode message Accepts a message to be printed out when running in "only-new" mode. A message may be accompanied by an identifier which should be translated to a name (if possible). Args: msg: the message id (optional): identifier (name mapping) associated with the message """ s = '[only-new] ' s += msg if id and id in self._name_cache: s += ' ' + self._name_cache[id] if id: s += ' ({})'.format(id) ConfluenceLogger.info(s + min(80, 80 - len(s)) * ' ') # 80c-min clearing
def _dryrun(self, msg, id_=None, misc=''): """ log a dry run mode message Accepts a message to be printed out when running in "dry run" mode. A message may be accompanied by an identifier which should be translated to a name (if possible). Args: msg: the message id_ (optional): identifier (name mapping) associated with the message misc (optional): additional information to append """ s = '[dryrun] ' s += msg if id_ and id_ in self._name_cache: s += ' ' + self._name_cache[id_] if id_: s += ' ({})'.format(id_) if misc: s += ' ' + misc logger.info(s + min(80, 80 - len(s)) * ' ') # 80c-min clearing
def _inline_all_toctrees(builder, docnameset, docname, tree, colorfunc, traversed, replace): tree = cast(nodes.document, tree.deepcopy()) for toctreenode in list(tree.traverse(addnodes.toctree)): newnodes = [] includefiles = map(str, toctreenode['includefiles']) for includefile in includefiles: if includefile not in traversed: try: traversed.append(includefile) logger.info(colorfunc(includefile) + " ", nonl=True) subtree = _inline_all_toctrees( builder, docnameset, includefile, builder.env.get_doctree(includefile), colorfunc, traversed, replace) docnameset.add(includefile) except Exception: logger.warn( __('toctree contains ref to nonexisting file %r'), includefile, location=docname) else: sof = addnodes.start_of_file(docname=includefile) sof.children = subtree.children for sectionnode in sof.traverse(nodes.section): if 'docname' not in sectionnode: sectionnode['docname'] = includefile newnodes.append(sof) if replace: toctreenode.parent.replace(toctreenode, newnodes) else: for node in newnodes: toctreenode.parent.append(node) return tree
def connect(self): self.rest_client = Rest(self.config) server_url = self.config.confluence_server_url try: rsp = self.rest_client.get('space', { 'spaceKey': self.space_key, 'limit': 1 }) except ConfluenceBadApiError as e: raise ConfluenceBadServerUrlError(server_url, e) # if no size entry is provided, this a non-Confluence API server if 'size' not in rsp: raise ConfluenceBadServerUrlError( server_url, 'server did not provide an expected response (no size)') # handle if the provided space key was not found if rsp['size'] == 0: if self.debug: logger.info('''could not find the configured space (notice to debugging user) Either the space does not exist, or the user does not have permission to see the space. Another space search will be performed to sanity check the configuration to see if a similar space key exists, which can hint to a user that the space key may be misconfigured. If the following search request results in an access restriction, it is most likely that the authentication options are not properly configured, even if the previous search request reported a success (which can be permitted for anonymous users). ''') extra_desc = '' # If the space key was not found, attempt to search for the space # based off its descriptive name. If something is found, hint to the # user to use a space's key value instead. search_fields = { 'cql': 'type=space and space.title~"' + self.space_key + '"', 'limit': 2, } rsp = self.rest_client.get('search', search_fields) if rsp['size'] == 1: detected_space = rsp['results'][0] space_key = detected_space['space']['key'] space_name = detected_space['title'] extra_desc = \ '''\n\n''' \ '''There appears to be a space '{0}' which has a name ''' \ ''''{1}'. Did you mean to use this space?\n''' \ '''\n''' \ ''' confluence_space_key = '{0}'\n''' \ ''''''.format(space_key, space_name) elif rsp['size'] > 1: extra_desc = \ '''\n\n''' \ '''Multiple spaces have been detected which use the ''' \ '''name '{}'. The unique key of the space should be ''' \ '''used instead. See also:\n\n''' \ ''' https://support.atlassian.com/confluence-cloud/docs/choose-a-space-key/\n''' \ ''''''.format(self.space_key) pw_set = bool(self.config.confluence_server_pass) token_set = bool(self.config.confluence_publish_token) raise ConfluenceBadSpaceError(self.space_key, self.config.confluence_server_user, pw_set, token_set, extra_desc) # sanity check that we have any result if 'results' not in rsp or not rsp['results']: raise ConfluenceBadServerUrlError( server_url, 'server did not provide an expected response (no results)') result = rsp['results'][0] if not isinstance(result, dict) or not result.get('name'): raise ConfluenceBadServerUrlError( server_url, 'server did not provide an expected response (no name)') # track required space information self.space_display_name = result['name'] self.space_type = result['type']
def __exit__(self, type, value, traceback): if type: ConfluenceLogger.info(__('failed')) else: ConfluenceLogger.info(__('done'))
def __enter__(self): ConfluenceLogger.info(bold(self.msg + '... '), nonl=True)
def wipe_main(args_parser): """ wipe mainline The mainline for the 'wipe' action. Args: args_parser: the argument parser to use for argument processing Returns: the exit code """ args_parser.add_argument('--danger', action='store_true') known_args = sys.argv[1:] args, unknown_args = args_parser.parse_known_args(known_args) if unknown_args: logger.warn('unknown arguments: {}'.format(' '.join(unknown_args))) work_dir = args.work_dir if args.work_dir else os.getcwd() # protection warning if not args.danger: print('') sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') print(""" A request has been made to attempt to wipe the pages from a configured Confluence instance. This is a helper utility call to assist a user in cleaning out a space since removing a bulk set of data may not be trivial for a user. Note that this action is not reversible with this tool and may require assistance from an administrator from a Confluence instance to recover pages. Only use this action if you know what you are doing. To use this action, the argument '--danger' must be set. """) sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') print('') return 1 # check configuration and prepare publisher publisher = None with TemporaryDirectory() as tmp_dir: with docutils_namespace(): app = Sphinx( work_dir, # document sources work_dir, # directory with configuration tmp_dir, # output for generated documents tmp_dir, # output for doctree files 'confluence') # builder to execute aggressive_search = app.config.confluence_adv_aggressive_search server_url = app.config.confluence_server_url space_name = app.config.confluence_space_name # initialize the publisher (if permitted) if app.config.confluence_publish: process_ask_configs(app.config) publisher = ConfluencePublisher() publisher.init(app.config) if not publisher: print('(error) publishing not configured in sphinx configuration') return 1 # reminder warning print('') sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') print(""" A request has been made to attempt to wipe the pages from a configured Confluence instance. This action is not reversible with this tool and may require assistance from an administrator from a Confluence instance to recover pages. Only use this action if you know what you are doing. """) sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') print('') if not ask_question('Are you sure you want to continue?'): return 0 print('') # user has confirmed; start an attempt to wipe publisher.connect() if aggressive_search: legacy_pages = publisher.getDescendantsCompat(None) else: legacy_pages = publisher.getDescendants(None) if not legacy_pages: print('No pages are published on this space. Exiting...') return 0 print(' URL:', server_url) print(' Space:', space_name) logger.note(' Pages: All Pages') print(' Total pages:', len(legacy_pages)) print('') if not ask_question('Are you sure you want to REMOVE these pages?'): return 0 print('') logger.info('Removing pages...', nonl=True) for page_id in legacy_pages: publisher.removePage(page_id) logger.info('.', nonl=True) logger.info(' done\n') return 0
def __exit__(self, type_, value, traceback): if type_: logger.info(__('failed')) else: logger.info(__('done'))
def __enter__(self): logger.info(bold(self.msg + '... '), nonl=True)
def wipe_main(args_parser): """ wipe mainline The mainline for the 'wipe' action. Args: args_parser: the argument parser to use for argument processing Returns: the exit code """ args_parser.add_argument('--danger', action='store_true') args_parser.add_argument('--parent', '-P', action='store_true') known_args = sys.argv[1:] args, unknown_args = args_parser.parse_known_args(known_args) if unknown_args: logger.warn('unknown arguments: {}'.format(' '.join(unknown_args))) work_dir = args.work_dir if args.work_dir else os.getcwd() # protection warning if not args.danger: print('') sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') print(""" A request has been made to attempt to wipe the pages from a configured Confluence instance. This is a helper utility call to assist a user in cleaning out a space since removing a bulk set of data may not be trivial for a user. Note that this action is not reversible with this tool and may require assistance from an administrator from a Confluence instance to recover pages. Only use this action if you know what you are doing. To use this action, the argument '--danger' must be set. """) sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') return 1 # check configuration and prepare publisher dryrun = False publisher = None try: with temp_dir() as tmp_dir: with docutils_namespace(): app = Sphinx( work_dir, # document sources work_dir, # directory with configuration tmp_dir, # output for built documents tmp_dir, # output for doctree files 'confluence', # builder to execute status=sys.stdout, # sphinx status output warning=sys.stderr) # sphinx warning output aggressive_search = app.config.confluence_adv_aggressive_search dryrun = app.config.confluence_publish_dryrun server_url = app.config.confluence_server_url space_key = app.config.confluence_space_key parent_ref = app.config.confluence_parent_page # initialize the publisher (if permitted) if app.config.confluence_publish: process_ask_configs(app.config) publisher = ConfluencePublisher() publisher.init(app.config) except Exception: sys.stdout.flush() logger.error(traceback.format_exc()) if os.path.isfile(os.path.join(work_dir, 'conf.py')): logger.error('unable to load configuration') else: logger.error('no documentation/missing configuration') return 1 if not publisher: logger.error('publishing not configured in sphinx configuration') return 1 if args.parent and not parent_ref: logger.error('parent option provided but no parent page is configured') return 1 # reminder warning print('') sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') print(""" A request has been made to attempt to wipe the pages from a configured Confluence instance. This action is not reversible with this tool and may require assistance from an administrator from a Confluence instance to recover pages. Only use this action if you know what you are doing. """) sys.stdout.flush() logger.warn('!!! DANGER DANGER DANGER !!!') print('') if not ask_question('Are you sure you want to continue?'): return 0 print('') # user has confirmed; start an attempt to wipe publisher.connect() base_page_id = None if args.parent: base_page_id = publisher.get_base_page_id() if aggressive_search: legacy_pages = publisher.get_descendants_compat(base_page_id) else: legacy_pages = publisher.get_descendants(base_page_id) print(' URL:', server_url) print(' Space:', space_key) if base_page_id: logger.note(' Pages: Child pages of ' + parent_ref) else: logger.note(' Pages: All Pages') print(' Total pages:', len(legacy_pages)) if dryrun: print(' Dry run:', 'Enabled (no pages will be removed)') if not legacy_pages: print('') print('No pages detected on this space. Exiting...') return 0 if args.verbose: print('-------------------------') page_names = [] for p in legacy_pages: page_names.append(publisher._name_cache[p]) sorted(page_names) print('\n'.join(page_names)) print('-------------------------') print('') if not ask_question('Are you sure you want to REMOVE these pages?'): return 0 print('') logger.info('Removing pages...', nonl=True) if dryrun: logger.info('') for page_id in legacy_pages: publisher.remove_page(page_id) if not dryrun: logger.info('.', nonl=True) if not dryrun: logger.info(__('done')) return 0