gjp 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -15,8 +15,8 @@ Easiest install is via RubyGems:
15
15
  ## Usage
16
16
 
17
17
  Currently available tools:
18
- * `gjp get-pom JAR` will attempt to find an jar's pom.xml (either from the package itself or through search.maven.org);
19
- * `gjp get-source-address POM` will attempt to find the SCM Internet address of a pom.xml (from the file itself or through api.github.com);
18
+ * `gjp get-pom NAME` will attempt to find a pom. `NAME` can be a jar file on your disk, a project directory, or simply a `name-version` string. `gjp` will get the pom either from the package itself or through search.maven.org using heuristic searching;
19
+ * `gjp get-source-address POM` will attempt to find the SCM Internet address of a pom.xml at the `POM` filename or URI (from the file itself or through api.github.com);
20
20
  * `gjp get-source POM ADDRESS` downloads the source of a pom.xml's project from its SCM at ADDRESS;
21
21
 
22
22
  ## Source
data/bin/gjp CHANGED
@@ -15,11 +15,15 @@
15
15
  # http://www.gnu.org/licenses/lgpl-2.1.html
16
16
  #
17
17
 
18
+ if File.exist?(File.join(File.dirname(__FILE__), "..", ".git"))
19
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
20
+ end
21
+
18
22
  begin
19
- require 'gjp'
23
+ require "gjp"
20
24
  rescue LoadError
21
- require 'rubygems'
22
- require 'gjp'
25
+ require "rubygems"
26
+ require "gjp"
23
27
  end
24
28
 
25
- MainCommand.run
29
+ Gjp::MainCommand.run
data/lib/gjp.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "gjp/logger"
1
2
  require "gjp/version"
2
3
  require "gjp/logger"
3
4
  require "gjp/cli"
@@ -1,51 +1,68 @@
1
1
  # encoding: UTF-8
2
-
2
+ require "gjp/logger"
3
3
  require "clamp"
4
4
 
5
- class MainCommand < Clamp::Command
6
- subcommand "get-pom", "Retrieves a pom corresponding to a jar" do
7
- parameter "JAR", "jar file path"
8
- option ["-v", "--verbose"], :flag, "verbose output"
9
- option ["--very-verbose"], :flag, "very verbose output"
10
- option ["--very-very-verbose"], :flag, "very very verbose output"
11
-
12
- def execute
13
- begin
14
- init_logger
15
- puts PomGetter.get_pom(jar)
16
- rescue Zip::ZipError
17
- $stderr.puts "#{jar} does not seem to be a valid jar archive, skipping"
18
- rescue TypeError
19
- $stderr.puts "#{jar} seems to be a valid jar archive but is corrupt, skipping"
20
- rescue RestClient::ResourceNotFound
21
- $stderr.puts "Got an error while looking for #{jar} in search.maven.org"
5
+ # Initialize global logger
6
+ Gjp.logger = ::Logger.new(STDERR)
7
+ Gjp.logger.datetime_format = "%Y-%m-%d %H:%M "
8
+ Gjp.logger.level = ::Logger::INFO
9
+ Gjp.logger.formatter = proc do |severity, datetime, progname, msg|
10
+ "#{severity.chars.first}: #{msg}\n"
11
+ end
12
+
13
+ module Gjp
14
+ class MainCommand < Clamp::Command
15
+ subcommand "get-pom", "Retrieves a pom corresponding to a filename" do
16
+ parameter "NAME", "a jar file path, a project directory path or a non-existing filename in the `project-version` form"
17
+ option ["-v", "--verbose"], :flag, "verbose output"
18
+ option ["--very-verbose"], :flag, "very verbose output"
19
+ option ["--very-very-verbose"], :flag, "very very verbose output"
20
+
21
+ def configure_log_level(v, vv, vvv)
22
+ if vvv
23
+ Gjp.logger.level = Logger::DEBUG
24
+ elsif vv
25
+ Gjp.logger.level = Logger::INFO
26
+ elsif v
27
+ Gjp.logger.level = Logger::WARN
28
+ else
29
+ Gjp.logger.level = Logger::ERROR
30
+ end
31
+ end
32
+
33
+ def very_very_verbose=(flag)
34
+ configure_log_level(verbose?, very_verbose?, flag)
35
+ end
36
+
37
+ def very_verbose=(flag)
38
+ configure_log_level(verbose?, flag, very_very_verbose?)
39
+ end
40
+
41
+ def verbose=(flag)
42
+ configure_log_level(flag, very_verbose?, very_very_verbose?)
43
+ end
44
+
45
+ def execute
46
+ puts Gjp::PomGetter.get_pom(name)
22
47
  end
23
48
  end
24
- end
49
+
50
+ subcommand "get-source-address", "Retrieves a project's SCM Internet address" do
51
+ parameter "POM", "project's pom file path"
52
+
53
+ def execute
54
+ puts Gjp::SourceAddressGetter.get_source_address(pom)
55
+ end
56
+ end
25
57
 
26
- subcommand "get-source-address", "Retrieves a project's SCM Internet address" do
27
- parameter "POM", "project's pom file path"
28
- option ["-v", "--verbose"], :flag, "verbose output"
29
- option ["--very-verbose"], :flag, "very verbose output"
30
- option ["--very-very-verbose"], :flag, "very very verbose output"
31
-
32
- def execute
33
- init_logger
34
- puts SourceAddressGetter.get_source_address(pom)
35
- end
36
- end
37
-
38
- subcommand "get-source", "Retrieves a project's source code directory" do
39
- parameter "ADDRESS", "project's SCM Internet address"
40
- parameter "POM", "project's pom file path"
41
- parameter "[DIRECTORY]", "directory in which to save the source code", :default => "."
42
- option ["-v", "--verbose"], :flag, "verbose output"
43
- option ["--very-verbose"], :flag, "very verbose output"
44
- option ["--very-very-verbose"], :flag, "very very verbose output"
45
-
46
- def execute
47
- init_logger
48
- puts SourceGetter.get_source(address, pom, directory)
49
- end
58
+ subcommand "get-source", "Retrieves a project's source code directory" do
59
+ parameter "ADDRESS", "project's SCM Internet address"
60
+ parameter "POM", "project's pom file path"
61
+ parameter "[DIRECTORY]", "directory in which to save the source code", :default => "."
62
+
63
+ def execute
64
+ puts Gjp::SourceGetter.get_source(address, pom, directory)
65
+ end
66
+ end
50
67
  end
51
68
  end
@@ -8,81 +8,100 @@ require "pathname"
8
8
 
9
9
  require "gjp/version_matcher"
10
10
 
11
- # implements the get-pom subcommand
12
- class PomGetter
11
+ module Gjp
12
+ # implements the get-pom subcommand
13
+ class PomGetter
13
14
 
14
- # returns the pom corresponding to a file or directory, if it can be found
15
- def self.get_pom(file)
16
- (get_pom_from_dir(file) or get_pom_from_jar(file) or get_pom_from_sha1(file) or get_pom_from_heuristic(file))
17
- end
15
+ def self.log
16
+ Gjp.logger
17
+ end
18
+
19
+ # returns the pom corresponding to a filename
20
+ def self.get_pom(filename)
21
+ (get_pom_from_dir(filename) or get_pom_from_jar(filename) or get_pom_from_sha1(filename) or get_pom_from_heuristic(filename))
22
+ end
18
23
 
19
- # returns the pom in a project directory
20
- def self.get_pom_from_dir(dir)
21
- if File.directory?(dir)
22
- pom_path = File.join(dir, "pom.xml")
23
- if File.file?(pom_path)
24
- $log.info("pom.xml found in #{dir}/pom.xml")
24
+ # returns the pom in a project directory
25
+ def self.get_pom_from_dir(dir)
26
+ if File.directory?(dir)
27
+ pom_path = File.join(dir, "pom.xml")
28
+ if File.file?(pom_path)
29
+ log.info("pom.xml found in #{dir}/pom.xml")
25
30
  return File.read(pom_path)
31
+ end
26
32
  end
27
33
  end
28
- end
29
-
30
- # returns a pom embedded in a jar file
31
- def self.get_pom_from_jar(file)
32
- Zip::ZipFile.foreach(file) do |entry|
33
- if entry.name =~ /\/pom.xml$/
34
- $log.info("pom.xml found in #{file}##{entry.name}")
35
- return entry.get_input_stream.read
34
+
35
+ # returns a pom embedded in a jar file
36
+ def self.get_pom_from_jar(file)
37
+ begin
38
+ Zip::ZipFile.foreach(file) do |entry|
39
+ if entry.name =~ /\/pom.xml$/
40
+ log.info("pom.xml found in #{file}##{entry.name}")
41
+ return entry.get_input_stream.read
42
+ end
43
+ end
44
+ rescue Zip::ZipError
45
+ log.info "#{file} does not seem to be a valid jar archive, skipping"
46
+ rescue TypeError
47
+ log.info "#{file} seems to be a valid jar archive but is corrupt, skipping"
36
48
  end
49
+ return nil
37
50
  end
38
- return nil
39
- end
40
-
41
- # returns a pom from search.maven.org with a jar sha1 search
42
- def self.get_pom_from_sha1(file)
43
- sha1 = Digest::SHA1.hexdigest File.read(file)
44
- results = repository_search({:q => "1:\"#{sha1}\""}).select {|result| result["ec"].include?(".pom")}
45
- result = results.first
46
- if result != nil
47
- $log.info("pom.xml for #{file} found on search.maven.org for sha1 #{sha1} (#{result["g"]}:#{result["a"]}:#{result["v"]})")
48
- return repository_download(result)
51
+
52
+ # returns a pom from search.maven.org with a jar sha1 search
53
+ def self.get_pom_from_sha1(file)
54
+ begin
55
+ if File.file?(file)
56
+ sha1 = Digest::SHA1.hexdigest File.read(file)
57
+ results = repository_search({:q => "1:\"#{sha1}\""}).select {|result| result["ec"].include?(".pom")}
58
+ result = results.first
59
+ if result != nil
60
+ log.info("pom.xml for #{file} found on search.maven.org for sha1 #{sha1} (#{result["g"]}:#{result["a"]}:#{result["v"]})")
61
+ return repository_download(result)
62
+ end
63
+ end
64
+ return nil
65
+ rescue RestClient::ResourceNotFound
66
+ $stderr.puts "Got an error while looking for #{file}'s SHA1 in search.maven.org"
67
+ end
49
68
  end
50
- end
51
69
 
52
- # returns a pom from search.maven.org with a heuristic name search
53
- def self.get_pom_from_heuristic(file)
54
- filename = Pathname.new(file).basename.to_s
55
- if filename =~ /([^\/]*)\.jar$/
56
- my_artifact_id, my_version = VersionMatcher.split_version($1)
70
+ # returns a pom from search.maven.org with a heuristic name search
71
+ def self.get_pom_from_heuristic(filename)
72
+ begin
73
+ filename = Pathname.new(filename).basename.to_s.sub(/.jar$/, "")
74
+ my_artifact_id, my_version = VersionMatcher.split_version(filename)
57
75
 
58
- result = repository_search({:q => my_artifact_id}).first
59
- if result != nil
76
+ result = repository_search({:q => my_artifact_id}).first
77
+ if result != nil
60
78
  results = repository_search({:q => "g:\"#{result["g"]}\" AND a:\"#{result["a"]}\"", :core => "gav"})
