Module: HelixSync::Methods
- Included in:
- App
- Defined in:
- lib/helix_sync/methods.rb
Defined Under Namespace
Classes: Describe, Plan, ShelfMeta, Subplan
Instance Method Summary (collapse)
- - (Object) assume_client_ownership(client_name, root)
-
- (Object) create_classic_onedir_client(client_name, project_id, root)
Generate a new client that only contains the project mapping.
- - (Object) create_client(client_name, project_id, root)
- - (Object) create_device_client(project_id, device, root)
- - (Object) create_device_client_name(project_id, device)
- - (Object) create_lock_client_name(project_id)
-
- (Object) create_pending_change(project_id)
If the user doesn't have a current pending change for the project, create one, and return that.
- - (Object) create_shelf_client(project_id, root)
- - (Object) create_shelf_client_name(project_id)
-
- (Object) delete_client(client_name)
Deletes the client and ignores “client doesn't exist” errors.
- - (Object) delete_device_client(project_id, device_id)
-
- (Object) delete_pending_change_for_project(project_id)
Remove the HVE project changelist (if it exists).
- - (Object) delete_shelf_client(project_id)
- - (Object) depot_path_for_name(name)
- - (Object) encode_name(name)
-
- (Object) fetch(id)
The ID is a URL encoded version of the directory name under HVE_PROJECTS_PATH.
-
- (Object) fetch_by_name(name)
Returns the project's “details” based on the project name.
-
- (Object) find_latest_change_for_project(project_id)
Find the latest submitted change for the project restricted to the shelf client.
-
- (Object) find_pending_change_for_project(project_id)
The HVE project 'changelist' is a shelved changelist whose client is the shelf client name.
- - (Object) hve_projects_path
-
- (Object) list(details: false, extension: nil)
List HVE Projects as configured in the system.
- - (Object) list_project_names
- - (Object) load_fstat_files(project_id, change)
- - (Object) load_shelf_plan(project_id, change, describe, shelf_meta)
-
- (Object) obtain_client_lock(project_id)
Will attempt to create a special “-x” client, and if that fails after re-attempting a few times, will throw a.
-
- (Object) p4_where_path(depot_path)
Determines the local path of the file on disk using “p4 where”.
- - (Object) p4host
- - (Object) p4port
-
- (Object) preview_pending_change(project_id)
Generates the resolution plan for the shelf.
- - (Object) readd(subplans, change)
-
- (Object) remove_from_shelf_and_plan(plan, change)
Remove all remove_actions from the shelf, and the plan.
-
- (Object) rename_all_locked_by_other(plan, change)
Will return true if anything actually happened.
- - (Object) resolve_and_submit_plan(plan, change)
-
- (Object) resolve_and_submit_shelf(project_id)
Will attempt to resolve all changes on the shelf and submit it.
- - (Object) safe_hve_projects_path
- - (Object) server
- - (Object) server_uri_for_id(id)
- - (Object) shelf_meta_from_json(description)
- - (Object) shelve_revert_and_sync(subplans, change)
- - (Object) unencode_name(name)
- - (Object) unshelve_and_resolve(subplans, change)
-
- (Object) userinfo
For HVE Projects, it may be interesting to people to see various connection settings for each server URL.
Instance Method Details
- (Object) assume_client_ownership(client_name, root)
303 304 305 306 307 |
# File 'lib/helix_sync/methods.rb', line 303 def assume_client_ownership(client_name, root) client_spec = p4.fetch_client(client_name) client_spec._root = root p4.save_client(client_spec) end |
- (Object) create_classic_onedir_client(client_name, project_id, root)
Generate a new client that only contains the project mapping.
The client name is a combination of user, project, and device. We prefix it with “_hve” just for clarity.
We do not host lock the client.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/helix_sync/methods.rb', line 112 def create_classic_onedir_client(client_name, project_id, root) return nil if env['hws_settings'].HVE_PROJECTS_PATH.nil? client_spec = p4.fetch_client(client_name) client_spec._root = root; client_spec._host = nil; client_spec. = 'allwrite clobber nocompress unlocked nomodtime rmdir'; project_name = unencode_name(project_id) client_spec._view = [ %Q|"#{depot_path_for_name(project_name)}/..." "//#{client_name}/..."| ] p4.save_client(client_spec) client_name end |
- (Object) create_client(client_name, project_id, root)
73 74 75 76 77 78 79 80 |
# File 'lib/helix_sync/methods.rb', line 73 def create_client(client_name, project_id, root) if !Cloud::Settings.cloud_enabled? return create_classic_onedir_client(client_name, project_id, root) else project_service = Cloud::Projects.new(env:env) return project_service.create_client(client_name, project_id, root) end end |
- (Object) create_device_client(project_id, device, root)
68 69 70 71 |
# File 'lib/helix_sync/methods.rb', line 68 def create_device_client(project_id, device, root) client_name = create_device_client_name(project_id, device) create_client(client_name, project_id, root) end |
- (Object) create_device_client_name(project_id, device)
132 133 134 |
# File 'lib/helix_sync/methods.rb', line 132 def create_device_client_name(project_id, device) "_hve_#{user}_#{project_id}_#{device}" end |
- (Object) create_lock_client_name(project_id)
140 141 142 |
# File 'lib/helix_sync/methods.rb', line 140 def create_lock_client_name(project_id) "#{create_shelf_client_name(project_id)}_lock" end |
- (Object) create_pending_change(project_id)
If the user doesn't have a current pending change for the project, create one, and return that.
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
# File 'lib/helix_sync/methods.rb', line 431 def create_pending_change(project_id) change = find_pending_change_for_project(project_id) return change if change shelf_client = create_shelf_client(project_id, '/dev/null') p4.client = shelf_client change_spec = p4.fetch_change change_spec._description = "_hws_#{user}_#{project_id}" change_spec._client = shelf_client save_results = p4.save_change(change_spec) change = save_results.first.gsub(/Change (\d+) created./, '\1') p4.client = 'INVALID' change end |
- (Object) create_shelf_client(project_id, root)
63 64 65 66 |
# File 'lib/helix_sync/methods.rb', line 63 def create_shelf_client(project_id, root) client_name = create_shelf_client_name(project_id) create_client(client_name, project_id, root) end |
- (Object) create_shelf_client_name(project_id)
136 137 138 |
# File 'lib/helix_sync/methods.rb', line 136 def create_shelf_client_name(project_id) "_hve_#{user}_#{project_id}_shelf" end |
- (Object) delete_client(client_name)
Deletes the client and ignores “client doesn't exist” errors
93 94 95 96 97 98 99 100 |
# File 'lib/helix_sync/methods.rb', line 93 def delete_client(client_name) p4.at_exception_level(P4::RAISE_NONE) do p4.run_client('-d', client_name) end unless p4..all?{ |m| m.msgid == 6178 || m.severity < P4::E_FAILED } fail P4Util.make_p4_error(p4) end end |
- (Object) delete_device_client(project_id, device_id)
87 88 89 90 |
# File 'lib/helix_sync/methods.rb', line 87 def delete_device_client(project_id, device_id) client_name = create_device_client_name(project_id, device_id) delete_client(client_name) end |
- (Object) delete_pending_change_for_project(project_id)
Remove the HVE project changelist (if it exists).
The general algorithm:
-
Take over ownership of our shelf client
-
Revert everything
-
Delete any shelved files
-
Delete the changelist
182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/helix_sync/methods.rb', line 182 def delete_pending_change_for_project(project_id) Dir.mktmpdir('delete_pending_change') do |dir| shelf_client = create_shelf_client_name(project_id) assume_client_ownership(shelf_client, dir) p4.client = shelf_client change = find_pending_change_for_project(project_id) if change p4.run_revert('-c', change, '//...') p4.run_shelve('-c', change, '-d') p4.run_change('-d', change) end end end |
- (Object) delete_shelf_client(project_id)
82 83 84 85 |
# File 'lib/helix_sync/methods.rb', line 82 def delete_shelf_client(project_id) client_name = create_shelf_client_name(project_id) delete_client(client_name) end |
- (Object) depot_path_for_name(name)
465 466 467 |
# File 'lib/helix_sync/methods.rb', line 465 def depot_path_for_name(name) "#{hve_projects_path}/#{name}" end |
- (Object) encode_name(name)
453 454 455 |
# File 'lib/helix_sync/methods.rb', line 453 def encode_name(name) HWSStrings.component_encode(name) end |
- (Object) fetch(id)
The ID is a URL encoded version of the directory name under HVE_PROJECTS_PATH.
This will unencode the ID and fetch by name.
41 42 43 44 |
# File 'lib/helix_sync/methods.rb', line 41 def fetch(id) name = unencode_name(id) fetch_by_name(name) end |
- (Object) fetch_by_name(name)
Returns the project's “details” based on the project name.
No validation is done to ensure this directory actually exists in the system.
50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/helix_sync/methods.rb', line 50 def fetch_by_name(name) id = encode_name(name) { 'id': id, 'name': name, 'server': server_uri_for_id(id), HVE_ID => { 'depotPath': depot_path_for_name(name) } } end |
- (Object) find_latest_change_for_project(project_id)
Find the latest submitted change for the project restricted to the shelf client.
Uses the command: 'p4 changes -m 1 -s submitted [shelf client]'
This has subtle surprises:
-
If a the client has not been used or does not exist, this does not return a changelist.
155 156 157 158 159 160 161 162 163 164 |
# File 'lib/helix_sync/methods.rb', line 155 def find_latest_change_for_project(project_id) client_name = create_shelf_client_name(project_id) begin p4.client = client_name results = p4.run_changes('-m', '1', '-s', 'submitted', "//#{client_name}/...") results.first['change'] unless results.empty? ensure p4.client = 'INVALID' end end |
- (Object) find_pending_change_for_project(project_id)
The HVE project 'changelist' is a shelved changelist whose client is the shelf client name
168 169 170 171 172 |
# File 'lib/helix_sync/methods.rb', line 168 def find_pending_change_for_project(project_id) client_name = create_shelf_client_name(project_id) results = p4.run_changes('-m', '1', '-u', user, '-s', 'shelved', '-c', client_name) results.first['change'] unless results.empty? end |
- (Object) hve_projects_path
469 470 471 |
# File 'lib/helix_sync/methods.rb', line 469 def hve_projects_path env['hws_settings'].HVE_PROJECTS_PATH || fail('HVE_PROJECTS_PATH not set') end |
- (Object) list(details: false, extension: nil)
List HVE Projects as configured in the system.
See the Appendix in the documentation for details on values.
13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/helix_sync/methods.rb', line 13 def list(details: false, extension: nil) return if extension and (extension != HVE_ID or extension != HVE_CONTENT_TYPE) project_dirs = list_project_names project_names = project_dirs.map { |d| File.basename(d) } if details project_names.map { |n| fetch_by_name(n) } else project_names.map { |n| encode_name(n) } end end |
- (Object) list_project_names
26 27 28 29 30 31 32 33 34 35 |
# File 'lib/helix_sync/methods.rb', line 26 def list_project_names if !Cloud::Settings.cloud_enabled? pattern = "#{hve_projects_path}/*" results = p4.run_dirs(pattern) results.map { |r| r['dir'] } else project_service = Cloud::Projects.new(env:env) project_service.list end end |
- (Object) load_fstat_files(project_id, change)
423 424 425 426 427 |
# File 'lib/helix_sync/methods.rb', line 423 def load_fstat_files(project_id, change) fstat_files = p4.run_fstat('-Rs', '-e', change, "//#{create_shelf_client_name(project_id)}/...") fstat_files.delete_if { |f| !f['depotFile'] } fstat_files end |
- (Object) load_shelf_plan(project_id, change, describe, shelf_meta)
414 415 416 417 418 419 420 421 |
# File 'lib/helix_sync/methods.rb', line 414 def load_shelf_plan(project_id, change, describe, ) fstat_files = load_fstat_files(project_id, change) plan = Plan.new plan.subplans = fstat_files.map { |f| Subplan.new(f) } plan end |
- (Object) obtain_client_lock(project_id)
Will attempt to create a special “-x” client, and if that fails after re-attempting a few times, will throw a
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/helix_sync/methods.rb', line 270 def obtain_client_lock(project_id) lock_p4 = P4Util.open_from_env(env) lock_p4.connect client_name = create_lock_client_name(project_id) locked = false retries_left = HWSSettings.system.HELIX_SYNC_LOCK_RETRIES lock_client = lock_p4.fetch_client(client_name) lock_p4.client = lock_client._client while !locked && retries_left > 0 retries_left -= 1 lock_p4.at_exception_level(P4::RAISE_NONE) do lock_p4.save_client(lock_client, '-x') end if lock_p4. && !lock_p4..empty? && lock_p4..any? {|x| x.msgid == 7748 } sleep(2) if retries_left > 0 elsif lock_p4..all? { |x| x.severity < P4::E_FAILED } locked = true else # This is a different error altogether fail P4Util.make_p4_error(lock_p4) end end fail LockFailed.new(client_name) unless locked return lock_p4 end |
- (Object) p4_where_path(depot_path)
Determines the local path of the file on disk using “p4 where”.
374 375 376 377 |
# File 'lib/helix_sync/methods.rb', line 374 def p4_where_path(depot_path) where_results = p4.run_where(depot_path) where_results.nil? ? nil : where_results.first['path'] end |
- (Object) p4host
505 506 507 |
# File 'lib/helix_sync/methods.rb', line 505 def p4host env['hws_settings'].P4HOST end |
- (Object) p4port
501 502 503 |
# File 'lib/helix_sync/methods.rb', line 501 def p4port env['hws_settings'].P4PORT || fail('P4PORT setting not available') end |
- (Object) preview_pending_change(project_id)
Generates the resolution plan for the shelf
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/helix_sync/methods.rb', line 198 def preview_pending_change(project_id) Dir.mktmpdir('hve_resolve') do |dir| shelf_client = create_shelf_client_name(project_id) assume_client_ownership(shelf_client, dir) p4.client = shelf_client begin change = find_pending_change_for_project(project_id) describe_results = p4.run_describe('-S', '-s', change) describe = Describe.new(describe_results.first) = (describe.desc) return load_shelf_plan(project_id, change, describe, ) ensure p4.client = 'INVALID' end end end |
- (Object) readd(subplans, change)
386 387 388 389 390 391 392 |
# File 'lib/helix_sync/methods.rb', line 386 def readd(subplans, change) depot_files = subplans.map(&:depotFile) p4.run_sync('-f', *depot_files) p4.run_unshelve('-c', change, '-s', change, *depot_files) p4.run_revert('-k', *depot_files) p4.run_add('-c', change, *depot_files) end |
- (Object) remove_from_shelf_and_plan(plan, change)
Remove all remove_actions from the shelf, and the plan.
380 381 382 383 384 |
# File 'lib/helix_sync/methods.rb', line 380 def remove_from_shelf_and_plan(plan, change) files_to_remove = plan.remove_actions.map(&:depotFile) p4.run_shelve('-d', '-c', change, *files_to_remove) plan.remove_actions.each { |x| plan.subplans.delete(x) } end |
- (Object) rename_all_locked_by_other(plan, change)
Will return true if anything actually happened. If that's true, you should rebuild the revised plan.
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/helix_sync/methods.rb', line 344 def rename_all_locked_by_other(plan, change) to_remove = plan.subplans.select {|s| s.locked_by_other_than?(user) } unless to_remove.empty? depot_files = to_remove.map { |s| s.depotFile } p4.run_sync('-f', *depot_files) p4.run_unshelve('-c', change, '-s', change, *depot_files) p4.run_shelve('-d', '-c', change, *depot_files) p4.run_revert('-k', *depot_files) to_readd = [] to_remove.each do |subplan| old_name = p4_where_path(subplan.depotFile) new_name = "#{old_name}.#{change}.locked" File.rename(old_name, new_name) to_readd << new_name end p4.run_add('-c', change, *to_readd) p4.run_shelve('-f', '-c', change, *to_readd) p4.run_revert(to_readd) return true end return false end |
- (Object) resolve_and_submit_plan(plan, change)
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/helix_sync/methods.rb', line 309 def resolve_and_submit_plan(plan, change) return true if plan.empty? if rename_all_locked_by_other(plan, change) return false end unless plan.remove_actions.empty? remove_from_shelf_and_plan(plan, change) end return true if plan.empty? unless plan.readd_actions.empty? readd(plan.readd_actions, change) end unless plan.resolve_actions.empty? unshelve_and_resolve(plan.resolve_actions, change) end if !plan.readd_actions.empty? or !plan.resolve_actions.empty? shelve_revert_and_sync(plan.readd_actions + plan.resolve_actions, change) end p4.at_exception_level(P4::RAISE_NONE) do p4.run_submit('-e', change) return false unless p4.errors.empty? end return true end |
- (Object) resolve_and_submit_shelf(project_id)
Will attempt to resolve all changes on the shelf and submit it
Note: there may be addition
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/helix_sync/methods.rb', line 222 def resolve_and_submit_shelf(project_id) lock_p4 = obtain_client_lock(project_id) # All resolves require setting the local client to a local directory, # that we delete when done. dir = Dir.mktmpdir('hve_resolve') shelf_client = create_shelf_client_name(project_id) assume_client_ownership(shelf_client, dir) p4.client = shelf_client change = find_pending_change_for_project(project_id) retries = HWSSettings.system.HELIX_SYNC_RECONCILE_RETRIES is_resolved = false while !is_resolved && retries > 0 describe_results = p4.run_describe('-S', '-s', change) describe = Describe.new(describe_results.first) = (describe.desc) shelf_plan = load_shelf_plan(project_id, change, describe, ) is_resolved = resolve_and_submit_plan(shelf_plan, change) retries -= 1 sleep(1) unless is_resolved && retries > 0 end if !is_resolved fail SubmitFailed.new(change) end ensure unless lock_p4.nil? lock_p4.run_client('-d', lock_p4.client) lock_p4.disconnect end p4.client = 'INVALID' # Our client has the 'rmdir' option set, which can delete the local # directory if there's nothing else remaining in the client. unless dir.nil? FileUtils.rmtree(dir) if Dir.exist?(dir) end end |
- (Object) safe_hve_projects_path
473 474 475 |
# File 'lib/helix_sync/methods.rb', line 473 def safe_hve_projects_path hve_projects_path.gsub('//', '/') end |
- (Object) server
492 493 494 495 496 497 498 499 |
# File 'lib/helix_sync/methods.rb', line 492 def server return p4port if p4port.include?(':') host = p4host ? p4host : 'localhost' port = p4port "#{host}:#{port}" end |
- (Object) server_uri_for_id(id)
461 462 463 |
# File 'lib/helix_sync/methods.rb', line 461 def server_uri_for_id(id) "p4://#{userinfo}#{server}#{safe_hve_projects_path}/#{id}" end |
- (Object) shelf_meta_from_json(description)
409 410 411 412 |
# File 'lib/helix_sync/methods.rb', line 409 def (description) parsed = JSON.parse(description) ShelfMeta.new(parsed) end |
- (Object) shelve_revert_and_sync(subplans, change)
401 402 403 404 405 406 407 |
# File 'lib/helix_sync/methods.rb', line 401 def shelve_revert_and_sync(subplans, change) depot_files = subplans.map(&:depotFile) p4.run_shelve('-f', '-c', change, *depot_files) p4.run_revert(depot_files) df_no_specs = depot_files.map{ |f| "#{f}#none"} p4.run_sync(df_no_specs) end |
- (Object) unencode_name(name)
457 458 459 |
# File 'lib/helix_sync/methods.rb', line 457 def unencode_name(name) HWSStrings.component_decode(name) end |
- (Object) unshelve_and_resolve(subplans, change)
394 395 396 397 398 399 |
# File 'lib/helix_sync/methods.rb', line 394 def unshelve_and_resolve(subplans, change) depot_files = subplans.map(&:depotFile) p4.run_unshelve('-c', change, '-s', change, *depot_files) p4.run_sync(depot_files) p4.run_resolve('-c', change, '-ay', *depot_files) end |
- (Object) userinfo
For HVE Projects, it may be interesting to people to see various connection settings for each server URL.
479 480 481 482 483 484 485 486 487 488 489 490 |
# File 'lib/helix_sync/methods.rb', line 479 def userinfo data = {} if env['hws_settings'].P4CHARSET data['P4CHARSET'] = env['hws_settings'].P4CHARSET end if data.keys.empty? '' else encoded_data = data.map {|k,v| "#{k}=#{v}"}.join(';') "#{encoded_data}@" end end |