@@ -3,12 +3,14 @@ use std::fs::{self, File};
3
3
use std:: io:: prelude:: * ;
4
4
use std:: io:: SeekFrom ;
5
5
use std:: path:: { self , Path , PathBuf } ;
6
+ use std:: rc:: Rc ;
6
7
use std:: sync:: Arc ;
7
8
9
+ use flate2:: read:: GzDecoder ;
8
10
use flate2:: { Compression , GzBuilder } ;
9
11
use log:: debug;
10
12
use serde_json:: { self , json} ;
11
- use tar:: { Builder , EntryType , Header } ;
13
+ use tar:: { Archive , Builder , EntryType , Header } ;
12
14
use termcolor:: Color ;
13
15
14
16
use crate :: core:: compiler:: { BuildConfig , CompileMode , DefaultExecutor , Executor } ;
@@ -20,6 +22,7 @@ use crate::ops;
20
22
use crate :: sources:: PathSource ;
21
23
use crate :: util:: errors:: { CargoResult , CargoResultExt } ;
22
24
use crate :: util:: paths;
25
+ use crate :: util:: toml:: TomlManifest ;
23
26
use crate :: util:: { self , internal, Config , FileLock } ;
24
27
25
28
pub struct PackageOpts < ' cfg > {
@@ -102,7 +105,7 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
102
105
. shell ( )
103
106
. status ( "Packaging" , pkg. package_id ( ) . to_string ( ) ) ?;
104
107
dst. file ( ) . set_len ( 0 ) ?;
105
- tar ( ws, & src_files, vcs_info. as_ref ( ) , & dst, & filename)
108
+ tar ( ws, & src_files, vcs_info. as_ref ( ) , dst. file ( ) , & filename)
106
109
. chain_err ( || failure:: format_err!( "failed to prepare local package for uploading" ) ) ?;
107
110
if opts. verify {
108
111
dst. seek ( SeekFrom :: Start ( 0 ) ) ?;
@@ -118,6 +121,34 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
118
121
Ok ( Some ( dst) )
119
122
}
120
123
124
+ /// Construct `Cargo.lock` for the package to be published.
125
+ fn build_lock ( ws : & Workspace < ' _ > ) -> CargoResult < String > {
126
+ let config = ws. config ( ) ;
127
+ let orig_resolve = ops:: load_pkg_lockfile ( ws) ?;
128
+
129
+ // Convert Package -> TomlManifest -> Manifest -> Package
130
+ let orig_pkg = ws. current ( ) ?;
131
+ let toml_manifest = Rc :: new ( orig_pkg. manifest ( ) . original ( ) . prepare_for_publish ( config) ?) ;
132
+ let package_root = orig_pkg. root ( ) ;
133
+ let source_id = orig_pkg. package_id ( ) . source_id ( ) ;
134
+ let ( manifest, _nested_paths) =
135
+ TomlManifest :: to_real_manifest ( & toml_manifest, source_id, package_root, config) ?;
136
+ let new_pkg = Package :: new ( manifest, orig_pkg. manifest_path ( ) ) ;
137
+
138
+ // Regenerate Cargo.lock using the old one as a guide.
139
+ let specs = vec ! [ PackageIdSpec :: from_package_id( new_pkg. package_id( ) ) ] ;
140
+ let tmp_ws = Workspace :: ephemeral ( new_pkg, ws. config ( ) , None , true ) ?;
141
+ let ( pkg_set, new_resolve) =
142
+ ops:: resolve_ws_with_method ( & tmp_ws, None , Method :: Everything , & specs) ?;
143
+
144
+ if let Some ( orig_resolve) = orig_resolve {
145
+ compare_resolve ( config, tmp_ws. current ( ) ?, & orig_resolve, & new_resolve) ?;
146
+ }
147
+ check_yanked ( config, & pkg_set, & new_resolve) ?;
148
+
149
+ ops:: resolve_to_string ( & tmp_ws, & new_resolve)
150
+ }
151
+
121
152
fn include_lockfile ( pkg : & Package ) -> bool {
122
153
pkg. manifest ( ) . publish_lockfile ( ) && pkg. targets ( ) . iter ( ) . any ( |t| t. is_example ( ) || t. is_bin ( ) )
123
154
}
@@ -283,28 +314,21 @@ fn tar(
283
314
ws : & Workspace < ' _ > ,
284
315
src_files : & [ PathBuf ] ,
285
316
vcs_info : Option < & serde_json:: Value > ,
286
- dst : & FileLock ,
317
+ dst : & File ,
287
318
filename : & str ,
288
319
) -> CargoResult < ( ) > {
289
320
// Prepare the encoder and its header.
290
321
let filename = Path :: new ( filename) ;
291
322
let encoder = GzBuilder :: new ( )
292
323
. filename ( util:: path2bytes ( filename) ?)
293
- . write ( dst. file ( ) , Compression :: best ( ) ) ;
324
+ . write ( dst, Compression :: best ( ) ) ;
294
325
295
326
// Put all package files into a compressed archive.
296
327
let mut ar = Builder :: new ( encoder) ;
297
328
let pkg = ws. current ( ) ?;
298
329
let config = ws. config ( ) ;
299
330
let root = pkg. root ( ) ;
300
- // While creating the tar file, also copy to the output directory.
301
- let dest_copy_root = dst
302
- . parent ( )
303
- . join ( format ! ( "{}-{}" , pkg. name( ) , pkg. version( ) ) ) ;
304
- if dest_copy_root. exists ( ) {
305
- paths:: remove_dir_all ( & dest_copy_root) ?;
306
- }
307
- fs:: create_dir_all ( & dest_copy_root) ?;
331
+
308
332
for src_file in src_files {
309
333
let relative = src_file. strip_prefix ( root) ?;
310
334
check_filename ( relative) ?;
@@ -369,19 +393,11 @@ fn tar(
369
393
ar. append ( & header, toml. as_bytes ( ) ) . chain_err ( || {
370
394
internal ( format ! ( "could not archive source file `{}`" , relative_str) )
371
395
} ) ?;
372
- fs:: write ( dest_copy_root. join ( relative) , toml) ?;
373
- fs:: copy ( src_file, dest_copy_root. join ( "Cargo.toml.orig" ) ) ?;
374
396
} else {
375
397
header. set_cksum ( ) ;
376
398
ar. append ( & header, & mut file) . chain_err ( || {
377
399
internal ( format ! ( "could not archive source file `{}`" , relative_str) )
378
400
} ) ?;
379
- let dest = dest_copy_root. join ( relative) ;
380
- let parent = dest. parent ( ) . unwrap ( ) ;
381
- if !parent. exists ( ) {
382
- fs:: create_dir_all ( parent) ?;
383
- }
384
- fs:: copy ( src_file, dest) ?;
385
401
}
386
402
}
387
403
@@ -415,29 +431,8 @@ fn tar(
415
431
}
416
432
417
433
if include_lockfile ( pkg) {
418
- let orig_lock_path = ws. root ( ) . join ( "Cargo.lock" ) ;
419
- let new_lock_path = dest_copy_root. join ( "Cargo.lock" ) ;
420
- if orig_lock_path. exists ( ) {
421
- fs:: copy ( & orig_lock_path, & new_lock_path) ?;
422
- }
434
+ let new_lock = build_lock ( & ws) ?;
423
435
424
- // Regenerate Cargo.lock using the old one as a guide.
425
- let orig_resolve = ops:: load_pkg_lockfile ( ws) ?;
426
- let id = SourceId :: for_path ( & dest_copy_root) ?;
427
- let mut src = PathSource :: new ( & dest_copy_root, id, ws. config ( ) ) ;
428
- let new_pkg = src. root_package ( ) ?;
429
- let specs = vec ! [ PackageIdSpec :: from_package_id( new_pkg. package_id( ) ) ] ;
430
- let tmp_ws = Workspace :: ephemeral ( new_pkg, config, None , true ) ?;
431
- let ( pkg_set, new_resolve) =
432
- ops:: resolve_ws_with_method ( & tmp_ws, None , Method :: Everything , & specs) ?;
433
- // resolve_ws_with_method won't save for ephemeral, do it manually.
434
- ops:: write_pkg_lockfile ( & tmp_ws, & new_resolve) ?;
435
- if let Some ( orig_resolve) = orig_resolve {
436
- compare_resolve ( config, tmp_ws. current ( ) ?, & orig_resolve, & new_resolve) ?;
437
- }
438
- check_yanked ( config, & pkg_set, & new_resolve) ?;
439
-
440
- let toml = paths:: read ( & new_lock_path) ?;
441
436
let path = format ! (
442
437
"{}-{}{}Cargo.lock" ,
443
438
pkg. name( ) ,
@@ -448,9 +443,9 @@ fn tar(
448
443
header. set_path ( & path) ?;
449
444
header. set_entry_type ( EntryType :: file ( ) ) ;
450
445
header. set_mode ( 0o644 ) ;
451
- header. set_size ( toml . len ( ) as u64 ) ;
446
+ header. set_size ( new_lock . len ( ) as u64 ) ;
452
447
header. set_cksum ( ) ;
453
- ar. append ( & header, toml . as_bytes ( ) )
448
+ ar. append ( & header, new_lock . as_bytes ( ) )
454
449
. chain_err ( || internal ( "could not archive source file `Cargo.lock`" ) ) ?;
455
450
}
456
451
@@ -566,9 +561,18 @@ fn run_verify(ws: &Workspace<'_>, tar: &FileLock, opts: &PackageOpts<'_>) -> Car
566
561
567
562
config. shell ( ) . status ( "Verifying" , pkg) ?;
568
563
564
+ let f = GzDecoder :: new ( tar. file ( ) ) ;
569
565
let dst = tar
570
566
. parent ( )
571
567
. join ( & format ! ( "{}-{}" , pkg. name( ) , pkg. version( ) ) ) ;
568
+ if dst. exists ( ) {
569
+ paths:: remove_dir_all ( & dst) ?;
570
+ }
571
+ let mut archive = Archive :: new ( f) ;
572
+ // We don't need to set the Modified Time, as it's not relevant to verification
573
+ // and it errors on filesystems that don't support setting a modified timestamp
574
+ archive. set_preserve_mtime ( false ) ;
575
+ archive. unpack ( dst. parent ( ) . unwrap ( ) ) ?;
572
576
573
577
// Manufacture an ephemeral workspace to ensure that even if the top-level
574
578
// package has a workspace we can still build our new crate.
0 commit comments