p4util 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ca08621e3878ebd6ab034b9046f0ed94425ad978
4
- data.tar.gz: 5be2227361463716cd9b0870eee7b2769a079f50
3
+ metadata.gz: 45a2fa04d57ee5b6aca04b509acc1705dffb1f35
4
+ data.tar.gz: 0561143880e7350548859aa309f2c499d3ac3d70
5
5
  SHA512:
6
- metadata.gz: 8ee68971ece495b7f3d3f7695e666e3b443d08a24e26c4d8a90b1a6a83df83d786c024c1d3ab12cb7980812028afa298508fae54628411d572a33e742348b347
7
- data.tar.gz: b2f844d7ba44aabffadbdbdcd317d623d0e9b671633de45290f784ad466549bd0aa6949b14cd64ba1f6523db658e328f3ebde00b209323c1a175b39ca302a16a
6
+ metadata.gz: 1c01e49961c05d2fe79b25c504e7748349e014407ef0975c6f1dc1434b24e02a344512d840758f68601fcb3dcd434769bcd2281eb36ed5e700de064a25039292
7
+ data.tar.gz: d4e3bc148311ae182387bfe3db5541d10e5a1dae0c26fe8d8bd12a432f8749d181adfcbfc5ac27b766b18b0d38b07645f15bfd0e22267eec613254c63d8f1be2
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in p4_util.gemspec
3
+ # Specify your gem's dependencies in p4util.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -1,6 +1,20 @@
1
- # P4util
1
+ # p4util - common p4 scripting tasks for ruby projects
2
+
3
+ When building any kind of tool that uses Perforce underneath, it's pretty common
4
+ to want a few capabilities:
5
+
6
+ * Download different versions of p4, p4d, and the C++ API
7
+ * Initialize up a consistent starting environment of p4d
8
+
9
+ This is a binary script and set of rake tasks that allows this.
10
+
11
+
12
+ ## Usage
13
+
14
+ After installation, `p4util help` will list available commands, and
15
+ `p4util help [command]` will list instructions. Some commands, like `p4util init`
16
+ are quite extensive, and should be used as the reference.
2
17
 
3
- TODO: Write a gem description
4
18
 
5
19
  ## Installation
6
20
 
@@ -18,14 +32,11 @@ Or install it yourself as:
18
32
 
19
33
  $ gem install p4util
20
34
 
21
- ## Usage
22
35
 
23
- TODO: Write usage instructions here
36
+ ## Changes
24
37
 
25
- ## Contributing
38
+ * 0.1.0: Added `p4util init` command that can do some common p4d configurations,
39
+ like setting unicode and security settings, along with users and basic
40
+ adds and edits of files.
26
41
 
