Skip to content

Commit df61c28

Browse files
authored
feat: Improve class file mapping #2021
Signed-off-by: Chin Yeung Li <[email protected]>
1 parent 25cad21 commit df61c28

File tree

5 files changed

+239
-10
lines changed

5 files changed

+239
-10
lines changed

scanpipe/pipelines/deploy_to_develop.py

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ def steps(cls):
8383
cls.find_grammar_packages,
8484
cls.map_grammar_to_class,
8585
cls.map_jar_to_grammar_source,
86+
cls.find_groovy_packages,
87+
cls.map_groovy_to_class,
88+
cls.map_jar_to_groovy_source,
89+
cls.find_aspectj_packages,
90+
cls.map_aspectj_to_class,
91+
cls.map_jar_to_aspectj_source,
92+
cls.find_clojure_packages,
93+
cls.map_clojure_to_class,
94+
cls.map_jar_to_clojure_source,
8695
cls.find_xtend_packages,
8796
cls.map_xtend_to_class,
8897
cls.map_javascript,
@@ -208,7 +217,7 @@ def find_scala_packages(self):
208217

209218
@optional_step("Scala")
210219
def map_scala_to_class(self):
211-
"""Map a .class compiled file to its .java source."""
220+
"""Map a .class compiled file to its .scala source."""
212221
d2d.map_jvm_to_class(
213222
project=self.project, jvm_lang=jvm.ScalaLanguage, logger=self.log
214223
)
@@ -222,14 +231,14 @@ def map_jar_to_scala_source(self):
222231

223232
@optional_step("Kotlin")
224233
def find_kotlin_packages(self):
225-
"""Find the java package of the .java source files."""
234+
"""Find the java package of the kotlin source files."""
226235
d2d.find_jvm_packages(
227236
project=self.project, jvm_lang=jvm.KotlinLanguage, logger=self.log
228237
)
229238

230239
@optional_step("Kotlin")
231240
def map_kotlin_to_class(self):
232-
"""Map a .class compiled file to its .java source."""
241+
"""Map a .class compiled file to its kotlin source."""
233242
d2d.map_jvm_to_class(
234243
project=self.project, jvm_lang=jvm.KotlinLanguage, logger=self.log
235244
)
@@ -262,6 +271,69 @@ def map_jar_to_grammar_source(self):
262271
project=self.project, jvm_lang=jvm.GrammarLanguage, logger=self.log
263272
)
264273

274+
@optional_step("Groovy")
275+
def find_groovy_packages(self):
276+
"""Find the package of the .groovy source files."""
277+
d2d.find_jvm_packages(
278+
project=self.project, jvm_lang=jvm.GroovyLanguage, logger=self.log
279+
)
280+
281+
@optional_step("Groovy")
282+
def map_groovy_to_class(self):
283+
"""Map a .class compiled file to its .groovy source."""
284+
d2d.map_jvm_to_class(
285+
project=self.project, jvm_lang=jvm.GroovyLanguage, logger=self.log
286+
)
287+
288+
@optional_step("Groovy")
289+
def map_jar_to_groovy_source(self):
290+
"""Map .jar files to their related source directory."""
291+
d2d.map_jar_to_jvm_source(
292+
project=self.project, jvm_lang=jvm.GroovyLanguage, logger=self.log
293+
)
294+
295+
@optional_step("AspectJ")
296+
def find_aspectj_packages(self):
297+
"""Find the package of the .aj source files."""
298+
d2d.find_jvm_packages(
299+
project=self.project, jvm_lang=jvm.AspectJLanguage, logger=self.log
300+
)
301+
302+
@optional_step("AspectJ")
303+
def map_aspectj_to_class(self):
304+
"""Map a .class compiled file to its .aj source."""
305+
d2d.map_jvm_to_class(
306+
project=self.project, jvm_lang=jvm.AspectJLanguage, logger=self.log
307+
)
308+
309+
@optional_step("AspectJ")
310+
def map_jar_to_aspectj_source(self):
311+
"""Map .jar files to their related source directory."""
312+
d2d.map_jar_to_jvm_source(
313+
project=self.project, jvm_lang=jvm.AspectJLanguage, logger=self.log
314+
)
315+
316+
@optional_step("Clojure")
317+
def find_clojure_packages(self):
318+
"""Find the package of the .clj source files."""
319+
d2d.find_jvm_packages(
320+
project=self.project, jvm_lang=jvm.ClojureLanguage, logger=self.log
321+
)
322+
323+
@optional_step("Clojure")
324+
def map_clojure_to_class(self):
325+
"""Map a .class compiled file to its .clj source."""
326+
d2d.map_jvm_to_class(
327+
project=self.project, jvm_lang=jvm.ClojureLanguage, logger=self.log
328+
)
329+
330+
@optional_step("Clojure")
331+
def map_jar_to_clojure_source(self):
332+
"""Map .jar files to their related source directory."""
333+
d2d.map_jar_to_jvm_source(
334+
project=self.project, jvm_lang=jvm.ClojureLanguage, logger=self.log
335+
)
336+
265337
@optional_step("Xtend")
266338
def find_xtend_packages(self):
267339
"""Find the java package of the xtend source files."""

