diff --git a/pyproject.toml b/pyproject.toml index 152d9f245..41e678fd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -155,8 +155,6 @@ lint.unfixable = [] # Exclude a variety of commonly ignored directories. exclude = [ "scal3/account/google.py", - "scal3/import_config_2to3.py", - "scal3/ui_gtk/import_config_2to3.py", "libs", # "setup.py", ] diff --git a/scal3/import_config_2to3.py b/scal3/import_config_2to3.py deleted file mode 100755 index 310626097..000000000 --- a/scal3/import_config_2to3.py +++ /dev/null @@ -1,508 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) Saeed Rasooli -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License along -# with this program. If not, see . - -# no logging in this file - -from __future__ import annotations - -import json -import logging -import os -import re -import shutil -from collections import OrderedDict -from collections.abc import Generator -from os.path import isdir, isfile, join, splitext -from time import time as now -from typing import Any - -from scal3.json_utils import dataToPrettyJson -from scal3.os_utils import makeDir -from scal3.path import confDir as newConfDir -from scal3.s_object import DefaultFileSystem, saveBsonObject - -log = logging.getLogger("starcal3") - -[ - "getOldVersion", - # 'importAccountsIter', - # 'importBasicConfigIter', - "importConfigIter", - # 'importEventBasicJsonIter', - # 'importEventsIter', - # 'importGroupsIter', - # 'importPluginsIter', - # 'importTrashIter', - # 'loadConf', - # 'loadCoreConf', - # 'loadUiCustomizeConf', - # 'newAccountsDir', - # 'newConfDir', - # 'newEventDir', - # 'newEventEventsDir', - # 'newGroupsDir', - # 'oldAccountsDir', - # 'oldConfDir', - # 'oldEventDir', - # 'oldEventEventsDir', - # 'oldGroupsDir', - # 'writeJsonConf' -] - - -oldConfDir = newConfDir.replace("starcal3", "starcal2") - -oldEventDir = join(oldConfDir, "event") -newEventDir = join(newConfDir, "event") - -oldEventEventsDir = join(oldEventDir, "events") -newEventEventsDir = join(newEventDir, "events") - -oldGroupsDir = join(oldEventDir, "groups") -newGroupsDir = join(newEventDir, "groups") - -oldAccountsDir = join(oldEventDir, "accounts") -newAccountsDir = join(newEventDir, "accounts") - -fsNew = DefaultFileSystem(newConfDir) - - -def loadConf(confPath) -> None: - if not isfile(confPath): - return - try: - with open(confPath) as fp: - text = fp.read() - except Exception as e: - print(f"failed to read file {confPath!r}: {e}") - return - # ----- - data = OrderedDict() - exec(text, {}, data) - return data - - -def loadCoreConf() -> None: - confPath = join(oldConfDir, "core.conf") - # ----- - - if not isfile(confPath): - return {} - - def loadPlugin(fname, **data): - data["_file"] = fname - return data - - try: - with open(confPath) as fp: - text = fp.read() - except Exception as e: - raise OSError(f"failed to read file {confPath!r}: {e}") from None - # ------ - text = text.replace("calTypes.activeNames", "activeCalTypes") - text = text.replace("calTypes.inactiveNames", "inactiveCalTypes") - # ------ - data = OrderedDict() - exec( - text, - { - "loadPlugin": loadPlugin, - }, - data, - ) - return data - - -def loadUiCustomizeConf() -> None: - confPath = join(oldConfDir, "ui-customize.conf") - # ----- - if not isfile(confPath): - return - # ----- - try: - with open(confPath) as fp: - text = fp.read() - except Exception as e: - print(f"failed to read file {confPath!r}: {e}") - return - # ----- - text = re.sub(r"^ui\.", "", text, flags=re.MULTILINE) - text = re.sub(r"^ud\.", "ud__", text, flags=re.MULTILINE) - # ------ - data = OrderedDict() - exec(text, {}, data) - data["wcal_toolbar_mainMenu_icon"] = "starcal.png" - return data - - -def writeJsonConf(name: str, data: Any): - if data is None: - return - fname = name + ".json" - jsonPath = join(newConfDir, fname) - text = dataToPrettyJson(data, sort_keys=True) - try: - open(jsonPath, "w").write(text) - except Exception as e: - print(f"failed to write file {jsonPath!r}: {e}") - - -def importEventsIter() -> Generator[int, None, None]: - makeDir(newEventEventsDir) - oldFiles = os.listdir(oldEventEventsDir) - yield len(oldFiles) - index = 0 - for dname in oldFiles: - yield index - index += 1 - # ---- - try: - _id = int(dname) - except ValueError: - continue - dpath = join(oldEventEventsDir, dname) - newDpath = join(newEventEventsDir, dname) - if not isdir(dpath): - log.info(f"{dpath!r} must be a directory") - continue - jsonPath = join(dpath, "event.json") - if not isfile(jsonPath): - log.info(f"{jsonPath!r}: not such file") - continue - try: - with open(jsonPath) as fp: - data = json.loads(fp.read()) - except Exception: - print(f"error while loading json file {jsonPath!r}") - continue - try: - tm = data.pop("modified") - except KeyError: - tm = now() - # --- - basicData = {} - # basicData["modified"] = tm - # --- - # remove extra params from data and add to basicData - for param in ( - "remoteIds", - "notifiers", # FIXME - ): - try: - basicData[param] = data.pop(param) - except KeyError: - pass - # --- - _hash = saveBsonObject(data, fsNew) - basicData["history"] = [(tm, _hash)] - open(newDpath + ".json", "w").write( - dataToPrettyJson(basicData, sort_keys=True), - ) - - -def importGroupsIter() -> Generator[int, None, None]: - groupsEnableDict = {} # {groupId -> enable} - # --- - makeDir(newGroupsDir) - # --- - oldFiles = os.listdir(oldGroupsDir) - yield len(oldFiles) + 1 - index = 0 - # --- - for fname in oldFiles: - yield index - index += 1 - jsonPath = join(oldGroupsDir, fname) - newJsonPath = join(newGroupsDir, fname) - if not isfile(jsonPath): - log.info(f"{jsonPath!r}: not such file") - continue - jsonPathNoX, ext = splitext(fname) - if ext != ".json": - continue - try: - _id = int(jsonPathNoX) - except ValueError: - continue - try: - with open(jsonPath) as fp: - data = json.loads(fp.read()) - except Exception: - print(f"error while loading json file {jsonPath!r}") - continue - # ---- - groupsEnableDict[_id] = data.pop("enable", True) - # ---- - if "history" in data: - log.info(f"skipping {jsonPath!r}: history already exists") - continue - try: - tm = data.pop("modified") - except KeyError: - tm = now() - # --- - basicData = {} - # basicData["modified"] = tm - # --- - # remove extra params from data and add to basicData - for param in ("remoteIds",): - basicData[param] = data.pop(param, None) - for param in ( - "enable", - "idList", - "remoteSyncData", - "deletedRemoteEvents", - ): - try: - basicData[param] = data.pop(param) - except KeyError: - pass - # --- - _hash = saveBsonObject(data, fsNew) - basicData["history"] = [(tm, _hash)] - open(newJsonPath, "w").write(dataToPrettyJson(basicData, sort_keys=True)) - # ---- - yield index - index += 1 - oldGroupListFile = join(oldEventDir, "group_list.json") - newGroupListFile = join(newEventDir, "group_list.json") - try: - with open(oldGroupListFile) as fp: - groupIds = json.loads(fp.read()) - except Exception as e: - print(f"error while loading {oldGroupListFile!r}: {e}") - else: - if isinstance(groupIds, list): - signedGroupIds = [ - (1 if groupsEnableDict.get(gid, True) else -1) * gid for gid in groupIds - ] - try: - open(newGroupListFile, "w").write(dataToPrettyJson(signedGroupIds)) - except Exception as e: - print(f"error while writing {newGroupListFile!r}: {e}") - else: - log.info( - f"file {oldGroupListFile!r} contains invalid data" - ", must contain a list", - ) - - -def importAccountsIter() -> Generator[int, None, None]: - makeDir(newAccountsDir) - # --- - oldFiles = os.listdir(oldAccountsDir) - yield len(oldFiles) - index = 0 - # --- - for fname in oldFiles: - yield index - index += 1 - jsonPath = join(oldAccountsDir, fname) - newJsonPath = join(newAccountsDir, fname) - if not isfile(jsonPath): - log.info(f"{jsonPath!r}: not such file") - continue - jsonPathNoX, ext = splitext(fname) - if ext != ".json": - continue - try: - _id = int(jsonPathNoX) - except ValueError: - continue - try: - with open(jsonPath) as fp: - data = json.loads(fp.read()) - except Exception: - print(f"error while loading json file {jsonPath!r}") - continue - if "history" in data: - log.info(f"skipping {jsonPath!r}: history already exists") - continue - try: - tm = data.pop("modified") - except KeyError: - tm = now() - # --- - basicData = {} - # basicData["modified"] = tm - # --- - # remove extra params from data and add to basicData - for param in ("enable",): - try: - basicData[param] = data.pop(param) - except KeyError: - pass - # --- - _hash = saveBsonObject(data, fsNew) - basicData["history"] = [(tm, _hash)] - open(newJsonPath, "w").write( - dataToPrettyJson(basicData, sort_keys=True), - ) - - -def importTrashIter() -> Generator[int, None, None]: - yield 1 - yield 0 - jsonPath = join(oldEventDir, "trash.json") - newJsonPath = join(newEventDir, "trash.json") - try: - with open(jsonPath) as fp: - data = json.loads(fp.read()) - except Exception as e: - log.info(e) - return - if "history" in data: - log.info(f"skipping {jsonPath!r}: history already exists") - return - try: - tm = data.pop("modified") - except KeyError: - tm = now() - # --- - basicData = {} - # basicData["modified"] = tm - # --- - # remove extra params from data and add to basicData - for param in ("idList",): - try: - basicData[param] = data.pop(param) - except KeyError: - pass - # --- - _hash = saveBsonObject(data, fsNew) - basicData["history"] = [(tm, _hash)] - open(newJsonPath, "w").write(dataToPrettyJson(basicData, sort_keys=True)) - - -def importBasicConfigIter() -> Generator[int, None, None]: - yield 8 # number of steps - index = 0 - # ---- - coreData = loadCoreConf() - coreData["version"] = "3.0.0" # FIXME - writeJsonConf("core", coreData) - yield index - index += 1 - # ---- - writeJsonConf("ui-customize", loadUiCustomizeConf()) - yield index - index += 1 - # remove adjustTimeCmd from ui-gtk.conf - for name in ( - "hijri", - "jalali", - "locale", - "ui", - "ui-gtk", - "ui-live", - ): - yield index - index += 1 - confPath = join(oldConfDir, name + ".conf") - writeJsonConf(name, loadConf(confPath)) - - -def importEventBasicJsonIter() -> Generator[int, None, None]: - yield 4 # number of steps - index = 0 - # ---- - for name in ( - "account_list", - "info", - "last_ids", - ): - yield index - index += 1 - fname = name + ".json" - try: - shutil.copy( - join(oldEventDir, fname), - join(newEventDir, fname), - ) - except Exception as e: - log.info(e) - - -def importPluginsIter() -> Generator[int, None, None]: - oldPlugConfDir = join(oldConfDir, "plugins.conf") - if isdir(oldPlugConfDir): - files = os.listdir(oldPlugConfDir) - else: - files = [] - # -------- - yield len(files) - index = 0 - # ---- - for plugName in files: - writeJsonConf( - plugName, # move it out of plugins.conf FIXME - loadConf( - join(oldPlugConfDir, plugName), - ), - ) - yield index - index += 1 - - -def importConfigIter() -> Generator[int, None, None]: - makeDir(newConfDir) - makeDir(newEventDir) - # --------- - funcs = [ - importBasicConfigIter, - importEventBasicJsonIter, - importPluginsIter, - importGroupsIter, - importGroupsIter, - importAccountsIter, - importTrashIter, - importEventsIter, - ] - # --- - iters = [func() for func in funcs] - # --- - counts = [itr.send(None) for itr in iters] - totalCount = sum(counts) - # --- - totalRatio = 0.0 - delta = 1.0 / totalCount - for iterIndex, itr in enumerate(iters): - iterCount = counts[iterIndex] - for stepIndex in itr: - yield totalRatio + stepIndex * delta - totalRatio += iterCount * delta - yield totalRatio - # --- - yield 1.0 - - -def getOldVersion() -> str: - """ - return version of installed starcal 2.3.x or 2.4.x - from user"s configuration directory (file ~/.starcal2/core.conf). - - before 2.3.0, version was not stored in configuration directory - """ - data = loadCoreConf() - return data.get("version", "") - - -# ---------------------------------- - - -if __name__ == "__main__": - list(importConfigIter()) diff --git a/scal3/ui_gtk/import_config_2to3.py b/scal3/ui_gtk/import_config_2to3.py deleted file mode 100755 index a029fe3a6..000000000 --- a/scal3/ui_gtk/import_config_2to3.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -- -# -- Copyright (C) Saeed Rasooli -# -- -# -- This program is free software; you can redistribute it and/or modify -# -- it under the terms of the GNU Affero General Public License as published by -# -- the Free Software Foundation; either version 3 of the License, or -# -- (at your option) any later version. -# -- -# -- This program is distributed in the hope that it will be useful, -# -- but WITHOUT ANY WARRANTY; without even the implied warranty of -# -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# -- GNU Affero General Public License for more details. -# -- -# -- You should have received a copy of the GNU Affero General Public License along -# -- If not, see . - -APP_DESC = "StarCalendar" - -from scal3 import logger - -log = logger.get() - -import os -import shutil -from os.path import isfile, join - -from scal3.import_config_2to3 import getOldVersion, importConfigIter -from scal3.json_utils import dataToPrettyJson -from scal3.locale_man import langDefault, langDict -from scal3.path import ( - confDir, - pixDir, - sourceDir, -) -from scal3.ui_gtk import HBox, gtk, pack -from scal3.ui_gtk.utils import dialog_add_button - -_ = str - -langConfDir = join(sourceDir, "conf", "defaults") - -gtk.Window.set_default_icon_from_file(join(pixDir, "starcal.png")) - -langNameList = [] -langCodeList = [] - - -win = gtk.Dialog( - title=APP_DESC + " 3.x - First Run", -) -dialog_add_button( - win, - imageName="dialog-ok.svg", - label=_("OK"), - res=gtk.ResponseType.OK, -) -dialog_add_button( - win, - imageName="dialog-cancel.svg", - label=_("Cancel"), - res=gtk.ResponseType.CANCEL, -) -langHbox = HBox() -pack(langHbox, gtk.Label(label="Select Language:")) - - -importCheckb = None -oldVersion = getOldVersion() -if oldVersion: # and "2.2.0" <= oldVersion < "2.5.0":-- FIXME - importCheckb = gtk.CheckButton( - f"Import configurations from {APP_DESC} {oldVersion}", - ) - importCheckb.connect( - "clicked", - lambda cb: langHbox.set_sensitive(not cb.get_active()), - ) - importCheckb.set_active(True) - pack(win.vbox, importCheckb) - - -langCombo = gtk.ComboBoxText() - -for langObj in langDict.values(): - langNameList.append(langObj.name) - langCodeList.append(langObj.code) - langCombo.append_text(langObj.name) - - -if langDefault and (langDefault in langCodeList): - langCombo.set_active(langCodeList.index(langDefault)) -else: - langCombo.set_active(0) - -pack(langHbox, langCombo, 1, 1) -pack(win.vbox, langHbox) - -pbarHbox = HBox() -pbar = gtk.ProgressBar() -pack(pbarHbox, pbar, 1, 1) -pack(win.vbox, pbarHbox) - - -win.vbox.show_all() - -if win.run() == gtk.ResponseType.OK: - # log.debug("RESPONSE OK") - if importCheckb and importCheckb.get_active(): - importCheckb.set_sensitive(False) - langHbox.set_sensitive(False) - win.get_action_area().set_sensitive(False) - for frac in importConfigIter(): - pbar.set_fraction(frac) - percent = frac * 100 - text = f"{percent:.1f}%" - pbar.set_text(text) - while gtk.events_pending(): - gtk.main_iteration_do(False) - else: - i = langCombo.get_active() - langCode = langCodeList[i] - thisLangConfDir = join(langConfDir, langCode) - # log.debug("Setting language", langCode) - if not os.path.isdir(confDir): - os.mkdir(confDir, 0o755) - if os.path.isdir(thisLangConfDir): - for fname in os.listdir(thisLangConfDir): - src_path = join(thisLangConfDir, fname) - if not isfile(src_path): - continue - dst_path = join(confDir, fname) - # log.debug(src_path) - shutil.copy(src_path, dst_path) - else: - open(join(confDir, "locale.json"), "w").write( - dataToPrettyJson( - { - "lang": langCode, - }, - ), - ) - -win.destroy() - -if not os.path.isdir(confDir): - os.mkdir(confDir, 0o755) diff --git a/scal3/ui_gtk/starcal.py b/scal3/ui_gtk/starcal.py index e91901325..114a45f81 100755 --- a/scal3/ui_gtk/starcal.py +++ b/scal3/ui_gtk/starcal.py @@ -27,7 +27,7 @@ import os.path import signal import typing -from os.path import dirname, isdir, isfile, join +from os.path import dirname, join from time import localtime, perf_counter if typing.TYPE_CHECKING: @@ -38,27 +38,12 @@ from scal3 import logger from scal3.cal_types import convert from scal3.path import ( - confDir, pixDir, sourceDir, ) log = logger.get() -if not (isfile(join(confDir, "core.json")) or isdir(join(confDir, "event"))): - from scal3.utils import restartLow - - try: - __import__("scal3.ui_gtk.import_config_2to3") - except Exception as e: - log.exception("") - log.error(str(e)) # TODO: log the full traceback - if not isdir(confDir): - os.mkdir(confDir, 0o755) - else: - if isfile(join(confDir, "core.json")): - restartLow() - from gi.repository import Gio as gio from scal3 import cal_types, core, event_lib, locale_man, ui diff --git a/update-perm b/update-perm index ba117fb92..7dc7a293d 100755 --- a/update-perm +++ b/update-perm @@ -1,7 +1,7 @@ #!/usr/bin/env sh set -x -cd "`dirname \"$0\"`" +cd "$(dirname \"$0\")" #chmod -R 755 . @@ -38,8 +38,6 @@ chmod 755 'locale.d/make-template' chmod 755 'scripts/version' chmod 755 'scripts/version.py' -chmod 755 'scal3/import_config_2to3.py' chmod 755 'scal3/ui_gtk/adjust_dtime.py' chmod 755 'scal3/ui_gtk/arch-enable-locale.py' -chmod 755 'scal3/ui_gtk/import_config_2to3.py'