Class: Tetra::Project

Inherits:
Object
  • Object
show all
Includes:
Logging, ProjectIniter
Defined in:
lib/tetra/project.rb

Overview

encapsulates a Tetra project directory

Constant Summary collapse

TEMPLATE_PATH =

path of the project template files

File.join(File.dirname(__FILE__), "..", "template")

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

#log

Methods included from ProjectIniter

#commit_source_archive, included, #template_files

Constructor Details

#initialize(path) ⇒ Project

Returns a new instance of Project.



14
15
16
17
# File 'lib/tetra/project.rb', line 14

def initialize(path)
  @full_path = Tetra::Project.find_project_dir(File.expand_path(path))
  @git = Tetra::Git.new(@full_path)
end

Instance Attribute Details

#full_pathObject (readonly)

Returns the value of attribute full_path.



12
13
14
# File 'lib/tetra/project.rb', line 12

def full_path
  @full_path
end

Class Method Details

.find_project_dir(starting_dir) ⇒ Object

finds the project directory up in the tree, like git does



32
33
34
35
36
37
38
39
40
41
# File 'lib/tetra/project.rb', line 32

def self.find_project_dir(starting_dir)
  result = starting_dir
  while project?(result) == false && result != "/"
    result = File.expand_path("..", result)
  end

  fail NoProjectDirectoryError, starting_dir if result == "/"

  result
end

Instance Method Details

#abortObject

ends a dry-run assuming the build went wrong reverts src/ and kit/ directories



89
90
91
92
# File 'lib/tetra/project.rb', line 89

def abort
  @git.revert_directories(%w(src kit), @git.latest_id("tetra: dry-run-started"))
  @git.undo_last_commit
end

#archive_kitObject

archives a tarball of kit/ in packages/ the latest commit marked as dry-run-finished is taken as the version



177
178
179
180
181
182
183
# File 'lib/tetra/project.rb', line 177

def archive_kit
  from_directory do
    id = @git.latest_id("tetra: dry-run-finished")
    destination_path = File.join(full_path, packages_dir, "#{name}-kit", "#{name}-kit.tar.xz")
    @git.archive("kit", id, destination_path)
  end
end

#build_script_linesObject



167
168
169
170
171
172
173
# File 'lib/tetra/project.rb', line 167

def build_script_lines
  @git.latest_comment("tetra: dry-run-finished")
    .split("\n")
    .map { |line| line[/^tetra: build-script-line: (.+)$/, 1] }
    .compact
    .sort
end

#commit_sources(message, new_tarball) ⇒ Object

commits files in the src/ dir as a patch or tarball update



95
96
97
98
99
100
101
102
103
104
# File 'lib/tetra/project.rb', line 95

def commit_sources(message, new_tarball)
  from_directory do
    comments = "#{message}\n"
    if new_tarball
      comments << "\ntetra: sources-tarball"
      @git.disable_special_files("src")
    end
    @git.commit_directories(["src"], comments)
  end
end

#dry_runObject

starts a dry running phase: files added to kit/ will be added to the kit package, src/ will be reset at the current state when finished



54
55
56
57
58
# File 'lib/tetra/project.rb', line 54

def dry_run
  current_directory = Pathname.new(Dir.pwd).relative_path_from(Pathname.new(@full_path))

  @git.commit_directories(%w(src kit), "Dry-run started\n\ntetra: dry-run-started: #{current_directory}")
end

#dry_running?Boolean

returns true iff we are currently dry-running

Returns:

  • (Boolean)


61
62
63
64
# File 'lib/tetra/project.rb', line 61

def dry_running?
  latest_comment = @git.latest_comment("tetra: dry-run-")
  !latest_comment.nil? && !(latest_comment =~ /tetra: dry-run-finished/)
end

#finish(build_script_lines) ⇒ Object

ends a dry-run assuming a successful build:

- reverts sources as before dry-run
- saves the list of generated files in git comments
- saves the build script lines in git comments


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/tetra/project.rb', line 70

def finish(build_script_lines)
  # keep track of changed files
  start_id = @git.latest_id("tetra: dry-run-started")
  changed_files = @git.changed_files("src", start_id)

  # revert to pre-dry-run status
  @git.revert_directories(["src"], start_id)

  # prepare commit comments
  comments = ["Dry run finished\n", "tetra: dry-run-finished"]
  comments += changed_files.map { |f| "tetra: file-changed: #{f}" }
  comments += build_script_lines.map { |l| "tetra: build-script-line: #{l}" }

  # commit end of dry run
  @git.commit_directories(["kit"], comments.join("\n"))
