[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