Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ RUN mkdir -p /go/bin && chown -R vscode:vscode /go

# Install Node.js 22.15.0
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
apt-get install -y nodejs && \
npm install -g npm@latest
apt-get install -y nodejs

# Set up non-root user and workspace
USER vscode
Expand Down
9 changes: 9 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"features": {
"ghcr.io/devcontainers/features/go:1": {
"version": "1.3.4",
"resolved": "ghcr.io/devcontainers/features/go@sha256:d85e921f91b41340055bb12b325d9d551170ed04b3b832e33530bf42f167c032",
"integrity": "sha256:d85e921f91b41340055bb12b325d9d551170ed04b3b832e33530bf42f167c032"
}
}
}
5 changes: 2 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@
"vscode": {
"extensions": [
"golang.go",
"svelte.svelte-vscode",
"eamodio.gitlens"
"svelte.svelte-vscode"
],
"settings": {
"go.toolsManagement.autoUpdate": true,
"svelte.enable-ts-plugin": true
}
}
},
"postCreateCommand": "go mod tidy && cd frontend && npm install && npm install @sveltejs/vite-plugin-svelte"
"postCreateCommand": "go mod tidy && cd frontend && npm install && npm install @sveltejs/vite-plugin-svelte && npm audit fix"
Comment thread
akirilov marked this conversation as resolved.
}
107 changes: 100 additions & 7 deletions src/steamcmd/steamcmd-helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"slices"
"strings"
"time"

Expand Down Expand Up @@ -293,9 +294,64 @@ func untarWrapper(r io.ReaderAt, _ int64, dest string) error {
return untar(dest, io.NewSectionReader(r, 0, 1<<63-1)) // Use a large size for the section reader
}

type distroFamily int

const (
distroUnknown distroFamily = iota
distroDebian
distroRHEL
)

// parseOSRelease parses a /etc/os-release file into a key-value map.
func parseOSRelease(content string) map[string]string {
fields := make(map[string]string)
for _, line := range strings.Split(content, "\n") {
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
continue
}
fields[parts[0]] = strings.Trim(parts[1], "\"'")
}
return fields
}

// detectDistroFamily reads /etc/os-release and returns the distro family.
// ID is checked first (single value); ID_LIKE is the fallback (space-separated list).
func detectDistroFamily() distroFamily {
data, err := os.ReadFile("/etc/os-release")
if err != nil {
return distroUnknown
}

debianIDs := []string{"ubuntu", "debian", "linuxmint", "pop", "elementary", "raspbian"}
rhelIDs := []string{"rhel", "centos", "fedora", "rocky", "almalinux", "ol"}

fields := parseOSRelease(string(data))

// Check ID first — it's a single value identifying the primary distro.
id := strings.ToLower(fields["ID"])
if slices.Contains(debianIDs, id) {
return distroDebian
}
if slices.Contains(rhelIDs, id) {
return distroRHEL
}

// Fall back to ID_LIKE — a space-separated list of closely related distros.
for _, like := range strings.Fields(strings.ToLower(fields["ID_LIKE"])) {
if slices.Contains(debianIDs, like) {
return distroDebian
}
if slices.Contains(rhelIDs, like) {
return distroRHEL
}
}

return distroUnknown
}

// installRequiredLibraries installs the required libraries for SteamCMD if they are not already installed.
func installRequiredLibraries() error {
// Check if the system is Debian-based
if runtime.GOOS != "linux" {
return nil // Only Linux systems need this
}
Expand All @@ -306,8 +362,19 @@ func installRequiredLibraries() error {
return nil
}

// According to https://developer.valvesoftware.com/wiki/SteamCMD#Manually only lib32gcc-s1 is needed
// List of required libraries
switch detectDistroFamily() {
case distroDebian:
return installRequiredLibrariesDebian()
case distroRHEL:
return installRequiredLibrariesRHEL()
default:
return fmt.Errorf("unsupported Linux distribution: only Ubuntu/Debian and RHEL-based distros are supported")
}
}

// installRequiredLibrariesDebian installs SteamCMD dependencies on Ubuntu/Debian using apt-get.
// According to https://developer.valvesoftware.com/wiki/SteamCMD#Manually only lib32gcc-s1 is needed.
func installRequiredLibrariesDebian() error {
requiredLibs := []string{
"lib32gcc-s1",
//"lib32stdc++6",
Expand All @@ -316,23 +383,49 @@ func installRequiredLibraries() error {
// Check and install each library
for _, lib := range requiredLibs {
// Check if the library is already installed
cmd := exec.Command("dpkg", "-s", lib)
if err := cmd.Run(); err == nil {
if err := exec.Command("dpkg", "-s", lib).Run(); err == nil {
logger.Install.Debug("✅ Library already installed: " + lib + "\n")
continue // Library is already installed, skip to the next one
continue
}

// Library is not installed, attempt to install it
logger.Install.Debug("🔄 Installing library: " + lib + "\n")
installCmd := exec.Command("sudo", "apt-get", "install", "-y", lib)
installCmd.Stdout = os.Stdout
installCmd.Stderr = os.Stderr

if err := installCmd.Run(); err != nil {
return fmt.Errorf("failed to install library %s: %w", lib, err)
}
logger.Install.Debug("✅ Installed library: " + lib + "\n")
}
return nil
}

// installRequiredLibrariesRHEL installs SteamCMD dependencies on RHEL-based distros using dnf.
// libgcc.i686 is the RHEL equivalent of lib32gcc-s1 on Debian-based distros.
func installRequiredLibrariesRHEL() error {
requiredLibs := []string{
"libgcc.i686",
"libstdc++.i686",
}

// Check and install each library
for _, lib := range requiredLibs {
// Check if the library is already installed
if err := exec.Command("rpm", "-q", lib).Run(); err == nil {
logger.Install.Debug("✅ Library already installed: " + lib + "\n")
continue
}

// Library is not installed, attempt to install it
logger.Install.Debug("🔄 Installing library: " + lib + "\n")
installCmd := exec.Command("sudo", "dnf", "install", "-y", lib)
installCmd.Stdout = os.Stdout
installCmd.Stderr = os.Stderr
if err := installCmd.Run(); err != nil {
return fmt.Errorf("failed to install library %s: %w", lib, err)
}
logger.Install.Debug("✅ Installed library: " + lib + "\n")
}
return nil
}
Loading