Skip to content

Instantly share code, notes, and snippets.

@tmtm
Last active March 3, 2019 02:14
Show Gist options
  • Save tmtm/10392069 to your computer and use it in GitHub Desktop.
Save tmtm/10392069 to your computer and use it in GitHub Desktop.
Postfix の tarball から Git リポジトリを作るスクリプト
# -*- coding: utf-8 -*-
# Postfix はソースが公開されてはいるもののリポジトリが公開されていない
# ので、公開されている tarball から git リポジトリを作るためのスクリプ
# トを作ってみました。
#
# 次の場所から、postfix-*.tar.gz を持ってきて、どっかに置いておきます。
# * ftp://ftp.porcupine.org/mirrors/project-history/postfix/official/
# * ftp://ftp.porcupine.org/mirrors/postfix-release/official/
# tar.gz ファイルの日付の古い順に処理するので、ファイルの日付までコピー
# できるツールを使って取得ください。
#
# 例:
# wget -nc -r -nH --cut-dirs=4 ftp://ftp.porcupine.org/mirrors/project-history/postfix/official/postfix-\*.tar.gz
# wget -nc -r -nH --cut-dirs=3 ftp://ftp.porcupine.org/mirrors/postfix-release/official/postfix-\*.tar.gz
#
# 第一引数に tar.gz を置いたディレクトリ、第二引数に作成する Git リポジ
# トリのパスを指定してこのスクリプトを実行すると Git リポジトリを作成し
# ます。第二引数のリポジトリが存在しない場合は自動的に作成するので、存
# 在しないディレクトリを指定すればOKです。
require 'tempfile'
require 'tmpdir'
require 'date'
class Version
attr_reader :str
attr_reader :ver
def initialize(str)
if str =~ /\.tar\.gz\z/
@str = File.basename(str, '.tar.gz').split(/-/, 2).last
else
@str = str
end
if @str =~ /\A\d{8}/
@ver = [0, 0, 0, 0, @str]
else
@ver = @str.split(/\./).map{|_| _ =~ /\A\d+\z/ ? _.to_i : _}
end
end
def ==(other)
@ver == other.ver
end
def <(other)
(@ver <=> other.ver) < 0
end
def >(other)
(@ver <=> other.ver) > 0
end
def <=>(other)
@ver <=> other.ver
end
def branch_name
@ver.first(2).join('.')
end
end
def system!(*args)
puts args.join(' ') if $VERBOSE
system(*args) or raise "#{args.first}: failed"
end
class Git
def initialize(repos)
@repos = repos
unless File.exist? repos
init
initial_commit
end
end
def init
command '--bare', 'init'
end
def initial_commit
Dir.mktmpdir do |tmpdir|
command '--bare', '--work-tree', tmpdir, 'commit', '--allow-empty', '-m' 'Initial commit'
end
end
def create_branch(new, src)
puts "create branch #{new} from #{src}"
command 'branch', new, src
end
def change_current_branch(branch)
puts "change to #{branch}"
Dir.mktmpdir do |dir|
command '--work-tree', dir, 'checkout', '-q', branch
end
end
def tags
`git --git-dir #{@repos} tag`.lines.map(&:chomp)
end
def command(*args)
system! 'git', '--git-dir', @repos, *args
end
end
class MakePostfixGitRepos
def initialize(tarballdir, gitrepos)
@tarballdir = tarballdir
@git = Git.new(gitrepos)
@versions = []
end
def main
tmpf = Tempfile.new('make-postfix-git-repos')
@git.command 'log', '--all', '--date-order', '--format=format:%d', out: tmpf
tmpf.rewind
tmpf.each_line do |line|
line.slice(/\((.*)\)/, 1).split(/, /).each do |n|
if n =~ /\Atag: (.*)/
@versions.push Version.new($1)
end
end
end
@versions = @versions.sort.reverse
files = Dir.glob("#{@tarballdir}/postfix-*.tar.gz").sort_by do |path|
[File.stat(path).mtime, Version.new(path)]
end
prev = @versions.first
files.each do |fname|
next if fname =~ /beta|RC|-\d\d\d\d\d\d\d\d/
puts fname if $VERBOSE
ver = Version.new(fname)
next if @versions.include? ver
if prev && ver < prev && ver.str != '1.1.0'
p = @versions.find{|v| ver > v}
branch = p.branch_name
begin
@git.change_current_branch branch
rescue
@git.create_branch branch, p.str
@git.change_current_branch branch
end
commit fname
@git.change_current_branch 'master'
next
end
prev = ver
commit fname
@versions.unshift ver
end
end
def commit(fname)
ver = Version.new(fname)
date = File.stat(fname).mtime.strftime('%Y-%m-%dT00:00:00')
Dir.mktmpdir do |tmpdir|
system! 'tar', 'xpCf', tmpdir, fname
dir = Dir.glob("#{tmpdir}/*").first
return if dir =~ /snapshot/
Dir.chdir dir do
@git.command '--work-tree=.', 'add', '--all', '.'
@git.command '--work-tree=.', 'commit', '-q', '--date', date, '-m', File.basename(fname, '.tar.gz')
@git.command 'tag', ver.str
end
end
end
end
MakePostfixGitRepos.new(*ARGV).main if __FILE__ == $0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment