1 | |
package org.apache.maven.plugin.gpg; |
2 | |
|
3 | |
import java.util.ArrayList; |
4 | |
import java.util.Iterator; |
5 | |
import java.util.List; |
6 | |
|
7 | |
import org.apache.maven.plugin.AbstractMojo; |
8 | |
import org.apache.maven.plugin.MojoExecutionException; |
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
@SuppressWarnings( "all" ) |
20 | 0 | public class HelpMojo |
21 | |
extends AbstractMojo |
22 | |
{ |
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
private boolean detail; |
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
private java.lang.String goal; |
36 | |
|
37 | |
|
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
private int lineLength; |
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | |
|
48 | |
|
49 | |
private int indentSize; |
50 | |
|
51 | |
|
52 | |
|
53 | |
public void execute() |
54 | |
throws MojoExecutionException |
55 | |
{ |
56 | 0 | if ( lineLength <= 0 ) |
57 | |
{ |
58 | 0 | getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." ); |
59 | 0 | lineLength = 80; |
60 | |
} |
61 | 0 | if ( indentSize <= 0 ) |
62 | |
{ |
63 | 0 | getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." ); |
64 | 0 | indentSize = 2; |
65 | |
} |
66 | |
|
67 | 0 | StringBuffer sb = new StringBuffer(); |
68 | |
|
69 | 0 | append( sb, "org.apache.maven.plugins:maven-gpg-plugin:1.4", 0 ); |
70 | 0 | append( sb, "", 0 ); |
71 | |
|
72 | 0 | append( sb, "Maven GPG Plugin", 0 ); |
73 | 0 | append( sb, "Signs the project artifacts with GnuPG.", 1 ); |
74 | 0 | append( sb, "", 0 ); |
75 | |
|
76 | 0 | if ( goal == null || goal.length() <= 0 ) |
77 | |
{ |
78 | 0 | append( sb, "This plugin has 3 goals:", 0 ); |
79 | 0 | append( sb, "", 0 ); |
80 | |
} |
81 | |
|
82 | 0 | if ( goal == null || goal.length() <= 0 || "help".equals( goal ) ) |
83 | |
{ |
84 | 0 | append( sb, "gpg:help", 0 ); |
85 | 0 | append( sb, "Display help information on maven-gpg-plugin.\nCall\n\u00a0\u00a0mvn\u00a0gpg:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 ); |
86 | 0 | append( sb, "", 0 ); |
87 | 0 | if ( detail ) |
88 | |
{ |
89 | 0 | append( sb, "Available parameters:", 1 ); |
90 | 0 | append( sb, "", 0 ); |
91 | |
|
92 | 0 | append( sb, "detail (Default: false)", 2 ); |
93 | 0 | append( sb, "If true, display all settable properties for each goal.", 3 ); |
94 | 0 | append( sb, "Expression: ${detail}", 3 ); |
95 | 0 | append( sb, "", 0 ); |
96 | |
|
97 | 0 | append( sb, "goal", 2 ); |
98 | 0 | append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 ); |
99 | 0 | append( sb, "Expression: ${goal}", 3 ); |
100 | 0 | append( sb, "", 0 ); |
101 | |
|
102 | 0 | append( sb, "indentSize (Default: 2)", 2 ); |
103 | 0 | append( sb, "The number of spaces per indentation level, should be positive.", 3 ); |
104 | 0 | append( sb, "Expression: ${indentSize}", 3 ); |
105 | 0 | append( sb, "", 0 ); |
106 | |
|
107 | 0 | append( sb, "lineLength (Default: 80)", 2 ); |
108 | 0 | append( sb, "The maximum length of a display line, should be positive.", 3 ); |
109 | 0 | append( sb, "Expression: ${lineLength}", 3 ); |
110 | 0 | append( sb, "", 0 ); |
111 | |
} |
112 | |
} |
113 | |
|
114 | 0 | if ( goal == null || goal.length() <= 0 || "sign".equals( goal ) ) |
115 | |
{ |
116 | 0 | append( sb, "gpg:sign", 0 ); |
117 | 0 | append( sb, "Sign project artifact, the POM, and attached artifacts with GnuPG for deployment.", 1 ); |
118 | 0 | append( sb, "", 0 ); |
119 | 0 | if ( detail ) |
120 | |
{ |
121 | 0 | append( sb, "Available parameters:", 1 ); |
122 | 0 | append( sb, "", 0 ); |
123 | |
|
124 | 0 | append( sb, "ascDirectory (Default: ${project.build.directory}/gpg)", 2 ); |
125 | 0 | append( sb, "The directory where to store signature files.", 3 ); |
126 | 0 | append( sb, "", 0 ); |
127 | |
|
128 | 0 | append( sb, "defaultKeyring (Default: true)", 2 ); |
129 | 0 | append( sb, "Whether to add the default keyrings from gpg\'s home directory to the list of used keyrings.", 3 ); |
130 | 0 | append( sb, "Expression: ${gpg.defaultKeyring}", 3 ); |
131 | 0 | append( sb, "", 0 ); |
132 | |
|
133 | 0 | append( sb, "excludes", 2 ); |
134 | 0 | append( sb, "A list of files to exclude from being signed. Can contain Ant-style wildcards and double wildcards. The default excludes are **/*.md5 **/*.sha1 **/*.asc.", 3 ); |
135 | 0 | append( sb, "", 0 ); |
136 | |
|
137 | 0 | append( sb, "executable", 2 ); |
138 | 0 | append( sb, "The path to the GnuPG executable to use for artifact signing. Defaults to either \'gpg\' or \'gpg.exe\' depending on the operating system.", 3 ); |
139 | 0 | append( sb, "Expression: ${gpg.executable}", 3 ); |
140 | 0 | append( sb, "", 0 ); |
141 | |
|
142 | 0 | append( sb, "homedir", 2 ); |
143 | 0 | append( sb, "The directory from which gpg will load keyrings. If not specified, gpg will use the value configured for its installation, e.g. ~/.gnupg or %APPDATA%/gnupg.", 3 ); |
144 | 0 | append( sb, "Expression: ${gpg.homedir}", 3 ); |
145 | 0 | append( sb, "", 0 ); |
146 | |
|
147 | 0 | append( sb, "keyname", 2 ); |
148 | 0 | append( sb, "The \'name\' of the key to sign with. Passed to gpg as --local-user.", 3 ); |
149 | 0 | append( sb, "Expression: ${gpg.keyname}", 3 ); |
150 | 0 | append( sb, "", 0 ); |
151 | |
|
152 | 0 | append( sb, "passphrase", 2 ); |
153 | 0 | append( sb, "The passphrase to use when signing.", 3 ); |
154 | 0 | append( sb, "Expression: ${gpg.passphrase}", 3 ); |
155 | 0 | append( sb, "", 0 ); |
156 | |
|
157 | 0 | append( sb, "publicKeyring", 2 ); |
158 | 0 | append( sb, "The path to a public keyring to add to the list of keyrings. By default, only the pubring.gpg from gpg\'s home directory is considered. Use this option (and defaultKeyring if required) to use a different public key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 ); |
159 | 0 | append( sb, "Expression: ${gpg.publicKeyring}", 3 ); |
160 | 0 | append( sb, "", 0 ); |
161 | |
|
162 | 0 | append( sb, "secretKeyring", 2 ); |
163 | 0 | append( sb, "The path to a secret keyring to add to the list of keyrings. By default, only the secring.gpg from gpg\'s home directory is considered. Use this option (in combination with publicKeyring and defaultKeyring if required) to use a different secret key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 ); |
164 | 0 | append( sb, "Expression: ${gpg.secretKeyring}", 3 ); |
165 | 0 | append( sb, "", 0 ); |
166 | |
|
167 | 0 | append( sb, "skip (Default: false)", 2 ); |
168 | 0 | append( sb, "Skip doing the gpg signing.", 3 ); |
169 | 0 | append( sb, "Expression: ${gpg.skip}", 3 ); |
170 | 0 | append( sb, "", 0 ); |
171 | |
|
172 | 0 | append( sb, "useAgent (Default: false)", 2 ); |
173 | 0 | append( sb, "Passes --use-agent or --no-use-agent to gpg. If using an agent, the passphrase is optional as the agent will provide it. For gpg2, specify true as --no-use-agent was removed in gpg2 and doesn\'t ask for a passphrase anymore.", 3 ); |
174 | 0 | append( sb, "Expression: ${gpg.useagent}", 3 ); |
175 | 0 | append( sb, "", 0 ); |
176 | |
} |
177 | |
} |
178 | |
|
179 | 0 | if ( goal == null || goal.length() <= 0 || "sign-and-deploy-file".equals( goal ) ) |
180 | |
{ |
181 | 0 | append( sb, "gpg:sign-and-deploy-file", 0 ); |
182 | 0 | append( sb, "Signs artifacts and installs the artifact in the remote repository.", 1 ); |
183 | 0 | append( sb, "", 0 ); |
184 | 0 | if ( detail ) |
185 | |
{ |
186 | 0 | append( sb, "Available parameters:", 1 ); |
187 | 0 | append( sb, "", 0 ); |
188 | |
|
189 | 0 | append( sb, "artifactId", 2 ); |
190 | 0 | append( sb, "ArtifactId of the artifact to be deployed. Retrieved from POM file if specified.", 3 ); |
191 | 0 | append( sb, "Expression: ${artifactId}", 3 ); |
192 | 0 | append( sb, "", 0 ); |
193 | |
|
194 | 0 | append( sb, "ascDirectory", 2 ); |
195 | 0 | append( sb, "The directory where to store signature files.", 3 ); |
196 | 0 | append( sb, "Expression: ${gpg.ascDirectory}", 3 ); |
197 | 0 | append( sb, "", 0 ); |
198 | |
|
199 | 0 | append( sb, "classifier", 2 ); |
200 | 0 | append( sb, "Add classifier to the artifact", 3 ); |
201 | 0 | append( sb, "Expression: ${classifier}", 3 ); |
202 | 0 | append( sb, "", 0 ); |
203 | |
|
204 | 0 | append( sb, "classifiers", 2 ); |
205 | 0 | append( sb, "A comma separated list of classifiers for each of the extra side artifacts to deploy. If there is a mis-match in the number of entries in files or types, then an error will be raised.", 3 ); |
206 | 0 | append( sb, "Expression: ${classifiers}", 3 ); |
207 | 0 | append( sb, "", 0 ); |
208 | |
|
209 | 0 | append( sb, "defaultKeyring (Default: true)", 2 ); |
210 | 0 | append( sb, "Whether to add the default keyrings from gpg\'s home directory to the list of used keyrings.", 3 ); |
211 | 0 | append( sb, "Expression: ${gpg.defaultKeyring}", 3 ); |
212 | 0 | append( sb, "", 0 ); |
213 | |
|
214 | 0 | append( sb, "description", 2 ); |
215 | 0 | append( sb, "Description passed to a generated POM file (in case of generatePom=true).", 3 ); |
216 | 0 | append( sb, "Expression: ${generatePom.description}", 3 ); |
217 | 0 | append( sb, "", 0 ); |
218 | |
|
219 | 0 | append( sb, "executable", 2 ); |
220 | 0 | append( sb, "The path to the GnuPG executable to use for artifact signing. Defaults to either \'gpg\' or \'gpg.exe\' depending on the operating system.", 3 ); |
221 | 0 | append( sb, "Expression: ${gpg.executable}", 3 ); |
222 | 0 | append( sb, "", 0 ); |
223 | |
|
224 | 0 | append( sb, "file", 2 ); |
225 | 0 | append( sb, "File to be deployed.", 3 ); |
226 | 0 | append( sb, "Required: Yes", 3 ); |
227 | 0 | append( sb, "Expression: ${file}", 3 ); |
228 | 0 | append( sb, "", 0 ); |
229 | |
|
230 | 0 | append( sb, "files", 2 ); |
231 | 0 | append( sb, "A comma separated list of files for each of the extra side artifacts to deploy. If there is a mis-match in the number of entries in types or classifiers, then an error will be raised.", 3 ); |
232 | 0 | append( sb, "Expression: ${files}", 3 ); |
233 | 0 | append( sb, "", 0 ); |
234 | |
|
235 | 0 | append( sb, "generatePom (Default: true)", 2 ); |
236 | 0 | append( sb, "Upload a POM for this artifact. Will generate a default POM if none is supplied with the pomFile argument.", 3 ); |
237 | 0 | append( sb, "Expression: ${generatePom}", 3 ); |
238 | 0 | append( sb, "", 0 ); |
239 | |
|
240 | 0 | append( sb, "groupId", 2 ); |
241 | 0 | append( sb, "GroupId of the artifact to be deployed. Retrieved from POM file if specified.", 3 ); |
242 | 0 | append( sb, "Expression: ${groupId}", 3 ); |
243 | 0 | append( sb, "", 0 ); |
244 | |
|
245 | 0 | append( sb, "homedir", 2 ); |
246 | 0 | append( sb, "The directory from which gpg will load keyrings. If not specified, gpg will use the value configured for its installation, e.g. ~/.gnupg or %APPDATA%/gnupg.", 3 ); |
247 | 0 | append( sb, "Expression: ${gpg.homedir}", 3 ); |
248 | 0 | append( sb, "", 0 ); |
249 | |
|
250 | 0 | append( sb, "javadoc", 2 ); |
251 | 0 | append( sb, "The bundled API docs for the artifact.", 3 ); |
252 | 0 | append( sb, "Expression: ${javadoc}", 3 ); |
253 | 0 | append( sb, "", 0 ); |
254 | |
|
255 | 0 | append( sb, "keyname", 2 ); |
256 | 0 | append( sb, "The \'name\' of the key to sign with. Passed to gpg as --local-user.", 3 ); |
257 | 0 | append( sb, "Expression: ${gpg.keyname}", 3 ); |
258 | 0 | append( sb, "", 0 ); |
259 | |
|
260 | 0 | append( sb, "packaging", 2 ); |
261 | 0 | append( sb, "Type of the artifact to be deployed. Retrieved from POM file if specified. Defaults to file extension if not specified via command line or POM.", 3 ); |
262 | 0 | append( sb, "Expression: ${packaging}", 3 ); |
263 | 0 | append( sb, "", 0 ); |
264 | |
|
265 | 0 | append( sb, "passphrase", 2 ); |
266 | 0 | append( sb, "The passphrase to use when signing.", 3 ); |
267 | 0 | append( sb, "Expression: ${gpg.passphrase}", 3 ); |
268 | 0 | append( sb, "", 0 ); |
269 | |
|
270 | 0 | append( sb, "pomFile", 2 ); |
271 | 0 | append( sb, "Location of an existing POM file to be deployed alongside the main artifact, given by the ${file} parameter.", 3 ); |
272 | 0 | append( sb, "Expression: ${pomFile}", 3 ); |
273 | 0 | append( sb, "", 0 ); |
274 | |
|
275 | 0 | append( sb, "publicKeyring", 2 ); |
276 | 0 | append( sb, "The path to a public keyring to add to the list of keyrings. By default, only the pubring.gpg from gpg\'s home directory is considered. Use this option (and defaultKeyring if required) to use a different public key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 ); |
277 | 0 | append( sb, "Expression: ${gpg.publicKeyring}", 3 ); |
278 | 0 | append( sb, "", 0 ); |
279 | |
|
280 | 0 | append( sb, "repositoryId (Default: remote-repository)", 2 ); |
281 | 0 | append( sb, "Server Id to map on the <id> under <server> section of settings.xml. In most cases, this parameter will be required for authentication.", 3 ); |
282 | 0 | append( sb, "Required: Yes", 3 ); |
283 | 0 | append( sb, "Expression: ${repositoryId}", 3 ); |
284 | 0 | append( sb, "", 0 ); |
285 | |
|
286 | 0 | append( sb, "repositoryLayout (Default: default)", 2 ); |
287 | 0 | append( sb, "The type of remote repository layout to deploy to. Try legacy for a Maven 1.x-style repository layout.", 3 ); |
288 | 0 | append( sb, "Expression: ${repositoryLayout}", 3 ); |
289 | 0 | append( sb, "", 0 ); |
290 | |
|
291 | 0 | append( sb, "retryFailedDeploymentCount (Default: 1)", 2 ); |
292 | 0 | append( sb, "Parameter used to control how many times a failed deployment will be retried before giving up and failing. If a value outside the range 1-10 is specified it will be pulled to the nearest value within the range 1-10.", 3 ); |
293 | 0 | append( sb, "Expression: ${retryFailedDeploymentCount}", 3 ); |
294 | 0 | append( sb, "", 0 ); |
295 | |
|
296 | 0 | append( sb, "secretKeyring", 2 ); |
297 | 0 | append( sb, "The path to a secret keyring to add to the list of keyrings. By default, only the secring.gpg from gpg\'s home directory is considered. Use this option (in combination with publicKeyring and defaultKeyring if required) to use a different secret key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 ); |
298 | 0 | append( sb, "Expression: ${gpg.secretKeyring}", 3 ); |
299 | 0 | append( sb, "", 0 ); |
300 | |
|
301 | 0 | append( sb, "sources", 2 ); |
302 | 0 | append( sb, "The bundled sources for the artifact.", 3 ); |
303 | 0 | append( sb, "Expression: ${sources}", 3 ); |
304 | 0 | append( sb, "", 0 ); |
305 | |
|
306 | 0 | append( sb, "types", 2 ); |
307 | 0 | append( sb, "A comma separated list of types for each of the extra side artifacts to deploy. If there is a mis-match in the number of entries in files or classifiers, then an error will be raised.", 3 ); |
308 | 0 | append( sb, "Expression: ${types}", 3 ); |
309 | 0 | append( sb, "", 0 ); |
310 | |
|
311 | 0 | append( sb, "uniqueVersion (Default: true)", 2 ); |
312 | 0 | append( sb, "Whether to deploy snapshots with a unique version or not.", 3 ); |
313 | 0 | append( sb, "Expression: ${uniqueVersion}", 3 ); |
314 | 0 | append( sb, "", 0 ); |
315 | |
|
316 | 0 | append( sb, "updateReleaseInfo (Default: false)", 2 ); |
317 | 0 | append( sb, "Parameter used to update the metadata to make the artifact as release.", 3 ); |
318 | 0 | append( sb, "Expression: ${updateReleaseInfo}", 3 ); |
319 | 0 | append( sb, "", 0 ); |
320 | |
|
321 | 0 | append( sb, "url", 2 ); |
322 | 0 | append( sb, "URL where the artifact will be deployed.\nie ( file:///C:/m2-repo or scp://host.com/path/to/repo )", 3 ); |
323 | 0 | append( sb, "Required: Yes", 3 ); |
324 | 0 | append( sb, "Expression: ${url}", 3 ); |
325 | 0 | append( sb, "", 0 ); |
326 | |
|
327 | 0 | append( sb, "useAgent (Default: false)", 2 ); |
328 | 0 | append( sb, "Passes --use-agent or --no-use-agent to gpg. If using an agent, the passphrase is optional as the agent will provide it. For gpg2, specify true as --no-use-agent was removed in gpg2 and doesn\'t ask for a passphrase anymore.", 3 ); |
329 | 0 | append( sb, "Expression: ${gpg.useagent}", 3 ); |
330 | 0 | append( sb, "", 0 ); |
331 | |
|
332 | 0 | append( sb, "version", 2 ); |
333 | 0 | append( sb, "Version of the artifact to be deployed. Retrieved from POM file if specified.", 3 ); |
334 | 0 | append( sb, "Expression: ${version}", 3 ); |
335 | 0 | append( sb, "", 0 ); |
336 | |
} |
337 | |
} |
338 | |
|
339 | 0 | if ( getLog().isInfoEnabled() ) |
340 | |
{ |
341 | 0 | getLog().info( sb.toString() ); |
342 | |
} |
343 | 0 | } |
344 | |
|
345 | |
|
346 | |
|
347 | |
|
348 | |
|
349 | |
|
350 | |
|
351 | |
|
352 | |
|
353 | |
|
354 | |
private static String repeat( String str, int repeat ) |
355 | |
{ |
356 | 0 | StringBuffer buffer = new StringBuffer( repeat * str.length() ); |
357 | |
|
358 | 0 | for ( int i = 0; i < repeat; i++ ) |
359 | |
{ |
360 | 0 | buffer.append( str ); |
361 | |
} |
362 | |
|
363 | 0 | return buffer.toString(); |
364 | |
} |
365 | |
|
366 | |
|
367 | |
|
368 | |
|
369 | |
|
370 | |
|
371 | |
|
372 | |
|
373 | |
|
374 | |
private void append( StringBuffer sb, String description, int indent ) |
375 | |
{ |
376 | 0 | for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); ) |
377 | |
{ |
378 | 0 | sb.append( it.next().toString() ).append( '\n' ); |
379 | |
} |
380 | 0 | } |
381 | |
|
382 | |
|
383 | |
|
384 | |
|
385 | |
|
386 | |
|
387 | |
|
388 | |
|
389 | |
|
390 | |
|
391 | |
|
392 | |
private static List toLines( String text, int indent, int indentSize, int lineLength ) |
393 | |
{ |
394 | 0 | List<String> lines = new ArrayList<String>(); |
395 | |
|
396 | 0 | String ind = repeat( "\t", indent ); |
397 | 0 | String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" ); |
398 | 0 | for ( int i = 0; i < plainLines.length; i++ ) |
399 | |
{ |
400 | 0 | toLines( lines, ind + plainLines[i], indentSize, lineLength ); |
401 | |
} |
402 | |
|
403 | 0 | return lines; |
404 | |
} |
405 | |
|
406 | |
|
407 | |
|
408 | |
|
409 | |
|
410 | |
|
411 | |
|
412 | |
|
413 | |
|
414 | |
private static void toLines( List<String> lines, String line, int indentSize, int lineLength ) |
415 | |
{ |
416 | 0 | int lineIndent = getIndentLevel( line ); |
417 | 0 | StringBuffer buf = new StringBuffer( 256 ); |
418 | 0 | String[] tokens = line.split( " +" ); |
419 | 0 | for ( int i = 0; i < tokens.length; i++ ) |
420 | |
{ |
421 | 0 | String token = tokens[i]; |
422 | 0 | if ( i > 0 ) |
423 | |
{ |
424 | 0 | if ( buf.length() + token.length() >= lineLength ) |
425 | |
{ |
426 | 0 | lines.add( buf.toString() ); |
427 | 0 | buf.setLength( 0 ); |
428 | 0 | buf.append( repeat( " ", lineIndent * indentSize ) ); |
429 | |
} |
430 | |
else |
431 | |
{ |
432 | 0 | buf.append( ' ' ); |
433 | |
} |
434 | |
} |
435 | 0 | for ( int j = 0; j < token.length(); j++ ) |
436 | |
{ |
437 | 0 | char c = token.charAt( j ); |
438 | 0 | if ( c == '\t' ) |
439 | |
{ |
440 | 0 | buf.append( repeat( " ", indentSize - buf.length() % indentSize ) ); |
441 | |
} |
442 | 0 | else if ( c == '\u00A0' ) |
443 | |
{ |
444 | 0 | buf.append( ' ' ); |
445 | |
} |
446 | |
else |
447 | |
{ |
448 | 0 | buf.append( c ); |
449 | |
} |
450 | |
} |
451 | |
} |
452 | 0 | lines.add( buf.toString() ); |
453 | 0 | } |
454 | |
|
455 | |
|
456 | |
|
457 | |
|
458 | |
|
459 | |
|
460 | |
|
461 | |
private static int getIndentLevel( String line ) |
462 | |
{ |
463 | 0 | int level = 0; |
464 | 0 | for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ ) |
465 | |
{ |
466 | 0 | level++; |
467 | |
} |
468 | 0 | for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ ) |
469 | |
{ |
470 | 0 | if ( line.charAt( i ) == '\t' ) |
471 | |
{ |
472 | 0 | level++; |
473 | 0 | break; |
474 | |
} |
475 | |
} |
476 | 0 | return level; |
477 | |
} |
478 | |
} |