def main():
    bindings = []

    for binding in sorted(os.listdir(generators_dir)):
        if not os.path.isdir(binding) or os.path.exists(os.path.join(generators_dir, binding, 'skip_generate_forum_post')):
            continue

        if binding not in ['.git', '.vscode', '.m2', '__pycache__', 'configs', 'docker']:
            bindings.append(binding)

    display_names = []
    downloads = []

    for binding in bindings:
        if len(sys.argv) > 1 and binding not in sys.argv[1:]:
            continue

        path = os.path.join(generators_dir, binding)
        version = common.get_changelog_version(path)

        display_names.append('{0} {1}.{2}.{3}'.format(DISPLAY_NAMES[binding], *version))
        downloads.append('<a href="https://download.tinkerforge.com/bindings/{0}/tinkerforge_{0}_bindings_{2}_{3}_{4}.zip">{1}</a>'
                         .format(binding, DISPLAY_NAMES[binding], *version))

    print("""<p><strong>Bindings:
{0}
</strong></p>
<ul>
<li>...</li>
</ul>
<p>Download:
{1}
</p>
""".format(',\n'.join(display_names), ',\n'.join(downloads)))
def generate(root_dir):
    tmp_dir        = os.path.join(root_dir, 'maven_package')
    tmp_source_dir = os.path.join(tmp_dir, 'source')

    # Make directories
    common.recreate_dir(tmp_dir)

    # Unzip
    version = common.get_changelog_version(root_dir)

    common.execute(['unzip',
                    '-q',
                    os.path.join(root_dir, 'tinkerforge_java_bindings_{0}_{1}_{2}.zip'.format(*version)),
                    '-d',
                    tmp_dir])

    # Override pom.xml
    common.specialize_template(os.path.join(root_dir, 'pom.xml.bundle-template'),
                               os.path.join(tmp_source_dir, 'pom.xml'),
                               {'{{VERSION}}': '.'.join(version)})

    # Make package
    with common.ChangedDirectory(tmp_source_dir):
        # FIXME: maven-toolchains-plugin doesn't stop the default JDK from
        #        leaking into the build process. it is still necessary to set
        #        JAVA_HOME to Java 8 in order to stop the default JDK from
        #        being recorded as the Build-Jdk-Spec in the manifest file.
        env = dict(os.environ)
        env['JAVA_HOME'] = java_common.detect_java_home()

        common.execute(['mvn',
                        'clean',
                        'verify'],
                       env=env)
def generate(root_dir, language):
    version = common.get_changelog_version(root_dir)
    debian_dir = os.path.join(root_dir, 'debian')
    tmp_dir = os.path.join(root_dir, 'debian_package')
    tmp_source_dir = os.path.join(tmp_dir, 'source')
    tmp_source_bashcompletion_dir = os.path.join(tmp_source_dir,
                                                 'bash-completion')
    tmp_source_debian_dir = os.path.join(tmp_source_dir, 'debian')
    tmp_build_dir = os.path.join(
        tmp_dir, 'tinkerforge-shell-bindings-{0}.{1}.{2}'.format(*version))

    # Make directories
    common.recreate_dir(tmp_dir)

    # Unzip
    common.execute([
        'unzip', '-q',
        os.path.join(
            root_dir,
            'tinkerforge_shell_bindings_{0}_{1}_{2}.zip'.format(*version)),
        '-d', tmp_dir
    ])

    os.makedirs(tmp_source_dir)
    os.makedirs(tmp_source_bashcompletion_dir)

    with open(os.path.join(tmp_dir, 'tinkerforge'), 'r') as f:
        script = f.read()

    assert script.startswith('#!/usr/bin/env python\n')

    script = '#!/usr/bin/python3 -u\n' + script.split('\n', 1)[1]

    with open(os.path.join(tmp_source_dir, 'tinkerforge'), 'w') as f:
        f.write(script)

    shutil.copy(os.path.join(tmp_dir, 'tinkerforge-bash-completion.sh'),
                os.path.join(tmp_source_bashcompletion_dir, 'tinkerforge'))

    shutil.copytree(debian_dir, tmp_source_debian_dir)

    common.specialize_template(
        os.path.join(tmp_source_debian_dir, 'changelog.template'),
        os.path.join(tmp_source_debian_dir, 'changelog'), {
            '<<VERSION>>': '.'.join(version),
            '<<DATE>>': subprocess.check_output(['date', '-R']).decode('utf-8')
        },
        remove_template=True)

    # Make package
    os.rename(tmp_source_dir, tmp_build_dir)

    with common.ChangedDirectory(tmp_build_dir):
        common.execute(['dpkg-buildpackage', '--no-sign'])

    # Check package
    with common.ChangedDirectory(tmp_dir):
        common.execute(['lintian', '--pedantic'] + glob.glob('*.deb'))
