killsite 0.2.0 → 0.3.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.
data/Gemfile CHANGED
@@ -1,6 +1,5 @@
1
1
  source :rubygems
2
2
 
3
- gem "em-http-request"
4
3
  gem "nokogiri"
5
4
 
6
5
  group :development do
@@ -1,13 +1,6 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- addressable (2.2.6)
5
- em-http-request (0.3.0)
6
- addressable (>= 2.0.0)
7
- escape_utils
8
- eventmachine (>= 0.12.9)
9
- escape_utils (0.2.3)
10
- eventmachine (0.12.10)
11
4
  git (1.2.5)
12
5
  jeweler (1.6.4)
13
6
  bundler (~> 1.0)
@@ -23,7 +16,6 @@ PLATFORMS
23
16
 
24
17
  DEPENDENCIES
25
18
  bundler (~> 1.0.0)
26
- em-http-request
27
19
  jeweler (~> 1.6.4)
28
20
  nokogiri
29
21
  rcov
@@ -0,0 +1,25 @@
1
+ = killsite
2
+
3
+ Recursively GET all the pages of a given site through hyperlinks.
4
+ The tool is for the usage of testing and profiling.
5
+
6
+ Using memory monitor to find out the memory leaks within different URLs.
7
+
8
+ == Installation
9
+
10
+ Simply `gem install killsite`.
11
+ `ab` (ApacheBench) is require as an benchmark tool.
12
+
13
+ == Usage
14
+
15
+ Usage: killsite [options]
16
+ -h, --help Show help message
17
+ -l, --limit NUM Setting the limit of a single test
18
+ -c, --concurrency NUM Setting the number of concurrent connection
19
+ -p, --pid PID The PID is the monitored server process
20
+
21
+ == Copyright
22
+
23
+ Copyright (c) 2011 Andrew Liu. See LICENSE.txt for
24
+ further details.
25
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -1,15 +1,59 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'optparse'
3
4
  require 'killsite'
5
+ require 'memory_monitor'
4
6
 
5
- if ARGV.size == 0
6
- puts "USAGE: killsite [site] [limit]"
7
- exit
7
+ if `which ab`.empty?
8
+ puts "ab (ApacheBench) must be installed to proceed"
9
+ exit -1
8
10
  end
9
11
 
10
- prefix = ARGV[0]
11
- limit = (ARGV[1] || 1).to_i
12
+ options = {}
12
13
 
13
- killer = SiteKiller.new(prefix, limit, true)
14
+ optparse = OptionParser.new do |opts|
15
+ opts.on('-h', '--help', 'Show help message') do
16
+ puts opts
17
+ exit 0
18
+ end
19
+
20
+ opts.on('-l', '--limit NUM', 'Setting the limit of a single test') do |limit|
21
+ if limit.to_i > 0
22
+ options[:limit] = limit.to_i
23
+ else
24
+ puts "Limit must greater than 1"
25
+ exit 1
26
+ end
27
+ end
28
+
29
+ opts.on('-c', '--concurrency NUM', 'Setting the number of concurrent connection') do |num|
30
+ if num.to_i > 0
31
+ options[:concurrency] = num.to_i
32
+ else
33
+ puts "The number of concurrency must greater than 1"
34
+ exit 2
35
+ end
36
+ end
37
+
38
+ opts.on('-p', '--pid PID', 'The PID is the monitored server process') do |pid|
39
+ if pid.to_i > 0 and `ps -o pid #{pid}`.split.size > 1
40
+ options[:pid] = pid.to_i
41
+ else
42
+ puts "PID not exists or invalid"
43
+ exit 3
44
+ end
45
+ end
46
+ end
47
+
48
+ optparse.parse!
49
+
50
+ options[:prefix] = ARGV.shift
51
+
52
+ unless options[:prefix]
53
+ puts "Please specify the URL"
54
+ exit 4
55
+ end
14
56
 
15
- EM.run { limit.times { killer.run } }
57
+ monitors = (options[:pid]) ? [MemoryMonitor.new(options[:pid])] : []
58
+ SiteKiller.new(options[:prefix], options[:limit], options[:concurrency], true, monitors).run
59
+ monitors.each(&:report) unless monitors.empty?
@@ -5,30 +5,31 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{killsite}
8
- s.version = "0.2.0"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andrew Liu"]
12
- s.date = %q{2011-07-16}
12
+ s.date = %q{2011-07-18}
13
13
  s.default_executable = %q{killsite}
14
14
  s.description = %q{Recursively GET the site by links, try to kill the site}
15
15
  s.email = %q{andrewliu33@gmail.com}
16
16
  s.executables = ["killsite"]
17
17
  s.extra_rdoc_files = [
18
18
  "LICENSE.txt",
19
- "README.rdoc"
19
+ "README.md"
20
20
  ]
