mirror of
https://github.com/neilotoole/sq.git
synced 2024-11-28 12:33:44 +03:00
* sq version host info * workflow: update bug_report.md with version instructions
This commit is contained in:
parent
1f9183aa68
commit
97739da1e1
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -11,16 +11,46 @@ assignees: ''
|
|||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
|
|
||||||
Steps to reproduce the behavior.
|
Steps to reproduce the behavior.
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
|
|
||||||
A clear and concise description of what you expected to happen.
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**`sq` version**
|
||||||
|
|
||||||
|
Include below the output of `sq version --yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# REPLACE THIS WITH YOUR OUTPUT
|
||||||
|
buildinfo:
|
||||||
|
version: v0.39.0
|
||||||
|
commit: eedc11ec46d1f0e78628158cc6fd58850601d701
|
||||||
|
timestamp: 2023-06-21T11:41:34Z
|
||||||
|
latest_version: v0.39.0
|
||||||
|
host:
|
||||||
|
platform: darwin
|
||||||
|
arch: arm64
|
||||||
|
kernel: Darwin
|
||||||
|
kernel_version: 22.5.0
|
||||||
|
variant: macOS
|
||||||
|
variant_version: "13.4"
|
||||||
|
```
|
||||||
|
|
||||||
**Logs**
|
**Logs**
|
||||||
Attach [log file](https://sq.io/docs/overview/#logging).
|
|
||||||
|
Attach [log file](https://sq.io/docs/config/#logging).
|
||||||
|
|
||||||
|
Don't paste the log file contents into the GH comment: attach the file.
|
||||||
|
The exception is if you know for sure that only a particular snippet of
|
||||||
|
the log file is relevant: then you can paste that short snippet. Be sure
|
||||||
|
to enclose it in a code block.
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots**
|
||||||
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
|
|
||||||
Add any other context about the problem here.
|
Add any other context about the problem here.
|
||||||
|
26
CHANGELOG.md
26
CHANGELOG.md
@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
Breaking changes are annotated with ☢️.
|
Breaking changes are annotated with ☢️.
|
||||||
|
|
||||||
|
## Upcoming
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [#263]: `sq version` now supports `--yaml` output.
|
||||||
|
- [#263]: `sq version` now outputs host OS details with `--verbose`, `--json`
|
||||||
|
and `--yaml` flags. The motivation behind this is bug submission: we want
|
||||||
|
to know which OS/arch the user is on. E.g. for `sq version -j`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "v0.38.1",
|
||||||
|
"commit": "eedc11ec46d1f0e78628158cc6fd58850601d701",
|
||||||
|
"timestamp": "2023-06-21T11:41:34Z",
|
||||||
|
"latest_version": "v0.39.0",
|
||||||
|
"host": {
|
||||||
|
"platform": "darwin",
|
||||||
|
"arch": "arm64",
|
||||||
|
"kernel": "Darwin",
|
||||||
|
"kernel_version": "22.5.0",
|
||||||
|
"variant": "macOS",
|
||||||
|
"variant_version": "13.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## [v0.38.1] - 2023-06-19
|
## [v0.38.1] - 2023-06-19
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
@ -607,6 +632,7 @@ make working with lots of sources much easier.
|
|||||||
[#256]: https://github.com/neilotoole/sq/issues/256
|
[#256]: https://github.com/neilotoole/sq/issues/256
|
||||||
[#258]: https://github.com/neilotoole/sq/issues/258
|
[#258]: https://github.com/neilotoole/sq/issues/258
|
||||||
[#261]: https://github.com/neilotoole/sq/issues/261
|
[#261]: https://github.com/neilotoole/sq/issues/261
|
||||||
|
[#263]: https://github.com/neilotoole/sq/issues/263
|
||||||
|
|
||||||
[v0.15.2]: https://github.com/neilotoole/sq/releases/tag/v0.15.2
|
[v0.15.2]: https://github.com/neilotoole/sq/releases/tag/v0.15.2
|
||||||
[v0.15.3]: https://github.com/neilotoole/sq/compare/v0.15.2...v0.15.3
|
[v0.15.3]: https://github.com/neilotoole/sq/compare/v0.15.2...v0.15.3
|
||||||
|
@ -63,8 +63,8 @@ func (bi BuildInfo) LogValue() slog.Value {
|
|||||||
return gv
|
return gv
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info returns BuildInfo.
|
// Get returns BuildInfo.
|
||||||
func Info() BuildInfo {
|
func Get() BuildInfo {
|
||||||
return BuildInfo{
|
return BuildInfo{
|
||||||
Version: Version,
|
Version: Version,
|
||||||
Commit: Commit,
|
Commit: Commit,
|
||||||
|
@ -27,6 +27,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/hostinfo"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/cli/run"
|
"github.com/neilotoole/sq/cli/run"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/cli/flag"
|
"github.com/neilotoole/sq/cli/flag"
|
||||||
@ -79,7 +81,8 @@ func Execute(ctx context.Context, stdin *os.File, stdout, stderr io.Writer, args
|
|||||||
func ExecuteWith(ctx context.Context, ru *run.Run, args []string) error {
|
func ExecuteWith(ctx context.Context, ru *run.Run, args []string) error {
|
||||||
log := lg.FromContext(ctx)
|
log := lg.FromContext(ctx)
|
||||||
log.Debug("EXECUTE", "args", strings.Join(args, " "))
|
log.Debug("EXECUTE", "args", strings.Join(args, " "))
|
||||||
log.Debug("Build info", "build", buildinfo.Info())
|
log.Debug("Build info", "build", buildinfo.Get())
|
||||||
|
log.Debug("Host info", "host", hostinfo.Get())
|
||||||
log.Debug("Config",
|
log.Debug("Config",
|
||||||
"config.version", ru.Config.Version,
|
"config.version", ru.Config.Version,
|
||||||
lga.Path, ru.ConfigStore.Location(),
|
lga.Path, ru.ConfigStore.Location(),
|
||||||
|
@ -8,6 +8,25 @@ import (
|
|||||||
"github.com/neilotoole/sq/cli/run"
|
"github.com/neilotoole/sq/cli/run"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DoCompleteAddLocationFile = locCompListFiles
|
||||||
|
PreprocessFlagArgVars = preprocessFlagArgVars
|
||||||
|
LastHandlePart = lastHandlePart
|
||||||
|
GetVersionFromBrewFormula = getVersionFromBrewFormula
|
||||||
|
FetchBrewVersion = fetchBrewVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToTestParseLocStage is a helper to test the
|
||||||
|
// non-exported locCompletionHelper.locCompParseLoc method.
|
||||||
|
func DoTestParseLocStage(t testing.TB, ru *run.Run, loc string) (PlocStage, error) { //nolint:revive
|
||||||
|
ploc, err := locCompParseLoc(loc)
|
||||||
|
if err != nil {
|
||||||
|
return PlocInit, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ploc.stageDone, nil
|
||||||
|
}
|
||||||
|
|
||||||
type PlocStage = plocStage
|
type PlocStage = plocStage
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -19,16 +38,3 @@ const (
|
|||||||
PlocHost = plocHost
|
PlocHost = plocHost
|
||||||
PlocPath = plocPath
|
PlocPath = plocPath
|
||||||
)
|
)
|
||||||
|
|
||||||
var DoCompleteAddLocationFile = locCompListFiles
|
|
||||||
|
|
||||||
// ToTestParseLocStage is a helper to test the
|
|
||||||
// non-exported locCompletionHelper.locCompParseLoc method.
|
|
||||||
func DoTestParseLocStage(t testing.TB, ru *run.Run, loc string) (PlocStage, error) { //nolint:revive
|
|
||||||
ploc, err := locCompParseLoc(loc)
|
|
||||||
if err != nil {
|
|
||||||
return PlocInit, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ploc.stageDone, nil
|
|
||||||
}
|
|
||||||
|
28
cli/cmd_mv_test.go
Normal file
28
cli/cmd_mv_test.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package cli_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli"
|
||||||
|
"github.com/neilotoole/sq/testh/tutil"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLastHandlePart(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
in string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"@handle", "handle"},
|
||||||
|
{"@prod/db", "db"},
|
||||||
|
{"@prod/sub/db", "db"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tutil.Name(i, tc.in), func(t *testing.T) {
|
||||||
|
got := cli.LastHandlePart(tc.in)
|
||||||
|
require.Equal(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/cli/testrun"
|
"github.com/neilotoole/sq/cli/testrun"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -19,7 +21,7 @@ import (
|
|||||||
"github.com/neilotoole/sq/testh/sakila"
|
"github.com/neilotoole/sq/testh/sakila"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestCmdSLQ_Insert tests "sq QUERY --insert=@src.tbl".
|
// TestCmdSLQ_Insert_Create tests "sq QUERY --insert=@src.tbl".
|
||||||
func TestCmdSLQ_Insert_Create(t *testing.T) {
|
func TestCmdSLQ_Insert_Create(t *testing.T) {
|
||||||
th := testh.New(t)
|
th := testh.New(t)
|
||||||
originSrc, destSrc := th.Source(sakila.SL3), th.Source(sakila.SL3)
|
originSrc, destSrc := th.Source(sakila.SL3), th.Source(sakila.SL3)
|
||||||
@ -192,3 +194,83 @@ func TestCmdSLQ_ActiveSrcHandle(t *testing.T) {
|
|||||||
recs = tr.MustReadCSV()
|
recs = tr.MustReadCSV()
|
||||||
require.Equal(t, sakila.TblActorCount, len(recs))
|
require.Equal(t, sakila.TblActorCount, len(recs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPreprocessFlagArgVars(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
in []string
|
||||||
|
want []string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
in: []string{},
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no flags",
|
||||||
|
in: []string{".actor"},
|
||||||
|
want: []string{".actor"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-arg flag",
|
||||||
|
in: []string{"--json", ".actor"},
|
||||||
|
want: []string{"--json", ".actor"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-arg flag with value",
|
||||||
|
in: []string{"--json", "true", ".actor"},
|
||||||
|
want: []string{"--json", "true", ".actor"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single arg flag",
|
||||||
|
in: []string{"--arg", "name", "TOM", ".actor"},
|
||||||
|
want: []string{"--arg", "name:TOM", ".actor"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid arg name",
|
||||||
|
in: []string{"--arg", "na me", "TOM", ".actor"},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid arg name (with colon)",
|
||||||
|
in: []string{"--arg", "na:me", "TOM", ".actor"},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "colon in value",
|
||||||
|
in: []string{"--arg", "name", "T:OM", ".actor"},
|
||||||
|
want: []string{"--arg", "name:T:OM", ".actor"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single arg flag with whitespace",
|
||||||
|
in: []string{"--arg", "name", "TOM DOWD", ".actor"},
|
||||||
|
want: []string{"--arg", "name:TOM DOWD", ".actor"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two arg flags",
|
||||||
|
in: []string{"--arg", "name", "TOM", "--arg", "eyes", "blue", ".actor"},
|
||||||
|
want: []string{"--arg", "name:TOM", "--arg", "eyes:blue", ".actor"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two arg flags with interspersed flag",
|
||||||
|
in: []string{"--arg", "name", "TOM", "--json", "true", "--arg", "eyes", "blue", ".actor"},
|
||||||
|
want: []string{"--arg", "name:TOM", "--json", "true", "--arg", "eyes:blue", ".actor"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got, gotErr := cli.PreprocessFlagArgVars(tc.in)
|
||||||
|
if tc.wantErr {
|
||||||
|
t.Log(gotErr.Error())
|
||||||
|
require.Error(t, gotErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, gotErr)
|
||||||
|
require.EqualValues(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/hostinfo"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/libsq/core/ioz"
|
"github.com/neilotoole/sq/libsq/core/ioz"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/cli/run"
|
"github.com/neilotoole/sq/cli/run"
|
||||||
@ -28,34 +30,53 @@ func newVersionCmd() *cobra.Command {
|
|||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "version",
|
Use: "version",
|
||||||
Short: "Show version info",
|
Short: "Show version info",
|
||||||
Long: `Show version info. Use --verbose for more detail.
|
Long: `Show version info.
|
||||||
The output will note if a new version of sq is available.
|
The output notes if a new version of sq is available.
|
||||||
|
|
||||||
|
Use --verbose, or --json or --yaml for more detail.
|
||||||
|
|
||||||
Before upgrading, check the changelog: https://sq.io/changelog`,
|
Before upgrading, check the changelog: https://sq.io/changelog`,
|
||||||
RunE: execVersion,
|
RunE: execVersion,
|
||||||
Example: ` # Show version (note that an update is available)
|
Example: ` # Show version (note that an update is available)
|
||||||
$ sq version
|
$ sq version
|
||||||
sq v0.32.0 Update available: v0.33.0
|
sq v0.38.0 Update available: v0.39.0
|
||||||
|
|
||||||
# Verbose output
|
# Verbose output
|
||||||
$ sq version -v
|
$ sq version -v
|
||||||
sq v0.32.0 #4e176716 2023-04-15T15:46:00Z Update available: v0.33.0
|
sq v0.38.0
|
||||||
|
Version: v0.38.0
|
||||||
|
Commit: #4e176716
|
||||||
|
Timestamp: 2023-06-21T11:39:39Z
|
||||||
|
Latest version: v0.39.0
|
||||||
|
Host: darwin arm64 | Darwin 22.5.0 | macOS 13.4
|
||||||
|
[...]
|
||||||
|
|
||||||
# JSON output
|
# JSON output
|
||||||
$ sq version -j
|
$ sq version -j
|
||||||
{
|
{
|
||||||
"version": "v0.32.0",
|
"version": "v0.38.0",
|
||||||
"commit": "4e176716",
|
"commit": "4e176716",
|
||||||
"timestamp": "2023-04-15T15:53:38Z",
|
"timestamp": "2023-06-19T22:08:54Z",
|
||||||
"latest_version": "v0.33.0"
|
"latest_version": "v0.39.0",
|
||||||
}
|
"host": {
|
||||||
|
"platform": "darwin",
|
||||||
|
"arch": "arm64",
|
||||||
|
"kernel": "Darwin",
|
||||||
|
"kernel_version": "22.5.0",
|
||||||
|
"variant": "macOS",
|
||||||
|
"variant_version": "13.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Extract just the semver string
|
# Extract just the semver string
|
||||||
$ sq version -j | jq -r .version
|
$ sq version -j | jq -r .version
|
||||||
v0.32.0`,
|
v0.38.0`,
|
||||||
}
|
}
|
||||||
|
|
||||||
addTextFlags(cmd)
|
addTextFlags(cmd)
|
||||||
cmd.Flags().BoolP(flag.JSON, flag.JSONShort, false, flag.JSONUsage)
|
cmd.Flags().BoolP(flag.JSON, flag.JSONShort, false, flag.JSONUsage)
|
||||||
cmd.Flags().BoolP(flag.Compact, flag.CompactShort, false, flag.CompactUsage)
|
cmd.Flags().BoolP(flag.Compact, flag.CompactShort, false, flag.CompactUsage)
|
||||||
|
cmd.Flags().BoolP(flag.YAML, flag.YAMLShort, false, flag.YAMLUsage)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -93,7 +114,7 @@ func execVersion(cmd *cobra.Command, _ []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ru.Writers.Version.Version(buildinfo.Info(), latestVersion)
|
return ru.Writers.Version.Version(buildinfo.Get(), latestVersion, hostinfo.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchBrewVersion fetches the latest available sq version via
|
// fetchBrewVersion fetches the latest available sq version via
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
package cli
|
package cli_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/libsq/core/ioz"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/buildinfo"
|
||||||
|
"github.com/neilotoole/sq/cli/testrun"
|
||||||
|
|
||||||
|
"github.com/ecnepsnai/osquery"
|
||||||
|
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -14,13 +25,68 @@ func TestGetVersionFromBrewFormula(t *testing.T) {
|
|||||||
f, err := os.ReadFile("testdata/sq-0.20.0.rb")
|
f, err := os.ReadFile("testdata/sq-0.20.0.rb")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
vers, err := getVersionFromBrewFormula(f)
|
vers, err := cli.GetVersionFromBrewFormula(f)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "0.20.0", vers)
|
require.Equal(t, "0.20.0", vers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchBrewVersion(t *testing.T) {
|
func TestFetchBrewVersion(t *testing.T) {
|
||||||
latest, err := fetchBrewVersion(context.Background())
|
latest, err := cli.FetchBrewVersion(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, semver.IsValid("v"+latest))
|
require.True(t, semver.IsValid("v"+latest))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOSQuery(t *testing.T) {
|
||||||
|
info, err := osquery.Get()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Logf("%+v", info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCmdVersion(t *testing.T) {
|
||||||
|
bi := buildinfo.Get()
|
||||||
|
ctx := context.Background()
|
||||||
|
tr := testrun.New(ctx, t, nil)
|
||||||
|
|
||||||
|
// --text
|
||||||
|
err := tr.Exec("version", "--text")
|
||||||
|
require.NoError(t, err)
|
||||||
|
text := tr.Out.String()
|
||||||
|
require.Contains(t, text, bi.Version)
|
||||||
|
|
||||||
|
tr = testrun.New(ctx, t, nil)
|
||||||
|
err = tr.Exec("version", "--text", "--verbose")
|
||||||
|
require.NoError(t, err)
|
||||||
|
text = tr.Out.String()
|
||||||
|
|
||||||
|
checkStringsFn := func(text string) {
|
||||||
|
require.Contains(t, text, bi.Version)
|
||||||
|
require.Contains(t, text, runtime.GOOS)
|
||||||
|
require.Contains(t, text, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
checkStringsFn(text)
|
||||||
|
|
||||||
|
// --json
|
||||||
|
tr = testrun.New(ctx, t, nil)
|
||||||
|
err = tr.Exec("version", "--json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
text = tr.Out.String()
|
||||||
|
checkStringsFn(text)
|
||||||
|
|
||||||
|
m := map[string]any{}
|
||||||
|
err = json.Unmarshal(tr.Out.Bytes(), &m)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, runtime.GOOS, m["host"].(map[string]any)["platform"])
|
||||||
|
|
||||||
|
// --yaml
|
||||||
|
tr = testrun.New(ctx, t, nil)
|
||||||
|
err = tr.Exec("version", "--yaml")
|
||||||
|
require.NoError(t, err)
|
||||||
|
text = tr.Out.String()
|
||||||
|
checkStringsFn(text)
|
||||||
|
|
||||||
|
m = map[string]any{}
|
||||||
|
err = ioz.UnmarshallYAML(tr.Out.Bytes(), &m)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, runtime.GOOS, m["host"].(map[string]any)["platform"])
|
||||||
|
}
|
||||||
|
103
cli/hostinfo/hostinfo.go
Normal file
103
cli/hostinfo/hostinfo.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// Package sysinfo provides high-level details about the runtime OS.
|
||||||
|
package hostinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slog"
|
||||||
|
|
||||||
|
"github.com/ecnepsnai/osquery"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Info encapsulates OS info.
|
||||||
|
type Info struct {
|
||||||
|
// The platform is a high-level description of the OS. This maps to GOOS.
|
||||||
|
Platform string `json:"platform" yaml:"platform"`
|
||||||
|
|
||||||
|
// Arch maps to runtime.
|
||||||
|
Arch string `json:"arch" yaml:"arch"`
|
||||||
|
|
||||||
|
// The name of the kernel used by the operating system.
|
||||||
|
Kernel string `json:"kernel,omitempty" yaml:"kernel,omitempty"`
|
||||||
|
|
||||||
|
// The specific version of the kernel.
|
||||||
|
KernelVersion string `json:"kernel_version,omitempty" yaml:"kernel_version,omitempty"`
|
||||||
|
|
||||||
|
// The variant or distribution of the kernel.
|
||||||
|
Variant string `json:"variant,omitempty" yaml:"variant,omitempty"`
|
||||||
|
|
||||||
|
// The version of the variant.
|
||||||
|
VariantVersion string `json:"variant_version,omitempty" yaml:"variant_version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogValue implements slog.LogValuer.
|
||||||
|
func (si Info) LogValue() slog.Value {
|
||||||
|
return slog.GroupValue(
|
||||||
|
slog.String("platform", si.Platform),
|
||||||
|
slog.String("arch", si.Arch),
|
||||||
|
slog.String("kernel", si.Kernel),
|
||||||
|
slog.String("kernel_version", si.KernelVersion),
|
||||||
|
slog.String("variant", si.Variant),
|
||||||
|
slog.String("variant_version", si.VariantVersion),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a log-debug friendly representation.
|
||||||
|
func (si Info) String() string {
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString(si.Platform)
|
||||||
|
sb.WriteRune('|')
|
||||||
|
sb.WriteString(si.Arch)
|
||||||
|
if si.Kernel != "" {
|
||||||
|
sb.WriteRune('|')
|
||||||
|
sb.WriteString(si.Kernel)
|
||||||
|
if si.KernelVersion != "" {
|
||||||
|
sb.WriteRune(' ')
|
||||||
|
sb.WriteString(si.KernelVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if si.Variant != "" {
|
||||||
|
sb.WriteRune('|')
|
||||||
|
sb.WriteString(si.Variant)
|
||||||
|
if si.VariantVersion != "" {
|
||||||
|
sb.WriteRune(' ')
|
||||||
|
sb.WriteString(si.VariantVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns system information. At a minimum, Info.Platform and
|
||||||
|
// Info.Arch are guaranteed to be populated.
|
||||||
|
func Get() Info {
|
||||||
|
info := Info{
|
||||||
|
Platform: runtime.GOOS,
|
||||||
|
Arch: runtime.GOARCH,
|
||||||
|
}
|
||||||
|
|
||||||
|
osq, err := osquery.Get()
|
||||||
|
if err != nil || osq == nil {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
const unk = "unknown"
|
||||||
|
// osquery sets unknown fields to "unknown".
|
||||||
|
// We'd rather they be empty.
|
||||||
|
if osq.Kernel != unk {
|
||||||
|
info.Kernel = osq.Kernel
|
||||||
|
}
|
||||||
|
if osq.KernelVersion != unk {
|
||||||
|
info.KernelVersion = osq.KernelVersion
|
||||||
|
}
|
||||||
|
if osq.Variant != unk {
|
||||||
|
info.Variant = osq.Variant
|
||||||
|
}
|
||||||
|
if osq.VariantVersion != unk {
|
||||||
|
info.VariantVersion = osq.VariantVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
return info
|
||||||
|
}
|
18
cli/hostinfo/hostinfo_test.go
Normal file
18
cli/hostinfo/hostinfo_test.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package hostinfo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/hostinfo"
|
||||||
|
|
||||||
|
"github.com/neilotoole/slogt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
info := hostinfo.Get()
|
||||||
|
|
||||||
|
log := slogt.New(t)
|
||||||
|
log.Debug("Via slog", "sys", info)
|
||||||
|
|
||||||
|
t.Logf("Via string: %s", info.String())
|
||||||
|
}
|
@ -1,138 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/neilotoole/slogt"
|
|
||||||
"github.com/neilotoole/sq/libsq/core/options"
|
|
||||||
"github.com/neilotoole/sq/testh/tutil"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_preprocessFlagArgVars(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
in []string
|
|
||||||
want []string
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "empty",
|
|
||||||
in: []string{},
|
|
||||||
want: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no flags",
|
|
||||||
in: []string{".actor"},
|
|
||||||
want: []string{".actor"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "non-arg flag",
|
|
||||||
in: []string{"--json", ".actor"},
|
|
||||||
want: []string{"--json", ".actor"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "non-arg flag with value",
|
|
||||||
in: []string{"--json", "true", ".actor"},
|
|
||||||
want: []string{"--json", "true", ".actor"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "single arg flag",
|
|
||||||
in: []string{"--arg", "name", "TOM", ".actor"},
|
|
||||||
want: []string{"--arg", "name:TOM", ".actor"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid arg name",
|
|
||||||
in: []string{"--arg", "na me", "TOM", ".actor"},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid arg name (with colon)",
|
|
||||||
in: []string{"--arg", "na:me", "TOM", ".actor"},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "colon in value",
|
|
||||||
in: []string{"--arg", "name", "T:OM", ".actor"},
|
|
||||||
want: []string{"--arg", "name:T:OM", ".actor"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "single arg flag with whitespace",
|
|
||||||
in: []string{"--arg", "name", "TOM DOWD", ".actor"},
|
|
||||||
want: []string{"--arg", "name:TOM DOWD", ".actor"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "two arg flags",
|
|
||||||
in: []string{"--arg", "name", "TOM", "--arg", "eyes", "blue", ".actor"},
|
|
||||||
want: []string{"--arg", "name:TOM", "--arg", "eyes:blue", ".actor"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "two arg flags with interspersed flag",
|
|
||||||
in: []string{"--arg", "name", "TOM", "--json", "true", "--arg", "eyes", "blue", ".actor"},
|
|
||||||
want: []string{"--arg", "name:TOM", "--json", "true", "--arg", "eyes:blue", ".actor"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
tc := tc
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
got, gotErr := preprocessFlagArgVars(tc.in)
|
|
||||||
if tc.wantErr {
|
|
||||||
t.Log(gotErr.Error())
|
|
||||||
require.Error(t, gotErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, gotErr)
|
|
||||||
require.EqualValues(t, tc.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_lastHandlePart(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
in string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{"@handle", "handle"},
|
|
||||||
{"@prod/db", "db"},
|
|
||||||
{"@prod/sub/db", "db"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
tc := tc
|
|
||||||
t.Run(tutil.Name(i, tc.in), func(t *testing.T) {
|
|
||||||
got := lastHandlePart(tc.in)
|
|
||||||
require.Equal(t, tc.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegisterDefaultOpts(t *testing.T) {
|
|
||||||
log := slogt.New(t)
|
|
||||||
reg := &options.Registry{}
|
|
||||||
|
|
||||||
log.Debug("options.Registry (before)", "reg", reg)
|
|
||||||
RegisterDefaultOpts(reg)
|
|
||||||
|
|
||||||
log.Debug("options.Registry (after)", "reg", reg)
|
|
||||||
|
|
||||||
keys := reg.Keys()
|
|
||||||
require.Len(t, keys, 31)
|
|
||||||
|
|
||||||
for _, opt := range reg.Opts() {
|
|
||||||
opt := opt
|
|
||||||
t.Run(opt.Key(), func(t *testing.T) {
|
|
||||||
require.NotNil(t, opt)
|
|
||||||
require.NotEmpty(t, opt.Key())
|
|
||||||
require.NotNil(t, opt.GetAny(nil))
|
|
||||||
require.NotNil(t, opt.DefaultAny())
|
|
||||||
require.Equal(t, opt.GetAny(nil), opt.DefaultAny())
|
|
||||||
require.NotEmpty(t, opt.Usage())
|
|
||||||
require.True(t, opt.Short() >= 0)
|
|
||||||
require.Equal(t, opt.Key(), opt.String())
|
|
||||||
require.NotEmpty(t, opt.Help())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
38
cli/options_test.go
Normal file
38
cli/options_test.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package cli_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/neilotoole/slogt"
|
||||||
|
"github.com/neilotoole/sq/cli"
|
||||||
|
"github.com/neilotoole/sq/libsq/core/options"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegisterDefaultOpts(t *testing.T) {
|
||||||
|
log := slogt.New(t)
|
||||||
|
reg := &options.Registry{}
|
||||||
|
|
||||||
|
log.Debug("options.Registry (before)", "reg", reg)
|
||||||
|
cli.RegisterDefaultOpts(reg)
|
||||||
|
|
||||||
|
log.Debug("options.Registry (after)", "reg", reg)
|
||||||
|
|
||||||
|
keys := reg.Keys()
|
||||||
|
require.Len(t, keys, 31)
|
||||||
|
|
||||||
|
for _, opt := range reg.Opts() {
|
||||||
|
opt := opt
|
||||||
|
t.Run(opt.Key(), func(t *testing.T) {
|
||||||
|
require.NotNil(t, opt)
|
||||||
|
require.NotEmpty(t, opt.Key())
|
||||||
|
require.NotNil(t, opt.GetAny(nil))
|
||||||
|
require.NotNil(t, opt.DefaultAny())
|
||||||
|
require.Equal(t, opt.GetAny(nil), opt.DefaultAny())
|
||||||
|
require.NotEmpty(t, opt.Usage())
|
||||||
|
require.True(t, opt.Short() >= 0)
|
||||||
|
require.Equal(t, opt.Key(), opt.String())
|
||||||
|
require.NotEmpty(t, opt.Help())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -256,6 +256,7 @@ func newWriters(cmd *cobra.Command, o options.Options, out, errOut io.Writer,
|
|||||||
w.Config = yamlw.NewConfigWriter(out2, pr)
|
w.Config = yamlw.NewConfigWriter(out2, pr)
|
||||||
w.Metadata = yamlw.NewMetadataWriter(out2, pr)
|
w.Metadata = yamlw.NewMetadataWriter(out2, pr)
|
||||||
w.Source = yamlw.NewSourceWriter(out2, pr)
|
w.Source = yamlw.NewSourceWriter(out2, pr)
|
||||||
|
w.Version = yamlw.NewVersionWriter(out2, pr)
|
||||||
}
|
}
|
||||||
|
|
||||||
recwFn := getRecordWriterFunc(fm)
|
recwFn := getRecordWriterFunc(fm)
|
||||||
|
@ -3,6 +3,8 @@ package jsonw
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/hostinfo"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/cli/buildinfo"
|
"github.com/neilotoole/sq/cli/buildinfo"
|
||||||
"github.com/neilotoole/sq/cli/output"
|
"github.com/neilotoole/sq/cli/output"
|
||||||
)
|
)
|
||||||
@ -21,16 +23,19 @@ func NewVersionWriter(out io.Writer, pr *output.Printing) output.VersionWriter {
|
|||||||
return &versionWriter{out: out, pr: pr}
|
return &versionWriter{out: out, pr: pr}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *versionWriter) Version(info buildinfo.BuildInfo, latestVersion string) error {
|
// Version implements output.VersionWriter.
|
||||||
|
func (w *versionWriter) Version(bi buildinfo.BuildInfo, latestVersion string, hi hostinfo.Info) error {
|
||||||
type cliBuildInfo struct {
|
type cliBuildInfo struct {
|
||||||
buildinfo.BuildInfo
|
buildinfo.BuildInfo
|
||||||
LatestVersion string `json:"latest_version"`
|
LatestVersion string `json:"latest_version"`
|
||||||
|
Host hostinfo.Info `json:"host"`
|
||||||
}
|
}
|
||||||
|
|
||||||
bi := cliBuildInfo{
|
cbi := cliBuildInfo{
|
||||||
BuildInfo: info,
|
BuildInfo: bi,
|
||||||
LatestVersion: latestVersion,
|
LatestVersion: latestVersion,
|
||||||
|
Host: hi,
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeJSON(w.out, w.pr, bi)
|
return writeJSON(w.out, w.pr, cbi)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/hostinfo"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/cli/buildinfo"
|
"github.com/neilotoole/sq/cli/buildinfo"
|
||||||
"github.com/neilotoole/sq/cli/output"
|
"github.com/neilotoole/sq/cli/output"
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
@ -23,38 +25,58 @@ func NewVersionWriter(out io.Writer, pr *output.Printing) output.VersionWriter {
|
|||||||
return &versionWriter{out: out, pr: pr}
|
return &versionWriter{out: out, pr: pr}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *versionWriter) Version(bi buildinfo.BuildInfo, latestVersion string) error {
|
// Version implements output.VersionWriter.
|
||||||
fmt.Fprintf(w.out, "sq %s", bi.Version)
|
func (w *versionWriter) Version(bi buildinfo.BuildInfo, latestVersion string, hi hostinfo.Info) error {
|
||||||
|
var newerAvailable bool
|
||||||
|
|
||||||
if w.pr.Verbose {
|
if latestVersion != "" {
|
||||||
if len(bi.Commit) > 0 {
|
newerAvailable = semver.Compare(latestVersion, bi.Version) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if !w.pr.Verbose {
|
||||||
|
fmt.Fprintf(w.out, "sq %s", bi.Version)
|
||||||
|
|
||||||
|
if newerAvailable {
|
||||||
fmt.Fprint(w.out, " ")
|
fmt.Fprint(w.out, " ")
|
||||||
w.pr.Faint.Fprint(w.out, "#"+bi.Commit)
|
w.pr.Faint.Fprintln(w.out, "Update available: "+latestVersion)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if len(bi.Timestamp) > 0 {
|
fmt.Fprintf(w.out, "sq %s\n", bi.Version)
|
||||||
fmt.Fprint(w.out, " ")
|
|
||||||
w.pr.Faint.Fprint(w.out, bi.Timestamp)
|
w.pr.Faint.Fprintf(w.out, "Version: %s\n", bi.Version)
|
||||||
|
|
||||||
|
if bi.Commit != "" {
|
||||||
|
w.pr.Faint.Fprintf(w.out, "Commit: #%s\n", bi.Commit)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bi.Timestamp != "" {
|
||||||
|
w.pr.Faint.Fprintf(w.out, "Timestamp: %s\n", bi.Timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// latestVersion = ""
|
||||||
|
w.pr.Faint.Fprint(w.out, "Latest version: ")
|
||||||
|
if latestVersion == "" {
|
||||||
|
w.pr.Error.Fprintf(w.out, "unknown\n")
|
||||||
|
} else {
|
||||||
|
if newerAvailable {
|
||||||
|
w.pr.Hilite.Fprintln(w.out, latestVersion)
|
||||||
|
} else {
|
||||||
|
w.pr.Faint.Fprintln(w.out, latestVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showUpdate := semver.Compare(latestVersion, bi.Version) > 0
|
w.pr.Faint.Fprintf(w.out, "Host: %s %s | %s %s | %s %s\n",
|
||||||
if showUpdate {
|
hi.Platform, hi.Arch, hi.Kernel, hi.KernelVersion, hi.Variant, hi.VariantVersion)
|
||||||
fmt.Fprint(w.out, " ")
|
|
||||||
w.pr.Faint.Fprint(w.out, "Update available: "+latestVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintln(w.out)
|
// Follow GNU standards (mostly)
|
||||||
|
// https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
|
||||||
|
const notice = `MIT License: https://opensource.org/license/mit
|
||||||
|
Website: https://sq.io
|
||||||
|
Source code: https://github.com/neilotoole/sq
|
||||||
|
Notice: Copyright (c) 2023 Neil O'Toole`
|
||||||
|
w.pr.Faint.Fprintln(w.out, notice)
|
||||||
|
|
||||||
if w.pr.Verbose {
|
|
||||||
// Follow GNU standards (mostly)
|
|
||||||
// https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
|
|
||||||
const notice = `
|
|
||||||
Copyright (c) 2023 Neil O'Toole
|
|
||||||
MIT License: https://opensource.org/license/mit
|
|
||||||
Website: https://sq.io
|
|
||||||
Source code: https://github.com/neilotoole/sq`
|
|
||||||
w.pr.Faint.Fprintln(w.out, notice)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/hostinfo"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/libsq/core/record"
|
"github.com/neilotoole/sq/libsq/core/record"
|
||||||
|
|
||||||
"github.com/neilotoole/sq/libsq/core/options"
|
"github.com/neilotoole/sq/libsq/core/options"
|
||||||
@ -107,7 +109,7 @@ type VersionWriter interface {
|
|||||||
// Version prints version info. Arg latestVersion is the latest
|
// Version prints version info. Arg latestVersion is the latest
|
||||||
// version available from the homebrew repository. The value
|
// version available from the homebrew repository. The value
|
||||||
// may be empty.
|
// may be empty.
|
||||||
Version(info buildinfo.BuildInfo, latestVersion string) error
|
Version(bi buildinfo.BuildInfo, latestVersion string, si hostinfo.Info) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigWriter prints config.
|
// ConfigWriter prints config.
|
||||||
|
44
cli/output/yamlw/versionwriter.go
Normal file
44
cli/output/yamlw/versionwriter.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package yamlw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/hostinfo"
|
||||||
|
|
||||||
|
"github.com/goccy/go-yaml/printer"
|
||||||
|
|
||||||
|
"github.com/neilotoole/sq/cli/buildinfo"
|
||||||
|
"github.com/neilotoole/sq/cli/output"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ output.VersionWriter = (*versionWriter)(nil)
|
||||||
|
|
||||||
|
// versionWriter implements output.VersionWriter for JSON.
|
||||||
|
type versionWriter struct {
|
||||||
|
p printer.Printer
|
||||||
|
out io.Writer
|
||||||
|
pr *output.Printing
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewVersionWriter returns a new output.VersionWriter instance
|
||||||
|
// that outputs version info in JSON.
|
||||||
|
func NewVersionWriter(out io.Writer, pr *output.Printing) output.VersionWriter {
|
||||||
|
return &versionWriter{p: newPrinter(pr), out: out, pr: pr}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version implements output.VersionWriter.
|
||||||
|
func (w *versionWriter) Version(bi buildinfo.BuildInfo, latestVersion string, hi hostinfo.Info) error {
|
||||||
|
type cliBuildInfo struct {
|
||||||
|
buildinfo.BuildInfo
|
||||||
|
LatestVersion string `json:"latest_version"`
|
||||||
|
Host hostinfo.Info `json:"host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
cbi := cliBuildInfo{
|
||||||
|
BuildInfo: bi,
|
||||||
|
LatestVersion: latestVersion,
|
||||||
|
Host: hi,
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeYAML(w.out, w.p, cbi)
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -32,6 +32,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/ecnepsnai/osquery v1.0.0
|
||||||
github.com/goccy/go-yaml v1.11.0
|
github.com/goccy/go-yaml v1.11.0
|
||||||
github.com/jackc/pgx/v5 v5.3.1
|
github.com/jackc/pgx/v5 v5.3.1
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1
|
github.com/mitchellh/go-wordwrap v1.0.1
|
||||||
|
2
go.sum
2
go.sum
@ -18,6 +18,8 @@ github.com/djherbis/fscache v0.10.1 h1:hDv+RGyvD+UDKyRYuLoVNbuRTnf2SrA2K3VyR1br9
|
|||||||
github.com/djherbis/fscache v0.10.1/go.mod h1:yyPYtkNnnPXsW+81lAcQS6yab3G2CRfnPLotBvtbf0c=
|
github.com/djherbis/fscache v0.10.1/go.mod h1:yyPYtkNnnPXsW+81lAcQS6yab3G2CRfnPLotBvtbf0c=
|
||||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
|
github.com/ecnepsnai/osquery v1.0.0 h1:FWwqlA7hCtO7Usg3N+DlZPNPHWf5nfdypnPEor2ayCs=
|
||||||
|
github.com/ecnepsnai/osquery v1.0.0/go.mod h1:vxsezNRznmkLa8UjVh88tlJiRbgW7iwinkjyg/Xc2RU=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||||
|
Loading…
Reference in New Issue
Block a user