mirror of
https://github.com/munki/munki.git
synced 2026-04-28 16:29:29 -05:00
Python-modernize munkilib/munkirepo and lay groundwork for loading additional repo plugins from an external directory
This commit is contained in:
@@ -26,6 +26,7 @@ try:
|
||||
__getattr__ = dict.__getitem__
|
||||
__setattr__ = dict.__setitem__
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
NetFS = Attrdict()
|
||||
# Can cheat and provide 'None' for the identifier, it'll just use
|
||||
# frameworkPath instead
|
||||
@@ -34,13 +35,16 @@ try:
|
||||
'NetFS', frameworkIdentifier=None,
|
||||
frameworkPath=objc.pathForFramework('NetFS.framework'),
|
||||
globals=NetFS, scan_classes=False)
|
||||
# pylint: enable=invalid-name
|
||||
|
||||
# https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/
|
||||
# ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
|
||||
# Fix NetFSMountURLSync signature
|
||||
del NetFS['NetFSMountURLSync']
|
||||
# pylint: disable=no-member
|
||||
objc.loadBundleFunctions(
|
||||
NetFS_bundle, NetFS, [('NetFSMountURLSync', 'i@@@@@@o^@')])
|
||||
# pylint: enable=no-member
|
||||
NETFSMOUNTURLSYNC_AVAILABLE = True
|
||||
except (ImportError, KeyError):
|
||||
NETFSMOUNTURLSYNC_AVAILABLE = False
|
||||
@@ -141,6 +145,7 @@ def mount_share_url(share_url):
|
||||
class FileRepo(Repo):
|
||||
'''Handles local filesystem repo and repos mounted via filesharing'''
|
||||
|
||||
# pylint: disable=super-init-not-called
|
||||
def __init__(self, baseurl):
|
||||
'''Constructor'''
|
||||
self.baseurl = baseurl
|
||||
@@ -156,6 +161,7 @@ class FileRepo(Repo):
|
||||
unicodeize(urllib.unquote(url_parts.path).lstrip('/')))
|
||||
self.we_mounted_repo = False
|
||||
self._connect()
|
||||
# pylint: enable=super-init-not-called
|
||||
|
||||
def __del__(self):
|
||||
'''Destructor -- unmount the fileshare if we mounted it'''
|
||||
|
||||
@@ -8,7 +8,7 @@ import pwd
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from .FileRepo import FileRepo
|
||||
from munkilib.munkirepo.FileRepo import FileRepo
|
||||
|
||||
# TODO: make this more easily customized
|
||||
GITCMD = '/usr/bin/git'
|
||||
|
||||
@@ -19,16 +19,20 @@ DEBUG = False
|
||||
CURL_CMD = '/usr/bin/curl'
|
||||
|
||||
class CurlError(Exception):
|
||||
'''Error for curl operations'''
|
||||
pass
|
||||
|
||||
|
||||
class MWA2APIRepo(Repo):
|
||||
'''Class for working with a repo accessible via the MWA2 API'''
|
||||
|
||||
# pylint: disable=super-init-not-called
|
||||
def __init__(self, baseurl):
|
||||
'''Constructor'''
|
||||
self.baseurl = baseurl
|
||||
self.authtoken = None
|
||||
self._connect()
|
||||
# pylint: enable=super-init-not-called
|
||||
|
||||
def _connect(self):
|
||||
'''For a fileshare repo, we'd mount the share, prompting for
|
||||
@@ -129,9 +133,9 @@ class MWA2APIRepo(Repo):
|
||||
if kind in ['catalogs', 'manifests', 'pkgsinfo']:
|
||||
# it's a list of dicts containing 'filename' key/values
|
||||
return [item['filename'] for item in plist]
|
||||
else:
|
||||
# it's a list of filenames
|
||||
return plist
|
||||
|
||||
# it's a list of filenames (pkgs, icons)
|
||||
return plist
|
||||
|
||||
def get(self, resource_identifier):
|
||||
'''Returns the content of item with given resource_identifier.
|
||||
|
||||
@@ -5,27 +5,57 @@ import imp
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
class RepoError(Exception):
|
||||
'''Base exception for repo errors'''
|
||||
pass
|
||||
from ._baseclasses import RepoError, Repo
|
||||
from .FileRepo import FileRepo
|
||||
|
||||
|
||||
class Repo(object):
|
||||
'''Abstract base class for repo'''
|
||||
def __init__(self, url):
|
||||
'''Override in subclasses'''
|
||||
pass
|
||||
def import_plugins(dirpath=None):
|
||||
"""Imports plugins from dirpath or the directory this file is in"""
|
||||
plugin_names = []
|
||||
|
||||
if not dirpath:
|
||||
# get the directory this __init__.py file is in
|
||||
dirpath = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# find all the .py files (minus __init__.py)
|
||||
plugin_files = [
|
||||
os.path.splitext(name)[0]
|
||||
for name in os.listdir(dirpath)
|
||||
if name.endswith(".py") and not name.startswith("_")
|
||||
]
|
||||
|
||||
for name in plugin_files:
|
||||
if name in globals():
|
||||
# we already imported it
|
||||
plugin_names.append(name)
|
||||
continue
|
||||
plugin_filename = os.path.join(dirpath, name + ".py")
|
||||
try:
|
||||
# attempt to import the module
|
||||
_tmp = imp.load_source(name, plugin_filename)
|
||||
# look for an attribute with the plugin name
|
||||
plugin = getattr(_tmp, name)
|
||||
# add the processor to munkirepo's namespace
|
||||
globals()[name] = plugin
|
||||
plugin_names.append(name)
|
||||
except (ImportError, AttributeError) as err:
|
||||
# if we aren't successful, print a warning
|
||||
print(
|
||||
"WARNING: %s: %s" % (plugin_filename, err), file=sys.stderr
|
||||
)
|
||||
return plugin_names
|
||||
|
||||
__all__ = import_plugins()
|
||||
|
||||
|
||||
def plugin_named(name):
|
||||
# Helper functions for munkirepo plugins
|
||||
|
||||
def plugin_named(some_name):
|
||||
'''Returns a plugin object given a name'''
|
||||
try:
|
||||
module = globals()[name]
|
||||
return getattr(module, name)
|
||||
return globals()[some_name]
|
||||
except (KeyError, AttributeError):
|
||||
print((
|
||||
"ERROR: %s repo plugin not found." % name), file=sys.stderr)
|
||||
print("ERROR: %s repo plugin not found." % some_name, file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
@@ -35,12 +65,4 @@ def connect(repo_url, plugin_name):
|
||||
if plugin:
|
||||
return plugin(repo_url)
|
||||
else:
|
||||
raise RepoError('Could not find repo plugin named %s' % plugin_name)
|
||||
|
||||
|
||||
# yes, having this at the end is weird. But it allows us to dynamically import
|
||||
# additional modules from our directory
|
||||
__all__ = [os.path.splitext(name)[0]
|
||||
for name in os.listdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
if name.endswith('.py') and not name == '__init__.py']
|
||||
from . import *
|
||||
raise RepoError('Could not find repo plugin named: %s' % plugin_name)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# encoding: utf-8
|
||||
"""Base classes for repo plugins"""
|
||||
|
||||
class RepoError(Exception):
|
||||
'''Base exception for repo errors'''
|
||||
pass
|
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
class Repo(object):
|
||||
'''Abstract base class for repo'''
|
||||
def __init__(self, url):
|
||||
'''Override in subclasses'''
|
||||
pass
|
||||
# pylint: enable=too-few-public-methods
|
||||
Reference in New Issue
Block a user