Skip to content

Commit

Permalink
Add a man page
Browse files Browse the repository at this point in the history
  • Loading branch information
zyedidia committed Jan 31, 2021
1 parent 7c780ae commit 799d8ca
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/cmd/sre/sre
/sre
/test.txt
/sre.1
26 changes: 26 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
VERSION = $(shell GOOS=$(shell go env GOHOSTOS) GOARCH=$(shell go env GOHOSTARCH) \
go run tools/build-version.go)
GOVARS = -X main.Version=$(VERSION)

build:
go build -trimpath -ldflags "-s -w $(GOVARS)" ./cmd/sre

install:
go install -trimpath -ldflags "-s -w $(GOVARS)" ./cmd/sre

sre.1: man/sre.md
pandoc man/sre.md -s -t man -o sre.1

package: build sre.1
mkdir sre-$(VERSION)
cp README.md sre-$(VERSION)
cp LICENSE sre-$(VERSION)
cp sre.1 sre-$(VERSION)
cp sre sre-$(VERSION)
tar -czf sre-$(VERSION).tar.gz sre-$(VERSION)

clean:
rm -f sre sre.1 sre-*.tar.gz
rm -rf sre-*/

.PHONY: build clean install package
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/zyedidia/sre
go 1.15

require (
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/jessevdk/go-flags v1.4.0
github.com/mattn/go-shellwords v1.0.11
github.com/zyedidia/gpeg v0.0.0-20210126031808-c49c92955001
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
github.com/blang/semver v1.1.0 h1:ol1rO7QQB5uy7umSNV7VAmLugfLRD+17sYJujRNYPhg=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/mattn/go-shellwords v1.0.11 h1:vCoR9VPpsk/TZFW2JwK5I9S0xdrtUq2bph6/YjEPnaw=
Expand Down
142 changes: 142 additions & 0 deletions man/sre.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
title: sre
section: 1
header: SRE Manual
---

# NAME
SRE - Structural Regular Expressions Tool

# SYNOPSIS
sre `[--version] [--help] [OPTIONS] EXPRESSION`

# DESCRIPTION
SRE is a tool for executing structural regular expressions from the command
line. SRE can be used to operate on streams of data and perform advanced
search and replace. For more information about structural regular
expressions, see Rob Pike's original description at
[http://doc.cat-v.org/bell_labs/structural_regexps/](http://doc.cat-v.org/bell_labs/structural_regexps/).

# COMMAND LANGUAGE

In a structural regular expression, regular expressions are composed using
commands to perform tasks like advanced search and replace. A command has an
input string and produces an output string. The following commands are
supported:

* **`p`**: prints the input string, and then returns the input string.
* **`d`**: returns the empty string.
* **`c/<s>/`**: returns the string **`<s>`**.
* **`s/<p>/<s>/`**: returns a string where occurrences of the regular expression
**`<p>`** have been replaced with **`<s>`**.
* **`g/<p>/<cmd>/`**: if **`<p>`** matches the input, returns the result of **`<cmd>`**
evaluated on the input. Otherwise returns the input with no modification.
* **`v/<p>/<cmd>/`**: if **`<p>`** does not match the input, returns the result of
**`<cmd>`** evaluated on the input. Otherwise returns the input with no
modification.
* **`x/<p>/<cmd>/`**: returns a string where all occurrences of the regular
expression **`<p>`** have been replaced with the return value of **`<cmd>`** applied
to the particular match.
* **`y/<p>/<cmd>/`**: returns a string where each part of the string that is not
matched by **`<cmd>`** is replaced by applying **`<cmd>`** to the particular
unmatched string.
* **`u/<sh>/`**: executes the shell command **`<sh>`** with the input as stdin and
returns the resulting stdout of the command. Shell commands use a simple
syntax where single or double quotes can be used to group arguments, and
environment variables are accessible with **`$`**. This command is only directly
available as part of the SRE CLI tool.

The SRE tool also provides an augmentation to the original SRE description from
Pike: command pipelines. A command may be given as **`<cmd> | <cmd> | ...`** where
the input of each command is the output of the previous one.

The syntax follows certain rules, such as using **`/`** as a delimiter. The
backslash (**`\`**) may be used to escape **`/`** or **`\`**, or to create
special characters such as **`\n`**, **`\r`**, or **`\t`**. The syntax also
supports specifying arbitrary bytes using octal, for example **`\14`**. Regular
expressions use the Go syntax described at
[https://golang.org/pkg/regexp/syntax/](https://golang.org/pkg/regexp/syntax/).

# EXAMPLES

Most of these examples are from Pike's description, so you can look there for
more detailed explanation. Since `p` is the only command that prints,
technically you must append `| p` to commands that search and replace, because
otherwise nothing will be printed. However, since you will probably forget to
do this, the SRE tool will print the result of the final command before
terminating if there were no calls to `p`. Thus when using the CLI tool you can
omit the `| p` in the following commands and still see the result.

Print all lines that contain "string":

```
x/.*\n/ g/string/p
```

Delete all occurrences of "string" and print the result:

```
x/string/d | p
```

Print all lines containing "rob" but not "robot":

```
x/.*\n/ g/rob v/robot/p
```

Capitalize all occurrences of the word "i":

```
x/[A-Za-z]+/ g/i/ v/../ c/I/ | p
```

or (more simply)

```
x/[A-Za-z]+/ g/^i$/ c/I/ | p
```

Change all occurrences of the complete word "foo" to "bar" except those
occurring in double or single quoted strings:

```
y/".*"/ y/'.*'/ x/[a-zA-Z0-9]+/ g/^foo$/ c/bar/ | p
```

Replace the complete word "TODAY" with the current date:

```
x/[A-Z]+/ g/^TODAY$/ u/date/ | p
```

Capitalize all words:

```
x/[a-zA-Z]+/ x/^./ u/tr a-z A-Z/ | p
```

Note: it is highly recommended that you enclose expressions in single or
double quotes to prevent your shell from interpreting special characters.

# OPTIONS
`-f, --file`

: Read input data from file (default: read from stdin).

`-v, --version`

: Show version information.

`-h, --help`

: Show this help message.


# BUGS

See GitHub Issues: <https://github.com/zyedidia/sre/issues>

# AUTHOR

Zachary Yedidia <[email protected]>
76 changes: 76 additions & 0 deletions tools/build-version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"fmt"
"os/exec"
"strings"

"github.com/blang/semver"
)

func getTag(match ...string) (string, *semver.PRVersion) {
args := append([]string{
"describe", "--tags",
}, match...)
tag, err := exec.Command("git", args...).Output()
if err != nil {
return "", nil
}
tagParts := strings.Split(string(tag), "-")
if len(tagParts) == 3 {
if ahead, err := semver.NewPRVersion(tagParts[1]); err == nil {
return tagParts[0], &ahead
}
} else if len(tagParts) == 4 {
if ahead, err := semver.NewPRVersion(tagParts[2]); err == nil {
return tagParts[0] + "-" + tagParts[1], &ahead
}
}

return string(tag), nil
}

func main() {
if tags, err := exec.Command("git", "tag").Output(); err != nil || len(tags) == 0 {
// no tags found -- fetch them
exec.Command("git", "fetch", "--tags").Run()
}
// Find the last vX.X.X Tag and get how many builds we are ahead of it.
versionStr, ahead := getTag("--match", "v*")
version, err := semver.ParseTolerant(versionStr)
if err != nil {
// no version tag found so just return what ever we can find.
fmt.Println("0.0.0-unknown")
return
}
// Get the tag of the current revision.
tag, _ := getTag("--exact-match")
if tag == versionStr {
// Seems that we are going to build a release.
// So the version number should already be correct.
fmt.Println(version.String())
return
}

// If we don't have any tag assume "dev"
if tag == "" || strings.HasPrefix(tag, "nightly") {
tag = "dev"
}
// Get the most likely next version:
if !strings.Contains(version.String(), "rc") {
version.Patch = version.Patch + 1
}

if pr, err := semver.NewPRVersion(tag); err == nil {
// append the tag as pre-release name
version.Pre = append(version.Pre, pr)
}

if ahead != nil {
// if we know how many commits we are ahead of the last release, append that too.
version.Pre = append(version.Pre, *ahead)
}

fmt.Println(version.String())
}

0 comments on commit 799d8ca

Please sign in to comment.