2020# ScanCode.io is a free software code scanning tool from nexB Inc. and others.
2121# Visit https://github.com/aboutcode-org/scancode.io for support and download.
2222
23+ import shutil
24+ import tempfile
2325from pathlib import Path
2426
2527from scanpipe .pipelines .deploy_to_develop import DeployToDevelop
2628from scanpipe .pipelines .scan_codebase import ScanCodebase
2729from scanpipe .pipelines .scan_single_package import ScanSinglePackage
2830from scanpipe .pipes import d2d
2931from scanpipe .pipes import flag
30- from scanpipe .pipes import rust
3132from scanpipe .pipes import utils
32-
33- from scanpipe .pipes .rust import check_input_and_return_purl , fetch_inputs
34-
35- import shutil
33+ from scanpipe . pipes . rust import build_crates
34+ from scanpipe .pipes .rust import check_input_and_return_purl
35+ from scanpipe . pipes . rust import get_cargo_toml_path
36+ from scanpipe . pipes . rust import get_repository_value_from_cargo_toml
3637
3738
3839class ScanRustPackage (ScanSinglePackage , DeployToDevelop , ScanCodebase ):
@@ -60,13 +61,18 @@ def steps(cls):
6061 cls .collect_input_info ,
6162 cls .extract_input_to_codebase_directory ,
6263 cls .check_docker_command ,
64+ cls .get_cargo_toml ,
6365 cls .build_crates ,
6466 cls .run_scan ,
6567 cls .load_inventory_from_toolkit_scan ,
6668 cls .add_from_to_tag ,
6769 cls .validate_package_license_integrity ,
6870 cls .identify_built_sources ,
6971 cls .flag_mapped_status ,
72+ cls .get_src_repo_download_url ,
73+ cls .download_src_repo ,
74+ cls .compare_src_repo_with_from_codebase ,
75+ cls .update_comparison_summary ,
7076 cls .make_summary_from_scan_results ,
7177 )
7278
@@ -76,32 +82,49 @@ def check_input_and_return_purl(self):
7682
7783 def fetch_inputs (self ):
7884 """Fetch the source of the given PURL."""
79- self .from_files = fetch_inputs (self .purl )
85+ self .from_files = utils . fetch_inputs (self .purl )
8086
8187 def collect_input_info (self ):
8288 """Collect information about the input."""
8389 self .input_path = self .from_files
8490 self .collect_input_information ()
8591
8692 def check_docker_command (self ):
93+ """Check if the Docker command is available."""
8794 self .have_docker = False
8895 if shutil .which ("docker" ):
8996 self .have_docker = True
9097
98+ def get_cargo_toml (self ):
99+ """Get the Cargo.toml path from the codebase directory."""
100+ self .cargo_toml_path = None
101+ self .devel_codebase_dir = None
102+ if self .have_docker :
103+ codebase_dir = Path (self .project .codebase_path )
104+ self .devel_codebase_dir = codebase_dir
105+ self .cargo_toml_path = get_cargo_toml_path (codebase_dir )
106+
91107 def build_crates (self ):
92108 """
93109 Build the Rust crate using Docker and put the built files under the
94110 "to" directory.
95111 """
96112 self .d2d_enable = False
97- if self .have_docker :
98- if rust .build_crates (self .project .codebase_path ):
113+ if self .cargo_toml_path :
114+ codebase_dir = self .devel_codebase_dir
115+ cargo_toml_path = self .cargo_toml_path
116+ if build_crates (codebase_dir , cargo_toml_path ):
99117 self .d2d_enable = True
118+ updated_path = cargo_toml_path .relative_to (codebase_dir )
119+ self .cargo_toml_path = codebase_dir / "from" / updated_path
120+ self .devel_codebase_dir = codebase_dir / "from"
100121 else :
101122 print ("Docker command not found. Skipping crate build." )
123+ else :
124+ print ("Cargo.toml is not found." )
102125
103126 def add_from_to_tag (self ):
104- """Update 'from' or 'to' tag to resources based on their path."""
127+ """Update 'from' and 'to' tag to resources based on their path."""
105128 if self .d2d_enable :
106129 d2d .update_from_to_tag (self .project )
107130
@@ -121,3 +144,67 @@ def flag_mapped_status(self):
121144 """Flag the from codebase resources that were mapped."""
122145 if self .d2d_enable :
123146 flag .flag_mapped_resources (self .project )
147+
148+ def get_src_repo_download_url (self ):
149+ """
150+ Get the source repository url from Cargo.toml and determine its
151+ download url.
152+ """
153+ self .src_download_url = None
154+ repository_url = get_repository_value_from_cargo_toml (self .cargo_toml_path )
155+ if not repository_url :
156+ self .project .add_warning (
157+ description = "No source repository URL found in Cargo.toml."
158+ )
159+ else :
160+ self .src_download_url = utils .get_download_url (
161+ repository_url , self .purl .version
162+ )
163+ if not self .src_download_url :
164+ self .project .add_warning (
165+ description = (
166+ "Not able to determine the source repository download URL from "
167+ "Cargo.toml."
168+ )
169+ )
170+
171+ def download_src_repo (self ):
172+ """Download the source from the source repo."""
173+ self .src_repo_path = None
174+ if self .src_download_url :
175+ self .src_repo_path = utils .download_src_repo (self .src_download_url )
176+ if not self .src_repo_path :
177+ self .project .add_warning (
178+ description = (
179+ f"The source repository URL "
180+ f"{ self .src_download_url } "
181+ f"could not be downloaded. Skipping the source "
182+ f"crate and source repository comparison."
183+ )
184+ )
185+
186+ def compare_src_repo_with_from_codebase (self ):
187+ """Compare the downloaded source repo with the from codebase."""
188+ self .matched_count = 0
189+ self .mismatches = []
190+ if self .src_repo_path :
191+ with tempfile .TemporaryDirectory () as source_repo_path :
192+ self .extract_archive (self .src_repo_path , source_repo_path )
193+
194+ self .matched_count , self .mismatches = utils .compare_directories (
195+ self .devel_codebase_dir , source_repo_path
196+ )
197+
198+ def update_comparison_summary (self ):
199+ """Update the comparison summary in the discovered package."""
200+ if self .src_repo_path :
201+ utils .update_comparison_summary (
202+ self .project ,
203+ self .purl ,
204+ self .devel_codebase_dir ,
205+ self .src_download_url ,
206+ self .purl .name ,
207+ self .purl .version ,
208+ self .matched_count ,
209+ self .mismatches ,
210+ )
0 commit comments