27
- 1. Fork it ( https://github.com/[my-github-username]/p4util/fork )
28
- 2. Create your feature branch (`git checkout -b my-new-feature`)
29
- 3. Commit your changes (`git commit -am 'Add some feature'`)
30
- 4. Push to the branch (`git push origin my-new-feature`)
31
- 5. Create a new Pull Request
42
+ * 0.0.1-0.0.3: Basic download capabilities
data/Rakefile CHANGED
@@ -1,2 +1,7 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rdoc/task'
2
3
 
4
+ RDoc::Task.new do |rdoc|
5
+ rdoc.main = 'README.md'
6
+ rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
7
+ end
data/bin/p4util CHANGED
@@ -4,6 +4,6 @@
4
4
  #
5
5
  lib_path = File.expand_path('../../lib', __FILE__)
6
6
  $LOAD_PATH.unshift(lib_path)
7
- require 'p4_util'
7
+ require 'p4util'
8
8
 
9
9
  P4Util::run ARGV
@@ -5,6 +5,8 @@ require 'net/ftp'
5
5
 
6
6
  module Commands
7
7
 
8
+ # TODO the p4ruby extconf.rb file mechanism has some logic to search the ftp
9
+ # site for things. We might also want to use HTTP
8
10
  def Commands.download(options=nil)
9
11
  version = 'r14.2'
10
12
  binary = 'p4d'
@@ -25,6 +27,8 @@ module Commands
25
27
  end
26
28
 
27
29
  case binary
30
+ when 'p4'
31
+ download_p4_via_ftp(version)
28
32
  when 'p4d'
29
33
  download_p4d_via_ftp(version)
30
34
  when 'p4api'
@@ -36,15 +40,16 @@ module Commands
36
40
 
37
41
  def Commands.print_download_help
38
42
  puts <<-END.gsub(/^ {6}/, '')
39
- p4util download [p4d|p4api]
43
+ p4util download [p4|p4d|p4api]
40
44
 
41
45
  Downloads one of the following utilities (in lieu of an installer) into
42
46
  a local work/ directory.
43
47
 
48
+ * p4
44
49
  * p4d
45
50
  * p4api
46
51
 
47
- Will default to the latest release unless you don't know what that is.
52
+ Will default to the r14.2 release.
48
53
 
49
54
  Options:
50
55
 
@@ -55,6 +60,14 @@ module Commands
55
60
 
56
61
  private
57
62
 
63
+ def Commands.download_p4_via_ftp(version)
64
+ download_via_ftp(version, OsUtil.p4_executable, OsUtil.p4_path)
65
+
66
+ if !File.executable?(OsUtil.p4_path)
67
+ File.chmod(0755, OsUtil.p4_path)
68
+ end
69
+ end
70
+
58
71
  def Commands.download_p4d_via_ftp(version)
59
72
  download_via_ftp(version, OsUtil.p4d_executable, OsUtil.p4d_path)
60
73
 
@@ -0,0 +1,101 @@
1
+ require 'commands/init/init_model'
2
+ require 'commands/init/p4_helpers'
3
+ require 'fileutils'
4
+
5
+ module Commands
6
+ module Init
7
+
8
+ class ChangelistModel < InitModel
9
+ include Commands::Init::P4Helpers
10
+
11
+ inheritable_attributes :description, :adds, :edits, :user
12
+
13
+ # Please make this descriptive
14
+ @description = 'Init changelist'
15
+
16
+ # An array of 'file definitions'
17
+ @adds = []
18
+
19
+ # An array of 'file definitions' expected to already exist
20
+ @edits = []
21
+
22
+ # The user we should operate as if you don't want to do this as the super
23
+ # user
24
+ @user = nil
25
+
26
+ #========================================================================
27
+ # Internal implementation
28
+ #========================================================================
29
+
30
+ def self.abstract
31
+ true
32
+ end
33
+
34
+ attr_accessor :description, :adds, :edits, :user
35
+
36
+ def initialize
37
+ @description = self.class.description
38
+ @adds = self.class.adds
39
+ @edits = self.class.edits
40
+ @user = self.class.user
41
+ end
42
+
43
+ def execute(p4, models, super_user)
44
+ # Set up our options with a user context if specified by searching the
45
+ # defined models.
46
+ options = {:p4 => p4}
47
+ if user
48
+ model = models.find {|m| m.class < UserModel && m.login == user }
49
+ options[:user] = model.login
50
+ options[:password] = model.password
51
+ options[:olduser] = super_user.login
52
+ options[:oldpass] = super_user.password
53
+ end
54
+
55
+ # Define the logic of what the changelist model really does: make adds
56
+ # and edits for the most part
57
+ open_client(options) do |client_path, name|
58
+
59
+ change_spec = p4.fetch_change
60
+ change_spec._description = description
61
+ results = p4.save_change(change_spec)
62
+ change_id = results[0].gsub(/^Change (\d+) created./, '\1')
63
+
64
+ @adds.each do |add|
65
+ add_path = File.join(client_path, add.path)
66
+ dir = File.dirname(add_path)
67
+ if dir && !dir.empty?
68
+ if !Dir.exist?(dir)
69
+ FileUtils.mkpath(dir)
70
+ end
71
+ end
72
+ if add.content
73
+ IO.write(add_path, add.content)
74
+ elsif add.local_path
75
+ FileUtils.copy(add.local_path, add_path)
76
+ end
77
+ p4.run_add('-c', change_id, add_path)
78
+ end
79
+
80
+ @edits.each do |edit|
81
+ edit_path = File.join(client_path, edit.path)
82
+ p4.run_edit('-c', change_id, edit_path)
83
+
84
+ if edit.content
85
+ IO.write(edit_path, edit.content)
86
+ else
87
+ FileUtils.copy(edit.local_path, edit_path)
88
+ end
89
+ end
90
+
91
+ p4.run_submit('-c', change_id)
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ # do stuff
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module Commands
3
+ module Init
4
+
5
+ class FileDefinition
6
+ attr_accessor :path, :content, :local_path
7
+
8
+ # Options should indicate :content or :local_path, but not both
9
+ def initialize(options)
10
+ @path = options[:path]
11
+ @content = options[:content] if options.key?(:content)
12
+ @local_path = options[:local_path] if options.key?(:local_path)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,95 @@
1
+ require 'P4'
2
+
3
+ module Commands
4
+ module Init
5
+ # Base class of 'initializers'.
6
+ #
7
+ # This actually acts more as a registry of defined classes.
8
+ class InitModel
9
+ # Child classes should define this number greater than one. 0 should be
10
+ # reserved for a single system settings instance.
11
+ def rank
12
+ 1
13
+ end
14
+
15
+ # It's likely that the main child class will handle overriding this method.
16
+ # Our default method does nothing.
17
+ def execute(p4)
18
+ end
19
+
20
+ #========================================================================
21
+ # Ok, the real business starts here.
22
+ #
23
+ # Don't even think about overriding the following rules
24
+ #========================================================================
25
+
26
+ class << self
27
+ attr_accessor :model_classes
28
+ end
29
+
30
+ # The registered set of non-abstract model classes.
31
+ #
32
+ @model_classes = []
33
+
34
+ @inheritable_attributes ||= [:inheritable_attributes]
35
+
36
+ # A lot of our settings are actually class instance variables, which
37
+ # can be overridden. This allows the child classes that depend on these
38
+ # values to define what they are.
39
+ def self.inheritable_attributes(*args)
40
+ @inheritable_attributes += args
41
+ args.each do |arg|
42
+ class_eval %(
43
+ class << self; attr_accessor :#{arg} end
44
+ )
45
+ end
46
+ @inheritable_attributes
47
+ end
48
+
49
+ def self.inherited(subclass)
50
+ # Copy 'down' any inheritable attribute to the new child class
51
+ @inheritable_attributes.each do |inheritable_attribute|
52
+ instance_var = "@#{inheritable_attribute}"
53
+ subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
54
+ end
55
+
56
+ if subclass.respond_to?(:abstract) && subclass.send(:abstract)
57
+ InitModel.model_classes.push(subclass)
58
+ end
59
+ end
60
+
61
+ def self.run(p4port)
62
+ system_settings = nil
63
+ super_user = nil
64
+ models = []
65
+
66
+ InitModel.model_classes.each do |model|
67
+ if model <= DefaultSuperUser
68
+ # do nothing
69
+ elsif model <= SystemSettingsModel
70
+ system_settings = model.new
71
+ elsif !super_user and model <= UserModel and model.super
72
+ super_user = model.new
73
+ else
74
+ models << model.new
75
+ end
76
+ end
77
+
78
+ if !super_user
79
+ super_user = DefaultSuperUser.new
80
+ end
81
+
82
+ models.sort! { |a, b| a.rank <=> b.rank }
83
+
84
+ p4 = P4.new
85
+ p4.port = p4port
86
+ p4.connect
87
+ p4.exception_level = P4::RAISE_ERRORS
88
+
89
+ system_settings.execute(p4, super_user)
90
+
91
+ models.each { |m| m.execute(p4, models, super_user) }
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,75 @@
1
+
2
+ require 'conventions'
3
+ require 'random_util'
4
+
5
+ module Commands
6
+ module Init
7
+ module P4Helpers
8
+
9
+ # Intended to be a block helper that creates a 'temporary client'
10
+ #
11
+ # Your block should take the client name and path.
12
+ #
13
+ # Example:
14
+ #
15
+ # open_client(p4) do |path, name|
16
+ # puts "my client #{name}'s root is #{path}"
17
+ # end
18
+ def open_client(options)
19
+ p4 = options[:p4]
20
+
21
+ # Switch user only if specified
22
+ user = nil
23
+ password = nil
24
+ olduser = nil
25
+ oldpass = nil
26
+ if (options[:user])
27
+ user = options[:user]
28
+ password = options[:password] if options.key?(:password)
29
+ olduser = options[:olduser]
30
+ oldpass = options[:oldpass] if options.key?(:oldpass)
31
+ p4.user = user
32
+ p4.password = password
33
+ p4.run_login if password
34
+ end
35
+
36
+ name = RandomUtil.randstr
37
+ dir = File.join(Conventions.client_root_dir, name)
38
+
39
+ if !Dir.exist?(dir)
40
+ FileUtils.mkpath(dir)
41
+ end
42
+
43
+ spec = p4.fetch_client
44
+ spec._root = dir
45
+ spec._client = name
46
+ spec._description = 'p4util init temp client'
47
+ spec._view = ["//depot/... //#{name}/depot/..."]
48
+
49
+ p4.save_client(spec)
50
+
51
+ p4.client = name
52
+
53
+ p4.run_sync('-f', '//...')
54
+
55
+ if block_given?
56
+ yield dir, name
57
+ else
58
+ return dir, name
59
+ end
60
+ ensure
61
+ if block_given?
62
+ if (user)
63
+ p4.user = olduser
64
+ p4.password = oldpass
65
+ p4.run_login if oldpass
66
+ end
67
+
68
+ p4.run_client('-d', '-f', name)
69
+ p4.client = 'invalid'
70
+ FileUtils.rmtree(dir)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,120 @@
1
+
2
+ require 'commands'
3
+ require 'commands/init/init_model'
4
+
5
+ module Commands
6
+ module Init
7
+
8
+ class SystemSettingsModel < InitModel
9
+ inheritable_attributes :unicode, :security_level, :configure_settings
10
+
11
+ # Pick some normal defaults
12
+
13
+ # This basically will upgrade the DB before anything happens to unicode
14
+ # mode. The default is false, though you probably should use true for
15
+ # most default 'setups' these days.
16
+ @unicode = false
17
+
18
+ # The security level is set basically as the first major setting, before
19
+ # most users are generated, to avoid password mayhem
20
+ @security_level = 0
21
+
22
+ # These basically map to 'p4 configure set #{key}=#{value}'
23
+ @configure_settings = {}
24
+
25
+ #========================================================================
26
+ # Internal implementation - don't mess with this
27
+ #========================================================================
28
+
29
+ def rank
30
+ 0
31
+ end
32
+
33
+ def self.abstract
34
+ true
35
+ end
36
+
37
+ attr_reader :unicode, :security_level, :configure_settings
38
+
39
+ def initialize
40
+ @unicode = self.class.unicode
41
+ @security_level = self.class.security_level
42
+ @configure_settings = self.class.configure_settings
43
+ end
44
+
45
+ # If the security level is > 0, we generate the super_user first, change
46
+ # security, then reset the super's password. The p4 connection is
47
+ # established here with whatever credentials we end up with the super
48
+ # user as.
49
+ def execute(p4, super_user)
50
+ set_unicode_mode(p4)
51
+ set_security_and_super_user(p4, super_user)
52
+ create_default_protections(p4)
53
+ end
54
+
55
+ private
56
+
57
+ def set_unicode_mode(p4)
58
+ if unicode
59
+ p4.disconnect
60
+
61
+ # Halt any exiting perforce server
62
+ Commands.kill
63
+
64
+ # Execute the upgrade of the p4d instance
65
+ Commands.unicode_upgrade
66
+
67
+ # Restart: this assumes the cwd of the init call is the same as the
68
+ # 'start' call. This is a pretty safe assumption, since our .init
69
+ # function will call start if it's not running.
70
+ Commands.start
71
+
72
+ while !Commands.p4d_running?
73
+ sleep 0.2
74
+ end
75
+
76
+ # I'm not sure this should be anything else for the purposes of
77
+ # initialization
78
+ p4.charset = 'auto'
79
+
80
+ p4.connect
81
+ end
82
+ end
83
+
84
+ def set_security_and_super_user(p4, super_user)
85
+ # update security mode if needed
86
+ if security_level > 0
87
+ # On some security levels, you *must* reset passwords when updating
88
+ # even if the base password is strong.
89
+ super_pwd = super_user.password
90
+ super_user.password = ''
91
+ super_user.execute(p4)
92
+
93
+ p4.run('configure', 'set', "security=#{security_level}")
94
+
95
+ p4.user = super_user.login
96
+ p4.password = super_user.password
97
+
98
+ p4.run_password(super_user.password, super_pwd)
99
+ super_user.password = super_pwd
100
+
101
+ p4.password = super_user.password
102
+ p4.run_login
103
+ else
104
+ # Just create the user
105
+ super_user.execute(p4)
106
+ if super_user.password
107
+ p4.password = super_user.password
108
+ p4.run_login
109
+ end
110
+ end
111
+ end
112
+
113
+ def create_default_protections(p4)
114
+ # This actually will establish the defaults with our super user as the
115
+ # only entry
116
+ results = p4.run_protect('-o')
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,84 @@
1
+ require 'commands/init/init_model'
2
+
3
+ module Commands
4
+ module Init
5
+
6
+ class UserModel < InitModel
7
+ inheritable_attributes :login, :full_name, :password, :email, :super
8
+
9
+ @login = nil
10
+ @full_name = nil
11
+ @password = nil
12
+ @email = nil
13
+ # Set this to true if you want the user to be our 'super user'. We'll
14
+ # generally need one of these for each init step. We will make sure a
15
+ # protections entry for this user exists
16
+ @super = false
17
+
18
+ #========================================================================
19
+ # Internal implementation - don't mess with this
20
+ #========================================================================
21
+
22
+ def self.abstract
23
+ true
24
+ end
25
+
26
+ attr_accessor :login, :password
27
+
28
+ def initialize
29
+ @login = self.class.login
30
+ @full_name = self.class.full_name
31
+ @password = self.class.password
32
+ @email = self.class.email
33
+ @super = self.class.super
34
+ end
35
+
36
+ def email
37
+ @email || "#{login}@example.com"
38
+ end
39
+
40
+ def full_name
41
+ @full_name || login
42
+ end
43
+
44
+ def super?
45
+ @super
46
+ end
47
+
48
+ def to_s
49
+ "UserModel: login=#{login} email=#{email} full_name=#{full_name} password=#{password}"
50
+ end
51
+
52
+ def to_spec
53
+ spec = {
54
+ 'User' => login,
55
+ 'Email' => email,
56
+ 'FullName' => full_name
57
+ }
58
+ spec
59
+ end
60
+
61
+ def execute(p4, models=nil, super_user=nil)
62
+ p4.save_user(to_spec, '-f')
63
+
64
+ p4.user = login
65
+ p4.password = ''
66
+
67
+ p4.run_password('', password) if password
68
+
69
+ if super_user
70
+ p4.user = super_user.login
71
+ p4.password = super_user.password
72
+ end
73
+ end
74
+ end
75
+
76
+ class DefaultSuperUser < UserModel
77
+ @login = 'p4super'
78
+ @password = 'superuser1A!'
79
+ @full_name = 'Super User'
80
+ @super = true
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,155 @@
1
+
2
+ require 'commands/start'
3
+ require 'commands/init/init_model'
4
+ require 'commands/init/changelist_model'
5
+ require 'commands/init/file_definition'
6
+ require 'commands/init/system_settings_model'
7
+ require 'commands/init/user_model'
8
+
9
+ module Commands
10
+
11
+ def Commands.init(options=nil)
12
+ init_dir = 'p4init'
13
+ # TODO we may want to allow this to be overridden, though I find this a
14
+ # spurious and dangerous use case
15
+ p4port = '127.0.0.1:1666'
16
+
17
+ if options and !options.params.empty?
18
+ init_dir = options.params.shift
19
+ end
20
+
21
+ if !p4d_running?
22
+ # The way this works: if you specify any options, like what to download
23
+ # you must specify the initialization directory.
24
+ Commands.start(options)
25
+ end
26
+
27
+ initialize_p4d(init_dir, p4port)
28
+ end
29
+
30
+ def Commands.print_init_help
31
+ puts <<-END.gsub(/^ {6}/, '')
32
+ p4util init [p4_init_dir]
33
+
34
+ Reads definitions in the directory p4_init_dir - by default, just
35
+ 'p4init' - and then calls methods on a p4d instance assumed to be running
36
+ locally.
37
+
38
+ This assumes we are basically starting from scratch. If you have an
39
+ existing p4d instance, it's highly likely your initialization run will
40
+ fail. Delete your settings and working area and reset.
41
+
42
+ ## Definition Files ##
43
+
44
+ Files are Ruby scripts, each basically extending a model class defined
45
+ by this application.
46
+
47
+ Each model type is defined separately later, however, you should have
48
+ at least one User model that's marked as a super user. If you don't do
49
+ this, you will always have a super user created with the login 'p4super'
50
+ and the password 'superuser1A!'.
51
+
52
+ ## Execution Order ##
53
+
54
+ Each model you define has a 'rank'. Models classes generate instances, and
55
+ each instance is sorted based on this rank. If you specify no rank, or
56
+ any rank is equivalent, well, you submit your will to the gods of random.
57
+
58
+ The only special model type that does not obey these rules is the
59
+ SystemSettings model, which is always handled in a very particular order.
60
+
61
+
62
+ ## SystemSettingsModel ##
63
+
64
+ Example:
65
+
66
+ class MySystemSettings < SystemSettingsModel
67
+ # These are default settings
68
+ @unicode = true
69
+ @security_level = 0
70
+
71
+ # By default this is empty, but here's an example of usage
72
+ @configure_settings = {
73
+ 'dm.keys.hide' => '2'
74
+ }
75
+ end
76
+
77
+ When `unicode` is enabled, this assumes that the `p4util init` command
78
+ is run in the *same directory* as `p4util start`.
79
+
80
+
81
+ ## UserModel ##
82
+
83
+ Example of a super user (you need one):
84
+
85
+ class SuperUser < UserModel
86
+ @super = true
87
+ # if you don't set, we'll just use this for the full_name and email
88
+ @login = 'super'
89
+ @password = 'superuser1A'
90
+ end
91
+
92
+ Example of a normal user:
93
+
94
+ class JohnDoeUser < UserModel
95
+ def rank; 100; end
96
+ @login = 'jdoe'
97
+ @full_name = 'John Doe'
98
+ @email = 'jdoe@example.com'
99
+ @password = 'johndoe1A!'
100
+ end
101
+
102
+ Note that with the super user, you don't really need a rank, but with
103
+ your other models, it's a good idea. (You can mix when users come and go
104
+ with other changes.)
105
+
106
+
107
+ ## ChangelistModel ##
108
+
109
+ Example of a changelist with an add and edit:
110
+
111
+ class Changelist2 < ChangelistModel
112
+ def rank; 1001 end
113
+ @description = 'An example add and edit'
114
+ @user = 'jdoe'
115
+ @edits = [
116
+ FileDefinition.new(:path => 'depot/README.txt',
117
+ :content => <<-STOP.gsub(/^ {8}/, '')
118
+ This is an example readme.
119
+ Added a second line
120
+ STOP
121
+ )
122
+ ]
123
+ @adds = [
124
+ FileDefinition.new(:path => 'depot/main/project2/example.txt',
125
+ :local_path => 'p4init/some_text.txt')
126
+ ]
127
+ end
128
+
129
+ Note that adds an edits are specified with 'FileDefinition' objects. Each
130
+ file definition instance can define text content inline, or via a
131
+ 'local_path' to a file relative to the current working directory.
132
+
133
+ The `@user` is not necessary, but you probably don't want to add everything
134
+ as your super user, so set this to a UserModel instance that should exist
135
+ at this point.
136
+
137
+ END
138
+ end
139
+
140
+ private
141
+
142
+ def Commands.initialize_p4d(init_dir, p4port)
143
+ # Go through our init_dir, and evaluate each script as if it were defined
144
+ # in the Commands::Init module.
145
+ Dir.glob("#{init_dir}/**/*.rb") do |file|
146
+ contents = IO.read(file)
147
+ Commands::Init.class_eval(contents, file)
148
+ end
149
+
150
+ # Note that nothing is actually done until this line. This allows classes
151
+ # to re-define methods and do fancy shit, like, 'oh in security_settings 0
152
+ # this guy actually doesn't have a password'.
153
+ Commands::Init::InitModel.run(p4port)
154
+ end
155
+ end
data/lib/commands/kill.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'commands/util'
1
2
  require 'sys/proctable'
