# trac-admin initenv # trac-admin /var/trac/p1 initenv "My Project" "sqlite:db/trac.db" /var/svn/p1 /usr/share/trac/templates # # test = DRbObject.new(nil, 'druby://localhost:8887') # test.on_create('trac', 'breakout') # class name, project name # test.on_create('trac', 'breakout') require 'control_tool' require 'subversion' require 'hg' require 'git' require 'inifile' require 'yaml' class Trac < ControlTool TRAC = 'trac' attr_accessor :svn, :vcs, :destination_dir, :project_name, :template_dir attr_accessor :base_dir, :trac_dir, :svn_dir, :trac_ini def initialize self.svn = Subversion.new self.vcs = svn self.base_dir = File.expand_path "#{$base_dir}/tmp/tools" self.trac_dir = "#{base_dir}/trac" self.svn_dir = "#{base_dir}/svn" self.template_dir = trac_dir self.vcs.template_dir = svn_dir end def prepare_template mkdir_p base_dir unless FileTest.directory?(base_dir) rm_rf([trac_dir, svn_dir]) self.destination_dir = trac_dir # prepare svn template vcs.template_dir = svn_dir vcs.prepare_template # prepare trac template args = "initenv \"#{trac_dir}\" \"sqlite:db/trac.db\" svn #{svn_dir} #{$config[TRAC]['templates_dir']}" run_trac_admin(args) # disallow plugin submission chmod(0555, "#{trac_dir}/plugins") old_base_dir = $config[TRAC]['base_dir'] begin $config[TRAC]['base_dir'] = base_dir self.project_name = 'trac' configure_trac_db ensure $config[TRAC]['base_dir'] = old_base_dir end end # Create a trac tool with version control system: subversion or mercurial # # +setttings+ hash should contains below keys: # project_url string, space wiki name, it is used to create directories that will hold tools # space_url string, used by trac in templates to link to space # space_name space title, will be used for trac project name # hg boolean, if true, it will create mercurial repository # secret_key string, used to authentificate users # allow_anonymous boolean, allow anonymous users to view tools, for write access, valid login is required # copy_vcs_from string, vcs directory from where new repo will be copied # svn_archive_file string, tar.gz file from control center tmp dir that will be unpacked and used as svn template def on_create(settings) project_url = settings['project_url'] self.project_name = settings['space_name'] $log.info "New trac tool: '#{project_name}'" secretKey = settings['secret_key'] allow_anonymous = settings['allow_anonymous'] self.destination_dir = dest_dir(project_url) if settings['hg'] self.vcs = Mercurial.new elsif settings['vcs'] == "git" self.vcs = Git.new end self.vcs.config = config vcs_url = vcs.on_create(settings) settings['svn_dir'] = vcs.vcs_dir(project_url) settings['trac_url'] = 'http://' + $config['server'] + '/' + project_url # copy from template dir if !FileTest.directory?(destination_dir) FileUtils.cp_r(template_dir, destination_dir) write_conf_file(destination_dir, settings) run_trac_admin("resync") return :trac_url => trac_url(project_url), :vcs_url => vcs_url else $log.error("Destination directory exists: #{destination_dir}") end return nil end def run_trac_admin args run("trac-admin #{destination_dir} #{args}") end def update_permissions(project_name, allow_anonymous = false) self.project_name = project_name load_trac_ini vcs.update_permissions(project_name, allow_anonymous) end def on_destroy(project_url) self.project_name = project_url backup_dir = $config['backup_dir'] + '/trac' Dir.mkdir(backup_dir) unless FileTest.directory?(backup_dir) if test(?d, dest_dir(project_url)) load_trac_ini suffix = "-#{Time.now.to_i}" mv dest_dir(project_url), "#{backup_dir}/" + fix_project_name(project_url) + suffix, :force => true vcs.on_destroy(project_url, suffix) end end def do_backup(settings) dir_name = settings['dir_name'] settings["bucket"] = "%s.%s" % [$config['amazon_base_bucket'], dir_name] backup_dir = $config['backup_dir'] + '/c-trac' svn_dir = vcs.dest_dir(dir_name) trac_dir = dest_dir(dir_name) nr = Time.now.day if FileTest.directory?(svn_dir) && FileTest.directory?(trac_dir) Dir.mkdir(backup_dir, 0755) unless FileTest.directory?(backup_dir) settings["send_files"] = ["#{backup_dir}/trac-#{dir_name}-#{nr}.tar.gz", "#{backup_dir}/svn-#{dir_name}-#{nr}.dump.gz"] run("cd #{trac_dir} && #{TAR} czf #{settings["send_files"][0]} .") run("svnadmin -q dump #{svn_dir} | gzip -9 >#{settings["send_files"][1]}") # TODO hg & git backup require 's3_backup' $log.info "Start s3 backup" if Breakout::S3backup.new.send_files(settings) settings["send_files"].map {|f| File.delete f} $log.info "Finished s3 backup" return true end else $log.error("At least one tool dir does not exists: %s, %s" % [svn_dir, trac_dir]) end false end def toggle_ticket_wiki_system(settings) self.project_name = settings[:dir_name] self.destination_dir = dest_dir(settings[:dir_name]) load_trac_ini disable_modules(trac_ini, settings[:mode]) trac_ini.write true end def disable_modules(ini, mode = :off) if mode == :on ini_value = "enabled " ini['trac']['default_handler'] = "WikiModule" else ini['trac']['default_handler'] = "BrowserModule" ini_value = "disabled" end ini['components'] ||= {} %w{ trac.ticket.api.ticketsystem trac.ticket.notification.ticketnotificationsystem trac.ticket.query.querymodule trac.ticket.query.ticketquerymacro trac.ticket.report.reportmodule trac.ticket.roadmap.milestonemodule trac.ticket.roadmap.roadmapmodule trac.ticket.web_ui.newticketmodule trac.ticket.web_ui.ticketmodule trac.wiki.api.wikisystem trac.wiki.web_ui.wikimodule }.each do |component| ini['components'][component] = ini_value end end def upload_pub_keys(settings) self.settings = settings self.project_name = settings[:dir_name] self.destination_dir = dest_dir(settings[:dir_name]) load_trac_ini vcs.upload_pub_keys end ############################################################################################ def dest_dir(project_name) destination_dir = $config[TRAC]['base_dir'] File.expand_path(destination_dir + "/" + fix_project_name(project_name)) end def write_conf_file(project_home, settings) ini = IniFile.new ini['header_logo'] = {'link' => settings['space_url']} ini['trac'] = {'repository_dir' => settings['svn_dir']} ini['project'] = {'url' => settings['space_url'], 'name' => settings['space_name']} ini['ticket'] = {'default_priority' => 'normal', 'default_severity' => 'normal'} if settings['hg'] ini['trac']['repository_type'] = 'hg' ini['components'] = {'tracvc.hg.*' => 'enabled'} # for Trac 0.10.x #ini['components'] = {'tracext.hg.*' => 'enabled'} # for Trac 0.11 elsif settings['vcs'] == 'git' # check http://trac-hacks.org/wiki/GitPlugin for more options ini['trac']['repository_type'] = 'git' ini['components'] = {'gitplugin.*' => 'enabled'} # for Trac 0.10.x #ini['components'] = {'tracext.git.*' => 'enabled'} # for Trac 0.11 end disable_modules(ini, settings["trac_modules"]) if settings["trac_modules"] ini.write(trac_conf(project_home)) end def trac_conf(project_home) project_home + "/conf/trac.ini" end def trac_url(project_name) 'http://' + $config['server'] + '/' + project_name end def disk_space(settings) dir = dest_dir(settings['dir_name']) dir_disk_space(dir) + vcs.disk_space(settings) end def update_svn_settings(settings) dir = settings[:dir_name] hook_file = vcs.dest_dir(dir) + "/hooks/breakout.vars.sh" File.open(hook_file, "w") do |f| f.write settings[:var_txt] end File.chmod 0755, hook_file end def rename_dir(old_name, new_name) self.destination_dir = dest_dir(old_name) if test(?d, destination_dir) File.rename destination_dir, dest_dir(new_name) self.project_name = new_name load_trac_ini vcs.rename_dir(old_name, new_name) trac_ini['trac']['repository_dir'] = vcs.dest_dir(new_name) trac_ini.write { :trac_url => trac_url(new_name), :vcs_url => vcs.url(new_name) } else nil end end def read_file(settings) self.destination_dir = dest_dir(settings[:dir_name]) file_path = File.join(destination_dir, settings[:file_path].gsub('/../', '')) get_file_data(file_path, settings[:offset]) end def get_file_data(file_path, offset) data = nil $log.info " file #{file_path}" if test(?f, file_path) f = File.new(file_path) f.seek(offset, IO::SEEK_SET) data = f.read(1024 * 1024 * 5) # 5Mb f.close end data end def read_tmp_file(file_name, offset) file_path = File.join(tmp_dir, file_name) get_file_data(file_path, offset) end # Write a file in tmp directory that will be later used for svn import # if file exists, data will be appended def write_file(file_name, data) File.open(File.join(tmp_dir, file_name), "a") do |f| f.write(data) end end def resync_trac(settings) self.destination_dir = dest_dir(settings[:dir_name]) run_trac_admin('resync') end def configure_trac_db run sqlite_util_cmd("init_db") end def on_reset_permissions(settings) self.destination_dir = dest_dir(settings[:dir_name]) run sqlite_util_cmd("reset_perms") end def load_trac_ini self.trac_ini = IniFile.new(trac_conf(dest_dir(project_name))) if trac_ini['trac']['repository_type'] == "hg" self.vcs = Mercurial.new elsif trac_ini['trac']['repository_type'] == "git" self.vcs = Git.new end self.vcs.config = config self.vcs.settings = settings end def milestones(project_name) self.destination_dir = dest_dir(project_name) if test ?d, destination_dir rows = [] cmd = sqlite_util_cmd("export_milestones") $log.info(cmd) IO::popen(cmd) do |io| rows = YAML::load(io.read) end rows else false end end def set_milestones(project_name, mstones) self.destination_dir = dest_dir(project_name) IO::popen(sqlite_util_cmd("import_milestones"), "w") do |io| io.write YAML::dump(mstones) end end def sqlite_util_cmd command File.dirname(__FILE__) + "/trac_db_util.rb #{destination_dir} -#{command}" end end