Module: Commands

Defined in:
lib/commands/help.rb,
lib/commands/init.rb,
lib/commands/kill.rb,
lib/commands/rake.rb,
lib/commands/util.rb,
lib/commands/start.rb,
lib/commands/version.rb,
lib/commands/download.rb,
lib/commands/init/init_model.rb,
lib/commands/init/p4_helpers.rb,
lib/commands/init/user_model.rb,
lib/commands/init/depot_model.rb,
lib/commands/init/group_model.rb,
lib/commands/init/trigger_model.rb,
lib/commands/init/file_definition.rb,
lib/commands/init/changelist_model.rb,
lib/commands/init/system_settings_model.rb

Defined Under Namespace

Modules: Init

Class Method Summary collapse

Class Method Details

.download(options = nil) ⇒ Object

TODO the p4ruby extconf.rb file mechanism has some logic to search the ftp site for things. We might also want to use HTTP



10
11
12
13
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
# File 'lib/commands/download.rb', line 10

def Commands.download(options=nil)
  version = 'r14.2'
  binary = 'p4d'

  if options and options.params and !options.params.empty?

    op = OptionParser.new do |op|
      op.on('-v VERSION', '--version VERSION', 'ftp.perforce.com version') do |v|
        version = v
      end
    end

    op.parse!(options.params)

    if !options.params.empty?
      binary = options.params.first
    end
  end

  case binary
    when 'p4'
      download_p4_via_ftp(version)
    when 'p4d'
      download_p4d_via_ftp(version)
    when 'p4api'
      download_p4api_via_ftp(version)
    else
      raise "Don't know how to download #{binary}, check 'p4util help download'"
  end
end

.help(options) ⇒ Object



4
5
6
7
8
9
10
11
# File 'lib/commands/help.rb', line 4

def Commands.help(options)
  if !options.params.empty? && Commands.respond_to?(options.params.first.to_sym)
    method_name = "print_#{options.params.first}_help".to_sym
    Commands.method(method_name).call()
  else
    print_general_help
  end
end

.init(options = nil) ⇒ Object



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
# File 'lib/commands/init.rb', line 14

def Commands.init(options=nil)
  init_dir = 'p4init'

  p4port = '127.0.0.1:1666'
  version = nil
  auto = false

  if options and !options.params.empty?

    op = OptionParser.new do |op|
      op.on('-p PORT', '--port PORT', 'P4PORT setting') { |x| p4port = x }
      op.on('-a', '--auto', 'Force charset to be auto') { |x| auto = true }
      op.on('-v VERSION', '--version VERSION', 'ftp.perforce.com version') do |v|
        version = v
      end
    end

    op.parse!(options.params)

    if !options.params.empty?
      init_dir = options.params.first
    end
  end

  if options and !options.params.empty?
    init_dir = options.params.shift
  end

  initialize_p4d(init_dir, p4port, auto)
end

.kill(options = nil) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/commands/kill.rb', line 5

def Commands.kill(options=nil)
  list_process_names.select{|p| p =~ /p4d/}.each do |p|
    pid = pid_for_process(p)
    next if pid.nil?
    begin
      puts "killing p4d #{p} at #{pid}"
      Process.kill('TERM', pid)
    rescue Exception => e
      puts "Problem killing #{p}: #{e.message}"
      puts e.backtrace.join('\n')
    end
  end

  is_running = true
  while is_running
    is_running = p4d_running?
    if is_running
      sleep 0.2
    end
  end
end

.list_process_namesObject



9
10
11
12
13
14
15
16
# File 'lib/commands/util.rb', line 9

def self.list_process_names
  if OsUtil.osx? or OsUtil.linux?
    return `ps aux | awk '{print $11}'`.split(/\n/).drop(1)
  else
    # TODO investigate using tasklist just for this
    raise 'No support for windows just yet'
  end
end

