Implemented an installer user interface and backend
This commit is contained in:
parent
3d3b794b1d
commit
ac46b45f05
1
citadel-installer-ui/.gitignore
vendored
Normal file
1
citadel-installer-ui/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
750
citadel-installer-ui/Cargo.lock
generated
Normal file
750
citadel-installer-ui/Cargo.lock
generated
Normal file
@ -0,0 +1,750 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
|
||||
|
||||
[[package]]
|
||||
name = "atk"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/gtk-rs/atk#9e3eb26374a4156297280769bd64102a4bebcad7"
|
||||
dependencies = [
|
||||
"atk-sys",
|
||||
"bitflags",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atk-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "cairo-rs"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/gtk-rs/cairo#2d5a1cb0003176224004c4e826929520bd1227f9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cairo-sys-rs",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cairo-sys-rs"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/cairo#2d5a1cb0003176224004c4e826929520bd1227f9"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "citadel-installer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dbus",
|
||||
"failure",
|
||||
"gdk",
|
||||
"gdk-pixbuf",
|
||||
"gio",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gtk",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dbus"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cd9e78c210146a1860f897db03412fd5091fd73100778e43ee255cca252cf32"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libdbus-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f"
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"failure_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/gtk-rs/gdk#fa2fb7819b13daa4fac55bd93ac217691cbd9dc8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cairo-rs",
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf",
|
||||
"gdk-sys",
|
||||
"gio",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-pixbuf"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/gtk-rs/gdk-pixbuf#2502779ebc0a81c8a03a64e1fbf576b16eb8b91d"
|
||||
dependencies = [
|
||||
"gdk-pixbuf-sys",
|
||||
"gio",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-pixbuf-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"pkg-config",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/gtk-rs/gio#809e580c56f1434327a3c81af49cb75baea5faf7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"futures",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/glib#200d34eab3421b53d0688f02093932e14540f411"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"glib-macros",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-macros"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/glib#200d34eab3421b53d0688f02093932e14540f411"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"itertools",
|
||||
"proc-macro-crate",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/gtk-rs/gtk#9b9cf0f623bd74bf71459f639beac2f6f26c163e"
|
||||
dependencies = [
|
||||
"atk",
|
||||
"bitflags",
|
||||
"cairo-rs",
|
||||
"cairo-sys-rs",
|
||||
"cc",
|
||||
"gdk",
|
||||
"gdk-pixbuf",
|
||||
"gdk-pixbuf-sys",
|
||||
"gdk-sys",
|
||||
"gio",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gtk-sys",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pango",
|
||||
"pango-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"atk-sys",
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf-sys",
|
||||
"gdk-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/gtk-rs/pango#b98784c9881f0def29c8e3bda6d2754e41f96b0f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pango-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango-sys"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gtk-rs/sys#56e03c021c393e1cf3f148005b348ac5a8a0ab72"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
|
||||
dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.115"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"pkg-config",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
15
citadel-installer-ui/Cargo.toml
Normal file
15
citadel-installer-ui/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "citadel-installer-ui"
|
||||
version = "0.1.0"
|
||||
authors = ["David McKinney <mckinney@subgraph.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libcitadel = { path = "../libcitadel" }
|
||||
failure = "0.1.8"
|
||||
dbus = "0.8.4"
|
||||
gtk = { version = "0.9.0", features = ["v3_16"] }
|
||||
gio = "0.9.1"
|
||||
glib = "0.10.2"
|
||||
gdk = "0.13.2"
|
||||
pango = "0.9.1"
|
23
citadel-installer-ui/README.md
Normal file
23
citadel-installer-ui/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Citadel Installer UI design
|
||||
|
||||
The installer is required to run in Wayland but also perform privileged
|
||||
operations. This necessitated splitting the installer into the following
|
||||
pieces:
|
||||
|
||||
- A user interface that can be run by a non-privileged user in their Wayland
|
||||
session
|
||||
- A back-end server that runs in the background to perform the privileged
|
||||
operations on behalf of the user
|
||||
|
||||
The user interface communicates with the back-end over DBUS. There are a simple
|
||||
set of messages/signals to initiate the install process and provide updates to
|
||||
the interface about the success/failure of each install stage.
|
||||
|
||||
Both the user interface can only be run in install/live mode. The user
|
||||
interface will start automatically when the computer is booted in install/live
|
||||
mode, however, the user can close the interface and test out the system in
|
||||
live mode to determine if it is compatible with their hardware, if they want to
|
||||
actually perform an install, etc. If the user decides to install the system,
|
||||
they can simply re-open the user interface while still in live mode.
|
||||
|
||||
|
126
citadel-installer-ui/data/citadel_password_page.ui
Normal file
126
citadel-installer-ui/data/citadel_password_page.ui
Normal file
@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkBox" id="citadel_password_page">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="citadel_password_page_header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="margin_bottom">40</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="citadel_password_header_icon">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="pixel_size">96</property>
|
||||
<property name="icon_name">dialog-password-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="citadel_password_header_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Set Citadel User Password</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="citadel_password_grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">40</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="citadel_password_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Password: </property>
|
||||
<property name="justify">right</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="citadel_password_confirm_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Confirm Password:</property>
|
||||
<property name="justify">right</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="citadel_password_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="citadel_password_confirm_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="citadel_password_status_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
101
citadel-installer-ui/data/confirm_install_page.ui
Normal file
101
citadel-installer-ui/data/confirm_install_page.ui
Normal file
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkBox" id="confirm_install_page">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="confirm_install_page_header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="margin_bottom">40</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="confirm_install_page_header_icon">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="pixel_size">96</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="icon_name">system-os-installer</property>
|
||||
<property name="icon_size">6</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="confirm_install_page_header_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Install Citadel</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="confirm_install_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="confirm_install_label_1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">You are about to install Citadel to the following destination:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="confirm_install_label_3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="confirm_install_label_2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Press the <b>Apply</b> button to continue with the installation. </property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="margin_top">20</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
80
citadel-installer-ui/data/install_destination_page.ui
Normal file
80
citadel-installer-ui/data/install_destination_page.ui
Normal file
@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkBox" id="install_destination_page">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="install_destination_page_header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="margin_bottom">40</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="name">install_destination_header_icon</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="pixel_size">96</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="icon_name">drive-harddisk-symbolic</property>
|
||||
<property name="icon_size">6</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="name">install_destination_header_label</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Choose an installation destination</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="install_destination_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">40</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="install_destination_listbox">
|
||||
<property name="width_request">600</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">18</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
88
citadel-installer-ui/data/install_page.ui
Normal file
88
citadel-installer-ui/data/install_page.ui
Normal file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkTextBuffer" id="install_textbuffer">
|
||||
<property name="text" translatable="yes">
|
||||
</property>
|
||||
</object>
|
||||
<object class="GtkBox" id="install_page">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="margin_bottom">40</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="margin_bottom">96</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="install_header_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Installing Citadel</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkProgressBar" id="install_progress">
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_bottom">40</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="install_scrolled_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<property name="min_content_width">200</property>
|
||||
<property name="min_content_height">200</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="install_textview">
|
||||
<property name="width_request">600</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="wrap_mode">word-char</property>
|
||||
<property name="indent">10</property>
|
||||
<property name="cursor_visible">False</property>
|
||||
<property name="buffer">install_textbuffer</property>
|
||||
<property name="accepts_tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
126
citadel-installer-ui/data/luks_password_page.ui
Normal file
126
citadel-installer-ui/data/luks_password_page.ui
Normal file
@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkBox" id="luks_password_page">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="luks_password_page_header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="margin_bottom">40</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="luks_password_header_icon">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">24</property>
|
||||
<property name="pixel_size">96</property>
|
||||
<property name="icon_name">dialog-password-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="luks_password_header_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Set a disk encryption password</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="luks_password_grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">40</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="luks_password_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Password: </property>
|
||||
<property name="justify">right</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="luks_password_confirm_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Confirm Password:</property>
|
||||
<property name="justify">right</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="luks_password_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="luks_password_confirm_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="luks_password_status_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
22
citadel-installer-ui/data/style.css
Normal file
22
citadel-installer-ui/data/style.css
Normal file
@ -0,0 +1,22 @@
|
||||
button.default:not(disabled) {
|
||||
background: #027b40;
|
||||
color: #D1D7d7;
|
||||
}
|
||||
|
||||
button.default:disabled {
|
||||
background: #D1D7d7;
|
||||
color: #929595;
|
||||
}
|
||||
|
||||
button {
|
||||
background: #D1D7d7;
|
||||
}
|
||||
|
||||
headerbar {
|
||||
background: #3C4141;
|
||||
}
|
||||
|
||||
text {
|
||||
background: #4C575C;
|
||||
color: #D1D7D7;
|
||||
}
|
58
citadel-installer-ui/data/welcome_page.ui
Normal file
58
citadel-installer-ui/data/welcome_page.ui
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkBox" id="welcome_page">
|
||||
<property name="name">welcome_page</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="welcome_header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">120</property>
|
||||
<property name="margin_bottom">40</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="welcome_header_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Welcome to the Citadel installer.</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="welcome_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">40</property>
|
||||
<property name="label" translatable="yes">To install Citadel on your computer, press <b>Next</b>.
|
||||
|
||||
To continue trying Citadel without installing it, press <b>Cancel</b>.
|
||||
|
||||
If you decide to install Citadel after trying it out, just re-open this application.
|
||||
</property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
48
citadel-installer-ui/src/builder.rs
Normal file
48
citadel-installer-ui/src/builder.rs
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
use gtk::prelude::*;
|
||||
use crate::{Error, Result};
|
||||
|
||||
pub struct Builder {
|
||||
builder: gtk::Builder,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new(source: &str) -> Self {
|
||||
let builder = gtk::Builder::from_string(source);
|
||||
Builder { builder }
|
||||
}
|
||||
|
||||
fn ok_or_err<T>(type_name: &str, name: &str, object: Option<T>) -> Result<T> {
|
||||
object.ok_or(Error::Builder(format!("failed to load {} {}", type_name, name)))
|
||||
}
|
||||
|
||||
pub fn get_entry(&self, name: &str) -> Result<gtk::Entry> {
|
||||
Self::ok_or_err("GtkEntry", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_box(&self, name: &str) -> Result<gtk::Box> {
|
||||
Self::ok_or_err("GtkBox", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn get_label(&self, name: &str) -> Result<gtk::Label> {
|
||||
Self::ok_or_err("GtkLabel", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_listbox(&self, name: &str) -> Result<gtk::ListBox> {
|
||||
Self::ok_or_err("GtkListBox", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_progress_bar(&self, name: &str) -> Result<gtk::ProgressBar> {
|
||||
Self::ok_or_err("GtkProgressBar", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_textview(&self, name: &str) -> Result<gtk::TextView> {
|
||||
Self::ok_or_err("GtkTextView", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_scrolled_window(&self, name: &str) -> Result<gtk::ScrolledWindow> {
|
||||
Self::ok_or_err("GtkScrolledWindow", name, self.builder.get_object(name))
|
||||
}
|
||||
}
|
207
citadel-installer-ui/src/dbus_client.rs
Normal file
207
citadel-installer-ui/src/dbus_client.rs
Normal file
@ -0,0 +1,207 @@
|
||||
use dbus::arg;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerInstallCompleted {
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerInstallCompleted {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerInstallCompleted {
|
||||
fn read(_i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerInstallCompleted {})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerInstallCompleted {
|
||||
const NAME: &'static str = "InstallCompleted";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerRunInstallStarted {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerRunInstallStarted {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerRunInstallStarted {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerRunInstallStarted {
|
||||
text: i.read()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerRunInstallStarted {
|
||||
const NAME: &'static str = "RunInstallStarted";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerDiskPartitioned {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerDiskPartitioned {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerDiskPartitioned {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerDiskPartitioned {
|
||||
text: i.read()?
|
||||
//sender,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerDiskPartitioned {
|
||||
const NAME: &'static str = "DiskPartitioned";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerLvmSetup {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerLvmSetup {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerLvmSetup {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerLvmSetup {
|
||||
text: i.read()?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerLvmSetup {
|
||||
const NAME: &'static str = "LvmSetup";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerLuksSetup {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerLuksSetup {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerLuksSetup {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerLuksSetup {
|
||||
text: i.read()?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerLuksSetup {
|
||||
const NAME: &'static str = "LuksSetup";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerBootSetup {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerBootSetup {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerBootSetup {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerBootSetup {
|
||||
text: i.read()?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerBootSetup {
|
||||
const NAME: &'static str = "BootSetup";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerStorageCreated {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerStorageCreated {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerStorageCreated {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerStorageCreated {
|
||||
//sender,
|
||||
text: i.read()?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerStorageCreated {
|
||||
const NAME: &'static str = "StorageCreated";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerRootfsInstalled {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerRootfsInstalled {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerRootfsInstalled {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerRootfsInstalled {
|
||||
text: i.read()?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerRootfsInstalled {
|
||||
const NAME: &'static str = "RootfsInstalled";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComSubgraphInstallerManagerInstallFailed {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for ComSubgraphInstallerManagerInstallFailed {
|
||||
fn append(&self, _: &mut arg::IterAppend) {
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for ComSubgraphInstallerManagerInstallFailed {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(ComSubgraphInstallerManagerInstallFailed {
|
||||
text: i.read()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for ComSubgraphInstallerManagerInstallFailed {
|
||||
const NAME: &'static str = "InstallFailed";
|
||||
const INTERFACE: &'static str = "com.subgraph.installer.Manager";
|
||||
}
|
11
citadel-installer-ui/src/error.rs
Normal file
11
citadel-installer-ui/src/error.rs
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
use std::result;
|
||||
|
||||
use dbus;
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Dbus(dbus::Error),
|
||||
Builder(String),
|
||||
}
|
43
citadel-installer-ui/src/main.rs
Normal file
43
citadel-installer-ui/src/main.rs
Normal file
@ -0,0 +1,43 @@
|
||||
#![allow(deprecated)]
|
||||
#[macro_use] extern crate glib;
|
||||
use gtk::prelude::*;
|
||||
use gio::prelude::*;
|
||||
use std::env::args;
|
||||
mod ui;
|
||||
mod builder;
|
||||
mod error;
|
||||
mod rowdata;
|
||||
mod dbus_client;
|
||||
use libcitadel::CommandLine;
|
||||
use ui::Ui;
|
||||
|
||||
pub use error::{Result,Error};
|
||||
|
||||
fn main() {
|
||||
let application =
|
||||
gtk::Application::new(Some("com.subgraph.citadel-installer"), Default::default())
|
||||
.expect("Initialization failed...");
|
||||
|
||||
application.connect_activate(|app| {
|
||||
if !(CommandLine::live_mode() || CommandLine::install_mode()) {
|
||||
let dialog = gtk::MessageDialog::new(
|
||||
None::<>k::Window>,
|
||||
gtk::DialogFlags::empty(),
|
||||
gtk::MessageType::Error,
|
||||
gtk::ButtonsType::Cancel,
|
||||
"Citadel Installer can only be run during install or live mode");
|
||||
dialog.run();
|
||||
} else {
|
||||
match Ui::build(app) {
|
||||
Ok(ui) => {
|
||||
ui.assistant.show_all();
|
||||
ui.start();
|
||||
},
|
||||
Err(err) => {
|
||||
println!("Could not start application: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
application.run(&args().collect::<Vec<_>>());
|
||||
}
|
156
citadel-installer-ui/src/rowdata.rs
Normal file
156
citadel-installer-ui/src/rowdata.rs
Normal file
@ -0,0 +1,156 @@
|
||||
|
||||
use gio::prelude::*;
|
||||
use std::fmt;
|
||||
|
||||
pub mod row_data {
|
||||
|
||||
use super::*;
|
||||
|
||||
use glib::subclass;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::*;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct RowData {
|
||||
model: RefCell<Option<String>>,
|
||||
path: RefCell<Option<String>>,
|
||||
size: RefCell<Option<String>>,
|
||||
removable: RefCell<bool>,
|
||||
}
|
||||
|
||||
static PROPERTIES: [subclass::Property; 4] = [
|
||||
subclass::Property("model", |name| {
|
||||
glib::ParamSpec::string(
|
||||
name,
|
||||
"Model",
|
||||
"Model",
|
||||
None, // Default value
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("path", |name| {
|
||||
glib::ParamSpec::string(
|
||||
name,
|
||||
"Path",
|
||||
"Path",
|
||||
None, // Default value
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("size", |name| {
|
||||
glib::ParamSpec::string(
|
||||
name,
|
||||
"Size",
|
||||
"Size",
|
||||
None, // Default value
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("removable", |name| {
|
||||
glib::ParamSpec::boolean(
|
||||
name,
|
||||
"Removable",
|
||||
"Removable",
|
||||
false, // Default value
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
];
|
||||
|
||||
impl ObjectSubclass for RowData {
|
||||
const NAME: &'static str = "RowData";
|
||||
type ParentType = glib::Object;
|
||||
type Instance = subclass::simple::InstanceStruct<Self>;
|
||||
type Class = subclass::simple::ClassStruct<Self>;
|
||||
|
||||
glib_object_subclass!();
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.install_properties(&PROPERTIES);
|
||||
}
|
||||
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
model: RefCell::new(None),
|
||||
path: RefCell::new(None),
|
||||
size: RefCell::new(None),
|
||||
removable: RefCell::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for RowData {
|
||||
glib_object_impl!();
|
||||
|
||||
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
|
||||
let prop = &PROPERTIES[id];
|
||||
|
||||
match *prop {
|
||||
subclass::Property("model", ..) => {
|
||||
let model = value
|
||||
.get()
|
||||
.expect("type conformity checked by `Object::set_property`");
|
||||
self.model.replace(model);
|
||||
}
|
||||
subclass::Property("path", ..) => {
|
||||
let path = value
|
||||
.get()
|
||||
.expect("type conformity checked by `Object::set_property`");
|
||||
self.path.replace(path);
|
||||
}
|
||||
subclass::Property("size", ..) => {
|
||||
let size = value
|
||||
.get()
|
||||
.expect("type conformity checked by `Object::set_property`");
|
||||
self.size.replace(size);
|
||||
}
|
||||
subclass::Property("removable", ..) => {
|
||||
let removable = value
|
||||
.get_some()
|
||||
.expect("type conformity checked by `Object::set_property`");
|
||||
self.removable.replace(removable);
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||
let prop = &PROPERTIES[id];
|
||||
|
||||
match *prop {
|
||||
subclass::Property("model", ..) => Ok(self.model.borrow().to_value()),
|
||||
subclass::Property("path", ..) => Ok(self.path.borrow().to_value()),
|
||||
subclass::Property("size", ..) => Ok(self.size.borrow().to_value()),
|
||||
subclass::Property("removable", ..) => Ok(self.removable.borrow().to_value()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib_wrapper! {
|
||||
pub struct RowData(Object<subclass::simple::InstanceStruct<imp::RowData>, subclass::simple::ClassStruct<imp::RowData>, RowDataClass>);
|
||||
|
||||
match fn {
|
||||
get_type => || imp::RowData::get_type().to_glib(),
|
||||
}
|
||||
}
|
||||
|
||||
impl RowData {
|
||||
pub fn new(model: &str, path: &str, size: &str, removable: bool) -> RowData {
|
||||
glib::Object::new(Self::static_type(), &[("model", &model), ("path", &path), ("size", &size), ("removable", &removable)])
|
||||
.expect("Failed to create row data")
|
||||
.downcast()
|
||||
.expect("Created row data is of wrong type")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RowData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self.1)
|
||||
}
|
||||
}
|
||||
}
|
420
citadel-installer-ui/src/ui.rs
Normal file
420
citadel-installer-ui/src/ui.rs
Normal file
@ -0,0 +1,420 @@
|
||||
use gtk::prelude::*;
|
||||
|
||||
use gio::prelude::*;
|
||||
use dbus::Message;
|
||||
use std::time::Duration;
|
||||
use std::thread;
|
||||
use std::collections::HashMap;
|
||||
use dbus::blocking::{Connection, Proxy};
|
||||
use crate::builder::*;
|
||||
use crate::rowdata::row_data::RowData;
|
||||
use crate::{Result, Error};
|
||||
use crate::dbus_client::*;
|
||||
|
||||
const STYLE: &str = include_str!("../data/style.css");
|
||||
const WELCOME_UI: &str = include_str!("../data/welcome_page.ui");
|
||||
const CITADEL_PASSWORD_UI: &str = include_str!("../data/citadel_password_page.ui");
|
||||
const LUKS_PASSWORD_UI: &str = include_str!("../data/luks_password_page.ui");
|
||||
const INSTALL_DESTINATION_UI: &str = include_str!("../data/install_destination_page.ui");
|
||||
const CONFIRM_INSTALL_UI: &str = include_str!("../data/confirm_install_page.ui");
|
||||
const INSTALL_UI: &str = include_str!("../data/install_page.ui");
|
||||
pub enum Msg {
|
||||
InstallStarted,
|
||||
LvmSetup(String),
|
||||
LuksSetup(String),
|
||||
BootSetup(String),
|
||||
StorageCreated(String),
|
||||
RootfsInstalled(String),
|
||||
InstallCompleted,
|
||||
InstallFailed(String)
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct Ui {
|
||||
pub assistant: gtk::Assistant,
|
||||
pub citadel_password_page: gtk::Box,
|
||||
pub citadel_password_entry: gtk::Entry,
|
||||
pub citadel_password_confirm_entry: gtk::Entry,
|
||||
pub citadel_password_status_label: gtk::Label,
|
||||
pub luks_password_page: gtk::Box,
|
||||
pub luks_password_entry: gtk::Entry,
|
||||
pub luks_password_confirm_entry: gtk::Entry,
|
||||
pub luks_password_status_label: gtk::Label,
|
||||
pub disks_listbox: gtk::ListBox,
|
||||
pub disks_model: gio::ListStore,
|
||||
pub confirm_install_label: gtk::Label,
|
||||
pub install_page: gtk::Box,
|
||||
pub install_progress: gtk::ProgressBar,
|
||||
pub install_scrolled_window: gtk::ScrolledWindow,
|
||||
pub install_textview: gtk::TextView,
|
||||
pub sender: glib::Sender<Msg>
|
||||
}
|
||||
|
||||
impl Ui {
|
||||
pub fn build(application: >k::Application) -> Result<Self> {
|
||||
let disks = Self::get_disks()?;
|
||||
let assistant = gtk::Assistant::new();
|
||||
assistant.set_default_size(800, 600);
|
||||
assistant.set_position(gtk::WindowPosition::CenterAlways);
|
||||
|
||||
assistant.set_application(Some(application));
|
||||
assistant.connect_delete_event(clone!(@strong application => move |_, _| {
|
||||
application.quit();
|
||||
gtk::Inhibit(false)
|
||||
}));
|
||||
assistant.connect_cancel(clone!(@strong application => move |_| {
|
||||
application.quit();
|
||||
}));
|
||||
let welcome_builder = Builder::new(WELCOME_UI);
|
||||
let welcome_page: gtk::Box = welcome_builder.get_box("welcome_page")?;
|
||||
let citadel_password_builder = Builder::new(CITADEL_PASSWORD_UI);
|
||||
let citadel_password_page: gtk::Box = citadel_password_builder.get_box("citadel_password_page")?;
|
||||
let citadel_password_entry: gtk::Entry = citadel_password_builder.get_entry("citadel_password_entry")?;
|
||||
let citadel_password_confirm_entry: gtk::Entry = citadel_password_builder.get_entry("citadel_password_confirm_entry")?;
|
||||
let citadel_password_status_label: gtk::Label = citadel_password_builder.get_label("citadel_password_status_label")?;
|
||||
|
||||
let luks_password_builder = Builder::new(LUKS_PASSWORD_UI);
|
||||
let luks_password_page: gtk::Box = luks_password_builder.get_box("luks_password_page")?;
|
||||
let luks_password_entry: gtk::Entry = luks_password_builder.get_entry("luks_password_entry")?;
|
||||
let luks_password_confirm_entry: gtk::Entry = luks_password_builder.get_entry("luks_password_confirm_entry")?;
|
||||
let luks_password_status_label: gtk::Label = luks_password_builder.get_label("luks_password_status_label")?;
|
||||
|
||||
let install_destination_builder = Builder::new(INSTALL_DESTINATION_UI);
|
||||
let install_destination_page: gtk::Box = install_destination_builder.get_box("install_destination_page")?;
|
||||
let disks_listbox = install_destination_builder.get_listbox("install_destination_listbox")?;
|
||||
|
||||
let confirm_install_builder = Builder::new(CONFIRM_INSTALL_UI);
|
||||
let confirm_install_page: gtk::Box = confirm_install_builder.get_box("confirm_install_page")?;
|
||||
let confirm_install_label: gtk::Label = confirm_install_builder.get_label("confirm_install_label_3")?;
|
||||
let disks_model = gio::ListStore::new(RowData::static_type());
|
||||
disks_listbox.bind_model(Some(&disks_model), move |item| {
|
||||
let row = gtk::ListBoxRow::new();
|
||||
let item = item.downcast_ref::<RowData>().expect("Row data is of wrong type");
|
||||
let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 5);
|
||||
hbox.set_homogeneous(true);
|
||||
let removable = item.get_property("removable").unwrap().get().unwrap().unwrap();
|
||||
let icon_name = Self::get_disk_icon(removable);
|
||||
let disk_icon = gtk::Image::from_icon_name(Some(&icon_name), gtk::IconSize::LargeToolbar);
|
||||
disk_icon.set_halign(gtk::Align::Start);
|
||||
let model_label = gtk::Label::new(None);
|
||||
model_label.set_halign(gtk::Align::Start);
|
||||
model_label.set_justify(gtk::Justification::Left);
|
||||
item.bind_property("model", &model_label, "label")
|
||||
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
||||
.build();
|
||||
let path_label = gtk::Label::new(None);
|
||||
path_label.set_halign(gtk::Align::Start);
|
||||
path_label.set_justify(gtk::Justification::Left);
|
||||
item.bind_property("path", &path_label, "label")
|
||||
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
||||
.build();
|
||||
let size_label = gtk::Label::new(None);
|
||||
size_label.set_halign(gtk::Align::Start);
|
||||
size_label.set_justify(gtk::Justification::Left);
|
||||
item.bind_property("size", &size_label, "label")
|
||||
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
||||
.build();
|
||||
hbox.pack_start(&disk_icon, true, true, 0);
|
||||
hbox.pack_start(&path_label, true, true, 0);
|
||||
hbox.pack_start(&model_label, true, true, 0);
|
||||
hbox.pack_start(&size_label, true, true, 0);
|
||||
row.add(&hbox);
|
||||
row.show_all();
|
||||
row.upcast::<gtk::Widget>()
|
||||
});
|
||||
disks_listbox.connect_row_selected(clone!(@strong assistant, @strong install_destination_page => move |_, listbox_row | {
|
||||
if let Some(_) = listbox_row {
|
||||
assistant.set_page_complete(&install_destination_page, true);
|
||||
}
|
||||
}));
|
||||
let install_builder = Builder::new(INSTALL_UI);
|
||||
let install_page: gtk::Box = install_builder.get_box("install_page")?;
|
||||
let install_progress: gtk::ProgressBar = install_builder.get_progress_bar("install_progress")?;
|
||||
let install_scrolled_window: gtk::ScrolledWindow = install_builder.get_scrolled_window("install_scrolled_window")?;
|
||||
let install_textview: gtk::TextView = install_builder.get_textview("install_textview")?;
|
||||
assistant.append_page(&welcome_page);
|
||||
assistant.set_page_type(&welcome_page, gtk::AssistantPageType::Intro);
|
||||
assistant.set_page_complete(&welcome_page, true);
|
||||
assistant.append_page(&citadel_password_page);
|
||||
assistant.append_page(&luks_password_page);
|
||||
assistant.append_page(&install_destination_page);
|
||||
assistant.append_page(&confirm_install_page);
|
||||
assistant.set_page_type(&confirm_install_page, gtk::AssistantPageType::Confirm);
|
||||
assistant.set_page_complete(&confirm_install_page, true);
|
||||
assistant.append_page(&install_page);
|
||||
assistant.set_page_type(&install_page, gtk::AssistantPageType::Progress);
|
||||
let disks_model_clone = disks_model.clone();
|
||||
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
let ui = Self {
|
||||
assistant,
|
||||
citadel_password_page,
|
||||
citadel_password_entry,
|
||||
citadel_password_confirm_entry,
|
||||
citadel_password_status_label,
|
||||
luks_password_page,
|
||||
luks_password_entry,
|
||||
luks_password_confirm_entry,
|
||||
luks_password_status_label,
|
||||
disks_listbox,
|
||||
disks_model,
|
||||
confirm_install_label,
|
||||
install_page,
|
||||
install_progress,
|
||||
install_scrolled_window,
|
||||
install_textview,
|
||||
sender,
|
||||
};
|
||||
receiver.attach(None,clone!(@strong ui, @strong application => move |msg| {
|
||||
match msg {
|
||||
Msg::InstallStarted => {
|
||||
ui.install_progress.set_fraction(0.1428);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
let text = format!(
|
||||
"+ Installing Citadel to {}. \nFor a full log, consult the systemd journal by running the following command:\n <i>sudo journalctl -u citadel-installer-backend.service</i>\n",
|
||||
ui.get_install_destination());
|
||||
buffer.insert_markup(&mut iter, &text);
|
||||
|
||||
},
|
||||
Msg::LuksSetup(text) => {
|
||||
ui.install_progress.set_fraction(0.1428 * 2.0);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
buffer.insert(&mut iter, &text);
|
||||
},
|
||||
Msg::LvmSetup(text) => {
|
||||
ui.install_progress.set_fraction(0.1428 * 3.0);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
buffer.insert(&mut iter, &text);
|
||||
},
|
||||
Msg::BootSetup(text) => {
|
||||
ui.install_progress.set_fraction(0.1428 * 4.0);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
buffer.insert(&mut iter, &text);
|
||||
},
|
||||
Msg::StorageCreated(text) => {
|
||||
ui.install_progress.set_fraction(0.1428 * 5.0);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
buffer.insert(&mut iter, &text);
|
||||
},
|
||||
Msg::RootfsInstalled(text) => {
|
||||
ui.install_progress.set_fraction(0.1428 * 6.0);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
buffer.insert(&mut iter, &text);
|
||||
},
|
||||
Msg::InstallCompleted => {
|
||||
ui.install_progress.set_fraction(1.0);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
buffer.insert(&mut iter, "+ Completed the installation successfully\n");
|
||||
let quit_button = gtk::Button::with_label("Quit");
|
||||
quit_button.connect_clicked(clone!(@strong application => move |_| {
|
||||
application.quit();
|
||||
}));
|
||||
quit_button.set_sensitive(true);
|
||||
ui.assistant.add_action_widget(&quit_button);
|
||||
ui.assistant.show_all();
|
||||
},
|
||||
Msg::InstallFailed(error) => {
|
||||
ui.install_progress.set_fraction(100.0);
|
||||
let buffer = ui.install_textview.get_buffer().unwrap();
|
||||
let mut iter = buffer.get_end_iter();
|
||||
let text = format!("+ Install failed with error:\n<i>{}</i>\n", error);
|
||||
buffer.insert_markup(&mut iter, &text);
|
||||
let quit_button = gtk::Button::with_label("Quit");
|
||||
quit_button.connect_clicked(clone!(@strong application => move |_| {
|
||||
application.quit();
|
||||
}));
|
||||
quit_button.set_sensitive(true);
|
||||
ui.assistant.add_action_widget(&quit_button);
|
||||
ui.assistant.show_all();
|
||||
}
|
||||
}
|
||||
glib::Continue(true)
|
||||
}));
|
||||
ui.setup_style();
|
||||
ui.setup_signals();
|
||||
for disk in disks {
|
||||
disks_model_clone.append(&disk);
|
||||
}
|
||||
Ok(ui)
|
||||
}
|
||||
|
||||
fn get_disks() -> Result<Vec<RowData>> {
|
||||
let mut disks = vec![];
|
||||
let conn = Connection::new_system().unwrap();
|
||||
let proxy = conn.with_proxy("com.subgraph.installer",
|
||||
"/com/subgraph/installer", Duration::from_millis(5000));
|
||||
let (devices,): (HashMap<String, Vec<String>>,) = proxy.method_call("com.subgraph.installer.Manager", "GetDisks", ()).map_err(Error::Dbus)?;
|
||||
for device in devices {
|
||||
let disk = RowData::new(
|
||||
&device.1[0].clone(),
|
||||
&device.0,
|
||||
&device.1[1].clone(),
|
||||
device.1[2].parse().unwrap());
|
||||
disks.push(disk);
|
||||
}
|
||||
Ok(disks)
|
||||
}
|
||||
|
||||
fn get_disk_icon(removable: bool) -> String {
|
||||
if removable {
|
||||
return "drive-harddisk-usb-symbolic".to_string();
|
||||
}
|
||||
"drive-harddisk-system-symbolic".to_string()
|
||||
}
|
||||
|
||||
pub fn setup_entry_signals(&self, page: >k::Box, first_entry: >k::Entry, second_entry: >k::Entry, status_label: >k::Label) {
|
||||
let ui = self.clone();
|
||||
let assistant = ui.assistant.clone();
|
||||
first_entry.connect_changed(clone!(@weak assistant, @weak page, @weak second_entry, @weak status_label => move |entry| {
|
||||
let password = entry.get_text();
|
||||
let confirm = second_entry.get_text();
|
||||
if password != "" && confirm != "" {
|
||||
let matches = password == confirm;
|
||||
if !matches {
|
||||
status_label.set_text("Passwords do not match");
|
||||
} else {
|
||||
status_label.set_text("");
|
||||
}
|
||||
assistant.set_page_complete(&page, matches);
|
||||
}
|
||||
}));
|
||||
first_entry.connect_activate(clone!(@weak second_entry => move |_| {
|
||||
second_entry.grab_focus();
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn setup_prepare_signal(&self) {
|
||||
let ui = self.clone();
|
||||
ui.assistant.connect_prepare(clone!(@strong ui => move |assistant, page| {
|
||||
let page_type = assistant.get_page_type(page);
|
||||
if page_type == gtk::AssistantPageType::Confirm {
|
||||
let path = ui.get_install_destination();
|
||||
let text = format!("<i>{}</i>", path);
|
||||
ui.confirm_install_label.set_markup(&text);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn setup_apply_signal(&self) {
|
||||
let ui = self.clone();
|
||||
ui.assistant.connect_apply(clone!(@strong ui => move |_| {
|
||||
let citadel_password = ui.get_citadel_password();
|
||||
let luks_password = ui.get_luks_password();
|
||||
let destination = ui.get_install_destination();
|
||||
let conn = Connection::new_system().unwrap();
|
||||
let proxy = conn.with_proxy("com.subgraph.installer",
|
||||
"/com/subgraph/installer", Duration::from_millis(5000));
|
||||
let (_,): (bool,) = proxy.method_call("com.subgraph.installer.Manager",
|
||||
"RunInstall", (destination, citadel_password, luks_password)).unwrap();
|
||||
let _= ui.sender.send(Msg::InstallStarted);
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn setup_autoscroll_signal(&self) {
|
||||
let ui = self.clone();
|
||||
let scrolled_window = ui.install_scrolled_window;
|
||||
ui.install_textview.connect_size_allocate(clone!(@weak scrolled_window => move |_, _| {
|
||||
let adjustment = scrolled_window.get_vadjustment().unwrap();
|
||||
adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn setup_signals(&self) {
|
||||
let ui = self.clone();
|
||||
self.setup_entry_signals(&ui.citadel_password_page, &ui.citadel_password_entry,
|
||||
&ui.citadel_password_confirm_entry, &ui.citadel_password_status_label);
|
||||
self.setup_entry_signals(&ui.citadel_password_page, &ui.citadel_password_confirm_entry,
|
||||
&ui.citadel_password_entry, &ui.citadel_password_status_label);
|
||||
self.setup_entry_signals(&ui.luks_password_page, &ui.luks_password_entry,
|
||||
&ui.luks_password_confirm_entry, &ui.luks_password_status_label);
|
||||
self.setup_entry_signals(&ui.luks_password_page, &ui.luks_password_confirm_entry,
|
||||
&ui.luks_password_entry, &ui.luks_password_status_label);
|
||||
self.setup_prepare_signal();
|
||||
self.setup_apply_signal();
|
||||
self.setup_autoscroll_signal();
|
||||
}
|
||||
|
||||
fn setup_style(&self) {
|
||||
let css = gtk::CssProvider::new();
|
||||
|
||||
if let Err(err) = css.load_from_data(STYLE.as_bytes()) {
|
||||
println!("Error parsing CSS style: {}", err);
|
||||
return;
|
||||
}
|
||||
if let Some(screen) = gdk::Screen::get_default() {
|
||||
gtk::StyleContext::add_provider_for_screen(&screen, &css, gtk::STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_citadel_password(&self) -> String {
|
||||
let ui = self.clone();
|
||||
let password = ui.citadel_password_entry.get_text();
|
||||
password.to_string()
|
||||
}
|
||||
|
||||
pub fn get_luks_password(&self) -> String {
|
||||
let ui = self.clone();
|
||||
let password = ui.luks_password_entry.get_text();
|
||||
password.to_string()
|
||||
}
|
||||
|
||||
pub fn get_install_destination(&self) -> String {
|
||||
let ui = self.clone();
|
||||
let model = ui.disks_model;
|
||||
if let Some(row) = ui.disks_listbox.get_selected_row() {
|
||||
let index = row.get_index() as u32;
|
||||
let data = model.get_object(index).unwrap();
|
||||
let data = data.downcast_ref::<RowData>().expect("Row data is of wrong type");
|
||||
// TODO: Fix unwrap
|
||||
let path: String = data.get_property("path").unwrap().get().unwrap().unwrap();
|
||||
return path.to_string();
|
||||
}
|
||||
"".to_string()
|
||||
}
|
||||
fn setup_signal_matchers(&self, proxy: Proxy<&Connection>) {
|
||||
let sender = self.sender.clone();
|
||||
let _ = proxy.match_signal(clone!(@strong sender => move |_: ComSubgraphInstallerManagerInstallCompleted, _: &Connection, _: &Message| {
|
||||
let _ = sender.send(Msg::InstallCompleted);
|
||||
true
|
||||
}));
|
||||
let _ = proxy.match_signal(clone!(@strong sender => move |h: ComSubgraphInstallerManagerLvmSetup, _: &Connection, _: &Message| {
|
||||
let _ = sender.send(Msg::LvmSetup(h.text));
|
||||
true
|
||||
}));
|
||||
let _ = proxy.match_signal(clone!(@strong sender => move |h: ComSubgraphInstallerManagerLuksSetup, _: &Connection, _: &Message| {
|
||||
let _ = sender.send(Msg::LuksSetup(h.text));
|
||||
true
|
||||
}));
|
||||
let _ = proxy.match_signal(clone!(@strong sender => move |h: ComSubgraphInstallerManagerBootSetup, _: &Connection, _: &Message| {
|
||||
let _ = sender.send(Msg::BootSetup(h.text));
|
||||
true
|
||||
}));
|
||||
let _ = proxy.match_signal(clone!(@strong sender => move |h: ComSubgraphInstallerManagerStorageCreated, _: &Connection, _: &Message| {
|
||||
let _ = sender.send(Msg::StorageCreated(h.text));
|
||||
true
|
||||
}));
|
||||
let _ = proxy.match_signal(clone!(@strong sender => move |h: ComSubgraphInstallerManagerRootfsInstalled, _: &Connection, _: &Message| {
|
||||
let _ = sender.send(Msg::RootfsInstalled(h.text));
|
||||
true
|
||||
}));
|
||||
let _ = proxy.match_signal(clone!(@strong sender => move |h: ComSubgraphInstallerManagerInstallFailed, _: &Connection, _: &Message| {
|
||||
let _ = sender.send(Msg::InstallFailed(h.text));
|
||||
true
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn start(&self) {
|
||||
let c = Connection::new_system().unwrap();
|
||||
let proxy = c.with_proxy("com.subgraph.installer", "/com/subgraph/installer", Duration::from_millis(5000));
|
||||
self.setup_signal_matchers(proxy);
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
c.process(Duration::from_millis(1000)).unwrap(); }
|
||||
});
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ name = "citadel-tool"
|
||||
version = "0.1.0"
|
||||
authors = ["Bruce Leidl <bruce@subgraph.com>"]
|
||||
edition = "2018"
|
||||
description = "citadel-tool"
|
||||
homepage = "https://subgraph.com"
|
||||
|
||||
[dependencies]
|
||||
libcitadel = { path = "../libcitadel" }
|
||||
@ -14,4 +16,5 @@ serde = "1.0"
|
||||
toml = "0.5"
|
||||
hex = "0.4"
|
||||
byteorder = "1"
|
||||
|
||||
dbus = "0.8.4"
|
||||
pwhash = "0.3.1"
|
||||
|
@ -5,6 +5,9 @@ use super::disk::Disk;
|
||||
use rpassword;
|
||||
use crate::install::installer::Installer;
|
||||
|
||||
const CITADEL_PASSPHRASE_PROMPT: &str = "Enter a password for the Citadel user (or 'q' to quit)";
|
||||
const LUKS_PASSPHRASE_PROMPT: &str = "Enter a disk encryption passphrase (or 'q' to quit";
|
||||
|
||||
pub fn run_cli_install() -> Result<bool> {
|
||||
let disk = match choose_disk()? {
|
||||
Some(disk) => disk,
|
||||
@ -13,7 +16,12 @@ pub fn run_cli_install() -> Result<bool> {
|
||||
|
||||
display_disk(&disk);
|
||||
|
||||
let passphrase = match read_passphrase().map_err(context!("error reading passphrase"))? {
|
||||
let citadel_passphrase = match read_passphrase(CITADEL_PASSPHRASE_PROMPT).map_err(context!("error reading citadel user passphrase"))? {
|
||||
Some(citadel_passphrase) => citadel_passphrase,
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
let passphrase = match read_passphrase(LUKS_PASSPHRASE_PROMPT).map_err(context!("error reading luks passphrase"))? {
|
||||
Some(passphrase) => passphrase,
|
||||
None => return Ok(false),
|
||||
};
|
||||
@ -21,7 +29,7 @@ pub fn run_cli_install() -> Result<bool> {
|
||||
if !confirm_install(&disk)? {
|
||||
return Ok(false);
|
||||
}
|
||||
run_install(disk, passphrase)?;
|
||||
run_install(disk, citadel_passphrase, passphrase)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@ -29,7 +37,12 @@ pub fn run_cli_install_with<P: AsRef<Path>>(target: P) -> Result<bool> {
|
||||
let disk = find_disk_by_path(target.as_ref())?;
|
||||
display_disk(&disk);
|
||||
|
||||
let passphrase = match read_passphrase().map_err(context!("error reading passphrase"))? {
|
||||
let citadel_passphrase = match read_passphrase(CITADEL_PASSPHRASE_PROMPT).map_err(context!("error reading citadel user passphrase"))? {
|
||||
Some(citadel_passphrase) => citadel_passphrase,
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
let passphrase = match read_passphrase(LUKS_PASSPHRASE_PROMPT).map_err(context!("error reading luks passphrase"))? {
|
||||
Some(passphrase) => passphrase,
|
||||
None => return Ok(false),
|
||||
};
|
||||
@ -38,12 +51,12 @@ pub fn run_cli_install_with<P: AsRef<Path>>(target: P) -> Result<bool> {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
run_install(disk, passphrase)?;
|
||||
run_install(disk, citadel_passphrase, passphrase)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn run_install(disk: Disk, passphrase: String) -> Result<()> {
|
||||
let mut install = Installer::new(disk.path(), &passphrase);
|
||||
fn run_install(disk: Disk, citadel_passphrase: String, passphrase: String) -> Result<()> {
|
||||
let mut install = Installer::new(disk.path(), &citadel_passphrase, &passphrase);
|
||||
install.set_install_syslinux(true);
|
||||
install.verify()?;
|
||||
install.run()
|
||||
@ -108,9 +121,9 @@ fn read_line() -> Result<String> {
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
fn read_passphrase() -> io::Result<Option<String>> {
|
||||
fn read_passphrase(prompt: &str) -> io::Result<Option<String>> {
|
||||
loop {
|
||||
println!("Enter a disk encryption passphrase (or 'q' to quit)");
|
||||
println!("{}", prompt);
|
||||
println!();
|
||||
let passphrase = rpassword::read_password_from_tty(Some(" Passphrase : "))?;
|
||||
if passphrase.is_empty() {
|
||||
|
@ -5,6 +5,7 @@ use std::os::unix::process::CommandExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::time::Instant;
|
||||
use pwhash::sha512_crypt;
|
||||
|
||||
use libcitadel::util;
|
||||
use libcitadel::RealmFS;
|
||||
@ -121,20 +122,23 @@ pub struct Installer {
|
||||
install_syslinux: bool,
|
||||
storage_base: PathBuf,
|
||||
target_device: Option<PathBuf>,
|
||||
citadel_passphrase: Option<String>,
|
||||
passphrase: Option<String>,
|
||||
artifact_directory: String,
|
||||
logfile: Option<RefCell<File>>,
|
||||
}
|
||||
|
||||
impl Installer {
|
||||
pub fn new<P: AsRef<Path>>(target_device: P, passphrase: &str) -> Installer {
|
||||
pub fn new<P: AsRef<Path>>(target_device: P, citadel_passphrase: &str, passphrase: &str) -> Installer {
|
||||
let target_device = Some(target_device.as_ref().to_owned());
|
||||
let citadel_passphrase = Some(citadel_passphrase.to_owned());
|
||||
let passphrase = Some(passphrase.to_owned());
|
||||
Installer {
|
||||
_type: InstallType::Install,
|
||||
install_syslinux: true,
|
||||
storage_base: PathBuf::from(INSTALL_MOUNT),
|
||||
target_device,
|
||||
citadel_passphrase,
|
||||
passphrase,
|
||||
artifact_directory: DEFAULT_ARTIFACT_DIRECTORY.to_string(),
|
||||
logfile: None,
|
||||
@ -147,6 +151,7 @@ impl Installer {
|
||||
install_syslinux: false,
|
||||
storage_base: PathBuf::from("/sysroot/storage"),
|
||||
target_device: None,
|
||||
citadel_passphrase: None,
|
||||
passphrase: None,
|
||||
artifact_directory: DEFAULT_ARTIFACT_DIRECTORY.to_string(),
|
||||
logfile: None,
|
||||
@ -161,6 +166,10 @@ impl Installer {
|
||||
self.target().to_str().unwrap()
|
||||
}
|
||||
|
||||
fn citadel_passphrase(&self) -> &str {
|
||||
self.citadel_passphrase.as_ref().expect("No citadel passphrase")
|
||||
}
|
||||
|
||||
fn passphrase(&self) -> &str {
|
||||
self.passphrase.as_ref().expect("No passphrase")
|
||||
}
|
||||
@ -251,14 +260,14 @@ impl Installer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn partition_disk(&self) -> Result<()> {
|
||||
pub fn partition_disk(&self) -> Result<()> {
|
||||
self.header("Partitioning target disk")?;
|
||||
self.cmd_list(PARTITION_COMMANDS, &[
|
||||
("$TARGET", self.target_str())
|
||||
])
|
||||
}
|
||||
|
||||
fn setup_luks(&self) -> Result<()> {
|
||||
pub fn setup_luks(&self) -> Result<()> {
|
||||
self.header("Setting up LUKS disk encryption")?;
|
||||
util::create_dir(INSTALL_MOUNT)?;
|
||||
util::write_file(LUKS_PASSPHRASE_FILE, self.passphrase().as_bytes())?;
|
||||
@ -274,12 +283,12 @@ impl Installer {
|
||||
util::remove_file(LUKS_PASSPHRASE_FILE)
|
||||
}
|
||||
|
||||
fn setup_lvm(&self) -> Result<()> {
|
||||
pub fn setup_lvm(&self) -> Result<()> {
|
||||
self.header("Setting up LVM volumes")?;
|
||||
self.cmd_list(LVM_COMMANDS, &[])
|
||||
}
|
||||
|
||||
fn setup_boot(&self) -> Result<()> {
|
||||
pub fn setup_boot(&self) -> Result<()> {
|
||||
self.header("Setting up /boot partition")?;
|
||||
let boot_partition = self.target_partition(1);
|
||||
self.cmd(format!("/sbin/mkfs.vfat -F 32 {}", boot_partition))?;
|
||||
@ -327,9 +336,11 @@ impl Installer {
|
||||
util::copy_file(dent.path(), dst.join(dent.file_name()))
|
||||
})?;
|
||||
|
||||
let kernel_version = self.kernel_version();
|
||||
self.info("Writing syslinux.cfg")?;
|
||||
util::write_file(dst.join("syslinux.cfg"),
|
||||
SYSLINUX_CONF.replace("$KERNEL_CMDLINE", KERNEL_CMDLINE))?;
|
||||
SYSLINUX_CONF.replace("$KERNEL_CMDLINE", KERNEL_CMDLINE)
|
||||
.replace("$KERNEL_VERSION", &kernel_version))?;
|
||||
self.cmd(format!("/sbin/extlinux --install {}", dst.display()))
|
||||
}
|
||||
|
||||
@ -343,7 +354,7 @@ impl Installer {
|
||||
|
||||
}
|
||||
|
||||
fn create_storage(&self) -> Result<()> {
|
||||
pub fn create_storage(&self) -> Result<()> {
|
||||
self.header("Setting up /storage partition")?;
|
||||
|
||||
self.cmd_list(CREATE_STORAGE_COMMANDS,
|
||||
@ -363,6 +374,7 @@ impl Installer {
|
||||
self.setup_realm_skel()?;
|
||||
self.setup_main_realm()?;
|
||||
self.setup_apt_cacher_realm()?;
|
||||
self.setup_citadel_passphrase()?;
|
||||
|
||||
self.info("Creating global realm config file")?;
|
||||
util::write_file(self.storage().join("realms/config"), self.global_realm_config())?;
|
||||
@ -382,6 +394,7 @@ impl Installer {
|
||||
keyring.write(self.storage().join("keyring"), self.passphrase.as_ref().unwrap())
|
||||
}
|
||||
|
||||
|
||||
fn setup_base_realmfs(&self) -> Result<()> {
|
||||
let realmfs_dir = self.storage().join("realms/realmfs-images");
|
||||
util::create_dir(&realmfs_dir)?;
|
||||
@ -460,14 +473,37 @@ impl Installer {
|
||||
self.sparse_copy_artifact(&kernel_img, &resources)
|
||||
}
|
||||
|
||||
fn install_rootfs_partitions(&self) -> Result<()> {
|
||||
fn setup_citadel_passphrase(&self) -> Result<()> {
|
||||
if self._type == InstallType::LiveSetup {
|
||||
self.info("Creating temporary citadel passphrase file for live mode")?;
|
||||
let path = self.storage().join("citadel-state/passwd");
|
||||
if !path.exists() {
|
||||
if let Ok(hash) = sha512_crypt::hash("citadel") {
|
||||
let contents = format!("citadel:{}\n", hash);
|
||||
util::create_dir(self.storage().join("citadel-state"))?;
|
||||
util::write_file(self.storage().join("citadel-state/passwd"), contents)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if self._type == InstallType::Install {
|
||||
self.info("Creating citadel passphrase file")?;
|
||||
if let Ok(hash) = sha512_crypt::hash(self.citadel_passphrase()) {
|
||||
let contents = format!("citadel:{}\n", hash);
|
||||
util::create_dir(self.storage().join("citadel-state"))?;
|
||||
util::write_file(self.storage().join("citadel-state/passwd"), contents)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn install_rootfs_partitions(&self) -> Result<()> {
|
||||
self.header("Installing rootfs partitions")?;
|
||||
let rootfs = self.artifact_path("citadel-rootfs.img");
|
||||
self.cmd(format!("/usr/bin/citadel-image install-rootfs --skip-sha {}", rootfs.display()))?;
|
||||
self.cmd(format!("/usr/bin/citadel-image install-rootfs --skip-sha --no-prefer {}", rootfs.display()))
|
||||
}
|
||||
|
||||
fn finish_install(&self) -> Result<()> {
|
||||
pub fn finish_install(&self) -> Result<()> {
|
||||
self.cmd_list(FINISH_COMMANDS, &[
|
||||
("$TARGET", self.target_str())
|
||||
])
|
||||
|
278
citadel-tool/src/install_backend/dbus.rs
Normal file
278
citadel-tool/src/install_backend/dbus.rs
Normal file
@ -0,0 +1,278 @@
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::{Sender};
|
||||
|
||||
use dbus::tree::{self, Factory, MTFn, MethodResult, Tree};
|
||||
use dbus::{Message};
|
||||
use dbus::blocking::LocalConnection;
|
||||
use libcitadel::{Result};
|
||||
// Use local version of disk.rs since we added some methods
|
||||
use crate::install_backend::disk::*;
|
||||
use crate::install::installer::*;
|
||||
use std::fmt;
|
||||
|
||||
type MethodInfo<'a> = tree::MethodInfo<'a, MTFn<TData>, TData>;
|
||||
|
||||
|
||||
const OBJECT_PATH: &str = "/com/subgraph/installer";
|
||||
const INTERFACE_NAME: &str = "com.subgraph.installer.Manager";
|
||||
const BUS_NAME: &str = "com.subgraph.installer";
|
||||
|
||||
pub enum Msg {
|
||||
RunInstall(String, String, String),
|
||||
LvmSetup(String),
|
||||
LuksSetup(String),
|
||||
BootSetup(String),
|
||||
StorageCreated(String),
|
||||
RootfsInstalled(String),
|
||||
InstallCompleted,
|
||||
InstallFailed(String)
|
||||
}
|
||||
|
||||
pub struct DbusServer {
|
||||
connection: Arc<LocalConnection>,
|
||||
//events: EventHandler,
|
||||
}
|
||||
|
||||
impl DbusServer {
|
||||
|
||||
pub fn connect() -> Result<DbusServer> {
|
||||
let connection = LocalConnection::new_system()
|
||||
.map_err(|e| format_err!("Failed to connect to DBUS system bus: {}", e))?;
|
||||
let connection = Arc::new(connection);
|
||||
//let events = EventHandler::new(connection.clone());
|
||||
let server = DbusServer { connection };
|
||||
Ok(server)
|
||||
|
||||
}
|
||||
|
||||
fn build_tree(&self, sender: mpsc::Sender<Msg>) -> Tree<MTFn<TData>, TData> {
|
||||
let f = Factory::new_fn::<TData>();
|
||||
let data = TreeData::new();
|
||||
let interface = f.interface(INTERFACE_NAME, ())
|
||||
// Methods
|
||||
.add_m(f.method("GetDisks", (), Self::do_get_disks)
|
||||
.in_arg(("name", "a{sas}")))
|
||||
|
||||
.add_m(f.method("RunInstall", (),move |m| {
|
||||
|
||||
let (device, citadel_passphrase, luks_passphrase): (String, String, String) = m.msg.read3()?;
|
||||
println!("Device: {} Citadel Passphrase: {} Luks Passphrase: {}", device, citadel_passphrase, luks_passphrase);
|
||||
let _ = sender.send(Msg::RunInstall(device, citadel_passphrase, luks_passphrase));
|
||||
Ok(vec![m.msg.method_return().append1(true)])
|
||||
})
|
||||
.in_arg(("device", "s")).in_arg(("citadel_passphrase", "s")).in_arg(("luks_passphrase", "s")))
|
||||
.add_s(f.signal("RunInstallStarted", ()))
|
||||
.add_s(f.signal("InstallCompleted", ()))
|
||||
.add_s(f.signal("CitadelPasswordSet", ()));
|
||||
let obpath = f.object_path(OBJECT_PATH, ())
|
||||
.introspectable()
|
||||
.add(interface);
|
||||
|
||||
f.tree(data).add(obpath)
|
||||
}
|
||||
|
||||
|
||||
fn do_get_disks(m: &MethodInfo) -> MethodResult {
|
||||
let list = m.tree.get_data().disks();
|
||||
Ok(vec![m.msg.method_return().append1(list)])
|
||||
}
|
||||
|
||||
fn run_install(path: String, citadel_passphrase: String, luks_passphrase: String, sender: Sender<Msg>) -> Result<()> {
|
||||
let mut install = Installer::new(path, &citadel_passphrase, &luks_passphrase);
|
||||
install.set_install_syslinux(true);
|
||||
install.verify()?;
|
||||
install.partition_disk()?;
|
||||
install.setup_luks()?;
|
||||
let _ = sender.send(Msg::LuksSetup("+ Setup LUKS disk encryption password successfully\n".to_string()));
|
||||
install.setup_lvm()?;
|
||||
let _ = sender.send(Msg::LvmSetup("+ Setup LVM volumes successfully\n".to_string()));
|
||||
install.setup_boot()?;
|
||||
let _ = sender.send(Msg::BootSetup("+ Setup /boot partition successfully\n".to_string()));
|
||||
install.create_storage()?;
|
||||
let _ = sender.send(Msg::StorageCreated("+ Setup /storage partition successfully\n".to_string()));
|
||||
install.install_rootfs_partitions()?;
|
||||
let _ = sender.send(Msg::RootfsInstalled("+ Installed rootfs partitions successfully\n".to_string()));
|
||||
install.finish_install()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*fn process_message(&self, _msg: Message) -> Result<()> {
|
||||
// add handlers for expected signals here
|
||||
Ok(())
|
||||
}*/
|
||||
|
||||
fn send_service_started(&self) {
|
||||
let signal = Self::create_signal("ServiceStarted");
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send ServiceStarted signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn send_install_completed(&self) {
|
||||
let signal = Self::create_signal("InstallCompleted");
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send InstallCompleted signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn send_lvm_setup(&self, text: String) {
|
||||
let signal = Self::create_signal_with_text("LvmSetup", text);
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send LvmSetup signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn send_luks_setup(&self, text: String) {
|
||||
let signal = Self::create_signal_with_text("LuksSetup", text);
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send LuksSetup signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn send_boot_setup(&self, text: String) {
|
||||
let signal = Self::create_signal_with_text("BootSetup", text);
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send BootSetup signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn send_storage_created(&self, text: String) {
|
||||
let signal = Self::create_signal_with_text("StorageCreated", text);
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send StorageCreated signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn send_rootfs_installed(&self, text: String) {
|
||||
let signal = Self::create_signal_with_text("RootfsInstalled", text);
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send StorageCreated signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn send_install_failed(&self, error: String) {
|
||||
let signal = Self::create_signal_with_text("InstallFailed", error);
|
||||
if self.connection.channel().send(signal).is_err() {
|
||||
warn!("Failed to send StorageCreated signal");
|
||||
}
|
||||
}
|
||||
|
||||
fn create_signal(name: &str) -> Message {
|
||||
let path = dbus::Path::new(OBJECT_PATH).unwrap();
|
||||
let iface = dbus::strings::Interface::new(INTERFACE_NAME).unwrap();
|
||||
let member = dbus::strings::Member::new(name).unwrap();
|
||||
Message::signal(&path, &iface, &member)
|
||||
}
|
||||
|
||||
fn create_signal_with_text(name: &str, text: String) -> Message {
|
||||
let path = dbus::Path::new(OBJECT_PATH).unwrap();
|
||||
let iface = dbus::strings::Interface::new(INTERFACE_NAME).unwrap();
|
||||
let member = dbus::strings::Member::new(name).unwrap();
|
||||
Message::signal(&path, &iface, &member).append1(text)
|
||||
}
|
||||
|
||||
pub fn start(&self) -> Result<()> {
|
||||
let (sender, receiver) = mpsc::channel::<Msg>();
|
||||
let sender_clone = sender.clone();
|
||||
let tree = self.build_tree(sender);
|
||||
if let Err(_err) = self.connection.request_name(BUS_NAME, false, true, false) {
|
||||
bail!("Failed to request name");
|
||||
}
|
||||
|
||||
tree.start_receive(self.connection.as_ref());
|
||||
|
||||
self.send_service_started();
|
||||
loop {
|
||||
self.connection
|
||||
.process(Duration::from_millis(1000))
|
||||
.map_err(context!("Error handling dbus messages"))?;
|
||||
|
||||
if let Ok(msg) = receiver.try_recv() {
|
||||
match msg {
|
||||
Msg::RunInstall(device, citadel_passphrase, luks_passphrase) => {
|
||||
let install_sender = sender_clone.clone();
|
||||
// TODO: Implement more stages
|
||||
match Self::run_install(device, citadel_passphrase, luks_passphrase, install_sender) {
|
||||
Ok(_) => {
|
||||
println!("Install completed");
|
||||
let _ = sender_clone.send(Msg::InstallCompleted);
|
||||
},
|
||||
Err(err) => {
|
||||
println!("Install error: {}", err);
|
||||
let _ = sender_clone.send(Msg::InstallFailed(err.to_string()));
|
||||
}
|
||||
}
|
||||
},
|
||||
Msg::LvmSetup(text) => {
|
||||
self.send_lvm_setup(text);
|
||||
},
|
||||
Msg::LuksSetup(text) => {
|
||||
self.send_luks_setup(text);
|
||||
},
|
||||
Msg::BootSetup(text) => {
|
||||
self.send_boot_setup(text);
|
||||
},
|
||||
Msg::StorageCreated(text) => {
|
||||
self.send_storage_created(text);
|
||||
},
|
||||
Msg::RootfsInstalled(text) => {
|
||||
self.send_rootfs_installed(text);
|
||||
},
|
||||
Msg::InstallCompleted => {
|
||||
self.send_install_completed();
|
||||
},
|
||||
Msg::InstallFailed(text) => {
|
||||
self.send_install_failed(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TreeData {
|
||||
}
|
||||
|
||||
impl TreeData {
|
||||
fn new() -> TreeData {
|
||||
TreeData {}
|
||||
}
|
||||
|
||||
|
||||
fn disks(&self) -> HashMap<String, Vec<String>> {
|
||||
let disks = Disk::probe_all().unwrap();
|
||||
|
||||
let mut disk_map = HashMap::new();
|
||||
for d in disks {
|
||||
let mut fields = vec![];
|
||||
fields.push(d.model().to_string());
|
||||
fields.push(d.size_str().to_string());
|
||||
fields.push(d.removable().to_string());
|
||||
disk_map.insert(d.path().to_string_lossy().to_string(), fields);
|
||||
}
|
||||
disk_map
|
||||
}
|
||||
|
||||
}
|
||||
impl fmt::Debug for TreeData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "<TreeData>")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct TData;
|
||||
|
||||
impl tree::DataType for TData {
|
||||
type Tree = TreeData;
|
||||
type ObjectPath = ();
|
||||
type Property = ();
|
||||
type Interface = ();
|
||||
type Method = ();
|
||||
type Signal = ();
|
||||
}
|
80
citadel-tool/src/install_backend/disk.rs
Normal file
80
citadel-tool/src/install_backend/disk.rs
Normal file
@ -0,0 +1,80 @@
|
||||
use std::path::{Path,PathBuf};
|
||||
use std::fs;
|
||||
|
||||
use libcitadel::{Result, util};
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Disk {
|
||||
path: PathBuf,
|
||||
size: usize,
|
||||
size_str: String,
|
||||
model: String,
|
||||
removable: bool,
|
||||
}
|
||||
|
||||
impl Disk {
|
||||
pub fn probe_all() -> Result<Vec<Disk>> {
|
||||
let mut v = Vec::new();
|
||||
util::read_directory("/sys/block", |dent| {
|
||||
let path = dent.path();
|
||||
if Disk::is_disk_device(&path) {
|
||||
let disk = Disk::read_device(&path)?;
|
||||
v.push(disk);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn is_disk_device(device: &Path) -> bool {
|
||||
device.join("device/model").exists()
|
||||
}
|
||||
|
||||
fn is_disk_removable(device: &Path) -> bool {
|
||||
if let Ok(removable) = util::read_to_string(device.join("removable")) {
|
||||
if removable.trim() == "1" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn read_device(device: &Path) -> Result<Disk> {
|
||||
let path = Path::new("/dev/").join(device.file_name().unwrap());
|
||||
|
||||
let size = fs::read_to_string(device.join("size"))
|
||||
.map_err(context!("failed to read device size for {:?}", device))?
|
||||
.trim()
|
||||
.parse::<usize>()
|
||||
.map_err(context!("error parsing device size for {:?}", device))?;
|
||||
|
||||
let size_str = format!("{}G", size >> 21);
|
||||
|
||||
let model = fs::read_to_string(device.join("device/model"))
|
||||
.map_err(context!("failed to read device/model for {:?}", device))?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
let removable = Disk::is_disk_removable(device);
|
||||
|
||||
Ok(Disk { path, size, size_str, model, removable })
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn size_str(&self) -> &str {
|
||||
&self.size_str
|
||||
}
|
||||
|
||||
pub fn model(&self) -> &str {
|
||||
&self.model
|
||||
}
|
||||
|
||||
pub fn removable(&self) -> &bool {
|
||||
&self.removable
|
||||
}
|
||||
}
|
24
citadel-tool/src/install_backend/mod.rs
Normal file
24
citadel-tool/src/install_backend/mod.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use libcitadel::Result;
|
||||
use std::process::exit;
|
||||
|
||||
mod disk;
|
||||
mod dbus;
|
||||
use libcitadel::CommandLine;
|
||||
|
||||
pub fn main() {
|
||||
if CommandLine::live_mode() || CommandLine::install_mode() {
|
||||
if let Err(e) = run_dbus_server() {
|
||||
warn!("Error: {}", e);
|
||||
}
|
||||
} else {
|
||||
println!("Citadel installer backend will only run in install or live mode");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_dbus_server() -> Result<()> {
|
||||
let server = dbus::DbusServer::connect()?;
|
||||
server.start()?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use libcitadel::RealmManager;
|
||||
mod boot;
|
||||
mod image;
|
||||
mod install;
|
||||
mod install_backend;
|
||||
mod mkimage;
|
||||
mod realmfs;
|
||||
mod sync;
|
||||
@ -30,6 +31,8 @@ fn main() {
|
||||
boot::main(args);
|
||||
} else if exe == Path::new("/usr/libexec/citadel-install") {
|
||||
install::main(args);
|
||||
} else if exe == Path::new("/usr/libexec/citadel-install-backend") {
|
||||
install_backend::main();
|
||||
} else if exe == Path::new("/usr/bin/citadel-image") {
|
||||
image::main(args);
|
||||
} else if exe == Path::new("/usr/bin/citadel-realmfs") {
|
||||
|
19
data/com.subgraph.installer.Manager.conf
Normal file
19
data/com.subgraph.installer.Manager.conf
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="com.subgraph.installer"/>
|
||||
</policy>
|
||||
|
||||
<policy context="default">
|
||||
<allow send_destination="com.subgraph.installer"/>
|
||||
<allow send_destination="com.subgraph.installer"
|
||||
send_interface="org.freedesktop.DBus.Properties"/>
|
||||
<allow send_destination="com.subgraph.installer"
|
||||
send_interface="org.freedesktop.DBus.Introspectable"/>
|
||||
</policy>
|
||||
</busconfig>
|
Loading…
Reference in New Issue
Block a user