depot-linux 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +10 -0
  3. data/README.md +56 -0
  4. data/Rakefile +10 -0
  5. data/bin/depot +8 -0
  6. data/bin/depot-gui +14 -0
  7. data/bin/setup-rubyqt6 +72 -0
  8. data/fixtures/assets/download.png +0 -0
  9. data/fixtures/flatpakrefs/org.qbittorrent.qBittorrent.flatpakref +10 -0
  10. data/fixtures/rpms/Modrinth App-0.13.14-1.x86_64.rpm +0 -0
  11. data/lib/depot/app_customizer.rb +152 -0
  12. data/lib/depot/assets.rb +11 -0
  13. data/lib/depot/backends/app_image.rb +210 -0
  14. data/lib/depot/backends/archive.rb +263 -0
  15. data/lib/depot/backends/deb.rb +265 -0
  16. data/lib/depot/backends/flatpak_ref.rb +123 -0
  17. data/lib/depot/backends/rpm.rb +280 -0
  18. data/lib/depot/backends/support.rb +39 -0
  19. data/lib/depot/cli.rb +344 -0
  20. data/lib/depot/desktop_entry.rb +37 -0
  21. data/lib/depot/doctor.rb +59 -0
  22. data/lib/depot/gui/app.rb +23 -0
  23. data/lib/depot/gui/drop_panel.rb +80 -0
  24. data/lib/depot/gui/main_window.rb +1196 -0
  25. data/lib/depot/inspection.rb +52 -0
  26. data/lib/depot/inspector.rb +387 -0
  27. data/lib/depot/installer.rb +54 -0
  28. data/lib/depot/manifest_store.rb +53 -0
  29. data/lib/depot/packages/archive.rb +188 -0
  30. data/lib/depot/packages/deb.rb +262 -0
  31. data/lib/depot/packages/flatpak_ref.rb +90 -0
  32. data/lib/depot/packages/rpm.rb +301 -0
  33. data/lib/depot/paths.rb +57 -0
  34. data/lib/depot/result.rb +13 -0
  35. data/lib/depot/sandbox.rb +285 -0
  36. data/lib/depot/settings.rb +43 -0
  37. data/lib/depot/source_resolver.rb +36 -0
  38. data/lib/depot/uninstaller.rb +90 -0
  39. data/lib/depot/update_downloader.rb +136 -0
  40. data/lib/depot/updater.rb +230 -0
  41. data/lib/depot/util.rb +33 -0
  42. data/lib/depot/version.rb +5 -0
  43. data/lib/depot.rb +21 -0
  44. metadata +139 -0
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "util"
4
+
5
+ module Depot
6
+ class DesktopEntry
7
+ attr_reader :app_id, :name, :exec_path, :icon_name
8
+
9
+ def initialize(app_id:, name:, exec_path:, icon_name: nil)
10
+ @app_id = app_id
11
+ @name = name
12
+ @exec_path = exec_path
13
+ @icon_name = icon_name
14
+ end
15
+
16
+ def contents
17
+ lines = [
18
+ "[Desktop Entry]",
19
+ "Type=Application",
20
+ "Version=1.0",
21
+ "Name=#{escape(name)}",
22
+ "Exec=#{Util.desktop_exec_quote(exec_path)}",
23
+ "Terminal=false",
24
+ "Categories=Utility;",
25
+ "X-Depot-AppID=#{escape(app_id)}"
26
+ ]
27
+ lines << "Icon=#{escape(icon_name)}" if icon_name && !icon_name.empty?
28
+ lines.join("\n") + "\n"
29
+ end
30
+
31
+ private
32
+
33
+ def escape(value)
34
+ value.to_s.gsub("\\", "\\\\\\").gsub("\n", "\\n")
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "manifest_store"
4
+ require_relative "paths"
5
+ require_relative "source_resolver"
6
+
7
+ module Depot
8
+ class Doctor
9
+ TOOLS = %w[flatpak bwrap bsdtar gtk-update-icon-cache update-desktop-database].freeze
10
+
11
+ def initialize(store: ManifestStore.new)
12
+ @store = store
13
+ end
14
+
15
+ def report
16
+ {
17
+ "tools" => TOOLS.to_h { |tool| [tool, command_available?(tool)] },
18
+ "paths" => {
19
+ "data_dir" => Dir.exist?(Paths.data_dir),
20
+ "apps_dir" => Dir.exist?(Paths.apps_dir),
21
+ "manifests_dir" => Dir.exist?(Paths.manifests_dir),
22
+ "desktop_entries_dir" => Dir.exist?(Paths.desktop_entries_dir)
23
+ },
24
+ "manifests" => manifest_checks
25
+ }
26
+ end
27
+
28
+ def healthy?
29
+ report.fetch("manifests").all? { |manifest| manifest.fetch("ok") }
30
+ end
31
+
32
+ private
33
+
34
+ def manifest_checks
35
+ @store.all.map do |manifest|
36
+ issues = []
37
+ issues << "missing installed executable" if missing_path?(manifest["installed_executable"])
38
+ issues << "missing desktop entry" if manifest["desktop_entry"].to_s != "" && !File.exist?(manifest["desktop_entry"])
39
+ source = manifest["install_source"]
40
+ issues << "missing original source" if source.to_s != "" && SourceResolver.resolve(source).nil?
41
+ {
42
+ "app_id" => manifest["app_id"],
43
+ "name" => manifest["display_name"],
44
+ "backend" => manifest["backend"],
45
+ "ok" => issues.empty?,
46
+ "issues" => issues
47
+ }
48
+ end
49
+ end
50
+
51
+ def missing_path?(path)
52
+ path.to_s == "" || !File.exist?(path)
53
+ end
54
+
55
+ def command_available?(command)
56
+ ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).any? { |dir| File.executable?(File.join(dir, command)) }
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "qt6/qtwidgets"
4
+ require_relative "../../depot"
5
+ require_relative "drop_panel"
6
+ require_relative "main_window"
7
+
8
+ module Depot
9
+ module GUI
10
+ module App
11
+ module_function
12
+
13
+ def run
14
+ app = QApplication.new
15
+ QApplication.set_application_name("Depot")
16
+ QApplication.set_organization_name("Depot")
17
+ QApplication.set_window_icon(QIcon.new(Assets.logo_path)) if File.exist?(Assets.logo_path)
18
+ MainWindow.new.show
19
+ app.exec
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Depot
4
+ module GUI
5
+ class DropPanel < RubyQt6::Bando::QFrame
6
+ def initialize(&on_file)
7
+ super()
8
+ @on_file = on_file
9
+ set_accept_drops(true)
10
+ set_object_name("depotDropPanel")
11
+ set_frame_shape(QFrame::StyledPanel)
12
+ set_minimum_height(280)
13
+
14
+ @label = QLabel.new("Drop software here")
15
+ @label.set_alignment(Qt::AlignCenter)
16
+ @label.set_word_wrap(true)
17
+ @label.set_object_name("depotDropTitle")
18
+ @label.set_attribute(Qt::WA_TransparentForMouseEvents)
19
+ @hint = QLabel.new("or choose a package with the file picker")
20
+ @hint.set_alignment(Qt::AlignCenter)
21
+ @hint.set_object_name("depotDropHint")
22
+ @hint.set_attribute(Qt::WA_TransparentForMouseEvents)
23
+
24
+ layout = QVBoxLayout.new
25
+ layout.add_stretch
26
+ layout.add_widget(@label)
27
+ layout.add_widget(@hint)
28
+ layout.add_stretch
29
+ set_layout(layout)
30
+ end
31
+
32
+ def drag_enter_event(event)
33
+ if file_from_event(event)
34
+ @hint.set_text("Release to inspect this software")
35
+ event.accept_proposed_action
36
+ else
37
+ event.ignore
38
+ end
39
+ end
40
+
41
+ def drag_leave_event(event)
42
+ @hint.set_text("or choose a package with the file picker")
43
+ end
44
+
45
+ def drag_move_event(event)
46
+ if file_from_event(event)
47
+ event.accept_proposed_action
48
+ else
49
+ event.ignore
50
+ end
51
+ end
52
+
53
+ def drop_event(event)
54
+ path = file_from_event(event)
55
+ return event.ignore unless path
56
+
57
+ @hint.set_text("or choose a package with the file picker")
58
+ @on_file.call(path)
59
+ event.accept_proposed_action
60
+ end
61
+
62
+ private
63
+
64
+ def file_from_event(event)
65
+ mime = event.mime_data
66
+ return nil unless mime.respond_to?(:has_urls) && mime.has_urls
67
+
68
+ url = mime.urls.first
69
+ return nil unless url
70
+
71
+ local = url.to_local_file.to_s
72
+ return nil if local.empty?
73
+
74
+ local
75
+ rescue StandardError
76
+ nil
77
+ end
78
+ end
79
+ end
80
+ end