diff options
-rw-r--r-- | COPYING | 24 | ||||
-rw-r--r-- | LICENSE | 19 | ||||
-rw-r--r-- | Makefile | 19 | ||||
-rwxr-xr-x | licenser | 181 | ||||
-rwxr-xr-x | licensor | 251 |
5 files changed, 287 insertions, 207 deletions
diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..0a06d2f --- /dev/null +++ b/COPYING | |||
@@ -0,0 +1,24 @@ | |||
1 | |||
2 | Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person | ||
5 | obtaining a copy of this software and associated documentation files | ||
6 | (the "Software"), to deal in the Software without restriction, | ||
7 | including without limitation the rights to use, copy, modify, merge, | ||
8 | publish, distribute, sublicense, and/or sell copies of the Software, | ||
9 | and to permit persons to whom the Software is furnished to do so, | ||
10 | subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be | ||
13 | included in all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
19 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
20 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | |||
24 | |||
diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 44c8493..0000000 --- a/LICENSE +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | Copyright 2020 Case Duckworth | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | of this software and associated documentation files (the "Software"), to deal | ||
5 | in the Software without restriction, including without limitation the rights | ||
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | copies of the Software, and to permit persons to whom the Software is | ||
8 | furnished to do so, subject to the following conditions: | ||
9 | |||
10 | The above copyright notice and this permission notice shall be included in all | ||
11 | copies or substantial portions of the Software. | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | SOFTWARE. | ||
diff --git a/Makefile b/Makefile index 6f7723b..cca469c 100644 --- a/Makefile +++ b/Makefile | |||
@@ -1,15 +1,20 @@ | |||
1 | # licenser | 1 | # licenser |
2 | 2 | ||
3 | PREFIX ?= /usr | 3 | PREFIX = /usr/local |
4 | 4 | ||
5 | .PHONY: def install uninstall | 5 | .PHONY: help install uninstall |
6 | 6 | ||
7 | def: | 7 | help: |
8 | @echo "run 'make install' to install" | 8 | @echo "licensor : drop urself a license" |
9 | @echo "run 'make uninstall' to uninstall" | 9 | @echo "(C) 2021--2022 Case Duckworth <acdw@acdw.net>" |
10 | @echo | ||
11 | @echo "TARGETS:" | ||
12 | @echo " install Install licensor to $(DESTDIR)$(PREFIX)/bin/licensor." | ||
13 | @echo " uninstall Uninstall licensor-related files." | ||
10 | 14 | ||
11 | install: licenser | 15 | install: licensor |
12 | install -D $< $(DESTDIR)$(PREFIX)/bin | 16 | install -D $< $(DESTDIR)$(PREFIX)/bin |
13 | 17 | ||
14 | uninstall: | 18 | uninstall: |
15 | rm -f $(DESTDIR)$(PREFIX)/bin/licenser | 19 | rm -f $(DESTDIR)$(PREFIX)/bin/licensor |
20 | rm -rf "${XDG_CACHE_HOME:-$HOME/.cache}/licensor" | ||
diff --git a/licenser b/licenser deleted file mode 100755 index 2337470..0000000 --- a/licenser +++ /dev/null | |||
@@ -1,181 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | # licenser: drop a little ol license in there | ||
3 | # Author: Case Duckworth <acdw@acdw.net> | ||
4 | # License: MIT | ||
5 | # Version: 0.2 | ||
6 | |||
7 | # Constants | ||
8 | ## where to download licenses from | ||
9 | PRGN="${0##*/}" | ||
10 | : "${LICENSER_SOURCE:=https://git.sr.ht/~acdw/licenser-licenses/blob/master}" | ||
11 | LICENSER_CACHE="${XDG_DATA_HOME:-$HOME/.local/share}/licenser" | ||
12 | LICENSER_LICENSE="${LICENSER_LICENSE:-MIT}" | ||
13 | EXEC="${EXEC:-true}" | ||
14 | |||
15 | usage() { | ||
16 | cat <<EOF | ||
17 | $PRGN: plop a license in your project | ||
18 | |||
19 | usage: $PRGN [-h|-m|-M] | ||
20 | $PRGN [-f] [-q] [-y YEAR] [-a AUTHOR] [-e EMAIL] | ||
21 | [-l LANG] [-o FILE] [LICENSE] | ||
22 | flags: | ||
23 | -h show this help and exit | ||
24 | -m list available licenses and exit | ||
25 | -M list licenses, disregarding cached manifest | ||
26 | -f overwrite existing license | ||
27 | -q quiet: don't log anything | ||
28 | options: | ||
29 | -y YEAR set copyright date(s) to YEAR. | ||
30 | default: \$(date +%Y). | ||
31 | this option accepts arbitrary input. | ||
32 | -a AUTHOR set copyright holder(s) to AUTHOR. | ||
33 | default: | ||
34 | - git config --get user.name | ||
35 | - getent password \$USER | ||
36 | - \$USER | ||
37 | -e EMAIL set AUTHOR's email address to EMAIL. | ||
38 | default: | ||
39 | - git config --get user.email | ||
40 | - [blank] | ||
41 | -l LANG set license language to LANG. | ||
42 | default: 'en' (subject to change) | ||
43 | -o FILE set output file to FILE. | ||
44 | default: LICENSE in \$PWD | ||
45 | parameters: | ||
46 | LICENSE which license to use. | ||
47 | default: \$LICENSER_LICENSE, which | ||
48 | defaults to MIT. | ||
49 | EOF | ||
50 | } | ||
51 | |||
52 | # entry point | ||
53 | licenser() { | ||
54 | _force=false # don't replace licenses | ||
55 | _quiet=false # log stuff | ||
56 | __OUT=LICENSE # default output file | ||
57 | __LANG=en # default to en because it's got the most licenses XXX | ||
58 | |||
59 | while getopts hmMfqy:a:e:o:l:s: OPT; do | ||
60 | case "$OPT" in | ||
61 | h) | ||
62 | usage | ||
63 | exit 0 | ||
64 | ;; | ||
65 | f) _force=true ;; | ||
66 | m) | ||
67 | list_licenses | ||
68 | exit "$?" | ||
69 | ;; | ||
70 | M) | ||
71 | list_licenses -f | ||
72 | exit "$?" | ||
73 | ;; | ||
74 | q) _quiet=true ;; | ||
75 | y) __YEAR="$OPTARG" ;; | ||
76 | a) __AUTHOR="$OPTARG" ;; | ||
77 | e) __EMAIL="$OPTARG" ;; | ||
78 | o) __OUT="$OPTARG" ;; | ||
79 | l) __LANG="$OPTARG" ;; | ||
80 | *) | ||
81 | usage | ||
82 | exit 1 | ||
83 | ;; | ||
84 | esac | ||
85 | done | ||
86 | shift $((OPTIND - 1)) | ||
87 | __LICENSE="${1:-$LICENSER_LICENSE}" | ||
88 | |||
89 | if ! __CACHED=$(get_license "$__LICENSE"); then | ||
90 | list_licenses | ||
91 | exit 2 | ||
92 | fi | ||
93 | |||
94 | if [ -e "$__OUT" ] && ! $_force; then | ||
95 | log "File exists: $__OUT" | ||
96 | exit 3 | ||
97 | fi | ||
98 | |||
99 | eval "$( | ||
100 | put "cat<<_END_LICENSE_" | ||
101 | cat "$__CACHED" | ||
102 | put | ||
103 | put "_END_LICENSE_" | ||
104 | )" >"$__OUT" | ||
105 | |||
106 | log "$__LICENSE written to $__OUT." | ||
107 | } | ||
108 | |||
109 | # download a license, or get it from the cache | ||
110 | # if there's not one, return error | ||
111 | get_license() { | ||
112 | license="$1" | ||
113 | cached="$LICENSER_CACHE/$license/$__LANG" | ||
114 | source="$LICENSER_SOURCE/$license/$__LANG" | ||
115 | |||
116 | mkdir -p "$LICENSER_CACHE/$license" | ||
117 | log "Checking cache for $license..." | ||
118 | if [ ! -f "$cached" ]; then | ||
119 | log "Not found. Downloading from $source..." | ||
120 | if ! curl -fLo "$cached" "$source"; then | ||
121 | log "License $license unavailable in language: $__LANG" | ||
122 | return 1 | ||
123 | fi | ||
124 | fi | ||
125 | put "$cached" | ||
126 | } | ||
127 | |||
128 | # download a list of the licenses, or get it from the cache | ||
129 | list_licenses() { | ||
130 | cached="$LICENSER_CACHE/manifest" | ||
131 | source="$LICENSER_SOURCE/manifest" | ||
132 | |||
133 | [ "x$1" = "x-r" ] && rm "$cached" | ||
134 | |||
135 | mkdir -p "$LICENSER_CACHE" | ||
136 | log "Checking cache for manifest..." | ||
137 | if [ ! -f "$cached" ]; then | ||
138 | log "Not found. Downloading from $source..." | ||
139 | if ! curl -fLo "$cached" "$LICENSER_SOURCE/manifest"; then | ||
140 | log "Unable to get the manifest" | ||
141 | return 1 | ||
142 | fi | ||
143 | fi | ||
144 | cat "$cached" | ||
145 | } | ||
146 | |||
147 | # template function for the copyright year | ||
148 | year() { | ||
149 | case "$__YEAR" in | ||
150 | '') # figure out the year | ||
151 | date +%Y ;; | ||
152 | *) # one was provided | ||
153 | put "$__YEAR" ;; | ||
154 | esac | ||
155 | } | ||
156 | |||
157 | # template function for author/owner | ||
158 | author() { | ||
159 | if [ -z "$__AUTHOR" ]; then | ||
160 | __AUTHOR="$(git config --get user.name)" # try from git | ||
161 | [ -z "$__AUTHOR" ] && __AUTHOR="$( | ||
162 | getent passwd "$USER" | awk -F: '{sub(/,+/,"",$5);print $5}' | ||
163 | )" # or, try from getent | ||
164 | [ -z "$__AUTHOR" ] && __AUTHOR="$USER" # give up, get $USER | ||
165 | fi | ||
166 | put "$__AUTHOR" | ||
167 | } | ||
168 | |||
169 | email() { | ||
170 | if [ -z "$__EMAIL" ]; then | ||
171 | __EMAIL="$(git config --get user.email)" # try from git | ||
172 | fi | ||
173 | [ -n "$__EMAIL" ] && put "<$__EMAIL>" | ||
174 | } | ||
175 | |||
176 | # helpers | ||
177 | put() { printf '%s\n' "$*"; } | ||
178 | log() { $_quiet || put "$PRGN: $*" >&2; } | ||
179 | |||
180 | # run | ||
181 | $EXEC && licenser "$@" | ||
diff --git a/licensor b/licensor new file mode 100755 index 0000000..47da938 --- /dev/null +++ b/licensor | |||
@@ -0,0 +1,251 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # Constants | ||
4 | PRGN="${0##*/}" | ||
5 | LICENSOR_CACHE="${XDG_CACHE_HOME:-$HOME/.cache/licensor" | ||
6 | # Configuration | ||
7 | : "${LICENSE_REPO_VERSION:=3.17}" | ||
8 | : "${LICENSE_REPO_URL:=https://github.com/spdx/license-list-data/archive/refs/tags/v$LICENSE_REPO_VERSION.tar.gz}" | ||
9 | : "${LICENSE_REPO_PATH:=license-list-data-$LICENSE_REPO_VERSION/template}" | ||
10 | : "${LICENSOR_LICENSE:=MIT}" | ||
11 | : "${LICENSOR_OUTPUT_FILE:=COPYING}" | ||
12 | |||
13 | usage() { | ||
14 | cat <<EOF | ||
15 | $PRGN: drop a lil ol license in yr project | ||
16 | USAGE: $PRGN [-h|-m|-M] | ||
17 | $PRGN [FLAGS] [OPTIONS] [LICENSE] | ||
18 | |||
19 | FLAGS: | ||
20 | -h Display this help and exit. | ||
21 | -l List available licenses and exit. | ||
22 | -L List available licenses, disregarding cache. | ||
23 | This flag will re-download the license repo. | ||
24 | -f Overwrite existing license. | ||
25 | -q Be quiet (don't log anything). | ||
26 | |||
27 | OPTIONS: | ||
28 | -y YEARS Set copyright date(s) to YEARS. | ||
29 | Default: \$(date +%Y). | ||
30 | -a AUTHORS Set copyright holder(s) to AUTHOR. | ||
31 | Default: use the first of | ||
32 | - git config --get user.name | ||
33 | - getent password \$USER | ||
34 | - \$USER | ||
35 | -e EMAILS Set AUTHOR's EMAIL address. | ||
36 | Default: \$(git config --get user.email), | ||
37 | or stay blank. | ||
38 | -o FILE Output the fetched license to FILE. | ||
39 | Default: \$PWD/$LICENSOR_OUTPUT_FILE. | ||
40 | |||
41 | PARAMETERS: | ||
42 | LICENSE The license to use. | ||
43 | Default: $LICENSOR_LICENSE. | ||
44 | EOF | ||
45 | exit ${1:-0} | ||
46 | } | ||
47 | |||
48 | main() { | ||
49 | _force=false | ||
50 | _quiet=false | ||
51 | _fold=1 | ||
52 | _optional=0 | ||
53 | __width=70 | ||
54 | __output="$LICENSOR_OUTPUT_FILE" | ||
55 | __year="$(date +%Y)" | ||
56 | __author="$(guess_author)" | ||
57 | __email="$(guess_email)" | ||
58 | __copyright="Copyright (C) $__year $__author <$__email>" | ||
59 | |||
60 | while getopts hlLs:fzZpPqy:a:e:o:w:c: opt; do | ||
61 | case "$opt" in | ||
62 | # commands | ||
63 | h) usage ;; | ||
64 | l) list_licenses && exit || exit $? ;; | ||
65 | L) list_licenses -f && exit || exit $? ;; | ||
66 | s) search_licenses "$OPTARG" ;; | ||
67 | # flags | ||
68 | f) _force=true ;; | ||
69 | z) _fold=1 ;; | ||
70 | Z) _fold=0 ;; | ||
71 | p) _optional=1 ;; | ||
72 | P) _optional=0 ;; | ||
73 | q) _quiet=true ;; | ||
74 | # options | ||
75 | y) __year="$OPTARG" ;; | ||
76 | a) __author="$OPTARG" ;; | ||
77 | e) __email="$OPTARG" ;; | ||
78 | o) __output="$OPTARG" ;; | ||
79 | w) __width="$OPTARG" ;; | ||
80 | c) __copyright="$OPTARG" ;; | ||
81 | *) usage 1 ;; | ||
82 | esac | ||
83 | done | ||
84 | shift $((OPTIND - 1)) | ||
85 | __license="${1:-$LICENSOR_LICENSE}" | ||
86 | |||
87 | if [ -e "$__output" ] && ! $_force; then | ||
88 | log "File exists: $__output" | ||
89 | exit 3 | ||
90 | fi | ||
91 | |||
92 | if [ "x$__output" = x- ]; then | ||
93 | __output=/dev/stdout | ||
94 | fi | ||
95 | |||
96 | license_file="$(get_license "$__license")" || exit $? | ||
97 | license_convert <"$LICENSOR_CACHE/$license_file.template.txt" \ | ||
98 | "$__copyright" "$_optional" "$_fold" "$__width" >"$__output" | ||
99 | [ "$__output" != /dev/stdout ] && log "$__license license written to $__output." | ||
100 | } | ||
101 | |||
102 | get_licenses() { | ||
103 | # Get licenses from cache, or download them | ||
104 | if ! [ -d "$LICENSOR_CACHE" ] || [ "x$1" = "x-f" ]; then | ||
105 | log "Downlading licenses from $LICENSE_REPO_URL..." | ||
106 | mkdir -p "$LICENSOR_CACHE" | ||
107 | tmpfile="/tmp/licenses.tar.gz" | ||
108 | if ! [ -f "$tmpfile" ]; then | ||
109 | curl -o "$tmpfile" -L "$LICENSE_REPO_URL" >/dev/null 2>&1 || | ||
110 | return 1 | ||
111 | fi | ||
112 | log "Extracting licenses to $LICENSOR_CACHE..." | ||
113 | if tar -C "$LICENSOR_CACHE" \ | ||
114 | -xvf "$tmpfile" --strip-components=2 \ | ||
115 | "$LICENSE_REPO_PATH" >/dev/null 2>&1; then | ||
116 | rm "$tmpfile" | ||
117 | else | ||
118 | return 1 | ||
119 | fi | ||
120 | fi | ||
121 | } | ||
122 | |||
123 | get_license() { | ||
124 | list_licenses | grep -iE '^'"$1"'$' || { | ||
125 | log "Can't find license \"$1\"." | ||
126 | exit 1 | ||
127 | } | ||
128 | } | ||
129 | |||
130 | list_licenses() { | ||
131 | get_licenses "$1" || exit 1 | ||
132 | |||
133 | find "$LICENSOR_CACHE" -iname '*.template.txt' | | ||
134 | sort | | ||
135 | xargs basename -s .template.txt | ||
136 | } | ||
137 | |||
138 | search_licenses() { | ||
139 | list_licenses | grep -iE "$1" | ||
140 | exit $? | ||
141 | } | ||
142 | |||
143 | guess_author() { | ||
144 | author="$(git config --get user.name)" | ||
145 | [ -z "$author" ] && | ||
146 | author="$(getent passwd "$USER" | awk -F: '{sub(/,+/,"",$5);print $5}')" | ||
147 | [ -z "$author" ] && | ||
148 | author="$USER" | ||
149 | put "$author" | ||
150 | } | ||
151 | guess_email() { | ||
152 | email="$(git config --get user.email)" | ||
153 | put "$email" | ||
154 | } | ||
155 | |||
156 | put() { printf '%s\n' "$*"; } | ||
157 | log() { $_quiet || put "$PRGN: $*" >&2; } | ||
158 | |||
159 | license_convert() { | ||
160 | copyright="$1" # "Copyright (C) 2022 Case Duckworth <acdw@acdw.net>" | ||
161 | show_optional="${2:-0}" # 0 | ||
162 | fold_output="${3:-1}" # 1 | ||
163 | fold_width="${4:-70}" # 70 | ||
164 | awk ' | ||
165 | BEGIN { | ||
166 | foldOutput = '"$fold_output"' | ||
167 | foldWidth = '"$fold_width"' | ||
168 | showOptional = '"$show_optional"' | ||
169 | copyright = "'"$copyright"'" | ||
170 | } | ||
171 | { buf = buf "\n" $0 } | ||
172 | END { | ||
173 | split(buf, b, "") | ||
174 | c = 1 | ||
175 | out = "" | ||
176 | optstr = "" | ||
177 | opt = 0 | ||
178 | while (c <= length(b)) { | ||
179 | if (b[c] == "<" && b[c + 1] == "<") { | ||
180 | tok = "" | ||
181 | c += 2 | ||
182 | closed = 0 | ||
183 | while (! closed) { | ||
184 | tok = tok b[c++] | ||
185 | if (b[c] == ">" && b[c + 1] == ">") { | ||
186 | closed++ | ||
187 | c += 2 | ||
188 | } | ||
189 | } | ||
190 | if (tok ~ /^beginOptional/) { | ||
191 | opt = 1 | ||
192 | } else if (tok == "endOptional") { | ||
193 | if (showOptional) { | ||
194 | out = out optstr | ||
195 | } | ||
196 | opt = 0 | ||
197 | optstr = "" | ||
198 | } else if (tok ~ /^var/) { | ||
199 | split(tok, ta, ";") | ||
200 | name = "" | ||
201 | original = "" | ||
202 | for (a in ta) { | ||
203 | if (ta[a] ~ "^name") { | ||
204 | match(ta[a], /=".*/) | ||
205 | name = substr(ta[a], RSTART + 2, RLENGTH - 3) | ||
206 | } else if (ta[a] ~ "^original") { | ||
207 | match(ta[a], /=".*/) | ||
208 | original = substr(ta[a], RSTART + 2, RLENGTH - 3) | ||
209 | } else if (ta[a] ~ "^match") { | ||
210 | # currently not used | ||
211 | } | ||
212 | } | ||
213 | if (name == "copyright") { | ||
214 | out = out copyright | ||
215 | } else { | ||
216 | out = out original | ||
217 | } | ||
218 | } | ||
219 | continue | ||
220 | } | ||
221 | if (opt) { | ||
222 | optstr = optstr b[c++] | ||
223 | } else { | ||
224 | out = out b[c++] | ||
225 | } | ||
226 | } | ||
227 | # "Fold" the output | ||
228 | if (foldOutput) { | ||
229 | split(out, oa, "\n") | ||
230 | out = "" | ||
231 | for (l in oa) { | ||
232 | split(oa[l], la, FS) | ||
233 | lc = 0 | ||
234 | for (w in la) { | ||
235 | lc += length(la[w]) + 1 | ||
236 | if (lc >= foldWidth) { | ||
237 | out = out "\n" la[w] " " | ||
238 | lc = length(la[w]) + 1 | ||
239 | } else { | ||
240 | out = out la[w] " " | ||
241 | } | ||
242 | } | ||
243 | out = out "\n" | ||
244 | } | ||
245 | } | ||
246 | print out | ||
247 | } | ||
248 | ' | ||
249 | } | ||
250 | |||
251 | main "$@" | ||