@@ -102,147 +102,141 @@ pub fn check_repo_state(
102
102
} ;
103
103
104
104
return Ok ( Some ( VcsInfo { git, path_in_vcs } ) ) ;
105
+ }
105
106
106
- fn git (
107
- pkg : & Package ,
108
- gctx : & GlobalContext ,
109
- src_files : & [ PathBuf ] ,
110
- repo : & git2:: Repository ,
111
- opts : & PackageOpts < ' _ > ,
112
- ) -> CargoResult < Option < GitVcsInfo > > {
113
- // This is a collection of any dirty or untracked files. This covers:
114
- // - new/modified/deleted/renamed/type change (index or worktree)
115
- // - untracked files (which are "new" worktree files)
116
- // - ignored (in case the user has an `include` directive that
117
- // conflicts with .gitignore).
118
- let mut dirty_files = Vec :: new ( ) ;
119
- collect_statuses ( repo, & mut dirty_files) ?;
120
- // Include each submodule so that the error message can provide
121
- // specifically *which* files in a submodule are modified.
122
- status_submodules ( repo, & mut dirty_files) ?;
123
-
124
- // Find the intersection of dirty in git, and the src_files that would
125
- // be packaged. This is a lazy n^2 check, but seems fine with
126
- // thousands of files.
127
- let cwd = gctx. cwd ( ) ;
128
- let mut dirty_src_files: Vec < _ > = src_files
129
- . iter ( )
130
- . filter ( |src_file| dirty_files. iter ( ) . any ( |path| src_file. starts_with ( path) ) )
131
- . chain ( dirty_metadata_paths ( pkg, repo) ?. iter ( ) )
132
- . map ( |path| {
133
- pathdiff:: diff_paths ( path, cwd)
134
- . as_ref ( )
135
- . unwrap_or ( path)
136
- . display ( )
137
- . to_string ( )
138
- } )
139
- . collect ( ) ;
140
- let dirty = !dirty_src_files. is_empty ( ) ;
141
- if !dirty || opts. allow_dirty {
142
- // Must check whetherthe repo has no commit firstly, otherwise `revparse_single` would fail on bare commit repo.
143
- // Due to lacking the `sha1` field, it's better not record the `GitVcsInfo` for consistency.
144
- if repo. is_empty ( ) ? {
145
- return Ok ( None ) ;
146
- }
147
- let rev_obj = repo. revparse_single ( "HEAD" ) ?;
148
- Ok ( Some ( GitVcsInfo {
149
- sha1 : rev_obj. id ( ) . to_string ( ) ,
150
- dirty,
151
- } ) )
152
- } else {
153
- dirty_src_files. sort_unstable ( ) ;
154
- anyhow:: bail!(
155
- "{} files in the working directory contain changes that were \
156
- not yet committed into git:\n \n {}\n \n \
157
- to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag",
158
- dirty_src_files. len( ) ,
159
- dirty_src_files. join( "\n " )
160
- )
107
+ fn git (
108
+ pkg : & Package ,
109
+ gctx : & GlobalContext ,
110
+ src_files : & [ PathBuf ] ,
111
+ repo : & git2:: Repository ,
112
+ opts : & PackageOpts < ' _ > ,
113
+ ) -> CargoResult < Option < GitVcsInfo > > {
114
+ // This is a collection of any dirty or untracked files. This covers:
115
+ // - new/modified/deleted/renamed/type change (index or worktree)
116
+ // - untracked files (which are "new" worktree files)
117
+ // - ignored (in case the user has an `include` directive that
118
+ // conflicts with .gitignore).
119
+ let mut dirty_files = Vec :: new ( ) ;
120
+ collect_statuses ( repo, & mut dirty_files) ?;
121
+ // Include each submodule so that the error message can provide
122
+ // specifically *which* files in a submodule are modified.
123
+ status_submodules ( repo, & mut dirty_files) ?;
124
+
125
+ // Find the intersection of dirty in git, and the src_files that would
126
+ // be packaged. This is a lazy n^2 check, but seems fine with
127
+ // thousands of files.
128
+ let cwd = gctx. cwd ( ) ;
129
+ let mut dirty_src_files: Vec < _ > = src_files
130
+ . iter ( )
131
+ . filter ( |src_file| dirty_files. iter ( ) . any ( |path| src_file. starts_with ( path) ) )
132
+ . chain ( dirty_metadata_paths ( pkg, repo) ?. iter ( ) )
133
+ . map ( |path| {
134
+ pathdiff:: diff_paths ( path, cwd)
135
+ . as_ref ( )
136
+ . unwrap_or ( path)
137
+ . display ( )
138
+ . to_string ( )
139
+ } )
140
+ . collect ( ) ;
141
+ let dirty = !dirty_src_files. is_empty ( ) ;
142
+ if !dirty || opts. allow_dirty {
143
+ // Must check whetherthe repo has no commit firstly, otherwise `revparse_single` would fail on bare commit repo.
144
+ // Due to lacking the `sha1` field, it's better not record the `GitVcsInfo` for consistency.
145
+ if repo. is_empty ( ) ? {
146
+ return Ok ( None ) ;
161
147
}
148
+ let rev_obj = repo. revparse_single ( "HEAD" ) ?;
149
+ Ok ( Some ( GitVcsInfo {
150
+ sha1 : rev_obj. id ( ) . to_string ( ) ,
151
+ dirty,
152
+ } ) )
153
+ } else {
154
+ dirty_src_files. sort_unstable ( ) ;
155
+ anyhow:: bail!(
156
+ "{} files in the working directory contain changes that were \
157
+ not yet committed into git:\n \n {}\n \n \
158
+ to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag",
159
+ dirty_src_files. len( ) ,
160
+ dirty_src_files. join( "\n " )
161
+ )
162
162
}
163
+ }
163
164
164
- /// Checks whether files at paths specified in `package.readme` and
165
- /// `package.license-file` have been modified.
166
- ///
167
- /// This is required because those paths may link to a file outside the
168
- /// current package root, but still under the git workdir, affecting the
169
- /// final packaged `.crate` file.
170
- fn dirty_metadata_paths ( pkg : & Package , repo : & git2:: Repository ) -> CargoResult < Vec < PathBuf > > {
171
- let mut dirty_files = Vec :: new ( ) ;
172
- let workdir = repo. workdir ( ) . unwrap ( ) ;
173
- let root = pkg. root ( ) ;
174
- let meta = pkg. manifest ( ) . metadata ( ) ;
175
- for path in [ & meta. license_file , & meta. readme ] {
176
- let Some ( path) = path. as_deref ( ) . map ( Path :: new) else {
177
- continue ;
178
- } ;
179
- let abs_path = paths:: normalize_path ( & root. join ( path) ) ;
180
- if paths:: strip_prefix_canonical ( abs_path. as_path ( ) , root) . is_ok ( ) {
181
- // Inside package root. Don't bother checking git status.
182
- continue ;
183
- }
184
- if let Ok ( rel_path) = paths:: strip_prefix_canonical ( abs_path. as_path ( ) , workdir) {
185
- // Outside package root but under git workdir,
186
- if repo. status_file ( & rel_path) ? != git2:: Status :: CURRENT {
187
- dirty_files. push ( if abs_path. is_symlink ( ) {
188
- // For symlinks, shows paths to symlink sources
189
- workdir. join ( rel_path)
190
- } else {
191
- abs_path
192
- } ) ;
193
- }
165
+ /// Checks whether files at paths specified in `package.readme` and
166
+ /// `package.license-file` have been modified.
167
+ ///
168
+ /// This is required because those paths may link to a file outside the
169
+ /// current package root, but still under the git workdir, affecting the
170
+ /// final packaged `.crate` file.
171
+ fn dirty_metadata_paths ( pkg : & Package , repo : & git2:: Repository ) -> CargoResult < Vec < PathBuf > > {
172
+ let mut dirty_files = Vec :: new ( ) ;
173
+ let workdir = repo. workdir ( ) . unwrap ( ) ;
174
+ let root = pkg. root ( ) ;
175
+ let meta = pkg. manifest ( ) . metadata ( ) ;
176
+ for path in [ & meta. license_file , & meta. readme ] {
177
+ let Some ( path) = path. as_deref ( ) . map ( Path :: new) else {
178
+ continue ;
179
+ } ;
180
+ let abs_path = paths:: normalize_path ( & root. join ( path) ) ;
181
+ if paths:: strip_prefix_canonical ( abs_path. as_path ( ) , root) . is_ok ( ) {
182
+ // Inside package root. Don't bother checking git status.
183
+ continue ;
184
+ }
185
+ if let Ok ( rel_path) = paths:: strip_prefix_canonical ( abs_path. as_path ( ) , workdir) {
186
+ // Outside package root but under git workdir,
187
+ if repo. status_file ( & rel_path) ? != git2:: Status :: CURRENT {
188
+ dirty_files. push ( if abs_path. is_symlink ( ) {
189
+ // For symlinks, shows paths to symlink sources
190
+ workdir. join ( rel_path)
191
+ } else {
192
+ abs_path
193
+ } ) ;
194
194
}
195
195
}
196
- Ok ( dirty_files)
197
196
}
197
+ Ok ( dirty_files)
198
+ }
198
199
199
- // Helper to collect dirty statuses for a single repo.
200
- fn collect_statuses (
201
- repo : & git2:: Repository ,
202
- dirty_files : & mut Vec < PathBuf > ,
203
- ) -> CargoResult < ( ) > {
204
- let mut status_opts = git2:: StatusOptions :: new ( ) ;
205
- // Exclude submodules, as they are being handled manually by recursing
206
- // into each one so that details about specific files can be
207
- // retrieved.
208
- status_opts
209
- . exclude_submodules ( true )
210
- . include_ignored ( true )
211
- . include_untracked ( true ) ;
212
- let repo_statuses = repo. statuses ( Some ( & mut status_opts) ) . with_context ( || {
213
- format ! (
214
- "failed to retrieve git status from repo {}" ,
215
- repo. path( ) . display( )
216
- )
217
- } ) ?;
218
- let workdir = repo. workdir ( ) . unwrap ( ) ;
219
- let this_dirty = repo_statuses. iter ( ) . filter_map ( |entry| {
220
- let path = entry. path ( ) . expect ( "valid utf-8 path" ) ;
221
- if path. ends_with ( "Cargo.lock" ) && entry. status ( ) == git2:: Status :: IGNORED {
222
- // It is OK to include Cargo.lock even if it is ignored.
223
- return None ;
224
- }
225
- // Use an absolute path, so that comparing paths is easier
226
- // (particularly with submodules).
227
- Some ( workdir. join ( path) )
228
- } ) ;
229
- dirty_files. extend ( this_dirty) ;
230
- Ok ( ( ) )
231
- }
200
+ /// Helper to collect dirty statuses for a single repo.
201
+ fn collect_statuses ( repo : & git2:: Repository , dirty_files : & mut Vec < PathBuf > ) -> CargoResult < ( ) > {
202
+ let mut status_opts = git2:: StatusOptions :: new ( ) ;
203
+ // Exclude submodules, as they are being handled manually by recursing
204
+ // into each one so that details about specific files can be
205
+ // retrieved.
206
+ status_opts
207
+ . exclude_submodules ( true )
208
+ . include_ignored ( true )
209
+ . include_untracked ( true ) ;
210
+ let repo_statuses = repo. statuses ( Some ( & mut status_opts) ) . with_context ( || {
211
+ format ! (
212
+ "failed to retrieve git status from repo {}" ,
213
+ repo. path( ) . display( )
214
+ )
215
+ } ) ?;
216
+ let workdir = repo. workdir ( ) . unwrap ( ) ;
217
+ let this_dirty = repo_statuses. iter ( ) . filter_map ( |entry| {
218
+ let path = entry. path ( ) . expect ( "valid utf-8 path" ) ;
219
+ if path. ends_with ( "Cargo.lock" ) && entry. status ( ) == git2:: Status :: IGNORED {
220
+ // It is OK to include Cargo.lock even if it is ignored.
221
+ return None ;
222
+ }
223
+ // Use an absolute path, so that comparing paths is easier
224
+ // (particularly with submodules).
225
+ Some ( workdir. join ( path) )
226
+ } ) ;
227
+ dirty_files. extend ( this_dirty) ;
228
+ Ok ( ( ) )
229
+ }
232
230
233
- // Helper to collect dirty statuses while recursing into submodules.
234
- fn status_submodules (
235
- repo : & git2:: Repository ,
236
- dirty_files : & mut Vec < PathBuf > ,
237
- ) -> CargoResult < ( ) > {
238
- for submodule in repo. submodules ( ) ? {
239
- // Ignore submodules that don't open, they are probably not initialized.
240
- // If its files are required, then the verification step should fail.
241
- if let Ok ( sub_repo) = submodule. open ( ) {
242
- status_submodules ( & sub_repo, dirty_files) ?;
243
- collect_statuses ( & sub_repo, dirty_files) ?;
244
- }
231
+ /// Helper to collect dirty statuses while recursing into submodules.
232
+ fn status_submodules ( repo : & git2:: Repository , dirty_files : & mut Vec < PathBuf > ) -> CargoResult < ( ) > {
233
+ for submodule in repo. submodules ( ) ? {
234
+ // Ignore submodules that don't open, they are probably not initialized.
235
+ // If its files are required, then the verification step should fail.
236
+ if let Ok ( sub_repo) = submodule. open ( ) {
237
+ status_submodules ( & sub_repo, dirty_files) ?;
238
+ collect_statuses ( & sub_repo, dirty_files) ?;
245
239
}
246
- Ok ( ( ) )
247
240
}
241
+ Ok ( ( ) )
248
242
}
0 commit comments