]> git.draconx.ca Git - squashmirror.git/blob - portage/sync/modules/squashmirror/squashmirror.py
d4a5d3d5022b9a9188fbeb3625ebbae87b4aebee
[squashmirror.git] / portage / sync / modules / squashmirror / squashmirror.py
1 # Copyright © 2015 Nick Bowler
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation, either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program.  If not, see <https://www.gnu.org/licenses/>
15
16 import time
17 import email.utils
18 import logging
19 import contextlib
20
21 import portage
22 from portage import os
23 from portage.util import writemsg_level
24 from portage.process import spawn
25 from portage.sync.syncbase import NewBase
26
27 # Determine snapshot date.  While timestamps from snapshots indicate
28 # early in the day (UTC), filenames indicate the previous day (snapshot
29 # at end of day).  Simply subtract 4 hours before calculating the day
30 # to accomodate this difference, assuming snapshot generation is faster
31 # than that.
32 def repo_date(repo):
33     with open(repo.sync_uri + '/metadata/timestamp.chk', 'r') as f:
34         timestamp = f.readline()
35     repotime  = email.utils.mktime_tz(email.utils.parsedate_tz(timestamp))
36     return time.strftime("%Y%m%d", time.gmtime(repotime - 4*3600))
37
38 def repo_filename(repo):
39     opts = repo.module_specific_options
40     return '%s/%s-%s.sqfs' % (opts['squash-cache-location'],
41                               repo.name, repo_date(repo))
42
43 class SquashMirror(NewBase):
44     def __init__(self):
45         NewBase.__init__(self, 'mksquashfs', 'sys-fs/squashfs-tools')
46
47     def msg(self, msg, level=0, noiselevel=0):
48         self.logger(self.xterm_titles, msg)
49         writemsg_level(msg + "\n", level, noiselevel)
50
51     def err(self, msg, level=0, noiselevel=0):
52         self.msg("!!! " + msg, level=logging.ERROR, noiselevel=-1)
53
54     def exists(self, **kwargs):
55         if kwargs:
56             self._kwargs(kwargs)
57         elif not self.repo:
58             return False
59         if not os.path.exists(repo_filename(self.repo)):
60             return False
61         return True;
62
63     def new(self, **kwargs):
64         opts = self.repo.module_specific_options
65         filename = repo_filename(self.repo)
66         self.msg("Creating squashfs image " + filename)
67
68         args = [self.bin_command]
69         args.extend([self.repo.sync_uri, filename])
70         args.extend(['-no-xattrs'])
71         args.extend(['-force-uid', 'portage', '-force-gid', 'portage'])
72         args.extend(['-comp', opts['squash-compression']])
73         args.extend(opts['squash-extra-opts'].split())
74
75         rc = spawn(args, **portage._native_kwargs(self.spawn_kwargs))
76         if rc != os.EX_OK:
77             self.err("command failed: %s" % " ".join(args))
78             return (rc, False)
79
80         symlink = "%s/%s-current.sqfs" % (opts['squash-cache-location'],
81                                           self.repo.name)
82
83         with contextlib.suppress(FileNotFoundError):
84             os.remove(symlink)
85         os.symlink(os.path.basename(filename), symlink)
86         return (0, True)
87
88     def update(self, **kwargs):
89         filename = repo_filename(self.repo)
90         self.err("%s already exists; exiting." % filename);
91         return (1, False)