@@ -3,30 +3,37 @@ use std::io::SeekFrom;
3
3
use std:: io:: prelude:: * ;
4
4
use std:: path:: { self , Path } ;
5
5
6
- use tar:: { Archive , Builder , Header } ;
7
- use flate2:: { GzBuilder , Compression } ;
8
6
use flate2:: read:: GzDecoder ;
7
+ use flate2:: { GzBuilder , Compression } ;
8
+ use git2;
9
+ use tar:: { Archive , Builder , Header } ;
9
10
10
11
use core:: { SourceId , Package , PackageId } ;
11
12
use sources:: PathSource ;
12
13
use util:: { self , CargoResult , human, internal, ChainError , Config , FileLock } ;
13
14
use ops;
14
15
16
+ pub struct PackageOpts < ' cfg > {
17
+ pub config : & ' cfg Config ,
18
+ pub list : bool ,
19
+ pub check_metadata : bool ,
20
+ pub allow_dirty : bool ,
21
+ pub verify : bool ,
22
+ }
23
+
15
24
pub fn package ( manifest_path : & Path ,
16
- config : & Config ,
17
- verify : bool ,
18
- list : bool ,
19
- metadata : bool ) -> CargoResult < Option < FileLock > > {
25
+ opts : & PackageOpts ) -> CargoResult < Option < FileLock > > {
26
+ let config = opts. config ;
20
27
let path = manifest_path. parent ( ) . unwrap ( ) ;
21
28
let id = try!( SourceId :: for_path ( path) ) ;
22
29
let mut src = PathSource :: new ( path, & id, config) ;
23
30
let pkg = try!( src. root_package ( ) ) ;
24
31
25
- if metadata {
32
+ if opts . check_metadata {
26
33
try!( check_metadata ( & pkg, config) ) ;
27
34
}
28
35
29
- if list {
36
+ if opts . list {
30
37
let root = pkg. root ( ) ;
31
38
let mut list: Vec < _ > = try!( src. list_files ( & pkg) ) . iter ( ) . map ( |file| {
32
39
util:: without_prefix ( & file, & root) . unwrap ( ) . to_path_buf ( )
@@ -38,6 +45,10 @@ pub fn package(manifest_path: &Path,
38
45
return Ok ( None )
39
46
}
40
47
48
+ if !opts. allow_dirty {
49
+ try!( check_not_dirty ( & pkg, & src) ) ;
50
+ }
51
+
41
52
let filename = format ! ( "{}-{}.crate" , pkg. name( ) , pkg. version( ) ) ;
42
53
let dir = config. target_dir ( & pkg) . join ( "package" ) ;
43
54
let mut dst = match dir. open_ro ( & filename, config, "packaged crate" ) {
@@ -57,7 +68,7 @@ pub fn package(manifest_path: &Path,
57
68
try!( tar ( & pkg, & src, config, dst. file ( ) , & filename) . chain_error ( || {
58
69
human ( "failed to prepare local package for uploading" )
59
70
} ) ) ;
60
- if verify {
71
+ if opts . verify {
61
72
try!( dst. seek ( SeekFrom :: Start ( 0 ) ) ) ;
62
73
try!( run_verify ( config, & pkg, dst. file ( ) ) . chain_error ( || {
63
74
human ( "failed to verify package tarball" )
@@ -109,6 +120,51 @@ fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
109
120
Ok ( ( ) )
110
121
}
111
122
123
+ fn check_not_dirty ( p : & Package , src : & PathSource ) -> CargoResult < ( ) > {
124
+ if let Ok ( repo) = git2:: Repository :: discover ( p. root ( ) ) {
125
+ if let Some ( workdir) = repo. workdir ( ) {
126
+ debug ! ( "found a git repo at {:?}, checking if index present" ,
127
+ workdir) ;
128
+ let path = p. manifest_path ( ) ;
129
+ let path = path. strip_prefix ( workdir) . unwrap_or ( path) ;
130
+ if let Ok ( status) = repo. status_file ( path) {
131
+ if ( status & git2:: STATUS_IGNORED ) . is_empty ( ) {
132
+ debug ! ( "Cargo.toml found in repo, checking if dirty" ) ;
133
+ return git ( p, src, & repo)
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ // No VCS recognized, we don't know if the directory is dirty or not, so we
140
+ // have to assume that it's clean.
141
+ return Ok ( ( ) ) ;
142
+
143
+ fn git ( p : & Package ,
144
+ src : & PathSource ,
145
+ repo : & git2:: Repository ) -> CargoResult < ( ) > {
146
+ let workdir = repo. workdir ( ) . unwrap ( ) ;
147
+ let dirty = try!( src. list_files ( p) ) . iter ( ) . filter ( |file| {
148
+ let relative = file. strip_prefix ( workdir) . unwrap ( ) ;
149
+ if let Ok ( status) = repo. status_file ( relative) {
150
+ status != git2:: STATUS_CURRENT
151
+ } else {
152
+ false
153
+ }
154
+ } ) . map ( |path| {
155
+ path. strip_prefix ( p. root ( ) ) . unwrap_or ( path) . display ( ) . to_string ( )
156
+ } ) . collect :: < Vec < _ > > ( ) ;
157
+ if dirty. is_empty ( ) {
158
+ Ok ( ( ) )
159
+ } else {
160
+ bail ! ( "{} dirty files found in the working directory:\n \n {}\n \n \
161
+ to publish despite this, pass `--allow-dirty` to \
162
+ `cargo publish`",
163
+ dirty. len( ) , dirty. join( "\n " ) )
164
+ }
165
+ }
166
+ }
167
+
112
168
fn tar ( pkg : & Package ,
113
169
src : & PathSource ,
114
170
config : & Config ,
0 commit comments