2
3
 
3
4
  include Sys
@@ -5,8 +6,21 @@ include Sys
5
6
  module Commands
6
7
 
7
8
  def Commands.kill(options=nil)
8
- ProcTable.ps().find_all{|p| p.comm =~ /p4d/}
9
- .each{|p| Process.kill('TERM', p.pid)}
9
+ ProcTable.ps().find_all{|p| p.comm =~ /p4d/}.each do |p|
10
+ begin
11
+ Process.kill('TERM', p.pid)
12
+ rescue
13
+ puts "Problem killing #{p}, ignoring"
14
+ end
15
+ end
16
+
17
+ is_running = true
18
+ while is_running
19
+ is_running = p4d_running?
20
+ if is_running
21
+ sleep 0.2
22
+ end
23
+ end
10
24
  end
11
25
 
12
26
  def Commands.print_kill_help
@@ -15,8 +29,6 @@ module Commands
15
29
 
16
30
  Finds local p4d processes and kills them.
17
31
 
18
- There should be a timeout that will force kill anything that appears stuck.
19
-
20
32
  On unix machines, will probably use `ps -x` and 'p4d', then will send
21
33
  SIGTERM signals to each process.
22
34
  END
@@ -1,9 +1,9 @@
1
1
 
2
2
  module Commands
