dbus-app-launcher 0.1.0.0 → 0.1.1.0
raw patch · 4 files changed
+90/−15 lines, 4 filesdep +regex-tdfadep +shellwordsdep ~base
Dependencies added: regex-tdfa, shellwords
Dependency ranges changed: base
Files
- CHANGELOG.md +5/−1
- README.md +51/−5
- app/Main.hs +30/−7
- dbus-app-launcher.cabal +4/−2
CHANGELOG.md view
@@ -1,6 +1,10 @@ # Changelog +## v0.1.1.0++Added shell-style parsing of the command to make it easier to pass arguments and+environment variables.+ ## v0.1.0.0 Initial version.-
README.md view
@@ -7,24 +7,70 @@ ## Installation +There is a number of ways to install. Choose one and follow the given steps.++The following installation options provide a complete package which already+include a D-Bus service configuration file, so require no extra steps after+installing:++- Install from the Arch User Repository (AUR):+ [`dbus-app-launcher`](https://aur.archlinux.org/packages/dbus-app-launcher)++The following installation options only provide you with the executable and+leave it up to you to set up the D-Bus service configuration file, for which+you will need to follow the steps in the section below:++- Download a static binary from the+ [releases page](https://github.com/DvdGiessen/dbus-app-launcher/releases).+- Install from Hackage:+ [`dbus-app-launcher`](https://hackage.haskell.org/package/dbus-app-launcher)++If none of the above options work for you, you can also follow the instructions+below to build the executable from source yourself.++### Building from source+ To build the code, you will need Haskell and the `stack` command line utility.-Get it [here](https://docs.haskellstack.org/en/stable/).+Get them [here](https://docs.haskellstack.org/en/stable/). To build and install, run `stack install`. This will build the code and copy the executable to `~/.local/bin`. -Next, set up a D-Bus service description that will automatically launch the new-service whenever it is accessed:+Next, follow the steps to set up the D-Bus service. -`/usr/share/dbus-1/services/nl.dvdgiessen.dbusapplauncher.service`+### Build a static executable using Docker +To build a static executable (the same as made available on the releases page),+you can use the following Docker command:++```sh+docker run -v $PWD:/dbus-app-launcher --rm benz0li/ghc-musl:9.8.4 sh -c "cd /dbus-app-launcher && exec stack --allow-different-user build --no-install-ghc --system-ghc --ghc-options='-static -optl-static'"+```++This will start a [`ghc-musl`](https://github.com/benz0li/ghc-musl) container,+mount the current directory (where you've checked out the code) into it, and+build a statically linked version of the service which should be able to run on+any system with the same CPU architecture.++When the build succeeded, the executable can be found at the following path:+`.stack-work/dist/x86_64-linux/ghc-9.8.4/build/dbus-app-launcher/dbus-app-launcher`++### Setting up the D-Bus service configuration++To set up a D-Bus service description that will automatically launch the new+service whenever it is accessed, create the following file:++`~/.local/share/dbus-1/services/nl.dvdgiessen.dbusapplauncher.service`+ ```ini [D-BUS Service] Name=nl.dvdgiessen.dbusapplauncher Exec=/home/USERNAME/.local/bin/dbus-app-launcher ``` -## Using the service+Replace the path in `Exec=` with the actual location of the executable.++## Using the D-Bus service from your own code The service currently exports one interface, `Exec`. Calling any of the methods of this interface will start the program using the `exec()` syscall.
app/Main.hs view
@@ -6,11 +6,32 @@ import Control.Concurrent.Chan import Control.Exception.Extra (ignore) import Control.Monad-import Data.Map+import Data.Either+import Data.List (uncons)+import Data.Map.Strict (fromList, toList)+import Data.Maybe (fromMaybe) import DBus.Client+import ShellWords (parse)+import System.Environment (getEnvironment) import System.Exit import System.Posix.Process+import Text.Regex.TDFA +splitEnv :: [String] -> ([String], [String])+splitEnv = span (\ s -> ((s =~ ("[a-zA-Z_][a-zA-Z0-9_]*=" :: String)) :: Bool))++parseEnv :: [String] -> [(String, String)]+parseEnv = map ((\ (k, _, v) -> (k, v)) . (\ d -> ((d =~ ("=" :: String)) :: (String, String, String))) )++uniqEnv :: [[(String, String)]] -> [(String, String)]+uniqEnv envs = toList (fromList (concat envs))++parseCmd :: String -> [String] -> [(String, String)] -> (String, [String], [(String, String)])+parseCmd cmd args env = (\ (a, b)+ -> uncurry+ (,,) (fromMaybe (cmd, args) (uncons (b ++ args)))+ (uniqEnv [parseEnv a, env])) (splitEnv (fromRight [] (parse cmd)))+ main :: IO () main = do -- Connect to D-Bus@@ -18,14 +39,14 @@ -- Channel for transfering exec parameters from the callback thread channel <- newChan- + -- Export object used for launching programs export client "/nl/dvdgiessen/DBusAppLauncher" defaultInterface { interfaceName = "nl.dvdgiessen.dbusapplauncher.Exec" , interfaceMethods =- [ autoMethod "Cmd" (\ cmd -> (writeChan channel (cmd, [], Nothing)))- , autoMethod "CmdArgs" (\ cmd args -> (writeChan channel (cmd, args, Nothing)))- , autoMethod "CmdArgsEnv" (\ cmd args env -> (writeChan channel (cmd, args, Just (toList env))))+ [ autoMethod "Cmd" (\ cmd -> writeChan channel (parseCmd cmd [] []))+ , autoMethod "CmdArgs" (\ cmd args -> writeChan channel (parseCmd cmd args []))+ , autoMethod "CmdArgsEnv" (\ cmd args env -> writeChan channel (parseCmd cmd args (toList env))) ] } @@ -50,9 +71,11 @@ -- Make sure we are in our own process group and session ignore (do _ <- createSession; return ()) + -- Environment that spawned processes will inherit+ globalEnv <- getEnvironment+ -- Exec with the requested parameters- _ <- executeFile cmd True args env+ _ <- executeFile cmd True args (Just (uniqEnv [globalEnv, env])) -- Never reached return ()-
dbus-app-launcher.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: dbus-app-launcher-version: 0.1.0.0+version: 0.1.1.0 license: MIT license-file: LICENSE copyright: 2024 Daniël van de Giessen@@ -34,8 +34,10 @@ -threaded -rtsopts -with-rtsopts=-N build-depends:- base >=4.7 && <5,+ base >=4.12 && <5, containers >=0.6 && <0.7, dbus >=1.3 && <1.4, extra >=1.7 && <1.8,+ regex-tdfa >=1.3 && <1.4,+ shellwords >=0.1.3.2 && <0.2, unix >=2.8 && <2.9