def stack_depends(metadata, distro_name, platform_name):
    """
    @return: list of debian stack dependencies
    @rtype: [str]
    """
    stackdeps = metadata.get("depends", [])
    stackdeps = ["ros-%s-%s" % (distro_name, debianize_name(s)) for s in stackdeps]

    return stackdeps
def stack_depends(metadata, distro_name, platform_name):
    """
    @return: list of debian stack dependencies
    @rtype: [str]
    """
    stackdeps = metadata.get('depends', [])
    stackdeps = [
        'ros-%s-%s' % (distro_name, debianize_name(s)) for s in stackdeps
    ]

    return stackdeps
def make_source_deb(distro_name, stack_name, stack_version, os_platform_name,
                    staging_dir):
    """
    @param os_platform_name: Name of OS platform/version, e.g. 'lucid'
    @type  os_platform_name: str
    @return: list of source-deb files
    @rtype: [str]
    """
    debian_name = 'ros-%s-%s' % (distro_name, debianize_name(stack_name))

    tmpl_d = os.path.join(roslib.packages.get_pkg_dir('rosdeb'), 'resources',
                          'source_deb')

    tarball = os.path.join(staging_dir,
                           "%s-%s.tar.bz2" % (stack_name, stack_version))
    if not os.path.exists(tarball):
        raise Exception("tarball must be copied to staging directory first")

    # keep track of files we've copied in to modify
    files = []

    # make STACK/debian
    stack_d = os.path.join(staging_dir, stack_name)
    debian_d = os.path.join(stack_d, 'debian')
    if not os.path.exists(debian_d):
        os.makedirs(debian_d)

    # Files which go into debian dir
    for f in ['rules', 'compat', 'postinst']:
        files.append((os.path.join(tmpl_d, f), os.path.join(debian_d, f)))

    # Files which go into stack dir
    for f in [
            'fixpc.py', 'fixbinpath.py', 'fixrpath.py', 'Makefile',
            'setup_deb.sh', 'purge_build.py', 'update_version.py',
            'gen_versioned_debs.py'
    ]:
        files.append((os.path.join(tmpl_d, f), os.path.join(stack_d, f)))

    # Files which go into stack dir and are different for ros stack
    if stack_name == 'ros':
        for f in ['setup_deb.sh', 'Makefile']:
            f_src = f + '-ros'
            files.append((os.path.join(tmpl_d,
                                       f_src), os.path.join(stack_d, f)))

    # Files which go into stack dir and only exist for ros
    if stack_name == 'ros':
        for f in ['setup.sh', 'setup.bash', 'setup.zsh', '.rosinstall']:
            files.append((os.path.join(tmpl_d, f), os.path.join(stack_d, f)))

    for src, dst in files:
        with open(src, 'r') as f:
            src_text = f.read()

        dst_text = src_text.replace('${ROS_DISTRO_NAME}', distro_name)
        dst_text = dst_text.replace('${ROS_STACK_NAME}', stack_name)
        dst_text = dst_text.replace('${ROS_STACK_DEBIAN_NAME}', debian_name)
        dst_text = dst_text.replace('${ROS_STACK_VERSION}', stack_version)
        with open(dst, 'w') as f:
            f.write(dst_text)

        # copy permission modes
        s = os.stat(src)
        os.chmod(dst, s.st_mode)

    # CONTROL: read in the control YAML data and convert it to an actual control file
    control_yaml = os.path.join(staging_dir,
                                '%s-%s.yaml' % (stack_name, stack_version))
    with open(control_yaml, 'r') as f:
        metadata = yaml.load(f.read())
    if not type(metadata) == dict:
        raise Exception("invalid control file: %s\nMetadata is [%s]" %
                        (control_yaml, metadata))

    # make distro-specific
    metadata['package'] = debian_name
    with open(os.path.join(debian_d, 'control'), 'w') as f:
        f.write(
            control_file(metadata, distro_name,
                         os_platform_name).encode('utf-8'))

    # CHANGELOG
    with open(os.path.join(debian_d, 'changelog'), 'w') as f:
        f.write(changelog_file(metadata, os_platform_name).encode('utf-8'))

    # We must use a build-version starting with a letter greater than r
    build_version = 's$BUILD_VERSION'

    with open(os.path.join(debian_d, 'changelog.tmp'), 'w') as f:
        f.write(changelog_file(metadata, os_platform_name, build_version))

    # MD5Sum of original stack tar.bz2:
    with open(os.path.join(stack_d, '%s-%s.md5' % (stack_name, stack_version)),
              'w') as mf:
        with open(
                os.path.join(staging_dir,
                             '%s-%s.tar.bz2' % (stack_name, stack_version)),
                'r') as f:
            m = hashlib.md5()
            m.update(f.read())
            mf.write('%s  %s\n' % (m.hexdigest(), '../%s-%s.tar.bz2' %
                                   (stack_name, stack_version)))

    # Note: this creates 3 files.  A .dsc, a .tar.gz, and a .changes
    check_call(['dpkg-buildpackage', '-S', '-uc', '-us'], cwd=stack_d)

    # SOURCE DEB: .dsc plus tarball of debian dir. Ignore the changes for now
    f_name = "%s_%s-0~%s" % (debian_name, stack_version, os_platform_name)
    files = [
        os.path.join(staging_dir, f_name + ext) for ext in ('.dsc', '.tar.gz')
    ]
    for f in files:
        assert os.path.exists(f), "File: %s does not exist" % f

    return files
