按安装状态过滤 Firefox 离线包

main
wangqiyang 3 days ago
parent 0cb69ed640
commit ebb079215b

@ -46,6 +46,12 @@ var forbiddenFirefoxDebPackages = map[string]struct{}{
"util-linux": {}, "util-linux": {},
} }
type firefoxBundleInstallPlan struct {
TotalPackageCount int
HasFirefoxPackage bool
BaseSystemPackages []string
}
func isFirefoxUsable() bool { func isFirefoxUsable() bool {
cmd := exec.Command("firefox", "--version") cmd := exec.Command("firefox", "--version")
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
@ -82,10 +88,12 @@ func isExecutableFile(path string) bool {
func installFirefox() error { func installFirefox() error {
bundlePath := firefoxBundlePath() bundlePath := firefoxBundlePath()
if err := validateFirefoxBundle(bundlePath); err != nil { plan, err := validateFirefoxBundle(bundlePath)
if err != nil {
kioskErrorf("firefox install refused bundle=%s err=%v", bundlePath, err) kioskErrorf("firefox install refused bundle=%s err=%v", bundlePath, err)
return err return err
} }
baseSystemPackages := strings.Join(plan.BaseSystemPackages, " ")
var p struct { var p struct {
DebPkgPath string `json:"DebPkgPath"` DebPkgPath string `json:"DebPkgPath"`
@ -107,7 +115,7 @@ echo "skip automatic dpkg purge to avoid touching base system packages"
echo "" echo ""
echo "=== clean previous offline bundle files ===" echo "=== clean previous offline bundle files ==="
rm -rf /opt/firefox-deb /opt/firefox-deb.tar.gz 2>/dev/null rm -rf /opt/firefox-deb /opt/firefox-installable /opt/firefox-deb.tar.gz 2>/dev/null
echo "" echo ""
echo "=== start Firefox install ===" echo "=== start Firefox install ==="
@ -119,20 +127,84 @@ echo "2. extract offline bundle..."
cd /opt && tar -xzvf firefox-deb.tar.gz || { echo "error: extract offline bundle failed"; exit 1; } cd /opt && tar -xzvf firefox-deb.tar.gz || { echo "error: extract offline bundle failed"; exit 1; }
echo "" echo ""
echo "3. install Firefox deb packages..." echo "3. filter Firefox deb packages..."
cd /opt/firefox-deb && sudo dpkg -i *.deb || { echo "error: install Firefox deb packages failed"; exit 1; } base_system_packages=%s
mkdir -p /opt/firefox-installable
selected_count=0
skipped_installed_count=0
selected_missing_base_count=0
selected_regular_count=0
firefox_selected=0
select_deb() {
cp -v "$deb" /opt/firefox-installable/
selected_count=$((selected_count + 1))
}
for deb in /opt/firefox-deb/*.deb; do
[ -e "$deb" ] || continue
file=$(basename "$deb")
pkg=${file%%_*}
pkg=${pkg%%.deb}
status=$(dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null || true)
installed=0
if [ "$status" = "install ok installed" ]; then
installed=1
fi
if [ "$pkg" = "firefox" ]; then
select_deb
firefox_selected=1
continue
fi
case " $base_system_packages " in
*" $pkg "*)
if [ "$installed" -eq 1 ]; then
echo "skip installed base system package: $file"
skipped_installed_count=$((skipped_installed_count + 1))
continue
fi
echo "select missing base system package: $file"
select_deb
selected_missing_base_count=$((selected_missing_base_count + 1))
continue
;;
esac
if [ "$installed" -eq 1 ]; then
echo "skip installed package: $file"
skipped_installed_count=$((skipped_installed_count + 1))
continue
fi
select_deb
selected_regular_count=$((selected_regular_count + 1))
done
echo "selected packages: $selected_count, selected missing base: $selected_missing_base_count, selected regular: $selected_regular_count, skipped installed: $skipped_installed_count"
if [ "$selected_count" -eq 0 ]; then
echo "error: no packages selected for install"
exit 1
fi
if [ "$firefox_selected" -ne 1 ]; then
echo "error: Firefox deb package was not selected"
exit 1
fi
echo "" echo ""
echo "4. verify Firefox..." echo "4. install selected Firefox packages..."
cd /opt/firefox-installable && sudo dpkg -i ./*.deb || { echo "error: install selected Firefox deb packages failed"; exit 1; }
echo ""
echo "5. verify Firefox..."
firefox --version || { echo "error: Firefox verification failed"; exit 1; } firefox --version || { echo "error: Firefox verification failed"; exit 1; }
echo "" echo ""
echo "=== Firefox install complete ===" echo "=== Firefox install complete ==="
`, shellQuote(bundlePath))) `, shellQuote(bundlePath), shellQuote(baseSystemPackages)))
command.Stdout = os.Stdout command.Stdout = os.Stdout
command.Stderr = os.Stderr command.Stderr = os.Stderr
err := command.Run() err = command.Run()
if err != nil { if err != nil {
kioskErrorf("firefox install command failed err=%v", err) kioskErrorf("firefox install command failed err=%v", err)
return err return err
@ -173,22 +245,38 @@ func firefoxBundlePath() string {
return filepath.Join(system.GetPathOfProgram(), g.Config().Firefox.DebPkgPath, g.Config().Firefox.DebPkgName) return filepath.Join(system.GetPathOfProgram(), g.Config().Firefox.DebPkgPath, g.Config().Firefox.DebPkgName)
} }
func validateFirefoxBundle(bundlePath string) error { func validateFirefoxBundle(bundlePath string) (firefoxBundleInstallPlan, error) {
packages, err := firefoxBundlePackageNames(bundlePath) packages, err := firefoxBundlePackageNames(bundlePath)
if err != nil { if err != nil {
return fmt.Errorf("read firefox bundle packages: %w", err) return firefoxBundleInstallPlan{}, fmt.Errorf("read firefox bundle packages: %w", err)
} }
if len(packages) == 0 { if len(packages) == 0 {
return fmt.Errorf("firefox bundle has no deb packages") return firefoxBundleInstallPlan{}, fmt.Errorf("firefox bundle has no deb packages")
} }
blocked := unsafeFirefoxDebPackages(packages) plan := firefoxBundleInstallPlanFromPackages(packages)
if len(blocked) > 0 { if !plan.HasFirefoxPackage {
return fmt.Errorf("firefox bundle contains blocked base system packages: %s", strings.Join(blocked, ", ")) return firefoxBundleInstallPlan{}, fmt.Errorf("firefox bundle has no firefox deb package")
} }
kioskInfof("firefox bundle validation passed bundle=%s packages=%d", bundlePath, len(packages)) if len(plan.BaseSystemPackages) > 0 {
return nil kioskWarnf("firefox bundle contains base system packages; installed ones will be skipped and missing ones may be installed packages=%s", strings.Join(plan.BaseSystemPackages, ", "))
}
kioskInfof("firefox bundle validation passed bundle=%s totalPackages=%d baseSystemPackages=%d hasFirefox=%v", bundlePath, plan.TotalPackageCount, len(plan.BaseSystemPackages), plan.HasFirefoxPackage)
return plan, nil
}
func firefoxBundleInstallPlanFromPackages(packages []string) firefoxBundleInstallPlan {
plan := firefoxBundleInstallPlan{
TotalPackageCount: len(packages),
BaseSystemPackages: unsafeFirefoxDebPackages(packages),
}
for _, name := range packages {
if name == "firefox" {
plan.HasFirefoxPackage = true
}
}
return plan
} }
func firefoxBundlePackageNames(bundlePath string) ([]string, error) { func firefoxBundlePackageNames(bundlePath string) ([]string, error) {

@ -35,6 +35,29 @@ func TestUnsafeFirefoxDebPackages(t *testing.T) {
} }
} }
func TestFirefoxBundleInstallPlanDetectsBasePackages(t *testing.T) {
packages := []string{
"firefox",
"libgtk-3-0",
"dpkg",
"coreutils",
"libc6",
"tar",
}
plan := firefoxBundleInstallPlanFromPackages(packages)
wantBlocked := []string{"coreutils", "dpkg", "libc6", "tar"}
if !plan.HasFirefoxPackage {
t.Fatal("plan should detect firefox package")
}
if plan.TotalPackageCount != len(packages) {
t.Fatalf("TotalPackageCount = %d, want %d", plan.TotalPackageCount, len(packages))
}
if !stringSlicesEqual(plan.BaseSystemPackages, wantBlocked) {
t.Fatalf("BaseSystemPackages = %v, want %v", plan.BaseSystemPackages, wantBlocked)
}
}
func stringSlicesEqual(left []string, right []string) bool { func stringSlicesEqual(left []string, right []string) bool {
if len(left) != len(right) { if len(left) != len(right) {
return false return false

Loading…
Cancel
Save