Skip to main content

使用 Copilot 将项目迁移到另一种编程语言

GitHub Copilot Chat 可以帮助你将项目移动到其他语言。 本指南介绍迁移过程中涉及的内容,并举例说明如何将 PHP 迁移到 Python。

简介

将项目迁移到新的编程语言可能是一项艰巨而耗时的任务。 GitHub Copilot 可帮助你完成此过程,方法是说明要做出的更改并使用新语言提供替换代码。

将项目迁移到新语言的原则

在开始迁移过程之前,请考虑以下几点:

  • 编码知识

    请确保充分了解这两种编程语言。 尽管 Copilot 可以为你转换代码,但你需要了解它建议的选项,并确定是要使用其建议还是请求提供其他建议。

  • 要迁移的系统的知识

    不仅要了解当前系统的功能和特性,还应了解它的体系结构和逻辑。 必须能够检查转换后的代码是否执行与原始代码相同的操作并产生相同的结果。

  • 借助 AI 的强大功能

    如果你不理解即将转换的代码中的某个部分,可以使用 Copilot 的“解释”功能,针对整个文件或文件中选定的代码部分进行解释。 请参阅“Asking GitHub Copilot questions in your IDE”。

  • 计划完成迁移的时间

    转换是一个多阶段过程。 要转换的项目越大,需要执行的步骤就越多。 请确保有足够的时间完成整个过程。

  • 迭代工作

    目标是分别转换项目的各个独立部分。 在继续进行项目的其他部分之前,请确保已验证所做的所有更改。 在进行项目的过程中,编写各个部分的测试,以便确认每个新组件按预期工作。

  • 避免在该过程增加复杂性

    最初,你应进行逐项等效转换。 并非项目中的所有代码都能进行逐项等效转换。 但是,为了避免给迁移任务增加复杂性,除转换代码以及使用新框架和适当的依赖项之外,应尽量限制引入的新更改数量。

  • 对转换后的代码进行基准测试和重构

    完成初始转换并拥有可用系统后,可以执行基准测试来比较旧系统和新系统。 现在可以使用新语言重构代码。 这是优化代码并减少技术债务的机会。

使用 Copilot 帮助将项目迁移到新语言

假设你已经熟悉了现有项目,启动迁移的一个好方法是在编辑器中打开仓库的分支,并向 Copilot 寻求帮助。

  1. 在编辑器中,打开 Copilot Chat 面板。 请参阅“Asking GitHub Copilot questions in your IDE”。

  2. 请求 Copilot 概述将项目迁移到新语言所需的步骤。

    例如,如果要从 PHP 迁移到 Python,可以这样询问:

    @workspace I want to migrate this project from PHP to Python. Give me a high level overview of the steps I need to take. Don't go into detail at this stage.

    Note

    @workspace 聊天参与者将当前工作区中的文件设置为所提的问题的上下文。

    Copilot 通常会返回一个步骤列表,指导你迁移项目所需采取的行动。

  3. 复制 Copilot 的回复,并将其保存到某个位置,以便在整个过程中参考。

  4. 按照流程中的每个步骤进行操作,必要时请求 Copilot 提供详细的帮助。

    仔细考虑 Copilot 提出的每个建议。 确保你理解它所建议的代码,并评估其是否适合你的项目。 如果你不确定,可以请 Copilot 为你解释代码。

    如果你认为 Copilot 建议的更改在某些方面不合适,请让它提供替代建议。

  5. 将组件迁移到可以运行的状态后,请检查它是否按预期工作。 如果生成错误,请将错误复制到 Copilot Chat 视图中,并请求 Copilot 帮助你修复此错误。

  6. 完成初始转换后,请通过 Copilot 使用新语言重构代码。 有关详细信息,请参阅“使用 GitHub Copilot 重构代码”。

示例:将 PHP 项目迁移到 Python

以下示例介绍了将简单的 Web 应用程序从 PHP 迁移到 Python 的过程。 即使这些语言不是在迁移中使用的编程语言,遵循此处描述的步骤也可能会对你有所帮助,帮助你熟悉项目迁移的过程。 将其他小项目从一种语言迁移到另一种语言时,步骤将类似。

从 PHP 迁移到 Python 之前“简单的 PHP 网站”的屏幕截图。

此示例假定:

  • 你正在使用 Visual Studio Code 进行操作。
  • 你已安装两种语言:PHP 和 Python 版本 3.12 或更高版本。

迁移简单的网站项目

我们将在 GitHub 上迁移此公共仓库中的代码:docs/simple-php-website

此仓库包含以下文件。

.gitignore
.htaccess
LICENSE
content
├── 404.phtml
├── about-us.phtml
├── contact.phtml
├── home.phtml
└── products.phtml
includes
├── config.php
└── functions.php
index.php
readme.md
template
├── style.css
└── template.php