def control_data(stack_name, stack_version, md5sum, stack_file=None):
    """
    Generate metadata for control file. Cannot generate debian dependencies as these are platform specific.
    
    @type  stack_name: name of stack
    @type  stack_name: str
    @type  stack_version: stack version id
    @type  stack_version: str
    @param stack_file: location of stack file, or None to use default rosstack lookup
    @type  stack_file: str
    """
    import roslib.stack_manifest
    if stack_file is None:
        stack_file = roslib.stack_manifest.stack_file(stack_name)
    m = roslib.stack_manifest.parse_file(stack_file)

    metadata = {}

    metadata['md5sum'] = md5sum  #3301
    metadata['stack'] = stack_name
    metadata['package'] = debianize_name(stack_name)
    metadata['version'] = stack_version
    metadata['homepage'] = m.url
    if m.author.startswith('Maintained by '):
        metadata['maintainer'] = m.author[len('Maintained by '):]
    else:
        metadata['maintainer'] = m.author
    metadata['priority'] = 'optional'
    if m.brief:
        # 60-char limit on control files
        metadata['description-brief'] = m.brief[:60]
    else:
        metadata['description-brief'] = m.brief[:60]

    try:
        description = convert_html_to_text(m.description).rstrip()
    except:
        description = "unknown"

    # per debian spec, single-space pad to signal paragraph
    desc_padded = ''
    for l in description.split('\n'):
        desc_padded += ' ' + l + '\n'
    metadata['description-full'] = desc_padded.rstrip()

    # do deps in two parts as ros stack depends need to become version
    # locked later on due to lack of ABI compat
    metadata['depends'] = [d.stack for d in m.depends]
    metadata['rosdeps'] = rosdeps = {}
    for platform in platforms():
        try:
            rosdeps[platform] = stack_rosdeps(stack_name,
                                              os.path.dirname(stack_file),
                                              platform)
        except Exception as e:
            # #3435
            # TODO: this is a hack that should be turned into a typed exception
            if "cannot generate" in str(e):
                sys.stderr.write("Error with platform [%s]: %s\n" %
                                 (platform, str(e)))
            # ignore other failures as these are generally unsupported
            # platforms. Later logic is responsible for erroring if
            # control file is missing bindings, and unit tests on
            # stack_rosdeps verify its functionality

    return metadata
