Esempio n. 1
0
def bv_packaging(name, type_, folder, make_options=None, platform_target=None):
    """Package a component with no dependency.

    Parameters
    ----------
    name   : package name.
    type_  : type of package: run, doc, usrdoc, devdoc, test.
    folder : destination full path.
    platform_target : target platform to generate packages for
    """
    args = [
        os.path.join(Paths.BV_BIN,
                     Paths.binary_name(Paths.BV_ENV_HOST, System.platform())),
        Paths.binary_name('python', System.platform()),
        os.path.join(Paths.BV_BIN, Paths.BV_PACKAGING), 'dir', '-o', folder,
        '--wrappers', '--no-deps', '--installer'
    ]

    if make_options is not None and len(make_options.strip()) > 0:
        args += ['--make-options', make_options]

    if platform_target is not None and len(platform_target.strip()) > 0:
        args += ['--platform-target', platform_target]

    args += ['+name=%s,type=%s' % (name, type_)]
    subprocess.check_call(args)
    def __create_hacks(self):
        "Regroup all hacks for specific problems."
        qt_menu_nib = None
        if System.platform() == System.MacOSX \
                and self.args.qt_menu_nib is None:
            # try to find qt_menu.nib in QtIFW
            import distutils.spawn
            binarycreator = distutils.spawn.find_executable(
                Paths.IFW_BINARYCREATOR)
            if binarycreator:
                real_path = os.path.realpath(binarycreator)
                path = os.path.dirname(os.path.dirname(real_path))
                qt_menu_nib = os.path.join(
                    path, "Uninstaller.app/Contents/Resources/qt_menu.nib")
                if not os.path.isdir(qt_menu_nib):
                    qt_menu_nib = None  # doesn't work
        else:
            qt_menu_nib = self.args.qt_menu_nib

        for installer in (self.args.installer, self.args.offline_installer):
            if installer is not None:
                if qt_menu_nib is not None:
                    src = qt_menu_nib
                    dst = "%s.app/Contents/Resources/qt_menu.nib" % installer
                    try:
                        shutil.copytree(src, dst)
                    except Exception:
                        # copying file attributes on the network may fail,
                        # but copy is OK.
                        pass

                if System.platform() == System.MacOSX \
                        and not self.args.repository_only:
                    # create .dmg
                    import distutils.spawn
                    create_dmg = distutils.spawn.find_executable('create-dmg')
                    if create_dmg:
                        installer_path = '%s.dmg' % installer
                        cmd = [
                            create_dmg, '--volname', 'BrainVISA-installer',
                            '--volicon',
                            '%s_tmp/config/icon.png' % self.args.repository,
                            installer_path,
                            '%s.app' % installer
                        ]
                        subprocess.check_call(cmd)
                    else:
                        raise RuntimeError('Impossible to find create-dmg '
                                           'executable. Please check it is '
                                           'available on the system.')

                    # build the MD5 sum file
                    import hashlib
                    m = hashlib.md5()
                    m.update(open(installer_path, 'rb').read())
                    mdsum = m.digest()
                    mdsum_str = ''.join(['%02x' % ord(x) for x in mdsum])
                    open(installer_path + '.md5', 'w').write(mdsum_str)
Esempio n. 3
0
def ifw_version(binary_creator_command=None, platform=None):
    """Try to guess IFW version.
    As the commands do not provide this info, all we can do for now is to try
    to find the "devtool" command, and guess it is version 2 if it is found,
    and 1 otherwise.
    """
    if not platform:
        platform = System.platform()

    if not binary_creator_command:
        bc = distutils.spawn.find_executable(
            Paths.binary_name(Paths.IFW_BINARYCREATOR, platform))
    else:
        bc = binary_creator_command

    if not bc:
        return []  # undefined
    real_bc = os.path.realpath(bc)
    path = os.path.dirname(real_bc)
    if os.path.exists(
            os.path.join(path, Paths.binary_name(Paths.IFW_DEVTOOL,
                                                 platform))):
        return [
            2,
        ]
    return [
        1,
    ]
Esempio n. 4
0
def repogen(path_repository_in,
            path_repository_out,
            components=None,
            update=False,
            exclude=None):  # pylint: disable=R0913
    """The repogen tool generates an online IFW repositoriy.

    Parameters
    ----------
    path_repository_in  : full path of temporary repository.
    path_repository_out : full path of IFW repository.
    components          : additional components (default None).
    update              : True if the existing IFW repository must be updated.
    exclude             : list of excluded package's names (default None).
    """
    param_components = [components.join(',')] if exclude else []
    param_update = ['--update'] if update else []
    param_exclude = ['--exclude', exclude.join(',')] if exclude else []
    # param_updateurl = '-u %s' % updateurl  if updateurl else ''
    param_packages = ["-p", "%s/packages" % path_repository_in]

    cmd = [Paths.binary_name(Paths.IFW_REPOGEN, System.platform())] \
        + param_packages + param_update + param_exclude \
        + param_components + [path_repository_out]
    # param_updateurl,
    print(' '.join(cmd))
    subprocess.check_call(cmd)