3
3
 
4
- def Commands.start(options)
4
+ def Commands.start(options=nil)
5
5
  if !File.exists?(OsUtil.p4d_path)
6
- Commands.download
6
+ Commands.download(options)
7
7
  end
8
8
  Conventions.init_p4droot_dir
9
9
  spawn_p4d
@@ -13,6 +13,14 @@ module Commands
13
13
  pid = Process.spawn("#{OsUtil.p4d_path} -r #{Conventions.p4droot_dir} "+
14
14
  "-v server=1 -L #{Conventions.p4d_log_path}")
15
15
  Process.detach(pid)
16
+
17
+ while !p4d_running?
18
+ sleep 0.2
19
+ end
20
+
21
+ while !p4d_available?
22
+ sleep 0.1
23
+ end
16
24
  end
17
25
 
18
26
  def Commands.print_start_help
@@ -0,0 +1,27 @@
1
+ require 'sys/proctable'
2
+ require 'P4'
3
+
4
+ module Commands
5
+ def Commands.p4d_running?
6
+ !ProcTable.ps().find_all { |p| p.comm =~ /p4d/ }.empty?
7
+ end
8
+
9
+ def Commands.p4d_available?(port=':1666')
10
+ begin
11
+ p4 = P4.new
12
+ p4.port = port
13
+ p4.connect
14
+ p4.disconnect
15
+ true
16
+ rescue
17
+ false
18
+ end
19
+ end
20
+
21
+ def Commands.unicode_upgrade
22
+ system("#{OsUtil.p4d_path} -r #{Conventions.p4droot_dir} "+
23
+ "-v server=1 -L #{Conventions.p4d_log_path} " +
24
+ "-xi")
25
+
26
+ end
27
+ end
data/lib/commands.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'commands/download'
2
+ require 'commands/init'
2
3
  require 'commands/help'
3
4
  require 'commands/kill'
4
5
  require 'commands/start'
data/lib/conventions.rb CHANGED
@@ -17,6 +17,10 @@ module Conventions
17
17
  File.expand_path(File.join(working_dir,'p4droot'))
18
18
  end
19
19
 
20
+ def Conventions.client_root_dir
21
+ File.expand_path(File.join(working_dir,'clients'))
22
+ end
23
+
20
24
  def Conventions.init_p4droot_dir
21
25
  if !File.directory?(p4droot_dir)
22
26
  FileUtils::makedirs(p4droot_dir)
data/lib/osutil.rb CHANGED
@@ -15,6 +15,18 @@ module OsUtil
15
15
  File.expand_path(File.join(Conventions.working_dir, OsUtil.p4d_executable))
16
16
  end
17
17
 
18
+ def OsUtil.p4_executable
19
+ if windows?
20
+ 'p4.exe'
21
+ else
22
+ 'p4'
23
+ end
24
+ end
25
+
26
+ def OsUtil.p4_path
27
+ File.expand_path(File.join(Conventions.working_dir, OsUtil.p4_executable))
28
+ end
29
+
18
30
  def OsUtil.osx?
19
31
  RbConfig::CONFIG['host_os'] =~ /darwin/
20
32
  end