def make_source_deb(distro_name, stack_name, stack_version, os_platform_name, staging_dir):
    """
    @param os_platform_name: Name of OS platform/version, e.g. 'lucid'
    @type  os_platform_name: str
    @return: list of source-deb files
    @rtype: [str]
    """
    debian_name = "ros-%s-%s" % (distro_name, debianize_name(stack_name))

    tmpl_d = os.path.join(os.path.dirname(__file__), "resources", "source_deb")

    tarball = os.path.join(staging_dir, "%s-%s.tar.bz2" % (stack_name, stack_version))
    if not os.path.exists(tarball):
        raise Exception("tarball must be copied to staging directory first")

    # keep track of files we've copied in to modify
    files = []

    # make STACK/debian
    stack_d = os.path.join(staging_dir, stack_name)
    debian_d = os.path.join(stack_d, "debian")
    if not os.path.exists(debian_d):
        os.makedirs(debian_d)

    # Files which go into debian dir
    for f in ["rules", "compat", "postinst"]:
        files.append((os.path.join(tmpl_d, f), os.path.join(debian_d, f)))

    # Files which go into stack dir
    for f in [
        "fixpc.py",
        "fixbinpath.py",
        "fixrpath.py",
        "Makefile",
        "setup_deb.sh",
        "purge_build.py",
        "update_version.py",
        "gen_versioned_debs.py",
    ]:
        files.append((os.path.join(tmpl_d, f), os.path.join(stack_d, f)))

    # Files which go into stack dir and are different for ros stack
    if stack_name == "ros":
        for f in ["setup_deb.sh", "Makefile"]:
            f_src = f + "-ros"
            files.append((os.path.join(tmpl_d, f_src), os.path.join(stack_d, f)))

    # Files which go into stack dir and only exist for ros
    if stack_name == "ros":
        for f in ["setup.sh", "setup.bash", "setup.zsh", ".rosinstall"]:
            files.append((os.path.join(tmpl_d, f), os.path.join(stack_d, f)))

    for src, dst in files:
        with open(src, "r") as f:
            src_text = f.read()

        dst_text = src_text.replace("${ROS_DISTRO_NAME}", distro_name)
        dst_text = dst_text.replace("${ROS_STACK_NAME}", stack_name)
        dst_text = dst_text.replace("${ROS_STACK_DEBIAN_NAME}", debian_name)
        dst_text = dst_text.replace("${ROS_STACK_VERSION}", stack_version)
        with open(dst, "w") as f:
            f.write(dst_text)

        # copy permission modes
        s = os.stat(src)
        os.chmod(dst, s.st_mode)

    # CONTROL: read in the control YAML data and convert it to an actual control file
    control_yaml = os.path.join(staging_dir, "%s-%s.yaml" % (stack_name, stack_version))
    with open(control_yaml, "r") as f:
        metadata = yaml.load(f.read())
    if not type(metadata) == dict:
        raise Exception("invalid control file: %s\nMetadata is [%s]" % (control_yaml, metadata))

    # make distro-specific
    metadata["package"] = debian_name
    with open(os.path.join(debian_d, "control"), "w") as f:
        f.write(control_file(metadata, distro_name, os_platform_name).encode("utf-8"))

    # CHANGELOG
    with open(os.path.join(debian_d, "changelog"), "w") as f:
        f.write(changelog_file(metadata, os_platform_name).encode("utf-8"))

    # We must use a build-version starting with a letter greater than r
    build_version = "s$BUILD_VERSION"

    with open(os.path.join(debian_d, "changelog.tmp"), "w") as f:
        f.write(changelog_file(metadata, os_platform_name, build_version))

    # MD5Sum of original stack tar.bz2:
    with open(os.path.join(stack_d, "%s-%s.md5" % (stack_name, stack_version)), "w") as mf:
        with open(os.path.join(staging_dir, "%s-%s.tar.bz2" % (stack_name, stack_version)), "r") as f:
            m = hashlib.md5()
            m.update(f.read())
            mf.write("%s  %s\n" % (m.hexdigest(), "../%s-%s.tar.bz2" % (stack_name, stack_version)))

    # Note: this creates 3 files.  A .dsc, a .tar.gz, and a .changes
    check_call(["dpkg-buildpackage", "-S", "-uc", "-us"], cwd=stack_d)

    # SOURCE DEB: .dsc plus tarball of debian dir. Ignore the changes for now
    f_name = "%s_%s-0~%s" % (debian_name, stack_version, os_platform_name)
    files = [os.path.join(staging_dir, f_name + ext) for ext in (".dsc", ".tar.gz")]
    for f in files:
        assert os.path.exists(f), "File: %s does not exist" % f

    return files
