pho 0.0.1 → 0.1

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/Rakefile CHANGED
@@ -5,12 +5,12 @@ require 'rake/testtask'
5
5
  require 'rake/clean'
6
6
 
7
7
  NAME = "pho"
8
- VER = "0.0.1"
8
+ VER = "0.1"
9
9
 
10
10
  RDOC_OPTS = ['--quiet', '--title', 'Pho (Talis Platform Client) Reference', '--main', 'README']
11
11
 
12
12
  PKG_FILES = %w( README Rakefile ) +
13
- Dir.glob("{bin,doc,tests,lib}/**/*")
13
+ Dir.glob("{bin,doc,tests,examples,lib}/**/*")
14
14
 
15
15
  CLEAN.include ['*.gem', 'pkg']
16
16
  SPEC =
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'pho'
3
+
4
+ # Create the store object
5
+ store = Pho::Store.new("http://api.talis.com/stores/ldodds-dev1", "ldodds", "XXXXXXX")
6
+
7
+ # Using StringIO object here, but could more usually provide a File object
8
+ data = StringIO.new("Some data to store")
9
+
10
+ puts "Uploading item..."
11
+ resp = store.upload_item(data, "text/plain", "/items/test.txt")
12
+
13
+ puts "Status code after storage is: #{resp.status}"
14
+
15
+ puts "Retrieving data..."
16
+ resp = store.get_item("http://api.talis.com/stores/ldodds-dev1/items/test.txt")
17
+
18
+ puts "Status code after retrieval is #{resp.status}"
19
+ # Should output "Some data to store"
20
+ puts "Retrieved data is: #{resp.content}"
21
+
22
+ puts "Deleting item..."
23
+ resp = store.delete_item("/items/test.txt")
24
+
25
+ puts "Status code after deletion is #{resp.status}"
26
+
27
+ puts "Retrieving data..."
28
+ resp = store.get_item("http://api.talis.com/stores/ldodds-dev1/items/test.txt")
29
+
30
+ puts "Status code after deletion is: #{resp.status}"
@@ -0,0 +1,84 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'pho'
4
+
5
+ # Use the demonstration store containing NASA space flight data
6
+ store = Pho::Store.new("http://api.talis.com/stores/space")
7
+
8
+ #Retrieve simple RDF description for this resource (Apollo 11 Launch) as RDF/XML
9
+ puts "Describe Apollo 11 Launch"
10
+ response = store.describe("http://purl.org/net/schemas/space/launch/1969-059")
11
+
12
+ # Dump to console
13
+ puts response.content
14
+
15
+ # SPARQL Query
16
+ SPARQL = <<-EOL
17
+ PREFIX space: <http://purl.org/net/schemas/space/>
18
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
19
+
20
+
21
+ DESCRIBE ?spacecraft WHERE {
22
+
23
+ ?launch space:launched "1969-07-16"^^xsd:date.
24
+
25
+ ?spacecraft space:launch ?launch.
26
+
27
+ }
28
+
29
+ EOL
30
+ puts "Describe spacecraft launched on 16th July 1969"
31
+ response = store.sparql_describe(SPARQL)
32
+ puts response.content
33
+
34
+ SPARQL_CONSTRUCT = <<-EOL
35
+
36
+ PREFIX space: <http://purl.org/net/schemas/space/>
37
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
38
+ PREFIX foaf: <http://xmlns.com/foaf/0.1/>
39
+
40
+ CONSTRUCT {
41
+ ?spacecraft foaf:name ?name;
42
+ space:agency ?agency;
43
+ space:mass ?mass.
44
+ }
45
+ WHERE {
46
+ ?launch space:launched "1969-07-16"^^xsd:date.
47
+
48
+ ?spacecraft space:launch ?launch;
49
+ foaf:name ?name;
50
+ space:agency ?agency;
51
+ space:mass ?mass.
52
+ }
53
+
54
+ EOL
55
+
56
+ puts "Get name, agency and mass for spacecraft launched on 16th July 1969"
57
+ response = store.sparql_construct(SPARQL_CONSTRUCT)
58
+ puts response.content
59
+
60
+ SPARQL_SELECT = <<-EOL
61
+ PREFIX space: <http://purl.org/net/schemas/space/>
62
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
63
+ PREFIX foaf: <http://xmlns.com/foaf/0.1/>
64
+
65
+ SELECT ?name
66
+ WHERE {
67
+
68
+ ?launch space:launched "1969-07-16"^^xsd:date.
69
+
70
+ ?spacecraft space:launch ?launch;
71
+ foaf:name ?name.
72
+ }
73
+
74
+ EOL
75
+
76
+ puts "Get name of spacecraft launched on 16th July 1969, as JSON"
77
+ response = store.sparql_construct(SPARQL_SELECT, "application/sparql-results+json")
78
+ json = JSON.parse( response.content )
79
+
80
+ json["results"]["bindings"].each do |b|
81
+
82
+ puts b["name"]["value"]
83
+
84
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'pho'
3
+
4
+ # Create the store object
5
+ store = Pho::Store.new("http://api.talis.com/stores/space")
6
+ # Retrieve the store status as a simple hash
7
+ status = store.status
8
+ # Dump the hash to the console
9
+ puts status.inspect
data/lib/pho.rb CHANGED
@@ -4,6 +4,7 @@ require 'json'
4
4
 
