def groupPackagesInCategories(packages): nocategory = tr('Uncategorized').lower() libcategory = tr('Libraries').lower() othercategory = tr('Other').lower() categories = {} for pkg in packages: pcats = pkg.categories if pcats: if pkg.type == 'Mod' and len( pcats) == 1 and pcats[0] == nocategory: pcats = [libcategory] for pcat in pcats: cat = categories.get(pcat) if not cat: cat = PackageCategory(pcat) categories[pcat] = cat cat.packages.append(pkg) categories = list(categories.values()) categories.sort( key=lambda c: c.name.lower() if c.name != nocategory and c.name != libcategory and c.name != othercategory else 'zzzz') return categories
def get_workbench_categories_from_string(name, cats): if cats: if isinstance(cats, str): return [tr(c) for c in CommaStringList(cats)] elif isinstance(cats, list): return [tr(c) for c in cats] return predefinedCategories.get(name, [tr('Uncategorized')])
def on_form_add_source(data, session): result = {'status': 'ok', 'validation': [], 'message': None} if not data.get('title'): result['status'] = 'error' result['validation'].append({ 'field': 'title', 'message': tr('title is required') }) if not data.get('url'): result['status'] = 'error' result['validation'].append({ 'field': 'url', 'message': tr('url is required') }) if not data.get('protocol'): result['status'] = 'error' result['validation'].append({ 'field': 'protocol', 'message': tr('protocol is required') }) if result['status'] != 'ok': result['message'] = tr('Validation error') return result name = str(hashlib.sha256(data['url'].encode()).hexdigest()) sources = json.loads(ExtManParameters.CustomCloudSources) sources = [s for s in sources if s['name'] != name] if data.get('protocol') in ('github', 'framagit'): if not data['url'].endswith('.git'): data['url'] = data['url'].strip('/') + '.git' source = { 'name': name, 'title': data['title'], 'description': data['description'], 'git': data['url'], 'protocol': data.get('protocol', 'github'), 'type': 'Mod', 'icon': 'html/img/package_source.svg' } sources.append(source) ExtManParameters.CustomCloudSources = json.dumps(sources) clearSourcesCache() return {"status": 'ok'}
def __init__(self, **kw): # Defaults self.key = None # Package identifier self.name = None # Name self.installDir = None # where to install self.installFile = None # for Macros: Path of installed file self.basePath = "" # for Macros: full root of source file self.title = None # Displayed name self.description = None # description self.icon = None # icon url self.iconSources = [] # List of alternative icons self.isCore = False # True for all packages included in FreeCAD self.type = 'Mod' # Mod, Macro, Workbench self.isGit = False # is based on git? self.isWiki = False # is based on wiki? self.markedAsSafe = False # for Macros: if True, does not ask for confirm self.categories = [tr('Uncategorized')] # Topics/Categories self.date = None # Last update self.version = None # Version self.git = None # Git Repoitory URL self.dependencies = None # List of dependencies self.homepage = None # Web self.flags = {} # py2only, obsolete, banned self.readmeUrl = None # url of readme self.readmeFormat = 'markdown' # markdown, mediawiki, html self.author = None # Authors self.channelId = None # Cloud package source channelId self.sourceName = None # Cloud package source name # Init all with parameters for k, v in kw.items(): setattr(self, k, v)
def findCloudChannels(): channels = [] data = getSourcesData() for channel in data: channel_id = channel['id'] channel_name = tr(channel['name']) sources = [] for source in channel['sources']: sources.append(CloudPackageSource(source, channel_id)) channels.append(CloudPackageChannel(channel_id, channel_name, sources)) return channels
def __init__(self, data, channelId): super().__init__('Cloud:' + data['protocol']) self.channelId = channelId self.name = data['name'] self.title = tr(data['title']) self.description = tr(data['description']) or data.get( 'git', data.get('wiki', '')) self.protocolName = data['protocol'] self.cacheTime = 0 self.type = data['type'] icon = data['icon'] if icon.startswith('html/img/'): self.icon = utils.path_to_url(get_resource_path(*icon.split('/'))) else: self.icon = icon if data['protocol'] == 'github': self.protocol = GithubProtocol( data['git'], data.get('git_submodules'), data.get('index_type'), data.get('index_url'), data.get('wiki'), ) elif data['protocol'] == 'framagit': self.protocol = FramagitProtocol( data['git'], data.get('git_submodules'), data.get('index_type'), data.get('index_url'), data.get('wiki'), ) elif data['protocol'] == 'fcwiki': self.protocol = FCWikiProtocol(data['url'], data['wiki']) else: raise UnsupportedSourceException( "Unsupported protocol: {0}".format(data['protocol'])) self.updates = {}
def run_macro(path, session, params, request, response): """ Execute macro """ path = Path(params['macro']) try: Gui.doCommandGui("exec(open(\"{0}\").read())".format(path.as_posix())) except Exception as ex: log_err(tr("Error in macro:"), path, str(ex)) response.html_ok()
def getMacroList(self): macros = [] install_dir = get_macro_path() default_icon = utils.path_to_url( get_resource_path('html', 'img', 'package_macro.svg')) try: content = http_get(self.url, timeout=45) if content: data = json.loads(content) wiki = get_page_content_from_json(data) for m_link in MACRO_LINK.finditer(wiki): name = m_link.group('name').replace(' ', '_') label = m_link.group('label') description = m_link.group('description') icon = m_link.group('icon') if icon: icon = self.wiki + '/Special:Redirect/file/' + icon.replace( ' ', '_') else: icon = default_icon pkg = PackageInfo( key=name, installDir=install_dir, installFile=Path(install_dir, name + '.FCMacro'), name=name, title=label, description=description, icon=icon, isCore=False, type='Macro', isGit=False, isWiki=True, markedAsSafe=False, categories=[tr('Uncategorized')], date=None, version=None, readmeUrl='{0}/Macro_{1}?origin=*'.format( self.wiki, name), readmeFormat='html') flags.apply_predefined_flags(pkg) macros.append(pkg) except: traceback.print_exc(file=sys.stderr) return macros
class ExtManWorkbench(Gui.Workbench): """Extension Manager Workbench""" Icon = str(get_resource_path('icons', 'ExtManWorkbench.svg')) MenuText = tr("Extension Manager") ToolTip = tr("Extension Manager") def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def GetClassName(self): return "Gui::PythonWorkbench" def Initialize(self): log("ExtMan Initialized") def Activated(self): install_router(create_router()) start_browser() def Deactivated(self): pass
def start_browser(): global __browser_instance__ if not __browser_instance__: main_window = Gui.getMainWindow().findChild(QtGui.QMdiArea) bi = WebView(tr('Extension Manager'), get_cache_path(), request_handler, message_handler, main_window) bi.closed.connect(on_web_view_close) index = path_to_extman_url(get_resource_path('html', 'index.html')) bi.load(index) main_window.addSubWindow(bi) bi.show() __browser_instance__ = bi return __browser_instance__
def eval_expr(match): try: etype = match.group(1) eexpr = match.group(2) # Translate shortcut if etype == 't:': return tr(eexpr) # Eval Expression elif etype == 'e:': return compile_and_execute(eexpr, model, 'eval') # Execute Statement elif etype == 'x:': return compile_and_execute(eexpr, model, 'exec') # Resolve local symbol else: return str( model.get(eexpr, '???{0}{1}???'.format(etype, eexpr))) except: # Catch All Errors/Exceptions log(traceback.format_exc()) log("Error executing expression {0} in template {1}".format( eexpr, path)) return 'Error:' + traceback.format_exc()
def installMacro(self, pkg): result = InstallResult() url = self.getWikiPageUrlJson("Macro_{0}".format(quote(pkg.name))) content = http_get(url) # Manage mediawiki redirects m = REDIRECT.search(content) max_redirects = 3 while m: url = self.getWikiPageUrlJson("{0}".format(quote(m.group('link')))) content = http_get(url) m = REDIRECT.search(content) max_redirects -= 1 if max_redirects <= 0: break if not content: result.message = tr( """This macro contains invalid content, it cannot be installed directly by the Extension Manager""") else: wikitext = get_page_content_from_json(json.loads(content)) # Try {{MacroCode ...}} m = MACRO_CODE.search(wikitext) if not m: # Try <pre> ... </pre> m = LEGACY_MACRO_CODE.search(wikitext) # Code in wiki if m: try: f = open(pkg.installFile, 'w', encoding='utf-8') except IOError as ex: result.message = str(ex) else: with f: try: f.write(m.group('code')) result.ok = True except: result.message = tr( """This macro contains invalid content, it cannot be installed directly by the Extension Manager""" ) # Try external source else: m = MACRO_CODE_EXTLINK.search(wikitext) if m: pre = tr("This macro must be downloaded from this link") pos = tr( """Copy the link, download it and install it manually or follow instructions from the external resource""") result.message = """{0}: <textarea class="form-control" style="min-height: 100px; margin: 5px;" readonly>{1} </textarea> {2}""".format(pre, m.group('link'), pos) return result
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program. If not, see <https://www.gnu.org/licenses/>. * # * * # *************************************************************************** # noinspection PyPep8Naming import os from urllib.parse import quote from freecad.extman import tr from freecad.extman.template.html_utils import get_resource_url, Components TR_RUN = tr('Run') TR_CLOSE = tr('Close') TR_EDIT = tr('Edit') TR_ACTIVATE = tr('Activate') TR_UPDATE = tr('Update') TR_CORE_PACKAGE = tr('Core Package') TR_COMMUNITY_PACKAGE = tr('Community Package') TR_WORKBENCH = tr('Workbench') TR_MACRO = tr('Macro') TR_MODULE = tr('Module') TR_INSTALLED = tr('Installed') TR_GIT = tr('Git') TR_WIKI = tr('Wiki') TR_FLAG_OBSOLETE = tr('Obsolete package') TR_FLAG_PY2ONLY = tr('Python2 only') TR_README = tr('readme')
def getTitle(self): return tr('Installed packages')
def get_workbench_categories(wb): if wb and hasattr(wb, 'Categories'): return wb.Categories else: return predefinedCategories.get(wb.__class__.__name__, [tr('Uncategorized')])
"A2plus": "a2pWorkbench", "ArchTextures": "ArchTextureWorkbench", "cadquery_module": "CadQueryWorkbench", "Defeaturing": "DefeaturingWB", "kicadStepUpMod": "KiCadStepUpWB", "Manipulator": "ManipulatorWB", "Part-o-magic": "PartOMagicWorkbench", "sheetmetal": "SMWorkbench", "FCGear": "gearWorkbench", "frame": "frame_Workbench", 'CurvedShapes': "CurvedShapesWB", "None": None } predefinedCategories = { "ArchWorkbench": [tr("Architecture")], "CompleteWorkbench": [tr("Other")], "DraftWorkbench": [tr("CAD/CAM")], "DrawingWorkbench": [tr("CAD/CAM")], "FemWorkbench": [tr("Analysis")], "ImageWorkbench": [tr("Other")], "InspectionWorkbench": [tr("Analysis")], "MeshWorkbench": [tr("3D")], "OpenSCADWorkbench": [tr("CAD/CAM")], "PartWorkbench": [tr("CAD/CAM")], "PartDesignWorkbench": [tr("CAD/CAM")], "PathWorkbench": [tr("CAD/CAM")], "PointsWorkbench": [tr("CAD/CAM")], "RaytracingWorkbench": [tr("3D")], "ReverseEngineeringWorkbench": [tr("Engineering")], "RobotWorkbench": [tr("Engineering")],
def getDescription(self): return tr('All installed packages')
def build_macro_package(path, macro_name, is_core=False, is_git=False, is_wiki=False, install_path=None, base_path=""): with open(path, 'r', encoding='utf-8') as f: try: tags = get_macro_tags(f.read(), path) except: # !TODO: Handle encoding problems in old windows platforms tags = {k: None for k in MACRO_TAG_FILTER} log_err(tr('Macro {0} contains invalid characters').format(path)) install_dir = get_macro_path() base = dict(key=str(install_path) if install_path else str(path), type='Macro', isCore=is_core, installDir=install_dir, installFile=Path(install_dir, path.name), isGit=is_git, isWiki=is_wiki, basePath=base_path) tags.update(base) if not tags['title']: tags['title'] = tags['name'] or macro_name tags['name'] = macro_name # Always override name with actual file name if not tags['icon']: tags['icon'] = get_resource_path('html', 'img', 'package_macro.svg') try: if not Path(tags['icon']).exists(): tags['icon'] = get_resource_path('html', 'img', 'package_macro.svg') except: tags['icon'] = get_resource_path('html', 'img', 'package_macro.svg') tags['icon'] = utils.path_to_url(tags['icon']) if tags['comment']: tags['description'] = tags['comment'] if not tags['description']: tags['description'] = tr('Warning! No description') if tags['categories']: cats = COMMA_SEP_LIST_PATTERN.split(tags['categories']) tags['categories'] = [tr(c) for c in cats] else: tags['categories'] = [tr('Uncategorized')] if tags['files']: tags['files'] = COMMA_SEP_LIST_PATTERN.split(tags['files']) if tags['readme']: tags['readmeUrl'] = tags['readme'] tags['readmeFormat'] = 'html' elif tags['wiki']: tags['readmeUrl'] = tags['wiki'] tags['readmeFormat'] = 'html' elif tags['web']: tags['readmeUrl'] = tags['web'] tags['readmeFormat'] = 'html' return PackageInfo(**tags)
def installMacro(self, pkg): (git_available, _, git_version, git_python, git_version_ok) = install_info() # Initialize result result = InstallResult(gitAvailable=git_available, gitPythonAvailable=git_python is not None, zipAvailable=zlib.is_zip_available(), gitVersionOk=git_version_ok, gitVersion=git_version) # Ensure last version if available locally src_dir = self.downloadMacroList() # Get path of source macro file src_file = Path(src_dir, pkg.basePath, pkg.installFile.name) # Copy Macro files = [] try: macros_dir = get_macro_path() if not macros_dir.exists(): macros_dir.mkdir(parents=True) log('Installing', pkg.installFile) shutil.copy2(src_file, pkg.installFile) files.append(pkg.installFile) # Copy files if pkg.files: for f in pkg.files: file_base_path = utils.path_relative(f) dst = Path(pkg.installDir, file_base_path).absolute() src = Path(src_dir, pkg.basePath, file_base_path).absolute() log('Installing ', dst) if pkg.installDir not in dst.parents: result.message = tr( 'Macro package attempts to install files outside of permitted path' ) raise Exception() if src_dir not in src.parents: result.message = tr( 'Macro package attempts to access files outside of permitted path' ) raise Exception() dst_dir = dst.parent if dst_dir != pkg.installDir and dst_dir not in files and not dst_dir.exists( ): dst_dir.mkdir(parents=True) files.append(dst_dir) shutil.copy2(src, dst) files.append(dst) result.ok = True except: log(traceback.format_exc()) result.ok = False if not result.message: result.message = tr( 'Macro was not installed, please contact the maintainer.') # Rollback files.sort(reverse=True) for f in files: try: log("Rollback ", f) if f.is_file(): f.unlink() elif f.is_dir(): shutil.rmtree(f, ignore_errors=True) except: log(traceback.format_exc()) return result