From b44411fb5399f75939a57f0ccc8166d06fa8ba6f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 1 Jun 2015 22:58:39 +0200 Subject: Use gitnamespaces for efficient storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using one Git repository per package, use a single large object storage for space efficiency. The refs of the individual package bases are divided using gitnamespaces(7) which allows for exposing each namespace as an independent repository easily. Also, git-serve is modified to create a branch for each package, allowing to browse the large repository with cgit. Helped-by: Florian Pritz Helped-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- INSTALL | 33 ++++++++++++++-- conf/cgitrc.proto | 4 +- conf/config.proto | 4 +- scripts/git-integration/gen-templates.py | 29 -------------- scripts/git-integration/git-serve.py | 68 ++++++++++++++++---------------- scripts/git-integration/git-update.py | 7 ++-- scripts/git-integration/init-repos.py | 50 ----------------------- upgrading/4.0.0.txt | 11 ++---- web/template/pkg_details.php | 6 +-- 9 files changed, 80 insertions(+), 132 deletions(-) delete mode 100755 scripts/git-integration/gen-templates.py delete mode 100755 scripts/git-integration/init-repos.py diff --git a/INSTALL b/INSTALL index 2a67f9b..026d4b9 100644 --- a/INSTALL +++ b/INSTALL @@ -19,13 +19,17 @@ Setup on Arch Linux $ mysql -uaur -p AUR 0) def list_repos(user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, @@ -57,19 +52,17 @@ def list_repos(user): print((' ' if row[1] else '*') + row[0]) db.close() -def setup_repo(repo, user): - if not re.match(repo_regex, repo): - die('%s: invalid repository name: %s' % (action, repo)) +def setup_repo(pkgbase, user): + if not re.match(repo_regex, pkgbase): + die('%s: invalid repository name: %s' % (action, pkgbase)) + if pkgbase_exists(pkgbase): + die('%s: package base already exists: %s' % (action, pkgbase)) db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, unix_socket=aur_db_socket) cur = db.cursor() - cur.execute("SELECT COUNT(*) FROM PackageBases WHERE Name = %s ", [repo]) - if cur.fetchone()[0] > 0: - die('%s: package base already exists: %s' % (action, repo)) - cur.execute("SELECT ID FROM Users WHERE Username = %s ", [user]) userid = cur.fetchone()[0] if userid == 0: @@ -77,7 +70,7 @@ def setup_repo(repo, user): cur.execute("INSERT INTO PackageBases (Name, SubmittedTS, ModifiedTS, " + "SubmitterUID, MaintainerUID) VALUES (%s, UNIX_TIMESTAMP(), " + - "UNIX_TIMESTAMP(), %s, %s)", [repo, userid, userid]) + "UNIX_TIMESTAMP(), %s, %s)", [pkgbase, userid, userid]) pkgbase_id = cur.lastrowid cur.execute("INSERT INTO CommentNotify (PackageBaseID, UserID) " + @@ -86,8 +79,11 @@ def setup_repo(repo, user): db.commit() db.close() - repo_path = repo_base_path + '/' + repo + '.git/' - pygit2.init_repository(repo_path, True, 48, template_path=template_path) + repo = pygit2.Repository(repo_path) + repo.create_reference('refs/heads/' + pkgbase, + 'refs/namespaces/' + pkgbase + '/refs/heads/master') + repo.create_reference('refs/namespaces/' + pkgbase + '/HEAD', + 'refs/namespaces/' + pkgbase + '/refs/heads/master') def check_permissions(pkgbase, user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, @@ -125,19 +121,25 @@ action = cmdargv[0] if action == 'git-upload-pack' or action == 'git-receive-pack': if len(cmdargv) < 2: die_with_help("%s: missing path" % (action)) - path = repo_base_path.rstrip('/') + cmdargv[1] - if not repo_path_validate(path): + + path = cmdargv[1].rstrip('/') + if not path.startswith('/') or not path.endswith('.git'): die('%s: invalid path: %s' % (action, path)) - pkgbase = repo_path_get_pkgbase(path) - if not os.path.exists(path): + pkgbase = path[1:-4] + if not re.match(repo_regex, pkgbase): + die('%s: invalid repository name: %s' % (action, repo)) + + if not pkgbase_exists(pkgbase): setup_repo(pkgbase, user) + if action == 'git-receive-pack': if not check_permissions(pkgbase, user): die('%s: permission denied: %s' % (action, user)) + os.environ["AUR_USER"] = user - os.environ["AUR_GIT_DIR"] = path os.environ["AUR_PKGBASE"] = pkgbase - cmd = action + " '" + path + "'" + os.environ["GIT_NAMESPACE"] = pkgbase + cmd = action + " '" + repo_path + "'" os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd) elif action == 'list-repos': if len(cmdargv) > 1: diff --git a/scripts/git-integration/git-update.py b/scripts/git-integration/git-update.py index 161d42f..2c15912 100755 --- a/scripts/git-integration/git-update.py +++ b/scripts/git-integration/git-update.py @@ -19,6 +19,8 @@ aur_db_user = config.get('database', 'user') aur_db_pass = config.get('database', 'password') aur_db_socket = config.get('database', 'socket') +repo_path = config.get('serve', 'repo-path') + def extract_arch_fields(pkginfo, field): values = [] @@ -166,12 +168,11 @@ sha1_new = sys.argv[3] user = os.environ.get("AUR_USER") pkgbase = os.environ.get("AUR_PKGBASE") -git_dir = os.environ.get("AUR_GIT_DIR") if refname != "refs/heads/master": die("pushing to a branch other than master is restricted") -repo = pygit2.Repository(git_dir) +repo = pygit2.Repository(repo_path) walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) if sha1_old != "0000000000000000000000000000000000000000": walker.hide(sha1_old) @@ -245,6 +246,6 @@ db.close() pkglist = list(srcinfo.GetPackageNames()) if len(pkglist) > 0: - with open(git_dir + '/description', 'w') as f: + with open(repo_path + '/description', 'w') as f: pkginfo = srcinfo.GetMergedPackage(pkglist[0]) f.write(pkginfo['pkgdesc']) diff --git a/scripts/git-integration/init-repos.py b/scripts/git-integration/init-repos.py deleted file mode 100755 index 5c4fcfe..0000000 --- a/scripts/git-integration/init-repos.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/python3 - -import configparser -import mysql.connector -import os -import pygit2 -import re -import shlex -import sys - -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../../conf/config") - -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') - -repo_base_path = config.get('serve', 'repo-base') -repo_regex = config.get('serve', 'repo-regex') -template_path = config.get('serve', 'template-path') - -def die(msg): - sys.stderr.write("%s\n" % (msg)) - exit(1) - -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket) -cur = db.cursor() - -cur.execute("SELECT Name FROM PackageBases") -repos = [row[0] for row in cur] -db.close() - -for repo in repos: - if not re.match(repo_regex, repo): - die('invalid repository name: %s' % (repo)) - -i = 1 -n = len(repos) - -for repo in repos: - print("[%s/%d] %s" % (str(i).rjust(len(str(n))), n, repo)) - - repo_path = repo_base_path + '/' + repo + '.git/' - pygit2.init_repository(repo_path, True, 48, template_path=template_path) - - i += 1 diff --git a/upgrading/4.0.0.txt b/upgrading/4.0.0.txt index 9a4a807..ed39c9f 100644 --- a/upgrading/4.0.0.txt +++ b/upgrading/4.0.0.txt @@ -9,18 +9,15 @@ afterwards. ALTER TABLE Users ADD COLUMN SSHPubKey VARCHAR(4096) NULL DEFAULT NULL; ---- -2. Create a new user and configure the sshd as described in INSTALL. +2. Create a new user and configure Git/SSH as described in INSTALL. -3. Run gen-templates.py to initialize the Git repository template. Create a -directory for the Git repositories and run init-repos.py to initialize them. - -4. Reset the packager field of all package bases: +3. Reset the packager field of all package bases: ---- UPDATE PackageBases SET PackagerUID = NULL; ---- -5. Create a new table for package base co-maintainers: +4. Create a new table for package base co-maintainers: ---- CREATE TABLE PackageComaintainers ( @@ -34,4 +31,4 @@ CREATE TABLE PackageComaintainers ( ) ENGINE = InnoDB; ---- -6. (optional) Setup cgit to browse the Git repositories via HTTP. +5. (optional) Setup cgit to browse the Git repositories via HTTP. diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index c1c07ba..ceece87 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -82,10 +82,10 @@ $sources = pkg_sources($row["ID"]);

  • - / - + / +
  • -
  • +
  • -- cgit v1.2.3-54-g00ecf