Commit 5a136f19 authored by Sébastien Luttringer's avatar Sébastien Luttringer
Browse files

temp rework repo

parent 573805ed
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -28,7 +28,9 @@ from installsystems.exception import ISError, ISException
from installsystems.image import PackageImage, SourceImage
from installsystems.printer import arrow, arrowlevel, setmode
from installsystems.printer import out, warn, error, debug, confirm
from installsystems.repository import Repository, RepositoryManager, RepositoryConfig
from installsystems.repository import split_list as split_repo_list, diff as repodiff
from installsystems.repository.manager import RepositoryManager
from installsystems.repository.config import RepositoryConfig
from installsystems.tools import chroot, prepare_chroot, unprepare_chroot
from installsystems.tools import islocal, smd5sum, argv
from os import getpid, getcwdu, chdir
@@ -48,8 +50,8 @@ def load_repositories(args):
    if args.no_cache:
        args.cache = None
    # split filter and search in list
    args.repo_filter = Repository.split_list(args.repo_filter)
    args.repo_search = Repository.split_list(args.repo_search)
    args.repo_filter = split_repo_list(args.repo_filter)
    args.repo_search = split_repo_list(args.repo_search)
    # init repo cache object
    repoman = RepositoryManager(args.cache, timeout=args.repo_timeout or args.timeout,
                                filter=args.repo_filter, search=args.repo_search)
@@ -252,7 +254,7 @@ def c_diff(args):
    repoman = load_repositories(args)
    if args.object[0] in repoman.onlines and args.object[1] in repoman.onlines:
        try:
            Repository.diff(repoman[args.object[0]], repoman[args.object[1]])
            diff(repoman[args.object[0]], repoman[args.object[1]])
        except IndexError as e:
            raise ISError(e)
    else:
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ from installsystems.tools import mkdir, abspath, time_rfc2822, human_size, argv,
from json import loads, dumps
from math import floor
from os import listdir
from os.path import join, basename, exists, isdir, dirname, abspath
from os.path import join, basename, exists, isdir, dirname
from time import time

class PackageImage(Image):
+77 −5
Original line number Diff line number Diff line
@@ -20,8 +20,80 @@
InstallSystems repository package
'''

from installsystems.repository.manager import RepositoryManager
from installsystems.repository.config import RepositoryConfig
from installsystems.repository.repository import Repository
from installsystems.repository.repository1 import Repository1
from installsystems.repository.repository2 import Repository2
__all__ = [
    "is_name",
    "check_name",
    "split_path",
    "split_list",
    "diff",
]

from installsystems.exception import ISError
from installsystems.printer import arrow, out
from re import match, split

def is_name(name):
    '''Check if name is a valid repository name'''
    return match("^[-_\w]+$", name) is not None

def check_name(name):
    '''
    Raise exception is repository name is invalid
    '''
    if not is_name(name):
        raise ISError(u"Invalid repository name %s" % name)
    return name

def split_path(path):
    '''
    Split an image path (repo/image:version)
    in a tuple (repo, image, version)
    '''
    x = match(u"^(?:([^/:]+)/)?([^/:]+)?(?::v?([^/:]+)?)?$", path)
    if x is None:
        raise ISError(u"invalid image path: %s" % path)
    return x.group(1, 2, 3)

def split_list(repolist, filter=None):
    '''
    Return a list of repository from a comma/spaces separated names of repo
    '''
    if filter is None:
        filter = is_name
    return [r for r in  split("[ ,\n\t\v]+", repolist) if filter(r)]

@staticmethod
def diff(repo1, repo2):
    '''
    Compute a diff between two repositories
    '''
    arrow(u"Diff between repositories #y#%s#R# and #g#%s#R#" % (repo1.config.name,
                                                                repo2.config.name))
    # Get info from databases
    i_dict1 = dict((b[0], b[1:]) for b in repo1.db.ask(
        "SELECT md5, name, version FROM image").fetchall())
    i_set1 = set(i_dict1.keys())
    i_dict2 = dict((b[0], b[1:]) for b in repo2.db.ask(
        "SELECT md5, name, version FROM image").fetchall())
    i_set2 = set(i_dict2.keys())
    p_dict1 = dict((b[0], b[1:]) for b in  repo1.db.ask(
        "SELECT md5, name FROM payload").fetchall())
    p_set1 = set(p_dict1.keys())
    p_dict2 = dict((b[0], b[1:]) for b in repo2.db.ask(
        "SELECT md5, name FROM payload").fetchall())
    p_set2 = set(p_dict2.keys())
    # computing diff
    i_only1 = i_set1 - i_set2
    i_only2 = i_set2 - i_set1
    p_only1 = p_set1 - p_set2
    p_only2 = p_set2 - p_set1
    # printing functions
    pimg = lambda r,c,m,d,: out("#%s#Image only in repository %s: %s v%s (%s)#R#" %
                                (c, r.config.name, d[m][0], d[m][1], m))
    ppay = lambda r,c,m,d,: out("#%s#Payload only in repository %s: %s (%s)#R#" %
                                (c, r.config.name, d[m][0], m))
    # printing image diff
    for md5 in i_only1: pimg(repo1, "y", md5, i_dict1)
    for md5 in p_only1: ppay(repo1, "y", md5, p_dict1)
    for md5 in i_only2: pimg(repo2, "g", md5, i_dict2)
    for md5 in p_only2: ppay(repo2, "g", md5, p_dict2)
+4 −4
Original line number Diff line number Diff line
@@ -22,8 +22,8 @@ Repository configuration module

from grp import getgrnam
from installsystems.printer import warn, debug
from installsystems.repository.repository import Repository
from installsystems.tools import isfile, chrights, mkdir, compare_versions
from installsystems.repository import check_name
from installsystems.tools import islocal, chrights, mkdir, compare_versions
from os  import getuid, getgid, umask, linesep
from os.path import join, abspath
from pwd import getpwnam
@@ -37,7 +37,7 @@ class RepositoryConfig(object):
        # set default value for arguments
        self._valid_param = ("name", "path", "dbpath", "lastpath",
                             "uid", "gid", "fmod", "dmod", "offline")
        self.name = Repository.check_name(name)
        self.name = check_name(name)
        self.path = ""
        self._offline = False
        self._dbpath = None
@@ -111,7 +111,7 @@ class RepositoryConfig(object):
        Set db path
        '''
        # dbpath must be local, sqlite3 requirement
        if not isfile(value):
        if not islocal(value):
            raise ValueError("Database path must be local")
        self._dbpath = abspath(value)

