golf 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +21 -0
- data/Rakefile +12 -0
- data/bin/golf +8 -0
- data/golf-java/README.markdown +41 -0
- data/golf-java/THANKS.markdown +14 -0
- data/golf-java/build/classes.zip +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping$MimeMappingSingleton.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfResource.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet$1.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfContext.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfParams.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfSession.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet$PermanentRedirectException.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet$RedirectException.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet$StoredJSVM.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/GolfServlet.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/JsonpTunnel.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/Main$1.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/Main$RingList.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/Main.class +0 -0
- data/golf-java/build/com/thinkminimo/golf/ProxyServlet.class +0 -0
- data/golf-java/build/com/yahoo/platform/yui/compressor/CssCompressor.class +0 -0
- data/golf-java/build/com/yahoo/platform/yui/compressor/JarClassLoader.class +0 -0
- data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptCompressor.class +0 -0
- data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.class +0 -0
- data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptToken.class +0 -0
- data/golf-java/build/com/yahoo/platform/yui/compressor/ScriptOrFnScope.class +0 -0
- data/golf-java/build/depends.zip +0 -0
- data/golf-java/build/golf +2 -0
- data/golf-java/build/org/json/JSONArray.class +0 -0
- data/golf-java/build/org/json/JSONException.class +0 -0
- data/golf-java/build/org/json/JSONObject$1.class +0 -0
- data/golf-java/build/org/json/JSONObject$Null.class +0 -0
- data/golf-java/build/org/json/JSONObject.class +0 -0
- data/golf-java/build/org/json/JSONString.class +0 -0
- data/golf-java/build/org/json/JSONStringer.class +0 -0
- data/golf-java/build/org/json/JSONTokener.class +0 -0
- data/golf-java/build/org/json/JSONWriter.class +0 -0
- data/golf-java/build/resources.zip +0 -0
- data/golf-java/build.xml +174 -0
- data/golf-java/dist/golf.zip +0 -0
- data/golf-java/lib/ant-launcher.jar +0 -0
- data/golf-java/lib/ant.jar +0 -0
- data/golf-java/lib/commons-codec-1.4.jar +0 -0
- data/golf-java/lib/commons-collections-3.2.1.jar +0 -0
- data/golf-java/lib/commons-fileupload-1.2.1.jar +0 -0
- data/golf-java/lib/commons-httpclient-3.1.jar +0 -0
- data/golf-java/lib/commons-io-1.4.jar +0 -0
- data/golf-java/lib/commons-lang-2.4.jar +0 -0
- data/golf-java/lib/commons-logging-1.1.1.jar +0 -0
- data/golf-java/lib/cssparser-0.9.5.jar +0 -0
- data/golf-java/lib/getopt-0.1-dev.jar +0 -0
- data/golf-java/lib/htmlunit-2.6.jar +0 -0
- data/golf-java/lib/htmlunit-core-js-2.6.jar +0 -0
- data/golf-java/lib/java-xmlbuilder-1.jar +0 -0
- data/golf-java/lib/jets3t-0.7.0.jar +0 -0
- data/golf-java/lib/jetty-6.1.15.jar +0 -0
- data/golf-java/lib/jetty-util-6.1.15.jar +0 -0
- data/golf-java/lib/log4j-1.2.15.jar +0 -0
- data/golf-java/lib/nekohtml-1.9.13.jar +0 -0
- data/golf-java/lib/sac-1.3.jar +0 -0
- data/golf-java/lib/serializer-2.7.1.jar +0 -0
- data/golf-java/lib/servlet-api-2.5-20081211.jar +0 -0
- data/golf-java/lib/xalan-2.7.1.jar +0 -0
- data/golf-java/lib/xercesImpl-2.9.1.jar +0 -0
- data/golf-java/lib/xml-apis-1.3.04.jar +0 -0
- data/golf-java/resources/app_error.html +60 -0
- data/golf-java/resources/error.html +29 -0
- data/golf-java/resources/forcebot.txt +0 -0
- data/golf-java/resources/forceclient.txt +0 -0
- data/golf-java/resources/forceproxy.txt +0 -0
- data/golf-java/resources/head.html +0 -0
- data/golf-java/resources/jquery.address.js +439 -0
- data/golf-java/resources/jquery.golf.js +945 -0
- data/golf-java/resources/jquery.js +4376 -0
- data/golf-java/resources/jsdetect.html +23 -0
- data/golf-java/resources/loading.gif +0 -0
- data/golf-java/resources/new.html +45 -0
- data/golf-java/resources/new.static.html +45 -0
- data/golf-java/resources/noscript.forceclient.html +11 -0
- data/golf-java/resources/noscript.html +18 -0
- data/golf-java/resources/noscript.static.html +15 -0
- data/golf-java/resources/project.xml +21 -0
- data/golf-java/resources/proxy_project.xml +11 -0
- data/golf-java/resources/proxy_web.xml +40 -0
- data/golf-java/resources/static_project.xml +37 -0
- data/golf-java/resources/version +1 -0
- data/golf-java/resources/web.xml +36 -0
- data/golf-java/resources/welcome2golf.html +50 -0
- data/golf-java/src/com/thinkminimo/golf/GolfResource.java +582 -0
- data/golf-java/src/com/thinkminimo/golf/GolfServlet.java +1055 -0
- data/golf-java/src/com/thinkminimo/golf/JsonpTunnel.java +86 -0
- data/golf-java/src/com/thinkminimo/golf/Main.java +1299 -0
- data/golf-java/src/com/thinkminimo/golf/ProxyServlet.java +577 -0
- data/golf-java/src/com/yahoo/platform/yui/compressor/CssCompressor.java +188 -0
- data/golf-java/src/com/yahoo/platform/yui/compressor/JarClassLoader.java +158 -0
- data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java +1281 -0
- data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java +55 -0
- data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java +28 -0
- data/golf-java/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java +160 -0
- data/golf-java/src/org/json/JSONArray.java +934 -0
- data/golf-java/src/org/json/JSONException.java +27 -0
- data/golf-java/src/org/json/JSONObject.java +1550 -0
- data/golf-java/src/org/json/JSONString.java +18 -0
- data/golf-java/src/org/json/JSONStringer.java +78 -0
- data/golf-java/src/org/json/JSONTokener.java +422 -0
- data/golf-java/src/org/json/JSONWriter.java +323 -0
- data/golf-java/test/client/golftest/README.markdown +3 -0
- data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.css +114 -0
- data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.html +17 -0
- data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.js +81 -0
- data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/asc.gif +0 -0
- data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/bg.gif +0 -0
- data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/desc.gif +0 -0
- data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/test/test.html +1 -0
- data/golf-java/test/client/golftest/controller.js +131 -0
- data/golf-java/test/client/golftest/forceclient.txt +0 -0
- data/golf-java/test/client/golftest/forceproxy.txt +0 -0
- data/golf-java/test/client/golftest/head.html +1 -0
- data/golf-java/test/client/golftest/scripts/jquery.tablesort.js +75 -0
- data/golf-java/test/client/golftest/styles/style.css +18 -0
- data/golf-java/test/client/golftest/test/test.html +1 -0
- data/golf.gemspec +24 -0
- data/lib/golf/cli.rb +32 -0
- data/lib/golf/compiler.rb +12 -0
- data/lib/golf/rack.rb +17 -0
- data/lib/golf/version.rb +3 -0
- data/lib/golf.rb +6 -0
- data/template/Gemfile +5 -0
- data/template/config.ru +7 -0
- data/template/golfapp/components/Test/Test.html +22 -0
- data/template/golfapp/components/Test/Test.res/myfile.txt +1 -0
- data/template/golfapp/controller.js +10 -0
- data/template/golfapp/plugins/mylib.js +12 -0
- data/test/test_compiler.rb +10 -0
- data/test/test_helper.rb +6 -0
- data/test/test_rack.rb +17 -0
- metadata +208 -0
@@ -0,0 +1,1299 @@
|
|
1
|
+
package com.thinkminimo.golf;
|
2
|
+
|
3
|
+
import com.thinkminimo.getopt.GetOpt;
|
4
|
+
|
5
|
+
import org.json.*;
|
6
|
+
|
7
|
+
import java.io.*;
|
8
|
+
import java.util.*;
|
9
|
+
import java.util.regex.Pattern;
|
10
|
+
import java.net.URL;
|
11
|
+
import java.net.URI;
|
12
|
+
import java.net.URISyntaxException;
|
13
|
+
import java.net.URLClassLoader;
|
14
|
+
import java.rmi.server.UID;
|
15
|
+
import java.security.NoSuchAlgorithmException;
|
16
|
+
|
17
|
+
import java.lang.reflect.Method;
|
18
|
+
import java.lang.reflect.Constructor;
|
19
|
+
|
20
|
+
import net.sourceforge.htmlunit.corejs.javascript.ErrorReporter;
|
21
|
+
import net.sourceforge.htmlunit.corejs.javascript.EvaluatorException;
|
22
|
+
import com.yahoo.platform.yui.compressor.CssCompressor;
|
23
|
+
import com.yahoo.platform.yui.compressor.JavaScriptCompressor;
|
24
|
+
|
25
|
+
import javax.servlet.ServletException;
|
26
|
+
import javax.servlet.http.HttpServlet;
|
27
|
+
import javax.servlet.http.HttpServletRequest;
|
28
|
+
import javax.servlet.http.HttpServletResponse;
|
29
|
+
|
30
|
+
import org.jets3t.service.CloudFrontService;
|
31
|
+
import org.jets3t.service.S3Service;
|
32
|
+
import org.jets3t.service.S3ServiceException;
|
33
|
+
import org.jets3t.service.acl.AccessControlList;
|
34
|
+
import org.jets3t.service.acl.GroupGrantee;
|
35
|
+
import org.jets3t.service.acl.Permission;
|
36
|
+
import org.jets3t.service.model.S3Bucket;
|
37
|
+
import org.jets3t.service.model.S3Object;
|
38
|
+
import org.jets3t.service.model.cloudfront.Distribution;
|
39
|
+
import org.jets3t.service.model.cloudfront.DistributionConfig;
|
40
|
+
import org.jets3t.service.impl.rest.httpclient.RestS3Service;
|
41
|
+
import org.jets3t.service.security.AWSCredentials;
|
42
|
+
|
43
|
+
import org.apache.tools.ant.*;
|
44
|
+
import org.apache.tools.ant.taskdefs.*;
|
45
|
+
import org.apache.tools.ant.types.resources.*;
|
46
|
+
|
47
|
+
import org.mortbay.log.Log;
|
48
|
+
import org.mortbay.jetty.Handler;
|
49
|
+
import org.mortbay.jetty.HandlerContainer;
|
50
|
+
import org.mortbay.jetty.Server;
|
51
|
+
import org.mortbay.jetty.handler.HandlerList;
|
52
|
+
import org.mortbay.jetty.handler.ContextHandlerCollection;
|
53
|
+
import org.mortbay.jetty.handler.DefaultHandler;
|
54
|
+
import org.mortbay.jetty.handler.ResourceHandler;
|
55
|
+
import org.mortbay.jetty.handler.RequestLogHandler;
|
56
|
+
import org.mortbay.jetty.servlet.Context;
|
57
|
+
import org.mortbay.jetty.servlet.ServletHolder;
|
58
|
+
import org.mortbay.jetty.servlet.DefaultServlet;
|
59
|
+
import org.mortbay.jetty.webapp.WebAppContext;
|
60
|
+
import org.mortbay.thread.QueuedThreadPool;
|
61
|
+
|
62
|
+
public class Main
|
63
|
+
{
|
64
|
+
public static class RingList<T> extends ArrayList <T> {
|
65
|
+
private int next = 0;
|
66
|
+
public T next() {
|
67
|
+
return get(next++ % size());
|
68
|
+
}
|
69
|
+
public void reset() {
|
70
|
+
next = 0;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
public static final String AWS_URL = "s3.amazonaws.com";
|
75
|
+
public static final int NUM_CFDOMAINS = 1;
|
76
|
+
public static final int NUM_VMPOOL = 20;
|
77
|
+
public static final int NUM_VMEXPIRE = 10;
|
78
|
+
public static final int JETTY_PORT = 4653;
|
79
|
+
private static final int BUF_SIZE = 1024;
|
80
|
+
|
81
|
+
public static final String NEW_HTML = "new.html";
|
82
|
+
public static final String NEW_FC_HTML = "new.fc.html";
|
83
|
+
public static final String NEW_ST_HTML = "new.static.html";
|
84
|
+
public static final String ERROR_HTML = "error.html";
|
85
|
+
public static final String HEAD_HTML = "head.html";
|
86
|
+
public static final String JSDETECT_HTML = "jsdetect.html";
|
87
|
+
public static final String COMPONENTS_JS = "components.js";
|
88
|
+
public static final String CONTROLLER_JS = "controller.js";
|
89
|
+
public static final String JQUERY_JS = "jquery.js";
|
90
|
+
public static final String JQUERY_GOLF_JS = "jquery.golf.js";
|
91
|
+
public static final String JQUERY_HIST_JS = "jquery.address.js";
|
92
|
+
public static final String FORCEPROXY_TXT = "forceproxy.txt";
|
93
|
+
public static final String FORCECLIENT_TXT = "forceclient.txt";
|
94
|
+
public static final String FORCEBOT_TXT = "forcebot.txt";
|
95
|
+
public static final String NOSCRIPT_HTML = "noscript.html";
|
96
|
+
public static final String NOSCRIPT_FC_HTML= "noscript.forceclient.html";
|
97
|
+
public static final String NOSCRIPT_ST_HTML= "noscript.static.html";
|
98
|
+
public static final String LOADING_GIF = "loading.gif";
|
99
|
+
|
100
|
+
public static final String DIR_COMPONENTS = "components";
|
101
|
+
public static final String DIR_MODULES = "plugins";
|
102
|
+
public static final String DIR_SCRIPTS = "scripts";
|
103
|
+
public static final String DIR_STYLES = "styles";
|
104
|
+
|
105
|
+
private static GetOpt o = null;
|
106
|
+
private static RingList<String> mCfDomains = null;
|
107
|
+
private static String mNewHtml = null;
|
108
|
+
|
109
|
+
private static String mAppName = null;
|
110
|
+
private static String mAppVersion = null;
|
111
|
+
|
112
|
+
private static HashMap<String, String> mApps = null;
|
113
|
+
private static HashMap<String, String> mBackends = null;
|
114
|
+
|
115
|
+
private AWSCredentials mAwsKeys = null;
|
116
|
+
private RestS3Service mS3svc = null;
|
117
|
+
private CloudFrontService mCfsvc = null;
|
118
|
+
private S3Bucket mBucket = null;
|
119
|
+
private AccessControlList mAcl = null;
|
120
|
+
|
121
|
+
public Main(String[] argv) throws Exception {
|
122
|
+
mApps = new HashMap<String, String>();
|
123
|
+
mBackends = new HashMap<String, String>();
|
124
|
+
mCfDomains = new RingList<String>();
|
125
|
+
mAppVersion = getResourceAsString("version").replaceFirst("\n", "");
|
126
|
+
|
127
|
+
// process single flag command lines
|
128
|
+
|
129
|
+
if (argv[0].equals("--version")) {
|
130
|
+
System.out.println(mAppVersion);
|
131
|
+
System.exit(0);
|
132
|
+
}
|
133
|
+
|
134
|
+
// Command line parser setup
|
135
|
+
|
136
|
+
o = new GetOpt("golf", argv);
|
137
|
+
|
138
|
+
o.addFlag(
|
139
|
+
"version",
|
140
|
+
"Display golf application server version info and exit."
|
141
|
+
).addSection(
|
142
|
+
"GENERAL OPTIONS",
|
143
|
+
"General configuration of the golf application server. These options "+
|
144
|
+
"will be rolled into the war file (where appropriate) if deploying to "+
|
145
|
+
"production, or used in the built-in servlet container for devmode "+
|
146
|
+
"operation."
|
147
|
+
).addOpt(
|
148
|
+
"port",
|
149
|
+
"Set the port the server will listen on (optional, devmode only)."
|
150
|
+
).addOpt(
|
151
|
+
"displayname",
|
152
|
+
"The display name to use for deploying as a war file into a servlet "+
|
153
|
+
"container (optional)."
|
154
|
+
).addOpt(
|
155
|
+
"description",
|
156
|
+
"Description of app when deploying as a war file into a servlet "+
|
157
|
+
"container (optional)."
|
158
|
+
).addOpt(
|
159
|
+
"pool-size",
|
160
|
+
"How many concurrent proxymode client virtual machines to allow."
|
161
|
+
).addOpt(
|
162
|
+
"pool-expire",
|
163
|
+
"Minimum idle time (seconds) before a proxymode client virtual "+
|
164
|
+
"machine can be scavenged."
|
165
|
+
).addOpt(
|
166
|
+
"static",
|
167
|
+
"Destination directory for a static app deployment. Static apps are "+
|
168
|
+
"compiled into pure HTML+JS. There is no proxy support with this option."
|
169
|
+
).addSection(
|
170
|
+
"AMAZON WEB SERVICES CONFIGURATION OPTIONS",
|
171
|
+
"The awspublic and awsprivate options provide the golf server with "+
|
172
|
+
"your AWS credentials. This enables it to automatically upload the "+
|
173
|
+
"application to CloudFront when deploying to production. AWS is not "+
|
174
|
+
"used in devmode."
|
175
|
+
).addOpt(
|
176
|
+
"awspublic",
|
177
|
+
"The amazon aws access key ID to use for cloudfront caching (required "+
|
178
|
+
"when using AWS)."
|
179
|
+
).addOpt(
|
180
|
+
"awsprivate",
|
181
|
+
"The amazon aws secret access key corresponding to the aws access "+
|
182
|
+
"key ID specified with the --awspublic option (required when using AWS)."
|
183
|
+
).addOpt(
|
184
|
+
"cloudfronts",
|
185
|
+
"How many CloudFront distributions to create (optional). This may be "+
|
186
|
+
"useful for getting browsers to load things in parallel rather than "+
|
187
|
+
"one at a time. On the other hand, it may be useless."
|
188
|
+
).addSection(
|
189
|
+
"HTTP PROXY CONFIGURATION OPTIONS",
|
190
|
+
"The golf application server ships with a built-in HTTP proxy servlet "+
|
191
|
+
"that can be used to provide access to backend web services without "+
|
192
|
+
"needing to resort to using JSONP or the 'window.name' hack."
|
193
|
+
).addOpt(
|
194
|
+
"proxyhost",
|
195
|
+
"The remote URI that the HTTP proxy will relay requests to. This will "+
|
196
|
+
"produce a war file containing the configured proxy servlet and exit, "+
|
197
|
+
"instead of starting the embedded servlet container."
|
198
|
+
).addOpt(
|
199
|
+
"proxyparams",
|
200
|
+
"Parameters to add to the query string of every request sent by the "+
|
201
|
+
"HTTP proxy to the remote host. This can be used to pass tokens that "+
|
202
|
+
"the client shouldn't have access to, and things like that."
|
203
|
+
).addOpt(
|
204
|
+
"proxymaxupload",
|
205
|
+
"The maximum file upload size for HTTP proxy requests (optional, in "+
|
206
|
+
"bytes)."
|
207
|
+
).addSection(
|
208
|
+
"WAR FILE CONFIGURATION OPTIONS",
|
209
|
+
"The golf application server jar file is able to roll a golf "+
|
210
|
+
"application into a war file for deployment to a servlet container "+
|
211
|
+
"for production. These options govern how this is done."
|
212
|
+
).addFlag(
|
213
|
+
"compress-js",
|
214
|
+
"Whether to yuicompress javascript resource files (production only)."
|
215
|
+
).addFlag(
|
216
|
+
"compress-css",
|
217
|
+
"Whether to yuicompress css resource files (production only)."
|
218
|
+
).addFlag(
|
219
|
+
"war",
|
220
|
+
"If present, create war file instead of starting embedded servlet "+
|
221
|
+
"container."
|
222
|
+
).addArg(
|
223
|
+
"approot|proxypath",
|
224
|
+
"The location of the golf app root directory, or when building HTTP "+
|
225
|
+
"proxy, the desired name of the resulting war file (.war extension "+
|
226
|
+
"will be added). When this argument specifies a golf approot, the "+
|
227
|
+
"application context path (or war file name, in the case of the --war "+
|
228
|
+
"option) is derived from the basename of the specified directory."
|
229
|
+
).addVarArg(
|
230
|
+
"backend [backend...]",
|
231
|
+
"The backend webapp war file or approot (not used when building HTTP "+
|
232
|
+
"proxy war files). Zero or more war files or directories may be "+
|
233
|
+
"specified here. The context path they are deployed to is taken from "+
|
234
|
+
"the basename of the war file or directory."
|
235
|
+
).addExample(
|
236
|
+
"RUN LOCAL DEVMODE SERVER WITH NO BACKEND",
|
237
|
+
"java -jar golf.jar ./apps/demo",
|
238
|
+
"This starts the golf application server, running the golf application "+
|
239
|
+
"locally from the embedded servlet container. The application will be "+
|
240
|
+
"accessible at the URL http://localhost:4653/demo/, and the approot is "+
|
241
|
+
"set to the ./apps/demo/ directory."
|
242
|
+
).addExample(
|
243
|
+
"RUN LOCAL DEVMODE SERVER WITH BACKEND",
|
244
|
+
"java -jar golf.jar ./apps/demo data1.war data2.war",
|
245
|
+
"This starts the golf application server, locally, as in the previous "+
|
246
|
+
"example, accessible at the URL http://localhost:4653/demo/, etc. "+
|
247
|
+
"Additionally, data1.war and data2.war (backend applications) will be "+
|
248
|
+
"deployed to the /data1/ and /data2/ context paths."
|
249
|
+
).addExample(
|
250
|
+
"PREPARE WAR FILE FOR DEPLOYMENT TO PRODUCTION",
|
251
|
+
"java -jar golf.jar --war ./apps/demo",
|
252
|
+
"Instead of starting the local golf application server, a war file is "+
|
253
|
+
"produced containing the golf application, in this case 'demo.war' is "+
|
254
|
+
"the resulting file. This war file can then be deployed to the "+
|
255
|
+
"production servlet container."
|
256
|
+
).addExample(
|
257
|
+
"PREPARE WAR FILE FOR DEPLOYMENT TO PRODUCTION WITH AWS",
|
258
|
+
"java -jar golf.jar --displayname 'My Golf App' \\\n"+
|
259
|
+
" --awspublic GKI69AJ344JLNT92X1QQ \\\n"+
|
260
|
+
" --awsprivate ke9S3CwVzLW9B21/HrkLiQfXEpoeGHwNDTlfBW5J \\\n"+
|
261
|
+
" --war ./apps/demo",
|
262
|
+
"As in the previous example, a war file is produced instead of starting "+
|
263
|
+
"the local golf application server. Additionally, the golf application "+
|
264
|
+
"is uploaded to Amazon's s3 service, and a CloudFront distribution is "+
|
265
|
+
"created. The golf app in the resulting war file will automatically "+
|
266
|
+
"load the frontend from CloudFront, rather than from the golf server."
|
267
|
+
).addExample(
|
268
|
+
"CREATE A HTTP PROXY",
|
269
|
+
"java -jar golf.jar --proxyhost www.example.com:8080/doit/ \\\n"+
|
270
|
+
" --proxyparams 'user=myname&pass=secret' data",
|
271
|
+
"This produces a HTTP proxy servlet configured to proxy HTTP requests "+
|
272
|
+
"to the specified remote URI, instead of starting the local embedded "+
|
273
|
+
"servlet container. The resulting war file will be saved to 'data.war'."
|
274
|
+
);
|
275
|
+
|
276
|
+
// default values for command line options
|
277
|
+
|
278
|
+
o.setOpt("port", String.valueOf(JETTY_PORT));
|
279
|
+
o.setOpt("displayname", "untitled web application");
|
280
|
+
o.setOpt("description", "powered by golf: http://thinkminimo.com");
|
281
|
+
o.setOpt("devmode", "false");
|
282
|
+
o.setOpt("awspublic", null);
|
283
|
+
o.setOpt("awsprivate", null);
|
284
|
+
o.setOpt("proxyhost", null);
|
285
|
+
o.setOpt("proxyparams", "");
|
286
|
+
o.setOpt("proxymaxupload",String.valueOf(10*1024*1024));
|
287
|
+
o.setOpt("pool-size", String.valueOf(NUM_VMPOOL));
|
288
|
+
o.setOpt("pool-expire", String.valueOf(NUM_VMEXPIRE));
|
289
|
+
o.setOpt("cloudfronts", String.valueOf(NUM_CFDOMAINS));
|
290
|
+
o.setOpt("cfdomains", "[]");
|
291
|
+
o.setOpt("compress-js", "false");
|
292
|
+
o.setOpt("compress-css", "false");
|
293
|
+
o.setOpt("war", "false");
|
294
|
+
|
295
|
+
// parse command line
|
296
|
+
try {
|
297
|
+
o.go();
|
298
|
+
} catch (Exception e) {
|
299
|
+
System.exit(1);
|
300
|
+
}
|
301
|
+
|
302
|
+
// command line option validation
|
303
|
+
|
304
|
+
if (o.getOpt("port") != null) {
|
305
|
+
try {
|
306
|
+
Integer.parseInt(o.getOpt("port"));
|
307
|
+
} catch (NumberFormatException e) {
|
308
|
+
usage(e.getMessage());
|
309
|
+
}
|
310
|
+
}
|
311
|
+
|
312
|
+
// start work
|
313
|
+
|
314
|
+
mAppName = (new File(o.getOpt("approot|proxypath")))
|
315
|
+
.getCanonicalFile().getName().replaceFirst("\\.war$", "");
|
316
|
+
mApps.put(mAppName, o.getOpt("approot|proxypath"));
|
317
|
+
|
318
|
+
while (o.getExtra().size() > 0) {
|
319
|
+
String path = o.getExtra().remove(0);
|
320
|
+
File f = new File(path);
|
321
|
+
String name = f.getCanonicalFile().getName().replaceFirst("\\.war$", "");
|
322
|
+
mBackends.put(name, path);
|
323
|
+
}
|
324
|
+
|
325
|
+
try {
|
326
|
+
if (o.getOpt("proxyhost") != null)
|
327
|
+
doProxyWarfile();
|
328
|
+
else if (o.getFlag("war"))
|
329
|
+
doWarfile();
|
330
|
+
else if (o.getOpt("static") != null)
|
331
|
+
doStatic();
|
332
|
+
else
|
333
|
+
doServer();
|
334
|
+
} catch (Exception e) {
|
335
|
+
System.err.println("golf: "+e.getMessage());
|
336
|
+
System.exit(1);
|
337
|
+
}
|
338
|
+
|
339
|
+
System.exit(0);
|
340
|
+
}
|
341
|
+
|
342
|
+
public static void main(String[] argv) {
|
343
|
+
try {
|
344
|
+
Main m = new Main(argv);
|
345
|
+
} catch (Exception e) {
|
346
|
+
System.exit(1);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
private void prepareAws() throws Exception {
|
351
|
+
mAwsKeys =
|
352
|
+
new AWSCredentials(o.getOpt("awspublic"), o.getOpt("awsprivate"));
|
353
|
+
mS3svc = new RestS3Service(mAwsKeys);
|
354
|
+
|
355
|
+
while (true) {
|
356
|
+
mBucket = mS3svc.getOrCreateBucket(randName(mAppName));
|
357
|
+
long nowTime = (new Date()).getTime();
|
358
|
+
long bktTime = mBucket.getCreationDate().getTime();
|
359
|
+
long oneMin = 1L * 60L * 1000L;
|
360
|
+
if (nowTime - bktTime < oneMin)
|
361
|
+
break;
|
362
|
+
}
|
363
|
+
|
364
|
+
mAcl = mS3svc.getBucketAcl(mBucket);
|
365
|
+
mAcl.grantPermission(
|
366
|
+
GroupGrantee.ALL_USERS,
|
367
|
+
Permission.PERMISSION_READ
|
368
|
+
);
|
369
|
+
|
370
|
+
mBucket.setAcl(mAcl);
|
371
|
+
mS3svc.putBucketAcl(mBucket);
|
372
|
+
}
|
373
|
+
|
374
|
+
private void doCloudFront() throws Exception {
|
375
|
+
mCfsvc = new CloudFrontService(mAwsKeys);
|
376
|
+
|
377
|
+
String orig = mBucket.getName() + "." + AWS_URL;
|
378
|
+
String cmnt;
|
379
|
+
if (o.getOpt("description") != null)
|
380
|
+
cmnt = o.getOpt("description");
|
381
|
+
else if (o.getOpt("displayname") != null)
|
382
|
+
cmnt = o.getOpt("displayname");
|
383
|
+
else
|
384
|
+
cmnt = mAppName;
|
385
|
+
|
386
|
+
JSONArray json = new JSONArray();
|
387
|
+
|
388
|
+
for (int i=0; i<Integer.valueOf(o.getOpt("cloudfronts")); i++) {
|
389
|
+
Distribution dist =
|
390
|
+
mCfsvc.createDistribution(orig, null, null, cmnt, true);
|
391
|
+
String domain = "http://"+dist.getDomainName()+"/";
|
392
|
+
mCfDomains.add(domain);
|
393
|
+
json.put(domain);
|
394
|
+
}
|
395
|
+
|
396
|
+
o.setOpt("cfdomains", json.toString());
|
397
|
+
}
|
398
|
+
|
399
|
+
private void doAws() throws Exception {
|
400
|
+
try {
|
401
|
+
System.err.print("Preparing S3 bucket....................");
|
402
|
+
if (o.getOpt("awspublic") != null && o.getOpt("awsprivate") != null) {
|
403
|
+
prepareAws();
|
404
|
+
System.err.println("done.");
|
405
|
+
} else {
|
406
|
+
System.err.println("skipped.");
|
407
|
+
}
|
408
|
+
|
409
|
+
System.err.print("Creating CloudFront distributions..");
|
410
|
+
if (o.getOpt("awspublic") != null && o.getOpt("awsprivate") != null) {
|
411
|
+
doCloudFront();
|
412
|
+
System.err.println("done.");
|
413
|
+
} else {
|
414
|
+
System.err.println("skipped.");
|
415
|
+
}
|
416
|
+
|
417
|
+
System.err.print("Compiling components...................");
|
418
|
+
cacheComponentsFile();
|
419
|
+
System.err.println("done.");
|
420
|
+
|
421
|
+
System.err.print("Creating new.html template file........");
|
422
|
+
cacheNewDotHtmlFile();
|
423
|
+
System.err.println("done.");
|
424
|
+
|
425
|
+
System.err.print("Uploading jar resources................");
|
426
|
+
if (o.getOpt("awspublic") != null && o.getOpt("awsprivate") != null) {
|
427
|
+
cacheJarResourcesAws();
|
428
|
+
System.err.println("done.");
|
429
|
+
} else {
|
430
|
+
System.err.println("skipped.");
|
431
|
+
}
|
432
|
+
|
433
|
+
System.err.print("Uploading resource files...............");
|
434
|
+
if (o.getOpt("awspublic") != null && o.getOpt("awsprivate") != null) {
|
435
|
+
cacheResourcesAws(new File(o.getOpt("approot|proxypath")), "");
|
436
|
+
System.err.println("done.");
|
437
|
+
} else {
|
438
|
+
System.err.println("skipped.");
|
439
|
+
}
|
440
|
+
} catch (Exception e) {
|
441
|
+
System.err.println("fail.");
|
442
|
+
throw new Exception(e);
|
443
|
+
}
|
444
|
+
}
|
445
|
+
|
446
|
+
private void doProxyWarfile() throws Exception {
|
447
|
+
String name = mAppName;
|
448
|
+
String host = o.getOpt("proxyhost");
|
449
|
+
int port = 80;
|
450
|
+
String path = "";
|
451
|
+
|
452
|
+
if (!host.startsWith("http://"))
|
453
|
+
host = "http://"+host;
|
454
|
+
|
455
|
+
URI uri = new URI(host);
|
456
|
+
|
457
|
+
host = uri.getHost();
|
458
|
+
port = uri.getPort() == -1 ? port : uri.getPort();
|
459
|
+
path = uri.getPath() == null ? path : uri.getPath();
|
460
|
+
|
461
|
+
doProxyAnt(name, host, port, path);
|
462
|
+
}
|
463
|
+
|
464
|
+
private void doWarfile() throws Exception {
|
465
|
+
o.setOpt("devmode", "false");
|
466
|
+
doAws();
|
467
|
+
doAnt();
|
468
|
+
}
|
469
|
+
|
470
|
+
private void doStatic() throws Exception {
|
471
|
+
cacheComponentsFile();
|
472
|
+
cacheNewDotHtmlFile();
|
473
|
+
doStaticAnt();
|
474
|
+
}
|
475
|
+
|
476
|
+
private void doServer() throws Exception {
|
477
|
+
o.setOpt("devmode", "true");
|
478
|
+
Server server = new Server(Integer.valueOf(o.getOpt("port")));
|
479
|
+
|
480
|
+
cacheComponentsFile();
|
481
|
+
cacheNewDotHtmlFile();
|
482
|
+
|
483
|
+
QueuedThreadPool threadPool = new QueuedThreadPool();
|
484
|
+
threadPool.setMaxThreads(100);
|
485
|
+
server.setThreadPool(threadPool);
|
486
|
+
|
487
|
+
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
488
|
+
HandlerList handlers = new HandlerList();
|
489
|
+
|
490
|
+
for (String app: mApps.keySet()) {
|
491
|
+
Log.info("Starting app `" + app + "'");
|
492
|
+
|
493
|
+
String docRoot = mApps.get(app);
|
494
|
+
|
495
|
+
String golfPath = "/" + app;
|
496
|
+
String golfRoot = docRoot;
|
497
|
+
|
498
|
+
Context cx1 = new Context(contexts, golfPath, Context.SESSIONS);
|
499
|
+
cx1.setResourceBase(golfRoot);
|
500
|
+
cx1.setDisplayName(o.getOpt("displayname"));
|
501
|
+
ServletHolder sh1 = new ServletHolder(new GolfServlet());
|
502
|
+
|
503
|
+
// manually set init parameters
|
504
|
+
sh1.setInitParameter("devmode", o.getOpt("devmode"));
|
505
|
+
sh1.setInitParameter("poolsize", o.getOpt("pool-size"));
|
506
|
+
sh1.setInitParameter("poolexpire", o.getOpt("pool-expire"));
|
507
|
+
sh1.setInitParameter("version", mAppVersion);
|
508
|
+
|
509
|
+
cx1.addServlet(sh1, "/*");
|
510
|
+
}
|
511
|
+
|
512
|
+
for (String app: mBackends.keySet()) {
|
513
|
+
Log.info("Starting app `" + app + "'");
|
514
|
+
|
515
|
+
String docRoot = mBackends.get(app);
|
516
|
+
|
517
|
+
String golfPath = "/" + app;
|
518
|
+
String golfRoot = docRoot;
|
519
|
+
|
520
|
+
WebAppContext wac = new WebAppContext();
|
521
|
+
wac.setContextPath(golfPath);
|
522
|
+
wac.setWar(docRoot);
|
523
|
+
|
524
|
+
handlers.addHandler(wac);
|
525
|
+
}
|
526
|
+
|
527
|
+
handlers.addHandler(contexts);
|
528
|
+
handlers.addHandler(new DefaultHandler());
|
529
|
+
//handlers.addHandler(new RequestLogHandler());
|
530
|
+
|
531
|
+
server.setHandler(handlers);
|
532
|
+
server.setStopAtShutdown(true);
|
533
|
+
server.setSendServerVersion(true);
|
534
|
+
|
535
|
+
server.start();
|
536
|
+
server.join();
|
537
|
+
}
|
538
|
+
|
539
|
+
public void doProxyAnt(String name, String host, int port, String path)
|
540
|
+
throws Exception {
|
541
|
+
try {
|
542
|
+
System.err.print("Building proxy warfile.................");
|
543
|
+
|
544
|
+
File dep = cacheResourceFile("depends.zip", ".zip", null);
|
545
|
+
File cls = cacheResourceFile("classes.zip", ".zip", null);
|
546
|
+
File web = getTmpFile(".xml");
|
547
|
+
File ant = getTmpFile(".xml", new File("."));
|
548
|
+
|
549
|
+
String webStr = getResourceAsString("proxy_web.xml");
|
550
|
+
String antStr = getResourceAsString("proxy_project.xml");
|
551
|
+
|
552
|
+
String dname = "HTTP proxy servlet ("+host+":"+port+"/"+path+")";
|
553
|
+
String ddesc = "HTTP proxy servlet ("+host+":"+port+"/"+path+")";
|
554
|
+
|
555
|
+
// set init parameters in the web.xml file
|
556
|
+
webStr = webStr.replaceAll("__DISPLAYNAME__", dname)
|
557
|
+
.replaceAll("__DESCRIPTION__", ddesc)
|
558
|
+
.replaceAll("__PROXY_HOST__", host)
|
559
|
+
.replaceAll("__PROXY_PORT__", String.valueOf(port))
|
560
|
+
.replaceAll("__PROXY_PATH__", path)
|
561
|
+
.replaceAll("__PROXY_QUERY__", o.getOpt("proxyparams"))
|
562
|
+
.replaceAll("__MAX_FILE_UPLOAD_SIZE__",
|
563
|
+
o.getOpt("proxymaxupload"));
|
564
|
+
|
565
|
+
// setup the ant build file
|
566
|
+
antStr = antStr.replaceAll("__OUTFILE__", name + ".war")
|
567
|
+
.replaceAll("__WEB.XML__", web.getAbsolutePath())
|
568
|
+
.replaceAll("__DEPENDENCIES.ZIP__", dep.getAbsolutePath())
|
569
|
+
.replaceAll("__CLASSES.ZIP__", cls.getAbsolutePath());
|
570
|
+
|
571
|
+
cacheStringFile(webStr, "", web);
|
572
|
+
cacheStringFile(antStr, "", ant);
|
573
|
+
|
574
|
+
Project project = new Project();
|
575
|
+
project.init();
|
576
|
+
project.setUserProperty("ant.file" , ant.getAbsolutePath());
|
577
|
+
ProjectHelper.configureProject(project, ant);
|
578
|
+
project.executeTarget("war");
|
579
|
+
|
580
|
+
System.err.println("done.");
|
581
|
+
} catch (Exception e) {
|
582
|
+
System.err.println("fail.");
|
583
|
+
throw new Exception(e);
|
584
|
+
}
|
585
|
+
}
|
586
|
+
|
587
|
+
public void doStaticAnt() throws Exception {
|
588
|
+
try {
|
589
|
+
System.err.print("Building static............................");
|
590
|
+
|
591
|
+
File res = cacheResourceFile("resources.zip", ".zip", null);
|
592
|
+
File ant = getTmpFile(".xml", new File("."));
|
593
|
+
|
594
|
+
String antStr = getResourceAsString("static_project.xml");
|
595
|
+
|
596
|
+
// setup the ant build file
|
597
|
+
antStr = antStr.replaceAll("__OUTFILE__", o.getOpt("static"))
|
598
|
+
.replaceAll("__RESOURCES.ZIP__", res.getAbsolutePath())
|
599
|
+
.replaceAll("__APPROOT__",
|
600
|
+
o.getOpt("approot|proxypath"));
|
601
|
+
|
602
|
+
cacheStringFile(antStr, "", ant);
|
603
|
+
|
604
|
+
Project project = new Project();
|
605
|
+
project.init();
|
606
|
+
project.setUserProperty("ant.file" , ant.getAbsolutePath());
|
607
|
+
ProjectHelper.configureProject(project, ant);
|
608
|
+
project.executeTarget("static");
|
609
|
+
|
610
|
+
System.err.println("done.");
|
611
|
+
} catch (Exception e) {
|
612
|
+
System.err.println("fail.");
|
613
|
+
throw new Exception(e);
|
614
|
+
}
|
615
|
+
}
|
616
|
+
|
617
|
+
public void doAnt() throws Exception {
|
618
|
+
try {
|
619
|
+
System.err.print("Building warfile...........................");
|
620
|
+
|
621
|
+
File dep = cacheResourceFile("depends.zip", ".zip", null);
|
622
|
+
File res = cacheResourceFile("resources.zip", ".zip", null);
|
623
|
+
File cls = cacheResourceFile("classes.zip", ".zip", null);
|
624
|
+
File web = getTmpFile(".xml");
|
625
|
+
File ant = getTmpFile(".xml", new File("."));
|
626
|
+
|
627
|
+
String webStr = getResourceAsString("web.xml");
|
628
|
+
String antStr = getResourceAsString("project.xml");
|
629
|
+
|
630
|
+
// set init parameters in the web.xml file
|
631
|
+
webStr = webStr.replaceAll("__DISPLAYNAME__", o.getOpt("displayname"))
|
632
|
+
.replaceAll("__DESCRIPTION__", o.getOpt("description"))
|
633
|
+
.replaceAll("__POOLSIZE__", o.getOpt("pool-size"))
|
634
|
+
.replaceAll("__POOLEXPIRE__", o.getOpt("pool-expire"))
|
635
|
+
.replaceAll("__GOLF_VERSION__", mAppVersion)
|
636
|
+
.replaceAll("__DEVMODE__", o.getOpt("devmode"));
|
637
|
+
|
638
|
+
// setup the ant build file
|
639
|
+
antStr = antStr.replaceAll("__OUTFILE__", mAppName + ".war")
|
640
|
+
.replaceAll("__WEB.XML__", web.getAbsolutePath())
|
641
|
+
.replaceAll("__RESOURCES.ZIP__", res.getAbsolutePath())
|
642
|
+
.replaceAll("__APPROOT__",
|
643
|
+
o.getOpt("approot|proxypath"))
|
644
|
+
.replaceAll("__DEPENDENCIES.ZIP__", dep.getAbsolutePath())
|
645
|
+
.replaceAll("__CLASSES.ZIP__", cls.getAbsolutePath());
|
646
|
+
|
647
|
+
cacheStringFile(webStr, "", web);
|
648
|
+
cacheStringFile(antStr, "", ant);
|
649
|
+
|
650
|
+
Project project = new Project();
|
651
|
+
project.init();
|
652
|
+
project.setUserProperty("ant.file" , ant.getAbsolutePath());
|
653
|
+
ProjectHelper.configureProject(project, ant);
|
654
|
+
project.executeTarget("war");
|
655
|
+
|
656
|
+
System.err.println("done.");
|
657
|
+
} catch (Exception e) {
|
658
|
+
System.err.println("fail.");
|
659
|
+
throw new Exception(e);
|
660
|
+
}
|
661
|
+
}
|
662
|
+
|
663
|
+
public static File getTmpFile(String ext) throws IOException {
|
664
|
+
File f = File.createTempFile("golf_deploy.", ext);
|
665
|
+
f.deleteOnExit();
|
666
|
+
return f;
|
667
|
+
}
|
668
|
+
|
669
|
+
public static File getTmpFile(String ext, File dir) throws IOException {
|
670
|
+
File f = File.createTempFile("golf_deploy.", ext, dir);
|
671
|
+
f.deleteOnExit();
|
672
|
+
return f;
|
673
|
+
}
|
674
|
+
|
675
|
+
public String getResourceAsString(String name) throws IOException {
|
676
|
+
JavaResource res = new JavaResource(name, null);
|
677
|
+
BufferedReader in =
|
678
|
+
new BufferedReader(new InputStreamReader(res.getInputStream()));
|
679
|
+
StringBuilder s = new StringBuilder();
|
680
|
+
|
681
|
+
String tmp;
|
682
|
+
while((tmp = in.readLine()) != null)
|
683
|
+
s.append(tmp).append("\n");
|
684
|
+
|
685
|
+
return s.toString();
|
686
|
+
}
|
687
|
+
|
688
|
+
public File cacheResourceFile(String name, String ext, File f)
|
689
|
+
throws IOException {
|
690
|
+
name = name.replaceFirst("^/+", "");
|
691
|
+
byte[] b = new byte[BUF_SIZE];
|
692
|
+
|
693
|
+
if (f == null)
|
694
|
+
f = getTmpFile(ext);
|
695
|
+
|
696
|
+
BufferedInputStream in = new BufferedInputStream(
|
697
|
+
getClass().getClassLoader().getResourceAsStream(name));
|
698
|
+
BufferedOutputStream out =
|
699
|
+
new BufferedOutputStream(new FileOutputStream(f));
|
700
|
+
|
701
|
+
int nread;
|
702
|
+
while ((nread = in.read(b)) != -1)
|
703
|
+
out.write(b, 0, nread);
|
704
|
+
out.close();
|
705
|
+
|
706
|
+
return f;
|
707
|
+
}
|
708
|
+
|
709
|
+
public static File cacheStringFile(String text, String ext, File f)
|
710
|
+
throws IOException {
|
711
|
+
if (f == null)
|
712
|
+
f = getTmpFile(ext);
|
713
|
+
|
714
|
+
PrintWriter out = new PrintWriter(new FileOutputStream(f));
|
715
|
+
out.print(text);
|
716
|
+
out.close();
|
717
|
+
|
718
|
+
return f;
|
719
|
+
}
|
720
|
+
|
721
|
+
private void cacheStringAws(String str, String key) throws Exception {
|
722
|
+
cacheStringAws(str, key, null);
|
723
|
+
}
|
724
|
+
|
725
|
+
private void cacheStringAws(String str, String key, String type)
|
726
|
+
throws Exception {
|
727
|
+
key = key.replaceFirst("^/+", "");
|
728
|
+
File f = cacheStringFile(str, key.replaceFirst("^.*/", ""), null);
|
729
|
+
cacheFileAws(f, key, type);
|
730
|
+
}
|
731
|
+
|
732
|
+
private void cacheFileAws(File file, String key) throws Exception {
|
733
|
+
cacheFileAws(file, key, null);
|
734
|
+
}
|
735
|
+
|
736
|
+
private void cacheFileAws(File file, String key, String type)
|
737
|
+
throws Exception {
|
738
|
+
key = key.replaceFirst("^/+", "");
|
739
|
+
|
740
|
+
if (key.endsWith(".js") || key.endsWith(".css") || key.endsWith(".html")) {
|
741
|
+
BufferedReader inBr = new BufferedReader(new FileReader(file));
|
742
|
+
StringBuilder sb = new StringBuilder();
|
743
|
+
|
744
|
+
String s;
|
745
|
+
while ((s = inBr.readLine()) != null)
|
746
|
+
sb.append(s).append("\n");
|
747
|
+
|
748
|
+
String src = sb.toString();
|
749
|
+
|
750
|
+
if (key.endsWith(".js"))
|
751
|
+
src = injectCloudfrontUrl(compressJs(src, key));
|
752
|
+
else if (key.endsWith(".css"))
|
753
|
+
src = injectCloudfrontUrl(compressCss(src, key));
|
754
|
+
else if (key.endsWith(".html"))
|
755
|
+
src = injectCloudfrontUrl(src);
|
756
|
+
|
757
|
+
file.delete();
|
758
|
+
|
759
|
+
PrintWriter out = new PrintWriter(new FileWriter(file));
|
760
|
+
out.print(src);
|
761
|
+
out.close();
|
762
|
+
}
|
763
|
+
|
764
|
+
S3Object obj = new S3Object(mBucket, file);
|
765
|
+
obj.setKey(key);
|
766
|
+
if (type == null)
|
767
|
+
obj.setContentType(GolfResource.MimeMapping.lookup(key));
|
768
|
+
else
|
769
|
+
obj.setContentType(type);
|
770
|
+
obj.setAcl(mAcl);
|
771
|
+
mS3svc.putObject(mBucket, obj);
|
772
|
+
}
|
773
|
+
|
774
|
+
private void cacheJarResourcesAws() throws Exception {
|
775
|
+
String[] resources = {
|
776
|
+
JSDETECT_HTML,
|
777
|
+
JQUERY_JS,
|
778
|
+
JQUERY_HIST_JS,
|
779
|
+
JQUERY_GOLF_JS,
|
780
|
+
LOADING_GIF
|
781
|
+
};
|
782
|
+
for (String res : resources)
|
783
|
+
cacheJarResourceAws("/"+res);
|
784
|
+
}
|
785
|
+
|
786
|
+
private void cacheJarResourceAws(String name) throws Exception {
|
787
|
+
File f = cacheResourceFile(name, name.replaceAll("^.*/", ""), null);
|
788
|
+
cacheFileAws(f, name.replaceFirst("^/+", ""));
|
789
|
+
}
|
790
|
+
|
791
|
+
public static void cacheNewDotHtmlFile() throws Exception {
|
792
|
+
String newHtmlStr = getNewDotHtmlString(false);
|
793
|
+
File f = new File(o.getOpt("approot|proxypath"), NEW_HTML);
|
794
|
+
if (f.exists())
|
795
|
+
f.delete();
|
796
|
+
f.deleteOnExit();
|
797
|
+
PrintWriter out = new PrintWriter(new FileWriter(f));
|
798
|
+
out.print(newHtmlStr);
|
799
|
+
out.close();
|
800
|
+
|
801
|
+
newHtmlStr = getNewDotHtmlString(true);
|
802
|
+
f = new File(o.getOpt("approot|proxypath"), NEW_FC_HTML);
|
803
|
+
if (f.exists())
|
804
|
+
f.delete();
|
805
|
+
f.deleteOnExit();
|
806
|
+
out = new PrintWriter(new FileWriter(f));
|
807
|
+
out.print(newHtmlStr);
|
808
|
+
out.close();
|
809
|
+
}
|
810
|
+
|
811
|
+
public static String getNewDotHtmlString(boolean fc) throws Exception {
|
812
|
+
File cwd = new File(o.getOpt("approot|proxypath"));
|
813
|
+
boolean st = o.getOpt("static") != null;
|
814
|
+
|
815
|
+
String newHtmlSrc = st ? NEW_ST_HTML : NEW_HTML;
|
816
|
+
|
817
|
+
GolfResource newHtml = new GolfResource(cwd, newHtmlSrc);
|
818
|
+
GolfResource headHtml = new GolfResource(cwd, HEAD_HTML);
|
819
|
+
GolfResource noscriptHtml =
|
820
|
+
new GolfResource(cwd,
|
821
|
+
(fc ? NOSCRIPT_FC_HTML : (st ? NOSCRIPT_ST_HTML : NOSCRIPT_HTML)));
|
822
|
+
|
823
|
+
if (mNewHtml == null)
|
824
|
+
mNewHtml = newHtml.toString();
|
825
|
+
|
826
|
+
String newStr = mNewHtml;
|
827
|
+
String headStr = headHtml.toString();
|
828
|
+
String noscriptStr = noscriptHtml.toString();
|
829
|
+
|
830
|
+
JSONArray backends = new JSONArray(mBackends.keySet());
|
831
|
+
|
832
|
+
String result = newStr;
|
833
|
+
result = result.replaceFirst("\n *__HEAD_HTML__ *\n *",
|
834
|
+
" custom head section -->\n"+headStr+
|
835
|
+
" <!-- end custom head section ");
|
836
|
+
result = result.replaceFirst("\n *__NOSCRIPT_HTML__ *\n *",
|
837
|
+
" custom noscript section -->\n"+noscriptStr+
|
838
|
+
" <!-- end custom noscript section ");
|
839
|
+
result = result.replaceFirst("__DEVMODE__",
|
840
|
+
Boolean.toString(o.getFlag("devmode")));
|
841
|
+
result = result.replaceFirst("__RESTBACKENDS__", backends.toString());
|
842
|
+
result = result.replaceFirst("__CLOUDFRONTDOMAIN__", o.getOpt("cfdomains"));
|
843
|
+
|
844
|
+
if (st)
|
845
|
+
result = result.replaceAll("\\?path=/*", "");
|
846
|
+
|
847
|
+
return result;
|
848
|
+
}
|
849
|
+
|
850
|
+
public static void cacheComponentsFile() throws Exception {
|
851
|
+
File f = new File(o.getOpt("approot|proxypath"), COMPONENTS_JS);
|
852
|
+
if (f.exists())
|
853
|
+
f.delete();
|
854
|
+
f.deleteOnExit();
|
855
|
+
PrintWriter out = new PrintWriter(new FileWriter(f));
|
856
|
+
out.print(getComponentsString());
|
857
|
+
out.close();
|
858
|
+
}
|
859
|
+
|
860
|
+
private void cacheComponentsAws() throws Exception {
|
861
|
+
cacheStringAws(getComponentsString(), COMPONENTS_JS, "text/javascript");
|
862
|
+
}
|
863
|
+
|
864
|
+
private static String getComponentsString() throws Exception {
|
865
|
+
String ret =
|
866
|
+
"jQuery.golf.components=" + getComponentsJSON(null, null) + ";" +
|
867
|
+
"jQuery.golf.res=" + getResourcesJSON(null, null) + ";" +
|
868
|
+
"jQuery.golf.plugins=" + getScriptsJSON(DIR_MODULES, null) + ";" +
|
869
|
+
"jQuery.golf.scripts=" + getScriptsJSON(DIR_SCRIPTS, null) + ";" +
|
870
|
+
"jQuery.golf.styles=" + getStylesJSON(DIR_STYLES, null) + ";" +
|
871
|
+
"jQuery.golf.setupComponents();";
|
872
|
+
if (o.getOpt("static") != null)
|
873
|
+
ret = ret.replaceAll("\\?path=/*", "");
|
874
|
+
return ret;
|
875
|
+
}
|
876
|
+
|
877
|
+
private static String getResourcesJSON(String path, JSONObject json)
|
878
|
+
throws Exception {
|
879
|
+
boolean isNew = false;
|
880
|
+
|
881
|
+
if (path == null) path = "";
|
882
|
+
if (json == null) {
|
883
|
+
json = new JSONObject();
|
884
|
+
isNew = true;
|
885
|
+
}
|
886
|
+
|
887
|
+
File file = new File(new File(o.getOpt("approot|proxypath")), path);
|
888
|
+
|
889
|
+
if (!file.getName().startsWith(".") || file.getName().equals(".")
|
890
|
+
|| file.getName().equals("..")) {
|
891
|
+
if (file.isFile()) {
|
892
|
+
String keyName = path.replaceFirst("^/+", "");
|
893
|
+
json.put(keyName.replaceFirst("^.*/", ""), "?path=" + keyName);
|
894
|
+
} else if (file.isDirectory()) {
|
895
|
+
JSONObject dir;
|
896
|
+
if (!isNew) {
|
897
|
+
dir = new JSONObject();
|
898
|
+
json.put(file.getName(), dir);
|
899
|
+
} else {
|
900
|
+
dir = json;
|
901
|
+
}
|
902
|
+
for (String f : file.list()) {
|
903
|
+
String ppath = path + "/" + f;
|
904
|
+
getResourcesJSON(path+"/"+f, dir);
|
905
|
+
}
|
906
|
+
}
|
907
|
+
}
|
908
|
+
|
909
|
+
// these are system files that are of no use to a golf app
|
910
|
+
for (String s : new String[] {
|
911
|
+
DIR_COMPONENTS,
|
912
|
+
DIR_SCRIPTS,
|
913
|
+
DIR_STYLES,
|
914
|
+
ERROR_HTML,
|
915
|
+
HEAD_HTML,
|
916
|
+
NEW_HTML,
|
917
|
+
NEW_FC_HTML,
|
918
|
+
NOSCRIPT_FC_HTML,
|
919
|
+
NOSCRIPT_HTML,
|
920
|
+
FORCEPROXY_TXT,
|
921
|
+
FORCECLIENT_TXT,
|
922
|
+
FORCEBOT_TXT,
|
923
|
+
COMPONENTS_JS,
|
924
|
+
CONTROLLER_JS
|
925
|
+
}) json.remove(s);
|
926
|
+
|
927
|
+
return json.toString();
|
928
|
+
}
|
929
|
+
|
930
|
+
private static String getComponentsJSON(String path, JSONObject json)
|
931
|
+
throws Exception {
|
932
|
+
if (path == null) path = "";
|
933
|
+
if (json == null) json = new JSONObject();
|
934
|
+
|
935
|
+
File file =
|
936
|
+
new File(new File(o.getOpt("approot|proxypath"), DIR_COMPONENTS), path);
|
937
|
+
|
938
|
+
if (!file.getName().startsWith(".")) {
|
939
|
+
if (file.isFile()) {
|
940
|
+
if (path.endsWith(".html")) {
|
941
|
+
String cmpName = path.replaceFirst("\\.html$", "");
|
942
|
+
JSONObject cmpJson = processComponent(cmpName);
|
943
|
+
json.put((String) cmpJson.get("name"), cmpJson);
|
944
|
+
}
|
945
|
+
} else if (file.isDirectory() && !file.getName().endsWith(".res")) {
|
946
|
+
for (String f : file.list()) {
|
947
|
+
String ppath = path + "/" + f;
|
948
|
+
getComponentsJSON(path+"/"+f, json);
|
949
|
+
}
|
950
|
+
}
|
951
|
+
}
|
952
|
+
|
953
|
+
return json.toString();
|
954
|
+
}
|
955
|
+
|
956
|
+
private static String getScriptsJSON(String path, JSONObject json)
|
957
|
+
throws Exception {
|
958
|
+
if (path == null) path = "";
|
959
|
+
if (json == null) json = new JSONObject();
|
960
|
+
|
961
|
+
File file = new File(o.getOpt("approot|proxypath"), path);
|
962
|
+
|
963
|
+
if (!file.getName().startsWith(".")) {
|
964
|
+
if (file.isFile()) {
|
965
|
+
if (path.endsWith(".js")) {
|
966
|
+
String cmpName = path.replaceFirst("\\.js$", "");
|
967
|
+
String keyName =
|
968
|
+
cmpName.replaceFirst("^[a-z]+/+", "");
|
969
|
+
json.put(keyName, processScript(cmpName).put("name", keyName));
|
970
|
+
}
|
971
|
+
} else if (file.isDirectory()) {
|
972
|
+
for (String f : file.list()) {
|
973
|
+
String ppath = path + "/" + f;
|
974
|
+
getScriptsJSON(path+"/"+f, json);
|
975
|
+
}
|
976
|
+
}
|
977
|
+
}
|
978
|
+
|
979
|
+
return json.toString();
|
980
|
+
}
|
981
|
+
|
982
|
+
private static String getStylesJSON(String path, JSONObject json)
|
983
|
+
throws Exception {
|
984
|
+
if (path == null) path = "";
|
985
|
+
if (json == null) json = new JSONObject();
|
986
|
+
|
987
|
+
File file = new File(o.getOpt("approot|proxypath"), path);
|
988
|
+
|
989
|
+
if (!file.getName().startsWith(".")) {
|
990
|
+
if (file.isFile()) {
|
991
|
+
if (path.endsWith(".css")) {
|
992
|
+
String cmpName = path.replaceFirst("\\.css$", "");
|
993
|
+
String keyName =
|
994
|
+
cmpName.replaceFirst("^[a-z]+/+", "").replace("/", ".");
|
995
|
+
json.put(keyName, processStyle(cmpName).put("name", keyName));
|
996
|
+
}
|
997
|
+
} else if (file.isDirectory()) {
|
998
|
+
for (String f : file.list()) {
|
999
|
+
String ppath = path + "/" + f;
|
1000
|
+
getStylesJSON(path+"/"+f, json);
|
1001
|
+
}
|
1002
|
+
}
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
return json.toString();
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
public static JSONObject processComponent(String name) throws Exception {
|
1009
|
+
name = name.replaceFirst("^/+", "");
|
1010
|
+
String shortName = name.replaceFirst("(^|/)[^/]+/([^/]+)$", "$1$2");
|
1011
|
+
String className = shortName.replace('/', '-');
|
1012
|
+
String classPath = shortName.replace('/', '.');
|
1013
|
+
File cwd = new File(o.getOpt("approot|proxypath"), DIR_COMPONENTS);
|
1014
|
+
|
1015
|
+
String html = name + ".html";
|
1016
|
+
String res = name + ".res";
|
1017
|
+
|
1018
|
+
GolfResource htmlRes = new GolfResource(cwd, html);
|
1019
|
+
File resDir = new File(cwd, res);
|
1020
|
+
|
1021
|
+
JSONObject resObj =
|
1022
|
+
processComponentRes(resDir, cwd, resDir, null);
|
1023
|
+
|
1024
|
+
String resUriPath = "?path=components/"+getRelativePath(resDir, cwd);
|
1025
|
+
|
1026
|
+
String htmlStr = htmlRes.toString().replaceAll("\\?resource=", resUriPath);
|
1027
|
+
|
1028
|
+
String pat1 = "</script>";
|
1029
|
+
String pat2 = "<script +([^>]* +)*type *= *\"text/golf\"( [^>]*)*>";
|
1030
|
+
|
1031
|
+
String cmpJs1 = Pattern
|
1032
|
+
.compile("^(.*"+pat2+").*$", Pattern.DOTALL)
|
1033
|
+
.matcher(htmlStr)
|
1034
|
+
.replaceFirst("$1");
|
1035
|
+
|
1036
|
+
String cmpJs2 = Pattern
|
1037
|
+
.compile(pat1+".*$", Pattern.DOTALL)
|
1038
|
+
.matcher(
|
1039
|
+
Pattern
|
1040
|
+
.compile("^.*"+pat2, Pattern.DOTALL)
|
1041
|
+
.matcher(htmlStr)
|
1042
|
+
.replaceFirst(""))
|
1043
|
+
.replaceFirst("");
|
1044
|
+
|
1045
|
+
String cmpJs3 = Pattern
|
1046
|
+
.compile("^.*("+pat1+".*)$", Pattern.DOTALL)
|
1047
|
+
.matcher(
|
1048
|
+
Pattern
|
1049
|
+
.compile("^.*"+pat2, Pattern.DOTALL)
|
1050
|
+
.matcher(htmlStr)
|
1051
|
+
.replaceFirst(""))
|
1052
|
+
.replaceFirst("$1");
|
1053
|
+
|
1054
|
+
File jsFile = cacheStringFile(cmpJs2, "js", null);
|
1055
|
+
cmpJs2 = processComponentJs(cmpJs2, jsFile.getCanonicalPath());
|
1056
|
+
|
1057
|
+
htmlStr = cmpJs1 + "\n" + cmpJs2 + "\n" + cmpJs3;
|
1058
|
+
|
1059
|
+
JSONObject json = new JSONObject()
|
1060
|
+
.put("name", classPath)
|
1061
|
+
.put("html", htmlStr)
|
1062
|
+
.put("res", resObj);
|
1063
|
+
|
1064
|
+
return json;
|
1065
|
+
}
|
1066
|
+
|
1067
|
+
public static JSONObject processScript(String name) throws Exception {
|
1068
|
+
String dir = name.replaceAll("/.*$", "");
|
1069
|
+
name = name.replaceFirst("^[a-z]+/+", "");
|
1070
|
+
|
1071
|
+
File cwd = new File(o.getOpt("approot|proxypath"), dir);
|
1072
|
+
String js = name + ".js";
|
1073
|
+
GolfResource jsRes = new GolfResource(cwd, js);
|
1074
|
+
String jsStr = processComponentJs(jsRes.toString(), (new File(cwd, js)).getCanonicalPath());
|
1075
|
+
JSONObject json = new JSONObject().put("js", jsStr);
|
1076
|
+
|
1077
|
+
return json;
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
public static JSONObject processStyle(String name) throws Exception {
|
1081
|
+
String dir = name.replaceAll("/.*$", "");
|
1082
|
+
name = name.replaceFirst("^[a-z]+/+", "");
|
1083
|
+
|
1084
|
+
File cwd = new File(o.getOpt("approot|proxypath"), dir);
|
1085
|
+
// FIXME: only in non-devmode should css be messed with like this
|
1086
|
+
//String css = (new GolfResource(cwd, name+".css")).toString()
|
1087
|
+
// .replaceAll(" *\n *", " ");
|
1088
|
+
String css = (new GolfResource(cwd, name+".css")).toString();
|
1089
|
+
JSONObject json = new JSONObject().put("css", css);
|
1090
|
+
|
1091
|
+
return json;
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
public static String injectCloudfrontUrl(String text) {
|
1095
|
+
String result = text;
|
1096
|
+
if (mCfDomains.size() > 0)
|
1097
|
+
while (! result.equals(result = result.replaceFirst("\\?path=/*", mCfDomains.next())));
|
1098
|
+
return result;
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
public static JSONObject processComponentRes(File f, File uriBase,
|
1102
|
+
File refBase, JSONObject res) throws URISyntaxException, JSONException {
|
1103
|
+
boolean isNew = false;
|
1104
|
+
|
1105
|
+
if (!f.exists() || f.getName().startsWith("."))
|
1106
|
+
return null;
|
1107
|
+
|
1108
|
+
if (res == null) {
|
1109
|
+
res = new JSONObject();
|
1110
|
+
isNew = true;
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
String ref = getRelativePath(f, refBase);
|
1114
|
+
|
1115
|
+
if (f.isDirectory()) {
|
1116
|
+
JSONObject dir;
|
1117
|
+
if (!isNew) {
|
1118
|
+
dir = new JSONObject();
|
1119
|
+
res.put(ref.replaceFirst("/+$", ""), dir);
|
1120
|
+
} else {
|
1121
|
+
dir = res;
|
1122
|
+
}
|
1123
|
+
for (String s : f.list())
|
1124
|
+
processComponentRes(new File(f, s), uriBase, refBase, dir);
|
1125
|
+
} else {
|
1126
|
+
String rel = getRelativePath(f, uriBase);
|
1127
|
+
res.put(ref.replaceFirst("^.*/", ""), "?path=components/"+rel);
|
1128
|
+
}
|
1129
|
+
return res;
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
public static String processComponentCss(String text, String className,
|
1133
|
+
String fileName) {
|
1134
|
+
String result = text;
|
1135
|
+
|
1136
|
+
// remove newlines
|
1137
|
+
result = result.replaceAll("[\\r\\n\\s]+", " ");
|
1138
|
+
// remove comments
|
1139
|
+
result = result.replaceAll("/\\*.*\\*/", "");
|
1140
|
+
result = result.trim();
|
1141
|
+
|
1142
|
+
if (!o.getFlag("devmode"))
|
1143
|
+
result = compressCss(result, fileName);
|
1144
|
+
|
1145
|
+
return result;
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
public static String compressCss(String in, String filename) {
|
1149
|
+
if (!o.getFlag("compress-css"))
|
1150
|
+
return in;
|
1151
|
+
|
1152
|
+
String result = in;
|
1153
|
+
try {
|
1154
|
+
CssCompressor css = new CssCompressor(new StringReader(in));
|
1155
|
+
|
1156
|
+
StringWriter out = new StringWriter();
|
1157
|
+
css.compress(out, -1);
|
1158
|
+
result = out.toString();
|
1159
|
+
} catch (Exception e) {
|
1160
|
+
System.err.println("golf: "+filename+" not compressed: "+e.toString());
|
1161
|
+
}
|
1162
|
+
return result;
|
1163
|
+
}
|
1164
|
+
|
1165
|
+
public static String processComponentJs(String text, String filename)
|
1166
|
+
throws Exception {
|
1167
|
+
String result = text;
|
1168
|
+
|
1169
|
+
if (text.startsWith("#!")) {
|
1170
|
+
result = "";
|
1171
|
+
|
1172
|
+
ArrayList<String> shbang = parseAsShell(
|
1173
|
+
text.substring(0, text.indexOf("\n"))
|
1174
|
+
.replaceFirst("^#![\\s]*", "")
|
1175
|
+
.replaceFirst("[\\s]*$", " ")
|
1176
|
+
);
|
1177
|
+
|
1178
|
+
shbang.add(filename);
|
1179
|
+
|
1180
|
+
Process p =
|
1181
|
+
Runtime.getRuntime().exec(shbang.toArray(new String[shbang.size()]));
|
1182
|
+
|
1183
|
+
int exitVal = p.waitFor();
|
1184
|
+
|
1185
|
+
BufferedReader br = new BufferedReader(new InputStreamReader(
|
1186
|
+
(exitVal == 0 ? p.getInputStream() : p.getErrorStream())));
|
1187
|
+
|
1188
|
+
while ((text = br.readLine()) != null)
|
1189
|
+
result += text + "\n";
|
1190
|
+
|
1191
|
+
if (exitVal != 0)
|
1192
|
+
throw new Exception(result);
|
1193
|
+
}
|
1194
|
+
|
1195
|
+
if (!o.getFlag("devmode"))
|
1196
|
+
result = compressJs(result, filename);
|
1197
|
+
|
1198
|
+
return result;
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
private static String compressJs(String in, String filename) {
|
1202
|
+
if (!o.getFlag("compress-js"))
|
1203
|
+
return in;
|
1204
|
+
|
1205
|
+
String result = in;
|
1206
|
+
|
1207
|
+
try {
|
1208
|
+
final String cn = filename;
|
1209
|
+
|
1210
|
+
ErrorReporter errz = new ErrorReporter() {
|
1211
|
+
public void warning(String message, String sourceName,
|
1212
|
+
int line, String lineSource, int lineOffset) {
|
1213
|
+
if (line < 0) {
|
1214
|
+
System.err.println(cn+": warning:\n"+message+"\n");
|
1215
|
+
} else {
|
1216
|
+
System.err.println(cn+": warning:\n"+line+':'+lineOffset+
|
1217
|
+
':'+message+"\n");
|
1218
|
+
}
|
1219
|
+
}
|
1220
|
+
public void error(String message, String sourceName,
|
1221
|
+
int line, String lineSource, int lineOffset) {
|
1222
|
+
if (line < 0) {
|
1223
|
+
System.err.println(cn+": error:\n"+message+"\n");
|
1224
|
+
} else {
|
1225
|
+
System.err.println(cn+": error:\n"+line+':'+lineOffset+
|
1226
|
+
':'+message+"\n");
|
1227
|
+
}
|
1228
|
+
}
|
1229
|
+
public EvaluatorException runtimeError(String message,
|
1230
|
+
String sourceName, int line, String lineSource, int lineOffset) {
|
1231
|
+
error(message, sourceName, line, lineSource, lineOffset);
|
1232
|
+
return new EvaluatorException(message);
|
1233
|
+
}
|
1234
|
+
};
|
1235
|
+
|
1236
|
+
JavaScriptCompressor js =
|
1237
|
+
new JavaScriptCompressor(new StringReader(in), errz);
|
1238
|
+
|
1239
|
+
StringWriter out = new StringWriter();
|
1240
|
+
js.compress(out, -1, false, false, false, true);
|
1241
|
+
result = out.toString().replace("\n", "\\n");
|
1242
|
+
} catch (Exception e) {
|
1243
|
+
System.err.println("golf: "+filename+" not compressed: "+e.toString());
|
1244
|
+
}
|
1245
|
+
return result;
|
1246
|
+
}
|
1247
|
+
|
1248
|
+
private void cacheResourcesAws(File file, String path) throws Exception {
|
1249
|
+
if (path.startsWith("/.") ||
|
1250
|
+
path.equals("/"+HEAD_HTML) ||
|
1251
|
+
path.equals("/"+NOSCRIPT_HTML))
|
1252
|
+
return;
|
1253
|
+
|
1254
|
+
if (file.isFile()) {
|
1255
|
+
cacheFileAws(file, path);
|
1256
|
+
} else if (file.isDirectory()) {
|
1257
|
+
for (String f : file.list()) {
|
1258
|
+
String ppath = path + (path.endsWith("/") ? f : "/" + f);
|
1259
|
+
cacheResourcesAws(new File(file, f), ppath);
|
1260
|
+
}
|
1261
|
+
}
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
private static String getRelativePath(File f, File base)
|
1265
|
+
throws URISyntaxException {
|
1266
|
+
URI u1 = new URI(base.toURI().toString());
|
1267
|
+
URI u2 = new URI(f.toURI().toString());
|
1268
|
+
return u1.relativize(u2).toString();
|
1269
|
+
}
|
1270
|
+
|
1271
|
+
public static ArrayList<String> parseAsShell(String line) throws Exception {
|
1272
|
+
ArrayList<String> ret = new ArrayList<String>();
|
1273
|
+
|
1274
|
+
StreamTokenizer st = new StreamTokenizer(new StringReader(line));
|
1275
|
+
st.resetSyntax();
|
1276
|
+
st.wordChars(33, 126);
|
1277
|
+
st.whitespaceChars(' ', ' ');
|
1278
|
+
st.quoteChar('"');
|
1279
|
+
st.quoteChar('\'');
|
1280
|
+
|
1281
|
+
while (st.nextToken() != StreamTokenizer.TT_EOF)
|
1282
|
+
ret.add(st.sval);
|
1283
|
+
|
1284
|
+
return ret;
|
1285
|
+
}
|
1286
|
+
|
1287
|
+
private String randName(String base) {
|
1288
|
+
String result =
|
1289
|
+
base + "-" + (new UID()).toString().replaceFirst("^.*:([^:]+):.*$", "$1");
|
1290
|
+
return result;
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
private void usage(String error) {
|
1294
|
+
if (error != null)
|
1295
|
+
System.err.println("golf: "+error);
|
1296
|
+
|
1297
|
+
o.printUsage();
|
1298
|
+
}
|
1299
|
+
}
|