def copy_docs_to_workspace(serialno=None, workspace=None, clearws=False, setwsno=True, fs=None, session=None): if serialno is None: raise AttributeError('serialno cannot be None') if fs is None: fs = workspace_fs if workspace is None: workspace = fs.makeopendir('workspace', recursive=True) elif workspace.startswith('/'): raise ValueError('workspace should be a relative path') else: workspace = fs.makeopendir(workspace, recursive=True) if clearws is True: for p in workspace.listdir(dirs_only=True): workspace.removedir(p, force=True) for p in workspace.listdir(files_only=True): workspace.remove(p) if setwsno is True: with workspace.open('wsno', 'wb') as f: f.write(serialno) for doc in controller.get_sno_documents(serialno=serialno, session=session): docname = os.path.split(doc.docpath)[1] if docname.startswith(serialno): if not os.path.splitext(docname)[0] == serialno: docname = docname[len(serialno) + 1:] copyfile(docstore_fs, doc.docpath, workspace, docname)
def _copy_files(self, src, dst, path, src_i, dst_i, files, truncated= False, depth= 0, cached_status= None,verbose=True): if verbose and files: print "\t"*depth+"Copy files" status= cached_status for file, info in files: if verbose: print "\t"*depth+"Object: "+file if not cached_status or cached_status==PathStatus.ignore or not self.cache_file_status: status= self.config.GetPathStatus(path+[file]) if status==PathStatus.include: src_index= None dst_index= None src_mtime= info["modified_time"] src_filesize= info["size"] try: copyfile(src, file, dst, file) #Change mod of newly created file #to mod of a source file dst.chmod(file, get_fmod(info)) except: continue if src_filesize>=0: print "Sync synch synch..............................." src_index= src_i.GetPathPart([src_i.name,file], True) dst_index= dst_i.GetPathPart([dst_i.name,file], True) src_index.CreationTime= self.dt2ut(src_mtime) dst_index.CreationTime= self.dt2ut(dst.getinfo(file)["modified_time"]) if status==PathStatus.stop: if verbose: print "\t"*depth+"Removing file" src.remove(file)
def copy_docs_to_workspace(serialno=None, workspace=None, clearws=False, setwsno=True, fs=None, session=None): if serialno is None: raise AttributeError("serialno cannot be None") if fs is None: fs = workspace_fs if workspace is None: workspace = fs.makeopendir("workspace", recursive=True) elif workspace.startswith("/"): raise ValueError("workspace should be a relative path") else: workspace = fs.makeopendir(workspace, recursive=True) if clearws is True: for p in workspace.listdir(dirs_only=True): workspace.removedir(p, force=True) for p in workspace.listdir(files_only=True): workspace.remove(p) if setwsno is True: with workspace.open("wsno", "wb") as f: f.write(serialno) for doc in controller.get_sno_documents(serialno=serialno, session=session): docname = os.path.split(doc.docpath)[1] if docname.startswith(serialno): if not os.path.splitext(docname)[0] == serialno: docname = docname[len(serialno) + 1 :] copyfile(docstore_fs, doc.docpath, workspace, docname)
def copy_file(source_fs, source_path, target_fs, target_path, overwrite=True, create_directory=True, chunk_size=64 * 1024): """ Copy a file from one filesystem/path to another filesystem/path. This will create the target directory if necessary, unless create_directory is set to False. """ try: utils.copyfile(source_fs, source_path, target_fs, target_path, overwrite=overwrite, chunk_size=chunk_size) except ParentDirectoryMissingError: if create_directory: target_fs.makedir(os.path.dirname(target_path), recursive=True, allow_recreate=True) utils.copyfile(source_fs, source_path, target_fs, target_path, overwrite=overwrite, chunk_size=chunk_size) else: raise
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
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
def patchfile(self, path): """Patch remote file with new user file if size has changed""" user_info = self.userfs.getinfo(path) remote_info = self.remotefs.getinfo(path) if user_info["size"] != remote_info["size"]: copyfile(self.userfs, path, self.remotefs, path, overwrite=True) print(term.yellow + " " * 4 + "updated " + path + term.normal)
def copy(self, dst, **kwargs): """Copy file to a new destination. Returns JSON Patch with proposed change pointing to new copy. """ _fs, filename = opener.parse(self.uri) _fs_dst, filename_dst = opener.parse(dst) copyfile(_fs, filename, _fs_dst, filename_dst, **kwargs) return [{'op': 'replace', 'path': self.pointer, 'value': dst}]
def copy_new(src, dst): """Copy files from src fs to dst fst only if they don't exist on dst""" from fs.utils import copystructure, copyfile copystructure(src, dst) copied_files = [] for path in src.walkfiles(): if not dst.exists(path): copyfile(src, path, dst, path) copied_files.append(path) return copied_files
def insert_document(sno, docpath, series): fname = os.path.split(docpath)[1] if not fname.startswith(sno) and not os.path.splitext(fname)[0].endswith(sno): fname = sno + "-" + fname if series is None: series = serialnos.get_series(sno) storepath = path.join(series, fname) if not docstore_fs.exists(path.dirname(storepath)): docstore_fs.makedir(path.dirname(storepath), recursive=True) copyfile(local_fs, docpath, docstore_fs, storepath) return storepath
def sync_files(self): """Copy files that don't exist on remote fs or patch them if they do exist""" if self.mode != "update": raise NotImplementedError("Only the update mode has been implemented yet.") for path in self.userfs.walkfiles(): if self.remotefs.exists(path): self.patchfile(path) else: copyfile(self.userfs, path, self.remotefs, path, overwrite=False) print(term.green + " " * 4 + "copied " + path + term.normal)
def get_sendable_path(fspath, fs, fs_root): if isinstance(fs, OSFS): path = os.path.join(fs_root, fspath) else: path = temp_expose_fs.getsyspath(fspath) if not temp_expose_fs.exists(fspath): temp_expose_fs.makedir(os.path.split(fspath)[0], recursive=True, allow_recreate=True) copyfile(fs, fspath, temp_expose_fs, fspath) return path
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 insert_document(sno, docpath, series): fname = os.path.split(docpath)[1] if not fname.startswith(sno) and \ not os.path.splitext(fname)[0].endswith(sno): fname = sno + '-' + fname if series is None: series = serialnos.get_series(sno) storepath = path.join(series, fname) if not docstore_fs.exists(path.dirname(storepath)): docstore_fs.makedir(path.dirname(storepath), recursive=True) copyfile(local_fs, docpath, docstore_fs, storepath) return storepath
def sync_files(self): """Copy files that don't exist on remote fs or patch them if they do exist""" if self.mode != "update": raise NotImplementedError( "Only the update mode has been implemented yet.") for path in self.userfs.walkfiles(): if self.remotefs.exists(path): self.patchfile(path) else: copyfile(self.userfs, path, self.remotefs, path, overwrite=False) print(term.green + " " * 4 + "copied " + path + term.normal)
def get_sendable_path(fspath, fs, fs_root): if isinstance(fs, OSFS): path = os.path.join(fs_root, fspath) else: path = temp_expose_fs.getsyspath(fspath) if not temp_expose_fs.exists(fspath): temp_expose_fs.makedir( os.path.split(fspath)[0], recursive=True, allow_recreate=True ) copyfile( fs, fspath, temp_expose_fs, fspath ) return path
def get_production_order_manifest_set(serialno): workspace = temp_fs.makeopendir(get_tempname()) children = serialnos.get_child_serialnos(sno=serialno) manifests = [] for child in children: files = [] am = docstore.get_docs_list_for_sno_doctype(serialno=child, doctype='ASSEMBLY MANIFEST') if len(am) == 1: uam = am[0] copyfile(uam.fs, uam.path, workspace, uam.filename, overwrite=True) files = [workspace.getsyspath(uam.filename)] elif len(am) > 1: raise ValueError( "Found {0} manifests for {2}".format(len(am), child) ) dms = docstore.get_docs_list_for_sno_doctype( serialno=child, doctype='DELTA ASSEMBLY MANIFEST' ) if len(dms): for dm in dms: copyfile(dm.fs, dm.path, workspace, dm.filename, overwrite=True) files.append(workspace.getsyspath(dm.filename)) if len(files) > 1: wdmfile = merge_pdf( files, os.path.join(workspace.getsyspath('/'), os.path.splitext(am[0].filename)[0] + '-wdm.pdf'), remove_sources=True ) manifests.append(wdmfile) elif len(files) == 1: manifests.append(files[0]) if len(manifests): output = merge_pdf( manifests, os.path.join(workspace.getsyspath('/'), serialno + '.pdf'), remove_sources=True ) return output return None
def get_production_order_manifest_set(serialno): workspace = temp_fs.makeopendir(get_tempname()) children = serialnos.get_child_serialnos(sno=serialno) manifests = [] for child in children: files = [] am = docstore.get_docs_list_for_sno_doctype( serialno=child, doctype='ASSEMBLY MANIFEST') if len(am) == 1: uam = am[0] copyfile(uam.fs, uam.path, workspace, uam.filename, overwrite=True) files = [workspace.getsyspath(uam.filename)] elif len(am) > 1: raise ValueError("Found {0} manifests for {2}".format( len(am), child)) dms = docstore.get_docs_list_for_sno_doctype( serialno=child, doctype='DELTA ASSEMBLY MANIFEST') if len(dms): for dm in dms: copyfile(dm.fs, dm.path, workspace, dm.filename, overwrite=True) files.append(workspace.getsyspath(dm.filename)) if len(files) > 1: wdmfile = merge_pdf( files, os.path.join(workspace.getsyspath('/'), os.path.splitext(am[0].filename)[0] + '-wdm.pdf'), remove_sources=True) manifests.append(wdmfile) elif len(files) == 1: manifests.append(files[0]) if len(manifests): output = merge_pdf(manifests, os.path.join(workspace.getsyspath('/'), serialno + '.pdf'), remove_sources=True) return output return None
def build(src_fs, dst_fs): """Build a firmware""" if not src_fs.exists('firmware.conf'): src_fs.setcontents('firmware.conf', DEFAULT_FIRMWARE_CONF) cfg = SafeConfigParser() with src_fs.open('firmware.conf') as f: cfg.readfp(f) version = int(cfg.get('firmware', 'version')) exclude = _get_list(cfg.get('firmware', 'exclude')) def wildcard(path): return not any(fnmatch(basename(path), wildcard) for wildcard in exclude) for file_path in src_fs.walkfiles(wildcard=wildcard, dir_wildcard=wildcard): copyfile(src_fs, file_path, dst_fs, file_path) return version
def _process_files(self, metadata): """Transfer files in a list from one ``fs`` object to another. All tranferer files will maintain the same filename. """ # FS object created at the folder of where the record specific bag is fs_dest = opener.opendir(self.folder, "files", create_dir=True) files_to_upload = [] for file_to_upload in metadata.get("files", []): dirname_ = os.path.dirname(file_to_upload["path"]) basename_ = os.path.basename(file_to_upload["path"]) fs_src = opener.opendir(dirname_) copyfile(fs_src, basename_, fs_dest, basename_) file_to_upload["path"] = os.path.join("files", basename_) del file_to_upload["url"] files_to_upload.append(file_to_upload) metadata["files_to_upload"] = files_to_upload return metadata
def transfer_data_files(self): """Transfer files in a list from one ``fs`` object to another. All tranferer files will maintain the same filename. """ # FS object created at the folder of where the record specific bag is fs_dest = opener.opendir(self.bagit_folder_path, create_dir=True) try: for docfile in self.docfiles: fs_src = opener.opendir(os.path.dirname(docfile.get_path())) copyfile(fs_src, os.path.basename(docfile.get_path()), fs_dest, os.path.basename(docfile.get_path())) except Exception: raise ArchiverError("Error while copying %s to %s" % (docfile.get_path(), os.path.join(self.bagit_folder_path, docfile.name + docfile.format))) return True
def get_document_path(key): """ Returns the absolute path to the document in the wallet referred to by the ``key``. If the wallet fs root is not an OS filesystem, then it copies the wallet document into the temporary folder and returns the path to it. :param key: Key of the document you want. :return: The absolute path to the document. """ if key in DOCUMENT_WALLET.keys(): try: return wallet_fs.getsyspath(DOCUMENT_WALLET[key]) except NoSysPathError: if not wallet_temp_fs.exists(DOCUMENT_WALLET[key]): copyfile(wallet_fs, DOCUMENT_WALLET[key], wallet_temp_fs, DOCUMENT_WALLET[key]) return wallet_temp_fs.getsyspath(DOCUMENT_WALLET[key]) else: raise ValueError
def _accessor(self, max_age, getcpath=False, *args, **kwargs): """ The primary accessor for the cache instance. Each subclass should provide a function which behaves similarly to that of the original, un-cached version of the resource getter. That function should adapt the parameters provided to it into the form needed for this one, and let this function maintain the cached responses and handle retrieval of the response. If the module's :data:`_internet_connected` is set to False, the cached value is returned regardless. """ filepath = self._get_filepath(*args, **kwargs) send_cached = False if not _internet_connected and self._cached_exists(filepath): send_cached = True if self._is_cache_fresh(filepath, max_age): logger.debug("Cache HIT") send_cached = True if send_cached is True: if getcpath is False: try: filecontent = self.cache_fs.open(filepath, 'rb').read() return self._deserialize(filecontent) except UnicodeDecodeError: # TODO This requires the cache_fs to be a local # filesystem. This may not be very nice. A way # to hook codecs upto to pyfilesystems would be better with codecs.open(self.cache_fs.getsyspath(filepath), encoding='utf-8') as f: filecontent = f.read() return self._deserialize(filecontent) else: return self.cache_fs.getsyspath(filepath) logger.debug("Cache MISS") data = self._get_fresh_content(*args, **kwargs) try: sdata = self._serialize(data) fd, temppath = tempfile.mkstemp() fp = os.fdopen(fd, 'wb') fp.write(sdata) fp.close() logger.debug("Creating new cache entry") # This can be pretty expensive if the move is across a real # filesystem boundary. We should instead use a temporary file # in the cache_fs itself try: copyfile(temp_fs, temp_fs.unsyspath(temppath), self.cache_fs, filepath) if isinstance(self.cache_fs, OSFS): # TODO Refine permissions os.chmod(self.cache_fs.getsyspath(filepath), 0o666) except (KeyboardInterrupt, SystemExit): raise except: logger.warning("Unable to write cache file " "{0}".format(filepath)) except: raise if getcpath is False: return data else: return self.cache_fs.getsyspath(filepath)
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_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
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_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 _update_files(self, src, dst, path, src_i, dst_i, files, truncated= False, depth= 0, cached_status= None,verbose=True): if verbose and files: print "\t"*depth+"Update files" status= cached_status for file, sinfo, dinfo in files: if verbose: print "\t"*depth+"Object: "+file if not cached_status or not self.cache_file_status: (truncated, status)= self.config.GetPathStatus(path+[file], True) if status==PathStatus.include: src_index= None dst_index= None src_mtime= sinfo["modified_time"] src_filesize= src.getsize(file) dst_mtime= dinfo["modified_time"] dst_filesize= dst.getsize(file) if verbose: print "\t"*depth+"Synching file" if src_filesize>1000 or dst_filesize>1000: src_index= src_i.GetPathPart([src_i.name,file], True) dst_index= dst_i.GetPathPart([dst_i.name,file], True) #If we get error when getting indexes, just action based on scr or dst mtime if src_index==None or dst_index==None: if src_mtime>dst_mtime: try: copyfile(src, file, dst, file) except: continue else: try: copyfile(dst, file, src, file) except: continue #Create index time, if it does not exist yet. elif src_index.CreationTime==None or dst_index.CreationTime==None: if verbose: print "\t"*depth+"No index time found." if src_mtime>dst_mtime: try: copyfile(src, file, dst, file) except: continue src_index.CreationTime= self.dt2ut(src_mtime) dst_index.CreationTime= self.dt2ut(dst.getinfo(file)["modified_time"]) else: try: copyfile(dst, file, src, file) except: continue dst_index.CreationTime= self.dt2ut(dst_mtime) src_index.CreationTime= self.dt2ut(src.getinfo(file)["modified_time"]) #When indexes exist else: #both files are unchanged if self.SmallTime(src_mtime, self.ut2dt(src_index.CreationTime)) and self.SmallTime(dst_mtime, self.ut2dt(dst_index.CreationTime)): if verbose: print "\t"*depth+"Both files are synched" #src has changed and dst has not elif self.ut2dt(src_index.CreationTime)<src_mtime and self.SmallTime(dst_mtime, self.ut2dt(dst_index.CreationTime)): if verbose: print "\t"*depth+"Src file has changed, but dst not" try: copyfile(src, file, dst, file) except: continue dst_index.CreationTime= self.dt2ut(dst.getinfo(file)["modified_time"]) #dst has changed and src has not elif self.ut2dt(dst_index.CreationTime)<dst_mtime and self.SmallTime(src_mtime, self.ut2dt(src_index.CreationTime)): if verbose: print "\t"*depth+"Dst file has changed, but src not" try: copyfile(dst, file, src, file) except: continue src_index.CreationTime= self.dt2ut(src.getinfo(file)["modified_time"]) #both files has changed, update indexes elif not self.SmallTime(src_mtime, self.ut2dt(src_index.CreationTime)) and not self.SmallTime(dst_mtime, self.ut2dt(dst_index.CreationTime)): if verbose: print "\t"*depth+"Both files has changed." if src_mtime>dst_mtime: try: copyfile(src, file, dst, file) except: continue src_index.CreationTime= self.dt2ut(src_mtime) dst_index.CreationTime= self.dt2ut(dst.getinfo(file)["modified_time"]) else: try: copyfile(dst, file, src, file) except: continue dst_index.CreationTime= self.dt2ut(dst_mtime) src_index.CreationTime= self.dt2ut(src.getinfo(file)["modified_time"]) #If we have stop on file just delete it on both sides if status==PathStatus.stop: if verbose: print "\t"*depth+"Removing file" src.remove(file) dst.remove(file)
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
def _accessor(self, max_age, getcpath=False, *args, **kwargs): """ The primary accessor for the cache instance. Each subclass should provide a function which behaves similarly to that of the original, un-cached version of the resource getter. That function should adapt the parameters provided to it into the form needed for this one, and let this function maintain the cached responses and handle retrieval of the response. If the module's :data:`_internet_connected` is set to False, the cached value is returned regardless. """ filepath = self._get_filepath(*args, **kwargs) send_cached = False if not _internet_connected and self._cached_exists(filepath): send_cached = True if self._is_cache_fresh(filepath, max_age): logger.debug("Cache HIT") send_cached = True if send_cached is True: if getcpath is False: try: filecontent = self.cache_fs.open(filepath, 'rb').read() return self._deserialize(filecontent) except UnicodeDecodeError: # TODO This requires the cache_fs to be a local # filesystem. This may not be very nice. A way # to hook codecs upto to pyfilesystems would be better with codecs.open( self.cache_fs.getsyspath(filepath), encoding='utf-8') as f: filecontent = f.read() return self._deserialize(filecontent) else: return self.cache_fs.getsyspath(filepath) logger.debug("Cache MISS") data = self._get_fresh_content(*args, **kwargs) try: sdata = self._serialize(data) fd, temppath = tempfile.mkstemp() fp = os.fdopen(fd, 'wb') fp.write(sdata) fp.close() logger.debug("Creating new cache entry") # This can be pretty expensive if the move is across a real filesystem # boundary. We should instead use a temporary file in the cache_fs # itself try: copyfile(temp_fs, temp_fs.unsyspath(temppath), self.cache_fs, filepath) except: logger.warning("Unable to write cache file {0}".format(filepath)) except: raise if getcpath is False: return data else: return self.cache_fs.getsyspath(filepath)
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_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