bee_java 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,482 @@
1
+ # Copyright 2008-2009 Michel Casabianca <michel.casabianca@gmail.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'net/http'
16
+ require 'fileutils'
17
+ require 'rexml/document'
18
+ require 'rexml/xpath'
19
+ require 'bee_util'
20
+
21
+ module Bee
22
+
23
+ module Task
24
+
25
+ # Parent of all dependency resolvers.
26
+ class BaseDependencyResolver
27
+
28
+ include Bee::Util::BuildErrorMixin
29
+
30
+ # Default repository.
31
+ DEFAULT_REPOSITORY = nil
32
+ # Default cache location.
33
+ DEFAULT_CACHE = nil
34
+ # Default dependency scope.
35
+ DEFAULT_SCOPE = 'compile'
36
+
37
+ # Constructor:
38
+ # - file: dependency file (should be maven.xml).
39
+ # - scope: the scope for dependencies (compile, runtime or test).
40
+ # - verbose: tells if we should be verbose.
41
+ def initialize(file, scope, verbose=false)
42
+ @file = file
43
+ @scope = scope
44
+ @verbose = verbose
45
+ @repositories = parse_repositories
46
+ @cache = DEFAULT_CACHE
47
+ @dependencies = nil
48
+ # print information if verbose
49
+ puts "Repositories: #{@repositories.join(', ')}" if @verbose
50
+ end
51
+
52
+ # Return the classpath.
53
+ def classpath
54
+ synchronize
55
+ classpath = @dependencies.map do |dependency|
56
+ build_path(@cache, dependency)
57
+ end
58
+ return classpath.join(File::PATH_SEPARATOR)
59
+ end
60
+
61
+ # Return dependencies as a list.
62
+ def dependencies
63
+ synchronize
64
+ dependencies = @dependencies.map do |dependency|
65
+ build_path(@cache, dependency)
66
+ end
67
+ return dependencies
68
+ end
69
+
70
+ private
71
+
72
+ # Resolve dependencies.
73
+ # Returns dependencies as a list.
74
+ def resolve
75
+ @dependencies = parse_dependencies(File.read(@file)) if
76
+ not @dependencies
77
+ return @dependencies
78
+ end
79
+
80
+ # Synchronize dependencies with local cache.
81
+ def synchronize
82
+ resolve
83
+ for dependency in @dependencies
84
+ tofile = build_path(@cache, dependency)
85
+ if not File.exists?(tofile)
86
+ save_file(download(dependency), tofile)
87
+ else
88
+ puts "Dependency '#{build_name(dependency)}' already downloaded" if
89
+ @verbose
90
+ end
91
+ end
92
+ end
93
+
94
+ # Extract repository list from file.
95
+ # Return: repository list.
96
+ def parse_repositories
97
+ raise 'Not implemented'
98
+ end
99
+
100
+ # Download a given dependency.
101
+ # - dependency: dependency as a map.
102
+ # Return: dependency as a binary.
103
+ def download(dependency, log=true)
104
+ name = build_name(dependency)
105
+ puts "Downloading dependency '#{name}'..." if log or @verbose
106
+ for repository in @repositories
107
+ url = build_path(repository, dependency)
108
+ puts "Trying '#{url}'..." if @verbose
109
+ begin
110
+ return fetch(url)
111
+ rescue
112
+ end
113
+ end
114
+ error "Dependency '#{name}' not found"
115
+ end
116
+
117
+ # Build a Maven path.
118
+ # - root: the path root (root directory for repository or cache).
119
+ # - dependency: dependency as a map.
120
+ # Return: path as a string.
121
+ def build_path(root, dependency)
122
+ raise 'Not implemented'
123
+ end
124
+
125
+ # Build dependency name for display.
126
+ # - dependency: dependency as a map.
127
+ # Return: name as a string.
128
+ def build_name(dependency)
129
+ groupid = dependency[:groupid]
130
+ artifactid = dependency[:artifactid]
131
+ version = dependency[:version]
132
+ type = dependency[:type] || 'jar'
133
+ return "#{artifactid}:#{groupid}:#{version}:#{type}"
134
+ end
135
+
136
+ # Extract dependencies from a file.
137
+ # - source: file source.
138
+ # Return: dependencies as a list of maps with keys groupid, artifactid,
139
+ # version, type, optional.
140
+ def parse_dependencies(source)
141
+ raise 'Not implemented'
142
+ end
143
+
144
+ # Tells if a given dependency should be selected.
145
+ # - dependency: the dependency to consider.
146
+ def selected?(dependency)
147
+ return false if dependency[:optional] == 'true'
148
+ dep_scope = dependency[:scope] || DEFAULT_SCOPE
149
+ if @scope == 'compile'
150
+ if dep_scope == 'compile'
151
+ return true
152
+ else
153
+ return false
154
+ end
155
+ elsif @scope == 'runtime'
156
+ if dep_scope == 'compile' or dep_scope == 'runtime'
157
+ return true
158
+ else
159
+ return false
160
+ end
161
+ elsif @scope == 'test'
162
+ if dep_scope == 'compile' or dep_scope == 'runtime' or dep_scope == 'test'
163
+ return true
164
+ else
165
+ return false
166
+ end
167
+ end
168
+ end
169
+
170
+ # Save a given binary in a file and create directories as necessary.
171
+ # - binary: data to save.
172
+ # - tofile: file to save into.
173
+ def save_file(binary, tofile)
174
+ puts "Saving file '#{tofile}'..." if @verbose
175
+ directory = File.dirname(tofile)
176
+ FileUtils.makedirs(directory) if not File.exists?(directory)
177
+ File.open(tofile, 'wb') { |file| file.write(binary) }
178
+ end
179
+
180
+ # Maximum number of HTTP redirections.
181
+ HTTP_REDIRECTIONS_LIMIT = 10
182
+
183
+ # Get a given URL.
184
+ # - url: URL to get.
185
+ # - limit: redirectrion limit (defaults to HTTP_REDIRECTIONS_LIMIT).
186
+ def fetch(url, limit = HTTP_REDIRECTIONS_LIMIT)
187
+ puts "Fetching '#{url}'..." if @verbose
188
+ raise 'HTTP redirect too deep' if limit == 0
189
+ response = Net::HTTP.get_response(URI.parse(url))
190
+ case response
191
+ when Net::HTTPSuccess
192
+ response.body
193
+ when Net::HTTPRedirection
194
+ fetch(response['location'], limit - 1)
195
+ else
196
+ response.error!
197
+ end
198
+ end
199
+
200
+ end
201
+
202
+ # Bee dependency resolver.
203
+ class BeeDependencyResolver < BaseDependencyResolver
204
+
205
+ # Default repository address.
206
+ DEFAULT_REPOSITORY = 'http://repo1.maven.org/maven2'
207
+ # Default cache location.
208
+ DEFAULT_CACHE = File.expand_path('~/.java/dependencies')
209
+
210
+ # Constructor:
211
+ # - file: dependency file (should be maven.xml).
212
+ # - scope: the scope for dependencies (compile, runtime or test).
213
+ # - verbose: tells if we should be verbose.
214
+ def initialize(file, scope, verbose=false)
215
+ super(file, scope, verbose)
216
+ @cache = DEFAULT_CACHE
217
+ end
218
+
219
+ # Extract dependencies from a file.
220
+ # - source: file source.
221
+ # Return: dependencies as a list of maps with keys groupid, artifactid,
222
+ # version, type, optional.
223
+ def parse_dependencies(source)
224
+ dependencies = YAML::load(source)
225
+ new_dependencies = []
226
+ for dependency in dependencies
227
+ if dependency['group']
228
+ new_dependency = {}
229
+ for key in dependency.keys
230
+ if key != 'group' and key != 'artifact'
231
+ new_dependency[key.to_sym] = dependency[key]
232
+ elsif key == 'group'
233
+ new_dependency[:groupid] = dependency['group']
234
+ elsif key == 'artifact'
235
+ new_dependency[:artifactid] = dependency['artifact']
236
+ end
237
+ end
238
+ new_dependencies << new_dependency
239
+ end
240
+ end
241
+ return new_dependencies
242
+ end
243
+
244
+ # Extract repository list from file.
245
+ # Return: repository list.
246
+ def parse_repositories
247
+ repositories = YAML::load(File.read(@file))
248
+ new_repositories = []
249
+ for repository in repositories
250
+ if repository['repository']
251
+ new_repositories << repository['repository']
252
+ elsif repository['repositories']
253
+ new_repositories = new_repositories + repository['repositories']
254
+ end
255
+ end
256
+ return new_repositories
257
+ end
258
+
259
+ # Build a Maven path.
260
+ # - root: the path root (root directory for repository or cache).
261
+ # - dependency: dependency as a map.
262
+ # Return: path as a string.
263
+ def build_path(root, dependency)
264
+ groupid = dependency[:groupid].split('.').join('/')
265
+ artifactid = dependency[:artifactid]
266
+ version = dependency[:version]
267
+ type = dependency[:type] || 'jar'
268
+ classifier = dependency[:classifier]
269
+ if classifier
270
+ return "#{root}/#{groupid}/#{artifactid}/#{version}/#{artifactid}-#{version}-#{classifier}.#{type}"
271
+ else
272
+ return "#{root}/#{groupid}/#{artifactid}/#{version}/#{artifactid}-#{version}.#{type}"
273
+ end
274
+ end
275
+
276
+ end
277
+
278
+ # Maven 1 dependency resolver.
279
+ class MavenDependencyResolver < BaseDependencyResolver
280
+
281
+ include Bee::Util::BuildErrorMixin
282
+
283
+ # Default repository.
284
+ DEFAULT_REPOSITORY = 'http://repo1.maven.org/maven'
285
+ # Default cache location.
286
+ DEFAULT_CACHE = File.expand_path('~/.maven/repository')
287
+ # Default dependency scope.
288
+ DEFAULT_SCOPE = 'compile'
289
+
290
+ # Constructor:
291
+ # - file: dependency file (should be maven.xml).
292
+ # - scope: the scope for dependencies (compile, runtime or test).
293
+ # - verbose: tells if we should be verbose.
294
+ def initialize(file, scope, verbose=false)
295
+ super(file, scope, verbose)
296
+ @cache = DEFAULT_CACHE
297
+ end
298
+
299
+ private
300
+
301
+ # Synchronize dependencies with local cache.
302
+ def synchronize
303
+ resolve
304
+ for dependency in @dependencies
305
+ tofile = build_path(@cache, dependency)
306
+ if not File.exists?(tofile)
307
+ save_file(download(dependency), tofile)
308
+ else
309
+ puts "Dependency '#{build_name(dependency)}' already downloaded" if
310
+ @verbose
311
+ end
312
+ end
313
+ end
314
+
315
+ # Extract repository list from file.
316
+ # Return: repository list.
317
+ def parse_repositories
318
+ repositories = []
319
+ doc = REXML::Document.new(File.read(@file))
320
+ REXML::XPath.each(doc, '/project/repository') do |element|
321
+ REXML::XPath.each(element, 'url') do |entry|
322
+ repositories << entry.text.strip
323
+ end
324
+ end
325
+ repositories << DEFAULT_REPOSITORY if repositories.empty?
326
+ return repositories
327
+ end
328
+
329
+ # Build a Maven path.
330
+ # - root: the path root (root directory for repository or cache).
331
+ # - dependency: dependency as a map.
332
+ # Return: path as a string.
333
+ def build_path(root, dependency)
334
+ groupid = dependency[:groupid]
335
+ artifactid = dependency[:artifactid]
336
+ version = dependency[:version]
337
+ type = dependency[:type] || 'jar'
338
+ return "#{root}/#{groupid}/#{type}s/#{artifactid}-#{version}.#{type}"
339
+ end
340
+
341
+ # Extract dependencies from a file.
342
+ # - source: file source.
343
+ # Return: dependencies as a list of maps with keys groupid, artifactid,
344
+ # version, type, optional.
345
+ def parse_dependencies(source)
346
+ dependencies = []
347
+ doc = REXML::Document.new(source)
348
+ properties = {}
349
+ REXML::XPath.each(doc, '/project/properties/*') do |element|
350
+ name = element.name.strip
351
+ value = element.text
352
+ value = value.strip if value
353
+ properties[name] = value
354
+ end
355
+ REXML::XPath.each(doc, '/project/dependencies/dependency') do |element|
356
+ dependency = {}
357
+ REXML::XPath.each(element, '*') do |entry|
358
+ name = entry.name.downcase.to_sym
359
+ value = entry.text.strip
360
+ for key in properties.keys
361
+ value = value.gsub(/\$\{#{key}\}/, properties[key]) if
362
+ properties[key]
363
+ end
364
+ dependency[name] = value
365
+ end
366
+ dependencies << dependency if selected?(dependency)
367
+ end
368
+ return dependencies
369
+ end
370
+
371
+ end
372
+
373
+ # Maven 2 dependency resolver.
374
+ class Maven2DependencyResolver < MavenDependencyResolver
375
+
376
+ # Default repository address.
377
+ DEFAULT_REPOSITORY = 'http://repo1.maven.org/maven2'
378
+ # Default cache location.
379
+ DEFAULT_CACHE = File.expand_path('~/.m2/repository')
380
+
381
+ # Constructor:
382
+ # - file: dependency file (should be maven.xml).
383
+ # - scope: the scope for dependencies (compile, runtime or test).
384
+ # - verbose: tells if we should be verbose.
385
+ def initialize(file, scope, verbose=false)
386
+ super(file, scope, verbose)
387
+ @cache = DEFAULT_CACHE
388
+ end
389
+
390
+ private
391
+
392
+ # Resolve dependencies.
393
+ # Returns dependencies as a list.
394
+ def resolve
395
+ if not @dependencies
396
+ @dependencies = parse_dependencies(File.read(@file))
397
+ for dependency in @dependencies
398
+ @dependencies = @dependencies + recurse_dependency(dependency)
399
+ end
400
+ end
401
+ return @dependencies
402
+ end
403
+
404
+ # Recurse on a given dependency.
405
+ # - dependency: depedency to recurse over as a map.
406
+ # Return: dependencies as a list.
407
+ def recurse_dependency(dependency)
408
+ pom = dependency.clone
409
+ pom[:type] = 'pom'
410
+ new_dependencies = []
411
+ begin
412
+ pom_file = build_path(@cache, pom)
413
+ if not File.exists?(pom_file)
414
+ new_pom = download(pom, false)
415
+ save_file(new_pom, pom_file)
416
+ else
417
+ name = build_name(pom)
418
+ puts "POM file '#{name}' already downloaded" if @verbose
419
+ new_pom = File.read(pom_file)
420
+ end
421
+ new_dependencies = parse_dependencies(new_pom)
422
+ for new_dependency in new_dependencies
423
+ to_add = recurse_dependency(new_dependency)
424
+ new_dependencies = new_dependencies + to_add if not to_add.empty
425
+ end
426
+ rescue
427
+ end
428
+ return new_dependencies
429
+ end
430
+
431
+ # Extract repository list from POM file or
432
+ # Return: repository list.
433
+ def parse_repositories
434
+ repositories = []
435
+ # search for repositories in POM file
436
+ doc = REXML::Document.new(File.read(@file))
437
+ REXML::XPath.each(doc, '/project/distributionManagement/repository') do |element|
438
+ REXML::XPath.each(element, 'url') do |entry|
439
+ repositories << entry.text.strip
440
+ end
441
+ end
442
+ # search for repositories in cache repository
443
+ begin
444
+ doc = REXML::Document.new(File.read(File.expand_path('~/.m2/settings.xml')))
445
+ REXML::XPath.each(doc, '/settings/mirrors/mirror') do |element|
446
+ REXML::XPath.each(element, 'url') do |entry|
447
+ repositories << entry.text.strip
448
+ end
449
+ end
450
+ REXML::XPath.each(doc, '/settings/profiles/profile/repositories/repository') do |element|
451
+ REXML::XPath.each(element, 'url') do |entry|
452
+ repositories << entry.text.strip
453
+ end
454
+ end
455
+ rescue
456
+ end
457
+ repositories << DEFAULT_REPOSITORY if repositories.empty?
458
+ return repositories.uniq
459
+ end
460
+
461
+ # Build a Maven path.
462
+ # - root: the path root (root directory for repository or cache).
463
+ # - dependency: dependency as a map.
464
+ # Return: path as a string.
465
+ def build_path(root, dependency)
466
+ groupid = dependency[:groupid].split('.').join('/')
467
+ artifactid = dependency[:artifactid]
468
+ version = dependency[:version]
469
+ type = dependency[:type] || 'jar'
470
+ classifier = dependency[:classifier]
471
+ if classifier
472
+ return "#{root}/#{groupid}/#{artifactid}/#{version}/#{artifactid}-#{version}-#{classifier}.#{type}"
473
+ else
474
+ return "#{root}/#{groupid}/#{artifactid}/#{version}/#{artifactid}-#{version}.#{type}"
475
+ end
476
+ end
477
+
478
+ end
479
+
480
+ end
481
+
482
+ end
data/test/build.yml ADDED
@@ -0,0 +1,125 @@
1
+ # Copyright 2008-2009 Michel Casabianca <michel.casabianca@gmail.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ - build: test_java
16
+ default: all
17
+ description: Build file to test Java package
18
+
19
+ - properties:
20
+ - name: "test"
21
+ - src: "src"
22
+ - build: "build"
23
+ - classes: "#{build}/classes"
24
+ - javadoc: "#{build}/api"
25
+ - jar: "#{build}/#{name}.jar"
26
+ - erb: "manifest.erb"
27
+ - manifest: "#{build}/manifest"
28
+ - main: "test.Test"
29
+ - classpath: :jar
30
+ - junit: "/opt/java/junit-4.4"
31
+ - test: "test"
32
+ - test_classes: "#{build}/test-classes"
33
+ - lib: "#{build}/lib"
34
+
35
+ - target: javac
36
+ description: Test javac task
37
+ script:
38
+ - java.javac:
39
+ src: :src
40
+ dest: :classes
41
+
42
+ - target: jar
43
+ depends: javac
44
+ description: Test jar task
45
+ script:
46
+ - erb:
47
+ src: :erb
48
+ dest: :manifest
49
+ - java.jar:
50
+ src: :classes
51
+ manifest: :manifest
52
+ dest: :jar
53
+
54
+ - target: junit
55
+ depends: javac
56
+ description: Run unit tests
57
+ script:
58
+ - find:
59
+ includes: "#{junit}/junit*.jar"
60
+ excludes: "#{junit}/junit*-src.jar"
61
+ property: junit_cp
62
+ - java.javac:
63
+ src: :test
64
+ dest: :test_classes
65
+ classpath: [:junit_cp, :classes]
66
+ - java.junit:
67
+ classpath: [:classes, :test_classes, :junit_cp]
68
+ src: :test
69
+
70
+ - target: javadoc
71
+ description: Document Java source files
72
+ script:
73
+ - java.javadoc:
74
+ src: :src
75
+ dest: :javadoc
76
+
77
+ - target: java
78
+ depends: jar
79
+ description: Run java program
80
+ script:
81
+ - java.java:
82
+ main: :main
83
+ classpath: :classpath
84
+ properties: { who: World }
85
+ - java.java:
86
+ main: :main
87
+ classpath: :classes
88
+ properties: { who: World }
89
+ - java.java:
90
+ jar: :jar
91
+ properties: { who: World }
92
+
93
+ - target: deps
94
+ description: Fetch dependencies
95
+ script:
96
+ # maven 1 repository
97
+ - rmdir: :build
98
+ - java.deps:
99
+ src: dependencies.yml
100
+ dest: :lib
101
+ repos: http://www.ibiblio.org/maven
102
+ # maven 2 repository
103
+ - rmdir: :build
104
+ - java.deps:
105
+ src: dependencies.xml
106
+ dest: :lib
107
+ repos: http://repo1.maven.org/maven2
108
+ repotype: maven2
109
+
110
+ - target: classpath
111
+ description: Compute a classpath
112
+ script:
113
+ #- java.clean:
114
+ - java.classpath:
115
+ file: pom.xml
116
+ property: classpath
117
+ - print: :classpath
118
+
119
+ - target: clean
120
+ description: Clean generated files
121
+ script:
122
+ - rmdir: :build
123
+
124
+ - target: all
125
+ depends: [clean, javac, jar, junit, javadoc, java, deps]
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+
3
+ <project>
4
+ <dependencies>
5
+ <dependency>
6
+ <groupId>junit</groupId>
7
+ <artifactId>junit</artifactId>
8
+ <version>4.3</version>
9
+ </dependency>
10
+ </dependencies>
11
+ </project>
@@ -0,0 +1,3 @@
1
+ - group: junit
2
+ artifact: junit
3
+ version: 4.3
data/test/manifest.erb ADDED
@@ -0,0 +1 @@
1
+ Main-Class: <%= main %>
data/test/pom.xml ADDED
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+
3
+ <project>
4
+
5
+ <modelVersion>4.0.0</modelVersion>
6
+ <groupId>test</groupId>
7
+ <artifactId>test</artifactId>
8
+ <name>Test</name>
9
+ <version>1.0.0</version>
10
+
11
+ <repositories>
12
+ <repository>
13
+ <id>central</id>
14
+ <name>Maven Repository Switchboard</name>
15
+ <layout>default</layout>
16
+ <url>http://repo1.maven.org/maven2</url>
17
+ <snapshots>
18
+ <enabled>false</enabled>
19
+ </snapshots>
20
+ </repository>
21
+ </repositories>
22
+
23
+ <dependencies>
24
+ <dependency>
25
+ <groupId>ehcache</groupId>
26
+ <artifactId>ehcache</artifactId>
27
+ <version>1.2beta4</version>
28
+ </dependency>
29
+ </dependencies>
30
+
31
+ </project>
@@ -0,0 +1,28 @@
1
+ // Copyright 2008-2009 Michel Casabianca <michel.casabianca@gmail.com>
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ package test;
16
+
17
+ public class Test {
18
+
19
+ public static void main(String[] args) {
20
+ String who = System.getProperty("who");
21
+ System.out.println(hello(who));
22
+ }
23
+
24
+ public static String hello(String who) {
25
+ return "Hello "+who+"!";
26
+ }
27
+
28
+ }