61
79
  their_versions = results.map {|doc| doc["v"]}
62
80
  best_matched_version = if my_version != nil then VersionMatcher.best_match(my_version, their_versions) else their_versions.max end
63
81
  best_matched_result = (results.select{|result| result["v"] == best_matched_version}).first
64
-
65
- $log.warn("pom.xml for #{file} found on search.maven.org with heuristic search (#{best_matched_result["g"]}:#{best_matched_result["a"]}:#{best_matched_result["v"]})")
66
-
82
+
83
+ log.warn("pom.xml for #{filename} found on search.maven.org with heuristic search (#{best_matched_result["g"]}:#{best_matched_result["a"]}:#{best_matched_result["v"]})")
84
+
67
85
  return repository_download(best_matched_result)
86
+ end
87
+ rescue RestClient::ResourceNotFound
88
+ $stderr.puts "Got an error while looking for #{filename} in search.maven.org"
89
+ end
90
+ end
91
+
92
+ # returns a JSON result from search.maven.com
93
+ def self.repository_search(params)
94
+ response = RestClient.get "http://search.maven.org/solrsearch/select", {:params => params.merge({"rows" => "100", "wt" => "json"})}
95
+ json = JSON.parse(response.to_s)
96
+ return json["response"]["docs"]
97
+ end
98
+
99
+ # downloads a POM from a search.maven.com search result
100
+ def self.repository_download(result)
101
+ if result != nil
102
+ path = "#{result["g"].gsub(".", "/")}/#{result["a"]}/#{result["v"]}/#{result["a"]}-#{result["v"]}.pom"
103
+ return (RestClient.get "http://search.maven.org/remotecontent", {:params => {:filepath => path}}).to_s
68
104
  end
69
- end
70
- end
71
-
72
- # returns a JSON result from search.maven.com
73
- def self.repository_search(params)
74
- response = RestClient.get "http://search.maven.org/solrsearch/select", {:params => params.merge({"rows" => "100", "wt" => "json"})}
75
- json = JSON.parse(response.to_s)
76
- return json["response"]["docs"]
77
- end
78
-
79
- # downloads a POM from a search.maven.com search result
80
- def self.repository_download(result)
81
- if result != nil
82
- path = "#{result["g"].gsub(".", "/")}/#{result["a"]}/#{result["v"]}/#{result["a"]}-#{result["v"]}.pom"
83
- return (RestClient.get "http://search.maven.org/remotecontent", {:params => {:filepath => path}}).to_s
84
105
  end
85
106
  end
86
-
87
107
  end
88
-
@@ -2,80 +2,84 @@
2
2
 
3
3
  require "rest_client"
4
4
 
5
- # implements the get-source subcommand
6
- class SourceGetter
5
+ module Gjp
6
+ # implements the get-source subcommand
7
+ class SourceGetter
8
+ def self.log
9
+ Gjp.logger
10
+ end
7
11
 
8
- # downloads a project's source into a specified directory
9
- def self.get_source(address, pomfile, directory)
10
- $log.info("downloading: #{address} in #{directory}, pomfile: #{pomfile}")
11
-
12
- dummy, prefix, scm_address = address.split(/^([^:]+):(.*)$/)
13
- $log.info("prefix: #{prefix}, scm_address: #{scm_address}")
14
-
15
- get_source_from_scm(prefix, scm_address, pomfile, directory)
16
- end
12
+ # downloads a project's source into a specified directory
13
+ def self.get_source(address, pomfile, directory)
14
+ log.info("downloading: #{address} in #{directory}, pomfile: #{pomfile}")
15
+
16
+ dummy, prefix, scm_address = address.split(/^([^:]+):(.*)$/)
17
+ log.info("prefix: #{prefix}, scm_address: #{scm_address}")
18
+
19
+ get_source_from_scm(prefix, scm_address, pomfile, directory)
20
+ end
17
21
 
18
- # checks code out from an scm
19
- def self.get_source_from_scm(prefix, scm_address, pomfile, directory)
20
- pom = Pom.new(pomfile)
21
- dir = File.join(directory, "#{pom.group_id}:#{pom.artifact_id}:#{pom.version}")
22
- begin
23
- Dir::mkdir(dir)
24
- rescue Errno::EEXIST
25
- $log.warn("Source directory exists, leaving...")
26
- end
27
-
28
- if prefix == "git"
29
- get_source_from_git(scm_address, dir, pom.version)
30
- elsif prefix == "svn"
31
- get_source_from_svn(scm_address, dir, pom.version)
32
- end
33
- end
22
+ # checks code out from an scm
23
+ def self.get_source_from_scm(prefix, scm_address, pomfile, directory)
24
+ pom = Pom.new(pomfile)
25
+ dir = File.join(directory, "#{pom.group_id}:#{pom.artifact_id}:#{pom.version}")
26
+ begin
27
+ Dir::mkdir(dir)
28
+ rescue Errno::EEXIST
29
+ log.warn("Source directory exists, leaving...")
30
+ end
31
+
32
+ if prefix == "git"
33
+ get_source_from_git(scm_address, dir, pom.version)
34
+ elsif prefix == "svn"
35
+ get_source_from_svn(scm_address, dir, pom.version)
36
+ end
37
+ end
34
38
 
35
- # checks code out of git
36
- def self.get_source_from_git(scm_address, dir, version)
37
- `git clone #{scm_address} #{dir}`
38
-
39
- Dir.chdir(dir) do
40
- tags = `git tag`.split("\n")
41
-
42
- if tags.any?
43
- best_tag = get_best_tag(tags, version)
44
- $log.info("checking out tag: #{best_tag}")
39
+ # checks code out of git
40
+ def self.get_source_from_git(scm_address, dir, version)
41
+ `git clone #{scm_address} #{dir}`
42
+
43
+ Dir.chdir(dir) do
44
+ tags = `git tag`.split("\n")
45
+
46
+ if tags.any?
47
+ best_tag = get_best_tag(tags, version)
48
+ log.info("checking out tag: #{best_tag}")
45
49
 
