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

13

La mia azienda (chiamiamoli Acme Technology) ha una libreria di circa mille file sorgente che originariamente proveniva dal suo gruppo di ricerca Acme Labs, incubata in un gruppo di sviluppo per un paio di anni, e più recentemente è stata fornita a una manciata dei clienti in caso di non divulgazione. Acme si sta preparando a rilasciare forse il 75% del codice per la 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 alle innovazioni future di cui hanno bisogno per tenersi fuori dalla concorrenza.

Il codice è attualmente formattato con #ifdefs che consente alla stessa base di codice di lavorare con le piattaforme di preproduzione che saranno disponibili per i ricercatori universitari e una gamma molto più ampia di clienti commerciali una volta che sarà disponibile per l'open source, mentre al Allo stesso tempo è disponibile per la sperimentazione e la prototipazione e test di compatibilità diretta con la piattaforma futura. Mantenere un singolo codice base è considerato essenziale per l'economia (e sanità) del mio gruppo che avrebbe difficoltà a mantenere due copie in parallelo.

I file nella nostra base attuale hanno un aspetto simile al seguente:

> // 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 di simile a:

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

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

Il codice è attualmente in Git e probabilmente sarà ospitato da qualche parte che usa Git. Ci sarebbe un modo per collegare in modo sicuro gli archivi in modo da poter reintegrare in modo efficiente i nostri miglioramenti con le versioni open source? Consigli su altre insidie sono i benvenuti.

    
posta DeveloperDon 07.11.2012 - 06:27
fonte

5 risposte

6

Sembra che non sarebbe troppo difficile scrivere uno script per analizzare i preprocessori, confrontarli con un elenco di costanti definite ( UNDER_RESEARCH , FUTURE_DEVELOPMENT , ecc.) e, se la direttiva può essere valutata a falso dato ciò che è definito, rimuovi tutto fino al prossimo #endif .

In Python, farei qualcosa di simile,

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

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

    
risposta data 08.11.2012 - 02:54
fonte
3

Stavo pensando di far passare il codice attraverso il preprocessore per espandere solo le macro, in modo da emettere solo la parte interessante in #ifdef s.

Qualcosa del genere dovrebbe funzionare:

gcc -E yourfile.c

Ma:

  • Perderai tutti i commenti. Puoi utilizzare -CC per (tipo) preservarli, ma dovrai ancora rimuovere la vecchia nota sul copyright
  • Anche #include s è espanso, quindi ti ritroverai con un grosso file contenente tutto il contenuto dei file header inclusi
  • Perderai le macro "standard".

Potrebbe esserci un modo per limitare quali macro vengono espanse; comunque il mio suggerimento qui è di suddividere le cose, invece di eseguire (potenzialmente pericolosi) l'elaborazione sui file (a proposito, come penseresti di mantenerli dopo? ad esempio reintrodurre il codice dalla versione opensource nel tuo closed source?).

Cioè, prova a inserire il codice che vuoi inserire in opensource nelle librerie esterne il più possibile, quindi usale come faresti con qualsiasi altra libreria, integrandoti con altre librerie closed-source "personalizzate".

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

    
risposta data 08.11.2012 - 03:26
fonte
2

Ho una soluzione ma richiederà un po 'di lavoro

pypreprocessor è una libreria che fornisce un puro preprocessore in stile c per python che può anche essere utilizzato come GPP (Pre-Processor General Purpose) 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. Effettua un passaggio attraverso la fonte e condiziona in modo condizionale la fonte in base a ciò che è definito.

Le definizioni possono essere impostate tramite le istruzioni #define nel sorgente 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 configurato per elaborare in batch un numero elevato di file, se desiderato.

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

Nota: in genere questo non dovrebbe essere impostato in modo esplicito perché Python rimuove automaticamente il codice commentato durante la compilazione in bytecode.

Vedo solo un caso limite. Poiché stai cercando di preelaborare la sorgente C, potresti voler impostare esplicitamente il processore in modo esplicito (ad es. Tramite pypreprocessor.defines) e dirgli di ignorare le istruzioni #define nell'origine. Questo dovrebbe impedirgli di rimuovere accidentalmente eventuali costanti che è possibile utilizzare nel codice sorgente del progetto. Al momento non ci sono parametri per impostare questa funzionalità, ma sarebbe banale da 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 [email protected] 
// for technical support, and www.acme.com/emergingTech for updates and RSS feed.
#endif

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

Disclosure: I am the original author of pypreprocessor.

A parte: inizialmente l'ho scritto come una soluzione al temuto problema di manutenzione di Python 2k / 3x. Il mio approccio era, fare lo sviluppo 2 e 3 negli stessi file sorgente e solo includere / escludere le differenze usando le direttive del preprocessore. Sfortunatamente, ho scoperto che è impossibile scrivere un vero preprocessore puro (cioè non richiede c) in python perché il lexer contrassegna gli errori di sintassi in codice incompatibile prima che il preprocessore abbia la possibilità di eseguire. In ogni caso, è comunque utile in una vasta gamma di circostanze, inclusa la tua.

    
risposta data 08.11.2012 - 03:37
fonte
1

Probabilmente sarebbe una buona idea

tag di commento 1.add 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. Scrive lo script per il generatore open source per esaminare tutti i file e sostituisci il testo tra i tag COPYRIGHT-BEGIN-TAG e COPYRIGHT-ENG-TAG

    
risposta data 08.11.2012 - 02:13
fonte
1

Non ho intenzione di mostrarti uno strumento per convertire il tuo codebase, 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 come questa)
  • Professional (chiamiamo la versione closed source come questa)

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

Hai paura di mantenere due copie in parallelo? Non ti preoccupare, puoi unire!

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

In questo modo, mantieni 2 copie mantenute del codice base. E rilasciare uno per l'open source è facile come torta.

    
risposta data 08.11.2012 - 09:04
fonte

Leggi altre domande sui tag