Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,25 @@ jobs:

- name: run check
run: make rpc-check


########################
# SQL compile and check
########################
sqlc-check:
name: SQL compilation check
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v2

- name: setup go ${{ env.GO_VERSION }}
uses: actions/setup-go@v2
with:
go-version: '~${{ env.GO_VERSION }}'

- name: run check
run: make sqlc-check

########################
# go mod check
########################
Expand Down Expand Up @@ -85,6 +103,26 @@ jobs:
- name: lint
run: make lint

########################
# Verify documentation
########################
docs-check:
name: verify that auto-generated documentation is up-to-date
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: setup go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: '~${{ env.GO_VERSION }}'

- name: check
run: make docs-check

########################
# run unit tests
########################
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ sqlc-check: sqlc
@$(call print, "Verifying sql code generation.")
if test -n "$$(git status --porcelain '*.go')"; then echo "SQL models not properly generated!"; git status --porcelain '*.go'; exit 1; fi

docs: build
@$(call print, "Building man and markdown files in docs/")
./loop-debug man > docs/loop.1
./loop-debug markdown > docs/loop.md

docs-check: docs
@$(call print, "Verifying man and markdown files in docs/")
if test -n "$$(git status --porcelain 'docs/loop.*')"; then echo "Man and markdown files not properly generated!"; git diff; exit 1; fi

