Ticket #38265: selfupdate-over-https-wip.patch

File selfupdate-over-https-wip.patch, 13.2 KB (added by raimue (Rainer Müller), 6 years ago)
  • macports1.0/selfupdate.tcl

    (this hunk was shorter than expected) 
    4949        upvar $updatestatusvar updatestatus
    5050        set updatestatus no
    5151    }
     52   
     53    ui_msg "$macports::ui_prefix Checking for latest version..."
     54   
     55    # download version information file
     56    set versionurl "https://www.macports.org/latest_version.txt"
     57    set versionfile [mktemp [file join [macports::gettmpdir] "macports-selfupdate.XXXXXXXX"]]
     58    ui_debug "Fetching from $versionurl"
     59    if {[catch {curl fetch $versionurl $versionfile} result]} {
     60        return -code error "Fetching latest version failed: $result"
     61    }
    5262
    53     # are we syncing a tarball? (implies detached signature)
    54     set is_tarball 0
    55     if {[string range $rsync_dir end-3 end] eq ".tar"} {
    56         set is_tarball 1
    57         set mp_source_path [file join $portdbpath sources $rsync_server [file dirname $rsync_dir]]
    58     } else {
    59         if {[string index $rsync_dir end] ne "/"} {
    60             append rsync_dir /
    61         }
    62         set mp_source_path [file join $portdbpath sources $rsync_server $rsync_dir]
     63    # parse version
     64    if {[catch {set fp [open $versionfile r]} result]} {
     65        return -code error "Reading latest version failed: $result"
    6366    }
    64     # create the path to the to be downloaded sources if it doesn't exist
    65     if {![file exists $mp_source_path]} {
    66         file mkdir $mp_source_path
    67     }
    68     ui_debug "MacPorts sources location: $mp_source_path"
     67    set data [read $fp]
     68    set data [split $data "\n"]
     69    close $fp
    6970
    70     # sync the MacPorts sources
    71     ui_msg "$macports::ui_prefix Updating MacPorts base sources using rsync"
    72     try -pass_signal {
    73         system "$rsync_path $rsync_options rsync://${rsync_server}/$rsync_dir $mp_source_path"
    74     } catch {{*} eCode eMessage} {
    75         return -code error "Error synchronizing MacPorts sources: $eMessage"
     71    # expect "version 1" in first file
     72    set firstline [lindex $data 0]
     73    if {$firstline ne "version 1"} {
     74        ui_debug "Expected \"version 1\", got \"$firstline\""
     75        ui_msg "\n\nPlease download latest version from http://www.macports.org\n\n"
     76        return -code error "Format of latest version file unsupported!"
    7677    }
    7778
    78     if {$is_tarball} {
    79         # verify signature for tarball
    80         global macports::archivefetch_pubkeys
    81         try -pass_signal {
    82             system "$rsync_path $rsync_options rsync://${rsync_server}/${rsync_dir}.rmd160 $mp_source_path"
    83         } catch {{*} eCode eMessage} {
    84             return -code error "Error synchronizing MacPorts source signature: $eMessage"
    85         }
    86         set openssl [macports::findBinary openssl $macports::autoconf::openssl_path]
    87         set tarball ${mp_source_path}/[file tail $rsync_dir]
    88         set signature ${tarball}.rmd160
    89         set verified 0
    90         foreach pubkey $macports::archivefetch_pubkeys {
    91             try -pass_signal {
    92                 exec $openssl dgst -ripemd160 -verify $pubkey -signature $signature $tarball
    93                 set verified 1
    94                 ui_debug "successful verification with key $pubkey"
    95                 break
    96             }  catch {{*} eCode eMessage} {
    97                 ui_debug "failed verification with key $pubkey"
    98                 ui_debug "openssl output: $eMessage"
    99             }
    100         }
    101         if {!$verified} {
    102             return -code error "Failed to verify signature for MacPorts source!"
    103         }
     79    # check if update is required
     80    set latest_version [lindex $data 1]
     81    set tarball_url [lindex $data 2]
    10482
    105         # extract tarball and move into place
    106         set tar [macports::findBinary tar $macports::autoconf::tar_path]
    107         file mkdir ${mp_source_path}/tmp
    108         set tar_cmd "$tar -C ${mp_source_path}/tmp -xf $tarball"
    109         try -pass_signal {
    110             system $tar_cmd
    111         } catch {*} {
    112             return -code error "Failed to extract MacPorts sources from tarball!"
    113         }
    114         file delete -force ${mp_source_path}/base
    115         file rename ${mp_source_path}/tmp/base ${mp_source_path}/base
    116         file delete -force ${mp_source_path}/tmp
    117         # set the final extracted source path
    118         set mp_source_path ${mp_source_path}/base
    119     }
    120 
    12183    # echo current MacPorts version
    122     ui_msg "MacPorts base version $macports::autoconf::macports_version installed,"
     84    ui_info "MacPorts base version $macports::autoconf::macports_version installed"
     85    ui_info "MacPorts base version $latest_version available"
    12386
    12487    if {[info exists options(ports_force)] && $options(ports_force)} {
    12588        set use_the_force_luke yes
     
    12993        ui_debug "Rebuilding and reinstalling MacPorts if needed"
    13094    }
    13195
    132     # Choose what version file to use: old, floating point format or new, real version number format
    133     set version_file [file join $mp_source_path config macports_version]
    134     if {[file exists $version_file]} {
    135         set fd [open $version_file r]
    136         gets $fd macports_version_new
    137         close $fd
    138         # echo downloaded MacPorts version
    139         ui_msg "MacPorts base version $macports_version_new downloaded."
    140     } else {
    141         ui_warn "No version file found, please rerun selfupdate."
    142         set macports_version_new 0
    143     }
    144 
    14596    # check if we we need to rebuild base
    146     set comp [vercmp $macports_version_new $macports::autoconf::macports_version]
     97    set comp [vercmp $latest_version $macports::autoconf::macports_version]
    14798
    148     # syncing ports tree.
    149     if {![info exists options(ports_selfupdate_nosync)] || !$options(ports_selfupdate_nosync)} {
    150         if {$comp > 0} {
    151             # updated portfiles potentially need new base to parse - tell sync to try to
    152             # use prefabricated PortIndex files and signal if it couldn't
    153             lappend optionslist no_reindex 1 needed_portindex_var needed_portindex
    154         }
    155         try {
    156             mportsync $optionslist
    157         }  catch {{*} eCode eMessage} {
    158             return -code error "Couldn't sync the ports tree: $eMessage"
    159         }
    160     }
    161 
    16299    if {$use_the_force_luke || $comp > 0} {
    163100        if {[info exists options(ports_dryrun)] && $options(ports_dryrun)} {
    164101            ui_msg "$macports::ui_prefix MacPorts base is outdated, selfupdate would install $macports_version_new (dry run)"
    165102        } else {
     103            global macports::portdbpath
     104
    166105            ui_msg "$macports::ui_prefix MacPorts base is outdated, installing new version $macports_version_new"
    167106
     107            # get parameters from given URL
     108            set srclist [split $tarball_url ://]
     109            set tarball_fetchpath [file join $portdbpath sources [lrange $srclist 3 end-1] /]
     110
     111            set tarball_filename [file tail $tarball_url]
     112            set tarball_fullpath [file join $tarball_fetchpath $tarball_filename]
     113            if {![regexp {^(.*)(\.tar\.(.*))$} $tarball_filename -> tarball_rootname tarball_extension]} {
     114                return -code error "Error parsing tarball filename"
     115            }
     116            set tarball_extractpath [file join $tarball_fetchpath $tarball_rootname]
     117            set signature_url "{$tarball_url}.rmd160"
     118            set signature_fullpath [file join $tarball_fullpath ".rmd160"]
     119
     120            # create the path for the to be downloaded sources if it doesn't exist
     121            if {![file exists $tarball_fetchpath]} {
     122                file mkdir $tarball_fetchpath
     123            }
     124            ui_debug "Downloading to directory: $tarball_fetchpath"
     125
     126            # determine curl flags
     127            set progressflag {}
     128            if {$macports::portverbose} {
     129                set progressflag "--progress builtin"
     130            } elseif {[info exists macports::ui_options(progress_download)]} {
     131                set progressflag "--progress ${macports::ui_options(progress_download)}"
     132            }
     133
     134            # fetch tarball and detached signature
     135            if {[catch {curl fetch {*}$progressflag $tarball_url $tarball_fullpath} result]} {
     136                return -code error "Error downloading MacPorts source tarball: $result"
     137            }
     138            if {[catch {curl fetch {*}$progressflag $signature_url $signature_fullpath} result]} {
     139                return -code error "Error downloading MacPorts source tarball: $result"
     140            }
     141
     142            # verify signature for tarball
     143            global macports::archivefetch_pubkeys
     144            set openssl [macports::findBinary openssl $macports::autoconf::openssl_path]
     145            set verified 0
     146            foreach pubkey $macports::archivefetch_pubkeys {
     147                try -pass_signal {
     148                    exec $openssl dgst -ripemd160 -verify $pubkey -signature $signature_fullpath $tarball_fullpath
     149                    set verified 1
     150                    ui_debug "successful verification with key $pubkey"
     151                    break
     152                }  catch {{*} eCode eMessage} {
     153                    ui_debug "failed verification with key $pubkey"
     154                    ui_debug "openssl output: $eMessage"
     155                }
     156            }
     157            if {!$verified} {
     158                return -code error "Failed to verify signature for MacPorts source"
     159            }
     160
     161            # set the MacPorts sources to the right owner
     162            set sources_owner [file attributes [file join $portdbpath sources/] -owner]
     163            ui_debug "Setting MacPorts sources ownership to $sources_owner"
     164            try -pass_signal {
     165                exec [macports::findBinary chown $macports::autoconf::chown_path] -R $sources_owner [file join $portdbpath $tarball_fetchpath]
     166            }  catch {{*} eCode eMessage} {
     167                return -code error "Could not change owner to $sources_owner for $tarball_fetchpath: $eMessage"
     168            }
     169
     170            # extract tarball and move into place
     171            set tar [macports::findBinary tar $macports::autoconf::tar_path]
     172            set tmppath [file join $tarball_fetchpath _tmp]
     173            file delete -force $tmppath
     174            file mkdir $tmppath
     175            set tar_cmd "$tar -C $tmppath -xof $tarball_fullpath"
     176            try -pass_signal {
     177                system $tar_cmd
     178            } catch {*} {
     179                file delete -force $tmppath
     180                return -code error "Failed to extract MacPorts sources from tarball"
     181            }
     182            file delete -force $tarball_extractpath
     183            file rename ${tmppath} ${tarball_extractpath}
     184            file delete -force $tmppath
     185
    168186            # get installation user/group and permissions
    169187            set owner [file attributes $prefix -owner]
    170188            set group [file attributes $prefix -group]
     
    206224        }
    207225    } elseif {$comp < 0} {
    208226        ui_msg "$macports::ui_prefix MacPorts base is probably trunk or a release candidate"
     227        ui_msg "Not updating, unless you specify --force to go back to the latest release."
    209228    } else {
    210229        ui_msg "$macports::ui_prefix MacPorts base is already the latest version"
    211230    }
    212231
    213     # set the MacPorts sources to the right owner
    214     set sources_owner [file attributes [file join $portdbpath sources/] -owner]
    215     ui_debug "Setting MacPorts sources ownership to $sources_owner"
    216     try {
    217         exec [macports::findBinary chown $macports::autoconf::chown_path] -R $sources_owner [file join $portdbpath sources/]
    218     }  catch {{*} eCode eMessage} {
    219         return -code error "Couldn't change permissions of the MacPorts sources at $mp_source_path to ${sources_owner}: $eMessage"
     232    return 0
     233
     234    # syncing ports tree.
     235    if {![info exists options(ports_selfupdate_nosync)] || !$options(ports_selfupdate_nosync)} {
     236        if {$comp > 0} {
     237            # updated portfiles potentially need new base to parse - tell sync to try to
     238            # use prefabricated PortIndex files and signal if it couldn't
     239            lappend optionslist no_reindex 1 needed_portindex_var needed_portindex
     240        }
     241        try {
     242            mportsync $optionslist
     243        }  catch {{*} eCode eMessage} {
     244            return -code error "Couldn't sync the ports tree: $eMessage"
     245        }
    220246    }
    221247
     248    if {$use_the_force_luke || $comp > 0} {
     249        if {[info exists options(ports_dryrun)] && $options(ports_dryrun)} {
     250            ui_msg "$macports::ui_prefix MacPorts base is outdated, selfupdate would install $macports_version_new (dry run)"
     251        } else {
     252            ui_msg "$macports::ui_prefix MacPorts base is outdated, installing new version $macports_version_new"
     253
     254
     255        }
     256    } elseif {$comp < 0} {
     257        ui_msg "$macports::ui_prefix MacPorts base is probably trunk or a release candidate"
     258    } else {
     259        ui_msg "$macports::ui_prefix MacPorts base is already the latest version"
     260    }
     261
    222262    if {![info exists options(ports_selfupdate_nosync)] || !$options(ports_selfupdate_nosync)} {
    223263        if {[info exists needed_portindex]} {
    224264            ui_msg "Not all sources could be fully synced using the old version of MacPorts."