def make_source_deb(distro_name, stack_name, stack_version, os_platform_name, staging_dir):
    """
    @param os_platform_name: Name of OS platform/version, e.g. 'lucid'
    @type  os_platform_name: str
    @return: list of source-deb files
    @rtype: [str]
    """
    debian_name = 'ros-%s-%s'%(distro_name, debianize_name(stack_name))

    tmpl_d = os.path.join(roslib.packages.get_pkg_dir('rosdeb'), 'resources', 'source_deb')
    
    tarball = os.path.join(staging_dir, "%s-%s.tar.bz2"%(stack_name, stack_version))
    if not os.path.exists(tarball):
        raise Exception("tarball must be copied to staging directory first")

    # keep track of files we've copied in to modify
    files = []
    
    # make STACK/debian
    stack_d  = os.path.join(staging_dir, stack_name)
    debian_d = os.path.join(stack_d, 'debian')
    if not os.path.exists(debian_d):
        os.makedirs(debian_d)

    # Files which go into debian dir
    for f in ['rules', 'compat', 'postinst']:
        files.append( (os.path.join(tmpl_d, f), os.path.join(debian_d, f)) )

    # Files which go into stack dir
    for f in ['fixpc.py', 'fixbinpath.py', 'fixrpath.py', 'Makefile', 'setup_deb.sh', 'purge_build.py', 'update_version.py', 'gen_versioned_debs.py']:
        files.append( (os.path.join(tmpl_d, f), os.path.join(stack_d, f)) )
        
    # Files which go into stack dir and are different for ros stack
    if stack_name == 'ros':
        for f in ['setup_deb.sh', 'Makefile']:
            f_src = f+'-ros'
            files.append( (os.path.join(tmpl_d, f_src), os.path.join(stack_d, f)) )
                      
    # Files which go into stack dir and only exist for ros
    if stack_name == 'ros':
        for f in ['setup.sh','setup.bash','setup.zsh','.rosinstall']:
            files.append( (os.path.join(tmpl_d, f), os.path.join(stack_d, f)))

    for src, dst in files:
        with open(src, 'r') as f:
            src_text = f.read()

        dst_text = src_text.replace('${ROS_DISTRO_NAME}', distro_name)
        dst_text = dst_text.replace('${ROS_STACK_NAME}', stack_name)
        dst_text = dst_text.replace('${ROS_STACK_DEBIAN_NAME}', debian_name)
        dst_text = dst_text.replace('${ROS_STACK_VERSION}', stack_version)
        with open(dst, 'w') as f:
            f.write(dst_text)

        # copy permission modes
        s = os.stat(src)
        os.chmod(dst, s.st_mode)
            
    # CONTROL: read in the control YAML data and convert it to an actual control file
    control_yaml = os.path.join(staging_dir, '%s-%s.yaml'%(stack_name, stack_version))
    with open(control_yaml, 'r') as f:
        metadata = yaml.load(f.read())
    if not type(metadata) == dict:
        raise Exception("invalid control file: %s\nMetadata is [%s]"%(control_yaml, metadata))

    # make distro-specific
    metadata['package'] = debian_name
    with open(os.path.join(debian_d, 'control'), 'w') as f:
        f.write(control_file(metadata, distro_name, os_platform_name).encode('utf-8'))

    # CHANGELOG
    with open(os.path.join(debian_d, 'changelog'), 'w') as f:
        f.write(changelog_file(metadata, os_platform_name).encode('utf-8'))

    # We must use a build-version starting with a letter greater than r
    build_version='s$BUILD_VERSION'

    with open(os.path.join(debian_d, 'changelog.tmp'), 'w') as f:
        f.write(changelog_file(metadata, os_platform_name, build_version))
    
    # MD5Sum of original stack tar.bz2:
    with open(os.path.join(stack_d, '%s-%s.md5'%(stack_name, stack_version)),'w') as mf:
        with open(os.path.join(staging_dir, '%s-%s.tar.bz2'%(stack_name, stack_version)),'r') as f:
            m = hashlib.md5()
            m.update(f.read())
            mf.write('%s  %s\n'%(m.hexdigest(), '../%s-%s.tar.bz2'%(stack_name, stack_version)))

    # Note: this creates 3 files.  A .dsc, a .tar.gz, and a .changes
    check_call(['dpkg-buildpackage', '-S', '-uc', '-us'], cwd=stack_d)


    # SOURCE DEB: .dsc plus tarball of debian dir. Ignore the changes for now
    f_name  = "%s_%s-0~%s"%(debian_name, stack_version, os_platform_name)
    files = [os.path.join(staging_dir, f_name+ext) for ext in ('.dsc', '.tar.gz')]
    for f in files:
        assert os.path.exists(f), "File: %s does not exist"%f

    return files
