Làm cách nào tôi có thể quản lý tốt nhất việc tạo các bản phát hành mã nguồn mở từ mã nghiên cứu bí mật của công ty tôi?


13

Công ty của tôi (hãy gọi chúng là Acme Technology) có một thư viện gồm khoảng một nghìn tệp nguồn gốc từ nhóm nghiên cứu Acme Labs của nó, được ươm tạo trong một nhóm phát triển trong một vài năm và gần đây đã được cung cấp cho một số ít khách hàng không tiết lộ. Acme đã sẵn sàng để phát hành có lẽ 75% mã cho cộng đồng nguồn mở. 25% còn lại sẽ được phát hành sau đó, nhưng hiện tại, chưa sẵn sàng cho khách hàng sử dụng hoặc chứa mã liên quan đến các đổi mới trong tương lai mà họ cần để tránh xa các đối thủ cạnh tranh.

Mã hiện được định dạng với #ifdefs cho phép cùng một cơ sở mã hoạt động với các nền tảng tiền sản xuất sẽ có sẵn cho các nhà nghiên cứu đại học và một phạm vi khách hàng thương mại rộng hơn nhiều khi nó chuyển sang nguồn mở, đồng thời có sẵn để thử nghiệm và tạo mẫu và thử nghiệm khả năng tương thích về phía trước với nền tảng trong tương lai. Giữ một cơ sở mã duy nhất được coi là cần thiết cho kinh tế (và sự tỉnh táo) của nhóm tôi, người sẽ có một thời gian khó khăn để duy trì song song hai bản sao.

Các tệp trong cơ sở hiện tại của chúng tôi trông giống như thế này:

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

Và chúng tôi muốn chuyển đổi chúng thành một cái gì đó như:

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

Có công cụ, thư viện phân tích hoặc tập lệnh phổ biến nào có thể thay thế bản quyền và loại bỏ không chỉ #ifdefs, mà cả các biến thể như #if được xác định (UNDER_RESEARCH), v.v.?

Mã hiện có trong Git và có khả năng sẽ được lưu trữ ở đâu đó sử dụng Git. Liệu có cách nào để liên kết các kho lưu trữ với nhau một cách an toàn để chúng tôi có thể tái hòa nhập một cách hiệu quả các cải tiến của chúng tôi với các phiên bản nguồn mở? Tư vấn về những cạm bẫy khác được chào đón.


13
Codebase này đang hét cho các chi nhánh.
Florian Margaine

Một ví dụ về việc sử dụng các chi nhánh cho mục đích này sẽ được hoan nghênh nhất.
Nhà phát

Câu trả lời:


6

Nó có vẻ như nó sẽ không quá khó khăn để viết một kịch bản để phân tích preprocessors, so sánh chúng với một danh sách các hằng số định nghĩa ( UNDER_RESEARCH, FUTURE_DEVELOPMENT, vv), và nếu chỉ có thể được đánh giá để GIVEN sai những gì đang được xác định, loại bỏ tất cả mọi thứ lên tiếp theo #endif.

Trong Python, tôi sẽ làm một cái gì đó như,

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

Tôi chắc chắn có nhiều cách thanh lịch hơn để làm điều đó, nhưng điều này nhanh chóng và bẩn thỉu và dường như để hoàn thành công việc.


Ồ cảm ơn nhé. Có rất nhiều logic có khả năng tạo ra một bộ lọc tốt và tôi đánh giá cao ví dụ của bạn. Tôi hy vọng tìm thấy thứ gì đó để sử dụng lại và máy phát triển của tôi rất nhanh với bộ nhớ lớn vì vậy hiệu suất không phải là vấn đề quá lớn để chạy các bộ lọc riêng cho bản quyền và định nghĩa hoặc chạy bộ lọc xác định nhiều lần. Chúng tôi thực sự có nhiều định nghĩa liên quan đến từ khóa chỉ định nhiều dự án trong tương lai và một vài dự án trong quá khứ sẽ không được phát hành nguồn mở, nhưng vẫn được sử dụng nội bộ và bởi những khách hàng sớm chấp nhận.
Nhà phát

3

Tôi đã suy nghĩ về việc chuyển mã của bạn thông qua bộ tiền xử lý để chỉ mở rộng các macro, do đó chỉ xuất ra phần thú vị trong #ifdefs.

