void CAddonInstaller::GetInstallList(VECADDONS &addons) const { CSingleLock lock(m_critSection); std::vector<std::string> addonIDs; for (JobMap::const_iterator i = m_downloadJobs.begin(); i != m_downloadJobs.end(); ++i) { if (i->second.jobID) addonIDs.push_back(i->first); } lock.Leave(); CAddonDatabase database; database.Open(); for (std::vector<std::string>::iterator it = addonIDs.begin(); it != addonIDs.end(); ++it) { AddonPtr addon; if (database.GetAddon(*it, addon)) addons.push_back(addon); } }
void CAddonInstaller::Install(const std::string& addonId, const AddonVersion& version, const std::string& repoId) { CLog::Log(LOGDEBUG, "CAddonInstaller: installing '%s' version '%s' from repository '%s'", addonId.c_str(), version.asString().c_str(), repoId.c_str()); AddonPtr addon; CAddonDatabase database; if (!database.Open() || !database.GetAddon(addonId, version, repoId, addon)) return; AddonPtr repo; if (!CAddonMgr::GetInstance().GetAddon(repoId, repo, ADDON_REPOSITORY)) return; std::string hash; if (!std::static_pointer_cast<CRepository>(repo)->GetAddonHash(addon, hash)) return; DoInstall(addon, std::static_pointer_cast<CRepository>(repo), hash, true, false); }
bool CGUIDialogAddonInfo::SetItem(const CFileItemPtr& item) { *m_item = *item; // grab the local addon, if it's available m_localAddon.reset(); if (CAddonMgr::Get().GetAddon(item->GetProperty("Addon.ID"), m_localAddon)) // sets m_addon if installed regardless of enabled state m_item->SetProperty("Addon.Enabled", "true"); else m_item->SetProperty("Addon.Enabled", "false"); m_item->SetProperty("Addon.Installed", m_addon ? "true" : "false"); CAddonDatabase database; database.Open(); database.GetAddon(item->GetProperty("Addon.ID"),m_addon); if (TranslateType(item->GetProperty("Addon.intType")) == ADDON_REPOSITORY) { CAddonDatabase database; database.Open(); VECADDONS addons; if (m_addon) database.GetRepository(m_addon->ID(), addons); else if (m_localAddon) // sanity database.GetRepository(m_localAddon->ID(), addons); int tot=0; for (int i = ADDON_UNKNOWN+1;i<ADDON_VIZ_LIBRARY;++i) { int num=0; for (unsigned int j=0;j<addons.size();++j) { if (addons[j]->Type() == (TYPE)i) ++num; } m_item->SetProperty(CStdString("Repo.") + TranslateType((TYPE)i), num); tot += num; } m_item->SetProperty("Repo.Addons", tot); } return true; }
bool CAddonUnInstallJob::DoWork() { ADDON::OnPreUnInstall(m_addon); //TODO: looks broken. it just calls the repo with the most recent version, not the owner RepositoryPtr repoPtr; CAddonInstaller::GetRepoForAddon(m_addon->ID(), repoPtr); if (repoPtr != NULL && !repoPtr->Props().libname.empty()) { CFileItemList dummy; std::string s = StringUtils::Format("plugin://%s/?action=uninstall&package=%s", repoPtr->ID().c_str(), m_addon->ID().c_str()); if (!CDirectory::GetDirectory(s, dummy)) return false; } else { //Unregister addon with the manager to ensure nothing tries //to interact with it while we are uninstalling. CAddonMgr::GetInstance().UnregisterAddon(m_addon->ID()); if (!DeleteAddon(m_addon->Path())) { CLog::Log(LOGERROR, "CAddonUnInstallJob[%s]: could not delete addon data.", m_addon->ID().c_str()); return false; } } ClearFavourites(); AddonPtr addon; CAddonDatabase database; // try to get the addon object from the repository as the local one does not exist anymore // if that doesn't work fall back to the local one if (!database.Open() || !database.GetAddon(m_addon->ID(), addon) || addon == NULL) addon = m_addon; CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24144))); ADDON::OnPostUnInstall(m_addon); return true; }
void CAddonInstallJob::ReportInstallError(const std::string& addonID, const std::string& fileName, const std::string& message /* = "" */) { AddonPtr addon; CAddonDatabase database; if (database.Open()) { database.GetAddon(addonID, addon); database.Close(); } MarkFinished(); std::string msg = message; EventPtr activity; if (addon != NULL) { AddonPtr addon2; CAddonMgr::GetInstance().GetAddon(addonID, addon2); if (msg.empty()) msg = g_localizeStrings.Get(addon2 != NULL ? 113 : 114); activity = EventPtr(new CAddonManagementEvent(addon, EventLevelError, msg)); if (IsModal()) CGUIDialogOK::ShowAndGetInput(CVariant{m_addon->Name()}, CVariant{msg}); } else { activity = EventPtr(new CNotificationEvent(EventLevelError, 24045, !msg.empty() ? msg : StringUtils::Format(g_localizeStrings.Get(24143).c_str(), fileName.c_str()))); if (IsModal()) CGUIDialogOK::ShowAndGetInput(CVariant{fileName}, CVariant{msg}); } CEventLog::GetInstance().Add(activity, !IsModal(), false); }
bool CAddonInstaller::CheckDependencies(const AddonPtr &addon, std::vector<std::string>& preDeps, CAddonDatabase &database) { if (!addon.get()) return true; // a NULL addon has no dependencies ADDONDEPS deps = addon->GetDeps(); database.Open(); for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i) { const CStdString &addonID = i->first; const AddonVersion &version = i->second.first; bool optional = i->second.second; AddonPtr dep; bool haveAddon = CAddonMgr::Get().GetAddon(addonID, dep); if ((haveAddon && !dep->MeetsVersion(version)) || (!haveAddon && !optional)) { // we have it but our version isn't good enough, or we don't have it and we need it if (!database.GetAddon(addonID, dep) || !dep->MeetsVersion(version)) { // we don't have it in a repo, or we have it but the version isn't good enough, so dep isn't satisfied. CLog::Log(LOGDEBUG, "Addon %s requires %s version %s which is not available", addon->ID().c_str(), addonID.c_str(), version.c_str()); database.Close(); return false; } } // at this point we have our dep, or the dep is optional (and we don't have it) so check that it's OK as well // TODO: should we assume that installed deps are OK? if (dep && std::find(preDeps.begin(), preDeps.end(), dep->ID()) == preDeps.end()) { if (!CheckDependencies(dep, preDeps, database)) { database.Close(); return false; } preDeps.push_back(dep->ID()); } } database.Close(); return true; }
bool CAddonUnInstallJob::DoWork() { ADDON::OnPreUnInstall(m_addon); //Unregister addon with the manager to ensure nothing tries //to interact with it while we are uninstalling. if (!CAddonMgr::GetInstance().UnloadAddon(m_addon)) { CLog::Log(LOGERROR, "CAddonUnInstallJob[%s]: failed to unload addon.", m_addon->ID().c_str()); return false; } CFilesystemInstaller fsInstaller; if (!fsInstaller.UnInstallFromFilesystem(m_addon->Path())) { CLog::Log(LOGERROR, "CAddonUnInstallJob[%s]: could not delete addon data.", m_addon->ID().c_str()); return false; } ClearFavourites(); if (m_removeData) CFileUtils::DeleteItem("special://profile/addon_data/"+m_addon->ID()+"/", true); AddonPtr addon; CAddonDatabase database; // try to get the addon object from the repository as the local one does not exist anymore // if that doesn't work fall back to the local one if (!database.Open() || !database.GetAddon(m_addon->ID(), addon) || addon == NULL) addon = m_addon; CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24144))); CAddonMgr::GetInstance().OnPostUnInstall(m_addon->ID()); database.OnPostUnInstall(m_addon->ID()); ADDON::OnPostUnInstall(m_addon); return true; }
void CAddonInstallJob::ReportInstallError(const CStdString& addonID, const CStdString& fileName) { AddonPtr addon; CAddonDatabase database; database.Open(); database.GetAddon(addonID, addon); if (addon) { AddonPtr addon2; CAddonMgr::Get().GetAddon(addonID, addon2); CGUIDialogKaiToast::QueueNotification(addon->Icon(), addon->Name(), g_localizeStrings.Get(addon2 ? 113 : 114), TOAST_DISPLAY_TIME, false); } else { CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, fileName, g_localizeStrings.Get(114), TOAST_DISPLAY_TIME, false); } }
bool CAddonInstaller::Install(const CStdString &addonID, bool force, const CStdString &referer, bool background) { AddonPtr addon; bool addonInstalled = CAddonMgr::Get().GetAddon(addonID, addon, ADDON_UNKNOWN, false); if (addonInstalled && !force) return true; // check whether we have it available in a repository CAddonDatabase database; database.Open(); if (database.GetAddon(addonID, addon)) { CStdString repo; database.GetRepoForAddon(addonID,repo); AddonPtr ptr; CAddonMgr::Get().GetAddon(repo,ptr); RepositoryPtr therepo = boost::dynamic_pointer_cast<CRepository>(ptr); CStdString hash; if (therepo) hash = therepo->GetAddonHash(addon); return DoInstall(addon, hash, addonInstalled, referer, background); } return false; }
bool CAddonsDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CStdString path1(strPath); URIUtils::RemoveSlashAtEnd(path1); CURL path(path1); items.ClearProperties(); items.SetContent("addons"); VECADDONS addons; // get info from repository bool reposAsFolders = true; if (path.GetHostName().Equals("enabled")) { CAddonMgr::Get().GetAllAddons(addons, true); items.SetProperty("reponame",g_localizeStrings.Get(24062)); items.SetLabel(g_localizeStrings.Get(24062)); } else if (path.GetHostName().Equals("disabled")) { // grab all disabled addons, including disabled repositories reposAsFolders = false; CAddonMgr::Get().GetAllAddons(addons, false, true); items.SetProperty("reponame",g_localizeStrings.Get(24039)); items.SetLabel(g_localizeStrings.Get(24039)); } else if (path.GetHostName().Equals("outdated")) { reposAsFolders = false; CAddonMgr::Get().GetAllOutdatedAddons(addons); items.SetProperty("reponame",g_localizeStrings.Get(24043)); items.SetLabel(g_localizeStrings.Get(24043)); } else if (path.GetHostName().Equals("repos")) { CAddonMgr::Get().GetAddons(ADDON_REPOSITORY,addons,true); items.SetLabel(g_localizeStrings.Get(24033)); // Get Add-ons } else if (path.GetHostName().Equals("sources")) { return GetScriptsAndPlugins(path.GetFileName(), items); } else if (path.GetHostName().Equals("all")) { CAddonDatabase database; database.Open(); database.GetAddons(addons); items.SetProperty("reponame",g_localizeStrings.Get(24032)); items.SetLabel(g_localizeStrings.Get(24032)); } else if (path.GetHostName().Equals("search")) { CStdString search(path.GetFileName()); if (search.IsEmpty() && !GetKeyboardInput(16017, search)) return false; items.SetProperty("reponame",g_localizeStrings.Get(283)); items.SetLabel(g_localizeStrings.Get(283)); CAddonDatabase database; database.Open(); database.Search(search, addons); GenerateListing(path, addons, items, true); path.SetFileName(search); items.SetPath(path.Get()); return true; } else { reposAsFolders = false; AddonPtr addon; CAddonMgr::Get().GetAddon(path.GetHostName(),addon); if (!addon) return false; // ensure our repos are up to date CAddonInstaller::Get().UpdateRepos(false, true); CAddonDatabase database; database.Open(); database.GetRepository(addon->ID(),addons); items.SetProperty("reponame",addon->Name()); items.SetLabel(addon->Name()); } if (path.GetFileName().IsEmpty()) { if (!path.GetHostName().Equals("repos")) { for (int i=ADDON_UNKNOWN+1;i<ADDON_VIZ_LIBRARY;++i) { for (unsigned int j=0;j<addons.size();++j) { if (addons[j]->IsType((TYPE)i)) { CFileItemPtr item(new CFileItem(TranslateType((TYPE)i,true))); item->SetPath(URIUtils::AddFileToFolder(strPath,TranslateType((TYPE)i,false))); item->m_bIsFolder = true; CStdString thumb = GetIcon((TYPE)i); if (!thumb.IsEmpty() && g_TextureManager.HasTexture(thumb)) item->SetArt("thumb", thumb); items.Add(item); break; } } } items.SetPath(strPath); return true; } } else { TYPE type = TranslateType(path.GetFileName()); items.SetProperty("addoncategory",TranslateType(type, true)); items.SetLabel(TranslateType(type, true)); items.SetPath(strPath); // FIXME: Categorisation of addons needs adding here for (unsigned int j=0;j<addons.size();++j) { if (!addons[j]->IsType(type)) addons.erase(addons.begin()+j--); } } items.SetPath(strPath); GenerateListing(path, addons, items, reposAsFolders); // check for available updates if (path.GetHostName().Equals("enabled")) { CAddonDatabase database; database.Open(); for (int i=0;i<items.Size();++i) { AddonPtr addon2; database.GetAddon(items[i]->GetProperty("Addon.ID").asString(),addon2); if (addon2 && addon2->Version() > AddonVersion(items[i]->GetProperty("Addon.Version").asString()) && !database.IsAddonBlacklisted(addon2->ID(),addon2->Version().c_str())) { items[i]->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); items[i]->SetProperty("Addon.UpdateAvail", true); } } } if (path.GetHostName().Equals("repos") && items.Size() > 1) { CFileItemPtr item(new CFileItem("addons://all/",true)); item->SetLabel(g_localizeStrings.Get(24032)); items.Add(item); } return true; }
bool CAddonsDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CStdString path1(strPath); CUtil::RemoveSlashAtEnd(path1); CURL path(path1); items.ClearProperties(); items.SetContent("addons"); VECADDONS addons; // get info from repository bool reposAsFolders = true; if (path.GetHostName().Equals("enabled")) { CAddonMgr::Get().GetAllAddons(addons, true); items.SetProperty("reponame",g_localizeStrings.Get(24062)); } else if (path.GetHostName().Equals("disabled")) { // grab all disabled addons, including disabled repositories reposAsFolders = false; CAddonMgr::Get().GetAllAddons(addons, false, true); items.SetProperty("reponame",g_localizeStrings.Get(24039)); } else if (path.GetHostName().Equals("outdated")) { reposAsFolders = false; CAddonMgr::Get().GetAllOutdatedAddons(addons); items.SetProperty("reponame",g_localizeStrings.Get(24043)); } else if (path.GetHostName().Equals("repos")) { CAddonMgr::Get().GetAddons(ADDON_REPOSITORY,addons,true); } else if (path.GetHostName().Equals("sources")) { return GetScriptsAndPlugins(path.GetFileName(), items); } else if (path.GetHostName().Equals("all")) { CAddonDatabase database; database.Open(); database.GetAddons(addons); items.SetProperty("reponame",g_localizeStrings.Get(24032)); } else { AddonPtr addon; CAddonMgr::Get().GetAddon(path.GetHostName(),addon); if (!addon) return false; CAddonDatabase database; database.Open(); if (!database.GetRepository(addon->ID(),addons)) { RepositoryPtr repo = boost::dynamic_pointer_cast<CRepository>(addon); addons = CRepositoryUpdateJob::GrabAddons(repo,false); } items.SetProperty("reponame",addon->Name()); } if (path.GetFileName().IsEmpty()) { if (!path.GetHostName().Equals("repos")) { for (int i=ADDON_UNKNOWN+1;i<ADDON_VIZ_LIBRARY;++i) { for (unsigned int j=0;j<addons.size();++j) { if (addons[j]->IsType((TYPE)i)) { CFileItemPtr item(new CFileItem(TranslateType((TYPE)i,true))); item->m_strPath = CUtil::AddFileToFolder(strPath,TranslateType((TYPE)i,false)); item->m_bIsFolder = true; CStdString thumb = GetIcon((TYPE)i); if (!thumb.IsEmpty() && g_TextureManager.HasTexture(thumb)) item->SetThumbnailImage(thumb); items.Add(item); break; } } } items.m_strPath = strPath; return true; } } else { TYPE type = TranslateType(path.GetFileName()); items.SetProperty("addoncategory",TranslateType(type, true)); items.m_strPath = strPath; // FIXME: Categorisation of addons needs adding here for (unsigned int j=0;j<addons.size();++j) { if (!addons[j]->IsType(type)) addons.erase(addons.begin()+j--); } } items.m_strPath = strPath; GenerateListing(path, addons, items, reposAsFolders); // check for available updates if (path.GetHostName().Equals("enabled")) { CAddonDatabase database; database.Open(); for (int i=0;i<items.Size();++i) { AddonPtr addon2; database.GetAddon(items[i]->GetProperty("Addon.ID"),addon2); if (addon2 && addon2->Version() > AddonVersion(items[i]->GetProperty("Addon.Version"))) { items[i]->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); items[i]->SetProperty("Addon.UpdateAvail","true"); } } } if (path.GetHostName().Equals("repos") && items.Size() > 1) { CFileItemPtr item(new CFileItem("addons://all/",true)); item->SetLabel(g_localizeStrings.Get(24032)); items.Add(item); } return true; }
bool CRepositoryUpdateJob::DoWork() { CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] checking for updates.", m_repo->ID().c_str()); CAddonDatabase database; database.Open(); std::string oldChecksum; if (database.GetRepoChecksum(m_repo->ID(), oldChecksum) == -1) oldChecksum = ""; std::string newChecksum; VECADDONS addons; auto status = m_repo->FetchIfChanged(oldChecksum, newChecksum, addons); database.SetLastChecked(m_repo->ID(), m_repo->Version(), CDateTime::GetCurrentDateTime().GetAsDBDateTime()); MarkFinished(); if (status == CRepository::STATUS_ERROR) return false; if (status == CRepository::STATUS_NOT_MODIFIED) { CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] checksum not changed.", m_repo->ID().c_str()); return true; } //Invalidate art. { CTextureDatabase textureDB; textureDB.Open(); textureDB.BeginMultipleExecute(); for (const auto& addon : addons) { AddonPtr oldAddon; if (database.GetAddon(addon->ID(), oldAddon) && addon->Version() > oldAddon->Version()) { if (!oldAddon->Icon().empty() || !oldAddon->FanArt().empty() || !oldAddon->Screenshots().empty()) CLog::Log(LOGDEBUG, "CRepository: invalidating cached art for '%s'", addon->ID().c_str()); if (!oldAddon->Icon().empty()) textureDB.InvalidateCachedTexture(oldAddon->Icon()); if (!oldAddon->FanArt().empty()) textureDB.InvalidateCachedTexture(oldAddon->Icon()); for (const auto& path : oldAddon->Screenshots()) textureDB.InvalidateCachedTexture(path); } } textureDB.CommitMultipleExecute(); } database.UpdateRepositoryContent(m_repo->ID(), m_repo->Version(), newChecksum, addons); //Notify about broken status changes for (const auto& addon : addons) { AddonPtr localAddon; if (!CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon)) continue; if (localAddon && localAddon->Version() > addon->Version()) //We have a newer version locally continue; AddonPtr oldAddon; database.GetAddon(addon->ID(), oldAddon); if (database.GetAddonVersion(addon->ID()).first > addon->Version()) //Newer version in db (ie. in a different repo) continue; std::string broken = addon->Broken(); bool isBroken = !addon->Broken().empty(); bool isBrokenInDb = oldAddon && !oldAddon->Broken().empty(); if (isBroken && !isBrokenInDb) { //newly broken if (HELPERS::ShowYesNoDialogLines(CVariant{addon->Name()}, CVariant{24096}, CVariant{24097}, CVariant{""}) == DialogResponse::YES) { CAddonMgr::GetInstance().DisableAddon(addon->ID()); } CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' marked broken. reason: \"%s\"", m_repo->ID().c_str(), addon->ID().c_str(), broken.c_str()); CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24096))); } else if (!isBroken && isBrokenInDb) { //Unbroken CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' unbroken", m_repo->ID().c_str(), addon->ID().c_str()); } } return true; }