bugfix [#24087] Blender can not install add-ons unless running with root priviledges
authorCampbell Barton <ideasman42@gmail.com>
Sun, 3 Oct 2010 20:00:22 +0000 (20:00 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 3 Oct 2010 20:00:22 +0000 (20:00 +0000)
now addon path is created using the same path functions and selecting where to save the startup.blend

also made some minor changes to path handling funcs.

release/scripts/modules/bpy/utils.py
release/scripts/ui/space_userpref.py
source/blender/blenlib/BLI_path_util.h
source/blender/blenlib/intern/path_util.c
source/blender/python/generic/bpy_internal_import.c
source/blender/python/generic/bpy_internal_import.h
source/blender/python/intern/bpy.c
source/blender/python/intern/bpy_interface.c
source/blender/windowmanager/intern/wm_files.c
source/gameengine/Ketsji/KX_PythonInit.cpp

index 0d9a780..d9229c2 100644 (file)
@@ -27,7 +27,7 @@ import bpy as _bpy
 import os as _os
 import sys as _sys
 
-from _bpy import blend_paths
+from _bpy import blend_paths, user_resource
 from _bpy import script_paths as _bpy_script_paths
 
 
index d15dc89..f601b25 100644 (file)
@@ -1096,7 +1096,24 @@ class WM_OT_addon_install(bpy.types.Operator):
         import zipfile
         pyfile = self.filepath
 
-        path_addons = bpy.utils.script_paths("addons")[-1]
+        # dont use bpy.utils.script_paths("addons") because we may not be able to write to it.
+        path_addons = bpy.utils.user_resource('SCRIPTS', 'addons')
+
+        # should never happen.
+        if not path_addons:
+            self.report({'WARNING'}, "Failed to get addons path\n")
+            return {'CANCELLED'}
+
+        # create path if not existing.
+        if not os.path.exists(path_addons):
+            try:
+                os.makedirs(path_addons)
+            except:
+                self.report({'WARNING'}, "Failed to create %r\n" % path_addons)
+
+                traceback.print_exc()
+                return {'CANCELLED'}
+
         contents = set(os.listdir(path_addons))
 
         #check to see if the file is in compressed format (.zip)
@@ -1115,7 +1132,7 @@ class WM_OT_addon_install(bpy.types.Operator):
             path_dest = os.path.join(path_addons, os.path.basename(pyfile))
 
             if os.path.exists(path_dest):
-                self.report({'WARNING'}, "File already installed to '%s'\n" % path_dest)
+                self.report({'WARNING'}, "File already installed to %r\n" % path_dest)
                 return {'CANCELLED'}
 
             #if not compressed file just copy into the addon path
@@ -1148,11 +1165,6 @@ class WM_OT_addon_install(bpy.types.Operator):
         return {'FINISHED'}
 
     def invoke(self, context, event):
-        paths = bpy.utils.script_paths("addons")
-        if not paths:
-            self.report({'ERROR'}, "No 'addons' path could be found in " + str(bpy.utils.script_paths()))
-            return {'CANCELLED'}
-
         wm = context.window_manager
         wm.add_fileselect(self)
         return {'RUNNING_MODAL'}
index f01e1a2..b9a4468 100644 (file)
@@ -44,6 +44,7 @@ char *BLI_getDefaultDocumentFolder(void);
 
 char *BLI_get_folder(int folder_id, char *subfolder);
 char *BLI_get_folder_create(int folder_id, char *subfolder);
+char *BLI_get_user_folder_notest(int folder_id, char *subfolder);
 
 /* folder_id */
 
index d388586..fd69b72 100644 (file)
@@ -477,7 +477,7 @@ int BLI_parent_dir(char *path)
        static char *parent_dir="../";
 #endif
        char tmp[FILE_MAXDIR+FILE_MAXFILE+4];
-       BLI_strncpy(tmp, path, sizeof(tmp));
+       BLI_strncpy(tmp, path, sizeof(tmp)-4);
        BLI_add_slash(tmp);
        strcat(tmp, parent_dir);
        BLI_cleanup_dir(NULL, tmp);
@@ -839,8 +839,6 @@ static int get_path_local(char *targetpath, char *folder_name, char *subfolder_n
        char bprogdir[FILE_MAX];
        char relfolder[FILE_MAX];
        char cwd[FILE_MAX];
-       char *s;
-       int i;
        
 #ifdef PATH_DEBUG2
        printf("get_path_local...\n");
@@ -853,9 +851,7 @@ static int get_path_local(char *targetpath, char *folder_name, char *subfolder_n
        }
        
        /* use argv[0] (bprogname) to get the path to the executable */
-       s = BLI_last_slash(bprogname);
-       i = s - bprogname + 1;
-       BLI_strncpy(bprogdir, bprogname, i);
+       BLI_split_dirfile(bprogname, bprogdir, NULL);
        
        /* try EXECUTABLE_DIR/folder_name */
        if(test_path(targetpath, bprogdir, "", relfolder))
@@ -1024,7 +1020,7 @@ char *BLI_get_folder(int folder_id, char *subfolder)
        return path;
 }
 
-static char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
+char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
 {
        static char path[FILE_MAX] = "";
 
@@ -1038,6 +1034,9 @@ static char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
                case BLENDER_USER_AUTOSAVE:
                        get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE");
                        break;
+               case BLENDER_USER_SCRIPTS:
+                       get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS");
+                       break;
        }
        if ('\0' == path[0]) {
                return NULL;
@@ -1050,7 +1049,7 @@ char *BLI_get_folder_create(int folder_id, char *subfolder)
        char *path;
 
        /* only for user folders */
-       if (!ELEM3(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_AUTOSAVE))
+       if (!ELEM4(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE))
                return NULL;
        
        path = BLI_get_folder(folder_id, subfolder);
@@ -1205,8 +1204,7 @@ void BLI_make_file_string(const char *relabase, char *string,  const char *dir,
                /* Get the file name, chop everything past the last slash (ie. the filename) */
                strcpy(string, relabase);
                
-               lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
-               
+               lslash= BLI_last_slash(string);
                if(lslash) *(lslash+1)= 0;
 
                dir+=2; /* Skip over the relative reference */
index 11f8ff4..394c388 100644 (file)
@@ -281,8 +281,8 @@ static PyObject *blender_reload( PyObject * self, PyObject * module )
        return newmodule;
 }
 
-PyMethodDef bpy_import_meth[] = { {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"} };
-PyMethodDef bpy_reload_meth[] = { {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"} };
+PyMethodDef bpy_import_meth = {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"};
+PyMethodDef bpy_reload_meth = {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"};
 
 
 /* Clear user modules.
index 09e1fa6..f191ab2 100644 (file)
@@ -53,8 +53,8 @@ PyObject*     bpy_text_reimport( PyObject *module, int *found );
 
 void bpy_text_filename_get(char *fn, struct Text *text);
 
-extern PyMethodDef bpy_import_meth[];
-extern PyMethodDef bpy_reload_meth[];
+extern PyMethodDef bpy_import_meth;
+extern PyMethodDef bpy_reload_meth;
 
 /* The game engine has its own Main struct, if this is set search this rather then G.main */
 struct Main *bpy_import_main_get(void);
index 12a5221..69b5fac 100644 (file)
@@ -112,8 +112,52 @@ static PyObject *bpy_blend_paths(PyObject * self, PyObject *args, PyObject *kw)
        return list;
 }
 
-static PyMethodDef meth_bpy_script_paths[] = {{ "script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc}};
-static PyMethodDef meth_bpy_blend_paths[] = {{ "blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc}};
+
+static char bpy_user_resource_doc[] =
+".. function:: user_resource(type, subdir)\n"
+"\n"
+"   Returns a list of paths to external files referenced by the loaded .blend file.\n"
+"\n"
+"   :arg type: Resource type in ['DATAFILES', 'CONFIG', 'SCRIPTS', 'AUTOSAVE'].\n"
+"   :type type: string\n"
+"   :arg subdir: Optional subdirectory.\n"
+"   :type subdir: string\n"
+"   :return: a path.\n"
+"   :rtype: string\n";
+static PyObject *bpy_user_resource(PyObject * self, PyObject *args, PyObject *kw)
+{
+       char *type;
+       char *subdir= NULL;
+       int folder_id;
+       static char *kwlist[] = {"type", "subdir", NULL};
+
+       char *path;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s:user_resource", kwlist, &type, &subdir))
+               return NULL;
+       
+       /* stupid string compare */
+       if     (!strcmp(type, "DATAFILES"))     folder_id= BLENDER_USER_DATAFILES;
+       else if(!strcmp(type, "CONFIG"))        folder_id= BLENDER_USER_CONFIG;
+       else if(!strcmp(type, "SCRIPTS"))       folder_id= BLENDER_USER_SCRIPTS;
+       else if(!strcmp(type, "AUTOSAVE"))      folder_id= BLENDER_USER_AUTOSAVE;
+       else {
+               PyErr_SetString(PyExc_ValueError, "invalid resource argument");
+               return NULL;
+       }
+       
+       /* same logic as BLI_get_folder_create(), but best leave it up to the script author to create */
+       path= BLI_get_folder(folder_id, subdir);
+
+       if (!path)
+               path = BLI_get_user_folder_notest(folder_id, subdir);
+
+       return PyUnicode_FromString(path ? path : "");
+}
+
+static PyMethodDef meth_bpy_script_paths = {"script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc};
+static PyMethodDef meth_bpy_blend_paths = {"blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc};
+static PyMethodDef meth_bpy_user_resource = {"user_resource", (PyCFunction)bpy_user_resource, METH_VARARGS|METH_KEYWORDS, bpy_user_resource_doc};
 
 static void bpy_import_test(char *modname)
 {
@@ -186,8 +230,9 @@ void BPy_init_modules( void )
        PyModule_AddObject(mod, "context", (PyObject *)bpy_context_module);
 
        /* utility func's that have nowhere else to go */
-       PyModule_AddObject(mod, meth_bpy_script_paths->ml_name, (PyObject *)PyCFunction_New(meth_bpy_script_paths, NULL));
-       PyModule_AddObject(mod, meth_bpy_blend_paths->ml_name, (PyObject *)PyCFunction_New(meth_bpy_blend_paths, NULL));
+       PyModule_AddObject(mod, meth_bpy_script_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_script_paths, NULL));
+       PyModule_AddObject(mod, meth_bpy_blend_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_blend_paths, NULL));
+       PyModule_AddObject(mod, meth_bpy_user_resource.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_user_resource, NULL));
 
        /* add our own modules dir, this is a python package */
        bpy_import_test("bpy");
index 6aaac3c..b905fb3 100644 (file)
@@ -248,8 +248,8 @@ void BPY_start_python( int argc, char **argv )
                //PyObject *m = PyImport_AddModule("__builtin__");
                //PyObject *d = PyModule_GetDict(m);
                PyObject *d = PyEval_GetBuiltins(  );
-               PyDict_SetItemString(d, "reload",               item=PyCFunction_New(bpy_reload_meth, NULL));   Py_DECREF(item);
-               PyDict_SetItemString(d, "__import__",   item=PyCFunction_New(bpy_import_meth, NULL));   Py_DECREF(item);
+               PyDict_SetItemString(d, "reload",               item=PyCFunction_New(&bpy_reload_meth, NULL));  Py_DECREF(item);
+               PyDict_SetItemString(d, "__import__",   item=PyCFunction_New(&bpy_import_meth, NULL));  Py_DECREF(item);
        }
        
        pyrna_alloc_types();
index 3356483..67decd6 100644 (file)
@@ -681,15 +681,20 @@ int WM_write_homefile(bContext *C, wmOperator *op)
                wm_window_close(C, wm, win);
        
        BLI_make_file_string("/", tstr, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
-       printf("trying to save homefile at %s \n", tstr);
+       printf("trying to save homefile at %s ", tstr);
        
        /*  force save as regular blend file */
        fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN);
 
-       BLO_write_file(CTX_data_main(C), tstr, fileflags, op->reports, NULL);
+       if(BLO_write_file(CTX_data_main(C), tstr, fileflags, op->reports, NULL) == 0) {
+               printf("fail\n");
+               return OPERATOR_CANCELLED;
+       }
        
+       printf("ok\n");
+
        G.save_over= 0;
-       
+
        return OPERATOR_FINISHED;
 }
 
index 3a754f1..a6b2453 100644 (file)
@@ -1760,8 +1760,8 @@ static void setSandbox(TPythonSecurityLevel level)
        */
        default:
                        /* Allow importing internal text, from bpy_internal_import.py */
-                       PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL));         Py_DECREF(item);
-                       PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL));     Py_DECREF(item);
+                       PyDict_SetItemString(d, "reload", item=PyCFunction_New(&bpy_reload_meth, NULL));                Py_DECREF(item);
+                       PyDict_SetItemString(d, "__import__", item=PyCFunction_New(&bpy_import_meth, NULL));    Py_DECREF(item);
                break;
        }
 }