Class: RSCM::Perforce

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

Constant Summary collapse

DATE_FORMAT =
"%Y/%m/%d:%H:%M:%S"
CHANGELIST_PATTERN =

Doesn’t work for empty messages, (Like 21358 in Aslak’s P4 repo)

/^Change \d+ by (.*)@.* on (.*)\n\n(.*)\n\nAffected files ...\n\n(.*)/m
CHANGELIST_PATTERN_NO_MSG =

But this one does

/^Change \d+ by (.*)@.* on (.*)\n\nAffected files ...\n\n(.*)/m
STATES =
{
  "add" => RevisionFile::ADDED,
  "edit" => RevisionFile::MODIFIED,
  "delete" => RevisionFile::DELETED
}

Constants included from RevisionPoller

RevisionPoller::BASE_INCREMENT, RevisionPoller::CRITICAL_REVISION_SIZE, RevisionPoller::TWENTY_FOUR_HOURS

Instance Attribute Summary collapse

Attributes inherited from Base

#default_options, #store_revisions_command

Attributes included from RevisionPoller

#logger

Instance Method Summary collapse

Methods inherited from Base

#==, #add, #available?, #can_create_central?, #central_exists?, #checked_out?, #checked_out_files, #checkout, #checkout_commandline, #checkout_dir, #checkout_dir=, #commit, #create_central, #destroy_central, #edit, #import_central, #install_trigger, #move, #store_revisions_command?, #supports_trigger?, #to_identifier, #to_yaml_properties, #transactional?, #trigger_installed?, #trigger_mechanism, #uninstall_trigger, #update_commandline, #uptodate?

Methods included from RevisionPoller

#poll

Instance Attribute Details

#passwordObject

Returns the value of attribute password.



31
32
33
# File 'lib/rscm/scm/perforce.rb', line 31

def password
  @password
end

#usernameObject

Returns the value of attribute username.



30
31
32
# File 'lib/rscm/scm/perforce.rb', line 30

def username
  @username
end

#viewObject

Returns the value of attribute view.



29
30
31
# File 'lib/rscm/scm/perforce.rb', line 29

def view
  @view
end

Instance Method Details

#destroy_working_copy(options = {}) ⇒ Object



117
118
119
# File 'lib/rscm/scm/perforce.rb', line 117

def destroy_working_copy(options={})
  execute("p4 #{p4_opts(false)} client -d #{client_name}", options)
end

#diffObject



129
130
131
# File 'lib/rscm/scm/perforce.rb', line 129

def diff
#p4 diff2 //depot/trunk/build.xml@26405 //depot/trunk/build.xml@26409
end

#installed?Boolean

Returns:

  • (Boolean)


33
34
35
36
37
38
39
40
# File 'lib/rscm/scm/perforce.rb', line 33

def installed?
  begin
    execute("p4 info", {}) 
    true
  rescue
    false
  end
end

#open(revision_file, options = {}, &block) ⇒ Object



121
122
123
124
125
126
127
# File 'lib/rscm/scm/perforce.rb', line 121

def open(revision_file, options={}, &block)
  path = @view.gsub(/\.\.\./, revision_file.path) # + "@" + revision_file.native_revision_identifier
  cmd = "p4 #{p4_opts(false)} print -q #{path}"
  execute(cmd, options) do |io|
    block.call io
  end
end

#revisions(from_identifier = Time.new.utc, options = {}) ⇒ Object



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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rscm/scm/perforce.rb', line 42

def revisions(from_identifier=Time.new.utc, options={})
  raise "from_identifer cannot be nil" if from_identifier.nil?
  set_utc_offset(options)
  view_as_regexp = "^" + @view.gsub(/\.\.\./, "(.*)")
  relative_path_pattern = Regexp.new(view_as_regexp)

  from_identifier = Time.epoch unless from_identifier
  from_identifier = Time.epoch if (from_identifier.is_a? Time and from_identifier < Time.epoch)
  from = revision_spec(from_identifier + 1) # We have to add 1 because of the contract of this method.

  to_identifier = options[:to_identifier] ? options[:to_identifier] : Time.infinity
  to = revision_spec(to_identifier - 1) # We have to subtract 1 because of the contract of this method.

  cmd = "p4 #{p4_opts(false)} changes #{@view}@#{from},#{to}"
  revisions = Revisions.new
  revisions.cmd = cmd if store_revisions_command?

  changes = execute(cmd, options) do |io|
    io.read
  end

  changes.each do |line|
    revision = nil
    identifier = line.match(/^Change (\d+)/)[1].to_i

    execute("p4 #{p4_opts(false)} describe -s #{identifier}", options) do |io|
      log = io.read

      if log =~ CHANGELIST_PATTERN
        developer, time, message, files = $1, $2, $3, $4
      elsif log =~ CHANGELIST_PATTERN_NO_MSG
        developer, time, files = $1, $2, $3
      else
        puts "PARSE ERROR:"
        puts log
        puts "\nDIDN'T MATCH:"
        puts CHANGELIST_PATTERN
      end

      # The parsed time doesn't have timezone info. We'll tweak it.
      time = Time.parse(time + " UTC") - @utc_offset

      files.each_line do |line|
        if line =~ /^\.\.\. (\/\/.+)#(\d+) (.+)/
          depot_path = $1
          file_identifier = $2.to_i
          state = $3.strip
          if(STATES[state])
            if(depot_path =~ relative_path_pattern)
              relative_path = $1

              if revision.nil?
                revision = Revision.new
                revision.identifier = identifier
                revision.developer = developer
                revision.message = message
                revision.time = time
                revisions.add revision
              end

              file = RevisionFile.new
              file.path = relative_path
              file.native_revision_identifier = file_identifier
              file.previous_native_revision_identifier = file.native_revision_identifier-1
              file.status = STATES[state]
              revision.add file
            end
          end
        end
      end
    end
  end
  revisions
end