vos 0.1.0 → 0.1.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
@@ -2,7 +2,7 @@ require 'rake_ext'
2
2
 
3
3
  project(
4
4
  name: "vos",
5
- version: "0.1.0",
5
+ version: "0.1.1",
6
6
  summary: "Virtual Operating System",
7
7
 
8
8
  author: "Alexey Petrushin",
data/lib/vos/box.rb CHANGED
@@ -4,22 +4,33 @@ module Vos
4
4
 
5
5
  attr_accessor :options
6
6
 
7
- def initialize options = {}
8
- @options = options
9
- options[:host] ||= 'localhost'
7
+ def initialize *args
8
+ first = args.first
9
+ if args.empty?
10
+ @driver = Drivers::Local.new
11
+ elsif first.is_a?(String) or first.is_a?(Symbol) or first.is_a?(Hash) and (args.size <= 2)
12
+ if first.is_a? Hash
13
+ options = first
14
+ options[:host] ||= 'localhost'
15
+ else
16
+ options = args[1] || {}
17
+ raise 'invalid arguments' unless options.is_a?(Hash)
18
+ options[:host] = first.to_s
19
+ end
20
+
21
+ @driver = options[:host] == 'localhost' ? Drivers::Local.new(options) : Drivers::Ssh.new(options)
22
+ elsif args.size == 1
23
+ @driver = first
24
+ else
25
+ raise 'invalid arguments'
26
+ end
10
27
  end
11
28
 
12
29
 
13
30
  #
14
31
  # driver
15
32
  #
16
- def driver
17
- unless @driver
18
- klass = options[:host] == 'localhost' ? Drivers::Local : Drivers::Ssh
19
- @driver = klass.new options
20
- end
21
- @driver
22
- end
33
+ attr_reader :driver
23
34
 
24
35
  def open &block
25
36
  driver.open &block
@@ -33,12 +44,13 @@ module Vos
33
44
  # Micelaneous
34
45
  #
35
46
  def inspect
36
- host = options[:host]
37
- if host == 'localhost'
38
- ''
39
- else
40
- host
41
- end
47
+ driver.to_s
48
+ # host = options[:host]
49
+ # if host == 'localhost'
50
+ # ''
51
+ # else
52
+ # host
53
+ # end
42
54
  end
43
55
  alias_method :to_s, :inspect
44
56
  end
@@ -33,6 +33,12 @@ module Vos
33
33
 
34
34
  return code, stdout_and_stderr
35
35
  end
36
+
37
+
38
+ #
39
+ # Other
40
+ #
41
+ def to_s; '' end
36
42
  end
37
43
  end
38
44
  end
@@ -4,142 +4,18 @@ require 'net/sftp'
4
4
  module Vos
5
5
  module Drivers
6
6
  class Ssh < Abstract
7
- module VfsStorage
8
- #
9
- # Attributes
10
- #
11
- def attributes path
12
-
13
- stat = sftp.stat! fix_path(path)
14
- attrs = {}
15
- attrs[:file] = stat.file?
16
- attrs[:dir] = stat.directory?
17
- # stat.symlink?
18
- attrs
19
- rescue Net::SFTP::StatusException
20
- {}
21
- end
22
-
23
- def set_attributes path, attrs
24
- raise 'not supported'
25
- end
26
-
27
- #
28
- # File
29
- #
30
- def read_file path, &block
31
- sftp.file.open fix_path(path), 'r' do |is|
32
- while buff = is.gets
33
- block.call buff
34
- end
35
- end
36
- end
37
-
38
- def write_file path, append, &block
39
- # there's no support for :append in Net::SFTP, so we just mimic it
40
- if append
41
- attrs = attributes(path)
42
- data = if attrs
43
- if attrs[:file]
44
- os = ""
45
- read_file(path){|buff| os << buff}
46
- delete_file path
47
- os
48
- else
49
- raise "can't append to dir!"
50
- end
51
- else
52
- ''
53
- end
54
- write_file path, false do |writer|
55
- writer.call data
56
- block.call writer
57
- end
58
- else
59
- sftp.file.open fix_path(path), 'w' do |os|
60
- writer = -> buff {os.write buff}
61
- block.call writer
62
- end
63
- end
64
- end
65
-
66
- def delete_file remote_file_path
67
- sftp.remove! fix_path(remote_file_path)
68
- end
69
-
70
- # def move_file path
71
- # raise 'not supported'
72
- # end
73
-
74
-
75
- #
76
- # Dir
77
- #
78
- def create_dir path
79
- sftp.mkdir! path
80
- end
81
-
82
- def delete_dir path
83
- exec "rm -r #{path}"
84
- end
85
-
86
- def each path, &block
87
- sftp.dir.foreach path do |stat|
88
- next if stat.name == '.' or stat.name == '..'
89
- if stat.directory?
90
- block.call stat.name, :dir
91
- else
92
- block.call stat.name, :file
93
- end
94
- end
95
- end
96
-
97
- def efficient_dir_copy from, to
98
- from.storage.open_fs do |from_fs|
99
- to.storage.open_fs do |to_fs|
100
- if from_fs.local?
101
- sftp.upload! from.path, fix_path(to.path)
102
- true
103
- elsif to_fs.local?
104
- sftp.download! fix_path(to.path), from.path, :recursive => true
105
- true
106
- else
107
- false
108
- end
109
- end
110
- end
111
- end
112
-
113
- # def move_dir path
114
- # raise 'not supported'
115
- # end
116
-
117
-
118
- #
119
- # Special
120
- #
121
- def tmp &block
122
- tmp_dir = "/tmp/vfs_#{rand(10**3)}"
123
- if block
124
- begin
125
- create_dir tmp_dir
126
- block.call tmp_dir
127
- ensure
128
- delete_dir tmp_dir
129
- end
130
- else
131
- create_dir tmp_dir
132
- tmp_dir
133
- end
134
- end
135
-
136
- def local?; false end
137
- end
7
+ DEFAULT_OPTIONS = {
8
+ config: true
9
+ }
138
10
 
139
11
  def initialize options = {}
140
- super
141
- raise "ssh options not provided!" unless options[:ssh]
142
- raise "invalid ssh options!" unless options[:ssh].is_a?(Hash)
12
+ super
13
+ raise ":host not provided!" unless options[:host]
14
+ @options = DEFAULT_OPTIONS.merge options
15
+
16
+ # config_options = Net::SSH.configuration_for(options[:host])
17
+ # options = DEFAULT_OPTIONS.merge(config_options).merge options
18
+ # raise ":user not provided (provide explicitly or in .ssh/config)!" unless options[:user]
143
19
  end
144
20
 
145
21
 
@@ -160,10 +36,11 @@ module Vos
160
36
  end
161
37
  else
162
38
  unless @ssh
163
- ssh_options = self.options[:ssh].clone
164
- host = options[:host] || raise('host not provided!')
165
- user = ssh_options.delete(:user) || raise('user not provied!')
166
- @ssh = Net::SSH.start(host, user, ssh_options)
39
+ opt = self.options.clone
40
+ host = opt.delete :host #] || raise('host not provided!')
41
+ # user = options.delete(:user) || raise('user not provied!')
42
+
43
+ @ssh = Net::SSH.start(host, nil, opt)
167
44
  @sftp = @ssh.sftp.connect
168
45
  end
169
46
  end
@@ -177,13 +54,11 @@ module Vos
177
54
  end
178
55
  end
179
56
 
180
- def to_s; options[:host] end
181
-
182
-
57
+
183
58
  #
184
59
  # Vfs
185
60
  #
186
- include VfsStorage
61
+ include SshVfsStorage
187
62
  alias_method :open_fs, :open
188
63
 
189
64
 
@@ -209,6 +84,11 @@ module Vos
209
84
  end
210
85
 
211
86
 
87
+ #
88
+ # Micelaneous
89
+ #
90
+ def to_s; options[:host] end
91
+
212
92
  protected
213
93
  attr_accessor :ssh, :sftp
214
94
 
@@ -0,0 +1,135 @@
1
+ module Vos
2
+ module Drivers
3
+ module SshVfsStorage
4
+ #
5
+ # Attributes
6
+ #
7
+ def attributes path
8
+
9
+ stat = sftp.stat! fix_path(path)
10
+ attrs = {}
11
+ attrs[:file] = stat.file?
12
+ attrs[:dir] = stat.directory?
13
+ # stat.symlink?
14
+ attrs
15
+ rescue Net::SFTP::StatusException
16
+ {}
17
+ end
18
+
19
+ def set_attributes path, attrs
20
+ raise 'not supported'
21
+ end
22
+
23
+ #
24
+ # File
25
+ #
26
+ def read_file path, &block
27
+ sftp.file.open fix_path(path), 'r' do |is|
28
+ while buff = is.gets
29
+ block.call buff
30
+ end
31
+ end
32
+ end
33
+
34
+ def write_file path, append, &block
35
+ # there's no support for :append in Net::SFTP, so we just mimic it
36
+ if append
37
+ attrs = attributes(path)
38
+ data = if attrs
39
+ if attrs[:file]
40
+ os = ""
41
+ read_file(path){|buff| os << buff}
42
+ delete_file path
43
+ os
44
+ else
45
+ raise "can't append to dir!"
46
+ end
47
+ else
48
+ ''
49
+ end
50
+ write_file path, false do |writer|
51
+ writer.call data
52
+ block.call writer
53
+ end
54
+ else
55
+ sftp.file.open fix_path(path), 'w' do |os|
56
+ writer = -> buff {os.write buff}
57
+ block.call writer
58
+ end
59
+ end
60
+ end
61
+
62
+ def delete_file remote_file_path
63
+ sftp.remove! fix_path(remote_file_path)
64
+ end
65
+
66
+ # def move_file path
67
+ # raise 'not supported'
68
+ # end
69
+
70
+
71
+ #
72
+ # Dir
73
+ #
74
+ def create_dir path
75
+ sftp.mkdir! path
76
+ end
77
+
78
+ def delete_dir path
79
+ exec "rm -r #{path}"
80
+ end
81
+
82
+ def each path, &block
83
+ sftp.dir.foreach path do |stat|
84
+ next if stat.name == '.' or stat.name == '..'
85
+ if stat.directory?
86
+ block.call stat.name, :dir
87
+ else
88
+ block.call stat.name, :file
89
+ end
90
+ end
91
+ end
92
+
93
+ def efficient_dir_copy from, to
94
+ from.storage.open_fs do |from_fs|
95
+ to.storage.open_fs do |to_fs|
96
+ if from_fs.local?
97
+ sftp.upload! from.path, fix_path(to.path)
98
+ true
99
+ elsif to_fs.local?
100
+ sftp.download! fix_path(to.path), from.path, :recursive => true
101
+ true
102
+ else
103
+ false
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ # def move_dir path
110
+ # raise 'not supported'
111
+ # end
112
+
113
+
114
+ #
115
+ # Special
116
+ #
117
+ def tmp &block
118
+ tmp_dir = "/tmp/vfs_#{rand(10**3)}"
119
+ if block
120
+ begin
121
+ create_dir tmp_dir
122
+ block.call tmp_dir
123
+ ensure
124
+ delete_dir tmp_dir
125
+ end
126
+ else
127
+ create_dir tmp_dir
128
+ tmp_dir
129
+ end
130
+ end
131
+
132
+ def local?; false end
133
+ end
134
+ end
135
+ end
@@ -12,19 +12,19 @@ module Vos
12
12
  file '/etc/profile' ## file '/etc/environment'
13
13
  end
14
14
 
15
- def append_to_environment file, reload = true
16
- raise "#{file} must be an Entry" unless file.is_a? Vfs::Entry
17
-
18
- env_ext = dir '/etc/profile_ext'
19
-
20
- remote_file = env_ext[file.name]
21
- file.copy_to! remote_file
22
-
23
- require_clause = "source #{remote_file.path}"
24
- env_file.append "\n#{require_clause}\n" unless env_file.content.include? require_clause
25
-
26
- reload_env if reload
27
- end
15
+ # def append_to_environment file, reload = true
16
+ # raise "#{file} must be an Entry" unless file.is_a? Vfs::Entry
17
+ #
18
+ # env_ext = dir '/etc/profile_ext'
19
+ #
20
+ # remote_file = env_ext[file.name]
21
+ # file.copy_to! remote_file
22
+ #
23
+ # require_clause = "source #{remote_file.path}"
24
+ # env_file.append "\n#{require_clause}\n" unless env_file.content.include? require_clause
25
+ #
26
+ # reload_env if reload
27
+ # end
28
28
 
29
29
  def reload_env
30
30
  bash ". #{env_file.path}"
@@ -35,6 +35,15 @@ end
35
35
 
36
36
  module Vfs
37
37
  class File
38
-
38
+ def append_to_environment_of box, reload = true
39
+ raise "#{box} must be an Vos::Box" unless file.is_a? Vos::Box
40
+
41
+ copy_to! box.dir('/etc/profile_ext').file(name)
42
+
43
+ require_clause = "source #{remote_file.path}"
44
+ box.env_file.append "\n#{require_clause}\n" unless env_file.content.include? require_clause
45
+
46
+ box.reload_env if reload
47
+ end
39
48
  end
40
49
  end
data/lib/vos.rb CHANGED
@@ -4,12 +4,12 @@ require 'vos/gems'
4
4
 
5
5
  require 'open3'
6
6
 
7
-
8
7
  %w(
9
8
  support
10
9
 
11
10
  drivers/abstract
12
11
  drivers/local
12
+ drivers/ssh_vfs_storage
13
13
  drivers/ssh
14
14
 
15
15
  box/shell
data/readme.md CHANGED
@@ -1,122 +1,44 @@
1
- # Vfs - Virtual File System
1
+ # Vos - Virtual Operating System
2
2
 
3
- Handy and simple abstraction over any storage that can represent concept of File and Directory (or at least part of it).
4
- The Vfs for File System Storages is the same as ActiveRecord is for Relational Databases.
3
+ Small abstraction over Operating System, mainly it should be used in conjunction with [Virtual File System][vos] tool. Kind of
4
+ Capistrano but without extra stuff and more universal, not forcing You to follow 'The Rails Way'.
5
5
 
6
6
  Currently, there are following implementations available:
7
7
 
8
- - local file system
9
- - remote file system (over ssh)
10
-
11
- ## Goals
12
-
13
- - **handy, simple and clean** API.
14
- - **high performance** - the same as by using low-level storage API, there should be no extra calls **.
15
- - same API for different storages (Local FS, SSH, Hadoop, or any other , ...).
16
- - should work **simultaneously with different storages**.
17
- - small codebase, easy to extend by others.
18
- - simple storage-driver implementation, easy add new storage types (Hadoop DFS, LDAP, Document Oriented DB, In-Memory, ...).
19
-
20
- ** all methods should have the same performance as native system calls, except for :move and :rename. Right now they are implemented
21
- ASAP by using copy+destroy approach, will be fixed as soon as I'll have free time to do it.
8
+ - local os
9
+ - remote os (over ssh)
22
10
 
23
11
  ## Installation
24
12
 
25
- $ gem install vfs
26
13
  $ gem install vos
27
14
 
28
15
  ## Code samples:
29
- gem 'vfs' # Virtual File System
30
- require 'vfs'
31
-
32
16
  gem 'vos' # Virtual Operating System
33
17
  require 'vos'
34
18
 
35
-
36
19
  # Connections, let's deploy our 'cool_app' project from our local box to remote server
37
20
  server = Vfs::Box.new(host: 'cool_app.com', ssh: {user: 'me', password: 'secret'})
38
- me = '~'.to_dir
39
-
40
- cool_app = server['apps/cool_app']
41
- projects = me['projects']
42
-
43
-
44
- # Working with dirs, copying dir from any source to any destination (local/remote/custom_storage_type)
45
- projects['cool_app'].copy_to cool_app
46
-
47
-
48
- # Working with files
49
- dbc = cool_app.file('config/database.yml') # <= the 'config' dir not exist yet
50
- dbc.write("user: root\npassword: secret") # <= now the 'database.yml' and parent 'config' has been created
51
- dbc.content =~ /database/ # => false, we forgot to add the database
52
- dbc.append("\ndatabase: mysql") # let's do it
53
-
54
- dbc.update do |content| # and add host info
55
- content + "\nhost: cool_app.com "
56
- end
57
-
58
- projects['cool_app/config/database.yml']. # or just overwrite it with our local dev version
59
- copy_to! dbc
60
-
61
- # there are also streaming support (read/write/append), please go to specs for docs
62
-
63
-
64
- # Checks
65
- cool_app['config'].exist? # => true
66
- cool_app.dir('config').exist? # => true
67
- cool_app.file('config').exist? # => false
68
-
69
- cool_app['config'].dir? # => true
70
- cool_app['config'].file? # => false
71
-
72
-
73
- # Navigation
74
- config = cool_app['config']
75
- config.parent # => </apps/cool_app>
76
- config['../..'] # => </>
77
- config['../..'].dir? # => true
78
-
79
- cool_app.entries # => list of dirs and files, also support &block
80
- cool_app.files # => list of files, also support &block
81
- cool_app.dirs # => list of dirs, also support &block
82
-
83
-
84
- # For more please go to specs (create/update/move/copy/destroy/...)
85
-
86
- ## Integration with [Vos][vos] (Virtual Operating System)
87
21
 
22
+ server.bash 'ls'
88
23
  server['apps/cool_app'].bash 'rails production'
89
24
 
90
- For more details please go to [Vos][vos] project page.
91
-
92
- # Why?
93
-
94
- To easy my work: with local FS, remote FS (cluster management, deployment automation), and some specific systems like Hadoop DFS.
95
-
96
- Because the API of standard File/Dir/FileUtils classes are just terrible. And there's the reason for it - the goal of thouse tools
97
- is to provide 1-to-1 clone of underlying OS API, instead of provididing handy tool.
98
-
99
- And if you want to use remote FS - things are getting even worse and more complicated (Net::SSH & Net::SFTP use a little
100
- different API than local FS, and you has to remember all thouse little quirks).
25
+ For more details look also to [Virtual File System][vos] project.
26
+ Or checkout configuration I use to control my production servers [My Cluster][my_cluster] in conjunction with small
27
+ configuration tool [Cluster Management][cluster_management].
101
28
 
102
29
  ## TODO
103
30
 
104
31
  ### v 0.1 (all done)
105
32
 
106
- - bash & basic support for
107
- - File.append
108
- - list of entries/files/dirs
109
- - support for efficient copy for Local and SSH storages
110
-
111
- ### v 0.2 (not started)
112
-
113
- - efficient (not copy/destroy) versions of move_to, rename
114
- - glob search for directories: Dir['**/*.yml']
115
- - access via attributes and helpers for unix chmod
116
- - add storages: remote FS over HTTP.
33
+ - bash
34
+ - some handy shortcuts for ubuntu
35
+ - integration with Vos
117
36
 
118
- ### future
37
+ ### v 0.2
119
38
 
120
- - add storages: Hadoop DFS, MongoDB, Amazon S3
39
+ - process management (find/kill/filters/attributes)
40
+ - other os resources management (disk)
121
41
 
122
- [vfs]: http://github.com/alexeypetrushin/vfs
42
+ [vos]: http://github.com/alexeypetrushin/vos
43
+ [cluster_management]: http://github.com/alexeypetrushin/cluster_management
44
+ [my_cluster]: http://github.com/alexeypetrushin/my_cluster
@@ -1,4 +1,6 @@
1
1
  :ssh:
2
2
  :host: some_host.com
3
- :user: some_user
4
- :password: some_password
3
+
4
+ # optional, you can omit and use id_rsa key instead
5
+ # :user: some_user
6
+ # :password: some_password
data/spec/config.yml CHANGED
@@ -1,5 +1,2 @@
1
- :remote_driver:
2
- :host: universal.4ire.net
3
- :ssh:
4
- :user: root
5
- :password: privateprivate
1
+ :ssh_driver:
2
+ :host: universal.4ire.net
@@ -5,7 +5,7 @@ describe Vos::Drivers::Ssh do
5
5
  it_should_behave_like "vfs storage"
6
6
 
7
7
  before :all do
8
- @storage = @driver = Vos::Drivers::Ssh.new(config[:remote_driver])
8
+ @storage = @driver = Vos::Drivers::Ssh.new(config[:ssh_driver])
9
9
  @driver.open
10
10
  end
11
11
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 0
9
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Alexey Petrushin
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-02-08 00:00:00 +03:00
17
+ date: 2011-02-09 00:00:00 +03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -50,6 +50,7 @@ files:
50
50
  - lib/vos/drivers/local.rb
51
51
  - lib/vos/drivers/specification.rb
52
52
  - lib/vos/drivers/ssh.rb
53
+ - lib/vos/drivers/ssh_vfs_storage.rb
53
54
  - lib/vos/gems.rb
54
55
  - lib/vos/helpers/ubuntu.rb
55
56
  - lib/vos/support.rb