File: package.py

package info (click to toggle)
datapm 0.10-1.1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 472 kB
  • ctags: 590
  • sloc: python: 2,760; makefile: 2
file content (176 lines) | stat: -rw-r--r-- 5,982 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import os
import shutil
from StringIO import StringIO
import urllib
import re
import distutils.dist

import dpm.metadata
from dpm import DatapkgException

def normalize_name(name):
    new_name = name.lower()
    regex = r'^[\w-]+$'
    if not re.match(regex, new_name):
        msg = 'Invalid package name: %s' % name
        raise ValueError(msg)
    return unicode(new_name)

class Manifest(dict):
    '''A package manifest, i.e. a list of resources the package provides.

    At present a simple dictionary keyed by file pathes.

    # TODO: use an ordered dictionary (waiting until available in standard
    # python distribution.)
    '''
    pass


## TODO: do we want to normalize name?
class Package(object):
    '''A knowledge (data or content) 'package'.

    It combines metadata with a manifest listing the material contained in this
    package.

    If it has an associated distribution then this material will be directly
    accessible. 
    '''
    def __init__(self, **kwargs):
        self.init_on_load(**kwargs)

    def init_on_load(self, **kwargs):
        '''Additional __init__ method.
        
        Separated out from __init__ for the benefit of sqlalchemy
        '''
        # TODO: rename to something like path_on_disk
        # path to distribution on disk associated to package (if any)
        self.installed_path = None
        self.manifest = Manifest()
        for k,v in kwargs.items():
            setattr(self, k, v)
        for k in dpm.metadata.Metadata.key_list:
            if not hasattr(self, k):
                setattr(self, k, dpm.metadata.Metadata.defaults.get(k, u''))

    def _get_metadata(self):
        return dpm.metadata.Metadata([ (k,getattr(self,k)) for k in
            dpm.metadata.Metadata.key_list ])
    
    metadata = property(_get_metadata)

    manager_metadata_keylist = ['installed_path']
    def _get_manager_metadata(self):
        out = [ (k,getattr(self,k)) for k in
             self.manager_metadata_keylist]
        return dict(out)
    manager_metadata = property(_get_manager_metadata)

    def update_metadata(self, metadata):
        for k,v in metadata.items():
            setattr(self, k, v)

    def _path_set(self, v):
        self.installed_path = v
    # TODO: rename installed path to path
    path = property(lambda self: self.installed_path, _path_set)

# TODO: remove (out of date as of 2010-04-09)
#     def download(self, tmpdir):
#         filepath = self.pi.download(self.download_url, tmpdir)
#         # if a local file/dir will not actually move it to tmpdir but will just return link
#         # Make sure the file has been downloaded to the temp dir.
#         if os.path.dirname(filepath) != tmpdir:
#             basename = os.path.basename(filepath)
#             dst = os.path.join(tmpdir, basename)
#             if os.path.isdir(filepath):
#                 # TODO: if dst already exists check if the same in which case
#                 # we can avoid this
#                 if os.path.exists(dst):
#                     shutil.rmtree(dst)
#                 shutil.copytree(filepath, dst)
#             else:
#                 from setuptools.command.easy_install import samefile
#                 if not samefile(filepath, dst):
#                     shutil.copy2(filepath, dst)
#             filepath=dst
#         return filepath
# 
#     def unpack(self, dist_filename, extract_dir):
#         if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'):
#             from setuptools.archive_util import unpack_archive
#             unpack_archive(dist_filename, extract_dir)
#             return extract_dir
#         elif os.path.isdir(dist_filename):
#             return os.path.abspath(dist_filename)

    def install(self, *args, **kwargs):
        '''Dispatch to same method on default L{Distribution}.'''
        return self.dist.install(*args, **kwargs)

    # TODO: deprecate this
    def write(self, *args, **kwargs):
        '''Dispatch to same method on default L{Distribution}.'''
        return self.dist.write(*args, **kwargs)

    def stream(self, *args, **kwargs):
        '''Dispatch to same method on default L{Distribution}.'''
        return self.dist.stream(*args, **kwargs)

    def _dist_get(self):
        '''Get a L{Distribution} associated with this package.'''
        import dpm.distribution
        klass = dpm.distribution.default_distribution()
        dist = klass(self)
        return dist

    dist = property(_dist_get)

    @classmethod
    def info_from_path(self, path):
        # will remove any trailing slash
        path = os.path.normpath(path)
        dir = os.path.dirname(path)
        name = os.path.basename(path)
        return dir, name

    @classmethod
    def create_on_disk(self, path, **kwargs):
        '''Helper method to create distribution at path.

        Assumes path gives both package name (last part of path) and path to
        create at.
        
        Type of distribution to use determined by: `dpm.distribution.default_distribution`

        args, kwargs as appropriate for write method on default distribution
        '''
        dir, name = self.info_from_path(path)
        pkg = Package(name=name)
        pkg.installed_path = path
        pkg.dist.write(path, **kwargs)
        return pkg

    @classmethod
    def load(self, path):
        '''Load a L{Package} object from a path to a package distribution.'''
        import dpm.distribution
        dist = dpm.distribution.load(path)
        # TODO: should we be recording the distribution type or something for
        # future stuff ...
        return dist.package

    def __str__(self):
        repr = 'Package'
        for key in dpm.metadata.Metadata.key_list:
            repr += ' %s: %s' % (key, getattr(self,key))
        return repr
    
    def pretty_print(self):
        repr = ''
        for key in dpm.metadata.Metadata.key_list:
            repr += '%s: %s\n' % (key, getattr(self,key))
        return repr