Compare commits
10 Commits
46c6a66e44
...
4190a5c54a
| Author | SHA1 | Date | |
|---|---|---|---|
| 4190a5c54a | |||
| 58ce442993 | |||
| 3a482d539c | |||
| fd26924773 | |||
| ece47803c4 | |||
| 562c15f685 | |||
| 22510ca52c | |||
| f2caad8251 | |||
| 6275836e40 | |||
| f35ade11d6 |
@@ -7,8 +7,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
|||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||||
|
|
||||||
find_package(Bluelib COMPONENTS Core Object Io Term Cmd REQUIRED)
|
find_package(Bluelib COMPONENTS Core Object Io Term Cmd Compress REQUIRED)
|
||||||
find_package(ZSTD REQUIRED)
|
|
||||||
|
|
||||||
add_subdirectory(libropkg)
|
add_subdirectory(libropkg)
|
||||||
add_subdirectory(ropkg)
|
add_subdirectory(ropkg)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ if (Bluelib_STATIC)
|
|||||||
set(_lib_suffix "-s")
|
set(_lib_suffix "-s")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(supported_components Core Object Term Cmd Io Serial)
|
set(supported_components Core Object Term Cmd Io Serial Compress)
|
||||||
set(components ${Bluelib_FIND_COMPONENTS})
|
set(components ${Bluelib_FIND_COMPONENTS})
|
||||||
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
|
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
|
||||||
|
|
||||||
@@ -177,5 +177,13 @@ if (Bluelib_FOUND)
|
|||||||
|
|
||||||
target_link_libraries(Bluelib::Io INTERFACE Bluelib::Core Bluelib::Object)
|
target_link_libraries(Bluelib::Io INTERFACE Bluelib::Core Bluelib::Object)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if ("${component}" STREQUAL "Compress")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Compress' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Compress INTERFACE Bluelib::Core Bluelib::Object)
|
||||||
|
endif ()
|
||||||
endforeach (component)
|
endforeach (component)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
31
doc/package-manifest.json
Normal file
31
doc/package-manifest.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"Name": "sample-package",
|
||||||
|
"Architecture": "amd64",
|
||||||
|
"Version": "1.2.5-2",
|
||||||
|
"Priority": "optional",
|
||||||
|
"Category": "misc",
|
||||||
|
"Maintainer": "John Doe <john@sample.com>",
|
||||||
|
"Provides": [
|
||||||
|
{ "Name": "sample-api", "Version": "1.2.5" }
|
||||||
|
],
|
||||||
|
"Depends": [
|
||||||
|
{ "Name": "libc", "Version": "2.0", "Predicate": ">=" },
|
||||||
|
{ "Name": "libstdc++", "Version": "2.3", "Predicate": ">=" },
|
||||||
|
{ "Name": "libc", "Version": "2.0", "Predicate": ">=" },
|
||||||
|
{
|
||||||
|
"One-Of": [
|
||||||
|
{ "Name": "libs1", "Version": "1.0", "Predicate": ">=" },
|
||||||
|
{ "Name": "libs2", "Version": "1.2", "Predicate": ">=" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Recommends": [ "sample-cli" ],
|
||||||
|
"Suggests": [
|
||||||
|
{ "One-Of": [ "sample-gtk", "sample-qt" ] },
|
||||||
|
{ "Name": "libc", "Version": "2.0", "Predicate": ">=" }
|
||||||
|
],
|
||||||
|
"Conflicts": [ "example-package" ],
|
||||||
|
"Enhances": [ "basic-package" ],
|
||||||
|
"Description": "A sample package",
|
||||||
|
"Installed-Size": 3245
|
||||||
|
}
|
||||||
25
doc/package-readme.txt
Normal file
25
doc/package-readme.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
+------------------------------------------------------------------------------+
|
||||||
|
| A Sample Package |
|
||||||
|
+------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
This is a sample package to demonstrate the layout and features of a Rosetta
|
||||||
|
package.
|
||||||
|
|
||||||
|
|
||||||
|
1 Main Package Layout
|
||||||
|
=====================
|
||||||
|
|
||||||
|
|
||||||
|
2 The Payload Package
|
||||||
|
=====================
|
||||||
|
|
||||||
|
|
||||||
|
3 The Control Package
|
||||||
|
=====================
|
||||||
|
|
||||||
|
|
||||||
|
4 The Meta Package
|
||||||
|
==================
|
||||||
|
|
||||||
|
|
||||||
|
vim: shiftwidth=3 expandtab
|
||||||
124
doc/package-versions.txt
Normal file
124
doc/package-versions.txt
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
+------------------------------------------------------------------------------+
|
||||||
|
| Rosetta Package Manager Documentation |
|
||||||
|
| ..................................... |
|
||||||
|
| Package Version Format and Comparison |
|
||||||
|
+------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
This document describes the format of Rosetta package version indicators, and
|
||||||
|
the way in which they are compared.
|
||||||
|
|
||||||
|
|
||||||
|
1 Permitted Characters
|
||||||
|
======================
|
||||||
|
|
||||||
|
The following characters can be used in a package version identifier:
|
||||||
|
- lowercase letters [a-z]
|
||||||
|
- digits [0-9]
|
||||||
|
- the following punctuation: - . ~
|
||||||
|
|
||||||
|
|
||||||
|
2 Version String Format
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The package version identifier should have the following layout:
|
||||||
|
|
||||||
|
[release-phase]<upstream-version>[~version-version-phase[version-release-phase-revision]][-package-revision]
|
||||||
|
|
||||||
|
Components surrounded by [square brackets] is optional, while components
|
||||||
|
surrounded by <triangular brackets> are required. If a component name
|
||||||
|
is preceded by a punctuation mark, the value of that component in a package
|
||||||
|
version identifier must also be preceded by that punctuation mark.
|
||||||
|
|
||||||
|
The different version identifier components are defined as follows:
|
||||||
|
- release-phase (optional) indicates the release stage of the upstream
|
||||||
|
software. allowable values are: alpha, beta
|
||||||
|
|
||||||
|
- upstream-version (required) indicates the version number of the upstream
|
||||||
|
release. this is made up of one to five integers >= 0 separated by full
|
||||||
|
stops.
|
||||||
|
|
||||||
|
- version-release-phase (optional) indicates the release stage of this
|
||||||
|
particular version of the upstream software. allowable values are:
|
||||||
|
alpha, beta, rc.
|
||||||
|
|
||||||
|
- version-release-phase-revision (optional) indicates the revision of the
|
||||||
|
upstream package version within a given pre-release-version. must be
|
||||||
|
a positive non-zero integer.
|
||||||
|
|
||||||
|
- package-revision (optional) indicates different versions of a particular
|
||||||
|
package that contain the same version of the upstream software.
|
||||||
|
|
||||||
|
Some examples of package versions include:
|
||||||
|
- 1.0.0
|
||||||
|
First revision of package for upstream release 1.0.0
|
||||||
|
|
||||||
|
- beta1.7
|
||||||
|
First revision of package for upstream beta pre-release 1.7
|
||||||
|
|
||||||
|
- 0.6-2
|
||||||
|
Second revision of package for upstream release 0.6
|
||||||
|
|
||||||
|
- 1.2~beta2
|
||||||
|
First revision of package for the second beta pre-release of upstream
|
||||||
|
version 1.2
|
||||||
|
|
||||||
|
- 5.15~rc1-2
|
||||||
|
Second revision of package for the first release-candidate pre-release of
|
||||||
|
upstream version 5.15
|
||||||
|
|
||||||
|
|
||||||
|
3 Version Comparison
|
||||||
|
====================
|
||||||
|
|
||||||
|
There are a number of rules that govern how package version identifiers are
|
||||||
|
compared.
|
||||||
|
|
||||||
|
|
||||||
|
3.1 Comparison Procedure
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
When comparing two version numbers, the five components are compared left to
|
||||||
|
right using the following procedure:
|
||||||
|
1. release-phase is compared according to Release Phase Precedence. If the
|
||||||
|
two packages have different release-phase values, the one with higher
|
||||||
|
precedence is considered the newer package. If one package does not have
|
||||||
|
a release-phase, a release-phase of 'release' is assumed, which has the
|
||||||
|
highest precedence.
|
||||||
|
|
||||||
|
2. Each digit in upstream-version is compared left-to-right. If one package
|
||||||
|
version has fewer digits than the other, the missing digits are assumed to
|
||||||
|
be zero. If one package has a version digit greater than the other when
|
||||||
|
read left-to-right, it is considered the newer package.
|
||||||
|
|
||||||
|
3. version-release-phase is compared according to Release Phase Precedence.
|
||||||
|
If the two packages have different version-release-phase values, the
|
||||||
|
one with higher precedence is considered the newer package. If a package
|
||||||
|
does not have a version-release-phase, a value of 'release' (with the
|
||||||
|
highest precedence) is assumed, and step 4 is skipped.
|
||||||
|
|
||||||
|
4. The package with the greater version-release-phase-revision is considered
|
||||||
|
the newer package. If a package does not have a
|
||||||
|
version-release-phase-revision, a value of one is assumed.
|
||||||
|
|
||||||
|
5. The package with the greater package-revision is considered the newer
|
||||||
|
package. If a package does not have a package-revision, a value of one is
|
||||||
|
assumed.
|
||||||
|
|
||||||
|
If each of the five components of two package versions is determined to be
|
||||||
|
equal according to the above procedure, the two packages are considered to
|
||||||
|
be equal in version.
|
||||||
|
|
||||||
|
|
||||||
|
3.2 Release Phase Precedence
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Release phases have a defined order of precedence which is used during
|
||||||
|
comparisons. This order, in decending level of precedence, is:
|
||||||
|
1. release (cannot be specified directly, but is used implicitly if no
|
||||||
|
release phase is specified).
|
||||||
|
2. rc
|
||||||
|
3. beta
|
||||||
|
4. alpha
|
||||||
|
|
||||||
|
|
||||||
|
vim: shiftwidth=3 expandtab
|
||||||
9
doc/release.json
Normal file
9
doc/release.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"mango-kernel": {
|
||||||
|
"0.1": {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rosetta-system": {
|
||||||
|
"0.1": {
|
||||||
|
}
|
||||||
|
}
|
||||||
3
doc/sample-package/control/post-install.sh
Executable file
3
doc/sample-package/control/post-install.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Hello, world!"
|
||||||
3
doc/sample-package/control/post-uninstall.sh
Executable file
3
doc/sample-package/control/post-uninstall.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Hello, world!"
|
||||||
3
doc/sample-package/control/pre-install.sh
Executable file
3
doc/sample-package/control/pre-install.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Hello, world!"
|
||||||
3
doc/sample-package/control/pre-uninstall.sh
Executable file
3
doc/sample-package/control/pre-uninstall.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Hello, world!"
|
||||||
22
doc/sample-package/make-package.sh
Executable file
22
doc/sample-package/make-package.sh
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
payload_name=payload.tar.zst
|
||||||
|
control_name=control.tar.zst
|
||||||
|
news_name=news.tar.zst
|
||||||
|
manifest_name=manifest.json.zst
|
||||||
|
|
||||||
|
payload_dest=$TMPDIR/$payload_name
|
||||||
|
control_dest=$TMPDIR/$control_name
|
||||||
|
news_dest=$TMPDIR/$news_name
|
||||||
|
manifest_dest=$TMPDIR/$manifest_name
|
||||||
|
|
||||||
|
pkg_dest=sample-package_0.1_amd64.ropkg
|
||||||
|
|
||||||
|
rm -rf $manifest_dest
|
||||||
|
|
||||||
|
tar cf $payload_dest --zstd -C payload .
|
||||||
|
tar cf $control_dest --zstd -C control .
|
||||||
|
tar cf $news_dest --zstd -C news .
|
||||||
|
zstd manifest.json -o $manifest_dest
|
||||||
|
|
||||||
|
tar cf $pkg_dest -C $TMPDIR $payload_name $control_name $news_name $manifest_name
|
||||||
17
doc/sample-package/manifest
Normal file
17
doc/sample-package/manifest
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Name: sample-package
|
||||||
|
Architecture: amd64
|
||||||
|
Version: 1.2.5-2
|
||||||
|
Priority: optional
|
||||||
|
Category: misc
|
||||||
|
Maintainer: John Doe <john@sample.com>
|
||||||
|
Provides: sample-api (= 1.2.5)
|
||||||
|
Depends: libc (>= 2.0), libstdc++ (>= 2.3), libs1 (>= 1.0) | libs2 (>= 1.2)
|
||||||
|
Recommends: sample-cli
|
||||||
|
Suggests: sample-gtk | sample-qt, sample-server
|
||||||
|
Conflicts: example-package
|
||||||
|
Enhances: basic-package
|
||||||
|
Description: A sample package
|
||||||
|
Installed-Size: 3245
|
||||||
|
|
||||||
|
This is a sample package that demonstrates the structure of a Rosetta package,
|
||||||
|
as well as the layout of the associated manifest and news files.
|
||||||
110
doc/sample-package/news/20250707.01.news
Normal file
110
doc/sample-package/news/20250707.01.news
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
PublishDate: 2025-07-07 09:00:00
|
||||||
|
Importance: Normal
|
||||||
|
Title: Welcome to the Rosetta Package Manager
|
||||||
|
Category: General
|
||||||
|
|
||||||
|
+------------------------------------------------------------------------------+
|
||||||
|
| Welcome to the Rosetta Package Manager! |
|
||||||
|
+------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
This is a sample news item to introduce you to the Rosetta package manager.
|
||||||
|
These news items can be used to provide information and updates to those who
|
||||||
|
use your repository.
|
||||||
|
|
||||||
|
|
||||||
|
1 News File Location
|
||||||
|
====================
|
||||||
|
|
||||||
|
News items come from four different sources:
|
||||||
|
- Repository-wide news items, located in /news
|
||||||
|
|
||||||
|
- Channel-related news items, located in /channel/<channel-id>/news
|
||||||
|
|
||||||
|
- Component-related news items, located in
|
||||||
|
/channel/<channel-id>/component/<component-id>/news
|
||||||
|
|
||||||
|
- Package-related news items, included in individual package files.
|
||||||
|
|
||||||
|
Specific news items can be published in different locations depending on who
|
||||||
|
the news is relevant for. For example, if there is some critical issue that
|
||||||
|
affects all users of a repository, /news would be the perfect place to use.
|
||||||
|
If, instead, the issue only affects users of a particular channel (maybe
|
||||||
|
you have a channel for each release of your operating system),
|
||||||
|
/channel/<channel-id>/news would be more appropriate. It's important that
|
||||||
|
news is targeted to the appropriate audience so that users don't have to sift
|
||||||
|
through news that isn't relevant to them.
|
||||||
|
|
||||||
|
|
||||||
|
2 News File Format
|
||||||
|
==================
|
||||||
|
|
||||||
|
News items have a specific plain-text format, which can be seen in this file.
|
||||||
|
The file begins with a set of headers that describe certain attributes of the
|
||||||
|
news, followed by the news content and an optional footer.
|
||||||
|
|
||||||
|
|
||||||
|
2.1 Header And Footer
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
These headers include:
|
||||||
|
- PublishDate: The date and time on which the news item was published. This
|
||||||
|
is used by clients to determine which news items have been released since
|
||||||
|
the user last checked the news. This is always in UTC.
|
||||||
|
|
||||||
|
- Title: The title of the news item.
|
||||||
|
|
||||||
|
- Category: The particular category that the news item is relevant to.
|
||||||
|
Possible values include:
|
||||||
|
* General
|
||||||
|
* Security
|
||||||
|
|
||||||
|
- Importance: How important it is that the user reads this news.
|
||||||
|
Possible values include:
|
||||||
|
* Low
|
||||||
|
* Normal
|
||||||
|
* High
|
||||||
|
* Critical
|
||||||
|
The user has to go out of their way to read Low and Normal news items, while
|
||||||
|
High and Critical news items will be shown automatically when the user next
|
||||||
|
interacts with the relevant part of the repo.
|
||||||
|
|
||||||
|
Immediately following these headers are two line-feed characters. This
|
||||||
|
denotes the end of the header and the start of the content of the news files.
|
||||||
|
With two line feeds, there should be exactly one blank line visible between
|
||||||
|
the last header line and the first content line.
|
||||||
|
|
||||||
|
At the end of the file is a line with 5 asterisk (*) characters. This denotes
|
||||||
|
the end of the of the news file's content and the start of the footer. Beyond
|
||||||
|
this point, you can put extra data, such as the vim formatting commands
|
||||||
|
visible in this file, that you don't want shown to the user. If no footer is
|
||||||
|
required, the 5-asterisk marker can be omitted, and the news content will
|
||||||
|
simply end where the file ends.
|
||||||
|
|
||||||
|
|
||||||
|
2.2 Content
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Between the header and footer is the actual news content that is shown to the
|
||||||
|
user. This section can be formatted in any way you prefer; any plaintext is
|
||||||
|
acceptable. This news file has been formated in a particular way to provide
|
||||||
|
example formatting that you may wish to use. It features a page header,
|
||||||
|
section and sub-section headings, and list formatting. All paragraphs
|
||||||
|
are indented with three spaces. The gap between a list item marker
|
||||||
|
and list item text is two spaces, with any following lines in that particular
|
||||||
|
list item indented with three spaces. There is one blank line between each
|
||||||
|
paragraph, and two blank lines between the last line in one section and
|
||||||
|
the heading of the next.
|
||||||
|
|
||||||
|
The only formatting rule that should be adhered to is that, like code, lines
|
||||||
|
should be kept to no longer than 80 characters. This is due to the fact that
|
||||||
|
the vast majority of users will be viewing news items within their terminal
|
||||||
|
as they are using the ropkg commands, and 80 cells is the standard width for
|
||||||
|
terminal displays.
|
||||||
|
|
||||||
|
Don't forget that, if your text editor supports in-line formatting directives
|
||||||
|
like vim, you can store these directives in the page footer so that they
|
||||||
|
aren't shown to the user.
|
||||||
|
|
||||||
|
*****
|
||||||
|
|
||||||
|
vim: shiftwidth=3 expandtab
|
||||||
0
doc/sample-package/payload/usr/bin/hello
Executable file
0
doc/sample-package/payload/usr/bin/hello
Executable file
BIN
doc/sample-package/sample-package_0.1.amd64.ropkg
Normal file
BIN
doc/sample-package/sample-package_0.1.amd64.ropkg
Normal file
Binary file not shown.
46
doc/sample.recipe
Normal file
46
doc/sample.recipe
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import ropkg
|
||||||
|
|
||||||
|
|
||||||
|
package_manifest = {
|
||||||
|
'Name': 'rosequartz',
|
||||||
|
'Version': '1.0',
|
||||||
|
'Maintainers': [ 'Max Wash <max@doorstuck.net>' ],
|
||||||
|
'Arch': ropkg.system.arch(),
|
||||||
|
'Platform': ropkg.system.platform_name(),
|
||||||
|
'Description': 'Cross platform C and C++ runtime',
|
||||||
|
'Depends': [ 'libc:1.0', 'libm:1.0'],
|
||||||
|
'License': '3-Clause BSD',
|
||||||
|
'Website': 'http://doorstuck.net',
|
||||||
|
'SourceWebsite': 'https://gitlab.com/doorstuck/rosequartz'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_sources():
|
||||||
|
ropkg.git.clone_repo('rosequartz', 'https://gitlab.com/doorstuck/rosequartz.git')
|
||||||
|
|
||||||
|
|
||||||
|
def configure():
|
||||||
|
ropkg.cmake.configure_project('rosequartz')
|
||||||
|
|
||||||
|
|
||||||
|
def build():
|
||||||
|
ropkg.build.build_project('rosequartz')
|
||||||
|
|
||||||
|
|
||||||
|
def package():
|
||||||
|
ropkg.pkg.build_package('rosequartz', package_manifest)
|
||||||
|
|
||||||
|
|
||||||
|
recipe = {
|
||||||
|
'name': 'rosequartz',
|
||||||
|
'steps': {
|
||||||
|
'get-src': get_sources,
|
||||||
|
'configure': configure,
|
||||||
|
'build': build,
|
||||||
|
'package': package,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ropkg.run_recipe(recipe)
|
||||||
|
|
||||||
|
# vim: ft=python
|
||||||
@@ -6,10 +6,9 @@ set_target_properties(libropkg PROPERTIES
|
|||||||
OUTPUT_NAME ropkg)
|
OUTPUT_NAME ropkg)
|
||||||
target_link_libraries(libropkg
|
target_link_libraries(libropkg
|
||||||
Bluelib::Io
|
Bluelib::Io
|
||||||
${ZSTD_LIBRARY})
|
Bluelib::Compress)
|
||||||
target_include_directories(libropkg PUBLIC
|
target_include_directories(libropkg PUBLIC
|
||||||
include/
|
include/)
|
||||||
${ZSTD_INCLUDE_DIR})
|
|
||||||
target_compile_definitions(libropkg PRIVATE
|
target_compile_definitions(libropkg PRIVATE
|
||||||
LIBROPKG_EXPORT=1
|
LIBROPKG_EXPORT=1
|
||||||
LIBROPKG_STATIC=0)
|
LIBROPKG_STATIC=0)
|
||||||
|
|||||||
87
libropkg/include/ropkg/manifest.h
Normal file
87
libropkg/include/ropkg/manifest.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef ROPKG_MANIFEST_H_
|
||||||
|
#define ROPKG_MANIFEST_H_
|
||||||
|
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <ropkg/misc.h>
|
||||||
|
#include <ropkg/status.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
enum ropkg_manifest_value_type {
|
||||||
|
ROPKG_MANIFEST_VALUE_T_NONE = 0,
|
||||||
|
ROPKG_MANIFEST_VALUE_T_STRING,
|
||||||
|
ROPKG_MANIFEST_VALUE_T_INT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ropkg_manifest_value_id {
|
||||||
|
ROPKG_MANIFEST_VALUE_N_NONE = 0,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_NAME,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_ARCHITECTURE,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_VERSION,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_PRIORITY,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_CATEGORY,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_MAINTAINER,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_PROVIDES,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_DEPENDS,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_RECOMMENDS,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_SUGGESTS,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_CONFLICTS,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_ENHANCES,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_INSTALLED_SIZE,
|
||||||
|
ROPKG_MANIFEST_VALUE_N_DESCRIPTION,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_manifest;
|
||||||
|
struct ropkg_manifest_value;
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_create(struct ropkg_manifest **out);
|
||||||
|
ROPKG_API void ropkg_manifest_destroy(struct ropkg_manifest *manifest);
|
||||||
|
|
||||||
|
ROPKG_API b_result ropkg_manifest_parse(FILE *fp, struct ropkg_manifest *dest);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_get_by_name(
|
||||||
|
struct ropkg_manifest *manifest,
|
||||||
|
const char *name,
|
||||||
|
struct ropkg_manifest_value **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_get_by_id(
|
||||||
|
struct ropkg_manifest *manifest,
|
||||||
|
enum ropkg_manifest_value_id id,
|
||||||
|
struct ropkg_manifest_value **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_put(
|
||||||
|
struct ropkg_manifest *manifest,
|
||||||
|
struct ropkg_manifest_value *value);
|
||||||
|
ROPKG_API const struct ropkg_manifest_value *ropkg_manifest_get_first_value(
|
||||||
|
const struct ropkg_manifest *manifest);
|
||||||
|
ROPKG_API const struct ropkg_manifest_value *ropkg_manifest_get_next_value(
|
||||||
|
const struct ropkg_manifest *manifest,
|
||||||
|
const struct ropkg_manifest_value *value);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_value_create_int_with_name(
|
||||||
|
size_t value,
|
||||||
|
const char *name,
|
||||||
|
struct ropkg_manifest_value **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_value_create_int_with_id(
|
||||||
|
size_t value,
|
||||||
|
enum ropkg_manifest_value_id id,
|
||||||
|
struct ropkg_manifest_value **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_value_create_string_with_name(
|
||||||
|
const char *value,
|
||||||
|
const char *name,
|
||||||
|
struct ropkg_manifest_value **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_manifest_value_create_string_with_id(
|
||||||
|
const char *value,
|
||||||
|
enum ropkg_manifest_value_id id,
|
||||||
|
struct ropkg_manifest_value **out);
|
||||||
|
ROPKG_API void ropkg_manifest_value_destroy(struct ropkg_manifest_value *value);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_manifest_value_type ropkg_manifest_value_get_type(
|
||||||
|
const struct ropkg_manifest_value *value);
|
||||||
|
ROPKG_API const char *ropkg_manifest_value_get_name(
|
||||||
|
const struct ropkg_manifest_value *value);
|
||||||
|
ROPKG_API enum ropkg_manifest_value_id ropkg_manifest_value_get_id(
|
||||||
|
const struct ropkg_manifest_value *value);
|
||||||
|
ROPKG_API const char *ropkg_manifest_value_get_string(
|
||||||
|
const struct ropkg_manifest_value *value);
|
||||||
|
ROPKG_API size_t
|
||||||
|
ropkg_manifest_value_get_int(const struct ropkg_manifest_value *value);
|
||||||
|
|
||||||
|
#endif
|
||||||
13
libropkg/include/ropkg/package.h
Normal file
13
libropkg/include/ropkg/package.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef ROPKG_PACKAGE_H_
|
||||||
|
#define ROPKG_PACKAGE_H_
|
||||||
|
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/io/directory.h>
|
||||||
|
#include <ropkg/misc.h>
|
||||||
|
|
||||||
|
struct ropkg_reader;
|
||||||
|
|
||||||
|
ROPKG_API b_result
|
||||||
|
ropkg_extract_metadata(struct ropkg_reader *reader, b_directory *dest);
|
||||||
|
|
||||||
|
#endif
|
||||||
51
libropkg/include/ropkg/pkg-expr.h
Normal file
51
libropkg/include/ropkg/pkg-expr.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef ROPKG_PKG_EXPR_H_
|
||||||
|
#define ROPKG_PKG_EXPR_H_
|
||||||
|
|
||||||
|
#include <ropkg/misc.h>
|
||||||
|
#include <ropkg/status.h>
|
||||||
|
|
||||||
|
enum ropkg_pkg_expr_type {
|
||||||
|
ROPKG_PKG_EXPR_NODE_PKG,
|
||||||
|
ROPKG_PKG_EXPR_NODE_AND,
|
||||||
|
ROPKG_PKG_EXPR_NODE_OR,
|
||||||
|
ROPKG_PKG_EXPR_NODE_GROUP,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ropkg_comparison_op;
|
||||||
|
|
||||||
|
struct ropkg_version;
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr;
|
||||||
|
struct ropkg_pkg_expr_pkg;
|
||||||
|
struct ropkg_pkg_expr_and;
|
||||||
|
struct ropkg_pkg_expr_or;
|
||||||
|
|
||||||
|
ROPKG_API void ropkg_pkg_expr_destroy(struct ropkg_pkg_expr *expr);
|
||||||
|
|
||||||
|
ROPKG_API b_result
|
||||||
|
ropkg_pkg_expr_parse(const char *s, struct ropkg_pkg_expr **out);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_pkg_expr_type ropkg_pkg_expr_get_type(
|
||||||
|
const struct ropkg_pkg_expr *expr);
|
||||||
|
|
||||||
|
ROPKG_API struct ropkg_pkg_expr_pkg *ropkg_pkg_expr_pkg_create(void);
|
||||||
|
ROPKG_API const char *ropkg_pkg_expr_pkg_get_name(
|
||||||
|
const struct ropkg_pkg_expr_pkg *expr);
|
||||||
|
ROPKG_API enum ropkg_comparison_op ropkg_pkg_expr_pkg_get_version_predicate(
|
||||||
|
const struct ropkg_pkg_expr_pkg *expr);
|
||||||
|
ROPKG_API const struct ropkg_version *ropkg_pkg_expr_pkg_get_version(
|
||||||
|
const struct ropkg_pkg_expr_pkg *expr);
|
||||||
|
|
||||||
|
ROPKG_API struct ropkg_pkg_expr_and *ropkg_pkg_expr_and_create(void);
|
||||||
|
ROPKG_API const struct ropkg_pkg_expr *ropkg_pkg_expr_and_get_left_node(
|
||||||
|
const struct ropkg_pkg_expr_and *expr);
|
||||||
|
ROPKG_API const struct ropkg_pkg_expr *ropkg_pkg_expr_and_get_right_node(
|
||||||
|
const struct ropkg_pkg_expr_and *expr);
|
||||||
|
|
||||||
|
ROPKG_API struct ropkg_pkg_expr_or *ropkg_pkg_expr_or_create(void);
|
||||||
|
ROPKG_API const struct ropkg_pkg_expr *ropkg_pkg_expr_or_get_left_node(
|
||||||
|
const struct ropkg_pkg_expr_or *expr);
|
||||||
|
ROPKG_API const struct ropkg_pkg_expr *ropkg_pkg_expr_or_get_right_node(
|
||||||
|
const struct ropkg_pkg_expr_or *expr);
|
||||||
|
|
||||||
|
#endif
|
||||||
33
libropkg/include/ropkg/reader.h
Normal file
33
libropkg/include/ropkg/reader.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef ROPKG_READER_H_
|
||||||
|
#define ROPKG_READER_H_
|
||||||
|
|
||||||
|
#include <ropkg/misc.h>
|
||||||
|
#include <ropkg/status.h>
|
||||||
|
|
||||||
|
struct ropkg_reader;
|
||||||
|
struct b_cstream;
|
||||||
|
|
||||||
|
struct ropkg_file_info {
|
||||||
|
char f_filename[255];
|
||||||
|
int f_mode;
|
||||||
|
int f_uid, f_gid;
|
||||||
|
unsigned long f_filesize;
|
||||||
|
unsigned long f_mtime;
|
||||||
|
int f_type;
|
||||||
|
char f_linkname[100];
|
||||||
|
};
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_reader_open(
|
||||||
|
struct b_cstream *fp,
|
||||||
|
struct ropkg_reader **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_reader_close(struct ropkg_reader *pkg);
|
||||||
|
|
||||||
|
ROPKG_API const struct ropkg_file_info *ropkg_reader_current_file(
|
||||||
|
struct ropkg_reader *reader);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_reader_move_next(struct ropkg_reader *pkg);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_reader_move_to_file(
|
||||||
|
struct ropkg_reader *pkg,
|
||||||
|
const char *name);
|
||||||
|
ROPKG_API bool ropkg_reader_eof(const struct ropkg_reader *pkg);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -4,11 +4,12 @@
|
|||||||
#include <blue/core/error.h>
|
#include <blue/core/error.h>
|
||||||
#include <ropkg/misc.h>
|
#include <ropkg/misc.h>
|
||||||
|
|
||||||
#define ROPKG_ERROR_VENDOR (ropkg_error_vendor())
|
#define ROPKG_ERROR_VENDOR (ropkg_error_vendor())
|
||||||
|
|
||||||
|
#define ROPKG_RESULT_SUCCESS B_RESULT_SUCCESS
|
||||||
#define ROPKG_RESULT_ERR(code) \
|
#define ROPKG_RESULT_ERR(code) \
|
||||||
b_error_with_code(ROPKG_ERROR_VENDOR, ROPKG_ERR_##code)
|
b_error_with_code(ROPKG_ERROR_VENDOR, ROPKG_ERR_##code)
|
||||||
#define ROPKG_RESULT_SUCCESS B_RESULT_SUCCESS
|
#define ROPKG_RESULT_STATUS(code) b_error_with_code(ROPKG_ERROR_VENDOR, code)
|
||||||
|
|
||||||
enum ropkg_status {
|
enum ropkg_status {
|
||||||
ROPKG_SUCCESS = 0,
|
ROPKG_SUCCESS = 0,
|
||||||
@@ -18,11 +19,17 @@ enum ropkg_status {
|
|||||||
ROPKG_ERR_BAD_STATE,
|
ROPKG_ERR_BAD_STATE,
|
||||||
ROPKG_ERR_INTERNAL_FAILURE,
|
ROPKG_ERR_INTERNAL_FAILURE,
|
||||||
ROPKG_ERR_IO_FAILURE,
|
ROPKG_ERR_IO_FAILURE,
|
||||||
|
ROPKG_ERR_NO_ENTRY,
|
||||||
|
ROPKG_ERR_NO_DATA,
|
||||||
|
ROPKG_ERR_NAME_EXISTS,
|
||||||
|
|
||||||
ROPKG_ERR_DIR_OPEN_FAILED,
|
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||||
ROPKG_ERR_INSTANCE_DIR_CREATE_FAILED,
|
ROPKG_ERR_INSTANCE_DIR_CREATE_FAILED,
|
||||||
ROPKG_ERR_FILE_OPEN_FAILED,
|
ROPKG_ERR_FILE_OPEN_FAILED,
|
||||||
|
ROPKG_ERR_INVALID_MANIFEST_FORMAT,
|
||||||
ROPKG_ERR_INVALID_VERSION_FORMAT,
|
ROPKG_ERR_INVALID_VERSION_FORMAT,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_FILE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ropkg_error_msg {
|
enum ropkg_error_msg {
|
||||||
|
|||||||
450
libropkg/manifest.c
Normal file
450
libropkg/manifest.c
Normal file
@@ -0,0 +1,450 @@
|
|||||||
|
#include "manifest.h"
|
||||||
|
|
||||||
|
#include <blue/object/string.h>
|
||||||
|
#include <ropkg/manifest.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static const char *value_id_names[] = {
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_NAME] = "Name",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_ARCHITECTURE] = "Architecture",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_VERSION] = "Version",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_PRIORITY] = "Priority",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_CATEGORY] = "Category",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_MAINTAINER] = "Maintainer",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_PROVIDES] = "Provides",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_DEPENDS] = "Depends",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_RECOMMENDS] = "Recommends",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_SUGGESTS] = "Suggests",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_CONFLICTS] = "Conflicts",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_ENHANCES] = "Enhances",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_INSTALLED_SIZE] = "Installed-Size",
|
||||||
|
[ROPKG_MANIFEST_VALUE_N_DESCRIPTION] = "Description",
|
||||||
|
};
|
||||||
|
static const size_t nr_value_id_names
|
||||||
|
= sizeof value_id_names / sizeof value_id_names[0];
|
||||||
|
|
||||||
|
static enum ropkg_manifest_value_id value_id_from_string(const char *s)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < nr_value_id_names; i++) {
|
||||||
|
const char *name = value_id_names[i];
|
||||||
|
if (name && !strcmp(name, s)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_MANIFEST_VALUE_N_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_manifest_create(struct ropkg_manifest **out)
|
||||||
|
{
|
||||||
|
struct ropkg_manifest *manifest = malloc(sizeof *manifest);
|
||||||
|
if (!manifest) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(manifest, 0x0, sizeof *manifest);
|
||||||
|
|
||||||
|
*out = manifest;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ropkg_manifest_destroy(struct ropkg_manifest *manifest)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_pop_back(&manifest->m_values);
|
||||||
|
while (entry) {
|
||||||
|
struct ropkg_manifest_value *value
|
||||||
|
= b_unbox(struct ropkg_manifest_value, entry, v_entry);
|
||||||
|
ropkg_manifest_value_destroy(value);
|
||||||
|
entry = b_queue_pop_back(&manifest->m_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result create_manifest_value(
|
||||||
|
b_string *name,
|
||||||
|
b_string *value,
|
||||||
|
struct ropkg_manifest_value **out)
|
||||||
|
{
|
||||||
|
const char *name_cstr = b_string_ptr(name);
|
||||||
|
enum ropkg_manifest_value_id id = value_id_from_string(name_cstr);
|
||||||
|
|
||||||
|
const char *value_cstr = b_string_ptr(value);
|
||||||
|
char *ep;
|
||||||
|
size_t v = strtoull(value_cstr, &ep, 10);
|
||||||
|
struct ropkg_manifest_value *result = NULL;
|
||||||
|
enum ropkg_status status = ROPKG_SUCCESS;
|
||||||
|
|
||||||
|
if (*ep == 0) {
|
||||||
|
if (id != ROPKG_MANIFEST_VALUE_N_NONE) {
|
||||||
|
status = ropkg_manifest_value_create_int_with_id(
|
||||||
|
v,
|
||||||
|
id,
|
||||||
|
&result);
|
||||||
|
} else {
|
||||||
|
status = ropkg_manifest_value_create_int_with_name(
|
||||||
|
v,
|
||||||
|
name_cstr,
|
||||||
|
&result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (id != ROPKG_MANIFEST_VALUE_N_NONE) {
|
||||||
|
status = ropkg_manifest_value_create_string_with_id(
|
||||||
|
value_cstr,
|
||||||
|
id,
|
||||||
|
&result);
|
||||||
|
} else {
|
||||||
|
status = ropkg_manifest_value_create_string_with_name(
|
||||||
|
value_cstr,
|
||||||
|
name_cstr,
|
||||||
|
&result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return b_error_with_code(ROPKG_ERROR_VENDOR, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = result;
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result ropkg_manifest_parse(FILE *fp, struct ropkg_manifest *dest)
|
||||||
|
{
|
||||||
|
enum parser_state {
|
||||||
|
PARSER_STATE_NAME,
|
||||||
|
PARSER_STATE_VALUE,
|
||||||
|
} parser_state = PARSER_STATE_NAME;
|
||||||
|
|
||||||
|
enum ropkg_status status = ROPKG_SUCCESS;
|
||||||
|
b_result result = B_RESULT_SUCCESS;
|
||||||
|
b_string *name = b_string_create();
|
||||||
|
b_string *value_string = b_string_create();
|
||||||
|
struct ropkg_manifest_value *value = NULL;
|
||||||
|
char s[2] = {0};
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
while (!done) {
|
||||||
|
char c = fgetc(fp);
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case ':':
|
||||||
|
if (parser_state == PARSER_STATE_NAME) {
|
||||||
|
parser_state = PARSER_STATE_VALUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s[0] = c;
|
||||||
|
b_string_append_cstr(value_string, s);
|
||||||
|
continue;
|
||||||
|
case '\n':
|
||||||
|
if (parser_state == PARSER_STATE_NAME) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = create_manifest_value(
|
||||||
|
name,
|
||||||
|
value_string,
|
||||||
|
&value);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ropkg_manifest_put(dest, value);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
result = b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
status);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_string_clear(name);
|
||||||
|
b_string_clear(value_string);
|
||||||
|
parser_state = PARSER_STATE_NAME;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
if (parser_state == PARSER_STATE_NAME
|
||||||
|
&& b_string_get_size(name, 0) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_state == PARSER_STATE_VALUE
|
||||||
|
&& b_string_get_size(value_string, 0) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
s[0] = c;
|
||||||
|
|
||||||
|
if (parser_state == PARSER_STATE_NAME) {
|
||||||
|
b_string_append_cstr(name, s);
|
||||||
|
} else {
|
||||||
|
b_string_append_cstr(value_string, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b_string_release(name);
|
||||||
|
b_string_release(value_string);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_manifest_get_by_name(
|
||||||
|
struct ropkg_manifest *manifest,
|
||||||
|
const char *name,
|
||||||
|
struct ropkg_manifest_value **out)
|
||||||
|
{
|
||||||
|
b_queue_iterator it;
|
||||||
|
b_queue_foreach(&it, &manifest->m_values)
|
||||||
|
{
|
||||||
|
struct ropkg_manifest_value *value = b_unbox(
|
||||||
|
struct ropkg_manifest_value,
|
||||||
|
it.entry,
|
||||||
|
v_entry);
|
||||||
|
if (value->v_name && !strcmp(value->v_name, name)) {
|
||||||
|
*out = value;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_ERR_NO_ENTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_manifest_get_by_id(
|
||||||
|
struct ropkg_manifest *manifest,
|
||||||
|
enum ropkg_manifest_value_id id,
|
||||||
|
struct ropkg_manifest_value **out)
|
||||||
|
{
|
||||||
|
b_queue_iterator it;
|
||||||
|
b_queue_foreach(&it, &manifest->m_values)
|
||||||
|
{
|
||||||
|
struct ropkg_manifest_value *value = b_unbox(
|
||||||
|
struct ropkg_manifest_value,
|
||||||
|
it.entry,
|
||||||
|
v_entry);
|
||||||
|
if (value->v_id != ROPKG_MANIFEST_VALUE_N_NONE
|
||||||
|
&& value->v_id == id) {
|
||||||
|
*out = value;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_ERR_NO_ENTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_manifest_put(
|
||||||
|
struct ropkg_manifest *manifest,
|
||||||
|
struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
enum ropkg_status status = ROPKG_ERR_NO_ENTRY;
|
||||||
|
struct ropkg_manifest_value *tmp;
|
||||||
|
if (value->v_name) {
|
||||||
|
status = ropkg_manifest_get_by_name(
|
||||||
|
manifest,
|
||||||
|
value->v_name,
|
||||||
|
&tmp);
|
||||||
|
} else if (value->v_id != ROPKG_MANIFEST_VALUE_N_NONE) {
|
||||||
|
status = ropkg_manifest_get_by_id(manifest, value->v_id, &tmp);
|
||||||
|
} else {
|
||||||
|
return ROPKG_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == ROPKG_SUCCESS) {
|
||||||
|
return ROPKG_ERR_NAME_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_queue_push_back(&manifest->m_values, &value->v_entry);
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_manifest_value *ropkg_manifest_get_first_value(
|
||||||
|
const struct ropkg_manifest *manifest)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&manifest->m_values);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b_unbox(struct ropkg_manifest_value, entry, v_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_manifest_value *ropkg_manifest_get_next_value(
|
||||||
|
const struct ropkg_manifest *manifest,
|
||||||
|
const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_next(&value->v_entry);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b_unbox(struct ropkg_manifest_value, entry, v_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_manifest_value_create_int_with_name(
|
||||||
|
size_t value,
|
||||||
|
const char *name,
|
||||||
|
struct ropkg_manifest_value **out)
|
||||||
|
{
|
||||||
|
struct ropkg_manifest_value *vp = malloc(sizeof *vp);
|
||||||
|
if (!vp) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(vp, 0x0, sizeof *vp);
|
||||||
|
|
||||||
|
vp->v_type = ROPKG_MANIFEST_VALUE_T_INT;
|
||||||
|
vp->v_name = b_strdup(name);
|
||||||
|
|
||||||
|
if (!vp->v_name) {
|
||||||
|
free(vp);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
vp->v_value.i = value;
|
||||||
|
|
||||||
|
*out = vp;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_manifest_value_create_int_with_id(
|
||||||
|
size_t value,
|
||||||
|
enum ropkg_manifest_value_id id,
|
||||||
|
struct ropkg_manifest_value **out)
|
||||||
|
{
|
||||||
|
struct ropkg_manifest_value *vp = malloc(sizeof *vp);
|
||||||
|
if (!vp) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(vp, 0x0, sizeof *vp);
|
||||||
|
|
||||||
|
vp->v_type = ROPKG_MANIFEST_VALUE_T_INT;
|
||||||
|
vp->v_id = id;
|
||||||
|
|
||||||
|
vp->v_value.i = value;
|
||||||
|
|
||||||
|
*out = vp;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_manifest_value_create_string_with_name(
|
||||||
|
const char *value,
|
||||||
|
const char *name,
|
||||||
|
struct ropkg_manifest_value **out)
|
||||||
|
{
|
||||||
|
struct ropkg_manifest_value *vp = malloc(sizeof *vp);
|
||||||
|
if (!vp) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(vp, 0x0, sizeof *vp);
|
||||||
|
|
||||||
|
vp->v_type = ROPKG_MANIFEST_VALUE_T_STRING;
|
||||||
|
vp->v_name = b_strdup(vp->v_name);
|
||||||
|
|
||||||
|
if (!vp->v_name) {
|
||||||
|
free(vp);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
vp->v_value.s = b_strdup(value);
|
||||||
|
if (!vp->v_value.s) {
|
||||||
|
free(vp);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = vp;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
enum ropkg_status ropkg_manifest_value_create_string_with_id(
|
||||||
|
const char *value,
|
||||||
|
enum ropkg_manifest_value_id id,
|
||||||
|
struct ropkg_manifest_value **out)
|
||||||
|
{
|
||||||
|
struct ropkg_manifest_value *vp = malloc(sizeof *vp);
|
||||||
|
if (!vp) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(vp, 0x0, sizeof *vp);
|
||||||
|
|
||||||
|
vp->v_type = ROPKG_MANIFEST_VALUE_T_STRING;
|
||||||
|
vp->v_id = id;
|
||||||
|
|
||||||
|
vp->v_value.s = b_strdup(value);
|
||||||
|
if (!vp->v_value.s) {
|
||||||
|
free(vp);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = vp;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ropkg_manifest_value_destroy(struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
if (value->v_type == ROPKG_MANIFEST_VALUE_T_STRING
|
||||||
|
&& value->v_value.s) {
|
||||||
|
free(value->v_value.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value->v_name) {
|
||||||
|
free(value->v_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_manifest_value_type ropkg_manifest_value_get_type(
|
||||||
|
const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
return value->v_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ropkg_manifest_value_get_name(
|
||||||
|
const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
if (value->v_name) {
|
||||||
|
return value->v_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value->v_id == ROPKG_MANIFEST_VALUE_N_NONE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_id_names[value->v_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_manifest_value_id ropkg_manifest_value_get_id(
|
||||||
|
const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
return value->v_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ropkg_manifest_value_get_string(
|
||||||
|
const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
if (value->v_type != ROPKG_MANIFEST_VALUE_T_STRING) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value->v_value.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ropkg_manifest_value_get_int(const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
if (value->v_type != ROPKG_MANIFEST_VALUE_T_INT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value->v_value.i;
|
||||||
|
}
|
||||||
24
libropkg/manifest.h
Normal file
24
libropkg/manifest.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _MANIFEST_H_
|
||||||
|
#define _MANIFEST_H_
|
||||||
|
|
||||||
|
#include <blue/core/queue.h>
|
||||||
|
#include <ropkg/manifest.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct ropkg_manifest_value {
|
||||||
|
enum ropkg_manifest_value_type v_type;
|
||||||
|
enum ropkg_manifest_value_id v_id;
|
||||||
|
char *v_name;
|
||||||
|
b_queue_entry v_entry;
|
||||||
|
|
||||||
|
union {
|
||||||
|
size_t i;
|
||||||
|
char *s;
|
||||||
|
} v_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_manifest {
|
||||||
|
b_queue m_values;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
132
libropkg/package.c
Normal file
132
libropkg/package.c
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
#include "reader.h"
|
||||||
|
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/io/directory.h>
|
||||||
|
#include <ropkg/reader.h>
|
||||||
|
|
||||||
|
static b_result extract_file(
|
||||||
|
struct ropkg_reader *pkg,
|
||||||
|
const char *path_cstr,
|
||||||
|
b_directory *dest)
|
||||||
|
{
|
||||||
|
b_path *path = b_path_create_from_cstr(path_cstr);
|
||||||
|
if (!path) {
|
||||||
|
return ROPKG_RESULT_ERR(NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_path *dir_path = NULL;
|
||||||
|
b_path_get_directory(path, &dir_path);
|
||||||
|
if (!dir_path) {
|
||||||
|
b_path_release(path);
|
||||||
|
return ROPKG_RESULT_ERR(NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result result = B_RESULT_SUCCESS;
|
||||||
|
if (b_path_length(dir_path) > 0) {
|
||||||
|
b_directory *parent_dir;
|
||||||
|
result = b_directory_open(
|
||||||
|
dest,
|
||||||
|
dir_path,
|
||||||
|
B_DIRECTORY_OPEN_CREATE_INTERMEDIATE,
|
||||||
|
&parent_dir);
|
||||||
|
b_directory_release(parent_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_file *dest_file = NULL;
|
||||||
|
result = b_file_open(
|
||||||
|
dest,
|
||||||
|
path,
|
||||||
|
B_FILE_WRITE_ONLY | B_FILE_CREATE | B_FILE_BINARY,
|
||||||
|
&dest_file);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
char data[] = "Hello";
|
||||||
|
size_t nr_written = 0;
|
||||||
|
b_file_write(dest_file, 0, sizeof data, data, &nr_written);
|
||||||
|
b_file_release(dest_file);
|
||||||
|
|
||||||
|
end:
|
||||||
|
b_path_release(path);
|
||||||
|
b_path_release(dir_path);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result extract_subpackage(
|
||||||
|
struct ropkg_reader *pkg,
|
||||||
|
const char *name,
|
||||||
|
b_directory *dest)
|
||||||
|
{
|
||||||
|
b_directory *dest_subdir;
|
||||||
|
b_result result = b_directory_open(
|
||||||
|
dest,
|
||||||
|
B_RV_PATH(name),
|
||||||
|
B_DIRECTORY_OPEN_CREATE,
|
||||||
|
&dest_subdir);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_cstream_begin_compressed_section(pkg->r_stream, NULL);
|
||||||
|
|
||||||
|
struct ropkg_reader *subpkg = NULL;
|
||||||
|
enum ropkg_status status = ropkg_reader_open(pkg->r_stream, &subpkg);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
result = ROPKG_RESULT_STATUS(status);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!ropkg_reader_eof(subpkg)) {
|
||||||
|
const struct ropkg_file_info *file
|
||||||
|
= ropkg_reader_current_file(subpkg);
|
||||||
|
result = extract_file(subpkg, file->f_filename, dest_subdir);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ropkg_reader_move_next(subpkg);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
result = ROPKG_RESULT_STATUS(status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
b_cstream_end_compressed_section(pkg->r_stream, NULL, NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result ropkg_extract_metadata(struct ropkg_reader *pkg, b_directory *dest)
|
||||||
|
{
|
||||||
|
b_result result = B_RESULT_SUCCESS;
|
||||||
|
|
||||||
|
while (!ropkg_reader_eof(pkg)) {
|
||||||
|
const struct ropkg_file_info *file
|
||||||
|
= ropkg_reader_current_file(pkg);
|
||||||
|
|
||||||
|
int section = -1;
|
||||||
|
|
||||||
|
if (!strncmp(file->f_filename, "meta.tar", 8)) {
|
||||||
|
result = extract_subpackage(pkg, "meta", dest);
|
||||||
|
} else if (!strncmp(file->f_filename, "control.tar", 11)) {
|
||||||
|
result = extract_subpackage(pkg, "control", dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status status = ropkg_reader_move_next(pkg);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
result = ROPKG_RESULT_STATUS(status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
639
libropkg/pkg-expr.c
Normal file
639
libropkg/pkg-expr.c
Normal file
@@ -0,0 +1,639 @@
|
|||||||
|
#include "pkg-expr.h"
|
||||||
|
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/object/string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
enum parse_state {
|
||||||
|
PARSE_NONE = 0,
|
||||||
|
PARSE_PKG_NAME,
|
||||||
|
PARSE_PKG_MID,
|
||||||
|
PARSE_PKG_VERSION,
|
||||||
|
PARSE_PKG_VERSION_PREDICATE,
|
||||||
|
PARSE_PKG_VERSION_MID,
|
||||||
|
PARSE_PKG_VERSION_ID,
|
||||||
|
PARSE_PKG_END,
|
||||||
|
|
||||||
|
PARSE_AND_SEP,
|
||||||
|
PARSE_OR_SEP,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct parse_ctx {
|
||||||
|
const char *ctx_str;
|
||||||
|
b_string *ctx_temp;
|
||||||
|
enum parse_state ctx_state;
|
||||||
|
size_t ctx_i;
|
||||||
|
b_queue ctx_stack, ctx_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ropkg_pkg_expr *parse_ctx_peek_stack(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_last(&ctx->ctx_stack);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b_unbox(struct ropkg_pkg_expr, entry, expr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ropkg_pkg_expr *parse_ctx_pop(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_pop_back(&ctx->ctx_stack);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b_unbox(struct ropkg_pkg_expr, entry, expr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_ctx_push(struct parse_ctx *ctx, struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
b_queue_push_back(&ctx->ctx_stack, &expr->expr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ropkg_pkg_expr *parse_ctx_dequeue(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_pop_front(&ctx->ctx_queue);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b_unbox(struct ropkg_pkg_expr, entry, expr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_ctx_enqueue(
|
||||||
|
struct parse_ctx *ctx,
|
||||||
|
struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
b_queue_push_back(&ctx->ctx_queue, &expr->expr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char parse_ctx_peek(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
return ctx->ctx_str[ctx->ctx_i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static char parse_ctx_advance(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx->ctx_str[ctx->ctx_i]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ctx_i++;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char c = parse_ctx_peek(ctx);
|
||||||
|
if (isspace(c)) {
|
||||||
|
ctx->ctx_i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx->ctx_str[ctx->ctx_i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_ctx_cleanup(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->ctx_temp) {
|
||||||
|
b_string_release(ctx->ctx_temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr *expr = parse_ctx_dequeue(ctx);
|
||||||
|
while (expr) {
|
||||||
|
ropkg_pkg_expr_destroy(expr);
|
||||||
|
expr = parse_ctx_dequeue(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
expr = parse_ctx_pop(ctx);
|
||||||
|
while (expr) {
|
||||||
|
ropkg_pkg_expr_destroy(expr);
|
||||||
|
expr = parse_ctx_pop(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_pkg_expr_create(struct ropkg_pkg_expr **out)
|
||||||
|
{
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ropkg_pkg_expr_destroy(struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
b_queue q = B_QUEUE_INIT;
|
||||||
|
b_queue_push_back(&q, &expr->expr_entry);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
b_queue_entry *entry = b_queue_pop_front(&q);
|
||||||
|
if (!entry) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr = b_unbox(struct ropkg_pkg_expr, entry, expr_entry);
|
||||||
|
|
||||||
|
switch (expr->expr_type) {
|
||||||
|
case ROPKG_PKG_EXPR_NODE_PKG: {
|
||||||
|
struct ropkg_pkg_expr_pkg *pkg_node
|
||||||
|
= (struct ropkg_pkg_expr_pkg *)expr;
|
||||||
|
if (pkg_node->pkg_name) {
|
||||||
|
free(pkg_node->pkg_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkg_node->pkg_version) {
|
||||||
|
ropkg_version_destroy(pkg_node->pkg_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ROPKG_PKG_EXPR_NODE_AND: {
|
||||||
|
struct ropkg_pkg_expr_and *and_node
|
||||||
|
= (struct ropkg_pkg_expr_and *)expr;
|
||||||
|
if (and_node->and_left) {
|
||||||
|
b_queue_push_back(
|
||||||
|
&q,
|
||||||
|
&and_node->and_left->expr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (and_node->and_right) {
|
||||||
|
b_queue_push_back(
|
||||||
|
&q,
|
||||||
|
&and_node->and_right->expr_entry);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ROPKG_PKG_EXPR_NODE_OR: {
|
||||||
|
struct ropkg_pkg_expr_or *or_node
|
||||||
|
= (struct ropkg_pkg_expr_or *)expr;
|
||||||
|
if (or_node->or_left) {
|
||||||
|
b_queue_push_back(
|
||||||
|
&q,
|
||||||
|
&or_node->or_left->expr_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (or_node->or_right) {
|
||||||
|
b_queue_push_back(
|
||||||
|
&q,
|
||||||
|
&or_node->or_right->expr_entry);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_pkg_name(
|
||||||
|
struct parse_ctx *ctx,
|
||||||
|
struct ropkg_pkg_expr_pkg *pkg)
|
||||||
|
{
|
||||||
|
b_string_clear(ctx->ctx_temp);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char c = parse_ctx_peek(ctx);
|
||||||
|
if (!isalnum(c) && c != '+' && c != '-' && c != '_') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char s[] = {c, 0};
|
||||||
|
b_string_append_cstr(ctx->ctx_temp, s);
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg->pkg_name = b_string_steal(ctx->ctx_temp);
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_pkg_version_predicate(
|
||||||
|
struct parse_ctx *ctx,
|
||||||
|
struct ropkg_pkg_expr_pkg *pkg)
|
||||||
|
{
|
||||||
|
b_string_clear(ctx->ctx_temp);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char c = parse_ctx_peek(ctx);
|
||||||
|
if (!ispunct(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char s[] = {c, 0};
|
||||||
|
b_string_append_cstr(ctx->ctx_temp, s);
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *pred = b_string_ptr(ctx->ctx_temp);
|
||||||
|
if (!strcmp(pred, ">=")) {
|
||||||
|
pkg->pkg_version_predicate = ROPKG_OP_GREATER_EQUAL;
|
||||||
|
} else if (!strcmp(pred, ">")) {
|
||||||
|
pkg->pkg_version_predicate = ROPKG_OP_GREATER_THAN;
|
||||||
|
} else if (!strcmp(pred, "<=")) {
|
||||||
|
pkg->pkg_version_predicate = ROPKG_OP_LESS_EQUAL;
|
||||||
|
} else if (!strcmp(pred, "<")) {
|
||||||
|
pkg->pkg_version_predicate = ROPKG_OP_LESS_THAN;
|
||||||
|
} else if (!strcmp(pred, "==") || !strcmp(pred, "=")) {
|
||||||
|
pkg->pkg_version_predicate = ROPKG_OP_EQUAL;
|
||||||
|
} else {
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_pkg_version_id(
|
||||||
|
struct parse_ctx *ctx,
|
||||||
|
struct ropkg_pkg_expr_pkg *pkg)
|
||||||
|
{
|
||||||
|
b_string_clear(ctx->ctx_temp);
|
||||||
|
while (1) {
|
||||||
|
char c = parse_ctx_peek(ctx);
|
||||||
|
if (!isalnum(c) && c != '.' && c != '-' && c != '~') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char s[] = {c, 0};
|
||||||
|
b_string_append_cstr(ctx->ctx_temp, s);
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_version *version = NULL;
|
||||||
|
enum ropkg_status status = ropkg_version_create(&version);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return b_error_with_code(ROPKG_ERROR_VENDOR, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result result
|
||||||
|
= ropkg_version_parse(version, b_string_ptr(ctx->ctx_temp));
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
ropkg_version_destroy(version);
|
||||||
|
version = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg->pkg_version = version;
|
||||||
|
return b_result_propagate(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_pkg_version(
|
||||||
|
struct parse_ctx *ctx,
|
||||||
|
struct ropkg_pkg_expr_pkg *pkg)
|
||||||
|
{
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
|
||||||
|
b_result result = B_RESULT_SUCCESS;
|
||||||
|
char c = parse_ctx_peek(ctx);
|
||||||
|
if (c == '>' || c == '<' || c == '=') {
|
||||||
|
result = parse_pkg_version_predicate(ctx, pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = parse_ctx_peek(ctx);
|
||||||
|
|
||||||
|
if (isalnum(c)) {
|
||||||
|
result = parse_pkg_version_id(ctx, pkg);
|
||||||
|
} else {
|
||||||
|
result = b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = parse_ctx_peek(ctx);
|
||||||
|
if (c == ')') {
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
} else {
|
||||||
|
result = b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_pkg(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct ropkg_pkg_expr_pkg *pkg = ropkg_pkg_expr_pkg_create();
|
||||||
|
|
||||||
|
b_result result = B_RESULT_SUCCESS;
|
||||||
|
char c = parse_ctx_peek(ctx);
|
||||||
|
if (isalpha(c)) {
|
||||||
|
result = parse_pkg_name(ctx, pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
ropkg_pkg_expr_destroy((struct ropkg_pkg_expr *)pkg);
|
||||||
|
return b_result_propagate(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = parse_ctx_peek(ctx);
|
||||||
|
if (c == '(') {
|
||||||
|
result = parse_pkg_version(ctx, pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
ropkg_pkg_expr_destroy((struct ropkg_pkg_expr *)pkg);
|
||||||
|
return b_result_propagate(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_ctx_enqueue(ctx, &pkg->pkg_base);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_and(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_and *and_node = ropkg_pkg_expr_and_create();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct ropkg_pkg_expr *top = parse_ctx_peek_stack(ctx);
|
||||||
|
if (!top) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top->expr_type == ROPKG_PKG_EXPR_NODE_GROUP) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top->expr_type < and_node->and_base.expr_type) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
top = parse_ctx_pop(ctx);
|
||||||
|
parse_ctx_enqueue(ctx, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_ctx_push(ctx, &and_node->and_base);
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_or(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_or *or_node = ropkg_pkg_expr_or_create();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct ropkg_pkg_expr *top = parse_ctx_peek_stack(ctx);
|
||||||
|
if (!top) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top->expr_type < or_node->or_base.expr_type) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
top = parse_ctx_pop(ctx);
|
||||||
|
parse_ctx_enqueue(ctx, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_ctx_push(ctx, &or_node->or_base);
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_group_start(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr *group_node = malloc(sizeof *group_node);
|
||||||
|
if (!group_node) {
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(group_node, 0x0, sizeof *group_node);
|
||||||
|
|
||||||
|
group_node->expr_type = ROPKG_PKG_EXPR_NODE_GROUP;
|
||||||
|
|
||||||
|
parse_ctx_push(ctx, group_node);
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result parse_group_end(struct parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
parse_ctx_advance(ctx);
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
while (!done) {
|
||||||
|
struct ropkg_pkg_expr *expr = parse_ctx_pop(ctx);
|
||||||
|
|
||||||
|
if (!expr) {
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (expr->expr_type) {
|
||||||
|
case ROPKG_PKG_EXPR_NODE_GROUP:
|
||||||
|
free(expr);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parse_ctx_enqueue(ctx, expr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result ropkg_pkg_expr_parse(const char *s, struct ropkg_pkg_expr **out)
|
||||||
|
{
|
||||||
|
while (isspace(*s)) {
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct parse_ctx ctx = {
|
||||||
|
.ctx_str = s,
|
||||||
|
.ctx_temp = b_string_create(),
|
||||||
|
};
|
||||||
|
|
||||||
|
b_result result = B_RESULT_SUCCESS;
|
||||||
|
|
||||||
|
while (!b_result_is_error(result)) {
|
||||||
|
char c = parse_ctx_peek(&ctx);
|
||||||
|
if (c == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '(') {
|
||||||
|
result = parse_group_start(&ctx);
|
||||||
|
} else if (c == ')') {
|
||||||
|
result = parse_group_end(&ctx);
|
||||||
|
} else if (c == ',') {
|
||||||
|
result = parse_and(&ctx);
|
||||||
|
} else if (c == '|') {
|
||||||
|
result = parse_or(&ctx);
|
||||||
|
} else if (isalpha(c)) {
|
||||||
|
result = parse_pkg(&ctx);
|
||||||
|
} else {
|
||||||
|
result = b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
parse_ctx_cleanup(&ctx);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr *expr = parse_ctx_pop(&ctx);
|
||||||
|
while (expr) {
|
||||||
|
parse_ctx_enqueue(&ctx, expr);
|
||||||
|
expr = parse_ctx_pop(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
expr = parse_ctx_dequeue(&ctx);
|
||||||
|
if (!expr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr->expr_type == ROPKG_PKG_EXPR_NODE_PKG) {
|
||||||
|
parse_ctx_push(&ctx, expr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr->expr_type == ROPKG_PKG_EXPR_NODE_GROUP) {
|
||||||
|
parse_ctx_cleanup(&ctx);
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr *left = NULL, *right = NULL;
|
||||||
|
right = parse_ctx_pop(&ctx);
|
||||||
|
left = parse_ctx_pop(&ctx);
|
||||||
|
if (!left || !right) {
|
||||||
|
parse_ctx_cleanup(&ctx);
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (expr->expr_type) {
|
||||||
|
case ROPKG_PKG_EXPR_NODE_AND: {
|
||||||
|
struct ropkg_pkg_expr_and *and_node
|
||||||
|
= (struct ropkg_pkg_expr_and *)expr;
|
||||||
|
and_node->and_left = left;
|
||||||
|
and_node->and_right = right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ROPKG_PKG_EXPR_NODE_OR: {
|
||||||
|
struct ropkg_pkg_expr_or *or_node
|
||||||
|
= (struct ropkg_pkg_expr_or *)expr;
|
||||||
|
or_node->or_left = left;
|
||||||
|
or_node->or_right = right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_ctx_push(&ctx, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = parse_ctx_pop(&ctx);
|
||||||
|
parse_ctx_cleanup(&ctx);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_pkg_expr_type ropkg_pkg_expr_get_type(
|
||||||
|
const struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
return expr->expr_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_pkg *ropkg_pkg_expr_pkg_create(void)
|
||||||
|
{
|
||||||
|
struct ropkg_pkg_expr_pkg *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
out->pkg_base.expr_type = ROPKG_PKG_EXPR_NODE_PKG;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ropkg_pkg_expr_pkg_get_name(const struct ropkg_pkg_expr_pkg *expr)
|
||||||
|
{
|
||||||
|
return expr->pkg_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_comparison_op ropkg_pkg_expr_pkg_get_version_predicate(
|
||||||
|
const struct ropkg_pkg_expr_pkg *expr)
|
||||||
|
{
|
||||||
|
return expr->pkg_version_predicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_version *ropkg_pkg_expr_pkg_get_version(
|
||||||
|
const struct ropkg_pkg_expr_pkg *expr)
|
||||||
|
{
|
||||||
|
return expr->pkg_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_and *ropkg_pkg_expr_and_create(void)
|
||||||
|
{
|
||||||
|
struct ropkg_pkg_expr_and *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
out->and_base.expr_type = ROPKG_PKG_EXPR_NODE_AND;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_pkg_expr *ropkg_pkg_expr_and_get_left_node(
|
||||||
|
const struct ropkg_pkg_expr_and *expr)
|
||||||
|
{
|
||||||
|
return expr->and_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_pkg_expr *ropkg_pkg_expr_and_get_right_node(
|
||||||
|
const struct ropkg_pkg_expr_and *expr)
|
||||||
|
{
|
||||||
|
return expr->and_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_or *ropkg_pkg_expr_or_create(void)
|
||||||
|
{
|
||||||
|
struct ropkg_pkg_expr_or *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
out->or_base.expr_type = ROPKG_PKG_EXPR_NODE_OR;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_pkg_expr *ropkg_pkg_expr_or_get_left_node(
|
||||||
|
const struct ropkg_pkg_expr_or *expr)
|
||||||
|
{
|
||||||
|
return expr->or_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_pkg_expr *ropkg_pkg_expr_or_get_right_node(
|
||||||
|
const struct ropkg_pkg_expr_or *expr)
|
||||||
|
{
|
||||||
|
return expr->or_right;
|
||||||
|
}
|
||||||
29
libropkg/pkg-expr.h
Normal file
29
libropkg/pkg-expr.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef _PKG_EXPR_H_
|
||||||
|
#define _PKG_EXPR_H_
|
||||||
|
|
||||||
|
#include <ropkg/pkg-expr.h>
|
||||||
|
#include <ropkg/version.h>
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr {
|
||||||
|
enum ropkg_pkg_expr_type expr_type;
|
||||||
|
b_queue_entry expr_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_pkg {
|
||||||
|
struct ropkg_pkg_expr pkg_base;
|
||||||
|
char *pkg_name;
|
||||||
|
enum ropkg_comparison_op pkg_version_predicate;
|
||||||
|
struct ropkg_version *pkg_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_and {
|
||||||
|
struct ropkg_pkg_expr and_base;
|
||||||
|
struct ropkg_pkg_expr *and_left, *and_right;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr_or {
|
||||||
|
struct ropkg_pkg_expr or_base;
|
||||||
|
struct ropkg_pkg_expr *or_left, *or_right;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
239
libropkg/reader.c
Normal file
239
libropkg/reader.c
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
#include "reader.h"
|
||||||
|
|
||||||
|
#include <ropkg/reader.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static struct ustar_header null_header = {0};
|
||||||
|
|
||||||
|
static void copy_string(
|
||||||
|
const char *src,
|
||||||
|
size_t src_max,
|
||||||
|
char *dest,
|
||||||
|
size_t dest_max)
|
||||||
|
{
|
||||||
|
size_t start = strlen(dest);
|
||||||
|
size_t max = b_min(size_t, src_max, dest_max - start);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < max; i++) {
|
||||||
|
dest[start + i] = src[i];
|
||||||
|
|
||||||
|
if (!src[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long long from_octal(const char *s, size_t len)
|
||||||
|
{
|
||||||
|
long at = (long)len - 2;
|
||||||
|
long long value = 0;
|
||||||
|
long mul = 1;
|
||||||
|
while (at >= 0) {
|
||||||
|
char c = s[at];
|
||||||
|
if (c == 0 || c == ' ') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v = c - '0';
|
||||||
|
|
||||||
|
value += (v * mul);
|
||||||
|
mul *= 8;
|
||||||
|
at--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status read_file_header(struct ropkg_reader *reader)
|
||||||
|
{
|
||||||
|
if (b_cstream_in_compressed_section(reader->r_stream)) {
|
||||||
|
b_cstream_tx_bytes_uncompressed(
|
||||||
|
reader->r_stream,
|
||||||
|
&reader->r_cur_header_offset);
|
||||||
|
} else {
|
||||||
|
b_cstream_tx_bytes(
|
||||||
|
reader->r_stream,
|
||||||
|
&reader->r_cur_header_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nr_read = 0;
|
||||||
|
b_status status = b_cstream_read(
|
||||||
|
reader->r_stream,
|
||||||
|
&reader->r_cur_header,
|
||||||
|
sizeof reader->r_cur_header,
|
||||||
|
&nr_read);
|
||||||
|
if (!B_OK(status)) {
|
||||||
|
return ROPKG_ERR_IO_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_read != sizeof reader->r_cur_header) {
|
||||||
|
return ROPKG_ERR_INVALID_PKG_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&reader->f_cur_file, 0x0, sizeof reader->f_cur_file);
|
||||||
|
|
||||||
|
copy_string(
|
||||||
|
reader->r_cur_header.tar_filename_prefix,
|
||||||
|
sizeof reader->r_cur_header.tar_filename_prefix,
|
||||||
|
reader->f_cur_file.f_filename,
|
||||||
|
sizeof reader->f_cur_file.f_filename);
|
||||||
|
copy_string(
|
||||||
|
reader->r_cur_header.tar_filename,
|
||||||
|
sizeof reader->r_cur_header.tar_filename,
|
||||||
|
reader->f_cur_file.f_filename,
|
||||||
|
sizeof reader->f_cur_file.f_filename);
|
||||||
|
copy_string(
|
||||||
|
reader->r_cur_header.tar_linkname,
|
||||||
|
sizeof reader->r_cur_header.tar_linkname,
|
||||||
|
reader->f_cur_file.f_linkname,
|
||||||
|
sizeof reader->f_cur_file.f_linkname);
|
||||||
|
|
||||||
|
reader->f_cur_file.f_mode = from_octal(
|
||||||
|
reader->r_cur_header.tar_mode,
|
||||||
|
sizeof reader->r_cur_header.tar_mode);
|
||||||
|
reader->f_cur_file.f_uid = from_octal(
|
||||||
|
reader->r_cur_header.tar_uid,
|
||||||
|
sizeof reader->r_cur_header.tar_uid);
|
||||||
|
reader->f_cur_file.f_gid = from_octal(
|
||||||
|
reader->r_cur_header.tar_gid,
|
||||||
|
sizeof reader->r_cur_header.tar_gid);
|
||||||
|
reader->f_cur_file.f_filesize = from_octal(
|
||||||
|
reader->r_cur_header.tar_filesize,
|
||||||
|
sizeof reader->r_cur_header.tar_filesize);
|
||||||
|
reader->f_cur_file.f_mtime = from_octal(
|
||||||
|
reader->r_cur_header.tar_mtime,
|
||||||
|
sizeof reader->r_cur_header.tar_mtime);
|
||||||
|
reader->f_cur_file.f_type = reader->r_cur_header.tar_type[0];
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_reader_open(b_cstream *fp, struct ropkg_reader **out)
|
||||||
|
{
|
||||||
|
struct ropkg_reader *reader = malloc(sizeof *reader);
|
||||||
|
if (!reader) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(reader, 0x0, sizeof *reader);
|
||||||
|
|
||||||
|
reader->r_stream = fp;
|
||||||
|
|
||||||
|
enum ropkg_status status = read_file_header(reader);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
free(reader);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(&reader->r_cur_header, &null_header, sizeof null_header)) {
|
||||||
|
b_cstream_skip(reader->r_stream, sizeof null_header, NULL);
|
||||||
|
reader->r_eof = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = reader;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_reader_close(struct ropkg_reader *pkg)
|
||||||
|
{
|
||||||
|
free(pkg);
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_file_info *ropkg_reader_current_file(
|
||||||
|
struct ropkg_reader *reader)
|
||||||
|
{
|
||||||
|
return &reader->f_cur_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_reader_move_next(struct ropkg_reader *pkg)
|
||||||
|
{
|
||||||
|
if (pkg->r_eof) {
|
||||||
|
return ROPKG_ERR_NO_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
if (b_cstream_in_compressed_section(pkg->r_stream)) {
|
||||||
|
b_cstream_tx_bytes_uncompressed(pkg->r_stream, &pos);
|
||||||
|
} else {
|
||||||
|
b_cstream_tx_bytes(pkg->r_stream, &pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t end = pkg->r_cur_header_offset + sizeof pkg->r_cur_header
|
||||||
|
+ pkg->f_cur_file.f_filesize;
|
||||||
|
if ((end % 512) != 0) {
|
||||||
|
end += 512 - (end % 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t skip = end - pos;
|
||||||
|
|
||||||
|
size_t nr_skipped = 0;
|
||||||
|
b_cstream_skip(pkg->r_stream, skip, &nr_skipped);
|
||||||
|
|
||||||
|
if (nr_skipped != skip) {
|
||||||
|
pkg->r_eof = true;
|
||||||
|
return ROPKG_ERR_INVALID_PKG_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status status = read_file_header(pkg);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(&pkg->r_cur_header, &null_header, sizeof null_header)) {
|
||||||
|
b_cstream_skip(pkg->r_stream, sizeof null_header, NULL);
|
||||||
|
pkg->r_eof = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool compare_name(const char *target, const char *candidate)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
for (size_t i = 0;; i++) {
|
||||||
|
if (target[i] == '*') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target[i] != candidate[i]) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate[i] == 0 || target[i] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_reader_move_to_file(
|
||||||
|
struct ropkg_reader *pkg,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
enum ropkg_status status = ROPKG_ERR_NO_ENTRY;
|
||||||
|
|
||||||
|
while (!ropkg_reader_eof(pkg)) {
|
||||||
|
struct ropkg_file_info *file = &pkg->f_cur_file;
|
||||||
|
bool match = compare_name(name, file->f_filename);
|
||||||
|
if (match) {
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ropkg_reader_move_next(pkg);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_ERR_NO_ENTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ropkg_reader_eof(const struct ropkg_reader *pkg)
|
||||||
|
{
|
||||||
|
return pkg->r_eof;
|
||||||
|
}
|
||||||
17
libropkg/reader.h
Normal file
17
libropkg/reader.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef _READER_H_
|
||||||
|
#define _READER_H_
|
||||||
|
|
||||||
|
#include "tar.h"
|
||||||
|
|
||||||
|
#include <blue/compress/cstream.h>
|
||||||
|
#include <ropkg/reader.h>
|
||||||
|
|
||||||
|
struct ropkg_reader {
|
||||||
|
b_cstream *r_stream;
|
||||||
|
struct ustar_header r_cur_header;
|
||||||
|
size_t r_cur_header_offset;
|
||||||
|
struct ropkg_file_info f_cur_file;
|
||||||
|
bool r_eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -18,6 +18,14 @@ static const b_error_definition ropkg_errors[] = {
|
|||||||
"INTERNAL_FAILURE",
|
"INTERNAL_FAILURE",
|
||||||
"Internal failure"),
|
"Internal failure"),
|
||||||
B_ERROR_DEFINITION(ROPKG_ERR_IO_FAILURE, "IO_FAILURE", "I/O failure"),
|
B_ERROR_DEFINITION(ROPKG_ERR_IO_FAILURE, "IO_FAILURE", "I/O failure"),
|
||||||
|
B_ERROR_DEFINITION(
|
||||||
|
ROPKG_ERR_NO_ENTRY,
|
||||||
|
"NO_ENTRY",
|
||||||
|
"Name does not exist"),
|
||||||
|
B_ERROR_DEFINITION(
|
||||||
|
ROPKG_ERR_NAME_EXISTS,
|
||||||
|
"NAME_EXISTS",
|
||||||
|
"Name already exist"),
|
||||||
|
|
||||||
B_ERROR_DEFINITION_TEMPLATE(
|
B_ERROR_DEFINITION_TEMPLATE(
|
||||||
ROPKG_ERR_DIR_OPEN_FAILED,
|
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||||
@@ -51,10 +59,20 @@ static const b_error_definition ropkg_errors[] = {
|
|||||||
B_ERROR_TEMPLATE_PARAM_STRING,
|
B_ERROR_TEMPLATE_PARAM_STRING,
|
||||||
"%s")),
|
"%s")),
|
||||||
|
|
||||||
|
B_ERROR_DEFINITION(
|
||||||
|
ROPKG_ERR_INVALID_MANIFEST_FORMAT,
|
||||||
|
"INVALID_MANIFSET_FORMAT",
|
||||||
|
"Invalid manifest format"),
|
||||||
|
|
||||||
B_ERROR_DEFINITION(
|
B_ERROR_DEFINITION(
|
||||||
ROPKG_ERR_INVALID_VERSION_FORMAT,
|
ROPKG_ERR_INVALID_VERSION_FORMAT,
|
||||||
"INVALID_VERSION_FORMAT",
|
"INVALID_VERSION_FORMAT",
|
||||||
"Invalid version format"),
|
"Invalid version format"),
|
||||||
|
|
||||||
|
B_ERROR_DEFINITION(
|
||||||
|
ROPKG_ERR_INVALID_PKG_EXPR,
|
||||||
|
"INVALID_PKG_EXPR",
|
||||||
|
"Invalid package expression"),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const b_error_msg ropkg_error_msg[] = {
|
static const b_error_msg ropkg_error_msg[] = {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
file(GLOB_RECURSE sources *.c *.h)
|
file(GLOB_RECURSE sources *.c *.h)
|
||||||
|
|
||||||
add_executable(ropam ${sources})
|
add_executable(ropam ${sources})
|
||||||
target_link_libraries(ropam Bluelib::Core Bluelib::Object Bluelib::Io Bluelib::Term Bluelib::Cmd)
|
target_link_libraries(ropam
|
||||||
|
libropkg
|
||||||
|
Bluelib::Core Bluelib::Object Bluelib::Io Bluelib::Term Bluelib::Cmd)
|
||||||
|
|||||||
60
ropam/bootstrap.c
Normal file
60
ropam/bootstrap.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <ropkg/instance.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_PATH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int bootstrap(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
const char *root_path = NULL;
|
||||||
|
b_status status = b_arglist_get_string(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_PATH,
|
||||||
|
0,
|
||||||
|
&root_path);
|
||||||
|
if (!B_OK(status)) {
|
||||||
|
b_arglist_report_missing_args(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_PATH,
|
||||||
|
0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_instance *inst;
|
||||||
|
b_result result = ropkg_instance_bootstrap(root_path, &inst);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
b_throw(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_BOOTSTRAP, CMD_ROOT)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("bootstrap");
|
||||||
|
B_COMMAND_DESC(
|
||||||
|
"initialise a new Rosetta package manager instance. use this "
|
||||||
|
"command to prepare a sysroot for the installation of Rosetta "
|
||||||
|
"packages.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(bootstrap);
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("sysroot");
|
||||||
|
B_ARG_DESC(
|
||||||
|
"the path to the system root directory to initialise.");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ enum {
|
|||||||
CMD_SYNC,
|
CMD_SYNC,
|
||||||
CMD_REMOVE,
|
CMD_REMOVE,
|
||||||
CMD_QUERY,
|
CMD_QUERY,
|
||||||
|
CMD_BOOTSTRAP,
|
||||||
|
|
||||||
CMD_REPO,
|
CMD_REPO,
|
||||||
CMD_REPO_ADD,
|
CMD_REPO_ADD,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/term/print.h>
|
||||||
|
|
||||||
B_COMMAND(CMD_ROOT, B_COMMAND_INVALID_ID)
|
B_COMMAND(CMD_ROOT, B_COMMAND_INVALID_ID)
|
||||||
{
|
{
|
||||||
@@ -28,5 +30,8 @@ B_COMMAND(CMD_ROOT, B_COMMAND_INVALID_ID)
|
|||||||
|
|
||||||
int main(int argc, const char **argv)
|
int main(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
|
b_set_error_report_function(
|
||||||
|
b_enhanced_error_reporter,
|
||||||
|
B_ERROR_REPORT_ALL);
|
||||||
return b_command_dispatch(CMD_ROOT, argc, argv);
|
return b_command_dispatch(CMD_ROOT, argc, argv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
file(GLOB sources *.c *.h)
|
file(GLOB_RECURSE sources *.c *.h)
|
||||||
|
|
||||||
add_executable(ropkg ${sources})
|
add_executable(ropkg ${sources})
|
||||||
target_link_libraries(ropkg
|
target_link_libraries(ropkg
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
#include "commands.h"
|
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
OPT_OUTPATH,
|
|
||||||
OPT_OUTPATH_PATH,
|
|
||||||
|
|
||||||
ARG_RECIPE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int build(
|
|
||||||
const b_command *self,
|
|
||||||
const b_arglist *opt,
|
|
||||||
const b_array *args)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
B_COMMAND(CMD_BUILD, CMD_ROOT)
|
|
||||||
{
|
|
||||||
B_COMMAND_NAME("build");
|
|
||||||
B_COMMAND_SHORT_NAME('B');
|
|
||||||
B_COMMAND_DESC("build a Rosetta package from a recipe");
|
|
||||||
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
|
||||||
B_COMMAND_FUNCTION(build);
|
|
||||||
|
|
||||||
B_COMMAND_HELP_OPTION();
|
|
||||||
|
|
||||||
B_COMMAND_OPTION(OPT_OUTPATH)
|
|
||||||
{
|
|
||||||
B_OPTION_SHORT_NAME('o');
|
|
||||||
B_OPTION_LONG_NAME("out");
|
|
||||||
B_OPTION_DESC("the path to save the new package file to");
|
|
||||||
|
|
||||||
B_OPTION_ARG(OPT_OUTPATH_PATH)
|
|
||||||
{
|
|
||||||
B_ARG_NAME("path");
|
|
||||||
B_ARG_NR_VALUES(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
B_COMMAND_ARG(ARG_RECIPE)
|
|
||||||
{
|
|
||||||
B_ARG_NAME("recipe");
|
|
||||||
B_ARG_DESC("the recipe to build the package from.");
|
|
||||||
B_ARG_NR_VALUES(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
B_COMMAND_USAGE()
|
|
||||||
{
|
|
||||||
B_COMMAND_USAGE_OPT(OPT_OUTPATH);
|
|
||||||
B_COMMAND_USAGE_ARG(ARG_RECIPE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,12 +3,29 @@
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
CMD_ROOT,
|
CMD_ROOT,
|
||||||
CMD_CREATE,
|
|
||||||
CMD_BUILD,
|
CMD_PACKAGE,
|
||||||
CMD_QUERY,
|
CMD_PACKAGE_CREATE,
|
||||||
CMD_EXTRACT,
|
CMD_PACKAGE_BUILD,
|
||||||
CMD_INSTALL,
|
CMD_PACKAGE_EXTRACT,
|
||||||
CMD_COMPARE_VERSION,
|
CMD_PACKAGE_INSTALL,
|
||||||
|
|
||||||
|
CMD_PACKAGE_QUERY,
|
||||||
|
CMD_PACKAGE_QUERY_README,
|
||||||
|
CMD_PACKAGE_QUERY_MANIFEST,
|
||||||
|
CMD_PACKAGE_QUERY_SUMMARY,
|
||||||
|
CMD_PACKAGE_QUERY_LIST,
|
||||||
|
|
||||||
|
CMD_VERSION,
|
||||||
|
CMD_VERSION_COMPARE,
|
||||||
|
|
||||||
|
CMD_MANIFEST,
|
||||||
|
CMD_MANIFEST_CREATE,
|
||||||
|
CMD_MANIFEST_VALIDATE,
|
||||||
|
|
||||||
|
CMD_NEWS,
|
||||||
|
CMD_NEWS_CREATE,
|
||||||
|
CMD_NEWS_VALIDATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
14
ropkg/main.c
14
ropkg/main.c
@@ -1,19 +1,29 @@
|
|||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/term/print.h>
|
||||||
|
|
||||||
B_COMMAND(CMD_ROOT, B_COMMAND_INVALID_ID)
|
B_COMMAND(CMD_ROOT, B_COMMAND_INVALID_ID)
|
||||||
{
|
{
|
||||||
B_COMMAND_NAME("ropkg");
|
B_COMMAND_NAME("ropkg");
|
||||||
B_COMMAND_DESC(
|
B_COMMAND_DESC(
|
||||||
"Rosetta package manipulation tool. This tool is used to "
|
"Rosetta package manipulation tool. This tool is used to "
|
||||||
"create, build, and otherwise manipulate individual Rosetta "
|
"create, build, and otherwise manipulate individual Rosetta "
|
||||||
"package files.");
|
"package files.");
|
||||||
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
B_COMMAND_HELP_OPTION();
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_COMMAND_PLACEHOLDER();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv)
|
int main(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
|
b_set_error_report_function(
|
||||||
|
b_enhanced_error_reporter,
|
||||||
|
B_ERROR_REPORT_ALL);
|
||||||
return b_command_dispatch(CMD_ROOT, argc, argv);
|
return b_command_dispatch(CMD_ROOT, argc, argv);
|
||||||
}
|
}
|
||||||
|
|||||||
106
ropkg/manifest/create.c
Normal file
106
ropkg/manifest/create.c
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include "../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <ropkg/pkg-expr.h>
|
||||||
|
#include <ropkg/version.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPT_HEADERS,
|
||||||
|
OPT_HEADERS_PATH,
|
||||||
|
OPT_README,
|
||||||
|
OPT_README_PATH,
|
||||||
|
OPT_OUTPATH,
|
||||||
|
OPT_OUTPATH_PATH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int create(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
const char *headers_path = NULL, *readme_path = NULL, *out_path = NULL;
|
||||||
|
b_status status = b_arglist_get_string(
|
||||||
|
opt,
|
||||||
|
OPT_HEADERS,
|
||||||
|
OPT_HEADERS_PATH,
|
||||||
|
0,
|
||||||
|
&headers_path);
|
||||||
|
if (!B_OK(status)) {
|
||||||
|
b_arglist_report_missing_option(opt, OPT_HEADERS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = b_arglist_get_string(
|
||||||
|
opt,
|
||||||
|
OPT_README,
|
||||||
|
OPT_README_PATH,
|
||||||
|
0,
|
||||||
|
&headers_path);
|
||||||
|
if (!B_OK(status)) {
|
||||||
|
b_arglist_report_missing_option(opt, OPT_README);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_arglist_get_string(opt, OPT_OUTPATH, OPT_OUTPATH_PATH, 0, &out_path);
|
||||||
|
|
||||||
|
FILE *headers, *readme, *out;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_MANIFEST_CREATE, CMD_MANIFEST)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("create");
|
||||||
|
B_COMMAND_SHORT_NAME('C');
|
||||||
|
B_COMMAND_DESC("create a manifest file.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(create);
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_HEADERS)
|
||||||
|
{
|
||||||
|
B_OPTION_LONG_NAME("headers");
|
||||||
|
B_OPTION_SHORT_NAME('H');
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"The path to a json file describing the package "
|
||||||
|
"manifest headers.");
|
||||||
|
|
||||||
|
B_OPTION_ARG(OPT_HEADERS_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("path");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_README)
|
||||||
|
{
|
||||||
|
B_OPTION_LONG_NAME("readme");
|
||||||
|
B_OPTION_SHORT_NAME('R');
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"The path to a plaintext file describing the package.");
|
||||||
|
|
||||||
|
B_OPTION_ARG(OPT_README_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("path");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_OUTPATH)
|
||||||
|
{
|
||||||
|
B_OPTION_LONG_NAME("out");
|
||||||
|
B_OPTION_SHORT_NAME('o');
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"The path to write the new manifest file to. If no "
|
||||||
|
"path is specified, the manifest will be written to "
|
||||||
|
"standard out.");
|
||||||
|
|
||||||
|
B_OPTION_ARG(OPT_OUTPATH_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("path");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
ropkg/manifest/root.c
Normal file
19
ropkg/manifest/root.c
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/term/print.h>
|
||||||
|
|
||||||
|
B_COMMAND(CMD_MANIFEST, CMD_ROOT)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("manifest");
|
||||||
|
B_COMMAND_SHORT_NAME('M');
|
||||||
|
B_COMMAND_DESC("Package manifest inspection and manipulation.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_COMMAND_PLACEHOLDER();
|
||||||
|
}
|
||||||
|
}
|
||||||
307
ropkg/manifest/validate.c
Normal file
307
ropkg/manifest/validate.c
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
#include "../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <ropkg/manifest.h>
|
||||||
|
#include <ropkg/pkg-expr.h>
|
||||||
|
#include <ropkg/status.h>
|
||||||
|
#include <ropkg/version.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_MANIFEST
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print_pkg_expr(const struct ropkg_pkg_expr *expr);
|
||||||
|
|
||||||
|
static void print_pkg_expr_and(const struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
const struct ropkg_pkg_expr_and *expr_and
|
||||||
|
= (const struct ropkg_pkg_expr_and *)expr;
|
||||||
|
const struct ropkg_pkg_expr *cur
|
||||||
|
= ropkg_pkg_expr_and_get_left_node(expr_and);
|
||||||
|
|
||||||
|
printf("(");
|
||||||
|
print_pkg_expr(cur);
|
||||||
|
printf(")");
|
||||||
|
|
||||||
|
printf(" AND ");
|
||||||
|
|
||||||
|
cur = ropkg_pkg_expr_and_get_right_node(expr_and);
|
||||||
|
printf("(");
|
||||||
|
print_pkg_expr(cur);
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_pkg_expr_or(const struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
const struct ropkg_pkg_expr_or *expr_or
|
||||||
|
= (const struct ropkg_pkg_expr_or *)expr;
|
||||||
|
const struct ropkg_pkg_expr *cur
|
||||||
|
= ropkg_pkg_expr_or_get_left_node(expr_or);
|
||||||
|
|
||||||
|
printf("(");
|
||||||
|
print_pkg_expr(cur);
|
||||||
|
printf(")");
|
||||||
|
|
||||||
|
printf(" OR ");
|
||||||
|
|
||||||
|
cur = ropkg_pkg_expr_or_get_right_node(expr_or);
|
||||||
|
printf("(");
|
||||||
|
print_pkg_expr(cur);
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_pkg_expr_pkg(const struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
const struct ropkg_pkg_expr_pkg *pkg
|
||||||
|
= (const struct ropkg_pkg_expr_pkg *)expr;
|
||||||
|
printf("%s", ropkg_pkg_expr_pkg_get_name(pkg));
|
||||||
|
|
||||||
|
const struct ropkg_version *version
|
||||||
|
= ropkg_pkg_expr_pkg_get_version(pkg);
|
||||||
|
if (version) {
|
||||||
|
char s[128];
|
||||||
|
ropkg_version_to_string(version, s, sizeof s);
|
||||||
|
|
||||||
|
printf("[");
|
||||||
|
|
||||||
|
switch (ropkg_pkg_expr_pkg_get_version_predicate(pkg)) {
|
||||||
|
case ROPKG_OP_LESS_THAN:
|
||||||
|
printf("<");
|
||||||
|
break;
|
||||||
|
case ROPKG_OP_LESS_EQUAL:
|
||||||
|
printf("<=");
|
||||||
|
break;
|
||||||
|
case ROPKG_OP_GREATER_THAN:
|
||||||
|
printf(">");
|
||||||
|
break;
|
||||||
|
case ROPKG_OP_GREATER_EQUAL:
|
||||||
|
printf(">=");
|
||||||
|
break;
|
||||||
|
case ROPKG_OP_EQUAL:
|
||||||
|
printf("=");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s", s);
|
||||||
|
|
||||||
|
printf("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_pkg_expr(const struct ropkg_pkg_expr *expr)
|
||||||
|
{
|
||||||
|
enum ropkg_pkg_expr_type type = ropkg_pkg_expr_get_type(expr);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ROPKG_PKG_EXPR_NODE_PKG:
|
||||||
|
print_pkg_expr_pkg(expr);
|
||||||
|
break;
|
||||||
|
case ROPKG_PKG_EXPR_NODE_AND:
|
||||||
|
print_pkg_expr_and(expr);
|
||||||
|
break;
|
||||||
|
case ROPKG_PKG_EXPR_NODE_OR:
|
||||||
|
print_pkg_expr_or(expr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result validate_pkg_expr_value(
|
||||||
|
const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
const char *value_str = ropkg_manifest_value_get_string(value);
|
||||||
|
if (!value_str) {
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_MANIFEST_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_pkg_expr *pkg_expr = NULL;
|
||||||
|
b_result result = ropkg_pkg_expr_parse(value_str, &pkg_expr);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
return b_result_propagate(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pkg_expr(pkg_expr);
|
||||||
|
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result validate_version_value(const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
const char *value_str = ropkg_manifest_value_get_string(value);
|
||||||
|
if (!value_str) {
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_MANIFEST_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_version *version = NULL;
|
||||||
|
enum ropkg_status status = ropkg_version_create(&version);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return b_error_with_code(ROPKG_ERROR_VENDOR, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result result = ropkg_version_parse(version, value_str);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
return b_result_propagate(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
char temp[128];
|
||||||
|
ropkg_version_to_string(version, temp, sizeof temp);
|
||||||
|
ropkg_version_destroy(version);
|
||||||
|
|
||||||
|
printf("%s", temp);
|
||||||
|
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result validate_string_value(const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
const char *value_str = ropkg_manifest_value_get_string(value);
|
||||||
|
if (!value_str) {
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_MANIFEST_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s", value_str);
|
||||||
|
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_result validate_int_value(const struct ropkg_manifest_value *value)
|
||||||
|
{
|
||||||
|
if (ropkg_manifest_value_get_type(value)
|
||||||
|
!= ROPKG_MANIFEST_VALUE_T_INT) {
|
||||||
|
return b_error_with_code(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_INVALID_MANIFEST_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%zu", ropkg_manifest_value_get_int(value));
|
||||||
|
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
return B_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int validate(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
const char *manifest_path;
|
||||||
|
b_status status = b_arglist_get_string(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_MANIFEST,
|
||||||
|
0,
|
||||||
|
&manifest_path);
|
||||||
|
if (!B_OK(status)) {
|
||||||
|
b_arglist_report_missing_args(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_MANIFEST,
|
||||||
|
0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *fp = fopen(manifest_path, "r");
|
||||||
|
if (!fp) {
|
||||||
|
b_throw_error_code(ROPKG_ERROR_VENDOR, ROPKG_ERR_NO_ENTRY);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_manifest *manifest;
|
||||||
|
enum ropkg_status status2 = ropkg_manifest_create(&manifest);
|
||||||
|
if (status2 != ROPKG_SUCCESS) {
|
||||||
|
b_throw_error_code(ROPKG_ERROR_VENDOR, status2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result result = ropkg_manifest_parse(fp, manifest);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
b_throw(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_manifest_value *value
|
||||||
|
= ropkg_manifest_get_first_value(manifest);
|
||||||
|
while (value && b_result_is_success(result)) {
|
||||||
|
const char *name = ropkg_manifest_value_get_name(value);
|
||||||
|
enum ropkg_manifest_value_type type
|
||||||
|
= ropkg_manifest_value_get_type(value);
|
||||||
|
enum ropkg_manifest_value_id id
|
||||||
|
= ropkg_manifest_value_get_id(value);
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
printf("%s ", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id != ROPKG_MANIFEST_VALUE_N_NONE) {
|
||||||
|
printf("[%d] ", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(": ");
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_DEPENDS:
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_PROVIDES:
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_RECOMMENDS:
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_SUGGESTS:
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_CONFLICTS:
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_ENHANCES:
|
||||||
|
result = validate_pkg_expr_value(value);
|
||||||
|
break;
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_INSTALLED_SIZE:
|
||||||
|
result = validate_int_value(value);
|
||||||
|
break;
|
||||||
|
case ROPKG_MANIFEST_VALUE_N_VERSION:
|
||||||
|
result = validate_version_value(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = validate_string_value(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
value = ropkg_manifest_get_next_value(manifest, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
b_throw(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_MANIFEST_VALIDATE, CMD_MANIFEST)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("validate");
|
||||||
|
B_COMMAND_SHORT_NAME('V');
|
||||||
|
B_COMMAND_DESC("check a manifest file for errors.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(validate);
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_MANIFEST)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("manifest-path");
|
||||||
|
B_ARG_DESC("the manifest file to validate");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_ARG(ARG_MANIFEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
ropkg/news/root.c
Normal file
19
ropkg/news/root.c
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/term/print.h>
|
||||||
|
|
||||||
|
B_COMMAND(CMD_NEWS, CMD_ROOT)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("news");
|
||||||
|
B_COMMAND_SHORT_NAME('N');
|
||||||
|
B_COMMAND_DESC("News file inspection and manipulation.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_COMMAND_PLACEHOLDER();
|
||||||
|
}
|
||||||
|
}
|
||||||
102
ropkg/package/build.c
Normal file
102
ropkg/package/build.c
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include "../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPT_OUTPATH,
|
||||||
|
OPT_OUTPATH_PATH,
|
||||||
|
|
||||||
|
OPT_SOURCE_DIRECTORY,
|
||||||
|
OPT_SOURCE_DIRECTORY_PATH,
|
||||||
|
|
||||||
|
OPT_EXT_SOURCE_DIRECTORY,
|
||||||
|
OPT_EXT_SOURCE_DIRECTORY_NAME,
|
||||||
|
OPT_EXT_SOURCE_DIRECTORY_PATH,
|
||||||
|
|
||||||
|
ARG_RECIPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int build(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_PACKAGE_BUILD, CMD_PACKAGE)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("build");
|
||||||
|
B_COMMAND_SHORT_NAME('B');
|
||||||
|
B_COMMAND_DESC("build a Rosetta package from a recipe");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(build);
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_OUTPATH)
|
||||||
|
{
|
||||||
|
B_OPTION_SHORT_NAME('o');
|
||||||
|
B_OPTION_LONG_NAME("out");
|
||||||
|
B_OPTION_DESC("the path to save the new package file to");
|
||||||
|
|
||||||
|
B_OPTION_ARG(OPT_OUTPATH_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("path");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_SOURCE_DIRECTORY)
|
||||||
|
{
|
||||||
|
B_OPTION_SHORT_NAME('s');
|
||||||
|
B_OPTION_LONG_NAME("source-dir");
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"the source directory to build the package from. if no "
|
||||||
|
"source directory is specified, the recipe will "
|
||||||
|
"download the sources automatically.");
|
||||||
|
|
||||||
|
B_OPTION_ARG(OPT_SOURCE_DIRECTORY_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("path");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_EXT_SOURCE_DIRECTORY)
|
||||||
|
{
|
||||||
|
B_OPTION_SHORT_NAME('S');
|
||||||
|
B_OPTION_LONG_NAME("named-source-dir");
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"a source directory to build the package from. if no "
|
||||||
|
"source directory is specified, the recipe will "
|
||||||
|
"download the sources automatically. use this option "
|
||||||
|
"if the recipe requires more than one separate source "
|
||||||
|
"directory.");
|
||||||
|
|
||||||
|
B_OPTION_ARG(OPT_EXT_SOURCE_DIRECTORY_NAME)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("name");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_OPTION_ARG(OPT_EXT_SOURCE_DIRECTORY_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("path");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_RECIPE)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("recipe");
|
||||||
|
B_ARG_DESC("the recipe to build the package from.");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_OPT(OPT_OUTPATH);
|
||||||
|
B_COMMAND_USAGE_ARG(ARG_RECIPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
#include "commands.h"
|
#include "../commands.h"
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/compress/cstream.h>
|
||||||
|
#include <blue/compress/function.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
#include <blue/io/directory.h>
|
#include <blue/io/directory.h>
|
||||||
#include <blue/term/print.h>
|
#include <blue/term/print.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ropkg/compress.h>
|
#include <ropkg/manifest.h>
|
||||||
#include <ropkg/stream.h>
|
|
||||||
#include <ropkg/writer.h>
|
#include <ropkg/writer.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -41,14 +43,17 @@ static int add_file_to_archive_ex(
|
|||||||
const char *dest)
|
const char *dest)
|
||||||
{
|
{
|
||||||
b_file *fp;
|
b_file *fp;
|
||||||
b_status status = b_file_open(
|
b_result result = b_file_open(
|
||||||
src_dir,
|
src_dir,
|
||||||
src,
|
src,
|
||||||
B_FILE_READ_ONLY | B_FILE_BINARY,
|
B_FILE_READ_ONLY | B_FILE_BINARY,
|
||||||
&fp);
|
&fp);
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
b_err("cannot open file '%s'", src);
|
b_throw_error_with_template_caused_by_error(
|
||||||
b_i("reason: %s", b_status_to_string(status));
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||||
|
result,
|
||||||
|
B_ERROR_PARAM("filepath", b_path_ptr(src)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +68,7 @@ static int add_file_to_archive_ex(
|
|||||||
int c;
|
int c;
|
||||||
while (1) {
|
while (1) {
|
||||||
size_t r;
|
size_t r;
|
||||||
status = b_file_read(fp, offset, sizeof buf, buf, &r);
|
b_status status = b_file_read(fp, offset, sizeof buf, buf, &r);
|
||||||
if (!B_OK(status)) {
|
if (!B_OK(status)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -97,7 +102,7 @@ static int add_file_to_archive(
|
|||||||
|
|
||||||
static int add_data_archive(
|
static int add_data_archive(
|
||||||
const b_arglist *args,
|
const b_arglist *args,
|
||||||
struct ropkg_stream *stream,
|
struct b_cstream *stream,
|
||||||
struct ropkg_writer *pkg)
|
struct ropkg_writer *pkg)
|
||||||
{
|
{
|
||||||
const char *data_path_cstr;
|
const char *data_path_cstr;
|
||||||
@@ -108,16 +113,23 @@ static int add_data_archive(
|
|||||||
0,
|
0,
|
||||||
&data_path_cstr);
|
&data_path_cstr);
|
||||||
if (!B_OK(bstatus)) {
|
if (!B_OK(bstatus)) {
|
||||||
b_arglist_report_missing_option(args, OPT_MANIFEST);
|
b_arglist_report_missing_args(
|
||||||
|
args,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_SOURCE_DIR,
|
||||||
|
0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
b_path *data_path = b_path_create_from_cstr(data_path_cstr);
|
b_path *data_path = b_path_create_from_cstr(data_path_cstr);
|
||||||
b_directory *data_dir;
|
b_directory *data_dir;
|
||||||
bstatus = b_directory_open(NULL, data_path, &data_dir);
|
b_result result = b_directory_open(NULL, data_path, 0, &data_dir);
|
||||||
if (!B_OK(bstatus)) {
|
if (b_result_is_error(result)) {
|
||||||
b_err("cannot open directory '%s'", data_path_cstr);
|
b_throw_error_with_template_caused_by_error(
|
||||||
b_i("reason: %s", b_status_to_string(bstatus));
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||||
|
result,
|
||||||
|
B_ERROR_PARAM("filepath", data_path_cstr));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +137,7 @@ static int add_data_archive(
|
|||||||
struct ropkg_writer_file_info file = {0};
|
struct ropkg_writer_file_info file = {0};
|
||||||
ropkg_writer_begin_file(pkg, ROPKG_PATH_DATA ".zst", &file);
|
ropkg_writer_begin_file(pkg, ROPKG_PATH_DATA ".zst", &file);
|
||||||
|
|
||||||
ropkg_stream_begin_compressed_section(stream);
|
b_cstream_begin_compressed_section(stream, NULL);
|
||||||
enum ropkg_status status = ropkg_writer_open(stream, &data);
|
enum ropkg_status status = ropkg_writer_open(stream, &data);
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -148,7 +160,7 @@ static int add_data_archive(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ropkg_writer_close(data);
|
ropkg_writer_close(data);
|
||||||
ropkg_stream_end_compressed_section(stream, NULL, NULL);
|
b_cstream_end_compressed_section(stream, NULL, NULL);
|
||||||
ropkg_writer_end_file(pkg);
|
ropkg_writer_end_file(pkg);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -156,7 +168,7 @@ static int add_data_archive(
|
|||||||
|
|
||||||
static int add_control_archive(
|
static int add_control_archive(
|
||||||
const b_arglist *args,
|
const b_arglist *args,
|
||||||
struct ropkg_stream *stream,
|
b_cstream *stream,
|
||||||
struct ropkg_writer *pkg)
|
struct ropkg_writer *pkg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -165,7 +177,7 @@ static int add_control_archive(
|
|||||||
struct ropkg_writer_file_info file = {0};
|
struct ropkg_writer_file_info file = {0};
|
||||||
ropkg_writer_begin_file(pkg, ROPKG_PATH_CONTROL ".zst", &file);
|
ropkg_writer_begin_file(pkg, ROPKG_PATH_CONTROL ".zst", &file);
|
||||||
|
|
||||||
ropkg_stream_begin_compressed_section(stream);
|
b_cstream_begin_compressed_section(stream, NULL);
|
||||||
enum ropkg_status status = ropkg_writer_open(stream, &control);
|
enum ropkg_status status = ropkg_writer_open(stream, &control);
|
||||||
|
|
||||||
b_arglist_option_iterator it;
|
b_arglist_option_iterator it;
|
||||||
@@ -188,16 +200,40 @@ static int add_control_archive(
|
|||||||
|
|
||||||
ropkg_writer_close(control);
|
ropkg_writer_close(control);
|
||||||
|
|
||||||
ropkg_stream_end_compressed_section(stream, NULL, NULL);
|
b_cstream_end_compressed_section(stream, NULL, NULL);
|
||||||
|
|
||||||
ropkg_writer_end_file(pkg);
|
ropkg_writer_end_file(pkg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static b_result validate_manifest(const char *path)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen(path, "r");
|
||||||
|
if (!fp) {
|
||||||
|
return b_error_with_template(
|
||||||
|
ROPKG_ERROR_VENDOR,
|
||||||
|
ROPKG_ERR_FILE_OPEN_FAILED,
|
||||||
|
B_ERROR_PARAM("filepath", path));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_manifest *manifest;
|
||||||
|
enum ropkg_status status = ropkg_manifest_create(&manifest);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return b_error_with_code(ROPKG_ERROR_VENDOR, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_result result = ropkg_manifest_parse(fp, manifest);
|
||||||
|
|
||||||
|
ropkg_manifest_destroy(manifest);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return b_result_propagate(result);
|
||||||
|
}
|
||||||
|
|
||||||
static int add_meta_archive(
|
static int add_meta_archive(
|
||||||
const b_arglist *args,
|
const b_arglist *args,
|
||||||
struct ropkg_stream *stream,
|
b_cstream *stream,
|
||||||
struct ropkg_writer *pkg)
|
struct ropkg_writer *pkg)
|
||||||
{
|
{
|
||||||
const char *manifest_path, *news_path;
|
const char *manifest_path, *news_path;
|
||||||
@@ -205,20 +241,26 @@ static int add_meta_archive(
|
|||||||
args,
|
args,
|
||||||
OPT_MANIFEST,
|
OPT_MANIFEST,
|
||||||
OPT_MANIFEST_PATH,
|
OPT_MANIFEST_PATH,
|
||||||
1,
|
0,
|
||||||
&manifest_path);
|
&manifest_path);
|
||||||
if (!B_OK(bstatus)) {
|
if (!B_OK(bstatus)) {
|
||||||
b_arglist_report_missing_option(args, OPT_MANIFEST);
|
b_arglist_report_missing_option(args, OPT_MANIFEST);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b_result result = validate_manifest(manifest_path);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
b_throw(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
struct ropkg_writer *meta;
|
struct ropkg_writer *meta;
|
||||||
struct ropkg_writer_file_info file = {0};
|
struct ropkg_writer_file_info file = {0};
|
||||||
ropkg_writer_begin_file(pkg, ROPKG_PATH_META ".zst", &file);
|
ropkg_writer_begin_file(pkg, ROPKG_PATH_META ".zst", &file);
|
||||||
|
|
||||||
ropkg_stream_begin_compressed_section(stream);
|
b_cstream_begin_compressed_section(stream, NULL);
|
||||||
enum ropkg_status status = ropkg_writer_open(stream, &meta);
|
enum ropkg_status status = ropkg_writer_open(stream, &meta);
|
||||||
|
|
||||||
bstatus = b_arglist_get_string(
|
bstatus = b_arglist_get_string(
|
||||||
@@ -243,7 +285,7 @@ static int add_meta_archive(
|
|||||||
|
|
||||||
ropkg_writer_close(meta);
|
ropkg_writer_close(meta);
|
||||||
|
|
||||||
ropkg_stream_end_compressed_section(stream, NULL, NULL);
|
b_cstream_end_compressed_section(stream, NULL, NULL);
|
||||||
|
|
||||||
ropkg_writer_end_file(pkg);
|
ropkg_writer_end_file(pkg);
|
||||||
|
|
||||||
@@ -255,8 +297,8 @@ static int create(
|
|||||||
const b_arglist *opt,
|
const b_arglist *opt,
|
||||||
const b_array *args)
|
const b_array *args)
|
||||||
{
|
{
|
||||||
const struct ropkg_compression_function *zstd
|
const b_compression_function *zstd
|
||||||
= ropkg_compression_function_for_type(ROPKG_COMPRESSION_ZSTD);
|
= b_compression_function_get_by_id(B_COMPRESSOR_FUNCTION_ZSTD);
|
||||||
struct ropkg_writer *pkg, *subpkg;
|
struct ropkg_writer *pkg, *subpkg;
|
||||||
enum ropkg_status status;
|
enum ropkg_status status;
|
||||||
|
|
||||||
@@ -265,7 +307,7 @@ static int create(
|
|||||||
opt,
|
opt,
|
||||||
OPT_OUTPATH,
|
OPT_OUTPATH,
|
||||||
OPT_OUTPATH_PATH,
|
OPT_OUTPATH_PATH,
|
||||||
1,
|
0,
|
||||||
&out_path);
|
&out_path);
|
||||||
if (!B_OK(bstatus)) {
|
if (!B_OK(bstatus)) {
|
||||||
b_arglist_report_missing_option(opt, OPT_OUTPATH);
|
b_arglist_report_missing_option(opt, OPT_OUTPATH);
|
||||||
@@ -273,37 +315,45 @@ static int create(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILE *fp = fopen(out_path, "wb");
|
FILE *fp = fopen(out_path, "wb");
|
||||||
struct ropkg_stream *stream;
|
b_stream *fp_stream = b_stream_open_fp(fp);
|
||||||
status = ropkg_stream_open(fp, zstd, ROPKG_STREAM_WRITE, &stream);
|
b_cstream *cstream;
|
||||||
|
bstatus = b_cstream_open(
|
||||||
|
fp_stream,
|
||||||
|
zstd,
|
||||||
|
B_COMPRESSION_MODE_COMPRESS,
|
||||||
|
&cstream);
|
||||||
|
|
||||||
status = ropkg_writer_open(stream, &pkg);
|
status = ropkg_writer_open(cstream, &pkg);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = add_data_archive(opt, stream, pkg);
|
ret = add_data_archive(opt, cstream, pkg);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = add_control_archive(opt, stream, pkg);
|
ret = add_control_archive(opt, cstream, pkg);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = add_meta_archive(opt, stream, pkg);
|
ret = add_meta_archive(opt, cstream, pkg);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
ropkg_writer_close(pkg);
|
ropkg_writer_close(pkg);
|
||||||
ropkg_stream_close(stream);
|
|
||||||
|
b_cstream_close(cstream);
|
||||||
|
b_stream_close(fp_stream);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
B_COMMAND(CMD_CREATE, CMD_ROOT)
|
B_COMMAND(CMD_PACKAGE_CREATE, CMD_PACKAGE)
|
||||||
{
|
{
|
||||||
B_COMMAND_NAME("create");
|
B_COMMAND_NAME("create");
|
||||||
B_COMMAND_SHORT_NAME('C');
|
B_COMMAND_SHORT_NAME('C');
|
||||||
@@ -376,7 +426,8 @@ B_COMMAND(CMD_CREATE, CMD_ROOT)
|
|||||||
B_OPTION_SHORT_NAME('s');
|
B_OPTION_SHORT_NAME('s');
|
||||||
B_OPTION_LONG_NAME("script");
|
B_OPTION_LONG_NAME("script");
|
||||||
B_OPTION_DESC(
|
B_OPTION_DESC(
|
||||||
"a control script to be run at a certain point in the "
|
"a control script to be run at a certain point "
|
||||||
|
"in the "
|
||||||
"package (un)installation process.");
|
"package (un)installation process.");
|
||||||
|
|
||||||
B_OPTION_ARG(OPT_SCRIPT_NAME)
|
B_OPTION_ARG(OPT_SCRIPT_NAME)
|
||||||
@@ -402,10 +453,13 @@ B_COMMAND(CMD_CREATE, CMD_ROOT)
|
|||||||
B_OPTION_SHORT_NAME('p');
|
B_OPTION_SHORT_NAME('p');
|
||||||
B_OPTION_LONG_NAME("parameter");
|
B_OPTION_LONG_NAME("parameter");
|
||||||
B_OPTION_DESC(
|
B_OPTION_DESC(
|
||||||
"a parameter to use when creating the new file. "
|
"a parameter to use when creating the new "
|
||||||
"if a parameter EXAMPLE is defined, any variable "
|
"file. "
|
||||||
|
"if a parameter EXAMPLE is defined, any "
|
||||||
|
"variable "
|
||||||
"reference "
|
"reference "
|
||||||
"of the form ${EXAMPLE} in the package manifest will "
|
"of the form ${EXAMPLE} in the package "
|
||||||
|
"manifest will "
|
||||||
"be "
|
"be "
|
||||||
"replaced with the specified parameter value.");
|
"replaced with the specified parameter value.");
|
||||||
|
|
||||||
@@ -426,8 +480,10 @@ B_COMMAND(CMD_CREATE, CMD_ROOT)
|
|||||||
{
|
{
|
||||||
B_ARG_NAME("source-dir");
|
B_ARG_NAME("source-dir");
|
||||||
B_ARG_DESC(
|
B_ARG_DESC(
|
||||||
"the directory to package. the specified directory "
|
"the directory to package. the specified "
|
||||||
"will become the root of the newly created package.");
|
"directory "
|
||||||
|
"will become the root of the newly created "
|
||||||
|
"package.");
|
||||||
B_ARG_NR_VALUES(1);
|
B_ARG_NR_VALUES(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "commands.h"
|
#include "../commands.h"
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
#include <blue/cmd.h>
|
||||||
|
|
||||||
@@ -17,12 +17,12 @@ static int extract(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
B_COMMAND(CMD_EXTRACT, CMD_ROOT)
|
B_COMMAND(CMD_PACKAGE_EXTRACT, CMD_PACKAGE)
|
||||||
{
|
{
|
||||||
B_COMMAND_NAME("extract");
|
B_COMMAND_NAME("extract");
|
||||||
B_COMMAND_SHORT_NAME('X');
|
B_COMMAND_SHORT_NAME('X');
|
||||||
B_COMMAND_DESC("extract the contents of a Rosetta package");
|
B_COMMAND_DESC("extract the contents of a Rosetta package");
|
||||||
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
// B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
B_COMMAND_FUNCTION(extract);
|
B_COMMAND_FUNCTION(extract);
|
||||||
|
|
||||||
B_COMMAND_HELP_OPTION();
|
B_COMMAND_HELP_OPTION();
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "commands.h"
|
#include "../commands.h"
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
#include <blue/cmd.h>
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ static int install(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
B_COMMAND(CMD_INSTALL, CMD_ROOT)
|
B_COMMAND(CMD_PACKAGE_INSTALL, CMD_PACKAGE)
|
||||||
{
|
{
|
||||||
B_COMMAND_NAME("install");
|
B_COMMAND_NAME("install");
|
||||||
B_COMMAND_SHORT_NAME('I');
|
B_COMMAND_SHORT_NAME('I');
|
||||||
193
ropkg/package/query/list.c
Normal file
193
ropkg/package/query/list.c
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
#include "../../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/compress/cstream.h>
|
||||||
|
#include <blue/compress/function.h>
|
||||||
|
#include <blue/core/bitop.h>
|
||||||
|
#include <ropkg/manifest.h>
|
||||||
|
#include <ropkg/reader.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPT_DATA = 0x01u,
|
||||||
|
OPT_META = 0x02u,
|
||||||
|
OPT_CONTROL = 0x04u,
|
||||||
|
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int print_file_list(
|
||||||
|
int section,
|
||||||
|
bool show_header,
|
||||||
|
struct ropkg_reader *pkg)
|
||||||
|
{
|
||||||
|
if (show_header) {
|
||||||
|
switch (section) {
|
||||||
|
case OPT_DATA:
|
||||||
|
printf("data:\n");
|
||||||
|
break;
|
||||||
|
case OPT_META:
|
||||||
|
printf("meta:\n");
|
||||||
|
break;
|
||||||
|
case OPT_CONTROL:
|
||||||
|
printf("control:\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status status = ROPKG_SUCCESS;
|
||||||
|
|
||||||
|
while (!ropkg_reader_eof(pkg)) {
|
||||||
|
if (show_header) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_file_info *file
|
||||||
|
= ropkg_reader_current_file(pkg);
|
||||||
|
printf("%s\n", file->f_filename);
|
||||||
|
status = ropkg_reader_move_next(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int query_list(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
const b_compression_function *zstd
|
||||||
|
= b_compression_function_get_by_id(B_COMPRESSOR_FUNCTION_ZSTD);
|
||||||
|
struct ropkg_reader *pkg;
|
||||||
|
enum ropkg_status status;
|
||||||
|
|
||||||
|
const char *in_path;
|
||||||
|
b_status bstatus = b_arglist_get_string(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
0,
|
||||||
|
&in_path);
|
||||||
|
if (!B_OK(bstatus)) {
|
||||||
|
b_arglist_report_missing_args(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sections = 0;
|
||||||
|
if (b_arglist_get_count(opt, OPT_DATA, B_COMMAND_INVALID_ID) > 0) {
|
||||||
|
sections |= OPT_DATA;
|
||||||
|
}
|
||||||
|
if (b_arglist_get_count(opt, OPT_META, B_COMMAND_INVALID_ID) > 0) {
|
||||||
|
sections |= OPT_META;
|
||||||
|
}
|
||||||
|
if (b_arglist_get_count(opt, OPT_CONTROL, B_COMMAND_INVALID_ID) > 0) {
|
||||||
|
sections |= OPT_CONTROL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sections == 0) {
|
||||||
|
sections = OPT_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool show_headers = b_popcountl(sections) > 1;
|
||||||
|
|
||||||
|
FILE *fp = fopen(in_path, "rb");
|
||||||
|
b_stream *fp_stream = b_stream_open_fp(fp);
|
||||||
|
b_cstream *cstream;
|
||||||
|
bstatus = b_cstream_open(
|
||||||
|
fp_stream,
|
||||||
|
zstd,
|
||||||
|
B_COMPRESSION_MODE_DECOMPRESS,
|
||||||
|
&cstream);
|
||||||
|
|
||||||
|
status = ropkg_reader_open(cstream, &pkg);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
printf("cannot open package\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!ropkg_reader_eof(pkg)) {
|
||||||
|
const struct ropkg_file_info *file
|
||||||
|
= ropkg_reader_current_file(pkg);
|
||||||
|
|
||||||
|
int section = -1;
|
||||||
|
if (!strncmp(file->f_filename, "data.tar", 8)) {
|
||||||
|
section = OPT_DATA;
|
||||||
|
} else if (!strncmp(file->f_filename, "meta.tar", 8)) {
|
||||||
|
section = OPT_META;
|
||||||
|
} else if (!strncmp(file->f_filename, "control.tar", 11)) {
|
||||||
|
section = OPT_CONTROL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section == -1 || (section & sections) != section) {
|
||||||
|
status = ropkg_reader_move_next(pkg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_reader *subpkg = NULL;
|
||||||
|
b_cstream_begin_compressed_section(cstream, NULL);
|
||||||
|
status = ropkg_reader_open(cstream, &subpkg);
|
||||||
|
print_file_list(section, show_headers, subpkg);
|
||||||
|
ropkg_reader_close(subpkg);
|
||||||
|
b_cstream_end_compressed_section(cstream, NULL, NULL);
|
||||||
|
|
||||||
|
status = ropkg_reader_move_next(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_PACKAGE_QUERY_LIST, CMD_PACKAGE_QUERY)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("list");
|
||||||
|
B_COMMAND_SHORT_NAME('L');
|
||||||
|
B_COMMAND_DESC("list the contents of a package");
|
||||||
|
B_COMMAND_FUNCTION(query_list);
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_PACKAGE_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("package");
|
||||||
|
B_ARG_DESC("the package to query.");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_DATA)
|
||||||
|
{
|
||||||
|
B_OPTION_SHORT_NAME('d');
|
||||||
|
B_OPTION_LONG_NAME("data");
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"list all data files contained within a "
|
||||||
|
"package. if no "
|
||||||
|
"options are specified, this behaviour is the "
|
||||||
|
"default.");
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_META)
|
||||||
|
{
|
||||||
|
B_OPTION_SHORT_NAME('m');
|
||||||
|
B_OPTION_LONG_NAME("meta");
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"list all metadata files contained within a "
|
||||||
|
"package.");
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_CONTROL)
|
||||||
|
{
|
||||||
|
B_OPTION_SHORT_NAME('c');
|
||||||
|
B_OPTION_LONG_NAME("control");
|
||||||
|
B_OPTION_DESC(
|
||||||
|
"list all control files contained within a "
|
||||||
|
"package.");
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_ARG(ARG_PACKAGE_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
ropkg/package/query/manifest.c
Normal file
38
ropkg/package/query/manifest.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "../../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int query_manifest(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_PACKAGE_QUERY_MANIFEST, CMD_PACKAGE_QUERY)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("manifest");
|
||||||
|
B_COMMAND_SHORT_NAME('M');
|
||||||
|
B_COMMAND_DESC("print the manifest of a package");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(query_manifest);
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_PACKAGE_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("package");
|
||||||
|
B_ARG_DESC("the package to query.");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_ARG(ARG_PACKAGE_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
ropkg/package/query/readme.c
Normal file
38
ropkg/package/query/readme.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "../../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int query_readme(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_PACKAGE_QUERY_README, CMD_PACKAGE_QUERY)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("readme");
|
||||||
|
B_COMMAND_SHORT_NAME('R');
|
||||||
|
B_COMMAND_DESC("print the readme of a package");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(query_readme);
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_PACKAGE_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("package");
|
||||||
|
B_ARG_DESC("the package to query.");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_ARG(ARG_PACKAGE_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
ropkg/package/query/root.c
Normal file
18
ropkg/package/query/root.c
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include "../../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
|
||||||
|
B_COMMAND(CMD_PACKAGE_QUERY, CMD_PACKAGE)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("query");
|
||||||
|
B_COMMAND_SHORT_NAME('Q');
|
||||||
|
B_COMMAND_DESC("query information about a Rosetta package");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_COMMAND_PLACEHOLDER();
|
||||||
|
}
|
||||||
|
}
|
||||||
99
ropkg/package/query/summary.c
Normal file
99
ropkg/package/query/summary.c
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "../../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/compress/cstream.h>
|
||||||
|
#include <blue/compress/function.h>
|
||||||
|
#include <blue/io/directory.h>
|
||||||
|
#include <ropkg/manifest.h>
|
||||||
|
#include <ropkg/package.h>
|
||||||
|
#include <ropkg/reader.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int query_summary(
|
||||||
|
const b_command *self,
|
||||||
|
const b_arglist *opt,
|
||||||
|
const b_array *args)
|
||||||
|
{
|
||||||
|
const b_compression_function *zstd
|
||||||
|
= b_compression_function_get_by_id(B_COMPRESSOR_FUNCTION_ZSTD);
|
||||||
|
struct ropkg_reader *pkg;
|
||||||
|
enum ropkg_status status;
|
||||||
|
|
||||||
|
const char *in_path;
|
||||||
|
b_status bstatus = b_arglist_get_string(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
0,
|
||||||
|
&in_path);
|
||||||
|
|
||||||
|
if (!B_OK(bstatus)) {
|
||||||
|
b_arglist_report_missing_args(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_PACKAGE_PATH,
|
||||||
|
0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *fp = fopen(in_path, "rb");
|
||||||
|
b_stream *fp_stream = b_stream_open_fp(fp);
|
||||||
|
b_cstream *cstream;
|
||||||
|
bstatus = b_cstream_open(
|
||||||
|
fp_stream,
|
||||||
|
zstd,
|
||||||
|
B_COMPRESSION_MODE_DECOMPRESS,
|
||||||
|
&cstream);
|
||||||
|
|
||||||
|
status = ropkg_reader_open(cstream, &pkg);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
printf("cannot open package\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_directory *dest;
|
||||||
|
b_directory_open(
|
||||||
|
NULL,
|
||||||
|
B_RV_PATH("data"),
|
||||||
|
B_DIRECTORY_OPEN_CREATE | B_DIRECTORY_OPEN_DELETE_ON_CLOSE,
|
||||||
|
&dest);
|
||||||
|
|
||||||
|
b_result result = ropkg_extract_metadata(pkg, dest);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
b_throw(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_directory_release(dest);
|
||||||
|
ropkg_reader_close(pkg);
|
||||||
|
b_cstream_close(cstream);
|
||||||
|
b_stream_close(fp_stream);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_PACKAGE_QUERY_SUMMARY, CMD_PACKAGE_QUERY)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("summary");
|
||||||
|
B_COMMAND_SHORT_NAME('S');
|
||||||
|
B_COMMAND_DESC("print a summary of information about a package");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(query_summary);
|
||||||
|
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_PACKAGE_PATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("package");
|
||||||
|
B_ARG_DESC("the package to query.");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_ARG(ARG_PACKAGE_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
ropkg/package/root.c
Normal file
19
ropkg/package/root.c
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/term/print.h>
|
||||||
|
|
||||||
|
B_COMMAND(CMD_PACKAGE, CMD_ROOT)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("package");
|
||||||
|
B_COMMAND_SHORT_NAME('P');
|
||||||
|
B_COMMAND_DESC("Package inspection and manipulation.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_COMMAND_PLACEHOLDER();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#include "commands.h"
|
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ARG_PACKAGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int query(
|
|
||||||
const b_command *self,
|
|
||||||
const b_arglist *opt,
|
|
||||||
const b_array *args)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
B_COMMAND(CMD_QUERY, CMD_ROOT)
|
|
||||||
{
|
|
||||||
B_COMMAND_NAME("query");
|
|
||||||
B_COMMAND_SHORT_NAME('Q');
|
|
||||||
B_COMMAND_DESC("query information about a Rosetta package");
|
|
||||||
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
|
||||||
B_COMMAND_FUNCTION(query);
|
|
||||||
|
|
||||||
B_COMMAND_HELP_OPTION();
|
|
||||||
|
|
||||||
B_COMMAND_ARG(ARG_PACKAGE)
|
|
||||||
{
|
|
||||||
B_ARG_NAME("package");
|
|
||||||
B_ARG_DESC("the package to query.");
|
|
||||||
B_ARG_NR_VALUES(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
B_COMMAND_USAGE()
|
|
||||||
{
|
|
||||||
B_COMMAND_USAGE_ARG(ARG_PACKAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "commands.h"
|
#include "../commands.h"
|
||||||
#include "ropkg/version.h"
|
#include "ropkg/version.h"
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
#include <blue/cmd.h>
|
||||||
@@ -175,9 +175,10 @@ end:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
B_COMMAND(CMD_COMPARE_VERSION, CMD_ROOT)
|
B_COMMAND(CMD_VERSION_COMPARE, CMD_VERSION)
|
||||||
{
|
{
|
||||||
B_COMMAND_NAME("compare-version");
|
B_COMMAND_NAME("compare");
|
||||||
|
B_COMMAND_SHORT_NAME('C');
|
||||||
B_COMMAND_DESC("compare two package version identifiers.");
|
B_COMMAND_DESC("compare two package version identifiers.");
|
||||||
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
B_COMMAND_FUNCTION(compare_version);
|
B_COMMAND_FUNCTION(compare_version);
|
||||||
19
ropkg/version/root.c
Normal file
19
ropkg/version/root.c
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "../commands.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/core/error.h>
|
||||||
|
#include <blue/term/print.h>
|
||||||
|
|
||||||
|
B_COMMAND(CMD_VERSION, CMD_ROOT)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("version");
|
||||||
|
B_COMMAND_SHORT_NAME('V');
|
||||||
|
B_COMMAND_DESC("Version identifier inspection and manipulation.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_COMMAND_PLACEHOLDER();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user