Wie kann ich Open-Source-Code-Releases aus dem vertraulichen Forschungscode meines Unternehmens am besten erstellen?

13

Meine Firma (nennen wir sie Acme-Technologie) verfügt über eine Bibliothek mit ungefähr tausend Quelldateien, die ursprünglich aus der Acme Labs-Forschungsgruppe stammten, in einer Entwicklungsgruppe für ein paar Jahre inkubiert wurden und in jüngerer Zeit an eine Handvoll Kunden unter bereitgestellt wurden Geheimhaltung. Acme bereitet sich darauf vor, vielleicht 75% des Codes für die Open-Source-Community freizugeben. Die anderen 25% würden später veröffentlicht, sind jedoch entweder noch nicht für den Kunden verfügbar oder enthalten Code für zukünftige Innovationen, die sie benötigen, um nicht in die Hände von Wettbewerbern zu gelangen.

Der Code ist derzeit mit #ifdefs formatiert, mit denen dieselbe Codebasis mit den Vorproduktionsplattformen zusammenarbeiten kann, die Universitätsforschern und einer viel breiteren Palette von kommerziellen Kunden zur Verfügung stehen, sobald sie Open Source nutzen verfügbar für Experimente und Prototypen sowie für Vorwärtskompatibilitätstests mit der zukünftigen Plattform. Die Aufrechterhaltung einer einzigen Codebasis wird als wesentlich für die Wirtschaftlichkeit (und Vernunft) meiner Fraktion angesehen, die es schwer haben würde, zwei Kopien parallel zu führen.

Dateien in unserer aktuellen Datenbank sehen ungefähr so ​​aus:

> // Copyright 2012 (C) Acme Technology, All Rights Reserved.
> // Very large, often varied and restrictive copyright license in English and French,
> // sometimes also embedded in make files and shell scripts with varied 
> // comment styles. 
> 
> 
>   ... Usual header stuff...
>
> void initTechnologyLibrary() {
>     nuiInterface(on);
> #ifdef  UNDER_RESEARCH
>     holographicVisualization(on);
> #endif
> }

Und wir möchten sie in so etwas wie konvertieren:

> // GPL Copyright (C) Acme Technology Labs 2012, Some rights reserved.
> // Acme appreciates your interest in its technology, please contact [email protected] 
> // for technical support, and www.acme.com/emergingTech for updates and RSS feed.
> 
>   ... Usual header stuff...
>
> void initTechnologyLibrary() {
>     nuiInterface(on);
> }

Gibt es ein Tool, eine Analysebibliothek oder ein beliebtes Skript, das das Urheberrecht ersetzen und nicht nur #ifdefs, sondern auch Variationen wie #if defined (UNDER_RESEARCH) usw. entfernen kann?

Der Code befindet sich derzeit in Git und wird wahrscheinlich an einem Ort gehostet, der Git verwendet. Gibt es eine Möglichkeit, Repositorys sicher miteinander zu verknüpfen, damit wir unsere Verbesserungen effizient in die Open-Source-Versionen integrieren können? Tipps zu anderen Fallstricken sind willkommen.

DeveloperDon
quelle
13
Diese Codebasis schreit nach Zweigen.
Florian Margaine
Ein Beispiel für die Verwendung von Zweigen für diesen Zweck wäre sehr willkommen.
DeveloperDon

Antworten:

6

Es scheint , wie es nicht zu schwierig sein würde , ein Skript zu schreiben , um die Pre - Prozessoren zu analysieren, vergleichen sie mit einer Liste des definierten Konstanten ( UNDER_RESEARCH, FUTURE_DEVELOPMENTusw.) , und wenn die Direktive kann zu falsch gegebenen ausgewertet werden , was definiert ist, entfernen Sie alles oben zum nächsten #endif.

In Python würde ich etwas tun,

import os

src_dir = 'src/'
switches = {'UNDER_RESEARCH': True, 'OPEN_SOURCE': False}
new_header = """// GPL Copyright (C) Acme Technology Labs 2012, Some rights reserved.
// Acme appreciates your interest in its technology, please contact [email protected] 
// for technical support, and www.acme.com/emergingTech for updates and RSS feed.
"""

filenames = os.listdir(src_dir)
for fn in filenames:
    contents = open(src_dir+fn, 'r').read().split('\n')
    outfile = open(src_dir+fn+'-open-source', 'w')
    in_header = True
    skipping = False
    for line in contents:
        # remove original header
        if in_header and (line.strip() == "" or line.strip().startswith('//')):
            continue
        elif in_header:
            in_header = False
            outfile.write(new_header)

        # skip between ifdef directives
        if skipping:
            if line.strip() == "#endif":
                skipping = False
            continue
        # check
        if line.strip().startswith("#ifdef"):
            # parse #ifdef (maybe should be more elegant)
            # this assumes a form of "#ifdef SWITCH" and nothing else
            if line.strip().split()[1] in switches.keys():
                skipping = True
                continue

        # checking for other forms of directives is left as an exercise

        # got this far, nothing special - echo the line
        outfile.write(line)
        outfile.write('\n')

Ich bin sicher, es gibt elegantere Wege, aber das ist schnell und schmutzig und scheint die Arbeit zu erledigen.

WasabiFlux
quelle
Wow, danke. Es gibt eine Menge Logik, um einen guten Filter zu erstellen, und ich schätze Ihr Beispiel. Ich hoffe, etwas für die Wiederverwendung zu finden, und meine Entwicklungsmaschine ist schnell mit einem großen Speicher, sodass die Leistung kein großes Problem darstellt, separate Filter für das Urheberrecht und die Definitionen auszuführen oder den Definitionsfilter mehr als einmal auszuführen. Wir haben tatsächlich mehrere Definitionen in Bezug auf Schlüsselwörter, die mehrere zukünftige Projekte kennzeichnen, und einige frühere Projekte, die nicht als Open Source veröffentlicht werden, aber dennoch intern und von Kunden verwendet werden.
DeveloperDon
3

Ich habe darüber nachgedacht, Ihren Code durch den Präprozessor zu leiten, um nur Makros zu erweitern und so nur den interessanten Teil im #ifdefs auszugeben.

So etwas sollte funktionieren:

gcc -E yourfile.c

Aber:

  • Sie verlieren alle Kommentare. Sie können verwenden, -CCum sie (irgendwie) zu bewahren, aber dann müssen Sie den alten Copyright-Hinweis noch entfernen
  • #includes werden ebenfalls erweitert, sodass Sie eine große Datei erhalten, die den gesamten Inhalt der enthaltenen Header-Dateien enthält
  • Sie verlieren "Standard" -Makros.

Es gibt möglicherweise eine Möglichkeit, die Anzahl der erweiterten Makros zu begrenzen. Mein Vorschlag hier ist jedoch, Dinge zu trennen, anstatt (potenziell gefährliche) Verarbeitungen an den Dateien vorzunehmen.

Versuchen Sie also, den Code, den Sie als OpenSource-Datei verwenden möchten, so weit wie möglich in externe Bibliotheken zu kopieren. Verwenden Sie ihn dann wie in jeder anderen Bibliothek und integrieren Sie ihn in andere "benutzerdefinierte" Closed-Source-Bibliotheken.

Es mag anfangs etwas länger dauern, um herauszufinden, wie man die Dinge umstrukturiert, aber es ist definitiv der richtige Weg, um dies zu erreichen.

redShadow
quelle
Ich hatte überlegt, ob mit dem Präprozessor möglicherweise etwas getan werden könnte, um selektiv die Blöcke zu entfernen, die wir noch nicht freigeben werden. Der Code ist komplex und wir werden wahrscheinlich mehr Kommentare als weniger brauchen, aber Ihr Vorschlag ist auf jeden Fall einen Besuch in der Brainstorming-Liste wert. WRT-Fragen dazu, wie wir den Quellcode pflegen und den Code in die Community verschieben möchten, erfordern mehr Planung. Das Einfügen von Code in den proprietären Code wirft einige gute Fragen auf.
DeveloperDon
2

