Class: TestIds::Git

Inherits:
Object
  • Object
show all
Includes:
Origen::Utility::InputCapture
Defined in:
lib/test_ids/git.rb

Overview

The Git driver is responsible for committing and fetching the store from the central Git repository.

All operations are automatically pushed immediately to the central repository and a lock will be taken out whenever a program generation operation is done in production mode to prevent the need to merge with other users.

An instance of this class is instantiated as TestIds.git

Defined Under Namespace

Classes: PathToLocal

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Git

Returns a new instance of Git.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/test_ids/git.rb', line 52

def initialize(options)
  if !(TestIds.lsf_manual_init_shutdown) && Origen.running_locally?
    unless File.exist?("#{options[:local]}/.git")
      FileUtils.rm_rf(options[:local]) if File.exist?(options[:local])
      FileUtils.mkdir_p(options[:local])
      Dir.chdir options[:local] do
        `git clone #{options[:remote]} .`
        unless File.exist?('lock.json')
          # Should really try to use the Git driver for this
          exec 'touch lock.json'
          exec 'git add lock.json'
          exec 'git commit -m "Initial commit"'
          exec 'git push'
        end
      end
    end
    @local = options[:local]
    @repo = ::Git.open(options[:local])
    # Get rid of any local edits coming in here, this is only called once at the start
    # of the program generation run.
    # No need to pull latest as that will be done when we obtain a lock.
    @repo.reset_hard
  end
end

Instance Attribute Details

#localObject (readonly)

Returns the value of attribute local.



15
16
17
# File 'lib/test_ids/git.rb', line 15

def local
  @local
end

#repoObject (readonly)

Returns the value of attribute repo.



15
16
17
# File 'lib/test_ids/git.rb', line 15

def repo
  @repo
end

Class Method Details

.path_to_localObject

Returns a path to the local test IDs repo, if multiple are found the user will be prompted to choose one



47
48
49
50
# File 'lib/test_ids/git.rb', line 47

def self.path_to_local
  # Implemented as a class as a hack to get access to InputCapture
  PathToLocal.new.find
end

Instance Method Details

#available_to_lock?(repo_to_use) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/test_ids/git.rb', line 160

def available_to_lock?(repo_to_use)
  result = false
  Origen.profile 'Checking for lock' do
    repo_to_use.fetch
    repo_to_use.reset_hard('origin/master')
    if lock_content && lock_user && lock_user != User.current.name
      result = Time.now.to_f > lock_expires
    else
      result = true
    end
  end
  result
end

#exec(cmd) ⇒ Object



105
106
107
108
109
110
# File 'lib/test_ids/git.rb', line 105

def exec(cmd)
  r = system(cmd)
  unless r
    fail "Something went wrong running command: #{cmd}"
  end
end

#get_lockObject



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

def get_lock
  if !(TestIds.lsf_manual_init_shutdown) && Origen.running_locally?
    return if @lock_open
    Origen.profile 'Obtaining test IDs lock' do
      until available_to_lock?(@repo)
        puts
        puts "Waiting for lock, currently locked by #{lock_user} (the lock will expire in less than #{lock_minutes_remaining} #{'minute'.pluralize(lock_minutes_remaining)} if not released before that)"
        puts
        sleep 5
      end
      data = {
        'user'    => User.current.name,
        'expires' => (Time.now + minutes(5)).to_f
      }
      write('lock.json', JSON.pretty_generate(data))
      repo.commit('Obtaining lock')
      repo.push('origin')
    end
    @lock_open = true
  end
end

#lock_contentObject



186
187
188
189
# File 'lib/test_ids/git.rb', line 186

def lock_content
  f = File.join(local, 'lock.json')
  JSON.load(File.read(f)) if File.exist?(f)
end

#lock_expiresObject



178
179
180
# File 'lib/test_ids/git.rb', line 178

def lock_expires
  lock_content['expires']
end

#lock_minutes_remainingObject



174
175
176
# File 'lib/test_ids/git.rb', line 174

def lock_minutes_remaining
  ((lock_expires - Time.now.to_f) / 60).ceil
end

#lock_userObject



182
183
184
# File 'lib/test_ids/git.rb', line 182

def lock_user
  lock_content['user']
end

#minutes(number) ⇒ Object



191
192
193
# File 'lib/test_ids/git.rb', line 191

def minutes(number)
  number * 60
end

#publishObject



112
113
114
115
116
117
118
119
120
121
# File 'lib/test_ids/git.rb', line 112

def publish
  if !(TestIds.lsf_manual_init_shutdown) && Origen.running_locally?
    Origen.profile 'Publishing the test IDs store' do
      release_lock
      repo.add  # Checkin everything
      repo.commit('Publishing latest store')
      repo.push('origin', 'master', force: true)
    end
  end
end

#release_lockObject



152
153
154
155
156
157
158
# File 'lib/test_ids/git.rb', line 152

def release_lock
  data = {
    'user'    => nil,
    'expires' => nil
  }
  write('lock.json', JSON.pretty_generate(data))
end

#rollback(id) ⇒ Object

Roll the repo back to the given commit ID



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/test_ids/git.rb', line 78

def rollback(id)
  name = Pathname.new(local).basename.to_s
  begin
    commit = repo.object(id)
  rescue ::Git::GitExecuteError
    puts 'The given commit ID cannot be found in that repository'
    exit
  end
  # day = 24 * 60 * 60
  # if commit.date < Time.now - (7 * day)
  #  puts "Sorry, that commit is more than a week old and I'm too scared to rollback that far."
  #  puts 'You will need to do that manually if you must.'
  #  exit
  # end
  puts
  puts "About to rollback the TestIds repository #{name} to commit #{id}."
  puts
  puts 'This will permanently delete any IDs assigned by anyone, anywhere, since that commit.'
  puts
  puts 'ARE YOU SURE YOU KNOW WHAT YOU ARE DOING?'
  puts
  get_text(confirm: true, default: 'no')
  repo.reset_hard(id)
  repo.push('origin', 'master', force: true)
  puts 'As you wish, rolled back successfully!'
end

#write(path, data = nil) ⇒ Object

Writes the data to the given file and pushes to the remote repo



124
125
126
127
128
# File 'lib/test_ids/git.rb', line 124

def write(path, data = nil)
  f = File.join(local, path)
  File.write(f, data) if data
  repo.add(f)
end