plugin.scm
| 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu> |
| 3 | ;;; |
| 4 | ;;; This file is part of GNU Guix. |
| 5 | ;;; |
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it |
| 7 | ;;; under the terms of the GNU General Public License as published by |
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at |
| 9 | ;;; your option) any later version. |
| 10 | ;;; |
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but |
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | ;;; GNU General Public License for more details. |
| 15 | ;;; |
| 16 | ;;; You should have received a copy of the GNU General Public License |
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. |
| 18 | |
| 19 | (define-module (more build maven plugin) |
| 20 | #:use-module (more build maven java) |
| 21 | #:use-module (ice-9 textual-ports) |
| 22 | #:use-module (ice-9 match) |
| 23 | #:use-module (srfi srfi-9) |
| 24 | #:export (generate-mojo-from-files |
| 25 | default-convert-type |
| 26 | maven-convert-type)) |
| 27 | |
| 28 | (define-record-type mojo |
| 29 | (make-mojo package name goal description requires-direct-invocation? |
| 30 | requires-project? requires-reports? aggregator? |
| 31 | requires-online? inherited-by-default? instantiation-strategy |
| 32 | execution-strategy since thread-safe? phase parameters components) |
| 33 | mojo? |
| 34 | (package mojo-package) |
| 35 | (name mojo-name) |
| 36 | (goal mojo-goal) |
| 37 | (description mojo-description) |
| 38 | (requires-direct-invocation? mojo-requires-direct-invocation?) |
| 39 | (requires-project? mojo-requires-project?) |
| 40 | (requires-reports? mojo-requires-reports?) |
| 41 | (aggregator? mojo-aggregator?) |
| 42 | (requires-online? mojo-requires-online?) |
| 43 | (inherited-by-default? mojo-inherited-by-default?) |
| 44 | (instantiation-strategy mojo-instantiation-strategy) |
| 45 | (execution-strategy mojo-execution-strategy) |
| 46 | (since mojo-since) |
| 47 | (thread-safe? mojo-thread-safe?) |
| 48 | (phase mojo-phase) |
| 49 | (parameters mojo-parameters) |
| 50 | (components mojo-components)) |
| 51 | |
| 52 | (define* (update-mojo mojo |
| 53 | #:key |
| 54 | (package (mojo-package mojo)) |
| 55 | (name (mojo-name mojo)) |
| 56 | (goal (mojo-goal mojo)) |
| 57 | (description (mojo-description mojo)) |
| 58 | (requires-direct-invocation? (mojo-requires-direct-invocation? mojo)) |
| 59 | (requires-project? (mojo-requires-project? mojo)) |
| 60 | (requires-reports? (mojo-requires-reports? mojo)) |
| 61 | (aggregator? (mojo-aggregator? mojo)) |
| 62 | (requires-online? (mojo-requires-online? mojo)) |
| 63 | (inherited-by-default? (mojo-inherited-by-default? mojo)) |
| 64 | (instantiation-strategy (mojo-instantiation-strategy mojo)) |
| 65 | (execution-strategy (mojo-execution-strategy mojo)) |
| 66 | (since (mojo-since mojo)) |
| 67 | (thread-safe? (mojo-thread-safe? mojo)) |
| 68 | (phase (mojo-phase mojo)) |
| 69 | (parameters (mojo-parameters mojo)) |
| 70 | (components (mojo-components mojo))) |
| 71 | (make-mojo package name goal description requires-direct-invocation? |
| 72 | requires-project? requires-reports? aggregator? |
| 73 | requires-online? inherited-by-default? instantiation-strategy |
| 74 | execution-strategy since thread-safe? phase parameters components)) |
| 75 | |
| 76 | (define-record-type mojo-parameter |
| 77 | (make-mojo-parameter name type since required editable description |
| 78 | configuration) |
| 79 | mojo-parameter? |
| 80 | (name mojo-parameter-name) |
| 81 | (type mojo-parameter-type) |
| 82 | (since mojo-parameter-since) |
| 83 | (required mojo-parameter-required) |
| 84 | (editable mojo-parameter-editable) |
| 85 | (description mojo-parameter-description) |
| 86 | (configuration mojo-parameter-configuration)) |
| 87 | |
| 88 | (define* (update-mojo-parameter mojo-parameter |
| 89 | #:key (name (mojo-parameter-name mojo-parameter)) |
| 90 | (type (mojo-parameter-type mojo-parameter)) |
| 91 | (since (mojo-parameter-since mojo-parameter)) |
| 92 | (required (mojo-parameter-required mojo-parameter)) |
| 93 | (editable (mojo-parameter-editable mojo-parameter)) |
| 94 | (description (mojo-parameter-description mojo-parameter)) |
| 95 | (configuration (mojo-parameter-configuration mojo-parameter))) |
| 96 | (make-mojo-parameter name type since required editable description |
| 97 | configuration)) |
| 98 | |
| 99 | (define-record-type mojo-component |
| 100 | (make-mojo-component field role hint) |
| 101 | mojo-component? |
| 102 | (field mojo-component-field) |
| 103 | (role mojo-component-role) |
| 104 | (hint mojo-component-hint)) |
| 105 | |
| 106 | (define* (update-mojo-component mojo-component |
| 107 | #:key (field (mojo-component-field mojo-component)) |
| 108 | (role (mojo-component-role mojo-component)) |
| 109 | (hint (mojo-component-hint mojo-component))) |
| 110 | (make-mojo-component field role hint)) |
| 111 | |
| 112 | (define (generate-mojo-parameter mojo-parameter) |
| 113 | `(parameter (name ,(mojo-parameter-name mojo-parameter)) |
| 114 | (type ,(mojo-parameter-type mojo-parameter)) |
| 115 | ,@(if (mojo-parameter-since mojo-parameter) |
| 116 | `(since (mojo-parameter-since mojo-parameter)) |
| 117 | '()) |
| 118 | (required ,(if (mojo-parameter-required mojo-parameter) "true" "false")) |
| 119 | (editable ,(if (mojo-parameter-editable mojo-parameter) "true" "false")) |
| 120 | (description ,(mojo-parameter-description mojo-parameter)))) |
| 121 | |
| 122 | (define (generate-mojo-configuration mojo-parameter) |
| 123 | (let ((config (mojo-parameter-configuration mojo-parameter))) |
| 124 | (if config |
| 125 | `(,(string->symbol (mojo-parameter-name mojo-parameter)) |
| 126 | (@ ,@config)) |
| 127 | #f))) |
| 128 | |
| 129 | (define (generate-mojo-component mojo-component) |
| 130 | `(requirement |
| 131 | (role ,(mojo-component-role mojo-component)) |
| 132 | (role-hint ,(mojo-component-hint mojo-component)) |
| 133 | (field-name ,(mojo-component-field mojo-component)))) |
| 134 | |
| 135 | (define (generate-mojo mojo) |
| 136 | `(mojo |
| 137 | (goal ,(mojo-goal mojo)) |
| 138 | (description ,(mojo-description mojo)) |
| 139 | ,@(let ((val (mojo-requires-direct-invocation? mojo))) |
| 140 | (if val |
| 141 | `((requiresDirectInvocation ,val)) |
| 142 | '())) |
| 143 | ,@(let ((val (mojo-requires-project? mojo))) |
| 144 | (if val |
| 145 | `((requiresProject ,val)) |
| 146 | '())) |
| 147 | ,@(let ((val (mojo-requires-reports? mojo))) |
| 148 | (if val |
| 149 | `((requiresReports ,val)) |
| 150 | '())) |
| 151 | ,@(let ((val (mojo-aggregator? mojo))) |
| 152 | (if val |
| 153 | `((aggregator ,val)) |
| 154 | '())) |
| 155 | ,@(let ((val (mojo-requires-online? mojo))) |
| 156 | (if val |
| 157 | `((requiresOnline ,val)) |
| 158 | '())) |
| 159 | ,@(let ((val (mojo-inherited-by-default? mojo))) |
| 160 | (if val |
| 161 | `((inheritedByDefault ,val)) |
| 162 | '())) |
| 163 | ,@(let ((phase (mojo-phase mojo))) |
| 164 | (if phase |
| 165 | `((phase ,phase)) |
| 166 | '())) |
| 167 | (implementation ,(string-append (mojo-package mojo) "." (mojo-name mojo))) |
| 168 | (language "java") |
| 169 | (instantiationStrategy ,(mojo-instantiation-strategy mojo)) |
| 170 | (executionStrategy ,(mojo-execution-strategy mojo)) |
| 171 | ,@(let ((since (mojo-since mojo))) |
| 172 | (if since |
| 173 | `((since ,since)) |
| 174 | '())) |
| 175 | ,@(let ((val (mojo-thread-safe? mojo))) |
| 176 | (if val |
| 177 | `((threadSafe ,val)) |
| 178 | '())) |
| 179 | (parameters |
| 180 | ,(map generate-mojo-parameter (mojo-parameters mojo))) |
| 181 | (configuration |
| 182 | ,@(filter (lambda (a) a) (map generate-mojo-configuration (mojo-parameters mojo)))) |
| 183 | (requirements |
| 184 | ,@(map generate-mojo-component (mojo-components mojo))))) |
| 185 | |
| 186 | |
| 187 | (define (default-convert-type type) |
| 188 | (cond |
| 189 | ((equal? type "String") "java.lang.String") |
| 190 | ((equal? type "File") "java.io.File") |
| 191 | ((and (> (string-length type) 6) |
| 192 | (equal? (substring type 0 5) "List<")) |
| 193 | "java.util.List") |
| 194 | ((and (> (string-length type) 15) |
| 195 | (equal? (substring type 0 14) "LinkedHashSet<")) |
| 196 | "java.util.LinkedHashSet") |
| 197 | (else type))) |
| 198 | |
| 199 | (define (maven-convert-type type) |
| 200 | (cond |
| 201 | ((equal? type "MavenProject") |
| 202 | "org.apache.maven.project.MavenProject") |
| 203 | (else (default-convert-type type)))) |
| 204 | |
| 205 | (define (update-mojo-from-file mojo file convert-type) |
| 206 | (define parse-tree (parse-java-file file)) |
| 207 | |
| 208 | (define (update-mojo-from-attrs mojo attrs) |
| 209 | (let loop ((mojo mojo) (attrs attrs)) |
| 210 | (match attrs |
| 211 | ('() mojo) |
| 212 | ((attr attrs ...) |
| 213 | (match attr |
| 214 | (('annotation-attr ('attr-name name) ('attr-value value)) |
| 215 | (cond |
| 216 | ((equal? name "name") |
| 217 | (loop (update-mojo mojo #:goal value) attrs)) |
| 218 | ((equal? name "defaultPhase") |
| 219 | (loop (update-mojo mojo #:phase value) attrs)) |
| 220 | ((equal? name "requiresProject") |
| 221 | (loop (update-mojo mojo #:requires-project? value) attrs)) |
| 222 | ((equal? name "threadSafe") |
| 223 | (loop (update-mojo mojo #:thread-safe? value) attrs)) |
| 224 | (else |
| 225 | (raise `(not-found-attr ,name))))) |
| 226 | (_ (loop mojo attrs))))))) |
| 227 | |
| 228 | (define (update-mojo-parameter-from-attrs mojo-parameter attrs) |
| 229 | (match attrs |
| 230 | ('() mojo-parameter) |
| 231 | (('annotation-attr ('attr-name name) ('attr-value value)) |
| 232 | (cond |
| 233 | ((equal? name "editable") |
| 234 | (update-mojo-parameter mojo-parameter #:editable value)) |
| 235 | ((equal? name "required") |
| 236 | (update-mojo-parameter mojo-parameter #:required value)) |
| 237 | (else |
| 238 | (update-mojo-parameter mojo-parameter |
| 239 | #:configuration |
| 240 | (cons |
| 241 | (list (string->symbol name) value) |
| 242 | (or |
| 243 | (mojo-parameter-configuration mojo-parameter) |
| 244 | '())))))) |
| 245 | ((attr attrs ...) |
| 246 | (match attr |
| 247 | (('annotation-attr ('attr-name name) ('attr-value value)) |
| 248 | (cond |
| 249 | ((equal? name "editable") |
| 250 | (update-mojo-parameter-from-attrs |
| 251 | (update-mojo-parameter mojo-parameter #:editable value) |
| 252 | attrs)) |
| 253 | ((equal? name "required") |
| 254 | (update-mojo-parameter-from-attrs |
| 255 | (update-mojo-parameter mojo-parameter #:required value) |
| 256 | attrs)) |
| 257 | (else (update-mojo-parameter-from-attrs |
| 258 | (update-mojo-parameter mojo-parameter |
| 259 | #:configuration |
| 260 | (cons |
| 261 | (list (string->symbol name) value) |
| 262 | (or |
| 263 | (mojo-parameter-configuration mojo-parameter) |
| 264 | '()))) |
| 265 | attrs)))) |
| 266 | ((attrss ...) |
| 267 | (update-mojo-parameter-from-attrs mojo-parameter (append attrss attrs))))))) |
| 268 | |
| 269 | (define (update-mojo-component-from-attrs mojo-component attrs) |
| 270 | (match attrs |
| 271 | ('() mojo-component) |
| 272 | ((attr attrs ...) |
| 273 | (match attr |
| 274 | (('annotation-attr ('attr-name name) ('attr-value value)) |
| 275 | (cond |
| 276 | ((equal? name "role") |
| 277 | (update-mojo-component-from-attrs |
| 278 | (update-mojo-component mojo-component #:role value) |
| 279 | attrs)) |
| 280 | ((equal? name "hint") |
| 281 | (update-mojo-component-from-attrs |
| 282 | (update-mojo-component mojo-component #:hint value) |
| 283 | attrs)) |
| 284 | (else (raise `(not-found-attr ,name))))) |
| 285 | ((attrss ...) |
| 286 | (update-mojo-component-from-attrs mojo-component (append attrss attrs))))))) |
| 287 | |
| 288 | (define (update-mojo-from-class-content mojo content) |
| 289 | (let loop ((content content) |
| 290 | (mojo mojo) |
| 291 | (last-comment #f)) |
| 292 | (match content |
| 293 | ('() mojo) |
| 294 | ((('comment last-comment) content ...) |
| 295 | (loop content mojo last-comment)) |
| 296 | ((('param-pat ('annotation-pat annot-name attrs ...) ('type-name type) |
| 297 | ('param-name name)) content ...) |
| 298 | (cond |
| 299 | ((equal? annot-name "Parameter") |
| 300 | (loop content |
| 301 | (update-mojo mojo |
| 302 | #:parameters |
| 303 | (cons (update-mojo-parameter-from-attrs |
| 304 | (make-mojo-parameter |
| 305 | name (convert-type type) #f #f #f last-comment #f) |
| 306 | attrs) |
| 307 | (mojo-parameters mojo))) |
| 308 | #f)) |
| 309 | ((equal? annot-name "Component") |
| 310 | (loop content |
| 311 | (update-mojo mojo |
| 312 | #:components |
| 313 | (cons (update-mojo-component-from-attrs |
| 314 | (make-mojo-component name #f #f) |
| 315 | attrs) |
| 316 | (mojo-components mojo))) |
| 317 | #f)) |
| 318 | (else (raise `(not-found-annot ,annot-name))))) |
| 319 | ((('param-pat _ ...) content ...) |
| 320 | (loop content mojo #f)) |
| 321 | ((('method-pat _ ...) content ...) |
| 322 | (loop content mojo #f))))) |
| 323 | |
| 324 | (let loop ((content parse-tree) |
| 325 | (mojo mojo) |
| 326 | (last-comment #f)) |
| 327 | (if (null? content) |
| 328 | mojo |
| 329 | (match content |
| 330 | ((tls content ...) |
| 331 | (match tls |
| 332 | (('package package) |
| 333 | (loop content (update-mojo mojo #:package package) last-comment)) |
| 334 | (('comment last-comment) |
| 335 | (loop content mojo last-comment)) |
| 336 | (('class-pat ('annotation-pat annot-name (attrs ...)) name ('extends extend) |
| 337 | ('class-body class-content ...)) |
| 338 | (loop content |
| 339 | (update-mojo-from-class-content |
| 340 | (update-mojo-from-attrs |
| 341 | (update-mojo mojo |
| 342 | #:name name |
| 343 | #:description last-comment) |
| 344 | attrs) |
| 345 | class-content) |
| 346 | #f)) |
| 347 | (('class-pat ('annotation-pat annot-name (attrs ...)) name ('extends extend) |
| 348 | ('implements implement) ('class-body class-content ...)) |
| 349 | (loop content |
| 350 | (update-mojo-from-class-content |
| 351 | (update-mojo-from-attrs |
| 352 | (update-mojo mojo |
| 353 | #:name name |
| 354 | #:description last-comment) |
| 355 | attrs) |
| 356 | class-content) |
| 357 | #f)) |
| 358 | (_ |
| 359 | (loop content mojo last-comment)))))))) |
| 360 | |
| 361 | (define (generate-mojo-from-files convert-type . files) |
| 362 | (let ((mojo (make-mojo #f #f #f #f #f #f #f #f #f #f "per-lookup" |
| 363 | "once-per-session" #f #f #f '() '()))) |
| 364 | (let loop ((files files) (mojo mojo)) |
| 365 | (if (null? files) |
| 366 | (generate-mojo mojo) |
| 367 | (loop |
| 368 | (cdr files) |
| 369 | (update-mojo-from-file |
| 370 | (update-mojo mojo |
| 371 | #:package #f |
| 372 | #:name #f |
| 373 | #:goal #f |
| 374 | #:description #f |
| 375 | #:requires-direct-invocation? #f |
| 376 | #:requires-project? #f |
| 377 | #:requires-reports? #f |
| 378 | #:aggregator? #f |
| 379 | #:requires-online? #f |
| 380 | #:inherited-by-default? #f |
| 381 | #:instantiation-strategy "per-lookup" |
| 382 | #:execution-strategy "once-per-session" |
| 383 | #:since #f |
| 384 | #:thread-safe? #f |
| 385 | #:phase #f) |
| 386 | (car files) |
| 387 | convert-type)))))) |
| 388 |