def gen_cobom_csv(projfolder, namebase, force=False): """ Generates a CSV file in the :mod:`tendril.boms.outputbase.CompositeOutputBom` format, including the BOMs of the all the defined configurations of the project. This function uses a :mod:`csv.writer` instead of rendering a jinja2 template. It also generates configdocs for all the defined configurations of the project, using :func:`gen_confpdf`. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output Files : ``<project_doc_folder>/confdocs/conf_boms.csv`` * Also triggers : :func:`gen_confpdf` for all listed configurations. * Source Files : The project's schematic folder. """ gpf = projfile.GedaProjectFile(projfolder) configfile = conffile.ConfigsFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.configsfile.schfolder) docfolder = get_project_doc_folder(projfolder) cobom_csv_path = path.join(docfolder, 'confdocs', 'conf-boms.csv') outf_mtime = fsutils.get_file_mtime(cobom_csv_path, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + cobom_csv_path) return cobom_csv_path logger.info('Regenerating ' + cobom_csv_path + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bomlist = [] for cfn in configfile.configuration_names: gen_confpdf(projfolder, cfn, namebase, force=force) lbom = boms_electronics.import_pcb(projfolder) lobom = lbom.create_output_bom(cfn) bomlist.append(lobom) cobom = boms_outputbase.CompositeOutputBom(bomlist) with refdoc_fs.open(cobom_csv_path, 'wb') as f: writer = csv.writer(f) writer.writerow(['device'] + [x.configname for x in cobom.descriptors]) for line in cobom.lines: writer.writerow([line.ident] + line.columns)
def gen_cobom_csv(projfolder, namebase, force=False): """ Generates a CSV file in the :mod:`tendril.boms.outputbase.CompositeOutputBom` format, including the BOMs of the all the defined configurations of the project. This function uses a :mod:`csv.writer` instead of rendering a jinja2 template. It also generates configdocs for all the defined configurations of the project, using :func:`gen_confpdf`. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output Files : ``<project_doc_folder>/confdocs/conf_boms.csv`` * Also triggers : :func:`gen_confpdf` for all listed configurations. * Source Files : The project's schematic folder. """ gpf = projfile.GedaProjectFile(projfolder) configfile = conffile.ConfigsFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) cobom_csv_path = path.join(docfolder, 'confdocs', 'conf-boms.csv') outf_mtime = fsutils.get_file_mtime(cobom_csv_path, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + cobom_csv_path) return cobom_csv_path logger.info('Regenerating ' + cobom_csv_path + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bomlist = [] for cfn in configfile.configuration_names: gen_confpdf(projfolder, cfn, namebase, force=force) lbom = boms_electronics.import_pcb(projfolder) lobom = lbom.create_output_bom(cfn) bomlist.append(lobom) cobom = boms_outputbase.CompositeOutputBom(bomlist) with refdoc_fs.open(cobom_csv_path, 'wb') as f: writer = csv.writer(f) writer.writerow(['device'] + [x.configname for x in cobom.descriptors]) for line in cobom.lines: writer.writerow([line.ident] + line.columns)
def gen_schpdf(projfolder, namebase, force=False): """ Generates a PDF file of all the project schematics listed in the gEDA project file. This function does not ise jinja2 and latex. It relies on :func:`tendril.gedaif.gschem.conv_gsch2pdf` instead. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/<namebase>-schematic.pdf`` * Source Files : The project's schematic folder. """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) configfile = conffile.ConfigsFile(projfolder) docfolder = get_project_doc_folder(projfolder) schpdfpath = path.join(docfolder, namebase + '-schematic.pdf') outf_mtime = fsutils.get_file_mtime(schpdfpath, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + schpdfpath) return schpdfpath logger.info('Regenerating ' + schpdfpath + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) if configfile.rawconfig is not None: workspace_outpath = workspace_fs.getsyspath(schpdfpath) workspace_folder = workspace_fs.getsyspath(path.dirname(schpdfpath)) workspace_fs.makedir(path.dirname(schpdfpath), recursive=True, allow_recreate=True) pdffiles = [] for schematic in gpf.schfiles: schfile = os.path.normpath(projfolder + '/schematic/' + schematic) pdffile = gschem.conv_gsch2pdf(schfile, workspace_folder) pdffiles.append(pdffile) pdf.merge_pdf(pdffiles, workspace_outpath) for pdffile in pdffiles: os.remove(pdffile) copyfile(workspace_fs, schpdfpath, refdoc_fs, schpdfpath, overwrite=True) return schpdfpath
def get_bom_file(self): if not os.path.exists(self._cache_folder): os.makedirs(self._cache_folder) os.chmod(self._cache_folder, 0o777) bom_mtime = fsutils.get_file_mtime(self._cached_bom_path) source_mtime = fsutils.get_folder_mtime(self._source_folder) if self._use_cached is True and bom_mtime is not None \ and source_mtime < bom_mtime: return open(self._cached_bom_path, 'r') else: self.generate_bom_file(self._temp_bom_path, **self._generator_args) shutil.copy(self._temp_bom_path, self._cached_bom_path) os.chmod(self._cached_bom_path, 0o666) return open(self._cached_bom_path, 'r')
def get_bom_file(self): if not os.path.exists(self._cache_folder): os.makedirs(self._cache_folder) bom_mtime = fsutils.get_file_mtime(self._cached_bom_path) source_folder = os.path.join(self.projectfolder, self._basefolder) source_mtime = fsutils.get_folder_mtime(source_folder) if self._use_cached is True and bom_mtime is not None \ and source_mtime < bom_mtime: return open(self._cached_bom_path, 'r') else: self.generate_bom_file(self._temp_bom_path, **self._generator_args) shutil.copy(self._temp_bom_path, self._cached_bom_path) return open(self._cached_bom_path, 'r')
def gen_pcb_gbr(projfolder, force=False): """ Generates gerber files for the PCB provided by the gEDA project, and also creates a ``zip`` file of the generated gerbers. The pcbfile is the one listed in the gEDA project file, and the pcbname is the one specified in the :mod:`tendril.gedaif.conffile.ConfigsFile`. This function does not use jinja2 and latex. It relies on :func:`tendril.gedaif.pcb.conv_pcb2gbr` instead. :param projfolder: The gEDA project folder. :type projfolder: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output Files : ``<project_doc_folder>/../gerber/*`` * Output Zip File : ``<project_doc_folder>/../<pcbfile>-gerber.zip`` * Source Files : The project's `.pcb` file. """ configfile = conffile.ConfigsFile(projfolder) gpf = projfile.GedaProjectFile(configfile.projectfolder) pcb_mtime = fsutils.get_file_mtime( os.path.join(configfile.projectfolder, 'pcb', gpf.pcbfile + '.pcb')) if pcb_mtime is None: logger.warning("PCB does not seem to exist for : " + projfolder) return docfolder = get_project_doc_folder(projfolder) imgfolder = os.path.join(docfolder, os.pardir, 'img') gbrfolder = os.path.join(docfolder, os.pardir, 'gerber') outf_mtime = None if not refdoc_fs.exists(gbrfolder): refdoc_fs.makedir(gbrfolder) else: outf_mtime = fsutils.get_folder_mtime(gbrfolder, fs=refdoc_fs) if not refdoc_fs.exists(imgfolder): refdoc_fs.makedir(imgfolder) if not force and outf_mtime is not None and outf_mtime > pcb_mtime: logger.debug('Skipping up-to-date ' + gbrfolder) return gbrfolder logger.info('Regenerating ' + gbrfolder + os.linesep + 'Last modified : ' + str(pcb_mtime) + '; Last Created : ' + str(outf_mtime)) rf = refdoc_fs.listdir(gbrfolder, files_only=True, full=True) for f in rf: refdoc_fs.remove(f) workspace_folder = workspace_fs.getsyspath(gbrfolder) workspace_fs.makedir(gbrfolder, recursive=True, allow_recreate=True) gbrfolder = pcb.conv_pcb2gbr( os.path.join(configfile.projectfolder, 'pcb', gpf.pcbfile + '.pcb'), workspace_folder) workspace_fs.makedir(imgfolder, recursive=True, allow_recreate=True) img_workspace_folder = workspace_fs.getsyspath(imgfolder) gen_pcb_img(gbrfolder, outfolder=img_workspace_folder, outfname=gpf.pcbfile, force=False) for f in os.listdir(img_workspace_folder): fpath = os.path.relpath(os.path.join(img_workspace_folder, f), workspace_fs.getsyspath('/')) copyfile(workspace_fs, fpath, refdoc_fs, fpath, overwrite=True) zfile = os.path.join(workspace_folder, os.pardir, gpf.pcbfile + '-gerber.zip') fsutils.zipdir(gbrfolder, zfile) for f in os.listdir(workspace_folder): fpath = os.path.relpath(os.path.join(workspace_folder, f), workspace_fs.getsyspath('/')) copyfile(workspace_fs, fpath, refdoc_fs, fpath, overwrite=True) zfpath = os.path.relpath(os.path.join(workspace_folder, zfile), workspace_fs.getsyspath('/')) copyfile(workspace_fs, zfpath, refdoc_fs, zfpath, overwrite=True) return gbrfolder
def gen_confpdf(projfolder, configname, namebase, force=False): """ Generates a PDF file of the documentation for a specific configuration of a project. It uses other document generator functions to make the various parts of the master document and then merges them. :param projfolder: The gEDA project folder. :type projfolder: str :param configname: The name of the configuration. :type configname: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/confdocs/<configname>.pdf`` * Source Files : The project's schematic folder. .. rubric:: Included Documents * Configuration BOM, generated by :func:`gen_confbom` * (Full) Schematic PDF, generated by :func:`gen_schpdf` .. todo:: It may be useful to rebuild the schematics after removing all the unpopulated components. This is a fairly involved process, and is deferred until later. """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) confdocfile = path.join(docfolder, 'confdocs', configname + '.pdf') outf_mtime = fsutils.get_file_mtime(confdocfile, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + confdocfile) return confdocfile logger.info('Regenerating ' + confdocfile + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) pdffiles = [ gen_confbom(projfolder, configname, force), gen_confdoc(projfolder, configname, force), gen_schpdf(projfolder, namebase, configname=configname, force=force) ] for p in pdffiles: if p and not workspace_fs.exists(p): workspace_fs.makedir(path.dirname(p), recursive=True, allow_recreate=True) copyfile(refdoc_fs, p, workspace_fs, p) workspace_pdffiles = [ workspace_fs.getsyspath(x) for x in pdffiles if x is not None ] workspace_outpath = workspace_fs.getsyspath(confdocfile) workspace_fs.makedir(path.dirname(confdocfile), recursive=True, allow_recreate=True) pdf.merge_pdf(workspace_pdffiles, workspace_outpath) copyfile(workspace_fs, confdocfile, refdoc_fs, confdocfile, overwrite=True) return confdocfile
def gen_masterdoc(projfolder, namebase, force=False): """ Generates a PDF file of the project's Master documentation. It uses other document generator functions to make the various parts of the master document and then merges them. .. note:: Due to the way groups and motifs are handled, an unconfigured BOM is somewhat meaningless. Therefore, no BOM is included in the masterdoc. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/<namebase>-masterdoc.pdf`` * Source Files : The project's schematic folder. .. rubric:: Included Documents * Config Documentation, generated by :func:`gen_configsdoc` * Schematic PDF, generated by :func:`gen_schpdf` """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) masterdocfile = path.join(docfolder, namebase + '-masterdoc.pdf') outf_mtime = fsutils.get_file_mtime(masterdocfile, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + masterdocfile) return masterdocfile logger.info('Regnerating ' + masterdocfile + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) pdffiles = [ gen_configsdoc(projfolder, namebase, force=False), gen_schpdf(projfolder, namebase, force=False) ] for p in pdffiles: if p and not workspace_fs.exists(p): workspace_fs.makedir(path.dirname(p), recursive=True, allow_recreate=True) copyfile(refdoc_fs, p, workspace_fs, p) workspace_pdffiles = [ workspace_fs.getsyspath(x) for x in pdffiles if x is not None ] workspace_outpath = workspace_fs.getsyspath(masterdocfile) workspace_fs.makedir(path.dirname(masterdocfile), recursive=True, allow_recreate=True) pdf.merge_pdf(workspace_pdffiles, workspace_outpath) copyfile(workspace_fs, masterdocfile, refdoc_fs, masterdocfile, overwrite=True) return masterdocfile
def gen_schpdf(projfolder, namebase, configname=None, force=False): """ Generates a PDF file of all the project schematics listed in the gEDA project file. This function does not use jinja2 and latex. It relies on :func:`tendril.gedaif.gschem.conv_gsch2pdf` instead. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/<namebase>-schematic.pdf`` * Source Files : The project's schematic folder. """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) configfile = conffile.ConfigsFile(projfolder) docfolder = get_project_doc_folder(projfolder) # TODO Consider converting all configurations in one go instead? if configname is None: schpdfpath = path.join(docfolder, namebase + '-schematic.pdf') else: docfolder = path.join(docfolder, 'confdocs') pdfname = configname + '-conf-schematic.pdf' schpdfpath = path.join(docfolder, pdfname) outf_mtime = fsutils.get_file_mtime(schpdfpath, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + schpdfpath) return schpdfpath logger.info('Regenerating ' + schpdfpath + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) if configfile.rawconfig is not None: workspace_outpath = workspace_fs.getsyspath(schpdfpath) workspace_folder = workspace_fs.getsyspath(docfolder) workspace_fs.makedir(docfolder, recursive=True, allow_recreate=True) pdffiles = [] obom = None if configname is not None: tfolder = path.join(docfolder, configname) workspace_tfolder = workspace_fs.getsyspath(tfolder) workspace_fs.makedir(tfolder, recursive=False, allow_recreate=True) bom = boms_electronics.import_pcb(projfolder) bom.configure_motifs(configname) obom = bom.create_output_bom(configname) for schematic in gpf.schfiles: schfile = os.path.normpath(projfolder + '/schematic/' + schematic) if configname is not None: tschfile = path.join(workspace_tfolder, schematic) gschem.rewrite_schematic(schfile, obom, gpf, tschfile) pdffile = gschem.conv_gsch2pdf(tschfile, workspace_tfolder) os.remove(tschfile) else: pdffile = gschem.conv_gsch2pdf(schfile, workspace_folder) pdffiles.append(pdffile) pdf.merge_pdf(pdffiles, workspace_outpath) for pdffile in pdffiles: os.remove(pdffile) copyfile(workspace_fs, schpdfpath, refdoc_fs, schpdfpath, overwrite=True) return schpdfpath
def gen_confdoc(projfolder, configname, force=False): """ Generate a PDF documenting a single configuration of the project. The document should include a reasonably thorough representation of the contents of the configuration related sections of the `tendril.gedaif.conffile.ConfigsFile``. :param projfolder: The gEDA project folder :type projfolder: str :param configname: The configuration name for which the BOM should be generated. :type configname: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/confdocs/<configname>-doc.pdf`` * Source Files : The project's schematic folder. .. rubric:: Template Used ``tendril/dox/templates/projects/geda-conf-doc.tex`` (:download:`Included version <../../tendril/dox/templates/projects/geda-conf-doc.tex>`) .. rubric:: Stage Keys Provided .. list-table:: * - ``configname`` - The name of the configuration (a card or cable name). * - ``desc`` - The description of the configuration. * - ``pcbname`` - The name of the base PCB. * - ``obom`` - An :mod:`tendril.boms.outputbase.OutputBom` instance """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) outpath = path.join(docfolder, 'confdocs', configname + '-doc.pdf') outf_mtime = fsutils.get_file_mtime(outpath, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + outpath) return outpath logger.info('Regenerating ' + outpath + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bom = boms_electronics.import_pcb(projfolder) obom = bom.create_output_bom(configname) group_oboms = bom.get_group_boms(configname) stage = { 'configname': obom.descriptor.configname, 'pcbname': obom.descriptor.pcbname, 'bom': bom, 'obom': obom, 'group_oboms': group_oboms } config = obom.descriptor.configurations.configuration(configname) stage['desc'] = config['desc'] template = 'projects/geda-conf-doc.tex' workspace_outpath = workspace_fs.getsyspath(outpath) workspace_fs.makedir(path.dirname(outpath), recursive=True, allow_recreate=True) render.render_pdf(stage, template, workspace_outpath) copyfile(workspace_fs, outpath, refdoc_fs, outpath, overwrite=True) return outpath
def gen_pcb_gbr(projfolder, force=False): """ Generates gerber files for the PCB provided by the gEDA project, and also creates a ``zip`` file of the generated gerbers. The pcbfile is the one listed in the gEDA project file, and the pcbname is the one specified in the :mod:`tendril.gedaif.conffile.ConfigsFile`. This function does not use jinja2 and latex. It relies on :func:`tendril.gedaif.pcb.conv_pcb2gbr` instead. :param projfolder: The gEDA project folder. :type projfolder: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output Files : ``<project_doc_folder>/../gerber/*`` * Output Zip File : ``<project_doc_folder>/../<pcbfile>-gerber.zip`` * Source Files : The project's `.pcb` file. """ configfile = conffile.ConfigsFile(projfolder) gpf = projfile.GedaProjectFile(configfile.projectfolder) pcb_mtime = fsutils.get_file_mtime( os.path.join(configfile.projectfolder, 'pcb', gpf.pcbfile + '.pcb') ) if pcb_mtime is None: logger.warning("PCB does not seem to exist for : " + projfolder) return docfolder = get_project_doc_folder(projfolder) imgfolder = os.path.join(docfolder, os.pardir, 'img') gbrfolder = os.path.join(docfolder, os.pardir, 'gerber') outf_mtime = None if not refdoc_fs.exists(gbrfolder): refdoc_fs.makedir(gbrfolder) else: outf_mtime = fsutils.get_folder_mtime(gbrfolder, fs=refdoc_fs) if not refdoc_fs.exists(imgfolder): refdoc_fs.makedir(imgfolder) if not force and outf_mtime is not None and outf_mtime > pcb_mtime: logger.debug('Skipping up-to-date ' + gbrfolder) return gbrfolder logger.info('Regenerating ' + gbrfolder + os.linesep + 'Last modified : ' + str(pcb_mtime) + '; Last Created : ' + str(outf_mtime)) rf = refdoc_fs.listdir(gbrfolder, files_only=True, full=True) for f in rf: refdoc_fs.remove(f) workspace_folder = workspace_fs.getsyspath(gbrfolder) workspace_fs.makedir(gbrfolder, recursive=True, allow_recreate=True) gbrfolder = pcb.conv_pcb2gbr( os.path.join(configfile.projectfolder, 'pcb', gpf.pcbfile + '.pcb'), workspace_folder ) workspace_fs.makedir(imgfolder, recursive=True, allow_recreate=True) img_workspace_folder = workspace_fs.getsyspath(imgfolder) gen_pcb_img(gbrfolder, outfolder=img_workspace_folder, outfname=gpf.pcbfile, force=False) for f in os.listdir(img_workspace_folder): fpath = os.path.relpath( os.path.join(img_workspace_folder, f), workspace_fs.getsyspath('/') ) copyfile(workspace_fs, fpath, refdoc_fs, fpath, overwrite=True) zfile = os.path.join( workspace_folder, os.pardir, gpf.pcbfile + '-gerber.zip' ) fsutils.zipdir(gbrfolder, zfile) for f in os.listdir(workspace_folder): fpath = os.path.relpath( os.path.join(workspace_folder, f), workspace_fs.getsyspath('/') ) copyfile(workspace_fs, fpath, refdoc_fs, fpath, overwrite=True) zfpath = os.path.relpath( os.path.join(workspace_folder, zfile), workspace_fs.getsyspath('/') ) copyfile(workspace_fs, zfpath, refdoc_fs, zfpath, overwrite=True) return gbrfolder
def gen_confpdf(projfolder, configname, namebase, force=False): """ Generates a PDF file of the documentation for a specific configuration of a project. It uses other document generator functions to make the various parts of the master document and then merges them. :param projfolder: The gEDA project folder. :type projfolder: str :param configname: The name of the configuration. :type configname: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/confdocs/<configname>.pdf`` * Source Files : The project's schematic folder. .. rubric:: Included Documents * Configuration BOM, generated by :func:`gen_confbom` * (Full) Schematic PDF, generated by :func:`gen_schpdf` .. todo:: It may be useful to rebuild the schematics after removing all the unpopulated components. This is a fairly involved process, and is deferred until later. """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) confdocfile = path.join(docfolder, 'confdocs', configname + '.pdf') outf_mtime = fsutils.get_file_mtime(confdocfile, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + confdocfile) return confdocfile logger.info('Regenerating ' + confdocfile + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) pdffiles = [gen_confbom(projfolder, configname, force), gen_confdoc(projfolder, configname, force), gen_schpdf(projfolder, namebase, force)] for p in pdffiles: if p and not workspace_fs.exists(p): workspace_fs.makedir(path.dirname(p), recursive=True, allow_recreate=True) copyfile(refdoc_fs, p, workspace_fs, p) workspace_pdffiles = [workspace_fs.getsyspath(x) for x in pdffiles if x is not None] workspace_outpath = workspace_fs.getsyspath(confdocfile) workspace_fs.makedir(path.dirname(confdocfile), recursive=True, allow_recreate=True) pdf.merge_pdf(workspace_pdffiles, workspace_outpath) copyfile(workspace_fs, confdocfile, refdoc_fs, confdocfile, overwrite=True) return confdocfile
def gen_masterdoc(projfolder, namebase, force=False): """ Generates a PDF file of the project's Master documentation. It uses other document generator functions to make the various parts of the master document and then merges them. .. note:: Due to the way groups and motifs are handled, an unconfigured BOM is somewhat meaningless. Therefore, no BOM is included in the masterdoc. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/<namebase>-masterdoc.pdf`` * Source Files : The project's schematic folder. .. rubric:: Included Documents * Config Documentation, generated by :func:`gen_configsdoc` * Schematic PDF, generated by :func:`gen_schpdf` """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) masterdocfile = path.join(docfolder, namebase + '-masterdoc.pdf') outf_mtime = fsutils.get_file_mtime(masterdocfile, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + masterdocfile) return masterdocfile logger.info('Regnerating ' + masterdocfile + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) pdffiles = [gen_configsdoc(projfolder, namebase, force=False), gen_schpdf(projfolder, namebase, force=False)] for p in pdffiles: if p and not workspace_fs.exists(p): workspace_fs.makedir(path.dirname(p), recursive=True, allow_recreate=True) copyfile(refdoc_fs, p, workspace_fs, p) workspace_pdffiles = [workspace_fs.getsyspath(x) for x in pdffiles if x is not None] workspace_outpath = workspace_fs.getsyspath(masterdocfile) workspace_fs.makedir(path.dirname(masterdocfile), recursive=True, allow_recreate=True) pdf.merge_pdf(workspace_pdffiles, workspace_outpath) copyfile(workspace_fs, masterdocfile, refdoc_fs, masterdocfile, overwrite=True) return masterdocfile
def gen_confdoc(projfolder, configname, force=False): """ Generate a PDF documenting a single configuration of the project. The document should include a reasonably thorough representation of the contents of the configuration related sections of the `tendril.gedaif.conffile.ConfigsFile``. :param projfolder: The gEDA project folder :type projfolder: str :param configname: The configuration name for which the BOM should be generated. :type configname: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/confdocs/<configname>-doc.pdf`` * Source Files : The project's schematic folder. .. rubric:: Template Used ``tendril/dox/templates/projects/geda-conf-doc.tex`` (:download:`Included version <../../tendril/dox/templates/projects/geda-conf-doc.tex>`) .. rubric:: Stage Keys Provided .. list-table:: * - ``configname`` - The name of the configuration (a card or cable name). * - ``desc`` - The description of the configuration. * - ``pcbname`` - The name of the base PCB. * - ``obom`` - An :mod:`tendril.boms.outputbase.OutputBom` instance """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) outpath = path.join(docfolder, 'confdocs', configname + '-doc.pdf') outf_mtime = fsutils.get_file_mtime(outpath, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + outpath) return outpath logger.info('Regenerating ' + outpath + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bom = boms_electronics.import_pcb(projfolder) obom = bom.create_output_bom(configname) group_oboms = bom.get_group_boms(configname) stage = {'configname': obom.descriptor.configname, 'pcbname': obom.descriptor.pcbname, 'bom': bom, 'obom': obom, 'group_oboms': group_oboms} config = obom.descriptor.configurations.configuration(configname) stage['desc'] = config['desc'] template = 'projects/geda-conf-doc.tex' workspace_outpath = workspace_fs.getsyspath(outpath) workspace_fs.makedir(path.dirname(outpath), recursive=True, allow_recreate=True) render.render_pdf(stage, template, workspace_outpath) copyfile(workspace_fs, outpath, refdoc_fs, outpath, overwrite=True) return outpath