Add support for shortcuts on Windows

This commit is contained in:
James 2018-08-06 20:51:59 +10:00
parent 94660994ec
commit 82b3681a74
22 changed files with 823 additions and 66 deletions

200
Cargo.lock generated
View File

@ -27,6 +27,14 @@ dependencies = [
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aster"
version = "0.41.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
@ -46,6 +54,31 @@ dependencies = [
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bindgen"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clang-sys 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "0.9.1"
@ -98,6 +131,14 @@ name = "cc"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cexpr"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cfg-if"
version = "0.1.4"
@ -113,6 +154,17 @@ dependencies = [
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clang-sys"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clap"
version = "2.32.0"
@ -204,6 +256,15 @@ dependencies = [
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fern"
version = "0.5.6"
@ -282,6 +343,11 @@ name = "gcc"
version = "0.3.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "glob"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "httparse"
version = "1.3.2"
@ -403,10 +469,22 @@ dependencies = [
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libloading"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "liftinstall"
version = "0.1.0"
dependencies = [
"bindgen 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -454,6 +532,14 @@ name = "matches"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.0.1"
@ -600,6 +686,14 @@ name = "nodrop"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nom"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.39"
@ -652,6 +746,11 @@ dependencies = [
"vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "percent-encoding"
version = "1.0.1"
@ -710,6 +809,26 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quasi"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quasi_codegen"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.5"
@ -811,6 +930,11 @@ dependencies = [
"uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "safemem"
version = "0.2.0"
@ -948,6 +1072,48 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex"
version = "0.58.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex_errors"
version = "0.58.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex_pos"
version = "0.58.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex_syntax"
version = "0.58.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "take"
version = "0.1.0"
@ -973,6 +1139,15 @@ dependencies = [
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "term"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
@ -1233,6 +1408,11 @@ name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
@ -1422,8 +1602,11 @@ dependencies = [
"checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9"
"checksum bindgen 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c57d6c0f6e31f8dcf4d12720a3c2a9ffb70638772a5784976cf4fce52145f22a"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
@ -1432,8 +1615,10 @@ dependencies = [
"checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
"checksum bzip2-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2c5162604199bbb17690ede847eaa6120a3f33d5ab4dcc8e7c25b16d849ae79b"
"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275"
"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c"
"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
"checksum chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e48d85528df61dc964aa43c5f6ca681a19cfa74939b2348d204bd08a981f2fb0"
"checksum clang-sys 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "611ec2e3a7623afd8a8c0d027887b6b55759d894abbf5fe11b9dc11b50d5b49a"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d"
@ -1444,6 +1629,7 @@ dependencies = [
"checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444"
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d"
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
"checksum fern 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "57915fe00a83af935983eb2d00b0ecc62419c4741b28c207ecbf98fd4a1b94c8"
"checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f"
"checksum flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37847f133aae7acf82bb9577ccd8bda241df836787642654286e79679826a54b"
@ -1455,6 +1641,7 @@ dependencies = [
"checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540"
"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7"
"checksum hyper-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb1bd5e518d3065840ab315dbbf44e4420e5f7d80e2cb93fa6ffffc50522378"
@ -1469,9 +1656,11 @@ dependencies = [
"checksum libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"checksum libflate 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7d4b4c7aff5bac19b956f693d0ea0eade8066deb092186ae954fa6ba14daab98"
"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2"
"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
@ -1487,12 +1676,14 @@ dependencies = [
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e752e3c216bc8a491c5b59fa46da10f1379ae450b19ac688e07f4bb55042e98"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
"checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985"
"checksum openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)" = "912f301a749394e1025d9dcddef6106ddee9252620e6d0a0e5f8d0681de9b129"
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7d37a244c75a9748e049225155f56dbcb98fe71b192fd25fd23cb914b5ad62f2"
"checksum phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4048fe7dd7a06b8127ecd6d3803149126e9b33c7558879846da3a63f734f2b"
@ -1501,6 +1692,8 @@ dependencies = [
"checksum pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "104630aa1c83213cbc76db0703630fcb0421dac3585063be4ce9a8a2feeaa745"
"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
"checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6"
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
"checksum quote 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3372dc35766b36a99ce2352bd1b6ea0137c38d215cc0c8780bf6de6df7842ba9"
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
@ -1511,6 +1704,7 @@ dependencies = [
"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum reqwest 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e7e237e32c3bfa55c95e29af872c8f481471d70b8a5ec15d85f4d274ffd92dd9"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f"
@ -1530,9 +1724,14 @@ dependencies = [
"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e13df71f29f9440b50261a5882c86eac334f1badb3134ec26f0de2f1418e44"
"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e"
"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c"
"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047"
"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791"
"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5"
"checksum tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f41ca4a5689f06998f0247fcb60da6c760f1950cc9df2a10d71575ad0b062a"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
@ -1559,6 +1758,7 @@ dependencies = [
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"

View File

@ -51,3 +51,5 @@ nfd = "0.0.4"
[target.'cfg(windows)'.build-dependencies]
winres = "0.1"
bindgen = "0.26.3"
cc = "1.0"

View File

@ -2,6 +2,12 @@ extern crate walkdir;
#[cfg(windows)]
extern crate winres;
#[cfg(windows)]
extern crate bindgen;
#[cfg(windows)]
extern crate cc;
use walkdir::WalkDir;
use std::env;
@ -24,6 +30,21 @@ fn handle_binary() {
let mut res = winres::WindowsResource::new();
res.set_icon("static/favicon.ico");
res.compile().expect("Failed to generate metadata");
let bindings = bindgen::Builder::default()
.header("src/native/interop.h")
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("interop.rs"))
.expect("Couldn't write bindings!");
cc::Build::new()
.cpp(true)
.file("src/native/interop.cpp")
.compile("interop");
}
#[cfg(not(windows))]

View File

@ -19,6 +19,14 @@ pub struct PackageSource {
pub config: toml::Value,
}
/// Describes if/how a shortcut should be built for a package.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct PackageShortcut {
pub name: String,
pub relative_path: String,
pub description: String,
}
/// Describes a overview of a individual package.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct PackageDescription {
@ -26,6 +34,8 @@ pub struct PackageDescription {
pub description: String,
pub default: Option<bool>,
pub source: PackageSource,
#[serde(default)]
pub shortcuts: Vec<PackageShortcut>,
}
/// Describes the application itself.

View File

@ -26,6 +26,8 @@ use logging::LoggingErrors;
use dirs::home_dir;
use std::fs::remove_file;
/// A message thrown during the installation of packages.
#[derive(Serialize)]
pub enum InstallMessage {
@ -61,7 +63,10 @@ pub struct InstallationStatus {
pub struct LocalInstallation {
pub name: String,
pub version: Version,
/// Relative paths to generated files
pub files: Vec<String>,
/// Absolute paths to generated shortcut files
pub shortcuts: Vec<String>,
}
impl InstallerFramework {
@ -148,7 +153,20 @@ impl InstallerFramework {
if let Err(v) = messages.send(InstallMessage::Status(msg.to_string(), progress as _)) {
error!("Failed to submit queue message: {:?}", v);
}
}).map(|_x| ())
}).map(|_x| ())?;
// Delete the metadata file
let path = self
.install_path
.as_ref()
.log_expect("No install path specified");
remove_file(path.join("metadata.json"))
.map_err(|x| format!("Failed to delete metadata: {:?}", x))?;
// Logging will have to be done later
Ok(())
}
/// Saves the applications database.

View File

@ -47,6 +47,7 @@ mod config;
mod http;
mod installer;
mod logging;
mod native;
mod rest;
mod sources;
mod tasks;

89
src/native/interop.cpp Normal file
View File

@ -0,0 +1,89 @@
/**
* Misc interop helpers.
**/
#include "windows.h"
#include "winnls.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
extern "C" int saveShortcut(
const char *shortcutPath,
const char *description,
const char *path,
const char *args,
const char *workingDir) {
char* errStr = NULL;
HRESULT h;
IShellLink* shellLink = NULL;
IPersistFile* persistFile = NULL;
#ifdef _WIN64
wchar_t wName[MAX_PATH+1];
#else
WORD wName[MAX_PATH+1];
#endif
int id;
// Initialize the COM library
h = CoInitialize(NULL);
if (FAILED(h)) {
errStr = "Failed to initialize COM library";
goto err;
}
h = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (PVOID*)&shellLink );
if (FAILED(h)) {
errStr = "Failed to create IShellLink";
goto err;
}
h = shellLink->QueryInterface(IID_IPersistFile, (PVOID*)&persistFile);
if (FAILED(h)) {
errStr = "Failed to get IPersistFile";
goto err;
}
//Append the shortcut name to the folder
MultiByteToWideChar(CP_ACP,0,shortcutPath,-1,wName,MAX_PATH);
// Load the file if it exists, to get the values for anything
// that we do not set. Ignore errors, such as if it does not exist.
h = persistFile->Load(wName, 0);
// Set the fields for which the application has set a value
if (description!=NULL)
shellLink->SetDescription(description);
if (path!=NULL)
shellLink->SetPath(path);
if (args!=NULL)
shellLink->SetArguments(args);
if (workingDir!=NULL)
shellLink->SetWorkingDirectory(workingDir);
//Save the shortcut to disk
h = persistFile->Save(wName, TRUE);
if (FAILED(h)) {
errStr = "Failed to save shortcut";
goto err;
}
persistFile->Release();
shellLink->Release();
CoUninitialize();
return h;
err:
if (persistFile != NULL)
persistFile->Release();
if (shellLink != NULL)
shellLink->Release();
CoUninitialize();
return h;
}

6
src/native/interop.h Normal file
View File

@ -0,0 +1,6 @@
int saveShortcut(
const char *shortcutPath,
const char *description,
const char *path,
const char *args,
const char *workingDir);

80
src/native/mod.rs Normal file
View File

@ -0,0 +1,80 @@
//! Natives/platform specific interactions.
#[cfg(windows)]
mod natives {
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use std::ffi::CString;
use logging::LoggingErrors;
use std::env;
include!(concat!(env!("OUT_DIR"), "/interop.rs"));
// Needed here for Windows interop
#[allow(unsafe_code)]
pub fn create_shortcut(
name: &str,
description: &str,
target: &str,
args: &str,
working_dir: &str,
) -> Result<String, String> {
let source_file = format!(
"{}\\Microsoft\\Windows\\Start Menu\\Programs\\{}.lnk",
env::var("APPDATA").log_expect("APPDATA is bad, apparently"),
name
);
info!("Generating shortcut @ {:?}", source_file);
let native_target_dir = CString::new(source_file.clone())
.log_expect("Error while converting to C-style string");
let native_description =
CString::new(description).log_expect("Error while converting to C-style string");
let native_target =
CString::new(target).log_expect("Error while converting to C-style string");
let native_args = CString::new(args).log_expect("Error while converting to C-style string");
let native_working_dir =
CString::new(working_dir).log_expect("Error while converting to C-style string");
let shortcutResult = unsafe {
saveShortcut(
native_target_dir.as_ptr(),
native_description.as_ptr(),
native_target.as_ptr(),
native_args.as_ptr(),
native_working_dir.as_ptr(),
)
};
match shortcutResult {
0 => Ok(source_file),
_ => Err(format!(
"Windows gave bad result while creating shortcut: {:?}",
shortcutResult
)),
}
}
}
#[cfg(not(windows))]
mod natives {
pub fn create_shortcut(
name: &str,
description: &str,
target: &str,
args: &str,
working_dir: &str,
) -> Result<String, String> {
// TODO: no-op
warn!("create_shortcut is stubbed!");
Ok("".to_string())
}
}
pub use self::natives::*;

View File

@ -338,9 +338,17 @@ impl Service for WebService {
thread::spawn(move || {
let mut tx = tx;
loop {
let response = receiver
.recv()
.log_expect("Failed to receive message from runner thread");
let mut panic_after_finish = false;
let response = match receiver
.recv() {
Ok(v) => v,
Err(v) => {
error!("Queue message failed: {:?}", v);
panic_after_finish = true;
InstallMessage::Error("Internal error".to_string())
}
};
if let InstallMessage::EOF = response {
break;
@ -353,6 +361,10 @@ impl Service for WebService {
.send(Ok(response.into_bytes().into()))
.wait()
.log_expect("Failed to write JSON response payload to client");
if panic_after_finish {
panic!("Failed to read from queue (flushed error message successfully)");
}
}
});

View File

@ -3,6 +3,8 @@
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskOrdering;
use tasks::TaskParamType;
use tasks::resolver::ResolvePackageTask;
@ -83,10 +85,13 @@ impl Task for DownloadPackageTask {
Ok(TaskParamType::FileContents(version, file, data_storage))
}
fn dependencies(&self) -> Vec<Box<Task>> {
vec![Box::new(ResolvePackageTask {
name: self.name.clone(),
})]
fn dependencies(&self) -> Vec<TaskDependency> {
vec![TaskDependency::build(
TaskOrdering::Pre,
Box::new(ResolvePackageTask {
name: self.name.clone(),
}),
)]
}
fn name(&self) -> String {

View File

@ -4,11 +4,12 @@ use installer::InstallerFramework;
use tasks::install_dir::VerifyInstallDirTask;
use tasks::install_pkg::InstallPackageTask;
use tasks::save_database::SaveDatabaseTask;
use tasks::save_executable::SaveExecutableTask;
use tasks::uninstall_pkg::UninstallPackageTask;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskOrdering;
use tasks::TaskParamType;
pub struct InstallTask {
@ -28,28 +29,38 @@ impl Task for InstallTask {
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<Box<Task>> {
let mut elements = Vec::<Box<Task>>::new();
fn dependencies(&self) -> Vec<TaskDependency> {
let mut elements = Vec::new();
elements.push(Box::new(VerifyInstallDirTask {
clean_install: self.fresh_install,
}));
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(VerifyInstallDirTask {
clean_install: self.fresh_install,
}),
));
for item in &self.items {
elements.push(Box::new(InstallPackageTask { name: item.clone() }));
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(InstallPackageTask { name: item.clone() }),
));
}
for item in &self.uninstall_items {
elements.push(Box::new(UninstallPackageTask {
name: item.clone(),
optional: false,
}));
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(UninstallPackageTask {
name: item.clone(),
optional: false,
}),
));
}
elements.push(Box::new(SaveDatabaseTask {}));
if self.fresh_install {
elements.push(Box::new(SaveExecutableTask {}));
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(SaveExecutableTask {}),
));
}
elements

View File

@ -3,6 +3,7 @@
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
use std::fs::create_dir_all;
@ -46,7 +47,7 @@ impl Task for VerifyInstallDirTask {
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<Box<Task>> {
fn dependencies(&self) -> Vec<TaskDependency> {
vec![]
}

View File

@ -2,7 +2,13 @@
use installer::InstallerFramework;
use tasks::download_pkg::DownloadPackageTask;
use tasks::install_shortcuts::InstallShortcutsTask;
use tasks::save_database::SaveDatabaseTask;
use tasks::uninstall_pkg::UninstallPackageTask;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskOrdering;
use tasks::TaskParamType;
use config::PackageDescription;
@ -11,9 +17,6 @@ use installer::LocalInstallation;
use std::fs::create_dir_all;
use std::io::copy;
use tasks::download_pkg::DownloadPackageTask;
use tasks::uninstall_pkg::UninstallPackageTask;
use logging::LoggingErrors;
use archives;
@ -59,19 +62,23 @@ impl Task for InstallPackageTask {
None => return Err(format!("Package {:?} could not be found.", self.name)),
};
// Check to see if no archive was available.
if let TaskParamType::Break = input
.pop()
.log_expect("Should have input from uninstaller!")
{
// No file to install, but all is good.
return Ok(TaskParamType::None);
}
// Grab data from the shortcut generator
let shortcuts = input.pop().log_expect("Should have input from resolver!");
let shortcuts = match shortcuts {
TaskParamType::GeneratedShortcuts(files) => files,
// If the resolver returned early, we need to unwind
TaskParamType::Break => return Ok(TaskParamType::None),
_ => return Err("Unexpected shortcuts param type to install package".to_string()),
};
// Ignore input from the uninstaller - no useful information passed
input.pop();
// Grab data from the resolver
let data = input.pop().log_expect("Should have input from resolver!");
let (version, file, data) = match data {
TaskParamType::FileContents(version, file, data) => (version, file, data),
_ => return Err("Unexpected param type to install package".to_string()),
_ => return Err("Unexpected file contents param type to install package".to_string()),
};
let mut archive = archives::read_archive(&file.name, data.as_slice())?;
@ -159,21 +166,35 @@ impl Task for InstallPackageTask {
context.database.push(LocalInstallation {
name: package.name.to_owned(),
version,
shortcuts,
files: installed_files,
});
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<Box<Task>> {
fn dependencies(&self) -> Vec<TaskDependency> {
vec![
Box::new(DownloadPackageTask {
name: self.name.clone(),
}),
Box::new(UninstallPackageTask {
name: self.name.clone(),
optional: true,
}),
TaskDependency::build(
TaskOrdering::Pre,
Box::new(DownloadPackageTask {
name: self.name.clone(),
}),
),
TaskDependency::build(
TaskOrdering::Pre,
Box::new(UninstallPackageTask {
name: self.name.clone(),
optional: true,
}),
),
TaskDependency::build(
TaskOrdering::Pre,
Box::new(InstallShortcutsTask {
name: self.name.clone(),
}),
),
TaskDependency::build(TaskOrdering::Post, Box::new(SaveDatabaseTask {})),
]
}

View File

@ -0,0 +1,98 @@
//! Generates shortcuts for a specified file.
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
use config::PackageDescription;
use logging::LoggingErrors;
use native::create_shortcut;
pub struct InstallShortcutsTask {
pub name: String,
}
impl Task for InstallShortcutsTask {
fn execute(
&mut self,
_: Vec<TaskParamType>,
context: &mut InstallerFramework,
messenger: &Fn(&str, f64),
) -> Result<TaskParamType, String> {
messenger(
&format!("Generating shortcuts for package {:?}...", self.name),
0.0,
);
let path = context
.install_path
.as_ref()
.log_expect("No install path specified");
let starting_dir = path
.to_str()
.log_expect("Unable to build shortcut metadata (startingdir)");
let mut installed_files = Vec::new();
let mut metadata: Option<PackageDescription> = None;
for description in &context
.config
.as_ref()
.log_expect("Should have packages by now")
.packages
{
if self.name == description.name {
metadata = Some(description.clone());
break;
}
}
let package = match metadata {
Some(v) => v,
None => return Err(format!("Package {:?} could not be found.", self.name)),
};
// Generate installer path
let platform_extension = if cfg!(windows) {
"maintenancetool.exe"
} else {
"maintenancetool"
};
for shortcut in package.shortcuts {
let tool_path = path.join(platform_extension);
let tool_path = tool_path
.to_str()
.log_expect("Unable to build shortcut metadata (tool)");
let exe_path = path.join(shortcut.relative_path);
let exe_path = exe_path
.to_str()
.log_expect("Unable to build shortcut metadata (exe)");
installed_files.push(create_shortcut(
&shortcut.name,
&shortcut.description,
tool_path,
// TODO: Send by list
&format!("--launcher \"{}\"", exe_path),
&starting_dir,
)?);
}
Ok(TaskParamType::GeneratedShortcuts(installed_files))
}
fn dependencies(&self) -> Vec<TaskDependency> {
vec![]
}
fn name(&self) -> String {
format!("InstallShortcutsTask (for {:?})", self.name)
}
}

View File

@ -13,11 +13,13 @@ pub mod download_pkg;
pub mod install;
pub mod install_dir;
pub mod install_pkg;
pub mod install_shortcuts;
pub mod resolver;
pub mod save_database;
pub mod save_executable;
pub mod uninstall;
pub mod uninstall_pkg;
pub mod uninstall_shortcuts;
/// An abstraction over the various parameters that can be passed around.
pub enum TaskParamType {
@ -26,10 +28,34 @@ pub enum TaskParamType {
File(Version, File),
/// Downloaded contents of a file
FileContents(Version, File, Vec<u8>),
/// List of shortcuts that have been generated
GeneratedShortcuts(Vec<String>),
/// Tells the runtime to break parsing other dependencies
Break,
}
/// Specifies the relative ordering of a dependency with it's parent.
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum TaskOrdering {
/// This task should occur before the main process
Pre,
/// This task should occur after the main process. These have their results discarded.
Post,
}
/// A dependency of a task with various properties.
pub struct TaskDependency {
ordering: TaskOrdering,
task: Box<Task>,
}
impl TaskDependency {
/// Builds a new dependency from the specified task.
pub fn build(ordering: TaskOrdering, task: Box<Task>) -> TaskDependency {
TaskDependency { ordering, task }
}
}
/// A Task is a small, async task conforming to a fixed set of inputs/outputs.
pub trait Task {
/// Executes this individual task, evaluating to the given Output result.
@ -44,7 +70,7 @@ pub trait Task {
/// Returns a vector containing all dependencies that need to be executed
/// before this task can function.
fn dependencies(&self) -> Vec<Box<Task>>;
fn dependencies(&self) -> Vec<TaskDependency>;
/// Returns a short name used for formatting the dependency tree.
fn name(&self) -> String;
@ -53,7 +79,7 @@ pub trait Task {
/// The dependency tree allows for smart iteration on a Task struct.
pub struct DependencyTree {
task: Box<Task>,
dependencies: Vec<DependencyTree>,
dependencies: Vec<(TaskOrdering, DependencyTree)>,
}
impl DependencyTree {
@ -64,8 +90,9 @@ impl DependencyTree {
buf += "\n";
for i in 0..self.dependencies.len() {
let dependencies = self.dependencies[i].render();
let dependencies = dependencies.trim();
let (order, dependency) = &(self.dependencies[i]);
let dependencies = dependency.render();
let dependencies = format!("{:?} {}", order, dependencies.trim());
if i + 1 == self.dependencies.len() {
buf += "└── ";
@ -92,7 +119,11 @@ impl DependencyTree {
let mut count = 0;
for i in &mut self.dependencies {
for (ordering, i) in &mut self.dependencies {
if ordering != &TaskOrdering::Pre {
continue;
}
let result = i.execute(context, &|msg: &str, progress: f64| {
messenger(
msg,
@ -114,13 +145,46 @@ impl DependencyTree {
}
}
self.task
let task_result = self
.task
.execute(inputs, context, &|msg: &str, progress: f64| {
messenger(
msg,
progress / total_tasks + (1.0 / total_tasks) * f64::from(count),
)
})
})?;
if let TaskParamType::Break = task_result {
// We are done here
return Ok(TaskParamType::Break);
}
for (ordering, i) in &mut self.dependencies {
if ordering != &TaskOrdering::Post {
continue;
}
let result = i.execute(context, &|msg: &str, progress: f64| {
messenger(
msg,
progress / total_tasks + (1.0 / total_tasks) * f64::from(count),
)
})?;
// Check to see if we skip matching other dependencies
let do_break = match &result {
TaskParamType::Break => true,
_ => false,
};
count += 1;
if do_break {
break;
}
}
Ok(task_result)
}
/// Builds a new pipeline from the specified task, iterating on dependencies.
@ -128,7 +192,7 @@ impl DependencyTree {
let dependencies = task
.dependencies()
.into_iter()
.map(|x| DependencyTree::build(x))
.map(|x| (x.ordering, DependencyTree::build(x.task)))
.collect();
DependencyTree { task, dependencies }

View File

@ -5,6 +5,7 @@ use std::env::consts::OS;
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
use config::PackageDescription;
@ -89,7 +90,7 @@ impl Task for ResolvePackageTask {
Ok(TaskParamType::File(latest_version, latest_file))
}
fn dependencies(&self) -> Vec<Box<Task>> {
fn dependencies(&self) -> Vec<TaskDependency> {
vec![]
}

View File

@ -3,6 +3,7 @@
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
pub struct SaveDatabaseTask {}
@ -22,7 +23,7 @@ impl Task for SaveDatabaseTask {
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<Box<Task>> {
fn dependencies(&self) -> Vec<TaskDependency> {
vec![]
}

View File

@ -3,6 +3,7 @@
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
use std::fs::File;
@ -71,7 +72,7 @@ impl Task for SaveExecutableTask {
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<Box<Task>> {
fn dependencies(&self) -> Vec<TaskDependency> {
vec![]
}

View File

@ -5,8 +5,9 @@ use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskParamType;
use tasks::save_database::SaveDatabaseTask;
use tasks::uninstall_pkg::UninstallPackageTask;
use tasks::TaskDependency;
use tasks::TaskOrdering;
pub struct UninstallTask {
pub items: Vec<String>,
@ -23,18 +24,19 @@ impl Task for UninstallTask {
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<Box<Task>> {
let mut elements = Vec::<Box<Task>>::new();
fn dependencies(&self) -> Vec<TaskDependency> {
let mut elements = Vec::new();
for item in &self.items {
elements.push(Box::new(UninstallPackageTask {
name: item.clone(),
optional: false,
}));
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(UninstallPackageTask {
name: item.clone(),
optional: false,
}),
));
}
elements.push(Box::new(SaveDatabaseTask {}));
elements
}

View File

@ -2,7 +2,10 @@
use installer::InstallerFramework;
use tasks::save_database::SaveDatabaseTask;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskOrdering;
use tasks::TaskParamType;
use installer::LocalInstallation;
@ -11,6 +14,7 @@ use std::fs::remove_dir;
use std::fs::remove_file;
use logging::LoggingErrors;
use tasks::uninstall_shortcuts::UninstallShortcutsTask;
pub struct UninstallPackageTask {
pub name: String,
@ -24,7 +28,7 @@ impl Task for UninstallPackageTask {
context: &mut InstallerFramework,
messenger: &Fn(&str, f64),
) -> Result<TaskParamType, String> {
assert_eq!(input.len(), 0);
assert_eq!(input.len(), 1);
let path = context
.install_path
@ -83,8 +87,17 @@ impl Task for UninstallPackageTask {
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<Box<Task>> {
vec![]
fn dependencies(&self) -> Vec<TaskDependency> {
vec![
TaskDependency::build(
TaskOrdering::Pre,
Box::new(UninstallShortcutsTask {
name: self.name.clone(),
optional: self.optional,
}),
),
TaskDependency::build(TaskOrdering::Post, Box::new(SaveDatabaseTask {})),
]
}
fn name(&self) -> String {

View File

@ -0,0 +1,100 @@
//! Uninstalls a specific package.
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
use installer::LocalInstallation;
use std::fs::remove_dir;
use std::fs::remove_file;
use logging::LoggingErrors;
pub struct UninstallShortcutsTask {
pub name: String,
pub optional: bool,
}
impl Task for UninstallShortcutsTask {
fn execute(
&mut self,
input: Vec<TaskParamType>,
context: &mut InstallerFramework,
messenger: &Fn(&str, f64),
) -> Result<TaskParamType, String> {
assert_eq!(input.len(), 0);
let path = context
.install_path
.as_ref()
.log_expect("No install path specified");
let mut metadata: Option<LocalInstallation> = None;
for i in 0..context.database.len() {
if self.name == context.database[i].name {
metadata = Some(context.database[i].clone());
break;
}
}
let mut package = match metadata {
Some(v) => v,
None => {
if self.optional {
return Ok(TaskParamType::None);
}
return Err(format!(
"Package {:?} could not be found for uninstall.",
self.name
));
}
};
messenger(
&format!("Uninstalling shortcuts for package {:?}...", self.name),
0.0,
);
// Reverse, as to delete directories last
package.files.reverse();
let max = package.files.len();
for (i, file) in package.shortcuts.iter().enumerate() {
let name = file.clone();
let file = path.join(file);
info!("Deleting {:?}", file);
messenger(
&format!("Deleting {} ({} of {})", name, i + 1, max),
(i as f64) / (max as f64),
);
let result = if file.is_dir() {
remove_dir(file)
} else {
remove_file(file)
};
if let Err(v) = result {
error!("Failed to delete file: {:?}", v);
}
}
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<TaskDependency> {
vec![]
}
fn name(&self) -> String {
format!(
"UninstallShortcutsTask (for {:?}, optional = {})",
self.name, self.optional
)
}
}