@@ -33,7 +33,12 @@ def assemble(cls, package_data, resource, codebase, package_adder):
3333 Always use go.mod first then go.sum
3434 """
3535 yield from cls .assemble_from_many_datafiles (
36- datafile_name_patterns = ('go.mod' , 'go.sum' ,),
36+ datafile_name_patterns = (
37+ 'go.mod' ,
38+ 'go.sum' ,
39+ 'go-mod-graph.deplock' ,
40+ 'go.mod.graph' ,
41+ ),
3742 directory = resource .parent (codebase ),
3843 codebase = codebase ,
3944 package_adder = package_adder ,
@@ -134,3 +139,75 @@ def parse(cls, location, package_only=False):
134139 primary_language = cls .default_primary_language ,
135140 )
136141 yield models .PackageData .from_data (package_data , package_only )
142+
143+
144+ class GoModGraphHandler (BaseGoModuleHandler ):
145+ datasource_id = 'go_mod_graph'
146+ path_patterns = ('*/go-mod-graph.deplock' , '*/go.mod.graph' )
147+ default_package_type = 'golang'
148+ default_primary_language = 'Go'
149+ description = 'Go module requirement graph from go mod graph'
150+ documentation_url = 'https://go.dev/ref/mod#go-mod-graph'
151+
152+ @classmethod
153+ def parse (cls , location , package_only = False ):
154+ """
155+ Parse a ``go mod graph`` dump.
156+
157+ Direct dependencies are modules required by the main module (the first
158+ requiring module in the dump). Other required modules are transitive.
159+ Versions in the graph are exact selected versions.
160+ """
161+ edges = go_mod .parse_gograph (location )
162+ if not edges :
163+ return
164+
165+ main = edges [0 ][0 ]
166+ direct_purls = {
167+ dst .purl (include_version = True )
168+ for src , dst in edges
169+ if src .module == main .module
170+ }
171+
172+ dependencies = []
173+ seen = set ()
174+ for _src , dst in edges :
175+ purl = dst .purl (include_version = True )
176+ if purl in seen :
177+ continue
178+ seen .add (purl )
179+ dependencies .append (
180+ models .DependentPackage (
181+ purl = purl ,
182+ extracted_requirement = dst .version ,
183+ scope = 'require' ,
184+ is_runtime = True ,
185+ is_optional = False ,
186+ is_pinned = True ,
187+ is_direct = purl in direct_purls ,
188+ )
189+ )
190+
191+ namespace = main .namespace
192+ name = main .name
193+ homepage_url = None
194+ vcs_url = None
195+ repository_homepage_url = None
196+ if namespace and name :
197+ homepage_url = f'https://pkg.go.dev/{ namespace } /{ name } '
198+ vcs_url = f'https://{ namespace } /{ name } .git'
199+ repository_homepage_url = homepage_url
200+
201+ package_data = dict (
202+ datasource_id = cls .datasource_id ,
203+ type = cls .default_package_type ,
204+ name = name ,
205+ namespace = namespace ,
206+ version = main .version ,
207+ vcs_url = vcs_url ,
208+ homepage_url = homepage_url ,
209+ repository_homepage_url = repository_homepage_url ,
210+ dependencies = dependencies ,
211+ primary_language = cls .default_primary_language ,
212+ )
213+ yield models .PackageData .from_data (package_data , package_only )
0 commit comments