Esempio n. 5
0
def translate_path(path,
                   platform_target,
                   translation_type=PathTranslationType.HOST_TO_TARGET):
    """Translate path between platform host and target."""
    platform_host = System.platform()
    platform_host_family = System.platform_family(platform_host)
    platform_target_family = System.platform_family(platform_target)

    # print('==== translate_path')
    if platform_host != platform_target.upper():
        if platform_host_family == System.Family.Linux \
                and platform_target_family == System.Family.Win:
            return translate_path_wine(path, translation_type)
        else:
            raise RuntimeError('No known path translation method between '
                               '%s (%s family) and %s (%s family) systems' %
                               (platform_host, platform_host_family,
                                platform_target, platform_target_family))

    else:
        return path
Esempio n. 6
0
 def exception_info_by_name(self, name, param):
     "Return the exception value from name and param."
     exceptions = self.root.find('EXCEPTIONS')
     if exceptions is not None:
         for exception in exceptions:
             if exception.tag == 'INFO' and \
                     exception.attrib.get('NAME') == name and \
                     exception.attrib.get('PARAM') == param:
                 platform = exception.attrib.get('PLATFORM')
                 if platform:
                     if platform != System.platform():
                         return None
                 return exception.attrib.get('VALUE')
     return None
 def __create_installer(self):
     "Create the binary installer(s)."
     if not self.args.repository_only:
         if self.args.installer is not None:
             if self.args.offline_installer is None:
                 online_only = self.args.online_only
                 offline_only = self.args.offline_only
             else:
                 online_only = True
                 offline_only = False
             logging.getLogger().info(MESSAGE_BVI_INSTALLER)
             binarycreator(
                 self.args.installer,
                 "%s_tmp" % self.args.repository,
                 online_only=online_only,
                 offline_only=offline_only,
                 platform_target=self.args.platform_target if
                 self.args.platform_target else System.platform().lower(),
                 command=self.args.binary_creator_command
                 if self.args.binary_creator_command else None)
         if self.args.offline_installer is not None:
             online_only = False
             offline_only = self.args.offline_only
             logging.getLogger().info(MESSAGE_BVI_OFFLINE_INSTALLER)
             binarycreator(
                 self.args.offline_installer,
                 "%s_tmp" % self.args.repository,
                 additional_repositories=[
                     os.path.join("%s_tmp", "packages") % r
                     for r in self.args.additional_repositories
                 ],
                 online_only=online_only,
                 offline_only=offline_only,
                 platform_target=self.args.platform_target if
                 self.args.platform_target else System.platform().lower(),
                 command=self.args.binary_creator_command
                 if self.args.binary_creator_command else None)
Esempio n. 8
0
 def is_package_excluded(self, name):
     "Return False if the package must be excluded."
     exceptions = self.root.find('EXCEPTIONS')
     excluded = self.data_packages
     if exceptions is not None:
         for exception in exceptions:
             if (exception.tag == 'PACKAGE' and
                     exception.attrib.get('NAME') == name):
                 platform = exception.attrib.get('PLATFORM')
                 if platform and platform != System.platform():
                     continue
                 etype = exception.attrib.get('TYPE')
                 if etype == 'DATA_PACKAGE':
                     excluded = not self.data_packages
                 elif etype == 'ALL':
                     return True
     return excluded
Esempio n. 9
0
 def init_from_configuration(self, element):
     "Initialize from an XML element from XML configuration file."
     self.Url = element.text.strip()
     self.Url = self.Url.replace('@release@', self.Release)
     self.Url = self.Url.replace('@platform@', self.PlatformName)
     att_platform = element.attrib.get('PLATFORM')
     self.Enabled = '1' if att_platform is None \
         or System.platform().lower() == att_platform.lower() else '0'
     # att_private = element.attrib.get('PRIVATE')
     # if att_private is not None and att_private in ('1', 'True', 'true'):
     # self.Enabled = '0'
     if self.Url.startswith("file://") and not self.private:
         self.Enabled = '0'
     self.Username = element.attrib.get('USERNAME')
     self.Password = element.attrib.get('PASSWORD')
     self.DisplayName = element.attrib.get('DISPLAYNAME')
     return self