+0 −129
Original line number Diff line number Diff line
# -*- python -*-
# -*- coding: utf-8 -*-

# This file is part of Installsystems.
#
# Installsystems is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Installsystems is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Installsystems.  If not, see <http://www.gnu.org/licenses/>.

'''
Database stuff
'''

import math
import os
import sqlite3
import uuid
import installsystems.tools as istools
from installsystems.exception import *
from installsystems.printer import *

class Database(object):
    '''
    Abstract repo database stuff
    It needs to be local cause of sqlite3 which need to open a file
    '''

    version = 2.0

    @classmethod
    def create(cls, path):
        arrow("Creating repository database")
        # check locality
        if not istools.isfile(path):
            raise ISError("Database creation must be local")
        path = os.path.abspath(path)
        if os.path.exists(path):
            raise ISError("Database already exists. Remove it before")
        try:
            conn = sqlite3.connect(path, isolation_level=None)
            conn.execute("PRAGMA foreign_keys = ON")
            conn.executescript(TEMPLATE_EMPTY_DB)
            conn.execute("INSERT INTO repository values (?,?,?)",
                         (str(uuid.uuid4()), Database.version, "",))
            conn.commit()
            conn.close()
        except Exception as e:
            raise ISError(u"Create database failed", e)
        return cls(path)

    def __init__(self, path):
        # check locality
        if not istools.isfile(path):
            raise ISError("Database must be local")
        self.path = os.path.abspath(path)
        if not os.path.exists(self.path):
            raise ISError("Database not exists")
        self.conn = sqlite3.connect(self.path, isolation_level=None)
        self.conn.execute("PRAGMA foreign_keys = ON")
        # get database version
        try:
            r = self.ask("SELECT version FROM repository").fetchone()
            if r is None:
                raise TypeError()
            self.version = float(r[0])
        except:
            self.version = 1.0
        if math.floor(self.version) >= math.floor(Database.version) + 1.0:
            raise ISWarning(u"New database format (%s), please upgrade "
                            "your Installsystems version" % self.version)
        # we make a query to be sure format is valid
        try:
            self.ask("SELECT * FROM image")
        except:
            debug(u"Invalid database format: %s" % self.version)
            raise ISError("Invalid database format")

    def begin(self):
        '''
        Start a db transaction
        '''
        self.conn.execute("BEGIN TRANSACTION")

    def commit(self):
        '''
        Commit current db transaction
        '''
        self.conn.execute("COMMIT TRANSACTION")


    def ask(self, sql, args=()):
        '''
        Ask question to db
        '''
        return self.conn.execute(sql, args)


TEMPLATE_EMPTY_DB = u"""
CREATE TABLE image (md5 TEXT NOT NULL PRIMARY KEY,
                    name TEXT NOT NULL,
                    version TEXT NOT NULL,
                    date INTEGER NOT NULL,
                    author TEXT,
                    description TEXT,
                    size INTEGER NOT NULL,
                    is_min_version INTEGER NOT NULL,
                    format INTEGER NOT NULL,
                    UNIQUE(name, version));

CREATE TABLE payload (md5 TEXT NOT NULL,
                      image_md5 TEXT NOT NULL REFERENCES image(md5),
                      name TEXT NOT NULL,
                      isdir INTEGER NOT NULL,
                      size INTEGER NOT NULL,
                      PRIMARY KEY(md5, image_md5));

CREATE TABLE repository (uuid TEXT NOT NULL PRIMARY KEY,
                         version FLOAT NOT NULL,
                         motd TEXT NOT NULL);
"""
Loading