Select Git revision
-
Rusty Russell authored
An exact mapping would be within_module_core(), but at this stage (MODULE_STATE_GOING) the init section is empty, and this is clearer. Reviewed-by:
Peter Oberparleiter <oberpar@linux.vnet.ibm.com> Signed-off-by:
Rusty Russell <rusty@rustcorp.com.au> Signed-off-by:
Jiri Kosina <jkosina@suse.cz>
Rusty Russell authoredAn exact mapping would be within_module_core(), but at this stage (MODULE_STATE_GOING) the init section is empty, and this is clearer. Reviewed-by:
Peter Oberparleiter <oberpar@linux.vnet.ibm.com> Signed-off-by:
Rusty Russell <rusty@rustcorp.com.au> Signed-off-by:
Jiri Kosina <jkosina@suse.cz>
main.py 10.18 KiB
#!/usr/bin/python
from __future__ import print_function
import os
from pathlib import Path
from tempfile import TemporaryDirectory
from urllib.request import pathname2url
import osc.conf as conf
import osc.core
from osc.oscerr import OscIOError, WrongArgs
from debian.deb822 import Changes, Dsc
statfrmt = osc.core.statfrmt
def get_objects_from_file(filename):
"""
Return a tuple containing (None or a Changes object), a Dsc object,
and the filename of the .dsc file.
"""
changes = None
dsc = None
dscfile = None
try:
with open(filename) as f:
if filename.endswith('.changes'):
changes = Changes(f)
if 'source' not in changes['architecture'].split():
raise WrongArgs(filename + ' does not contain source code')
for rec in changes['files']:
if rec['name'].endswith('.dsc'):
dscfile = Path(filename).with_name(rec['name'])
with open(dscfile) as fdsc:
dsc = Dsc(fdsc)
return changes, dsc, dscfile
else:
raise WrongArgs(filename + ' does not list a .dsc file')
elif filename.endswith('.dsc'):
dsc = Dsc(f)
dscfile = filename
return changes, dsc, dscfile
else:
raise WrongArgs(filename + ' is not a .dsc or .changes file')
except FileNotFoundError as e:
raise OscIOError(e, "File " + filename + " not found.")
except IOError as e:
raise OscIOError(e, "File " + filename + " couldn't be read.")
class DPut(object):
def __init__(self, project_name=None, package_name=None, working_dir=None):
self.project_name = project_name
self.package_name = package_name
self.working_dir = Path(working_dir)
def _create_package(self):
"""
Create a package on the remote server
"""
current_path = os.getcwd()
project_path = self.working_dir / self.project_name
os.chdir(project_path)
osc.core.createPackageDir(self.package_name)
project = osc.core.Project(".", getPackageList=False)
project.update()
project.commit()
os.chdir(current_path)
def get_package_object(self):
"""
Returns a valid package object depending if the package already exists or
if it needs to be created
"""
# this one is needed because there's two ways of getting the package object
# first one fails if the folder already exists, the second one fail if it doesn't
path = self.working_dir / self.project_name / self.package_name
if path.is_dir():
os.chdir(path)
return osc.core.Package('.')
elif not path.exists():
path.mkdir()
os.chdir(path)
package = osc.core.Package.init_package(conf.config['apiurl'],
project=self.project_name,
package=self.package_name,
dir='.',
meta=False)
# Updating the package files with size_limit set to 1 after
# the initialisation allows us to start with a mostly
# clean working directory and still proceed without downloading
# all of the current contents only to possibly remove it in the
# first step; if we were to configure this in init_package,
# the setting would get stored in the local checkout config.
# We override the checkout formatter temporarily to prevent it
# from printing a scary file listing with all files deleted
# (which it prints because when files are skipped, it doesn’t
# find them in a local checkout).
print("Existing files in the package:")
osc.core.statfrmt = lambda _, file: statfrmt(' ', file)
package.update(size_limit=1)
osc.core.statfrmt = statfrmt
package.rev = package.latest_rev()
return package
else:
raise IOError("Package folder couldn't be created")
def get_remote_file_list(self, package):
"""
Returns a list of files inside an specific package
"""
return {
f.name: f for f in osc.core.meta_get_filelist(conf.config['apiurl'], self.project_name, self.package_name, verbose=True)
}
def do_dput(self, subcmd, opts, *args):
if len(args) < 1:
raise WrongArgs('Missing the project name and the source package.\n\n'
+ self.get_cmd_help('dput'))
if len(args) == 1:
if opts.no_auto:
raise WrongArgs('Missing the project name.\n\n'
+ self.get_cmd_help('dput'))
dsc_or_changes_file = args[0]
cwd = Path.cwd()
if osc.core.is_project_dir(cwd) or osc.core.is_package_dir(cwd):
proj_name = osc.core.store_read_project(cwd)
elif osc.core.is_project_dir(cwd.parent) or osc.core.is_package_dir(cwd.parent):
proj_name = osc.core.store_read_project(cwd.parent)
else:
raise WrongArgs('Can\'t guess the project name and none passed.')
print("Automatically detected the project to submit changes to:", proj_name)
elif len(args) == 2:
proj_name, dsc_or_changes_file = args
else:
raise WrongArgs('Too many arguments, not sure what to do.\n\n'
+ self.get_cmd_help('dput'))
with TemporaryDirectory('_oscdput') as working_dir:
# get debian .change object before moving current path to the
# working_dir
changes, dsc, dsc_file = get_objects_from_file(dsc_or_changes_file)
package_name = dsc.get("Source")
dput = DPut(proj_name, package_name, working_dir)
# Filenames in the .dsc are relative to the directory where it appears.
# We need to make it absolute before we chdir elsewhere.
dsc_or_changes_file = Path(dsc_or_changes_file).resolve()
dsc_file = Path(dsc_file).resolve()
dscdir = Path(dsc_file).resolve().parent
# Get the list of packages
# TODO: Probably it can be done after checking out the project
# So we can save one http request
package_list = osc.core.meta_get_packagelist(
conf.config['apiurl'], proj_name)
# Start the project
osc.core.Project.init_project(conf.config['apiurl'],
dir=dput.working_dir / proj_name,
project=proj_name)
# check if the package exists on server, otherwise create one
if package_name not in package_list:
dput._create_package()
# it also changes the current_dir to the package dir
package = dput.get_package_object()
# defining file list, so we can decide which one to delete
remote_file_list = dput.get_remote_file_list(package)
local_file_list = [f["name"]
for f in dsc.get("Files")] # local lambda list
# Remove old files, but only those that are part of the Debian package
superseded = set()
retained = set()
# osc <1.6.1 doesn't automatically escape path members.
should_escape_filename = osc.core.makeurl('', ['+']) == '/+'
for f in remote_file_list.keys():
if f.endswith('.dsc'):
u = osc.core.makeurl(conf.config['apiurl'],
['source',
proj_name,
package_name,
pathname2url(f)
if should_escape_filename
else f],
query={})
remote_dsc = Dsc(osc.core.streamfile(u, bufsize='line'))
for entry in remote_dsc.get('Files'):
if entry['name'] in remote_file_list:
superseded.add(entry['name'])
superseded.add(f)
elif f.endswith('.changes'):
superseded.add(f)
else:
retained.add(f)
retained -= superseded
# It may happen that there were some files lying around which
# we still want to overwrite
retained -= set(local_file_list)
# reset the file list, so that we can add files freely without
# osc barking at us each time we re-add an existing file
package.filenamelist = []
# adding local_file_list to the package as links
for f in local_file_list:
filepath = dscdir / f
os.symlink(filepath, f)
package.addfile(f)
f = dsc_file.name
os.symlink(dsc_file, f)
package.addfile(f)
if opts.maintained_in_git:
open('MAINTAINED_IN_GIT.txt', 'w+').close()
package.addfile('MAINTAINED_IN_GIT.txt')
# a plain .dsc file has very little metadata, so "hello_2.10-1.dsc"
# is about the best commit message we can provide without unpacking
# the source package
msg = f
if changes is not None:
f = dsc_or_changes_file.name
os.symlink(dsc_or_changes_file, f)
package.addfile(f)
msg = changes.get('changes', msg)
added = set(package.to_be_added)
# We don’t want to create commits with no actual changes.
# We only proceed with the commit in these cases:
# 1. If any new file is added
# 2. Any of the files is of a different size than recorded
# 3. Any of the files has a different MD5 hash than recorded
files_changed = (any(added - superseded - retained) or
any(os.path.getsize(f) != remote_file_list[f].size for f in superseded & added) or
any(osc.core.dgst(f) != remote_file_list[f].md5 for f in superseded & added))
if files_changed:
package.commit(msg=msg)
else:
print("No changes, not submitting anything")