Esempio n. 10
0
def archivegen(folder):
    """The archivegen tool compresses the files in folder as a 7zip archive.

    The archive will have the same name what the folder with the 7z extension.

    Parameter
    ---------
    folder:
        folder with data which must be compressed.
    """
    command = Paths.binary_name(Paths.IFW_ARCHIVEGEN, System.platform())
    archive = '%s.7z' % folder

    args = [command] + Paths.ARCHIVEGEN_OPTIONS + [archive, '%s' % folder]
    print(' '.join(args))
    if os.path.exists(archive):
        os.unlink(archive)
    process = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=folder)
    result = process.wait()
    logging.getLogger().info(result)
    if result < 0:
        raise BVIException(BVIException.ARCHIVEGEN_FAILED, folder)
    def __init__(self, argv):
        "Parse the command line arguments."
        parser = argparse.ArgumentParser(
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description=MESSAGE_HELP_HEADER,
            epilog=MESSAGE_HELP_EPILOG)

        parser.add_argument('-p',
                            '--projects',
                            type=valid_projects,
                            nargs='+',
                            metavar='project',
                            help='Projects to include in the installer and '
                            'the repository')

        parser.add_argument('-n',
                            '--names',
                            type=valid_names,
                            nargs='+',
                            metavar='name',
                            help='Package names to include in the installer '
                            'and the repository')

        parser.add_argument('-t',
                            '--types',
                            nargs='+',
                            choices=['run', 'dev', 'usrdoc', 'devdoc', 'test'],
                            default=['run', 'dev', 'usrdoc', 'devdoc', 'test'],
                            metavar='types',
                            help='Package\'s types (default: "run", "dev", '
                            '"usrdoc", "devdoc" and "test")')

        parser.add_argument('--online-only',
                            action='store_true',
                            help='Create only an online installer')

        parser.add_argument('--offline-only',
                            action='store_true',
                            help='Create only an offline installer')

        parser.add_argument('--repository-only',
                            action='store_true',
                            help='Create only the repository for the online '
                            'installer')

        parser.add_argument('--compress',
                            action='store_true',
                            help='The packages data in the temporary '
                            'repository will be compressed [experimental].')

        parser.add_argument(
            '-i',
            '--installer',
            default=None,
            metavar='file',
            help=
            'Installer name (optional only if --repository-only is specified). Note: if an additional offline installer (-j option) is specified, -i will be an online-only installer. Otherwise it will follow the options --online-only and --offline-only if they are specified, with the same meaning as in the binarycreator tool.'
        )

        parser.add_argument(
            '-j',
            '--offline-installer',
            default=None,
            metavar='file',
            help=
            'Offline installer name (optional). The offline installer will contain all packages, ignoring --online-only option, but still following --offline-only if specified. Using both -i and -j will generate two installer binaries, one online and one offline.'
        )

        parser.add_argument('-r',
                            '--repository',
                            default=None,
                            metavar='dir',
                            required=True,
                            help='Repository name.')

        parser.add_argument(
            '-f',
            '--additional-repositories',
            default=[],
            nargs='+',
            metavar='additional_dir',
            help=
            'Additional existing repositories (optional). This is particularly usefull for offline installer that need to contain all installation packages. This packages may exists in separated repositories.'
        )

        parser.add_argument('-c',
                            '--config',
                            type=valid_config,
                            default=None,
                            metavar='file',
                            help='Additional configuration XML file')

        parser.add_argument('--no-main-config',
                            action='store_true',
                            help='don\'t read the main BrainVisa config file. '
                            'Must be used with the -c option')

        parser.add_argument(
            '--qt_menu_nib',
            default=None,
            help=
            'For Mac OS X 10.5: copy the specified qt_menu.nib folder in the \
            installer OSX App package. Use this option if the OS X installer \
            did not find the qt_menu.nib folder.')

        parser.add_argument('--release',
                            type=valid_release,
                            default=None,
                            help='force repository release version. default: '
                            'use BrainVISA release version from the current '
                            'build.')

        parser.add_argument(
            '--i2bm',
            action='store_true',
            help=
            'Include I2BM private components - by default such private components are excluded from the package.'
        )

        parser.add_argument('--data',
                            action='store_true',
                            help='Package only data packages (which are '
                            'excluded from normal packaging).')

        parser.add_argument('-v',
                            '--version',
                            action='version',
                            version='%(prog)s [' + __status__ + '] - ' +
                            __version__,
                            help='Show the version number.')

        parser.add_argument('--no-thirdparty',
                            action='store_true',
                            help='Do not package thirdparty libraries, and '
                            'ignore them in dependencies.')

        parser.add_argument(
            '--no-dependencies',
            action='store_true',
            help=
            'Do not package dependencies: take only explicitely named packages/projects. Their dependencies will still be marked so they must either already exist in the repository, either exist in another repository.'
        )

        parser.add_argument('--platform-target',
                            dest='platform_target',
                            default=None,
                            help='target platform to use for cross '
                            'compilation (default: %s)' %
                            System.platform().lower())

        parser.add_argument('--platform_name',
                            default=None,
                            help='force platform name in packages repository '
                            'URL (default: %s)' % System.platform().lower())

        parser.add_argument('--make-options',
                            dest='make_options',
                            default=None,
                            help='make options to use during components '
                            'packaging')

        parser.add_argument('--binary-creator-cmd',
                            dest='binary_creator_command',
                            default=None,
                            help='Path to the binary creator command to use '
                            'to generate the installer.')

        parser.add_argument('--archivegen-cmd',
                            dest='archivegen_cmd',
                            default=None,
                            help='Path to the archivegen command to use to '
                            'generate 7z archives. Default: look (in that '
                            'order) for: 7z, 7za, archivegen.')

        parser.add_argument('--archivegen-opts',
                            dest='archivegen_opts',
                            default='',
                            help='archivegen command options. Default: none '
                            'for archivegen, "a" for 7z/7za. Options are '
                            'split by space character.')

        parser.add_argument('--skip-repos',
                            dest='skip_repos',
                            action='store_true',
                            help='Skip initial (temp) repository creation. '
                            'Assumes it has already been done.')

        parser.add_argument('--skip-repogen',
                            dest='skip_repogen',
                            action='store_true',
                            help='Skip repogen (final repository creation + '
                            'compression). Assumes it has already been done.')

        parser.add_argument('--skip-existing',
                            dest='skip_existing',
                            action='store_true',
                            help='Don\'t rebuild components which already '
                            'have a directory in the temporary repository '
                            'directory.')

        self.__configure_logging()
        args = parser.parse_args(argv[1:])

        if args.online_only + args.offline_only + args.repository_only > 1:
            logging.getLogger().error(
                "[ BVI ] Error: --online-only, --offline-only and "
                "--repository-only are incompatible.")
            exit(1)

        if args.qt_menu_nib is not None:
            if args.installer is None and args.offline_installer is None:
                logging.getLogger().error(
                    "[ BVI ] Error: --installer and/or --offline_installer "
                    "must be specified if --qt_menu_nib is used.")
                exit(1)
            if System.platform() != System.MacOSX:
                logging.getLogger().error(
                    "[ BVI ] Error: --qt_menu_nib is only for Mac OS X.")
                exit(1)

        self.args = args
        self.logging_level = logging.DEBUG
        if self.args.no_main_config:
            kwargs = {'filename': self.args.config}
        else:
            kwargs = {'alt_filename': self.args.config}
        if self.args.release is not None:
            kwargs['release'] = self.args.release
        if self.args.no_thirdparty:
            kwargs['with_thirdparty'] = False
        if self.args.no_dependencies:
            kwargs['with_dependencies'] = False
        if self.args.platform_target:
            kwargs['platform_target'] = self.args.platform_target
            if not self.args.platform_name:
                # Defaultly use target platform as platform name
                self.args.platform_name = self.args.platform_target
        if self.args.platform_name:
            kwargs['platform_name'] = self.args.platform_name

        kwargs['make_options'] = self.args.make_options
        kwargs['binary_creator_command'] = self.args.binary_creator_command
        kwargs['archivegen_cmd'] = self.args.archivegen_cmd
        kwargs['archivegen_opts'] = self.args.archivegen_opts.split(' ')
        if kwargs['archivegen_opts'] == ['']:
            kwargs['archivegen_opts'] = []
        kwargs['skip_repos'] = self.args.skip_repos
        kwargs['skip_repogen'] = self.args.skip_repogen
        kwargs['skip_existing'] = self.args.skip_existing
        kwargs['data_packages'] = self.args.data
        kwargs['private_repos'] = self.args.i2bm
        self.config = Configuration(**kwargs)
        self.components = self.__group_components()
