What is it?
--------
-It aims to be a set of task to help PostgreSQL extension's developers to focus more on the problem that they wants to solve than in the all structure and files and control files need to PGXS to build the extension.
+It aims to be a set of task to help PostgreSQL extension's developers to focus more on the problem that they wants to solve than in all structure and files and control files need to PGXS to build the extension.
How to install it?
------------------
+If you have pgxn client installed you can do:
+
+ pgxn install pgxn_utils
+
+Or you can install it by rubygems:
+
gem install pgxn_utils
How it works?
autoload :CLI, 'pgxn_utils/cli'
autoload :VERSION, 'pgxn_utils/version'
autoload :Constants, 'pgxn_utils/constants'
+ autoload :NoTasks, 'pgxn_utils/no_tasks'
end
attr_accessor :pgxn_username, :pgxn_password
include Thor::Actions
- include PgxnUtils::Constants
+ include PgxnUtils::NoTasks
- desc "skeleton extension_name", "Creates an extension skeleton in current directory."
+ desc "skeleton extension_name", "Creates an extension skeleton in current directory"
method_option :target, :aliases => "-p", :default => ".", :desc => "Define the target directory"
# META required fields
method_option :maintainer, :aliases => "-m", :type => :string, :desc => "Maintainer's name <maintainer@email>"
method_option :abstract, :aliases => "-a", :type => :string, :desc => "Defines a short description to abstract"
- method_option :license, :aliases => "-l", :type => :string, :desc => "The extension license."
+ method_option :license, :aliases => "-l", :type => :string, :desc => "The extension license"
method_option :version, :aliases => "-v", :type => :string, :desc => "Initial version"
# META optional fields
end
end
- desc "change [extension_name]", "Change META's attributes in current extension."
+ desc "change [extension_name]", "Changes META's attributes in current extension"
method_option :target, :aliases => "-p", :type => :string, :default => ".", :desc => "Define the target directory"
end
end
- desc "bundle [extension_name]", "Bundles an extension."
+ desc "bundle [extension_name]", "Bundles the extension in a zip file"
def bundle(extension_name=".")
unless is_extension?(extension_name)
end
end
- desc "release filename", "Release a extension"
+ desc "release filename", "Release an extension to PGXN"
def release(filename)
send_file_to_pgxn(filename)
end
- no_tasks do
- def make_dist_clean(path)
- inside path do
- run 'make distclean', :capture => true
- end
- end
-
- def ask_for_pgxn_credential
- self.pgxn_username = ENV["PGXN_USER"] || HighLine.ask("Enter your PGXN username: ") { |q| q.validate = /^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$/ }
- self.pgxn_password = ENV["PGXN_PASS"] || HighLine.ask("Enter your PGXN password: ") { |q| q.echo = '*' }
- end
-
- def check_response(response)
- case response
- when Net::HTTPUnauthorized then
- say "oops!", :red
- say "It seems that you entered a wrong username or password.", :red
- when Net::HTTPConflict then
- say "conflict!", :yellow
- say "Distribution already exists! Please, check your META.json.", :yellow
- when Net::HTTPSeeOther then
- say "released successfully!", :green
- say "Visit: #{URI.parse(response['Location'])}", :green
- else
- say "Unknown error. (#{response})"
- end
- end
-
- def prepare_multipart_post_for(filename)
- file_basename = File.basename(filename)
- zip_file = File.open(filename)
- Net::HTTP::Post::Multipart.new(
- UPLOAD_URL.path,
- "archive" => UploadIO.new(zip_file, "application/zip", file_basename),
- "Expect" => ""
- )
- end
-
- def try_send_file(request, filename)
- begin
- http = Net::HTTP.new(UPLOAD_URL.host, UPLOAD_URL.port)
- http.use_ssl = true
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
- say "Trying to release #{File.basename(filename)} ... "
- http.request(request)
- rescue SocketError
- say "Please, check your connection.", :red
- exit(1)
- end
- end
-
- def send_file_to_pgxn(filename)
- request = prepare_multipart_post_for(filename)
- ask_for_pgxn_credential
-
- request.basic_auth pgxn_username, pgxn_password
- response = try_send_file(request, filename)
- check_response(response)
- end
-
- def resolve_extension_path_and_name(extension_name)
- target = options[:target]
- extension_path = "."
-
- if target != "." && extension_name == "."
- raise ArgumentError, "Please, supply a extension name"
- elsif target == "."
- extension_path = File.expand_path(extension_name)
- extension_name = File.basename(extension_path)
- else
- extension_path = "#{target}/#{extension_name}"
- end
- [ extension_path, extension_name ]
- end
-
- def can_zip?(archive)
- can_zip = false
-
- if File.exists?(archive)
- say_status :conflict, archive, :red
- if yes? "Overwrite #{archive}? [yN]"
- can_zip = true
- else
- can_zip = false
- end
- else
- can_zip = true
- end
- end
-
- def is_extension?(dir=".")
- File.directory?(dir) && File.exists?("#{dir}/META.json")
- end
-
- def is_dir?(dir)
- File.directory?(dir)
- end
-
- def config_options
- file = File.join(target, "META.json")
-
- if File.exist?(file)
- @@config_options ||= JSON.load(File.read(file))
- else
- {}
- end
- end
-
- def set_accessors(extension_name="your_extension_name")
- self.extension_name = extension_name
-
- self.maintainer = options[:maintainer] || config_options["maintainer"] || "The maintainer's name"
- self.abstract = options[:abstract] || config_options["abstract"] || "A short description"
- self.license = options[:license] || config_options["license"] || "postgresql"
- self.version = options[:version] || config_options["version"] || "0.0.1"
-
- self.description = options[:description] || config_options["description"] || "A long description"
- self.generated_by = options[:generated_by] || config_options["generated_by"] || maintainer
- self.tags = options[:tags] || config_options["tags"]
- self.release_status = options[:release_status] || config_options["release_status"] || "unstable"
-
- self.destination_root = target
- end
- end
-
def self.source_root
@_source_root ||= File.expand_path('../templates', __FILE__)
end
--- /dev/null
+module PgxnUtils
+ module NoTasks
+
+ include PgxnUtils::Constants
+
+ def make_dist_clean(path)
+ inside path do
+ run 'make distclean', :capture => true
+ end
+ end
+
+ def ask_for_pgxn_credential
+ self.pgxn_username = ENV["PGXN_USER"] || HighLine.ask("Enter your PGXN username: ") { |q| q.validate = /^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$/ }
+ self.pgxn_password = ENV["PGXN_PASS"] || HighLine.ask("Enter your PGXN password: ") { |q| q.echo = '*' }
+ end
+
+ def check_response(response)
+ case response
+ when Net::HTTPUnauthorized then
+ say "oops!", :red
+ say "It seems that you entered a wrong username or password.", :red
+ when Net::HTTPConflict then
+ say "conflict!", :yellow
+ say "Distribution already exists! Please, check your META.json.", :yellow
+ when Net::HTTPSeeOther then
+ say "released successfully!", :green
+ say "Visit: #{URI.parse(response['Location'])}", :green
+ else
+ say "Unknown error. (#{response})"
+ end
+ end
+
+ def prepare_multipart_post_for(filename)
+ file_basename = File.basename(filename)
+ zip_file = File.open(filename)
+ Net::HTTP::Post::Multipart.new(
+ UPLOAD_URL.path,
+ "archive" => UploadIO.new(zip_file, "application/zip", file_basename),
+ "Expect" => ""
+ )
+ end
+
+ def try_send_file(request, filename)
+ begin
+ http = Net::HTTP.new(UPLOAD_URL.host, UPLOAD_URL.port)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ say "Trying to release #{File.basename(filename)} ... "
+ http.request(request)
+ rescue SocketError
+ say "Please, check your connection.", :red
+ exit(1)
+ end
+ end
+
+ def send_file_to_pgxn(filename)
+ request = prepare_multipart_post_for(filename)
+ ask_for_pgxn_credential
+
+ request.basic_auth pgxn_username, pgxn_password
+ response = try_send_file(request, filename)
+ check_response(response)
+ end
+
+ def resolve_extension_path_and_name(extension_name)
+ target = options[:target]
+ extension_path = "."
+
+ if target != "." && extension_name == "."
+ raise ArgumentError, "Please, supply a extension name"
+ elsif target == "."
+ extension_path = File.expand_path(extension_name)
+ extension_name = File.basename(extension_path)
+ else
+ extension_path = "#{target}/#{extension_name}"
+ end
+ [ extension_path, extension_name ]
+ end
+
+ def can_zip?(archive)
+ can_zip = false
+
+ if File.exists?(archive)
+ say_status :conflict, archive, :red
+ if yes? "Overwrite #{archive}? [yN]"
+ can_zip = true
+ else
+ can_zip = false
+ end
+ else
+ can_zip = true
+ end
+ end
+
+ def is_extension?(dir=".")
+ is_dir?(dir) && File.exists?("#{dir}/META.json")
+ end
+
+ def is_dir?(dir)
+ File.directory?(dir)
+ end
+
+ def config_options
+ file = File.join(target, "META.json")
+
+ if File.exist?(file)
+ @@config_options ||= JSON.load(File.read(file))
+ else
+ {}
+ end
+ end
+
+ def set_accessors(extension_name="your_extension_name")
+ self.extension_name = extension_name
+
+ self.maintainer = options[:maintainer] || config_options["maintainer"] || "The maintainer's name"
+ self.abstract = options[:abstract] || config_options["abstract"] || "A short description"
+ self.license = options[:license] || config_options["license"] || "postgresql"
+ self.version = options[:version] || config_options["version"] || "0.0.1"
+
+ self.description = options[:description] || config_options["description"] || "A long description"
+ self.generated_by = options[:generated_by] || config_options["generated_by"] || maintainer
+ self.tags = options[:tags] || config_options["tags"]
+ self.release_status = options[:release_status] || config_options["release_status"] || "unstable"
+
+ self.destination_root = target
+ end
+ end
+end
--- /dev/null
+require File.expand_path('spec/spec_helper')
+
+describe PgxnUtils::NoTasks do
+ include PgxnUtils::NoTasks
+ include FileUtils
+
+ after(:all) do
+ rm_r("/tmp/teste")
+ rm_r("/tmp/teste2")
+ end
+
+ context "#resolve_extension_path_and_name" do
+ it "should raise error when no extension name was supplied" do
+ PgxnUtils::NoTasks.send(:define_method, :options) do
+ { :target => "/something" }
+ end
+ extension_name = "."
+ lambda {resolve_extension_path_and_name(extension_name)}.should raise_error(ArgumentError)
+ end
+
+ it "should return correctly if target is '.'" do
+ PgxnUtils::NoTasks.send(:define_method, :options) do
+ { :target => "." }
+ end
+
+ original_dir = File.expand_path(".")
+ destination_dir = "/tmp/teste"
+ mkdir destination_dir
+ cd destination_dir
+
+ extension_name = "teste"
+ resolved_path, resolved_name = resolve_extension_path_and_name(extension_name)
+
+ cd original_dir
+
+ resolved_path.should == "#{destination_dir}/#{extension_name}"
+ resolved_name.should == extension_name
+ end
+
+ it "should return correctly when target are not '.' and a extension name was specified" do
+ PgxnUtils::NoTasks.send(:define_method, :options) do
+ { :target => "/tmp" }
+ end
+
+ original_dir = File.expand_path(".")
+ destination_dir = "/tmp/teste2"
+ mkdir destination_dir
+ cd destination_dir
+
+ extension_name = "teste2"
+ resolved_path, resolved_name = resolve_extension_path_and_name(extension_name)
+
+ cd original_dir
+
+ resolved_path.should == destination_dir
+ resolved_name.should == extension_name
+ end
+ end
+end
$counter = 0
LIB_PATH = File.expand_path('../../lib', __FILE__)
-BIN_PATH = File.expand_path('../../bin/pgxn_utils', __FILE__)
+BIN_PATH = File.expand_path('../../bin/pgxn-utils', __FILE__)
DESTINATION_ROOT = File.expand_path('../pgxn_utils', __FILE__)
FileUtils.rm_rf(DESTINATION_ROOT)