46
- `git checkout #{best_tag}`
47
- end
48
- end
49
- end
50
+ `git checkout #{best_tag}`
51
+ end
52
+ end
53
+ end
50
54
 
51
- # checks code out of svn
52
- def self.get_source_from_svn(scm_address, dir, version)
53
- `svn checkout #{scm_address} #{dir}`
54
-
55
- Dir.chdir(dir) do
56
- tags = `svn ls "^/tags"`.split("\n")
57
-
58
- if tags.any?
59
- best_tag = get_best_tag(tags, version)
60
- $log.info("checking out tag: #{best_tag}")
55
+ # checks code out of svn
56
+ def self.get_source_from_svn(scm_address, dir, version)
57
+ `svn checkout #{scm_address} #{dir}`
58
+
59
+ Dir.chdir(dir) do
60
+ tags = `svn ls "^/tags"`.split("\n")
61
+
62
+ if tags.any?
63
+ best_tag = get_best_tag(tags, version)
64
+ log.info("checking out tag: #{best_tag}")
61
65
 
62
- `svn checkout #{scm_address}/tags/#{best_tag}`
63
- end
64
- end
65
- end
66
+ `svn checkout #{scm_address}/tags/#{best_tag}`
67
+ end
68
+ end
69
+ end
66
70
 
67
- # return the (heuristically) most similar tag to the specified version
68
- def self.get_best_tag(tags, version)
69
- versions_to_tags =Hash[
70
- *tags.map do |tag|
71
- [VersionMatcher.split_version(tag)[1], tag]
72
- end.flatten
73
- ]
74
-
75
- $log.info("found the following versions and tags: #{versions_to_tags}")
71
+ # return the (heuristically) most similar tag to the specified version
72
+ def self.get_best_tag(tags, version)
73
+ versions_to_tags =Hash[
74
+ *tags.map do |tag|
75
+ [VersionMatcher.split_version(tag)[1], tag]
76
+ end.flatten
77
+ ]
78
+
79
+ log.info("found the following versions and tags: #{versions_to_tags}")
76
80
 
77
- best_version = VersionMatcher.best_match(version, versions_to_tags.keys)
78
- versions_to_tags[best_version]
79
- end
81
+ best_version = VersionMatcher.best_match(version, versions_to_tags.keys)
82
+ versions_to_tags[best_version]
83
+ end
84
+ end
80
85
  end
81
-
@@ -4,45 +4,50 @@ require "rest_client"
4
4
  require "json"
5
5
  require "open-uri"
6
6
 
7
- # implements the get-source-address subcommand
8
- class SourceAddressGetter
7
+ module Gjp
8
+ # implements the get-source-address subcommand
9
+ class SourceAddressGetter
10
+ def self.log
11
+ Gjp.logger
12
+ end
9
13
 
10
- # returns the pom corresponding to a file or directory, if it can be found
11
- def self.get_source_address(file)
12
- $log.info("looking for source address for: #{file}")
13
- (get_source_address_from_pom(file) or get_source_address_from_github(file))
14
- end
14
+ # returns the pom corresponding to a file or directory, if it can be found
15
+ def self.get_source_address(file)
16
+ log.info("looking for source address for: #{file}")
17
+ (get_source_address_from_pom(file) or get_source_address_from_github(file))
18
+ end
15
19
 
16
- # returns an scm address in a pom file
17
- def self.get_source_address_from_pom(file)
18
- pom = Pom.new(file)
19
- result = pom.connection_address
20
+ # returns an scm address in a pom file
21
+ def self.get_source_address_from_pom(file)
22
+ pom = Pom.new(file)
23
+ result = pom.connection_address
20
24
 
21
- if result != nil
22
- $log.info("address found in pom")
23
- result
25
+ if result != nil
26
+ log.info("address found in pom")
27
+ result
28
+ end
24
29
  end
25
- end
26
-
27
- # returns an scm address looking for it on github
28
- def self.get_source_address_from_github(file)
29
- pom = Pom.new(file)
30
-
31
- result = (github_search(pom.artifact_id) or github_search(pom.artifact_id.split("-").first) or github_search(pom.group_id))
32
30
 
33
- if result != nil
34
- $log.info("address found on Github: #{result}")
35
- result
31
+ # returns an scm address looking for it on github
32
+ def self.get_source_address_from_github(file)
33
+ pom = Pom.new(file)
34
+
35
+ result = (github_search(pom.artifact_id) or github_search(pom.artifact_id.split("-").first) or github_search(pom.group_id))
36
+
37
+ if result != nil
38
+ log.info("address found on Github: #{result}")
39
+ result
40
+ end
36
41
  end
37
- end
38
-
39
- # returns a Giuthub repo address based on the keyword
40
- def self.github_search(keyword)
41
- if keyword != "" and keyword != nil
42
- response = RestClient.get "https://api.github.com/legacy/repos/search/" + CGI::escape(keyword), :user_agent => "gjp/" + Gjp::VERSION, :language => "java", :sort => "forks"
43
- json = JSON.parse(response.to_s)
44
42
 
45
- (json["repositories"].map {|repository| "git:" + repository["url"]}).first
43
+ # returns a Giuthub repo address based on the keyword
44
+ def self.github_search(keyword)
45
+ if keyword != "" and keyword != nil
46
+ response = RestClient.get "https://api.github.com/legacy/repos/search/" + CGI::escape(keyword), :user_agent => "gjp/" + Gjp::VERSION, :language => "java", :sort => "forks"
47
+ json = JSON.parse(response.to_s)
48
+
49
+ (json["repositories"].map {|repository| "git:" + repository["url"]}).first
50
+ end
46
51
  end
