def uninstall_package(self, pkg_type, id): """ Uninstall a package For the moment, we will only delete the package Json file for plugins and external @param pkg_type : package type @param id : package id """ if PACKAGE_MODE != True: raise PackageException("Package mode not activated") self.log("Start uninstall for package '%s-%s'" % (pkg_type, id)) self.log( "Only Json description file will be deleted in this Domogik version" ) try: if pkg_type in ('plugin'): os.unlink("%s/domogik_packages/plugins/%s.json" % (INSTALL_PATH, id)) elif pkg_type in ('external'): os.unlink("%s/domogik_packages/externals/%s.json" % (INSTALL_PATH, id)) else: raise PackageException("Package type '%s' not uninstallable" % pkg_type) except: msg = "Error while unstalling package : %s" % ( traceback.format_exc()) self.log(msg) raise PackageException(msg) self.log("Package successfully uninstalled.") return True
def get_available_updates(self, pkg_type, pkg_id, version): """ List all available updates for a package @param pkg_type : package type @param id : package id @param version : package version """ if PACKAGE_MODE != True: raise PackageException("Package mode not activated") pkg_list = [] for root, dirs, files in os.walk(REPO_CACHE_DIR): for fic in files: if fic[-5:] != ".json": continue my_json = json.load(open("%s/%s" % (root, fic))) for my_pkg in my_json["packages"]: if pkg_type == my_pkg["type"] and \ pkg_id == my_pkg["id"] and \ version < my_pkg["version"]: pkg_list.append({ "type": pkg_type, "id": pkg_id, "version": my_pkg["version"], "priority": my_pkg["priority"], "changelog": my_pkg["changelog"] }) return pkg_list
def cache_package(self, cache_dir, pkg_type, id, version, pkg_path=None): """ Download package to put it in cache @param cache_dir : folder in which we want to cache the file @param pkg_type : package type @param id : package id @param version : package version @param pkg_path : path of the package to cache on local host """ if PACKAGE_MODE != True: raise PackageException("Package mode not activated") dl_path = "%s/%s-%s-%s.tgz" % (cache_dir, pkg_type, id, version) ### cache from the web if pkg_path == None: package = "%s-%s" % (pkg_type, id) pkg, status = self._find_package(package, version) if status != True: return False # download package path = pkg["archive_url"] self.log("Caching package : '%s' to '%s'" % (path, dl_path)) urllib.urlretrieve(path, dl_path) ### cache from a local file else: self.log("Caching package : '%s' to '%s'" % (pkg_path, dl_path)) shutil.copyfile(pkg_path, dl_path) self.log("OK") return True
def _create_tar_gz(self, name, output_dir, files, info_file=None, icon_file=None, doc_path=None): """ Create a .tar.gz file anmmed <name.tgz> which contains <files> @param name : file name @param output_dir : if != None, the path to put .tar.gz @param files : table of file names to add in tar.gz @param info_file : path for info.json file @param icon_file : path for icon.png file @param doc_path : path for doc """ if output_dir == None: my_tar = "%s/%s.tgz" % (tempfile.gettempdir(), name) else: my_tar = "%s/%s.tgz" % (output_dir, name) self.log("Generating package : '%s'" % my_tar) try: tar = tarfile.open(my_tar, "w:gz") for my_file in files: path = str(my_file) self.log("- %s" % path) if os.path.isfile(SRC_PATH + path): tar.add(SRC_PATH + path, arcname=path) elif os.path.isdir(SRC_PATH + path): self.log(" (directory)") tar.add(SRC_PATH + path, arcname=path) else: self.log(" WARNING : file doesn't exists : %s" % SRC_PATH + path) if info_file != None: self.log("- info.json") tar.add(info_file, arcname="info.json") if icon_file != None: if os.path.isfile(icon_file): self.log("- icon.png") tar.add(icon_file, arcname="icon.png") if doc_path != None: self.log("- package documentation") tar.add(doc_path, arcname="docs") tar.close() # delete temporary Json file if info_file != None: os.unlink(info_file) except: msg = "Error generating package : %s : %s" % ( my_tar, traceback.format_exc()) self.log(msg) # delete temporary Json file if info_file != None: os.unlink(info_file) raise PackageException(msg) self.log("OK")
def _create_folder(self, folder): """ Try to create a folder (does nothing if it already exists) @param folder : folder path """ try: if os.path.isdir(folder) == False: self.log("Creating directory : %s" % folder) os.makedirs(folder) except: msg = "Error while creating temporary folder '%s' : %s" % ( folder, traceback.format_exc()) self.log(msg) raise PackageException(msg)
def _extract_package(self, pkg_path, extract_path): """ Extract package <pkg_path> in <extract_path> @param pkg_path : path to package @param extract_path : path for extraction """ tar = tarfile.open(pkg_path) # check if there is no .. or / in files path for fic in tar.getnames(): if fic[0:1] == "/" or fic[0:2] == "..": msg = "Error while extracting package '%s' : filename '%s' in tgz not allowed" % ( pkg_path, fic) self.log(msg) raise PackageException(msg) tar.extractall(path=extract_path) tar.close()
def get_installed_packages_list(self): """ List all packages in install folder and return a detailed list """ if PACKAGE_MODE != True: raise PackageException("Package mode not activated") pkg_list = [] for rep in [PLUGIN_JSON_PATH, EXTERNAL_JSON_PATH]: for root, dirs, files in os.walk(rep): for fic in files: if fic[-5:] == ".json": pkg_json = PackageJson(path="%s/%s" % (root, fic)).json # TODO : replace by identity and repo informations # from the json ??? pkg_list.append(pkg_json["identity"]) return sorted(pkg_list, key=lambda k: (k['fullname'], k['version']))
def _clean_folder(self, folder): """ Delete the content of a folder @param folder: folder to clean """ # Clean folder try: for root, dirs, files in os.walk(folder): for fic in files: os.unlink(os.path.join(root, fic)) for dir in dirs: shutil.rmtree(os.path.join(root, dir)) except: msg = "Error while cleaning cache folder '%s' : %s" % ( folder, traceback.format_exc()) self.log(msg) raise PackageException(msg)
def get_repositories_list(self): """ Read repository source file and return list """ try: repo_list = [] src_file = open(REPO_SRC_FILE, "r") for line in src_file.readlines(): # if the line is not a comment if line.strip()[0] != "#": url = line.split()[1] # remove all useless final "/" while url[-1] == "/": url = url[0:-1] repo_list.append({"priority": line.split()[0], "url": url}) src_file.close() except: msg = "Error reading source file : %s : %s" % ( REPO_SRC_FILE, str(traceback.format_exc())) self.log(msg) raise PackageException(msg) # return sorted list return sorted(repo_list, key=lambda k: k['priority'], reverse=True)
def get_packages_list(self, fullname=None, version=None, pkg_type=None): """ List all packages in cache folder and return a detailed list @param fullname (optionnal) : fullname of a package @param version (optionnal) : version of a package (to use with name) @param pkg_type (optionnal) : package type Used by Rest """ if PACKAGE_MODE != True: raise PackageException("Package mode not activated") pkg_list = [] for root, dirs, files in os.walk(REPO_CACHE_DIR): for fic in files: if fic[-5:] != ".json": continue my_json = json.load(open("%s/%s" % (root, fic))) for my_pkg in my_json["packages"]: if fullname == None or (fullname == my_pkg["fullname"] and version == my_pkg["version"]): if pkg_type == None or pkg_type == my_pkg["type"]: pkg_list.append(my_pkg) return sorted(pkg_list, key=lambda k: (k['id']))
def _install_plugin_or_external(self, pkg_dir, install_path, pkg_type, package_part): """ Install plugin @param pkg_dir : directory where package is extracted @param install_path : path where we install packages @param pkg_type : plugin, external @param pkg_id : package id @param package_part : PKG_PART_XPL (for manager), PKG_PART_RINOR (for RINOR) @param repo_source : path from which the package comes """ ### create needed directories # create install directory self.log("Creating directories for %s..." % pkg_type) plg_path = "%s/domogik_packages/" % (install_path) self._create_folder(plg_path) ### copy files self.log("Copying files for %s..." % pkg_type) try: # xpl/* and plugins/*.json are installed on target host if package_part == PKG_PART_XPL: if pkg_type == "plugin": copytree("%s/src/domogik_packages/xpl" % pkg_dir, "%s/xpl" % plg_path, self.log) copytree("%s/src/domogik_packages/tests" % pkg_dir, "%s/tests" % plg_path, self.log) self._create_init_py("%s/" % plg_path) self._create_init_py("%s/xpl/" % plg_path) self._create_init_py("%s/xpl/bin/" % plg_path) self._create_init_py("%s/xpl/lib/" % plg_path) self._create_init_py("%s/xpl/helpers/" % plg_path) self._create_init_py("%s/tests/" % plg_path) self._create_init_py("%s/tests/plugin/" % plg_path) type_path = "plugins" if pkg_type == "external": type_path = "externals" print("%s => %s" % ("%s/src/share/domogik/%ss" % (pkg_dir, pkg_type), "%s/%s" % (plg_path, type_path))) copytree("%s/src/share/domogik/%ss" % (pkg_dir, pkg_type), "%s/%s" % (plg_path, type_path), self.log) copytree("%s/src/share/domogik/data/" % pkg_dir, "%s/data/" % plg_path, self.log) # design/* # stats/* # url2xpl/* # exernal/* are installed on rinor host if package_part == PKG_PART_RINOR: copytree("%s/src/share/domogik/design/" % pkg_dir, "%s/design/" % plg_path, self.log) #copytree("%s/src/share/domogik/url2xpl/" % pkg_dir, "%s/url2xpl/" % plg_path, self.log) #copytree("%s/src/share/domogik/stats/" % pkg_dir, "%s/stats/" % plg_path, self.log) copytree("%s/src/external/" % pkg_dir, "%s/external" % plg_path, self.log) copytree("%s/src/domogik_packages/conversions" % pkg_dir, "%s/conversions" % plg_path, self.log) except: msg = "Error while copying %s files : %s" % ( pkg_type, traceback.format_exc()) self.log(msg) raise PackageException(msg)
def install_package(self, path, version=None, package_part=PKG_PART_XPL): """ Install a package 0. Eventually download package 1. Extract tar.gz 2. Install package 3. Insert data in database @param path : path for tar.gz @param version : version to install (default : highest) @param package_part : PKG_PART_XPL (for manager), PKG_PART_RINOR (for RINOR) """ if PACKAGE_MODE != True: raise PackageException("Package mode not activated") self.log("Start install for part '%s' of '%s'" % (package_part, path)) if path[0:6] == "cache:": path = "%s/package/download/%s" % (REST_URL, path[6:]) if path[0:5] == "repo:": pkg, status = self._find_package(path[5:], version) if status != True: return status path = pkg.archive_url # get package name if path[0:4] == "http": # special process for a http path id = full_name = '-'.join(path.split("/")[-3:]) print("id=%s" % full_name) else: full_name = os.path.basename(path) # twice to remove first .gz and then .tar id = os.path.splitext(full_name)[0] id = os.path.splitext(id)[0] self.log("Ask for installing package id : %s" % id) # get temp dir to extract data my_tmp_dir_dl = TMP_EXTRACT_DIR my_tmp_dir = "%s/%s" % (my_tmp_dir_dl, id) self._create_folder(my_tmp_dir) # Check if we need to download package if path[0:4] == "http": dl_path = "%s/%s.tgz" % (my_tmp_dir_dl, full_name) self.log("Downloading package : '%s' to '%s'" % (path, dl_path)) urllib.urlretrieve(path, dl_path) path = dl_path self.log("Package downloaded : %s" % path) # extract in tmp directory self.log("Extracting package...") try: self._extract_package(path, my_tmp_dir) except: msg = "Error while extracting package '%s' : %s" % ( path, traceback.format_exc()) self.log(msg) raise PackageException(msg) self.log("Package successfully extracted.") # get Json informations pkg_json = PackageJson(path="%s/info.json" % my_tmp_dir).json # check compatibility with domogik installed version __import__("domogik") dmg = sys.modules["domogik"] self.log("Domogik version = %s" % dmg.__version__) self.log("Minimum Domogik version required for package = %s" % pkg_json["identity"]["domogik_min_version"]) print("%s < %s" % (pkg_json["identity"]["domogik_min_version"], dmg.__version__)) if pkg_json["identity"]["domogik_min_version"] > dmg.__version__: msg = "This package needs a Domogik version >= %s. Actual is %s. Installation ABORTED!" % ( pkg_json["identity"]["domogik_min_version"], dmg.__version__) self.log(msg) raise PackageException(msg) # check the json_version file self.log("Required json version = %s" % MIN_JSON_VERSION) self.log("Package json version = %s" % pkg_json["json_version"]) if pkg_json["json_version"] < MIN_JSON_VERSION: msg = "This package has json_version set to %s, but Domogik needs at least %s" % ( pkg_json["json_version"], MIN_JSON_VERSION) self.log(msg) raise PackageException(msg) # create install directory self._create_folder(INSTALL_PATH) # install plugin in $HOME self.log("Installing package (%s)..." % pkg_json["identity"]["type"]) try: if pkg_json["identity"]["type"] in ('plugin', 'external'): self._install_plugin_or_external(my_tmp_dir, INSTALL_PATH, pkg_json["identity"]["type"], package_part) else: raise "Package type '%s' not installable" % pkg_json[ "identity"]["type"] except: msg = "Error while installing package : %s" % ( traceback.format_exc()) self.log(msg) raise PackageException(msg) self.log("Package successfully extracted.") # insert data in database if pkg_json["identity"]["type"] in ('plugin', 'external'): if package_part == PKG_PART_RINOR: self.log("Insert data in database...") pkg_data = PackageData("%s/info.json" % my_tmp_dir) pkg_data.insert() self.log("Package installation finished") return True
""" Create __init__.py file in path param path : path where we wan to create the file """ try: self.log("Create __init__.py file in %s" % path) open("%s/__init__.py" % path, "a").close() except IOError as (errno, strerror): if errno == 2: self.log("No directory '%s'" % path) return raise except: msg = "Error while creating __init__.py file in %s : %s" % ( path, traceback.format_exc()) self.log(msg) raise PackageException(msg) def update_cache(self): """ update local package cache """ if PACKAGE_MODE != True: self.log("Update cache not possible : Package mode not activated") return # Get repositories list try: # Read repository source file and generate repositories list repo_list = self.get_repositories_list() except: self.log(str(traceback.format_exc())) return False