Merge pull request #56 from belissent/master_test2

Environment variables in mediapath
This commit is contained in:
Doug Blank 2015-08-20 12:23:42 -04:00
commit f8d04b5cb8
6 changed files with 220 additions and 84 deletions

View File

@ -7,7 +7,7 @@
<researcher>
<resname>Alex Roitman,,,</resname>
</researcher>
<mediapath>/home/pierre/Gramps/master/example/gramps</mediapath>
<mediapath>{GRAMPS_RESOURCES}/example/gramps</mediapath>
</header>
<name-formats>
<format number="-1" name="SURNAME, Given (Common)" fmt_str="SURNAME, given (common)" active="1"/>

View File

@ -11,7 +11,7 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# 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 General Public License for more details.
@ -85,16 +85,16 @@ APP_VCARD = ["text/x-vcard", "text/x-vcalendar"]
#
#-------------------------------------------------------------------------
if 'GRAMPSHOME' in os.environ:
USER_HOME = get_env_var('GRAMPSHOME')
USER_HOME = get_env_var('GRAMPSHOME')
HOME_DIR = os.path.join(USER_HOME, 'gramps')
elif 'USERPROFILE' in os.environ:
USER_HOME = get_env_var('USERPROFILE')
USER_HOME = get_env_var('USERPROFILE')
if 'APPDATA' in os.environ:
HOME_DIR = os.path.join(get_env_var('APPDATA'), 'gramps')
else:
HOME_DIR = os.path.join(USER_HOME, 'gramps')
else:
USER_HOME = get_env_var('HOME')
USER_HOME = get_env_var('HOME')
HOME_DIR = os.path.join(USER_HOME, '.gramps')
@ -115,9 +115,10 @@ USER_PLUGINS = os.path.join(VERSION_DIR, "plugins")
USER_DIRLIST = (USER_HOME, HOME_DIR, VERSION_DIR, ENV_DIR, TEMP_DIR, THUMB_DIR,
THUMB_NORMAL, THUMB_LARGE, USER_PLUGINS)
#-------------------------------------------------------------------------
#
# Paths to python modules - assumes that the root directory is one level
# Paths to python modules - assumes that the root directory is one level
# above this one, and that the plugins directory is below the root directory.
#
#-------------------------------------------------------------------------
@ -170,6 +171,32 @@ LOGO = os.path.join(IMAGE_DIR, "logo.png")
SPLASH = os.path.join(IMAGE_DIR, "splash.jpg")
LICENSE_FILE = os.path.join(_resources.doc_dir, 'COPYING')
#-------------------------------------------------------------------------
#
# GRAMPS environment variables dictionary
#
#-------------------------------------------------------------------------
ENV = {
"USER_HOME": USER_HOME,
"HOME_DIR": HOME_DIR,
"VERSION": VERSION,
"major_version": major_version,
"VERSION_DIR": VERSION_DIR,
"ENV_DIR": ENV_DIR,
"TEMP_DIR": TEMP_DIR,
"THUMB_DIR": THUMB_DIR,
"THUMB_NORMAL": THUMB_NORMAL,
"THUMB_LARGE": THUMB_LARGE,
"USER_PLUGINS": USER_PLUGINS,
"ROOT_DIR": ROOT_DIR,
"GLADE_DIR": GLADE_DIR,
"PLUGINS_DIR": PLUGINS_DIR,
"WEB_DIR": WEB_DIR,
"DATA_DIR": DATA_DIR,
"IMAGE_DIR": IMAGE_DIR,
}
#-------------------------------------------------------------------------
#
# Init Localization
@ -192,21 +219,21 @@ COMMENTS = _("Gramps\n (Genealogical Research and Analysis "
"is a personal genealogy program.")
AUTHORS = [
"Alexander Roitman",
"Benny Malengier",
"Benny Malengier",
"Brian Matherly",
"Donald A. Peterson",
"Donald N. Allingham",
"David Hampton",
"Donald A. Peterson",
"Donald N. Allingham",
"David Hampton",
"Martin Hawlisch",
"Richard Taylor",
"Richard Taylor",
"Tim Waugh",
"John Ralls"
]
AUTHORS_FILE = os.path.join(DATA_DIR, "authors.xml")
DOCUMENTERS = [
'Alexander Roitman',
'Alexander Roitman',
]
#-------------------------------------------------------------------------
@ -232,14 +259,14 @@ ARABIC_SEMICOLON = "؛"
# (longName, shortName, type , default, flags, descrip , argDescrip)
POPT_TABLE = [
("config", 'c', str, None, 0, "Set config setting(s) and start Gramps", ""),
("open", 'O', str, None, 0, "Open family tree", "FAMILY_TREE"),
("create", 'C', str, None, 0, "Create or Open family tree", "FAMILY_TREE"),
("import", 'i', str, None, 0, "Import file", "FILENAME"),
("open", 'O', str, None, 0, "Open family tree", "FAMILY_TREE"),
("create", 'C', str, None, 0, "Create or Open family tree", "FAMILY_TREE"),
("import", 'i', str, None, 0, "Import file", "FILENAME"),
("export", 'e', str, None, 0, "Export file", "FILENAME"),
("format", 'f', str, None, 0, 'Specify format', "FORMAT"),
("action", 'a', str, None, 0, 'Specify action', "ACTION"),
("options", 'p', str, None, 0, 'Specify options', "OPTIONS_STRING"),
("debug", 'd', str, None, 0, 'Enable debug logs', "LOGGER_NAME"),
("format", 'f', str, None, 0, 'Specify format', "FORMAT"),
("action", 'a', str, None, 0, 'Specify action', "ACTION"),
("options", 'p', str, None, 0, 'Specify options', "OPTIONS_STRING"),
("debug", 'd', str, None, 0, 'Enable debug logs', "LOGGER_NAME"),
("", 'l', None, None, 0, 'List Family Trees', ""),
("", 'L', None, None, 0, 'List Family Tree Details', ""),
("show", 's', None, None, 0, "Show config settings", ""),
@ -248,42 +275,42 @@ POPT_TABLE = [
]
LONGOPTS = [
"action=",
"action=",
"class=",
"config=",
"debug=",
"display=",
"disable-sound",
"disable-crash-dialog",
"disable-sound",
"disable-crash-dialog",
"enable-sound",
"espeaker=",
"export=",
"force-unlock",
"format=",
"gdk-debug=",
"gdk-no-debug=",
"gtk-debug=",
"gtk-no-debug=",
"gtk-module=",
"gdk-debug=",
"gdk-no-debug=",
"gtk-debug=",
"gtk-no-debug=",
"gtk-module=",
"g-fatal-warnings",
"help",
"import=",
"import=",
"load-modules=",
"list"
"list"
"name=",
"oaf-activate-iid=",
"oaf-ior-fd=",
"oaf-activate-iid=",
"oaf-ior-fd=",
"oaf-private",
"open=",
"create=",
"options=",
"screen=",
"show",
"sm-client-id=",
"sm-config-prefix=",
"show",
"sm-client-id=",
"sm-config-prefix=",
"sm-disable",
"sync",
"usage",
"usage",
"version",
"qml",
"yes",

View File

@ -10,7 +10,7 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# 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 General Public License for more details.
@ -43,7 +43,7 @@ LOG = logging.getLogger(".gen.utils.file")
#
#-------------------------------------------------------------------------
from ..constfunc import win, mac, conv_to_unicode, get_env_var
from ..const import TEMP_DIR, USER_HOME, GRAMPS_LOCALE as glocale
from ..const import TEMP_DIR, USER_HOME, ENV, GRAMPS_LOCALE as glocale
#-------------------------------------------------------------------------
#
@ -91,7 +91,7 @@ def get_empty_tempdir(dirname):
""" Return path to TEMP_DIR/dirname, a guaranteed empty directory
makes intervening directories if required
fails if _file_ by that name already exists,
fails if _file_ by that name already exists,
or for inadequate permissions to delete dir/files or create dir(s)
"""
@ -121,10 +121,10 @@ def relative_path(original, base):
return original
original = os.path.normpath(original)
base = os.path.normpath(base)
# If the db_dir and obj_dir are on different drives (win only)
# then there cannot be a relative path. Return original obj_path
(base_drive, base) = os.path.splitdrive(base)
(base_drive, base) = os.path.splitdrive(base)
(orig_drive, orig_name) = os.path.splitdrive(original)
if base_drive.upper() != orig_drive.upper():
return original
@ -133,7 +133,7 @@ def relative_path(original, base):
# shared by base and target.
base_list = (base).split(os.sep)
target_list = (orig_name).split(os.sep)
# make sure '/home/person' and 'c:/home/person' both give
# make sure '/home/person' and 'c:/home/person' both give
# list ['home', 'person']
base_list = [_f for _f in base_list if _f]
target_list = [_f for _f in target_list if _f]
@ -146,14 +146,51 @@ def relative_path(original, base):
rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:]
return os.path.join(*rel_list)
def expand_path(path, normalize = True):
"""
Expand environment variables in a path
Uses both the environment variables and the GRAMPS environment
The expansion uses the str.format, e.g. "~/{GRAMPSHOME}/{VERSION}/filename.txt"
We make the assumption that the user will not use a path that contain variable names
(it is technically possible to use characters "{", "}" in paths)
"""
environment = dict(os.environ)
environment.update(ENV)
if not 'GRAMPSHOME' in environment:
environment['GRAMPSHOME'] = USER_HOME
path = path.format(**environment)
if normalize:
path = os.path.normcase(os.path.normpath(os.path.abspath(path)))
return path
def media_path(db):
"""
Given a database, return the mediapath to use as basedir for media
"""
mpath = db.get_mediapath()
return expand_media_path(mpath, db)
def expand_media_path(mpath, db):
"""
Normalize a mediapath:
- Relative mediapath are considered as relative to the database
- Expand variables, see expand_path
- Convert to absolute path
- Convert slashes and case (on Windows)
"""
# Use home dir if no media_path specified
if mpath is None:
#use home dir
mpath = USER_HOME
mpath = os.path.abspath(USER_HOME)
# Expand environment variables
mpath = expand_path(mpath, False)
# Relative mediapath are considered as relative to the database
if not os.path.isabs(mpath):
basepath = db.get_save_path()
if not basepath:
basepath = USER_HOME
mpath = os.path.join(os.path.abspath(basepath), mpath)
# Normalize path
mpath = os.path.normcase(os.path.normpath(os.path.abspath(mpath)))
return mpath
def media_path_full(db, filename):
@ -178,7 +215,7 @@ def search_for(name):
return 1
if os.access(name, os.X_OK) and not os.path.isdir(name):
return 1
else:
else:
for i in os.environ['PATH'].split(':'): #not win()
fname = os.path.join(i, name)
if os.access(fname, os.X_OK) and not os.path.isdir(fname):

View File

@ -0,0 +1,103 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007-2009 B. Malengier
# Copyright (C) 2009 Swoon on bug tracker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import os
import shutil
import unittest
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from gramps.gen.const import TEMP_DIR, USER_HOME, USER_PLUGINS, VERSION
from gramps.gen.constfunc import get_env_var
from gramps.gen.utils.file import media_path, get_empty_tempdir
from gramps.gen.dbstate import DbState
#-------------------------------------------------------------------------
#
# FileTest class
#
#-------------------------------------------------------------------------
class FileTest(unittest.TestCase):
def test_mediapath(self):
# Create database
dbstate = DbState()
db = dbstate.make_database("bsddb")
path = get_empty_tempdir("utils_file_test")
db.write_version(path)
db.load(path)
dbstate.change_database(db)
# Test without db.mediapath set
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(USER_HOME))))
self.assertTrue(os.path.exists(media_path(db)))
# Test with absolute db.mediapath
db.set_mediapath(os.path.abspath(USER_HOME) + "/test_abs")
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(USER_HOME + "/test_abs"))))
# Test with relative db.mediapath
db.set_mediapath("test_rel")
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(TEMP_DIR + "/utils_file_test/test_rel"))))
# Test with environment variable
db.set_mediapath("/test/{VERSION}/test_var")
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath("/test/" + VERSION + "/test_var"))))
db.set_mediapath("{USER_PLUGINS}/test_var")
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(USER_PLUGINS + "/test_var"))))
db.set_mediapath("{VERSION}/test_var")
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(TEMP_DIR + "/utils_file_test/" + VERSION + "/test_var"))))
# Test with $GRAMPSHOME environment variable not set
old_env = os.environ.copy()
if 'GRAMPSHOME' in os.environ:
del os.environ['GRAMPSHOME']
db.set_mediapath("{GRAMPSHOME}/test_var")
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(USER_HOME + "/test_var"))))
# Test with $GRAMPSHOME environment variable set
os.environ['GRAMPSHOME'] = "/this/is/a/test"
db.set_mediapath("{GRAMPSHOME}/test_var")
self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath("/this/is/a/test/test_var"))))
# Restore environment
os.environ = old_env
#-------------------------------------------------------------------------
#
# main
#
#-------------------------------------------------------------------------
if __name__ == "__main__":
unittest.main()

