Skip to content
Snippets Groups Projects
Select Git revision
  • 0f0836b7eb1b9d14862ee40c7856227a3ead70db
  • vme-testing default
  • ci-test
  • master
  • remoteproc
  • am625-sk-ov5640
  • pcal6534-upstreaming
  • lps22df-upstreaming
  • msc-upstreaming
  • imx8mp
  • iio/noa1305
  • vme-next
  • vme-next-4.14-rc4
  • v4.14-rc4
  • v4.14-rc3
  • v4.14-rc2
  • v4.14-rc1
  • v4.13
  • vme-next-4.13-rc7
  • v4.13-rc7
  • v4.13-rc6
  • v4.13-rc5
  • v4.13-rc4
  • v4.13-rc3
  • v4.13-rc2
  • v4.13-rc1
  • v4.12
  • v4.12-rc7
  • v4.12-rc6
  • v4.12-rc5
  • v4.12-rc4
  • v4.12-rc3
32 results

base.c

Blame
  • 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")