@@ -6,6 +6,7 @@ use std::io::{Command, BufferedReader, Process, IoResult, File, fs};
6
6
use std:: io;
7
7
use std:: os;
8
8
9
+ use semver;
9
10
use flate2:: reader:: GzDecoder ;
10
11
use git2;
11
12
use serialize:: json;
@@ -15,13 +16,14 @@ use conduit::{Request, Response};
15
16
use app:: { App , RequestApp } ;
16
17
use util:: { CargoResult , internal} ;
17
18
18
- #[ deriving( Encodable ) ]
19
+ #[ deriving( Encodable , Decodable ) ]
19
20
pub struct GitCrate {
20
21
pub name : String ,
21
22
pub vers : String ,
22
23
pub deps : Vec < String > ,
23
24
pub cksum : String ,
24
25
pub features : HashMap < String , Vec < String > > ,
26
+ pub yanked : Option < bool > ,
25
27
}
26
28
27
29
pub fn serve_index ( req : & mut Request ) -> CargoResult < Response > {
@@ -101,25 +103,24 @@ pub fn serve_index(req: &mut Request) -> CargoResult<Response> {
101
103
}
102
104
}
103
105
106
+ fn index_file ( base : & Path , name : & str ) -> Path {
107
+ match name. len ( ) {
108
+ 1 => base. join ( "1" ) . join ( name) ,
109
+ 2 => base. join ( "2" ) . join ( name) ,
110
+ 3 => base. join ( "3" ) . join ( name. slice_to ( 1 ) ) . join ( name) ,
111
+ _ => base. join ( name. slice ( 0 , 2 ) )
112
+ . join ( name. slice ( 2 , 4 ) )
113
+ . join ( name) ,
114
+ }
115
+ }
116
+
104
117
pub fn add_crate ( app : & App , krate : & GitCrate ) -> CargoResult < ( ) > {
105
118
let repo = app. git_repo . lock ( ) ;
106
119
let repo = & * repo;
107
- let name = krate. name . as_slice ( ) ;
108
120
let repo_path = repo. path ( ) . dir_path ( ) ;
109
- let dst = match name. len ( ) {
110
- 1 => repo_path. join ( "1" ) . join ( name) ,
111
- 2 => repo_path. join ( "2" ) . join ( name) ,
112
- 3 => repo_path. join ( "3" ) . join ( name. slice_to ( 1 ) ) . join ( name) ,
113
- _ => repo_path. join ( name. slice ( 0 , 2 ) )
114
- . join ( name. slice ( 2 , 4 ) )
115
- . join ( name) ,
116
- } ;
121
+ let dst = index_file ( & repo_path, krate. name . as_slice ( ) ) ;
117
122
118
- // Attempt to commit the crate in a loop. It's possible that we're going
119
- // to need to rebase our repository, and after that it's possible that we're
120
- // going to race to commit the changes. For now we just cap out the maximum
121
- // number of retries at a fixed number.
122
- for _ in range ( 0 i, 20 ) {
123
+ commit_and_push ( repo, || {
123
124
// Add the crate to its relevant file
124
125
try!( fs:: mkdir_recursive ( & dst. dir_path ( ) , io:: USER_RWX ) ) ;
125
126
let prev = if dst. exists ( ) {
@@ -131,6 +132,53 @@ pub fn add_crate(app: &App, krate: &GitCrate) -> CargoResult<()> {
131
132
let new = if prev. len ( ) == 0 { s} else { prev + "\n " + s} ;
132
133
try!( File :: create ( & dst) . write ( new. as_bytes ( ) ) ) ;
133
134
135
+ Ok ( ( format ! ( "Updating crate `{}#{}`" , krate. name, krate. vers) ,
136
+ dst. clone ( ) ) )
137
+ } )
138
+ }
139
+
140
+ pub fn yank ( app : & App , krate : & str , version : & semver:: Version ,
141
+ yanked : bool ) -> CargoResult < ( ) > {
142
+ let repo = app. git_repo . lock ( ) ;
143
+ let repo = & * repo;
144
+ let repo_path = repo. path ( ) . dir_path ( ) ;
145
+ let dst = index_file ( & repo_path, krate) ;
146
+
147
+ commit_and_push ( repo, || {
148
+ let prev = try!( File :: open ( & dst) . read_to_string ( ) ) ;
149
+ let new = prev. as_slice ( ) . lines ( ) . map ( |line| {
150
+ let mut git_crate = try!( json:: decode :: < GitCrate > ( line) . map_err ( |_| {
151
+ internal ( format ! ( "couldn't decode: `{}`" , line) )
152
+ } ) ) ;
153
+ if git_crate. name . as_slice ( ) != krate ||
154
+ git_crate. vers . to_string ( ) != version. to_string ( ) {
155
+ return Ok ( line. to_string ( ) )
156
+ }
157
+ git_crate. yanked = Some ( yanked) ;
158
+ Ok ( json:: encode ( & git_crate) )
159
+ } ) . collect :: < CargoResult < Vec < String > > > ( ) ;
160
+ let new = try!( new) . as_slice ( ) . connect ( "\n " ) ;
161
+ try!( File :: create ( & dst) . write ( new. as_bytes ( ) ) ) ;
162
+
163
+ Ok ( ( format ! ( "{} crate `{}#{}`" ,
164
+ if yanked { "Yanking" } else { "Unyanking" } ,
165
+ krate, version) ,
166
+ dst. clone ( ) ) )
167
+ } )
168
+ }
169
+
170
+ fn commit_and_push ( repo : & git2:: Repository ,
171
+ f: || -> CargoResult < ( String , Path ) > )
172
+ -> CargoResult < ( ) > {
173
+ let repo_path = repo. path( ) . dir_path ( ) ;
174
+
175
+ // Attempt to commit in a loop. It's possible that we're going to need to
176
+ // rebase our repository, and after that it's possible that we're going to
177
+ // race to commit the changes. For now we just cap out the maximum number of
178
+ // retries at a fixed number.
179
+ for _ in range ( 0 i, 20 ) {
180
+ let ( msg, dst) = try!( f ( ) ) ;
181
+
134
182
// git add $file
135
183
let mut index = try!( repo. index ( ) ) ;
136
184
try!( index. add_path ( & dst. path_relative_from ( & repo_path) . unwrap ( ) ) ) ;
@@ -142,7 +190,6 @@ pub fn add_crate(app: &App, krate: &GitCrate) -> CargoResult<()> {
142
190
let head = try!( repo. head ( ) ) ;
143
191
let parent = try!( repo. find_commit ( head. target ( ) . unwrap ( ) ) ) ;
144
192
let sig = try!( repo. signature ( ) ) ;
145
- let msg = format ! ( "Updating crate `{}#{}`" , krate. name, krate. vers) ;
146
193
try!( repo. commit ( Some ( "HEAD" ) , & sig, & sig, msg. as_slice ( ) ,
147
194
& tree, & [ & parent] ) ) ;
148
195
0 commit comments