Changes between Version 56 and Version 57 of PortfileRecipes


Ignore:
Timestamp:
Mar 6, 2013, 3:00:47 AM (11 years ago)
Author:
larryv (Lawrence Velázquez)
Comment:

simplify deactivate hack recipe

Legend:

Unmodified
Added
Removed
Modified
  • PortfileRecipes

    v56 v57  
    448448* Public domain code, while technically not having or needing a license, should list the license as 'public-domain'.
    449449
    450 == Using the "deactivate hack" == #deactivatehack
    451 Using the so-called deactivate hack becomes necessary when a file that used to be provided by port A is going to be provided by port B from now on and we need a seamless update path. Without the deactivate hack the activation phase of port B would fail because one of the files it tries to install is already there. The deactivate hack works around this problem, by deactivating A if it is active. It is often combined with a check for a specific version of A. An example might clear this up:
    452 
    453 Let's say the `kerberos5` port used to install the file `${prefix}/bin/compile_et`, but we're trying to move this part to a library called `libcomerr`. Since the `kerberos5` port will still need `compile_et` to build, it will add a dependency on `libcomerr`. This will cause MacPorts to install `libcomerr` before upgrading `kerberos5`. When MacPorts tries to activate `libcomerr`, the old version of `kerberos5` is still active and the conflicting file is still installed. Usually, MacPorts would bail out at this point and require the user to solve this problem manually. However, since this would affect all users that had `kerberos5` installed, this is undesirable.
    454 
    455 In this very case, we know `kerberos5` stopped providing `compile_et` in version 1.11. We will add the deactivate hack to `libcomerr`, where it will check whether any `kerberos5` <= 1.11 port is active, and if there is, it will deactivate it before activating `libcomerr`. After activating `libcomerr`, MacPorts will then happily continue with the upgrade and install the new (and non-conflicting) version of `kerberos5`. The following block is taken from the `libcomerr` Portfile:
     450== Using the “deactivate hack” == #deactivatehack
     451Using the so-called “deactivate hack” becomes necessary when a file that used to be provided by port A is going to be provided by port B from now on and we need a seamless update path. Without the deactivate hack the activation phase of port B would fail because one of the files it tries to install is already there. The deactivate hack works around this problem, by deactivating A if it is active. It is often combined with a check for a specific version of A.
     452
     453For example, let's say the `kerberos5` port used to install the file `${prefix}/bin/compile_et`, but we're trying to move this part to a library called `libcomerr`. Since the `kerberos5` port will still need `compile_et` to build, it will add a dependency on `libcomerr`. This will cause MacPorts to install `libcomerr` before upgrading `kerberos5`. When MacPorts tries to activate `libcomerr`, the old version of `kerberos5` is still active and the conflicting file is still installed. Usually, MacPorts would bail out at this point and require the user to solve this problem manually. However, since this would affect all users that had `kerberos5` installed, this is undesirable.
     454
     455In this particular case, we know `kerberos5` stopped providing `compile_et` in version 1.11. We will add the deactivate hack to `libcomerr`, where it will check whether any `kerberos5` < 1.11 port is active, and if there is, it will deactivate it before activating `libcomerr`. After activating `libcomerr`, MacPorts will then happily continue with the upgrade and install the new (and non-conflicting) version of `kerberos5`. The following block is taken from the `libcomerr` Portfile:
    456456
    457457{{{#!tcl
    458 # both kerberos5 and e2fsprogs previsouly conflicted because they installed files now provided by libcomerr
     458# both kerberos5 and e2fsprogs previously conflicted because they installed files now provided by libcomerr
    459459if {![catch {set installed [lindex [registry_active kerberos5] 0]}]} {
    460460    set krb_version [lindex $installed 1]
     
    466466}}}
    467467
    468 * `registry_active` takes a port name as argument and returns a list of matching active ports. It is defined in source:trunk/base/src/macports1.0/macports.tcl as an alias of `registry::active`. While it might seem odd that it returns a list, it makes sense if you know that it will return a list of all active ports when called with an empty argument.
    469 * `registry::active` is defined in source:trunk/base/src/registry2.0/registry.tcl. The only relevant case (since we're all using the SQLite registry by now) forwards the call to `receipt_sqlite::active` (in source:trunk/base/src/registry2.0/receipt_sqlite.tcl), where it queries all matching ports using `registry::entry installed $name` (which is defined as `entry_installed` in source:trunk/base/src/registry2.0/entry.c, if you want to dig in). It then converts the returned list of registry entry objects to a Tcl list using the following line of code (which is the reason why we've been digging through the code):
    470   {{{#!tcl
    471 foreach port $ports {
    472     lappend rlist [list [$port name] [$port version] [$port revision] [$port variants] [string equal [$port state] "installed"] [$port epoch]]
    473 }
    474 }}}
    475   This snippet tells us which values can be found at which offsets in the (second level) list returned by `registry_active` to the Portfile:
    476  - Index 0: name of the port
    477  - Index 1: port version
    478  - Index 2: port revision
    479  - Index 3: port variants (this is what the active_variants PortGroup uses!)
    480  - Index 4: 1, if the port is installed, 0 otherwise
    481  - Index 5: port epoch
    482 * From this journey into MacPorts internals, we know that `registry_active` will return a list, but in our case it will always only contain one element. We can strip the outer list using
    483   {{{#!tcl
    484 lindex $returnval_of_registry_active 0
    485 }}}
    486 * Because `registry_active` will raise an error if the port requested is not active, we need to wrap it in a catch statement. If catch returns 0 (i.e., no error occured), we know the port in question is active.
    487 * In the example above, we retrieve the version of `kerberos5` (from index 1) and check using `vercmp` whether it is lower than 1.11. If it is, we need to deactivate the `kerberos5` port. Your case might differ here, because you might have to check revision and/or epoch.
    488 * To deactivate the conflicting port, we can use `registry_deactivate_composite` (and you can probably guess that this is an alias, too, and where you can find it).
    489   {{{#!tcl
    490 registry_deactivate_composite $name "" $options
    491 }}}
    492   is a shorthand for
    493   {{{#!tcl
    494 registry_deactivate $name "" "" 0 $options
    495 }}}
    496   and will deactivate the port indicated by `$name`. The second argument is a version number, which we can leave empty in this case. If we would normally try to deactivate `kerberos5` it might fail, because other ports might still depend on `kerberos5` being present. Since we know that it will be reinstalled soon anyway, we can just force deactivation without paying respect to the dependent ports (which we do by passing `[list ports_nodepcheck 1]` as `$options` argument.
     468* `registry_active` returns a list containing information about active ports. Given a particular name, only one active port can match, so the returning list has at most one element, which we save as `installed`. (If we had not provided an argument, the list would have had one element for every active port.)
     469* `installed` is now a list containing information on the active port. The elements relevant to version checking are the the second, third, and sixth, which contain the port version, revision, and epoch, respectively.
     470* If the active port is not recent enough, we deactivate it using `registry_deactivate_composite`. (The second argument is a version number, which in this case we leave empty. The third argument is a list of options; setting `ports_nodepcheck` to 1 forces deactivation regardless of whether there are active dependents. This is fine, since `kerberos5` will be reinstalled shortly.