Esempio n. 12
0
    def __init__(self, filename=Paths.BVI_CONFIGURATION, alt_filename=None,
                 release=None, with_dependencies=True, with_thirdparty=True,
                 platform_target=None, platform_name=None, skip_repos=False,
                 skip_repogen=False, skip_existing=False, data_packages=False,
                 private_repos=False, make_options=None,
                 binary_creator_command=None, archivegen_cmd=None,
                 archivegen_opts=[]):
        "filename is the default configuration file in share, \
        alt_filename is an optional configuration file \
        to override the default configuration."
        self.tree = None
        self.root = None
        self.Name = None
        self.Version = None
        self.Title = None
        self.Publisher = None
        self.Producturl = None
        self.Targetdir = None
        self.Admintargetdir = None
        self.Icon = None
        self.Logo = None
        self.Watermark = None
        self.MaintenanceToolName = None
        self.Allownonasciicharacters = None
        self.Allowspaceinpath = None
        self.Repositories = list()
        self.Licenses = list()
        self.Categories = list()
        self.Release = release
        if binary_creator_command:
            self.IFWVersion = ifw_version(binary_creator_command,
                                          platform_target)
        else:
            self.IFWVersion = None

        if platform_name is None:
            platform_name = System.platform().lower()
        self.PlatformName = platform_name
        if platform_target is None:
            platform_target = System.platform().lower()
        self.platform_target = platform_target
        self.make_options = make_options
        self.binary_creator_command = binary_creator_command
        self.archivegen_opts = archivegen_opts
        self.with_dependencies = with_dependencies
        self.with_thirdparty = with_thirdparty
        self.skip_repos = skip_repos
        self.skip_repogen = skip_repogen
        self.skip_existing = skip_existing
        self.data_packages = data_packages
        self.private_repos = private_repos
        self.read(filename)
        if alt_filename is not None:
            self.read(alt_filename)

        if archivegen_cmd is None:
            archivegen_opts = []
            archivegen_cmd = distutils.spawn.find_executable('7z')
            if archivegen_cmd is not None:
                archivegen_opts = ['a']
            else:
                archivegen_cmd = distutils.spawn.find_executable('7za')
                if archivegen_cmd is not None:
                    archivegen_opts = ['a']
                else:
                    archivegen_cmd \
                        = distutils.spawn.find_executable('archivegen')
        # print('archivegen_cmd:', archivegen_cmd)
        # print('archivegen_opts:', archivegen_opts)
        self.archivegen_cmd = archivegen_cmd
        self.archivegen_opts = archivegen_opts
        if self.archivegen_cmd is not None:
            Paths.IFW_ARCHIVEGEN = self.archivegen_cmd
            Paths.ARCHIVEGEN_OPTIONS = self.archivegen_opts
