kenai_tools 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/kenai_tools.iml +40 -0
- data/.idea/misc.xml +8 -0
- data/.idea/modules.xml +9 -0
- data/.idea/vcs.xml +7 -0
- data/Gemfile +4 -0
- data/README.md +28 -0
- data/Rakefile +2 -0
- data/bin/dlutil +139 -0
- data/kenai_tools.gemspec +43 -0
- data/lib/kenai_tools/downloads_client.rb +241 -0
- data/lib/kenai_tools/kenai_client.rb +168 -0
- data/lib/kenai_tools/version.rb +3 -0
- data/lib/kenai_tools.rb +7 -0
- data/spec/downloads_client_spec.rb +302 -0
- data/spec/fixtures/data/irs_docs/irs-form-1040.pdf +0 -0
- data/spec/fixtures/data/irs_docs/irs-p555.pdf +0 -0
- data/spec/fixtures/data/sax.tgz +0 -0
- data/spec/fixtures/data/sax2/.cvsignore +9 -0
- data/spec/fixtures/data/sax2/CHANGES +245 -0
- data/spec/fixtures/data/sax2/COPYING +12 -0
- data/spec/fixtures/data/sax2/ChangeLog +666 -0
- data/spec/fixtures/data/sax2/Makefile +77 -0
- data/spec/fixtures/data/sax2/README +62 -0
- data/spec/fixtures/data/sax2/build.xml +68 -0
- data/spec/fixtures/data/sax2/src/SAXDump.java +238 -0
- data/spec/fixtures/data/sax2/src/SAXTest.java +351 -0
- data/spec/fixtures/data/sax2/src/org/xml/sax/Attributes.java +257 -0
- data/spec/fixtures/data/sax2/src/org/xml/sax/package.html +297 -0
- data/spec/fixtures/data/sax2r2.jar +0 -0
- data/spec/fixtures/data/text1.txt +4 -0
- data/spec/spec_helper.rb +9 -0
- metadata +222 -0
data/.gitignore
ADDED
data/.idea/.name
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
kenai_tools
|
data/.idea/.rakeTasks
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Settings><!--This file was automatically generated by Ruby plugin.
|
3
|
+
You are allowed to:
|
4
|
+
1. Remove rake task
|
5
|
+
2. Add existing rake tasks
|
6
|
+
To add existing rake tasks automatically delete this file and reload the project.
|
7
|
+
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build kenai_tools-0.0.1.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Build and install kenai_tools-0.0.1.gem into system gems" fullCmd="install" taksId="install" /><RakeTask description="Create tag v0.0.1 and build and push kenai_tools-0.0.1.gem to Rubygems" fullCmd="release" taksId="release" /></RakeGroup></Settings>
|
data/.idea/encodings.xml
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<module type="RUBY_MODULE" version="4">
|
3
|
+
<component name="GemRequirementsHolder" version="3">
|
4
|
+
<requirement>
|
5
|
+
<requirement>
|
6
|
+
<dependency name="highline" version="1.6" bound="LATEST_IN_BRANCH" git="false" path="false" doRequire="true" />
|
7
|
+
</requirement>
|
8
|
+
<source from="Gemfile" />
|
9
|
+
</requirement>
|
10
|
+
<requirement>
|
11
|
+
<requirement>
|
12
|
+
<dependency name="json" version="1.5" bound="LATEST_IN_BRANCH" git="false" path="false" doRequire="true" />
|
13
|
+
</requirement>
|
14
|
+
<source from="Gemfile" />
|
15
|
+
</requirement>
|
16
|
+
<requirement>
|
17
|
+
<requirement>
|
18
|
+
<dependency name="rest-client" version="1.6" bound="LATEST_IN_BRANCH" git="false" path="false" doRequire="true" />
|
19
|
+
</requirement>
|
20
|
+
<source from="Gemfile" />
|
21
|
+
</requirement>
|
22
|
+
</component>
|
23
|
+
<component name="NewModuleRootManager">
|
24
|
+
<content url="file://$MODULE_DIR$" />
|
25
|
+
<orderEntry type="inheritedJdk" />
|
26
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
27
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec (v2.5.0, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
28
|
+
<orderEntry type="library" scope="PROVIDED" name="rest-client (v1.6.3, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
29
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-core (v2.5.2, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
30
|
+
<orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.1.2, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
31
|
+
<orderEntry type="library" scope="PROVIDED" name="highline (v1.6.2, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
32
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v1.0.12, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
33
|
+
<orderEntry type="library" scope="PROVIDED" name="mime-types (v1.16, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
34
|
+
<orderEntry type="library" scope="PROVIDED" name="json (v1.5.3, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
35
|
+
<orderEntry type="library" scope="PROVIDED" name="gemcutter (v0.7.0, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
36
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v2.5.0, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
37
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v2.5.0, RVM: ruby-1.8.7-p302 [kenai_tools]) [gem]" level="application" />
|
38
|
+
</component>
|
39
|
+
</module>
|
40
|
+
|
data/.idea/misc.xml
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="DependencyValidationManager">
|
4
|
+
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
5
|
+
</component>
|
6
|
+
<component name="ProjectRootManager" version="2" project-jdk-name="RVM: ruby-1.8.7-p302 [kenai_tools]" project-jdk-type="RUBY_SDK" />
|
7
|
+
</project>
|
8
|
+
|
data/.idea/modules.xml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="ProjectModuleManager">
|
4
|
+
<modules>
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/kenai_tools.iml" filepath="$PROJECT_DIR$/.idea/kenai_tools.iml" />
|
6
|
+
</modules>
|
7
|
+
</component>
|
8
|
+
</project>
|
9
|
+
|
data/.idea/vcs.xml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Kenai Tools
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
The kenai_tools gem provides command line tools to access web services for
|
6
|
+
web sites that are hosted on the Kenai application platform. Currently,
|
7
|
+
there is a dlutil tool that project admins can use to manage the downloads
|
8
|
+
feature of a project. For example, they can perform bulk uploads and
|
9
|
+
downloads of files to a site hosted on Kenai such as java.net.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
$ gem install kenai_tools
|
14
|
+
|
15
|
+
or
|
16
|
+
|
17
|
+
$ sudo gem install kenai_tools
|
18
|
+
|
19
|
+
## Usage and documentation
|
20
|
+
|
21
|
+
Please see the command usage information.
|
22
|
+
|
23
|
+
$ dlutil --help
|
24
|
+
|
25
|
+
## Problems
|
26
|
+
|
27
|
+
Some dlutil commands do not work on Windows so a unix-based OS is
|
28
|
+
recommended.
|
data/Rakefile
ADDED
data/bin/dlutil
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require "bundler/setup"
|
5
|
+
|
6
|
+
$LOAD_PATH << File.dirname(__FILE__) + '/../lib'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'optparse'
|
9
|
+
require 'highline/import'
|
10
|
+
require 'kenai_tools'
|
11
|
+
|
12
|
+
PROGRAM = File.basename(__FILE__)
|
13
|
+
|
14
|
+
# Array of command info. Keys are
|
15
|
+
# :name = command line name
|
16
|
+
# :call = name of method to call instead of :name, if specified
|
17
|
+
# :result = method produces a result
|
18
|
+
# :login = method requires authentication
|
19
|
+
# :core = core, i.e. main command
|
20
|
+
COMMANDS = [{:name => :ping, :result => true, :core => true},
|
21
|
+
{:name => :login, :call => :ping, :login => true, :result => true, :core => true},
|
22
|
+
{:name => :pull, :core => true},
|
23
|
+
{:name => :push, :login => true, :core => true},
|
24
|
+
{:name => :exist?, :result => true},
|
25
|
+
{:name => :entry_type, :result => true},
|
26
|
+
{:name => :mkdir, :login => true},
|
27
|
+
{:name => :rmdir, :login => true, :result => nil},
|
28
|
+
{:name => :rm, :login => true},
|
29
|
+
{:name => :rm_r, :login => true},
|
30
|
+
{:name => :delete_feature, :login => true},
|
31
|
+
{:name => :get_or_create, :login => true, :result => true},
|
32
|
+
{:name => :downloads_name, :result => true},
|
33
|
+
{:name => :downloads_feature, :result => true},
|
34
|
+
{:name => :ls, :result => true}]
|
35
|
+
|
36
|
+
options = OpenStruct.new
|
37
|
+
@opts = OptionParser.new do |opts|
|
38
|
+
opts.banner = "Usage: #{PROGRAM} [options] COMMAND [args] ..."
|
39
|
+
|
40
|
+
def wrap(s, width = 78)
|
41
|
+
s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
|
42
|
+
end
|
43
|
+
|
44
|
+
str = COMMANDS.select { |info| info[:core] }.map { |info| info[:name] }.join(', ')
|
45
|
+
opts.separator "Main commands: #{wrap(str)}"
|
46
|
+
str = COMMANDS.reject { |info| info[:core] }.map { |info| info[:name] }.join(', ')
|
47
|
+
opts.separator "Other commands: #{wrap(str)}"
|
48
|
+
opts.separator "Note: Unix OS is recommended as some commands fail on Windows"
|
49
|
+
opts.separator "Examples:"
|
50
|
+
opts.separator " #{PROGRAM} -r kenai.com,my-project pull / my-project-downloads"
|
51
|
+
opts.separator " #{PROGRAM} -r java.net,my-project push dist/ /version-3.1"
|
52
|
+
opts.separator " #{PROGRAM} -r java.net,my-project push toolkit-1.2.3.jar /"
|
53
|
+
opts.separator " #{PROGRAM} -r java.net,glassfish login"
|
54
|
+
opts.separator " #{PROGRAM} -r java.net,my-project rm /toolkit-1.2.3.jar"
|
55
|
+
opts.separator " #{PROGRAM} -r java.net,my-project rm_r /version-3.1"
|
56
|
+
opts.separator ""
|
57
|
+
opts.separator "Specific options:"
|
58
|
+
|
59
|
+
def to_url(host_or_url)
|
60
|
+
host_or_url =~ %r{^http(s?)://} ? host_or_url : "https://#{host_or_url}/"
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-r", "--remote ENDPOINT_SPEC", "Remote endpoint SITE,PROJECT,[DOWNLOADS_NAME]",
|
64
|
+
" SITE may be simply HOST or http(s)?://HOST:PORT") do |v|
|
65
|
+
host, project, downloads_name = v.split(',')
|
66
|
+
options.remote_valid = host && project
|
67
|
+
options.host_url = to_url(host)
|
68
|
+
options.project = project
|
69
|
+
options.downloads_name = downloads_name
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on("-p", "--password-file FILE", "Read username/password (nl-separated) from FILE") do |v|
|
73
|
+
options.password_file = v
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
77
|
+
options.verbose = v
|
78
|
+
end
|
79
|
+
|
80
|
+
opts.on("-t", "--timeout SECS", "Timeout in seconds") do |v|
|
81
|
+
options.timeout = v
|
82
|
+
end
|
83
|
+
|
84
|
+
opts.on("--cloak-password PASSWORD", "Cloaking password") do |v|
|
85
|
+
options.cloak_password = v
|
86
|
+
end
|
87
|
+
|
88
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
89
|
+
puts opts
|
90
|
+
exit
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def usage
|
95
|
+
puts @opts
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
|
99
|
+
begin
|
100
|
+
@opts.parse!
|
101
|
+
rescue
|
102
|
+
usage
|
103
|
+
end
|
104
|
+
|
105
|
+
usage unless command = ARGV.shift and
|
106
|
+
cmd_info = COMMANDS.find { |info| info[:name] == command.to_sym } and
|
107
|
+
options.remote_valid
|
108
|
+
|
109
|
+
def get_credentials(options, dlc_opts)
|
110
|
+
user, password = nil
|
111
|
+
if options.password_file
|
112
|
+
File.open(options.password_file) do |f|
|
113
|
+
user, password = f.read.split
|
114
|
+
end
|
115
|
+
else
|
116
|
+
say "Please enter your login credentials for #{options.host_url}"
|
117
|
+
user = ask('Username: ')
|
118
|
+
password = ask('Password: ') { |q| q.echo = '*' }
|
119
|
+
end
|
120
|
+
if user
|
121
|
+
dlc_opts[:user] = user
|
122
|
+
dlc_opts[:password] = password
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
dlc_opts = {:downloads_name => options.downloads_name}
|
127
|
+
if cmd_info[:login]
|
128
|
+
get_credentials(options, dlc_opts)
|
129
|
+
end
|
130
|
+
dlc_opts[:timeout] = options.timeout if options.timeout
|
131
|
+
dlc_opts[:cloak_password] = options.cloak_password if options.cloak_password
|
132
|
+
dlc_opts[:log] = $stderr if options.verbose
|
133
|
+
dlclient = KenaiTools::DownloadsClient.new(options.host_url, options.project, dlc_opts)
|
134
|
+
|
135
|
+
method_name = cmd_info[:call] ? cmd_info[:call] : cmd_info[:name]
|
136
|
+
result = dlclient.send(method_name, *ARGV)
|
137
|
+
if cmd_info[:result]
|
138
|
+
puts String === result ? result : result.inspect
|
139
|
+
end
|
data/kenai_tools.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "kenai_tools/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "kenai_tools"
|
7
|
+
s.version = KenaiTools::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Edwin Goei", "Project Kenai Team"]
|
10
|
+
s.email = ["edwin.goei@oracle.com"]
|
11
|
+
s.homepage = "http://kenai.com/projects/kenaiapis"
|
12
|
+
s.summary = %q{Tools for sites hosted on the Kenai platform. Use dlutil to upload and download files.}
|
13
|
+
s.description = %q{Tools for sites such as java.net that are hosted on the Kenai platform. Use dlutil to upload and download files.}
|
14
|
+
s.post_install_message = %q{
|
15
|
+
==============================================================================
|
16
|
+
|
17
|
+
Thanks for installing kenai_tools. Run the following command for what to do
|
18
|
+
next:
|
19
|
+
|
20
|
+
dlutil --help
|
21
|
+
|
22
|
+
Warning: this tool is not yet supported on Windows. Please use a unix-based
|
23
|
+
OS. For more info, see http://kenai.com/jira/browse/KENAI-2853.
|
24
|
+
|
25
|
+
==============================================================================
|
26
|
+
|
27
|
+
|
28
|
+
}
|
29
|
+
|
30
|
+
s.rubyforge_project = "kenai_tools"
|
31
|
+
|
32
|
+
s.files = `git ls-files`.split("\n")
|
33
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
34
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
|
37
|
+
s.add_development_dependency("rspec", "~> 2.5")
|
38
|
+
s.add_development_dependency("bundler", "~> 1.0")
|
39
|
+
s.add_development_dependency("gemcutter")
|
40
|
+
s.add_dependency("rest-client", "~> 1.6")
|
41
|
+
s.add_dependency("json", "~> 1.5")
|
42
|
+
s.add_dependency("highline", "~> 1.6")
|
43
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'forwardable'
|
5
|
+
require 'rest_client'
|
6
|
+
|
7
|
+
module KenaiTools
|
8
|
+
# Path arguments to public methods of this API work with Pathname objects as well as Strings
|
9
|
+
class DownloadsClient
|
10
|
+
CONTENT_TYPE_KENAI_ENTRIES = "application/vnd.com.kenai.entries+json"
|
11
|
+
|
12
|
+
extend Forwardable
|
13
|
+
def_delegators :@kc, :authenticate, :authenticated?
|
14
|
+
|
15
|
+
attr_accessor :project, :cloak_password
|
16
|
+
|
17
|
+
#
|
18
|
+
# Local options are :downloads_name, :log, :cloak_password
|
19
|
+
# Other options such as :timeout are forwarded
|
20
|
+
# DownloadClient.new("https://kenai.com/", "jruby")
|
21
|
+
# DownloadClient.new("https://testkenai.com/", "my-project", :downloads_name => 'downloads2', :log => $stderr
|
22
|
+
# :timeout => 36000, :cloak_password => 'a_secret')
|
23
|
+
#
|
24
|
+
def initialize(site, project, opts = {})
|
25
|
+
@site = site
|
26
|
+
@project = project
|
27
|
+
@specified_downloads_name = opts.delete(:downloads_name)
|
28
|
+
@cloak_password = opts.delete(:cloak_password)
|
29
|
+
RestClient.log = opts.delete(:log)
|
30
|
+
@kc = KenaiClient.new(site, opts)
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_or_create
|
34
|
+
unless ping
|
35
|
+
@specified_downloads_name = "downloads" unless @specified_downloads_name
|
36
|
+
params = {:feature => {:name => @specified_downloads_name, :service => "downloads",
|
37
|
+
:display_name => @specified_downloads_name.capitalize}}
|
38
|
+
@kc["projects/#{project}/features"].post(params, :content_type => 'application/json')
|
39
|
+
end
|
40
|
+
downloads_name
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete_feature(confirm = nil)
|
44
|
+
unless confirm == 'yes'
|
45
|
+
fail "Confirm delete project downloads feature with an argument of 'yes'"
|
46
|
+
else
|
47
|
+
# Flush cache
|
48
|
+
orig_downloads_name = downloads_name
|
49
|
+
@downloads_feature = @downloads_name = nil
|
50
|
+
@kc["projects/#{project}/features/#{orig_downloads_name}"].delete
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Returns the specified downloads feature if found, or a discovered one
|
56
|
+
# if the project only has one
|
57
|
+
#
|
58
|
+
def downloads_feature
|
59
|
+
@downloads_feature ||= begin
|
60
|
+
project = @kc.project(@project)
|
61
|
+
features = project && project['features']
|
62
|
+
if downloads_features = features && features.select { |f| f['type'] == 'downloads' }
|
63
|
+
if @specified_downloads_name
|
64
|
+
downloads_features.detect { |f| f['name'] == @specified_downloads_name }
|
65
|
+
elsif downloads_features.size == 1
|
66
|
+
downloads_features.first
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
else
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def downloads_name
|
77
|
+
@downloads_name ||= downloads_feature && downloads_feature['name']
|
78
|
+
end
|
79
|
+
|
80
|
+
alias_method :ping, :downloads_name
|
81
|
+
|
82
|
+
def ls(path = '/')
|
83
|
+
entry(path)
|
84
|
+
end
|
85
|
+
|
86
|
+
def exist?(path = '/')
|
87
|
+
!!entry(path)
|
88
|
+
end
|
89
|
+
|
90
|
+
def entry_type(path)
|
91
|
+
if h = entry(path)
|
92
|
+
h['entry_type']
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Pull a remote file or directory hierarchy to the local host. Use
|
98
|
+
# +remote_path+ to specify the remote file or directory hierarchy to
|
99
|
+
# download. If +remote_path+ is '/', download all content. Use
|
100
|
+
# +local_dest_dir+ to specify the target location for the content which
|
101
|
+
# defaults to the current directory.
|
102
|
+
#
|
103
|
+
# For example:
|
104
|
+
# dlclient.pull('version-1.9')
|
105
|
+
# dlclient.pull('version-1.9', '/tmp/project_downloads')
|
106
|
+
#
|
107
|
+
def pull(remote_path, local_dest_dir = '.')
|
108
|
+
dest = Pathname(local_dest_dir)
|
109
|
+
fail "Destination must be a directory" unless dest.directory?
|
110
|
+
remote_pn = clean_id_pn(remote_path)
|
111
|
+
if ent = entry(remote_pn)
|
112
|
+
display_name = ent['display_name']
|
113
|
+
basename = display_name == '/' ? '.' : display_name
|
114
|
+
local_path = dest + basename
|
115
|
+
case ent['entry_type']
|
116
|
+
when 'directory'
|
117
|
+
local_path.mkdir unless local_path.exist?
|
118
|
+
ent['children'].each do |ch|
|
119
|
+
remote_child = remote_pn + ch['display_name']
|
120
|
+
pull(remote_child, local_path)
|
121
|
+
end
|
122
|
+
when 'file'
|
123
|
+
content = get_cloaked_url(ent['content_url'])
|
124
|
+
local_path.open("w") { |f| f.write(content) }
|
125
|
+
else
|
126
|
+
puts "Warning: skipping unsupported entry type"
|
127
|
+
end
|
128
|
+
else
|
129
|
+
puts "Unknown downloads entry: #{remote_pn}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Push a local file or directory hierarchy to the server. Use
|
135
|
+
# +local_path+ path to specify the local file or directory to upload. If
|
136
|
+
# +local_path+ is a directory that ends in '/', upload the contents of
|
137
|
+
# that directory instead of the directory and its contents. Use
|
138
|
+
# +remote_dir+ to specify the remote directory to upload to.
|
139
|
+
#
|
140
|
+
# For example:
|
141
|
+
# dlclient.push('version-1.9')
|
142
|
+
# dlclient.push('dist', '/version-1.9')
|
143
|
+
#
|
144
|
+
def push(local_path, remote_dir = '/', opts = {})
|
145
|
+
src = Pathname(local_path)
|
146
|
+
if src.directory?
|
147
|
+
if src.to_s.end_with?('/')
|
148
|
+
target_dir = remote_dir
|
149
|
+
else
|
150
|
+
target_dir = Pathname(remote_dir) + src.basename
|
151
|
+
mkdir(target_dir)
|
152
|
+
end
|
153
|
+
src.children.each do |ch|
|
154
|
+
push(ch, target_dir)
|
155
|
+
end
|
156
|
+
else
|
157
|
+
remote_id = Pathname(remote_dir) + src.basename
|
158
|
+
entry = {:content_data => File.new(src)}.merge(opts)
|
159
|
+
begin
|
160
|
+
@kc[entry_api_path(remote_id)].put(:entry => entry)
|
161
|
+
rescue => ex
|
162
|
+
err_msg = "Error: unable to upload to target '#{remote_id}'"
|
163
|
+
if server_msg = extract_error_message(ex)
|
164
|
+
err_msg += ": #{server_msg}"
|
165
|
+
end
|
166
|
+
$stderr.puts err_msg
|
167
|
+
raise ex
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def mkdir(dir, opts = {})
|
173
|
+
path = Pathname(dir)
|
174
|
+
entry = {:display_name => path.basename}
|
175
|
+
entry.merge(opts)
|
176
|
+
@kc[entry_api_path(path)].put(:entry => entry)
|
177
|
+
end
|
178
|
+
|
179
|
+
def rm_r(path)
|
180
|
+
@kc[entry_api_path(path)].delete
|
181
|
+
end
|
182
|
+
|
183
|
+
def rm(path)
|
184
|
+
if entry_type(path) == 'directory'
|
185
|
+
fail "Entry is a directory: #{path}"
|
186
|
+
else
|
187
|
+
@kc[entry_api_path(path)].delete
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def rmdir(path)
|
192
|
+
entry = entry(path)
|
193
|
+
if entry['entry_type'] == 'directory'
|
194
|
+
if entry['children'].size == 0
|
195
|
+
@kc[entry_api_path(path)].delete
|
196
|
+
else
|
197
|
+
fail "Directory not empty: #{path}"
|
198
|
+
end
|
199
|
+
else
|
200
|
+
fail "Not a directory: #{path}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
private
|
205
|
+
|
206
|
+
# Canonicalize an entry id and return a relative Pathname or root Pathname
|
207
|
+
def clean_id_pn(remote_path)
|
208
|
+
remote_pn = Pathname(remote_path)
|
209
|
+
root = Pathname('/')
|
210
|
+
if remote_pn.absolute? && remote_pn != root
|
211
|
+
remote_pn.relative_path_from(root)
|
212
|
+
else
|
213
|
+
remote_pn
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def entry_api_path(id)
|
218
|
+
fail "Downloads feature not found" unless downloads_name
|
219
|
+
escaped_id = URI.escape(clean_id_pn(id).to_s)
|
220
|
+
"projects/#{@project}/features/#{downloads_name}/entries/#{escaped_id}"
|
221
|
+
end
|
222
|
+
|
223
|
+
def entry(path)
|
224
|
+
begin
|
225
|
+
resource = @kc[entry_api_path(path)].get
|
226
|
+
rescue RestClient::ResourceNotFound => err
|
227
|
+
return nil
|
228
|
+
end
|
229
|
+
JSON.parse(resource)
|
230
|
+
end
|
231
|
+
|
232
|
+
def get_cloaked_url(url)
|
233
|
+
opts = @cloak_password ? {:user => "dont_care", :password => @cloak_password} : {}
|
234
|
+
RestClient::Resource.new(url, opts).get
|
235
|
+
end
|
236
|
+
|
237
|
+
def extract_error_message(ex)
|
238
|
+
ex.response if ex.respond_to?(:response)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|