5
5
  require 'pho/etags'
6
6
  require 'pho/store'
7
+ require 'pho/snapshot'
7
8
  require 'pho/rdf_collection'
8
9
 
9
10
  module Pho
@@ -16,6 +17,9 @@ module Pho
16
17
  JOB_RESET = "http://schemas.talis.com/2006/bigfoot/configuration#ResetDataJob".freeze
17
18
  JOB_SNAPSHOT = "http://schemas.talis.com/2006/bigfoot/configuration#SnapshotJob".freeze
18
19
  JOB_REINDEX = "http://schemas.talis.com/2006/bigfoot/configuration#ReindexJob".freeze
20
+ JOB_RESTORE = "http://schemas.talis.com/2006/bigfoot/configuration#RestoreJob".freeze
19
21
 
20
22
 
23
+ NAMESPACE_CONFIG = "http://schemas.talis.com/2006/bigfoot/configuration#"
24
+
21
25
  end
@@ -0,0 +1,17 @@
1
+ module Pho
2
+
3
+ # Captures information about a Platform Job
4
+ class Job
5
+
6
+
7
+ # Parse out an array of Job objects from a response returned from the Platform
8
+ def Job.parse_jobs(resp)
9
+ if resp.status != 200
10
+ throw
11
+ end
12
+ return nil
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -28,6 +28,7 @@ module Pho
28
28
  files_to_store.each do |filename|
29
29
  file = File.new(filename)
30
30
  response = @store.store_file(file)
31
+ #TODO error checking
31
32
  end
32
33
  end
33
34
 
