def _execute(self, options, args): """Apply mincss the generated site.""" output_folder = self.site.config["OUTPUT_FOLDER"] if Processor is None: LOGGER.warn("To use the mincss command," ' you have to install the "mincss" package.') return p = Processor(preserve_remote_urls=False) urls = [] css_files = {} for root, dirs, files in os.walk(output_folder): for f in files: url = os.path.join(root, f) if url.endswith(".css"): fname = os.path.basename(url) if fname in css_files: LOGGER.error("You have two CSS files with the same name and that confuses me.") sys.exit(1) css_files[fname] = url if not f.endswith(".html"): continue urls.append(url) p.process(*urls) for inline in p.links: fname = os.path.basename(inline.href) with open(css_files[fname], "wb+") as outf: outf.write(inline.after)
def handleMatch(self, m): gist_id = m.group("gist_id") gist_file = m.group("filename") gist_elem = etree.Element("div") gist_elem.set("class", "gist") script_elem = etree.SubElement(gist_elem, "script") if requests: noscript_elem = etree.SubElement(gist_elem, "noscript") try: if gist_file: script_elem.set("src", GIST_FILE_JS_URL.format(gist_id, gist_file)) raw_gist = self.get_raw_gist_with_filename(gist_id, gist_file) else: script_elem.set("src", GIST_JS_URL.format(gist_id)) raw_gist = self.get_raw_gist(gist_id) # Insert source as <pre/> within <noscript> pre_elem = etree.SubElement(noscript_elem, "pre") pre_elem.text = AtomicString(raw_gist) except GistFetchException as e: LOGGER.warn(e.message) warning_comment = etree.Comment(" WARNING: {0} ".format(e.message)) noscript_elem.append(warning_comment) else: LOGGER.warn('"requests" package not installed. ' "Please install to add inline gist source.") return gist_elem
def site_context(self, site, client_templates): from nikola.utils import TranslatableSetting, LOGGER, Functionary result = {} translated_settings = {} for l in site.config['TRANSLATIONS']: translated_settings[l] = {} for k, v in site.GLOBAL_CONTEXT.items(): if k in ['template_hooks', 'get_post_data', 'timezone']: continue if callable(v): if isinstance(v, TranslatableSetting): for l in site.config['TRANSLATIONS']: translated_settings[l][k] = v.values[l] continue elif isinstance(v, Functionary): # just a callable dict pass else: LOGGER.warn('Found unserializable callable in GLOBAL_CONTEXT: %r, %s' % (k, type(v))) continue result[k] = v result['translated_settings'] = translated_settings # TODO: LEGAL_VALUES isn't exported by nikola.py! # result['lang'] in LEGAL_VALUES['RTL_LANGUAGES'] result['is_rtl'] = False result['default_lang'] = site.default_lang result['BASE_URL'] = site.config['BASE_URL'] result['client_templates'] = client_templates return result
def emoji_role(name, rawtext, text, lineno, inliner, options={}, content=[]): text = text.lower() LOGGER.warn('The role :emoji:`{0}` is deprecated. Use |{0}| instead'.format(text)) node = nodes.image( uri='https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/images/basic/{0}.png'.format(text), alt=text, classes=['emoji'], ) return [node], []
def emoji_role(name, rawtext, text, lineno, inliner, options={}, content=[]): text = text.lower() LOGGER.warn('The role :emoji:`{0}` is deprecated. Use |{0}| instead'.format(text)) node = nodes.image( uri='http://www.tortue.me/emoji/{0}.png'.format(text), alt=text, classes=['emoji'], ) return [node], []
def emoji_role(name, rawtext, text, lineno, inliner, options={}, content=[]): text = text.lower() LOGGER.warn( 'The role :emoji:`{0}` is deprecated. Use |{0}| instead'.format(text)) node = nodes.image( uri='http://www.tortue.me/emoji/{0}.png'.format(text), alt=text, classes=['emoji'], ) return [node], []
def doc_shortcode(*args, **kwargs): """Implement the doc shortcode.""" text = kwargs['data'] success, twin_slugs, title, permalink, slug = _doc_link(text, text, LOGGER) if success: if twin_slugs: LOGGER.warn( 'More than one post with the same slug. Using "{0}" for doc shortcode'.format(permalink)) return '<a href="{0}">{1}</a>'.format(permalink, title) else: LOGGER.error( '"{0}" slug doesn\'t exist.'.format(slug)) return '<span class="error text-error" style="color: red;">Invalid link: {0}</span>'.format(text)
def doc_shortcode(*args, **kwargs): """Implement the doc shortcode.""" text = kwargs['data'] success, twin_slugs, title, permalink, slug = _doc_link(text, text, LOGGER) if success: if twin_slugs: LOGGER.warn( 'More than one post with the same slug. Using "{0}" for doc shortcode'.format(permalink)) return '<a href="{0}">{1}</a>'.format(permalink, title) else: LOGGER.error( '"{0}" slug doesn\'t exist.'.format(slug)) return '<span class="error text-error" style="color: red;">Invalid link: {0}</span>'.format(text)
def analyze(self, task, find_sources=False): rv = False self.whitelist = [re.compile(x) for x in self.site.config['LINK_CHECK_WHITELIST']] try: filename = task.split(":")[-1] d = lxml.html.fromstring(open(filename).read()) for l in d.iterlinks(): target = l[0].attrib[l[1]] if target == "#": continue parsed = urlparse(target) if parsed.scheme or target.startswith('//'): continue if parsed.fragment: target = target.split('#')[0] target_filename = os.path.abspath( os.path.join(os.path.dirname(filename), unquote(target))) if any(re.match(x, target_filename) for x in self.whitelist): continue elif target_filename not in self.existing_targets: if os.path.exists(target_filename): self.existing_targets.add(target_filename) else: rv = True LOGGER.warn("Broken link in {0}: ".format(filename), target) if find_sources: LOGGER.warn("Possible sources:") LOGGER.warn(os.popen('nikola list --deps ' + task, 'r').read()) LOGGER.warn("===============================\n") except Exception as exc: LOGGER.error("Error with:", filename, exc) return rv
def doc_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """Handle the doc role.""" success, twin_slugs, title, permalink, slug = _doc_link(rawtext, text, options, content) if success: if twin_slugs: inliner.reporter.warning( 'More than one post with the same slug. Using "{0}"'.format(permalink)) LOGGER.warn( 'More than one post with the same slug. Using "{0}" for doc role'.format(permalink)) node = make_link_node(rawtext, title, permalink, options) return [node], [] else: msg = inliner.reporter.error( '"{0}" slug doesn\'t exist.'.format(slug), line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg]
def doc_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """Handle the doc role.""" success, twin_slugs, title, permalink, slug = _doc_link(rawtext, text, options, content) if success: if twin_slugs: inliner.reporter.warning( 'More than one post with the same slug. Using "{0}"'.format(permalink)) LOGGER.warn( 'More than one post with the same slug. Using "{0}" for doc role'.format(permalink)) node = make_link_node(rawtext, title, permalink, options) return [node], [] else: msg = inliner.reporter.error( '"{0}" slug doesn\'t exist.'.format(slug), line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg]
def _execute(self, command, args): # Get last succesful deploy date timestamp_path = os.path.join(self.site.config['CACHE_FOLDER'], 'lastdeploy') if self.site.config['COMMENT_SYSTEM_ID'] == 'nikolademo': LOGGER.warn("\nWARNING WARNING WARNING WARNING\n" "You are deploying using the nikolademo Disqus account.\n" "That means you will not be able to moderate the comments in your own site.\n" "And is probably not what you want to do.\n" "Think about it for 5 seconds, I'll wait :-)\n\n") time.sleep(5) deploy_drafts = self.site.config.get('DEPLOY_DRAFTS', True) deploy_future = self.site.config.get('DEPLOY_FUTURE', False) if not (deploy_drafts and deploy_future): # Remove drafts and future posts out_dir = self.site.config['OUTPUT_FOLDER'] self.site.scan_posts() for post in self.site.timeline: if (not deploy_drafts and post.is_draft) or \ (not deploy_future and post.publish_later): remove_file(os.path.join(out_dir, post.destination_path())) remove_file(os.path.join(out_dir, post.source_path)) for command in self.site.config['DEPLOY_COMMANDS']: try: with open(timestamp_path, 'rb') as inf: last_deploy = literal_eval(inf.read().strip()) except Exception: last_deploy = datetime(1970, 1, 1) # NOQA LOGGER.notice("==>", command) ret = subprocess.check_call(command, shell=True) if ret != 0: # failed deployment raise Exception("Failed deployment") LOGGER.notice("Successful deployment") new_deploy = datetime.now() # Store timestamp of successful deployment with codecs.open(timestamp_path, 'wb+', 'utf8') as outf: outf.write(repr(new_deploy))
def scan_files(self): failure = False LOGGER.notice("Checking Files:") LOGGER.notice("===============\n") only_on_output, only_on_input = self.real_scan_files() if only_on_output: only_on_output.sort() LOGGER.warn("Files from unknown origins:") for f in only_on_output: LOGGER.warn(f) failure = True if only_on_input: only_on_input.sort() LOGGER.warn("Files not generated:") for f in only_on_input: LOGGER.warn(f) if not failure: LOGGER.notice("All files checked.") return failure
def set_site(self, site): """ Map navstories config to nav_config[*] as TranslatableSettings """ # Read NAVSTORIES_SUBMENU_INDENTION and store in self.navstories_submenu_indention if 'NAVSTORIES_SUBMENU_INDENTION' in site.config: self.navstories_submenu_indention = site.config[ 'NAVSTORIES_SUBMENU_INDENTION'] nav_config = {} for i in self.conf_vars: # Read config variables in a try...except in case a variable is missing try: nav_config[i] = utils.TranslatableSetting( i, site.config[i], site.config['TRANSLATIONS']) except KeyError: # Initialize to "empty" in case config variable i is missing nav_config[i] = utils.TranslatableSetting( i, self.conf_defaults[i](), site.config['TRANSLATIONS']) site.scan_posts() # NAVIGATION_LINKS is a TranslatableSetting, values is an actual dict for lang in site.config['NAVIGATION_LINKS'].values: # navstories config for lang nav_conf_lang = {} for i in self.conf_vars: nav_conf_lang[i] = nav_config[i](lang) # Which paths are navstories active for current lang? - Must start and end with / paths = tuple(('/' + s.strip('/') + '/') for s in nav_conf_lang['NAVSTORIES_PATHS']) # Unsorted (raw) new entries, deleted as mapped to new new_raw = {} # Sorted entries as a list of top-level menu entries, later new = [] # Map site pages to new_raw structure for p in site.pages: # Generate navpath (menu) based on permalink without language prefix # If TRANSLATION[DEFAULT_LANG] = '', then "permalink_nolang = p.permalink()" is ok permalink_nolang = re.sub( r'^/' + nav_conf_lang['TRANSLATIONS'].lstrip('./') + '/?', '/', p.permalink(lang)) s_candidates = [ s for s in paths if permalink_nolang.startswith(s) ] if not s_candidates: continue # get longest path s = max(s_candidates, key=len) # Strip off the longest path in paths navpath = permalink_nolang[len(s):].strip('/').split('/') if len(navpath) == 0: # Should not happen that navpath is empty, but to prevent errors, and inform via a warning LOGGER.warn( "Page with permalink: '%s', title: '%s', not added to menu by navstories." % (p.permalink(lang), p.title(lang))) continue if lang in p.translated_to and not p.meta('hidefromnav'): # Add entry if not navpath[0] in new_raw: new_raw[navpath[0]] = [] new_raw[navpath[0]].append( self.NavNode(navpath, p.permalink(lang), p.title(lang))) # Map from new_raw to new, sorting by NAVSTORIES_MAPPING for map_key, map_txt in nav_conf_lang['NAVSTORIES_MAPPING']: # Loop over all new_raw entries, checking if it matches map_key; if match: add it and delete from new_raw if map_key in new_raw: new.append([map_txt, new_raw[map_key]]) del (new_raw[map_key]) # Add remaing new_raw entries which didn't match any map_key new.extend([[None, new_raw[_]] for _ in sorted(new_raw)]) # Map to tuple new_entries = self.map_to_menu(new) old_entries = site.config['NAVIGATION_LINKS'](lang) # Update NAVIGATION_LINKS with navstories dynamically generated entries and NAVIGATION_LINKS_POST_NAVSTORIES entries site.config['NAVIGATION_LINKS'].values[ lang] = old_entries + new_entries + nav_conf_lang[ 'NAVIGATION_LINKS_POST_NAVSTORIES'] super(NavStories, self).set_site(site)
def set_site(self, site): """ Map navstories config to nav_config[*] as TranslatableSettings """ # Read NAVSTORIES_SUBMENU_INDENTION and store in self.navstories_submenu_indention if 'NAVSTORIES_SUBMENU_INDENTION' in site.config: self.navstories_submenu_indention = site.config['NAVSTORIES_SUBMENU_INDENTION'] nav_config = {} for i in self.conf_vars: # Read config variables in a try...except in case a variable is missing try: nav_config[i] = utils.TranslatableSetting(i, site.config[i], site.config['TRANSLATIONS']) except KeyError: # Initialize to "empty" in case config variable i is missing nav_config[i] = utils.TranslatableSetting(i, self.conf_defaults[i](), site.config['TRANSLATIONS']) site.scan_posts() # NAVIGATION_LINKS is a TranslatableSetting, values is an actual dict for lang in site.config['NAVIGATION_LINKS'].values: # navstories config for lang nav_conf_lang = {} for i in self.conf_vars: nav_conf_lang[i] = nav_config[i](lang) # Which paths are navstories active for current lang? - Must start and end with / paths = tuple(('/' + s.strip('/') + '/') for s in nav_conf_lang['NAVSTORIES_PATHS']) # Unsorted (raw) new entries, deleted as mapped to new new_raw = {} # Sorted entries as a list of top-level menu entries, later new = [] # Map site pages to new_raw structure for p in site.pages: # Generate navpath (menu) based on permalink without language prefix # If TRANSLATION[DEFAULT_LANG] = '', then "permalink_nolang = p.permalink()" is ok permalink_nolang = re.sub(r'^/' + nav_conf_lang['TRANSLATIONS'].lstrip('./') + '/?', '/', p.permalink(lang)) s_candidates = [s for s in paths if permalink_nolang.startswith(s)] if not s_candidates: continue # get longest path s = max(s_candidates, key=len) # Strip off the longest path in paths navpath = permalink_nolang[len(s):].strip('/').split('/') if len(navpath) == 0: # Should not happen that navpath is empty, but to prevent errors, and inform via a warning LOGGER.warn("Page with permalink: '%s', title: '%s', not added to menu by navstories." % (p.permalink(lang), p.title(lang))) continue if lang in p.translated_to and not p.meta('hidefromnav'): # Add entry if not navpath[0] in new_raw: new_raw[navpath[0]] = [] new_raw[navpath[0]].append(self.NavNode(navpath, p.permalink(lang), p.title(lang))) # Map from new_raw to new, sorting by NAVSTORIES_MAPPING for map_key, map_txt in nav_conf_lang['NAVSTORIES_MAPPING']: # Loop over all new_raw entries, checking if it matches map_key; if match: add it and delete from new_raw if map_key in new_raw: new.append([map_txt, new_raw[map_key]]) del(new_raw[map_key]) # Add remaing new_raw entries which didn't match any map_key new.extend([[None, new_raw[_]] for _ in sorted(new_raw)]) # Map to tuple new_entries = self.map_to_menu(new) old_entries = site.config['NAVIGATION_LINKS'](lang) # Update NAVIGATION_LINKS with navstories dynamically generated entries and NAVIGATION_LINKS_POST_NAVSTORIES entries site.config['NAVIGATION_LINKS'].values[lang] = old_entries + new_entries + nav_conf_lang['NAVIGATION_LINKS_POST_NAVSTORIES'] super(NavStories, self).set_site(site)