]> git.ipfire.org Git - pakfire.git/blame - pakfire/server/master.py
Add support to fetch packages from the server and build them.
[pakfire.git] / pakfire / server / master.py
CommitLineData
677ff42a
MT
1#!/usr/bin/python
2
3import logging
4import os
5import random
6import shutil
7import subprocess
8import xmlrpclib
9
10import pakfire.packages as packages
11import pakfire.repository as repository
12import pakfire.util as util
13from pakfire.constants import *
14
15class Source(object):
16 def __init__(self, master, id, name, path, targetpath, revision, branch):
17 self.master = master
18 self.id = id
19 self.name = name
20 self.path = path
21 self.targetpath = targetpath
22 self.revision = revision
23 self.branch = branch
24
25 @property
26 def pakfire(self):
27 return self.master.pakfire
28
29 def _git(self, cmd):
30 cmd = "cd %s; git %s" % (self.path, cmd)
31
32 logging.debug("Running command: %s" % cmd)
33
34 return subprocess.check_output(["/bin/sh", "-c", cmd])
35
36 def _git_rev_list(self, revision=None):
37 if not revision:
38 revision = self.revision
39
a52f536c 40 command = "rev-list %s..origin/%s" % (revision, self.branch)
677ff42a 41
a52f536c
MT
42 # Get all normal commits.
43 commits = self._git("%s --no-merges" % command)
44 commits = commits.splitlines()
45
46 revisions = []
47 for commit in self._git(command).splitlines():
48 # Check if commit is a normal commit or merge commit.
49 merge = not commit in commits
50
51 revisions.append((commit, merge))
52
53 return reversed(revisions)
677ff42a
MT
54
55 def _git_changed_files(self, revision1, revision2=""):
56 files = self._git("diff --name-only %s %s" % (revision1, revision2))
57
58 return [os.path.join(self.path, f) for f in files.splitlines()]
59
60 def _git_checkout_revision(self, revision):
61 self._git("checkout %s" % revision)
62
a52f536c
MT
63 def update_revision(self, (revision, merge)):
64 if not merge:
65 self._git_checkout_revision(revision)
677ff42a 66
a52f536c
MT
67 # Get list of all changes files between the current revision and
68 # the previous one.
69 files = self._git_changed_files("HEAD^", "HEAD")
677ff42a 70
a52f536c 71 self.update_files([f for f in files if f.endswith(".%s" % MAKEFILE_EXTENSION)])
677ff42a
MT
72
73 # Send update to the server.
a52f536c 74 self.master.update_revision(self, revision)
677ff42a
MT
75
76 def update_files(self, files):
77 rnd = random.randint(0, 1024**2)
78 tmpdir = "/tmp/pakfire-source-%s" % rnd
79
80 pkgs = []
81 for file in files:
82 if os.path.exists(file):
83 pkgs.append(packages.Makefile(self.pakfire, file))
84 else:
85 pkg_name = os.path.basename(os.path.dirname(file))
86
87 # Send deleted package to server.
88 self.master.package_remove(self, pkg_name)
89
90 if not pkgs:
91 return
92
93 # XXX This totally ignores the local configuration.
94 self.pakfire.dist(pkgs, destroy=False, resultdirs=[tmpdir,])
95
96 # Create a kind of dummy repository to link the packages against it.
97 repo = repository.LocalSourceRepository(self.pakfire,
98 "source-%s" % rnd, "Source packages", tmpdir, idx="directory")
99 repo.update(force=True)
100
101 for pkg in repo.get_all():
102 logging.debug("Processing package: %s" % pkg)
103
104 pkg_path = "%(name)s/%(epoch)s-%(version)s-%(release)s/%(arch)s" % pkg.info
105
106 file = os.path.join(self.targetpath, pkg_path, os.path.basename(pkg.filename))
107 dir = os.path.dirname(file)
108
109 print file
110
111 if os.path.exists(file):
112 logging.warning("Package does already exist: %s" % file)
113
114 else:
115 if not os.path.exists(dir):
116 os.makedirs(dir)
117
118 # Copy the source file to the designated data pool.
119 shutil.copy2(pkg.filename, file)
120
121 # Register package in database and get an ID.
122 pkg_id = self.master.package_add(self, pkg)
123
124 # Re-read the package metadata (mainly update filenames).
125 pkg = packages.SourcePackage(self.pakfire, repo, file)
126
127 self.master.package_file_add(self, pkg_id, pkg)
128
129 util.rm(tmpdir)
130
131 def update(self):
132 # Update files from server.
133 self._git("fetch")
134
135 # If there has been no data, yet we need to import all packages
136 # that are currently checked out.
137 if not self.revision:
138 self.update_all()
139
140 for rev in self._git_rev_list():
141 self.update_revision(rev)
142
143 def update_all(self):
144 _files = []
145 for dir, subdirs, files in os.walk(self.path):
146 for f in files:
147 if not f.endswith(".%s" % MAKEFILE_EXTENSION):
148 continue
149
150 _files.append(os.path.join(dir, f))
151
152 self.update_files(_files)
153
154
155class Master(object):
156 def __init__(self, pakfire):
157 self.pakfire = pakfire
158
159 server = self.pakfire.config._master.get("server")
160
161 logging.info("Establishing RPC connection to: %s" % server)
162
163 self.conn = xmlrpclib.Server(server)
164
165 def update_sources(self):
166 sources = self.conn.sources_get_all()
167
168 for source in sources:
169 source = Source(self, **source)
170
171 source.update()
172
173 def update_revision(self, source, revision):
174 self.conn.sources_update_revision(source.id, revision)
175
176 def package_add(self, source, pkg):
177 logging.info("Adding package: %s" % pkg.friendly_name)
178
179 # Collect data that is sent to the database...
180 info = {
181 "name" : pkg.name,
182 "epoch" : pkg.epoch,
183 "version" : pkg.version,
184 "release" : pkg.release,
185 "groups" : " ".join(pkg.groups),
186 "maintainer" : pkg.maintainer,
187 "license" : pkg.license,
188 "url" : pkg.url,
189 "summary" : pkg.summary,
190 "description" : pkg.description,
191 "supported_arches" : pkg.supported_arches,
192 "source_id" : source.id,
193 }
194
195 return self.conn.package_add(info)
196
197 def package_file_add(self, source, pkg_id, pkg):
198 logging.info("Adding package file: %s" % pkg.filename)
199
200 info = {
201 "path" : pkg.filename[len(source.path) + 1:],
202 "source_id" : source.id,
203 "type" : pkg.type,
204 "arch" : pkg.arch,
205 "summary" : pkg.summary,
206 "description" : pkg.description,
207 "requires" : " ".join(pkg.requires),
208 "provides" : "",
209 "obsoletes" : "",
210 "conflicts" : "",
211 "url" : pkg.url,
212 "license" : pkg.license,
213 "maintainer" : pkg.maintainer,
214 "size" : pkg.size,
215 "hash1" : pkg.hash1,
216 "build_host" : pkg.build_host,
217 "build_id" : pkg.build_id,
218 "build_time" : pkg.build_time,
219 "uuid" : pkg.uuid,
220 }
221
222 if isinstance(pkg, packages.BinaryPackage):
223 info.update({
224 "provides" : " ".join(pkg.provides),
225 "obsoletes" : " ".join(pkg.obsoletes),
226 "conflicts" : " ".join(pkg.conflicts),
227 })
228
229 return self.conn.package_file_add(pkg_id, info)
230
231 def package_remove(self, source, pkg):
232 logging.info("Package '%s' has been removed." % pkg)
233