Beispiel #4
0
def generate(root_dir, language):
    version = common.get_changelog_version(root_dir)
    debian_dir = os.path.join(root_dir, 'debian')
    tmp_dir = os.path.join(root_dir, 'debian_package')
    tmp_octave_dir = os.path.join(tmp_dir, 'octave')
    tmp_octave_debian_dir = os.path.join(tmp_octave_dir, 'debian')
    tmp_build_dir = os.path.join(
        tmp_dir, 'tinkerforge-octave-bindings-{0}.{1}.{2}'.format(*version))

    # Make directories
    common.recreate_dir(tmp_dir)

    # Unzip
    common.execute([
        'unzip', '-q',
        os.path.join(
            root_dir,
            'tinkerforge_matlab_bindings_{0}_{1}_{2}.zip'.format(*version)),
        os.path.join('octave', '*'), '-x',
        os.path.join('octave', 'examples', '*'), '-d', tmp_dir
    ])

    shutil.copytree(debian_dir, tmp_octave_debian_dir)

    common.specialize_template(
        os.path.join(tmp_octave_debian_dir, 'changelog.template'),
        os.path.join(tmp_octave_debian_dir, 'changelog'), {
            '<<VERSION>>': '.'.join(version),
            '<<DATE>>': subprocess.check_output(['date', '-R']).decode('utf-8')
        },
        remove_template=True)

    os.replace(os.path.join(tmp_octave_dir, 'Tinkerforge.jar'),
               os.path.join(tmp_octave_dir, 'tinkerforge.jar'))

    # Make package
    os.rename(tmp_octave_dir, tmp_build_dir)

    with common.ChangedDirectory(tmp_build_dir):
        # FIXME: maven-toolchains-plugin doesn't stop the default JDK from
        #        leaking into the build process. it is still necessary to set
        #        JAVA_HOME to Java 8 in order to stop the default JDK from
        #        being recorded as the Build-Jdk-Spec in the manifest file.
        env = dict(os.environ)
        env['JAVA_HOME'] = java_common.detect_java_home()

        common.execute(['dpkg-buildpackage', '--no-sign'], env=env)

    # Check package
    with common.ChangedDirectory(tmp_dir):
        common.execute(['lintian', '--pedantic'] + glob.glob('*.deb'))
def generate(root_dir, language):
    version = common.get_changelog_version(root_dir)
    debian_dir = os.path.join(root_dir, 'debian')
    tmp_dir = os.path.join(root_dir, 'debian_package')
    tmp_tinkerforge_dir = os.path.join(tmp_dir, 'tinkerforge')
    tmp_tinkerforge_debian_dir = os.path.join(tmp_tinkerforge_dir, 'debian')
    tmp_build_dir = os.path.join(
        tmp_dir, 'tinkerforge-ruby-bindings-{0}.{1}.{2}'.format(*version))

    # Make directories
    common.recreate_dir(tmp_dir)

    # Unzip
    common.execute([
        'unzip', '-q',
        os.path.join(
            root_dir,
            'tinkerforge_ruby_bindings_{0}_{1}_{2}.zip'.format(*version)),
        '-d', tmp_dir
    ])

    common.execute(['gem2tgz', os.path.join(tmp_dir, 'tinkerforge.gem')])

    common.execute([
        'tar', '-xf',
        os.path.join(tmp_dir, 'tinkerforge.tar.gz'.format(*version)), '-C',
        tmp_dir
    ])

    shutil.copytree(debian_dir, tmp_tinkerforge_debian_dir)

    common.specialize_template(
        os.path.join(tmp_tinkerforge_debian_dir, 'changelog.template'),
        os.path.join(tmp_tinkerforge_debian_dir, 'changelog'), {
            '<<VERSION>>': '.'.join(version),
            '<<DATE>>': subprocess.check_output(['date', '-R']).decode('utf-8')
        },
        remove_template=True)

    # Make package
    os.rename(tmp_tinkerforge_dir, tmp_build_dir)

    with common.ChangedDirectory(tmp_build_dir):
        common.execute(['dpkg-buildpackage', '--no-sign'])

    # Check package
    with common.ChangedDirectory(tmp_dir):
        common.execute(['lintian', '--pedantic'] + glob.glob('*.deb'))