scanpipe/pipes/d2d.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ def map_jvm_to_class(project, jvm_lang: jvm.JvmLanguage, logger=None):
239239

240240
if logger:
241241
logger(
242-
f"Mapping {to_resource_count:,d} .class resources to "
243-
f"{from_resource_count:,d} {jvm_lang.source_extensions}"
242+
f"Mapping {to_resource_count:,d} .class (or other deployed file) "
243+
f"resources to {from_resource_count:,d} {jvm_lang.source_extensions}"
244244
)
245245

246246
# build an index using from-side fully qualified class file names

scanpipe/pipes/d2d_config.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ class EcosystemConfig:
112112
"*kotlin-project-structure-metadata.json",
113113
],
114114
),
115+
"Groovy": EcosystemConfig(
116+
ecosystem_option="Groovy",
117+
matchable_package_extensions=[".jar", ".war"],
118+
matchable_resource_extensions=[".class"],
119+
deployed_resource_path_exclusions=[
120+
"*META-INF/*",
121+
],
122+
),
115123
"JavaScript": EcosystemConfig(
116124
ecosystem_option="JavaScript",
117125
matchable_resource_extensions=[

scanpipe/pipes/jvm.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,39 @@ class JavaLanguage(JvmLanguage):
192192
class ScalaLanguage(JvmLanguage):
193193
name = "scala"
194194
source_extensions = (".scala",)
195-
binary_extensions = (".class",)
195+
binary_extensions = (".class", ".tasty")
196196
source_package_attribute_name = "scala_package"
197197
package_regex = re.compile(r"^\s*package\s+([\w\.]+)\s*;?")
198198
binary_map_type = "scala_to_class"
199199

200200

201+
class GroovyLanguage(JvmLanguage):
202+
name = "groovy"
203+
source_extensions = (".groovy",)
204+
binary_extensions = (".class",)
205+
source_package_attribute_name = "groovy_package"
206+
package_regex = re.compile(r"^\s*package\s+([\w\.]+)\s*;?")
207+
binary_map_type = "groovy_to_class"
208+
209+
210+
class AspectJLanguage(JvmLanguage):
211+
name = "aspectj"
212+
source_extensions = (".aj",)
213+
binary_extensions = (".class",)
214+
source_package_attribute_name = "aspectj_package"
215+
package_regex = re.compile(r"^\s*package\s+([\w\.]+)\s*;?")
216+
binary_map_type = "aspectj_to_class"
217+
218+
219+
class ClojureLanguage(JvmLanguage):
220+
name = "clojure"
221+
source_extensions = (".clj",)
222+
binary_extensions = (".class",)
223+
source_package_attribute_name = "clojure_package"
224+
package_regex = re.compile(r"^\s*package\s+([\w\.]+)\s*;?")
225+
binary_map_type = "clojure_to_class"
226+
227+
201228
class KotlinLanguage(JvmLanguage):
202229
name = "kotlin"
203230
source_extensions = (".kt", ".kts")

scanpipe/tests/pipes/test_d2d.py

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ def test_scanpipe_pipes_d2d_map_java_to_class(self):
372372
self.project1, logger=buffer.write, jvm_lang=jvm.JavaLanguage
373373
)
374374

375-
expected = "Mapping 3 .class resources to 2 ('.java',)"
375+
expected = "Mapping 3 .class (or other deployed file) resources to 2 ('.java',)"
376376
self.assertIn(expected, buffer.getvalue())
377377

378378
self.assertEqual(2, self.project1.codebaserelations.count())
@@ -432,7 +432,7 @@ def test_scanpipe_pipes_d2d_map_java_to_class_with_java_in_deploy(self):
432432
d2d.map_jvm_to_class(
433433
self.project1, logger=buffer.write, jvm_lang=jvm.JavaLanguage
434434
)
435-
expected = "Mapping 1 .class resources to 1 ('.java',)"
435+
expected = "Mapping 1 .class (or other deployed file) resources to 1 ('.java',)"
436436
self.assertIn(expected, buffer.getvalue())
437437

438438
def test_scanpipe_pipes_d2d_map_grammar_to_class(self):
@@ -452,7 +452,9 @@ def test_scanpipe_pipes_d2d_map_grammar_to_class(self):
452452
self.project1, logger=buffer.write, jvm_lang=jvm.GrammarLanguage
453453
)
454454

