原田です。今回はSubmin 2系のデータベースをRepoMatの設定ファイルに変換するスクリプトについてお話しします。
RepoMatとは、当社が開発したSubminと互換性のあるSubversionリポジトリ管理インターフェイスです。こちらのブログでもご紹介しています。昨年11月にMy Subversionを新システムに切り替えました。旧システムとデータの互換性があるので、Submin 1.2系の設定ファイルはそのまま利用できます。
今回会社から「Submin 2系のデータをMy Subversionで使用したい」という要望を頂きました。Submin 2系はSubversion 1.2系とは異なり、データベースで各種情報を管理しているのでそのままではMy Subverionで使用することはできません。
データベースをRepoMatの設定ファイルとして使用するためにデータ変換スクリプト(Ruby)を作成することにしました。
Submin2のデータがどのような構造なのか知っておく必要があります。データベースはSQLite、まずテーブル構造を確認しました。
# sqlite3 submin.db
sqlite> .schema
CREATE TABLE users
(
id integer primary key autoincrement,
name text not null unique,
password text not null,
email text,
fullname text,
is_admin bool default 0
);
CREATE TABLE groups
(
id integer primary key autoincrement,
name text not null unique
);
CREATE TABLE group_members
(
groupid integer not null references groups(id),
userid integer not null references user(id),
PRIMARY KEY(groupid, userid)
);
CREATE TABLE options
(
key text primary key not null unique,
value text not null
);
CREATE TABLE notifications
(
userid integer references users(id),
repository text,
allowed bool default 0,
enabled bool default 0,
PRIMARY KEY(userid, repository)
);
CREATE TABLE permissions
(
repository text,
repositorytype text,
path text not null,
subjecttype text not null, -- user, group or all
subjectid integer, -- only null if subjecttype is all
type text default '', -- '', 'r' or 'rw'
UNIQUE(repository, path, subjecttype, subjectid)
);
CREATE TABLE managers
(
id integer primary key autoincrement,
managertype text not null, -- user or group
managerid integer,
objecttype text not null, -- group or repository
objectid integer, -- groupid if objecttype is group
objectname text -- name of repository if objecttype is repository
);
CREATE TABLE ssh_keys
(
id integer primary key autoincrement,
userid integer not null references user(id),
title text,
ssh_key text not null
);
CREATE TABLE password_reset (
userid integer not null references user(id) primary key, -- valid for this user
expires integer not null, -- this entry expires at Unix Time
key text not null -- random secret
);
CREATE TABLE sessions
(
key text not null primary key not null unique,
value text not null -- pickled dictionary
);
sqlite>
上記テーブル構造と登録データを確認したところ、データ変換に必要なテーブルは一部のようです。
SQLiteのデータを設定ファイル(テキストファイル)に変換するのですが、今回テーブルに対するデータアクセスはActive Recordに任せることにしました。
class Option < ActiveRecord::Base
self.primary_key = :key
end
class Notification < ActiveRecord::Base
self.primary_key = [:userid, :repository]
end
class User < ActiveRecord::Base
self.primary_key = :id
has_many :group_user_relationships, class_name: "GroupMember", foreign_key: "userid"
has_many :groups, through: :group_user_relationships
has_many :notifications, class_name: "Notification", foreign_key: "userid"
def notifications_allowed_repos
notifications.where(allowed: 1).pluck(:repository)
end
def notifications_enabled_repos
notifications.where(enabled: 1).pluck(:repository)
end
end
class Group < ActiveRecord::Base
self.primary_key = :id
has_many :group_user_relationships, class_name: "GroupMember", foreign_key: "groupid"
has_many :members, through: :group_user_relationships
end
class GroupMember < ActiveRecord::Base
self.primary_key = [:groupid, :userid]
belongs_to :group, class_name: "Group", foreign_key: "groupid"
belongs_to :member, class_name: "User", foreign_key: "userid"
end
class Permission < ActiveRecord::Base
self.primary_key = [:repository, :repositorytype, :path, :subjecttype, :subjectid]
self.inheritance_column = :_type_disabled
scope :svn, ->{ where(repositorytype: 'svn') }
scope :order_repo_path, ->{ order(repositorytype: :asc, repository: :asc, path: :asc, subjecttype: :asc, subjectid: :asc) }
belongs_to :subject_group, class_name: "Group", foreign_key: "subjectid", optional: true
belongs_to :subject_user, class_name: "User", foreign_key: "subjectid", optional: true
def group?
subjecttype == 'group'
end
def user?
subjecttype == 'user'
end
def all?
subjecttype == 'all'
end
def subject
if group?
subject_group
elsif user?
subject_user
else
nil
end
end
end
上記Active Recordクラスを使用した設定ファイル(htpasswd, userproperties.conf, authz)へのデータ変換処理は以下のとおりです。
# Generate htpasswd
File.open("#{ENV['OUTDIR']}/htpasswd", 'w') do |f|
User.find_each do |user|
f.puts "#{user.name}:#{user.password}"
end
end
# Generate userproperties.conf
File.open("#{ENV['OUTDIR']}/userproperties.conf", 'w') do |f|
User.find_each do |user|
f.puts "[#{user.name}]"
f.puts "fullname = #{user.fullname}"
f.puts "email = #{user.email}"
f.puts "notifications_allowed = #{user.notifications_allowed_repos.join(',')}"
f.puts "notifications_enabled = #{user.notifications_enabled_repos.join(',')}"
f.puts
end
end
# Generate authz
File.open("#{ENV['OUTDIR']}/authz", 'w') do |f|
f.puts "[groups]"
Group.find_each do |group|
members = group.members.pluck(:name).join(',')
f.puts "#{group.name} = #{members}"
end
f.puts
perms = {}
Permission.svn.order_repo_path.find_each do |perm|
key = "#{perm.repository}:#{perm.path}"
perms[key] ||= []
role =
if perm.all?
'*'
elsif perm.group?
"@#{perm.subject.name}"
else
perm.subject.name
end
perms[key] << "#{role} = #{perm.type}"
end
perms.each do |repo_path, arr|
f.puts "[#{repo_path}]"
arr.each do |role_perm|
f.puts role_perm
end
f.puts
end
end
今回はSubmin 2.0.3のデータベースを設定ファイルに変換するスクリプトを作成しましたが、マイナーバージョンの違いによりテーブル構造が変更になっている場合があります。本ブログの内容と同様のことをご検討の方はデータベースのバージョン、テーブル構造を確認してからスクリプトを作成してください。
sqlite> select * from options where key = 'database_version';
+------------------+-------+
| key | value |
+------------------+-------+
| database_version | 7 |
+------------------+-------+
【スタッフ募集中】
弊社ではAWSを活用したソリューションの企画・設計・構築・運用や、Ruby on Rails・JavaScriptフレームワークなどを使用したアプリケーション開発を行うスタッフを募集しています。採用情報の詳細
弊社での勤務に関心をお持ちの方は、知り合いの弊社社員・関係者を通じてご連絡ください。
Subversionのホスティングサービス「My Subversion」を新システムに切り替えた My Subversion」の新システムへの切り替えによりサービス提供用システムを一新することができました。 |
|
My Redmineのサポート業務で最近活用している機能 お客様からのお問い合わせ対応にRedmineを使っています。 |
|
来るRedmine 6.0でのデフォルトテーマの改善状況:見やすく、読みやすく リリースが近いRedmine 6.0では、色の変更とベクターアイコンへの移行により見やすくなり、フォントとフォントサイズ、行間、余白の調整により読みやすくなります。 |
|
ruby/ruby.wasm を使って Redmine をブラウザ内で動かす話 Ruby on Rails アプリケーションである Redmine の Wasm 化を試しました。 |
|
続たのしい自作キーボード〜PiPi GherkinビルドログとRedmineショートカットキー〜 自作キーボード「PiPi Gherkin」を作ってみました。Redmineの便利なショートカットキーを割り当てることもできます。 |
「しまね移住の先輩セミナー ~未経験からはじめるIT移住~」に弊社社員の呂 勝男が登壇 「しまね移住の先輩セミナー ~未経験からはじめるIT移住~」に、ファーエンドテクノロジー社員の呂勝男が登壇いたします。 |
|
オープンソースカンファレンス2025 Osakaに弊社代表の前田が登壇(ブース出展あり) 2025年1月25日に開催されるオープンソースカンファレンス2025 Osakaで、弊社代表の前田によるセミナー発表とブース出展を行います。 |
|
プロジェクト管理ツール「RedMica」バージョン 3.1.0をリリース Redmine互換のオープンソースソフトウェア ファーエンドテクノロジー株式会社は、2024年11月19日(日本時間)、Redmine互換のプロジェクト管理ソフトウェア「RedMica 3.1.0」をリリースしました。 |
|
プロジェクト管理ツールRedmineのクラウドサービス「My Redmine」の海外向けサービス「My Redmine Global Edition」の提供を開始 「My Redmine」の海外向けサービスとして、新たに「My Redmine Global Edition」の提供を開始しました。 |
|
Redmineの最新情報をメールでお知らせする「Redmine News」配信中 新バージョンやセキュリティ修正のリリース情報、そのほか最新情報を迅速にお届け |