[27525] trunk/base/src

source_changes at macosforge.org source_changes at macosforge.org
Mon Aug 6 13:13:01 PDT 2007


Revision: 27525
          http://trac.macosforge.org/projects/macports/changeset/27525
Author:   sfiera at macports.org
Date:     2007-08-06 13:13:00 -0700 (Mon, 06 Aug 2007)

Log Message:
-----------
Further fix mapping; refactor installed/active into imaged/installed

Modified Paths:
--------------
    trunk/base/src/cregistry/entry.c
    trunk/base/src/cregistry/entry.h
    trunk/base/src/cregistry/registry.c
    trunk/base/src/registry2.0/entry.c
    trunk/base/src/registry2.0/registry.c
    trunk/base/src/registry2.0/tests/entry.tcl

Modified: trunk/base/src/cregistry/entry.c
===================================================================
--- trunk/base/src/cregistry/entry.c	2007-08-06 20:12:54 UTC (rev 27524)
+++ trunk/base/src/cregistry/entry.c	2007-08-06 20:13:00 UTC (rev 27525)
@@ -44,22 +44,23 @@
  * Simple concatenation. Only guaranteed to work with strings that have been
  * allocated with `malloc`. Amortizes cost of expanding string buffer for O(N)
  * concatenation and such. Uses `memcpy` in favor of `strcpy` in hopes it will
