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



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

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

.check_bare_ext(barefolder) ⇒ Object

Check that barefolder ends in .cr.git



234
235
236
237
238
# File 'lib/coderunner/repository.rb', line 234

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

.init(folder) ⇒ Object

Create a coderunner repo, which consists of a twin set of a bare repo and a clone of that repo. folder must end in ‘.cr.git’



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/coderunner/repository.rb', line 55

def self.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(folder + '.cr.git', bare: true)
  repo = clone(folder + '.cr.git', 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.



83
84
85
86
87
# File 'lib/coderunner/repository.rb', line 83

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



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

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

.url_regexObject



44
45
46
# File 'lib/coderunner/repository.rb', line 44

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

Instance Method Details

#add_folder(folder) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/coderunner/repository.rb', line 115

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



224
225
226
227
228
229
230
231
# File 'lib/coderunner/repository.rb', line 224

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



135
136
137
# File 'lib/coderunner/repository.rb', line 135

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

#autocommit_all(*args) ⇒ Object



138
139
140
# File 'lib/coderunner/repository.rb', line 138

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

#bare_ext_regObject



240
241
242
# File 'lib/coderunner/repository.rb', line 240

def bare_ext_reg
  self.class.bare_ext_reg
end

#bare_repoObject

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



90
91
92
# File 'lib/coderunner/repository.rb', line 90

def bare_repo
  @bare_repo ||= Git::Base.open(dir.to_s + '.cr.git')
end

#deleted_in_folder(folder) ⇒ Object



183
184
185
# File 'lib/coderunner/repository.rb', line 183

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



141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/coderunner/repository.rb', line 141

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



104
105
106
107
108
109
110
111
# File 'lib/coderunner/repository.rb', line 104

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



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

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



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

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

#modified?(file) ⇒ Boolean

Returns:

  • (Boolean)


186
187
188
# File 'lib/coderunner/repository.rb', line 186

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



179
180
181
# File 'lib/coderunner/repository.rb', line 179

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).



250
251
252
253
254
255
# File 'lib/coderunner/repository.rb', line 250

def pull(remote)
  namehost, folder, _barefolder = split_url(remote.name)
  try_system %[ssh #{namehost} "cd #{folder} && git push origin"]
  bare_repo.pull(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.



268
269
270
271
272
273
# File 'lib/coderunner/repository.rb', line 268

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

#readme_textObject



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

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



93
94
95
# File 'lib/coderunner/repository.rb', line 93

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

#repo_file(path) ⇒ Object



96
97
98
# File 'lib/coderunner/repository.rb', line 96

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).



192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/coderunner/repository.rb', line 192

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).



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

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



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

alias :simple_pull :pull

#simple_pushObject

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



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

alias :simple_push :push

#split_url(remote_name) ⇒ Object



171
172
173
174
175
176
177
178
# File 'lib/coderunner/repository.rb', line 171

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

#try_system(str) ⇒ Object



274
275
276
# File 'lib/coderunner/repository.rb', line 274

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