Skip to content

Improve Linux prerequisite installation by detecting package manager (apt vs dnf) #1010

Description

@ChaiJahan

Answers checklist

  • I have read the documentation ESP-AT Programming Guide and the issue is not addressed there.
  • I have compiled the hello_world example Get Started with ESP-IDF and the issue is not addressed there.
  • I have updated my ESP-AT branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

ESP-AT version

v5.0.0.0-113-ga86e103b

Operating System used

Linux

If you are using Windows, please specify command line type.

None

What is the expected behavior?

Running the ESP-AT install script on any common Linux distribution should successfully install prerequisites without requiring manual changes.

The script should detect the system’s package manager (e.g., apt-get, dnf) and use the appropriate command automatically.

What is the actual behavior?

The current script assumes a Debian-based system and uses apt-get unconditionally.

On non-Debian distributions such as Fedora, this results in failure unless the user manually installs dependencies or modifies the script.

Steps to reproduce

  1. Use a Fedora-based system
  2. Run the ESP-AT installation script (./build.py install)
  3. Observe failure due to apt-get not being available:

Build or installation Logs

muhammadali@fedora:~/Documents/dev/esp-at$ ./build.py install
Ready to install ESP-IDF prerequisites..
sudo: apt-get: command not found
A fatal error occurred: install prerequisites failed! Please manually run:
sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv python3-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0

More Information

I modified the build.py script to account for package managers on linux. Here are my changes:

# NEW FUNCTION THAT DETECTS PACKAGE MANAGER
def detect_package_manager():
    for pm in ['apt-get', 'dnf']:
        if subprocess.call('which ' + pm, shell=True) == 0:
            return pm
    return None

def install_prerequisites():
    # install ESP-IDF prerequisites
    ESP_LOGI('Ready to install ESP-IDF prerequisites..')
    cmd = ''
    if sys.platform == 'linux':
        # New if-elif block that gets the package manager and uses the appropriate one
        # Note that the same packages may not have the same name accross distributions (libssl-dev for debian, openssl-devel for fedora)
        pm = detect_package_manager();
        if pm == 'apt-get':
            cmd = 'sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv python3-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0'
        elif pm == 'dnf':
            cmd = 'sudo dnf install -y git wget flex bison gperf python3 python3-pip python3-virtualenv python3-setuptools cmake ninja-build ccache libffi-devel openssl-devel dfu-util libusb1 python3-virtualenv'
        else:
            raise Exception('Unsupported package manager. Please submit a github issue for your package manager!')
    elif sys.platform == 'darwin':
        cmd = 'brew install cmake ninja dfu-util ccache python3'
    elif sys.platform == 'win32':
        print('Windows Installer Download has already installed all prerequisites.')
    elif sys.platform == 'linux2':
        print('GitLab CI has already installed all prerequisites.')
    else:
        raise Exception('unsupported platform: {} till now.'.format(sys.platform))

    if not os.environ.get('HAS_IDF_PREREQUISITES'):
        ret = subprocess.call(cmd, shell = True)
        if ret:
            raise Exception('install prerequisites failed! Please manually run:\r\n{}'.format(cmd))

    # install ESP-AT prerequisites
    ESP_LOGI('Ready to install ESP-AT prerequisites..')
    cmd = '{} -m pip install -r requirements.txt'.format(sys.executable)
    ret = subprocess.call(cmd, shell = True)
    if ret:
        raise Exception('install ESP-AT prerequisites failed!')

Attached is my successful build after updating the build.py file like shown above

successful-build.txt

Caveat with my solution

If someone has multiple of these package managers installed on their system, it will choose the one that comes earliest in the defined list. This is not great.

A potential solution to this is having an environment variable that represents which package manager is being used. There are likely better solutions that this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions