tetra 0.40.0 → 0.41.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +1 -1
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +48 -0
  4. data/MOTIVATION.md +9 -3
  5. data/README.md +5 -5
  6. data/SPECIAL_CASES.md +1 -3
  7. data/integration-tests/{commons.sh → build-commons.sh} +26 -6
  8. data/integration-tests/build-obs.sh +21 -0
  9. data/lib/template/kit_item.spec +53 -0
  10. data/lib/template/package.spec +4 -2
  11. data/lib/tetra.rb +5 -3
  12. data/lib/tetra/archiver.rb +23 -87
  13. data/lib/tetra/commands/generate_all.rb +13 -16
  14. data/lib/tetra/commands/generate_kit_archive.rb +4 -4
  15. data/lib/tetra/commands/generate_kit_spec.rb +4 -2
  16. data/lib/tetra/commands/generate_package_archive.rb +1 -1
  17. data/lib/tetra/commands/generate_package_spec.rb +2 -2
  18. data/lib/tetra/git.rb +19 -10
  19. data/lib/tetra/glue_kit_item.rb +42 -0
  20. data/lib/tetra/jar_kit_item.rb +45 -0
  21. data/lib/tetra/kit.rb +73 -0
  22. data/lib/tetra/maven_kit_item.rb +64 -0
  23. data/lib/tetra/package.rb +82 -0
  24. data/lib/tetra/project.rb +26 -22
  25. data/lib/tetra/spec_generator.rb +38 -42
  26. data/lib/tetra/version.rb +1 -1
  27. data/spec/lib/archiver_spec.rb +30 -86
  28. data/spec/lib/git_spec.rb +8 -8
  29. data/spec/lib/glue_kit_item_spec.rb +31 -0
  30. data/spec/lib/kit_spec.rb +67 -0
  31. data/spec/lib/maven_kit_item_spec.rb +74 -0
  32. data/spec/lib/package_spec.rb +78 -0
  33. data/spec/lib/project_spec.rb +1 -1
  34. data/spec/lib/spec_generator_spec.rb +59 -87
  35. metadata +15 -8
  36. data/lib/template/kit.spec +0 -64
  37. data/lib/tetra/kit_spec_adapter.rb +0 -28
  38. data/lib/tetra/package_spec_adapter.rb +0 -59
  39. data/lib/tetra/template_manager.rb +0 -33
  40. data/spec/lib/template_manager_spec.rb +0 -54
@@ -3,14 +3,14 @@
3
3
  module Tetra
4
4
  # tetra generate-kit-archive
5
5
  class GenerateKitArchiveCommand < Tetra::BaseCommand
6
- option %w(-w --whole), :flag, "recreate the whole archive (not incremental)"
7
-
8
6
  def execute
9
7
  checking_exceptions do
10
8
  project = Tetra::Project.new(".")
11
9
  ensure_dry_running(false, project) do
12
- result_path = Tetra::Archiver.new(project).archive_kit(whole?)
13
- print_generation_result(project, result_path)
10
+ Tetra::Kit.new(project).items.each do |item|
11
+ result_path = item.to_archive
12
+ print_generation_result(project, result_path)
13
+ end
14
14
  end
15
15
  end
16
16
  end
@@ -7,8 +7,10 @@ module Tetra
7
7
  checking_exceptions do
8
8
  project = Tetra::Project.new(".")
9
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)
10
+ Tetra::Kit.new(project).items.each do |item|
11
+ result_path, conflict_count = item.to_spec
12
+ print_generation_result(project, result_path, conflict_count)
13
+ end
12
14
  end
13
15
  end
14
16
  end
@@ -10,7 +10,7 @@ module Tetra
10
10
  project = Tetra::Project.new(".")
11
11
  ensure_dry_running(false, project) do
12
12
  package_name = project.get_package_name(directory)
13
- result_path = Tetra::Archiver.new(project).archive_package package_name
13
+ result_path = Tetra::Package.new(project, package_name).to_archive
14
14
  print_generation_result(project, result_path)
15
15
  end
16
16
  end
@@ -12,8 +12,8 @@ module Tetra
12
12
  project = Tetra::Project.new(".")
13
13
  ensure_dry_running(false, project) do
14
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)
15
+ result_path, conflict_count =
16
+ Tetra::Package.new(project, package_name, pom, filter).to_spec
17
17
  print_generation_result(project, result_path, conflict_count)
18
18
  end
19
19
  end
data/lib/tetra/git.rb CHANGED
@@ -46,10 +46,10 @@ module Tetra
46
46
  end
47
47
  end
48
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)
49
+ # adds all files in the current directory, removes
50
+ # all files not in the current directory, commits
51
+ # and tags with prefix
52
+ def commit_whole_directory(message, tag, tag_message = nil)
53
53
  Dir.chdir(@directory) do
54
54
  log.debug "committing with message: #{message}"
55
55
 
@@ -65,16 +65,25 @@ module Tetra
65
65
  `git add .`
66
66
  `git commit -m "#{message}"`
67
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
68
+ if !tag_message.nil?
69
+ `git tag tetra_#{tag} -m "#{tag_message}"`
70
+ else
71
+ `git tag tetra_#{tag}`
74
72
  end
75
73
  end
76
74
  end
77
75
 
76
+ # commits and tags one single file
77
+ # if tag is given, commit is also tagged
78
+ def commit_file(path, message, tag)
79
+ Dir.chdir(@directory) do
80
+ log.debug "committing path #{path} with message: #{message}"
81
+ `git add #{path}`
82
+ `git commit -m "#{message}"`
83
+ `git tag tetra_#{tag}`
84
+ end
85
+ end
86
+
78
87
  # returns the highest suffix found in tags with the given prefix
79
88
  def get_tag_maximum_suffix(prefix)
80
89
  Dir.chdir(@directory) do
