p4_web_api 2014.2.0.pre1 → 2014.2.0.pre2

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: 3a33dc12a8f5e6304cf6408d9aa711b206173a00
4
- data.tar.gz: e9a9c2af51c18f19a22f8267cdade878f69b40e8
3
+ metadata.gz: 069a887b3fabfbb41e4014f0351e9ad79e699ee9
4
+ data.tar.gz: 6fc582c57a30740878523f1265eade7bd6d24749
5
5
  SHA512:
6
- metadata.gz: 2864edc78108d670eaabd5e4b0e868a46950c3b2cffcb62c9920b0e09ba8c4827036359869b70ddddb4fbf1b2f4e4cc8cc7f4fa4627c6d7026897378488564f4
7
- data.tar.gz: a1dc0543c17c29071686891eec720d25d0987aa4e5a4e9750b698cd57b8c06c474368720b94e30201de7773449a6fb5898bffb5d0b876ebe3ec18a583b88b4cc
6
+ metadata.gz: a055d9ca2f41db3f61c9f8d3969d8b5ef506759671437d157eec182af6eb8ff18ff0567704203b4c4755b2deff87806cc2867ac98e0f161de93c52245f3c24e2
7
+ data.tar.gz: fa442bde271cf8387ac423ae2ba3fc9b8a88d38bd396478998990a8c1c74fb14f37065700acdf0e2276a89562143a25705038a8a85ba95bae5813de9382595da
@@ -2,5 +2,5 @@
2
2
  # format, with a RubyGems-style suffix for 'prereleases'. Please use your branch
3
3
  # as the prerelease label.
4
4
  module P4WebAPI
5
- VERSION = '2014.2.0.pre1'
5
+ VERSION = '2014.2.0.pre2'
6
6
  end
data/lib/p4_web_api.rb CHANGED
@@ -54,6 +54,7 @@ module P4WebAPI
54
54
  configure do
55
55
  set(:p4, 'host' => 'localhost', 'port' => '1666')
56
56
  set(:token_path, '/tmp/p4_web_api/tokens')
57
+ set(:workspace_folder, '/tmp/p4_web_api/workspaces')
57
58
 
