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.



265
266
267
# File 'lib/perforce.rb', line 265

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



201
202
203
204
205
206
207
208
# File 'lib/perforce.rb', line 201

def chdir(dir)
  previous_dir = File.expand_path(".")
  Dir.chdir(dir) {
    @p4.cwd = File.expand_path(".")
    yield
  }
  @p4.cwd = previous_dir
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
    unix_dir = Util.unix_path(dir)
    if dir != unix_dir
      add_unix_root
    end
    unix_dir
  else
    dir
  end
end

#run(*args) ⇒ Object

Run a general p4 command.

Example:

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


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/perforce.rb', line 225

def run(*args)
  go = lambda {
    @p4.run(*args).tap {
      puts(@p4.warnings)
    }
  }
  if CYGWIN
    begin
      go.call
    rescue P4Exception
      if @p4.connected?
        # 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)



213
214
215
216
# File 'lib/perforce.rb', line 213

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