tetra 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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