@@ -0,0 +1,42 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # represents a prebuilt package dependency from a jar file
5
+ # in a kit
6
+ class GlueKitItem
7
+ # implement to_spec
8
+ include SpecGenerator
9
+ attr_reader :project
10
+ attr_reader :package_name
11
+ attr_reader :spec_dir
12
+ attr_reader :template_spec_name
13
+ attr_reader :conflicts
14
+
15
+ # implement to_archive
16
+ include Archiver
17
+ attr_reader :source_dir
18
+ attr_reader :source_paths
19
+ attr_reader :destination_dir
20
+
21
+ # template-specific attributes
22
+ attr_reader :provides_symbol
23
+ attr_reader :provides_version
24
+ attr_reader :install_dir
25
+
26
+ def initialize(project, source_paths)
27
+ @project = project
28
+ @package_name = "kit-item-glue-#{project.name}"
29
+ @spec_dir = "kit"
30
+ @template_spec_name = "kit_item.spec"
31
+ @conflicts = true
32
+
33
+ @source_dir = File.join("kit")
34
+ @source_paths = source_paths
35
+ @destination_dir = @package_name
36
+
37
+ @provides_symbol = "tetra-glue"
38
+ @provides_version = "#{project.name}-#{project.version}"
39
+ @install_dir = ""
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # represents a prebuilt package dependency from a jar file
5
+ # in a kit
6
+ class JarKitItem
7
+ # implement to_spec
8
+ include SpecGenerator
9
+ attr_reader :project
10
+ attr_reader :package_name
11
+ attr_reader :spec_dir
12
+ attr_reader :template_spec_name
13
+ attr_reader :conflicts
14
+
15
+ # implement to_archive
16
+ include Archiver
17
+ attr_reader :source_dir
18
+ attr_reader :source_paths
19
+ attr_reader :destination_dir
20
+
21
+ # template-specific attributes
22
+ attr_reader :provides_symbol
23
+ attr_reader :provides_version
24
+ attr_reader :install_dir
25
+
26
+ def initialize(project, path)
27
+ _, name = Pathname.new(path).split
28
+ hash = Digest::SHA1.file(path).hexdigest
29
+
30
+ @project = project
31
+ @package_name = "kit-item-#{name.to_s.gsub(".", "-")}"
32
+ @spec_dir = "kit"
33
+ @template_spec_name = "kit_item.spec"
34
+ @conflicts = false
35
+
36
+ @source_dir = File.join("kit", "jars")
37
+ @source_paths = [path]
38
+ @destination_dir = @package_name
39
+
40
+ @provides_symbol = "tetra-jar(#{name})"
41
+ @provides_version = hash
42
+ @install_dir = "jars"
43
+ end
44
+ end
45
+ end
data/lib/tetra/kit.rb ADDED
@@ -0,0 +1,73 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # represents a set of binary dependency packages
5
+ class Kit
6
+ include Logging
7
+
8
+ def initialize(project)
9
+ @project = project
10
+ end
11
+
12
+ def items
13
+ managed_items = maven_kit_items + jar_kit_items
14
+
15
+ managed_items + glue_kit_items(managed_items)
16
+ end
17
+
18
+ def maven_kit_items
19
+ @project.from_directory(File.join("kit", "m2")) do
20
+ files_in_dir = {}
21
+ poms = []
22
+ Find.find(".") do |file|
23
+ dir = File.dirname(file)
24
+ if files_in_dir.key?(dir)
25
+ files_in_dir[dir] << file
26
+ else
27
+ files_in_dir[dir] = [file]
28
+ end
29
+
30
+ if file =~ /\.pom$/
31
+ log.debug "pom found in #{file}"
32
+ poms << file
33
+ end
34
+ end
35
+
36
+ poms.map do |pom|
37
+ Tetra::MavenKitItem.new(@project, pom, files_in_dir[File.dirname(pom)])
38
+ end
39
+ end
40
+ end
41
+
42
+ def jar_kit_items
43
+ @project.from_directory(File.join("kit", "jars")) do
44
+ Pathname.new(".").children.select do |child|
45
+ child.to_s =~ /.jar$/
46
+ end.sort.map do |jar|
47
+ Tetra::JarKitItem.new(@project, jar)
48
+ end
49
+ end
50
+ end
51
+
52
+ def glue_kit_items(managed_items)
53
+ managed_files = managed_items.map do |item|
54
+ item.source_paths.map do |e|
55
+ Pathname.new(File.join(item.source_dir, e)).cleanpath
56
+ end
57
+ end.flatten
58
+
59
+ unmanaged_files = []
60
+
61
+ @project.from_directory do
62
+ Find.find("kit") do |file|
63
+ pathname = Pathname.new(file)
64
+ if !managed_files.include?(pathname) && !File.directory?(pathname)
65
+ unmanaged_files << pathname.relative_path_from(Pathname.new("kit"))
66
+ end
67
+ end
68
+ end
69
+
70
+ [Tetra::GlueKitItem.new(@project, unmanaged_files)]
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # represents a prebuilt package dependency from a Maven local repo
5
+ # in a kit
6
+ class MavenKitItem
7
+ # implement to_spec
8
+ include SpecGenerator
9
+ attr_reader :project
10
+ attr_reader :package_name
11
+ attr_reader :spec_dir
12
+ attr_reader :template_spec_name
13
+ attr_reader :conflicts
14
+
15
+ # implement to_archive
16
+ include Archiver
17
+ attr_reader :source_dir
18
+ attr_reader :source_paths
19
+ attr_reader :destination_dir
20
+
21
+ # template-specific attributes
22
+ attr_reader :provides_symbol
23
+ attr_reader :provides_version
24
+ attr_reader :install_dir
25
+
26
+ def initialize(project, pom, source_paths)
27
+ path, _ = path_split(pom)
28
+ rest, version = path_split(path)
29
+ group_directory, artifact_id = path_split(rest)
30
+ group_id = path_to_group(group_directory)
31
+
32
+ @project = project
33
+ @package_name = "kit-item-#{group_id.gsub(".", "-")}-#{artifact_id}-#{version}"
34
+ @spec_dir = "kit"
35
+ @template_spec_name = "kit_item.spec"
36
+ @conflicts = false
37
+
38
+ @provides_symbol = "tetra-mvn(#{group_id}:#{artifact_id})"
39
+ @provides_version = version
40
+ @install_dir = "m2"
41
+
42
+ @source_dir = File.join("kit", "m2")
43
+ @source_paths = source_paths
44
+ @destination_dir = @package_name
45
+ end
46
+
47
+ private
48
+
49
+ # splits a path string into a [head, tail] string couple
50
+ def path_split(path)
51
+ Pathname.new(path).split.map { |e| e.to_s }
52
+ end
53
+
54
+ # transforms a path into a Maven group
55
+ def path_to_group(path)
56
+ splits = path_split(path)
57
+ if splits[0] == "."
58
+ return splits[1]
59
+ else
60
+ return "#{path_to_group(splits[0])}.#{splits[1]}"
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tetra
4
+ # represents a Java project package in Tetra, corresponding to a directory
5
+ # in src/
6
+ class Package
7
+ extend Forwardable
8
+ include SpecGenerator
9
+
10
+ attr_reader :name
11
+
12
+ def_delegator :@project, :name, :project_name
13
+
14
+ def_delegator :@kit, :items, :kit_items
15
+
16
+ def_delegator :@pom, :license_name, :license
17
+ def_delegator :@pom, :url
18
+ def_delegator :@pom, :group_id
19
+ def_delegator :@pom, :artifact_id
20
+ def_delegator :@pom, :version
21
+ def_delegator :@pom, :runtime_dependency_ids
22
+
23
+ # implement to_archive
24
+ include Archiver
25
+ attr_reader :source_dir
26
+ attr_reader :source_paths
27
+ attr_reader :destination_dir
28
+
29
+ def initialize(project, name, pom_path = nil, filter = nil)
30
+ @project = project
31
+ @kit = Tetra::Kit.new(project)
32
+ @name = name
33
+ @pom = pom_path.nil? ? nil : Tetra::Pom.new(pom_path)
34
+ @filter = filter
35
+
36
+ @source_dir = File.join("src", name)
37
+ @source_paths = ["*"]
38
+ @destination_dir = name
39
+ end
40
+
41
+ # a short summary from the POM
42
+ def summary
43
+ cleanup_description(@pom.description, 60)
44
+ end
45
+
46
+ # a long summary from the POM
47
+ def description
48
+ cleanup_description(@pom.description, 1500)
49
+ end
50
+
51
+ # files produced by this package
52
+ def outputs
53
+ @project.get_produced_files(@name).select do |file|
54
+ File.fnmatch?(@filter, File.basename(file))
55
+ end
56
+ end
57
+
58
+ def cleanup_description(raw, max_length)
59
+ raw
60
+ .gsub(/[\s]+/, " ")
61
+ .strip
62
+ .slice(0..max_length - 1)
63
+ .sub(/\s\w+$/, "")
64
+ .sub(/\.+$/, "")
65
+ end
66
+
67
+ # needed by SpecGenerator
68
+ attr_reader :project
69
+
70
+ def package_name
71
+ name
72
+ end
73
+
74
+ def spec_dir
75
+ File.join("src", name)
76
+ end
77
+
78
+ def template_spec_name
79
+ "package.spec"
80
+ end
81
+ end
82
+ end
data/lib/tetra/project.rb CHANGED
@@ -61,19 +61,26 @@ module Tetra
61
61
  Dir.chdir(dir) do