@@ -0,0 +1,95 @@
1
+ module Pho
2
+
3
+ require 'digest/md5'
4
+
5
+ #In the Talis Platform a "snapshot" is an backup of the contents of a Store
6
+ #
7
+ #A snapshot consists of a tar file that contains all data (contentbox and metabox)
8
+ #in the store. The snapshot also contains the store configuration but this is encrypted
9
+ #and not intended for reuse.
10
+ #
11
+ #A snapshot can be generated (or scheduled) using the Store.snapshot method.
12
+ #
13
+ class Snapshot
14
+
15
+ #The URL from which the snapshot can be retrieved
16
+ attr_reader :url
17
+
18
+ #The URL from which the MD5 for the snapshot can be retrieved
19
+ attr_reader :md5_url
20
+
21
+ #Size of the snapshot
22
+ attr_reader :size
23
+
24
+ #Units for Size, e.g. KB
25
+ attr_reader :units
26
+
27
+ #Class method to parse the HTML response from API, e.g. as produced by the Store.get_snapshots method
28
+ #and create a new Snapshot object. At the moment the Platform only supports single snapshot.
29
+ #
30
+ #If the response was an error, then an exception will be thrown
31
+ #
32
+ # resp:: HTTP response generated by the Store.get_snapshots method
33
+ def Snapshot.parse(resp)
34
+ if (resp.status > 200)
35
+ raise "Response was not successful. Status code was: #{resp.status}"
36
+ end
37
+ content = resp.content
38
+
39
+ snapshot_url = content.match("<a href=\"(http://api.talis.com/stores/\.+/snapshots/\.+tar)\">\.+</a>")[1]
40
+
41
+ metadata = Regexp.new("<a href=\"(http://api.talis.com/stores/\.+/snapshots/\.+tar\.md5)\">\.+</a>\n\s+\-\s+([0-9]+) ([a-zA-Z]+)", "m")
42
+ snapshot_md5_url = metadata.match(content)[1]
43
+ snapshot_size = metadata.match(content)[2]
44
+ snapshot_units = metadata.match(content)[3]
45
+
46
+ return Snapshot.new(snapshot_url, snapshot_md5_url, snapshot_size, snapshot_units)
47
+
48
+ end
49
+
50
+ def initialize(url, md5_url, size, units)
51
+ @url = url
52
+ @md5_url = md5_url
53
+ @size = size
54
+ @units = units
55
+ end
56
+
57
+
58
+ #Read the published MD5 value
59
+ def read_md5(client=HttpClient.new())
60
+ return client.get_content(@md5_url)
61
+ end
62
+
63
+ # Download this snapshot to the specified directory. Will automatically calculate an MD5 checksum for
64
+ # the download and compare it against the published value. If they don't match then a RuntimeError will
65
+ # be raised
66
+ #
67
+ # dir:: directory in which snapshot will be stored
68
+ # client:: specify a preconfigured client, e.g. to configure proxy servers, etc
69
+ def download(dir, client=HTTPClient.new())
70
+
71
+ published_md5 = read_md5(client)
72
+
73
+ digest = Digest::MD5.new()
74
+
75
+ filename = @url.split("/").last
76
+ file = File.open( File.join(dir, filename), "w" ) do |file|
77
+
78
+ #FIXME: this is not efficient as the snapshot may be very large and this
79
+ #will just read all of the data into memory
80
+ content = client.get_content(@url)
81
+ puts content
82
+ file.print(content)
83
+ digest << content
84
+
85
+ end
86
+
87
+ calc_md5 = digest.hexdigest
88
+ if (calc_md5 != published_md5)
89
+ raise "Calculated digest of #{calc_md5} but does not match published md5 #{published_md5}"
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -4,12 +4,19 @@ module Pho
4
4
  #
5
5
  # Changesets
6
6
  # Multisparql
7
- #
7
+ #
8
+ # Listing jobs
9
+ # Retrieving single job
10
+ # FP Map
11
+ # Query Profile
12
+ # List snapshots
13
+ # Get snapshot
14
+ #
15
+ #
8
16
  # Conditional deletions
9
17
  # If-Modified-Since support
10
18
  # Robustness in uri fetching
11
- #
12
- # RDOC
19
+
13
20
 
14
21
  # The Store class acts as a lightweight client interface to the Talis Platform API
15
22
  # (http://n2.talis.com/wiki/Platform_API). The class provides methods for interacting
@@ -25,7 +32,8 @@ module Pho
25
32
  # store.reset
26
33
  #
27
34
  # == Examples
28
- #
35
+ #
36
+ # See the examples directory in the distribution
29
37
  class Store
30
38
 
31
39
  #Retrieve the HTTPClient instance being used by this object
@@ -330,7 +338,7 @@ module Pho
330
338
  #############
331
339
  # JOBS
332
340
  #############
333
-
341
+
334
342
  # Construct an RDF/XML document containing a job request for submitting to the Platform.
335
343
  #
336
344
  # t:: a Time object, specifying the time at which the request should be carried out
@@ -362,6 +370,27 @@ module Pho
362
370
  return submit_job(JOB_SNAPSHOT, "Snapshot my store", t)
363
371
  end
364
372
 