该示例提供了你可以输入到 Copilot Chat 中以完成迁移的提示,并展示了 Copilot 为此迁移的一个实例返回的回复。 Copilot Chat 的回复具有不确定性,因此你可能会收到与此处展示的回复略有不同的回复。

在迁移过程中,你可能会遇到需要修复的错误,只有在解决这些错误后才能继续进行。 Copilot 可以帮助你完成此操作。 该示例包含一些错误,并展示了如何让 Copilot 来帮助修复它们。

由于你从 Copilot Chat 获得的回复可能与此处展示的不同,因此你可能会遇到不同的错误。 因此,你可能会发现使用这里展示的回复逐步完成此示例迁移比直接使用你从 Copilot 获得的回复来完成迁移更容易。

完成此示例迁移后,可以在自己的项目中使用相同的方法。

  1. 首先,将仓库的副本克隆到本地计算机。

  2. 运行应用程序以验证其是否正常运行。

    为此,请在终端中导航到克隆的仓库的根目录并运行以下命令:

    Shell
     php -S localhost:8000
    

    然后在浏览器中转到 http://localhost:8000。

  3. 浏览一下网站,熟悉其结构,这样你就能验证迁移是否成功。

  4. 在仓库中创建有效分支,并将其作为 Visual Studio Code 中的新工作区打开。

  5. 熟悉现有项目的内容和体系结构。 Copilot 可以在这方面提供帮助:

    1. 打开 Copilot Chat 试图。

    2. 输入提示,例如:

      @workspace Describe this project in detail, explaining what the various components do and how they interact.

  6. 让 Copilot 提供迁移过程的大致概述:

    @workspace I want to migrate this project from PHP to Python. Give me a high level overview of the steps I need to take. Don't go into detail at this stage.

    Copilot 将在回复中提供如下说明:

    To migrate this project from PHP to Python, follow these high-level steps:
    
    1. Set Up Python Environment:
       - Install Python and set up a virtual environment.
       - Install necessary packages (e.g., Flask for web framework).
    
    2. Convert Configuration:
       - Translate the configuration settings from config.php to a Python configuration file.
    
    3. Rewrite Functions:
       - Convert PHP functions in functions.php to Python functions.
    
    4. Create Flask Application:
       - Set up a Flask application to handle routing and views.
       - Map the routes to corresponding views.
    
    5. Convert Templates:
       - Translate template.php to a Jinja2 template.
       - Update the CSS file path in the template.
    
    6. Convert Content Pages:
       - Convert .phtml content files to HTML or Jinja2 templates.
    
    7. Update .htaccess Rules:
       - Translate .htaccess rewrite rules to Flask route handling.
    
    8. Run and Test:
       - Run the Flask application and test all routes and functionalities.
       - Ensure the site works as expected and fix any issues.
    
    9. Documentation:
       - Update the readme.md with new instructions for running the Python project.
    
  7. 复制 Copilot 的回复,并将其保存到某个位置,以便在此过程的其余部分中参考。 完成上述每个步骤,在此过程中可以向 Copilot 寻求帮助。

  8. 如果你尚未确定要使用的 Python 框架,可以询问 Copilot 获取建议:

    @workspace What Python frameworks can I use for this project once it is migrated to Python? Give me a selection of options, with a brief summary of the pros and cons of each in relation to this website project. Which framework would you recommend?

    Copilot 会在回复中提供有关各种框架的信息,并总结如下:

    For a project like yours - which is a simple, content-driven website - Flask is highly recommended. Its simplicity, flexibility, and ease of use (especially with its templating system that can easily replace your current PHP template structure) make it a great fit.
    

    我们将采用 Copilot 给出的建议并使用 Flask。

  9. 返回到 Copilot 的大致概述,第一步是设置 Python 环境并安装必要的包。 要了解如何执行此作,请在 Copilot Chat 中输入以下内容:

    @workspace I want to use Flask. Tell me how to set up a virtual environment and install the necessary packages.

    Copilot 将在回复中提供如下说明:

    1. Create a virtual environment:
       - Open a terminal and navigate to your project directory.
       - Run the following command to create a virtual environment:
         python3 -m venv venv
    
    2. Activate the virtual environment:
       - On macOS and Linux:
         source venv/bin/activate
    
       - On Windows:
         venv\Scripts\activate
    
    3. Install Flask and necessary packages:
       - With the virtual environment activated, run the following command
         to install Flask and other necessary packages:
         pip install Flask
    
    4. Verify the installation:
       - You can verify that Flask is installed by running:
         pip list
    
  10. 按照 Copilot 的说明进行操作,使用 pip list 验证是否已安装 Flask。

  11. 返回到 Copilot 给出的迁移过程概述,下一步是转换配置。 请求 Copilot 提供此方面的帮助。 例如:

    @workspace As the first step in migrating this project from PHP to Python, create a Python configuration file by converting the functions in functions.php to Python functions. Tell me where to locate the Python config file in the project.

    Copilot 建议在 includes 目录中创建名为 config.py 的文件,并在文件中包含以下代码。

    Python
    config = {
       'name': 'Simple Python Website',
       'site_url': '',
       'pretty_uri': False,
       'nav_menu': {
          '': 'Home',
          'about-us': 'About Us',
          'products': 'Products',
          'contact': 'Contact',
       },
      'template_path': 'template',
      'content_path': 'content',
      'version': 'v3.1',
    }
    
    def get_config(key=''):
       return config.get(key, None)
    
    def site_name():
       return get_config('name')
    
    def site_url():
       return get_config('site_url')
    
    def site_version():
       return get_config('version')
    
    def nav_menu(sep=' | '):
       nav_menu = ''
       nav_items = get_config('nav_menu')
    
       for uri, name in nav_items.items():
          query_string = request.args.get('page', '')
          class_active = ' active' if query_string == uri else ''
          url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}"
    
          nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}'
    
       return nav_menu.strip(sep)
    
    def page_title():
       page = request.args.get('page', 'Home')
       return ' '.join(word.capitalize() for word in page.split('-'))
    
    def page_content():
       page = request.args.get('page', 'home')
       path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml')
    
       if not os.path.exists(path):
          path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml')
    
       with open(path, 'r') as file:
          return file.read()
    
    def init():
       template_path = os.path.join(get_config('template_path'), 'template.html')
       with open(template_path, 'r') as file:
          return file.read()
    
  12. 创建 includes/config.py 文件并删除现有的 includes/config.php 文件。

  13. 再次返回到概述,请求 Copilot 帮助重写 PHP 函数。

    @workspace Continuing the migration of this project from PHP to Python, create Python functions to replace the existing PHP functions. Tell me where to locate the Python functions in the project.

    Copilot 建议在 includes 目录中创建名为 functions.py 的文件,并在文件中包含以下代码。

    Python
    import os
    from flask import request
    from .config import get_config
    
    def site_name():
       return get_config('name')
    
    def site_url():
       return get_config('site_url')
    
    def site_version():
       return get_config('version')
    
    def nav_menu(sep=' | '):
       nav_menu = ''
       nav_items = get_config('nav_menu')
    
       for uri, name in nav_items.items():
          query_string = request.args.get('page', '')
          class_active = ' active' if query_string == uri else ''
          url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}"
    
          nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}'
    
       return nav_menu.strip(sep)
    
    def page_title():
       page = request.args.get('page', 'Home')
       return ' '.join(word.capitalize() for word in page.split('-'))
    
    def page_content():
       page = request.args.get('page', 'home')
       path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml')
    
       if not os.path.exists(path):
          path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml')
    
       with open(path, 'r') as file:
          return file.read()
    
    def init():
       template_path = os.path.join(get_config('template_path'), 'template.html')
       with open(template_path, 'r') as file:
          return file.read()
    
  14. 创建 includes/functions.py 文件并删除现有的 includes/functions.php 文件。

  15. 继续处理概述内容,下一步是创建 Flask 应用程序。 请求 Copilot 提供这方面的帮助:

    @workspace Set up a Flask application to handle routing and views, and map the routes to corresponding views. Tell me the location of any files that need to be created or changed.

    Copilot 建议在项目的根目录中创建名为 app.py 的文件,并在文件中包含以下代码。

    Python
    from flask import Flask, render_template, request
    import os
    
    app = Flask(__name__)
    
    config = {
       'name': 'Simple Python Website',
       'site_url': '',
       'pretty_uri': False,
       'nav_menu': {
          '': 'Home',
          'about-us': 'About Us',
          'products': 'Products',
          'contact': 'Contact',
       },
       'template_path': 'template',
       'content_path': 'content',
       'version': 'v3.1',
    }
    
    def get_config(key=''):
       return config.get(key, None)
    
    @app.route('/')
    @app.route('/<page>')
    def index(page='home'):
       page_content = get_page_content(page)
       page_title = get_page_title(page)
       nav_menu = get_nav_menu()
       return render_template('template.html', page_title=page_title, page_content=page_content, nav_menu=nav_menu)
    
    def get_page_title(page):
       return ' '.join(word.capitalize() for word in page.split('-'))
    
    def get_page_content(page):
       path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml')
       if not os.path.exists(path):
          path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml')
       with open(path, 'r') as file:
          return file.read()
    
    def get_nav_menu(sep=' | '):
       nav_menu = ''
       nav_items = get_config('nav_menu')
       for uri, name in nav_items.items():
          query_string = request.args.get('page', '')
          class_active = ' active' if query_string == uri else ''
          url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}"
          nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}'
       return nav_menu.strip(sep)
    
    if __name__ == '__main__':
       app.run(debug=True)
    

    Copilot 还建议将 template/template.php 重命名为 template/template.html 并更新文件,以使用 Jinja2 模板语法:

    HTML
    
    <!DOCTYPE html>
    <html>
    <head>
       <meta charset="utf-8" />
       <meta http-equiv="x-ua-compatible" content="ie=edge"/>
       <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
       <title>{{ page_title }} | {{ get_config('name') }}</title>
       <link href="{{ get_config('site_url') }}/template/style.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <div class="wrap">
    
       <header>
          <h1>{{ get_config('name') }}</h1>
          <nav class="menu">
             {{ nav_menu|safe }}
          </nav>
       </header>
    
       <article>
          <h2>{{ page_title }}</h2>
          {{ page_content|safe }}
       </article>
    
       <footer>
          <small>&copy;{{ get_config('version') }} {{ get_config('name') }}.<br>{{ get_config('version') }}</small>
       </footer>
    
    </div>
    </body>
    </html>
    
    
  16. 按照建议创建 app.pytemplate/template.html 文件。

  17. Copilot 还可能会建议在创建这些文件后,在终端中从仓库根目录运行 python app.py,然后浏览到 http://127.0.0.1:5000

    Note

    根据计算机上安装 Python 的方式,可能需要使用命令 python3 app.py 而不是 python app.py,以确保使用正确的 Python 版本。

    执行此操作时,浏览器中会显示错误消息。

  18. 将初始 TemplateNotFound 错误消息复制到 Copilot Chat 视图,并询问如何解决此问题。 例如:

    @workspace When I run `python3 app.py`, I get the following error in the browser: `jinja2.exceptions.TemplateNotFound: template.html`. How can I fix this?

    Copilot 回复称,该错误表明 Flask 找不到 template.html 文件。

    它告诉你,默认情况下,Flask 会在项目根目录中的名为 templates 的文件夹中查找模板。 但 template.html 文件位于 template 目录中。 要解决此问题,需要在创建 Flask 应用时指定正确的模板文件夹。 它会建议你更新 app.py 文件,更改分配 app = Flask(__name__) 以包括 template_folder 参数:

    Python
    app = Flask(__name__, template_folder='template')
    
  19. 假设 Flask 开发服务器仍在运行,如果刷新浏览器页面 (http://127.0.0.1:5000/),则现在会看到与 get_config 函数相关的新错误。

    将此错误消息复制到 Copilot Chat 视图,并寻求帮助。

    @workspace When I run `python3 app.py`, I get the following error in the browser: `jinja2.exceptions.UndefinedError: 'get_config' is undefined.` How can I fix this?

    Copilot 回复称,错误发生的原因是 get_config 在 Jinja2 模板上下文中不可用。 它建议将以下代码添加到 app.py 文件,直接放在第 @app.route('/') 行前面:

    Python
    app.jinja_env.globals.update(get_config=get_config)
    
  20. 刷新浏览器,现在应会看到该网站。

    不含 CSS 样式的“简单 Python 网站”的屏幕截图。

    但是,未应用任何 CSS 样式。 稍后我们将解决此问题。

  21. 询问 Copilot 以下问题:

    @workspace The deployed website does not use the CSS styles. How can I fix this?

    Copilot 回复称,Flask 希望 CSS 文件位于名为 static 的目录中。 它建议将现有 style.css 文件从 template 目录移动到新的 static 目录中,然后更新 template.html 文件的 head 部分中 style.css 文件的路径。 将路径更新为:

    HTML
    
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    
    

    刷新浏览器后,网站现在应会正确呈现。

    要完成初始迁移,请继续完成 Copilot 提供的大致概述中的步骤,并根据需要寻求帮助。

完成迁移

成功完成迁移过程的进一步工作涉及以下内容:

  • 全面检查初始迁移****。
  • 修复 Bug****。 例如,在此处所述的示例中,只有在 app.py 文件的 config 部分,将 pretty_uri 设置为 True 时,页面链接才会有效。 如果需要在页面 URL 中使用查询字符串参数这一选项,或者如果希望从代码中删除此选项,可以请 Copilot 帮助你完成此操作。
  • 为迁移的项目编写测试****。
  • 通过删除不再需要的任何文件,清理项目****。
  • 使用新语言重构代码****。 迁移过程导致 Python 项目的体系结构基于原始 PHP 项目的体系结构。 完成初始迁移后,现在可以重构代码,充分利用 Python 语言和 Flask 框架的功能。
  • 更新文档readme.md 文件现已过期,需要重写。