commit 2f1cc20e80f39b9154895b0078c235908f01f42b Author: decentral1se Date: Mon Nov 27 13:04:00 2023 +0100 feat: init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0684cda --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/ppppcg +/ppppcg.yml diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..f53ba21 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,19 @@ +--- + +project_name: ppppcg + +before: + hooks: + - go mod tidy + +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + +archives: + - format: binary diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1bc8297 --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +pppcg: A PrePostPrint inspired political compass generator with SVG output. +Copyright (C) 2023 decentral1se + +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 . diff --git a/README.md b/README.md new file mode 100644 index 0000000..416f38b --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# `ppppcg` + +A [PrePostPrint](https://prepostprint.org) inspired political compass generator with SVG output. + +Why? You may find some answers on [here](http://blog.osp.kitchen) or [there](https://pad.vvvvvvaria.org/PPP-local-meetup). + +

+ +

+ +## Install + +### Linux + +``` +curl https://git.coopcloud.tech/decentral1se/ppppcg/raw/branch/main/dist/ppppcg_linux_amd64_v1/ppppcg -o ppppcg +chmod +x ppppcg +``` + +### MacOS + +``` +curl https://git.coopcloud.tech/decentral1se/ppppcg/raw/branch/main/dist/ppppcg_darwin_amd64_v1/ppppcg -o ppppcg +chmod +x ppppcg +``` + +## Usage + +Wire up a config file (`ppppcg.yml`). + +```yaml +width: 500 +height: 500 + +axis: + top: W3C + right: Industry + bottom: Custom hacks + left: Punk + +points: + - {name: "???", x: 50, y: 450} +``` + +And generate the SVG like so. + +``` +./ppppcg +``` + +You can pipe it to a graphical program or save it to file. + +``` +./ppppcg | display # X11 viewer +./ppppcg > pc.svg # to file +``` + +👋 + +## License + + + + + +## ACK + +* [PrePostPrint](https://prepostprint.org) +* [`svgo`](https://github.com/ajstarks/svgo) diff --git a/dist/artifacts.json b/dist/artifacts.json new file mode 100644 index 0000000..766ad1d --- /dev/null +++ b/dist/artifacts.json @@ -0,0 +1 @@ +[{"name":"ppppcg","path":"dist/ppppcg_linux_amd64_v1/ppppcg","goos":"linux","goarch":"amd64","goamd64":"v1","internal_type":4,"type":"Binary","extra":{"Binary":"ppppcg","Ext":"","ID":"ppppcg"}},{"name":"ppppcg","path":"dist/ppppcg_darwin_amd64_v1/ppppcg","goos":"darwin","goarch":"amd64","goamd64":"v1","internal_type":4,"type":"Binary","extra":{"Binary":"ppppcg","Ext":"","ID":"ppppcg"}},{"name":"ppppcg_0.0.0-SNAPSHOT-b702efc_darwin_amd64","path":"dist/ppppcg_darwin_amd64_v1/ppppcg","goos":"darwin","goarch":"amd64","goamd64":"v1","internal_type":2,"type":"Binary","extra":{"Binary":"ppppcg","Builds":[{"name":"ppppcg","path":"dist/ppppcg_darwin_amd64_v1/ppppcg","goos":"darwin","goarch":"amd64","goamd64":"v1","internal_type":4,"type":"Binary","extra":{"Binary":"ppppcg","Ext":"","ID":"ppppcg"}}],"Checksum":"sha256:fa300bf90314dc21c4df14a4e2cdd22066e9ff9848783e60f79b471ade9f7bcf","Format":"binary","ID":"default","Replaces":null}},{"name":"ppppcg_0.0.0-SNAPSHOT-b702efc_linux_amd64","path":"dist/ppppcg_linux_amd64_v1/ppppcg","goos":"linux","goarch":"amd64","goamd64":"v1","internal_type":2,"type":"Binary","extra":{"Binary":"ppppcg","Builds":[{"name":"ppppcg","path":"dist/ppppcg_linux_amd64_v1/ppppcg","goos":"linux","goarch":"amd64","goamd64":"v1","internal_type":4,"type":"Binary","extra":{"Binary":"ppppcg","Ext":"","ID":"ppppcg"}}],"Checksum":"sha256:a43a4d5eac79d3a2671321f1fa5c2c5e5fab5607f3f12e2256d7984baf34f8ed","Format":"binary","ID":"default","Replaces":null}},{"name":"ppppcg_0.0.0-SNAPSHOT-b702efc_checksums.txt","path":"dist/ppppcg_0.0.0-SNAPSHOT-b702efc_checksums.txt","internal_type":12,"type":"Checksum","extra":{}}] \ No newline at end of file diff --git a/dist/config.yaml b/dist/config.yaml new file mode 100644 index 0000000..b8f6ecb --- /dev/null +++ b/dist/config.yaml @@ -0,0 +1,106 @@ +project_name: ppppcg +release: + github: + owner: decentral1se + name: ppppcg + name_template: '{{.Tag}}' +builds: + - id: ppppcg + goos: + - linux + - darwin + goarch: + - amd64 + goarm: + - "6" + gomips: + - hardfloat + goamd64: + - v1 + targets: + - linux_amd64_v1 + - darwin_amd64_v1 + dir: . + main: . + binary: ppppcg + builder: go + gobinary: go + command: build + ldflags: + - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser + env: + - CGO_ENABLED=0 +archives: + - id: default + name_template: '{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}' + format: binary + files: + - src: license* + - src: LICENSE* + - src: readme* + - src: README* + - src: changelog* + - src: CHANGELOG* +snapshot: + name_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}' +checksum: + name_template: '{{ .ProjectName }}_{{ .Version }}_checksums.txt' + algorithm: sha256 +dist: dist +env_files: + github_token: ~/.config/goreleaser/github_token + gitlab_token: ~/.config/goreleaser/gitlab_token + gitea_token: ~/.config/goreleaser/gitea_token +before: + hooks: + - go mod tidy +source: + name_template: '{{ .ProjectName }}-{{ .Version }}' + format: tar.gz +gomod: + gobinary: go +announce: + twitter: + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + mastodon: + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + server: "" + reddit: + title_template: '{{ .ProjectName }} {{ .Tag }} is out!' + url_template: '{{ .ReleaseURL }}' + slack: + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + username: GoReleaser + discord: + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + author: GoReleaser + color: "3888754" + icon_url: https://goreleaser.com/static/avatar.png + teams: + title_template: '{{ .ProjectName }} {{ .Tag }} is out!' + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + color: '#2D313E' + icon_url: https://goreleaser.com/static/avatar.png + smtp: + subject_template: '{{ .ProjectName }} {{ .Tag }} is out!' + body_template: 'You can view details from: {{ .ReleaseURL }}' + mattermost: + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + title_template: '{{ .ProjectName }} {{ .Tag }} is out!' + username: GoReleaser + linkedin: + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + telegram: + message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}' + webhook: + message_template: '{ "message": "{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}"}' + content_type: application/json; charset=utf-8 + opencollective: + title_template: '{{ .Tag }}' + message_template: '{{ .ProjectName }} {{ .Tag }} is out!
Check it out at {{ .ReleaseURL }}' +git: + tag_sort: -version:refname +github_urls: + download: https://github.com +gitlab_urls: + download: https://gitlab.com diff --git a/dist/metadata.json b/dist/metadata.json new file mode 100644 index 0000000..b7a469d --- /dev/null +++ b/dist/metadata.json @@ -0,0 +1 @@ +{"project_name":"ppppcg","tag":"v0.0.0","previous_tag":"","version":"0.0.0-SNAPSHOT-b702efc","commit":"b702efce9ecc07c9f63edfff38f2a340f2b40407","date":"2023-12-03T12:10:13.695832688+01:00","runtime":{"goos":"linux","goarch":"amd64"}} \ No newline at end of file diff --git a/dist/ppppcg_0.0.0-SNAPSHOT-b702efc_checksums.txt b/dist/ppppcg_0.0.0-SNAPSHOT-b702efc_checksums.txt new file mode 100644 index 0000000..1549474 --- /dev/null +++ b/dist/ppppcg_0.0.0-SNAPSHOT-b702efc_checksums.txt @@ -0,0 +1,2 @@ +a43a4d5eac79d3a2671321f1fa5c2c5e5fab5607f3f12e2256d7984baf34f8ed ppppcg_0.0.0-SNAPSHOT-b702efc_linux_amd64 +fa300bf90314dc21c4df14a4e2cdd22066e9ff9848783e60f79b471ade9f7bcf ppppcg_0.0.0-SNAPSHOT-b702efc_darwin_amd64 diff --git a/dist/ppppcg_darwin_amd64_v1/ppppcg b/dist/ppppcg_darwin_amd64_v1/ppppcg new file mode 100755 index 0000000..cd168f8 Binary files /dev/null and b/dist/ppppcg_darwin_amd64_v1/ppppcg differ diff --git a/dist/ppppcg_linux_amd64_v1/ppppcg b/dist/ppppcg_linux_amd64_v1/ppppcg new file mode 100755 index 0000000..37b3bf9 Binary files /dev/null and b/dist/ppppcg_linux_amd64_v1/ppppcg differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0174ddc --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module d1/ppppcg + +go 1.21.1 + +require ( + github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b + gopkg.in/yaml.v2 v2.4.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..79a1ce3 --- /dev/null +++ b/go.sum @@ -0,0 +1,33 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= diff --git a/makefile b/makefile new file mode 100644 index 0000000..f42bca1 --- /dev/null +++ b/makefile @@ -0,0 +1,7 @@ +PROG := ./ppppcg + +default: + @go build -ldflags="-s -w" .; ./$(PROG) | display + +release: + @goreleaser release --snapshot --rm-dist diff --git a/ppppcg.go b/ppppcg.go new file mode 100644 index 0000000..651c941 --- /dev/null +++ b/ppppcg.go @@ -0,0 +1,178 @@ +// ppppcg is a PrePostPrint inspired political compass generator with SVG output. +package main + +import ( + "flag" + "fmt" + "log" + "os" + "path/filepath" + + svg "github.com/ajstarks/svgo" + "gopkg.in/yaml.v2" +) + +// help is the CLI help text. +const help = `ppppcg [options] + +A PrePostPrint inspired political compass generator with SVG output. + +Options: + -h output help +` + +// config is the user configuration file. +type config struct { + Width int + Height int + + Axis struct { + Top string + Right string + Bottom string + Left string + } + + Points []struct { + Name string + X int + Y int + } +} + +var ( + helpFlag bool + configFlag string + + // rectMargin is the margin for the compass rectangle. + rectMargin = 50 + + // fillNoneStrokeBlack is a default calm line style. + fillNoneStrokeBlack = "fill:none;stroke:black" + + // axisFontStyle is the default axis font style + axisFontStyle = "font-size: 13pt;font-weight:bold" + + // pointFontStyle is the default point font style + pointFontStyle = "font-size: 11pt;font-style:italic" + + // lineOverflow is the amount of overflow permitted for each compass line. + lineOverflow = 10 +) + +// handleCliFlags parses CLI flags. +func handleCliFlags() { + flag.BoolVar(&helpFlag, "h", false, "output help") + flag.StringVar(&configFlag, "c", "ppppcg.yml", "config file") + flag.Parse() +} + +// loadYAMLConfig loads a mppppcg YAML user config. +func loadYAMLConfig() (config, error) { + var cfg config + + configPath, err := filepath.Abs(configFlag) + if err != nil { + return config{}, fmt.Errorf("loadYAMLConfig: unable to convert %s to an absolute path: %w", configFlag, err) + } + + conf, err := os.ReadFile(configPath) + if err != nil { + return config{}, fmt.Errorf("loadYAMLConfig: unable to read %s: %w", configFlag, err) + } + + err = yaml.UnmarshalStrict(conf, &cfg) + if err != nil { + return config{}, fmt.Errorf("loadYAMLConfig: unable to unmarshal %s: %w", string(conf), err) + } + + return cfg, nil +} + +// main is the CLI entrypoint. +func main() { + handleCliFlags() + + if helpFlag { + fmt.Print(help) + os.Exit(0) + } + + cfg, err := loadYAMLConfig() + if err != nil { + log.Fatal(err) + } + + canvas := svg.New(os.Stdout) + canvas.Start(cfg.Width, cfg.Height) + + canvas.CenterRect( + cfg.Width/2, + cfg.Height/2, + cfg.Width-rectMargin, + cfg.Width-rectMargin, + fillNoneStrokeBlack, + ) + + canvas.Line( + cfg.Width/2, + lineOverflow, + cfg.Width/2, + cfg.Width-lineOverflow, + fillNoneStrokeBlack, + ) + + canvas.Line( + lineOverflow, + cfg.Width/2, + cfg.Width-lineOverflow, + cfg.Width/2, + fillNoneStrokeBlack, + ) + + canvas.TranslateRotate( + lineOverflow, + cfg.Width/2, + 270, + ) + canvas.Text( + -15, + 35, + cfg.Axis.Left, + axisFontStyle, + ) + canvas.Gend() + + canvas.Text( + cfg.Width/2+10, + lineOverflow+10, + cfg.Axis.Top, + axisFontStyle, + ) + + canvas.TranslateRotate( + cfg.Width-lineOverflow, + (cfg.Width/2)-lineOverflow+5, + 90, + ) + canvas.Text( + 35, + -(cfg.Width/2)-3, + cfg.Axis.Right, + axisFontStyle, + ) + canvas.Gend() + + canvas.Text( + (cfg.Width/2)+lineOverflow, + cfg.Width-lineOverflow, + cfg.Axis.Bottom, + axisFontStyle, + ) + + for _, p := range cfg.Points { + canvas.Text(p.X, p.Y, p.Name, pointFontStyle) + } + + canvas.End() +} diff --git a/ppppcg.png b/ppppcg.png new file mode 100644 index 0000000..5a811a9 Binary files /dev/null and b/ppppcg.png differ