Module: P4Util

Defined in:
lib/p4_util.rb

Constant Summary

PROPERTIES =
[
    :password, :port, :user, :api_level, :charset, :client,
    :host, :handler, :maxlocktime, :maxresults, :maxscanrows, :prog,
    :ticketfile
]

Class Method Summary (collapse)

Class Method Details

+ (Object) create_p4(options)



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/p4_util.rb', line 104

def self.create_p4(options)
  p4 = P4.new

  init_p4(p4)

  PROPERTIES.each do|key|
    p4.method(key.to_s + '=').call(options[key]) if options[key]
  end

  # From the WTF department, if you think you don't want a charset set,
  # make damn sure P4Ruby isn't going to get confused.
  p4.charset = nil if p4.charset == 'none'

  # Make P4Ruby only raise exceptions if there are errors. Warnings
  # (such as 'no such file(s)' don't get the same treatment.
  p4.exception_level = P4::RAISE_ERRORS

  p4
end

+ (Object) create_temp_client(p4)



165
166
167
168
169
170
171
172
# File 'lib/p4_util.rb', line 165

def self.create_temp_client(p4)
  name = (0...8).map { (65 + rand(26)).chr }.join
  p4_root = init_temp_workspace_dir(name)

  init_temp_client(name, p4, p4_root)

  p4_root
end

+ (Object) create_temp_stream_client_duplicate(p4, src_client)

Generates a stream client based on an existing stream



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/p4_util.rb', line 175

def self.create_temp_stream_client_duplicate(p4, src_client)
  name = (0...8).map { (65 + rand(26)).chr }.join
  p4_root = init_temp_workspace_dir(name)

  p4.client = name

  spec = p4.fetch_client
  spec._root = p4_root
  spec._client = name
  spec._stream = src_client._stream
  spec._view = nil

  p4.save_client(spec)

  p4_root
end

+ (Object) init_p4(p4)

Before we do anything, clear out any environment variables that may have leaked in from your environment

Some of our HTTP APIs (e.g, Git Fusion) do utilize environment setups for a system user, that may be installed alongside this API. We want this system to always explicitly state which configuration to use. (So, it's not just a concern of our development environments.)



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/p4_util.rb', line 131

def self.init_p4(p4)
  p4.client = 'invalid'
  p4.port = ''
  p4.host = ''
  p4.password = ''

  # Disable the use of ticket files.
  # It might happen that an admin may decide to use the p4 command line
  # client to log in using the same system user we're running web services
  # as. If we happen to point to that file (say, via defaults) this will
  # use the valid ticket in the file instead of what has been specified
  # via headers.
  if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
    p4.ticket_file = 'nul'
    p4.enviro_file = 'nul'
  else
    p4.ticket_file = '/dev/null'
    p4.enviro_file = '/dev/null'
  end

  if ENV['P4TRUST'].nil?
    ENV['P4TRUST'] = HWSSettings.system.P4TRUST
  end
end

+ (Object) make_p4_error(p4)



156
157
158
159
160
161
162
163
# File 'lib/p4_util.rb', line 156

def self.make_p4_error(p4)
  if p4.messages && p4.messages.first
    m = p4.messages.first
    P4Error.new(m.msgid, m.severity, m.to_s)
  else
    P4Error.default_error($ERROR_INFO.to_s)
  end
end

+ (Object) open(options = {})

Creates your p4 connection using some common forms.

If you call open with a block, this will call connect before your block executes, and disconnect afterwards.

If you do not call open with a block, it is up to the caller to connect and disconnect. (It's assumed you are calling w/o a block because you want to manage when the connection actually needs to happen.)



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/p4_util.rb', line 77

def self.open(options = {})
  p4 = create_p4(options)

  # Again, if we're calling using the block, we'll connect and disconnect.
  # Otherwise, just return the created p4 object.
  if block_given?
    begin
      p4.connect
      yield p4
    rescue P4Exception => ex
      puts "trace:"
      ex.backtrace.each { |l| puts "\t#{l}" }
      raise make_p4_error(p4)
    end
  else
    return p4
  end
ensure
  p4.disconnect if block_given? && p4 && p4.connected?
end

+ (Object) open_from_env(env)

Create a p4 connection using our Rack environment setup.

This will seed options to a call to open() via attributes set on env:

  • hws_settings, which contains things like P4PORT

  • AUTH_CREDENTIALS, which might be used if this is called after our Auth middleware (or we've stored these credentials in a session, etc)



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/p4_util.rb', line 14

def self.open_from_env(env)
  options = {}

  if env.key?('hws_settings')
    hws_settings = env['hws_settings']

    port = nil
    if hws_settings.P4URL
      p4_url = URI(hws_settings.P4URL)
      options[:port] = "#{p4_url.host}:#{p4_url.port}"
    end

    if hws_settings.P4HOST
      options[:host] = hws_settings.P4HOST
    end

    if hws_settings.P4PORT
      # Apparently, the P4API will ports with 'rsh:' to mean "I'm going
      # to have a way to launch random things for you". It's great. And by
      # great I mean a another fantastic feature that makes no sense to anyone
      # who's not debugging a local client application.
      #
      # See netportparser.cc for how the P4API parses out the transport type.
      if hws_settings.P4PORT.downcase.start_with?('rsh:') ||
         hws_settings.P4PORT.downcase.start_with?('jsh:')
        fail P4Error.new(0, 3, 'Do not use rsh: or jsh: P4PORT values')
      end
      options[:port] = hws_settings.P4PORT
    end

    if hws_settings.P4CHARSET
      options[:charset] = hws_settings.P4CHARSET
    end

    if hws_settings.P4APILEVEL
      options[:api_level] = Integer(hws_settings.P4APILEVEL)
    end

    if hws_settings.P4PASSWD
      options[:password] = hws_settings.P4PASSWD
    end
  end

  if env.key?('AUTH_CREDENTIALS')
    options[:user] = env['AUTH_CREDENTIALS'].first
    if !options.key?(:password) or options[:password].nil?
      options[:password] = env['AUTH_CREDENTIALS'].last
    end
  end

  options[:client] = 'INVALID'

  self.open(options)
end