47
52
  end
48
53
  end
@@ -2,23 +2,16 @@
2
2
 
3
3
  require "logger"
4
4
 
5
- def init_logger(level = nil)
6
- $log = Logger.new(STDERR)
7
- $log.level = if level == nil
8
- if very_very_verbose?
9
- Logger::DEBUG
10
- elsif very_verbose?
11
- Logger::INFO
12
- elsif verbose?
13
- Logger::WARN
14
- else
15
- Logger::ERROR
16
- end
17
- else
18
- level
5
+ module Gjp
6
+ def self.logger=(logger)
7
+ @logger = logger
19
8
  end
20
-
21
- $log.formatter = proc do |severity, datetime, progname, msg|
22
- "#{severity.chars.first}: #{msg}\n"
9
+
10
+ def self.logger
11
+ @logger ||= Logger.new('/dev/null')
12
+ end
13
+
14
+ def logger
15
+ Gjp.logger
23
16
  end
24
17
  end
@@ -1,30 +1,34 @@
1
- # encoding: UTF-8
1
+ # encoding: UTF-8
2
2
 
3
3
  require "nokogiri"
4
+ require "open-uri"
4
5
 
5
- # encapsulates a pom.xml file
6
- class Pom
7
- def initialize(filename)
8
- @doc = Nokogiri::XML(File.read(filename))
9
- @doc.remove_namespaces!
10
- end
11
-
12
- def connection_address
13
- connection_nodes = @doc.xpath("//scm/connection/text()")
14
- if connection_nodes.any?
15
- connection_nodes.first.to_s.sub(/^scm:/, "")
6
+ module Gjp
7
+ # encapsulates a pom.xml file
8
+ class Pom
9
+ def initialize(filename)
10
+ @doc = Nokogiri::XML(open(filename).read)
11
+ @doc.remove_namespaces!
12
+ end
13
+
14
+ def connection_address
15
+ connection_nodes = @doc.xpath("//scm/connection/text()")
16
+ if connection_nodes.any?
17
+ connection_nodes.first.to_s.sub(/^scm:/, "")
18
+ end
19
+ end
20
+
21
+ def group_id
22
+ @doc.xpath("project/groupId/text()").to_s
23
+ end
24
+
25
+ def artifact_id
26
+ @doc.xpath("project/artifactId/text()").to_s
27
+ end
28
+
29
+ def version
30
+ @doc.xpath("project/version/text()").to_s
16
31
  end
17
- end
18
-
19
- def group_id
20
- @doc.xpath("project/groupId/text()").to_s
21
- end
22
-
23
- def artifact_id
24
- @doc.xpath("project/artifactId/text()").to_s
25
- end
26
-
27
- def version
28
- @doc.xpath("project/version/text()").to_s
29
32
  end
30
33
  end
34
+
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module Gjp
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -2,93 +2,92 @@
2
2
 
3
3
  require "text"
4
4
 
5
- # heuristically matches version strings
6
- class VersionMatcher
7
-
8
- # heuristically extracts a version number from a full name
9
- # assumes that all leading non-numeric chars are not related the version
10
- # returns a version string
11
- def self.extract_version(full_name)
12
- full_name.sub /^[^0-9]+/, ""
13
- end
5
+ module Gjp
6
+ # heuristically matches version strings
7
+ class VersionMatcher
8
+ def self.log
9
+ Gjp.logger
10
+ end
14
11
 
15
- # heuristically splits a full name into an artifact name and version string
16
- # assumes that version strings begin with a numeric character and are separated
17
- # by a ., -, _, ~ or space
18
- # returns a [name, version] pair
19
- def self.split_version(full_name)
20
- matches = full_name.match(/(.*?)(?:[\.\-\_ ~,]?([0-9].*))?$/)
21
- if matches != nil and matches.length > 1
22
- [matches[1], matches[2]]
23
- else
24
- [full_string, nil]
25
- end
26
- end
12
+ # heuristically splits a full name into an artifact name and version string
13
+ # assumes that version strings begin with a numeric character and are separated
14
+ # by a ., -, _, ~ or space
15
+ # returns a [name, version] pair
16
+ def self.split_version(full_name)
17
+ matches = full_name.match(/(.*?)(?:[\.\-\_ ~,]?([0-9].*))?$/)
18
+ if matches != nil and matches.length > 1
19
+ [matches[1], matches[2]]
20
+ else
21
+ [full_string, nil]
22
+ end
23
+ end
27
24
 
28
- # returns the "best match" between a version number and a set of available version numbers
29
- # using a heuristic criterion. Idea:
30
- # - split the version number in chunks divided by ., - etc.
31
- # - every chunk with same index is "compared", differences make up a score
32
- # - "comparison" is a subtraction if the chunk is an integer, a string distance measure otherwise
33
- # - score weighs differently on chunk index (first chunks are most important)
34
- # - lowest score wins
35
- def self.best_match(my_version, their_versions)
36
- $log.debug("version comparison: #{my_version} vs #{their_versions.join(', ')}")
37
-
38
- my_chunks = my_version.split /[\.\-\_ ~,]/
39
- their_chunks_hash = Hash[
40
- their_versions.map do |their_version|
41
- their_chunks_for_version = their_version.split /[\.\-\_ ~,]/
42
- their_chunks_for_version += [nil]*[my_chunks.length - their_chunks_for_version.length, 0].max
43
- [their_version, their_chunks_for_version]
44
- end
45
- ]
25
+ # returns the "best match" between a version number and a set of available version numbers
26
+ # using a heuristic criterion. Idea:
27
+ # - split the version number in chunks divided by ., - etc.
28
+ # - every chunk with same index is "compared", differences make up a score
29
+ # - "comparison" is a subtraction if the chunk is an integer, a string distance measure otherwise
30
+ # - score weighs differently on chunk index (first chunks are most important)
31
+ # - lowest score wins
32
+ def self.best_match(my_version, their_versions)
33
+ log.debug("version comparison: #{my_version} vs #{their_versions.join(', ')}")
46
34
 
