-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial Open Source release of can-go
- Loading branch information
Showing
155 changed files
with
17,287 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
version: 2 | ||
jobs: | ||
build: | ||
docker: | ||
- image: circleci/golang:1.13-stretch-node | ||
steps: | ||
- checkout | ||
- run: make |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.idea | ||
.gobincache | ||
build/files |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2019 Einride AB | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
all: \ | ||
go-stringer \ | ||
go-mock-gen \ | ||
testdata \ | ||
go-lint \ | ||
go-test \ | ||
go-mod-tidy \ | ||
git-verify-nodiff | ||
|
||
include build/rules.mk | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -rf $(FILES_DIR) | ||
|
||
.PHONY: go-lint | ||
go-lint: $(GOLANGCI_LINT) | ||
# funlen: too strict | ||
# dupl: allow duplication in tests | ||
# interfacer: deprecated | ||
# godox: allow TODOs | ||
# lll: long go:generate directives | ||
$(GOLANGCI_LINT) run --enable-all --disable funlen,dupl,interfacer,godox,lll | ||
|
||
.PHONY: go-mock-gen | ||
go-mock-gen: \ | ||
internal/mocks/mockcanrunner/mocks.go \ | ||
internal/mocks/mockclock/mocks.go \ | ||
internal/mocks/mocksocketcan/mocks.go | ||
|
||
internal/mocks/mockcanrunner/mocks.go: pkg/canrunner/run.go $(GOBIN) | ||
$(GOBIN) -m -run github.com/golang/mock/mockgen -destination $@ \ | ||
-package mockcanrunner go.einride.tech/can/pkg/canrunner \ | ||
Node,TransmittedMessage,ReceivedMessage,FrameTransmitter,FrameReceiver | ||
|
||
internal/mocks/mockclock/mocks.go: internal/clock/clock.go $(GOBIN) | ||
$(GOBIN) -m -run github.com/golang/mock/mockgen -destination $@ \ | ||
-package mockclock go.einride.tech/can/internal/clock \ | ||
Clock,Ticker | ||
|
||
internal/mocks/mocksocketcan/mocks.go: pkg/socketcan/fileconn.go $(GOBIN) | ||
$(GOBIN) -m -run github.com/golang/mock/mockgen -destination $@ \ | ||
-package mocksocketcan -source $< | ||
|
||
.PHONY: go-stringer | ||
go-stringer: \ | ||
pkg/descriptor/sendtype_string.go \ | ||
pkg/socketcan/errorclass_string.go \ | ||
pkg/socketcan/protocolviolationerrorlocation_string.go \ | ||
pkg/socketcan/protocolviolationerror_string.go \ | ||
pkg/socketcan/controllererror_string.go \ | ||
pkg/socketcan/transceivererror_string.go | ||
|
||
%_string.go: %.go | ||
go generate $< | ||
|
||
.PHONY: testdata | ||
testdata: | ||
go run cmd/cantool/main.go generate testdata/dbc testdata/gen/go | ||
|
||
.PHONY: go-test | ||
go-test: | ||
go test -race -cover ./... | ||
|
||
.PHONY: go-mod-tidy | ||
go-mod-tidy: | ||
go mod tidy -v |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# :electric_plug: CAN Go [![GoDoc][doc-img]][doc] | ||
|
||
CAN toolkit for Go programmers. | ||
|
||
[doc-img]: https://godoc.org/go.einride.tech/can?status.svg | ||
[doc]: https://godoc.org/go.einride.tech/can |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.PHONY: git-verify-nodiff | ||
git-verify-nodiff: | ||
@$(BUILD_DIR)/scripts/git-verify-nodiff.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
GOLANGCI_LINT_VERSION := 1.19.1 | ||
GOLANGCI_LINT := $(FILES_DIR)/golangci-lint/$(GOLANGCI_LINT_VERSION)/golangci-lint | ||
|
||
GOBIN_VERSION := 0.0.13 | ||
GOBIN := $(FILES_DIR)/gobin/$(GOBIN_VERSION)/gobin | ||
export PATH := $(dir $(GOBIN)):$(PATH) | ||
|
||
$(GOLANGCI_LINT): | ||
mkdir -p $(dir $@) | ||
curl -s -L -o $(dir $(GOLANGCI_LINT))/archive.tar.gz \ | ||
https://github.com/golangci/golangci-lint/releases/download/v$(GOLANGCI_LINT_VERSION)/golangci-lint-$(GOLANGCI_LINT_VERSION)-$(UNAME)-amd64.tar.gz | ||
tar xzf $(dir $(GOLANGCI_LINT))/archive.tar.gz -C $(dir $(GOLANGCI_LINT)) --strip 1 | ||
chmod +x $@ | ||
touch $@ | ||
|
||
$(GOBIN): | ||
mkdir -p $(dir $@) | ||
curl -s -L -o $@ \ | ||
https://github.com/myitcv/gobin/releases/download/v$(GOBIN_VERSION)/$(UNAME)-amd64 | ||
chmod +x $@ | ||
touch $@ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
SHELL := /bin/bash | ||
|
||
BUILD_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) | ||
FILES_DIR := $(BUILD_DIR)/files | ||
|
||
UNAME := $(shell uname -s) | ||
UNAME_LOWERCASE := $(shell uname -s | tr '[:upper:]' '[:lower:]') | ||
|
||
ifeq ($(UNAME),Linux) | ||
else ifeq ($(UNAME),Darwin) | ||
else | ||
$(error This Makefile only supports Linux and OSX build agents.) | ||
endif | ||
|
||
ifneq ($(shell uname -m),x86_64) | ||
$(error This Makefile only supports x86_64 build agents.) | ||
endif | ||
|
||
ifneq ($(shell which curl >/dev/null; echo $$?),0) | ||
$(error cURL not installed. This Makefile requires cURL.) | ||
endif | ||
|
||
ifneq ($(shell which realpath >/dev/null; echo $$?),0) | ||
$(error Coreutils not installed. OSX users run: brew install coreutils) | ||
endif | ||
|
||
include $(BUILD_DIR)/git.mk | ||
include $(BUILD_DIR)/go.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/bin/bash | ||
|
||
set -euo pipefail | ||
|
||
if [[ ! -z $(git status --porcelain) ]]; then | ||
echo "Staging area is dirty, please add all files created by the build to .gitignore" | ||
git status -s | ||
exit 1 | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// Package can provides primitives for working with CAN. | ||
// | ||
// See: https://en.wikipedia.org/wiki/CAN_bus | ||
package can // import "go.einride.tech/can" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"text/scanner" | ||
|
||
"github.com/fatih/color" | ||
"go.einride.tech/can/internal/generate" | ||
"go.einride.tech/can/pkg/dbc" | ||
"go.einride.tech/can/pkg/dbc/analysis" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/definitiontypeorder" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/intervals" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/lineendings" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/messagenames" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/multiplexedsignals" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/newsymbols" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/nodereferences" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/noreservedsignals" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/requireddefinitions" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/signalbounds" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/signalnames" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/singletondefinitions" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/siunits" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/uniquenodenames" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/uniquesignalnames" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/unitsuffixes" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/valuedescriptions" | ||
"go.einride.tech/can/pkg/dbc/analysis/passes/version" | ||
"gopkg.in/alecthomas/kingpin.v2" | ||
) | ||
|
||
func main() { | ||
app := kingpin.New("cantool", "CAN tool for Go programmers") | ||
generateCommand(app) | ||
lintCommand(app) | ||
kingpin.MustParse(app.Parse(os.Args[1:])) | ||
} | ||
|
||
func generateCommand(app *kingpin.Application) { | ||
command := app.Command("generate", "generate CAN messages") | ||
inputDir := command. | ||
Arg("input-dir", "input directory"). | ||
Required(). | ||
ExistingDir() | ||
outputDir := command. | ||
Arg("output-dir", "output directory"). | ||
Required(). | ||
String() | ||
command.Action(func(c *kingpin.ParseContext) error { | ||
return filepath.Walk(*inputDir, func(p string, i os.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
if i.IsDir() || filepath.Ext(p) != ".dbc" { | ||
return nil | ||
} | ||
relPath, err := filepath.Rel(*inputDir, p) | ||
if err != nil { | ||
return err | ||
} | ||
outputFile := relPath + ".go" | ||
outputPath := filepath.Join(*outputDir, outputFile) | ||
if err := genGo(p, outputPath); err != nil { | ||
return err | ||
} | ||
return nil | ||
}) | ||
}) | ||
} | ||
|
||
func lintCommand(app *kingpin.Application) { | ||
command := app.Command("lint", "lint DBC files") | ||
fileOrDir := command. | ||
Arg("file-or-dir", "DBC file or directory"). | ||
Required(). | ||
ExistingFileOrDir() | ||
command.Action(func(context *kingpin.ParseContext) error { | ||
filesToLint, err := resolveFileOrDirectory(*fileOrDir) | ||
if err != nil { | ||
return err | ||
} | ||
var hasFailed bool | ||
for _, lintFile := range filesToLint { | ||
f, err := os.Open(lintFile) | ||
if err != nil { | ||
return err | ||
} | ||
source, err := ioutil.ReadAll(f) | ||
if err != nil { | ||
return err | ||
} | ||
p := dbc.NewParser(f.Name(), source) | ||
if err := p.Parse(); err != nil { | ||
printError(source, err.Position(), err.Reason(), "parse") | ||
continue | ||
} | ||
for _, a := range analyzers() { | ||
pass := &analysis.Pass{ | ||
Analyzer: a, | ||
File: p.File(), | ||
} | ||
if err := a.Run(pass); err != nil { | ||
return err | ||
} | ||
hasFailed = hasFailed || len(pass.Diagnostics) > 0 | ||
for _, d := range pass.Diagnostics { | ||
printError(source, d.Pos, d.Message, a.Name) | ||
} | ||
} | ||
} | ||
if hasFailed { | ||
return errors.New("one or more lint errors") | ||
} | ||
return nil | ||
}) | ||
} | ||
|
||
func analyzers() []*analysis.Analyzer { | ||
return []*analysis.Analyzer{ | ||
// TODO: Re-evaluate if we want boolprefix.Analyzer(), since it creates a lot of churn in vendor schemas | ||
definitiontypeorder.Analyzer(), | ||
intervals.Analyzer(), | ||
lineendings.Analyzer(), | ||
messagenames.Analyzer(), | ||
multiplexedsignals.Analyzer(), | ||
newsymbols.Analyzer(), | ||
nodereferences.Analyzer(), | ||
noreservedsignals.Analyzer(), | ||
requireddefinitions.Analyzer(), | ||
signalbounds.Analyzer(), | ||
signalnames.Analyzer(), | ||
singletondefinitions.Analyzer(), | ||
siunits.Analyzer(), | ||
uniquenodenames.Analyzer(), | ||
uniquesignalnames.Analyzer(), | ||
unitsuffixes.Analyzer(), | ||
valuedescriptions.Analyzer(), | ||
version.Analyzer(), | ||
} | ||
} | ||
|
||
func genGo(inputFile string, outputFile string) error { | ||
if err := os.MkdirAll(filepath.Dir(outputFile), 0755); err != nil { | ||
return err | ||
} | ||
input, err := ioutil.ReadFile(inputFile) | ||
if err != nil { | ||
return err | ||
} | ||
result, err := generate.Compile(inputFile, input) | ||
if err != nil { | ||
return err | ||
} | ||
for _, warning := range result.Warnings { | ||
return warning | ||
} | ||
output, err := generate.Database(result.Database) | ||
if err != nil { | ||
return err | ||
} | ||
if err := ioutil.WriteFile(outputFile, output, 0644); err != nil { | ||
return err | ||
} | ||
fmt.Println("wrote:", outputFile) | ||
return nil | ||
} | ||
|
||
func resolveFileOrDirectory(fileOrDirectory string) ([]string, error) { | ||
fileInfo, err := os.Stat(fileOrDirectory) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if !fileInfo.IsDir() { | ||
return []string{fileOrDirectory}, nil | ||
} | ||
var files []string | ||
if err := filepath.Walk(fileOrDirectory, func(path string, info os.FileInfo, err error) error { | ||
if !info.IsDir() && filepath.Ext(path) == ".dbc" { | ||
files = append(files, path) | ||
} | ||
return nil | ||
}); err != nil { | ||
return nil, err | ||
} | ||
return files, nil | ||
} | ||
|
||
func printError(source []byte, pos scanner.Position, msg string, name string) { | ||
fmt.Printf("\n%s: %s (%s)\n", pos, color.RedString("%s", msg), name) | ||
fmt.Printf("%s\n", getSourceLine(source, pos)) | ||
fmt.Printf("%s\n", caretAtPosition(pos)) | ||
} | ||
|
||
func getSourceLine(source []byte, pos scanner.Position) []byte { | ||
lineStart := pos.Offset | ||
for lineStart > 0 && source[lineStart-1] != '\n' { | ||
lineStart-- | ||
} | ||
lineEnd := pos.Offset | ||
for lineEnd < len(source) && source[lineEnd] != '\n' { | ||
lineEnd++ | ||
} | ||
return source[lineStart:lineEnd] | ||
} | ||
|
||
func caretAtPosition(pos scanner.Position) string { | ||
return strings.Repeat(" ", pos.Column-1) + color.YellowString("^") | ||
} |
Oops, something went wrong.