Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

A bash script to automate DarwinPorts upgrades UNIX
Upgrading DarwinPorts' installed packages is somewhat harder than it should be, it seems. The problem is that when you do a port -acu upgrade in DarwinPorts, it wants you to uninstall all packages that are dependent upon the package you want to upgrade, and then to uninstall the packages that depend on these, repeat ad infinitum. Keeping track of all this is a major PitA.

Thus, I eventually got my act together and wrote this script. I've tested it rather exhaustively, but I don't claim 100% functionality. One problem seems to be that if you have installed a variant of a package, even by default the port deps command doesn't give you all of the dependencies -- see this bug report as an example of what I'm talking about.

Most of the code should be readily understandable, as I've tried to use descriptive variable names and have commented the code throughout. But the central discovery process is a nasty comglomeration of (clever ;-) ) hacks. In programming terms, the dependency structure is a network. You can question the status of each node and get the children (dependencies) of each port. However, knowing that a port needs to be upgraded, there's no readily avaliable method for finding the ports that depend upon a given port (the parent nodes), except by going through all of the ports you have installed and questioning each and every one of them. This is where the PitA enters the picture!

The script handles all of this work itself; read on for more detail on some of the routines, in case you're curious as to how it exactly works.

[robg adds: I haven't tested this one; make sure you make the script executable with chmod a+x scriptname before running it.]

What needs explaining are the following pieces of code:
# build the total list of ports that have dependencies
(( index=0 ))
for listet in ${portList[@]}
do
  portDepends=( $( port deps ${listet} | sed "/${listet}/d" |tr -d 't' ) )
  if [ ${#portDepends[@]} -ne 0 ]
  then
    portDependencies[${index}]=$( echo "${listet}: ${portDepends[@]}" )
    (( index++ ))
  fi
done
port deps ${listet} will give you the ports that a port depends on, but with some extraneous information that's unwelcome in this connection, like this:
[18:48:46@~]$ port deps nessus-plugins
nessus-plugins has build dependencies on:
        nessus-core
nessus-plugins has library dependencies on:
        nessus-libraries
[18:52:10@~]$
So the sed "/${listet}/d" bit in the above code removes the descriptive lines, and tr -d 't' removes the Tab at the beginning of each line of dependencies. Lastly, every kind of dependency is made into a list: portDepends=( $( ... commands ... ) ). Then it's checked whether the port has any dependecies at all -- with the if [ ${#portDepends[@]} -ne 0 ] line -- and if so, it's added to the list

Next, there's this bit of code:
portDeactivate=( \
  $( { for (( index=0 ; index < ${#portDependencies[@]} ; index++ ))
  do
    echo "${portDependencies[${index}]}"
  done } \
  | grep ${deactivate} |  sed -E "/^${deactivate}:/d" | cut -f 1 -d ':' ) )
This piece of code loops through all of the ports with dependencies, and extracts the ports that have dependencies on the port we have to deactivate or upgrade. The reason for using a numerical index instead of just doing for listed in ${portDependencies[@]} is that ${listed} then isn't a text-string, but a list in itself, which will cause problems further on, because each item in ${listed} then gets treated by itself, instead of as a total.

The for loop is made into a sub-program by enclosing it in curly brackets ({ for... }, and then the output from the sub-program is piped into the subsequent commands. These commands then extract the name of the port that has dependencies on a port, and removes the port itself from the list. The whole mess is then once again made into a list.
    •    
  • Currently 2.00 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (3 votes cast)
 
[15,899 views]  

A bash script to automate DarwinPorts upgrades | 11 comments | Create New Account
Click here to return to the 'A bash script to automate DarwinPorts upgrades' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
A bash script to automate DarwinPorts upgrades
Authored by: jsumners on Oct 28, '05 07:29:53AM

`man port`

"-u uninstall non-active ports when upgrading and uninstalling"

Seems to me, the easiest solution is to not use the -u parameter.



[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: dluke on Oct 28, '05 07:33:03AM

Why not just add '-f'?

That will force it to uninstall the to-be-upgraded port even if other ports depend on it (yeah, it might break something, but so could the above script).



[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: BjarneDM on Oct 28, '05 04:11:30PM
-u doesn't force an un-install when dependencies are present. If a port is dependent upon the old version you'll get an error-message that port was unable to un-install the old version along with a list of the ports that are dependent upon the old version and a suggestion to un-install these.

The only way I'm at present aware that my script can mess up is if a dependency isn't found, but that won't break your DarwonPort installation - you'll just have to do some manual work to fix the situation.

[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: BjarneDM on Oct 28, '05 04:01:54PM
If you don't use the -u option the old versions will be kept and used by the ports that are dependent upon them. Thus, if you want all of the ports to use the newest version of a port you'll have to use -u and un-install.

You could try to use the -f option, but that's fraught with danger and not at all recommended by the DarwinPorts team. I've had to re-install my whole DarwinPorts structure because of excessive use of -f.

For instance, if you are linking to the MySQL libraries, these change names between versions, so if you have compiled support for MySQL into eg PHP and Postfix, you'll have to recompile these from scratch in order to get the new libraries installed. Otherwise, the programs simply cease to function.

[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: 10drill on Oct 28, '05 09:05:55PM

I've been upgrading ports with "sudo port -vuf upgrade portname" for months now with no problem. So far no big dependency issues either...



[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: sjk on Oct 28, '05 02:57:05PM

[robg adds: I haven't tested this one; make sure you make the script executable with chmod a+x scriptname before running it.]

The 'a' in "a+x" is redundant. :-)



[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: acrylic on Oct 29, '05 12:30:14PM

No. a means all, so a+x means all users may execute it.



[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: samual.icky on Oct 29, '05 01:30:00PM

I know I'm going to come off... well in a not so nice way but... yes he knows a+x is all. However chmod +x file will set all set the user, group and guest bits to executable as well, thus +x is the same as a+x.



[ Reply to This | # ]
"chmod +x" == "chmod a+x"
Authored by: sjk on Oct 29, '05 03:49:18PM
I appreciate your astute explanation of my pedantic remark. :-)

Personally, I prefer using chmod u+x ... just to set the user execute bit for files that are intended to only be run by the owner and/or with root access (e.g. using sudo). That preserves other mode bits, which may or may not allow others to read (but not execute) the file.

UNIX file permissions bits and ownership are generally much sloppier and harder to manage on OS X than on more traditional UNIX(ish) systems. It can have implications for security that aren't often discussed. But without specific reasons, attempting to maintain file permission integrity (beyond Repair Disk Permissions) can easily become more tediously time consuming than it's worth.

And the second paragraph of my recent "... and ACLs" post implies the near- and long-term futility of that effort, especially for non-admins and unsophisticated users likely to say "why bother?". The complexity of effectively and reliably managing permissions with a file-based level of granularity decreases security and increases vulnerability.

[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: BjarneDM on Jan 09, '06 08:47:02AM

There's an error in my script :-(
Remove the section starting with:

    # don't recurse down through the outdated ports

Reason:
If the ports to be updated are dependent upon each other in some way, you'll get a bit of a mess. I've observed this in particular when nessus needs updating, as that port is actully three interdependent ports that are usually updated at the same time



[ Reply to This | # ]
A bash script to automate DarwinPorts upgrades
Authored by: madteckhead on Jun 15, '08 02:41:38AM

What about:

sudo port -n -f -u upgrade outdated

p.s. This script didn't work for me. it removed all the dependencies then never did the "port -acu upgrade" as command not found. I think you could just drop the -acu, however I found this more elegant way. :)



[ Reply to This | # ]