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.

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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)
[View source]

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
[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

def name
  File.basename(@full_path)
end

#packages_dirObject

[View source]

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

[View source]

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

[View source]

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

[View source]

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)
[View source]

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

[View source]

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

[View source]

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