@@ -0,0 +1,94 @@
1
+ # p4util/task.rb - Rake tasks
2
+
3
+ require 'commands'
4
+ require 'conventions'
5
+ require 'fileutils'
6
+ require 'ostruct'
7
+ require 'rake/tasklib'
8
+
9
+ module P4Util
10
+ # Creates a few tasks to allow launching init and kill commands via rake
11
+ # tasks, which should make it easy to script with test tasks, for example.
12
+ #
13
+ # Example:
14
+ #
15
+ # require 'p4util/tasks'
16
+ #
17
+ # P4Util::Tasks.new do |p4util|
18
+ # p4util.version = 'r14.2' # Indicate p4d version to download
19
+ # end
20
+ #
21
+ # Tasks:
22
+ # - p4init
23
+ # - p4kill
24
+ # - p4reset
25
+ class Tasks < Rake::TaskLib
26
+ # The task base name, defaults to ':p4'
27
+ attr_accessor :basename
28
+
29
+ # P4 Version to use, defaults to 'r14.2'
30
+ attr_accessor :version
31
+
32
+ # The directory containing p4 init scripts, defaults to 'p4init'
33
+ attr_accessor :p4_init_dir
34
+
35
+ def initialize basename = :p4
36
+ @basename = basename
37
+ @version = 'r14.2'
38
+ @p4_init_dir = 'p4init'
39
+
40
+ yield self if block_given?
41
+
42
+ define_tasks
43
+ end
44
+
45
+ # Create the tasks defined by this task library
46
+ def define_tasks
47
+ desc init_task_description
48
+ task init_task_name do
49
+ options = OpenStruct.new
50
+ options.params = [p4_init_dir, '--version', version]
51
+ Commands.init(options)
52
+ end
53
+
54
+ desc kill_task_description
55
+ task kill_task_name do
56
+ options = OpenStruct.new
57
+ options.params = ['--version', version]
58
+ Commands.kill(options)
59
+ end
60
+
61
+ desc reset_task_description
62
+ task reset_task_name => kill_task_name do
63
+ FileUtils.rmtree(Conventions.p4droot_dir)
64
+ end
65
+
66
+ self
67
+ end
68
+
69
+ def init_task_description
70
+ "Initializes a p4d instance, and ensures it's downloaded and running"
71
+ end
72
+
73
+ def init_task_name
74
+ "#{basename}init"
75
+ end
76
+
77
+ def kill_task_description
78
+ 'Halt any locally running p4d instance'
79
+ end
80
+
81
+ def kill_task_name
82
+ "#{basename}kill"
83
+ end
84
+
85
+ def reset_task_description
86
+ 'Cleans out the current p4droot working directory (after killing p4d)'
87
+ end
88
+
89
+ def reset_task_name
90
+ "#{basename}reset"
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,3 @@
1
+ module P4Util
2
+ VERSION = '0.1.0'
3
+ end
@@ -1,4 +1,4 @@
1
- require 'p4_util/version'
1
+ require 'p4util/version'
2
2
  require 'commands'
3
3
  require 'optparse'
4
4
  require 'ostruct'
@@ -0,0 +1,7 @@
1
+
2
+ module RandomUtil
3
+
4
+ def RandomUtil.randstr(len=8)
5
+ (0...len).map { (65 + rand(26)).chr }.join
6
+ end
7
+ end
data/p4init/287.jpg ADDED
Binary file
@@ -0,0 +1,36 @@
1
+
2
+ class Changelist1 < ChangelistModel
3
+ def rank; 1000 end
4
+ @description = 'A couple of new files'
5
+ @adds = [
6
+ FileDefinition.new(:path => 'depot/README.txt',
7
+ :content => <<-END.gsub(/^ {8}/, '')
8
+ This is an example readme.
9
+ END
10
+ ),
11
+ FileDefinition.new(:path => 'depot/dev/memorabilia/kitty.jpg',
12
+ :local_path => 'p4init/287.jpg'
13
+ )
14
+ ]
15
+ end
16
+
17
+ class Changelist2 < ChangelistModel
18
+ def rank; 1001 end
19
+ @description = 'An example add and edit'
20
+ @user = 'jdoe'
21
+ @edits = [
22
+ FileDefinition.new(:path => 'depot/README.txt',
23
+ :content => <<-END.gsub(/^ {8}/, '')
24
+ This is an example readme.
25
+ Added a second line
26
+ END
27
+ )
28
+ ]
29
+ @adds = [
30
+ FileDefinition.new(:path => 'depot/main/project2/example.txt',
31
+ :content => <<-END.gsub(/^ {8}/, '')
32
+ Example text file.
33
+ END
34
+ )
35
+ ]
36
+ end
@@ -0,0 +1,4 @@
1
+
2
+ class TestSystemSettings < SystemSettingsModel
3
+ @unicode = true
4
+ end
@@ -0,0 +1,15 @@
1
+ # User ranks should generally be 10-100, creating them early makes sense.
2
+
3
+ class TestSuperUser < UserModel
4
+ @login = 'p4super'
5
+ @password = 'superuser1A!'
6
+ @full_name = 'Super User'
7
+ @super = true
8
+ end
9
+
10
+ class JohnDoeUser < UserModel
11
+ def rank; 10 end
12
+ @login = 'jdoe'
13
+ @full_name = 'John Doe'
14
+ @password = 'johndoe1A!'
15
+ end
data/p4util.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'p4_util/version'
4
+ require 'p4util/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'p4util'
@@ -19,7 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_development_dependency 'bundler', '~> 1.7'
22
- spec.add_development_dependency 'rake', '~> 10.0'
23
22
 
24
23
  spec.add_runtime_dependency 'sys-proctable', '~> 0.9'
24
+ spec.add_runtime_dependency 'p4ruby', '2014.2.0.pre1'
25
+ spec.add_runtime_dependency 'rake', '~> 10.3'
25
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: p4util
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tristan Juricek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-23 00:00:00.000000000 Z
11
+ date: 2014-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,33 +25,47 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.7'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: sys-proctable
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
33
+ version: '0.9'
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0.9'
41
41
  - !ruby/object:Gem::Dependency
42
- name: sys-proctable
42
+ name: p4ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 2014.2.0.pre1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2014.2.0.pre1
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '0.9'
61
+ version: '10.3'
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '0.9'
68
+ version: '10.3'
55
69
  description: The p4util command itself provides other commands, see 'p4util help'
56
70
  after install. This allows you to things like download a p4d, start it, kill it,
57
71
  etc mostly for quick setup of testing systems.
@@ -70,12 +84,26 @@ files:
70
84
  - "./lib/commands.rb"
71
85
  - "./lib/commands/download.rb"
72
86
  - "./lib/commands/help.rb"
87
+ - "./lib/commands/init.rb"
88
+ - "./lib/commands/init/changelist_model.rb"
89
+ - "./lib/commands/init/file_definition.rb"
90
+ - "./lib/commands/init/init_model.rb"
91
+ - "./lib/commands/init/p4_helpers.rb"
92
+ - "./lib/commands/init/system_settings_model.rb"
93
+ - "./lib/commands/init/user_model.rb"
73
94
  - "./lib/commands/kill.rb"
74
95
  - "./lib/commands/start.rb"
96
+ - "./lib/commands/util.rb"
75
97
  - "./lib/conventions.rb"
76
98
  - "./lib/osutil.rb"
77
- - "./lib/p4_util.rb"
78
- - "./lib/p4_util/version.rb"
99
+ - "./lib/p4util.rb"
100
+ - "./lib/p4util/tasks.rb"
101
+ - "./lib/p4util/version.rb"
102
+ - "./lib/random_util.rb"
103
+ - "./p4init/287.jpg"
104
+ - "./p4init/test_changelists.rb"
105
+ - "./p4init/test_system_settings.rb"
106
+ - "./p4init/test_users.rb"
79
107
  - "./p4util.gemspec"
80
108
  - bin/p4util
81
109
  homepage: http://perforce.com
@@ -1,3 +0,0 @@
1
- module P4Util
2
- VERSION = "0.0.3"
3
- end