end

#from_directory(subdirectory = "") ⇒ Object

runs a block from the project directory or a subdirectory



147
148
149
150
151
# File 'lib/tetra/project.rb', line 147

def from_directory(subdirectory = "")
  Dir.chdir(File.join(@full_path, subdirectory)) do
    yield
  end
end

#latest_dry_run_directoryObject

returns the latest dry run start directory



154
155
156
# File 'lib/tetra/project.rb', line 154

def latest_dry_run_directory
  @git.latest_comment("tetra: dry-run-started")[/tetra: dry-run-started: (.*)$/, 1]
end

#merge_new_content(new_content, path, comment, kind) ⇒ Object

replaces content in path with new_content, commits using comment and 3-way merges new and old content with the previous version of file of the same kind, if it exists. returns the number of conflicts



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/tetra/project.rb', line 110

def merge_new_content(new_content, path, comment, kind)
  from_directory do
    log.debug "merging new content to #{path} of kind #{kind}"
    already_existing = File.exist?(path)

    generated_comment = "tetra: generated-#{kind}"
    whole_comment = [comment, generated_comment].join("\n\n")

    if already_existing
      unless @git.latest_id(generated_comment)
        log.debug "committing new file"
        @git.commit_file(path, whole_comment)
      end
      log.debug "moving #{path} to #{path}.tetra_user_edited"
      File.rename(path, "#{path}.tetra_user_edited")
    end

    previous_id = @git.latest_id(generated_comment)

    File.open(path, "w") { |io| io.write(new_content) }
    log.debug "committing new content: #{comment}"
    @git.commit_file(path, whole_comment)

    if already_existing
      # 3-way merge
      conflict_count = @git.merge_with_id(path, "#{path}.tetra_user_edited", previous_id)
      File.delete("#{path}.tetra_user_edited")

      @git.commit_file(path, "User changes merged back") if conflict_count == 0

      return conflict_count
    end
    return 0
  end
end

#nameObject



19
20
21
# File 'lib/tetra/project.rb', line 19

def name
  File.basename(@full_path)
end

#packages_dirObject



27
28
29
# File 'lib/tetra/project.rb', line 27

def packages_dir
  "packages"
end

#produced_filesObject

returns a list of files produced during the last dry-run



159
160
161
162
163
164
165
# File 'lib/tetra/project.rb', line 159

def produced_files
  @git.latest_comment("tetra: dry-run-finished")
    .split("\n")
    .map { |line| line[%r{^tetra: file-changed: src/(.+)$}, 1] }
    .compact
    .sort
end

#purge_jarsObject

moves any .jar from src/ to kit/ and links it back



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/tetra/project.rb', line 210

def purge_jars
  from_directory do
    result = []
    Find.find("src") do |file|
      next unless file =~ /.jar$/ && !File.symlink?(file)

      new_location = File.join("kit", "jars", Pathname.new(file).split[1])
      FileUtils.mv(file, new_location)

      link_target = Pathname.new(new_location)
                    .relative_path_from(Pathname.new(file).split.first)
                    .to_s

      File.symlink(link_target, file)
      result << [file, new_location]
    end

    result
  end
end

#src_archiveObject

returns the name of the source archive file, if any



186
187
188
189
190
191
192
193
194
195
# File 'lib/tetra/project.rb', line 186

def src_archive
  from_directory do
    Find.find(File.join("packages", name)) do |file|
      if File.file?(file) && file.match(/\.(spec)|(sh)|(patch)$/).nil?
        return File.basename(file)
      end
    end
    nil
  end
end

#src_patched?Boolean

checks whether there were edits to src/ since last mark

Returns:

  • (Boolean)


45
46
47
48
49
# File 'lib/tetra/project.rb', line 45

def src_patched?
  from_directory do
    @git.changed_files("src", "HEAD").any?
  end
end

#versionObject



23
24
25
# File 'lib/tetra/project.rb', line 23

def version
  @git.latest_id("tetra: dry-run-finished")
end

#write_source_patchesObject

generates patches of src/ in packages/ the latest commit marked as tarball is taken as the base version, other commits are assumed to be patches on top returns filenames



201
202
203
204
205
206
207
# File 'lib/tetra/project.rb', line 201

def write_source_patches
  from_directory do
    id = @git.latest_id("tetra: sources-tarball")
    destination_path = File.join(full_path, packages_dir, name)
    @git.format_patch("src", id, destination_path)
  end
end