diff --git a/example/gramps/example.gramps b/example/gramps/example.gramps
index b2433a548..23fcd15e9 100644
--- a/example/gramps/example.gramps
+++ b/example/gramps/example.gramps
@@ -7,7 +7,7 @@
Alex Roitman,,,
- /home/pierre/Gramps/master/example/gramps
+ $GRAMPS_RESOURCES/example/gramps
diff --git a/gramps/gen/const.py b/gramps/gen/const.py
index 66e954a4a..fcb8d3bc1 100644
--- a/gramps/gen/const.py
+++ b/gramps/gen/const.py
@@ -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,26 @@ 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)
+
+# Update environment
+# This could be of general use, for example when using os.path.expandvars
+os.environ['GRAMPS_VERSION'] = VERSION
+os.environ['GRAMPS_VERSION_MAJOR'] = major_version
+os.environ['GRAMPS_VERSION_DIR'] = VERSION_DIR
+os.environ['GRAMPS_ENV_DIR'] = ENV_DIR
+os.environ['GRAMPS_TEMP_DIR'] = TEMP_DIR
+os.environ['GRAMPS_THUMB_DIR'] = THUMB_DIR
+os.environ['GRAMPS_THUMB_NORMAL'] = THUMB_NORMAL
+os.environ['GRAMPS_THUMB_LARGE'] = THUMB_LARGE
+os.environ['GRAMPS_USER_PLUGINS'] = USER_PLUGINS
+# Attention: $GRAMPSHOME should NOT be set, because it redefines the HOME_DIR behavior
+# This leads to bugs, especially when a test calls GRAMPS again:
+# the HOME_DIR is then re-computed with a wrong $GRAMPSHOME
+
+
#-------------------------------------------------------------------------
#
-# 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.
#
#-------------------------------------------------------------------------
@@ -192,21 +209,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 +249,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 +265,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",
diff --git a/gramps/gen/utils/file.py b/gramps/gen/utils/file.py
index 6d36d466d..f2ecb64ac 100644
--- a/gramps/gen/utils/file.py
+++ b/gramps/gen/utils/file.py
@@ -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.
@@ -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,48 @@ def relative_path(original, base):
rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:]
return os.path.join(*rel_list)
+def expanded_vars_path(path):
+ """
+ Expand environment variables in a path
+ $GRAMPSHOME is set and restored afterwards,
+ because undefined $GRAMPSHOME has a special meaning (see const.py).
+ """
+ if not 'GRAMPSHOME' in os.environ:
+ os.environ['GRAMPSHOME'] = USER_HOME
+ grampshome_added = True
+ path = os.path.expandvars(path)
+ if (grampshome_added):
+ del os.environ['GRAMPSHOME']
+ return path
+
def media_path(db):
"""
Given a database, return the mediapath to use as basedir for media
"""
mpath = db.get_mediapath()
+ return norm_media_path(mpath, db)
+
+def norm_media_path(mpath, db):
+ """
+ Normalize a mediapath:
+ - Relative mediapath are considered as relative to the database
+ - Expand variables ($GRAMPSHOME, $GRAMPS_RESOURCES, etc.)
+ - 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 = expanded_vars_path(mpath)
+ # 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 +212,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):
diff --git a/gramps/gen/utils/test/file_test.py b/gramps/gen/utils/test/file_test.py
new file mode 100644
index 000000000..d6812b675
--- /dev/null
+++ b/gramps/gen/utils/test/file_test.py
@@ -0,0 +1,84 @@
+#!/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
+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
+from gramps.version import VERSION
+
+#-------------------------------------------------------------------------
+#
+# 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("$GRAMPSHOME/test_var")
+ self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(USER_HOME + "/test_var"))))
+ db.set_mediapath("/test/$GRAMPS_VERSION/test_var")
+ self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath("/test/" + VERSION + "/test_var"))))
+ db.set_mediapath("${GRAMPS_USER_PLUGINS}/test_var")
+ self.assertEqual(media_path(db), os.path.normcase(os.path.normpath(os.path.abspath(USER_PLUGINS + "/test_var"))))
+
+
+#-------------------------------------------------------------------------
+#
+# main
+#
+#-------------------------------------------------------------------------
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gramps/gui/configure.py b/gramps/gui/configure.py
index 0a71b6ffe..e56d02f8f 100644
--- a/gramps/gui/configure.py
+++ b/gramps/gui/configure.py
@@ -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()
diff --git a/gramps/plugins/importer/importxml.py b/gramps/plugins/importer/importxml.py
index f76a37246..3802f0100 100644
--- a/gramps/plugins/importer/importxml.py
+++ b/gramps/plugins/importer/importxml.py
@@ -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, norm_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 .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) == norm_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 "