tetra 0.40.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/.gitignore +27 -0
  2. data/.rubocop.yml +14 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +28 -0
  5. data/MOTIVATION.md +27 -0
  6. data/README.md +106 -0
  7. data/Rakefile +9 -0
  8. data/SPECIAL_CASES.md +130 -0
  9. data/bin/tetra +29 -0
  10. data/integration-tests/commons.sh +55 -0
  11. data/lib/template/gitignore +2 -0
  12. data/lib/template/kit.spec +64 -0
  13. data/lib/template/kit/CONTENTS +8 -0
  14. data/lib/template/kit/jars/CONTENTS +1 -0
  15. data/lib/template/kit/m2/settings.xml +10 -0
  16. data/lib/template/output/CONTENTS +3 -0
  17. data/lib/template/package.spec +65 -0
  18. data/lib/template/src/CONTENTS +6 -0
  19. data/lib/tetra.rb +63 -0
  20. data/lib/tetra/ant_runner.rb +27 -0
  21. data/lib/tetra/archiver.rb +95 -0
  22. data/lib/tetra/commands/ant.rb +23 -0
  23. data/lib/tetra/commands/base.rb +89 -0
  24. data/lib/tetra/commands/download_maven_source_jars.rb +29 -0
  25. data/lib/tetra/commands/dry_run.rb +17 -0
  26. data/lib/tetra/commands/finish.rb +22 -0
  27. data/lib/tetra/commands/generate_all.rb +38 -0
  28. data/lib/tetra/commands/generate_kit_archive.rb +18 -0
  29. data/lib/tetra/commands/generate_kit_spec.rb +16 -0
  30. data/lib/tetra/commands/generate_package_archive.rb +19 -0
  31. data/lib/tetra/commands/generate_package_script.rb +21 -0
  32. data/lib/tetra/commands/generate_package_spec.rb +22 -0
  33. data/lib/tetra/commands/get_pom.rb +33 -0
  34. data/lib/tetra/commands/get_source.rb +30 -0
  35. data/lib/tetra/commands/init.rb +15 -0
  36. data/lib/tetra/commands/list_kit_missing_sources.rb +21 -0
  37. data/lib/tetra/commands/move_jars_to_kit.rb +18 -0
  38. data/lib/tetra/commands/mvn.rb +23 -0
  39. data/lib/tetra/git.rb +140 -0
  40. data/lib/tetra/kit_checker.rb +104 -0
  41. data/lib/tetra/kit_runner.rb +43 -0
  42. data/lib/tetra/kit_spec_adapter.rb +28 -0
  43. data/lib/tetra/logger.rb +28 -0
  44. data/lib/tetra/main.rb +102 -0
  45. data/lib/tetra/maven_runner.rb +47 -0
  46. data/lib/tetra/maven_website.rb +59 -0
  47. data/lib/tetra/package_spec_adapter.rb +59 -0
  48. data/lib/tetra/pom.rb +55 -0
  49. data/lib/tetra/pom_getter.rb +104 -0
  50. data/lib/tetra/project.rb +245 -0
  51. data/lib/tetra/script_generator.rb +57 -0
  52. data/lib/tetra/source_getter.rb +41 -0
  53. data/lib/tetra/spec_generator.rb +60 -0
  54. data/lib/tetra/template_manager.rb +33 -0
  55. data/lib/tetra/version.rb +6 -0
  56. data/lib/tetra/version_matcher.rb +90 -0
  57. data/spec/data/ant-super-simple-code/build.xml +133 -0
  58. data/spec/data/ant-super-simple-code/build/HW.class +0 -0
  59. data/spec/data/ant-super-simple-code/build/mypackage/HW.class +0 -0
  60. data/spec/data/ant-super-simple-code/dist/antsimple-20130618.jar +0 -0
  61. data/spec/data/ant-super-simple-code/lib/junit-4.11.jar +0 -0
  62. data/spec/data/ant-super-simple-code/lib/log4j-1.2.13.jar +0 -0
  63. data/spec/data/ant-super-simple-code/src/mypackage/HW.java +15 -0
  64. data/spec/data/antlr/antlr-2.7.2.jar +0 -0
  65. data/spec/data/antlr/pom.xml +6 -0
  66. data/spec/data/commons-logging/commons-logging-1.1.1.jar +0 -0
  67. data/spec/data/commons-logging/parent_pom.xml +420 -0
  68. data/spec/data/commons-logging/pom.xml +504 -0
  69. data/spec/data/nailgun/nailgun-0.7.1.jar +0 -0
  70. data/spec/data/nailgun/pom.xml +153 -0
  71. data/spec/data/struts-apps/pom.xml +228 -0
  72. data/spec/data/tomcat/pom.xml +33 -0
  73. data/spec/lib/ant_runner_spec.rb +45 -0
  74. data/spec/lib/archiver_spec.rb +106 -0
  75. data/spec/lib/git_spec.rb +105 -0
  76. data/spec/lib/kit_checker_spec.rb +119 -0
  77. data/spec/lib/maven_runner_spec.rb +68 -0
  78. data/spec/lib/maven_website_spec.rb +56 -0
  79. data/spec/lib/pom_getter_spec.rb +36 -0
  80. data/spec/lib/pom_spec.rb +69 -0
  81. data/spec/lib/project_spec.rb +254 -0
  82. data/spec/lib/script_generator_spec.rb +67 -0
  83. data/spec/lib/source_getter_spec.rb +36 -0
  84. data/spec/lib/spec_generator_spec.rb +130 -0
  85. data/spec/lib/template_manager_spec.rb +54 -0
  86. data/spec/lib/version_matcher_spec.rb +64 -0
  87. data/spec/spec_helper.rb +37 -0
  88. data/spec/support/kit_runner_examples.rb +15 -0
  89. data/tetra.gemspec +31 -0
  90. data/utils/delete_nonet_user.sh +8 -0
  91. data/utils/setup_nonet_user.sh +8 -0
  92. metadata +267 -0
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra finish
5
+ class FinishCommand < Tetra::BaseCommand
6
+ option %w(-a --abort), :flag, "build abort, restore files as before dry-run"
7
+
8
+ def execute
9
+ checking_exceptions do
10
+ if Tetra::Project.new(".").finish(abort?)
11
+ if abort?
12
+ puts "Project reverted as before dry-run."
13
+ else
14
+ puts "Dry-run finished."
15
+ end
16
+ else
17
+ puts "No dry-run is in progress."
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra generate-all
5
+ class GenerateAllCommand < Tetra::BaseCommand
6
+ option %w(-f --filter), "FILTER", "filter files to be installed by this package spec", default: "*.jar"
7
+ option %w(-w --whole), :flag, "recreate the whole archive (not incremental)"
8
+ parameter "[DIRECTORY]", "path to a package directory (src/<package name>)", default: "."
9
+ parameter "[POM]", "a package pom file path", default: "pom.xml"
10
+
11
+ def execute
12
+ checking_exceptions do
13
+ project = Tetra::Project.new(".")
14
+ ensure_dry_running(false, project) do
15
+ package_name = project.get_package_name(directory)
16
+
17
+ result_path = Tetra::Archiver.new(project).archive_kit(whole?)
18
+ print_generation_result(project, result_path)
19
+
20
+ result_path, conflict_count = Tetra::SpecGenerator.new(project).generate_kit_spec
21
+ print_generation_result(project, result_path, conflict_count)
22
+
23
+ history_file = File.join(Dir.home, ".bash_history")
24
+ result_path, conflict_count = Tetra::ScriptGenerator.new(project, history_file)
25
+ .generate_build_script(package_name)
26
+ print_generation_result(project, result_path, conflict_count)
27
+
28
+ result_path = Tetra::Archiver.new(project).archive_package package_name
29
+ print_generation_result(project, result_path)
30
+
31
+ result_path, conflict_count = Tetra::SpecGenerator.new(project)
32
+ .generate_package_spec package_name, pom, filter
33
+ print_generation_result(project, result_path, conflict_count)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra generate-kit-archive
5
+ class GenerateKitArchiveCommand < Tetra::BaseCommand
6
+ option %w(-w --whole), :flag, "recreate the whole archive (not incremental)"
7
+
8
+ def execute
9
+ checking_exceptions do
10
+ project = Tetra::Project.new(".")
11
+ ensure_dry_running(false, project) do
12
+ result_path = Tetra::Archiver.new(project).archive_kit(whole?)
13
+ print_generation_result(project, result_path)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra generate-kit-spec
5
+ class GenerateKitSpecCommand < Tetra::BaseCommand
6
+ def execute
7
+ checking_exceptions do
8
+ project = Tetra::Project.new(".")
9
+ ensure_dry_running(false, project) do
10
+ result_path, conflict_count = Tetra::SpecGenerator.new(project).generate_kit_spec
11
+ print_generation_result(project, result_path, conflict_count)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra generate-package-archive
5
+ class GeneratePackageArchiveCommand < Tetra::BaseCommand
6
+ parameter "[DIRECTORY]", "path to a package directory (src/<package name>)", default: "."
7
+
8
+ def execute
9
+ checking_exceptions do
10
+ project = Tetra::Project.new(".")
11
+ ensure_dry_running(false, project) do
12
+ package_name = project.get_package_name(directory)
13
+ result_path = Tetra::Archiver.new(project).archive_package package_name
14
+ print_generation_result(project, result_path)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra generate-package-script
5
+ class GeneratePackageScriptCommand < Tetra::BaseCommand
6
+ parameter "[DIRECTORY]", "path to a package directory (src/<package name>)", default: "."
7
+
8
+ def execute
9
+ checking_exceptions do
10
+ project = Tetra::Project.new(".")
11
+ ensure_dry_running(false, project) do
12
+ package_name = project.get_package_name(directory)
13
+ history_file = File.join(Dir.home, ".bash_history")
14
+ result_path, conflict_count = Tetra::ScriptGenerator.new(project, history_file)
15
+ .generate_build_script(package_name)
16
+ print_generation_result(project, result_path, conflict_count)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra generate-package-spec
5
+ class GeneratePackageSpecCommand < Tetra::BaseCommand
6
+ option %w(-f --filter), "FILTER", "filter files to be installed by this spec", default: "*.jar"
7
+ parameter "[DIRECTORY]", "path to a package directory (src/<package name>)", default: "."
8
+ parameter "[POM]", "a pom file path", default: "pom.xml"
9
+
10
+ def execute
11
+ checking_exceptions do
12
+ project = Tetra::Project.new(".")
13
+ ensure_dry_running(false, project) do
14
+ package_name = project.get_package_name(directory)
15
+ result_path, conflict_count = Tetra::SpecGenerator.new(project)
16
+ .generate_package_spec(package_name, pom, filter)
17
+ print_generation_result(project, result_path, conflict_count)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra get-pom
5
+ class GetPomCommand < Tetra::BaseCommand
6
+ parameter "NAME", "a jar file name or a `name-version` string (heuristic)"
7
+
8
+ def execute
9
+ checking_exceptions do
10
+ project = Tetra::Project.new(".")
11
+ pom_getter = Tetra::PomGetter.new
12
+
13
+ path, status = pom_getter.get_pom(name)
14
+ if path
15
+ text_status = (
16
+ if status == :found_in_jar
17
+ "was inside the jar"
18
+ elsif status == :found_via_sha1
19
+ "found by sha1 search from search.maven.org"
20
+ elsif status == :found_via_heuristic
21
+ "found by heuristic search from search.maven.org"
22
+ end
23
+ )
24
+
25
+ puts "#{format_path(path, project)} written, #{text_status}"
26
+ else
27
+ puts "#{name}'s pom not found. Try:"
28
+ puts "http://google.com/#q=#{URI.encode(pom_getter.cleanup_name(name) + " pom")}"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra get-source
5
+ class GetSourceCommand < Tetra::BaseCommand
6
+ parameter "POM", "a pom file path or URI"
7
+
8
+ def execute
9
+ checking_exceptions do
10
+ project = Tetra::Project.new(".")
11
+ source_getter = Tetra::SourceGetter.new
12
+
13
+ puts "Attempting to find source through Maven..."
14
+ if source_getter.get_maven_source_jar(project, pom)
15
+ puts "Source jar found and added to Maven repository."
16
+ else
17
+ effective_pom_path = Tetra::MavenRunner.new(project).get_effective_pom(pom)
18
+ puts "Source jar not found in Maven. Try looking here:"
19
+ pom = Tetra::Pom.new(effective_pom_path)
20
+ puts "Website: #{pom.url}" unless pom.url.empty?
21
+ puts "SCM connection: #{pom.scm_connection}" unless pom.scm_connection.empty?
22
+ puts "SCM connection: #{pom.scm_url}" unless pom.scm_url.empty?
23
+ puts "The effective POM: #{effective_pom_path}"
24
+ name = !pom.name.empty? ? pom.name : pom.artifact_id
25
+ puts "Google: http://google.com/#q=#{URI.encode("#{name} sources")}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra init
5
+ class InitCommand < Tetra::BaseCommand
6
+ def execute
7
+ checking_exceptions do
8
+ Tetra::Project.init(".")
9
+ puts "Project inited."
10
+ puts "Add sources to src/<package name>, binary dependencies to kit/."
11
+ puts "When you are ready to test a build, use \"tetra dry-run\"."
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra list-kit-missing-sources
5
+ class ListKitMissingSourcesCommand < Tetra::BaseCommand
6
+ def execute
7
+ checking_exceptions do
8
+ project = Tetra::Project.new(".")
9
+ kit_checker = Tetra::KitChecker.new(project)
10
+
11
+ ensure_dry_running(false, project) do
12
+ puts "Some source files were not found in these archives:"
13
+ kit_checker.unsourced_archives.each do |archive|
14
+ percentage = 100.0 * archive[:unsourced_class_names].length / archive[:class_names].length
15
+ puts "#{format_path(archive[:archive], project)} (~#{format("%.2f", percentage)}% missing)"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra move-jars-to-kit
5
+ class MoveJarsToKitCommand < Tetra::BaseCommand
6
+ def execute
7
+ checking_exceptions do
8
+ project = Tetra::Project.new(".")
9
+
10
+ ensure_dry_running(false, project) do
11
+ project.purge_jars.each do |original, final|
12
+ puts "Replaced #{original} with symlink pointing to to #{final}"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # tetra mvn
5
+ class MavenCommand < Tetra::BaseCommand
6
+ parameter "[MAVEN OPTIONS] ...", "mvn options", attribute_name: "dummy"
7
+
8
+ # override parsing in order to pipe everything to mvn
9
+ # rubocop:disable TrivialAccessors
10
+ def parse(args)
11
+ @options = args
12
+ end
13
+
14
+ def execute
15
+ checking_exceptions do
16
+ project = Tetra::Project.new(".")
17
+ ensure_dry_running(true, project) do
18
+ Tetra::MavenRunner.new(project).mvn(@options)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,140 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # facade to git, currently implemented with calls to the git command
5
+ # prefixes all tags with "tetra_"
6
+ class Git
7
+ include Logging
8
+
9
+ # inits a new git manager object pointing to the specified
10
+ # directory
11
+ def initialize(directory)
12
+ @directory = directory
13
+ end
14
+
15
+ # inits a repo
16
+ def init
17
+ Dir.chdir(@directory) do
18
+ if Dir.exist?(".git") == false
19
+ `git init`
20
+ else
21
+ fail GitAlreadyInitedError
22
+ end
23
+ end
24
+ end
25
+
26
+ # returns a list of filenames that changed in the repo
27
+ # since the specified tag
28
+ def changed_files_since(tag)
29
+ changed_files_between(tag, nil, ".")
30
+ end
31
+
32
+ # returns a list of filenames that changed in the repo
33
+ # between specified tags, in a certain directory
34
+ def changed_files_between(start_tag, end_tag, directory)
35
+ Dir.chdir(@directory) do
36
+ prefixed_start_tag = "tetra_#{start_tag}"
37
+ prefixed_end_tag = (
38
+ if end_tag
39
+ "tetra_#{end_tag}"
40
+ else
41
+ "HEAD"
42
+ end
43
+ )
44
+ `git diff-tree --no-commit-id --name-only -r #{prefixed_start_tag} #{prefixed_end_tag} -- #{directory}`
45
+ .split("\n")
46
+ end
47
+ end
48
+
49
+ # adds all files in the current directory and removes
50
+ # all files not in the current directory.
51
+ # if tag is given, commit is also tagged
52
+ def commit_whole_directory(message, tag = nil, tag_message = nil)
53
+ Dir.chdir(@directory) do
54
+ log.debug "committing with message: #{message}"
55
+
56
+ # rename all .gitignore files by default as
57
+ # they prevent snapshotting
58
+ Find.find(".") do |file|
59
+ next unless file =~ /\.gitignore$/
60
+
61
+ FileUtils.mv(file, "#{file}_disabled_by_tetra")
62
+ end
63
+
64
+ `git rm -r --cached --ignore-unmatch .`
65
+ `git add .`
66
+ `git commit -m "#{message}"`
67
+
68
+ unless tag.nil?
69
+ if !tag_message.nil?
70
+ `git tag tetra_#{tag} -m "#{tag_message}"`
71
+ else
72
+ `git tag tetra_#{tag}`
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ # returns the highest suffix found in tags with the given prefix
79
+ def get_tag_maximum_suffix(prefix)
80
+ Dir.chdir(@directory) do
81
+ `git tag`.split.map do |tag|
82
+ if tag =~ /^tetra_#{prefix}_([0-9]+)$/
83
+ Regexp.last_match[1].to_i
84
+ else
85
+ 0
86
+ end
87
+ end.max || 0
88
+ end
89
+ end
90
+
91
+ # reverts path contents as per specified tag
92
+ def revert_whole_directory(path, tag)
93
+ Dir.chdir(@directory) do
94
+ # reverts added and modified files, both in index and working tree
95
+ `git checkout -f tetra_#{tag} -- #{path}`
96
+
97
+ # compute the list of deleted files
98
+ files_in_tag = `git ls-tree --name-only -r tetra_#{tag} -- #{path}`.split("\n")
99
+ files_in_head = `git ls-tree --name-only -r HEAD -- #{path}`.split("\n")
100
+ files_added_after_head = `git ls-files -o -- #{path}`.split("\n")
101
+ files_to_delete = files_in_head - files_in_tag + files_added_after_head
102
+
103
+ files_to_delete.each do |file|
104
+ FileUtils.rm_rf(file)
105
+ end
106
+ end
107
+ end
108
+
109
+ # 3-way merges the git file at path with the one in new_path
110
+ # assuming they have a common ancestor at the specified tag
111
+ # returns the conflict count
112
+ def merge_with_tag(path, new_path, tag)
113
+ Dir.chdir(@directory) do
114
+ log.debug "calling git show tetra_#{tag}:#{path} > #{path}.old_version, output follows"
115
+ `git show tetra_#{tag}:#{path} > #{path}.old_version`
116
+ log.debug "calling git merge-file #{path} #{path}.old_version #{new_path}, output follows"
117
+ `git merge-file #{path} #{path}.old_version #{new_path} \
118
+ -L "newly generated" -L "previously generated" -L "user edited"`
119
+ conflict_count = $CHILD_STATUS.exitstatus
120
+ File.delete "#{path}.old_version"
121
+ return conflict_count
122
+ end
123
+ end
124
+
125
+ # deletes a tag
126
+ def delete_tag(tag)
127
+ Dir.chdir(@directory) do
128
+ `git tag -d tetra_#{tag}`
129
+ end
130
+ end
131
+
132
+ # returns the tag message
133
+ def get_message(tag)
134
+ `git cat-file tag tetra_#{tag}`.split.last
135
+ end
136
+ end
137
+
138
+ class GitAlreadyInitedError < StandardError
139
+ end
140
+ end