Пример #1
0
    def __init__(self, string):
        super(Config, self).__init__()

        try:
            self.update(yaml.load(string))
        except yaml.YAMLError:
            raise ConfigException('Config contains unsupported YAML.')
        except:
            raise ConfigException('Invalid config format.')
Пример #2
0
    def _parse(self, container):
        for f in container.path:
            Timer.start()

            item = Item(f.path)

            try:
                frontmatter, bodymatter = re.search(
                    r'\A---\s+^(.+?)$\s+---\s*(.*)\Z', f.content,
                    re.M | re.S).groups()
                frontmatter = Config(frontmatter)
            except AttributeError:
                raise ContentException('Invalid frontmatter.',
                                       'src: {0}'.format(f.path),
                                       'frontmatter must not be empty')
            except ConfigException:
                raise ConfigException('Invalid frontmatter.',
                                      'src: {0}'.format(f.path),
                                      'fontmatter contains invalid YAML')

            if 'layout' not in frontmatter:
                raise ContentException('Invalid frontmatter.',
                                       'src: {0}'.format(f.path),
                                       'layout must be set')

            parser = self._get_parser(
                f,
                frontmatter.get('parser', container.config.get('parser',
                                                               None)))

            slug, date = self._parse_filename(f)
            content = parser.parse(
                self._writer.from_string(bodymatter, frontmatter))

            item['content'] = content
            item['date'] = date.strftime(
                self.site['date_format']).decode('utf-8')
            item['excerpt'] = re.search(r'\A.*?(?:<p>(.+?)</p>)?', content,
                                        re.M | re.S).group(1)
            item['tags'] = []
            item['timestamp'] = timegm(date.utctimetuple())

            item.update(frontmatter)

            item['url'] = self._get_content_url(container.config['url'], slug,
                                                date, frontmatter)

            container.add(item)

            logger.debug('..  (%.3fs) %s', Timer.stop(),
                         f.path.replace(self.src.path, ''))

        container.sort()
        container.tag()
        container.archive()

        return container
Пример #3
0
 def __init__(self, string):
     super(Config, self).__init__()
     
     try:
         self.update(yaml.load(string))
     except yaml.YAMLError:
         raise ConfigException('Config contains unsupported YAML.')
     except:
         logger.debug('..  config file is empty')
         
         pass
Пример #4
0
    def _get_path(self, url):
        parts = [self.dest.path] + url.split('/')

        if url.endswith('/'):
            parts.append('index.html')

        path = normpath(*parts)

        if op.commonprefix((self.dest.path, path)) != self.dest.path:
            raise ConfigException('Invalid URL.', 'url: {0}'.format(url),
                                  'path traversal is not allowed')

        return path
Пример #5
0
    def _initialize(self):
        logger.debug('>> Initializing\n..  src:  %s\n..  dest: %s',
                     self.src.path, self.dest.path)

        self._update_config()

        if self.config['locale']:
            try:
                locale.setlocale(locale.LC_ALL,
                                 (self.config['locale'], 'utf-8'))
            except locale.Error:
                raise ConfigException(
                    'Locale not available.',
                    'run `locale -a` to see available locales')

        self.writer.register({'site': self.config})
Пример #6
0
    def _generate(self):
        logger.debug('>> Initializing\n..  src:  %s\n..  dest: %s',
                     self.src.path, self.dest.path)

        self._update_config()

        if self.config['locale']:
            try:
                locale.setlocale(locale.LC_ALL,
                                 (self.config['locale'], 'utf-8'))
            except locale.Error:
                raise ConfigException(
                    'Locale not available.',
                    'run `locale -a` to see available locales')

        self.writer.register({'site': self.config})

        self._render()

        logger.info('>> Generating')

        assets_src = Directory(normpath(self.src.path, '_assets'))
        assets_dest = Directory(
            normpath(self.dest.path, *self.config['assets_url'].split('/')))

        if self.dest.exists:
            if self.opts['force']:
                self.dest.empty()
            else:
                self.dest.rm()
        else:
            self.dest.mk()

        for page in self.pages:
            page.mk()

        assets_src.cp(assets_dest.path)

        for pattern in self.config['include']:
            for path in iglob(normpath(self.src.path, pattern)):
                dest = path.replace(self.src.path, self.dest.path)

                if op.isdir(path):
                    Directory(path).cp(dest, False)
                elif op.isfile(path):
                    File(path).cp(dest)
