From 26aaa96f5aba2f6fad1e7e253b83893e94afc7e0 Mon Sep 17 00:00:00 2001
From: Seblu <sebastien.luttringer@smartjog.com>
Date: Tue, 31 May 2011 20:16:26 +0200
Subject: [PATCH] Improve remote cache. Http transport enabled

---
 bin/isinstall                |  4 +-
 installsystems/config.py     |  9 ++--
 installsystems/database.py   |  4 +-
 installsystems/repository.py | 87 +++++++++++++++++++++---------------
 installsystems/tools.py      | 13 ++++--
 5 files changed, 70 insertions(+), 47 deletions(-)

diff --git a/bin/isinstall b/bin/isinstall
index c1ec467..687fdb5 100755
--- a/bin/isinstall
+++ b/bin/isinstall
@@ -45,9 +45,9 @@ try:
     # load config
     config = ConfigFile("isinstall", args.config)
     # looks if arguments is a file or image name
-    image_name_type = istools.get_path_type(args.image_name)
+    image_name_type = istools.pathtype(args.image_name)
     if image_name_type == "file":
-        pkg = PackageImage(istools.complete_path(args.image_name))
+        pkg = PackageImage(istools.abspath(args.image_name))
     elif image_name_type == "name":
         # init repo cache object
         repocache = RepositoryCache(config.cache, verbose=args.verbose)
diff --git a/installsystems/config.py b/installsystems/config.py
index 087cacf..d2d212c 100644
--- a/installsystems/config.py
+++ b/installsystems/config.py
@@ -32,7 +32,7 @@ class ConfigFile(object):
         '''Load/Reload config file'''
         # seting default config
         self._config = {}
-        self._repos = {}
+        self._repos = []
         # loading config file if exists
         if self.path is not None:
             debug("Loading config file: %s" % self.path)
@@ -49,7 +49,7 @@ class ConfigFile(object):
                     if "image" not in cp.options(rep):
                         continue
                     # get all options in repo
-                    self._repos[rep] = RepositoryConfig(rep, **dict(cp.items(rep)))
+                    self._repos.append( RepositoryConfig(rep, **dict(cp.items(rep))))
             except Exception as e:
                 raise
                 raise Exception("Unable load file %s: %s" % (self.path, e))
@@ -89,5 +89,6 @@ class ConfigFile(object):
 
     @property
     def repos(self):
-        '''Get a list of repository available'''
-        return self._repos.copy()
+        '''Get a dict of repository available'''
+        # deep copy
+        return list(self._repos)
diff --git a/installsystems/database.py b/installsystems/database.py
index 2237134..6a7667e 100644
--- a/installsystems/database.py
+++ b/installsystems/database.py
@@ -22,7 +22,7 @@ class Database(object):
     @classmethod
     def create(cls, path, verbose=True):
         arrow("Creating repository database", 1, verbose)
-        dbpath = os.path.abspath(path)
+        dbpath = istools.abspath(path)
         if os.path.exists(dbpath):
             raise Exception("db already exists")
         try:
@@ -34,7 +34,7 @@ class Database(object):
         return cls(path, verbose)
 
     def __init__(self, path, verbose=True):
-        self.path = os.path.abspath(path)
+        self.path = istools.abspath(path)
         self.verbose = verbose
 
     def add(self, package):
diff --git a/installsystems/repository.py b/installsystems/repository.py
index 88fc9ac..d03ed39 100644
--- a/installsystems/repository.py
+++ b/installsystems/repository.py
@@ -11,6 +11,7 @@ import time
 import shutil
 import pwd
 import grp
+import copy
 import installsystems
 import installsystems.tools as istools
 from installsystems.printer import *
@@ -176,61 +177,75 @@ class RepositoryCache(object):
     '''Local repository cache class'''
 
     def __init__(self, cache_path, verbose=True):
-        self.base_path = os.path.abspath(cache_path)
-        self.image_path = os.path.join(self.base_path, "image")
-        self.last_path = os.path.join(self.base_path, "last")
-        self.db_path = os.path.join(self.base_path, "db")
-        for path in (self.base_path, self.image_path, self.last_path, self.db_path):
-            if not os.path.exists(path):
-                os.mkdir(path)
-            if not os.access(path, os.W_OK | os.X_OK):
-                raise Exception("%s is not writable or executable" % path)
         self.verbose = verbose
-        self.repos = dict()
-        debug("Repository cache is in %s" % self.base_path)
+        self.repos = {}
+        self.path = os.path.abspath(cache_path)
+        # ensure cache directories are avaiblable
+        if not os.path.exists(self.path):
+            os.mkdir(self.path)
+        if not os.access(self.path, os.W_OK | os.X_OK):
+            raise Exception("%s is not writable or executable" % path)
+        debug("Repository cache is in %s" % self.path)
 
