life-sync 1.0 → 1.0.1
raw patch · 12 files changed
+58/−42 lines, 12 filesdep +exceptionsdep +reludedep −universumdep ~tomland
Dependencies added: exceptions, relude
Dependencies removed: universum
Dependency ranges changed: tomland
Files
- CHANGELOG.md +6/−2
- README.md +24/−21
- life-sync.cabal +4/−3
- src/Life/Configuration.hs +12/−8
- src/Life/Github.hs +2/−2
- src/Life/Main/Add.hs +1/−0
- src/Life/Main/Init.hs +1/−1
- src/Life/Main/Push.hs +1/−0
- src/Life/Main/Remove.hs +1/−0
- src/Life/Message.hs +2/−2
- src/Prelude.hs +3/−3
- test/Test/Roundtrip.hs +1/−0
CHANGELOG.md view
@@ -4,9 +4,13 @@ life-sync uses [PVP Versioning][1]. The change log is available [on GitHub][2]. -[1]: https://pvp.haskell.org-[2]: https://github.com/kowainik/life-sync/releases+# 1.0.1 +* Switch to `relude`.+ # 1.0 * Initially created.++[1]: https://pvp.haskell.org+[2]: https://github.com/kowainik/life-sync/releases
README.md view
@@ -6,8 +6,8 @@ [](http://stackage.org/lts/package/life-sync) [](http://stackage.org/nightly/package/life-sync) -`life-sync` is a CLI tool that makes it easier to synchronize `dotfiles`-repository with personal configs across multiple machines.+`life-sync` is a CLI tool that makes it easier to synchronize a repository of +personal config files across multiple machines. ## Motivation @@ -18,24 +18,30 @@ 2. Useful bash aliases and other miscellaneous shell settings. 3. Git configuration. -And much more! But sometimes you start working from a new fresh machine without-having your settings within touch, like in these situations:+And much more! But sometimes you start working from a fresh machine without+having your settings within reach, as in these situations: 1. You bought a new PC or laptop.-2. You might reinstall your system on your working machine.+2. You reinstalled the operating system on your machine. 3. You were given a new laptop at work. Every time this happens, you need to walk through the tedious process of copying your data again. It's a well-known practice to-[store configs in `dotfiles` GitHub repository](https://dotfiles.github.io/).+[store configs in a `dotfiles` GitHub repository](https://dotfiles.github.io/). And `life-sync` makes it much easier to maintain this repository! With a single-command, your can copy every file and directory from `dotfiles` repository to+command, your can copy every file and directory from your `dotfiles` repository to your machine. Or update your remote `dotfiles` repository after multiple local changes to different files. +## Prerequisites++* [`git`](https://git-scm.com)+* [`hub`](https://github.com/github/hub)+* SSH access to Github configured+ ## Installation -Installation process can be done with one simple command:+Install with one simple command: ```shell $ cabal install life-sync@@ -47,7 +53,7 @@ $ stack install life-sync-1.0 ``` -You can turn on the bash auto-completion by running the following command:+You can turn on bash auto-completion by running the following command: ``` $ source <(life --bash-completion-script `which life`)@@ -55,10 +61,7 @@ ## Usage -> **NOTE:** make sure you configured SSH for your Github. `life-sync` assumes-> that you have SSH configured.--After installing `life-sync` you need to call command `life` with specified options:+After installing `life-sync` you need to call the command `life` with specified options: ``` $ life --help@@ -98,25 +101,25 @@ ``` -> **NOTE:** If some command takes a path to a file or a directory as an+> **NOTE:** If a command takes a path to a file or a directory as an > argument, the path should be specifed relative to the home directory. `life-sync` keeps the structure of your `dotfiles` repository in its own file-called `.life` which is stored in `dotfiles` repository as well.+called `.life` which is also stored in your `dotfiles` repository. -You can see an example of `dotfiles` repository maintained by `life-sync` here:+You can see an example of a `dotfiles` repository maintained by `life-sync` here: * [ChShersh/dotfiles](https://github.com/ChShersh/dotfiles) ## Examples -### Create `dotfiles` repository for the first time+### Create a `dotfiles` repository for the first time ``` $ life init MyGithubName ``` -### Track new file or directory+### Track a new file or directory To track a file: @@ -130,15 +133,15 @@ $ life add -d path/to/dir/relative/from/home ``` -To stop tracking some file, use `life remove` command instead.+To stop tracking some file, use `life remove` instead. -### Push all changes to remote repository+### Push all changes to the remote repository ``` $ life push ``` -### Pull all changes from remote repository+### Pull all changes from the remote repository To pull every file and directory:
life-sync.cabal view
@@ -1,5 +1,5 @@ name: life-sync-version: 1.0+version: 1.0.1 description: Synchronize personal configs across multiple machines homepage: https://github.com/kowainik/life-sync bug-reports: https://github.com/kowainik/life-sync/issues@@ -40,14 +40,15 @@ , ansi-terminal , bytestring , containers+ , exceptions , fmt , microlens-platform , path , path-io , process+ , relude >= 0.1.0 , text >= 1.2- , tomland >= 0.2.1- , universum >= 1.2.0+ , tomland ^>= 0.3 ghc-options: -Wall default-language: Haskell2010
src/Life/Configuration.hs view
@@ -33,18 +33,19 @@ , writeGlobalLife ) where +import Control.Monad.Catch (MonadThrow (..)) import Fmt (indentF, unlinesF, (+|), (|+))-import Lens.Micro.Platform (makeFields)+import Lens.Micro.Platform (makeFields, (.~), (^.)) import Path (Dir, File, Path, Rel, fromAbsFile, parseRelDir, parseRelFile, toFilePath, (</>))-import Toml (BiToml, Valuer (..), (.=))+import Toml (AnyValue (..), BiToml, Prism (..), (.=)) import Life.Shell (lifePath, relativeToHome, repoName) import qualified Data.Set as Set+import qualified Data.Text as T import qualified Text.Show as Show import qualified Toml - -- | Data type to represent either file or directory. data LifePath = File FilePath | Dir FilePath deriving (Show)@@ -102,11 +103,14 @@ corpseConfiguationT :: BiToml CorpseConfiguration corpseConfiguationT = CorpseConfiguration- <$> Toml.arrayOf stringV "files" .= corpseFiles- <*> Toml.arrayOf stringV "directories" .= corpseDirectories+ <$> Toml.arrayOf _String "files" .= corpseFiles+ <*> Toml.arrayOf _String "directories" .= corpseDirectories where- stringV :: Valuer 'Toml.TString String- stringV = Valuer (Toml.matchText >=> pure . toString) (Toml.String . toText)+ _String :: Prism AnyValue String+ _String = Prism+ { preview = \(AnyValue t) -> Toml.matchText t >>= pure . toString+ , review = AnyValue . Toml.Text . toText+ } resurrect :: MonadThrow m => CorpseConfiguration -> m LifeConfiguration resurrect CorpseConfiguration{..} = do@@ -131,7 +135,7 @@ render :: Text -> Set (Path b t) -> Maybe Text render key paths = do let prefix = key <> " = "- let array = renderStringArray (length prefix) (map show $ toList paths)+ let array = renderStringArray (T.length prefix) (map show $ toList paths) if not printIfEmpty && null paths then Nothing
src/Life/Github.hs view
@@ -21,7 +21,7 @@ , updateFromRepo ) where -import Control.Exception (throwIO)+import Control.Exception (catch, throwIO) import Path (Abs, Dir, File, Path, Rel, toFilePath, (</>)) import Path.IO (copyDirRecur, copyFile, getHomeDir, withCurrentDir) import System.IO.Error (IOError, isDoesNotExistError)@@ -67,7 +67,7 @@ ---------------------------------------------------------------------------- -- | Executes action with 'repoName' set as pwd.-insideRepo :: (MonadIO m, MonadMask m) => m a -> m a+insideRepo :: IO a -> IO a insideRepo action = do repoPath <- relativeToHome repoName withCurrentDir repoPath action
src/Life/Main/Add.hs view
@@ -6,6 +6,7 @@ ( lifeAdd ) where +import Lens.Micro.Platform (Lens', (%~)) import Path (Abs, Dir, File, Path, Rel, parent, toFilePath, (</>)) import Path.IO (copyDirRecur, copyFile, doesDirExist, doesFileExist, ensureDir, getHomeDir, makeRelative, resolveDir, resolveFile)
src/Life/Main/Init.hs view
@@ -89,7 +89,7 @@ ) partitionM :: forall f m a . (Monad m, Foldable f) => (a -> m Bool) -> f a -> m ([a], [a])-partitionM check = foldM partitionAction ([], [])+partitionM check = foldlM partitionAction ([], []) where partitionAction :: ([a], [a]) -> a -> m ([a], [a]) partitionAction (ifTrue, ifFalse) a = check a >>= \case
src/Life/Main/Push.hs view
@@ -6,6 +6,7 @@ ( lifePush ) where +import Lens.Micro.Platform ((^.)) import Path (Abs, Path, Rel, toFilePath, (</>)) import Path.IO (doesDirExist, doesFileExist, removeDirRecur, removeFile)
src/Life/Main/Remove.hs view
@@ -6,6 +6,7 @@ ( lifeRemove ) where +import Lens.Micro.Platform (Lens', (%~)) import Path (Abs, Path, Rel) import Path.IO (getHomeDir, makeRelative, removeDirRecur, removeFile, resolveDir, resolveFile)
src/Life/Message.hs view
@@ -23,7 +23,7 @@ import System.IO (hFlush) import qualified Data.Text as T-import qualified Universum.Unsafe as Unsafe+import qualified Relude.Unsafe as Unsafe ---------------------------------------------------------------------------- -- Ansi-terminal@@ -65,7 +65,7 @@ promptNonEmpty :: IO Text promptNonEmpty = do res <- T.strip <$> prompt- if null res+ if T.null res then warningMessage "The answer shouldn't be empty" >> promptNonEmpty else pure res
src/Prelude.hs view
@@ -1,7 +1,7 @@--- | Uses @universum@ as default prelude.+-- | Uses @relude@ as default prelude. module Prelude- ( module Universum+ ( module Relude ) where -import Universum+import Relude
test/Test/Roundtrip.hs view
@@ -1,5 +1,6 @@ module Test.Roundtrip where +import Data.Foldable (foldr1) import Hedgehog (Gen, Property, forAll, property, tripping) import Path.Internal (Path (Path)) import System.FilePath (pathSeparator, (</>))