def run(self): self.logger.debug('Meta command generate started') filename = self.options['filename'] result = None with spinner(f'Generating metadata', self.logger, self.quiet, self.debug): self._gen_meta() with open(filename, 'w', encoding='utf8') as f: yaml.dump(self.meta.dump(), f, default_flow_style=False, allow_unicode=True, sort_keys=False) result = filename if result: self.logger.info(f'Result: {result}') if not self.quiet: print('─' * 20) print(f'Result: {result}') else: print(result) self.logger.debug('Meta command generate finished')
def apply_preprocessor(self, preprocessor: str or dict): '''Apply preprocessor. :param preprocessor: Preprocessor name or a dict of the preprocessor name and its options ''' if isinstance(preprocessor, str): preprocessor_name, preprocessor_options = preprocessor, {} elif isinstance(preprocessor, dict): (preprocessor_name, preprocessor_options), = (*preprocessor.items(), ) with spinner(f'Applying preprocessor {preprocessor_name}', self.logger, self.quiet, self.debug): try: preprocessor_module = import_module( f'foliant.preprocessors.{preprocessor_name}') preprocessor_module.Preprocessor(self.context, self.logger, self.quiet, self.debug, preprocessor_options).apply() except ModuleNotFoundError as module_not_found: raise ModuleNotFoundError( f'Preprocessor {preprocessor_name} is not installed' ) from module_not_found except Exception as exception: raise RuntimeError( f'Failed to apply preprocessor {preprocessor_name}: {exception}' ) from exception
def get_config(self, project_path: Path, config_file_name: str, quiet=False, debug=False) -> dict: with spinner('Parsing config', self.logger, quiet, debug): try: config = Parser(project_path, config_file_name, self.logger, quiet).parse() except FileNotFoundError as exception: config = None raise FileNotFoundError( f'{exception} not found') from exception except Exception as exception: config = None raise RuntimeError( f'Invalid config: {exception}') from exception if config is None: raise ConfigError('Config parsing failed.') return config
def make(self, target: str) -> str: self.meta = load_meta(self.config.get('chapters', []), self.working_dir) with spinner(f'Making {target} with Pandoc', self.logger, self.quiet, self.debug): result = [] if self._pandoc_config['build_whole_project']: result.append(self._build_flat(target)) result.extend(self._build_separate(target)) return '\n' + '\n'.join(result)
def make(self, target: str) -> str: with spinner(f'Making {target}', self.logger, self.quiet, self.debug): output('', self.quiet) # empty line for better output try: if target == 'confluence': return self._build() else: raise ValueError(f'Confluence cannot make {target}') except Exception as exception: raise RuntimeError(f'Build failed: {exception}')
def gupload(self, target, backend='', project_path=Path('.'), config_file_name='foliant.yml', quiet=False, keep_tmp=False, debug=False): file_to_upload = make.Cli() self._filename = file_to_upload.make(target, backend, project_path, config_file_name, quiet, keep_tmp, debug) print('─────────────────────') self._gdoc_config = file_to_upload.get_config(project_path, config_file_name, quiet=True)['gupload'] self._gdrive_auth() with spinner(f"Uploading '{self._filename}' to Google Drive", self.logger, quiet=False, debug=False): try: self._create_gdrive_folder() self._upload_file(target) except Exception as exception: raise type(exception)(f'The error occurs: {exception}') if self._gdoc_link: self.logger.info( f'File {self._filename} uploaded to Google Drive: {self._gdoc_link}' ) if not quiet: print('─────────────────────') print(f"Result:\n\ Doc link: {self._gdoc_link}\n\ Google drive folder ID: {self._gdoc_config['gdrive_folder_id']}\n\ Google document ID: {self._gdoc_config['gdoc_id']}") return self._gdoc_link else: self.logger.critical('Upload failed') exit('Upload failed') return None
def make(self, target: str) -> str: with spinner(f'Making {target} with md-to-pdf', self.logger, self.quiet, self.debug): try: command = self._get_pdf_command() self.logger.debug('Running the command.') run(command, shell=True, check=True, stdout=PIPE, stderr=STDOUT) return f'{self._slug}.{target}' except CalledProcessError as exception: raise RuntimeError( f'Build failed: {exception.output.decode()}') except Exception as exception: raise type(exception)(f'Build failed: {exception}')
def get_config( self, project_path: Path, config_file_name: str, quiet=False, debug=False ) -> dict: with spinner('Parsing config', self.logger, quiet, debug): try: config = Parser(project_path, config_file_name, self.logger).parse() except FileNotFoundError as exception: config = None raise FileNotFoundError(f'{exception} not found') except Exception as exception: config = None raise type(exception)(f'Invalid config: {exception}') if config is None: raise ConfigError('Config parsing failed.') return config
def make(self, target: str) -> str: with spinner(f'Making {target}', self.logger, self.quiet, self.debug): try: img_dir = self._site_dir / 'img' shutil.rmtree(self._site_dir, ignore_errors=True) img_dir.mkdir(parents=True) source_path = self.working_dir / self._flat_src_file_name with open(source_path) as f: source = f.read() processed_source = self._process_images(source, img_dir) with open(source_path, 'w') as f: f.write(processed_source) try: command = self._get_command(self._aglio_config, source_path, self._site_dir / "index.html") self.logger.debug(f'Constructed command: {command}') r = run(command, shell=True, check=True, stdout=PIPE, stderr=STDOUT) except CalledProcessError as e: raise RuntimeError(e.output.decode('utf8', errors='ignore')) command_output_decoded = r.stdout.decode('utf8', errors='ignore') output(command_output_decoded, self.quiet) return self._site_dir except Exception as exception: err = traceback.format_exc() self.logger.debug(err) raise type(exception)(f'Build failed: {err}')
def make(self, target: str) -> str: with spinner(f'Making {target} with MkDocs', self.logger, self.quiet): try: mkdocs_project_path = self.working_dir / self._mkdocs_project_dir_name config = self._mkdocs_config.get('mkdocs.yml', {}) self.logger.debug(f'Backend config: {config}') if 'site_name' not in config and self._mkdocs_config.get( 'use_title', True): config['site_name'] = self.config['title'] if 'pages' not in config and self._mkdocs_config.get( 'use_chapters', True): config['pages'] = self.config['chapters'] if self._mkdocs_config.get('use_headings', True): config['pages'] = self._get_pages_with_headings( config['pages']) self.logger.debug(f'mkdocs.yml: {config}') with open(mkdocs_project_path / 'mkdocs.yml', 'w', encoding='utf8') as mkdocs_config: self.logger.debug( f'Saving mkdocs.yml into {mkdocs_project_path}') dump(config, mkdocs_config, default_flow_style=False) if target == 'mkdocs': rmtree(self._mkdocs_project_dir_name, ignore_errors=True) copytree(mkdocs_project_path, self._mkdocs_project_dir_name) return self._mkdocs_project_dir_name elif target == 'site': try: mkdocs_site_path = Path( self._mkdocs_site_dir_name).absolute() run(self._get_build_command(mkdocs_site_path), shell=True, check=True, stdout=PIPE, stderr=STDOUT, cwd=mkdocs_project_path) return self._mkdocs_site_dir_name except CalledProcessError as exception: raise RuntimeError( f'Build failed: {exception.output.decode()}') elif target == 'ghp': try: mkdocs_site_path = Path( self._mkdocs_site_dir_name).absolute() process = run(self._get_ghp_command(), shell=True, check=True, stdout=PIPE, stderr=STDOUT, cwd=mkdocs_project_path) ghp_url = process.stdout.decode().splitlines( )[-1].split(': ')[-1] return ghp_url except CalledProcessError as exception: raise RuntimeError( f'GitHub Pages deploy failed: {exception.output.decode()}' ) else: raise ValueError(f'MkDocs cannot make {target}') except Exception as exception: raise type(exception)(f'Build failed: {exception}')
def init(self, project_name='', template='base', quiet=False, debug=False): '''Generate new Foliant project.''' self.logger.setLevel(DEBUG if debug else WARNING) self.logger.info('Project creation started.') self.logger.debug(f'Template: {template}') template_path = Path(template) if not template_path.exists(): self.logger.debug( f'Template not found in {template_path}, looking in installed templates.' ) installed_templates_path = Path( Path(__file__).parent / 'templates') installed_templates = [ item.name for item in installed_templates_path.iterdir() if item.is_dir() ] self.logger.debug(f'Available templates: {installed_templates}') if template in installed_templates: self.logger.debug('Template found.') else: self.logger.debug('Template not found, asking for user input.') try: template = prompt( f'Please pick a template from {installed_templates}: ', completer=WordCompleter(installed_templates), validator=BuiltinTemplateValidator( installed_templates)) except KeyboardInterrupt: self.logger.warning('Project creation interrupted.') return template_path = installed_templates_path / template self.logger.debug(f'Template path: {template_path}') if not project_name: self.logger.debug( 'Project name not specified, asking for user input.') try: project_name = prompt('Enter the project name: ') except KeyboardInterrupt: self.logger.warning('Project creation interrupted.') return project_slug = slugify(project_name) project_path = Path(project_slug) properties = {'title': project_name, 'slug': project_slug} self.logger.debug(f'Project properties: {properties}') result = None with spinner('Generating project', self.logger, quiet, debug): copytree(template_path, project_path) text_types = '*.md', '*.yml', '*.txt', '*.py' text_file_paths = reduce(lambda acc, matches: acc + [*matches], (project_path.rglob(text_type) for text_type in text_types), []) for text_file_path in text_file_paths: self.logger.debug(f'Processing content of {text_file_path}') replace_placeholders(text_file_path, properties) for item in project_path.rglob('*'): self.logger.debug(f'Processing name of {item}') item.rename( Template(item.as_posix()).safe_substitute(properties)) result = project_path if result: self.logger.info(f'Result: {result}') if not quiet: print('─' * 20) print(f'Project "{project_name}" created in {result}') else: print(result) else: self.logger.critical('Project creation failed.') exit(1)