Class: CodeRunner::Repository

Inherits:
Git::Base
  • Object
show all
Defined in:
lib/coderunner/repository.rb

Overview

This is a class which implements methods for managing a CodeRunner repository, which is a slightly customised git repository. It contains methods for initializing standard files, and maintains a small amount of metadata about the repository. In addition, every clone of coderunner repository comes in a pair: one bare repository, and one local repository, which is a clone of the bare repository. This allows easy synchronisation of working directories without the need for a central server which all working directories have access to.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.bare_ext_regObject



51
52
53
# File 'lib/coderunner/repository.rb', line 51

def self.bare_ext_reg
  /\.cr\.git$/
end

.check_bare_ext(barefolder) ⇒ Object

Check that barefolder ends in .cr.git



253
254
255
256
257
# File 'lib/coderunner/repository.rb', line 253

def self.check_bare_ext(barefolder)
  unless barefolder =~ bare_ext_reg
    raise "Remotes must end in .cr.git for coderunnerrepo"
  end
end

.clone(url, name) ⇒ Object



74
75
76
77
78
79
# File 'lib/coderunner/repository.rb', line 74

def clone(url, name)
  namehost, folder, _barefolder = split_url(url)
  try_system %[ssh #{namehost} "cd #{folder} && git push origin"]
  simple_clone(url, bflocal=name+'.cr.git', bare: true, repository: bflocal)  
  return simple_clone(bflocal, name)  
end

.init(folder) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/coderunner/repository.rb', line 61

def init(folder)
  if folder =~ /\.git$/
    raise "Please do not add '.git' to the end of #{folder}. Two repositories will be created: a bare repo ending in .cr.git and a clone of this bare repo"
  end
  super(bflocal = folder + '.cr.git', bare: true, repository: bflocal)
  repo = simple_clone(bflocal, folder)
  repo.
  repo.init_readme
  repo.init_defaults_folder
  p 'remotes', repo.remotes.map{|r| r.name}
  repo.simple_push(repo.remote("origin"))
end

.open_in_subfolder(folder = Dir.pwd) ⇒ Object

Open a git object from within a subfolder of a repository Checks to see if the subfolder actually is inside a CodeRunner repository.



98
99
100
101
102
# File 'lib/coderunner/repository.rb', line 98

def self.open_in_subfolder(folder = Dir.pwd)
  f2 = repo_folder(folder)
  raise "#{folder} is not a coderunner repository " if not f2
  return open(f2)
end

.repo_folder(folder = Dir.pwd) ⇒ Object

If the folder is within a coderunner repository return the root folder of the repository; else return nil



85
86
87
88
89
90
91
92
93
94
# File 'lib/coderunner/repository.rb', line 85

def self.repo_folder(folder = Dir.pwd)
  f2 = File.expand_path(folder)
  while not (Dir.entries(f2).include?('.git') and 
        Dir.entries(f2).include?('.code_runner_repo_metadata'))
    f2 = File.expand_path(f2 + '/..')
    (f2=nil; break) if f2 == '/' 
    #p 'f2 is ', f2
  end
  return f2
end

.simple_cloneObject



73
# File 'lib/coderunner/repository.rb', line 73

alias :simple_clone :clone

.simple_initObject



60
# File 'lib/coderunner/repository.rb', line 60

alias :simple_init :init

.split_url(url) ⇒ Object



187
188
189
190
191
192
193
194
# File 'lib/coderunner/repository.rb', line 187

def self.split_url(url)
  url =~ Repository.url_regex
  namehost = $~[:namehost]
  barefolder = $~[:folder]
  check_bare_ext(barefolder)
  folder = barefolder.sub(/\.cr\.git$/, '')
  return [namehost, folder, barefolder]
end

.try_system(str) ⇒ Object



301
302
303
# File 'lib/coderunner/repository.rb', line 301

def self.try_system(str)
  RepositoryManager.try_system(str)
end

.url_regexObject



48
49
50
# File 'lib/coderunner/repository.rb', line 48

def self.url_regex
  (/(?:ssh:\/\/)?(?<namehost>[^\/:]+):?(?<folder>.*$)/)
end

Instance Method Details

#add_folder(folder) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/coderunner/repository.rb', line 131

def add_folder(folder)
  Dir.chdir(folder) do
    require 'find'
    #files = []
    Find.find('.') { |e| (puts e; add(e)) if
      e =~ /code_runner_info.rb/ or
      e =~ /code_runner_results.rb/ or 
      e =~ /.code-runner-irb-save-history/ or
      e =~ /.code_runner_script_defaults.rb/ or
      (Dir.entries(Dir.pwd).include?('.code_runner_script_defaults') and
       (repo_file_match = (
         rcp = CodeRunner.fetch_runner(Y: folder, U: true).run_class.rcp; 
         rcp.repo_file_match? ? rcp.repo_file_match : false); 
         repo_file_match =~ m
       )
      )
    }
  end
  autocommit_all("Added folder #{relative_path(folder)}")
end

#add_remote(name, url) ⇒ Object



243
244
245
246
247
248
249
250
# File 'lib/coderunner/repository.rb', line 243

def add_remote(name, url)
  url =~ Repository.url_regex
  barefolder = $~[:folder]
  unless barefolder =~ Repository.bare_ext_reg
    raise "All remotes must end in .cr.git for coderunnerrepo"
  end
  super(name, url)
end

#autocommit(*args) ⇒ Object



151
152
153
# File 'lib/coderunner/repository.rb', line 151

def autocommit(*args)
  commit(*args) if [:autocommit]
end

#autocommit_all(*args) ⇒ Object



154
155
156
# File 'lib/coderunner/repository.rb', line 154

def autocommit_all(*args)
  commit_all(*args) if [:autocommit]
end

#bare_ext_regObject



259
260
261
# File 'lib/coderunner/repository.rb', line 259

def bare_ext_reg
  self.class.bare_ext_reg
end

#bare_repoObject

Returns a Git::Base object referring to the bare twin repository.



105
106
107
108
# File 'lib/coderunner/repository.rb', line 105

def bare_repo
  #puts 'bare_repo', dir.to_s + '.cr.git'
  @bare_repo ||= Git::Base.bare(dir.to_s + '.cr.git')
end

#deleted_in_folder(folder) ⇒ Object



202
203
204
# File 'lib/coderunner/repository.rb', line 202

def deleted_in_folder(folder)
  (status.deleted).find_all{|k,f| File.expand_path(dir.to_s + '/' + f.path).include?(File.expand_path(folder))}
end

#init_defaults_folderObject



157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/coderunner/repository.rb', line 157

def init_defaults_folder
  FileUtils.makedirs(repo_file("defaults_files"))
  File.open(repo_file("defaults_files/README"), "w"){|f|
     f.puts  <<EOF
This folder is where defaults files for codes should be placed, with
paths such as defaults_files/<code>crmod/my_defaults.rb. This folder 
will automatically be checked for defaults files when submitting simulations
within this repository.
EOF
  
  }
  add(repo_file("defaults_files/README"))
  autocommit_all('Added defaults folder')
end

#init_metadataObject



120
121
122
123
124
125
126
127
# File 'lib/coderunner/repository.rb', line 120

def 
  Hash.phoenix(repo_file('.code_runner_repo_metadata')) do |hash|
    hash[:creation_time] = Time.now.to_i
    hash[:autocommit] = true
  end
  add(repo_file('.code_runner_repo_metadata'))
  autocommit_all('Added metadata')
end

#init_readmeObject



115
116
117
118
119
# File 'lib/coderunner/repository.rb', line 115

def init_readme
  File.open(repo_file("README.md"), "w"){|f| f.puts readme_text}
  add(repo_file("README.md"))
  autocommit_all('Added README.md')
end

#metadataObject



128
129
130
# File 'lib/coderunner/repository.rb', line 128

def 
  Hash.phoenix(repo_file('.code_runner_repo_metadata'))
end

#modified?(file) ⇒ Boolean

Returns:

  • (Boolean)


205
206
207
# File 'lib/coderunner/repository.rb', line 205

def modified?(file)
  (status.changed + status.added).find{|k,f| File.expand_path(dir.to_s + '/' + f.path).include?(File.expand_path(file))}
end

#modified_in_folder(folder) ⇒ Object Also known as: changed_in_folder



198
199
200
# File 'lib/coderunner/repository.rb', line 198

def modified_in_folder(folder)
  (status.changed + status.added + status.deleted).find_all{|k,f| File.expand_path(dir.to_s + '/' + f.path).include?(File.expand_path(folder))}
end

#pull(remote) ⇒ Object

Pull from the given remote object. remote must be a remote object from the twin bare repo, i.e. a member of bare_repo.remotes NOT a remote from the coderunner repo (which only ever has one remote: origin, corresponding to the bare repo).



269
270
271
272
273
274
275
276
277
# File 'lib/coderunner/repository.rb', line 269

def pull(remote)
  namehost, folder, _barefolder = split_url(remote.name)
  try_system %[ssh #{namehost} "cd #{folder} && git push origin"]
  Dir.chdir(bare_repo.repo.to_s) do
    try_system("git fetch #{remote.name} master:master")
  end
  #bare_repo.fetch(remote)
  simple_pull(remote('origin'))
end

#push(remote) ⇒ Object

Push to the given remote object. remote must be a remote object from the twin bare repo, i.e. a member of bare_repo.remotes NOT a remote from the coderunner repo (which only ever has one remote: origin, corresponding to the bare repo).

First push to the bare ‘.git’ twin repo, then push that bare repo to the remote, then pull remote repos from the remote bare repos.



290
291
292
293
294
295
296
297
# File 'lib/coderunner/repository.rb', line 290

def push(remote)
  namehost, folder, _barefolder = split_url(remote.name)
  puts 'simple_push'
  simple_push(remote('origin'))
  puts 'bare_repo.push'
  bare_repo.push(remote)
  try_system %[ssh #{namehost} "cd #{folder} && git pull origin"]
end

#readme_textObject



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/coderunner/repository.rb', line 171

def readme_text
  return <<EOF
#{File.basename(dir.path)} CodeRunner Repository
================================================

This is a coderunner repository, which consists of
a managed set of simulation folders and defaults files which are 
synchronised across systems using git. 

This readme is a stub which was created automatically...
feel free to modify this and describe this repo.

Created on: #{Time.now.to_s}

EOF
end

#relative_path(folder = Dir.pwd) ⇒ Object



109
110
111
# File 'lib/coderunner/repository.rb', line 109

def relative_path(folder=Dir.pwd)
  File.expand_path(folder).sub(File.expand_path(dir.to_s) + '/', '')
end

#repo_file(path) ⇒ Object



112
113
114
# File 'lib/coderunner/repository.rb', line 112

def repo_file(path)
  "#{dir}/#{path}"
end

#rsyncd(remote_name, folder) ⇒ Object

Bring all files in the given folder from the given remote. (Obviously folder must be a subfolder within the repository).



211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/coderunner/repository.rb', line 211

def rsyncd(remote_name, folder)
  namehost, remote_folder, _barefolder = split_url(remote_name)
  rpath = relative_path(folder)
  if File.expand_path(folder) == File.expand_path(dir.to_s)
    raise "Cannot run rsyncd in the top level of a repository"
  end 
  string =  "rsync -av #{namehost}:#{remote_folder}/#{rpath}/ #{folder}/"
  if changed_in_folder(folder).size > 0
    raise "You have some uncommitted changes in the folder #{folder}. Please commit these changes before calling rsyncd"
  end
  puts string
  system string
end

#rsyncu(remote_name, folder) ⇒ Object

Send all files in the given folder to the given remote. (Obviously folder must be a subfolder within the repository).



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/coderunner/repository.rb', line 227

def rsyncu(remote_name, folder)
  namehost, remote_folder, _barefolder = split_url(remote_name)
  rpath = relative_path(folder)
  if File.expand_path(folder) == File.expand_path(dir.to_s)
    raise "Cannot run rsyncd in the top level of a repository"
  end 
  string =  "rsync -av  #{folder}/ #{namehost}:#{remote_folder}/#{rpath}/"

  cif = `ssh #{namehost} "cd #{remote_folder}/#{rpath} && echo "START" && git status"`
  if cif =~ /START.*modified/m
    raise "You have some uncommitted changes in the remote folder #{rpath}. Please commit these changes before calling rsyncu"
  end
  puts string
  system string
end

#simple_pullObject



263
# File 'lib/coderunner/repository.rb', line 263

alias :simple_pull :pull

#simple_pushObject

A simple git push… does not try to push to local bare repo or pull remote working repos



280
# File 'lib/coderunner/repository.rb', line 280

alias :simple_push :push

#split_url(remote_name) ⇒ Object



195
196
197
# File 'lib/coderunner/repository.rb', line 195

def split_url(remote_name)
  return self.class.split_url(bare_repo.remote(remote_name).url)
end

#try_system(str) ⇒ Object



298
299
300
# File 'lib/coderunner/repository.rb', line 298

def try_system(str)
  RepositoryManager.try_system(str)
end