Пример #7
0
 def _parse_item(self, config, f, simple = False):
     Timer.start()
     
     item = Item(f.path)
     
     try:
         frontmatter, bodymatter = re.search(r'\A---\s+^(.+?)$\s+---\s*(.*)\Z', f.content, re.M | re.S).groups()
         frontmatter = Config(frontmatter)
     except AttributeError:
         raise ContentException('Invalid frontmatter.',
             'src: {0}'.format(f.path),
             'frontmatter must not be empty')
     except ConfigException:
         raise ConfigException('Invalid frontmatter.',
             'src: {0}'.format(f.path),
             'fontmatter contains invalid YAML')
     
     if 'layout' not in frontmatter:
         raise ContentException('Invalid frontmatter.',
             'src: {0}'.format(f.path),
             'layout must be set')
     
     frontmatter.pop('url', None)
     
     parser = self._get_parser(f, frontmatter.get('parser', config.get('parser', None)))
     
     text, date = self._parse_filename(f)
     content = parser.parse(self._writer.from_string(bodymatter, frontmatter))
     
     item['content'] = content
     item['date'] = date.strftime(self.site['date_format'])
     item['timestamp'] = timegm(date.utctimetuple())
     
     if simple:
         item['url'] = Url.from_path(f.root.path.replace(self.src.path, ''), text)
     else:
         item['excerpt'] = re.search(r'\A.*?(?:<p>(.+?)</p>)?', content, re.M | re.S).group(1)
         item['tags'] = []
         item['url'] = Url.from_format(config['url'], text, date, frontmatter)
     
     item.update(frontmatter)
     
     logger.debug('..  (%.3fs) %s', Timer.stop(), f.path.replace(self.src.path, ''))
     
     return item
Пример #8
0
    def _update_config(self):
        self.config = deepcopy(self.defaults)

        logger.debug('>> Searching for config')

        for ext in ('.yml', '.yaml'):
            f = File(normpath(self.src.path, 'config' + ext))

            if f.exists:
                logger.debug('..  found: {0}'.format(f.path))

                try:
                    self.config.update(Config(f.content))
                except ConfigException as e:
                    raise ConfigException(e.message, 'src: {0}'.format(f.path))

                break
        else:
            logger.debug('..  no config file found')
Пример #9
0
    def __init__(self, args=None):
        self._start = time()

        self.opts = self._get_opts(args)

        self.src = Directory(self.opts['src'])
        self.dest = Directory(self.opts['dest'])

        logger.setLevel(getattr(logging, self.opts['level'], logging.INFO))
        logger.debug('>> Initializing\n..  src:  {0}\n..  dest: {1}'.format(
            self.src, self.dest))

        if self.src == self.dest:
            raise OptionException('Source and destination must differ.')
        elif self.src.path in ('/', '//') or self.dest.path in ('/', '//'):
            raise OptionException('Root is not a valid source or destination.')

        logger.debug('>> Searching for config')

        for ext in ('.yml', '.yaml'):
            f = File(normpath(self.src.path, 'config' + ext))

            if f.exists:
                logger.debug('..  found: {0}'.format(f.path))

                try:
                    self.config.update(Config(f.content))
                except ConfigException as e:
                    raise ConfigException(e.message, 'src: {0}'.format(f.path))

                break
        else:
            logger.debug('..  no config file found')

        for opt in ('base_url', ):
            if opt in self.opts:
                self.config[opt] = self.opts[opt]

        self.renderer.register({'site': self.config})
Пример #10
0
    def __init__(self, post):
        self.path = post.path
        self.root = post.root
        self.name = post.name
        self.extension = post.extension

        logger.debug('..  {0}.{1}'.format(self.name, self.extension))

        try:
            date, self.slug = re.match(r'(\d{4}(?:-\d{2}-\d{2}){1,2})-(.+)',
                                       self.name).groups()
            self.date = self._get_date(post.mtime, date)
        except (AttributeError, ValueError):
            raise PostException(
                'Invalid post filename.', 'src: {0}'.format(self.path),
                'must be of the format \'YYYY-MM-DD[-HH-MM]-Post-title.md\'')

        try:
            frontmatter, self.bodymatter = re.search(
                r'\A---\s+^(.+?)$\s+---\s*(.*)\Z', post.content,
                re.M | re.S).groups()
        except AttributeError:
            raise PostException('Invalid post format.',
                                'src: {0}'.format(self.path),
                                'frontmatter must not be empty')

        try:
            self.frontmatter = Config(frontmatter)
        except ConfigException as e:
            raise ConfigException('Invalid post frontmatter.',
                                  'src: {0}'.format(self.path),
                                  e.message.lower().replace('.', ''))

        if 'layout' not in self.frontmatter:
            raise PostException('Invalid post frontmatter.',
                                'src: {0}'.format(self.path),
                                'layout must be set')
Пример #11
0
    def _update_config(self):
        self.config = deepcopy(self.defaults)

        logger.debug('>> Searching for config')

        for ext in ('.yml', '.yaml'):
            f = File(normpath(self.src.path, 'config' + ext))

            if f.exists:
                logger.debug('..  found: %s', f.path)

                try:
                    self.config.update(Config(f.content))
                except ConfigException as e:
                    raise ConfigException(e.message, 'src: {0}'.format(f.path))

                self.config['locale'] = self.opts.get('locale',
                                                      self.config['locale'])

                self.config['assets_url'] = Url.join(self.config['assets_url'],
                                                     '')
                self.config['base_url'] = Url.join(
                    self.opts.get('base_url', self.config['base_url']), '')

                for setting in ('archives_url', 'posts_url', 'tags_url'):
                    self.config[setting] = Url.join(self.config[setting])

                for setting in ('archives_url', 'assets_url', 'base_url',
                                'posts_url', 'tags_url'):
                    if re.search(r'(?:^\.{2}/|/\.{2}$|/\.{2}/)',
                                 self.config[setting]):
                        raise ConfigException('Invalid config setting.',
                                              'setting: {0}'.format(setting),
                                              'path traversal is not allowed')

                containers_src = normpath(self.src.path, '_containers')

                for name, config in self.config['containers'].iteritems():
                    if op.commonprefix(
                        (containers_src, normpath(containers_src,
                                                  name))) != containers_src:
                        raise ConfigException(
                            'Invalid config setting.',
                            'setting: containers:{0}'.format(name),
                            'container name contains illegal characters')

                    try:
                        url = Url.join(config['url'])
                    except KeyError:
                        raise ConfigException(
                            'Invalid config setting.',
                            'setting: containers:{0}'.format(name),
                            'url must be set for all containers')

                    if re.search(r'(?:^\.{2}/|/\.{2}$|/\.{2}/)', url):
                        raise ConfigException(
                            'Invalid config setting.',
                            'setting: containers:{0}:url'.format(name),
                            'path traversal is not allowed')

                    config.update(
                        (k, v) for k, v in self.container_defaults.iteritems()
                        if k not in config)
                    config['url'] = url

                for pattern in self.config['include']:
                    if op.commonprefix(
                        (self.src.path, normpath(self.src.path,
                                                 pattern))) != self.src.path:
                        raise ConfigException('Invalid include path.',
                                              'path: {0}'.format(pattern),
                                              'path traversal is not allowed')

                break
        else:
            logger.debug('..  no config file found')