Esempio n. 13
0
def binarycreator(installer_path,
                  repository_path,
                  additional_repositories=[],
                  online_only=False,
                  offline_only=False,
                  exclude=None,
                  include=None,
                  platform_target=System.platform(),
                  command=None):
    """The binarycreator tool creates an IFW installer.

    Parameters
    ----------
    installer_path          : full path of installer binary.
    repository_path         : full path of temporary repository.
    additional_repositories : additional repositories to find packages in.
    online_only             : True if the installer is only online
                              (default False).
    offline_only            : True if the installer is only offline
                              (default False).
    exclude                 : list of excluded package's names (default None).
    include                 : list of included package's names (default None).
    platform_target         : target platform to generate installer binary on
                              (default is the host platform)
    command                 : binarycreator command to use (default:)
    """

    param_online_only = ['--online-only'] if online_only else []
    param_offline_only = ['--offline-only'] if offline_only else []
    param_exclude = ['--exclude', exclude.join(',')] if exclude else []
    param_include = ['--include', include.join('')] if include else []
    param_config = [
        '-c',
        translate_path('%s/config/config.xml' % repository_path,
                       platform_target)
    ]
    param_packages = [
        '-p',
        translate_path('%s/packages' % repository_path, platform_target)
    ]
    for r in additional_repositories:
        param_packages += ['-p', translate_path(r, platform_target)]

    path = os.path.dirname(installer_path)
    if not os.path.exists(path):
        os.makedirs(path)

    # Starts binary creator through target bv_env
    cmd = [command if command else Paths.binary_name(Paths.IFW_BINARYCREATOR,
                                                     platform_target)] \
        + param_online_only + param_offline_only + param_exclude \
        + param_include + param_config + param_packages \
        + [translate_path(installer_path, platform_target)]
    print(' '.join(cmd))
    subprocess.check_call(cmd)

    if System.platform() == System.MacOSX:
        return  # don't do the .md5 now: we must build the .dmg first.
    # build the MD5 sum file
    m = hashlib.md5()
    m.update(open(installer_path, 'rb').read())
    mdsum = m.digest()
    if sys.version_info[0] >= 3:
        mdsum_str = ''.join(['%02x' % x for x in mdsum])
    else:
        mdsum_str = ''.join(['%02x' % ord(x) for x in mdsum])
    open(installer_path + '.md5', 'w').write(mdsum_str)