require 'hws_settings' require 'projects/project_service' require 'base64' require 'hws_strings' module HelixVersioningEngine # Define simple projects based on a single directory location in a Helix # Versioning Engine. # # This project service uses the HVE_PROJECTS_PATH setting to list available # projects on the particular server. If you only have one Helix Versioning # Engine, it's suitable to create this as a systemwide default. Otherwise, # you likely only want to specify this via headers. # # This will return everything as "helix versioning engine" project. class HVEProjectsService HVE_CONTENT_TYPE = 'application/vnd.perforce.project.hve.v1+json' HVE_ID = 'hveProject' # Rack environment. attr_accessor :env def initialize(env: nil) @env = env end # List HVE Projects as configured in the system. # # See the Appendix in the documentation for details on values. 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 def list_project_names pattern = "#{hve_projects_path}/*" results = p4.run_dirs(pattern) results.map { |r| r['dir'] } end # The ID is a URL encoded version of the directory name under # HVE_PROJECTS_PATH. # # This will unencode the ID and fetch by name. def fetch(id) name = unencode_name(id) fetch_by_name(name) end # Returns the project's "details" based on the project name. # # No validation is done to ensure this directory actually exists in the # system. 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 # 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. # # @param project_id {String} Our encoded project name # @param device {String} A device ID, like a hostname # @param root {String} The `Root` value for the client parameter def create_client(project_id, device, root) client_name = "_hve_#{user}_#{project_id}_#{device}" client_spec = p4.fetch_client(client_name) client_spec._root = root; client_spec._host = nil; client_spec._options = 'allwrite noclobber nocompress unlocked nomodtime rmdir'; project_name = unencode_name(project_id) client_spec._view = [ %Q|"#{depot_path_for_name(project_name)}/..." "//#{client_name}/..."| ] results = p4.save_client(client_spec) puts "new client results: #{results}" client_name end # Find the latest submitted change for the project # # Use the 'p4 changes -m 1 -s submitted [depot path]' # # @param project_id [String] The encoded project ID def find_latest_change_for_project(project_id) project_name = unencode_name(project_id) depot_path = depot_path_for_name(project_name) results = p4.run_changes('-m', '1', '-s', 'submitted', "#{depot_path}/...") results.first['change'] unless results.empty? end # The HVE project 'changelist' is a pending changelist whose description is # `_hve_[user]_[project_id]` # # We use 'changes -l' to find the change to match potentially long project # names. def find_pending_change_for_project(project_id) results = p4.run_changes('-l', '-u', user, '-s', 'pending') change = results.find { |r| r['desc'].include?(project_id) } change['change'] if change end # If the user doesn't have a current pending change for the project, # create one, and return that. def create_pending_change(project_id) change = find_pending_change_for_project(project_id) return change if change change_spec = p4.fetch_change change_spec._description = "_hws_#{user}_#{project_id}" save_results = p4.save_change(change_spec) change = save_results.first.gsub(/Change (\d+) created./, '\1') # If we don't reset the client of this pending change, we won't be able # to cleanup the temporary client. change_spec = p4.fetch_change(change) change_spec._client = 'INVALID' p4.save_change(change_spec) change end def encode_name(name) HWSStrings.component_encode(name) end def unencode_name(name) HWSStrings.component_decode(name) end def server_uri_for_id(id) "p4://#{userinfo}#{server}#{safe_hve_projects_path}/#{id}" end def depot_path_for_name(name) "#{hve_projects_path}/#{name}" end def p4 env['p4'] || fail('p4 required to use HVEProjects') end def hve_projects_path env['hws_settings'].HVE_PROJECTS_PATH || fail('HVE_PROJECTS_PATH not set') end def safe_hve_projects_path hve_projects_path.gsub('//', '/') end def user env['AUTH_CREDENTIALS'].first end # For HVE Projects, it may be interesting to people to see various # connection settings for each server URL. 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 def server return p4port if p4port.include?(':') host = p4host ? p4host : 'localhost' port = p4port "#{host}:#{port}" end def p4port env['hws_settings'].P4PORT || fail('P4PORT setting not available') end def p4host env['hws_settings'].P4HOST end end end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#10 | 15837 | tjuricek | Removed HVEProjectsService, moved methods to module of projects app | ||
#9 | 15828 | tjuricek |
Remove 'service object' abstraction for helix sync, revise to module code. This begins removing an unnecessary level of indirection. As it turns out, the Helix Sync logic will remain largely untouched between different systems. If we need very specific logic, we'll have to adjust each method, likely with configuration. Which will of course need some testing, or just outright replacement, which *should* be easier with module includes. |
||
#8 | 15824 | tjuricek |
Fixes to the 'preview' or 'shelf resolve plan'. There's something fundamentally off about the shelf preview and resolve mechanism, I'm still investigating. Until that point, obvious flaws should be cleared up. |
||
#7 | 15821 | tjuricek | Clean up diagnostic information. | ||
#6 | 15787 | tjuricek | Added 'readd' test for Helix Sync submit | ||
#5 | 15786 | tjuricek |
Add 'remove from shelf' resolution test (with bug fixes). Also, removed a couple of old tasks from the top-level Rakefile. |
||
#4 | 15773 | tjuricek |
Add basic 'add' test for the submit shelf mechanism. Added a *slightly* modified deviceSync script, which ideally functions somewhat like the helix sync script. We'll start with this to generate our JSON examples for testing. |
||
#3 | 15761 | tjuricek |
Naive implementation of the "preview resolve plan". The API needs to be avaiable for the integration effort between Helix Cloud and Helix Sync. Tests to follow. |
||
#2 | 15757 | tjuricek |
Add resolve implementation for submitting from shelves for Helix Sync Includes additional concepts for creating a "helix sync shelf client" vs a "helix sync device client". It's expected that there's basically one shelf client per user per project. The "device" client is an additional client per user per project per machine. The HWS services will submit via the "shelf client". The resolve implementation remains untested at the moment in order to get the client changes in the hands of Helix Sync developers. |
||
#1 | 15622 | tjuricek |
Move source code to 'source/' subdirectory of branch. build/ will remain where it is. |
||
//guest/perforce_software/helix-web-services/main/helix_web_services/lib/helix_versioning_engine/hve_projects_service.rb | |||||
#5 | 15542 | tjuricek |
Add spaces to our basic 'component encode' mechanism, and use it for HVE project IDs. In general, this will make the HVE IDs a bit more readable. |
||
#4 | 15497 | tjuricek | Add support to fetch the latest change of a project. | ||
#3 | 15496 | tjuricek |
Revise GET /helix_sync/v1/changes/[project] to /helix_sync/v1/changes/[project]/pending The base method is really intended for the latest changelist number. Meh. |
||
#2 | 15487 | tjuricek | Add basic ability to create pending changelists for helix sync projects. | ||
#1 | 15479 | tjuricek | Added a basic "HVE project" implementation for creating clients. | ||
//guest/perforce_software/helix-web-services/main/helix_web_services/lib/projects/hve_projects.rb | |||||
#1 | 15437 | tjuricek |
Basic "HVE Project" implementation. This will allow directories in a HVE instance to host 'projects' for use by helix sync. There are no methods defined for creating the projects, however. This does not include any specialization or testing in the Qt API yet. I may investigate creating a "higher level" interface for Qt client apps. |