- * perform a bit better. If passing in a static string to dst, make sure
- * dst_space starts at dst_len. Also make sure dst_space is never 0 (so don't
- * use "" as the starter string, allocate some space);
+ * perform a bit better.
  */
 void reg_strcat(char** dst, int* dst_len, int* dst_space, char* src) {
     int src_len = strlen(src);
-    if (*dst_len + src_len >= *dst_space) {
+    int result_len = *dst_len + src_len;
+    if (result_len >= *dst_space) {
         char* old_dst = *dst;
-        char* new_dst = malloc(*dst_space * 2 * sizeof(char));
         *dst_space *= 2;
-        memcpy(new_dst, old_dst, *dst_len);
-        *dst = new_dst;
+        if (*dst_space < result_len) {
+            *dst_space = result_len;
+        }
+        *dst = malloc(*dst_space * sizeof(char) + 1);
+        memcpy(*dst, old_dst, *dst_len);
         free(old_dst);
     }
-    memcpy(&((*dst)[*dst_len]), src, src_len+1);
-    *dst_len += src_len;
+    memcpy(*dst + *dst_len, src, src_len+1);
+    *dst_len = result_len;
 }
 
 /**
@@ -84,13 +85,13 @@
 /**
  * Returns the operator to use for the given strategy.
  */
-static char* reg_strategy_op(int strategy, reg_error* errPtr) {
+static char* reg_strategy_op(reg_strategy strategy, reg_error* errPtr) {
     switch (strategy) {
-        case 0:
+        case reg_strategy_equal:
             return "=";
-        case 1:
+        case reg_strategy_glob:
             return " GLOB ";
-        case 2:
+        case reg_strategy_regexp:
             return " REGEXP ";
         default:
             errPtr->code = "registry::invalid-strategy";
@@ -100,6 +101,11 @@
     }
 }
 
+/**
+ * Converts a `sqlite3_stmt` into a `reg_entry`. The first column of the stmt's
+ * row must be the id of an entry; the second either `SQLITE_NUL`L or the
+ * address of the entry in memory.
+ */
 static int reg_stmt_to_entry(void* userdata, void** entry, void* stmt,
         reg_error* errPtr UNUSED) {
     if (sqlite3_column_type(stmt, 1) == SQLITE_NULL) {
@@ -115,12 +121,18 @@
     return 1;
 }
 
+/**
+ * Saves the addresses of existing `reg_entry` items into the temporary sqlite3
+ * table `entries`. These addresses will be retrieved by anything else that
+ * needs to get entries, so only one `reg_entry` will exist in memory for any
+ * given id. They will be freed when the registry is closed.
+ */
 static int reg_save_addresses(sqlite3* db, reg_entry** entries,
         int entry_count, reg_error* errPtr) {
     sqlite3_stmt* stmt;
     int i;
     char* query = "INSERT INTO entries (id, address) VALUES (?, ?)";
-    /* avoid unnecessarily making queries */
+    /* avoid preparing the statement if unnecessary */
     for (i=0; i<entry_count; i++) {
         if (!entries[i]->saved) {
             break;
@@ -129,7 +141,7 @@
     if (i == entry_count) {
         return 1;
     }
-    /* BEGIN */
+    begin_exclusive(db);
     if (sqlite3_prepare(db, query, -1, &stmt, NULL)
                 == SQLITE_OK) {
         for (i=0; i<entry_count; i++) {
@@ -144,13 +156,17 @@
             } else {
                 sqlite3_finalize(stmt);
                 reg_sqlite_error(db, errPtr, query);
+                commit_transaction(db);
+                return 0;
             }
         }
         sqlite3_finalize(stmt);
+        commit_transaction(db);
         return 1;
     } else {
         sqlite3_finalize(stmt);
         reg_sqlite_error(db, errPtr, query);
+        commit_transaction(db);
     }
     return 0;
 }
@@ -280,9 +296,9 @@
 }
 
 /*
- * Frees the given entry
+ * Frees the given entry - not good to expose?
  */
-void reg_entry_free(sqlite3* db UNUSED, reg_entry* entry) {
+static void reg_entry_free(sqlite3* db UNUSED, reg_entry* entry) {
     sqlite3_stmt* stmt;
     if (entry->proc != NULL) {
         free(entry->proc);
@@ -355,8 +371,8 @@
     int i;
     char* kwd = " WHERE ";
     char* query;
-    int query_len = 32;
-    int query_space = 32;
+    int query_len = 96;
+    int query_space = 96;
     int result;
     /* get the strategy */
     char* op = reg_strategy_op(strategy, errPtr);
@@ -386,10 +402,19 @@
 }
 
 /**
- * TODO: fix this to return ports where state=active too
- * TODO: add more arguments (epoch, revision, variants), maybe
+ * Finds ports which are installed as an image, and/or those which are active
+ * in the filesystem. When the install mode is 'direct', this will be equivalent
+ * to `reg_entry_installed`.
+ * @todo add more arguments (epoch, revision, variants), maybe
+ *
+ * @param [in] db       registry database as created by `registry_open`
+ * @param [in] name     specific port to find (NULL for any)
+ * @param [in] version  specific version to find (NULL for any)
+ * @param [out] entries list of ports meeting the criteria
+ * @param [out] errPtr  description of error encountered, if any
+ * @return              the number of such ports found
  */
-int reg_entry_installed(sqlite3* db, char* name, char* version, 
+int reg_entry_imaged(sqlite3* db, char* name, char* version, 
         reg_entry*** entries, reg_error* errPtr) {
     char* format;
     char* query;
@@ -397,11 +422,11 @@
     char* select = "SELECT registry.ports.id, entries.address FROM "
         "registry.ports LEFT OUTER JOIN entries USING (id)";
     if (name == NULL) {
-        format = "%s WHERE (state='installed' OR state='active')";
+        format = "%s WHERE (state='imaged' OR state='installed')";
     } else if (version == NULL) {
-        format = "%s WHERE (state='installed' OR state='active') AND name='%q'";
+        format = "%s WHERE (state='imaged' OR state='installed') AND name='%q'";
     } else {
-        format = "%s WHERE (state='installed' OR state='active') AND name='%q' "
+        format = "%s WHERE (state='imaged' OR state='installed') AND name='%q' "
             "AND version='%q'";
     }
     query = sqlite3_mprintf(format, select, name, version);
@@ -418,8 +443,17 @@
 }
 
 /**
+ * Finds ports which are active in the filesystem. These ports are able to fill
+ * dependencies, and properly own the files they map.
+ * @todo add more arguments (epoch, revision, variants), maybe
+ *
+ * @param [in] db       registry database as created by `registry_open`
+ * @param [in] name     specific port to find (NULL for any)
+ * @param [out] entries list of ports meeting the criteria
+ * @param [out] errPtr  description of error encountered, if any
+ * @return              the number of such ports found
  */
-int reg_entry_active(sqlite3* db, char* name, reg_entry*** entries,
+int reg_entry_installed(sqlite3* db, char* name, reg_entry*** entries,
         reg_error* errPtr) {
     char* format;
     char* query;
@@ -427,9 +461,9 @@
     char* select = "SELECT registry.ports.id, entries.address FROM "
         "registry.ports LEFT OUTER JOIN entries USING (id)";
     if (name == NULL) {
-        format = "%s WHERE state='active'";
+        format = "%s WHERE state='installed'";
     } else {
-        format = "%s WHERE state='active' AND name='%q'";
+        format = "%s WHERE state='installed' AND name='%q'";
     }
     query = sqlite3_mprintf(format, select, name);
     result = reg_all_objects(db, query, -1, (void***)entries,
@@ -449,8 +483,9 @@
     sqlite3_stmt* stmt;
     reg_entry* result;
     char* query = "SELECT registry.files.id, entries.address "
-        "FROM registry.files LEFT OUTER JOIN entries USING (id) "
-        "WHERE path=?";
+        "FROM registry.files INNER JOIN registry.ports USING(id)"
+        " LEFT OUTER JOIN entries USING(id) "
+        "WHERE path=? AND registry.ports.state = 'installed'";
     if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
             && (sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC)
                 == SQLITE_OK)) {
@@ -546,7 +581,8 @@
     sqlite3_stmt* stmt2 = NULL;
     char* insert = "INSERT INTO registry.files (id, path) VALUES (?, ?)";
     char* select = "SELECT registry.ports.name FROM registry.files "
-        "INNER JOIN registry.ports USING(id) WHERE registry.files.path=?";
+        "INNER JOIN registry.ports USING(id) WHERE registry.files.path=? AND "
+        "registry.ports.state = 'installed'";
     begin_exclusive(db);
     if ((sqlite3_prepare(db, insert, -1, &stmt, NULL) == SQLITE_OK)
             && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
@@ -556,11 +592,11 @@
             if ((sqlite3_bind_text(stmt2, 1, files[i], -1, SQLITE_STATIC)
                     == SQLITE_OK)
                     && (sqlite3_step(stmt2) == SQLITE_ROW)) {
-                char* port = sqlite3_column_text(stmt2, 0);
+                const char* port = sqlite3_column_text(stmt2, 0);
                 errPtr->code = "registry::already-owned";
                 errPtr->description = sqlite3_mprintf("file at path \"%s\" is "
                         "already owned by port %s", files[i], port);
-                errPtr->free = sqlite3_free;
+                errPtr->free = (reg_error_destructor*)sqlite3_free;
                 sqlite3_finalize(stmt);
                 sqlite3_finalize(stmt2);
                 rollback_transaction(db);

Modified: trunk/base/src/cregistry/entry.h
===================================================================
--- trunk/base/src/cregistry/entry.h	2007-08-06 20:12:54 UTC (rev 27524)
+++ trunk/base/src/cregistry/entry.h	2007-08-06 20:13:00 UTC (rev 27525)
@@ -35,6 +35,12 @@
 #include <sqlite3.h>
 #include <cregistry/registry.h>
 
+typedef enum {
+    reg_strategy_equal = 1,
+    reg_strategy_glob = 2,
+    reg_strategy_regexp = 3
+} reg_strategy;
+
 typedef struct {
     sqlite_int64 id; /* rowid in database */
     sqlite3* db; /* database */
@@ -50,15 +56,12 @@
 
 int reg_entry_delete(sqlite3* db, reg_entry* entry, reg_error* errPtr);
 
-void reg_entry_free(sqlite3* db, reg_entry* entry);
-
 int reg_entry_search(sqlite3* db, char** keys, char** vals, int key_count,
         int strategy, reg_entry*** entries, reg_error* errPtr);
 
-int reg_entry_installed(sqlite3* db, char* name, char* version, 
+int reg_entry_imaged(sqlite3* db, char* name, char* version, 
         reg_entry*** entries, reg_error* errPtr);
-
-int reg_entry_active(sqlite3* db, char* name, reg_entry*** entries,
+int reg_entry_installed(sqlite3* db, char* name, reg_entry*** entries,
         reg_error* errPtr);
 
 int reg_entry_owner(sqlite3* db, char* path, reg_entry** entry,

Modified: trunk/base/src/cregistry/registry.c
===================================================================
--- trunk/base/src/cregistry/registry.c	2007-08-06 20:12:54 UTC (rev 27524)
+++ trunk/base/src/cregistry/registry.c	2007-08-06 20:13:00 UTC (rev 27525)
@@ -32,6 +32,7 @@
 
 #include <stdio.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <sqlite3.h>
 #include <sys/stat.h>
 #include <errno.h>
@@ -135,7 +136,11 @@
                 switch (r) {
                     case SQLITE_ROW:
                         entry = *(reg_entry**)sqlite3_column_blob(stmt, 0);
-                        reg_entry_free(db, entry);
+                        if (entry->proc != NULL) {
+                            free(entry->proc);
+                        }
+                        free(entry);
+                        /* reg_entry_free(db, entry); */
                         break;
                     case SQLITE_DONE:
                         break;

Modified: trunk/base/src/registry2.0/entry.c
===================================================================
--- trunk/base/src/registry2.0/entry.c	2007-08-06 20:12:54 UTC (rev 27524)
+++ trunk/base/src/registry2.0/entry.c	2007-08-06 20:13:00 UTC (rev 27525)
@@ -40,14 +40,42 @@
 #include "registry.h"
 #include "util.h"
 
+/**
+ * Converts a command name into a `reg_entry`.
+ *
+ * @param [in] interp  Tcl interpreter to check within
+ * @param [in] name    name of entry to get
+ * @param [out] errPtr description of error if the entry can't be found
+ * @return             an entry, or NULL if one couldn't be found
+ * @see get_object
+ */
 static reg_entry* get_entry(Tcl_Interp* interp, char* name, reg_error* errPtr) {
     return (reg_entry*)get_object(interp, name, "entry", entry_obj_cmd, errPtr);
 }
 
+/**
+ * Removes the entry from the Tcl interpreter. Doesn't actually delete it since
+ * that's the registry's job. This is written to be used as the
+ * `Tcl_CmdDeleteProc` for an entry object command.
+ *
+ * @param [in] clientData address of a reg_entry to remove
+ */
 static void delete_entry(ClientData clientData) {
-    reg_entry_free(NULL, (reg_entry*)clientData);
+    reg_entry* entry = (reg_entry*)clientData;
+    free(entry->proc);
+    entry->proc = NULL;
 }
 
+/**
+ * Sets a given name to be an entry object.
+ *
+ * @param [in] interp  Tcl interpreter to create the entry within
+ * @param [in] name    name to associate the given entry with
+ * @param [in] entry   entry to associate with the given name
+ * @param [out] errPtr description of error if it couldn't be set
+ * @return             true if success; false if failure
+ * @see set_object
+ */
 static int set_entry(Tcl_Interp* interp, char* name, reg_entry* entry,
         reg_error* errPtr) {
     if (set_object(interp, name, entry, "entry", entry_obj_cmd, delete_entry,
@@ -128,7 +156,6 @@
                 Tcl_SetObjResult(interp, result);
                 return TCL_OK;
             }
-            reg_entry_free(db, entry);
         }
         return registry_failed(interp, &error);
     }
@@ -162,7 +189,7 @@
 /**
  * registry::entry open portname version revision variants epoch ?name?
  *
- *
+ * Opens an entry matching the given parameters.
  */
 static int entry_open(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
     sqlite3* db = registry_db(interp, 1);
@@ -252,8 +279,8 @@
             keys[i] = Tcl_GetString(objv[2*i+2]);
             vals[i] = Tcl_GetString(objv[2*i+3]);
         }
-        entry_count = reg_entry_search(db, keys, vals, key_count, 0, &entries,
-                &error);
+        entry_count = reg_entry_search(db, keys, vals, key_count,
+                reg_strategy_equal, &entries, &error);
         if (entry_count >= 0) {
             Tcl_Obj* resultObj;
             Tcl_Obj** objs;
@@ -291,15 +318,21 @@
 }
 
 /**
- * registry::entry installed ?name? ?version?
+ * registry::entry imaged ?name? ?version?
  *
- * Returns a list of all installed ports. If `name` is specified, only returns
- * ports with that name, and if `version` is specified, only with that version.
- * Remember, the variants can still be different.
+ * Returns a list of all ports installed as images and/or active in the
+ * filesystem. If `name` is specified, only returns ports with that name, and if
+ * `version` is specified, only with that version. Remember, the variants can
+ * still be different, so specifying both places no constraints on the number
+ * of returned values.
  *
+ * Note that this command corresponds to installed ports in 'image' mode and has
+ * no analogue in 'direct' mode (it will be equivalent to `registry::entry
+ * installed`). That is, these ports are available but cannot meet dependencies.
+ *
  * TODO: add more arguments (epoch, revision, variants), maybe
  */
-static int entry_installed(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]){
+static int entry_imaged(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
     sqlite3* db = registry_db(interp, 1);
     if (objc > 4) {
         Tcl_WrongNumArgs(interp, 2, objv, "?name? ?version?");
@@ -311,7 +344,14 @@
         char* version = (objc == 4) ? Tcl_GetString(objv[3]) : NULL;
         reg_entry** entries;
         reg_error error;
-        int entry_count = reg_entry_installed(db, name, version, &entries,
+        /* name or version of "" means not specified */
+        if (name != NULL && *name == '\0') {
+            name = NULL;
+        }
+        if (version != NULL && *version == '\0') {
+            version = NULL;
+        }
+        int entry_count = reg_entry_imaged(db, name, version, &entries,
                 &error);
         if (entry_count >= 0) {
             Tcl_Obj* resultObj;
@@ -328,12 +368,17 @@
 }
 
 /**
- * registry::entry active ?name?
+ * registry::entry installed ?name?
  *
- * Returns a list of all active ports. If `name` is specified, only returns the
- * active port named, still in a list.
+ * Returns a list of all installed and active ports. If `name` is specified,
+ * only returns the active port named, but still in a list. Treating it as
+ * a single item will probably work but is bad form.
+ *
+ * Note that this command corresponds to active ports in 'image' mode and
+ * installed ports in 'direct' mode. That is, any port which is capable of
+ * satisfying a dependency.
  */
-static int entry_active(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]){
+static int entry_installed(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]){
     sqlite3* db = registry_db(interp, 1);
     if (objc > 3) {
         Tcl_WrongNumArgs(interp, 2, objv, "?name?");
@@ -344,7 +389,11 @@
         char* name = (objc == 3) ? Tcl_GetString(objv[2]) : NULL;
         reg_entry** entries;
         reg_error error;
-        int entry_count = reg_entry_active(db, name, &entries,
+        /* name of "" means not specified */
+        if (name != NULL && *name == '\0') {
+            name = NULL;
+        }
+        int entry_count = reg_entry_installed(db, name, &entries,
                 &error);
         if (entry_count >= 0) {
             Tcl_Obj* resultObj;
@@ -402,8 +451,8 @@
     { "close", entry_close },
     { "search", entry_search },
     { "exists", entry_exists },
+    { "imaged", entry_imaged },
     { "installed", entry_installed },
-    { "active", entry_active },
     { "owner", entry_owner },
     { NULL, NULL }
 };

Modified: trunk/base/src/registry2.0/registry.c
===================================================================
--- trunk/base/src/registry2.0/registry.c	2007-08-06 20:12:54 UTC (rev 27524)
+++ trunk/base/src/registry2.0/registry.c	2007-08-06 20:13:00 UTC (rev 27525)
@@ -57,7 +57,9 @@
     if (entry_count >= 0) {
         int i;
         for (i=0; i<entry_count; i++) {
-            Tcl_DeleteCommand(interp, entries[i]->proc);
+            if (entries[i]->proc) {
+                Tcl_DeleteCommand(interp, entries[i]->proc);
+            }
         }
         if (reg_detach(db, errPtr)) {
             Tcl_SetAssocData(interp, "registry::attached", NULL, (void*)0);

Modified: trunk/base/src/registry2.0/tests/entry.tcl
===================================================================
--- trunk/base/src/registry2.0/tests/entry.tcl	2007-08-06 20:12:54 UTC (rev 27524)
+++ trunk/base/src/registry2.0/tests/entry.tcl	2007-08-06 20:13:00 UTC (rev 27525)
@@ -19,11 +19,11 @@
     set pcre [registry::entry create pcre 7.1 1 {utf8 +} 0]
 
     # check that their properties can be set
-    $vim1 state installed
-    $vim2 state installed
-    $vim3 state active
-    $zlib state active
-    $pcre state installed
+    $vim1 state imaged
+    $vim2 state imaged
+    $vim3 state installed
+    $zlib state installed
+    $pcre state imaged
 
     # check that their properties can be retrieved
     test_equal {[$vim1 name]} vim
@@ -32,14 +32,20 @@
     test_equal {[$zlib revision]} 1
     test_equal {[$pcre variants]} {utf8 +}
     
+    set imaged [registry::entry imaged]
     set installed [registry::entry installed]
-    set active [registry::entry active]
 
-    # check that installed and active give correct results
+    # check that imaged and installed give correct results
     # have to sort these because their orders aren't defined
-    test_equal {[lsort $installed]} {[lsort "$vim1 $vim2 $vim3 $zlib $pcre"]}
-    test_equal {[lsort $active]} {[lsort "$vim3 $zlib"]}
+    test_equal {[lsort $imaged]} {[lsort "$vim1 $vim2 $vim3 $zlib $pcre"]}
+    test_equal {[lsort $installed]} {[lsort "$vim3 $zlib"]}
 
+    # try searching for ports
+    set no_variants [registry::entry search variants {}]
+    set vim71002 [registry::entry search name vim version 7.1.002]
+    test_equal {[lsort $no_variants]} {[lsort "$vim2 $zlib"]}
+    test_equal {[lsort $vim71002]} {[lsort "$vim2 $vim3"]}
+
     # try mapping files and checking their owners
     $vim3 map
     $vim3 map /opt/local/bin/vim
@@ -62,7 +68,7 @@
     test_throws {$zlib unmap /opt/local/bin/emacs} registry::not-owned
 
     # delete pcre
-    test_equal {[registry::entry installed pcre]} {$pcre}
+    test_equal {[registry::entry imaged pcre]} {$pcre}
     registry::entry delete $pcre
     test_throws {[registry::entry open pcre 7.1 1 {utf8 +} 0]} registry::not-found
     test {![registry::entry exists $pcre]}
@@ -79,8 +85,8 @@
     test {![registry::entry exists $vim3]}
     registry::open test.db
 
-    # check that the same vim is active from before
-    set vim3 [registry::entry active vim]
+    # check that the same vim is installed from before
+    set vim3 [registry::entry installed vim]
     test_equal {[$vim3 version]} 7.1.002
 
     # find the zlib we inserted before

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20070806/800d74cd/attachment.html


More information about the macports-changes mailing list