версия для Kodi 19
This commit is contained in:
1 parent
9aefb9451b
commit
5d2aff9bc5
60 files changed
+5831
No files matched your search
@@ -0,0 +1,26 @@
|
||||
Copyright (c) 2011 Mikel Azkolain
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of copyright holders nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,372 @@
|
||||
"""
|
||||
Created on 09/08/2011
|
||||
|
||||
@author: mikel
|
||||
"""
|
||||
__all__ = ["fonts", "includes"]
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
import xml.etree.ElementTree as ET
|
||||
from datetime import datetime
|
||||
from os import listdir
|
||||
from os.path import isdir, dirname, basename
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
|
||||
class SkinUtilsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def reload_skin():
|
||||
xbmc.executebuiltin("XBMC.ReloadSkin()")
|
||||
|
||||
|
||||
def setup_logging():
|
||||
# Keep comaptibility with Python2.6
|
||||
if hasattr(logging, 'NullHandler'):
|
||||
logger = logging.getLogger('skinutils')
|
||||
logger.addHandler(logging.NullHandler())
|
||||
|
||||
|
||||
def get_logger():
|
||||
return logging.getLogger('skinutils')
|
||||
|
||||
|
||||
def debug_log(msg):
|
||||
get_logger().debug(msg)
|
||||
|
||||
|
||||
def get_sha1_obj():
|
||||
# SHA1 lib 2.4 compatibility
|
||||
try:
|
||||
from hashlib import sha1
|
||||
return sha1()
|
||||
except:
|
||||
import sha
|
||||
return sha.new()
|
||||
|
||||
|
||||
def sha1_file(file, block_size=2 ** 20):
|
||||
f = open(file, 'rb')
|
||||
sha1 = get_sha1_obj()
|
||||
|
||||
while True:
|
||||
data = f.read(block_size)
|
||||
if not data:
|
||||
break
|
||||
sha1.update(data)
|
||||
|
||||
f.close()
|
||||
|
||||
return sha1.hexdigest()
|
||||
|
||||
|
||||
def try_remove_file(file, wait=0.5, tries=10):
|
||||
removed = False
|
||||
num_try = 0
|
||||
|
||||
while num_try < tries and not removed:
|
||||
try:
|
||||
os.remove(file)
|
||||
return True
|
||||
|
||||
except OSError:
|
||||
num_try += 1
|
||||
time.sleep(wait)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def case_file_exists(file):
|
||||
if not os.path.isfile(file):
|
||||
return False
|
||||
|
||||
else:
|
||||
file_dir = dirname(file)
|
||||
if not isdir(file_dir):
|
||||
return False
|
||||
|
||||
else:
|
||||
dir_contents = listdir(file_dir)
|
||||
return basename(file) in dir_contents
|
||||
|
||||
|
||||
def get_current_skin_path():
|
||||
return os.path.normpath(xbmc.translatePath("special://skin/"))
|
||||
|
||||
|
||||
def get_skin_name():
|
||||
return os.path.basename(get_current_skin_path())
|
||||
|
||||
|
||||
def get_local_skin_path():
|
||||
user_addons_path = xbmc.translatePath("special://home/addons")
|
||||
return os.path.normpath(
|
||||
os.path.join(user_addons_path, get_skin_name())
|
||||
)
|
||||
|
||||
|
||||
def copy_skin_to_userdata(ask_user=True):
|
||||
# Warn user before doing this weird thing
|
||||
d = xbmcgui.Dialog()
|
||||
msg1 = "This addon needs to install some extra resources."
|
||||
msg2 = "This installation requires a manual XBMC restart."
|
||||
msg3 = "Begin installation now? After that it will exit."
|
||||
|
||||
make_copy = (
|
||||
not ask_user or
|
||||
d.yesno("Notice", msg1, msg2, msg3)
|
||||
)
|
||||
|
||||
if make_copy:
|
||||
# Get skin dest name
|
||||
local_skin_path = get_local_skin_path()
|
||||
|
||||
# If it was not copied before...
|
||||
if not os.path.exists(local_skin_path):
|
||||
shutil.copytree(get_current_skin_path(), local_skin_path)
|
||||
|
||||
return make_copy
|
||||
|
||||
|
||||
def is_invalid_local_skin():
|
||||
# Get skin paths
|
||||
current_skin_path = get_current_skin_path()
|
||||
local_skin_path = get_local_skin_path()
|
||||
|
||||
# If the local path does not exist
|
||||
if not os.path.isdir(local_skin_path):
|
||||
return False
|
||||
|
||||
else:
|
||||
# Get addon xml paths
|
||||
current_xml = os.path.join(current_skin_path, 'addon.xml')
|
||||
local_xml = os.path.join(local_skin_path, 'addon.xml')
|
||||
|
||||
# Both files must exist
|
||||
if not os.path.isfile(current_xml) or not os.path.isfile(local_xml):
|
||||
return True
|
||||
|
||||
# If sum of both files mismatch, got it!
|
||||
elif sha1_file(current_xml) != sha1_file(local_xml):
|
||||
return True
|
||||
|
||||
# Otherwise everything is ok
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def fix_invalid_local_skin():
|
||||
local_skin_path = get_local_skin_path()
|
||||
time_suffix = datetime.now().strftime('%Y%m%d%H%M%S')
|
||||
backup_skin_path = local_skin_path + '-skinutils-' + time_suffix
|
||||
|
||||
# Just move the skin, if it already exists someone is trolling us...
|
||||
shutil.move(local_skin_path, backup_skin_path)
|
||||
|
||||
# And now do the real copy
|
||||
copy_skin_to_userdata(ask_user=False)
|
||||
|
||||
# Inform the user about the operation...
|
||||
d = xbmcgui.Dialog()
|
||||
l1 = "Your local skin is not in use (probably outdated)."
|
||||
l2 = "Press OK to apply a fix (archiving the old skin)."
|
||||
l3 = "You will need to restart XBMC once more."
|
||||
d.ok("Notice", l1 + '\n' + '\n' + l2 + '\n' + l3)
|
||||
sys.exit()
|
||||
|
||||
|
||||
# Skin was copied but XBMC was not restarted
|
||||
def check_needs_restart():
|
||||
# Get skin paths
|
||||
current_skin_path = get_current_skin_path()
|
||||
local_skin_path = get_local_skin_path()
|
||||
|
||||
# Local skin exists and does not match current skin path
|
||||
if os.path.isdir(local_skin_path) and current_skin_path != local_skin_path:
|
||||
# Check if the local skin is a leftover from a previous XBMC install
|
||||
if is_invalid_local_skin():
|
||||
fix_invalid_local_skin()
|
||||
|
||||
# Local skin is correct, a restart is needed
|
||||
else:
|
||||
d = xbmcgui.Dialog()
|
||||
d.ok("Notice", "Restart XBMC to complete the installation.")
|
||||
sys.exit()
|
||||
|
||||
|
||||
def do_write_test(path):
|
||||
test_file = os.path.join(path, 'write_test.txt')
|
||||
get_logger().debug('performing write test: %s' % test_file)
|
||||
|
||||
try:
|
||||
# Open and cleanup
|
||||
open(test_file, 'w').close()
|
||||
os.remove(test_file)
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def skin_is_local():
|
||||
return get_current_skin_path() == get_local_skin_path()
|
||||
|
||||
|
||||
def check_skin_writability():
|
||||
# Some debug info
|
||||
debug_log("-- skinutils debug info --")
|
||||
debug_log("current skin path: %s\n" % get_current_skin_path())
|
||||
debug_log("local path should be: %s" % get_local_skin_path())
|
||||
|
||||
# Check if XBMC needs a restart
|
||||
check_needs_restart()
|
||||
|
||||
# Get the current skin's path
|
||||
skin_path = get_local_skin_path()
|
||||
|
||||
# Check if it's local or not (contained in userdata)
|
||||
if not skin_is_local():
|
||||
copy_skin_to_userdata()
|
||||
sys.exit()
|
||||
|
||||
# Check if this path is writable
|
||||
elif not os.access(skin_path, os.W_OK) or not do_write_test(skin_path):
|
||||
raise IOError("Skin directory is not writable.")
|
||||
|
||||
|
||||
def make_backup(path):
|
||||
backup_path = path + '-skinutilsbackup'
|
||||
# If the backup already exists, don't overwrite it
|
||||
if not os.path.exists(backup_path):
|
||||
shutil.copy(path, backup_path)
|
||||
|
||||
|
||||
def restore_backup(path):
|
||||
backup_path = path + '-skinutilsbackup'
|
||||
|
||||
# Do nothing if no backup exists
|
||||
if os.path.exists(backup_path):
|
||||
|
||||
# os.rename is atomic on unix, and it will overwrite silently
|
||||
if os.name != 'nt':
|
||||
os.rename(backup_path, path)
|
||||
|
||||
# Windows will complain if the file exists
|
||||
else:
|
||||
os.remove(path)
|
||||
os.rename(backup_path, path)
|
||||
|
||||
|
||||
def is_invalid_xml(file):
|
||||
contents = open(file, 'r').read()
|
||||
|
||||
# Check for invalid comments
|
||||
pattern = re.compile('<!--(.*?)-->', re.MULTILINE | re.DOTALL)
|
||||
group_pattern = re.compile('^-|--|-$')
|
||||
for match in re.finditer(pattern, contents):
|
||||
if re.match(group_pattern, match.group(1)) is not None:
|
||||
return True
|
||||
|
||||
# Check also for whitespace prior to declaration
|
||||
whitespace_pattern = re.compile('^\s+', re.MULTILINE)
|
||||
return whitespace_pattern.match(contents) is not None
|
||||
|
||||
|
||||
def sanitize_xml(file):
|
||||
contents = open(file, 'r').read()
|
||||
|
||||
# Remove leading whitespace to declaration
|
||||
contents = contents.lstrip()
|
||||
|
||||
# Strip invalid comments
|
||||
p = re.compile('<!--.*?-->', re.MULTILINE | re.DOTALL)
|
||||
clean_contents, num_repl = re.subn(p, '', contents)
|
||||
|
||||
open(file, 'w').write(clean_contents)
|
||||
|
||||
|
||||
def install_resources():
|
||||
pass
|
||||
|
||||
|
||||
class DocumentCache:
|
||||
__cached_docs = None
|
||||
|
||||
def __init__(self):
|
||||
self.__cached_docs = {}
|
||||
|
||||
def _check_file_exists(self, file):
|
||||
if not os.path.isfile(file):
|
||||
raise IOError('File not found: %s' % file)
|
||||
|
||||
def contains(self, file):
|
||||
return file in self.__cached_docs
|
||||
|
||||
def _check_file_known(self, file):
|
||||
if not self.contains(file):
|
||||
raise KeyError('Unknown file: %s' % file)
|
||||
|
||||
def list_files(self):
|
||||
return self.__cached_docs.keys()
|
||||
|
||||
def items(self):
|
||||
return self.__cached_docs.items()
|
||||
|
||||
def add(self, file):
|
||||
self._check_file_exists(file)
|
||||
self.__cached_docs[file] = None
|
||||
|
||||
def read(self, file):
|
||||
self._check_file_exists(file)
|
||||
|
||||
# If there is no cached data...
|
||||
if not self.contains(file) or self.__cached_docs[file] is None:
|
||||
# Check if the file about to load is sane
|
||||
if is_invalid_xml(file):
|
||||
make_backup(file)
|
||||
sanitize_xml(file)
|
||||
|
||||
# Parse the document
|
||||
self.__cached_docs[file] = ET.parse(file)
|
||||
|
||||
return self.__cached_docs[file]
|
||||
|
||||
def write(self, file):
|
||||
self._check_file_known(file)
|
||||
|
||||
# If there is a document in cache it may contain modifications
|
||||
if self.__cached_docs[file] is not None:
|
||||
make_backup(file)
|
||||
self.__cached_docs[file].write(file)
|
||||
|
||||
def write_all(self):
|
||||
for item in self.__cached_docs:
|
||||
self.write(item)
|
||||
|
||||
def clear(self, file):
|
||||
self._check_file_known(file)
|
||||
self.__cached_docs[file] = None
|
||||
|
||||
def clear_all(self):
|
||||
for item in self.__cached_docs:
|
||||
self.clear(item)
|
||||
|
||||
def rollback(self, file):
|
||||
self._check_file_known(file)
|
||||
restore_backup(file)
|
||||
self.clear(file)
|
||||
|
||||
def rollback_all(self):
|
||||
for item in self.__cached_docs:
|
||||
self.rollback(item)
|
||||
|
||||
|
||||
setup_logging()
|
||||
@@ -0,0 +1,210 @@
|
||||
"""
|
||||
Created on 09/08/2011
|
||||
|
||||
@author: mikel
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import xbmc
|
||||
from . import SkinUtilsError, check_skin_writability, reload_skin, try_remove_file, case_file_exists, \
|
||||
DocumentCache, get_logger
|
||||
|
||||
|
||||
class FontXmlError(SkinUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
class FontManager:
|
||||
__installed_names = None
|
||||
__installed_fonts = None
|
||||
__doc_cache = None
|
||||
|
||||
def _list_skin_font_files(self):
|
||||
font_xml_list = []
|
||||
skin_path = xbmc.translatePath("special://skin/")
|
||||
|
||||
# Go into each dir. Could be 720, 1080...
|
||||
for dir_item in os.listdir(skin_path):
|
||||
dir_path = os.path.join(skin_path, dir_item)
|
||||
if os.path.isdir(dir_path):
|
||||
# Try with font.xml
|
||||
file = os.path.join(dir_path, "font.xml")
|
||||
if case_file_exists(file):
|
||||
font_xml_list.append(file)
|
||||
|
||||
# Don't try the next step on windows, wasted time
|
||||
file = os.path.join(dir_path, "Font.xml")
|
||||
if case_file_exists(file):
|
||||
font_xml_list.append(file)
|
||||
|
||||
return font_xml_list
|
||||
|
||||
def __init__(self):
|
||||
self.__installed_names = []
|
||||
self.__installed_fonts = []
|
||||
self.__doc_cache = DocumentCache()
|
||||
|
||||
# Check if the environment is sane
|
||||
check_skin_writability()
|
||||
|
||||
# Initialize the doc cache with the skin's files
|
||||
for file in self._list_skin_font_files():
|
||||
self.__doc_cache.add(file)
|
||||
|
||||
def is_name_installed(self, name):
|
||||
return name in self.__installed_names
|
||||
|
||||
def is_font_installed(self, file):
|
||||
return file in self.__installed_fonts
|
||||
|
||||
def _get_font_attr(self, node, name):
|
||||
attrnode = node.find(name)
|
||||
if attrnode is not None:
|
||||
return attrnode.text
|
||||
|
||||
def _copy_font_file(self, file):
|
||||
skin_font_path = xbmc.translatePath("special://skin/fonts/")
|
||||
file_name = os.path.basename(file)
|
||||
dest_file = os.path.join(skin_font_path, file_name)
|
||||
|
||||
# TODO: Unix systems could use symlinks
|
||||
|
||||
# Check if it's already there
|
||||
if dest_file not in self.__installed_fonts:
|
||||
self.__installed_fonts.append(dest_file)
|
||||
|
||||
# Overwrite if file exists
|
||||
shutil.copyfile(file, dest_file)
|
||||
|
||||
def _add_font_attr(self, fontdef, name, value):
|
||||
attr = ET.SubElement(fontdef, name)
|
||||
attr.text = value
|
||||
attr.tail = "\n\t\t\t"
|
||||
return attr
|
||||
|
||||
def _install_font_def(self, skin_file, name, filename, size, style="", aspect="", linespacing=""):
|
||||
# Add it to the registry
|
||||
self.__installed_names.append(name)
|
||||
|
||||
# Get the parsed skin font file
|
||||
font_doc = self.__doc_cache.read(skin_file)
|
||||
|
||||
# Iterate over all the fontsets on the file
|
||||
for fontset in font_doc.getroot().findall("fontset"):
|
||||
fontset.findall("font")[-1].tail = "\n\t\t"
|
||||
fontdef = ET.SubElement(fontset, "font")
|
||||
fontdef.text, fontdef.tail = "\n\t\t\t", "\n\t"
|
||||
|
||||
self._add_font_attr(fontdef, "name", name)
|
||||
|
||||
# We get the full file path to the font, so let's basename
|
||||
self._add_font_attr(fontdef, "filename", os.path.basename(filename))
|
||||
self._copy_font_file(filename)
|
||||
|
||||
last = self._add_font_attr(fontdef, "size", size)
|
||||
|
||||
if style:
|
||||
if style in ["normal", "bold", "italics", "bolditalics", "lighten"]:
|
||||
last = self._add_font_attr(fontdef, "style", style)
|
||||
|
||||
else:
|
||||
raise FontXmlError(
|
||||
"Font '%s' has an invalid style definition: %s"
|
||||
% (name, style)
|
||||
)
|
||||
|
||||
if aspect:
|
||||
last = self._add_font_attr(fontdef, "aspect", aspect)
|
||||
|
||||
if linespacing:
|
||||
last = self._add_font_attr(fontdef, "linespacing", linespacing)
|
||||
|
||||
last.tail = "\n\t\t"
|
||||
|
||||
def _install_file(self, doc_cache, user_file, skin_file, font_path):
|
||||
user_doc = doc_cache.read(user_file)
|
||||
|
||||
# Handle only the first fontset
|
||||
fontset = user_doc.getroot().find("fontset")
|
||||
if len(fontset):
|
||||
# Every font definition inside it
|
||||
for item in fontset.findall("font"):
|
||||
name = self._get_font_attr(item, "name")
|
||||
|
||||
# Basic check for malformed defs.
|
||||
if name is None:
|
||||
raise FontXmlError("Malformed XML: No name for font definition.")
|
||||
|
||||
# Omit already defined fonts
|
||||
elif not self.is_name_installed(name):
|
||||
font_file_path = os.path.join(
|
||||
font_path, self._get_font_attr(item, "filename")
|
||||
)
|
||||
self._install_font_def(
|
||||
skin_file,
|
||||
name,
|
||||
font_file_path,
|
||||
self._get_font_attr(item, "size"),
|
||||
self._get_font_attr(item, "style"),
|
||||
self._get_font_attr(item, "aspect"),
|
||||
self._get_font_attr(item, "linespacing")
|
||||
)
|
||||
|
||||
def _get_res_folder(self, path):
|
||||
return os.path.basename(os.path.dirname(path))
|
||||
|
||||
def _get_res_filename(self, res_folder, user_file):
|
||||
path, ext = os.path.splitext(user_file)
|
||||
return path + '-' + res_folder + ext
|
||||
|
||||
def install_file(self, user_file, font_path, commit=True, clear=True):
|
||||
doc_cache = DocumentCache()
|
||||
|
||||
# If the file does not exist the following will fail
|
||||
doc_cache.add(user_file)
|
||||
|
||||
# Install the file into every cached skin font file
|
||||
for skin_file in self.__doc_cache.list_files():
|
||||
res_folder = self._get_res_folder(skin_file)
|
||||
res_file = self._get_res_filename(res_folder, user_file)
|
||||
|
||||
# If an specific res file exists...
|
||||
if os.path.isfile(res_file):
|
||||
self._install_file(doc_cache, res_file, skin_file, font_path)
|
||||
|
||||
# Otherwise use the dafault fallback
|
||||
else:
|
||||
self._install_file(doc_cache, user_file, skin_file, font_path)
|
||||
|
||||
# If save was requested
|
||||
if commit:
|
||||
self.__doc_cache.write_all()
|
||||
|
||||
# Clear cached docs after write (if requested)
|
||||
if clear:
|
||||
self.__doc_cache.clear_all()
|
||||
|
||||
def remove_font(self, name):
|
||||
pass
|
||||
|
||||
def remove_installed_names(self):
|
||||
self.__doc_cache.rollback_all()
|
||||
|
||||
def remove_installed_fonts(self):
|
||||
for item in self.__installed_fonts:
|
||||
if not try_remove_file(item):
|
||||
get_logger().error(
|
||||
'Failed removing font file "%s". XBMC may still be using it.' % item
|
||||
)
|
||||
|
||||
def cleanup(self):
|
||||
self.remove_installed_names()
|
||||
|
||||
# Reload skin so font files are no longer in use, and then delete them
|
||||
reload_skin()
|
||||
self.remove_installed_fonts()
|
||||
|
||||
def __del__(self):
|
||||
self.cleanup()
|
||||
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
Created on 09/08/2011
|
||||
|
||||
@author: mikel
|
||||
"""
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import xbmc
|
||||
from . import SkinUtilsError, check_skin_writability, case_file_exists, DocumentCache, get_logger
|
||||
|
||||
|
||||
class IncludeXmlError(SkinUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
class IncludeManager:
|
||||
__installed_names = None
|
||||
__doc_cache = None
|
||||
|
||||
def _list_skin_include_files(self):
|
||||
include_list = []
|
||||
skin_path = xbmc.translatePath("special://skin/")
|
||||
|
||||
# Go into each dir. Could be 720, 1080...
|
||||
for dir_item in os.listdir(skin_path):
|
||||
dir_path = os.path.join(skin_path, dir_item)
|
||||
if os.path.isdir(dir_path):
|
||||
file = os.path.join(dir_path, "includes.xml")
|
||||
if case_file_exists(file):
|
||||
include_list.append(file)
|
||||
|
||||
file = os.path.join(dir_path, "Includes.xml")
|
||||
if case_file_exists(file):
|
||||
include_list.append(file)
|
||||
|
||||
return include_list
|
||||
|
||||
def __init__(self):
|
||||
self.__installed_names = []
|
||||
self.__doc_cache = DocumentCache()
|
||||
|
||||
# Check if the environment is sane
|
||||
check_skin_writability()
|
||||
|
||||
# Initialize the doc cache with found files
|
||||
for file in self._list_skin_include_files():
|
||||
self.__doc_cache.add(file)
|
||||
|
||||
def is_name_installed(self, name):
|
||||
return name in self.__installed_names
|
||||
|
||||
def add_include(self, name, node):
|
||||
for file in self.__doc_cache.list_files():
|
||||
doc = self.__doc_cache.read(file)
|
||||
doc.getroot().append(node)
|
||||
self.__installed_names.append(name)
|
||||
|
||||
def install_file(self, file, commit=True, clear=True):
|
||||
get_logger().info('install include: %s' % file)
|
||||
tree = ET.parse(file)
|
||||
|
||||
# Handle all includes
|
||||
for item in tree.getroot().findall("include"):
|
||||
name = item.get("name")
|
||||
if name is None:
|
||||
get_logger().warning('Only named includes are supported.')
|
||||
|
||||
elif self.is_name_installed(name):
|
||||
get_logger().warning('Include name "%s" already installed' % name)
|
||||
|
||||
else:
|
||||
self.add_include(name, item)
|
||||
|
||||
# If a save was requested
|
||||
if commit:
|
||||
self.__doc_cache.write_all()
|
||||
|
||||
# If we where requested to clear the cached docs
|
||||
if clear:
|
||||
self.__doc_cache.clear_all()
|
||||
|
||||
def remove_installed_names(self):
|
||||
self.__doc_cache.rollback_all()
|
||||
|
||||
def cleanup(self):
|
||||
self.remove_installed_names()
|
||||
|
||||
def __del__(self):
|
||||
self.cleanup()
|
||||
Reference in new issue
Block a user