Skip to content

Commit

Permalink
Support for custom root (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
gvolpe authored Sep 20, 2020
1 parent 57eba64 commit cf976e0
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 54 deletions.
36 changes: 30 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,16 @@ dconf dump / > dconf.settings

### Run

Once compiled and installed (via `nix-build` or `cabal new-install`), you can use it as follows:
The easiest way is to pipe the standard input to `dconf2nix` and expect the result in the standard output:

```shell
dconf2nix -i data/dconf.settings -o output/dconf.nix
dconf dump / | dconf2nix > dconf.nix
```

It is also possible to pipe the standard input to `dconf2nix` and expect the result in the standard output:
If you have an input file instead, you can run the following command:

```shell
dconf dump / | dconf2nix > dconf.nix
dconf2nix -i data/dconf.settings -o output/dconf.nix
```

Type `--help` for some more information.
Expand All @@ -96,23 +96,47 @@ Type `--help` for some more information.
dconf2nix - Nixify dconf configuration files

Usage: dconf2nix [-v|--version]
[[-t|--timeout ARG] [--verbose] | (-i|--input ARG)
(-o|--output ARG) [-t|--timeout ARG] [--verbose]]
[[-r|--root ARG] [-t|--timeout ARG] [--verbose] |
(-i|--input ARG) (-o|--output ARG) [-r|--root ARG]
[-t|--timeout ARG] [--verbose]]
Convert a dconf file into a Nix file, as expected by Home Manager.

Available options:
-h,--help Show this help text
-v,--version Show the current version
-r,--root ARG Custom root path. e.g.: system/locale/
-t,--timeout ARG Timeout in seconds for the conversion
process (default: 5)
--verbose Verbose mode (debug)
-i,--input ARG Path to the dconf file (input)
-o,--output ARG Path to the Nix output file (to be created)
-r,--root ARG Custom root path. e.g.: system/locale/
-t,--timeout ARG Timeout in seconds for the conversion
process (default: 5)
--verbose Verbose mode (debug)
```

#### Custom root

By default, `dconf2nix` expects the root to be `/`. If you want to create a dump of a custom root, you can use the `--root` flag. For example:

```shell
dconf dump /system/locale/ | dconf2nix --root system/locale > dconf.nix
```

This will generate an output similar to the one below.

```nix
{
dconf.settings = {
"system/locale" = {
region = "en_US.UTF-8";
};
};
}
```

### Supported types

For now, only types supported by Home Manager as specified [here](https://github.com/rycee/home-manager/blob/master/modules/lib/gvariant.nix) are supported. If there's enough interest, we might be able to work on supporting the [full specification](https://developer.gnome.org/glib/stable/gvariant-text.html).
Expand Down
8 changes: 4 additions & 4 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dconf2nix (ProcessTimeout t) fa successMsg = timeout (t * 1000000) fa >>= \case

main :: IO ()
main = runArgs >>= \case
FileInput (FileArgs i o t v) ->
dconf2nix t (dconf2nixFile i o v) (Just "🚀 Successfully Nixified! ❄️")
StdinInput (StdinArgs t v) ->
dconf2nix t (dconf2nixStdin v) Nothing
FileInput (FileArgs i o r t v) ->
dconf2nix t (dconf2nixFile i o r v) (Just "🚀 Successfully Nixified! ❄️")
StdinInput (StdinArgs r t v) ->
dconf2nix t (dconf2nixStdin r v) Nothing
6 changes: 6 additions & 0 deletions data/custom.settings
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[/]
saved-pathbar-path='/org/gnome/desktop/input-sources/'
saved-view='/org/gnome/desktop/input-sources/'
window-height=709
window-is-maximized=false
window-width=785
7 changes: 7 additions & 0 deletions data/root.settings
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[mouse]
natural-scroll=false
speed=-0.5

[touchpad]
tap-to-click=false
two-finger-scrolling-enabled=true
18 changes: 18 additions & 0 deletions output/custom.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated via dconf2nix: https://github.com/gvolpe/dconf2nix
{ lib, ... }:

let
mkTuple = lib.hm.gvariant.mkTuple;
in
{
dconf.settings = {
"ca/desrt/dconf-editor" = {
saved-pathbar-path = "/org/gnome/desktop/input-sources/";
saved-view = "/org/gnome/desktop/input-sources/";
window-height = 709;
window-is-maximized = false;
window-width = 785;
};

};
}
20 changes: 20 additions & 0 deletions output/root.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated via dconf2nix: https://github.com/gvolpe/dconf2nix
{ lib, ... }:

let
mkTuple = lib.hm.gvariant.mkTuple;
in
{
dconf.settings = {
"org/gnome/desktop/peripherals/mouse" = {
natural-scroll = false;
speed = -0.5;
};

"org/gnome/desktop/peripherals/touchpad" = {
tap-to-click = false;
two-finger-scrolling-enabled = true;
};

};
}
39 changes: 24 additions & 15 deletions src/CommandLine.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ module CommandLine
)
where

import qualified Data.Text as T
import Data.Version ( showVersion )
import DConf.Data ( InputFilePath(..)
, OutputFilePath(..)
, ProcessTimeout(..)
, Verbosity(..)
)
import DConf.Data
import Options.Applicative
import Paths_dconf2nix ( version )

Expand All @@ -20,17 +17,20 @@ data Input = FileInput FileArgs | StdinInput StdinArgs
data FileArgs = FileArgs
{ fileInput :: InputFilePath
, fileOutput :: OutputFilePath
, fileRoot :: Root
, fileTimeout :: ProcessTimeout
, fileVerbosity :: Verbosity
}

data StdinArgs = StdinArgs
{ stdinTimeout :: ProcessTimeout
{ stdinRoot :: Root
, stdinTimeout :: ProcessTimeout
, stdinVerbosity :: Verbosity
}

timeoutArgs :: Parser ProcessTimeout
timeoutArgs = ProcessTimeout <$> option auto
timeoutArgs = ProcessTimeout <$> option
auto
(long "timeout" <> short 't' <> showDefault <> value 5 <> help
"Timeout in seconds for the conversion process"
)
Expand All @@ -39,6 +39,12 @@ verbosityArgs :: Parser Verbosity
verbosityArgs =
flag Normal Verbose (long "verbose" <> help "Verbose mode (debug)")

rootArgs :: Parser Root
rootArgs = Root <$> strOption
(long "root" <> short 'r' <> value T.empty <> help
"Custom root path. e.g.: system/locale/"
)

fileArgs :: Parser Input
fileArgs = fmap FileInput $ FileArgs
<$> (InputFilePath <$> strOption
Expand All @@ -49,11 +55,13 @@ fileArgs = fmap FileInput $ FileArgs
"Path to the Nix output file (to be created)"
)
)
<*> rootArgs
<*> timeoutArgs
<*> verbosityArgs

stdinArgs :: Parser Input
stdinArgs = StdinInput <$> (StdinArgs <$> timeoutArgs <*> verbosityArgs)
stdinArgs =
StdinInput <$> (StdinArgs <$> rootArgs <*> timeoutArgs <*> verbosityArgs)

versionInfo :: String
versionInfo = unlines
Expand All @@ -76,11 +84,12 @@ versionOpt = infoOption versionInfo

runArgs :: IO Input
runArgs =
let opts = info
(helper <*> versionOpt <*> (stdinArgs <|> fileArgs))
( fullDesc
<> progDesc
"Convert a dconf file into a Nix file, as expected by Home Manager."
<> header "dconf2nix - Nixify dconf configuration files"
)
let
opts = info
(helper <*> versionOpt <*> (stdinArgs <|> fileArgs))
( fullDesc
<> progDesc
"Convert a dconf file into a Nix file, as expected by Home Manager."
<> header "dconf2nix - Nixify dconf configuration files"
)
in execParser opts
6 changes: 4 additions & 2 deletions src/DConf/Data.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ data Verbosity = Normal | Verbose

newtype Nix = Nix { unNix :: Text } deriving Show

newtype Root = Root Text deriving (Eq, Show)

newtype Key = Key Text deriving (Eq, Ord, Show)

data Value = S Text
Expand All @@ -28,6 +30,6 @@ type Header = Text
type Content = Map Key Value

data Entry = Entry
{ header :: Header
, content :: Content
{ entryHeader :: Header
, entryContent :: Content
} deriving (Eq, Show)
17 changes: 9 additions & 8 deletions src/DConf2Nix.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,26 @@ import Text.Parsec ( ParseError
, runParser
)

dconf2nixFile :: InputFilePath -> OutputFilePath -> Verbosity -> IO ()
dconf2nixFile (InputFilePath input) (OutputFilePath output) v = do
dconf2nixFile :: InputFilePath -> OutputFilePath -> Root -> Verbosity -> IO ()
dconf2nixFile (InputFilePath input) (OutputFilePath output) root v = do
parsed <- parseFromFile (dconfParser v) input
handler (T.writeFile output) (T.appendFile output) parsed
handler (T.writeFile output) (T.appendFile output) root parsed

dconf2nixStdin :: Verbosity -> IO ()
dconf2nixStdin v = do
dconf2nixStdin :: Root -> Verbosity -> IO ()
dconf2nixStdin root v = do
input <- T.getContents
handler T.putStr T.putStr $ runParser (dconfParser v) () "<stdin>" input
handler T.putStr T.putStr root $ runParser (dconfParser v) () "<stdin>" input

handler
:: (T.Text -> IO ())
-> (T.Text -> IO ())
-> Root
-> Either ParseError [Entry]
-> IO ()
handler writer appender parsed = do
handler writer appender root parsed = do
case parsed of
Left err -> error $ show err
Right xs -> do
writer Nix.renderHeader
traverse (\e -> appender (unNix $ Nix.renderEntry e)) xs
traverse (\e -> appender (unNix $ Nix.renderEntry e root)) xs
appender Nix.renderFooter
23 changes: 15 additions & 8 deletions src/Nix.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,22 @@ renderHeader = T.unlines
]

renderFooter :: Header
renderFooter = T.unlines
[ " };"
, "}"
]
renderFooter = T.unlines [" };", "}"]

normalizeRoot :: T.Text -> T.Text
normalizeRoot r | T.null r = r
| T.isSuffixOf "/" r = T.dropWhile (== '/') r
| otherwise = T.dropWhile (== '/') r <> "/"

normalizeHeader :: Header -> Root -> Header
normalizeHeader "/" (Root r) = T.dropWhileEnd (== '/') (normalizeRoot r) <> ""
normalizeHeader h (Root r) = normalizeRoot r <> h

renderEntry :: Entry -> Nix
renderEntry (Entry h c) =
let header = " \"" <> h <> "\" = {\n"
body = Map.toList c >>= \(Key k, v) ->
renderEntry :: Entry -> Root -> Nix
renderEntry (Entry h c) root =
let header =
" \"" <> normalizeHeader h root <> "\" = {\n"
body = Map.toList c >>= \(Key k, v) ->
T.unpack $ " " <> k <> " = " <> unNix (renderValue v) <> "\n"
close = " };\n\n"
in Nix $ header <> T.pack body <> close
Expand Down
42 changes: 34 additions & 8 deletions test/DConf2NixTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ where
import Data.IORef
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Data.Text ( Text )
import DConf ( dconfParser )
import DConf2Nix ( handler )
import DConf.Data
Expand All @@ -18,17 +17,44 @@ import Text.Parsec ( runParser )
prop_dconf2nix :: Property
prop_dconf2nix = withTests (10 :: TestLimit) dconf2nix

dconf2nix :: Property
dconf2nix = property $ do
input <- evalIO $ T.readFile "data/dconf.settings"
output <- evalIO $ T.readFile "output/dconf.nix"
ref <- evalIO $ newIORef ("" :: Text)
evalIO $ handler (writer ref) (writer ref) (entries input)
baseProperty :: FilePath -> FilePath -> Root -> Property
baseProperty i o root = property $ do
input <- evalIO $ T.readFile i
output <- evalIO $ T.readFile o
ref <- evalIO $ newIORef T.empty
evalIO $ handler (writer ref) (writer ref) root (entries input)
result <- evalIO $ readIORef ref
result === output
where
entries i = runParser (dconfParser Normal) () "<test>" i
entries = runParser (dconfParser Normal) () "<test>"
writer ref x = modifyIORef ref (`T.append` x)

dconf2nix :: Property
dconf2nix =
let input = "data/dconf.settings"
output = "output/dconf.nix"
root = Root T.empty
in baseProperty input output root

prop_dconf2nix_custom_root :: Property
prop_dconf2nix_custom_root = withTests (10 :: TestLimit) dconf2nixCustomRoot

dconf2nixCustomRoot :: Property
dconf2nixCustomRoot =
let input = "data/custom.settings"
output = "output/custom.nix"
root = Root "ca/desrt/dconf-editor"
in baseProperty input output root

prop_dconf2nix_root :: Property
prop_dconf2nix_root = withTests (10 :: TestLimit) dconf2nixRoot

dconf2nixRoot :: Property
dconf2nixRoot =
let input = "data/root.settings"
output = "output/root.nix"
root = Root "org/gnome/desktop/peripherals"
in baseProperty input output root

dconf2nixTests :: Group
dconf2nixTests = $$(discover)
6 changes: 3 additions & 3 deletions test/DConfTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ testInput = T.unlines

testOutput :: Entry
testOutput = Entry
{ header = "org/gnome/desktop/peripherals/mouse"
, content = M.fromList
[(Key "natural-scroll", B False), (Key "speed", D (-0.5))]
{ entryHeader = "org/gnome/desktop/peripherals/mouse"
, entryContent = M.fromList
[(Key "natural-scroll", B False), (Key "speed", D (-0.5))]
}

dconfParserTests :: Group
Expand Down

0 comments on commit cf976e0

Please sign in to comment.