Module: Commands

Defined in:
lib/commands/help.rb,
lib/commands/init.rb,
lib/commands/kill.rb,
lib/commands/util.rb,
lib/commands/start.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/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.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

.download_p4_via_ftp(version) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/commands/download.rb', line 63

def Commands.download_p4_via_ftp(version)
  download_via_ftp(version, OsUtil.p4_executable, OsUtil.p4_path)

  if !File.executable?(OsUtil.p4_path)
    File.chmod(0755, OsUtil.p4_path)
  end
end

.download_p4api_via_ftp(version) ⇒ Object



79
80
81
82
83
# File 'lib/commands/download.rb', line 79

def Commands.download_p4api_via_ftp(version)
  download_via_ftp(version, OsUtil.p4api_file, OsUtil.p4api_path)

  # um, probably should expand this guy out
end

.download_p4d_via_ftp(version) ⇒ Object



71
72
73
74
75
76
77
# File 'lib/commands/download.rb', line 71

def Commands.download_p4d_via_ftp(version)
  download_via_ftp(version, OsUtil.p4d_executable, OsUtil.p4d_path)

  if !File.executable?(OsUtil.p4d_path)
    File.chmod(0755, OsUtil.p4d_path)
  end
end

.download_via_ftp(version, filename, output_path) ⇒ Object



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

def Commands.download_via_ftp(version, filename, output_path)
  ftp = Net::FTP.new('ftp.perforce.com')
  ftp.

  dir = OsUtil.ftp_download_dir(version)
  ftp.chdir(dir)

  ftp.passive=true

  Conventions.init_working_dir

  ftp.getbinaryfile(filename, output_path)
ensure
  ftp.close if ftp and !ftp.closed?
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



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/commands/init.rb', line 11

def Commands.init(options=nil)
  init_dir = 'p4init'
  # TODO we may want to allow this to be overridden, though I find this a
  #      spurious and dangerous use case
  p4port = '127.0.0.1:1666'

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

  if !p4d_running?
    # The way this works: if you specify any options, like what to download
    # you must specify the initialization directory.
    Commands.start(options)
  end

  initialize_p4d(init_dir, p4port)
end

.initialize_p4d(init_dir, p4port) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/commands/init.rb', line 142

def Commands.initialize_p4d(init_dir, p4port)
  # Go through our init_dir, and evaluate each script as if it were defined
  # in the Commands::Init module.
  Dir.glob("#{init_dir}/**/*.rb") do |file|
    contents = IO.read(file)
    Commands::Init.class_eval(contents, file)
  end

  # Note that nothing is actually done until this line. This allows classes
  # to re-define methods and do fancy shit, like, 'oh in security_settings 0
  # this guy actually doesn't have a password'.
  Commands::Init::InitModel.run(p4port)
end

.kill(options = nil) ⇒ Object



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

def Commands.kill(options=nil)
  ProcTable.ps().find_all{|p| p.comm =~ /p4d/}.each do |p|
    begin
      Process.kill('TERM', p.pid)
    rescue
      puts "Problem killing #{p}, ignoring"
    end
  end

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

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

Returns:

  • (Boolean)


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

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?
  !ProcTable.ps().find_all { |p| p.comm =~ /p4d/ }.empty?
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 work/ 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


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

def Commands.print_general_help
  puts <<-END.gsub(/^ {6}/, '')
    p4util [command] [params]

    Executes various commands useful when writing Perforce applications.

    Use `p4util help [command]` for more information on each command.

    List of available commands:
      download - Download Perforce binaries for your platform
      init - Seed the local p4d instance using local configuration files
      kill - Shutdown p4d processes using SIGTERM
      start - Spawn the p4d process in your working directory
  END
end


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

def Commands.print_init_help
  puts <<-END.gsub(/^ {6}/, '')
    p4util init [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.

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

  END
end


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

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 work/p4droot directory.

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

    Will try to set up a server log at work/server.log. It'll be fairly
    verbose by default; this is *not* intended for any kind of performance
    testing.
  END
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



21
22
23
24
25
26
# File 'lib/commands/util.rb', line 21

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

end