Ich habe eine Lösung, aber es wird ein wenig Arbeit erfordern

pypreprocessor ist eine Bibliothek, die einen reinen C-Präprozessor für Python bereitstellt, der auch als GPP (General Purpose Pre-Processor) für andere Arten von Quellcode verwendet werden kann.

Hier ist ein einfaches Beispiel:

from pypreprocessor import pypreprocessor

pypreprocessor.input = 'input_file.c'
pypreprocessor.output = 'output_file.c'
pypreprocessor.removeMeta = True
pypreprocessor.parse()

Der Präprozessor ist extrem einfach. Es durchläuft die Quelle und kommentiert die Quelle basierend auf der Definition bedingt aus.

Bestimmt kann entweder durch eingestellt werden # define - Anweisungen in der Quelle oder von ihnen in der pypreprocessor.defines Liste zu setzen.

Durch Festlegen der Eingabe- / Ausgabeparameter können Sie explizit definieren, welche Dateien geöffnet / geschlossen werden, sodass ein einzelner Präprozessor für die Stapelverarbeitung einer großen Anzahl von Dateien eingerichtet werden kann, falls dies gewünscht wird.

Wenn Sie den Parameter removeMeta auf True setzen, sollte der Präprozessor automatisch alle Präprozessoranweisungen extrahieren, wobei nur der nachverarbeitete Code übrig bleibt.

Hinweis: Normalerweise muss dies nicht explizit festgelegt werden, da Python kommentierten Code während der Kompilierung in Bytecode automatisch entfernt hat.

Ich sehe nur einen Randfall. Weil du Vorprozess C - Quelle suchen, können Sie den Prozessor definiert explizit setzen (dh durch pypreprocessor.defines) und sagen , dass es die ignorieren # define - Anweisungen in der Quelle. Dies sollte verhindern, dass Konstanten versehentlich entfernt werden, die Sie möglicherweise im Quellcode Ihres Projekts verwenden. Derzeit gibt es keinen Parameter zum Einstellen dieser Funktionalität, das Hinzufügen wäre jedoch trivial.

Hier ist ein einfaches Beispiel:

from pypreprocessor import pypreprocessor

# run the script in 'production' mode
if 'commercial' in sys.argv:
    pypreprocessor.defines.append('commercial')

if 'open' in sys.argv:
    pypreprocessor.defines.append('open')

pypreprocessor.removeMeta = True
pypreprocessor.parse()

Dann die Quelle:

#ifdef commercial
// Copyright 2012 (C) Acme Technology, All Rights Reserved.
// Very large, often varied and restrictive copyright license in English and French,
// sometimes also embedded in make files and shell scripts with varied 
// comment styles.
#ifdef open
// GPL Copyright (C) Acme Technology Labs 2012, Some rights reserved.
// Acme appreciates your interest in its technology, please contact [email protected] 
// for technical support, and www.acme.com/emergingTech for updates and RSS feed.
#endif

Hinweis: Natürlich müssen Sie einen Weg finden, um die Eingabe- / Ausgabedateien festzulegen, aber das sollte nicht allzu schwierig sein.

Offenlegung: Ich bin der ursprüngliche Autor von pypreprocessor.


Nebenbei: Ich habe es ursprünglich als Lösung für das gefürchtete Python 2k / 3x-Wartungsproblem geschrieben. Mein Ansatz war, 2 und 3 in denselben Quelldateien zu entwickeln und die Unterschiede nur mit Hilfe von Präprozessor-Direktiven ein- / auszuschließen. Leider entdeckte ich die Schwierigkeit, dass es unmöglich ist, einen echten reinen (dh keinen c) Präprozessor in Python zu schreiben, da der Lexer Syntaxfehler in inkompatiblem Code kennzeichnet, bevor der Präprozessor die Möglichkeit erhält, ausgeführt zu werden. In jedem Fall ist es unter einer Vielzahl von Umständen, einschließlich Ihrer, immer noch nützlich.