.p4d_available?(port = ':1666') ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
35
36
37
38
39
40
41
# File 'lib/commands/util.rb', line 31

def Commands.p4d_available?(port=':1666')
  begin
    p4 = P4.new
    p4.port = port
    p4.connect
    p4.disconnect
    true
  rescue
    false
  end
end

.p4d_running?Boolean

Returns:

  • (Boolean)


5
6
7
# File 'lib/commands/util.rb', line 5

def Commands.p4d_running?
  list_process_names.select { |p| p =~ /p4d/ }.empty? == false
end

.pid_for_process(process) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/commands/util.rb', line 18

def self.pid_for_process(process)
  if OsUtil.osx? or OsUtil.linux?
    line = `ps aux | awk '{print $2,$11}'`.split(/\n/).drop(1).find { |p| p =~ /#{process}/ }
    unless line.nil?
      return line.split('\n').first.to_i
    else
      return nil
    end
  else
    raise 'NO support for windows yet'
  end
end


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/commands/download.rb', line 41

def Commands.print_download_help
  puts <<-END.gsub(/^ {6}/, '')
    p4util download [p4|p4d|p4api]

    Downloads one of the following utilities (in lieu of an installer) into
    a local /tmp/p4util/ directory.

    * p4
    * p4d
    * p4api

    Will default to the r14.2 release.

    Options:

    --version X where X looks like the version in the ftp.perforce.com site,
              e.g., 'r14.2' instead of '2014.2'
  END
end


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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/commands/init.rb', line 45

def Commands.print_init_help
  puts <<-END.gsub(/^ {6}/, '')
    p4util init [-p P4PORT] [-a] [p4_init_dir]

    Reads definitions in the directory p4_init_dir - by default, just
    'p4init' - and then calls methods on a p4d instance assumed to be running
    locally.

    This assumes we are basically starting from scratch. If you have an
    existing p4d instance, it's highly likely your initialization run will
    fail. Delete your settings and working area and reset.

    Options:

      -p P4PORT : Specify p4 port setting, defaults to ':1666' (uses localhost)
      -a        : Force our 'charset' to be 'auto'

    ## Definition Files ##

    Files are Ruby scripts, each basically extending a model class defined
    by this application.

    Each model type is defined separately later, however, you should have
    at least one User model that's marked as a super user. If you don't do
    this, you will always have a super user created with the login 'p4super'
    and the password 'superuser1A!'.

    ## Execution Order ##

    Each model you define has a 'rank'. Models classes generate instances, and
    each instance is sorted based on this rank. If you specify no rank, or
    any rank is equivalent, well, you submit your will to the gods of random.

    The only special model type that does not obey these rules is the
    SystemSettings model, which is always handled in a very particular order.


    ## SystemSettingsModel ##

    Example:

    class MySystemSettings < SystemSettingsModel
      # These are default settings
      @unicode = true
      @security_level = 0

      # By default this is empty, but here's an example of usage
      @configure_settings = {
        'dm.keys.hide' => '2'
      }
    end

    When `unicode` is enabled, this assumes that the `p4util init` command
    is run in the *same directory*  as `p4util start`.


    ## UserModel ##

    Example of a super user (you need one):

    class SuperUser < UserModel
      @super = true
      # if you don't set, we'll just use this for the full_name and email
      @login = 'super'
      @password = 'superuser1A'
    end

    Example of a normal user:

    class JohnDoeUser < UserModel
      def rank; 100; end
      @login = 'jdoe'
      @full_name = 'John Doe'
      @email = '[email protected]'
      @password = 'johndoe1A!'
    end

    Note that with the super user, you don't really need a rank, but with
    your other models, it's a good idea. (You can mix when users come and go
    with other changes.)


    ## ChangelistModel ##

    Example of a changelist with an add and edit:

    class Changelist2 < ChangelistModel
      def rank; 1001 end
      @description = 'An example add and edit'
      @user = 'jdoe'
      @edits = [
          FileDefinition.new(:path => 'depot/README.txt',
                         :content => <<-STOP.gsub(/^ {8}/, '')
            This is an example readme.
            Added a second line
          STOP
          )
        ]
        @adds = [
            FileDefinition.new(:path => 'depot/main/project2/example.txt',
                               :local_path => 'p4init/some_text.txt')
        ]
    end

    Note that adds an edits are specified with 'FileDefinition' objects. Each
    file definition instance can define text content inline, or via a
    'local_path' to a file relative to the current working directory.

    The `@user` is not necessary, but you probably don't want to add everything
    as your super user, so set this to a UserModel instance that should exist
    at this point.

    ## DepotModel ##

    Example creating a new standard depot:

      class ProjectDepot < DepotModel
        def rank
          1001
        end
        @depot = 'my_project'
        @description = 'The My Project depot'
      end

    Other attributes that can be set that update the depot spec being written:

      :type, :address, :suffix, :map, :spec_map

    ## GroupModel ##

    Example:

      class SystemGroup < GroupModel
        def rank; 2000 end
        @group = 'system'
        @timeout = 'unset'
        @password_timeout = 'unset'
        @users = ['app']
      end

    Attributes:

        :group, :max_results, :max_scan_rows,
        :max_lock_time, :password_timeout, :timeout,
        :users, :subgroups, :owners

    ## TriggerModel ##

    Example:

      class ExampleTriggers < TriggerModel
        def rank; 50; end

        @triggers = [
          'trig1 change-submit //depot/dir/... "/usr/bin/s1.pl %changelist%"',
          'trig2 change-submit -//depot/z/... "/usr/bin/s1.pl %user%"'
        ]
      end
  END
