def header(renderer, text, level, raw): anchor_type = self.get_config().get('anchor-type') if anchor_type == "random": anchor = uuid.uuid4().hex[:6] elif anchor_type == "custom": # Extract custom anchor from origin header. # The header should match the syntax: # `text (#anchor)`, # if matched, text and anchor get the value respectively, # otherwise fallback to slugify function. # # Firstly, this syntax give the user the ability to # customize the TOC anchor link. # `# How Lektor Works (#anchor-text)` renders to # <h1 id="anchor-text">How Lektor Works</h1> # # However this is a pretty workaround and useful way for # those non-ascii languages, such as CJK to use the # custom anchor as the slug. # `# 中文标题 (#chinese-title)` renders to # <h1 id="chinese-title">中文标题</h1> match = re.search(r'(.*)\(#(.*)\)', text) if match: text, anchor = match.groups() anchor = anchor.replace(' ', '') else: anchor = slugify(raw) else: anchor = slugify(raw) renderer.meta['toc'].append((level, anchor, Markup(text))) return '<h%d id="%s">%s</h%d>' % (level, anchor, text, level)
def test_slugify(): from lektor.utils import slugify assert slugify("w o w") == "w-o-w" assert slugify(u"Șö prĕtty") == "so-pretty" assert slugify("im age.jpg") == "im-age.jpg" assert slugify("slashed/slug") == "slashed/slug"
def header(renderer, text, level, raw): if self.get_config().get('anchor-type') == "random": anchor = uuid.uuid4().hex[:6] else: anchor = slugify(raw) renderer.meta['toc'].append((level, anchor, Markup(text))) return '<h%d id="%s">%s</h%d>' % (level, anchor, text, level)
def get_slug(self, source): slug_expr = self.slug_expr if slug_expr is None: slug = source._id else: slug = str(slug_expr.__get__(source)) return slugify(slug)
def _meetup_to_lektor_id(data): """""" local_date = data.get('local_date', '') name = data.get('name', '') _name = unidecode(name) for key, val in _REPLACE.items(): _name = _name.replace(key, val) _name = slugify(_name) id_ = local_date + '-' + _name date_part = '/'.join(local_date.split('-')[:-1]) slug = date_part + '/' + _name if id_ not in _ID_CACHE: _ID_CACHE[id_] = 0 final_id = id_ else: _ID_CACHE[id_] += 1 final_id = id_ + '-' + str(_ID_CACHE[id_]) if slug not in _SLUG_CACHE: _SLUG_CACHE[slug] = 0 final_slug = slug[:] else: _SLUG_CACHE[slug] += 1 if slug not in SLUG_WARNING_IGNORE: print(slug) final_slug = slug + '-' + str(_SLUG_CACHE[slug]) return final_id, final_slug
def header(renderer, text, level, raw): anchor = slugify(raw) renderer.meta['toc'].append((level, anchor, Markup(text))) return u'<h{level:d} id="{anchor}">{text}</h{level:d}>'.format( level=renderer.adjusted_header_level(level), anchor=anchor, text=text, )
def get_default_child_slug(self, pad, data): """Formats out the child slug.""" slug_format = self.child_config.slug_format if slug_format is None: return slugify(data['_id']) if self._child_slug_tmpl is None or \ self._child_slug_tmpl[0] != slug_format: self._child_slug_tmpl = (slug_format, FormatExpression(self.env, slug_format)) try: return '_'.join(self._child_slug_tmpl[1].evaluate( pad, this=data).strip().split()).strip('/') except Exception: # XXX: log return 'temp-' + slugify(data['_id'])
def project_quickstart(defaults=None): if not defaults: defaults = {} g = Generator('project') g.title('Lektor Quickstart') g.text( 'This wizard will generate a new basic project with some sensible ' 'defaults for getting started quickly. We just need to go through ' 'a few questions so that the project is set up correctly for you.' ) name = defaults.get('name') if name is None: name = g.prompt('Project Name', None, 'A project needs a name. The name is primarily used for the admin ' 'UI and some other places to refer to your project to not get ' 'confused if multiple projects exist. You can change this at ' 'any later point.') author_name = g.prompt('Author Name', get_default_author(), 'Your name. This is used in a few places in the default template ' 'to refer to in the default copyright messages.') path = defaults.get('path') if path is None: here = os.path.abspath(os.getcwd()) default_project_path = None try: if len(os.listdir(here)) == []: default_project_path = here except OSError: pass if default_project_path is None: default_project_path = os.path.join(os.getcwd(), name) path = g.prompt('Project Path', default_project_path, 'This is the path where the project will be located. You can ' 'move a project around later if you do not like the path. If ' 'you provide a relative path it will be relative to the working ' 'directory.') path = os.path.expanduser(path) with_blog = g.prompt('Add Basic Blog', True, 'Do you want to generate a basic blog module? If you enable this ' 'the models for a very basic blog will be generated.') g.confirm('That\'s all. Create project?') g.run({ 'project_name': name, 'project_slug': slugify(name), 'project_path': path, 'with_blog': with_blog, 'this_year': datetime.utcnow().year, 'today': datetime.utcnow().strftime('%Y-%m-%d'), 'author_name': author_name, }, path)
def get_default_child_slug(self, pad, data): """Formats out the child slug.""" slug_format = self.child_config.slug_format if slug_format is None: return slugify(data['_id']) if self._child_slug_tmpl is None or \ self._child_slug_tmpl[0] != slug_format: self._child_slug_tmpl = ( slug_format, FormatExpression(self.env, slug_format) ) try: return '_'.join(self._child_slug_tmpl[1].evaluate( pad, this=data).strip().split()).strip('/') except Exception: # XXX: log return 'temp-' + slugify(data['_id'])
def publish(self, target_url, credentials=None, server_info=None, **extra): draft = '--draft' in click.get_current_context().args host = target_url.host if credentials and credentials.get('key'): access_token = credentials['key'] elif server_info and server_info.extra.get('key'): access_token = server_info.extra['key'] else: raise RuntimeError( "Use lektor deploy --key <ACCESS_TOKEN>," " see https://github.com/ajdavis/lektor-netlify/README.md") sites_url = ( 'https://api.netlify.com/api/v1/sites?access_token=' + access_token) response = requests.get( sites_url, headers={'User-Agent': 'https://github.com/ajdavis/lektor-netlify'}) response.raise_for_status() j = response.json() for site in j: site_url = urls.url_parse(unicode(site['url'])) if site_url.host == host: site_id = site['site_id'] break else: site_name = slugify(host).replace('.', '-') force_ssl = bool_from_string(server_info.extra.get('force_ssl'), default=False) print('Creating new Netlify site "%s" at %s' % (site_name, host)) response = requests.post(sites_url, { 'name': site_name, 'custom_domain': host, 'force_ssl': force_ssl}) response.raise_for_status() site_id = response.json()['site_id'] cmd = [ 'netlify', 'deploy', '--auth', access_token, '--site', site_id, '--dir', self.output_path] if draft: yield "Deploying as draft" else: cmd.append('--prod') for line in Command(cmd): yield line
def publish(self, target_url, credentials=None, server_info=None, **extra): draft = '--draft' in click.get_current_context().args host = target_url.host if credentials and credentials.get('key'): access_token = credentials['key'] elif server_info and server_info.extra.get('key'): access_token = server_info.extra['key'] else: raise RuntimeError( "Use lektor deploy --key <ACCESS_TOKEN>," " see https://github.com/ajdavis/lektor-netlify/README.md") sites_url = ( 'https://api.netlify.com/api/v1/sites?access_token=' + access_token) response = requests.get( sites_url, headers={'User-Agent': 'https://github.com/ajdavis/lektor-netlify'}) response.raise_for_status() j = response.json() for site in j: site_url = urls.url_parse(unicode(site['url'])) if site_url.host == host: site_id = site['site_id'] break else: site_name = slugify(host).replace('.', '-') force_ssl = bool_from_string(server_info.extra.get('force_ssl'), default=False) print('Creating new Netlify site "%s" at %s' % (site_name, host)) response = requests.post(sites_url, { 'name': site_name, 'custom_domain': host, 'force_ssl': force_ssl}) response.raise_for_status() site_id = response.json()['site_id'] cmd = [ 'netlify', '-t', access_token, 'deploy', '-s', site_id, '-p', self.output_path] if draft: yield "Deploying as draft" cmd.append('--draft') for line in Command(cmd): yield line
def plugin_quickstart(defaults=None, project=None): if defaults is None: defaults = {} g = Generator('plugin') plugin_name = defaults.get('plugin_name') if plugin_name is None: plugin_name = g.prompt( 'Plugin Name', default=None, info='This is the human readable name for this plugin') plugin_id = plugin_name.lower() # pylint: disable=no-member if plugin_id.startswith('lektor'): plugin_id = plugin_id[6:] if plugin_id.endswith('plugin'): plugin_id = plugin_id[:-6] plugin_id = slugify(plugin_id) path = defaults.get('path') if path is None: if project is not None: default_path = os.path.join(project.tree, 'packages', plugin_id) else: if len(os.listdir('.')) == 0: default_path = os.getcwd() else: default_path = os.path.join(os.getcwd(), plugin_id) path = g.prompt('Plugin Path', default_path, 'The place where you want to initialize the plugin') author_name = g.prompt( 'Author Name', get_default_author(), 'Your name as it will be embedded in the plugin metadata.') author_email = g.prompt('Author E-Mail', get_default_author_email(), 'Your e-mail address for the plugin info.') g.confirm('Create Plugin?') g.run( { 'plugin_name': plugin_name, 'plugin_id': plugin_id, 'plugin_class': plugin_id.title().replace('-', '') + 'Plugin', 'plugin_module': 'lektor_' + plugin_id.replace('-', '_'), 'author_name': author_name, 'author_email': author_email, }, path)
def plugin_quickstart(defaults=None, project=None): if defaults is None: defaults = {} g = Generator('plugin') plugin_name = defaults.get('plugin_name') if plugin_name is None: plugin_name = g.prompt('Plugin Name', default=None, info='This is the human readable name for this plugin') plugin_id = plugin_name.lower() # pylint: disable=no-member if plugin_id.startswith('lektor'): plugin_id = plugin_id[6:] if plugin_id.endswith('plugin'): plugin_id = plugin_id[:-6] plugin_id = slugify(plugin_id) path = defaults.get('path') if path is None: if project is not None: default_path = os.path.join(project.tree, 'packages', plugin_id) else: if len(os.listdir('.')) == 0: default_path = os.getcwd() else: default_path = os.path.join(os.getcwd(), plugin_id) path = g.prompt('Plugin Path', default_path, 'The place where you want to initialize the plugin') author_name = g.prompt('Author Name', get_default_author(), 'Your name as it will be embedded in the plugin metadata.') author_email = g.prompt('Author E-Mail', get_default_author_email(), 'Your e-mail address for the plugin info.') g.confirm('Create Plugin?') g.run({ 'plugin_name': plugin_name, 'plugin_id': plugin_id, 'plugin_class': plugin_id.title().replace('-', '') + 'Plugin', 'plugin_module': 'lektor_' + plugin_id.replace('-', '_'), 'author_name': author_name, 'author_email': author_email, }, path)
def get_default_child_slug(self, pad, data): """Formats out the child slug.""" slug_format = self.child_config.slug_format if slug_format is None: return data["_id"] if self._child_slug_tmpl is None or self._child_slug_tmpl[ 0] != slug_format: self._child_slug_tmpl = ( slug_format, FormatExpression(self.env, slug_format), ) try: return "_".join(self._child_slug_tmpl[1].evaluate( pad, this=data).strip().split()).strip("/") except Exception: # XXX: log return "temp-" + slugify(data["_id"])
def get_default_child_slug(self, pad, data): """Formats out the child slug.""" slug_format = self.child_config.slug_format if slug_format is None: return data["_id"] if self._child_slug_tmpl is None or self._child_slug_tmpl[ 0] != slug_format: self._child_slug_tmpl = ( slug_format, FormatExpression(self.env, slug_format), ) try: return "_".join(self._child_slug_tmpl[1].evaluate( pad, this=data).strip().split()).strip("/") except Exception as exc: reporter.report_generic("Failed to expand child slug_format: %s" % exc) return "temp-" + slugify(data["_id"])
def header(renderer, text, level, raw): anchor = slugify(raw) renderer.meta['toc'].append((level, anchor, Markup(text))) return '<h%d id="%s">%s</h%d>' % (level, anchor, text, level)
def value_from_raw(self, raw): if raw.value is None: return raw.missing_value('Missing slug') return slugify(raw.value)
def theme_quickstart(defaults=None, project=None): if defaults is None: defaults = {} g = Generator("theme") theme_name = defaults.get("theme_name") if theme_name is None: theme_name = g.prompt( "Theme Name", default=None, info="This is the human readable name for this theme", ) theme_id = theme_name.lower() # pylint: disable=no-member if theme_id != "lektor" and theme_id.startswith("lektor"): theme_id = theme_id[6:].strip() if theme_id != "theme" and theme_id.startswith("theme"): theme_id = theme_id[5:] if theme_id != "theme" and theme_id.endswith("theme"): theme_id = theme_id[:-5] theme_id = slugify(theme_id) path = defaults.get("path") if path is None: if project is not None: default_path = os.path.join(project.tree, "themes", "lektor-theme-{}".format(theme_id)) else: if len(os.listdir(".")) == 0: default_path = os.getcwd() else: default_path = os.path.join(os.getcwd(), theme_id) path = g.prompt( "Theme Path", default_path, "The place where you want to initialize the theme", ) author_name = g.prompt( "Author Name", get_default_author(), "Your name as it will be embedded in the theme metadata.", ) author_email = g.prompt( "Author E-Mail", get_default_author_email(), "Your e-mail address for the theme info.", ) g.confirm("Create Theme?") g.run( { "theme_name": theme_name, "theme_id": theme_id, "author_name": author_name, "author_email": author_email, }, path, ) # symlink theme_dir = os.getcwd() example_themes = os.path.join(path, "example-site/themes") os.makedirs(example_themes) os.chdir(example_themes) try: os.symlink( "../../../lektor-theme-{}".format(theme_id), "lektor-theme-{}".format(theme_id), ) except AttributeError: g.warn( "Could not automatically make a symlink to have your example-site" "easily pick up your theme.") os.chdir(theme_dir) # Sample image os.makedirs(os.path.join(path, "images")) source_image_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), "quickstart-templates/theme/images/homepage.png", ) destination_image_path = os.path.join(path, "images/homepage.png") with open(source_image_path, "rb") as f: image = f.read() with open(destination_image_path, "wb") as f: f.write(image)
def plugin_quickstart(defaults=None, project=None): if defaults is None: defaults = {} g = Generator("plugin") plugin_name = defaults.get("plugin_name") if plugin_name is None: plugin_name = g.prompt( "Plugin Name", default=None, info="This is the human readable name for this plugin", ) plugin_id = plugin_name.lower() # pylint: disable=no-member if plugin_id.startswith("lektor"): plugin_id = plugin_id[6:] if plugin_id.endswith("plugin"): plugin_id = plugin_id[:-6] plugin_id = slugify(plugin_id) path = defaults.get("path") if path is None: if project is not None: default_path = os.path.join(project.tree, "packages", plugin_id) else: if len(os.listdir(".")) == 0: default_path = os.getcwd() else: default_path = os.path.join(os.getcwd(), plugin_id) path = g.prompt( "Plugin Path", default_path, "The place where you want to initialize the plugin", ) author_name = g.prompt( "Author Name", get_default_author(), "Your name as it will be embedded in the plugin metadata.", ) author_email = g.prompt( "Author E-Mail", get_default_author_email(), "Your e-mail address for the plugin info.", ) g.confirm("Create Plugin?") g.run( { "plugin_name": plugin_name, "plugin_id": plugin_id, "plugin_class": plugin_id.title().replace("-", "") + "Plugin", "plugin_module": "lektor_" + plugin_id.replace("-", "_"), "author_name": author_name, "author_email": author_email, }, path, )
def project_quickstart(defaults=None): if not defaults: defaults = {} g = Generator("project") g.title("Lektor Quickstart") g.text("This wizard will generate a new basic project with some sensible " "defaults for getting started quickly. We just need to go through " "a few questions so that the project is set up correctly for you.") name = defaults.get("name") if name is None: name = g.prompt( "Project Name", None, "A project needs a name. The name is primarily used for the admin " "UI and some other places to refer to your project to not get " "confused if multiple projects exist. You can change this at " "any later point.", ) author_name = g.prompt( "Author Name", get_default_author(), "Your name. This is used in a few places in the default template " "to refer to in the default copyright messages.", ) path = defaults.get("path") if path is None: here = os.path.abspath(os.getcwd()) default_project_path = None try: if len(os.listdir(here)) == []: default_project_path = here except OSError: pass if default_project_path is None: default_project_path = os.path.join(os.getcwd(), name) path = g.prompt( "Project Path", default_project_path, "This is the path where the project will be located. You can " "move a project around later if you do not like the path. If " "you provide a relative path it will be relative to the working " "directory.", ) path = os.path.expanduser(path) with_blog = g.prompt( "Add Basic Blog", True, "Do you want to generate a basic blog module? If you enable this " "the models for a very basic blog will be generated.", ) g.confirm("That's all. Create project?") g.run( { "project_name": name, "project_slug": slugify(name), "project_path": path, "with_blog": with_blog, "this_year": datetime.utcnow().year, "today": datetime.utcnow().strftime("%Y-%m-%d"), "author_name": author_name, }, path, )
def test_slugify(): assert slugify("w o w") == "w-o-w" assert slugify(u"Șö prĕtty") == "so-pretty" assert slugify("im age.jpg") == "im-age.jpg" assert slugify("slashed/slug") == "slashed/slug"
def theme_quickstart(defaults=None, project=None): if defaults is None: defaults = {} g = Generator("theme") theme_name = defaults.get("theme_name") if theme_name is None: theme_name = g.prompt( "Theme Name", default=None, info="This is the human readable name for this theme", ) theme_id = theme_name.lower() if theme_id != "lektor" and theme_id.startswith("lektor"): theme_id = theme_id[6:].strip() if theme_id != "theme" and theme_id.startswith("theme"): theme_id = theme_id[5:] if theme_id != "theme" and theme_id.endswith("theme"): theme_id = theme_id[:-5] theme_id = slugify(theme_id) path = defaults.get("path") if path is None: if project is not None: default_path = os.path.join(project.tree, "themes", "lektor-theme-{}".format(theme_id)) else: if len(os.listdir(".")) == 0: default_path = os.getcwd() else: default_path = os.path.join(os.getcwd(), theme_id) path = g.prompt( "Theme Path", default_path, "The place where you want to initialize the theme", ) author_name = g.prompt( "Author Name", get_default_author(), "Your name as it will be embedded in the theme metadata.", ) author_email = g.prompt( "Author E-Mail", get_default_author_email(), "Your e-mail address for the theme info.", ) g.confirm("Create Theme?") g.run( { "theme_name": theme_name, "theme_id": theme_id, "author_name": author_name, "author_email": author_email, }, path, ) # symlink theme_dir = os.getcwd() example_themes = os.path.join(path, "example-site/themes") os.makedirs(example_themes) os.chdir(example_themes) try: os.symlink( "../../../lektor-theme-{}".format(theme_id), "lektor-theme-{}".format(theme_id), ) except OSError as exc: # Windows, by default, only allows members of the "Administrators" group # to create symlinks. For users who are not allowed to create symlinks, # error Code 1314 - "A required privilege is not held by the client" # is raised. if getattr(exc, "winerror", None) != 1314: raise g.warn( "Could not automatically make a symlink to have your example-site" "easily pick up your theme.") os.chdir(theme_dir) # Sample image os.makedirs(os.path.join(path, "images")) source_image_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), "quickstart-templates/theme/images/homepage.png", ) destination_image_path = os.path.join(path, "images/homepage.png") with open(source_image_path, "rb") as f: image = f.read() with open(destination_image_path, "wb") as f: f.write(image)