def generate(root_dir):
    tmp_dir = os.path.join(root_dir, 'cpan_package')
    tmp_unzipped_dir = os.path.join(tmp_dir, 'unzipped')
    tmp_unzipped_source_dir = os.path.join(tmp_unzipped_dir, 'source')
    tmp_unzipped_source_lib_dir = os.path.join(tmp_unzipped_source_dir, 'lib')
    tmp_cpan_dir = os.path.join(tmp_dir, 'cpan')
    tmp_cpan_lib_dir = os.path.join(tmp_cpan_dir, 'lib')

    # Make directories
    common.recreate_dir(tmp_dir)

    # Unzip
    version = common.get_changelog_version(root_dir)

    common.execute([
        'unzip', '-q',
        os.path.join(
            root_dir,
            'tinkerforge_perl_bindings_{0}_{1}_{2}.zip'.format(*version)),
        '-d', tmp_unzipped_dir
    ])

    # Make CPAN package structure
    modules = ['Tinkerforge']

    for filename in os.listdir(
            os.path.join(tmp_unzipped_source_lib_dir, 'Tinkerforge')):
        modules.append('Tinkerforge::' + filename.replace('.pm', ''))

    common.execute([
        'module-starter', '--dir=' + tmp_cpan_dir,
        '--module=' + ','.join(modules), '--distro=Tinkerforge',
        '--author="Ishraq Ibne Ashraf"', '[email protected]'
    ])

    # Make README
    common.specialize_template(os.path.join(root_dir, 'README.template'),
                               os.path.join(tmp_cpan_dir, 'README'),
                               {'<<VERSION>>': '.'.join(version)})

    # Make Changes
    shutil.copy(os.path.join(tmp_unzipped_dir, 'changelog.txt'),
                os.path.join(tmp_cpan_dir, 'Changes'))

    # Copy Makefile.PL
    shutil.copy(os.path.join(tmp_unzipped_source_dir, 'Makefile.PL'),
                tmp_cpan_dir)

    # Copy source
    shutil.rmtree(tmp_cpan_lib_dir)
    shutil.copytree(os.path.join(tmp_unzipped_source_lib_dir),
                    os.path.join(tmp_cpan_lib_dir))

    # Make package
    with common.ChangedDirectory(tmp_cpan_dir):
        common.execute(['perl', 'Makefile.PL'])
        common.execute(['make', 'dist'])

    shutil.copy(
        os.path.join(tmp_cpan_dir,
                     'Tinkerforge-{0}.{1}.{2}.tar.gz'.format(*version)),
        root_dir)