def control_data(stack_name, stack_version, md5sum, stack_file=None):
    """
    Generate metadata for control file. Cannot generate debian dependencies as these are platform specific.
    
    @type  stack_name: name of stack
    @type  stack_name: str
    @type  stack_version: stack version id
    @type  stack_version: str
    @param stack_file: location of stack file, or None to use default rosstack lookup
    @type  stack_file: str
    """
    import roslib.stack_manifest
    if stack_file is None:
        stack_file = roslib.stack_manifest.stack_file(stack_name)
    m = roslib.stack_manifest.parse_file(stack_file)

    metadata = {}
    
    metadata['md5sum']     = md5sum #3301
    metadata['stack']      = stack_name
    metadata['package']    = debianize_name(stack_name)
    metadata['version']    = stack_version
    metadata['homepage']   = m.url
    if m.author.startswith('Maintained by '):
        metadata['maintainer'] = m.author[len('Maintained by '):]
    else:
        metadata['maintainer'] = m.author        
    metadata['priority']   = 'optional'
    if m.brief:
        # 60-char limit on control files
        metadata['description-brief'] = m.brief[:60]
    else:
        metadata['description-brief'] = m.brief[:60]

    try:
        description = convert_html_to_text(m.description).rstrip()
    except:
        description = "unknown"

    # per debian spec, single-space pad to signal paragraph
    desc_padded = ''
    for l in description.split('\n'):
        desc_padded += ' '+l+'\n'
    metadata['description-full'] = desc_padded.rstrip()

    # do deps in two parts as ros stack depends need to become version
    # locked later on due to lack of ABI compat
    metadata['depends'] = [d.stack for d in m.depends]
    metadata['rosdeps'] = rosdeps = {}
    for platform in platforms():
        try:
            rosdeps[platform] = stack_rosdeps(stack_name, os.path.dirname(stack_file), platform)
        except Exception as e:
            # #3435
            # TODO: this is a hack that should be turned into a typed exception
            if "cannot generate" in str(e):
                sys.stderr.write("Error with platform [%s]: %s\n"%(platform, str(e)))
            # ignore other failures as these are generally unsupported
            # platforms. Later logic is responsible for erroring if
            # control file is missing bindings, and unit tests on
            # stack_rosdeps verify its functionality
    
    return metadata