21
21
  s.files = [
22
22
  ".document",
23
23
  "Gemfile",
24
24
  "Gemfile.lock",
25
25
  "LICENSE.txt",
26
- "README.rdoc",
26
+ "README.md",
27
27
  "Rakefile",
28
28
  "VERSION",
29
29
  "bin/killsite",
30
30
  "killsite.gemspec",
31
31
  "lib/killsite.rb",
32
+ "lib/memory_monitor.rb",
32
33
  "test/helper.rb"
33
34
  ]
34
35
  s.homepage = %q{http://github.com/eggegg/killsite}
@@ -41,14 +42,12 @@ Gem::Specification.new do |s|
41
42
  s.specification_version = 3
42
43
 
43
44
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
44
- s.add_runtime_dependency(%q<em-http-request>, [">= 0"])
45
45
  s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
46
46
  s.add_development_dependency(%q<shoulda>, [">= 0"])
47
47
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
48
48
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
49
49
  s.add_development_dependency(%q<rcov>, [">= 0"])
50
50
  else
51
- s.add_dependency(%q<em-http-request>, [">= 0"])
52
51
  s.add_dependency(%q<nokogiri>, [">= 0"])
53
52
  s.add_dependency(%q<shoulda>, [">= 0"])
54
53
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -56,7 +55,6 @@ Gem::Specification.new do |s|
56
55
  s.add_dependency(%q<rcov>, [">= 0"])
57
56
  end
58
57
  else
59
- s.add_dependency(%q<em-http-request>, [">= 0"])
60
58
  s.add_dependency(%q<nokogiri>, [">= 0"])
61
59
  s.add_dependency(%q<shoulda>, [">= 0"])
62
60
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -1,49 +1,48 @@
1
- require 'bundler'
2
- require 'uri'
3
- Bundler.require
1
+ require 'open-uri'
2
+ require 'nokogiri'
4
3
 
5
4
  class SiteKiller
6
- def initialize(prefix, limit = 1, verbose = false)
7
- @count = 1
5
+ def initialize(prefix, limit = nil, concurrency = nil, verbose = nil, observers = nil)
8
6
  @prefix = URI.parse(prefix)
9
- @visited = { @prefix => 0 }
10
- @verbose = verbose
11
- @limit = limit
7
+ @visited = [@prefix]
8
+ @queue = [@prefix]
9
+ @verbose = verbose || false
10
+ @limit = limit || 1
11
+ @concurrency = concurrency || 10
12
+ @concurrency = @limit if @concurrency > @limit
13
+ @observers = observers || []
12
14
  end
13
15
 
14
- def run url = nil
15
- url ||= @prefix
16
-
17
- http = EventMachine::HttpRequest.new(url).get
18
- http.callback do
19
- if @visited[url] == 0
20
- puts "Processing '#{url}'" if @verbose
21
- Nokogiri::HTML.parse(http.response).xpath("//a[@href]").each do |link|
16
+ def run
17
+ while @queue.size > 0
18
+ url = @queue.shift
19
+
20
+ @observers.each { |o| o.before_request(url) if o.respond_to? :before_request }
21
+ `ab -n #{@limit} -c #{@concurrency} #{url}`
22
+ @observers.each { |o| o.after_request(url) if o.respond_to? :after_request }
23
+
24
+ puts "Processing '#{url}'" if @verbose
25
+ begin
26
+ response = open(url).read
27
+ Nokogiri::HTML.parse(response).xpath("//a[@href]").each do |link|
22
28
  next_url = process_url link['href']
23
29
  if next_url and !@visited.include?(next_url)
24
30
  puts " Queueing '#{next_url}'" if @verbose
25
31
 
26
- @visited[next_url] = 0
27
- @count += @limit
28
- @limit.times { run next_url }
32
+ @visited << next_url
33
+ @queue << next_url
29
34
  end
30
35
  end
31
- print " Progress " if @verbose
32
- else
33
- print '*' if @verbose
36
+ rescue => e
37
+ puts " No valid response: #{e}"
34
38
  end
35
-
36
- @visited[url] += 1
37
- puts if @verbose and @visited[url] == @limit
38
- @count -= 1
39
- EM.stop if @count == 0
40
39
  end
41
40
  end
42
41
 
43
42
  private
44
43
  def process_url url
45
44
  return nil if url =~ /^http/ and URI.parse(@prefix.to_s).host != URI.parse(url).host
46
- return nil if url =~ /^javascript/ or url =~ /^#/
45
+ return nil if url =~ /^javascript|^#|^mailto/
47
46
  URI.join @prefix.to_s, url
48
47
  end
49
48
  end
@@ -0,0 +1,32 @@
1
+
2
+ class MemoryMonitor
3
+ def initialize pid
4
+ @pid = pid
5
+ @data = {}
6
+ end
7
+
8
+ def before_request url
9
+ @data[url] = memory
10
+ end
11
+
12
+ def after_request url
13
+ @data[url] = memory - @data[url]
14
+ end
15
+
16
+ def report
17
+ sorted = @data.sort_by { |url, memory| -memory }
18
+
19
+
20
+ puts "\nMost memory used actions:"
21
+ sorted.each_with_index do |(url, memory), index|
22
+ puts "##{index + 1}\t#{memory/1024} KB\t=> #{url.to_s}"
23
+ end
24
+ end
25
+
26
+ private
27
+ def memory
28
+ mem = `ps -o rss #{@pid}`[/\d+/].to_i
29
+ raise 'invalid PID' unless mem > 0
30
+ mem
31
+ end
32
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: killsite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,23 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-16 00:00:00.000000000 +08:00
12
+ date: 2011-07-18 00:00:00.000000000 +08:00
13
13
  default_executable: killsite
14
14
  dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: em-http-request
17
- requirement: &2157593620 !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: '0'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: *2157593620
26
15
  - !ruby/object:Gem::Dependency
27
16
  name: nokogiri
28
- requirement: &2157593140 !ruby/object:Gem::Requirement
17
+ requirement: &2158843600 !ruby/object:Gem::Requirement
29
18
  none: false
30
19
  requirements:
31
20
  - - ! '>='
@@ -33,10 +22,10 @@ dependencies:
33
22
  version: '0'
34
23
  type: :runtime
35
24
  prerelease: false
36
- version_requirements: *2157593140
25
+ version_requirements: *2158843600
37
26
  - !ruby/object:Gem::Dependency
38
27
  name: shoulda
39
- requirement: &2157592660 !ruby/object:Gem::Requirement
28
+ requirement: &2158843120 !ruby/object:Gem::Requirement
40
29
  none: false
41
30
  requirements:
42
31
  - - ! '>='
@@ -44,10 +33,10 @@ dependencies:
44
33
  version: '0'
45
34
  type: :development
46
35
  prerelease: false
47
- version_requirements: *2157592660
36
+ version_requirements: *2158843120
48
37
  - !ruby/object:Gem::Dependency
49
38
  name: bundler
50
- requirement: &2157592180 !ruby/object:Gem::Requirement
39
+ requirement: &2158842640 !ruby/object:Gem::Requirement
51
40
  none: false
52
41
  requirements:
53
42
  - - ~>
@@ -55,10 +44,10 @@ dependencies:
55
44
  version: 1.0.0
56
45
  type: :development
57
46
  prerelease: false
58
- version_requirements: *2157592180
47
+ version_requirements: *2158842640
59
48
  - !ruby/object:Gem::Dependency
60
49
  name: jeweler
61
- requirement: &2157591700 !ruby/object:Gem::Requirement
50
+ requirement: &2158842160 !ruby/object:Gem::Requirement
62
51
  none: false
63
52
  requirements:
64
53
  - - ~>
@@ -66,10 +55,10 @@ dependencies:
66
55
  version: 1.6.4
67
56
  type: :development
68
57
  prerelease: false
69
- version_requirements: *2157591700
58
+ version_requirements: *2158842160
70
59
  - !ruby/object:Gem::Dependency
71
60
  name: rcov
72
- requirement: &2157591220 !ruby/object:Gem::Requirement
61
+ requirement: &2158841680 !ruby/object:Gem::Requirement
73
62
  none: false
74
63
  requirements:
75
64
  - - ! '>='
@@ -77,7 +66,7 @@ dependencies:
77
66
  version: '0'
78
67
  type: :development
79
68
  prerelease: false
80
- version_requirements: *2157591220
69
+ version_requirements: *2158841680
81
70
  description: Recursively GET the site by links, try to kill the site
82
71
  email: andrewliu33@gmail.com
83
72
  executables:
@@ -85,18 +74,19 @@ executables:
85
74
  extensions: []
86
75
  extra_rdoc_files:
87
76
  - LICENSE.txt
88
- - README.rdoc
77
+ - README.md
89
78
  files:
90
79
  - .document
91
80
  - Gemfile
92
81
  - Gemfile.lock
93
82
  - LICENSE.txt
94
- - README.rdoc
83
+ - README.md
95
84
  - Rakefile
96
85
  - VERSION
97
86
  - bin/killsite
98
87
  - killsite.gemspec
99
88
  - lib/killsite.rb
89
+ - lib/memory_monitor.rb
100
90
  - test/helper.rb
101
91
  has_rdoc: true
102
92
  homepage: http://github.com/eggegg/killsite
@@ -114,7 +104,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
104
  version: '0'
115
105
  segments:
116
106
  - 0
117
- hash: -2909793090681244207
107
+ hash: -1937579483118733362
118
108
  required_rubygems_version: !ruby/object:Gem::Requirement
119
109
  none: false
120
110
  requirements:
@@ -1,20 +0,0 @@
1
- = killsite
2
-
3
- Recursively GET all the pages of a given site through hyperlinks.
4
- The tool is for the usage of testing and profiling.
5
-
6
- == Installation
7
-
8
- Simply `gem install killsite`.
9
-
10
- == Usage
11
-
12
- killsite [website] [# of GET for each pages]
13
-
14
- The second argument can be omitted.
15
-
16
- == Copyright
17
-
18
- Copyright (c) 2011 Andrew Liu. See LICENSE.txt for
19
- further details.
20
-