View File

@ -53,6 +53,7 @@ from gramps.gen.datehandler import get_date_formats
from gramps.gen.display.name import displayer as _nd
from gramps.gen.display.name import NameDisplayError
from gramps.gen.utils.alive import update_constants
from gramps.gen.utils.file import media_path
from gramps.gen.utils.keyword import (get_keywords, get_translation_from_keyword,
get_translations, get_keyword_from_translation)
from gramps.gen.lib import Date, FamilyRelType
@ -1460,9 +1461,7 @@ class GrampsPreferences(ConfigureDialog):
_('_Apply'),
Gtk.ResponseType.OK)
)
mpath = self.dbstate.db.get_mediapath()
if not mpath:
mpath = HOME_DIR
mpath = media_path(self.dbstate.db)
f.set_current_folder(os.path.dirname(mpath))
status = f.run()

View File

@ -62,7 +62,7 @@ from gramps.gen.errors import GrampsImportError
from gramps.gen.utils.id import create_id
from gramps.gen.utils.db import family_name
from gramps.gen.utils.unknown import make_unknown, create_explanation_note
from gramps.gen.utils.file import create_checksum
from gramps.gen.utils.file import create_checksum, media_path, expand_media_path
from gramps.gen.datehandler import parser, set_date
from gramps.gen.display.name import displayer as name_displayer
from gramps.gen.db.dbconst import (PERSON_KEY, FAMILY_KEY, SOURCE_KEY,
@ -165,35 +165,6 @@ def importData(database, filename, user):
database.readonly = read_only
return info
## TODO - WITH MEDIA PATH, IS THIS STILL NEEDED?
## BETTER LEAVE ALL RELATIVE TO NEW RELATIVE PATH
## save_path is in .gramps/dbbase, no good place !
## # copy all local images into <database>.images directory
## db_dir = os.path.abspath(os.path.dirname(database.get_save_path()))
## db_base = os.path.basename(database.get_save_path())
## img_dir = os.path.join(db_dir, db_base)
## first = not os.path.exists(img_dir)
##
## for m_id in database.get_media_object_handles():
## mobject = database.get_object_from_handle(m_id)
## oldfile = mobject.get_path()
## if oldfile and not os.path.isabs(oldfile):
## if first:
## os.mkdir(img_dir)
## first = 0
## newfile = os.path.join(img_dir, oldfile)
##
## try:
## oldfilename = os.path.join(basefile, oldfile)
## shutil.copyfile(oldfilename, newfile)
## try:
## shutil.copystat(oldfilename, newfile)
## except:
## pass
## mobject.set_path(newfile)
## database.commit_media_object(mobject, None, change)
## except (IOError, OSError), msg:
## ErrorDialog(_('Could not copy file'), str(msg))
#-------------------------------------------------------------------------
#
@ -965,14 +936,13 @@ class GrampsParser(UpdateCallback):
person = self.db.get_person_from_handle(self.home)
self.db.set_default_person_handle(person.handle)
#set media path, this should really do some parsing to convert eg
# windows path to unix ?
# Set media path
# The paths are normalized before being compared.
if self.mediapath:
oldpath = self.db.get_mediapath()
if not oldpath:
if not self.db.get_mediapath():
self.db.set_mediapath(self.mediapath)
elif not oldpath == self.mediapath:
self.user.notify_error(_("Could not change media path"),
elif not media_path(self.db) == expand_media_path(self.mediapath, self.db):
self.user.notify_error(_("Could not change media path"),
_("The opened file has media path %s, which conflicts with"
" the media path of the Family Tree you import into. "
"The original media path has been retained. Copy the "