47
- max_chunks_length = ([my_chunks.length] + their_chunks_hash.values.map {|chunk| chunk.length}).max
48
-
49
- scoreboard = []
50
- their_versions.each do |their_version|
51
- their_chunks = their_chunks_hash[their_version]
52
- score = 0
53
- their_chunks.each_with_index do |their_chunk, i|
54
- score_multiplier = 100**(max_chunks_length -i -1)
55
- my_chunk = my_chunks[i]
56
- score += chunk_distance(my_chunk, their_chunk) * score_multiplier
35
+ my_chunks = my_version.split /[\.\-\_ ~,]/
36
+ their_chunks_hash = Hash[
37
+ their_versions.map do |their_version|
38
+ their_chunks_for_version = their_version.split /[\.\-\_ ~,]/
39
+ their_chunks_for_version += [nil]*[my_chunks.length - their_chunks_for_version.length, 0].max
40
+ [their_version, their_chunks_for_version]
41
+ end
42
+ ]
43
+
44
+ max_chunks_length = ([my_chunks.length] + their_chunks_hash.values.map {|chunk| chunk.length}).max
45
+
46
+ scoreboard = []
47
+ their_versions.each do |their_version|
48
+ their_chunks = their_chunks_hash[their_version]
49
+ score = 0
50
+ their_chunks.each_with_index do |their_chunk, i|
51
+ score_multiplier = 100**(max_chunks_length -i -1)
52
+ my_chunk = my_chunks[i]
53
+ score += chunk_distance(my_chunk, their_chunk) * score_multiplier
54
+ end
55
+ scoreboard << {:version => their_version, :score => score}
57
56
  end
58
- scoreboard << {:version => their_version, :score => score}
59
- end
60
-
61
- scoreboard = scoreboard.sort_by {|element| element[:score]}
57
+
58
+ scoreboard = scoreboard.sort_by {|element| element[:score]}
62
59
 
63
- $log.debug("scoreboard: ")
64
- scoreboard.each_with_index do |element, i|
65
- $log.debug(" #{i+1}. #{element[:version]} (score: #{element[:score]})")
60
+ log.debug("scoreboard: ")
61
+ scoreboard.each_with_index do |element, i|
62
+ log.debug(" #{i+1}. #{element[:version]} (score: #{element[:score]})")
63
+ end
64
+
65
+ winner = scoreboard.first
66
+
67
+ if winner != nil
68
+ return winner[:version]
69
+ end
66
70
  end
67
71
 
68
- winner = scoreboard.first
69
-
70
- if winner != nil
71
- return winner[:version]
72
- end
73
- end
74
-
75
- # returns a score representing the distance between two version chunks
76
- # for integers, the score is the difference between their values
77
- # for strings, the score is the Levenshtein distance
78
- # in any case score is normalized between 0 (identical) and 99 (very different/uncomparable)
79
- def self.chunk_distance(my_chunk, their_chunk)
80
- if my_chunk == nil
81
- my_chunk = "0"
82
- end
83
- if their_chunk == nil
84
- their_chunk = "0"
85
- end
86
- if my_chunk.is_i? and their_chunk.is_i?
87
- return [(my_chunk.to_i - their_chunk.to_i).abs, 99].min
88
- else
89
- return [Text::Levenshtein.distance(my_chunk.upcase, their_chunk.upcase), 99].min
72
+ # returns a score representing the distance between two version chunks
73
+ # for integers, the score is the difference between their values
74
+ # for strings, the score is the Levenshtein distance
75
+ # in any case score is normalized between 0 (identical) and 99 (very different/uncomparable)
76
+ def self.chunk_distance(my_chunk, their_chunk)
77
+ if my_chunk == nil
78
+ my_chunk = "0"
79
+ end
80
+ if their_chunk == nil
81
+ their_chunk = "0"
82
+ end
83
+ if my_chunk.is_i? and their_chunk.is_i?
84
+ return [(my_chunk.to_i - their_chunk.to_i).abs, 99].min
85
+ else
86
+ return [Text::Levenshtein.distance(my_chunk.upcase, their_chunk.upcase), 99].min
87
+ end
90
88
  end
91
89
  end
90
+
92
91
  end
93
92
 
94
93
  class String
@@ -96,4 +95,3 @@ class String
96
95
  !!(self =~ /^[0-9]+$/)
97
96
  end
98
97
  end
99
-
@@ -2,33 +2,33 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe PomGetter do
5
+ describe Gjp::PomGetter do
6
6
  describe ".get_pom" do
7
7
  it "gets the pom from a directory" do
8
8
  dir_path = File.join("spec", "data", "commons-logging")
9
9
  pom_path = File.join(dir_path, "pom.xml")
10
- PomGetter.get_pom(dir_path).should eq(File.read(pom_path))
10
+ Gjp::PomGetter.get_pom(dir_path).should eq(File.read(pom_path))
11
11
  end
12
12
 
13
13
  it "gets the pom from a jar" do
14
14
  dir_path = File.join("spec", "data", "commons-logging")
15
15
  pom_path = File.join(dir_path, "pom.xml")
16
16
  jar_path = File.join(dir_path, "commons-logging-1.1.1.jar")
17
- PomGetter.get_pom(jar_path).should eq(File.read(pom_path))
17
+ Gjp::PomGetter.get_pom(jar_path).should eq(File.read(pom_path))
18
18
  end
19
19
 
20
20
  it "gets the pom from sha1" do
