20
20
21
21
import com .google .common .base .Strings ;
22
22
23
+ import java .io .BufferedInputStream ;
23
24
import java .io .BufferedOutputStream ;
24
25
import java .io .BufferedReader ;
25
26
import java .io .File ;
27
+ import java .io .FileInputStream ;
26
28
import java .io .FileOutputStream ;
27
29
import java .io .FileReader ;
28
30
import java .io .FileWriter ;
29
31
import java .io .IOException ;
30
32
import java .io .InputStream ;
31
33
import java .io .InputStreamReader ;
32
34
import java .io .OutputStream ;
35
+ import java .math .BigInteger ;
33
36
import java .net .HttpURLConnection ;
37
+ import java .net .MalformedURLException ;
34
38
import java .net .URL ;
39
+ import java .nio .channels .Channels ;
40
+ import java .nio .channels .ReadableByteChannel ;
35
41
import java .nio .file .FileVisitResult ;
36
42
import java .nio .file .Files ;
37
43
import java .nio .file .Path ;
38
44
import java .nio .file .Paths ;
39
45
import java .nio .file .SimpleFileVisitor ;
40
46
import java .nio .file .attribute .BasicFileAttributes ;
47
+ import java .security .MessageDigest ;
48
+ import java .security .NoSuchAlgorithmException ;
49
+ import java .util .Locale ;
41
50
import java .util .zip .ZipEntry ;
42
51
import java .util .zip .ZipInputStream ;
43
52
@@ -52,8 +61,18 @@ public class LocalGcdHelper {
52
61
53
62
public static final String DEFAULT_PROJECT_ID = "projectid1" ;
54
63
public static final int PORT = 8080 ;
55
- private static final String GCD = "gcd-head" ;
56
- private static final String GCD_LOC = '/' + GCD + ".zip" ;
64
+ private static final String GCD = "gcd-v1beta2-rev1-2.1.2b" ;
65
+ private static final String GCD_FILENAME = GCD + ".zip" ;
66
+ private static final String MD5_CHECKSUM = "d84384cdfa8658e1204f4f8be51300e8" ;
67
+ private static final URL GCD_URL ;
68
+
69
+ static {
70
+ try {
71
+ GCD_URL = new URL ("http://storage.googleapis.com/gcd/tools/" + GCD_FILENAME );
72
+ } catch (MalformedURLException e ) {
73
+ throw new RuntimeException (e );
74
+ }
75
+ }
57
76
58
77
private static class ProcessStreamReader extends Thread {
59
78
@@ -101,13 +120,32 @@ public LocalGcdHelper(String projectId) {
101
120
this .projectId = projectId ;
102
121
}
103
122
123
+ /**
124
+ * Starts the local datastore for the specific project.
125
+ *
126
+ * This will unzip the gcd tool, create the project and start it.
127
+ * All content is written to a temporary directory that will be deleted when
128
+ * {@link #stop()} is called or when the program terminates) to make sure that no left-over
129
+ * data from prior runs is used.
130
+ */
104
131
public void start () throws IOException , InterruptedException {
132
+ // send a quick request in case we have a hanging process from a previous run
105
133
sendQuitRequest ();
134
+ // Each run is associated with its own folder that is deleted once test completes.
106
135
gcdPath = Files .createTempDirectory ("gcd" );
107
136
File gcdFolder = gcdPath .toFile ();
108
137
gcdFolder .deleteOnExit ();
109
138
110
- try (ZipInputStream zipIn = new ZipInputStream (getClass ().getResourceAsStream (GCD_LOC ))) {
139
+ // check if we already have a local copy of the gcd utility and download it if not.
140
+ File gcdZipFile = new File (System .getProperty ("java.io.tmpdir" ), GCD_FILENAME );
141
+ if (!gcdZipFile .exists () || !MD5_CHECKSUM .equals (md5 (gcdZipFile ))) {
142
+ ReadableByteChannel rbc = Channels .newChannel (GCD_URL .openStream ());
143
+ FileOutputStream fos = new FileOutputStream (gcdZipFile );
144
+ fos .getChannel ().transferFrom (rbc , 0 , Long .MAX_VALUE );
145
+ fos .close ();
146
+ }
147
+ // unzip the gcd
148
+ try (ZipInputStream zipIn = new ZipInputStream (new FileInputStream (gcdZipFile ))) {
111
149
ZipEntry entry = zipIn .getNextEntry ();
112
150
while (entry != null ) {
113
151
File filePath = new File (gcdFolder , entry .getName ());
@@ -120,27 +158,60 @@ public void start() throws IOException, InterruptedException {
120
158
entry = zipIn .getNextEntry ();
121
159
}
122
160
}
123
-
161
+ // cleanup any possible data for the same project
124
162
File datasetFolder = new File (gcdFolder , GCD + '/' + projectId );
125
163
deleteRecurse (datasetFolder .toPath ());
126
164
127
- // TODO: if System.getProperty("os.name").startsWith("Windows") use cmd.exe /c and gcd.cmd
128
- Process temp = new ProcessBuilder ()
129
- .redirectErrorStream (true )
130
- .directory (new File (gcdFolder , GCD ))
131
- .redirectOutput (new File ("/dev/null" ))
132
- .command ("bash" , "gcd.sh" , "create" , "-d" , projectId , projectId )
133
- .start ();
165
+ // create the datastore for the project
166
+ ProcessBuilder processBuilder = new ProcessBuilder ()
167
+ .redirectError (ProcessBuilder .Redirect .INHERIT )
168
+ .directory (new File (gcdFolder , GCD ));
169
+ if (isWindows ()) {
170
+ processBuilder .command ("cmd" , "/C" , "gcd.cmd" , "create" , "-p" , projectId , projectId );
171
+ processBuilder .redirectOutput (new File ("NULL:" ));
172
+ } else {
173
+ processBuilder .redirectOutput (new File ("/dev/null" ));
174
+ processBuilder .command ("bash" , "gcd.sh" , "create" , "-p" , projectId , projectId );
175
+ }
176
+
177
+ Process temp = processBuilder .start ();
134
178
temp .waitFor ();
135
179
136
- temp = new ProcessBuilder ()
180
+ // start the datastore for the project
181
+ processBuilder = new ProcessBuilder ()
137
182
.directory (new File (gcdFolder , GCD ))
138
- .redirectErrorStream (true )
139
- .command ("bash" , "gcd.sh" , "start" , "--testing" , "--allow_remote_shutdown" , projectId )
140
- .start ();
183
+ .redirectErrorStream (true );
184
+ if (isWindows ()) {
185
+ processBuilder .command ("cmd" , "/C" , "gcd.cmd" , "start" , "--testing" ,
186
+ "--allow_remote_shutdown" , projectId );
187
+ } else {
188
+ processBuilder .command ("bash" , "gcd.sh" , "start" , "--testing" , "--allow_remote_shutdown" ,
189
+ projectId );
190
+ }
191
+ temp = processBuilder .start ();
141
192
processReader = ProcessStreamReader .start (temp , "Dev App Server is now running" );
142
193
}
143
194
195
+ private static String md5 (File gcdZipFile ) throws IOException {
196
+ try {
197
+ MessageDigest md5 = MessageDigest .getInstance ("MD5" );
198
+ try (InputStream is = new BufferedInputStream (new FileInputStream (gcdZipFile ))) {
199
+ byte [] bytes = new byte [4 * 1024 * 1024 ];
200
+ int len ;
201
+ while ((len = is .read (bytes )) >= 0 ) {
202
+ md5 .update (bytes , 0 , len );
203
+ }
204
+ }
205
+ return String .format ("%032x" ,new BigInteger (1 , md5 .digest ()));
206
+ } catch (NoSuchAlgorithmException e ) {
207
+ throw new IOException (e );
208
+ }
209
+ }
210
+
211
+ private static boolean isWindows () {
212
+ return System .getProperty ("os.name" ).toLowerCase (Locale .ENGLISH ).indexOf ("windows" ) > -1 ;
213
+ }
214
+
144
215
private static void extractFile (ZipInputStream zipIn , File filePath ) throws IOException {
145
216
try (BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream (filePath ))) {
146
217
byte [] bytesIn = new byte [1024 ];
0 commit comments