Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.17% covered (warning)
73.17%
30 / 41
80.00% covered (warning)
80.00%
8 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
InstallTarget
73.17% covered (warning)
73.17%
30 / 41
80.00% covered (warning)
80.00%
8 / 10
24.26
0.00% covered (danger)
0.00%
0 / 1
 __construct
16.67% covered (danger)
16.67%
2 / 12
0.00% covered (danger)
0.00%
0 / 1
8.21
 current
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 from
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 normalizeArchitecture
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 detectDistro
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
4.13
 architecture
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 distro
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 withArchitecture
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 withDistro
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 cacheKey
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Install;
10
11use InvalidArgumentException;
12use OCA\Libresign\Vendor\LibreSign\WhatOSAmI\OperatingSystem;
13
14/**
15 * Immutable description of the platform a dependency is installed for.
16 *
17 * Keeping architecture and distribution together prevents install, verification
18 * and background processes from silently using different environment values.
19 */
20final readonly class InstallTarget {
21    public const array SUPPORTED_ARCHITECTURES = [
22        'x86_64',
23        'aarch64',
24    ];
25
26    public const array SUPPORTED_DISTROS = [
27        'linux',
28        'alpine-linux',
29    ];
30
31    public function __construct(
32        private string $architecture,
33        private string $distro,
34    ) {
35        if (!in_array($architecture, self::SUPPORTED_ARCHITECTURES, true)) {
36            throw new InvalidArgumentException(sprintf(
37                'Unsupported architecture "%s". Supported architectures: %s',
38                $architecture,
39                implode(', ', self::SUPPORTED_ARCHITECTURES),
40            ));
41        }
42        if (!in_array($distro, self::SUPPORTED_DISTROS, true)) {
43            throw new InvalidArgumentException(sprintf(
44                'Unsupported distribution "%s". Supported distributions: %s',
45                $distro,
46                implode(', ', self::SUPPORTED_DISTROS),
47            ));
48        }
49    }
50
51    public static function current(): self {
52        return new self(
53            self::normalizeArchitecture(php_uname('m')),
54            self::detectDistro(),
55        );
56    }
57
58    public static function from(
59        ?string $architecture = null,
60        ?string $distro = null,
61    ): self {
62        return new self(
63            self::normalizeArchitecture($architecture ?: php_uname('m')),
64            $distro ?: self::detectDistro(),
65        );
66    }
67
68    public static function normalizeArchitecture(string $architecture): string {
69        return match (strtolower(trim($architecture))) {
70            'x86_64', 'amd64' => 'x86_64',
71            'aarch64', 'arm64' => 'aarch64',
72            default => throw new InvalidArgumentException(sprintf(
73                'Unsupported architecture "%s". Supported architectures: %s',
74                $architecture,
75                implode(', ', self::SUPPORTED_ARCHITECTURES),
76            )),
77        };
78    }
79
80    private static function detectDistro(): string {
81        try {
82            $distribution = (new OperatingSystem())->getLinuxDistribution();
83            if (is_string($distribution) && strtolower($distribution) === 'alpine') {
84                return 'alpine-linux';
85            }
86        } catch (\Exception) {
87        }
88
89        return 'linux';
90    }
91
92    public function architecture(): string {
93        return $this->architecture;
94    }
95
96    public function distro(): string {
97        return $this->distro;
98    }
99
100    public function withArchitecture(string $architecture): self {
101        return new self(self::normalizeArchitecture($architecture), $this->distro);
102    }
103
104    public function withDistro(string $distro): self {
105        return new self($this->architecture, $distro);
106    }
107    public function cacheKey(string $resource): string {
108        if ($resource === 'java') {
109            return $resource . ':' . $this->architecture . ':' . $this->distro;
110        }
111        return $resource . ':' . $this->architecture;
112    }
113
114}