21
21
  dir_path = File.join("spec", "data", "antlr")
22
22
  pom_path = File.join(dir_path, "pom.xml")
23
23
  jar_path = File.join(dir_path, "antlr-2.7.2.jar")
24
- PomGetter.get_pom(jar_path).should eq(File.read(pom_path))
24
+ Gjp::PomGetter.get_pom(jar_path).should eq(File.read(pom_path))
25
25
  end
26
26
 
27
27
  it "gets the pom from a heuristic" do
28
28
  dir_path = File.join("spec", "data", "nailgun")
29
29
  pom_path = File.join(dir_path, "pom.xml")
30
30
  jar_path = File.join(dir_path, "nailgun-0.7.1.jar")
31
- PomGetter.get_pom(jar_path).should eq(File.read(pom_path))
31
+ Gjp::PomGetter.get_pom(jar_path).should eq(File.read(pom_path))
32
32
  end
33
33
  end
34
34
  end
@@ -2,16 +2,16 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe SourceAddressGetter do
5
+ describe Gjp::SourceAddressGetter do
6
6
  describe ".get_source_address" do
7
7
  it "gets the source address from a pom file" do
8
8
  pom_path = File.join("spec", "data", "commons-logging", "pom.xml")
9
- SourceAddressGetter.get_source_address(pom_path).should eq "svn:http://svn.apache.org/repos/asf/commons/proper/logging/tags/commons-logging-1.1.1"
9
+ Gjp::SourceAddressGetter.get_source_address(pom_path).should eq "svn:http://svn.apache.org/repos/asf/commons/proper/logging/tags/commons-logging-1.1.1"
10
10
  end
11
11
 
12
12
  it "gets the source address from Github" do
13
13
  pom_path = File.join("spec", "data", "antlr", "pom.xml")
14
- SourceAddressGetter.get_source_address(pom_path).should eq "git:https://github.com/antlr/antlr4"
14
+ Gjp::SourceAddressGetter.get_source_address(pom_path).should eq "git:https://github.com/antlr/antlr4"
15
15
  end
16
16
  end
17
17
  end
@@ -3,7 +3,7 @@
3
3
  require "spec_helper"
4
4
  require "fileutils"
5
5
 
6
- describe SourceGetter do
6
+ describe Gjp::SourceGetter do
7
7
  describe ".get_source_from_git" do
8
8
  it "gets the sources from a git repo" do
9
9
  dir_path = File.join("spec", "data", "nailgun")
@@ -13,7 +13,7 @@ describe SourceGetter do
13
13
 
14
14
  FileUtils.rm_rf(repo_path)
15
15
 
16
- SourceGetter.get_source("git:git@github.com:martylamb/nailgun.git", pom_path, dir_path)
16
+ Gjp::SourceGetter.get_source("git:git@github.com:martylamb/nailgun.git", pom_path, dir_path)
17
17
 
18
18
  File.open(file_path).readline.should eq "nailgun\n"
19
19
  end
@@ -28,7 +28,7 @@ describe SourceGetter do
28
28
 
29
29
  FileUtils.rm_rf(repo_path)
30
30
 
31
- SourceGetter.get_source("svn:http://svn.apache.org/repos/asf/struts/struts2/tags/STRUTS_2_3_14/apps", pom_path, dir_path)
31
+ Gjp::SourceGetter.get_source("svn:http://svn.apache.org/repos/asf/struts/struts2/tags/STRUTS_2_3_14/apps", pom_path, dir_path)
32
32
 
33
33
  File.open(file_path).readline.should eq "README.txt - showcase\n"
34
34
  end
@@ -2,30 +2,38 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Pom do
6
- let(:pom) { Pom.new(File.join("spec", "data", "commons-logging", "pom.xml")) }
7
-
8
- describe "#connection_address" do
9
- it "reads the SCM connection address" do
10
- pom.connection_address.should eq "svn:http://svn.apache.org/repos/asf/commons/proper/logging/tags/commons-logging-1.1.1"
5
+ describe Gjp::Pom do
6
+ [ File.join("spec", "data", "commons-logging", "pom.xml"),
7
+ 'http://search.maven.org/remotecontent?filepath=commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.pom'].each do |loc|
8
+
9
+ let(:pom) { Gjp::Pom.new(loc) }
10
+
11
+ describe "#connection_address" do
12
+ it "reads the SCM connection address" do
13
+ pom.connection_address.should eq "svn:http://svn.apache.org/repos/asf/commons/proper/logging/tags/commons-logging-1.1.1"
14
+ end
15
+
16
+ it "reads the SCM connection address from a remote repository" do
17
+ pom.connection_address.should eq "svn:http://svn.apache.org/repos/asf/commons/proper/logging/tags/commons-logging-1.1.1"
18
+ end
11
19
  end
12
- end
13
-
14
- describe "#group_id" do
15
- it "reads the group id" do
16
- pom.group_id.should eq "commons-logging"
20
+
21
+ describe "#group_id" do
22
+ it "reads the group id" do
23
+ pom.group_id.should eq "commons-logging"
24
+ end
17
25
  end
18
- end
19
26
 
20
- describe "#artifact_id" do
21
- it "reads the artifact id" do
22
- pom.artifact_id.should eq "commons-logging"
27
+ describe "#artifact_id" do
28
+ it "reads the artifact id" do
29
+ pom.artifact_id.should eq "commons-logging"
30
+ end
23
31
  end
24
- end
25
-
26
- describe "#version" do
27
- it "reads the version" do
28
- pom.version.should eq "1.1.1"
32
+
33
+ describe "#version" do
34
+ it "reads the version" do
35
+ pom.version.should eq "1.1.1"
36
+ end
29
37
  end
30
38
  end
31
39
  end
@@ -2,63 +2,57 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe VersionMatcher do
5
+ describe Gjp::VersionMatcher do
6
6
 
