Come posso gestire al meglio le pubblicazioni di codice open source dal codice di ricerca confidenziale della mia azienda?


13

La mia azienda (chiamiamoli Acme Technology) ha una libreria di circa un migliaio di file di origine originari del gruppo di ricerca Acme Labs, incubati in un gruppo di sviluppo per un paio d'anni e più recentemente sono stati forniti a una manciata di clienti non divulgazione. Acme si sta preparando a rilasciare forse il 75% del codice alla comunità open source. L'altro 25% verrebbe rilasciato in seguito, ma per ora non è pronto per l'uso da parte dei clienti o contiene codice relativo a innovazioni future che devono tenere fuori dalle mani della concorrenza.

Il codice è attualmente formattato con #ifdefs che consente alla stessa base di codice di lavorare con le piattaforme di pre-produzione che saranno disponibili per i ricercatori universitari e una gamma molto più ampia di clienti commerciali una volta che passano all'open source, mentre allo stesso tempo sono disponibile per sperimentazione e prototipazione e test di compatibilità con la futura piattaforma. Mantenere una singola base di codice è considerato essenziale per l'economia (e la sanità mentale) del mio gruppo che farebbe fatica a mantenere due copie in parallelo.

I file nella nostra base attuale assomigliano a questo:

> // 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
> }

E vorremmo convertirli in qualcosa del tipo:

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

Esiste uno strumento, una libreria di analisi o uno script popolare che può sostituire il copyright e rimuovere non solo #ifdefs, ma varianti come #if definite (UNDER_RESEARCH), ecc.?

Il codice è attualmente in Git e probabilmente sarebbe ospitato da qualche parte che utilizza Git. Ci sarebbe un modo per collegare in modo sicuro i repository in modo da poter reintegrare in modo efficiente i nostri miglioramenti con le versioni open source? I consigli su altre insidie ​​sono ben accetti.


13
Questa base di codice sta gridando per i rami.
Florian Margaine,

Un esempio di utilizzo dei rami per questo scopo sarebbe il benvenuto.
Sviluppatore:

Risposte:


6

Sembra che non sarebbe troppo difficile da scrivere uno script per analizzare i preprocessori, li confronta con un elenco di costanti definite ( UNDER_RESEARCH, FUTURE_DEVELOPMENT, ecc) e, se la direttiva può essere valutato a false Visto quello che sta definito, rimuovere tutto ciò fino al prossimo #endif.

In Python, farei qualcosa del tipo,

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 xyz@acme.com 
// 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')

Sono sicuro che ci sono modi più eleganti per farlo, ma questo è veloce e sporco e sembra fare il lavoro.


Wow grazie. C'è molta logica potenzialmente per creare un buon filtro e apprezzo il tuo esempio. Spero di trovare qualcosa da riutilizzare e la mia macchina di sviluppo è veloce con una grande memoria, quindi le prestazioni non sono una grande preoccupazione per eseguire filtri separati per il copyright e le definizioni o per eseguire il filtro di definizione più di una volta. In realtà abbiamo molteplici definizioni relative a parole chiave che designano più progetti futuri e un paio di progetti passati che non verranno rilasciati open source, ma che vengono comunque utilizzati internamente e dai clienti che adottano in anticipo.
Sviluppatore:

3

Stavo pensando di passare il codice attraverso il preprocessore per espandere solo le macro, producendo così solo la parte interessante nella #ifdefs.

Qualcosa del genere dovrebbe funzionare:

gcc -E yourfile.c

Ma:

  • Perderai tutti i commenti. Puoi usarli -CCper (preservarli), ma dovrai comunque eliminare la vecchia nota sul copyright
  • #includeanche gli s vengono espansi, quindi finirai con un file di grandi dimensioni contenente tutto il contenuto dei file di intestazione inclusi
  • Perderai macro "standard".

Potrebbe esserci un modo per limitare le macro espanse; tuttavia il mio suggerimento qui è quello di dividere le cose, invece di fare (potenzialmente pericoloso) l'elaborazione dei file (a proposito, come penseresti di mantenerli dopo? ad esempio reintrodurre il codice dalla versione opensource nella tua fonte chiusa?).

Cioè, prova a inserire il codice che vuoi openource nelle librerie esterne il più possibile, quindi usali come faresti con qualsiasi altra libreria, integrandosi con altre librerie "personalizzate" di origine chiusa.

All'inizio potrebbe essere necessario un po 'più di tempo per capire come ristrutturare le cose, ma è sicuramente il modo giusto per farlo.


Avevo considerato se ci fosse qualcosa che poteva essere fatto con il preprocessore per eliminare selettivamente i blocchi che non rilasceremo ancora. Il codice è complesso e probabilmente avremo bisogno di più commenti piuttosto che di meno, ma vale sicuramente la pena suggerire il tuo suggerimento nell'elenco di brainstorming. Domande WRT su come intendiamo mantenere il codice sorgente e spostare il codice avanti e indietro nella comunità, è necessaria una maggiore pianificazione. L'inserimento del codice nel codice proprietario solleva alcune buone domande.
Sviluppatore:

2

Ho una soluzione ma richiederà un po 'di lavoro

pypreprocessor è una libreria che fornisce un preprocessore puro in stile c per python che può anche essere usato come GPP (General Purpose Pre-Processor) per altri tipi di codice sorgente.

Ecco un esempio di base:

from pypreprocessor import pypreprocessor

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

Il preprocessore è estremamente semplice. Passa attraverso la fonte e commenta condizionalmente la fonte in base a ciò che è definito.

Le definizioni possono essere impostate tramite le istruzioni #define nell'origine o impostandole nell'elenco pypreprocessor.defines.

L'impostazione dei parametri di input / output consente di definire esplicitamente quali file vengono aperti / chiusi in modo che un singolo preprocessore possa essere impostato per elaborare in batch un numero elevato di file, se lo si desidera.

Impostando il parametro removeMeta su True, il preprocessore dovrebbe estrarre automaticamente tutte le istruzioni del preprocessore lasciando solo il codice post-elaborato.

Nota: di solito questo non dovrebbe essere impostato esplicitamente perché python ha rimosso automaticamente il codice commentato durante la compilazione in bytecode.

Vedo solo un caso limite. Poiché stai cercando di preelaborare l'origine C, potresti voler impostare in modo esplicito il processore in modo esplicito (ovvero tramite pypreprocessor.defines) e dirgli di ignorare le istruzioni #define nell'origine. Ciò dovrebbe impedirgli di rimuovere accidentalmente tutte le costanti che è possibile utilizzare nel codice sorgente del progetto. Al momento non esiste alcun parametro per impostare questa funzionalità, ma sarebbe banale aggiungere.

Ecco un esempio banale:

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()

Quindi la fonte:

#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 xyz@acme.com 
// for technical support, and www.acme.com/emergingTech for updates and RSS feed.
#endif

Nota: ovviamente, dovrai scegliere un modo per impostare i file di input / output, ma ciò non dovrebbe essere troppo difficile.

Divulgazione: sono l'autore originale di pypreprocessor.


A parte: inizialmente l'ho scritto come soluzione al temuto problema di manutenzione di Python 2k / 3x. Il mio approccio è stato quello di fare lo sviluppo 2 e 3 negli stessi file sorgente e includere / escludere le differenze usando le direttive del preprocessore. Sfortunatamente, ho scoperto nel modo più duro che è impossibile scrivere un vero preprocessore puro (cioè non richiede c) in Python perché il lexer segnala errori di sintassi in codice incompatibile prima che il preprocessore abbia la possibilità di funzionare. Ad ogni modo, è ancora utile in una vasta gamma di circostanze tra cui la tua.


Questo rocce. Se non altro potremmo fare una sorta di diff a tre vie che ha elaborato i file con e senza il codice che volevamo escludere, ha preso il loro diff, quindi ha rimosso le righe diffuse dall'originale.
Sviluppatore:

@DeveloperDon Yep, questa è l'idea generale. Esistono diversi modi per gestirlo, dipende da come si pianifica di gestire il ciclo di commit-release. Questo pezzo automatizza gran parte del lavoro che altrimenti sarebbe noioso e / o soggetto a errori.
Evan Plaice,

1

Probabilmente sarebbe una buona idea

1.aggiungere tag come:

> // *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. Scrivere uno script per il builder open source per esaminare tutti i file e sostituire il testo tra i tag COPYRIGHT-BEGIN-TAG e COPYRIGHT-ENG-TAG


1
Ho bisogno del tag di inizio? Finora tutti i nostri file di origine iniziano con il copyright nella prima riga e i nostri script di shell iniziano con il copyright nella seconda riga. Ci sono molti file, quindi mi piacerebbe fare il minor numero possibile di editing manuale.
Sviluppatore:

Penso che alcuni file possano usare Doxygen per delineare la loro funzione, parametro e restituire i nomi dei valori. Per quei file che non sono già stati configurati in questo modo, potrebbe davvero essere un sacco di editing se prendessimo una scelta che ha preso ulteriormente in quella direzione.
Sviluppatore:

Almeno devi cambiarlo una volta. se la tua politica sul copyright è cambiata puoi gestirla.
Alex Hashimi,

1

Non ti mostrerò uno strumento per convertire la tua base di codice, molte risposte lo hanno già fatto. Piuttosto, sto rispondendo al tuo commento su come gestire i rami per questo.

Dovresti avere 2 rami:

  • Community (chiamiamo la versione open source in questo modo)
  • Professionale (chiamiamo la versione chiusa come questa)

I preprocessori non dovrebbero esistere. Hai due versioni diverse. E una base di codice più pulita in generale.

Hai paura di mantenere due copie in parallelo? Non preoccuparti, puoi unirti!

Se stai apportando modifiche al ramo della comunità, basta unirle nel ramo professionale. Git lo gestisce davvero bene.

In questo modo, conservi 2 copie mantenute della tua base di codice. E rilasciarne uno per l'open source è facile come una torta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.