protonscr

Steam repeatedly tries to install dependencies

steamclosed reviewedSteam client
ValveSoftware/steam-for-linux#603 · opened 2013-01-09 by Majkl578 · updated 2013-02-09 · 27 comments · github
MMajkl578 2013-01-09 github

Hi,
after today's update, Steam repeatedly tries to install some missing dependencies, even if these are not satisfiable. In my case, it is:

  1. start Steam
  2. console pops-up, prompting for my password
  3. I enter the password, it tries to install some packages, but then it fails (packages do not exist) [see at the end of the report]
  4. I press return
  5. Steam starts up
  6. Library and Friends windows pop-up, but also a console prompting for a password
  7. now steps 3. & 4. repeat
  8. it prompts again
  9. now steps 3. & 4. repeat
  10. finally, I am no longer bothered
  11. now I quit Steam (from a menu, I select Steam -> Exit
  12. it prompts for a password again
  13. now steps 3. & 4. repeat
  14. Steam does NOT exit, but loggs me in again!
  15. steps 6.-8. repeat
  16. step 11. repeats
  17. finally, Steam quits!

Please note that each time I started Steam, it behaved slightly differently (especially the moments with password prompts), but generally it always annoys the user again and again.

Ad 3.:

Steam needs to install these additional packages: 
    jockey-common, libjpeg-turbo8:i386
[sudo] password for majkl: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Package libjpeg-turbo8:i386 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Unable to locate package jockey-common
E: Package 'libjpeg-turbo8:i386' has no installation candidate
Press return to continue:

I am unable to provide Steam-formatted system info due to another bug, but generally it's Debian x64 experimental + Gnome Shell 3.6.

Mmicb25 2013-01-09 github

I've also a strange behavior after todays update when I want to quit Steam through the menu 'Steam -> Exit':
Steam closes, the Updater window appears, Steam starts again. Finally I have to quit Steam again and then it is really terminated.

Ggtmanfred 2013-01-09 github

this is part of their new /usr/bin/steamdeps binary which shouldn't exist... they should continue shipping the libs with the games and let the packages take care of the deps for the steam app

MMajkl578 2013-01-09 github

@gtmanfred: I just noticed that weird thing some moments ago. I completely agree with you, we're not on Windows here, it should be left up to paclage manager.

I work-arounded the issue by replacing the contents of /usr/bin/steamdeps by:

#!/bin/bash

exit 0

Steam does not prompt for anything now.

MMajkl578 2013-01-09 github

@micb25: Same here, it seems to be a different issue, here's the report: #605.

MMrSchism 2013-01-09 github

@Majkl578 regarding your "We're not on Windows here..." I could say that we're not on Windows and that we should manually place all files.

Some people prefer some methods. Windows isn't as singularly designed as many people make it seem. Most of my Windows programs aren't in Program Files.

Ggtmanfred 2013-01-09 github

@MrSchism, well then you won't like the steamdeps either because it automatically calls apt-get for you

MMrSchism 2013-01-09 github

It is what it is. I deal with it as it works well enough. We're still in beta and will probably see more changes in package management before an official public stable release.

MMajkl578 2013-01-09 github

@MrSchism: So they won't probably use *.deb files to install Steam, don't you think? They will use tgz installer (when it's provided), which might contain some dependency-checking utility like steamdeps. It's really nonsense to provide *.deb files and also something like steamdeps, because *.deb files themselves contain their deps…

MMrSchism 2013-01-09 github

Odds are that with an already existent .deb, they may go the way that so many others do and let you chose your package.

Note: This is my personal opinion and not based on anything heard or mentioned; it is based entirely on how other companies handle their software (Skype, NX NoMachine, etc).

MMajkl578 2013-01-09 github

@MrSchism:

it is based entirely on how other companies handle their software (Skype, NX NoMachine, etc).

Until now, I have never seen any *.deb package containing its own dependency manager. It's just against the main principle of package managers - dependencies should be resolved by the manager, not package itself…
Also I haven't noticed Skype to provide something like this - they provide multiarch package with just a single binary (with correct dependencies for both Ubuntu and Debian at once).

MMrSchism 2013-01-09 github

I was more referring to the multiple package offering, not how the .deb is handled. Those companies offer .deb, .rpm (Fedora/Redhat), .rpm (openSUSE), and .tar.gz.

Both are offered in 32- and 64-bit.

Ggtmanfred 2013-01-09 github

sure, that is fine we are only talking about how there shouldn't be a file inside the package called steam deps that calls and tries to install more packages, which maybe dependencies of steam, but aren't installed as dependencies reliably because otherwise they would already be installed. So not only is it a bad idea because there is no reason for steam to have to use sudo and call the package manager. but when it does call the package manager, it is going to mess up the dependencies tree because you can't install jockey or whatever it does install as a dependency, as a package that isn't installed explicitly, when you tell the package manager to clean up un needed dependencies, all of those things will get removed.

MMajkl578 2013-01-12 github

Still not fixed after today's update…

?ghost 2013-01-25 github

I was in the same situation as you are, I created two dummy packages for jockey-common, and libjpeg-turbo8, it works.
I wrote a little script to simply update and patch steam on debian, then install a deb: http://pastebin.com/N9GZQwNT
If you don't want to use it, building dummy packages with equivs is pretty simple.

MMajkl578 2013-01-25 github

I am currently locally changing & repacking official deb package by this simple script: https://gist.github.com/4544397. Generally, I'm only removing steamdeps and fixing libpulse0 version, no other changes are needed (for me).

Sslouken 2013-01-31 github

This should be fixed in the latest update. Please let me know if this is still an issue for you.

Aadamreeve 2013-02-01 github

This wasn't an issue for me until the update today. I'm on Fedora 18 and Steam now tries to install a bunch of non-existent packages every time it starts:

Steam needs to install these additional packages:
jockey-common, python-apt, zenity, xterm, libgl1-mesa-dri:i386, libgl1-mesa-glx:i386, libc6:i386
[sudo] password for adam: 
Loaded plugins: langpacks, presto, refresh-packagekit
No package jockey-common available.
No package python-apt available.
Package zenity-3.6.0-1.fc18.x86_64 already installed and latest version
Package xterm-287-1.fc18.x86_64 already installed and latest version
No package libgl1-mesa-dri:i386 available.
No package libgl1-mesa-glx:i386 available.
No package libc6:i386 available.
Nothing to do
Press return to continue:
Zztoufie 2013-02-02 github

This seems to be happening to me too as of today, I'm using Fedora 17 on x86_64 and it keeps trying to install a whole bunch of i386 libs. Steam runs fine though once I hit enter, so it's more of annoyance, and it doesn't stop me from playing TF2.

Steam needs to install these additional packages:
jockey-common, python-apt, zenity, xterm, multiarch-support, libcurl3-gnutls:i386, libgl1-mesa-dri:i386, libgl1-mesa-glx:i386, libogg0:i386, libpixman-1-0:i386, libtheora0:i386, libudev0:i386, libvorbis0a:i386, libvorbisenc2:i386, libvorbisfile3:i386, libasound2:i386, libc6:i386, libcairo2:i386, libcups2:i386, libdbus-1-3:i386, libfontconfig1:i386, libfreetype6:i386, libgcc1:i386, libgcrypt11:i386, libgdk-pixbuf2.0-0:i386, libglib2.0-0:i386, libgtk2.0-0:i386, libnspr4:i386, libnss3:i386, libopenal1:i386, libpango1.0-0:i386, libpng12-0:i386, libpulse0:i386, libstdc++6:i386, libx11-6:i386, libxext6:i386, libxfixes3:i386, libxi6:i386, libxinerama1:i386, libxrandr2:i386, libxrender1:i386, zlib1g:i386, libsdl1.2debian:i386
Loaded plugins: auto-update-debuginfo, langpacks, presto, refresh-packagekit
No package jockey-common available.
No package python-apt available.
Package zenity-3.4.0-2.fc17.x86_64 already installed and latest version
Package xterm-286-1.fc17.x86_64 already installed and latest version
No package multiarch-support available.
No package libcurl3-gnutls:i386 available.
No package libgl1-mesa-dri:i386 available.
No package libgl1-mesa-glx:i386 available.
No package libogg0:i386 available.
No package libpixman-1-0:i386 available.
No package libtheora0:i386 available.
No package libudev0:i386 available.
No package libvorbis0a:i386 available.
No package libvorbisenc2:i386 available.
No package libvorbisfile3:i386 available.
No package libasound2:i386 available.
No package libc6:i386 available.
No package libcairo2:i386 available.
No package libcups2:i386 available.
No package libdbus-1-3:i386 available.
No package libfontconfig1:i386 available.
No package libfreetype6:i386 available.
No package libgcc1:i386 available.
No package libgcrypt11:i386 available.
No package libgdk-pixbuf2.0-0:i386 available.
No package libglib2.0-0:i386 available.
No package libgtk2.0-0:i386 available.
No package libnspr4:i386 available.
No package libnss3:i386 available.
No package libopenal1:i386 available.
No package libpango1.0-0:i386 available.
No package libpng12-0:i386 available.
No package libpulse0:i386 available.
No package libstdc++6:i386 available.
No package libx11-6:i386 available.
No package libxext6:i386 available.
No package libxfixes3:i386 available.
No package libxi6:i386 available.
No package libxinerama1:i386 available.
No package libxrandr2:i386 available.
No package libxrender1:i386 available.
No package zlib1g:i386 available.
No package libsdl1.2debian:i386 available.
Nothing to do
Press return to continue:

Sslouken 2013-02-02 github

That's weird. We just removed a whole bunch of dependencies from steamdeps.txt.
Does /usr/bin/steamdeps exist on your system? If so, what does it contain?
Does ~/.steam/root/steamdeps.txt exist on your system? What does that contain?

Zztoufie 2013-02-02 github

Just as a side note, I know that Valve doesn't officially package Steam for Fedora so I'm using a package from http://spot.fedorapeople.org/steam/ that pushed an update yesterday. This is the version that I've updated too, steam-1.0.0.22-1.fc17.i686.

Here is the contents of those 2 files. Sorry about the cut and paste, I don't now how to attach files in Github comments.

$ cat /usr/bin/steamdeps
#!/usr/bin/python
"""
This script handles installing system dependencies for games using the
Steam runtime. It is intended to be customized by other distributions
to "do the right thing"

    Usage: steamdeps dependencies.txt

"""

import os
import re
import stat
import subprocess
import sys
import tempfile

try:
from platform import architecture, uname
if sys.version_info[:2] < (2, 6): # Python < 2.6
from platform import dist
else:
from platform import linux_distribution as dist
except: # "platform" not installed. Python < 2.3
sys.exit("Python too old for platform, upgrade!")

This is the set of supported Steam runtime environments

SUPPORTED_STEAM_RUNTIME = [ '1' ]

This is the set of supported dependency formats

SUPPORTED_STEAM_DEPENDENCY_VERSION = [ '1' ]

def getDistro():
"""
Try to identify distribution of Linux
"""
global _distro
if dist()[0].lower() == 'fedora':
_distro = 'fedora'
_distro_version = dist()[1]
elif dist()[0].lower() == 'redhat':
_distro = 'rhel'
_distro_version = dist()[1]
elif dist()[0].lower() == 'debian':
_distro = 'debian'
_distro_version = dist()[1]
elif dist()[0].lower() == 'ubuntu':
_distro = 'ubuntu'
_distro_version = dist()[1]
elif dist()[0].lower() == 'suse':
_distro = 'suse'
_distro_version = dist()[1]
else:
_distro = 'unknown'
_distro_version = '1'
return _distro

Get the current package architecture

This may be different than the actual architecture for the case of i386

chroot environments on amd64 hosts.

_arch = None
def getArch():
"""
Get the current architecture
"""
distro = getDistro()

    global _arch

    if ( _arch is None ):
            if distro == 'fedora' or distro == 'rhel' or distro == 'suse':
                    _arch = subprocess.check_output(['rpm', '--eval', '%{_arch}']).decode("utf-8").strip()
            elif distro == 'ubuntu' or distro == 'debian' or distro == 'unknown':
                    _arch = subprocess.check_output(['dpkg', '--print-architecture']).decode("utf-8").strip()
    return _arch

def getFullPackageName( name ):
"""
Get the full name of a package, qualified by architecture
"""
if ( name.find(":") < 0 ):
return name + ":" + getArch()
else:
return name

class Package:
"""
Package definition class
"""
def init(self, name, versionConditions):
self.name = name
self.versionConditions = versionConditions
self.installed = None

    def setInstalled(self, version):
            self.installed = version

    def isAvailable(self):
            distro = getDistro()

            if ( self.installed is None ):
                    return False

            for (op, version) in self.versionConditions:
                    if distro == 'fedora' or distro == 'rhel':
                            import rpm
                            comp_result = rpm.labelCompare(('1', self.installed, '1'), ('1', version, '1'))
                            if op == '=':
                                    if comp_result == 0:
                                            return True
                                    else:
                                            return False
                            elif op == '>=':
                                    if comp_result == 1 or comp_result == 0:
                                            return True
                                    else:
                                            return False
                            elif op == '<=':
                                    if comp_result == -1 or comp_result == 0:
                                            return True
                                    else:
                                            return False
                            elif op == '>':
                                    if comp_result == 1:
                                            return True
                                    else:
                                            return False
                            elif op == '<':
                                    if comp_result == -1:
                                            return True
                                    else:
                                            return False
                            else:
                                    # Unknown op, just go with False
                                    return False
                    else:
                            if ( subprocess.call( ['dpkg', '--compare-versions', self.installed, op, version] ) != 0 ):
                                    return False

            return True

    def __str__(self):
            text = self.name
            for (op, version) in self.versionConditions:
                    text += " (%s %s)" % (op, version)
            return text

def createPackage( description ):
"""
Create a package object based on a description.
This can return None if the package isn't meaningful on this platform.
"""
# Look for architecture conditions, e.g. foo [i386]
match = re.match( r"(.*) [([^]]+)]", description )
if match is not None:
description = match.group(1).strip()
condition = match.group(2)
if ( condition[0] == '!' ):
if ( getArch() == condition[1:] ):
return None
else:
if ( getArch() != condition ):
return None

    # Look for version requirements, e.g. foo (>= 1.0)
    versionConditions = []
    while True:
            match = re.search( r"\s*\(\s*([<>=]+)\s*([\w\-\.:]+)\s*\)\s*", description )
            if ( match is None ):
                    break

            versionConditions.append( ( match.group(1), match.group(2) ) )
            description = description[:match.start()] + description[match.end():]

    return Package( description.strip(), versionConditions )

def getTerminalCommandLine( title ):
"""
Function to find a useful terminal like xterm or compatible
"""
if ( "DISPLAY" in os.environ ):
programs = [
( "gnome-terminal", ["gnome-terminal", "--disable-factory", "-t", title, "-e"] ),
( "xterm", ["xterm", "-T", title, "-e"] ),
]
for (program, commandLine) in programs:
if ( subprocess.call( ['which', program], stdout=subprocess.PIPE ) == 0 ):
return commandLine

    # Fallback if no GUI terminal program is available
    return ['/bin/sh']

def updatePackages( packages ):
"""
Function to install or update package dependencies
Ideally we would call some sort of system UI that users were familiar with to do this, but nothing that exists yet does what we need.
"""
distro = getDistro()

    packageList = " ".join( [ package.name for package in packages ] )

    # Create a temporary file to hold the installation completion status
    (fd, statusFile) = tempfile.mkstemp()
    os.close( fd )

    # Create a script to run, in a secure way
    (fd, scriptFile) = tempfile.mkstemp()
    if distro == 'fedora' or distro == 'redhat':
            script = """#!/bin/sh

cat <<EOF
Steam needs to install these additional packages:
%s
EOF
sudo yum install %s
echo $? >%s
echo -n "Press return to continue: "
read line
""" % ( ", ".join( [ package.name for package in packages ] ), packageList, statusFile )
else:
script = """#!/bin/sh
cat <<EOF
Steam needs to install these additional packages:
%s
EOF
sudo apt-get install %s
echo $? >%s
echo -n "Press return to continue: "
read line
""" % ( ", ".join( [ package.name for package in packages ] ), packageList, statusFile )
os.write( fd, script.encode("utf-8") )
os.close( fd )
os.chmod( scriptFile, (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) )

    try:
            subprocess.call( getTerminalCommandLine( "Package Install" ) + [scriptFile] )
    except KeyboardInterrupt:
            pass
    os.unlink( scriptFile )

    # Read the status out of the file, since if we ran the script in a
    # terminal the process status will be whether the terminal started
    try:
            status = int( open( statusFile ).read() )
    except ValueError:
            # The status wasn't written to the file
            status = 255

    os.unlink( statusFile )

    return status

def checkConfig( config ):
if ( "STEAM_RUNTIME" not in config ):
sys.stderr.write( "Missing STEAM_RUNTIME definition in %s\n" % args[1] )
return False

    if ( config["STEAM_RUNTIME"] not in SUPPORTED_STEAM_RUNTIME ):
            sys.stderr.write( "Unsupported Steam runtime: %s\n" % config["STEAM_RUNTIME"] )
            return False

    if ( "STEAM_DEPENDENCY_VERSION" not in config ):
            sys.stderr.write( "Missing STEAM_DEPENDENCY_VERSION definition in %s\n" % args[0] )
            return False

    if ( config["STEAM_DEPENDENCY_VERSION"] not in SUPPORTED_STEAM_DEPENDENCY_VERSION ):
            sys.stderr.write( "Unsupported dependency version: %s\n" % config["STEAM_DEPENDENCY_VERSION"] )
            return False

    return True

def main( *args ):
config = {}
distro = getDistro()

    # Check the command line arguments
    if ( len(args) < 1 ):
            sys.stderr.write( "Usage: %s dependencies.txt\n" % sys.argv[0] )
            return 1

    # Make sure we can open the file
    try:
            fp = open(args[0])
    except Exception as e:
            sys.stderr.write( "Couldn't open file: %s\n" % (e) )
            return 2

    # Look for configuration variables
    config_pattern = re.compile( r"(\w+)\s*=\s*(\w+)" )
    for line in fp:
            line = line.strip()
            if ( line == "" or line[0] == '#' ):
                    continue

            match = re.match(config_pattern, line)
            if ( match is not None ):
                    config[match.group(1)] = match.group(2)

    # Check to make sure we have a valid config
    if ( not checkConfig( config ) ):
            return 3

    # Seek back to the beginning of the file
    fp.seek(0)

    # Load the package dependency information
    packages = {}
    dependencies = []
    lineNumber = 0
    for line in fp:
            ++lineNumber
            line = line.strip()
            if ( line == "" or line[0] == '#' ):
                    continue

            match = re.match( config_pattern, line )
            if ( match is not None ):
                    continue

            row = []
            for section in line.split( "|" ):
                    package = createPackage( section )
                    if ( package is None ):
                            continue

                    packages[ package.name ] = package
                    row.append( package )

            dependencies.append( row )

    # Print package dependency information for debug
    """
    for row in dependencies:
            print " | ".join( [ str(package) for package in row ] )
    """

    # Get the installed package versions
    # Make sure COLUMNS isn't set, or dpkg will truncate its output
    if ( "COLUMNS" in os.environ ):
            del os.environ[ "COLUMNS" ]

    if distro == 'fedora' or distro == 'rhel':
            process = subprocess.Popen( ['rpm', '-qf', '"ii\t%{NAME}\t%{VERSION}-%{RELEASE}\t%{SUMMARY}\n"', '-q'] + list( packages.keys() ), stdout=subprocess.PIPE, stderr=subprocess.PIPE )
    else:
            process = subprocess.Popen( ['dpkg', '-l'] + list( packages.keys() ), stdout=subprocess.PIPE, stderr=subprocess.PIPE )
    installed_pattern = re.compile( r"^ii\s+([^\s]+)\s+([^\s]+)" )
    for line in process.stdout:
            line = line.decode( "utf-8" ).strip()
            match = re.match( installed_pattern, line )
            if ( match is None ):
                    continue

            name = match.group(1)
            if ( name not in packages ):
                    name = getFullPackageName( name )
            packages[ name ].setInstalled( match.group(2) )

    # See which ones need to be installed
    needed = []
    for row in dependencies:
            if ( len(row) == 0 ):
                    continue

            satisfied = False
            for dep in row:
                    if ( dep.isAvailable() ):
                            satisfied = True
                            break
            if ( not satisfied ):
                    needed.append( row[0] )

    # If we have anything to install, do it!
    if ( len(needed) > 0 ):
            for package in needed:
                    if package.installed:
                            print( "Package %s is installed with version '%s' but doesn't match requirements: %s" % (package.name, package.installed, package) )
                    else:
                            print( "Package %s needs to be installed" % package.name )

            return updatePackages( needed )
    else:
            return 0

if name == "main":
status = main( *sys.argv[1:] )
sys.exit(status)

$ cat ~/.steam/root/steamdeps.txt

This is a package dependency manifest used by steamdep

This should be set to the version of the Steam runtime that this program

is built with.

Available values are:

1 - Ubuntu 12.04 LTS

STEAM_RUNTIME=1

This should be set to the version of the dependency file format

The file can contain lines starting with #, blank lines and dependencies

A dependency line consists of a package name for the current runtime,

along with optional architecture or version requirements using the

Debian package syntax:

http://www.debian.org/doc/debian-policy/ch-relationships.html

STEAM_DEPENDENCY_VERSION=1

These are non-arch specific dependencies

jockey-common
python-apt
zenity
xterm | gnome-terminal
multiarch-support (>= 2.15-0ubuntu10.2)

These are i386 dependencies for Steam itself

libcurl3-gnutls:i386
libgl1-mesa-dri:i386
libgl1-mesa-glx:i386
libogg0:i386
libpixman-1-0:i386
libtheora0:i386
libudev0:i386
libvorbis0a:i386
libvorbisenc2:i386
libvorbisfile3:i386
libasound2:i386
libc6:i386
libcairo2:i386
libcups2:i386
libdbus-1-3:i386
libfontconfig1:i386
libfreetype6:i386
libgcc1:i386
libgcrypt11:i386
libgdk-pixbuf2.0-0:i386
libglib2.0-0:i386
libgtk2.0-0:i386
libnspr4:i386
libnss3:i386
libopenal1:i386
libpango1.0-0:i386
libpng12-0:i386
libpulse0:i386
libstdc++6:i386
libx11-6:i386
libxext6:i386
libxfixes3:i386
libxi6:i386
libxinerama1:i386
libxrandr2:i386
libxrender1:i386
zlib1g:i386

These are dependencies that are commonly required for games

libsdl1.2debian:i386

Sslouken 2013-02-02 github

I just installed on Fedora as well, and my steamdeps.txt file only has a few dependencies in it.
What's the output of:
ls -l ~/.steam/steam/steamdeps.txt
?

Sslouken 2013-02-02 github

FYI, that Fedora package has a version of steamdeps that doesn't properly check to see if dependencies are installed or even available. Please contact the author and have them fix it.

Zztoufie 2013-02-02 github

-rwxr-xr-x. 1 mzt root 856 Jan 29 13:13 /home/mzt/.steam/steam/steamdeps.txt

Sslouken 2013-02-02 github

Okay, that's the correct file. It doesn't have that long list of dependencies you listed though. It should only have a few.

Sspotrh 2013-02-07 github

This should be fixed in my latest build. 1.0.0.22-2. Sorry for the pain!

Zztoufie 2013-02-07 github

No worries mate, like I said it was a mere irritation but I could still play TF2 :-).

Thank you though for the update, will download tonight and give it a run.

Zztoufie 2013-02-09 github

All good, just did an update and it's back to normal. No more dependency checking window when Steam starts up.

Nothing extracted yet.