Một cái gì đó như thế này sẽ hoạt động:

gcc -E yourfile.c

Nhưng:

  • Bạn sẽ mất tất cả các ý kiến. Bạn có thể sử dụng -CCđể (loại) bảo quản chúng, nhưng sau đó bạn sẽ vẫn phải loại bỏ thông báo bản quyền cũ
  • #includes cũng được mở rộng, vì vậy bạn sẽ kết thúc với một tệp lớn chứa tất cả nội dung của các tệp tiêu đề được bao gồm
  • Bạn sẽ mất các macro "tiêu chuẩn".

Có thể có một cách để hạn chế các macro được mở rộng; tuy nhiên, đề nghị của tôi ở đây là phân tách mọi thứ, thay vì xử lý (có khả năng gây nguy hiểm) trên các tệp (nhân tiện, bạn dự định duy trì chúng sau như thế nào? ví dụ: giới thiệu lại mã từ phiên bản mã nguồn mở vào nguồn đóng của bạn?).

Đó là, hãy thử đặt mã bạn muốn mở vào các thư viện bên ngoài càng nhiều càng tốt, sau đó sử dụng chúng như với bất kỳ thư viện nào khác, tích hợp với các thư viện nguồn đóng "tùy chỉnh" khác.

Ban đầu có thể mất một chút thời gian để tìm ra cách tái cấu trúc mọi thứ, nhưng chắc chắn đó là cách đúng đắn để thực hiện điều này.


Tôi đã xem xét liệu có thể có một cái gì đó có thể được thực hiện với bộ tiền xử lý để loại bỏ có chọn lọc các khối mà chúng tôi sẽ không phát hành chưa. Mã này rất phức tạp và chúng tôi có thể sẽ cần nhiều bình luận hơn là ít hơn, nhưng đề xuất của bạn chắc chắn có giá trị trong danh sách động não. Các câu hỏi của WRT về cách chúng tôi dự định duy trì nguồn và di chuyển mã ngược và chuyển tiếp tới cộng đồng, cần có thêm kế hoạch. Đưa mã vào mã độc quyền đặt ra một số câu hỏi hay.
Nhà phát

2

Tôi có một giải pháp nhưng nó sẽ đòi hỏi một chút công việc

pypre Processor là một thư viện cung cấp bộ tiền xử lý kiểu c thuần cho python cũng có thể được sử dụng làm GPP (Bộ xử lý trước mục đích chung) cho các loại mã nguồn khác.

Đây là một ví dụ cơ bản:

from pypreprocessor import pypreprocessor

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

Bộ tiền xử lý cực kỳ đơn giản. Nó thực hiện chuyển qua nguồn và nhận xét có điều kiện ra nguồn dựa trên những gì được xác định.

Các định nghĩa có thể được đặt thông qua các câu lệnh #define trong nguồn hoặc bằng cách đặt chúng trong danh sách pypre Processor.defines.

Đặt tham số đầu vào / đầu ra cho phép bạn xác định rõ ràng tệp nào đang được mở / đóng để một bộ xử lý trước có thể được thiết lập để xử lý hàng loạt một số lượng lớn tệp nếu muốn.

Đặt tham số removeMeta thành True, bộ xử lý trước sẽ tự động trích xuất bất kỳ và tất cả các câu lệnh tiền xử lý chỉ để lại mã được xử lý sau.

Lưu ý: Thông thường, điều này sẽ không cần phải được đặt rõ ràng vì python đã tự động xóa mã nhận xét trong quá trình biên dịch thành mã byte.

Tôi chỉ thấy một trường hợp cạnh. Vì bạn đang tìm kiếm nguồn C tiền xử lý, bạn có thể muốn đặt bộ xử lý xác định rõ ràng (tức là thông qua pypre Processor.defines) và bảo nó bỏ qua các câu lệnh #define trong nguồn. Điều đó sẽ giúp nó không vô tình xóa bất kỳ hằng số nào bạn có thể sử dụng trong mã nguồn dự án của mình. Hiện tại không có tham số để thiết lập chức năng này nhưng nó sẽ là không đáng kể để thêm.

Đây là một ví dụ tầm thường:

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