62
62
  Tetra::Git.new(".").init
63
63
 
64
- FileUtils.mkdir_p "src"
65
- FileUtils.mkdir_p "kit"
64
+ FileUtils.mkdir_p("src")
65
+ FileUtils.mkdir_p("kit")
66
66
 
67
67
  # populate the project with templates and take a snapshot
68
68
  project = Project.new(".")
69
69
 
70
- template_manager = Tetra::TemplateManager.new
71
- template_manager.copy "output", "."
72
- template_manager.copy "kit", "."
73
- template_manager.copy "src", "."
74
- template_manager.copy "gitignore", ".gitignore"
70
+ template_path = File.join(File.dirname(__FILE__), "..", "template")
75
71
 
76
- project.take_snapshot "Template files added", :init
72
+ templates = {
73
+ "output" => ".",
74
+ "kit" => ".",
75
+ "src" => ".",
76
+ "gitignore" => ".gitignore"
77
+ }
78
+
79
+ templates.each do |source, destination|
80
+ FileUtils.cp_r(File.join(template_path, source), destination)
81
+ end
82
+
83
+ project.take_snapshot("Template files added", :init)
77
84
  end
78
85
  end
79
86
 
@@ -83,7 +90,7 @@ module Tetra
83
90
  def dry_run
84
91
  return false if dry_running?
