There's been a request for a way to tell rev-upgrade to ignore a file it
would mark as broken, but in fact is not.

I've written a patch against base (r88777), which should implement this,
but I'd like to ask for a review before commiting this into base.

The patch adds a new database column[1] in the files table, which can be
set to 1 causing rev-upgrade to ignore the file. Since the exception
list has to be specified on a port-by-port base I added a new Portfile
option called precompiled (I didn't name it after rev-upgrade, because
the other GSoC project doing sanity checks should probably use this,
too) which takes glob patterns (multiple can be separated by whitespace)
and sets the bit on each file installed by that port that matches any of
the patterns.
The pattern is evaluated using fnmatch(3) in cregistry/entry.c using the
flag FNM_LEADING_DIR.

e.g.:
precompiled $prefix/lib $prefix/bin/foobar

Would set the precompiled bit on all files installed into lib and the
file bin/foobar.

Patch is attached.

[1] Other than I had expected the database version isn't compared using
float semantics, which means any new datbase version must be >= 1.101.
-- 
Clemens Lang
GSoC Student

Index: cregistry/sql.c
===================================================================
--- cregistry/sql.c	(revision 88777)
+++ cregistry/sql.c	(working copy)
@@ -190,8 +190,29 @@
             goto err_out;
         }
 
-        /* TODO: Walk the file tree and set the binary field */
+        /* Walking the file tree and updating the added field is done in rev-upgrade code */
     }
+
+    if (sql_version(NULL, strlen(version), version, strlen("1.200"), "1.200") < 0) {
+		/* add field to mark precompiled binaries for exclusion in rev-upgrade/post-destroot */
+		static char* version_1_200_queries[] = {
+			"BEGIN",
+
+			"ALTER TABLE registry.files ADD COLUMN precompiled BOOL CONSTRAINT precompiled DEFAULT 0",
+
+			"UPDATE registry.metadata SET value = '1.200' WHERE key = 'version'",
+
+			"COMMIT",
+			NULL
+		};
+
+		if (!do_queries(db, version_1_200_queries, errPtr)) {
+			goto err_out;
+		}
+
+		/* The precompiled-flag will be set during install of a port */
+	}
+
     sqlite3_finalize(stmt);
     return 1;
 
Index: cregistry/entry.c
===================================================================
--- cregistry/entry.c	(revision 88777)
+++ cregistry/entry.c	(working copy)
@@ -36,6 +36,7 @@
 #include "sql.h"
 #include "util.h"
 
+#include <fnmatch.h>
 #include <sqlite3.h>
 #include <stdlib.h>
 #include <string.h>
@@ -676,37 +677,59 @@
  * @param [in] entry      the entry to map the files to
  * @param [in] files      a list of files to map
  * @param [in] file_count the number of files