end


27
28
29
30
31
32
33
34
35
36
# File 'lib/commands/kill.rb', line 27

def Commands.print_kill_help
  puts <<-END.gsub(/^ {6}/,'')
    p4util kill

    Finds local p4d processes and kills them.

    On unix machines, will probably use `ps -x` and 'p4d', then will send
    SIGTERM signals to each process.
  END
end


26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/commands/start.rb', line 26

def Commands.print_start_help
  puts <<-END.gsub(/^ {6}/,'')
    p4util start

    Spawns a Perforce process in your local /tmp/p4util/p4droot directory.

    If the Perforce executable does not exist, will download the binary first.

    Will try to set up a server log at /tmp/p4util/server.log. It'll be fairly
    verbose by default; this is *not* intended for any kind of performance
    testing.
  END
end

.rake(options) ⇒ Object



4
5
6
# File 'lib/commands/rake.rb', line 4

def Commands.rake(options)
  print_rake_help
end

.spawn_p4dObject



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/commands/start.rb', line 12

def Commands.spawn_p4d
  pid = Process.spawn("#{OsUtil.p4d_path} -r #{Conventions.p4droot_dir} "+
                      "-v server=1 -L #{Conventions.p4d_log_path}")
  Process.detach(pid)

  while !p4d_running?
    sleep 0.2
  end

  while !p4d_available?
    sleep 0.1
  end
end

.start(options = nil) ⇒ Object



4
5
6
7
8
9
10
# File 'lib/commands/start.rb', line 4

def Commands.start(options=nil)
  if !File.exists?(OsUtil.p4d_path)
    Commands.download(options)
  end
  Conventions.init_p4droot_dir
  spawn_p4d
end

.unicode_upgradeObject



43
44
45
46
47
48
# File 'lib/commands/util.rb', line 43

def Commands.unicode_upgrade
  system("#{OsUtil.p4d_path} -r #{Conventions.p4droot_dir} "+
             "-v server=1 -L #{Conventions.p4d_log_path} " +
             "-xi")

end

.version(options) ⇒ Object



6
7
8
# File 'lib/commands/version.rb', line 6

def Commands.version(options)
  print_version_help
end