Beispiel #7
0
def generate(root_dir):
    tmp_dir = os.path.join(root_dir, 'nuget_package')
    tmp_unzipped_net20_dir = os.path.join(tmp_dir, 'unzipped_net20')
    tmp_unzipped_net40_dir = os.path.join(tmp_dir, 'unzipped_net40')
    tmp_unzipped_net40_source_tinkerforge_dir = os.path.join(
        tmp_unzipped_net40_dir, 'source', 'Tinkerforge')
    tmp_unzipped_netcoreapp20_dir = os.path.join(tmp_dir,
                                                 'unzipped_netcoreapp20')
    tmp_unzipped_netcoreapp20_source_tinkerforge_dir = os.path.join(
        tmp_unzipped_netcoreapp20_dir, 'source', 'Tinkerforge')

    # Make directories
    common.recreate_dir(tmp_dir)

    # Unzip
    version = common.get_changelog_version(root_dir)

    common.execute([
        'unzip', '-q',
        os.path.join(
            root_dir,
            'tinkerforge_csharp_bindings_{0}_{1}_{2}.zip'.format(*version)),
        '-d', tmp_unzipped_net20_dir
    ])

    shutil.copytree(tmp_unzipped_net20_dir, tmp_unzipped_net40_dir)
    shutil.copytree(tmp_unzipped_net20_dir, tmp_unzipped_netcoreapp20_dir)

    # Make DLL for NET 4.0
    with common.ChangedDirectory(tmp_unzipped_net40_dir):
        common.execute([
            'mcs', '/debug:full', '/optimize+', '/warn:4', '/sdk:4',
            '/target:library',
            '/doc:' + os.path.join(tmp_unzipped_net40_dir, 'Tinkerforge.xml'),
            '/out:' + os.path.join(tmp_unzipped_net40_dir, 'Tinkerforge.dll'),
            os.path.join(tmp_unzipped_net40_source_tinkerforge_dir, '*.cs')
        ])

    # Make DLL for NET Core 2.0
    with open(
            os.path.join(tmp_unzipped_netcoreapp20_source_tinkerforge_dir,
                         'Tinkerforge.csproj'), 'w') as f:
        f.write(NETCORE_CSPROJ)

    with common.ChangedDirectory(
            tmp_unzipped_netcoreapp20_source_tinkerforge_dir):
        common.execute(['dotnet', 'build', '-c', 'Release'])

    # Download nuget.exe
    with common.ChangedDirectory(tmp_dir):
        common.execute([
            'wget',
            'https://dist.nuget.org/win-x86-commandline/v5.0.2/nuget.exe'
        ])

    # Make Tinkerforge.nuspec
    common.specialize_template(
        os.path.join(root_dir, 'Tinkerforge.nuspec.template'),
        os.path.join(tmp_dir, 'Tinkerforge.nuspec'),
        {'{{VERSION}}': '.'.join(version)})

    # Make package
    with common.ChangedDirectory(tmp_dir):
        common.execute([
            'mono',
            os.path.join(tmp_dir, 'nuget.exe'), 'pack',
            os.path.join(tmp_dir, 'Tinkerforge.nuspec')
        ])

    shutil.move(
        os.path.join(tmp_dir,
                     'Tinkerforge.{0}.{1}.{2}.nupkg'.format(*version)),
        os.path.join(root_dir,
                     'tinkerforge.{0}.{1}.{2}.nupkg'.format(*version)))
