Class: Perforce

Inherits:
Object
  • Object
show all
Defined in:
lib/perforce.rb

Overview

Perforce – class representing a connection to a perforce server.

Defined Under Namespace

Modules: Util Classes: Changelist

Constant Summary collapse

CYGWIN =

:nodoc:

(RUBY_PLATFORM =~ %r!cygwin!)

Class Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(spec = {}) ⇒ Perforce

Connect to a perforce depot.

The argument spec is a hash of (method, value) pairs sent to the underlying P4 object.

The given values override the P4PORT, P4CLIENT, etc. environment variables.

Example:

#
# This calls P4#user=, P4#password=, P4#client=, P4#port= with
# these values, then calls P4#connect.
#
Perforce.new(
  :user => "iggy_fenton",
  :password => "<password or ticket number>",
  :client => "iggy_fenton_project",
  :port => "server_name:1666")


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
68
69
70
71
72
73
74
75
76
# File 'lib/perforce.rb', line 32

def initialize(spec = {})
  #
  # Remove PWD during creation to avoid some troubles.  The user
  # probably wants perforce to use the absolute path of the current
  # directory, not a path infected by symlinks.
  # 
  # Since ~/project was a symlink to my perforce-based project,
  # perforce would not run when I got there via "cd project" from my
  # home directory.
  #
  @p4 = 
    if self.class.use_pwd_symlinks
      P4.new
    else
      Thread.exclusive {
        previous_pwd = ENV["PWD"]
        ENV.delete("PWD")
        begin
          P4.new
        ensure
          if previous_pwd
            ENV["PWD"] = previous_pwd
          end
        end
      }
    end
  spec.each_pair { |key, value|
    @p4.send("#{key}=", value)
  }
  unless spec.has_key?(:user)
    # guess user
    @p4.user = [
      ENV["USER"],
      ENV["USERNAME"],
    ].select { |name|
      name != nil and name != ""
    }.first.tap { |user|
      unless user 
        raise "Could not determine username"
      end
    }
  end
  @p4.exception_level = P4::RAISE_ERRORS
  @p4.connect
end

Class Attribute Details

Whether the current directory as reported to the perforce server can contain symlinks. Default is false.



281
282
283
# File 'lib/perforce.rb', line 281

def use_pwd_symlinks
  @use_pwd_symlinks
end

Instance Method Details

#add_unix_rootObject

Cygwin-only.

Add a UNIX-style AltRoot.

This allows P4Win and cygwin to work in the same client spec.



184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/perforce.rb', line 184

def add_unix_root #:nodoc:
  client = run(*%w(client -o)).first
  alt_roots = client["AltRoots"]
  if alt_roots and alt_roots.include?(Util.unix_path(client["Root"]))
    # has proper alt root
  else
    client["AltRoots"] =
      alt_roots.to_a + [Util.unix_path(client["Root"])]
    run_with_input(client, "client", "-i")
    puts("Note: added unix AltRoot to client")
  end
end

#chdir(dir) ⇒ Object

Change working directory (locally and remotely).

If a block is given, the original working directory is restored when the block exits. (Behavior is like Dir.chdir.)



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/perforce.rb', line 204

def chdir(dir)
  previous_dir = File.expand_path(".")

  Dir.chdir(dir)
  begin
    @p4.cwd = File.expand_path(".")
  rescue
    Dir.chdir(previous_dir)
    raise
  end

  if block_given?
    begin
      yield dir
    ensure
      Dir.chdir(previous_dir)
      @p4.cwd = previous_dir
    end
  end
end

#delete_empty_changelistsObject

Delete all empty changelists.



126
127
128
129
130
# File 'lib/perforce.rb', line 126

def delete_empty_changelists
  pending_changelists.each { |changelist|
    changelist.delete
  }
end

#edit_and_submit(changelist_description, files) ⇒ Object

Edit and submit files in one step.

Example:

perforce.edit_and_submit("remove trailing whitespace", files) {
  #
  # Do stuff with the files.
  # ...
  #
}
#
# Changes are submitted when the block ends.
#


153
154
155
156
157
158
# File 'lib/perforce.rb', line 153

def edit_and_submit(changelist_description, files)
  changelist = new_changelist(changelist_description)
  changelist.add_files(files)
  yield
  changelist.submit
end

#new_changelist(desc) ⇒ Object

Create a Changelist with the given description (a string).



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/perforce.rb', line 88

def new_changelist(desc)
  input = {
    "Change" => "new",
    "Description" => desc,
  }

  number =
    run_with_input(input, "change", "-i").
    first.
    match(%r!\AChange (\d+) created\.!).
    captures.
    first

  Changelist.new(self, number)
end

#p4Object

The underlying P4 object from the P4Ruby package.



81
82
83
# File 'lib/perforce.rb', line 81

def p4
  @p4
end

#pending_changelistsObject

Return the pending changelists (as Changelist objects).



116
117
118
119
120
121
# File 'lib/perforce.rb', line 116

def pending_changelists
  command = %W(changelists -u #{@p4.user} -c #{@p4.client} -s pending)
  run(*command).map { |elem|
    Changelist.new(self, elem["change"].to_i)
  }
end

#revert_files(files) ⇒ Object

Revert these files.



107
108
109
110
111
# File 'lib/perforce.rb', line 107

def revert_files(files)
  unless files.empty?
    run("revert", *files)
  end
end

#rootObject

Client root directory.



163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/perforce.rb', line 163

def root
  dir = run(*%w(client -o)).first["Root"]
  if CYGWIN
    Util.unix_path(dir).tap { |unix_dir|
      if dir != unix_dir
        add_unix_root
      end
    }
  else
    dir
  end
end

#run(*args) ⇒ Object

Run a general p4 command.

Example:

puts "Your server version is: "
puts perforce.run("info").first["serverVersion"]


240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/perforce.rb', line 240

def run(*args)
  go = lambda {
    @p4.run(*args).tap {
      puts(@p4.warnings)
    }
  }
  if CYGWIN
    begin
      go.call
    rescue P4Exception => exception
      if @p4.connected? and
          exception.message =~ %r!not under client\'s root!
        # maybe unix root is not present; try again
        add_unix_root
        go.call
      else
        raise
      end
    end
  else
    # not CYGWIN
    go.call
  end
end

#run_with_input(input, *args) ⇒ Object

Call P4#input(input) and then P4#run(*args)



228
229
230
231
# File 'lib/perforce.rb', line 228

def run_with_input(input, *args)
  @p4.input = input
  run(*args)
end

#sync(*args) ⇒ Object

Calls run("sync", *args)



135
136
137
# File 'lib/perforce.rb', line 135

def sync(*args)
  run("sync", *args)
end