3
3
import org .slf4j .Logger ;
4
4
5
5
import java .io .*;
6
- import java .net .URI ;
7
- import java .net .URISyntaxException ;
8
6
import java .net .URL ;
9
7
import java .nio .charset .StandardCharsets ;
10
8
import java .nio .file .Files ;
11
9
import java .nio .file .NoSuchFileException ;
12
10
import java .nio .file .Paths ;
11
+ import java .security .MessageDigest ;
12
+ import java .security .NoSuchAlgorithmException ;
13
13
import java .util .Arrays ;
14
14
import java .util .List ;
15
15
import java .util .Locale ;
16
+ import java .util .Objects ;
16
17
import java .util .function .Function ;
17
18
18
19
public final class Execution {
@@ -29,8 +30,9 @@ private Execution() {
29
30
private static final String FILE_NAME_MAC = "cx-mac" ;
30
31
private static final String FILE_NAME_WINDOWS = "cx.exe" ;
31
32
private static final String LINE_SEPARATOR = System .getProperty ("line.separator" );
33
+ private static final String TEMP_DIR = System .getProperty ("java.io.tmpdir" );
32
34
33
- private static URL executable = null ;
35
+ private static String executable = null ;
34
36
35
37
static <T > T executeCommand (List <String > arguments ,
36
38
Logger logger ,
@@ -83,6 +85,29 @@ static String executeCommand(List<String> arguments,
83
85
StandardCharsets .UTF_8 );
84
86
}
85
87
88
+ static String getTempBinary () throws IOException {
89
+ if (executable == null ) {
90
+ String fileName = detectBinaryName ();
91
+ if (fileName == null ) {
92
+ throw new IOException ("Unsupported architecture" );
93
+ }
94
+ URL resource = Execution .class .getClassLoader ().getResource (fileName );
95
+ if (resource == null ) {
96
+ throw new NoSuchFileException ("Could not find CLI executable" );
97
+ }
98
+ File tempExecutable = new File (TEMP_DIR , fileName );
99
+ if (!tempExecutable .exists () || !compareChecksum (resource .openStream (),
100
+ new FileInputStream (tempExecutable ))) {
101
+ copyURLToFile (resource , tempExecutable );
102
+ }
103
+ if (!tempExecutable .canExecute () && !tempExecutable .setExecutable (true )) {
104
+ throw new IOException ("Could not set CLI as executable" );
105
+ }
106
+ executable = tempExecutable .getAbsolutePath ();
107
+ }
108
+ return executable ;
109
+ }
110
+
86
111
private static BufferedReader getReader (Process process ) {
87
112
InputStream is = process .getInputStream ();
88
113
InputStreamReader isr = new InputStreamReader (is );
@@ -95,38 +120,56 @@ private static Process buildProcess(List<String> commands) throws IOException {
95
120
return lmBuilder .start ();
96
121
}
97
122
98
- /**
99
- * Detect binary name by the current architecture.
100
- *
101
- * @return binary name
102
- * @throws IOException when architecture is unsupported
103
- * @throws URISyntaxException when the file has an invalid URI
104
- */
105
- public static URI detectBinary () throws IOException , URISyntaxException {
106
- if (executable == null ) {
107
- final String arch = OS_NAME ;
108
- String fileName = null ;
109
- if (arch .contains (OS_LINUX )) {
110
- fileName = FILE_NAME_LINUX ;
111
- } else if (arch .contains (OS_WINDOWS )) {
112
- fileName = FILE_NAME_WINDOWS ;
113
- } else {
114
- for (String macStr : OS_MAC ) {
115
- if (arch .contains (macStr )) {
116
- fileName = FILE_NAME_MAC ;
117
- break ;
118
- }
123
+ private static String detectBinaryName () {
124
+ String arch = OS_NAME ;
125
+ String fileName = null ;
126
+ if (arch .contains (OS_LINUX )) {
127
+ fileName = FILE_NAME_LINUX ;
128
+ } else if (arch .contains (OS_WINDOWS )) {
129
+ fileName = FILE_NAME_WINDOWS ;
130
+ } else {
131
+ for (String macStr : OS_MAC ) {
132
+ if (arch .contains (macStr )) {
133
+ fileName = FILE_NAME_MAC ;
134
+ break ;
119
135
}
120
136
}
121
- if (fileName == null ) {
122
- throw new IOException ("Unsupported architecture" );
137
+ }
138
+ return fileName ;
139
+ }
140
+
141
+ private static void copyURLToFile (URL source , File destination ) throws IOException {
142
+ final byte [] buf = new byte [8192 ];
143
+ try (InputStream reader = source .openStream ();
144
+ OutputStream writer = new FileOutputStream (destination )) {
145
+ int i ;
146
+ while ((i = reader .read (buf )) != -1 ) {
147
+ writer .write (buf , 0 , i );
123
148
}
124
- executable = Execution .class .getClassLoader ().getResource (fileName );
149
+ } catch (IOException e ) {
150
+ throw new IOException ("Could not copy CLI to the temporary directory" , e );
125
151
}
126
- URL resource = executable ;
127
- if (resource == null ) {
128
- throw new NoSuchFileException ("Could not find CLI executable" );
152
+ }
153
+
154
+ private static boolean compareChecksum (InputStream a , InputStream b ) {
155
+ String aMD5 = md5 (a );
156
+ String bMD5 = md5 (b );
157
+ return aMD5 != null && bMD5 != null && Objects .equals (aMD5 , bMD5 );
158
+ }
159
+
160
+ private static String md5 (InputStream a ) {
161
+ String md5 = null ;
162
+ final byte [] buf = new byte [8192 ];
163
+ try {
164
+ MessageDigest md = MessageDigest .getInstance ("MD5" );
165
+ int i ;
166
+ while ((i = a .read (buf )) != -1 ) {
167
+ md .update (buf , 0 , i );
168
+ }
169
+ md5 = new String (md .digest ());
170
+ } catch (NoSuchAlgorithmException | IOException e ) {
171
+ // ignore
129
172
}
130
- return resource . toURI () ;
173
+ return md5 ;
131
174
}
132
175
}
0 commit comments