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)

[View source]

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)

[View source]

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

[View source]

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.)

[View source]

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)

[View source]

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.)

[View source]

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)

[View source]

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