H

I've often wanted to run arbitrary code outside of a Portfile (and the port 
command) but using variables and procedures available when in that Portfile's 
context. Today I wanted to modify part of a big port's post-destroot without 
having to go through the whole build process again (slow machine...) so I came 
up with with a solution which might be of interest to others. The Tcl code 
below expects to live in a file that is inside the target port's portdir but 
the principle can of course be used in something much more flexible/generic.

HTH :)
R.

{{{
#!/opt/local/libexec/macports/bin/tclsh8.5

package require Tclx
package require macports
package require Pextlib
package require portutil

# Initialise mport
# This must be done following parse of global options, as some options are
# evaluated by mportinit.
if {[catch {mportinit ui_options global_options global_variations} result]} {
    global errorInfo
    puts "$errorInfo"
    fatal "Failed to initialise MacPorts, $result"
}

# open the port in corresponding to the directory we're living in
if {[catch {set mport [mportopen "file://[file dirname [info script]]"]} 
result]} {
    global errorInfo
    ui_debug $errorInfo
    ui_error "Unable to open port: $result"
    return 1
}

# get the interpreter that was used for evaluating code inside the Portfile
set portinterp [ditem_key ${mport} workername]

# One can export a number of variables of interest from that interpreter like 
so:
# set qt_cmake_module_dir [$portinterp eval set "qt_cmake_module_dir"]
# but it is much more practical to insert the code to run into the interpreter,
# and run it there.

# http://wiki.tcl.tk/15349
proc inject {name} {
    if {[info exists ::auto_index($name)]} {
        set body "# $::auto_index($name)\n"
    } else {
        set body ""
    }
    append body [info body $name]
    set argl {}
    foreach a [info args $name] {
        if {[info default $name $a def]} {
            lappend a $def
        }
        lappend argl $a
    }
    list proc $name $argl $body
}

# the code we want to run, written exactly like it would inside the Portfile:
proc fix_cmake_modules {} {
    global destroot subport
    ui_msg "${subport} has ${destroot}"
# snip
}

# inject the above procedure into $portinterp
$portinterp eval [inject "fix_cmake_modules"]
# evaluate the new procedure
$portinterp eval "fix_cmake_modules"

mportclose ${mport}
mportshutdown
}}}
_______________________________________________
macports-dev mailing list
macports-dev@lists.macosforge.org
https://lists.macosforge.org/mailman/listinfo/macports-dev

Reply via email to