Beispiel #8
0
    def finish(self):
        root_dir = self.get_root_dir()

        if self.get_config_name().space == 'Tinkerforge':
            shutil.copy(os.path.join(root_dir, 'changelog.txt'), self.tmp_dir)
            shutil.copy(os.path.join(root_dir, 'readme.txt'), self.tmp_dir)
            shutil.copy(os.path.join(root_dir, '..', 'configs', 'license.txt'),
                        self.tmp_dir)
        else:
            shutil.copy(os.path.join(self.get_config_dir(), 'changelog.txt'),
                        self.tmp_dir)

        for flavor in ['matlab', 'octave']:
            tmp_dir = self.tmp_flavor_dir[flavor]
            tmp_source_dir = self.tmp_flavor_source_dir[flavor]
            tmp_source_src_main_java_com_tinkerforge_dir = self.tmp_flavor_source_src_main_java_com_tinkerforge_dir[
                flavor]
            tmp_source_src_main_resources_metainf_services_dir = self.tmp_flavor_source_src_main_resources_metainf_services_dir[
                flavor]
            tmp_source_src_main_resources_com_tinkerforge_dir = self.tmp_flavor_source_src_main_resources_com_tinkerforge_dir[
                flavor]
            tmp_source_target_dir = self.tmp_flavor_source_target_dir[flavor]
            tmp_examples_dir = self.tmp_flavor_examples_dir[flavor]

            # Copy IP Connection examples
            if self.get_config_name().space == 'Tinkerforge':
                for example in common.find_examples(
                        root_dir, '^' + flavor + r'_example_.*\.m$'):
                    shutil.copy(example[1], tmp_examples_dir)

            # Copy bindings and readme
            for filename in self.get_released_files():
                shutil.copy(
                    os.path.join(root_dir, self.get_bindings_dir(), flavor,
                                 filename),
                    tmp_source_src_main_java_com_tinkerforge_dir)

            shutil.copy(
                os.path.join(self.get_bindings_dir(), flavor,
                             'com.tinkerforge.DeviceProvider'),
                tmp_source_src_main_resources_metainf_services_dir)

            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'BrickDaemon.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'DeviceBase.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, 'Device_{0}.java'.format(flavor)),
                os.path.join(tmp_source_src_main_java_com_tinkerforge_dir,
                             'Device.java'))
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'DeviceListener.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'DeviceProvider.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'DeviceFactory.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, 'IPConnection_{0}.java'.format(flavor)),
                os.path.join(tmp_source_src_main_java_com_tinkerforge_dir,
                             'IPConnection.java'))
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'IPConnectionBase.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'TinkerforgeException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'TimeoutException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'AlreadyConnectedException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'NotConnectedException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'CryptoException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java', 'NetworkException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'StreamOutOfSyncException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'InvalidParameterException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'NotSupportedException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'UnknownErrorCodeException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'WrongDeviceTypeException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'DeviceReplacedException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'WrongResponseLengthException.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)
            shutil.copy(
                os.path.join(root_dir, '..', 'java',
                             'TinkerforgeListener.java'),
                tmp_source_src_main_java_com_tinkerforge_dir)

            if flavor == 'octave':
                shutil.copy(os.path.join(root_dir, 'liboctaveinvokewrapper.c'),
                            tmp_source_src_main_resources_com_tinkerforge_dir)
                shutil.copy(
                    os.path.join(root_dir,
                                 'liboctaveinvokewrapper-linux-i386.so'),
                    tmp_source_src_main_resources_com_tinkerforge_dir)
                shutil.copy(
                    os.path.join(root_dir,
                                 'liboctaveinvokewrapper-linux-amd64.so'),
                    tmp_source_src_main_resources_com_tinkerforge_dir)
                shutil.copy(
                    os.path.join(root_dir,
                                 'liboctaveinvokewrapper-linux-arm.so'),
                    tmp_source_src_main_resources_com_tinkerforge_dir)
                shutil.copy(
                    os.path.join(root_dir,
                                 'liboctaveinvokewrapper-windows-x86.dll'),
                    tmp_source_src_main_resources_com_tinkerforge_dir)
                shutil.copy(
                    os.path.join(root_dir,
                                 'liboctaveinvokewrapper-windows-amd64.dll'),
                    tmp_source_src_main_resources_com_tinkerforge_dir)
                shutil.copy(
                    os.path.join(root_dir,
                                 'liboctaveinvokewrapper-macos-x86_64.dynlib'),
                    tmp_source_src_main_resources_com_tinkerforge_dir)

            # Make pom.xml
            version = self.get_changelog_version()

            if self.get_config_name().space == 'Tinkerforge':
                common.specialize_template(
                    os.path.join(root_dir,
                                 'pom.xml.{0}-jar-template'.format(flavor)),
                    os.path.join(tmp_source_dir, 'pom.xml'),
                    {'{{VERSION}}': '.'.join(version)})
            else:
                common.specialize_template(
                    os.path.join(root_dir,
                                 'pom.xml.{0}-custom-template'.format(flavor)),
                    os.path.join(tmp_source_dir, 'pom.xml'), {
                        '{{CONFIG_NAME}}':
                        self.get_config_name().dash,
                        '{{VERSION}}':
                        '.'.join(version),
                        '{{TINKERFORGE_VERSION}}':
                        '.'.join(common.get_changelog_version(root_dir))
                    })

            # Compile source
            with common.ChangedDirectory(tmp_source_dir):
                # FIXME: maven-toolchains-plugin doesn't stop the default JDK from
                #        leaking into the build process. it is still necessary to set
                #        JAVA_HOME to Java 8 in order to stop the default JDK from
                #        being recorded as the Build-Jdk-Spec in the manifest file.
                env = dict(os.environ)
                env['JAVA_HOME'] = java_common.detect_java_home()

                common.execute(['mvn', 'clean', 'install'], env=env)

            os.rename(
                os.path.join(
                    tmp_source_target_dir, '{0}-{1}-{2}.{3}.{4}.jar'.format(
                        self.get_config_name().dash, flavor, *version)),
                os.path.join(tmp_dir,
                             '{0}.jar'.format(self.get_config_name().camel)))

            shutil.rmtree(tmp_source_target_dir)

        # Make zip
        self.create_zip_file(self.tmp_dir)
