CN113391826B - 一种定制镜像中软件包依赖的解决方法 - Google Patents
一种定制镜像中软件包依赖的解决方法 Download PDFInfo
- Publication number
- CN113391826B CN113391826B CN202110934204.2A CN202110934204A CN113391826B CN 113391826 B CN113391826 B CN 113391826B CN 202110934204 A CN202110934204 A CN 202110934204A CN 113391826 B CN113391826 B CN 113391826B
- Authority
- CN
- China
- Prior art keywords
- software package
- data
- storage device
- dependency
- dependent
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Active
Links
- 238000000034 method Methods 0.000 title claims abstract description 63
- 230000001419 dependent effect Effects 0.000 claims abstract description 76
- 230000008569 process Effects 0.000 claims abstract description 22
- 238000004891 communication Methods 0.000 description 16
- 238000010586 diagram Methods 0.000 description 8
- 238000012545 processing Methods 0.000 description 6
- 230000006870 function Effects 0.000 description 5
- 230000008901 benefit Effects 0.000 description 3
- 230000002093 peripheral effect Effects 0.000 description 3
- 238000009434 installation Methods 0.000 description 2
- 230000011218 segmentation Effects 0.000 description 2
- 238000012546 transfer Methods 0.000 description 2
- 230000007723 transport mechanism Effects 0.000 description 2
- 239000002699 waste material Substances 0.000 description 2
- 230000002159 abnormal effect Effects 0.000 description 1
- 230000001413 cellular effect Effects 0.000 description 1
- 238000013500 data storage Methods 0.000 description 1
- 230000002452 interceptive effect Effects 0.000 description 1
- 238000012986 modification Methods 0.000 description 1
- 230000004048 modification Effects 0.000 description 1
- 238000004806 packaging method and process Methods 0.000 description 1
- 238000005192 partition Methods 0.000 description 1
- 239000011800 void material Substances 0.000 description 1
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/70—Software maintenance or management
- G06F8/71—Version control; Configuration management
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/60—Software deployment
- G06F8/61—Installation
- G06F8/63—Image based installation; Cloning; Build to order
Landscapes
- Engineering & Computer Science (AREA)
- Software Systems (AREA)
- General Engineering & Computer Science (AREA)
- Theoretical Computer Science (AREA)
- Physics & Mathematics (AREA)
- General Physics & Mathematics (AREA)
- Computer Security & Cryptography (AREA)
- Stored Programmes (AREA)
Abstract
本发明公开了一种定制镜像中软件包依赖的解决方法,涉及计算机领域,方法包括:确定目标软件包的所有依赖软件包,作为第一软件包;在定制镜像过程中,遍历任一第一软件包;若从第一存储装置中查找到当前遍历的第一软件包的数据,则从第一存储装置中获取当前遍历的第一软件包的数据;若未从第一存储装置中查找到当前遍历的第一软件包的数据,则下载当前遍历的第一软件包由上述内容可知,本发明实现了在定制镜像过程中依赖原始操作系统已安装的软件包,遍历目标预装软件包所缺失的依赖,由于基于原始操作系统中已安装的软件包确定缺失依赖,从而能够在定制镜像过程中准确识别目标预装软件包所缺失的依赖。
Description
技术领域
本发明涉及计算机领域,特别涉及一种定制镜像中软件包依赖的解决方法、计算设备及存储介质。
背景技术
软件包是指具有特定的功能,用来完成特定任务的一个程序或一组程序。Linux操作系统的软件包依赖关系复杂,例如,软件包A依赖于软件包B1、B2、B3等,而软件包B1又依赖于软件包C1、C2、C3等,也即,一个软件包和其依赖软件包实际上可以理解为一个多叉树形结构。
预装软件包,即在计算设备出厂时已安装的软件包。在定制镜像(即在原始操作系统之上复制一个操作系统)过程中,如果要将一个预装软件包定制到镜像操作系统中且能正常运行,需要在镜像操作系统中安装该预装软件包的所有依赖软件包。目前,主要通过分析工作计算设备(即定制镜像过程中所使用的计算设备)已下载的软件包,下载预装软件包所缺失的依赖软件包,但是,原始操作系统的软件包安装情况与工作计算设备的往往不同,容易造成缺少依赖软件包的情况。因此,通过上述方法定制镜像后,由于缺少依赖软件包,使得预装软件包无法正常运行。也即,通过已有的预装软件包的依赖软件包解决方法无法准确识别所缺失的依赖软件包,使得预装软件包无法在镜像操作系统上正常运行。
发明内容
为此,本发明提供一种定制镜像中软件包依赖的解决方法,以力图解决或者至少缓解上面存在的问题。
根据本发明的一个方面,提供了一种定制镜像中软件包依赖的解决方法,在计算设备中执行,计算设备与第一存储装置通信连接,其中,第一存储装置存储有定制镜像的原始操作系统上已安装的所有软件包的数据,所述方法包括:确定目标软件包的所有依赖软件包,作为第一软件包,其中,所述目标软件包为任一预装软件包;在定制镜像过程中,遍历任一第一软件包;若从第一存储装置中查找到当前遍历的所述第一软件包的数据,则从第一存储装置中获取当前遍历的第一软件包的数据;若未从第一存储装置中查找到当前遍历的第一软件包的数据,则下载当前遍历的第一软件包。
可选地,计算设备还与第二存储装置通信连接,所述方法还包括步骤:将已下载的第一软件包的数据存储至第二存储装置。
可选地,下载当前遍历的第一软件包的步骤包括:判断第二存储装置中是否存储有当前遍历的第一软件包的数据,若是,从第二存储装置中获取当前遍历的第一软件包的数据,若否,下载当前遍历的第一软件包。
可选地,还包括步骤:通过已获取的第一软件包的数据、或者已下载的第一软件包的数据确定当前遍历的第一软件包的所有依赖软件包;遍历第一软件包的任一依赖软件包。
可选地,还包括步骤:获取原始操作系统的第一预定文件;从第一预定文件中读取原始操作系统上已安装的所有软件包的数据;将已读取的所有软件包的数据存储至第一存储装置。
可选地,通过深度优先算法遍历任一第一软件包。
可选地,第一存储装置存储的任一已安装软件包的数据包括:已安装软件包名称、已安装软件包版本号和依赖软件包信息,所述依赖软件包信息包括:依赖软件包的名称、版本号和版本号类型,以及备选依赖软件包的版本号、名称以及本版号类型。
可选地,第二存储装置存储的任一已下载软件包的数据包括:已下载软件包的名称、版本号、版本号类型和第二预定文件的路径,第二预定文件中包括已下载软件包的所有依赖的名称、版本号、版本号类型以及备选依赖软件包的名称、版本号和版本号类型。
可选地,任一第一软件包包括目标软件包的任一依赖软件包和任一依赖软件包的备选依赖软件包。
根据本发明的一个方面,提供了一种计算设备,包括:至少一个处理器;以及存储器,存储有程序指令,其中,所述程序指令被配置为适于由所述至少一个处理器执行,所述程序指令包括用于执行如上所述方法的指令。
根据本发明的一个方面,提供了一种存储有程序指令的可读存储介质,当所述程序指令被计算设备读取并执行时,使得所述计算设备执行如上所述的方法。
根据本发明的技术方案,提供了一种定制镜像中软件包依赖的解决方法,该方法首先确定目标软件包的所有依赖,在定制镜像过程中,遍历任一依赖,并判断是否从第一存储装置(包括原始操作系统已安装的软件包的数据)中查找到当前遍历的依赖的数据,若是,从第一存储装置中获取当前遍历依赖的数据,若未从第一存储装置中查找到当前遍历的依赖的数据,下载当前遍历的依赖,将已下载依赖的数据存储至第二存储装置。
由上述内容可知,本发明实现了在定制镜像过程中依赖原始操作系统已安装的软件包,遍历目标预装软件包所缺失的依赖,由于基于原始操作系统中已安装的软件包确定缺失依赖,从而能够在定制镜像过程中准确识别目标预装软件包所缺失的依赖,提高缺失依赖的识别准确性。
另外,本发明中还会存储已下载的依赖,只有未存储时才会下载缺失依赖,从而避免重复下载,提高软件包依赖的解决速度,也可避免资源浪费,提高资源利用率。
上述说明仅是本发明技术方案的概述,为了能够更清楚了解本发明的技术手段,而可依照说明书的内容予以实施,并且为了让本发明的上述和其它目的、特征和优点能够更明显易懂,以下特举本发明的具体实施方式。
附图说明
为了实现上述以及相关目的,本文结合下面的描述和附图来描述某些说明性方面,这些方面指示了可以实践本文所公开的原理的各种方式,并且所有方面及其等效方面旨在落入所要求保护的主题的范围内。通过结合附图阅读下面的详细描述,本公开的上述以及其它目的、特征和优势将变得更加明显。遍及本公开,相同的附图标记通常指代相同的部件或元素。
图1示出了根据本发明一个实施例的软件包依赖的树形结构的示意图;
图2示出了根据本发明一个实施例的定制镜像中软件包依赖的解决系统100的示意图;
图3示出了根据本发明一个实施例的计算设备200的示意图;以及
图4示出了根据本发明一个实施例的定制镜像中软件包依赖的解决方法300的流程图。
具体实施方式
下面将参照附图更详细地描述本公开的示例性实施例。虽然附图中显示了本公开的示例性实施例,然而应当理解,可以以各种形式实现本公开而不应被这里阐述的实施例所限制。相反,提供这些实施例是为了能够更透彻地理解本公开,并且能够将本公开的范围完整的传达给本领域的技术人员。
Linux操作系统中,软件包依赖关系复杂,例如,软件包A依赖于软件包B1、B2、B3等,而软件包B1又依赖于软件包C1、C2、C3等,也即,一个软件包和其依赖软件包实际上可以理解为一个多叉树形结构,如图1所示,图1示出了根据本发明一个实施例的软件包依赖的树形结构的示意图。
在定制镜像过程中,如果要将一个预装软件包定制到镜像操作系统中且能正常运行,需要在镜像操作系统中安装该预装软件包的所有依赖软件包。目前,主要通过分析工作计算设备已下载的软件包,下载预装软件包所缺失的依赖软件包,但是,原始操作系统的软件包安装情况与工作计算设备的往往不同,例如,如果工作计算设备安装了软件包C2,那么在下载预装软件包的依赖软件包过程中不会下载软件包C2,但是实际情况是原始操作系统并未安装软件包C2。因此,通过已有的预装软件包的依赖软件包解决方法无法准确识别所缺失的依赖软件包,使得预装软件包无法在镜像操作系统上正常运行。
为了解决上述问题,本发明提供一种定制镜像中软件包依赖的解决系统。图2示出了根据本发明一个实施例的定制镜像中软件包依赖的解决系统100的示意图。如图2所示,定制镜像中软件包依赖的解决系统100包括计算设备200、第一存储装置110和第二存储装置120,计算设备200分别与第一存储装置110、第二存储装置120通信连接,例如通过有线或无线的方式网络连接。
第一存储装置110存储有定制镜像的原始操作系统上已安装的所有软件包的数据,任一已安装软件包的数据包括:已安装软件包名称、已安装软件包版本号和依赖软件包信息。依赖软件包信息包括:依赖软件包名称、依赖软件包版本号、依赖软件包版本号类型、备选依赖(即备选依赖软件包)版本号、备选依赖名称以及备选依赖本版号类型。值得注意的是,在以下描述中,将依赖软件包简称为依赖。
其中,版本号类型表示对该依赖的版本要求,包括NA、>=、=、=<等,NA表示对依赖的版本无要求,>=表示依赖的版本号为当前及以上版本,=表示依赖的版本号为当前版本,=<表示依赖的版本号为当前版本及以下版本。例如,版本号为1.0,版本号类型为>=,表示需要依赖的版本号为1.0及以上的版本,版本号类型为<=,表示需要依赖的版本号为1.0及以下的版本,版本号类型为=,表示需要依赖的版本号为1.0的版本。备选依赖,表示可替代依赖的依赖,每一依赖可以有一个或多个备选依赖,也可以没有备选依赖。如果原始操作系统中没有安装目标软件包的任一依赖,但是安装了该依赖的任意一个备选依赖,也认为依赖已满足,即认为原始操作系统中已安装了目标软件包的该依赖。根据各已安装软件包的依赖软件包信息即可确定各已安装软件包的所有依赖。第一存储装置的部分内容如表1所示:
表1
由表1的第一行数据可以看出,已安装软件包zlib1g-dev的版本号为1:1.2.12.2-1+dde,包括两个依赖,分别为zlib1g、libc6-dev。依赖zlib1g的版本号为1:1.2.12.2-1+dde、无备选依赖,版本号类型为=,即依赖zlib1g的版本号等于1:1.2.12.2-1+dde。依赖libc6-dev的版本号为空、备选依赖为libc-dev,版本号类型为NA,即对依赖libc6-dev的版本无要求,备选依赖libc-dev的本版号为空,版本号类型为NA,即对备选依赖libc-dev的版本无要求。表1中其他数据同样按照上述方式进行分析,此处不再详述。
第二存储装置120存储有在定制镜像过程中已下载依赖的数据,任一已下载依赖的数据包括:已下载依赖名称、已下载依赖版本号、已下载依赖版本号类型、第二预定文件的路径(已下载依赖的第二预定文件的存储路径)。其中,第二预定文件中包括已下载依赖的所有依赖的名称、版本号、版本号类型以及备选依赖的名称、版本号和版本号类型,即,通过第二预定文件即可确定当前依赖的所有子依赖,以及各子依赖的备选依赖。例如,第二预定文件可以为软件包的control文件。第二存储装置120的部分内容如表2所示:
表2
由表2的第一行数据可以看出,已下载依赖libdrm-radeon1的版本号为2.4.39,版本号类型为>=,即已下载依赖libdrm-radeon1的版本号等于2.4.39及以上版本。已下载依赖libdrm-radeon1的第二预定文件的路径为/var/cache/apt/libdrm-radeon1_2.4.3_amd64.deb,通过访问路径/var/cache/apt/libdrm-radeon1_2.4.3_amd64.deb,即可从第二预定文件中获取当前已下载依赖的所有子依赖数据,从而确定当前已下载依赖的所有子依赖。表2中其他数据同样按照上述方式进行分析,此处不再详述。
在一个实施方式中,第一存储装置110和第二存储装置120可以是数据库,进一步地,数据库可以是关系型数据库,例如MYSQL、SqlServer、ACCESS 等,第一存储装置110和第二存储装置120的数据库可以是驻留于计算设备200中的本地数据库,也可以作为分布式数据库例如Hbase 等设置于多个地理位置处;第一存储装置110和第二存储装置120也可以是缓存,例如redis缓存等,总之第一存储装置110和第二存储装置120分别用于存储定制镜像的原始操作系统上已安装的所有软件包的数据、在定制镜像过程中已下载软件包的数据。本发明对第一存储装置110和第二存储装置120的具体部署、配置情况不做限制。
在一个实施方式中,计算设备200可以实现为服务器,例如应用服务器、Web服务器等;也可以实现为桌面电脑、笔记本电脑、处理器芯片、平板电脑等,但不限于此。计算设备200可以与第一存储装置110和第二存储装置120连接,将定制镜像的原始操作系统上已安装的所有软件包的数据存储至第一存储装置110,并从中读取已安装的所有软件包的数据,也会将已下载软件包的数据存储至第二存储装置120,并从中读取已下载软件包的数据。
例如,计算设备200可以直接读取第一存储装置110、第二存储装置120中的数据,并向第一存储装置110、第二存储装置120中写入数据(在第一存储装置110和第二存储装置120为计算设备200的本地数据库时),也可以通过有线或无线的方式接入互联网,并通过数据接口来读取第一存储装置110、第二存储装置120中的数据,并向第一存储装置110、第二存储装置120中写入数据。
本发明的一种定制镜像中软件包依赖的解决方法可以在计算设备200中执行。图3示出了根据本发明一个实施例的计算设备200的结构图。如图3所示,在基本配置202中,计算设备200典型地包括系统存储器206和一个或者多个处理器204。存储器总线208可以用于在处理器204和系统存储器206之间的通信。
取决于期望的配置,处理器204可以是任何类型的处理,包括但不限于:微处理器(µP)、微控制器(µC)、数字信息处理器(DSP)或者它们的任何组合。处理器204可以包括诸如一级高速缓存210和二级高速缓存212之类的一个或者多个级别的高速缓存、处理器核心214和寄存器216。示例的处理器核心214可以包括运算逻辑单元(ALU)、浮点数单元(FPU)、数字信号处理核心(DSP核心)或者它们的任何组合。示例的存储器控制器218可以与处理器204一起使用,或者在一些实现中,存储器控制器218可以是处理器204的一个内部部分。
取决于期望的配置,系统存储器206可以是任意类型的存储器,包括但不限于:易失性存储器(诸如RAM)、非易失性存储器(诸如ROM、闪存等)或者它们的任何组合。系统存储器206可以包括操作系统220、一个或者多个应用222以及程序数据224。在一些实施方式中,应用222可以布置为在操作系统上利用程序数据224进行操作。程序数据224包括指令,在根据本发明的计算设备200中,程序数据224包含用于执行数据存储方法300的指令。
计算设备200还包括储存设备232,储存设备232包括可移除储存器236和不可移除储存器238,可移除储存器236和不可移除储存器238均与储存接口总线234连接。本发明中,程序执行过程中发生的各事件的相关数据和指示各事件发生的时间信息,可存储于储存设备232中,操作系统220适于管理储存设备232。其中,储存设备232可为磁盘。
计算设备200还可以包括有助于从各种接口设备(例如,输出设备242、外设接口244和通信设备246)到基本配置202经由总线/接口控制器230的通信的接口总线240。示例的输出设备242包括图像处理单元248和音频处理单元250。它们可以被配置为有助于经由一个或者多个A/V端口252与诸如显示器或者扬声器之类的各种外部设备进行通信。示例外设接口244可以包括串行接口控制器254和并行接口控制器256,它们可以被配置为有助于经由一个或者多个I/O端口258和诸如输入设备(例如,键盘、鼠标、笔、语音输入设备、触摸输入设备)或者其他外设(例如打印机、扫描仪等)之类的外部设备进行通信。示例的通信设备246可以包括网络控制器260,其可以被布置为便于经由一个或者多个通信端口264与一个或者多个其他计算设备262通过网络通信链路的通信。
网络通信链路可以是通信介质的一个示例。通信介质通常可以体现为在诸如载波或者其他传输机制之类的调制数据信号中的计算机可读指令、数据结构、程序模块,并且可以包括任何信息递送介质。“调制数据信号”可以这样的信号,它的数据集中的一个或者多个或者它的改变可以在信号中编码信息的方式进行。作为非限制性的示例,通信介质可以包括诸如有线网络或者专线网络之类的有线介质,以及诸如声音、射频(RF)、微波、红外(IR)或者其它无线介质在内的各种无线介质。这里使用的术语计算机可读介质可以包括存储介质和通信介质二者。
计算设备200可以实现为服务器,例如文件服务器、数据库服务器、应用程序服务器和WEB服务器等,也可以实现为小尺寸便携(或者移动)电子设备的一部分,这些电子设备可以是诸如蜂窝电话、个人数字助理(PDA)、个人媒体播放器设备、无线网络浏览设备、个人头戴设备、应用专用设备、或者可以包括上面任何功能的混合设备。计算设备200还可以实现为包括桌面计算机和笔记本计算机配置的个人计算机。在一些实施例中,计算设备200被配置为执行根据本发明的一种定制镜像中软件包依赖的解决方法300。
图4示出了根据本发明一个实施例的定制镜像中软件包依赖的解决方法300的流程图。方法300适于在计算设备200(如上所述的计算设备)中执行,定制镜像中软件包依赖的解决方法300包括步骤S301至步骤S310。在步骤S301中,将原始操作系统中已安装的所有软件包的数据存储至第一存储装置中,任一已安装软件包的数据如上所述,此处不再赘述。
在一个实施方式中,步骤S301具体包括:首先,获取原始操作系统的第一预定文件,第一预定文件中存储原始操作系统中已安装的所有软件包的数据,例如,第一预定文件可以为/var/lib/dpkg/status文件。接着,从第一预定文件中读取原始操作系统上已安装的所有软件包的数据,并将已读取的所有软件包的数据存储至第一存储装置110。第一存储装置110存储的部分数据如表1所示,此处不再赘述。
接着在步骤S302中,确定目标软件包的所有依赖,目标软件包为定制镜像过程中的任一预装软件包。具体地,从目标软件包的第二预定文件中提取所有依赖的名称、版本号、版本号类型以及各依赖的备选依赖的名称、版本号和版本号类型,从而确定目标软件包的所有依赖以及各依赖的备选依赖(此处确定的目标软件包的所有依赖以及各依赖的备选依赖可以理解为目标软件包的直接依赖)。
在定制镜像的过程中,执行步骤S303,遍历任一依赖,在一个实施方式中,通过深度优先算法遍历任一依赖以及依赖的备选依赖,通过深度优先算法进行遍历的方法为已有技术,在本发明的保护范围之内,此处不进行论述。
继续执行步骤S304,从第一存储装置中查找当前遍历依赖的数据,并判断是否从第一存储装置110中查找到当前遍历的依赖的数据。在一个实施方式中,步骤S304包括:从第一存储装置110中查找当前遍历的依赖的数据,或者从第一存储装置110中查找当前遍历依赖的备选依赖的数据,只要从第一存储装置110中查找到当前遍历依赖的数据或者当前遍历依赖的备选依赖的数据,即可判定从第一存储装置110中查找到当前遍历依赖的数据,若从第一存储装置110中没有查找到当前遍历依赖的数据和备选依赖的数据,即可判定没有从第一存储装置110中查找到当前遍历依赖的数据。
若从第一存储装置110中查找到当前遍历依赖的数据,执行步骤S305,从第一存储装置中获取当前遍历依赖的数据,具体地,从第一存储装置110中获取当前遍历依赖的依赖信息,包括一个或多个字段,每一字段包括依赖的名称、版本号、版本号类型、与依赖对应的备选依赖的名称、版本号和版本号类型。若没有从第一存储装置110中查找到当前遍历依赖的数据,执行步骤S306,判断第二存储装置中是否存储有当前遍历依赖的数据。
若第二存储装置中存储有当前遍历依赖的数据,为了避免重复下载,执行步骤S307,从第二存储装置中获取当前遍历依赖的数据,具体地,从第二存储装置中获取当前遍历依赖的第二预定文件的路径。若第二存储装置中没有存储当前遍历依赖的数据,执行步骤S308,下载当前遍历的依赖。
接着在步骤S309中,将已下载依赖的数据存储至第二存储装置。在定制镜像过程中,任一已下载依赖的数据如上所述,第二存储装置120存储的部分数据如表2所示,此处均不再赘述。接着在步骤S310中,通过已获取依赖的数据、或者已下载依赖的数据确定当前遍历依赖的所有子依赖以及各子依赖的备选依赖。
在一个实施方式中,若从第一存储装置110中获取当前遍历依赖的依赖软件包信息,那么通过依赖软件包信息,确定当前遍历的依赖软件包的所有子依赖以及各子依赖的备选依赖。若从第二存储装置120中获取当前遍历依赖的第二预定文件的路径,那么通过第二预定文件的路径访问第二预定文件,从而确定当前遍历依赖的所有子依赖以及各子依赖的备选依赖。若下载当前遍历的依赖,那么通过已下载依赖的第二预定文件的路径访问第二预定文件,从而确定当前遍历依赖的所有子依赖以及各子依赖的备选依赖。
需要说明的是,本发明的实现过程中,目标软件包和其依赖对应的树形结构是动态生成的,在下载或者获取到目标软件包的任一直接依赖后,才可确定当前直接依赖的子依赖,并继续执行步骤S303至步骤 S311,以遍历当前直接依赖的任一子依赖,并从第一存储装置110获取子依赖,或者下载子依赖,直至当前直接依赖的所有子依赖不再包括依赖时,当前直接依赖的树形结构分支遍历完成。继续执行步骤S303至步骤 S311,以遍历目标软件包的任一其他直接依赖的树形结构分支,依此类推,遍历完成树形结构的所有依赖。
以图1示出的树形结构为例(图1未示出各依赖的备选依赖),对遍历依赖的过程进行详细说明(此过程中不包括备选依赖)。由图1可知,目标软件包为A,目标软件包A的直接依赖包括B1、B2、B3,而依赖B1又依赖于软件包C1、C2、C3。那么,本方案中,首先遍历依赖B1,执行步骤S303至步骤 S311,从而确定依赖B1又依赖于软件包C1、C2、C3。之后,针对依赖C1执行步骤S303至步骤 S311,若依赖C1不存在依赖,那么针对依赖C2执行步骤S303至步骤S311,若依赖C2不存在依赖,那么针对依赖C3继续执行步骤S303至步骤 S311,若依赖C3不存在依赖,此时针对依赖B2执行步骤S303至步骤 S311,依此类推,直至遍历完成目标软件包的任一依赖。以下为本发明的关键性代码示例:
/*
解析软件包的控制信息,提取包名、版本号和所有的依赖信息,软件包控制信息示例:
*/
Package: zssh
Status: install ok installed
Priority: optional
Section: net
Installed-Size: 63
Maintainer: Debian Deepin Packaging Team <pkg-deepin-devel@lists.alioth.debian.org>
Architecture: amd64
Version: 1.5c.debian.1-7
Depends: lrzsz, openssh-client | telnet | telnet-ssl, libc6 (>=2.27), libreadline7 (>= 6.0)
Description: interactive file transfers over ssh
zssh (Zmodem SSH) is a program for interactively transferring filesto a
remote machine while using the secure shell (ssh). It is intended to
be a convenient alternative to scp, allowing to transfer fileswithout
having to open another session and re-authenticate oneself .
Files are transferred through the zmodem protocol, using the rz andsz
commands.
Homepage: http://zssh.sourceforge.net/
/*控制信息中信息较多,这里只关注Package、Version、Depends三行数据,这三行分别表示软件包的包名、版本号、依赖信息。*/
PackageInfo PackageInfo::parseControlData(const QString &controlData)
{
// 以换行符作为分隔符,将整段控制数据的每一行提出来放到链表中,便于后续遍历处理
auto tmpLines = controlData.split('\n', QString::SplitBehavior::SkipEmptyParts);
adjustControlData(tmpLines); // 将以空格开头的数据与上一行合并成一行,将Description行及下面那些以空格开头的行合成一行
PackageInfo packageInfo;
for (auto &line : tmpLines) {
QString tmpValue;
if (getSectionValue(line, "Package", tmpValue)) { // 找到以Package开始的一行,提取后面的信息作为包名
packageInfo.m_packageName = tmpValue;
if (packageInfo.m_packageName.isEmpty()) // 如果提取的包名为空,说明本段控制数据存在异常,直接结束分析
return packageInfo;
} else if (getSectionValue(line, "Version", tmpValue)) { //找到以Version开始的一行,提取后面的信息作为版本号
packageInfo.m_version = PackageInfo::Version(tmpValue);
} else if (getDepend(line, packageInfo.m_depends)) { // 提取依赖信息
}
}
return packageInfo;
}
/*
从控制提取所有依赖信息
依赖信息示例:dictionaries-common (>= 0.20), debconf (>= 0.5) |debconf-2.0
','是多条依赖信息的分隔符,'|'是备选依赖的分割符,'()'中的是版本号
*/
bool PackageInfo::getDepend(const QString &controlLineData, QList<PackageInfo::Depend> &value)
{
if (!controlLineData.startsWith("Depends")) // 如果这一行数据不是Depends开头,说明不是依赖数据行
return false;
// 提取Depends:后面的数据
auto tmpList = controlLineData.split("Depends:", QString::SkipEmptyParts);
if (tmpList.size() != 1)
return true; // 如果Depends:后面的数据为空,说明此软件包没有依赖,结束分析
// 这是分析单个依赖的局部函数
// 其中,:amd64表示仅在amd64架构才需要该依赖,()中的是版本号,|后面的是备选依赖
auto getSingleDepend = [](const QString &dependInfo) ->PackageInfo::Depend {
// 用左括号将一条依赖信息分割成两部分,用于提取依赖包名
auto tmpDepend = dependInfo.split('(', QString::SkipEmptyParts);
PackageInfo::Depend depend;
if (tmpDepend.isEmpty())
return depend;
auto tmpStr = tmpDepend.first().trimmed();
if (tmpStr.contains(':')) { // 如果用'('分割后的第一部分包含':',说明依赖有架构要求
auto tmpPackageName = tmpStr.split(':', QString::SkipEmptyParts);
if (!tmpPackageName.isEmpty())
depend.m_packageName = tmpPackageName.first().trimmed(); // 提取':'前面的部分作为包名
} else {
depend.m_packageName = tmpStr; // 如果用'('分割后的第一部分部不包含':',第一部分整个作为包名
}
if (tmpDepend.size() != 2) { // 如果用'('分割的结果只有1份,说明不存在'(',说明没有版本信息
depend.m_versionRequireType = PackageInfo::Depend::None;// 版本号需求类型为NA
} else {
// 处理版本信息,示例:(>= 0.20),空格作为版本号需求类型与具体版本号的分隔符
// 用空格分割,取第一段做为版本号
depend.m_version = PackageInfo::Version(tmpDepend.last().split(" ").last().chopped(1));
// 第二段作为版本号需求类型
if (tmpDepend.last().contains(">="))
depend.m_versionRequireType = PackageInfo::Depend::BiggerAndEqual;
...
else
depend.m_versionRequireType = PackageInfo::Depend::Equal;
}
return depend;
};
// 用','将每一条依赖信息分割开,遍历处理分割出的每一条依赖
for (auto &dependInfo : tmpList.first().trimmed().split(',',QString::SkipEmptyParts)) {
// 尝试用'|'分割依赖与备选依赖
auto splitResult = dependInfo.split('|', QString::SkipEmptyParts);
if (splitResult.size() > 1) { // 如果分割结果大于1,说明有备选依赖
// 第1条分割结果表示依赖
auto depend = getSingleDepend(splitResult.first().trimmed());
// 后面的是备选依赖
for (int i = 1; i < splitResult.size(); i++)
depend.m_alternativePackages.append(getSingleDepend(splitResult.value(i).trimmed()));
value.append(depend);
} else { // 没有备选依赖
value.append(getSingleDepend(dependInfo));
}
}
return true;
}
/*
从第一存储装置中检查指定软件包的所有依赖是否已满足
m_db表示第一存储装置
*/
bool PackageInfoDB::isDependSatisfied(const PackageInfo &package)
{
auto depends = package.m_depends;
for (auto &depend : package.m_depends) { // 遍历分析该软件包的每一个依赖
if (isDependSatisfied(depend)) { // 如果该依赖已满足,则继续分析下一个
depends.removeOne(depend);
continue;
}
// 如果该依赖不满足,则遍历该依赖的备选依赖,看是否可以满足
for (auto &alternativePackage : depend.m_alternativePackages){
if (isDependSatisfied(alternativePackage)) { // 只要有一个备选依赖满足,则认为依赖满足
depends.removeOne(depend);
break;
}
}
}
// 如果剩余未满足的依赖为空,说明所有的依赖已满足,否则说明依赖不满足
return depends.isEmpty();
}
/*
从第一存储装置中检查指定依赖是否已满足
m_db表示第一存储装置
*/
bool PackageInfoDB::isDependSatisfied(const PackageInfo::Depend &depend)
{
// 如果第一存储装置包含不存在指定的依赖包名,依赖不满足
if (!m_db.contains(depend.m_packageName)) {
return false;
}
// 如果第一存储装置存在指定的依赖包名,而且指定的依赖对版本号没有要求,那么依赖满足
if (depend.m_versionRequireType == PackageInfo::Depend::None)
return true;
// 如果对版本号有要求,则依次检查第一存储装置中该依赖包的各个版本,看是否有满足的依赖包
for (auto &tmpPackage : m_db.values(depend.m_packageName)) {
if (isVersionMatchEx(depend, tmpPackage)) // 只要有一个符合要求,则说明依赖已满足
return true;
}
// 遍历完第一存储装置该依赖包名对应的各版本依赖包,都没有找到满足版本要求的包,则依赖不满足
return false;
}
/*
每下载一个依赖包,就在第二存储装置中插入一条数据
m_downloadedDepends表示第二存储装置
*/
void PackageInfoDB::addNewDependFile(const PackageInfo::Depend &depend, const QString &packageFile)
{
DownloadedDepend downloadedDepend;
downloadedDepend.depend = depend; // 依赖信息
downloadedDepend.packageFile = packageFile; // 下载的依赖包文件路径
m_downloadedDepends.insertMulti(depend.m_packageName,downloadedDepend);
}
/*
处理指定软件包的依赖信息,如果依赖不满足,自动下载依赖
*/
QList<PackageInfo::Depend> PackageDependHandler::handlePackageDepend(const QString &packageFile)
{
QList<PackageInfo::Depend> failedDepends;
// 从第一存储装置中获取所有未满足的依赖
auto unsatisfiedDepends = d->packageInfoDB.getUnsatisfiedDepends(PackageInfo::fromPackageFile(packageFile));
// 遍历处理所有未满足的依赖
for (auto &depend : unsatisfiedDepends) {
// 下载该依赖对应的依赖包文件
auto downloadDependFiles = downloadDepend(depend);
...
// 下载仅会下载指定的依赖包,不会下载该依赖包的依赖,因此需要递归分析每个下载的依赖包
for (auto &dependFile : downloadDependFiles)
failedDepends += handlePackageDepend(dependFile, depth);
}
return failedDepends;
}
/*
下载指定的依赖包
*/
QStringList PackageDependHandler::downloadDepend(const PackageInfo::Depend &dependInfo)
{
// 如果该依赖在第二存储装置中则不用下载,直接返回
auto packageFile = d->packageInfoDB.getExistsDepend(dependInfo);
if (!packageFile.isEmpty())
return {packageFile};
// 如果该依赖的任一备选依赖在第二存储装置中则也不用下载,直接返回
for (auto &alternativePackage : dependInfo.m_alternativePackages){
packageFile = d->packageInfoDB.getExistsDepend(alternativePackage);
if (!packageFile.isEmpty())
return {packageFile};
}
// 使用apt下载依赖包文件
bool result = DownloadDebDepends(dependInfo.m_packageName);
if (result) {
// 从下载路径中获取新下载的依赖包文件
auto dependsFiles = findPackgeDependsFiles(dependInfo.m_packageName);
for (auto dependsFile : dependsFiles)
// 将新下载的依赖包信息及对应文件插入到第二存储装置中
d->packageInfoDB.addNewDependFile(dependInfo,dependsFile);
return dependsFiles;
}
return {};
}
基于上述内容可知,本发明提供的定制镜像中软件包依赖的解决方法,实现了在定制镜像过程中依赖原始操作系统已安装的软件包,遍历目标预装软件包所缺失的依赖,由于基于原始操作系统中已安装的软件包确定缺失依赖,从而能够在定制镜像过程中准确识别目标预装软件包所缺失的依赖。另外,本发明中还会存储已下载的依赖,只有未存储时才会下载缺失依赖,从而避免重复下载,提高软件包依赖的解决速度,也可避免资源浪费,提高资源利用率。
这里描述的各种技术可结合硬件或软件,或者它们的组合一起实现。从而,本发明的方法和设备,或者本发明的方法和设备的某些方面或部分可采取嵌入有形媒介,例如可移动硬盘、U盘、软盘、CD-ROM或者其它任意机器可读的存储介质中的程序代码(即指令)的形式,其中当程序被载入诸如计算机之类的机器,并被所述机器执行时,所述机器变成实践本发明的设备。
在程序代码在可编程计算机上执行的情况下,计算设备一般包括处理器、处理器可读的存储介质(包括易失性和非易失性存储器和/或存储元件),至少一个输入装置,和至少一个输出装置。其中,存储器被配置用于存储程序代码;处理器被配置用于根据该存储器中存储的所述程序代码中的指令,执行本发明的定制镜像中软件包依赖的解决方法。
以示例而非限制的方式,可读介质包括可读存储介质和通信介质。可读存储介质存储诸如计算机可读指令、数据结构、程序模块或其它数据等信息。通信介质一般以诸如载波或其它传输机制等已调制数据信号来体现计算机可读指令、数据结构、程序模块或其它数据,并且包括任何信息传递介质。以上的任一种的组合也包括在可读介质的范围之内。
在此处所提供的说明书中,算法和显示不与任何特定计算机、虚拟系统或者其它设备固有相关。各种通用系统也可以与本发明的示例一起使用。根据上面的描述,构造这类系统所要求的结构是显而易见的。此外,本发明也不针对任何特定编程语言。应当明白,可以利用各种编程语言实现在此描述的本发明的内容,并且上面对特定语言所做的描述是为了披露本发明的最佳实施方式。
在此处所提供的说明书中,说明了大量具体细节。然而,能够理解,本发明的实施例可以在没有这些具体细节的情况下被实践。在一些实例中,并未详细示出公知的方法、结构和技术,以便不模糊对本说明书的理解。
类似地,应当理解,为了精简本公开并帮助理解各个发明方面中的一个或多个,在上面对本发明的示例性实施例的描述中,本发明的各个特征有时被一起分组到单个实施例、图、或者对其的描述中。然而,并不应将该公开的方法解释成反映如下意图:即所要求保护的本发明要求比在每个权利要求中所明确记载的特征更多特征。更确切地说,如权利要求书所反映的那样,发明方面在于少于前面公开的单个实施例的所有特征。因此,遵循具体实施方式的权利要求书由此明确地并入该具体实施方式,其中每个权利要求本身都作为本发明的单独实施例。
本领域那些技术人员应当理解在本文所公开的示例中的设备的模块或单元或组件可以布置在如该实施例中所描述的设备中,或者可替换地可以定位在与该示例中的设备不同的一个或多个设备中。前述示例中的模块可以组合为一个模块或者此外可以分成多个子模块。
本领域那些技术人员可以理解,可以对实施例中的设备中的模块进行自适应性地改变并且把它们设置在与该实施例不同的一个或多个设备中。可以把实施例中的模块或单元或组件组合成一个模块或单元或组件,以及此外可以把它们分成多个子模块或子单元或子组件。除了这样的特征和/或过程或者单元中的至少一些是相互排斥之外,可以采用任何组合对本说明书(包括伴随的权利要求、摘要和附图)中公开的所有特征以及如此公开的任何方法或者设备的所有过程或单元进行组合。除非另外明确陈述,本说明书(包括伴随的权利要求、摘要和附图)中公开的每个特征可以由提供相同、等同或相似目的的替代特征来代替。
此外,本领域的技术人员能够理解,尽管在此所述的一些实施例包括其它实施例中所包括的某些特征而不是其它特征,但是不同实施例的特征的组合意味着处于本发明的范围之内并且形成不同的实施例。例如,在权利要求书中,所要求保护的实施例的任意之一都可以以任意的组合方式来使用。
此外,所述实施例中的一些在此被描述成可以由计算机系统的处理器或者由执行所述功能的其它装置实施的方法或方法元素的组合。因此,具有用于实施所述方法或方法元素的必要指令的处理器形成用于实施该方法或方法元素的装置。此外,装置实施例的在此所述的元素是如下装置的例子:该装置用于实施由为了实施该发明的目的的元素所执行的功能。
如在此所使用的那样,除非另行规定,使用序数词“第一”、“第二”、“第三”等等来描述普通对象仅仅表示涉及类似对象的不同实例,并且并不意图暗示这样被描述的对象必须具有时间上、空间上、排序方面或者以任意其它方式的给定顺序。
尽管根据有限数量的实施例描述了本发明,但是受益于上面的描述,本技术领域内的技术人员明白,在由此描述的本发明的范围内,可以设想其它实施例。此外,应当注意,本说明书中使用的语言主要是为了可读性和教导的目的而选择的,而不是为了解释或者限定本发明的主题而选择的。因此,在不偏离所附权利要求书的范围和精神的情况下,对于本技术领域的普通技术人员来说许多修改和变更都是显而易见的。对于本发明的范围,对本发明所做的公开是说明性的,而非限制性的,本发明的范围由所附权利要求书限定。
Claims (8)
1.一种定制镜像中软件包依赖的解决方法,在计算设备中执行,所述计算设备分别与第一存储装置和第二存储装置通信连接,其中,所述第一存储装置存储有定制镜像的原始操作系统上已安装的所有软件包的数据,所述方法包括:
确定目标软件包的所有依赖软件包,作为第一软件包,其中,所述目标软件包为任一预装软件包;
在定制镜像过程中,遍历任一所述第一软件包;
若从所述第一存储装置中查找到当前遍历的所述第一软件包的数据,则从所述第一存储装置中获取当前遍历的所述第一软件包的数据;
若未从所述第一存储装置中查找到当前遍历的所述第一软件包的数据, 判断所述第二存储装置中是否存储有当前遍历的所述第一软件包的数据,若是,从所述第二存储装置中获取当前遍历的所述第一软件包的数据,若否,下载当前遍历的所述第一软件包;
将已下载的所述第一软件包的数据存储至所述第二存储装置。
2.如权利要求1所述的方法,还包括步骤:
通过已获取的所述第一软件包的数据、或者已下载的所述第一软件包的数据确定当前遍历的所述第一软件包的所有依赖软件包;
遍历所述第一软件包的任一依赖软件包。
3.如权利要求1或2所述的方法,还包括步骤:
获取原始操作系统的第一预定文件;
从所述第一预定文件中读取原始操作系统上已安装的所有软件包的数据;
将已读取的所有软件包的数据存储至所述第一存储装置。
4.如权利要求3所述的方法,其中,通过深度优先算法遍历任一所述第一软件包。
5.如权利要求1所述的方法,其中,所述第一存储装置存储的任一已安装软件包的数据包括:已安装软件包名称、已安装软件包版本号和依赖软件包信息,所述依赖软件包信息包括:依赖软件包的名称、版本号和版本号类型,以及备选依赖软件包的版本号、名称以及本版号类型。
6.如权利要求1所述的方法,其中,所述第二存储装置存储的任一已下载软件包的数据包括:已下载软件包的名称、版本号、版本号类型和第二预定文件的路径,所述第二预定文件中包括已下载软件包的所有依赖的名称、版本号、版本号类型以及备选依赖软件包的名称、版本号和版本号类型,任一所述第一软件包包括目标软件包的任一依赖软件包和任一依赖软件包的备选依赖软件包。
7.一种计算设备,包括:
至少一个处理器;以及
存储器,存储有程序指令,其中,所述程序指令被配置为适于由所述至少一个处理器执行,所述程序指令包括用于执行如权利要求1-6中任一项所述的方法的指令。
8.一种存储有程序指令的可读存储介质,当所述程序指令被计算设备读取并执行时,使得所述计算设备执行如权利要求1-6中任一项所述的方法。
Priority Applications (2)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202110934204.2A CN113391826B (zh) | 2021-08-16 | 2021-08-16 | 一种定制镜像中软件包依赖的解决方法 |
CN202111215741.8A CN113885936A (zh) | 2021-08-16 | 2021-08-16 | 一种定制镜像中软件包依赖的解决方法 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202110934204.2A CN113391826B (zh) | 2021-08-16 | 2021-08-16 | 一种定制镜像中软件包依赖的解决方法 |
Related Child Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN202111215741.8A Division CN113885936A (zh) | 2021-08-16 | 2021-08-16 | 一种定制镜像中软件包依赖的解决方法 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN113391826A CN113391826A (zh) | 2021-09-14 |
CN113391826B true CN113391826B (zh) | 2021-11-09 |
Family
ID=77622562
Family Applications (2)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN202110934204.2A Active CN113391826B (zh) | 2021-08-16 | 2021-08-16 | 一种定制镜像中软件包依赖的解决方法 |
CN202111215741.8A Pending CN113885936A (zh) | 2021-08-16 | 2021-08-16 | 一种定制镜像中软件包依赖的解决方法 |
Family Applications After (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN202111215741.8A Pending CN113885936A (zh) | 2021-08-16 | 2021-08-16 | 一种定制镜像中软件包依赖的解决方法 |
Country Status (1)
Country | Link |
---|---|
CN (2) | CN113391826B (zh) |
Families Citing this family (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN114706628B (zh) * | 2022-04-02 | 2023-02-17 | 北京星辰天合科技股份有限公司 | 基于一池多芯的分布式存储系统的数据处理方法和装置 |
CN114706564B (zh) * | 2022-05-16 | 2022-08-30 | 龙芯中科技术股份有限公司 | 软件包制作方法、装置、电子设备及存储介质 |
CN114756255B (zh) * | 2022-06-14 | 2022-09-27 | 统信软件技术有限公司 | 一种离线包生成方法、一种软件包安装方法 |
CN114860273B (zh) * | 2022-07-04 | 2022-12-20 | 广东睿江云计算股份有限公司 | 自适应软件包管理方法及管理系统 |
Family Cites Families (7)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US9690562B2 (en) * | 2010-02-26 | 2017-06-27 | Red Hat, Inc. | Detecting computing processes requiring reinitialization after a software package update |
CN102118500B (zh) * | 2010-12-27 | 2013-08-21 | 清华大学 | 移动终端开源操作系统基于软件包的在线自动更新方法 |
CN102945155B (zh) * | 2012-10-22 | 2016-08-03 | 中标软件有限公司 | 一种用于检测Linux操作系统软件包及其依赖关系缺失的方法 |
CN109634617A (zh) * | 2018-10-25 | 2019-04-16 | 深圳壹账通智能科技有限公司 | 软件安装方法、用户设备、存储介质及装置 |
CN109933342B (zh) * | 2019-03-18 | 2020-10-16 | 北京升鑫网络科技有限公司 | 一种从本地docker镜像中提取文件内容的方法及装置 |
CN110990020A (zh) * | 2019-11-24 | 2020-04-10 | 苏州浪潮智能科技有限公司 | 一种软件编译方法、装置及电子设备和存储介质 |
CN111198709A (zh) * | 2019-12-29 | 2020-05-26 | 浪潮电子信息产业股份有限公司 | 一种rpm软件包管理方法、系统、装置及可读存储介质 |
-
2021
- 2021-08-16 CN CN202110934204.2A patent/CN113391826B/zh active Active
- 2021-08-16 CN CN202111215741.8A patent/CN113885936A/zh active Pending
Also Published As
Publication number | Publication date |
---|---|
CN113391826A (zh) | 2021-09-14 |
CN113885936A (zh) | 2022-01-04 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN113391826B (zh) | 一种定制镜像中软件包依赖的解决方法 | |
CA3198981A1 (en) | Constructing executable program code based on sequence codes | |
CN110187880B (zh) | 一种同类元素识别方法、装置和计算设备 | |
US20220292082A1 (en) | Method, apparatus and device for parallel execution of smart contract, and medium | |
US20180159830A1 (en) | Obfuscating Source Code Sent, from a Server Computer, to a Browser on a Client Computer | |
CN110377563A (zh) | 文件处理方法和装置、以及电子设备和可读存储介质 | |
WO2017034953A1 (en) | System and method for object compression and state synchronization | |
CN109783346A (zh) | 基于关键字驱动的自动化测试方法、装置及终端设备 | |
CN110990001A (zh) | Ivr流程执行方法及装置 | |
US10387124B2 (en) | System and method for creating domain specific language | |
CN114924810A (zh) | 一种异构程序执行方法、装置、计算设备及可读存储介质 | |
WO2022068556A1 (zh) | 一种代码翻译方法、装置及设备 | |
CN111078228A (zh) | 网页到小程序的转换方法、装置、服务器及存储介质 | |
CN113204385A (zh) | 一种插件加载方法、装置、计算设备及可读存储介质 | |
CN111930392A (zh) | 一种应用服务部署方法、计算设备及可读存储介质 | |
CN109324838B (zh) | 单片机程序的执行方法、执行装置及终端 | |
CN111581098A (zh) | 接口数据转移存储的方法、装置、服务器及存储介质 | |
CN114879978A (zh) | 软件包依赖关系的处理方法、计算设备及可读存储介质 | |
CN114168937A (zh) | 一种资源访问方法、计算设备及可读存储介质 | |
CN110737431B (zh) | 软件开发方法、开发平台、终端设备及存储介质 | |
CN114186958A (zh) | 将列表数据导出为电子表格的方法、计算设备及存储介质 | |
CN111913814A (zh) | 对象拷贝方法及计算设备 | |
TWI740393B (zh) | 應用程式維護方法 | |
CN116578281B (zh) | 基于代码包的网页开发方法、系统、电子设备及存储介质 | |
CN117075912B (zh) | 用于程序语言转换的方法、编译方法及相关设备 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
PB01 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
GR01 | Patent grant | ||
GR01 | Patent grant |