initial commit

This commit is contained in:
2025-09-24 00:01:06 +02:00
parent 3a93f48397
commit 26bca77a03
12 changed files with 759 additions and 0 deletions

10
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "monthly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

36
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: build-and-test-gfn
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
version: [1.23.5]
os: [ubuntu-latest, windows-latest, macos-latest]
name: Build
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go ${{ matrix.os }}
uses: actions/setup-go@v5
with:
go-version: '${{ matrix.version }}'
id: go
- name: checkout
uses: actions/checkout@v4
- name: build
run: go build
- name: test
run: make test
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v5
with:
go-version: 1.23
- uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v8

87
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,87 @@
name: build-release
on:
push:
tags:
- "v*.*.*"
jobs:
release:
name: Build Release Assets
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.23.5
- name: Build the executables
run: ./mkrel.sh ts ${{ github.ref_name}}
- name: List the executables
run: ls -l ./releases
- name: Upload the binaries
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
file: ./releases/*
file_glob: true
- name: Build Changelog
id: github_release
uses: mikepenz/release-changelog-builder-action@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
mode: "PR"
configurationJson: |
{
"template": "#{{CHANGELOG}}\n\n**Full Changelog**: #{{RELEASE_DIFF}}",
"pr_template": "- #{{TITLE}} (##{{NUMBER}}) by #{{AUTHOR}}\n#{{BODY}}",
"empty_template": "- no changes",
"categories": [
{
"title": "## New Features",
"labels": ["add", "feature"]
},
{
"title": "## Bug Fixes",
"labels": ["fix", "bug", "revert"]
},
{
"title": "## Documentation Enhancements",
"labels": ["doc"]
},
{
"title": "## Refactoring Efforts",
"labels": ["refactor"]
},
{
"title": "## Miscellaneus Changes",
"labels": []
}
],
"ignore_labels": [
"duplicate", "good first issue", "help wanted", "invalid", "question", "wontfix"
],
"label_extractor": [
{
"pattern": "(.) (.+)",
"target": "$1"
},
{
"pattern": "(.) (.+)",
"target": "$1",
"on_property": "title"
}
]
}
- name: Create Release
uses: softprops/action-gh-release@v2
with:
body: ${{steps.github_release.outputs.changelog}}

87
Makefile Normal file
View File

@@ -0,0 +1,87 @@
# Copyright © 2024 Thomas von Dein
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# no need to modify anything below
tool = gfn
VERSION = $(shell grep VERSION config.go | head -1 | cut -d '"' -f2)
archs = darwin freebsd linux windows
PREFIX = /usr/local
UID = root
GID = 0
HAVE_POD := $(shell pod2text -h 2>/dev/null)
all: buildlocal
buildlocal:
CGO_LDFLAGS='-static' go build -tags osusergo,netgo -ldflags "-extldflags=-static" -o $(tool)
install: buildlocal
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/
clean:
rm -rf $(tool) coverage.out testdata t/out
test: clean
mkdir -p t/out
go test ./... $(ARGS)
testlint: test lint
lint:
golangci-lint run
lint-full:
golangci-lint run --enable-all --exclude-use-default --disable exhaustivestruct,exhaustruct,depguard,interfacer,deadcode,golint,structcheck,scopelint,varcheck,ifshort,maligned,nosnakecase,godot,funlen,gofumpt,cyclop,noctx,gochecknoglobals,paralleltest
testfuzzy: clean
go test -fuzz ./... $(ARGS)
singletest:
@echo "Call like this: make singletest TEST=TestPrepareColumns ARGS=-v"
go test -run $(TEST) $(ARGS)
cover-report:
go test ./... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out
goupdate:
go get -t -u=patch ./...
buildall:
./mkrel.sh $(tool) $(VERSION)
release:
gh release create v$(VERSION) --generate-notes
show-versions: buildlocal
@echo "### gfn version:"
@./gfn -V
@echo
@echo "### go module versions:"
@go list -m all
@echo
@echo "### go version used for building:"
@grep -m 1 go go.mod
# lint:
# golangci-lint run -p bugs -p unused

View File

@@ -1,2 +1,81 @@
# ts
generic cli timestamp parser and calculator tool
# Usage
```default
This is ts, a timestamp tool.
Usage: ts <time string> [<time string>]
-d --diff Calculate difference between two timestamps (default).
-a --add Add two timestamps (second parameter must be a time).
-f --format For diffs: duration, hour, min, sec, msec.
For timestamps: datetime, rfc3339, date, time, unix, string.
string is a strftime(1) format string. datetime is
the default.
-u --unit Add unit to the output of timestamp diffs.
--debug Show debugging output.
-v --version Show program version.
-h --help Show this help screen.
-e --examples Show examples or supported inputs.
```
## Installation
The tool does not have any dependencies. Just download the binary for
your platform from the releases page and you're good to go.
### Installation using a pre-compiled binary
Go to the [latest release page](https://github.com/TLINDEN/ts/releases/latest)
and look for your OS and platform. There are two options to install the binary:
Directly download the binary for your platform,
e.g. `ts-linux-amd64-0.0.2`, rename it to `ts` (or whatever
you like more!) and put it into your bin dir (e.g. `$HOME/bin` or as
root to `/usr/local/bin`).
Be sure to verify the signature of the binary file. For this also
download the matching `ts-linux-amd64-0.0.2.sha256` file and:
```shell
cat ts-linux-amd64-0.0.2.sha25 && sha256sum ts-linux-amd64-0.0.2
```
You should see the same SHA256 hash.
You may also download a binary tarball for your platform, e.g.
`ts-linux-amd64-0.0.2.tar.gz`, unpack and install it. GNU Make is
required for this:
```shell
tar xvfz ts-linux-amd64-0.0.2.tar.gz
cd ts-linux-amd64-0.0.2
sudo make install
```
### Installation from source
You will need the Golang toolchain in order to build from source. GNU
Make will also help but is not strictly neccessary.
If you want to compile the tool yourself, use `git clone` to clone the
repository. Then execute `go mod tidy` to install all
dependencies. Then just enter `go build` or - if you have GNU Make
installed - `make`.
To install after building either copy the binary or execute `sudo make
install`.
# Report bugs
[Please open an issue](https://github.com/TLINDEN/ts/issues). Thanks!
# License
This work is licensed under the terms of the General Public Licens
version 3.
# Author
Copyleft (c) 2025 Thomas von Dein

129
cmd/config.go Normal file
View File

@@ -0,0 +1,129 @@
package cmd
import (
"errors"
"fmt"
"io"
"log"
"os"
"github.com/knadh/koanf/providers/posflag"
"github.com/knadh/koanf/v2"
flag "github.com/spf13/pflag"
)
const (
VERSIONstring = "0.0.1"
Usage string = `This is ts, a timestamp tool.
Usage: ts <time string> [<time string>]
-d --diff Calculate difference between two timestamps (default).
-a --add Add two timestamps (second parameter must be a time).
-f --format For diffs: duration, hour, min, sec, msec.
For timestamps: datetime, rfc3339, date, time, unix, string.
string is a strftime(1) format string. datetime is
the default.
-u --unit Add unit to the output of timestamp diffs.
--debug Show debugging output.
-v --version Show program version.
-h --help Show this help screen.
-e --examples Show examples or supported inputs.
`
Examples string = `Example timestamp inputs:
now 10:25:30 Last sunday at 5:30pm 2 weeks ago
a minute from now 17:25:30 Next sunday at 22:45 A week from now
a minute ago On Friday at noon UTC Next sunday at 22:45 A week from today
1 minute ago On Tuesday at 11am UTC November 3rd, 1986 at 4:30pm A month ago
5 minutes ago On 3 feb 2025 at 5:35:52pm September 17, 2012 at 10:09am UTC 1 month ago
five minutes ago 3 feb 2025 at 5:35:52pm September 17, 2012 at 10:09am UTC-8 2 months ago
5 minutes ago 3 days ago at 11:25am September 17, 2012 at 10:09am UTC+8 12 months ago
2 minutes from now 3 days from now at 14:26 September 17, 2012, 10:11:09 A month from now
two minutes from now 2 weeks ago at 8am September 17, 2012, 10:11 One month hence
an hour from now Today at 10am September 17, 2012 10:11 1 month from now
an hour ago 10am today September 17 2012 10:11 2 months from now
1 hour ago Yesterday 10am September 17 2012 at 10:11 Last January
6 hours ago 10am yesterday Mon Jan 2 15:04:05 2006 Last january
1 hour from now Yesterday at 10am Mon Jan 02 15:04:05 -0700 2006 Next january
noon Yesterday at 10:15am Mon, 02 Jan 2006 15:04:05 -0700 One year ago
5:35:52pm Tomorrow 10am Mon 02 Jan 2006 15:04:05 -0700 One year from now
10am 10am tomorrow 2006-01-02T15:04:05Z One year from today
10 am Tomorrow at 10am 1990-12-31T15:59:59-08:00 Two years ago
5pm Tomorrow at 10:15am One day ago 2 years ago
10:25am 10:15am tomorrow 1 day ago This year
1:05pm Next dec 22nd at 3pm 3 days ago 1999AD
10:25:10am Next December 25th at 7:30am UTC-7 Three days ago 1999 AD
1:05:10pm Next December 23rd AT 5:25 PM 1 day from now 2008CE
10:25 Last December 23rd AT 5:25 PM 1 week ago 2008 CE
`
ModeDiff int = iota
ModeAdd
)
type Config struct {
// TODO: add Timezone parameter
Showversion bool `koanf:"version"`
Debug bool `koanf:"debug"`
Diff bool `koanf:"diff"`
Add bool `koanf:"add"`
Examples bool `koanf:"examples"`
Unit bool `koanf:"unit"`
Format string `koanf:"format"`
Args []string
Output io.Writer
Mode int
}
func InitConfig(output io.Writer) (*Config, error) {
var kloader = koanf.New(".")
// setup custom usage
flagset := flag.NewFlagSet("config", flag.ContinueOnError)
flagset.Usage = func() {
_, err := fmt.Fprintln(output, Usage)
if err != nil {
log.Fatalf("failed to print to output: %s", err)
}
os.Exit(0)
}
// parse commandline flags
flagset.BoolP("version", "v", false, "show program version")
flagset.BoolP("debug", "", false, "enable debug output")
flagset.BoolP("diff", "d", false, "diff two timestamps")
flagset.BoolP("add", "a", false, "add two timestamps")
flagset.BoolP("unit", "u", false, "add unit to diff outputs")
flagset.BoolP("examples", "e", false, "show examples of supported inputs")
flagset.StringP("format", "f", "", "format to print timestamps or diffs")
if err := flagset.Parse(os.Args[1:]); err != nil {
return nil, fmt.Errorf("failed to parse program arguments: %w", err)
}
// command line setup
if err := kloader.Load(posflag.Provider(flagset, ".", kloader), nil); err != nil {
return nil, fmt.Errorf("error loading flags: %w", err)
}
// fetch values
conf := &Config{Output: output}
if err := kloader.Unmarshal("", &conf); err != nil {
return nil, fmt.Errorf("error unmarshalling: %w", err)
}
// args are timestamps
if len(flagset.Args()) == 0 {
return nil, errors.New("no timestamp argument[s] specified.\n" + Usage)
}
conf.Args = flagset.Args()
if conf.Add {
conf.Mode = ModeAdd
} else {
conf.Mode = ModeDiff
}
return conf, nil
}

34
cmd/root.go Normal file
View File

@@ -0,0 +1,34 @@
package cmd
import (
"fmt"
"io"
"log"
"os"
)
func Die(err error) int {
log.Fatal("Error: ", err.Error())
return 1
}
func Main(output io.Writer) int {
conf, err := InitConfig(output)
if err != nil {
return Die(err)
}
if conf.Examples {
fmt.Fprintln(output, Examples)
os.Exit(0)
}
tp := NewTP(conf)
if err := tp.ProcessTimestamps(); err != nil {
return Die(err)
}
return 0
}

175
cmd/times.go Normal file
View File

@@ -0,0 +1,175 @@
package cmd
import (
"fmt"
"log"
"time"
"github.com/ijt/go-anytime"
"github.com/itlightning/dateparse"
"github.com/jinzhu/now"
)
type TimestampProccessor struct {
Config
}
func NewTP(conf *Config) *TimestampProccessor {
formats := []string{
time.UnixDate, time.RubyDate,
time.RFC1123, time.RFC1123Z, time.RFC3339, time.RFC3339Nano,
time.RFC822, time.RFC822Z, time.RFC850,
"Mon Jan 02 15:04:05 PM MST 2006", // linux date
"Mo. 02 Jan. 2006 15:04:05 MST", // freebsd date (fails, see golang/go/issues/75576)
}
now.TimeFormats = append(now.TimeFormats, formats...)
return &TimestampProccessor{Config: *conf}
}
func (tp *TimestampProccessor) ProcessTimestamps() error {
switch len(tp.Args) {
case 1:
return tp.SingleTimestamp(tp.Args[0])
case 2:
return tp.Calc(tp.Args[0], tp.Args[1])
}
return nil
}
func (tp *TimestampProccessor) SingleTimestamp(timestamp string) error {
ts, err := tp.Parse(timestamp)
if err != nil {
return err
}
tp.Print(ts)
return nil
}
// Parse uses 3 different timestamp parser modules to provide the maximum flexibility
func (tp *TimestampProccessor) Parse(timestamp string) (time.Time, error) {
reference := time.Now()
ts, err := anytime.Parse(timestamp, reference)
if err == nil {
return ts, nil
}
// anytime failed, try module now
ts, err = now.Parse(timestamp)
if err == nil {
return ts, nil
}
// now failed, try module dateparse
ts, err = dateparse.ParseAny(timestamp)
return ts, nil
}
func (tp *TimestampProccessor) Calc(timestampA, timestampB string) error {
now := time.Now()
tsA, err := anytime.Parse(timestampA, now)
if err != nil {
return err
}
tsB, err := anytime.Parse(timestampB, now)
if err != nil {
return err
}
switch tp.Mode {
case ModeDiff:
var diff time.Duration
if tsA.Unix() > tsB.Unix() {
diff = tsA.Sub(tsB)
} else {
diff = tsB.Sub(tsA)
}
tp.Print(diff)
case ModeAdd:
seconds := (tsB.Hour() * 3600) + (tsB.Minute() * 60) + tsB.Second()
tp.Print(tsA.Add(time.Duration(seconds) * time.Second))
}
return nil
}
func (tp *TimestampProccessor) Print(msg any) {
var repr string
switch msg := msg.(type) {
case string:
repr = msg
case time.Time:
repr = tp.StringTime(msg)
case time.Duration:
repr = tp.StringDuration(msg)
}
_, err := fmt.Fprintln(tp.Output, repr)
if err != nil {
log.Fatalf("failed to print to given output handle: %s", err)
}
}
func (tp *TimestampProccessor) StringDuration(msg time.Duration) string {
var unit string
if tp.Unit {
switch tp.Format {
case "d", "day", "days":
unit = " days"
case "h", "hour", "hours":
unit = " hours"
case "m", "min", "mins", "minutes":
unit = " minutes"
case "s", "sec", "secs", "seconds":
unit = " seconds"
case "ms", "msec", "msecs", "milliseconds":
unit = " milliseconds"
}
}
// duration, days, hour, min, sec, msec
switch tp.Format {
case "d", "day", "days":
return fmt.Sprintf("%.02f%s", msg.Hours()/24+(msg.Minutes()/60), unit)
case "h", "hour", "hours":
return fmt.Sprintf("%.02f%s", msg.Hours(), unit)
case "m", "min", "mins", "minutes":
return fmt.Sprintf("%.02f%s", msg.Minutes(), unit)
case "s", "sec", "secs", "seconds":
return fmt.Sprintf("%.02f%s", msg.Seconds(), unit)
case "ms", "msec", "msecs", "milliseconds":
return fmt.Sprintf("%d%s", msg.Milliseconds(), unit)
case "dur", "duration":
fallthrough
default:
return msg.String()
}
}
func (tp *TimestampProccessor) StringTime(msg time.Time) string {
// datetime(default), date, time, unix, string
switch tp.Format {
case "rfc3339":
return msg.Format(time.RFC3339)
case "date":
return msg.Format("2006-01-02")
case "time":
return msg.Format("03:04:05")
case "unix":
return fmt.Sprintf("%d", msg.Unix())
case "datetime":
fallthrough
case "":
return msg.String()
default:
return msg.Format(tp.Format)
}
}

19
go.mod Normal file
View File

@@ -0,0 +1,19 @@
module github.com/tlinden/ts
go 1.23.0
toolchain go1.23.5
require (
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/ijt/go-anytime v1.9.2 // indirect
github.com/ijt/goparsify v0.0.0-20221203142333-3a5276334b8d // indirect
github.com/itlightning/dateparse v0.2.1 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/posflag v1.0.1 // indirect
github.com/knadh/koanf/v2 v2.3.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/spf13/pflag v1.0.10 // indirect
)

22
go.sum Normal file
View File

@@ -0,0 +1,22 @@
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/ijt/go-anytime v1.9.2 h1:DmYgVwUiFPNR+n6c1T5P070tlGATRZG4aYNJs6XDUfU=
github.com/ijt/go-anytime v1.9.2/go.mod h1:egBT6FhVjNlXNHUN2wTPi6ILCNKXeeXFy04pWJjw/LI=
github.com/ijt/goparsify v0.0.0-20221203142333-3a5276334b8d h1:LFOmpWrSbtolg0YqYC9hQjj5WSLtRGb6aZ3JAugLfgg=
github.com/ijt/goparsify v0.0.0-20221203142333-3a5276334b8d/go.mod h1:112TOyA+aruNSUBlyBWlKBdLVYTdhjiO2CKD0j/URSU=
github.com/itlightning/dateparse v0.2.1 h1:AB0NJTyI0HYcerEUMovKZOiQVBg1mBPxgAnWQwzLP6g=
github.com/itlightning/dateparse v0.2.1/go.mod h1:xHlmL8lT0L9JIBlaKotRwsoDYpKJskXpiU9ZwbbSkNA=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/providers/posflag v1.0.1 h1:EnMxHSrPkYCFnKgBUl5KBgrjed8gVFrcXDzaW4l/C6Y=
github.com/knadh/koanf/providers/posflag v1.0.1/go.mod h1:3Wn3+YG3f4ljzRyCUgIwH7G0sZ1pMjCOsNBovrbKmAk=
github.com/knadh/koanf/v2 v2.3.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM=
github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=

11
main.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import (
"os"
"github.com/tlinden/ts/cmd"
)
func main() {
os.Exit(cmd.Main(os.Stdout))
}

70
mkrel.sh Executable file
View File

@@ -0,0 +1,70 @@
#!/bin/bash
# Copyright © 2024 Thomas von Dein
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# get list with: go tool dist list
DIST="darwin/amd64
freebsd/amd64
linux/amd64
windows/amd64
freebsd/arm64
linux/arm64"
tool="$1"
version="$2"
if test -z "$version"; then
echo "Usage: $0 <tool name> <release version>"
exit 1
fi
rm -rf releases
mkdir -p releases
for D in $DIST; do
os=${D/\/*/}
arch=${D/*\//}
binfile="releases/${tool}-${os}-${arch}-${version}"
if test "$os" = "windows"; then
binfile="${binfile}.exe"
fi
tardir="${tool}-${os}-${arch}-${version}"
tarfile="releases/${tool}-${os}-${arch}-${version}.tar.gz"
set -x
GOOS=${os} GOARCH=${arch} go build -tags osusergo,netgo -ldflags "-extldflags=-static" -o ${binfile}
mkdir -p ${tardir}
cp ${binfile} README.md LICENSE ${tardir}/
echo 'tool = ts
PREFIX = /usr/local
UID = root
GID = 0
install:
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/' > ${tardir}/Makefile
tar cpzf ${tarfile} ${tardir}
sha256sum ${binfile} | cut -d' ' -f1 > ${binfile}.sha256
sha256sum ${tarfile} | cut -d' ' -f1 > ${tarfile}.sha256
rm -rf ${tardir}
set +x
done