def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) if ODF2XHTML is None: req_missing(["odfpy"], "build this site (compile odt)") odhandler = ODF2XHTML(True, False) data = odhandler.odf2xhtml(source) # Take the CSS from the head and put it in body doc = etree.fromstring(data) body = doc.find("{http://www.w3.org/1999/xhtml}body") for style in doc.findall("*//{http://www.w3.org/1999/xhtml}style"): style.getparent().remove(style) # keep only classes: filtered = [] for line in style.text.splitlines(): if line and line[0] in ".\t}": filtered.append(line) style.text = "".join(filtered) body.insert(0, style) with io.open(dest, "w+", encoding="utf-8") as outf: outf.write(etree.tostring(body, encoding="unicode"))
def process_tree(self, src, dst): """Process all images in a src tree and put the (possibly) rescaled images in the dst folder.""" thumb_fmt = self.kw['image_thumbnail_format'] base_len = len(src.split(os.sep)) for root, dirs, files in os.walk(src, followlinks=True): root_parts = root.split(os.sep) dst_dir = os.path.join(dst, *root_parts[base_len:]) utils.makedirs(dst_dir) for src_name in files: if (not src_name.lower().endswith(tuple(self.image_ext_list)) and not src_name.upper().endswith(tuple(self.image_ext_list))): continue dst_file = os.path.join(dst_dir, src_name) src_file = os.path.join(root, src_name) thumb_name, thumb_ext = os.path.splitext(src_name) thumb_file = os.path.join(dst_dir, thumb_fmt.format( name=thumb_name, ext=thumb_ext, )) yield { 'name': dst_file, 'file_dep': [src_file], 'targets': [dst_file, thumb_file], 'actions': [(self.process_image, (src_file, dst_file, thumb_file))], 'clean': True, }
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) try: command = [ 'emacs', '--batch', '-l', join(dirname(abspath(__file__)), 'init.el'), '--eval', '(nikola-html-export "{0}" "{1}")'.format( abspath(source), abspath(dest)) ] # Dirty walkaround for this plugin to run on Windows platform. if os.name == 'nt': command[5] = command[5].replace("\\", "\\\\") subprocess.check_call(command) with io.open(dest, 'r', encoding='utf-8') as inf: output, shortcode_deps = self.site.apply_shortcodes(inf.read(), with_dependencies=True) with io.open(dest, 'w', encoding='utf-8') as outf: outf.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps except OSError as e: import errno if e.errno == errno.ENOENT: req_missing(['emacs', 'org-mode'], 'use the orgmode compiler', python=False) except subprocess.CalledProcessError as e: raise Exception('Cannot compile {0} -- bad org-mode configuration (return code {1})'.format(source, e.returncode))
def compile_html(self, source, dest, is_two_file=True): """Compile source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) with io.open(dest, "w+", encoding="utf8") as out_file: output = self.compile_html_string(source, is_two_file) output = apply_shortcodes(output, self.site.shortcode_registry, self.site, source) out_file.write()
def write_content(cls, filename, content): doc = html.document_fromstring(content) doc.rewrite_links(replacer) utils.makedirs(os.path.dirname(filename)) with open(filename, "wb+") as fd: fd.write(html.tostring(doc, encoding='utf8'))
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) if ODF2XHTML is None: req_missing(['odfpy'], 'build this site (compile odt)') odhandler = ODF2XHTML(True, False) data = odhandler.odf2xhtml(source) # Take the CSS from the head and put it in body doc = etree.fromstring(data) body = doc.find('{http://www.w3.org/1999/xhtml}body') for style in doc.findall('*//{http://www.w3.org/1999/xhtml}style'): style.getparent().remove(style) # keep only classes: filtered = [] for line in style.text.splitlines(): if line and line[0] in '.\t}': filtered.append(line) style.text = ''.join(filtered) body.insert(0, style) with io.open(dest, 'w+', encoding='utf-8') as outf: outf.write(etree.tostring(body, encoding='unicode'))
def create_redirect(src, dst): utils.makedirs(os.path.dirname(src)) with io.open(src, "w+", encoding="utf8") as fd: fd.write('<!DOCTYPE html><head><title>Redirecting...</title>' '<meta name="robots" content="noindex">' '<meta http-equiv="refresh" content="0; ' 'url={0}"></head><body><p>Page moved <a href="{0}">here</a></p></body>'.format(dst))
def generate_css(): # Compass compile for theme_name in self.site.THEMES: theme_root = os.path.abspath(utils.get_theme_path(theme_name)) compass_root = os.path.abspath(os.path.join(theme_root, 'style')) tmp_dir = os.path.abspath(os.path.join(theme_root, '_tmp')) if os.path.exists(compass_root): LOGGER.notice("PYGMENTS CSS CODE") create_code_css(self.site.config['CODE_COLOR_SCHEME'], os.path.join(compass_root, 'css', 'code.css')) LOGGER.notice("COMPASS COMPILE") run('compass clean', cwd=compass_root) run('compass compile', cwd=compass_root) LOGGER.notice("AUTOPREFIXER") LOGGER.notice("CWD: {}".format(theme_root)) run('autoprefixer -o _tmp/all.pre.css _tmp/all.css', cwd=theme_root) LOGGER.notice("CSSO (CSS optimizer)") LOGGER.notice("CWD: {}".format(theme_root)) run('csso _tmp/all.pre.css _tmp/all.min.css', cwd=theme_root) LOGGER.notice("Move CSS to output") css_output_dir = os.path.join(os.path.abspath(self.site.config['OUTPUT_FOLDER']), 'assets', 'css') utils.makedirs(css_output_dir) shutil.copy2(os.path.join(tmp_dir, 'all.min.css'), css_output_dir)
def compile_html(self, source, dest, is_two_file=True): """Compile reSt into HTML.""" if not has_docutils: req_missing(['docutils'], 'build this site (compile REST') makedirs(os.path.dirname(dest)) error_level = 100 with codecs.open(dest, "w+", "utf8") as out_file: with codecs.open(source, "r", "utf8") as in_file: data = in_file.read() if not is_two_file: data = data.split('\n\n', 1)[-1] output, error_level, deps = rst2html( data, settings_overrides={ 'initial_header_level': 2, 'record_dependencies': True, 'stylesheet_path': None, 'link_stylesheet': True, 'syntax_highlight': 'short', 'math_output': 'mathjax', }) out_file.write(output) deps_path = dest + '.dep' if deps.list: with codecs.open(deps_path, "wb+", "utf8") as deps_file: deps_file.write('\n'.join(deps.list)) else: if os.path.isfile(deps_path): os.unlink(deps_path) if error_level == 2: LOGGER.warning('Docutils reports warnings on {0}'.format(source)) if error_level < 3: return True else: return False
def create_post(self, path, **kw): content = kw.pop('content', None) onefile = kw.pop('onefile', False) # is_page is not needed to create the file kw.pop('is_page', False) makedirs(os.path.dirname(path)) if onefile: raise Exception('The one-file format is not supported by this compiler.') with io.open(path, "w+", encoding="utf8") as fd: if not content.startswith("Write your"): fd.write(content) else: fd.write("""{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }""")
def _execute(self, options, args): """Install theme into current site.""" if requests is None: utils.LOGGER.error('This command requires the requests package be installed.') return False listing = options['list'] url = options['url'] if args: name = args[0] else: name = None if name is None and not listing: utils.LOGGER.error("This command needs either a theme name or the -l option.") return False data = requests.get(url).text data = json.loads(data) if listing: print("Themes:") print("-------") for theme in sorted(data.keys()): print(theme) return True else: if name in data: utils.makedirs('themes') utils.LOGGER.notice('Downloading: ' + data[name]) zip_file = BytesIO() zip_file.write(requests.get(data[name]).content) utils.LOGGER.notice('Extracting: {0} into themes'.format(name)) utils.extract_all(zip_file) else: utils.LOGGER.error("Can't find theme " + name) return False
def create_archive_redirect(src, dst): if os.path.exists(src): return utils.makedirs(os.path.dirname(src)) with codecs.open(src, "wb+", "utf8") as fd: fd.write('<!DOCTYPE html><head><title>Redirecting...</title>' '<meta http-equiv="refresh" content="0; ' 'url={0}"></head>'.format(dst))
def process_tree(self, src, dst): """Process all images in a src tree and put the (possibly) rescaled images in the dst folder.""" ignore = set(['.svn']) base_len = len(src.split(os.sep)) for root, dirs, files in os.walk(src, followlinks=True): root_parts = root.split(os.sep) if set(root_parts) & ignore: continue dst_dir = os.path.join(dst, *root_parts[base_len:]) utils.makedirs(dst_dir) for src_name in files: if src_name in ('.DS_Store', 'Thumbs.db'): continue if (not src_name.lower().endswith(tuple(self.image_ext_list)) and not src_name.upper().endswith(tuple(self.image_ext_list))): continue dst_file = os.path.join(dst_dir, src_name) src_file = os.path.join(root, src_name) thumb_file = '.thumbnail'.join(os.path.splitext(dst_file)) yield { 'name': dst_file, 'file_dep': [src_file], 'targets': [dst_file, thumb_file], 'actions': [(self.process_image, (src_file, dst_file, thumb_file))], 'clean': True, }
def process_tree(self, src, dst): """Processes all images in a src tree and put the (possibly) rescaled images in the dst folder.""" ignore = set([".svn"]) base_len = len(src.split(os.sep)) for root, dirs, files in os.walk(src, followlinks=True): root_parts = root.split(os.sep) if set(root_parts) & ignore: continue dst_dir = os.path.join(dst, *root_parts[base_len:]) utils.makedirs(dst_dir) for src_name in files: if src_name in (".DS_Store", "Thumbs.db"): continue if not src_name.lower().endswith(tuple(self.image_ext_list)) and not src_name.upper().endswith( tuple(self.image_ext_list) ): continue dst_file = os.path.join(dst_dir, src_name) src_file = os.path.join(root, src_name) thumb_file = ".thumbnail".join(os.path.splitext(dst_file)) yield { "name": dst_file, "file_dep": [src_file], "targets": [dst_file, thumb_file], "actions": [(self.process_image, (src_file, dst_file, thumb_file))], "clean": True, }
def _execute(self, options, args): """Given a swatch name and a parent theme, creates a custom theme.""" if requests is None: utils.req_missing(["requests"], "install Bootswatch themes") name = options["name"] swatch = options["swatch"] parent = options["parent"] version = "" # See if we need bootswatch for bootstrap v2 or v3 themes = utils.get_theme_chain(parent) if "bootstrap3" not in themes: version = "2" elif "bootstrap" not in themes: LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap') elif "bootstrap3-gradients" in themes or "bootstrap3-gradients-jinja" in themes: LOGGER.warn('"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family') LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent)) utils.makedirs(os.path.join("themes", name, "assets", "css")) for fname in ("bootstrap.min.css", "bootstrap.css"): url = "/".join(("http://bootswatch.com", version, swatch, fname)) LOGGER.info("Downloading: " + url) data = requests.get(url).text with open(os.path.join("themes", name, "assets", "css", fname), "wb+") as output: output.write(data.encode("utf-8")) with open(os.path.join("themes", name, "parent"), "wb+") as output: output.write(parent.encode("utf-8")) LOGGER.notice('Theme created. Change the THEME setting to "{0}" to use it.'.format(name))
def run(self): if matplotlib is None: msg = req_missing(['matplotlib'], 'use the plot directive', optional=True) return [nodes.raw('', '<div class="text-error">{0}</div>'.format(msg), format='html')] if not self.arguments and not self.content: raise self.error('The plot directive needs either an argument or content.') if self.arguments and self.content: raise self.error('The plot directive needs either an argument or content, not both.') if self.arguments: plot_path = self.arguments[0] with io.open(plot_path, encoding='utf-8') as fd: data = fd.read() elif self.content: data = '\n'.join(self.content) plot_path = md5(data).hexdigest() # Always reset context plt.close('all') matplotlib.rc_file_defaults() # Run plot exec(data) out_path = os.path.join(self.out_dir, plot_path + '.svg') plot_url = '/' + os.path.join('pyplots', plot_path + '.svg').replace(os.sep, '/') figures = [manager.canvas.figure for manager in matplotlib._pylab_helpers.Gcf.get_all_fig_managers()] for figure in figures: makedirs(os.path.dirname(out_path)) figure.savefig(out_path, format='svg') # Yes, if there's more than one, it's overwritten, sucks. self.arguments = [plot_url] return super(PyPlot, self).run()
def create_code_css(): from pygments.formatters import get_formatter_by_name formatter = get_formatter_by_name('html', style=kw["code_color_scheme"]) utils.makedirs(os.path.dirname(code_css_path)) with codecs.open(code_css_path, 'wb+', 'utf8') as outf: outf.write(formatter.get_style_defs(kw["code.css_selectors"])) outf.write(kw["code.css_close"])
def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) try: subprocess.check_call(['pandoc', '-o', dest, source] + self.site.config['PANDOC_OPTIONS']) except OSError as e: if e.strreror == 'No such file or directory': req_missing(['pandoc'], 'build this site (compile with pandoc)', python=False)
def create_post(self, path, **kw): """Create a new post.""" content = kw.pop('content', None) onefile = kw.pop('onefile', False) # is_page is not used by create_post as of now. kw.pop('is_page', False) metadata = {} metadata.update(self.default_metadata) metadata.update(kw) if not metadata['description']: # For PHP, a description must be set. Otherwise, Nikola will # take the first 200 characters of the post as the Open Graph # description (og:description meta element)! # If the PHP source leaks there: # (a) The script will be executed multiple times # (b) PHP may encounter a syntax error if it cuts too early, # therefore completely breaking the page # Here, we just use the title. The user should come up with # something better, but just using the title does the job. metadata['description'] = metadata['title'] makedirs(os.path.dirname(path)) if not content.endswith('\n'): content += '\n' with io.open(path, "w+", encoding="utf8") as fd: if onefile: fd.write(write_metadata(metadata, comment_wrap=True, site=self.site, compiler=self)) fd.write(content)
def do_install(self, name, data): if name in data: utils.makedirs(self.output_dir) LOGGER.notice('Downloading: ' + data[name]) zip_file = BytesIO() zip_file.write(requests.get(data[name]).content) LOGGER.notice('Extracting: {0} into themes'.format(name)) utils.extract_all(zip_file) dest_path = os.path.join('themes', name) else: try: theme_path = utils.get_theme_path(name) except: LOGGER.error("Can't find theme " + name) return False utils.makedirs(self.output_dir) dest_path = os.path.join(self.output_dir, name) if os.path.exists(dest_path): LOGGER.error("{0} is already installed".format(name)) return False LOGGER.notice('Copying {0} into themes'.format(theme_path)) shutil.copytree(theme_path, dest_path) confpypath = os.path.join(dest_path, 'conf.py.sample') if os.path.exists(confpypath): LOGGER.notice('This plugin has a sample config file.') print('Contents of the conf.py.sample file:\n') with codecs.open(confpypath, 'rb', 'utf-8') as fh: print(indent(pygments.highlight( fh.read(), PythonLexer(), TerminalFormatter()), 4 * ' ')) return True
def _execute(self, options, args): """Given a swatch name and a parent theme, creates a custom theme.""" if requests is None: utils.req_missing(['requests'], 'install Bootswatch themes') name = options['name'] swatch = options['swatch'] parent = options['parent'] version = '' # See if we need bootswatch for bootstrap v2 or v3 themes = utils.get_theme_chain(parent) if 'bootstrap3' not in themes: version = '2' elif 'bootstrap' not in themes: LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap') LOGGER.notice("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent)) utils.makedirs(os.path.join('themes', name, 'assets', 'css')) for fname in ('bootstrap.min.css', 'bootstrap.css'): url = '/'.join(('http://bootswatch.com', version, swatch, fname)) LOGGER.notice("Downloading: " + url) data = requests.get(url).text with open(os.path.join('themes', name, 'assets', 'css', fname), 'wb+') as output: output.write(data.encode('utf-8')) with open(os.path.join('themes', name, 'parent'), 'wb+') as output: output.write(parent.encode('utf-8')) LOGGER.notice('Theme created. Change the THEME setting to "{0}" to use ' 'it.'.format(name))
def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) with codecs.open(dest, "w+", "utf8") as out_file: with open(source, "rb") as in_file: hash = md5(in_file.read()).hexdigest() out_file.write('<!-- __NIKOLA_PHP_TEMPLATE_INJECTION source:{0} checksum:{1}__ -->'.format(source, hash)) return True
def do_install(self, name, data): if name in data: utils.makedirs(self.output_dir) LOGGER.info("Downloading '{0}'".format(data[name])) zip_file = io.BytesIO() zip_file.write(requests.get(data[name]).content) LOGGER.info("Extracting '{0}' into themes/".format(name)) utils.extract_all(zip_file) dest_path = os.path.join(self.output_dir, name) else: dest_path = os.path.join(self.output_dir, name) try: theme_path = utils.get_theme_path(name) LOGGER.error("Theme '{0}' is already installed in {1}".format(name, theme_path)) except Exception: LOGGER.error("Can't find theme {0}".format(name)) return False confpypath = os.path.join(dest_path, 'conf.py.sample') if os.path.exists(confpypath): LOGGER.notice('This theme has a sample config file. Integrate it with yours in order to make this theme work!') print('Contents of the conf.py.sample file:\n') with io.open(confpypath, 'r', encoding='utf-8') as fh: if self.site.colorful: print(utils.indent(pygments.highlight( fh.read(), PythonLexer(), TerminalFormatter()), 4 * ' ')) else: print(utils.indent(fh.read(), 4 * ' ')) return True
def write_urlmap_csv(output_file, url_map): utils.makedirs(os.path.dirname(output_file)) fmode = 'wb+' if sys.version_info[0] == 2 else 'w+' with io.open(output_file, fmode) as fd: csv_writer = csv.writer(fd) for item in url_map.items(): csv_writer.writerow(item)
def create_post(self, path, **kw): # content and onefile are ignored by ipynb. kw.pop('content', None) onefile = kw.pop('onefile', False) kw.pop('is_page', False) makedirs(os.path.dirname(path)) if onefile: raise Exception('The one-file format is not supported by this compiler.') with io.open(path, "w+", encoding="utf8") as fd: fd.write("""{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }""")
def create_code_css(): from pygments.formatters import get_formatter_by_name formatter = get_formatter_by_name('html', style=kw["code_color_scheme"]) utils.makedirs(os.path.dirname(code_css_path)) with codecs.open(code_css_path, 'wb+', 'utf8') as outf: outf.write(formatter.get_style_defs('pre.code')) outf.write("table.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}")
def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) try: subprocess.check_call(('asciidoc', '-f', 'html', '-s', '-o', dest, source)) except OSError as e: if e.strreror == 'No such file or directory': req_missing(['asciidoc'], 'build this site (compile with asciidoc)', python=False)
def create_post(self, path, **kw): content = kw.pop('content', None) onefile = kw.pop('onefile', False) kw.pop('is_page', False) metadata = OrderedDict() metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write("#+BEGIN_COMMENT\n") if write_metadata: fd.write(write_metadata(metadata)) else: for k, v in metadata.items(): fd.write('.. {0}: {1}\n'.format(k, v)) fd.write("#+END_COMMENT\n") fd.write("\n\n") if content: fd.write(content) else: fd.write('Write your post here.')
def _execute(self, options, args): """Given a swatch name and a parent theme, creates a custom theme.""" name = options['name'] swatch = options['swatch'] if not swatch: LOGGER.error('The -s option is mandatory') return 1 parent = options['parent'] version = '' # See if we need bootswatch for bootstrap v2 or v3 themes = utils.get_theme_chain(parent) if 'bootstrap3' not in themes and 'bootstrap3-jinja' not in themes: version = '2' elif 'bootstrap' not in themes and 'bootstrap-jinja' not in themes: LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap') elif 'bootstrap3-gradients' in themes or 'bootstrap3-gradients-jinja' in themes: LOGGER.warn('"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family') LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent)) utils.makedirs(os.path.join('themes', name, 'assets', 'css')) for fname in ('bootstrap.min.css', 'bootstrap.css'): url = 'https://bootswatch.com' if version: url += '/' + version url = '/'.join((url, swatch, fname)) LOGGER.info("Downloading: " + url) data = requests.get(url).text with open(os.path.join('themes', name, 'assets', 'css', fname), 'wb+') as output: output.write(data.encode('utf-8')) with open(os.path.join('themes', name, 'parent'), 'wb+') as output: output.write(parent.encode('utf-8')) LOGGER.notice('Theme created. Change the THEME setting to "{0}" to use it.'.format(name))
def _commit_and_push(self): """Commit all the files and push.""" source = self.site.config['GITHUB_SOURCE_BRANCH'] deploy = self.site.config['GITHUB_DEPLOY_BRANCH'] remote = self.site.config['GITHUB_REMOTE_NAME'] source_commit = uni_check_output(['git', 'rev-parse', source]) commit_message = ( 'Nikola auto commit.\n\n' 'Source commit: %s' 'Nikola version: %s' % (source_commit, __version__) ) output_folder = self.site.config['OUTPUT_FOLDER'] command = ['ghp-import', '-n', '-m', commit_message, '-p', '-r', remote, '-b', deploy, output_folder] self.logger.info("==> {0}".format(command)) try: subprocess.check_call(command) except subprocess.CalledProcessError as e: self.logger.error( 'Failed GitHub deployment — command {0} ' 'returned {1}'.format(e.cmd, e.returncode) ) return e.returncode self.logger.info("Successful deployment") # Store timestamp of successful deployment timestamp_path = os.path.join(self.site.config["CACHE_FOLDER"], "lastdeploy") new_deploy = datetime.utcnow() makedirs(self.site.config["CACHE_FOLDER"]) with io.open(timestamp_path, "w+", encoding="utf8") as outf: outf.write(unicode_str(new_deploy.isoformat()))
def create_post(self, path, onefile=False, **kw): if OrderedDict is not None: metadata = OrderedDict() else: metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write('<!-- \n') for k, v in metadata.items(): fd.write('.. {0}: {1}\n'.format(k, v)) fd.write('-->\n\n') fd.write("Write your post here.")
def create_post(self, path, **kw): content = kw.pop('content', None) onefile = kw.pop('onefile', False) # is_page is not used by create_post as of now. kw.pop('is_page', False) metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if not content.endswith('\n'): content += '\n' with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write(write_metadata(metadata)) fd.write('\n' + content)
def do_install(self, name, data): """Download and install a theme.""" if name in data: utils.makedirs(self.output_dir) url = data[name] LOGGER.info("Downloading '{0}'".format(url)) try: zip_data = requests.get(url).content except requests.exceptions.SSLError: LOGGER.warning( "SSL error, using http instead of https (press ^C to abort)" ) time.sleep(1) url = url.replace('https', 'http', 1) zip_data = requests.get(url).content zip_file = io.BytesIO() zip_file.write(zip_data) LOGGER.info("Extracting '{0}' into themes/".format(name)) utils.extract_all(zip_file) dest_path = os.path.join(self.output_dir, name) else: dest_path = os.path.join(self.output_dir, name) try: theme_path = utils.get_theme_path_real(name, self.site.themes_dirs) LOGGER.error("Theme '{0}' is already installed in {1}".format( name, theme_path)) except Exception: LOGGER.error("Can't find theme {0}".format(name)) return False confpypath = os.path.join(dest_path, 'conf.py.sample') if os.path.exists(confpypath): LOGGER.notice( 'This theme has a sample config file. Integrate it with yours in order to make this theme work!' ) print('Contents of the conf.py.sample file:\n') with io.open(confpypath, 'r', encoding='utf-8') as fh: if self.site.colorful: print( utils.indent( pygments.highlight(fh.read(), PythonLexer(), TerminalFormatter()), 4 * ' ')) else: print(utils.indent(fh.read(), 4 * ' ')) return True
def write_metadata(filename, title, slug, post_date, description, tags, **kwargs): if not description: description = "" utils.makedirs(os.path.dirname(filename)) with io.open(filename, "w+", encoding="utf8") as fd: data = { 'title': title, 'slug': slug, 'date': post_date, 'tags': ','.join(tags), 'description': description } data.update(kwargs) fd.write(utils.write_metadata(data))
def set_directories(self, directories, cache_folder): """Create a new template lookup with set directories.""" if jinja2 is None: req_missing(['jinja2'], 'use this theme') cache_folder = os.path.join(cache_folder, 'jinja') makedirs(cache_folder) cache = jinja2.FileSystemBytecodeCache(cache_folder) self.lookup = jinja2.Environment(bytecode_cache=cache) self.lookup.trim_blocks = True self.lookup.lstrip_blocks = True self.lookup.filters['tojson'] = json.dumps self.lookup.globals['enumerate'] = enumerate self.lookup.globals['isinstance'] = isinstance self.lookup.globals['tuple'] = tuple self.directories = directories self.create_lookup()
def create_post(self, path, **kw): content = kw.pop('content', 'Write your post here.') onefile = kw.pop('onefile', False) kw.pop('is_page', False) metadata = OrderedDict() metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if not content.endswith('\n'): content += '\n' with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write('<notextile> <!--\n') fd.write(write_metadata(metadata)) fd.write('--></notextile>\n\n') fd.write(content)
def create_post(self, path, content=None, onefile=False, is_page=False, **kw): content = kw.pop('content', None) onefile = kw.pop('onefile', False) kw.pop('is_page', False) metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if not content.endswith('\n'): content += '\n' with io.open(path, "w+", encoding="utf8") as fd: if onefile: fd.write(write_metadata(metadata)) fd.write('\n') fd.write(content)
def create_post(self, path, **kw): """Create a new post.""" content = kw.pop('content', None) onefile = kw.pop('onefile', False) # is_page is not used by create_post as of now. kw.pop('is_page', False) metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if not content.endswith('\n'): content += '\n' with io.open(path, "w+", encoding="utf-8") as fd: if onefile: fd.write(write_metadata(metadata, comment_wrap=False, site=self.site, compiler=self)) fd.write(content)
def compile(self, source, dest, is_two_file=False, post=None, lang=None): """Compile the source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) with io.open(dest, "w+", encoding="utf8") as out_file: with io.open(source, "r", encoding="utf8") as in_file: nb_str = in_file.read() output, shortcode_deps = self.compile_string( nb_str, is_two_file, post, lang) out_file.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps
def download_additional_image_sizes(self, item, wordpress_namespace, source_path): if phpserialize is None: return additional_metadata = item.findall('{{{0}}}postmeta'.format(wordpress_namespace)) if additional_metadata is None: return for element in additional_metadata: meta_key = element.find('{{{0}}}meta_key'.format(wordpress_namespace)) if meta_key is not None and meta_key.text == '_wp_attachment_metadata': meta_value = element.find('{{{0}}}meta_value'.format(wordpress_namespace)) if meta_value is None: continue # Someone from Wordpress thought it was a good idea # serialize PHP objects into that metadata field. Given # that the export should give you the power to insert # your blogging into another site or system its not. # Why don't they just use JSON? if sys.version_info[0] == 2: metadata = phpserialize.loads(utils.sys_encode(meta_value.text)) size_key = 'sizes' file_key = 'file' else: metadata = phpserialize.loads(meta_value.text.encode('UTF-8')) size_key = b'sizes' file_key = b'file' if not size_key in metadata: continue for filename in [metadata[size_key][size][file_key] for size in metadata[size_key]]: url = '/'.join([source_path, filename.decode('utf-8')]) path = urlparse(url).path dst_path = os.path.join(*([self.output_folder, 'files'] + list(path.split('/')))) dst_dir = os.path.dirname(dst_path) utils.makedirs(dst_dir) LOGGER.info("Downloading {0} => {1}".format(url, dst_path)) self.download_url_content_to_file(url, dst_path) dst_url = '/'.join(dst_path.split(os.sep)[2:]) links[url] = '/' + dst_url links[url] = '/' + dst_url
def gallery_rss(self, img_list, dest_img_list, img_titles, lang, permalink, output_path, title): """Create a RSS showing the latest images in the gallery. This doesn't use generic_rss_renderer because it doesn't involve Post objects. """ def make_url(url): return urljoin(self.site.config['BASE_URL'], url.lstrip('/')) items = [] for img, srcimg, title in list(zip( dest_img_list, img_list, img_titles))[:self.kw["feed_length"]]: img_size = os.stat( os.path.join(self.site.config['OUTPUT_FOLDER'], img)).st_size args = { 'title': title, 'link': make_url(img), 'guid': rss.Guid(img, False), 'pubDate': self.image_date(srcimg), 'enclosure': rss.Enclosure(make_url(img), img_size, mimetypes.guess_type(img)[0]), } items.append(rss.RSSItem(**args)) rss_obj = rss.RSS2(title=title, link=make_url(permalink), description='', lastBuildDate=datetime.datetime.utcnow(), items=items, generator='http://getnikola.com/', language=lang) rss_obj.rss_attrs["xmlns:dc"] = "http://purl.org/dc/elements/1.1/" rss_obj.self_url = make_url(permalink) rss_obj.rss_attrs["xmlns:atom"] = "http://www.w3.org/2005/Atom" dst_dir = os.path.dirname(output_path) utils.makedirs(dst_dir) with io.open(output_path, "w+", encoding="utf-8") as rss_file: data = rss_obj.to_xml(encoding='utf-8') if isinstance(data, utils.bytes_str): data = data.decode('utf-8') rss_file.write(data)
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" if not has_docutils: req_missing(['docutils'], 'build this site (compile reStructuredText)') if not has_rst2html5: req_missing(['rst2html5'], 'build this site (compile reStructuredText into HTML5)') makedirs(os.path.dirname(dest)) error_level = 100 with io.open(dest, "w+", encoding="utf8") as out_file: with io.open(source, "r", encoding="utf8") as in_file: data = in_file.read() add_ln = 0 if not is_two_file: spl = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1) data = spl[-1] if len(spl) != 1: # If errors occur, this will be added to the line # number reported by docutils so the line number # matches the actual line number (off by 7 with default # metadata, could be more or less depending on the post # author). add_ln = len(spl[0].splitlines()) + 1 default_template_path = os.path.join(os.path.dirname(__file__), 'template.txt') output, error_level, deps = rst2html( data, settings_overrides={ 'initial_header_level': 0, 'record_dependencies': True, 'stylesheet_path': None, 'link_stylesheet': True, 'syntax_highlight': 'short', 'math_output': 'mathjax', 'template': default_template_path, }, logger=self.logger, source_path=source, l_add_ln=add_ln) out_file.write(output) deps_path = dest + '.dep' if deps.list: with io.open(deps_path, "w+", encoding="utf8") as deps_file: deps_file.write('\n'.join(deps.list)) else: if os.path.isfile(deps_path): os.unlink(deps_path) if error_level < 3: return True else: return False
def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) if mw is None: req_missing(['smc.mw'], 'build this site (compile with MediaWiki)', python=True) with io.open(dest, "w+", encoding="utf8") as out_file: with io.open(source, "r", encoding="utf8") as in_file: data = in_file.read() if not is_two_file: data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1] parser = mw.Parser(parseinfo=False, whitespace='', nameguard=False) ast = parser.parse(data, 'document', semantics=mw.Semantics(parser)) output = etree.tostring(ast, encoding='utf8').decode('utf8') out_file.write(output)
def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) try: command = [ 'emacs', '--batch', '-l', join(dirname(abspath(__file__)), 'init.el'), '--eval', '(nikola-html-export "{0}" "{1}")'.format( abspath(source), abspath(dest)) ] # Dirty walkaround for this plugin to run on Windows platform. if os.name == 'nt': command[5] = command[5].replace("\\", "\\\\") subprocess.check_call(command) try: post = self.site.post_per_input_file[source] except KeyError: post = None with io.open(dest, 'r', encoding='utf-8') as inf: output, shortcode_deps = self.site.apply_shortcodes( inf.read(), with_dependencies=True) output = self.adjust_pretty_urls(output) with io.open(dest, 'w', encoding='utf-8') as outf: outf.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} due to unregistered source file name", source) else: post._depfile[dest] += shortcode_deps except OSError as e: import errno if e.errno == errno.ENOENT: req_missing(['emacs', 'org-mode'], 'use the orgmode compiler', python=False) except subprocess.CalledProcessError as e: raise Exception('Cannot compile {0} -- bad org-mode ' 'configuration (return code {1})'.format( source, e.returncode))
def create_post(self, path, **kw): """Create a new post.""" content = kw.pop("content", None) onefile = kw.pop("onefile", False) if onefile: self.logger.warning( "The observable compiler only supports two-file format.") # is_page is not used by create_post as of now. kw.pop("is_page", False) metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if not content.endswith("\n"): content += "\n" with io.open(path, "w+", encoding="utf8") as fd: fd.write(content)
def _execute(self, options, args): """Given a swatch name and a parent theme, creates a custom theme.""" name = options['name'] swatch = options['swatch'] if not swatch: LOGGER.error('The -s option is mandatory') return 1 parent = options['parent'] version = '' # See if we need bootswatch for bootstrap v2 or v3 themes = utils.get_theme_chain(parent) if 'bootstrap3' not in themes and 'bootstrap3-jinja' not in themes: version = '2' elif 'bootstrap' not in themes and 'bootstrap-jinja' not in themes: LOGGER.warn( '"bootswatch_theme" only makes sense for themes that use bootstrap' ) elif 'bootstrap3-gradients' in themes or 'bootstrap3-gradients-jinja' in themes: LOGGER.warn( '"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family' ) LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format( name, swatch, parent)) utils.makedirs(os.path.join('themes', name, 'assets', 'css')) for fname in ('bootstrap.min.css', 'bootstrap.css'): url = 'https://bootswatch.com' if version: url += '/' + version url = '/'.join((url, swatch, fname)) LOGGER.info("Downloading: " + url) r = requests.get(url) if r.status_code > 299: LOGGER.error('Error {} getting {}', r.status_code, url) exit(1) data = r.text with open(os.path.join('themes', name, 'assets', 'css', fname), 'wb+') as output: output.write(data.encode('utf-8')) with open(os.path.join('themes', name, 'parent'), 'wb+') as output: output.write(parent.encode('utf-8')) LOGGER.notice( 'Theme created. Change the THEME setting to "{0}" to use it.'. format(name))
def record_post(self, output_path, post, lang): workdir = tempfile.mkdtemp() utils.makedirs(os.path.dirname(output_path)) # Intro text introfile = os.path.join(workdir, 'intro.wav') if 'NETCAST_INTRO' in self.site.config: introtext = self.site.config['NETCAST_INTRO'][lang].format(title=post.title(lang=lang), author=post.author(lang=lang), date=post.formatted_date("%A, %d. %B %Y"), permalink=self.site.abs_link(post.permalink()).split('//', 1)[1]) else: introtext = self.default_text_intro.format(title=post.title(lang=lang), author=post.author(lang=lang), date=post.formatted_date("%A, %d. %B %Y"), permalink=self.site.abs_link(post.permalink()).split('//', 1)[1]) self.record_wave(lang, introfile, introtext, False, False) # Post text postfile = os.path.join(workdir, 'text.wav') posttextfile = os.path.join(workdir, 'text.txt') with codecs.open(posttextfile, 'wb+', 'utf8') as outf: outf.write(post.text(lang=lang, teaser_only=False, strip_html=False, show_read_more_link=False)) self.record_wave(lang, postfile, False, posttextfile, False) # Outro outrofile = os.path.join(workdir, 'outro.wav') if 'NETCAST_OUTRO' in self.site.config: outrotext = self.site.config['NETCAST_OUTRO'][lang].format(title=post.title(lang=lang), author=post.author(lang=lang), date=post.formatted_date("%A, %d. %B %Y"), permalink=self.site.abs_link(post.permalink()).split('//', 1)[1]) else: outrotext = self.default_text_outro.format(title=post.title(lang=lang), author=post.author(lang=lang), date=post.formatted_date("%A, %d. %B %Y"), permalink=self.site.abs_link(post.permalink()).split('//', 1)[1]) self.record_wave(lang, outrofile, outrotext, False, True) # Combined recording command = "sox {0} -p pad 0 0.8 | sox - {1} -p pad 0 0.8 | sox - {2} -p pad 0 1.2 | sox - -C 0 {3}".format(introfile, postfile, outrofile, output_path) os.system(command) shutil.rmtree(workdir) # cleanup the tempdir return output_path
def compile_html(self, source, dest, is_two_file=True): """Compile source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) try: subprocess.check_call(['pandoc', '-o', dest, source] + self.site.config['PANDOC_OPTIONS']) with open(dest, 'r', encoding='utf-8') as inf: output = apply_shortcodes(inf.read(), self.site.shortcode_registry, self.site, source) with open(dest, 'w', encoding='utf-8') as outf: outf.write(output) except OSError as e: if e.strreror == 'No such file or directory': req_missing(['pandoc'], 'build this site (compile with pandoc)', python=False)
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" if Markdown is None: req_missing(['markdown'], 'build this site (compile Markdown)') makedirs(os.path.dirname(dest)) with io.open(dest, "w+", encoding="utf8") as out_file: with io.open(source, "r", encoding="utf8") as in_file: data = in_file.read() output, shortcode_deps = self.compile_string(data, source, is_two_file, post, lang) out_file.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps
def create_post(self, path, **kw): """Create a new post.""" self._req_missing_ipynb() content = kw.pop('content', None) onefile = kw.pop('onefile', False) kernel = kw.pop('jupyter_kernel', None) # is_page is not needed to create the file kw.pop('is_page', False) metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if content.startswith("{"): # imported .ipynb file, guaranteed to start with "{" because it’s JSON. nb = nbformat.reads(content, current_nbformat) else: nb = nbformat.v4.new_notebook() nb["cells"] = [nbformat.v4.new_markdown_cell(content)] if kernel is None: kernel = self.default_kernel self.logger.notice('No kernel specified, assuming "{0}".'.format(kernel)) IPYNB_KERNELS = {} ksm = kernelspec.KernelSpecManager() for k in ksm.find_kernel_specs(): IPYNB_KERNELS[k] = ksm.get_kernel_spec(k).to_dict() IPYNB_KERNELS[k]['name'] = k del IPYNB_KERNELS[k]['argv'] if kernel not in IPYNB_KERNELS: self.logger.error('Unknown kernel "{0}". Maybe you mispelled it?'.format(kernel)) self.logger.info("Available kernels: {0}".format(", ".join(sorted(IPYNB_KERNELS)))) raise Exception('Unknown kernel "{0}"'.format(kernel)) nb["metadata"]["kernelspec"] = IPYNB_KERNELS[kernel] if onefile: nb["metadata"]["nikola"] = metadata with io.open(path, "w+", encoding="utf8") as fd: nbformat.write(nb, fd, 4)
def create_post(self, path, content=None, onefile=False, is_page=False, **kw): """Create post file with optional metadata.""" metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if not content.endswith('\n'): content += '\n' with io.open(path, "w+", encoding="utf8") as fd: if onefile: fd.write(write_metadata(metadata)) fd.write('\n\n') fd.write(content)
def write_metadata(self, filename, title, slug, post_date, description, tags, **kwargs): """Write metadata to meta file.""" if not description: description = "" utils.makedirs(os.path.dirname(filename)) with io.open(filename, "w+", encoding="utf8") as fd: data = { 'title': title, 'slug': slug, 'date': post_date, 'tags': ','.join(tags), 'description': description } data.update(kwargs) fd.write( utils.write_metadata(data, site=self.site, comment_wrap=False))
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" if txt2tags is None: req_missing(['txt2tags'], 'build this site (compile txt2tags)') makedirs(os.path.dirname(dest)) cmd = ["-t", "html", "--no-headers", "--outfile", dest, source] txt2tags(cmd) with open(dest, 'r', encoding='utf-8') as inf: output, shortcode_deps = self.site.apply_shortcodes(inf.read()) with open(dest, 'w', encoding='utf-8') as outf: outf.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) with io.open(dest, "w+", encoding="utf8") as out_file: with io.open(source, "r", encoding="utf8") as in_file: data = in_file.read() if not is_two_file: _, data = self.split_metadata(data) data, shortcode_deps = self.site.apply_shortcodes(data, with_dependencies=True, extra_context=dict(post=post)) out_file.write(data) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps return True
def compile_html(self, source, dest, is_two_file=False): makedirs(os.path.dirname(dest)) with io.open(dest, "w+", encoding="utf8") as out_file: # Read post with io.open(source, "r", encoding="utf8") as in_file: data = in_file.read() if not is_two_file: data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1] # Read additional data additional_data, dependent_files = self.load_additional_data(source) # Process post context = Context(hash(data), name=source, additional_data=additional_data) for filename in dependent_files: context.add_file_dependency(filename, 'fragment') output = self.__formatData(data, context) # Write result out_file.write(output) self._write_deps(context, dest)
def compile(self, source, dest, is_two_file=False, post=None, lang=None): """Compile the source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) with io.open(dest, "w+", encoding="utf8") as out_file: output = self.compile_string(source, is_two_file) output, shortcode_deps = self.site.apply_shortcodes( output, filename=source, with_dependencies=True, extra_context=dict(post=post)) out_file.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps
def create_post(self, path, content=None, onefile=False, is_page=False, **kw): """Create post file with optional metadata.""" metadata = OrderedDict() metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) if not content.endswith("\n"): content += "\n" with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write("<!--\n") fd.write(write_metadata(metadata).rstrip()) fd.write("\n-->\n\n") fd.write(content)
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) with codecs.open(source, "rb+", "utf8") as in_f: with codecs.open(dest, "wb+", "utf8") as out_f: data = in_f.read() if not is_two_file: spl = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1) data = spl[-1] output = m2h.markmin2html(data, pretty_print=True) output, shortcode_deps = self.site.apply_shortcodes(output, filename=source, with_dependencies=True, extra_context=dict(post=post)) out_f.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps
def import_attachment(self, item, wordpress_namespace): url = get_text_tag(item, '{{{0}}}attachment_url'.format(wordpress_namespace), 'foo') link = get_text_tag(item, '{{{0}}}link'.format(wordpress_namespace), 'foo') path = urlparse(url).path dst_path = os.path.join(*([self.output_folder, 'files'] + list(path.split('/')))) dst_dir = os.path.dirname(dst_path) utils.makedirs(dst_dir) LOGGER.info("Downloading {0} => {1}".format(url, dst_path)) self.download_url_content_to_file(url, dst_path) dst_url = '/'.join(dst_path.split(os.sep)[2:]) links[link] = '/' + dst_url links[url] = '/' + dst_url self.download_additional_image_sizes(item, wordpress_namespace, os.path.dirname(url))
def compile(self, source, dest, is_two_file=True, post=None, lang=None): """Compile the source file into HTML and save as dest.""" makedirs(os.path.dirname(dest)) try: subprocess.check_call(['pandoc', '-o', dest, source] + self._get_pandoc_options(source)) with open(dest, 'r', encoding='utf-8-sig') as inf: output, shortcode_deps = self.site.apply_shortcodes(inf.read()) with open(dest, 'w', encoding='utf-8') as outf: outf.write(output) if post is None: if shortcode_deps: self.logger.error( "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += shortcode_deps except OSError as e: if e.strreror == 'No such file or directory': req_missing(['pandoc'], 'build this site (compile with pandoc)', python=False)