Skip to content

Commit 79d5b61

Browse files
add: support for markdown docopts.md
1 parent 6656185 commit 79d5b61

13 files changed

Lines changed: 266 additions & 18 deletions

File tree

common.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333
const OPSFILE = "opsfile.yml"
3434
const OPSROOT = "opsroot.json"
3535
const DOCOPTS_TXT = "docopts.txt"
36-
const DOCOPTS_MD = "docopts.txt"
36+
const DOCOPTS_MD = "docopts.md"
3737

3838
const PREREQ = "prereq.yml"
3939
const CONFIGFILE = "config.json"

ops.go

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ import (
2424
"sort"
2525
"strings"
2626

27+
"github.com/a8m/envsubst/parse"
28+
"github.com/apache/openserverless-cli/tools"
2729
docopt "github.com/docopt/docopt-go"
2830
"github.com/mitchellh/go-homedir"
2931
"golang.org/x/exp/slices"
3032
"gopkg.in/yaml.v3"
31-
32-
envsubst "github.com/nuvolaris/envsubst/cmd/envsubstmain"
3333
)
3434

3535
type TaskNotFoundErr struct {
@@ -40,18 +40,19 @@ func (e *TaskNotFoundErr) Error() string {
4040
return fmt.Sprintf("no command named %s found", e.input)
4141
}
4242

43-
func help() error {
44-
if os.Getenv("OPS_NO_DOCOPTS") == "" && exists(".", DOCOPTS_TXT) {
45-
os.Args = []string{"envsubst", "-no-unset", "-i", DOCOPTS_TXT}
46-
return envsubst.EnvsubstMain()
43+
func help(helpMessage string) error {
44+
45+
if helpMessage != "" {
46+
fmt.Println(helpMessage)
47+
return nil
4748
}
49+
4850
// In case of syntax error, Task will return an error
4951
list := "-l"
5052
if os.Getenv("OPS_NO_DOCOPTS") != "" {
5153
list = "--list-all"
5254
}
5355
_, err := Task("-t", OPSFILE, list)
54-
5556
return err
5657
}
5758

@@ -152,6 +153,55 @@ func loadSavedArgs() []string {
152153
return res
153154
}
154155

156+
// read docpts
157+
// return the doppts and the help text
158+
// expand the environment variables
159+
// if the file is markdown expand the markdown
160+
func readDocOpts() (string, string) {
161+
if os.Getenv("OPS_NO_DOCOPTS") != "" {
162+
if exists(".", DOCOPTS_TXT) {
163+
fmt.Printf("Warning: ignoring %s - you have to provide all the options.\n", DOCOPTS_TXT)
164+
}
165+
if exists(".", DOCOPTS_MD) {
166+
fmt.Printf("Warning: ignoring %s - you have to provide all the options.\n", DOCOPTS_MD)
167+
}
168+
return "", ""
169+
}
170+
if exists(".", DOCOPTS_MD) {
171+
text := readfile(DOCOPTS_MD)
172+
173+
// parse embedded variables
174+
restrictions := &parse.Restrictions{false, false, true}
175+
result, err := (&parse.Parser{Name: "string", Env: os.Environ(), Restrict: restrictions, Mode: parse.AllErrors}).Parse(text)
176+
if err != nil {
177+
return "", err.Error()
178+
}
179+
// convert to markdown
180+
help := tools.MarkdownToText(result)
181+
// extract the embedded usage
182+
opts := tools.ExtractUsage(result)
183+
184+
// warn if there is a docopts.txt
185+
if exists(".", DOCOPTS_TXT) {
186+
help = fmt.Sprintf("%s\nWarning: both %s and %s are present, %s ignored.",
187+
help, DOCOPTS_TXT, DOCOPTS_MD, DOCOPTS_TXT)
188+
}
189+
return opts, help
190+
}
191+
192+
if exists(".", DOCOPTS_TXT) {
193+
text := readfile(DOCOPTS_TXT)
194+
restrictions := &parse.Restrictions{false, false, true}
195+
help, err := (&parse.Parser{Name: "string", Env: os.Environ(), Restrict: restrictions, Mode: parse.AllErrors}).Parse(text)
196+
if err != nil {
197+
help = err.Error()
198+
}
199+
return help, help
200+
}
201+
202+
return "", ""
203+
}
204+
155205
// Ops parses args moving into the folder corresponding to args
156206
// then parses them with docopts and invokes the task
157207
func Ops(base string, args []string) error {
@@ -209,9 +259,12 @@ func Ops(base string, args []string) error {
209259
}
210260
}
211261

262+
// read docopts and help text
263+
opts, helpMessage := readDocOpts()
264+
265+
// print help
212266
if len(rest) == 0 || rest[0] == "help" {
213-
trace("print help")
214-
err := help()
267+
err := help(helpMessage)
215268
if !isSubCmd {
216269
fmt.Println()
217270
return printPluginsHelp()
@@ -222,18 +275,22 @@ func Ops(base string, args []string) error {
222275
// load saved args
223276
savedArgs := loadSavedArgs()
224277

225-
// parsed args
226-
if os.Getenv("OPS_NO_DOCOPTS") == "" && exists(".", DOCOPTS_TXT) {
278+
// parse options if an opts file is available
279+
trace("DOCOPTS:", opts)
280+
if opts != "" {
227281
debug("PREPARSE:", rest)
228-
opts := readfile(DOCOPTS_TXT)
229-
trace("DOCOPTS: size=", len(opts))
282+
283+
// parse args
230284
parsedArgs := parseArgs(opts, rest)
231285
trace("DOCOPTS: parsedargs=", parsedArgs)
286+
287+
// append -t optfile.yml to the Task cli
232288
prefix := []string{"-t", OPSFILE}
233289
if len(rest) > 0 && rest[0][0] != '-' {
234290
prefix = append(prefix, rest[0])
235291
}
236292

293+
// parse args
237294
parsedArgs = append(savedArgs, parsedArgs...)
238295
parsedArgs = append(prefix, parsedArgs...)
239296
extra := os.Getenv("EXTRA")

tests/base64.bats

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ setup() {
2323

2424
@test "-base64 help message" {
2525
run ops -base64
26-
assert_line "Usage: ops -base64 [options] <string>"
26+
assert_line --partial "ops -base64 [options] <string>"
2727

2828
run ops -base64 -h
29-
assert_line "Usage: ops -base64 [options] <string>"
29+
assert_line --partial "ops -base64 [options] <string>"
3030
}
3131

3232
@test "-base64 --encode" {

tests/docopts.bats

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
setup() {
19+
load 'test_helper/bats-support/load'
20+
load 'test_helper/bats-assert/load'
21+
export NO_COLOR=1
22+
}
23+
24+
@test "legacy docops without markdown" {
25+
# show the legacy docopts.txt
26+
run ops docopts legacy
27+
assert_success
28+
assert_line --partial "legacy simple [-f]"
29+
run ops docopts legacy simple
30+
assert_line --partial "simple without flag"
31+
run ops docopts legacy simple -f
32+
assert_line "simple with flag"
33+
}
34+
35+
@test "docops with markdown" {
36+
run ops docopts
37+
assert_success
38+
assert_line --partial "--------"
39+
assert_line --partial "Synopsis"
40+
assert_line --partial "simple [-f]"
41+
42+
run env OPS_NO_DOCOPTS=1 ops docopts simple _f=false
43+
assert_line --partial "Warning: ignoring docopts.md"
44+
assert_line "simple without flag"
45+
run env OPS_NO_DOCOPTS=1 ops docopts simple _f=true
46+
assert_line --partial "Warning: ignoring docopts.md"
47+
assert_line "simple with flag"
48+
49+
run ops docopts simple
50+
assert_line "simple without flag"
51+
52+
run ops docopts simple -f
53+
assert_line "simple with flag"
54+
55+
run ops docopts simple -g
56+
assert_failure
57+
assert_line "Usage:"
58+
assert_line --partial "docopts simple [-f]"
59+
60+
}
61+
62+
@test "docops with both" {
63+
# show the docopts.txt with a warning
64+
run ops docopts both
65+
assert_success
66+
refute_line "This should be ignored"
67+
assert_line --partial "both simple [-f]"
68+
assert_line "Warning: both docopts.txt and docopts.md are present, docopts.txt ignored."
69+
70+
run ops docopts both simple -f
71+
assert_success
72+
assert_line "simple with flag"
73+
}
74+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Task `docopts both`
2+
3+
Simple task with flag
4+
5+
## Synopsis
6+
7+
```text
8+
Usage:
9+
both simple [-f]
10+
```
11+
12+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
This should be ignored
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
#
18+
version: "3"
19+
20+
tasks:
21+
simple:
22+
silent: true
23+
desc: simple task in other
24+
cmds:
25+
- |
26+
if {{.__f__}}
27+
then echo simple with flag
28+
else echo simple without flag
29+
fi

tests/olaris/docopts/docopts.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Task `docopts`
2+
3+
Simple task with flag
4+
5+
## Synopsis
6+
7+
```text
8+
Usage:
9+
docopts simple [-f]
10+
```
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Task: docopts legacy
2+
3+
Simple task with flag
4+
5+
Usage:
6+
legacy simple [-f]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
#
18+
version: "3"
19+
20+
tasks:
21+
simple:
22+
silent: true
23+
desc: simple task in other
24+
cmds:
25+
- |
26+
if {{._f}}
27+
then echo simple with flag
28+
else echo simple without flag
29+
fi

0 commit comments

Comments
 (0)