add CLI draft
This commit is contained in:
5
cli/CHANGELOG.md
Normal file
5
cli/CHANGELOG.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Revision history for cli
|
||||||
|
|
||||||
|
## 0.1.0.0 -- YYYY-mm-dd
|
||||||
|
|
||||||
|
* First version. Released on an unsuspecting world.
|
||||||
26
cli/LICENSE
Normal file
26
cli/LICENSE
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) 2024, Alexander Foremny
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
33
cli/app/API/Collection.hs
Normal file
33
cli/app/API/Collection.hs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
|
module API.Collection where
|
||||||
|
|
||||||
|
import Data.Aeson qualified as A
|
||||||
|
import Data.Aeson.KeyMap qualified as AM
|
||||||
|
import Data.Text qualified as T
|
||||||
|
import Process.Shell (Quotable (..), sh)
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
|
insert :: T.Text -> T.Text -> A.Object -> IO T.Text
|
||||||
|
insert
|
||||||
|
collectionName
|
||||||
|
fileName
|
||||||
|
( traceShowId -> AM.insert "$fileName" (A.String fileName) -> traceShowId ->
|
||||||
|
A.Object -> traceShowId -> contents
|
||||||
|
) =
|
||||||
|
{- TODO REST/ CRUD API
|
||||||
|
[sh|
|
||||||
|
curl -fsS http://localhost:8081/collections/#{collectionName}/#{filePath} \
|
||||||
|
--data #{contents}
|
||||||
|
\|]-}
|
||||||
|
[sh|
|
||||||
|
set -efux
|
||||||
|
curl -fsS http://localhost:8081 \
|
||||||
|
--data "INSERT "'#{contents}'" INTO #{collectionName}"
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- TODO sh
|
||||||
|
instance Quotable A.Value where
|
||||||
|
toString = toString . A.encode
|
||||||
88
cli/app/Main.hs
Normal file
88
cli/app/Main.hs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
{-# LANGUAGE NoFieldSelectors #-}
|
||||||
|
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import API.Collection qualified
|
||||||
|
import Control.Applicative ((<**>))
|
||||||
|
import Data.Aeson qualified as J
|
||||||
|
import Data.ByteString.Lazy qualified as LB
|
||||||
|
import Data.Text qualified as T
|
||||||
|
import Options.Applicative qualified as O
|
||||||
|
import Text.ParserCombinators.ReadP qualified as R
|
||||||
|
import Text.ParserCombinators.ReadPrec qualified as R
|
||||||
|
import Text.Read (Read (..))
|
||||||
|
|
||||||
|
data Args = Args
|
||||||
|
{ cmd :: Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
args :: O.Parser Args
|
||||||
|
args = Args <$> cmd_
|
||||||
|
|
||||||
|
data Cmd = Collection CollectionCmd
|
||||||
|
|
||||||
|
cmd_ :: O.Parser Cmd
|
||||||
|
cmd_ =
|
||||||
|
O.hsubparser . mconcat $
|
||||||
|
[ O.command "collection" . O.info collectionCmd $
|
||||||
|
O.progDesc "Manage content collections"
|
||||||
|
]
|
||||||
|
|
||||||
|
data CollectionCmd = CollectionInsert
|
||||||
|
{ filePath :: CollectionPath
|
||||||
|
}
|
||||||
|
|
||||||
|
data CollectionPath = CollectionPath
|
||||||
|
{ collectionName :: T.Text,
|
||||||
|
fileName :: T.Text
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Read CollectionPath where
|
||||||
|
readPrec = R.lift do
|
||||||
|
(T.pack -> collectionName) <- R.munch (/= '/')
|
||||||
|
_ <- R.string "/"
|
||||||
|
(T.pack -> fileName) <- do
|
||||||
|
fileName <- R.munch (liftA2 (&&) (/= '.') (/= '/'))
|
||||||
|
fileExt <- R.string ".json"
|
||||||
|
pure (fileName <> fileExt)
|
||||||
|
pure CollectionPath {..}
|
||||||
|
|
||||||
|
instance Show CollectionPath where
|
||||||
|
show (CollectionPath {collectionName, fileName}) =
|
||||||
|
show (collectionName <> "/" <> fileName)
|
||||||
|
|
||||||
|
collectionCmd :: O.Parser Cmd
|
||||||
|
collectionCmd =
|
||||||
|
fmap Collection . O.hsubparser . mconcat $
|
||||||
|
[ O.command "insert" . O.info collectionInsertCmd $
|
||||||
|
O.progDesc "Insert an entity"
|
||||||
|
]
|
||||||
|
|
||||||
|
collectionInsertCmd :: O.Parser CollectionCmd
|
||||||
|
collectionInsertCmd =
|
||||||
|
CollectionInsert
|
||||||
|
<$> collectionPathArg
|
||||||
|
|
||||||
|
collectionPathArg :: O.Parser CollectionPath
|
||||||
|
collectionPathArg =
|
||||||
|
O.argument O.auto (O.metavar "COLLECTION_PATH")
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
O.execParser (O.info (args <**> O.helper) O.idm) >>= \case
|
||||||
|
Args
|
||||||
|
{ cmd =
|
||||||
|
Collection
|
||||||
|
CollectionInsert
|
||||||
|
{ filePath = CollectionPath {collectionName, fileName}
|
||||||
|
}
|
||||||
|
} ->
|
||||||
|
print
|
||||||
|
=<< API.Collection.insert collectionName fileName
|
||||||
|
=<< J.throwDecode
|
||||||
|
=<< LB.getContents
|
||||||
24
cli/cli.cabal
Normal file
24
cli/cli.cabal
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
cabal-version: 3.4
|
||||||
|
name: cli
|
||||||
|
version: 0.1.0.0
|
||||||
|
license: BSD-2-Clause
|
||||||
|
license-file: LICENSE
|
||||||
|
maintainer: aforemny@posteo.de
|
||||||
|
author: Alexander Foremny
|
||||||
|
build-type: Simple
|
||||||
|
extra-doc-files: CHANGELOG.md
|
||||||
|
|
||||||
|
executable cli
|
||||||
|
main-is: Main.hs
|
||||||
|
hs-source-dirs: app
|
||||||
|
other-modules: API.Collection
|
||||||
|
default-language: GHC2021
|
||||||
|
ghc-options: -Wall
|
||||||
|
build-depends:
|
||||||
|
aeson,
|
||||||
|
base,
|
||||||
|
bytestring,
|
||||||
|
filepath,
|
||||||
|
optparse-applicative,
|
||||||
|
sh,
|
||||||
|
text
|
||||||
22
docs/get-started-cli.md
Normal file
22
docs/get-started-cli.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Get started with the CLI
|
||||||
|
|
||||||
|
## Create a new project
|
||||||
|
|
||||||
|
Create a new folder for your project, `my-project`. Change into it, and set `AMCS_CONTENT` to the folder that should store your content.
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir -p my-project
|
||||||
|
cd my-project
|
||||||
|
export ACMS_CONTENT=$PWD/content
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create a restaurant collection
|
||||||
|
|
||||||
|
```
|
||||||
|
acms collection insert restaurant/1.json <<'EOF'
|
||||||
|
{
|
||||||
|
"name": "Biscotte Restaurant",
|
||||||
|
"description": "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers."
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
```
|
||||||
4
docs/get-started.md
Normal file
4
docs/get-started.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Get started
|
||||||
|
|
||||||
|
- [Get started with the CLI](./get-started-cli.md)
|
||||||
|
- [Get started with the web interface](./get-started-web-interface.md)
|
||||||
Reference in New Issue
Block a user