Skip to content
Snippets Groups Projects
Commit 09f8b869 authored by Seblu's avatar Seblu
Browse files

Add/Delete package in repository

parent fce99ab1
No related branches found
No related tags found
No related merge requests found
......@@ -81,10 +81,10 @@ p_add = subparsers.add_parser("add", help = add.__doc__.lower())
p_add.add_argument("path")
p_add.set_defaults(func = add)
# Del command parser
#p_del = subparsers.add_parser("del", help=delete.__doc__.lower())
#p_del.add_argument("image_name", type=str)
#p_del.add_argument("image_version", type=str)
#p_del.set_defaults(func=delete)
p_del = subparsers.add_parser("del", help = delete.__doc__.lower())
p_del.add_argument("image_name")
p_del.add_argument("image_version")
p_del.set_defaults(func = delete)
try:
# Parse and run
args = p_main.parse_args()
......
......@@ -50,26 +50,23 @@ class Database(object):
self.conn = sqlite3.connect(self.path, isolation_level=None)
self.conn.execute("PRAGMA foreign_keys = ON")
def get(self, name, version):
'''Return a description dict from a image name'''
# parse tarball
try:
self.file.seek(0)
tarball = Tarball.open(fileobj=self.file, mode="r:gz")
rdata = tarball.get_str("%s-%s" % (name, version))
tarball.close()
except KeyError:
raise Exception("No image %s version %s in metadata" % (name, version))
except Exception as e:
raise Exception("Unable to read db %s version %s: %s" % (name, version, e))
# convert loaded data into dict (json parser)
try:
return json.loads(rdata)
except Exception as e:
raise Exception("Invalid metadata in image %s version %s: e" % (name, version, e))
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'''
'''
Ask question to db
'''
return self.conn.execute(sql, args)
def add(self, image):
......@@ -81,7 +78,7 @@ class Database(object):
self.conn.execute("BEGIN TRANSACTION")
# insert image information
arrow("Add image metadata")
self.conn.execute("INSERT OR REPLACE INTO image values (?,?,?,?,?,?,?)",
self.conn.execute("INSERT INTO image values (?,?,?,?,?,?,?)",
(image.md5,
image.name,
image.version,
......@@ -93,7 +90,7 @@ class Database(object):
# insert data informations
arrow("Add payload metadata")
for name, obj in image.payload.items():
self.conn.execute("INSERT OR REPLACE INTO payload values (?,?,?,?,?)",
self.conn.execute("INSERT INTO payload values (?,?,?,?,?)",
(obj.md5,
image.md5,
name,
......@@ -106,25 +103,3 @@ class Database(object):
arrowlevel(-1)
except Exception as e:
raise Exception("Adding metadata fail: %s" % e)
def delete(self, name, version):
'''Delete a packaged image'''
arrow("Removing metadata from db")
# check locality
if istools.pathtype(self.path) != "file":
raise NotImplementedError("Database deletion must be local")
newdb_path = "%s.new" % self.path
fname = "%s-%s.json" % (name, version)
try:
db = Tarball.open(self.path, mode='r:gz')
newdb = Tarball.open(newdb_path, mode='w:gz')
for ti in db.getmembers():
if ti.name != fname:
newdb.addfile(ti, db.extractfile(ti))
db.close()
newdb.close()
# preserve permission and stats when moving
shutil.copystat(self.path, newdb_path)
os.rename(newdb_path, self.path)
except Exception as e:
raise Exception("Removing metadata fail: %s" % e)
......@@ -70,7 +70,7 @@ def debug(message, fd=sys.stderr, endl=os.linesep):
if installsystems.debug:
out("#light##black#%s#reset#" % message, fd, endl)
def arrowlevel(inc=None,level=None):
def arrowlevel(inc=None, level=None):
global _arrow_level
old_level = _arrow_level
if level is not None:
......@@ -79,12 +79,11 @@ def arrowlevel(inc=None,level=None):
_arrow_level = max(1, min(4, _arrow_level + inc))
return old_level
def arrow(message, level=None, fd=sys.stdout, endl=os.linesep):
def arrow(message, inclevel=None, level=None, fd=sys.stdout, endl=os.linesep):
if installsystems.quiet:
return
# set a one shot level
if level is not None:
old_level = arrowlevel(level=level)
# define new level
old_level = arrowlevel(inc=inclevel, level=level)
if _arrow_level == 1:
out("#light##red#=>#reset# %s" % message)
elif _arrow_level == 2:
......@@ -94,5 +93,4 @@ def arrow(message, level=None, fd=sys.stdout, endl=os.linesep):
elif _arrow_level == 4:
out(" #light##green#=>#reset# %s" % message)
# restore old on one shot level
if level is not None:
arrowlevel(level=old_level)
arrowlevel(level = old_level)
......@@ -31,10 +31,12 @@ class Repository(object):
@classmethod
def create(cls, config):
'''Create an empty base repository'''
'''
Create an empty base repository
'''
# check local repository
if istools.pathtype(config.path) != "file":
raise NotImplementedError("Repository creation must be local")
raise Exception("Repository creation must be local")
# create base directories
arrow("Creating base directories")
arrowlevel(1)
......@@ -58,10 +60,12 @@ class Repository(object):
return self
def update_last(self):
'''Update last file to current time'''
'''
Update last file to current time
'''
# check local repository
if istools.pathtype(self.config.path) != "file":
raise NotImplementedError("Repository addition must be local")
raise Exception("Repository addition must be local")
try:
arrow("Updating last file")
last_path = os.path.join(self.config.path, self.config.lastname)
......@@ -71,7 +75,9 @@ class Repository(object):
raise Exception("Update last file failed: %s" % e)
def last(self):
'''Return the last value'''
'''
Return the last value
'''
try:
last_path = os.path.join(config.path, config.lastname)
return int(istools.uopen(last_path, "r").read().rstrip())
......@@ -80,10 +86,15 @@ class Repository(object):
return 0
def add(self, image):
'''Add a packaged image to repository'''
'''
Add a packaged image to repository
'''
# check local repository
if istools.pathtype(self.config.path) != "file":
raise NotImplementedError("Repository addition must be local")
raise Exception("Repository addition must be local")
# cannot add already existant image
if self.has(image.name, image.version):
raise Exception("Image already in database, delete first!")
# checking data tarballs md5 before copy
image.check("Check image and payload before copy")
# adding file to repository
......@@ -112,43 +123,60 @@ class Repository(object):
self.update_last()
def delete(self, name, version):
'''Delete an image from repository'''
raise NotImplementedError()
'''
Delete an image from repository
'''
# check local repository
if istools.pathtype(self.config.path) != "file":
raise NotImplementedError("Repository deletion must be local")
desc = self.db.find(name, version)
if desc is None:
error("Unable to find %s version %s in database" % (name, version))
# removing script tarballs
arrow("Removing script tarball")
arrowlevel(1)
tpath = os.path.join(self.config.path,
"%s-%s%s" % (name, version, Image.extension))
if os.path.exists(tpath):
os.unlink(tpath)
arrow("%s removed" % os.path.basename(tpath))
raise Exception("Repository deletion must be local")
# get md5 of files related to images (exception is raised if not exists
md5s = self.getmd5(name, version)
# cleaning db (must be done before cleaning)
arrow("Cleaning database")
arrow("Remove payloads from database", 1)
self.db.begin()
for md5 in md5s[1:]:
self.db.ask("DELETE FROM payload WHERE md5 = ? AND image_md5 = ?",
(md5, md5s[0])).fetchone()
arrow("Remove image from database", 1)
self.db.ask("DELETE FROM image WHERE md5 = ?",
(md5s[0],)).fetchone()
self.db.commit()
# Removing script image
arrow("Removing files from pool")
arrowlevel(1)
# removing data tarballs
arrow("Removing data tarballs")
arrowlevel(1)
for tb in self.db.databalls(name, version):
tpath = os.path.join(self.config.data, tb)
if os.path.exists(tpath):
os.unlink(tpath)
arrow("%s removed" % tb)
for md5 in md5s:
self._remove_file(md5)
arrowlevel(-1)
# removing metadata
self.db.delete(name, version)
# update last file
arrow("Updating last file")
self.update_last()
def _remove_file(self, filename):
'''
Remove a filename from pool. Check if it's not needed by db before
'''
# check existance in table image
have = False
for table in ("image", "payload"):
have = have or self.db.ask("SELECT md5 FROM %s WHERE md5 = ? LIMIT 1" % table,
(filename,)).fetchone() is not None
# if no reference, delete!
if not have:
arrow("%s, deleted" % filename)
os.unlink(os.path.join(self.config.path, filename))
else:
arrow("%s, skipped" % filename)
def has(self, name, version):
return self.db.ask("select name,version from image where name = ? and version = ? limit 1", (name,version)).fetchone() is not None
'''
Return the existance of a package
'''
return self.db.ask("SELECT name,version FROM image WHERE name = ? AND version = ? LIMIT 1", (name,version)).fetchone() is not None
def get(self, name, version):
'''return a image from a name and version of pakage'''
'''
return a image from a name and version
'''
# get file md5 from db
r = self.db.ask("select md5 from image where name = ? and version = ? limit 1",
(name,version)).fetchone()
......@@ -156,11 +184,29 @@ class Repository(object):
raise Exception("No such image %s version %s" % name, version)
path = os.path.join(self.config.path, r[0])
debug("Getting %s v%s from %s" % (name, version, path))
return PackageImage(path, md5name=True)
pkg = PackageImage(path, md5name=True)
pkg.md5 = r[0]
return pkg
def getmd5(self, name, version):
'''
return a image md5 and payload md5 from name and version. Order matter !
image md5 will still be the first
'''
# get file md5 from db
a = self.db.ask("SELECT md5 FROM image WHERE name = ? AND version = ? LIMIT 1",
(name,version)).fetchone()
if a is None:
raise Exception("No such image %s version %s" % name, version)
b = self.db.ask("SELECT md5 FROM payload WHERE image_md5 = ?",
(a[0],)).fetchall()
return [ a[0] ] + [ x[0] for x in b ]
def last(self, name):
'''Return last version of name in repo or -1 if not found'''
r = self.db.ask("select version from image where name = ? order by version desc limit 1", (name,)).fetchone()
'''
Return last version of name in repo or -1 if not found
'''
r = self.db.ask("SELECT version FROM image WHERE name = ? ORDER BY version DESC LIMIT 1", (name,)).fetchone()
# no row => no way
if r is None:
return -1
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment