Add user documentation
Add a manpage for ca-store. Additionally, modify the 'file verify' command to behave exactly as the manpage mentions. This commit required me to break a cycle caused by having CAStore.Type.Text imported by CAStore.Type.
This commit is contained in:
parent
1849baa588
commit
d2016d1863
9 changed files with 119 additions and 32 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,6 +5,7 @@
|
||||||
!flake.lock
|
!flake.lock
|
||||||
!package.yaml
|
!package.yaml
|
||||||
!app/Main.hs
|
!app/Main.hs
|
||||||
|
!doc/man/*.scd
|
||||||
!src/CAStore/Command.hs
|
!src/CAStore/Command.hs
|
||||||
!src/CAStore/Command/Autocomplete.hs
|
!src/CAStore/Command/Autocomplete.hs
|
||||||
!src/CAStore/Command/Type.hs
|
!src/CAStore/Command/Type.hs
|
||||||
|
|
|
||||||
73
doc/man/ca-store.1.scd
Normal file
73
doc/man/ca-store.1.scd
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
ca-store(1)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
ca-store - A simple content-addressable store with tagging support
|
||||||
|
|
||||||
|
# SYNOPSIS
|
||||||
|
|
||||||
|
*ca-store* [opts] store [command..]
|
||||||
|
|
||||||
|
# OPTIONS
|
||||||
|
|
||||||
|
## File commands
|
||||||
|
|
||||||
|
*file* *add* [file..]
|
||||||
|
Adds the given files to the store and returns the ids of these files,
|
||||||
|
one per line. The ids will be returned in the same order that the files
|
||||||
|
are given on the command line. This command is idempotent.
|
||||||
|
|
||||||
|
|
||||||
|
*file* *remove* [id..]
|
||||||
|
Remove the files from the store. This command is permanent, so it is
|
||||||
|
recommended to make a backup of the file. Also consider making a copy
|
||||||
|
of its tags as well with the *tag* *show* command.
|
||||||
|
|
||||||
|
*file* *verify* [id..]
|
||||||
|
Recalculate the ids of every id given to ensure they still match. Any
|
||||||
|
corrupted file will have its id printed to standard output.
|
||||||
|
|
||||||
|
## Tag commands
|
||||||
|
|
||||||
|
*tag* *add* id tag [tag..]
|
||||||
|
Add all of the given tags to the file referenced by 'id'.
|
||||||
|
|
||||||
|
*tag* *remove* id tag [tag..]
|
||||||
|
Remove all the given tags from the file referenced by 'id'. No error
|
||||||
|
will be raised if you attempt to remove a non-existent tag.
|
||||||
|
|
||||||
|
*tag* *show* id
|
||||||
|
Show all tags assigned to the file referenced by 'id'. No error will
|
||||||
|
be raised if you attempt to reference a non-existent file.
|
||||||
|
|
||||||
|
*tag* *super* *add* supertag [subtag..]
|
||||||
|
Declare the first tag to be a supertag to all other given tags. A
|
||||||
|
supertag is a tag that is automatically implied by any of its subtags.
|
||||||
|
|
||||||
|
A supertag cannot be a subtag of any of its subtags. *ca-store* will
|
||||||
|
silently ignore any attempt to make an infinite cycle of tags.
|
||||||
|
|
||||||
|
*tag* *super* *remove* supertag [subtag..]
|
||||||
|
Remove the supertag relationship between the supertag and its subtags.
|
||||||
|
|
||||||
|
If you wish for certain files to keep their supertags and not others,
|
||||||
|
manually add the supertag with the *tag* *add* command before running
|
||||||
|
*tag* *super* *remove*.
|
||||||
|
|
||||||
|
*tag* *super* *show* supertag
|
||||||
|
Show all subtags of the given supertag. If the given tag isn't a
|
||||||
|
supertag then nothing will be displayed.
|
||||||
|
|
||||||
|
*tag* *sub* *add* subtag [supertag..]
|
||||||
|
Declare the first tag to be a subtag to all other given tags. A subtag
|
||||||
|
is a tag that automatically implies any supertags.
|
||||||
|
|
||||||
|
A subtag cannot be a supertag of any of its supertags. *ca-store* will
|
||||||
|
silently ignore any attempt to make an infinite cycle of tags.
|
||||||
|
|
||||||
|
*tag* *sub* *remove* subtag [supertag..]
|
||||||
|
Remove the subtag relationship between the subtag and its supertags.
|
||||||
|
|
||||||
|
*tag* *sub* *show* subtag
|
||||||
|
Show all supertags of the given subtag. If the given tag isn't a
|
||||||
|
subtag then nothing will be displayed.
|
||||||
17
flake.nix
17
flake.nix
|
|
@ -17,11 +17,26 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
overlays.default = final: prev: {
|
overlays.default = final: prev: {
|
||||||
ca-store = final.haskellPackages.developPackage {
|
ca-store = prev.symlinkJoin {
|
||||||
|
pname = "ca-store";
|
||||||
|
version = final.ca-store-bin.version;
|
||||||
|
paths = [ final.ca-store-bin final.ca-store-man ];
|
||||||
|
};
|
||||||
|
ca-store-bin = prev.haskellPackages.developPackage {
|
||||||
root = ./.;
|
root = ./.;
|
||||||
name = "ca-store";
|
name = "ca-store";
|
||||||
withHoogle = false;
|
withHoogle = false;
|
||||||
};
|
};
|
||||||
|
ca-store-man = prev.stdenv.mkDerivation {
|
||||||
|
pname = "ca-store-man";
|
||||||
|
version = "0.0.1";
|
||||||
|
src = ./.;
|
||||||
|
nativeBuildInputs = [ final.scdoc final.installShellFiles ];
|
||||||
|
buildCommand = ''
|
||||||
|
scdoc < "$src/doc/man/ca-store.1.scd" > ./ca-store.1
|
||||||
|
installManPage ./ca-store.1
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ library:
|
||||||
- CAStore.Program.IO.Text
|
- CAStore.Program.IO.Text
|
||||||
- CAStore.Program.Storage
|
- CAStore.Program.Storage
|
||||||
- CAStore.Type
|
- CAStore.Type
|
||||||
- CAStore.Type.Text
|
|
||||||
- Data.List.Extra
|
- Data.List.Extra
|
||||||
|
|
||||||
executables:
|
executables:
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import CAStore.Program (Program, storeFile, unstoreFile, getFileLocation)
|
||||||
import CAStore.Program.IO
|
import CAStore.Program.IO
|
||||||
import CAStore.Program.IO.Text
|
import CAStore.Program.IO.Text
|
||||||
import CAStore.Program.Storage
|
import CAStore.Program.Storage
|
||||||
import CAStore.Type.Text
|
import CAStore.Type
|
||||||
import Control.Monad (forM_)
|
import Control.Monad (forM_, filterM, (<=<))
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import System.Directory (doesFileExist)
|
import System.Directory (doesFileExist)
|
||||||
|
|
||||||
|
|
@ -23,15 +23,10 @@ runCommand (FileAdd fs) = do
|
||||||
runCommand (FileRemove ss)
|
runCommand (FileRemove ss)
|
||||||
= unregisterFiles ss
|
= unregisterFiles ss
|
||||||
*> forM_ ss unstoreFile
|
*> forM_ ss unstoreFile
|
||||||
runCommand (FileVerify ss) = forM_ ss $ \sid -> do
|
runCommand (FileVerify ss)
|
||||||
file <- getFileLocation sid
|
= mapM_ (err . ErrCorruptStoreId)
|
||||||
liftIO (doesFileExist file) >>= \case
|
<=< filterM (fmap not . verifyFile)
|
||||||
True -> do
|
$ ss
|
||||||
sid' <- generateId file
|
|
||||||
case sid == sid' of
|
|
||||||
True -> msg $ MsgArb $ show sid ++ " is valid."
|
|
||||||
False -> err $ ErrArb $ show sid ++ " has been corrupted."
|
|
||||||
False -> err $ ErrArb $ show sid ++ " does not exist in the store."
|
|
||||||
runCommand (TagAdd sid ts) = do
|
runCommand (TagAdd sid ts) = do
|
||||||
registerTags ts
|
registerTags ts
|
||||||
assignTags sid ts
|
assignTags sid ts
|
||||||
|
|
@ -53,3 +48,11 @@ runCommand (TagSuperShow sup) = do
|
||||||
showRelationSuper sup
|
showRelationSuper sup
|
||||||
runCommand (TagSubShow sub) = do
|
runCommand (TagSubShow sub) = do
|
||||||
showRelationSub sub
|
showRelationSub sub
|
||||||
|
|
||||||
|
-- | Recalculate the store id of a file and check to see if it matches.
|
||||||
|
verifyFile :: StoreId -> Program Bool
|
||||||
|
verifyFile sid = do
|
||||||
|
file <- getFileLocation sid
|
||||||
|
liftIO (doesFileExist file) >>= \case
|
||||||
|
True -> ((==) sid) <$> generateId file
|
||||||
|
False -> pure True
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ where
|
||||||
|
|
||||||
import CAStore.Program.Internal (Program(..), getArguments, getConnectionHandle)
|
import CAStore.Program.Internal (Program(..), getArguments, getConnectionHandle)
|
||||||
import CAStore.Program.IO.Text (msg)
|
import CAStore.Program.IO.Text (msg)
|
||||||
import CAStore.Type.Text (Message(MsgArb))
|
import CAStore.Type (Message(MsgArb))
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Data.Foldable (for_)
|
import Data.Foldable (for_)
|
||||||
import Database.SQLite.Simple (Query, query_, fromOnly)
|
import Database.SQLite.Simple (Query, query_, fromOnly)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ module CAStore.Program.IO.Text
|
||||||
where
|
where
|
||||||
|
|
||||||
import CAStore.Program.Internal (Program(..))
|
import CAStore.Program.Internal (Program(..))
|
||||||
import CAStore.Type.Text
|
import CAStore.Type
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Data.Foldable1 (intercalate1)
|
import Data.Foldable1 (intercalate1)
|
||||||
import Data.List.NonEmpty (NonEmpty(..))
|
import Data.List.NonEmpty (NonEmpty(..))
|
||||||
|
|
@ -21,6 +21,8 @@ err (ErrInvalidCommand [])
|
||||||
= display $ "ERROR: No command specified"
|
= display $ "ERROR: No command specified"
|
||||||
err (ErrInvalidCommand (x:xs))
|
err (ErrInvalidCommand (x:xs))
|
||||||
= display $ "ERROR: Invalid command '" ++ intercalate1 " " (x :| xs) ++ "'"
|
= display $ "ERROR: Invalid command '" ++ intercalate1 " " (x :| xs) ++ "'"
|
||||||
|
err (ErrCorruptStoreId (StoreId x))
|
||||||
|
= display x
|
||||||
|
|
||||||
warn :: Warning -> Program ()
|
warn :: Warning -> Program ()
|
||||||
warn (WarnArb x) = display $ "WARN: " ++ x
|
warn (WarnArb x) = display $ "WARN: " ++ x
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ module CAStore.Type
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import CAStore.Type.Text
|
|
||||||
import Database.SQLite.Simple.FromField (FromField, fromField)
|
import Database.SQLite.Simple.FromField (FromField, fromField)
|
||||||
import Database.SQLite.Simple.ToField (ToField, toField)
|
import Database.SQLite.Simple.ToField (ToField, toField)
|
||||||
|
|
||||||
|
|
@ -47,3 +46,14 @@ parseStoreLocation x = pure $ StoreShort x
|
||||||
|
|
||||||
data OutputType = OutputId | OutputFilename
|
data OutputType = OutputId | OutputFilename
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
|
data Error
|
||||||
|
= ErrArb String
|
||||||
|
| ErrInvalidCommand [String]
|
||||||
|
| ErrCorruptStoreId StoreId
|
||||||
|
|
||||||
|
data Warning
|
||||||
|
= WarnArb String
|
||||||
|
|
||||||
|
data Message
|
||||||
|
= MsgArb String
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
module CAStore.Type.Text
|
|
||||||
( Error(..)
|
|
||||||
, Warning(..)
|
|
||||||
, Message(..)
|
|
||||||
)
|
|
||||||
where
|
|
||||||
|
|
||||||
data Error
|
|
||||||
= ErrArb String
|
|
||||||
| ErrInvalidCommand [String]
|
|
||||||
|
|
||||||
data Warning
|
|
||||||
= WarnArb String
|
|
||||||
|
|
||||||
data Message
|
|
||||||
= MsgArb String
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue