# Copyright (c) 2014-2015 Perforce Software, Inc. All rights reserved. # # This is a HTTP interface to the p4d server (via p4ruby). require 'sinatra/base' require 'sinatra/json' require 'sinatra/config_file' require 'helix_versioning_engine/util' module HelixVersioningEngine # This web application is mostly a lightweight way of connecting the tagged # output via P4Ruby to JSON clients can consume relatively simply. class App < Sinatra::Base register Sinatra::ConfigFile # TODO not sure this should be in a sub-module not_found do return { # This is not an application error, so I'm using error code 0 to mean # 'use HTTP status' MessageCode: 0, MessageSeverity: 3, MessageText: 'Resource not found' }.to_json end def to_msg(message) { MessageCode: message.msgid, MessageSeverity: message.severity, MessageText: message.to_s } end # Will fetch the system offset based on the server date. # # If allow_env_p4_config is true, we don't cache. Each request could come # in from a new server, and the different servers may have different # offsets. def offset if settings.allow_env_p4_config fetch_offset else @offset ||= fetch_offset end end def fetch_offset offset = nil open_p4_as_user do |p4| results = p4.run_info offset = Util.p4_date_offset(results[0]['serverDate']) end offset end @normalizers = {} class << self attr_accessor :normalizers end # It's assumed that these are typically used to find the different spec # types within typical requests. def method_missing(method, *args) return unless method.to_s =~ /^normalize_(.*)/ spec_type = Regexp.last_match[1] unless self.class.normalizers.key?(spec_type) self.class.normalizers[spec_type] = Util.normalizer(spec_type, offset) end self.class.normalizers[spec_type].call(*args) end # Basically a "blacklist" of things we know the frameworks going to add to # the params array we don't want to pass on to the p4 command sets for spec # input def filter_params(params) params.select do |k, _v| k != 'spec_type' && k != 'id' && k != 'splat' && k != 'captures' end end before do match = /^\/helix_versioning_engine\/v(\d+)\//.match(request.path_info) if match level = Integer(match[1]) # In case the p4 handle is not available, override any header env['HTTP_X_PERFORCE_HELIX_WEB_SERVICES_P4APILEVEL'] = match[1] if env['p4'] env['p4'].api_level = level end end end end end # Reopen up the P4WebAPI::App class and add most of our method handling. This # is done in lieu of having multiple Sinatra apps, so we can have the same # configuration and error handling. require 'helix_versioning_engine/app/changes' require 'helix_versioning_engine/app/commands' require 'helix_versioning_engine/app/counters' require 'helix_versioning_engine/app/files' require 'helix_versioning_engine/app/protections' require 'helix_versioning_engine/app/specs' require 'helix_versioning_engine/app/streams' require 'helix_versioning_engine/app/triggers' require 'helix_versioning_engine/app/users'