455-
expected = "Mapping 1 .class resources to 1 ('.g', '.g4')"
455+
expected = (
456+
"Mapping 1 .class (or other deployed file) resources to 1 ('.g', '.g4')"
457+
)
456458
self.assertIn(expected, buffer.getvalue())
457459
self.assertEqual(1, self.project1.codebaserelations.count())
458460

@@ -480,7 +482,9 @@ def test_scanpipe_pipes_d2d_map_xtend_to_class(self):
480482
self.project1, logger=buffer.write, jvm_lang=jvm.XtendLanguage
481483
)
482484

483-
expected = "Mapping 1 .class resources to 1 ('.xtend',)"
485+
expected = (
486+
"Mapping 1 .class (or other deployed file) resources to 1 ('.xtend',)"
487+
)
484488
self.assertIn(expected, buffer.getvalue())
485489
self.assertEqual(1, self.project1.codebaserelations.count())
486490

@@ -569,6 +573,124 @@ def test_scanpipe_pipes_d2d_map_jar_to_java_source(self):
569573
self.assertEqual(from2, relation.from_resource)
570574
self.assertEqual(to_jar, relation.to_resource)
571575

576+
def test_scanpipe_pipes_d2d_map_groovy_to_class(self):
577+
from1 = make_resource_file(
578+
self.project1,
579+
path="from/project/test.groovy",
580+
extra_data={"groovy_package": "project"},
581+
)
582+
583+
to1 = make_resource_file(
584+
self.project1,
585+
path="to/project/test.class",
586+
)
587+
588+
buffer = io.StringIO()
589+
d2d.map_jvm_to_class(
590+
self.project1, logger=buffer.write, jvm_lang=jvm.GroovyLanguage
591+
)
592+
593+
expected = (
594+
"Mapping 1 .class (or other deployed file) resources to 1 ('.groovy',)"
595+
)
596+
self.assertIn(expected, buffer.getvalue())
597+
self.assertEqual(1, self.project1.codebaserelations.count())
598+
599+
r1 = self.project1.codebaserelations.get(to_resource=to1, from_resource=from1)
600+
self.assertEqual("groovy_to_class", r1.map_type)
601+
expected = {"from_source_root": "from/"}
602+
self.assertEqual(expected, r1.extra_data)
603+
604+
def test_scanpipe_pipes_d2d_map_aspectj_to_class(self):
605+
from1 = make_resource_file(
606+
self.project1,
607+
path="from/project/test.aj",
608+
extra_data={"aspectj_package": "project"},
609+
)
610+
611+
to1 = make_resource_file(
612+
self.project1,
613+
path="to/project/test.class",
614+
)
615+
616+
buffer = io.StringIO()
617+
d2d.map_jvm_to_class(
618+
self.project1, logger=buffer.write, jvm_lang=jvm.AspectJLanguage
619+
)
620+
621+
expected = "Mapping 1 .class (or other deployed file) resources to 1 ('.aj',)"
622+
self.assertIn(expected, buffer.getvalue())
623+
self.assertEqual(1, self.project1.codebaserelations.count())
624+
625+
r1 = self.project1.codebaserelations.get(to_resource=to1, from_resource=from1)
626+
self.assertEqual("aspectj_to_class", r1.map_type)
627+
expected = {"from_source_root": "from/"}
628+
self.assertEqual(expected, r1.extra_data)
629+
630+
def test_scanpipe_pipes_d2d_map_clojure_to_class(self):
631+
from1 = make_resource_file(
632+
self.project1,
633+
path="from/project/test.clj",
634+
extra_data={"clojure_package": "project"},
635+
)
636+
637+
to1 = make_resource_file(
638+
self.project1,
639+
path="to/project/test.class",
640+
)
641+
642+
buffer = io.StringIO()
643+
d2d.map_jvm_to_class(
644+
self.project1, logger=buffer.write, jvm_lang=jvm.ClojureLanguage
645+
)
646+
647+
expected = "Mapping 1 .class (or other deployed file) resources to 1 ('.clj',)"
648+
self.assertIn(expected, buffer.getvalue())
649+
self.assertEqual(1, self.project1.codebaserelations.count())
650+
651+
r1 = self.project1.codebaserelations.get(to_resource=to1, from_resource=from1)
652+
self.assertEqual("clojure_to_class", r1.map_type)
653+
expected = {"from_source_root": "from/"}
654+
self.assertEqual(expected, r1.extra_data)
655+
656+
def test_scanpipe_pipes_d2d_map_scala_to_class(self):
657+
from1 = make_resource_file(
658+
self.project1,
659+
path="from/tastyquery/Annotations.scala",
660+
extra_data={"scala_package": "tastyquery"},
661+
)
662+
663+
to1 = make_resource_file(
664+
self.project1,
665+
path="to/tastyquery/Annotations.tasty",
666+
)
667+
668+
to2 = make_resource_file(
669+
self.project1,
670+
path="to/tastyquery/Annotations.class",
671+
)
672+
673+
buffer = io.StringIO()
674+
d2d.map_jvm_to_class(
675+
self.project1, logger=buffer.write, jvm_lang=jvm.ScalaLanguage
676+
)
677+
678+
expected = (
679+
"Mapping 2 .class (or other deployed file) resources to 1 ('.scala',)"
680+
)
681+
self.assertIn(expected, buffer.getvalue())
682+
self.assertEqual(2, self.project1.codebaserelations.count())
683+
684+
r1 = self.project1.codebaserelations.get(to_resource=to1, from_resource=from1)
685+
self.assertEqual("scala_to_class", r1.map_type)
686+
expected = {"from_source_root": "from/"}
687+
self.assertEqual(expected, r1.extra_data)
688+
689+
r2 = self.project1.codebaserelations.get(to_resource=to2, from_resource=from1)
690+
self.assertEqual("scala_to_class", r2.map_type)
691+
expected = {"from_source_root": "from/"}
692+
self.assertEqual(expected, r2.extra_data)
693+
572694
def test_scanpipe_pipes_d2d_map_jar_to_scala_source(self):
573695
from1 = make_resource_file(
574696
self.project1,

0 commit comments

Comments
 (0)