+ * @param [in] precompiled_list
+ *                        a list of glob patterns passed to fnmatch(3). If a
+ *                        pattern matches a filename, this file will have the
+ *                        precompiled flag set in the database. Used flags for
+ *                        fnmatch(3) are FNM_LEADING_DIR.
+ * @param [in] precomiled_count
+ *                        the number of patterns. Try to keep this low, as this
+ *                        function's complexity will increase linearly in
+ *                        precompiled_count
  * @param [out] errPtr    on error, a description of the error that occurred
  * @return                true if success; false if failure
  */
 int reg_entry_map(reg_entry* entry, char** files, int file_count,
-        reg_error* errPtr) {
+        char** precompiled_list, int precompiled_count, reg_error* errPtr) {
     reg_registry* reg = entry->reg;
     int result = 1;
     sqlite3_stmt* stmt = NULL;
-    char* insert = "INSERT INTO registry.files (id, path, mtime, active) "
-        "VALUES (?, ?, 0, 0)";
+    char* insert = "INSERT INTO registry.files (id, path, mtime, active, "
+        "precompiled) VALUES (?, ?, 0, 0, ?)";
     if ((sqlite3_prepare(reg->db, insert, -1, &stmt, NULL) == SQLITE_OK)
             && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
-        int i;
+        int i, j;
         for (i=0; i<file_count && result; i++) {
             if (sqlite3_bind_text(stmt, 2, files[i], -1, SQLITE_STATIC)
                     == SQLITE_OK) {
-                int r;
-                do {
-                    r = sqlite3_step(stmt);
-                    switch (r) {
-                        case SQLITE_DONE:
-                            sqlite3_reset(stmt);
-                            break;
-                        case SQLITE_BUSY:
-                            break;
-                        default:
-                            reg_sqlite_error(reg->db, errPtr, insert);
-                            result = 0;
-                            break;
+                int is_precompiled = 0;
+                for (j = 0; j < precompiled_count; ++j) {
+					printf("fnmatch(%s, %s)\n", precompiled_list[j], files[i]);
+                    if (fnmatch(precompiled_list[j], files[i], FNM_LEADING_DIR) == 0) {
+						printf("HIT!\n");
+                        is_precompiled = 1;
+                        break;
                     }
-                } while (r == SQLITE_BUSY);
+                }
+                if (sqlite3_bind_int(stmt, 3, is_precompiled) == SQLITE_OK) {
+                    int r;
+                    do {
+                        r = sqlite3_step(stmt);
+                        switch (r) {
+                            case SQLITE_DONE:
+                                sqlite3_reset(stmt);
+                                break;
+                            case SQLITE_BUSY:
+                                break;
+                            default:
+                                reg_sqlite_error(reg->db, errPtr, insert);
+                                result = 0;
+                                break;
+                        }
+                    } while (r == SQLITE_BUSY);
+                } else {
+                    reg_sqlite_error(reg->db, errPtr, insert);
+                }
             } else {
                 reg_sqlite_error(reg->db, errPtr, insert);
                 result = 0;
Index: cregistry/entry.h
===================================================================
--- cregistry/entry.h	(revision 88777)
+++ cregistry/entry.h	(working copy)
@@ -70,8 +70,8 @@
 int reg_entry_propset(reg_entry* entry, char* key, char* value,
         reg_error* errPtr);
 
-int reg_entry_map(reg_entry* entry, char** files, int file_count,
-        reg_error* errPtr);
+int reg_entry_map(reg_entry* entry, char** files, int file_count, char**
+		precompiled_list, int precompiled_count, reg_error* errPtr);
 int reg_entry_unmap(reg_entry* entry, char** files, int file_count,
         reg_error* errPtr);
 
Index: registry2.0/entryobj.c
===================================================================
--- registry2.0/entryobj.c	(revision 88777)
+++ registry2.0/entryobj.c	(working copy)
@@ -114,12 +114,10 @@
 } filemap_op;
 
 static filemap_op filemap_cmds[] = {
-    { "map", reg_entry_map },
     { "unmap", reg_entry_unmap },
     { "deactivate", reg_entry_deactivate },
     { NULL, NULL }
 };
-
 static int entry_obj_filemap(Tcl_Interp* interp, reg_entry* entry, int objc,
         Tcl_Obj* CONST objv[]) {
     reg_registry* reg = registry_for(interp, reg_attached);
@@ -155,6 +153,51 @@
     }
 }
 
+static int entry_obj_filemap_precompiled_list(Tcl_Interp* interp,
+        reg_entry* entry, int objc, Tcl_Obj* CONST objv[]) {
+    reg_registry* reg = registry_for(interp, reg_attached);
+    if (objc != 4) {
+        Tcl_WrongNumArgs(interp, 2, objv, "file-list precompiled-glob-pattern");
+        return TCL_ERROR;
+    } else if (reg == NULL) {
+        return TCL_ERROR;
+    } else {
+        char** files;
+        char** precompiled;
+        reg_error error;
+        Tcl_Obj** listv;
+        Tcl_Obj** precompiled_list;
+        int listc;
+        int precompiled_count;
+        int result = TCL_ERROR;
+        if (Tcl_ListObjGetElements(interp, objv[2], &listc, &listv) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (Tcl_ListObjGetElements(interp, objv[3], &precompiled_count,
+                    &precompiled_list) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (list_obj_to_string(&precompiled, precompiled_list, precompiled_count, &error)) {
+            if (list_obj_to_string(&files, listv, listc, &error)) {
+				if (reg_entry_map(entry, files, listc, precompiled,
+							precompiled_count, &error)) {
+                    result = TCL_OK;
+                } else {
+                    result = registry_failed(interp, &error);
+                }
+                free(files);
+            } else {
+                result = registry_failed(interp, &error);
+            }
+            free(precompiled);
+        } else {
+            result = registry_failed(interp, &error);
+        }
+        return result;
+    }
+}
+
+
 static int entry_obj_files(Tcl_Interp* interp, reg_entry* entry, int objc,
         Tcl_Obj* CONST objv[]) {
     reg_registry* reg = registry_for(interp, reg_attached);
@@ -381,7 +424,7 @@
     { "os_major", entry_obj_prop },
     { "requested", entry_obj_prop },
     /* filemap */
-    { "map", entry_obj_filemap },
+    { "map", entry_obj_filemap_precompiled_list },
     { "unmap", entry_obj_filemap },
     { "files", entry_obj_files },
     { "imagefiles", entry_obj_imagefiles },
Index: registry2.0/fileobj.c
===================================================================
--- registry2.0/fileobj.c	(revision 88777)
+++ registry2.0/fileobj.c	(working copy)
@@ -48,6 +48,7 @@
     "md5sum",
     "editable",
     "binary",
+    "precompiled",
     NULL
 };
 
@@ -114,6 +115,7 @@
     { "md5sum", file_obj_prop },
     { "editable", file_obj_prop },
     { "binary", file_obj_prop },
+    { "precompiled", file_obj_prop },
     { NULL, NULL }
 };
 
Index: port1.0/portinstall.tcl
===================================================================
--- port1.0/portinstall.tcl	(revision 88777)
+++ port1.0/portinstall.tcl	(working copy)
@@ -51,6 +51,10 @@
 # Set defaults
 default install.asroot no
 
+# list of precompiled binaries to ignore in some checks, e.g. rev-upgrade, post-destroot
+options precompiled
+default precompiled ""
+
 set_ui_prefix
 
 proc portinstall::install_start {args} {
@@ -87,11 +91,11 @@
 # 5: md5 checksum information
 proc portinstall::_fake_fileinfo_for_index {flist} {
     global 
-	set rval [list]
-	foreach file $flist {
-		lappend rval [list $file [getuid] [getgid] 0644 0 "MD5 ($fname) NONE"]
-	}
-	return $rval
+    set rval [list]
+    foreach file $flist {
+        lappend rval [list $file [getuid] [getgid] 0644 0 "MD5 ($fname) NONE"]
+    }
+    return $rval
 }
 
 proc portinstall::putel { fd el data } {
@@ -484,7 +488,7 @@
     homepage depends_run package-install workdir workpath \
     worksrcdir UI_PREFIX destroot revision maintainers user_options \
     portvariants negated_variants targets depends_lib PortInfo epoch license \
-    os.platform os.major portarchivetype installPlist
+    os.platform os.major portarchivetype installPlist precompiled
 
     set oldpwd [pwd]
     if {$oldpwd == ""} {
@@ -517,6 +521,14 @@
         }
     }
 
+	set precompiled_list {}
+	foreach pattern [split $precompiled " "] {
+		set pattern_trimmed [string trim $pattern]
+		if {$pattern_trimmed != ""} {
+			lappend precompiled_list $pattern_trimmed
+		}
+	}
+
     registry::write {
 
         set regref [registry::entry create $subport $version $revision $portvariants $epoch]
@@ -545,9 +557,9 @@
 
         if {[info exists installPlist]} {
             # register files
-            $regref map $installPlist
+            $regref map $installPlist $precompiled
         }
-        
+
         # store portfile
         set fd [open [file join ${portpath} Portfile]]
         $regref portfile [read $fd]
Index: macports1.0/macports.tcl
===================================================================
--- macports1.0/macports.tcl	(revision 88777)
+++ macports1.0/macports.tcl	(working copy)
@@ -3931,6 +3931,11 @@
             #ui_debug "$i/[llength $binaries]: [$b path]"
             incr i
 
+            if {[$b precompiled] == "1"} {
+                ui_debug "Ignoring precompiled binary [$b path]"
+                continue;
+            }
+
             set resultlist [machista::parse_file $handle [$b path]]
             set returncode [lindex $resultlist 0]
             set result     [lindex $resultlist 1]
_______________________________________________
macports-dev mailing list
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/macports-dev

Reply via email to