85
92
 
86
- current_directory = Pathname.new(Dir.pwd).relative_path_from Pathname.new(@full_path)
93
+ current_directory = Pathname.new(Dir.pwd).relative_path_from(Pathname.new(@full_path))
87
94
 
88
95
  take_snapshot("Dry-run started", :dry_run_started, current_directory)
89
96
  true
@@ -103,11 +110,11 @@ module Tetra
103
110
  @git.revert_whole_directory(".", latest_tag(:dry_run_started))
104
111
  @git.delete_tag(latest_tag(:dry_run_started))
105
112
  else
106
- take_snapshot "Changes during dry-run", :dry_run_changed
113
+ take_snapshot("Changes during dry-run", :dry_run_changed)
107
114
 
108
115
  @git.revert_whole_directory("src", latest_tag(:dry_run_started))
109
116
 
110
- take_snapshot "Dry run finished", :dry_run_finished
117
+ take_snapshot("Dry run finished", :dry_run_finished)
111
118
  end
112
119
  return true
113
120
  end
@@ -115,16 +122,8 @@ module Tetra
115
122
  end
116
123
 
117
124
  # takes a revertable snapshot of this project
118
- def take_snapshot(message, tag_prefix = nil, tag_message = nil)
119
- tag = (
120
- if tag_prefix
121
- "#{tag_prefix}_#{latest_tag_count(tag_prefix) + 1}"
122
- else
123
- nil
124
- end
125
- )
126
-
127
- @git.commit_whole_directory(message, tag, tag_message)
125
+ def take_snapshot(message, tag_prefix, tag_message = nil)
126
+ @git.commit_whole_directory(message, next_tag(tag_prefix), tag_message)
128
127
  end
129
128
 
130
129
  # replaces content in path with new_content, takes a snapshot using
@@ -144,7 +143,7 @@ module Tetra
144
143
 
145
144
  File.open(path, "w") { |io| io.write(new_content) }
146
145
  log.debug "taking snapshot with new content: #{snapshot_message}"
147
- take_snapshot(snapshot_message, tag_prefix)
146
+ @git.commit_file(path, snapshot_message, next_tag(tag_prefix))
148
147
 
149
148
  if already_existing
150
149
  if previous_tag == ""
@@ -172,6 +171,11 @@ module Tetra
172
171
  @git.get_tag_maximum_suffix(prefix)
173
172
  end
174
173
 
174
+ # returns the next tag for a given tag prefix
175
+ def next_tag(prefix)
176
+ "#{prefix}_#{latest_tag_count(prefix) + 1}"
177
+ end
178
+
175
179
  # runs a block from the project directory or a subdirectory
176
180
  def from_directory(subdirectory = "")
177
181
  Dir.chdir(File.join(@full_path, subdirectory)) do