fsm:
@$(call print, "Generating state machine docs")
./scripts/fsm-generate.sh;
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ loop in <amt_in_satoshis>
```

### More info
For more information about using Loop checkout our [Loop FAQs](./docs/faqs.md).

- [Loop FAQs](./docs/faqs.md)
- [Loop CLI manual](./docs/loop.md)

## Development

Expand Down
21 changes: 10 additions & 11 deletions cmd/loop/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,32 @@ import (
"context"

"github.com/lightninglabs/loop/looprpc"
"github.com/urfave/cli"
"github.com/urfave/cli/v3"
)

func init() {
// Register the debug command.
commands = append(commands, forceAutoloopCmd)
}

var forceAutoloopCmd = cli.Command{
var forceAutoloopCmd = &cli.Command{
Name: "forceautoloop",
Usage: `
Forces to trigger an autoloop step, regardless of the current internal
autoloop timer. THIS MUST NOT BE USED IN A PROD ENVIRONMENT.
`,
Action: forceAutoloop,
Hidden: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command is already hidden behind the dev build flag, but nothing wrong with adding extra hidden flag.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The man and the markdown are built using loop-debug binary built by make build. That target builds with "dev" tag.

}

func forceAutoloop(ctx *cli.Context) error {
client, cleanup, err := getDebugClient(ctx)
func forceAutoloop(ctx context.Context, cmd *cli.Command) error {
client, cleanup, err := getDebugClient(ctx, cmd)
if err != nil {
return err
}
defer cleanup()

cfg, err := client.ForceAutoLoop(
context.Background(), &looprpc.ForceAutoLoopRequest{},
)
cfg, err := client.ForceAutoLoop(ctx, &looprpc.ForceAutoLoopRequest{})
if err != nil {
return err
}
Expand All @@ -43,13 +42,13 @@ func forceAutoloop(ctx *cli.Context) error {
return nil
}

func getDebugClient(ctx *cli.Context) (looprpc.DebugClient, func(), error) {
rpcServer := ctx.GlobalString("rpcserver")
tlsCertPath, macaroonPath, err := extractPathArgs(ctx)
func getDebugClient(ctx context.Context, cmd *cli.Command) (looprpc.DebugClient, func(), error) {
rpcServer := cmd.String("rpcserver")
tlsCertPath, macaroonPath, err := extractPathArgs(cmd)
if err != nil {
return nil, nil, err
}
conn, err := getClientConn(rpcServer, tlsCertPath, macaroonPath)
conn, err := getClientConn(ctx, rpcServer, tlsCertPath, macaroonPath)
if err != nil {
return nil, nil, err
}
Expand Down
152 changes: 152 additions & 0 deletions cmd/loop/docs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package main

import (
"context"
_ "embed"
"fmt"

docs "github.com/urfave/cli-docs/v3"
"github.com/urfave/cli/v3"
)

//go:embed markdown_tabular.md.gotmpl
var markdownTabularDocTemplate string

// We have a copy of this template taken from
// https://github.com/urfave/cli-docs where we remove column
// "Environment variables" if it has no values.
// TODO: remove this when https://github.com/urfave/cli-docs/pull/15
// is merged.
func init() {
docs.MarkdownTabularDocTemplate = markdownTabularDocTemplate
}

var printManCommand = &cli.Command{
Name: "man",
Usage: "prints man file",
Description: "Prints documentation of loop CLI in man format",
Action: printMan,
Hidden: true,
}

func printMan(_ context.Context, cmd *cli.Command) error {
root := filterNestedHelpCommands(cmd.Root())

const userCommandsSection = 1
man, err := docs.ToManWithSection(root, userCommandsSection)
if err != nil {
return fmt.Errorf("failed to produce man: %w", err)
}

fmt.Println(man)

return nil
}

var printMarkdownCommand = &cli.Command{
Name: "markdown",
Usage: "prints markdown file",
Description: "Prints documentation of loop CLI in markdown format",
Action: printMarkdown,
Hidden: true,
}

func printMarkdown(_ context.Context, cmd *cli.Command) error {
root := filterNestedHelpCommands(cmd.Root())

md, err := docs.ToTabularMarkdown(root, "loop")
if err != nil {
return fmt.Errorf("failed to produce man: %w", err)
}

fmt.Println(md)

return nil
}

// filterNestedHelpCommands clones cmd, drops nested help commands, and normalises
// flag defaults so generated documentation avoids absolute paths.
func filterNestedHelpCommands(cmd *cli.Command) *cli.Command {
cloned := cloneCommand(cmd, 0)
overrideDocFlags(cloned)
return cloned
}

// cloneCommand clones the command, filtering out nested "help" subcommands.
func cloneCommand(cmd *cli.Command, depth int) *cli.Command {
if cmd == nil {
return nil
}

cloned := *cmd
if len(cmd.Commands) == 0 {
return &cloned
}

filtered := make([]*cli.Command, 0, len(cmd.Commands))
for _, sub := range cmd.Commands {
if sub == nil {
continue
}
childDepth := depth + 1

// TODO: remove when https://github.com/urfave/cli-docs/pull/16
if childDepth > 0 && sub.Name == "help" {
continue
}

filtered = append(filtered, cloneCommand(sub, childDepth))
}

cloned.Commands = filtered
return &cloned
}

// overrideDocFlags walks the command tree and replaces string flag defaults
// that leak user-specific filesystem paths, keeping generated docs stable.
func overrideDocFlags(cmd *cli.Command) {
if cmd == nil {
return
}

if len(cmd.Flags) > 0 {
clonedFlags := make([]cli.Flag, len(cmd.Flags))
for i, fl := range cmd.Flags {
clonedFlags[i] = cloneFlagWithOverrides(fl)
}
cmd.Flags = clonedFlags
}

for _, sub := range cmd.Commands {
overrideDocFlags(sub)
}
}

// docFlagOverrides maps global flag names to the canonical values we want to
// show in documentation instead of user-specific absolute paths.
var docFlagOverrides = map[string]string{
loopDirFlag.Name: "~/.loop",
tlsCertFlag.Name: "~/.loop/mainnet/tls.cert",
macaroonPathFlag.Name: "~/.loop/mainnet/loop.macaroon",
}

// cloneFlagWithOverrides returns a copy of flag with overridden default values
// when the flag participates in docFlagOverrides. Non-string flags are reused
// unchanged to minimise allocations.
func cloneFlagWithOverrides(flag cli.Flag) cli.Flag {
sf, ok := flag.(*cli.StringFlag)
if !ok {
return flag
}

value, ok := docFlagOverrides[sf.Name]
if !ok {
return flag
}

cloned := *sf
cloned.Value = value
cloned.DefaultText = value

return &cloned
}
12 changes: 5 additions & 7 deletions cmd/loop/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"context"

"github.com/lightninglabs/loop/looprpc"
"github.com/urfave/cli"
"github.com/urfave/cli/v3"
)

var getInfoCommand = cli.Command{
var getInfoCommand = &cli.Command{
Name: "getinfo",
Usage: "show general information about the loop daemon",
Description: "Displays general information about the daemon like " +
Expand All @@ -16,16 +16,14 @@ var getInfoCommand = cli.Command{
Action: getInfo,
}

func getInfo(ctx *cli.Context) error {
client, cleanup, err := getClient(ctx)
func getInfo(ctx context.Context, cmd *cli.Command) error {
client, cleanup, err := getClient(ctx, cmd)
if err != nil {
return err
}
defer cleanup()

cfg, err := client.GetInfo(
context.Background(), &looprpc.GetInfoRequest{},
)
cfg, err := client.GetInfo(ctx, &looprpc.GetInfoRequest{})
if err != nil {
return err
}
Expand Down
Loading