|
资源探索者

|
1#
大 中
小 发表于 2008-3-26 22:21 只看该作者
发段代码,关于SVN的管理操作的
介绍一下背景,因为是从事.Net开发的,但是业余情况下又喜欢 php?name=Ruby" onclick="tagshow(event)" class="t_tag">Ruby,所以在空闲的时候做了个这样的东西。
Ruby生了一段时间了,好多方法都是在IRB里用puts a.methods.sort这样一个一个看才知道的, 呵呵。
这段代码的主要作用是操作SVN服务端的ini文件来达到管理svn responstries的目的,支持几个指令: svn_project_list, svn_group_list, svn_memeber_list
svn_project_get, svn_group_get, svn_member_get
svn_project_create, svn_group_create, svn_member_create
svn_project_update, svn_group_update, svn_member_update
svn_project_delete, svn_group_delete, svn_member_delete
exit 服务端使用scoket server,在socket之间使用json序列化来传输对象,这是因为YAML在其它语言中支持不太好,例如C#.
但是Json就不一样了,有内置的支持。
冒昧的把代码贴出来,注释在代码里有一些,写得不好,请大家指正。
Model.rb# this file is a model file which includes several classes. SVNOperator: Module,
# Ini: Class, Base: Class, Project: Class, Directory: Class, Group: Class
# Member: Class
#
# this file is used as converting strings in 'ini' file to objects and provides
# a way to find, save and delete easily.
# basic operations: find(:all), find(name), instance.save, instance.delete
# this file needs 3 gems: ini, json and activesupport. run commands as following: gem install json -v 1.1.1
#
# author: ops
# email: [email]ops@ruby-lang.org.cn[/email]
# 2008-3-15
require 'ini'
require 'activesupport'
module SVNOperator
# this need to be called before calling other functions
# parameters: :authz and :passwd
# for now, only clear password format be supported.
def init opts = {}
@authz = opts[:authz] || 'authz.conf'
@passwd = opts[:passwd] || 'passwd.conf'
@i_authz = Ini.new @authz, :comment => '#'
@i_passwd = Ini.new @passwd, :comment => '#'
end
public
def authz
@i_authz
end
def passwd
@i_passwd
end
end
class Ini
# this method provides a way to modify the integrated Hash easily.
def []=(sec,hash)
@ini[sec] = hash
end
end
# this is a base class to provide common methods such as name
# accessor, json serialization etc..
class Base
extend SVNOperator
attr_accessor :name
def initialize name
@name = name
end
# this is an abstract method, needs to be implemented.
def delete
raise 'Not Implemented'
end
# since the json string generated from C# doesn't contains 'json_class' property,
# so we provide this method so that we know which class we need to instance.
def self.parse json_str
json_create JSON.parse(json_str)
end
# this method notices JSON module how to recover the object from JSON string.
def self.json_create(object)
obj = new
for key, value in object
next if key == 'json_class'
# the property name are camelized from C#.
obj.instance_variable_set "@#{key.underscore}", value
end
obj
end
def to_json(*a)
result = {
'json_class' => self.class.name
}
instance_variables.inject(result) do |r, name|
# we have to camelize the variable names so that C# can deserilize it.
r[name[1..-1].camelize] = instance_variable_get(name)
r
end
result.to_json(*a)
end
end
# this is a class represents a project.
class Project < Base
attr_accessor :directories
#if init_parameters equals true, then the code will find
# the sub directories from the ini file automatically.
def initialize name = nil, init_parameters = false
super name
self.directories ||= {}
if init_parameters
Base.authz.each_section do |sec|
self.directories.merge!({sec, Directory.find(sec)}) if sec =~ /^#{self.name}\:\//i
end
end
end
public
# the find method provide a way to find a project easily.
# :all parameter returns all projects.
# a string or symbol name returns the specify project.
# it always returns an instance with the specify name.
def self.find opts
case opts
when :all
Base.authz.sections.collect do |x|
Project.find $1 if x =~ /^(\w+)\:\/$/i
end - [nil]
when String, Symbol
Project.new opts.to_s, true
end
end
# save the project to ini file.
# this method has 2 functionalities. creating and updating.
def save
self.directories.each do |k, dir|
Base.authz[k] = dir.permissions
end
Base.authz.save and 'success'
end
# this provides a simple way to access the sub directories.
def [](name)
name = name.to_s
name = "#{self.name}:#{name}" if(name !~ /^#{self.name}/)
return directories[name]
end
# project can not be deleted for now.
def delete
raise 'Project cannot be removed.'
end
# since project has directories objects property, so we have to
# override the json_create method to deserilize the directories
# property.
def self.json_create(object)
obj = new
for key, value in object
next if key == 'json_class'
val = case value
when Hash # there is only one property is Hash.
value.each do |k, v|
value[k] = Directory.parse(v.to_json)
end
else
value
end
obj.instance_variable_set "@#{key.underscore}", val
end
obj
end
end
# this is a class represents a folder in ini file.
class Directory < Base
attr_accessor :owner, :permissions
#if init_parameters equals true, then the code will fill
# the permissions from the ini file automatically.
def initialize name = nil, init_parameters = false
super name
self.permissions ||= {}
if init_parameters
Base.authz[self.name].each do |k, v|
self.permissions.merge!({k, v})
end
end
end
# this method only supports find_by_name, :all isn't supported.
def self.find opts
case opts
when String,Symbol
Directory.new opts.to_s, true
end
end
end
# this class represents a group.
class Group < Base
attr_accessor :members
#if init_parameters equals true, then the code will fill
# the members from the ini file automatically.
def initialize name=nil, init_members = false
super name
self.members ||= []
self.members += (Base.authz['groups'][self.name] || '').split(',').map{|x| x.strip} if init_members
end
# the find method provides a way to find a group easily.
# :all parameter returns all groups.
# a string or symbol name returns the specify group.
# it always returns an instance with the specify name.
def self.find opts
case opts
when :all
Base.authz['groups'].keys.map do |k|
Group.find k
end
when String, Symbol
Group.new opts.to_s, true
else
raise ArgumentError
end
end
# save current instance to ini file.
def save
Base.authz['groups'][self.name] = members.join(', ')
Base.authz.save and 'success'
end
# delete current group and related data from ini file.
def delete
# group section
Base.authz['groups'].delete(self.name)
# project directory sections.
Base.authz.each_section do |sec|
next if sec == 'groups'
Base.authz[sec].each do |k, v|
Base.authz[sec].delete(k) if k == '@' + self.name
end
end
# save changes to ini file.
Base.authz.save and 'sucess'
end
end
# this class represents a member in ini file.
class Member < Base
attr_accessor :password
def initialize opt = {}
super opt[:name]
self.password = opt[:password]
end
# find method, by :all or by name(string, symbol).
def self.find opt
case opt
when :all
Base.passwd['users'].keys.map do |k|
Member.find k
end
when String, Symbol
Member.new :name => opt.to_s, :password => Base.passwd["users"][opt.to_s]
end
end
# save changes to ini file.
def save
Base.passwd['users'][self.name] = self.password
Base.passwd.save and 'success'
end
# remove current user from ini file.
# not only from the passwd also from the authz.
def delete
# remove from passwd.
Base.passwd['users'].delete(self.name)
# remove from the group section of authz.
Base.authz['groups'].each do |k, v|
# since the format is 'g_group = ops, abc, xyz', so the first step
# is split it to Array to strip every memeber, then reject the one which
# has the same name to self.name, then rejoin the Array by ',' and a space.
Base.authz['groups'][k] = v.split(',').map{|x| x.strip}.reject{|item| item == self.name}.join(', ')
end
# remove from other project directories.
Base.authz.each_section do |sec|
next if sec == 'groups'
Base.authz[sec].each do |k, v|
Base.authz[sec].delete(k) if k == self.name
end
end
# save to ini file.
Base.passwd.save
Base.authz.save and nil
end
end
# this class is used to send to client to communicate.
class Message
attr_accessor :message_type, :text, :refresh_required
# message_type: normal or error.
# refresh_required means if we do something to ini file and needs to refresh the data.
# text: an array, a base64 string from JSON string.
def initialize opts = {}
self.message_type = opts[:message_type] || :normal
self.refresh_required = opts[:refresh_required] || false
self.text = opts[:text] || []
end
# since we need all messages into one line, so we use base64 encoding and replace all '\r\n' to none.
def to_s
"#{self.message_type.to_s} #{self.refresh_required.to_s} #{Base64.encode64(self.text.to_json).gsub(/\n/,'')}\n"
end
end
if __FILE__ == $0
Base.init :authz => 'conf/authz.conf', :passwd => 'conf/passwd.conf'
Project.find "Project1"
Member.find :ops
end
|