Beispiel #9
0
def main():
    argv = sys.argv[1:]

    for path in [os.path.expanduser('~/.zip_diffrc'), './.zip_diffrc']:
        if os.path.exists(path):
            with open(path, 'r') as f:
                argv += shlex.split(f.read(), comments=True)

    parser = argparse.ArgumentParser()

    parser.add_argument('-p',
                        '--prepare',
                        action='store_true',
                        help='prepare unreleased zip as old diff input')
    parser.add_argument('-u',
                        '--unreleased',
                        action='store_true',
                        help='use unreleased zip as old diff input')
    parser.add_argument('-d',
                        '--diff-tool',
                        default='geany',
                        help='program to open diff with')
    parser.add_argument('bindings',
                        nargs='?',
                        help='bindings to create diff for')

    args = parser.parse_args(argv)

    diff_tool = args.diff_tool

    ignored = [
        '.git', '.vscode', '.m2', '__pycache__', 'configs', 'docker', 'modbus',
        'tcpip', 'stubs', 'tvpl', 'openhab', 'uc'
    ]

    if args.bindings != None:
        b = args.bindings.rstrip('/')

        if not os.path.isdir(os.path.join(generators_dir, b)):
            print('error: {0} is not a directory'.format(b))
            sys.exit(1)

        bindings = [b]
    elif os.path.samefile(generators_dir, os.getcwd()):
        bindings = sorted(
            [x for x in os.listdir(generators_dir) if x not in ignored])
    else:
        parent_dir, b = os.path.split(os.getcwd())

        if parent_dir != generators_dir:
            print(
                'error: wrong working directory, cannot auto-detect bindings')
            sys.exit(1)

        bindings = [b]

    if args.prepare:
        for b in bindings:
            path = os.path.join(generators_dir, b)

            if not os.path.isdir(path):
                continue

            zip_path = os.path.join(path, 'zip')
            zip_old_path = os.path.join(path, 'zip_old')

            if not os.path.isdir(zip_path):
                print('skipping {0}, no zip directory'.format(d))
                continue

            print('preparing ' + d)

            if os.path.isdir(zip_old_path):
                shutil.rmtree(zip_old_path)

            shutil.copytree(zip_path, zip_old_path)
    else:
        c_like_header1 = re.compile(r'^@@ -1,8 \+1,8 @@\n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '  \* .+ Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n$')

        c_like_header2 = re.compile(r'^@@ -1,10 \+1,10 @@\n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '- \* .+ Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '\+ \* .+ Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n' + \
        '  \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/\n' + \
        ' \n$')

        delphi_header1 = re.compile(r'^@@ -1,8 \+1,8 @@\n' + \
        ' {\n' + \
        '-  This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.\n' + \
        '\+  This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.\n' + \
        ' \n' + \
        '   Delphi/Lazarus Bindings Version 2\.[0-9]+\.[0-9]+\n' + \
        ' \n' + \
        '   If you have a bugfix for this file and want to commit it,\n' + \
        '   please fix the bug in the generator\. You can find a link\n' + \
        '   to the generators git on tinkerforge\.com\n$')

        delphi_header2 = re.compile(r'^@@ -1,10 \+1,10 @@\n' + \
        ' {\n' + \
        '-  This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.\n' + \
        '\+  This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.\n' + \
        ' \n' + \
        '-  Delphi/Lazarus Bindings Version 2\.[0-9]+\.[0-9]+\n' + \
        '\+  Delphi/Lazarus Bindings Version 2\.[0-9]+\.[0-9]+\n' + \
        ' \n' + \
        '   If you have a bugfix for this file and want to commit it,\n' + \
        '   please fix the bug in the generator\. You can find a link\n' + \
        '   to the generators git on tinkerforge\.com\n' + \
        ' }\n' + \
        ' \n$')

        javascript_header1 = re.compile(r'^@@ -[0-9]+,8 \+[0-9]+,8 @@\n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '  \* JavaScript Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n$')

        javascript_header2 = re.compile(r'^@@ -[0-9]+,10 \+[0-9]+,10 @@\n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '- \* JavaScript Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '\+ \* JavaScript Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n' + \
        '  \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/\n' + \
        ' \n$')

        javascript_header3 = re.compile(r'^@@ -[0-9]+,13 \+[0-9]+,13 @@\n' + \
        ' }\n' + \
        ' \n' + \
        ' module\.exports = Brick[A-Za-z0-9]+;\n' + \
        ' \n' + \
        ' },{"\./Device":[0-9]+,"\./IPConnection":[0-9]+}\],[0-9]+:\[function\(require,module,exports\){\n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '  \* JavaScript Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n$')

        javascript_header4 = re.compile(r'^@@ -[0-9]+,15 \+[0-9]+,15 @@\n' + \
        ' }\n' + \
        ' \n' + \
        ' module\.exports = Brick[A-Za-z0-9]+;\n' + \
        ' \n' + \
        ' },{"\./Device":[0-9]+,"\./IPConnection":[0-9]+}\],[0-9]+:\[function\(require,module,exports\){\n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '- \* JavaScript Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '\+ \* JavaScript Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n' + \
        '  \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/\n' + \
        ' \n$')

        perl_header1 = re.compile(r'^@@ -1,8 \+1,8 @@\n' + \
        ' #############################################################\n' + \
        '-# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        '\+# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        ' #                                                           #\n' + \
        ' # Perl Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        ' #                                                           #\n' + \
        ' # If you have a bugfix for this file and want to commit it, #\n' + \
        ' # please fix the bug in the generator\. You can find a link  #\n' + \
        ' # to the generators git repository on tinkerforge\.com       #\n$')

        perl_header2 = re.compile(r'^@@ -1,10 \+1,10 @@\n' + \
        ' #############################################################\n' + \
        '-# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        '\+# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        ' #                                                           #\n' + \
        '-# Perl Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        '\+# Perl Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        ' #                                                           #\n' + \
        ' # If you have a bugfix for this file and want to commit it, #\n' + \
        ' # please fix the bug in the generator\. You can find a link  #\n' + \
        ' # to the generators git repository on tinkerforge\.com       #\n' + \
        ' #############################################################\n' + \
        ' \n$')

        php_header1 = re.compile(r'^@@ -1,10 \+1,10 @@\n' + \
        ' <\?php\n' + \
        ' \n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '  \* PHP Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n$')

        php_header2 = re.compile(r'^@@ -1,12 \+1,12 @@\n' + \
        ' <\?php\n' + \
        ' \n' + \
        ' /\* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\\n' + \
        '- \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '\+ \* This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      \*\n' + \
        '  \*                                                           \*\n' + \
        '- \* PHP Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '\+ \* PHP Bindings Version 2\.[0-9]+\.[0-9]+[ ]+\*\n' + \
        '  \*                                                           \*\n' + \
        '  \* If you have a bugfix for this file and want to commit it, \*\n' + \
        '  \* please fix the bug in the generator\. You can find a link  \*\n' + \
        '  \* to the generators git repository on tinkerforge\.com       \*\n' + \
        '  \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/\n' + \
        ' \n$')

        python_header1 = re.compile(r'^@@ -1,9 \+1,9 @@\n' + \
        ' # -\*- coding: utf-8 -\*-\n' + \
        ' #############################################################\n' + \
        '-# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        '\+# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        ' #                                                           #\n' + \
        ' # Python Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        ' #                                                           #\n' + \
        ' # If you have a bugfix for this file and want to commit it, #\n' + \
        ' # please fix the bug in the generator\. You can find a link  #\n' + \
        ' # to the generators git repository on tinkerforge\.com       #\n$')

        python_header2 = re.compile(r'^@@ -1,11 \+1,11 @@\n' + \
        ' # -\*- coding: utf-8 -\*-\n' + \
        ' #############################################################\n' + \
        '-# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        '\+# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        ' #                                                           #\n' + \
        '-# Python Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        '\+# Python Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        ' #                                                           #\n' + \
        ' # If you have a bugfix for this file and want to commit it, #\n' + \
        ' # please fix the bug in the generator\. You can find a link  #\n' + \
        ' # to the generators git repository on tinkerforge\.com       #\n' + \
        ' #############################################################\n' + \
        ' \n$')

        ruby_header1 = re.compile(r'^@@ -1,9 \+1,9 @@\n' + \
        ' # -\*- ruby encoding: utf-8 -\*-\n' + \
        ' #############################################################\n' + \
        '-# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        '\+# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        ' #                                                           #\n' + \
        ' # Ruby Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        ' #                                                           #\n' + \
        ' # If you have a bugfix for this file and want to commit it, #\n' + \
        ' # please fix the bug in the generator\. You can find a link  #\n' + \
        ' # to the generators git repository on tinkerforge\.com       #\n$')

        ruby_header2 = re.compile(r'^@@ -1,11 \+1,11 @@\n' + \
        ' # -\*- ruby encoding: utf-8 -\*-\n' + \
        ' #############################################################\n' + \
        '-# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        '\+# This file was automatically generated on [0-9]{4}-[0-9]{2}-[0-9]{2}\.      #\n' + \
        ' #                                                           #\n' + \
        '-# Ruby Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        '\+# Ruby Bindings Version 2\.[0-9]+\.[0-9]+[ ]+#\n' + \
        ' #                                                           #\n' + \
        ' # If you have a bugfix for this file and want to commit it, #\n' + \
        ' # please fix the bug in the generator\. You can find a link  #\n' + \
        ' # to the generators git repository on tinkerforge\.com       #\n' + \
        ' #############################################################\n' + \
        ' \n$')

        tmp = tempfile.mkdtemp()

        print('using tmpdir ' + tmp)

        for b in bindings:
            path = os.path.join(generators_dir, b)

            if not os.path.isdir(path):
                continue

            if not os.path.isdir(os.path.join(path, 'zip')):
                print('skipping {0}, no zip directory'.format(b))
                continue

            version = common.get_changelog_version(path)

            if args.unreleased:
                if not os.path.isdir(os.path.join(path, 'zip_old')):
                    print('skipping {0}, no zip_old directory'.format(b))
                    continue

                print('diffing ' + b)

                shutil.copytree(os.path.join(path, 'zip_old'),
                                os.path.join(tmp, 'old_{0}'.format(b)))
            else:
                print('diffing ' + b)

                if os.system(
                        'bash -ce "curl -sf https://download.tinkerforge.com/bindings/{0}/tinkerforge_{0}_bindings_latest.zip -o {1}/old_{0}.zip"'
                        .format(b, tmp)) != 0:
                    print('download latest.zip failed')
                    sys.exit(1)

                if os.system(
                        'bash -ce "pushd {1} > /dev/null && unzip -q -d old_{0} old_{0}.zip && popd > /dev/null"'
                        .format(b, tmp)) != 0:
                    print('unzip latest.zip failed')
                    sys.exit(1)

            if os.system(
                    'bash -ce "cp {0}/tinkerforge_{1}_bindings_{3}_{4}_{5}.zip {2} && pushd {2} > /dev/null && unzip -q -d new_{1} tinkerforge_{1}_bindings_{3}_{4}_{5}.zip && popd > /dev/null"'
                    .format(path, b, tmp, *version)) != 0:
                print('copy and unzip new.zip failed')
                sys.exit(1)

            if os.system(
                    'bash -c "pushd {1} > /dev/null && diff -ru6 old_{0}/ new_{0}/ > diff_{0}.diff; popd > /dev/null"'
                    .format(b, tmp)) != 0:
                print('diff old vs new failed')
                sys.exit(1)

            with open(os.path.join(tmp, 'diff_{0}.diff'.format(b)), 'r') as f:
                diffs = [[[]]]  # list of diffs as lists of lines

                for line in f.readlines():
                    if line.startswith('diff ') or line[0] not in [
                            '@', '-', '+', ' '
                    ]:
                        diffs.append([[]])

                    if line.startswith('@@ '):
                        diffs[-1].append([])

                    diffs[-1][-1].append(line)

            filtered = []

            for diff in diffs:
                filtered_lines = []

                for lines in diff:
                    if len(lines) == 0:
                        continue

                    hunk = ''.join(lines)

                    if not c_like_header1.match(hunk) and \
                       not c_like_header2.match(hunk) and \
                       not delphi_header1.match(hunk) and \
                       not delphi_header2.match(hunk) and \
                       not javascript_header1.match(hunk) and \
                       not javascript_header2.match(hunk) and \
                       not javascript_header3.match(hunk) and \
                       not javascript_header4.match(hunk) and \
                       not perl_header1.match(hunk) and \
                       not perl_header2.match(hunk) and \
                       not php_header1.match(hunk) and \
                       not php_header2.match(hunk) and \
                       not python_header1.match(hunk) and \
                       not python_header2.match(hunk) and \
                       not ruby_header1.match(hunk) and \
                       not ruby_header2.match(hunk):
                        filtered_lines += lines
                    else:
                        filtered_lines += [
                            lines[0].rstrip() + ' // dropped header hunk\n'
                        ]

                if len(filtered_lines) == 0:
                    continue

                if len(filtered_lines) == 4 and \
                   filtered_lines[0].startswith('diff -ru6 ') and \
                   filtered_lines[1].startswith('--- ') and \
                   filtered_lines[2].startswith('+++ ') and \
                   filtered_lines[3].endswith('// dropped header hunk\n'):
                    filtered += [
                        filtered_lines[0].rstrip() +
                        ' // dropped header diff\n'
                    ]
                else:
                    filtered += filtered_lines

            with open(os.path.join(tmp, 'diff.diff'), 'a') as f:
                f.writelines(filtered)

        if os.system('bash -ce "{0} {1}/diff.diff"'.format(diff_tool,
                                                           tmp)) != 0:
            print('{0} diff.diff failed'.format(diff_tool))
            sys.exit(1)