373
+ #Restore this store from a previously generated Snapshot
374
+ #The Platform can restore from any snapshot that is web-accessible
375
+ #
376
+ #snapshot_url:: the URL of the snapshot
377
+ def restore(snapshot_url, t=Time.now)
378
+ time = t.strftime("%Y-%m-%dT%H:%M:%SZ")
379
+ data = "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" "
380
+ data << " xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\" "
381
+ data << " xmlns:bf=\"http://schemas.talis.com/2006/bigfoot/configuration#\"> "
382
+ data << " <bf:JobRequest>"
383
+ data << " <rdfs:label>Restore my store</rdfs:label>"
384
+ data << " <bf:jobType rdf:resource=\"#{Pho::JOB_RESTORE}\"/>"
385
+ data << " <bf:snapshotUri rdf:resource=\"#{snapshot_url}\"/>"
386
+ data << " <bf:startTime>#{time}</bf:startTime>"
387
+ data << " </bf:JobRequest>"
388
+ data << "</rdf:RDF>"
389
+ u = build_uri("/jobs")
390
+ response = @client.post(u, data, RDF_XML )
391
+ return response
392
+ end
393
+
365
394
  def submit_job(joburi, label, t=Time.now)
366
395
  u = build_uri("/jobs")
367
396
  data = build_job_request(t, joburi, label)
@@ -383,7 +412,17 @@ module Pho
383
412
  state["accessMode"] = json[u.to_s]["http:\/\/schemas.talis.com\/2006\/bigfoot\/configuration#accessMode"][0]["value"]
384
413
  return state
385
414
  end
386
-
415
+
416
+ # Retrieve the list of snapshots for this store
417
+ #
418
+ # Currently the response will contain an HTML document. Use Snapshot.parse to turn this into
419
+ # a Snapshot object
420
+ def get_snapshots()
421
+ u = build_uri("/snapshots")
422
+ response = @client.get(u, nil, nil)
423
+ return response
424
+ end
425
+
387
426
  end
388
427
 
389
428
  end
@@ -55,5 +55,11 @@ class JobControlTest < Test::Unit::TestCase
55
55
  store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
56
56
  job_req = store.snapshot()
57
57
  end
58
-
58
+
59
+ def test_restore
60
+ mc = mock()
61
+ set_expectations("http://api.talis.com/stores/testing", mc, Pho::JOB_RESTORE, "Restore my store" )
62
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
63
+ job_req = store.restore("http://www.example.com.tar")
64
+ end
59
65
  end
@@ -0,0 +1,77 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+ require 'pho'
3
+ require 'test/unit'
4
+ require 'mocha'
5
+ require 'tmpdir'
6
+
7
+ class SnapshotsTest < Test::Unit::TestCase
8
+
9
+ def setup()
10
+ @snapshot = <<-EOL
11
+ <?xml version="1.0" encoding="UTF-8"?><html xmlns:bf="http://schemas.talis.com/2006/bigfoot/configuration#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><title>Snapshots</title><style type="text/css">
12
+
13
+ </style></head><body><div id="wrap"><div id="content"><div class="gutter"><h1>Snapshots for this store</h1><ul class="xoxo"><li><span class="field-name"><a href="http://api.talis.com/stores/test-store/snapshots/20090222113727.tar">http://api.talis.com/stores/test-store/snapshots/20090222113727.tar</a>
14
+ - <a href="http://api.talis.com/stores/test-store/snapshots/20090222113727.tar.md5">MD5</a>
15
+ - 30 KB
16
+ - 11:37 22-February-2009</span></li></ul></div><ul id="footer"><li id="learn"><a href="http://n2.talis.com/wiki/Platform_API">learn more</a></li></ul></div></div></body></html>
17
+ EOL
18
+
19
+ end
20
+
21
+ def teardown()
22
+
23
+ f = File.join(Dir.tmpdir, "2009022213727.tar")
24
+ if File.exists?(f)
25
+ # File.delete(f)
26
+ end
27
+
28
+ end
29
+
30
+ def test_get_snapshots()
31
+ mc = mock()
32
+ mc.expects(:set_auth)
33
+ mc.expects(:get).with("http://api.talis.com/stores/testing/snapshots", nil, nil)
34
+
35
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
36
+ response = store.get_snapshots()
37
+ end
38
+
39
+ def test_parse_snapshots()
40
+
41
+ mc = mock()
42
+ mc.expects(:status).returns(200)
43
+ mc.expects(:content).returns(@snapshot)
44
+
45
+ snapshot = Pho::Snapshot.parse(mc)
46
+
47
+ assert_equal(true, snapshot != nil)
48
+ assert_equal("http://api.talis.com/stores/test-store/snapshots/20090222113727.tar", snapshot.url)
49
+ assert_equal("http://api.talis.com/stores/test-store/snapshots/20090222113727.tar.md5", snapshot.md5_url)
50
+ assert_equal("30", snapshot.size)
51
+ assert_equal("KB", snapshot.units)
52
+ end
53
+
54
+ def test_parse_snapshots_raises_exception()
55
+
56
+ mc = mock()
57
+ mc.expects(:status).at_least_once.returns(500)
58
+
59
+ assert_raise RuntimeError do
60
+ Pho::Snapshot.parse(mc)
61
  end
