-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
283 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# -*- coding: UTF-8 -*- | ||
""" | ||
Provide standard ways to get various dirs | ||
This is similar to th pyxdg module but it does not automatically creates the | ||
dirs. Not creating the dirs is important to be able to show default values in | ||
`yokadid --help` output without creating anything. | ||
@author: Aurélien Gâteau <mail@agateau.com> | ||
@license: GPL v3 or later | ||
""" | ||
import os | ||
import getpass | ||
import shutil | ||
import tempfile | ||
|
||
from yokadi.core import fileutils | ||
|
||
|
||
_WINDOWS = os.name == "nt" | ||
|
||
|
||
class MigrationException(Exception): | ||
pass | ||
|
||
|
||
def _getAppDataDir(): | ||
assert _WINDOWS | ||
return os.environ["APPDATA"] | ||
|
||
|
||
def getRuntimeDir(): | ||
value = os.getenv("XDG_RUNTIME_DIR") | ||
if not value: | ||
# Running on a system where XDG_RUNTIME_DIR is not set, fallback to | ||
# $tempdir/yokadi-$user | ||
tmpdir = tempfile.gettempdir() | ||
value = os.path.join(tmpdir, "yokadi-" + getpass.getuser()) | ||
return value | ||
|
||
|
||
def getLogDir(): | ||
return getCacheDir() | ||
|
||
|
||
def getCacheDir(): | ||
if _WINDOWS: | ||
value = os.path.join(_getAppDataDir(), "yokadi", "cache") | ||
else: | ||
cacheBaseDir = os.getenv("XDG_CACHE_HOME") | ||
if not cacheBaseDir: | ||
cacheBaseDir = os.path.expandvars("$HOME/.cache") | ||
value = os.path.join(cacheBaseDir, "yokadi") | ||
return value | ||
|
||
|
||
def getDataDir(): | ||
if _WINDOWS: | ||
value = os.path.join(_getAppDataDir(), "yokadi", "data") | ||
else: | ||
dataBaseDir = os.environ.get("XDG_DATA_HOME") | ||
if not dataBaseDir: | ||
dataBaseDir = os.path.expandvars("$HOME/.local/share") | ||
value = os.path.join(dataBaseDir, "yokadi") | ||
return value | ||
|
||
|
||
def getHistoryPath(): | ||
path = os.getenv("YOKADI_HISTORY") | ||
if path: | ||
return path | ||
return os.path.join(getCacheDir(), "history") | ||
|
||
|
||
def getDbPath(): | ||
path = os.getenv("YOKADI_DB") | ||
if path: | ||
return path | ||
return os.path.join(getDataDir(), "yokadi.db") | ||
|
||
|
||
def _getOldHistoryPath(): | ||
if _WINDOWS: | ||
return os.path.join(_getAppDataDir(), ".yokadi_history") | ||
else: | ||
return os.path.expandvars("$HOME/.yokadi_history") | ||
|
||
|
||
def migrateOldHistory(): | ||
oldHistoryPath = _getOldHistoryPath() | ||
if not os.path.exists(oldHistoryPath): | ||
return | ||
|
||
newHistoryPath = getHistoryPath() | ||
if os.path.exists(newHistoryPath): | ||
# History is not critical, just overwrite the new file | ||
os.unlink(newHistoryPath) | ||
fileutils.createParentDirs(newHistoryPath) | ||
shutil.move(oldHistoryPath, newHistoryPath) | ||
print("Moved %s to %s" % (oldHistoryPath, newHistoryPath)) | ||
|
||
|
||
def migrateOldDb(): | ||
oldDbPath = os.path.normcase(os.path.expandvars("$HOME/.yokadi.db")) | ||
if not os.path.exists(oldDbPath): | ||
return | ||
|
||
newDbPath = getDbPath() | ||
if os.path.exists(newDbPath): | ||
raise MigrationException("Tried to move %s to %s, but %s already exists. You must remove one of the two files." % (oldDbPath, newDbPath, newDbPath)) | ||
fileutils.createParentDirs(newDbPath) | ||
shutil.move(oldDbPath, newDbPath) | ||
print("Moved %s to %s" % (oldDbPath, newDbPath)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
""" | ||
Various file utility functions | ||
@author: Aurélien Gâteau <mail@agateau.com> | ||
@license: GPL v3 or later | ||
""" | ||
import os | ||
|
||
|
||
def createParentDirs(path, mode=0o777): | ||
parent = os.path.dirname(path) | ||
if os.path.exists(parent): | ||
return | ||
os.makedirs(parent, mode=mode) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
# -*- coding: UTF-8 -*- | ||
""" | ||
Basepaths test cases | ||
@author: Aurélien Gâteau <mail@agateau.com> | ||
@license: GPL v3 or later | ||
""" | ||
import os | ||
import shutil | ||
import tempfile | ||
import unittest | ||
|
||
from pathlib import Path | ||
|
||
from yokadi.core import basepaths | ||
|
||
|
||
def saveEnv(): | ||
return dict(os.environ) | ||
|
||
|
||
def restoreEnv(env): | ||
# Do not use `os.environ = env`: this would replace the special os.environ | ||
# object with a plain dict. We must update the *existing* object. | ||
os.environ.clear() | ||
os.environ.update(env) | ||
|
||
|
||
class BasePathsUnixTestCase(unittest.TestCase): | ||
def setUp(self): | ||
self._oldWindows = basepaths._WINDOWS | ||
basepaths._WINDOWS = False | ||
|
||
self._oldEnv = saveEnv() | ||
self.testHomeDir = tempfile.mkdtemp(prefix="yokadi-basepaths-testcase") | ||
os.environ["HOME"] = self.testHomeDir | ||
|
||
def tearDown(self): | ||
shutil.rmtree(self.testHomeDir) | ||
restoreEnv(self._oldEnv) | ||
basepaths._WINDOWS = self._oldWindows | ||
|
||
def testMigrateOldDb(self): | ||
oldDb = Path(self.testHomeDir) / '.yokadi.db' | ||
newDb = Path(basepaths.getDbPath()) | ||
|
||
oldDb.touch() | ||
|
||
basepaths.migrateOldDb() | ||
self.assertFalse(oldDb.exists()) | ||
self.assertTrue(newDb.exists()) | ||
|
||
def testMigrateNothingToDo(self): | ||
newDb = Path(basepaths.getDbPath()) | ||
basepaths.migrateOldDb() | ||
basepaths.migrateOldHistory() | ||
self.assertFalse(newDb.exists()) | ||
|
||
def testMigrateOldDbFails(self): | ||
oldDb = Path(self.testHomeDir) / '.yokadi.db' | ||
newDb = Path(basepaths.getDbPath()) | ||
|
||
oldDb.touch() | ||
newDb.parent.mkdir(parents=True) | ||
newDb.touch() | ||
|
||
self.assertRaises(basepaths.MigrationException, basepaths.migrateOldDb) | ||
|
||
def testMigrateOldHistory(self): | ||
old = Path(self.testHomeDir) / '.yokadi_history' | ||
new = Path(basepaths.getHistoryPath()) | ||
|
||
old.touch() | ||
|
||
basepaths.migrateOldHistory() | ||
self.assertFalse(old.exists()) | ||
self.assertTrue(new.exists()) | ||
|
||
def testMigrateOldHistoryOverwriteNew(self): | ||
old = Path(self.testHomeDir) / '.yokadi_history' | ||
new = Path(basepaths.getHistoryPath()) | ||
|
||
with old.open('w') as f: | ||
f.write('old') | ||
new.parent.mkdir(parents=True) | ||
with new.open('w') as f: | ||
f.write('new') | ||
|
||
basepaths.migrateOldHistory() | ||
self.assertFalse(old.exists()) | ||
with new.open() as f: | ||
newData = f.read() | ||
self.assertEqual(newData, 'old') | ||
|
||
def testHistoryEnvVar(self): | ||
path = "foo" | ||
os.environ["YOKADI_HISTORY"] = path | ||
self.assertEqual(basepaths.getHistoryPath(), path) | ||
|
||
def testDbEnvVar(self): | ||
path = "foo" | ||
os.environ["YOKADI_DB"] = path | ||
self.assertEqual(basepaths.getDbPath(), path) | ||
|
||
|
||
class BasePathsWindowsTestCase(unittest.TestCase): | ||
def setUp(self): | ||
self._oldWindows = basepaths._WINDOWS | ||
self._oldEnv = saveEnv() | ||
basepaths._WINDOWS = True | ||
self.testAppDataDir = tempfile.mkdtemp(prefix="yokadi-basepaths-testcase") | ||
os.environ["APPDATA"] = self.testAppDataDir | ||
|
||
def tearDown(self): | ||
shutil.rmtree(self.testAppDataDir) | ||
basepaths._WINDOWS = self._oldWindows | ||
restoreEnv(self._oldEnv) | ||
|
||
def testGetCacheDir(self): | ||
expected = os.path.join(self.testAppDataDir, "yokadi", "cache") | ||
self.assertEqual(basepaths.getCacheDir(), expected) | ||
|
||
def testGetDataDir(self): | ||
expected = os.path.join(self.testAppDataDir, "yokadi", "data") | ||
self.assertEqual(basepaths.getDataDir(), expected) | ||
|
||
def testOldHistoryPath(self): | ||
expected = os.path.join(self.testAppDataDir, ".yokadi_history") | ||
self.assertEqual(basepaths._getOldHistoryPath(), expected) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.