Normadize
Normadize

Reputation: 1222

How to list packages and dependencies that will be installed in Macports?

Is there a way to just list all new packages and their dependencies that port will install for a given command?

For instance, consider installing the SciPy stack with the suggested:

sudo port install py27-numpy py27-scipy py27-matplotlib py27-ipython +notebook py27-pandas py27-sympy py27-nose

That installs a ton of packages and dependencies not listed in the above command.

Also, some of them I already have.

I'm already aware of the -y switch but that gives a verbose output of everything, including packages I had already installed.

I'm interested to have port tell me which new packages (be it dependencies or not) will be installed.

Is there a known way or do people just parse the -y output of the command, comparing each reported package against the existing installed packages?

Cheers

p.s. I'm fairly new to Macports and MacOSX (in Linux, apt-get always tells you which new packages will be installed)

Upvotes: 2

Views: 2211

Answers (3)

Dmitriy Buldakov
Dmitriy Buldakov

Reputation: 51

Why do not just run install for the port, like:

port install XXX

And then it'll list everything required and ask to proceed. At this moment you could interrupt the installation if you do not want to proceed.

root@my-mac macports # port install npm10
--->  Computing dependencies for npm10
The following dependencies will be installed: 
 icu
 libcxx
 nodejs22
Continue? [Y/n]: Y

Like, in the example above, installing npm10 would require installing 3 new ports: icu, libcxx, and nodejs22.

Upvotes: 1

Yongwei Wu
Yongwei Wu

Reputation: 5582

neverpanic already gave a answer, but it seems unable to handle variants (like +notebook) and command-line options (like configure.compiler=macports-clang-3.7). I had a separate solution. The following Python script can display the new dependencies recursively:

#!/usr/bin/env python
#coding: utf-8

import re
import sys
import subprocess

# Gets command output as a list of lines
def popen_readlines(cmd):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    p.wait()
    if p.returncode != 0:
        raise subprocess.CalledProcessError(p.returncode, cmd)
    else:
        return map(lambda line: line.rstrip('\n'), p.stdout.readlines())

# Gets the port name from a line like "  gcc6 @6.1.0_0 (active)"
def get_port_name(port_line):
    return re.sub(r'^  (\S+).*', r'\1', port_line)

# Gets installed ports as a set
def get_installed():
    installed_ports_lines = popen_readlines(['port', 'installed'])[1:]
    installed_ports = set(map(get_port_name, installed_ports_lines))
    return installed_ports

# Gets port names from items that may contain version specifications,
# variants, or options
def get_ports(ports_and_specs):
    requested_ports = set()
    for item in ports_and_specs:
        if not (re.search(r'^[-+@]', item) or re.search(r'=', item)):
            requested_ports.add(item)
    return requested_ports

# Gets dependencies for the given port list (which may contain options
# etc.), as a list of tuples (combining with level), excluding items in
# ignored_ports
def get_deps(ports, ignored_ports, level):
    if ports == []:
        return []

    deps_raw = popen_readlines(['port', 'deps'] + ports)
    uninstalled_ports = []
    for line in deps_raw:
        if re.search(r'Dependencies:', line):
            deps = re.sub(r'.*Dependencies:\s*', '', line).split(', ')
            uninstalled_ports += [x for x in deps if x not in ignored_ports]
            ignored_ports |= set(deps)

    port_level_pairs = []
    for port in uninstalled_ports:
        port_level_pairs += [(port, level)]
        port_level_pairs += get_deps([port], ignored_ports, level + 1)
    return port_level_pairs

def main():
    if sys.argv[1:]:
        ports_and_specs = sys.argv[1:]
        ignored_ports = get_installed() | get_ports(ports_and_specs)
        uninstalled_ports = get_deps(ports_and_specs, ignored_ports, 0)
        for (port, level) in uninstalled_ports:
            print ' ' * (level * 2) + port

if __name__ == '__main__':
    main()

It can be invoked like port_rdeps.py libomp configure.compiler=macports-clang-3.7. As a bonus, it can show the uninstalled dependencies as a tree.

Upvotes: 0

neverpanic
neverpanic

Reputation: 2998

You can use a port expression to print what will be installed:

port echo rdepof:$yourport and not installed

or for multiple ports

port echo \( rdepof:$yourport rdepof:$yourport2 ... \) and not installed

Due to the number of Portfiles involved in this and how the set operations are implemented, this will be rather slow. That being said, we're also working on improving this and providing feedback prior to installation like apt-get in a future MacPorts version.

Upvotes: 3

Related Questions