def _acq_sym(self, fpath):
        _last_updated = get_file_mtime(fpath)
        with open(fpath, 'r') as f:
            for line in f.readlines():
                if line.startswith('device='):
                    self.device = line.split('=')[1].strip()
                if line.startswith('value='):
                    self.value = line.split('=')[1].strip()
                if line.startswith('footprint'):
                    self.footprint = line.split('=')[1].strip()
                    if self.footprint[0:3] == 'MY-':
                        self.footprint = self.footprint[3:]
                if line.startswith('description'):
                    self.description = line.split('=')[1].strip()
                if line.startswith('status'):
                    self.status = line.split('=')[1].strip()
                if line.startswith('package'):
                    self.package = line.split('=')[1].strip()
                if line.startswith('source'):
                    self.source = line.split('=')[1].strip()
            if self.status == '':
                self.status = 'Active'

        if self.is_generator:
            _genftime = get_file_mtime(self.genpath)
            if _genftime and (not _last_updated or _genftime > _last_updated):
                _last_updated = _genftime
        if self.is_subcircuit:
            _schftime = get_file_mtime(self.schematic_path)
            if _schftime and (not _last_updated or _schftime > _last_updated):
                _last_updated = _schftime
        self.last_updated = _last_updated
예제 #2
0
파일: gsymlib.py 프로젝트: chintal/tendril
    def _acq_sym(self, fpath):
        _last_updated = get_file_mtime(fpath)
        with open(fpath, "r") as f:
            for line in f.readlines():
                if line.startswith("device="):
                    self.device = line.split("=")[1].strip()
                if line.startswith("value="):
                    self.value = line.split("=")[1].strip()
                if line.startswith("footprint"):
                    self.footprint = line.split("=")[1].strip()
                    if self.footprint[0:3] == "MY-":
                        self.footprint = self.footprint[3:]
                if line.startswith("description"):
                    self.description = line.split("=")[1].strip()
                if line.startswith("status"):
                    self.status = line.split("=")[1].strip()
                if line.startswith("package"):
                    self.package = line.split("=")[1].strip()
                if line.startswith("source"):
                    self.source = line.split("=")[1].strip()
            if self.status == "":
                self.status = "Active"

        if self.is_generator:
            _genftime = get_file_mtime(self.genpath)
            if not _genftime or _genftime > _last_updated:
                _last_updated = _genftime
        if self.is_subcircuit:
            _schftime = get_file_mtime(self.schematic_path)
            if not _last_updated or _schftime > _last_updated:
                _last_updated = _schftime
        self.last_updated = _last_updated
예제 #3
0
def gen_pcb_dxf(projfolder, force=False):
    """
    Generates a DXF file of the PCB provided by the gEDA project.

    The pcb file 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.connectors.geda.pcb.conv_pcb2dxf` 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 File :  ``<projectfolder>/pcb/<pcbfile>.dxf``
    * 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)
    dxffile = path.normpath(os.path.join(docfolder, os.pardir,
                            configfile.pcbname + '.dxf'))
    bottom_dxffile = path.normpath(os.path.join(docfolder, os.pardir,
                                   configfile.pcbname + 'bottom.dxf'))

    outf_mtime = fsutils.get_file_mtime(dxffile, fs=refdoc_fs)

    if not force and outf_mtime is not None and outf_mtime > pcb_mtime:
        logger.debug('Skipping up-to-date ' + dxffile)
        return dxffile

    logger.info('Regenerating ' + dxffile + os.linesep +
                'Last modified : ' + str(pcb_mtime) +
                '; Last Created : ' + str(outf_mtime))

    workspace_folder = workspace_fs.getsyspath(path.dirname(dxffile))
    workspace_fs.makedir(path.dirname(dxffile),
                         recursive=True, allow_recreate=True)

    pcb.conv_pcb2dxf(
        os.path.join(configfile.projectfolder, 'pcb', gpf.pcbfile + '.pcb'),
        workspace_folder, configfile.pcbname
    )

    copyfile(workspace_fs, dxffile, refdoc_fs, dxffile, overwrite=True)
    copyfile(workspace_fs, bottom_dxffile, refdoc_fs, bottom_dxffile, overwrite=True)
    return dxffile
예제 #4
0
def gen_pcb_dxf(projfolder, force=False):
    """
    Generates a DXF file of the PCB provided by the gEDA project.

    The pcb file 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_pcb2dxf` 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 File :  ``<projectfolder>/pcb/<pcbfile>.dxf``
    * 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)
    dxffile = path.normpath(os.path.join(docfolder, os.pardir,
                            configfile.pcbname + '.dxf'))
    bottom_dxffile = path.normpath(os.path.join(docfolder, os.pardir,
                                   configfile.pcbname + 'bottom.dxf'))

    outf_mtime = fsutils.get_file_mtime(dxffile, fs=refdoc_fs)

    if not force and outf_mtime is not None and outf_mtime > pcb_mtime:
        logger.debug('Skipping up-to-date ' + dxffile)
        return dxffile

    logger.info('Regenerating ' + dxffile + os.linesep +
                'Last modified : ' + str(pcb_mtime) +
                '; Last Created : ' + str(outf_mtime))

    workspace_folder = workspace_fs.getsyspath(path.dirname(dxffile))
    workspace_fs.makedir(path.dirname(dxffile),
                         recursive=True, allow_recreate=True)

    pcb.conv_pcb2dxf(
        os.path.join(configfile.projectfolder, 'pcb', gpf.pcbfile + '.pcb'),
        workspace_folder, configfile.pcbname
    )

    copyfile(workspace_fs, dxffile, refdoc_fs, dxffile, overwrite=True)
    copyfile(workspace_fs, bottom_dxffile, refdoc_fs, bottom_dxffile, overwrite=True)
    return dxffile
예제 #5
0
파일: gsymlib.py 프로젝트: chintal/tendril
 def _sch_img_repr(self):
     outfolder = os.path.join(INSTANCE_CACHE, "gsymlib")
     self._sch_img_repr_fname = self.source + ".png"
     self._sch_img_repr_path = os.path.join(outfolder, self._sch_img_repr_fname)
     if not os.path.exists(outfolder):
         os.makedirs(outfolder)
     if os.path.exists(self._sch_img_repr_path):
         if get_file_mtime(self._sch_img_repr_path) > get_file_mtime(self.schematic_path):  # noqa
             return
     if MAKE_GSYMLIB_IMG_CACHE:
         conv_gsch2png(self.schematic_path, outfolder, include_extension=True)
예제 #6
0
파일: gsymlib.py 프로젝트: chintal/tendril
 def _generate_img_repr(self):
     outfolder = os.path.join(INSTANCE_CACHE, "gsymlib")
     self._img_repr_fname = os.path.splitext(self.fname)[0] + ".png"
     self._img_repr_path = os.path.join(outfolder, self._img_repr_fname)
     if not os.path.exists(outfolder):
         os.makedirs(outfolder)
     if os.path.exists(self._img_repr_path):
         if get_file_mtime(self._img_repr_path) > get_file_mtime(self.fpath):  # noqa
             return
     if MAKE_GSYMLIB_IMG_CACHE:
         conv_gsch2png(self.fpath, outfolder)
예제 #7
0
파일: gsymlib.py 프로젝트: SayCV/tendril
 def _generate_img_repr(self):
     outfolder = os.path.join(INSTANCE_CACHE, 'gsymlib')
     self._img_repr_fname = os.path.splitext(self.fname)[0] + '.png'
     self._img_repr_path = os.path.join(outfolder, self._img_repr_fname)
     if not os.path.exists(outfolder):
         os.makedirs(outfolder)
     if os.path.exists(self._img_repr_path):
         if get_file_mtime(self._img_repr_path) > get_file_mtime(
                 self.fpath):  # noqa
             return
     if MAKE_GSYMLIB_IMG_CACHE:
         conv_gsch2png(self.fpath, outfolder)
 def _generate_img_repr(self):
     if not MAKE_GSYMLIB_IMG_CACHE:
         return
     outfolder = os.path.join(INSTANCE_CACHE, 'esymlib.geda')
     self._img_repr_path = os.path.join(outfolder, self.img_repr_fname)
     if not os.path.exists(outfolder):
         os.makedirs(outfolder)
     if os.path.exists(self._img_repr_path):
         if get_file_mtime(self._img_repr_path) > get_file_mtime(
                 self.fpath):  # noqa
             return
     conv_gsch2png(self.fpath, outfolder)
예제 #9
0
def generate_pcb_pricing(projfolder, noregen=True, forceregen=False):
    gpf = projfile.GedaProjectFile(projfolder)

    try:
        pcbparams = gpf.configsfile.configdata['pcbdetails']['params']
    except KeyError:
        logger.warning('Geda project does not seem have pcb details. '
                       'Not generating PCB pricing information : ' +
                       projfolder)
        return None

    try:
        if gpf.configsfile.configdata['pcbdetails']['params'][
                'panelize'] is True:
            logger.warning('Not obtaining pricing for panelized pcb : ' +
                           projfolder)
            return None
    except KeyError:
        pass

    try:
        searchparams = gpf.configsfile.configdata['pcbdetails'][
            'indicativepricing']
    except KeyError:
        searchparams = {
            'qty': 20,
            'dterm': 7,
        }

    pricingfp = os.path.join(gpf.configsfile.projectfolder, 'pcb',
                             'sourcing.yaml')

    if noregen is True:
        if os.path.exists(pricingfp):
            return pricingfp
    if forceregen is False:
        pcb_mtime = fsutils.get_file_mtime(
            os.path.join(gpf.configsfile.projectfolder, 'pcb',
                         gpf.pcbfile + '.pcb'))  # noqa
        outf_mtime = fsutils.get_file_mtime(pricingfp)
        if outf_mtime is not None and outf_mtime > pcb_mtime:
            logger.info('Skipping up-to-date ' + pricingfp)
            return pricingfp
    logger.info('Generating PCB Pricing for ' + pricingfp)

    pcbparams['qty'] = range(searchparams['qty'])
    sourcingdata = get_csil_prices(pcbparams)
    dumpdata = {'params': pcbparams, 'pricing': sourcingdata}

    with open(pricingfp, 'w') as pricingf:
        pricingf.write(yaml.dump(dumpdata))

    return pricingfp
예제 #10
0
파일: csil.py 프로젝트: chintal/tendril
def generate_pcb_pricing(projfolder, noregen=True, forceregen=False):
    gpf = projfile.GedaProjectFile(projfolder)

    try:
        pcbparams = gpf.configsfile.configdata['pcbdetails']['params']
    except KeyError:
        logger.warning(
            'Geda project does not seem have pcb details. '
            'Not generating PCB pricing information : ' +
            projfolder)
        return None

    try:
        if gpf.configsfile.configdata['pcbdetails']['params']['panelize'] is True:
            logger.warning(
                'Not obtaining pricing for panelized pcb : ' + projfolder
            )
            return None
    except KeyError:
        pass

    try:
        searchparams = gpf.configsfile.configdata['pcbdetails']['indicativepricing']
    except KeyError:
        searchparams = {
            'qty': 20,
            'dterm': 7,
        }

    pricingfp = os.path.join(gpf.configsfile.projectfolder,
                             'pcb', 'sourcing.yaml')

    if noregen is True:
        if os.path.exists(pricingfp):
            return pricingfp
    if forceregen is False:
        pcb_mtime = fsutils.get_file_mtime(os.path.join(gpf.configsfile.projectfolder, 'pcb', gpf.pcbfile + '.pcb'))  # noqa
        outf_mtime = fsutils.get_file_mtime(pricingfp)
        if outf_mtime is not None and outf_mtime > pcb_mtime:
            logger.info('Skipping up-to-date ' + pricingfp)
            return pricingfp
    logger.info('Generating PCB Pricing for ' + pricingfp)

    pcbparams['qty'] = range(searchparams['qty'])
    sourcingdata = get_csil_prices(pcbparams)
    dumpdata = {'params': pcbparams,
                'pricing': sourcingdata}

    with open(pricingfp, 'w') as pricingf:
        pricingf.write(yaml.dump(dumpdata))

    return pricingfp
 def _generate_sch_img_repr(self):
     if not MAKE_GSYMLIB_IMG_CACHE:
         return
     outfolder = os.path.join(INSTANCE_CACHE, 'esymlib.geda')
     self._sch_img_repr_fname = self.source + '.png'
     self._sch_img_repr_path = os.path.join(outfolder,
                                            self._sch_img_repr_fname)
     if not os.path.exists(outfolder):
         os.makedirs(outfolder)
     if os.path.exists(self._sch_img_repr_path):
         if get_file_mtime(self._sch_img_repr_path) > get_file_mtime(
                 self.schematic_path):  # noqa
             return
     conv_gsch2png(self.schematic_path, outfolder, include_extension=True)
예제 #12
0
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)
예제 #13
0
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)
예제 #14
0
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
예제 #15
0
    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')
예제 #16
0
    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')
예제 #17
0
 def __init__(self, name, dname, pclass, mappath=None,
              currency_code=None, currency_symbol=None,
              pricelistpath=None, **kwargs):
     if pricelistpath is None:
         pricelistpath = os.path.join(PRICELISTVENDORS_FOLDER,
                                      name + '-pricelist.yaml')
     with open(pricelistpath, 'r') as f:
         self._pricelist = yaml.load(f)
     self._last_updated = get_file_mtime(pricelistpath)
     if currency_code is None:
         currency_code = self._pricelist["currency"]["code"].strip()
     if currency_symbol is None:
         currency_symbol = self._pricelist["currency"]["symbol"].strip()
     self._currency = currency.CurrencyDefinition(
         currency_code, currency_symbol
     )
     super(VendorPricelist, self).__init__(name, dname, pclass, mappath,
                                           currency_code, currency_symbol,
                                           **kwargs)
     if 'vendorinfo' in self._pricelist:
         if "effectivefactor" in self._pricelist["vendorinfo"]:
             self.add_order_additional_cost_component(
                 "Unspecified",
                 self._pricelist["vendorinfo"]["effectivefactor"] * 100
             )
     self._vpart_class = PricelistPart
     try:
         self.add_order_baseprice_component(
             "Shipping Cost",
             self._pricelist["vendorinfo"]["shippingcost"]
         )
     except KeyError:
         pass
     if "prices" not in self._pricelist:
         try:
             pass
         except:
             logger.error("No prices found for " + self.name)
     if "pricegens" in self._pricelist:
         self._generate_insert_idents()
     if "pricecsv" in self._pricelist:
         self._load_pricecsv(self._pricelist["pricecsv"])
예제 #18
0
파일: pricelist.py 프로젝트: SayCV/tendril
 def __init__(self,
              name,
              dname,
              pclass,
              mappath=None,
              currency_code=None,
              currency_symbol=None,
              pricelistpath=None,
              **kwargs):
     if pricelistpath is None:
         pricelistpath = os.path.join(PRICELISTVENDORS_FOLDER,
                                      name + '-pricelist.yaml')
     with open(pricelistpath, 'r') as f:
         self._pricelist = yaml.load(f)
     self._last_updated = get_file_mtime(pricelistpath)
     if currency_code is None:
         currency_code = self._pricelist["currency"]["code"].strip()
     if currency_symbol is None:
         currency_symbol = self._pricelist["currency"]["symbol"].strip()
     self._currency = currency.CurrencyDefinition(currency_code,
                                                  currency_symbol)
     super(VendorPricelist,
           self).__init__(name, dname, pclass, mappath, currency_code,
                          currency_symbol, **kwargs)
     if 'vendorinfo' in self._pricelist:
         if "effectivefactor" in self._pricelist["vendorinfo"]:
             self.add_order_additional_cost_component(
                 "Unspecified",
                 self._pricelist["vendorinfo"]["effectivefactor"] * 100)
     self._vpart_class = PricelistPart
     try:
         self.add_order_baseprice_component(
             "Shipping Cost", self._pricelist["vendorinfo"]["shippingcost"])
     except KeyError:
         pass
     if "prices" not in self._pricelist:
         logger.error("No prices found for " + self.name)
     if "pricegens" in self._pricelist:
         self._generate_insert_idents()
     if "pricecsv" in self._pricelist:
         self._load_pricecsv(self._pricelist["pricecsv"])
예제 #19
0
 def _load_pricecsv(self, fname):
     pricecsvpath = os.path.join(PRICELISTVENDORS_FOLDER, fname)
     self._last_updated = get_file_mtime(pricecsvpath)
     with open(pricecsvpath, 'r') as f:
         reader = csv.reader(f)
         for line in reader:
             line = [elem.strip() for elem in line]
             if line[0] == '':
                 continue
             if line[0] == 'ident':
                 continue
             partdict = {'ident': line[0],
                         'vpno': line[1],
                         'unitp': float(line[2]),
                         'moq': int(line[3]),
                         'oqmultiple': int(line[4]),
                         'pkgqty': int(line[5])}
             try:
                 partdict['avail'] = int(line[6])
             except ValueError:
                 partdict['avail'] = None
             self._pricelist["prices"].append(partdict)
예제 #20
0
파일: pricelist.py 프로젝트: SayCV/tendril
 def _load_pricecsv(self, fname):
     pricecsvpath = os.path.join(PRICELISTVENDORS_FOLDER, fname)
     self._last_updated = get_file_mtime(pricecsvpath)
     with open(pricecsvpath, 'r') as f:
         reader = csv.reader(f)
         for line in reader:
             line = [elem.strip() for elem in line]
             if line[0] == '':
                 continue
             if line[0] == 'ident':
                 continue
             partdict = {
                 'ident': line[0],
                 'vpno': line[1],
                 'unitp': float(line[2]),
                 'moq': int(line[3]),
                 'oqmultiple': int(line[4]),
                 'pkgqty': int(line[5])
             }
             try:
                 partdict['avail'] = int(line[6])
             except ValueError:
                 partdict['avail'] = None
             self._pricelist["prices"].append(partdict)
예제 #21
0
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
예제 #22
0
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
예제 #23
0
파일: maps.py 프로젝트: chintal/tendril
 def get_map_time(self, canonical):
     return get_file_mtime(self._mappath)
예제 #24
0
파일: maps.py 프로젝트: SayCV/tendril
 def get_map_time(self, canonical):
     return get_file_mtime(self._mappath)
예제 #25
0
def gen_pcbpricing(projfolder, namebase, force=False):
    """
    Generates a PDF file with the pricing of the (bare) PCB provided by the
    gEDA project.

    The pcb file is the one listed in the gEDA project file, and the
    pcbname is the one specified in the
    :mod:`tendril.gedaif.conffile.ConfigsFile`. The pricing information is
    read out from the PCB's ``sourcing.yaml`` file, which in turn is intended
    to be created by sourcing modules.

    .. todo:: This function presently uses
              :func:`tendril.dox.render.render_lineplot`, which is marked for
              deprecation. It should be rewritten to use the
              :func:`tendril.dox.render.make_graph` route 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>-pricing.pdf``
    * Source Files : ``<projectfolder>/pcb/sourcing.yaml``

    """
    gpf = projfile.GedaProjectFile(projfolder)
    pcbpricingfp = os.path.join(gpf.configsfile.projectfolder, 'pcb',
                                'sourcing.yaml')
    pcbpricing_mtime = fsutils.get_file_mtime(pcbpricingfp)

    if not os.path.exists(pcbpricingfp):
        return None

    docfolder = get_project_doc_folder(projfolder)
    plotfile = path.join(docfolder, namebase + '-pricing.pdf')
    outf_mtime = fsutils.get_file_mtime(plotfile, fs=refdoc_fs)

    if not force and outf_mtime is not None and outf_mtime > pcbpricing_mtime:
        logger.debug('Skipping up-to-date ' + pcbpricingfp)
        return pcbpricingfp

    logger.info('Regnerating ' + plotfile + os.linesep + 'Last modified : ' +
                str(pcbpricing_mtime) + '; Last Created : ' + str(outf_mtime))

    with open(pcbpricingfp, 'r') as f:
        data = yaml.load(f)

    workspace_outpath = workspace_fs.getsyspath(plotfile)
    workspace_folder = workspace_fs.getsyspath(path.dirname(plotfile))
    workspace_fs.makedir(path.dirname(plotfile),
                         recursive=True,
                         allow_recreate=True)

    plot1file = os.path.join(workspace_folder, namebase + '-1pricing.pdf')
    plot2file = os.path.join(workspace_folder, namebase + '-2pricing.pdf')

    pltnote = "This pricing refers to the bare PCB only. " \
              "See the corresponding Config Docs for Card Pricing"

    plt1data = {
        key: data['pricing'][key]
        for key in data['pricing'].keys() if key <= 10
    }
    plt1title = gpf.configsfile.configdata['pcbname']
    plt1title += " PCB Unit Price vs Order Quantity (Low Quantity)"
    plot1file = render.render_lineplot(plot1file, plt1data, plt1title, pltnote)

    if max(data['pricing'].keys()) > 10:
        plt2data = {
            key: data['pricing'][key]
            for key in data['pricing'].keys() if key > 10
        }
        plt2title = gpf.configsfile.configdata['pcbname']
        plt2title += " PCB Unit Price vs Order Quantity (Production Quantity)"
        plot2file = render.render_lineplot(plot2file, plt2data, plt2title,
                                           pltnote)
        pdf.merge_pdf([plot1file, plot2file], workspace_outpath)
        os.remove(plot2file)
    else:
        shutil.copyfile(plot1file, workspace_outpath)
    os.remove(plot1file)
    copyfile(workspace_fs, plotfile, refdoc_fs, plotfile, overwrite=True)
    return plotfile
예제 #26
0
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
예제 #27
0
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
예제 #28
0
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
예제 #29
0
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
예제 #30
0
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
예제 #31
0
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
예제 #32
0
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
예제 #33
0
def gen_pcbpricing(projfolder, namebase, force=False):
    """
    Generates a PDF file with the pricing of the (bare) PCB provided by the
    gEDA project.

    The pcb file is the one listed in the gEDA project file, and the
    pcbname is the one specified in the
    :mod:`tendril.gedaif.conffile.ConfigsFile`. The pricing information is
    read out from the PCB's ``sourcing.yaml`` file, which in turn is intended
    to be created by sourcing modules.

    .. todo:: This function presently uses
              :func:`tendril.dox.render.render_lineplot`, which is marked for
              deprecation. It should be rewritten to use the
              :func:`tendril.dox.render.make_graph` route 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>-pricing.pdf``
    * Source Files : ``<projectfolder>/pcb/sourcing.yaml``

    """
    gpf = projfile.GedaProjectFile(projfolder)
    pcbpricingfp = os.path.join(
        gpf.configsfile.projectfolder, 'pcb', 'sourcing.yaml'
    )
    pcbpricing_mtime = fsutils.get_file_mtime(pcbpricingfp)

    if not os.path.exists(pcbpricingfp):
        return None

    docfolder = get_project_doc_folder(projfolder)
    plotfile = path.join(docfolder, namebase + '-pricing.pdf')
    outf_mtime = fsutils.get_file_mtime(plotfile, fs=refdoc_fs)

    if not force and outf_mtime is not None and outf_mtime > pcbpricing_mtime:
        logger.debug('Skipping up-to-date ' + pcbpricingfp)
        return pcbpricingfp

    logger.info('Regnerating ' + plotfile + os.linesep +
                'Last modified : ' + str(pcbpricing_mtime) +
                '; Last Created : ' + str(outf_mtime))

    with open(pcbpricingfp, 'r') as f:
        data = yaml.load(f)

    workspace_outpath = workspace_fs.getsyspath(plotfile)
    workspace_folder = workspace_fs.getsyspath(path.dirname(plotfile))
    workspace_fs.makedir(path.dirname(plotfile),
                         recursive=True, allow_recreate=True)

    plot1file = os.path.join(workspace_folder, namebase + '-1pricing.pdf')
    plot2file = os.path.join(workspace_folder, namebase + '-2pricing.pdf')

    pltnote = "This pricing refers to the bare PCB only. " \
              "See the corresponding Config Docs for Card Pricing"

    plt1data = {key: data['pricing'][key]
                for key in data['pricing'].keys() if key <= 10}
    plt1title = gpf.configsfile.configdata['pcbname']
    plt1title += " PCB Unit Price vs Order Quantity (Low Quantity)"
    plot1file = render.render_lineplot(
        plot1file, plt1data, plt1title, pltnote
    )

    if max(data['pricing'].keys()) > 10:
        plt2data = {key: data['pricing'][key]
                    for key in data['pricing'].keys() if key > 10}
        plt2title = gpf.configsfile.configdata['pcbname']
        plt2title += " PCB Unit Price vs Order Quantity (Production Quantity)"
        plot2file = render.render_lineplot(
            plot2file, plt2data, plt2title, pltnote
        )
        pdf.merge_pdf([plot1file, plot2file], workspace_outpath)
        os.remove(plot2file)
    else:
        shutil.copyfile(plot1file, workspace_outpath)
    os.remove(plot1file)
    copyfile(workspace_fs, plotfile, refdoc_fs, plotfile, overwrite=True)
    return plotfile