Sau đó, nguồn:

#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

Lưu ý: Rõ ràng, bạn sẽ cần sắp xếp một cách để đặt các tệp đầu vào / đầu ra nhưng điều đó không quá khó.

Tiết lộ: Tôi là tác giả gốc của pypre Processor.


Ngoài ra: ban đầu tôi đã viết nó như là một giải pháp cho vấn đề bảo trì 2k / 3x của con trăn đáng sợ. Cách tiếp cận của tôi là, thực hiện phát triển 2 và 3 trong cùng một tệp nguồn và chỉ bao gồm / loại trừ sự khác biệt bằng cách sử dụng các chỉ thị tiền xử lý. Thật không may, tôi đã phát hiện ra một cách khó khăn là không thể viết một bộ tiền xử lý thuần túy (nghĩa là không yêu cầu c) trong python vì lexer đánh dấu các lỗi cú pháp trong mã không tương thích trước khi bộ tiền xử lý có cơ hội chạy. Dù bằng cách nào, nó vẫn hữu ích trong một loạt các trường hợp bao gồm cả của bạn.


Những hòn đá này. Nếu không có gì khác, chúng tôi có thể thực hiện một số cách khác như ba cách xử lý các tệp có và không có mã mà chúng tôi muốn loại trừ, lấy diff của chúng, sau đó xóa các dòng khác khỏi bản gốc.
DeveloperDon

@DeveloperDon Yep, đó là ý tưởng chung. Có một vài cách khác nhau để xử lý nó, nó phụ thuộc vào cách bạn lên kế hoạch quản lý chu kỳ phát hành cam kết. Phần này chỉ tự động hóa đi rất nhiều công việc mà nếu không sẽ tẻ nhạt và / hoặc dễ bị lỗi.
Evan Plaice

1

Có lẽ nó sẽ là ý tưởng tốt để

1.add thẻ nhận xét như:

> // *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. script Viết cho người xây dựng mã nguồn mở phải đi qua tất cả các file và thay thế văn bản giữa BẢN QUYỀN-BEGIN-TAGVỀ BẢN QUYỀN-ENG-TAG thẻ


1
Tôi có cần thẻ bắt đầu không? Cho đến nay, tất cả các tệp nguồn của chúng tôi đều bắt đầu với bản quyền ở dòng đầu tiên và các tập lệnh shell của chúng tôi bắt đầu bằng bản quyền ở dòng thứ hai. Có rất nhiều tập tin, vì vậy tôi muốn thực hiện số lượng chỉnh sửa tay nhỏ nhất có thể.
DeveloperDon

Tôi nghĩ rằng một số tệp có thể sử dụng Doxygen để phân định chức năng, tham số và trả về tên giá trị của chúng. Đối với những tệp chưa được thiết lập theo cách đó, nó thực sự có thể được chỉnh sửa rất nhiều nếu chúng tôi đưa ra lựa chọn tiếp tục theo hướng đó.
Nhà phát

Ít nhất bạn phải thay đổi nó một lần. nếu chính sách bản quyền của bạn thay đổi, bạn có thể quản lý nó.
Alex Hashimi

1

Tôi sẽ không chỉ cho bạn một công cụ để chuyển đổi cơ sở mã của bạn, rất nhiều câu trả lời đã làm điều đó. Thay vào đó, tôi đang trả lời bình luận của bạn về cách xử lý các nhánh cho việc này.

Bạn nên có 2 chi nhánh:

  • Cộng đồng (hãy gọi phiên bản nguồn mở như thế này)
  • Chuyên nghiệp (hãy gọi phiên bản nguồn đóng như thế này)

Các tiền xử lý không nên tồn tại. Bạn có hai phiên bản khác nhau. Và một codebase tổng thể sạch hơn.

Bạn sợ duy trì song song hai bản sao? Đừng lo lắng, bạn có thể hợp nhất!

Nếu bạn đang thực hiện sửa đổi cho chi nhánh cộng đồng, chỉ cần hợp nhất chúng trong chi nhánh chuyên nghiệp. Git xử lý việc này thực sự tốt.

Bằng cách này, bạn giữ 2 bản sao duy trì của cơ sở mã của bạn. Và phát hành một cho nguồn mở dễ dàng như chiếc bánh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.