-    def register(self, iterepo):
-        '''Register a repository to track'''
-        for r in iterepo:
-            self.repos[r[0]] = Repository(istools.abspath(r[1]),
-                                          istools.abstpath(r[2]),
-                                          verbose=self.verbose)
+    def register(self, configs):
+        '''Register a list of repository from its config'''
+        for conf in configs:
+            self.repos[conf.name] = {}
+            # keep original repository conf
+            self.repos[conf.name]["orig"] = Repository(conf, self.verbose)
+            # change configuration to make remote repository in cache
+            cconf = copy.copy(conf)
+            cconf.image = os.path.join(self.path, conf.name)
+            cconf.data = "/dev/null"
+            self.repos[conf.name]["cache"] = Repository(cconf, self.verbose)
+            # create a local directory
+            if not os.path.exists(cconf.image):
+                os.mkdir(cconf.image)
 
     def update(self):
         '''Update cache info'''
         arrow("Updating repositories", 1, self.verbose)
         for r in self.repos:
-            debug("%s: remote_last: %s, local_last:%s" % (r,
-                                                          self.repos[r].last(),
-                                                          self.last(r)))
-            if self.repos[r].last() > self.last(r):
-                # copy last file
-                istools.copy(self.repos[r].last_path, os.path.join(self.last_path, r))
+            # last local
+            local_last = self.last(r)
+            # copy last file
+            arrow("Copying %s repository last" % r, 2, self.verbose)
+            istools.copy(self.repos[r]["orig"].last_path,
+                         self.repos[r]["cache"].last_path,)
+            # last after update
+            remote_last = self.last(r)
+            debug("%s: last: local: %s, remote:%s" % (r, local_last, remote_last))
+            # Updating db?
+            remote_db = self.repos[r]["orig"].db.path
+            local_db = self.repos[r]["cache"].db.path
+            if remote_last > local_last or not os.path.exists(local_db):
                 # copy db file
-                istools.copy(self.repos[r].db.path, os.path.join(self.db_path, r))
+                arrow("Copying %s repository db" % r, 2, self.verbose)
+                istools.copy(remote_db, local_db)
                 arrow("%s updated" % r, 2, self.verbose)
 
     def last(self, reponame):
         '''Return the last timestamp of a repo'''
-        last_path = os.path.join(self.last_path, reponame)
-        if os.path.exists(last_path):
+        last_path = os.path.join(self.path, reponame, "last")
+        try:
             return int(open(last_path, "r").read().rstrip())
-        return 0
+        except Exception:
+            return 0
 
     def get_image(self, reponame, imagename, imageversion):
         '''Obtain a local path in cache for a remote image in repo'''
         arrow("Getting image", 1, self.verbose)
         filename = "%s-%s%s" % (imagename, imageversion, Image.image_extension)
-        localpath = os.path.join(self.image_path, filename)
+        cachepath = os.path.join(self.repos[reponame]["cache"].config.image, filename)
         # return db path if exists
-        if os.path.exists(localpath):
+        if os.path.exists(cachepath):
             arrow("Found in cache", 2, self.verbose)
-            return localpath
-        # get remote image
-        remotepath = os.path.join(self.repos[reponame].image_path, filename)
-        arrow("Copying from repository", 2, self.verbose)
-        istools.copy(remotepath, localpath)
-        return localpath
+        else:
+            # get remote image
+            remotepath = os.path.join(self.repos[reponame]["orig"].config.image, filename)
+            arrow("Copying from repository", 2, self.verbose)
+            istools.copy(remotepath, cachepath)
+        return cachepath
 
     def find_image(self, name, version):
         '''Find an image in repositories'''
@@ -241,7 +256,7 @@ class RepositoryCache(object):
         img = None
         # search in all repositories
         for repo in self.repos:
-            tempdb = Database(os.path.join(self.db_path, repo), False)
+            tempdb = Database(self.repos[repo]["cache"].db.path, False)
             img = tempdb.find(name, version)
             if img is not None:
                 # \o/
diff --git a/installsystems/tools.py b/installsystems/tools.py
index b4a084b..1f9340b 100644
--- a/installsystems/tools.py
+++ b/installsystems/tools.py
@@ -9,6 +9,7 @@ InstallSystems Generic Tools Library
 import os
 import hashlib
 import shutil
+import urllib2
 
 def md5sum(path):
     '''Compute md5 of a file'''
@@ -16,20 +17,26 @@ def md5sum(path):
     m.update(open(path, "r").read())
     return m.hexdigest()
 
-def copy(source, destination, uid=None, gid=None, mode=None):
+def copy(source, destination, uid=None, gid=None, mode=None, timeout=None):
     '''Copy a source to destination. Take care of path type'''
     stype = pathtype(source)
     dtype = pathtype(destination)
+    # ensure destination is not a directory
+    if dtype == "file" and os.path.isdir(destination):
+        destination = os.path.join(destination, os.path.basename(source))
+    # trivial case
     if stype == dtype == "file":
         shutil.copy(source, destination)
+    elif stype == "http" and dtype == "file":
+        f_dest = open(destination, "w")
+        f_source = urllib2.urlopen(source, timeout=timeout)
+        f_dest.write(f_source.read())
     elif stype == "file" and dtype == "":
         raise NotImplementedError
     else:
         raise NotImplementedError
     # setting destination file rights
     if dtype == "file":
-        if os.path.isdir(destination):
-            destination = os.path.join(destination, os.path.basename(source))
         chrights(destination, uid, gid, mode)
 
 def mkdir(path, uid=None, gid=None, mode=None):
-- 
GitLab