7
7
  it "splits full names into names and version numbers" do
8
- VersionMatcher.split_version("moio-3.2beta1").should eq(["moio", "3.2beta1"])
9
- VersionMatcher.split_version("3.2beta1").should eq(["3", "2beta1"])
10
- VersionMatcher.split_version("v3.2beta1").should eq(["v", "3.2beta1"])
11
- end
12
-
13
- it "extracts version numbers" do
14
- VersionMatcher.extract_version("moio-3.2beta1").should eq("3.2beta1")
15
- VersionMatcher.extract_version("3.2beta1").should eq("3.2beta1")
16
- VersionMatcher.extract_version("v3.2beta1").should eq("3.2beta1")
8
+ Gjp::VersionMatcher.split_version("moio-3.2beta1").should eq(["moio", "3.2beta1"])
9
+ Gjp::VersionMatcher.split_version("3.2beta1").should eq(["", "3.2beta1"])
10
+ Gjp::VersionMatcher.split_version("v3.2beta1").should eq(["v", "3.2beta1"])
17
11
  end
18
12
 
19
13
  it "computes chunk distances" do
20
- VersionMatcher.chunk_distance(nil, "1").should eq(1)
21
- VersionMatcher.chunk_distance("alpha", nil).should eq(5)
14
+ Gjp::VersionMatcher.chunk_distance(nil, "1").should eq(1)
15
+ Gjp::VersionMatcher.chunk_distance("alpha", nil).should eq(5)
22
16
 
23
- VersionMatcher.chunk_distance("1", "1").should eq(0)
24
- VersionMatcher.chunk_distance("1", "9").should eq(8)
25
- VersionMatcher.chunk_distance("1", "999").should eq(99)
17
+ Gjp::VersionMatcher.chunk_distance("1", "1").should eq(0)
18
+ Gjp::VersionMatcher.chunk_distance("1", "9").should eq(8)
19
+ Gjp::VersionMatcher.chunk_distance("1", "999").should eq(99)
26
20
 
27
- VersionMatcher.chunk_distance("snap", "SNAP").should eq(0)
28
- VersionMatcher.chunk_distance("snap", "snippete").should eq(5)
29
- VersionMatcher.chunk_distance("snap", "l"*999).should eq(99)
21
+ Gjp::VersionMatcher.chunk_distance("snap", "SNAP").should eq(0)
22
+ Gjp::VersionMatcher.chunk_distance("snap", "snippete").should eq(5)
23
+ Gjp::VersionMatcher.chunk_distance("snap", "l"*999).should eq(99)
30
24
 
31
- VersionMatcher.chunk_distance("1", "SNAP").should eq(4)
25
+ Gjp::VersionMatcher.chunk_distance("1", "SNAP").should eq(4)
32
26
 
33
- VersionMatcher.chunk_distance("0", "10").should eq(10)
34
- VersionMatcher.chunk_distance("0", "9").should eq(9)
27
+ Gjp::VersionMatcher.chunk_distance("0", "10").should eq(10)
28
+ Gjp::VersionMatcher.chunk_distance("0", "9").should eq(9)
35
29
  end
36
30
 
37
31
  it "finds the best match" do
38
32
  my_version = "1.0"
39
33
  available_versions = ["1.0", "1", "2.0", "1.0.1", "4.5.6.7.8"]
40
- VersionMatcher.best_match(my_version, available_versions).should eq("1.0")
34
+ Gjp::VersionMatcher.best_match(my_version, available_versions).should eq("1.0")
41
35
 
42
36
  available_versions = ["3.0", "2.0", "1.0.1"]
43
- VersionMatcher.best_match(my_version, available_versions).should eq("1.0.1")
37
+ Gjp::VersionMatcher.best_match(my_version, available_versions).should eq("1.0.1")
44
38
 
45
39
  available_versions = ["1.snap", "2.0", "4.0.1"]
46
- VersionMatcher.best_match(my_version, available_versions).should eq("1.snap")
40
+ Gjp::VersionMatcher.best_match(my_version, available_versions).should eq("1.snap")
47
41
 
48
42
  available_versions = ["1.10", "1.9", "2.0", "3.0.1"]
49
- VersionMatcher.best_match(my_version, available_versions).should eq("1.9")
43
+ Gjp::VersionMatcher.best_match(my_version, available_versions).should eq("1.9")
50
44
 
51
45
  my_version = "1.snap"
52
46
  available_versions = ["1.snap", "1"]
53
- VersionMatcher.best_match(my_version, available_versions).should eq("1.snap")
47
+ Gjp::VersionMatcher.best_match(my_version, available_versions).should eq("1.snap")
54
48
 
55
49
  my_version = "1.very-very_very_longish"
56
50
  available_versions = ["1.snap", "1"]
57
- VersionMatcher.best_match(my_version, available_versions).should eq("1.snap")
51
+ Gjp::VersionMatcher.best_match(my_version, available_versions).should eq("1.snap")
58
52
 
59
53
  my_version = "1.snap"
60
54
  available_versions = []
61
- VersionMatcher.best_match(my_version, available_versions).should be_nil
55
+ Gjp::VersionMatcher.best_match(my_version, available_versions).should be_nil
62
56
  end
63
57
  end
64
58
 
@@ -3,4 +3,8 @@
3
3
  require "gjp"
4
4
  require "logger"
5
5
 
6
- init_logger(Logger::INFO)
6
+ Gjp.logger = ::Logger.new(STDERR)
7
+ Gjp.logger.level = ::Logger::INFO
8
+ Gjp.logger.formatter = proc do |severity, datetime, progname, msg|
9
+ "#{severity.chars.first}: #{msg}\n"
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gjp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-03 00:00:00.000000000 Z
12
+ date: 2013-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake