Ejemplo n.º 1
0
    def test_subproject_extra_assets(self):
        proj = Project(self)
        self.project = proj
        sm_path = self._create_sitemap('sitemap.txt',
                                       'index.markdown\n\tsubproject.json')
        index_path = self._create_md_file('index.markdown', '# Project')

        sub_sm_path = self._create_sitemap('subsitemap.txt',
                                           'subindex.markdown')
        sub_index_path = self._create_md_file('subindex.markdown',
                                              '# Subproject')
        sub_asset = self._create_md_file('subassets/fake_asset.md', 'Fakery')
        self._create_conf_file(
            'subproject.json', {
                'index': sub_index_path,
                'sitemap': sub_sm_path,
                'project_name': 'subproject',
                'extra_assets': [os.path.dirname(sub_asset)],
                'project_version': '0.2'
            })

        extra_assets = self._create_md_file('extra_assets/fake_asset.md',
                                            'Main fake')
        conf = Config({
            'sitemap': sm_path,
            'index': index_path,
            'project_name': 'test-project',
            'project_version': '0.1',
            'extra_assets': [os.path.dirname(extra_assets)],
            'output': self._output_dir
        })
        proj.parse_name_from_config(conf)
        proj.parse_config(conf, toplevel=True)
        proj.setup()

        self.assertEqual(len(proj.tree.get_pages()), 2)
        proj.format(self.link_resolver, self.output)
        proj.write_out(self.output)

        # FIXME: reenable with a different testing strategy
        # pylint: disable=pointless-string-statement
        '''
Ejemplo n.º 2
0
class Application(Configurable):
    """
    Banana banana
    """

    # pylint: disable=too-many-instance-attributes

    def __init__(self, extension_classes):
        self.extension_classes = OrderedDict(
            {CoreExtension.extension_name: CoreExtension})
        for ext_class in extension_classes:
            self.extension_classes[ext_class.extension_name] = ext_class
        self.output = None
        self.private_folder = None
        self.database = None
        self.link_resolver = None
        self.dry = False
        self.hostname = None
        self.config = None
        self.project = None
        self.formatted_signal = Signal()
        self.__all_projects = {}

    @staticmethod
    def add_arguments(parser):
        parser.add_argument('--dry',
                            help='Dry run, nothing will be output',
                            dest='dry',
                            action='store_true')
        parser.add_argument('--deps-file-dest',
                            help='Where to output the dependencies file')
        parser.add_argument('--deps-file-target',
                            help='Name of the dependencies target',
                            default='doc.stamp.d')
        parser.add_argument("-o",
                            "--output",
                            action="store",
                            dest="output",
                            help="where to output the rendered "
                            "documentation")
        parser.add_argument('--hostname',
                            dest='hostname',
                            action='store',
                            help='Where the documentation will be hosted, '
                            'for example <http://hotdoc.com>. When provided, '
                            'an XML sitemap will be generated for SEO '
                            'purposes.')

    def parse_config(self, config):
        self.config = config
        self.output = config.get_path('output')
        self.dry = config.get('dry')
        self.hostname = config.get('hostname')
        self.project = Project(self)
        self.project.parse_name_from_config(self.config)
        self.private_folder = os.path.abspath('hotdoc-private-%s' %
                                              self.project.sanitized_name)
        shutil.rmtree(self.private_folder, ignore_errors=True)
        self.project.parse_config(self.config, toplevel=True)

        self.__setup_private_folder()
        self.__setup_database()

    def run(self):
        """
        Banana banana
        """
        res = 0

        self.project.setup()
        self.__retrieve_all_projects(self.project)

        self.link_resolver.get_link_signal.connect_after(self.__get_link_cb)
        self.project.format(self.link_resolver, self.output)
        self.project.write_out(self.output)

        # Generating an XML sitemap makes no sense without a hostname
        if self.hostname:
            self.project.write_seo_sitemap(self.hostname, self.output)

        self.link_resolver.get_link_signal.disconnect(self.__get_link_cb)

        self.formatted_signal(self)
        self.__persist()

        return res

    def __get_link_cb(self, link_resolver, name):
        url_components = urlparse(name)

        project = self.__all_projects.get(url_components.path)
        if not project:
            return None

        page = project.tree.root
        ext = project.extensions[page.extension_name]
        formatter = ext.formatter
        prefix = formatter.get_output_folder(page)
        ref = page.link.ref
        if url_components.fragment:
            ref += '#%s' % url_components.fragment

        return Link(os.path.join(prefix, ref), page.link.get_title(), None)

    def __retrieve_all_projects(self, project):
        self.__all_projects[project.project_name] = project

        for subproj in project.subprojects.values():
            self.__retrieve_all_projects(subproj)

    def __persist(self):
        if self.dry:
            return

        info('Persisting database and private files', 'persisting')

        self.database.persist()
        self.__dump_deps_file(self.project)

    def finalize(self):
        """
        Banana banana
        """
        self.project.finalize()

    def __setup_private_folder(self):
        if os.path.exists(self.private_folder):
            if not os.path.isdir(self.private_folder):
                error('setup-issue',
                      '%s exists but is not a directory' % self.private_folder)
        else:
            os.mkdir(self.private_folder)

    def __setup_database(self):
        self.database = Database(self.private_folder)
        self.link_resolver = LinkResolver(self.database)

    def __dump_project_deps_file(self, project, deps_file, empty_targets):
        for page in list(project.tree.get_pages().values()):
            if not page.generated:
                empty_targets.append(page.source_file)
                deps_file.write(u'%s ' % page.source_file)

        for subproj in project.subprojects.values():
            self.__dump_project_deps_file(subproj, deps_file, empty_targets)

    def __dump_deps_file(self, project):
        dest = self.config.get('deps_file_dest', None)
        target = self.config.get('deps_file_target')

        if dest is None:
            info("Not dumping deps file")
            return

        info("Dumping deps file to %s with target %s" % (dest, target))

        destdir = os.path.dirname(dest)
        if not os.path.exists(destdir):
            os.makedirs(destdir)

        empty_targets = []
        with open(dest, 'w', encoding='utf-8') as _:
            _.write(u'%s: ' % target)

            for dep in self.config.get_dependencies():
                empty_targets.append(dep)
                _.write(u'%s ' % dep.replace(' ', '\\ '))

            self.__dump_project_deps_file(project, _, empty_targets)

            for empty_target in empty_targets:
                _.write(u'\n\n%s:' % empty_target)
Ejemplo n.º 3
0
class Application(Configurable):
    def __init__(self, extension_classes):
        self.extension_classes = OrderedDict(
            {CoreExtension.extension_name: CoreExtension})
        for ext_class in extension_classes:
            self.extension_classes[ext_class.extension_name] = ext_class
        self.output = None
        self.private_folder = None
        self.change_tracker = None
        self.database = None
        self.link_resolver = None
        self.dry = False
        self.incremental = False
        self.config = None
        self.project = None
        self.formatted_signal = Signal()
        self.__all_projects = {}

    @staticmethod
    def add_arguments(parser):
        parser.add_argument('--dry',
                            help='Dry run, nothing will be output',
                            dest='dry',
                            action='store_true')
        parser.add_argument('--deps-file-dest',
                            help='Where to output the dependencies file')
        parser.add_argument('--deps-file-target',
                            help='Name of the dependencies target',
                            default='doc.stamp.d')
        parser.add_argument("-o",
                            "--output",
                            action="store",
                            dest="output",
                            help="where to output the rendered "
                            "documentation")

    def parse_config(self, config):
        self.config = config
        self.output = config.get_path('output')
        self.dry = config.get('dry')
        self.project = Project(self)
        self.project.parse_name_from_config(self.config)
        self.private_folder = os.path.abspath('hotdoc-private-%s' %
                                              self.project.sanitized_name)
        self.__create_change_tracker(self.config.get('disable_incremental'))
        self.project.parse_config(self.config, toplevel=True)

        self.__setup_private_folder()
        self.__setup_database()

    def run(self):
        res = 0

        if self.config.conf_file:
            self.change_tracker.add_hard_dependency(self.config.conf_file)

        self.project.setup()
        self.__retrieve_all_projects(self.project)

        self.link_resolver.get_link_signal.connect_after(self.__get_link_cb)
        self.project.format(self.link_resolver, self.output)
        self.project.write_out(self.output)

        self.link_resolver.get_link_signal.disconnect(self.__get_link_cb)

        self.formatted_signal(self)
        self.__persist(self.project)

        return res

    def __get_link_cb(self, link_resolver, name):
        url_components = urlparse(name)

        project = self.__all_projects.get(url_components.path)
        if not project:
            return None

        page = project.tree.root
        ext = project.extensions[page.extension_name]
        formatter = ext.formatter
        prefix = formatter.get_output_folder(page)
        ref = page.link.ref
        if url_components.fragment:
            ref += '#%s' % url_components.fragment

        return Link(os.path.join(prefix, ref), page.link.get_title(), None)

    def __retrieve_all_projects(self, project):
        self.__all_projects[project.project_name] = project

        for subproj in project.subprojects.values():
            self.__retrieve_all_projects(subproj)

    def __dump_project_deps_file(self, project, deps_file, empty_targets):
        for page in list(project.tree.get_pages().values()):
            if not page.generated:
                empty_targets.append(page.source_file)
                deps_file.write(u'%s ' % page.source_file)

        for subproj in project.subprojects.values():
            self.__dump_project_deps_file(subproj, deps_file, empty_targets)

    def __dump_deps_file(self, project):
        dest = self.config.get('deps_file_dest', None)
        target = self.config.get('deps_file_target')

        if dest is None:
            info("Not dumping deps file")
            return

        info("Dumping deps file to %s with target %s" % (dest, target))

        destdir = os.path.dirname(dest)
        if not os.path.exists(destdir):
            os.makedirs(destdir)

        empty_targets = []
        with open(dest, 'w', encoding='utf-8') as _:
            _.write(u'%s: ' % target)

            for dep in self.config.get_dependencies():
                empty_targets.append(dep)
                _.write(u'%s ' % dep)

            self.__dump_project_deps_file(project, _, empty_targets)

            for empty_target in empty_targets:
                _.write(u'\n\n%s:' % empty_target)

    def __persist(self, project):
        if self.dry:
            return

        info('Persisting database and private files', 'persisting')

        project.persist()
        self.database.persist()
        with open(os.path.join(self.private_folder, 'change_tracker.p'),
                  'wb') as _:
            _.write(pickle.dumps(self.change_tracker))
        self.__dump_deps_file(project)

    def finalize(self):
        if self.database is not None:
            info('Closing database')
            self.database.close()
        self.project.finalize()

    def __setup_private_folder(self):
        if os.path.exists(self.private_folder):
            if not os.path.isdir(self.private_folder):
                error('setup-issue',
                      '%s exists but is not a directory' % self.private_folder)
        else:
            os.mkdir(self.private_folder)

    def __setup_database(self):
        self.database = Database()
        #self.database.comment_added_signal.connect(self.__add_default_tags)
        #self.database.comment_updated_signal.connect(
        #    self.__add_default_tags)
        self.database.setup(self.private_folder)
        self.link_resolver = LinkResolver(self.database)

    def __create_change_tracker(self, disable_incremental):
        if not disable_incremental:
            try:
                with open(
                        os.path.join(self.private_folder, 'change_tracker.p'),
                        'rb') as _:
                    self.change_tracker = pickle.loads(_.read())

                if self.change_tracker.hard_dependencies_are_stale():
                    raise IOError
                self.incremental = True
                info("Building incrementally")
            # pylint: disable=broad-except
            except Exception:
                pass

        if not self.incremental:
            info("Building from scratch")
            shutil.rmtree(self.private_folder, ignore_errors=True)
            self.change_tracker = ChangeTracker()