io-afc 0.0.3.2

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/lib/io/afc.rb ADDED
@@ -0,0 +1,115 @@
1
+ require 'io/afc/version'
2
+ require 'io/afc/afc_base'
3
+ require 'io/afc/file'
4
+
5
+ class IO
6
+ class AFC < AFCBase
7
+ private
8
+ def dict_to_hash(dict)
9
+ v = nil
10
+ dict.inject({}){|s, k|
11
+ unless v
12
+ v = k
13
+ else
14
+ v = v.to_i if v=~/^\d+$/
15
+ s[k.to_sym] = v
16
+ v = nil
17
+ end
18
+ s
19
+ }
20
+ end
21
+
22
+ public
23
+
24
+ ##
25
+ # Connect to iOS-Device and yield block with handle if specified.
26
+ # @option [:uuid=>String] Target UUID. if nil, connect to default device.
27
+ # @option [:appid=>String] Mount application document folder if specified.
28
+ # @return [IO::AFC or block-result]
29
+ def self.connect(opt={}, &block)
30
+ dev = self.new(opt[:udid], opt[:appid])
31
+ return dev unless block_given?
32
+
33
+ begin
34
+ r = yield(dev)
35
+ dev.close
36
+ rescue Exception=>e
37
+ dev.close
38
+ throw e
39
+ end
40
+ r
41
+ end
42
+
43
+ ##
44
+ # Get storage info.
45
+ # @return [Hash]
46
+ #
47
+ # Example:
48
+ # afc.statfs
49
+ # => {:FSBlockSize=>4096,
50
+ # :FSFreeBytes=>27478216704,
51
+ # :FSTotalBytes=>30178787328,
52
+ # :Model=>"iPod5,1"}
53
+ def statfs
54
+ dict_to_hash(super)
55
+ end
56
+
57
+ ##
58
+ # Open file.
59
+ # @param [String] path for target file.
60
+ # @param [IO::Constants] mode for open mode. Default is IO::RDONLY.
61
+ def open(path, mode = IO::RDONLY, &block)
62
+ raise ArgumentError, "block is required." unless block_given?
63
+ File.open_file(self, path, mode, &block)
64
+ end
65
+
66
+ ##
67
+ # Get file/directory attribytes.
68
+ # @param [String] path.
69
+ # @return [Hash]
70
+ #
71
+ # Example:
72
+ # afc.getattr("/Safari")
73
+ # => {:st_birthtime=>2012-12-17 12:28:23 +0900,
74
+ # :st_mtime=>2013-06-22 20:32:01 +0900
75
+ # :st_ifmt=>"S_IFDIR",
76
+ # :st_nlink=>2,
77
+ # :st_blocks=>0,
78
+ # :st_size=>102}
79
+ #
80
+ # afc.getattr("/Safari/goog-phish-shavar.db")
81
+ # => {:st_birthtime=>2013-06-21 02:31:17 +0900,
82
+ # :st_mtime=>2013-06-21 02:31:18 +0900,
83
+ # :st_ifmt=>"S_IFREG",
84
+ # :st_nlink=>1,
85
+ # :st_blocks=>11256,
86
+ # :st_size=>5763072}
87
+ def getattr(path)
88
+ r = dict_to_hash(super(path))
89
+ [:st_birthtime, :st_mtime].each{|k|
90
+ r[k] = Time.at(r[k] / 1000000000.0)
91
+ }
92
+ r
93
+ end
94
+
95
+ ##
96
+ # Check exist
97
+ # @param [String] path.
98
+ # @return [String or nil] return type or nil.
99
+ def exist?(path)
100
+ begin
101
+ getattr(path)[:st_ifmt]
102
+ rescue Errno::ENOENT
103
+ nil
104
+ end
105
+ end
106
+
107
+ ##
108
+ # Read symlink.
109
+ # @param [String] path.
110
+ # @return [String or nil] return symlink-target.
111
+ def readlink(path)
112
+ getattr(path)[:LinkTarget]
113
+ end
114
+ end
115
+ end
Binary file
Binary file
@@ -0,0 +1,39 @@
1
+ $LOAD_PATH << "./ext"
2
+ $LOAD_PATH << "./lib"
3
+ require 'spec_helper'
4
+ require 'io/afc'
5
+
6
+
7
+ describe IO::AFC::File do
8
+ before do
9
+ @afc = IO::AFC.connect
10
+ end
11
+
12
+ context "method: open, " do
13
+ it "should require block." do
14
+ expect{ @afc.open("/") }.to raise_error(ArgumentError)
15
+ end
16
+
17
+ it "should be open '/'" do
18
+ r = @afc.open("/"){|f|
19
+ expect(f).to be_an_instance_of(IO::AFC::File)
20
+ expect(f.closed?).to eq(false)
21
+ f
22
+ }
23
+ expect(r).to be_an_instance_of(IO::AFC::File)
24
+ expect(r.closed?).to eq(true)
25
+ end
26
+
27
+ it "should be create file and write." do
28
+ @afc.open("/tempfile", IO::RDWR){|f|
29
+ expect(f).to be_an_instance_of(IO::AFC::File)
30
+ expect(f.write("Hello")).to eq(5)
31
+ }
32
+ end
33
+ end
34
+
35
+ after do
36
+ @afc.unlink("/tempfile") rescue nil
37
+ @afc.close
38
+ end
39
+ end
data/spec/afc_spec.rb ADDED
@@ -0,0 +1,87 @@
1
+ $LOAD_PATH << "./ext"
2
+ $LOAD_PATH << "./lib"
3
+ require 'spec_helper'
4
+ require 'io/afc'
5
+
6
+
7
+ describe IO::AFC do
8
+ it "should be connect." do
9
+ r = IO::AFC.connect{|afc|
10
+ expect(afc).to be_an_instance_of(IO::AFC)
11
+ expect(afc.closed?).to eq(false)
12
+ afc
13
+ }
14
+ expect(r).to be_an_instance_of(IO::AFC)
15
+ expect(r.closed?).to eq(true)
16
+ end
17
+
18
+ it "should be connect without block." do
19
+ afc = IO::AFC.connect
20
+ expect(afc).to be_an_instance_of(IO::AFC)
21
+ expect(afc.closed?).to eq(false)
22
+ expect(afc.close).to be_nil
23
+ expect(afc.closed?).to eq(true)
24
+ end
25
+
26
+
27
+ context "test for storage methods, " do
28
+ before do
29
+ @afc = IO::AFC.connect
30
+ end
31
+
32
+ it "should be mkdir and unlink." do
33
+ expect(@afc.mkdir("/tempdir")).to be_true
34
+ expect(@afc.unlink("/tempdir")).to be_true
35
+ end
36
+
37
+ it "should be getattr for directory." do
38
+ attr = @afc.getattr("/Safari")
39
+ expect(attr).to be_an_instance_of(Hash)
40
+ expect(attr[:st_birthtime]).to be_an_instance_of(Time)
41
+ expect(attr[:st_mtime]).to be_an_instance_of(Time)
42
+ expect(attr[:st_ifmt]).to eq("S_IFDIR")
43
+ end
44
+
45
+ context "with tempdir, " do
46
+ before do
47
+ make_directory("/tempdir")
48
+ @now = Time.now
49
+ end
50
+
51
+ it "should be getattr for directory (Time)." do
52
+ attr = @afc.getattr("/tempdir")
53
+ expect(attr[:st_birthtime].to_i).to be_within(@now.to_i+10).of(@now.to_i-10)
54
+ expect(attr[:st_mtime].to_i).to be_within(@now.to_i+10).of(@now.to_i+10)
55
+ end
56
+
57
+ it "should be mkdir, rename and unlink subdir." do
58
+ expect(@afc.mkdir("/tempdir/subdir")).to be_true
59
+ expect(@afc.rename("/tempdir/subdir", "/tempdir/subdir-2")).to be_true
60
+ expect(@afc.unlink("/tempdir/subdir-2")).to be_true
61
+ end
62
+
63
+ it "should be symlink, readlink and unlink." do
64
+ expect(@afc.symlink("subdir", "/tempdir/subdir-2")).to be_true
65
+ expect(@afc.readlink("/tempdir/subdir-2")).to eq("subdir")
66
+ expect(@afc.unlink("/tempdir/subdir-2")).to be_true
67
+ end
68
+
69
+ it "should be nil if readlink to not a link." do
70
+ expect(@afc.readlink("/tempdir")).to be_nil
71
+ end
72
+
73
+ it "should be check exists." do
74
+ expect(@afc.exist?("/tempdir")).to be_an_instance_of(String)
75
+ expect(@afc.exist?("/tempdir-not-exist")).to be_nil
76
+ end
77
+
78
+ after do
79
+ remove_directory("/tempdir")
80
+ end
81
+ end
82
+
83
+ after do
84
+ @afc.close
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,50 @@
1
+ $LOAD_PATH << "./ext"
2
+ require 'io/afc/afc_base'
3
+ require 'spec_helper'
4
+
5
+
6
+ describe IO::AFCBase do
7
+ context "Basic storage I/O, " do
8
+ context "File control, " do
9
+ before do
10
+ @afc = IO::AFCBase.new(nil, nil)
11
+ f = IO::AFCBase::Descriptor.new(@afc, "/tempfile", 2)
12
+ begin
13
+ f.write("hello")
14
+ ensure
15
+ f.close
16
+ end
17
+ end
18
+
19
+ it "should be utimens." do
20
+ t = Time.now - 200000000
21
+ expect(@afc.utimens("/tempfile", t)).to be_true
22
+ stat = dict_to_hash(@afc.getattr("/tempfile"))
23
+ expect(stat["st_mtime"].to_i).to eq(t.to_i*1000_000_000)
24
+ end
25
+
26
+ it "should be get file size." do
27
+ stat = dict_to_hash(@afc.getattr("/tempfile"))
28
+ expect(stat["st_size"].to_i).to eq(5)
29
+ end
30
+
31
+ it "should be truncate." do
32
+ expect(@afc.truncate("/tempfile", 1)).to be_true
33
+ stat = dict_to_hash(@afc.getattr("/tempfile"))
34
+ expect(stat["st_size"].to_i).to eq(1)
35
+ end
36
+
37
+ it "should be create hardlink." do
38
+ expect(@afc.link("/tempfile", "/tempfile-2")).to be_true
39
+ expect(@afc.readdir("/")).to be_include("tempfile-2")
40
+ end
41
+
42
+ after do
43
+ %w{/tempfile /tempfile-2}.each{|p|
44
+ @afc.unlink(p) rescue nil
45
+ }
46
+ @afc.close
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,60 @@
1
+ $LOAD_PATH << "./ext"
2
+ require 'io/afc/afc_base'
3
+ require 'spec_helper'
4
+
5
+
6
+ describe IO::AFCBase do
7
+ context "Basic storage I/O, " do
8
+ context "File IO, " do
9
+ before do
10
+ @afc = IO::AFCBase.new(nil, nil)
11
+ end
12
+
13
+ it "should be create file and close." do
14
+ f = IO::AFCBase::Descriptor.new(@afc, "/tempfile", 2)
15
+ begin
16
+ expect(f).to be_an_instance_of(IO::AFCBase::Descriptor)
17
+ expect(f.closed?).to eq(false)
18
+ expect(f.write("hello")).to eq(5)
19
+ ensure
20
+ expect(f.close).to be_nil
21
+ expect(f.closed?).to eq(true)
22
+ end
23
+
24
+ f = IO::AFCBase::Descriptor.new(@afc, "/tempfile", 0)
25
+ begin
26
+ expect(f.read(-1)).to eq("hello")
27
+ expect(f.tell).to eq(5)
28
+ expect(f.seek(0, IO::SEEK_SET)).to be_true
29
+ expect(f.tell).to eq(0)
30
+ ensure
31
+ f.close
32
+ end
33
+
34
+ f = IO::AFCBase::Descriptor.new(@afc, "/tempfile", 2)
35
+ begin
36
+ expect(f.ftruncate(2)).to be_true
37
+ ensure
38
+ f.close
39
+ end
40
+ info = @afc.getattr("/tempfile")
41
+ size = info[info.find_index("st_size")-1].to_i
42
+ expect(size).to eq(2)
43
+ end
44
+
45
+ it "should be write 0 bytes when data is nil." do
46
+ f = IO::AFCBase::Descriptor.new(@afc, "/tempfile", 2)
47
+ begin
48
+ expect(f.write(nil)).to eq(0)
49
+ ensure
50
+ f.close
51
+ end
52
+ end
53
+
54
+ after do
55
+ @afc.unlink("/tempfile") rescue nil
56
+ @afc.close
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,79 @@
1
+ $LOAD_PATH << "./ext"
2
+ require 'spec_helper'
3
+ require 'io/afc/afc_base'
4
+
5
+
6
+ describe IO::AFCBase do
7
+ context "Basic storage I/O, " do
8
+ it "should be connect device." do
9
+ expect(IO::AFCBase.new(nil, nil)).to be_an_instance_of(IO::AFCBase)
10
+ end
11
+
12
+ it "should be close." do
13
+ afc = IO::AFCBase.new(nil, nil)
14
+ expect(afc.closed?).to eq(false)
15
+ expect(afc.close).to be_nil
16
+ expect(afc.closed?).to eq(true)
17
+ end
18
+
19
+ context "After connect, " do
20
+ before do
21
+ @afc = IO::AFCBase.new(nil, nil)
22
+ end
23
+
24
+ it "should be get attributes." do
25
+ attr = @afc.getattr("/")
26
+ expect(attr).to be_an_instance_of(Array)
27
+ end
28
+
29
+ it "should be readdir." do
30
+ dirs = @afc.readdir("/")
31
+ expect(dirs).to be_an_instance_of(Array)
32
+ end
33
+
34
+ it "should be get statfs." do
35
+ stat = @afc.statfs
36
+ expect(stat).to be_an_instance_of(Array)
37
+ end
38
+
39
+ it "should be make a directory, rename, and unlink." do
40
+ expect(@afc.mkdir("/tmp")).to be_true
41
+ expect(@afc.rename("/tmp", "/temp")).to be_true
42
+ expect(@afc.unlink("/temp")).to be_true
43
+ end
44
+
45
+ it "should be crerate a symlink." do
46
+ expect(@afc.symlink("hello", "/tempfile-2")).to be_true
47
+ expect(@afc.readdir("/")).to be_include("tempfile-2")
48
+ stat = dict_to_hash(@afc.getattr("/tempfile-2"))
49
+ expect(stat["LinkTarget"]).to eq("hello")
50
+ end
51
+
52
+ it "should be get device udid." do
53
+ expect(@afc.device_udid).to be_an_instance_of(String)
54
+ end
55
+
56
+ it "should be get device display name." do
57
+ expect(@afc.device_display_name).to be_an_instance_of(String)
58
+ end
59
+
60
+ it "should be get application list." do
61
+ apps = @afc.applications
62
+ expect(apps).to be_an_instance_of(Hash)
63
+ apps.each{|app, val|
64
+ expect(app).to be_an_instance_of(String)
65
+ expect(val).to be_an_instance_of(Hash)
66
+ expect(val["CFBundleDisplayName"]).to be_an_instance_of(String)
67
+ expect([true, false]).to include(val["UIFileSharingEnabled"])
68
+ }
69
+ end
70
+
71
+ after do
72
+ %w{/tempfile /tempfile-2 /tmp /temp}.each{|p|
73
+ @afc.unlink(p) rescue nil
74
+ }
75
+ @afc.close
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,48 @@
1
+ require 'thread'
2
+ require 'pry-nav'
3
+
4
+ puts Process.pid
5
+ #binding.pry
6
+
7
+
8
+ def dict_to_hash(dict)
9
+ v = nil
10
+ h = {}
11
+ dict.each_index{|n|
12
+ case n%2
13
+ when 0
14
+ v = dict[n]
15
+ when 1
16
+ k = dict[n]
17
+ h[k] = v
18
+ end
19
+ }
20
+ h
21
+ end
22
+
23
+
24
+ $mutex = Mutex.new
25
+ $dirs = {}
26
+ def make_directory(path)
27
+ $mutex.synchronize{
28
+ unless $dirs[path]
29
+ IO::AFC.connect{|afc|
30
+ afc.mkdir(path)
31
+ }
32
+ $dirs[path] = 0
33
+ end
34
+ $dirs[path] += 1
35
+ }
36
+ end
37
+
38
+ def remove_directory(path)
39
+ $mutex.synchronize{
40
+ $dirs[path] -= 1
41
+ if $dirs[path] == 0
42
+ IO::AFC.connect{|afc|
43
+ afc.unlink(path)
44
+ $dirs.delete(path)
45
+ }
46
+ end
47
+ }
48
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: io-afc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Toshiyuki Suzumura
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Access to the file system of iOS devices from Ruby.
47
+ email:
48
+ - suz.labo@amail.plala.or.jp
49
+ executables: []
50
+ extensions:
51
+ - ext/io/afc/extconf.rb
52
+ extra_rdoc_files: []
53
+ files:
54
+ - ext/io/afc/build.xcconfig
55
+ - ext/io/afc/extconf.rb
56
+ - ext/io/afc/ioafc.cpp
57
+ - ext/io/afc/ioafc.h
58
+ - ext/io/afc/ruby_wrapper.h
59
+ - Gemfile
60
+ - Gemfile.lock
61
+ - io-afc.gemspec
62
+ - io-afc.xcodeproj/project.pbxproj
63
+ - lib/io/afc/file.rb
64
+ - lib/io/afc/version.rb
65
+ - lib/io/afc.rb
66
+ - LICENSE.txt
67
+ - pkg/io-afc-0.0.3.1.gem
68
+ - pkg/io-afc-0.0.3.2.gem
69
+ - Rakefile
70
+ - README.md
71
+ - spec/afc_file_spec.rb
72
+ - spec/afc_spec.rb
73
+ - spec/basicio_filectrl_spec.rb
74
+ - spec/basicio_fileio_spec.rb
75
+ - spec/basicio_spec.rb
76
+ - spec/spec_helper.rb
77
+ homepage: https://github.com/suzumura-ss/ruby-io-afc
78
+ licenses:
79
+ - MIT
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ segments:
91
+ - 0
92
+ hash: 378568250842512408
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ segments:
100
+ - 0
101
+ hash: 378568250842512408
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 1.8.25
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Access to the file system of iOS devices from Ruby. Required 'libimobiledevice'.
108
+ test_files:
109
+ - spec/afc_file_spec.rb
110
+ - spec/afc_spec.rb
111
+ - spec/basicio_filectrl_spec.rb
112
+ - spec/basicio_fileio_spec.rb
113
+ - spec/basicio_spec.rb
114
+ - spec/spec_helper.rb