File: install.go

package info (click to toggle)
debpkg 0.0.1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 80 kB
  • sloc: makefile: 33
file content (127 lines) | stat: -rw-r--r-- 3,201 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package cmd

import (
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"

	"salsa.debian.org/otto/debpkg/internal/apt"
	"salsa.debian.org/otto/debpkg/internal/download"
	"salsa.debian.org/otto/debpkg/internal/ui"
)

var installCmd = &cobra.Command{
	Use:   "install <url>",
	Short: "Download and install a Debian package from URL",
	Long: `Download a .deb package from the specified URL and install it using apt.

The URL must point to a valid .deb file. The file will be downloaded to a
temporary location and then installed using 'sudo apt install'.`,
	Example: `  debpkg install https://example.com/package.deb
  debpkg install https://github.com/user/repo/releases/download/v1.0.0/package.deb`,
	Args: cobra.ExactArgs(1),
	RunE: runInstall,
}

func init() {
	rootCmd.AddCommand(installCmd)
}

func runInstall(cmd *cobra.Command, args []string) error {
	packageURL := args[0]

	// Validate URL
	if err := validateURL(packageURL); err != nil {
		PrintError(fmt.Sprintf("Invalid URL: %v", err))
		return err
	}

	// Check if running with appropriate permissions
	if err := apt.CheckPermissions(); err != nil {
		PrintError(err.Error())
		return err
	}

	// Extract filename from URL
	filename, err := extractFilename(packageURL)
	if err != nil {
		PrintError(fmt.Sprintf("Could not determine filename from URL: %v", err))
		return err
	}

	// Create temporary directory
	tempDir, err := os.MkdirTemp("", "debpkg-*")
	if err != nil {
		PrintError(fmt.Sprintf("Failed to create temporary directory: %v", err))
		return err
	}
	defer os.RemoveAll(tempDir)

	debFile := filepath.Join(tempDir, filename)

	// Show what we're about to do
	ui.ShowHeader("Installing Debian Package")
	PrintInfo(fmt.Sprintf("URL: %s", packageURL))
	PrintInfo(fmt.Sprintf("File: %s", filename))
	fmt.Println()

	// Download the file
	PrintInfo("Downloading package...")
	if err := download.File(packageURL, debFile); err != nil {
		PrintError(fmt.Sprintf("Download failed: %v", err))
		return err
	}
	PrintSuccess("Package downloaded successfully")
	fmt.Println()

	// Install the package
	PrintInfo("Installing package with apt...")
	if err := apt.InstallDeb(debFile); err != nil {
		PrintError(fmt.Sprintf("Installation failed: %v", err))
		return err
	}

	PrintSuccess("Package installed successfully!")
	return nil
}

func validateURL(rawURL string) error {
	parsedURL, err := url.Parse(rawURL)
	if err != nil {
		return fmt.Errorf("malformed URL: %w", err)
	}

	if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
		return fmt.Errorf("only HTTP and HTTPS URLs are supported")
	}

	if parsedURL.Host == "" {
		return fmt.Errorf("URL must have a host")
	}

	// Check if URL looks like it points to a .deb file
	path := parsedURL.Path
	if !strings.HasSuffix(strings.ToLower(path), ".deb") {
		return fmt.Errorf("URL must point to a .deb file")
	}

	return nil
}

func extractFilename(rawURL string) (string, error) {
	parsedURL, err := url.Parse(rawURL)
	if err != nil {
		return "", err
	}

	filename := filepath.Base(parsedURL.Path)
	if filename == "" || filename == "." || filename == "/" {
		return "", fmt.Errorf("could not extract filename from URL")
	}

	return filename, nil
}