Evan Scholle
quelle
Das rockt. Wenn nichts anderes möglich wäre, könnten wir so etwas wie ein Drei-Wege-Diff machen, das die Dateien mit und ohne den Code verarbeitet, den wir ausschließen wollten, ihr Diff nehmen und dann die diffusen Linien aus dem Original entfernen.
DeveloperDon
@DeveloperDon Yep, das ist die allgemeine Idee. Es gibt verschiedene Möglichkeiten, damit umzugehen. Dies hängt davon ab, wie Sie den Zyklus der Festschreibungsfreigabe verwalten möchten. Dieses Stück automatisiert nur einen Großteil der Arbeit, die sonst mühsam und / oder fehleranfällig wäre.
Evan Plaice
1

Wahrscheinlich wäre es eine gute Idee

1.add Kommentar Tags wie:

> // *COPYRIGHT-BEGIN-TAG*
> // Copyright 2012 (C) Acme Technology, All Rights Reserved.
> // Very large, often varied and restrictive copyright license in English and French,
> // sometimes also embedded in make files and shell scripts with varied 
> // comment styles. 
> // *COPYRIGHT-ENG-TAG*
>   ... Usual header stuff...
>
> void initTechnologyLibrary() {
>     nuiInterface(on);
> #ifdef  UNDER_RESEARCH
>     holographicVisualization(on);
> #endif
> }

2. Schreiben Sie ein Skript für den Open Source Builder, um alle Dateien zu durchsuchen und Text zwischen den Tags COPYRIGHT-BEGIN-TAG und COPYRIGHT-ENG-TAG zu ersetzen

Alex Hashimi
quelle
1
Benötige ich das Start-Tag? Bisher beginnen alle unsere Quelldateien mit dem Copyright in der ersten Zeile, und unsere Shell-Skripte beginnen mit dem Copyright in der zweiten Zeile. Da es viele Dateien gibt, möchte ich die kleinstmögliche Menge an Handbearbeitungen durchführen.
DeveloperDon
Ich denke, einige Dateien verwenden möglicherweise Doxygen, um ihre Funktion, Parameter und Rückgabewertnamen zu definieren. Für solche Dateien, die noch nicht auf diese Weise eingerichtet wurden, könnte es sehr viel Zeit in Anspruch nehmen, sie zu bearbeiten, wenn wir eine Entscheidung treffen, die weiter in diese Richtung geht.
DeveloperDon
Zumindest müssen Sie es einmal ändern. Wenn sich Ihre Copyright-Richtlinien geändert haben, können Sie sie verwalten.
Alex Hashimi
1

Ich werde Ihnen kein Tool zum Konvertieren Ihrer Codebasis zeigen, viele Antworten haben dies bereits getan. Ich beantworte vielmehr Ihren Kommentar zum Umgang mit Zweigen.

Sie sollten 2 Zweige haben:

  • Community (nennen wir die Open Source Version so)
  • Professional (nennen wir die Closed-Source-Version so)

Die Präprozessoren sollten nicht existieren. Sie haben zwei verschiedene Versionen. Und insgesamt eine sauberere Codebasis.

Sie haben Angst, zwei Exemplare parallel zu führen? Keine Sorge, du kannst fusionieren!

Wenn Sie Änderungen am Community-Zweig vornehmen, fügen Sie diese einfach in den Professional-Zweig ein. Git schafft das wirklich gut.

Auf diese Weise behalten Sie 2 gepflegte Kopien Ihrer Codebasis. Und eine für Open Source freizugeben, ist kinderleicht.

Florian Margaine
quelle