62
+
63
+ end
64
+
65
+ def test_download()
66
+
67
+ mc = mock()
68
+ mc.expects(:get_content).with("http://api.talis.com/stores/test-store/snapshots/20090222113727.tar.md5").returns("4880c0340c65d142838ea33ace9b850a")
69
+ mc.expects(:get_content).with("http://api.talis.com/stores/test-store/snapshots/20090222113727.tar").returns("12345abcdef")
70
+
71
+ snapshot = Pho::Snapshot.new("http://api.talis.com/stores/test-store/snapshots/20090222113727.tar", "http://api.talis.com/stores/test-store/snapshots/20090222113727.tar.md5", "1", "KB")
72
+
73
+ snapshot.download(Dir.tmpdir, mc)
74
+
75
+ assert_equal(true, File.exists?( File.join(Dir.tmpdir, "20090222113727.tar" ) ) )
76
+ end
77
+
78
+ end
@@ -5,6 +5,7 @@ require 'tc_etags.rb'
5
5
  require 'tc_contentbox.rb'
6
6
  require 'tc_metabox.rb'
7
7
  require 'tc_jobcontrol.rb'
8
+ require 'tc_snapshots.rb'
8
9
  require 'tc_search.rb'
9
10
  require 'tc_sparql.rb'
10
11
  require 'tc_rdf_collection.rb'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pho
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: "0.1"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leigh Dodds
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-21 00:00:00 +00:00
12
+ date: 2009-02-23 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -60,14 +60,19 @@ files:
60
60
  - tests/tc_rdf_collection.rb
61
61
  - tests/ts_pho.rb
62
62
  - tests/tc_jobcontrol.rb
63
+ - tests/tc_snapshots.rb
63
64
  - tests/tc_search.rb
64
65
  - tests/tc_etags.rb
65
- - lib/test.rb
66
+ - examples/status.rb
67
+ - examples/sparql.rb
68
+ - examples/contentbox.rb
66
69
  - lib/pho.rb
67
70
  - lib/pho
68
71
  - lib/pho/etags.rb
69
72
  - lib/pho/rdf_collection.rb
70
73
  - lib/pho/store.rb
74
+ - lib/pho/job.rb
75
+ - lib/pho/snapshot.rb
71
76
  has_rdoc: true
72
77
  homepage: http://pho.rubyforge.net
73
78
  post_install_message:
@@ -1,29 +0,0 @@
1
- require 'pho'
2
-
3
- store = Pho::Store.new("http://api.talis.local/stores/space", "ldodds", "gwpjmv7z")
4
-
5
- state = store.status()
6
- puts state.inspect
7
-
8
- resp = store.store_file("/home/ldodds/data/space/nssdc/n3/1969-059A.rdf")
9
- puts resp
10
- puts resp.status
11
-
12
- resp = store.store_file(File.new("/home/ldodds/data/space/nssdc/n3/1969-059B.rdf") )
13
- puts resp.status
14
-
15
- resp = store.store_url("http://api.talis.local/stores/space/meta?about=http://purl.org/net/schemas/space/spacecraft/1969-059A")
16
- puts resp.status
17
-
18
- resp = store.store_url( URI.parse("http://api.talis.local/stores/space/meta?about=http://purl.org/net/schemas/space/spacecraft/1969-059A") )
19
- puts resp.status
20
-
21
- resp = store.describe("http://purl.org/net/schemas/space/spacecraft/1969-059A")
22
- puts resp
23
-
24
- resp = store.describe("http://purl.org/net/schemas/space/spacecraft/1969-059A", "application/json")
25
- puts resp
26
-
27
- store.snapshot
28
- store.reindex
29
- store.reset