58
59
  set(:run_get_blacklist, %w(add change changelist clean copy cstat
59
60
  delete diff edit flush have integ integrate
@@ -111,6 +112,65 @@ module P4WebAPI
111
112
  P4Util.open(options, &block)
112
113
  end
113
114
 
115
+ # Block helper to open a p4 handle with a temporary client workspace.
116
+ # The client workspace will map the series of depot path expressions
117
+ # directly into the client workspace.
118
+ #
119
+ # The depot_paths are generally expected to be complete file path
120
+ # expressions, e.g., '//depot/dir1/dir2/file'. They'll be mapped directly
121
+ # to the temporary working area: '//client/depot/dir/1/dir2/file'
122
+ #
123
+ # The block handler here will be called with the arguments (p4, root),
124
+ # where root is the temporary client's root directory.
125
+ def open_p4_temp_client(depot_paths, &block)
126
+ open_p4 do |p4|
127
+ name = (0...8).map { (65 + rand(26)).chr }.join
128
+ dir = init_temp_workspace_dir(name)
129
+ init_temp_client(p4, name, dir, depot_paths)
130
+
131
+ ex = nil
132
+ begin
133
+ block.call(p4, dir)
134
+ rescue StandardError => e
135
+ ex = e
136
+ end
137
+
138
+ delete_temp_client(p4, name, dir)
139
+
140
+ fail ex unless ex.nil?
141
+ end
142
+ end
143
+ end
144
+
145
+ def init_temp_workspace_dir(name)
146
+ dir = File.join(settings.workspace_folder, name)
147
+ unless Dir.exist?(dir)
148
+ FileUtils.mkpath(dir)
149
+ FileUtils.chmod(0700, dir)
150
+ end
151
+ dir
152
+ end
153
+
154
+ def init_temp_client(p4, name, dir, depot_paths)
155
+ spec = p4.fetch_client
156
+ spec._root = dir
157
+ spec._client = name
158
+ spec._description = 'p4_web_api temp client'
159
+
160
+ spec._view = depot_paths.map do |path|
161
+ stripped = path.gsub(/^[\/]*/, '')
162
+ "\"//#{stripped}\" \"//#{name}/#{stripped}\""
163
+ end
164
+
165
+ p4.save_client(spec)
166
+ p4.client = name
167
+
168
+ p4.run_sync('//...')
169
+ end
170
+
171
+ def delete_temp_client(p4, name, dir)
172
+ p4.run_client('-d', '-f', name)
173
+ FileUtils.rmtree(dir)
114
174
  end
115
175
 
116
176
  error do
@@ -686,6 +746,100 @@ module P4WebAPI
686
746
  ''
687
747
  end
688
748
 
749
+ # The print method uses the print command underneath to output file content.
750
+ #
751
+ # Unlike most of the other methods, this does not output application/json.
752
+ # If the type contains 'text' we set the Content-Type to 'text/plain',
753
+ # otherwise it's 'application/octet-stream'.
754
+ get '/v1/print/*' do
755
+ path = params[:splat].join('')
756
+ path = "//#{path}"
757
+
758
+ results = nil
759
+ open_p4 do |p4|
760
+ results = p4.run_print(path)
761
+ end
762
+
763
+ file_type = results[0]
764
+ content = results[1]
765
+
766
+ if file_type['type'] =~ /text/
767
+ content_type 'text/plain'
768
+ else
769
+ content_type 'application/octet-stream'
770
+ end
771
+
772
+ content
773
+ end
774
+
775
+ # The upload method adds new file revisions.
776
+ #
777
+ # This is a multipart method that accepts and array of files, plus,
778
+ # a 'mappings' array to indicate the target depot path for each file.
779
+ # This should be a JSON encoded array of strings.
780
+ #
781
+ # An optional 'description' attribute can describe the changes to be made.
782
+ post '/v1/upload' do
783
+ # if mappings[] and files[] do not have equivalent lengths, the error
784
+ # might be kind of lame.
785
+ mappings = params[:mappings]
786
+ files = []
787
+ mappings.each_index { |idx| files << params["file_#{idx}".to_sym] }
788
+
789
+ open_p4_temp_client(mappings) do |p4, root|
790
+ message = params[:description] || 'Uploaded files'
791
+ change_id = init_changelist(p4, message)
792
+
793
+ # Information used to determine if the new rev should be an add or edit
794
+ files_results = p4.run_files(mappings)
795
+
796
+ (0...mappings.length).each do |idx|
797
+ type = existing_path?(files_results, mappings[idx]) ? 'edit' : 'add'
798
+
799
+ if type == 'edit'
800
+ mark_change('edit', p4, change_id, root, mappings[idx])
801
+ save_content(root, mappings[idx], files[idx])
802
+ else
803
+ save_content(root, mappings[idx], files[idx])
804
+ mark_change('add', p4, change_id, root, mappings[idx])
805
+ end
806
+ end
807
+
808
+ p4.run_submit('-c', change_id)
809
+ end
810
+ end
811
+
812
+ def init_changelist(p4, description)
813
+ change_spec = p4.fetch_change
814
+ change_spec._description = description
815
+ results = p4.save_change(change_spec)
816
+ results[0].gsub(/^Change (\d+) created./, '\1')
817
+ end
818
+
819
+ def save_content(root, depot_path, file)
820
+ local_file = local_path(depot_path, root)
821
+ dir = File.dirname(local_file)
822
+ FileUtils.mkpath(dir) unless Dir.exist?(dir)
823
+
824
+ IO.write(local_file, file[:tempfile].read)
825
+ end
826
+
827
+ def existing_path?(existing_results, depot_path)
828
+ existing_results.any? do |result|
829
+ result['depotFile'] == depot_path
830
+ end
831
+ end
832
+
833
+ def mark_change(type, p4, change_id, root, depot_path)
834
+ local_file = local_path(depot_path, root)
835
+ p4.run(type, '-c', change_id, local_file)
836
+ end
837
+
838
+ def local_path(depot_path, root)
839
+ stripped = depot_path.gsub(/^\/+/, '')
840
+ File.join(root, stripped)
841
+ end
842
+
689
843
  # Basically a "blacklist" of things we know the frameworks going to add to
690
844
  # the params array we don't want to pass on to the p4 command sets for spec
691
845
  # input
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: p4_web_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 2014.2.0.pre1
4
+ version: 2014.2.0.pre2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Perforce Software, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-25 00:00:00.000000000 Z
11
+ date: 2014-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler