Compare commits
10 Commits
46c6a66e44
...
main
| 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_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
|
||||
find_package(Bluelib COMPONENTS Core Object Io Term Cmd REQUIRED)
|
||||
find_package(ZSTD REQUIRED)
|
||||
find_package(Bluelib COMPONENTS Core Object Io Term Cmd Compress REQUIRED)
|
||||
|
||||
add_subdirectory(libropkg)
|
||||
add_subdirectory(ropkg)
|
||||
|
||||
@@ -49,7 +49,7 @@ if (Bluelib_STATIC)
|
||||
set(_lib_suffix "-s")
|
||||
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})
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
target_link_libraries(libropkg
|
||||
Bluelib::Io
|
||||
${ZSTD_LIBRARY})
|
||||
Bluelib::Compress)
|
||||
target_include_directories(libropkg PUBLIC
|
||||
include/
|
||||
${ZSTD_INCLUDE_DIR})
|
||||
include/)
|
||||
target_compile_definitions(libropkg PRIVATE
|
||||
LIBROPKG_EXPORT=1
|
||||
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 <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) \
|
||||
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 {
|
||||
ROPKG_SUCCESS = 0,
|
||||
@@ -18,11 +19,17 @@ enum ropkg_status {
|
||||
ROPKG_ERR_BAD_STATE,
|
||||
ROPKG_ERR_INTERNAL_FAILURE,
|
||||
ROPKG_ERR_IO_FAILURE,
|
||||
ROPKG_ERR_NO_ENTRY,
|
||||
ROPKG_ERR_NO_DATA,
|
||||
ROPKG_ERR_NAME_EXISTS,
|
||||
|
||||
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||
ROPKG_ERR_INSTANCE_DIR_CREATE_FAILED,
|
||||
ROPKG_ERR_FILE_OPEN_FAILED,
|
||||
ROPKG_ERR_INVALID_MANIFEST_FORMAT,
|
||||
ROPKG_ERR_INVALID_VERSION_FORMAT,
|
||||
ROPKG_ERR_INVALID_PKG_EXPR,
|
||||
ROPKG_ERR_INVALID_PKG_FILE,
|
||||
};
|
||||
|
||||
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"),
|
||||
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(
|
||||
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||
@@ -51,10 +59,20 @@ static const b_error_definition ropkg_errors[] = {
|
||||
B_ERROR_TEMPLATE_PARAM_STRING,
|
||||
"%s")),
|
||||
|
||||
B_ERROR_DEFINITION(
|
||||
ROPKG_ERR_INVALID_MANIFEST_FORMAT,
|
||||
"INVALID_MANIFSET_FORMAT",
|
||||
"Invalid manifest format"),
|
||||
|
||||
B_ERROR_DEFINITION(
|
||||
ROPKG_ERR_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[] = {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
file(GLOB_RECURSE sources *.c *.h)
|
||||
|
||||
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_REMOVE,
|
||||
CMD_QUERY,
|
||||
CMD_BOOTSTRAP,
|
||||
|
||||
CMD_REPO,
|
||||
CMD_REPO_ADD,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "commands.h"
|
||||
|
||||
#include <blue/cmd.h>
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/term/print.h>
|
||||
|
||||
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)
|
||||
{
|
||||
b_set_error_report_function(
|
||||
b_enhanced_error_reporter,
|
||||
B_ERROR_REPORT_ALL);
|
||||
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})
|
||||
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 {
|
||||
CMD_ROOT,
|
||||
CMD_CREATE,
|
||||
CMD_BUILD,
|
||||
CMD_QUERY,
|
||||
CMD_EXTRACT,
|
||||
CMD_INSTALL,
|
||||
CMD_COMPARE_VERSION,
|
||||
|
||||
CMD_PACKAGE,
|
||||
CMD_PACKAGE_CREATE,
|
||||
CMD_PACKAGE_BUILD,
|
||||
CMD_PACKAGE_EXTRACT,
|
||||
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
|
||||
|
||||
14
ropkg/main.c
14
ropkg/main.c
@@ -1,19 +1,29 @@
|
||||
#include "commands.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_NAME("ropkg");
|
||||
B_COMMAND_DESC(
|
||||
"Rosetta package manipulation tool. This tool is used to "
|
||||
"create, build, and otherwise manipulate individual Rosetta "
|
||||
"package files.");
|
||||
"create, build, and otherwise manipulate individual Rosetta "
|
||||
"package files.");
|
||||
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||
B_COMMAND_HELP_OPTION();
|
||||
|
||||
B_COMMAND_USAGE()
|
||||
{
|
||||
B_COMMAND_USAGE_COMMAND_PLACEHOLDER();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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/compress/cstream.h>
|
||||
#include <blue/compress/function.h>
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/io/directory.h>
|
||||
#include <blue/term/print.h>
|
||||
#include <errno.h>
|
||||
#include <ropkg/compress.h>
|
||||
#include <ropkg/stream.h>
|
||||
#include <ropkg/manifest.h>
|
||||
#include <ropkg/writer.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -41,14 +43,17 @@ static int add_file_to_archive_ex(
|
||||
const char *dest)
|
||||
{
|
||||
b_file *fp;
|
||||
b_status status = b_file_open(
|
||||
b_result result = b_file_open(
|
||||
src_dir,
|
||||
src,
|
||||
B_FILE_READ_ONLY | B_FILE_BINARY,
|
||||
&fp);
|
||||
if (!fp) {
|
||||
b_err("cannot open file '%s'", src);
|
||||
b_i("reason: %s", b_status_to_string(status));
|
||||
b_throw_error_with_template_caused_by_error(
|
||||
ROPKG_ERROR_VENDOR,
|
||||
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||
result,
|
||||
B_ERROR_PARAM("filepath", b_path_ptr(src)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -63,7 +68,7 @@ static int add_file_to_archive_ex(
|
||||
int c;
|
||||
while (1) {
|
||||
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)) {
|
||||
break;
|
||||
}
|
||||
@@ -97,7 +102,7 @@ static int add_file_to_archive(
|
||||
|
||||
static int add_data_archive(
|
||||
const b_arglist *args,
|
||||
struct ropkg_stream *stream,
|
||||
struct b_cstream *stream,
|
||||
struct ropkg_writer *pkg)
|
||||
{
|
||||
const char *data_path_cstr;
|
||||
@@ -108,16 +113,23 @@ static int add_data_archive(
|
||||
0,
|
||||
&data_path_cstr);
|
||||
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;
|
||||
}
|
||||
|
||||
b_path *data_path = b_path_create_from_cstr(data_path_cstr);
|
||||
b_directory *data_dir;
|
||||
bstatus = b_directory_open(NULL, data_path, &data_dir);
|
||||
if (!B_OK(bstatus)) {
|
||||
b_err("cannot open directory '%s'", data_path_cstr);
|
||||
b_i("reason: %s", b_status_to_string(bstatus));
|
||||
b_result result = b_directory_open(NULL, data_path, 0, &data_dir);
|
||||
if (b_result_is_error(result)) {
|
||||
b_throw_error_with_template_caused_by_error(
|
||||
ROPKG_ERROR_VENDOR,
|
||||
ROPKG_ERR_DIR_OPEN_FAILED,
|
||||
result,
|
||||
B_ERROR_PARAM("filepath", data_path_cstr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -125,7 +137,7 @@ static int add_data_archive(
|
||||
struct ropkg_writer_file_info file = {0};
|
||||
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);
|
||||
|
||||
int ret = 0;
|
||||
@@ -148,7 +160,7 @@ static int add_data_archive(
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return ret;
|
||||
@@ -156,7 +168,7 @@ static int add_data_archive(
|
||||
|
||||
static int add_control_archive(
|
||||
const b_arglist *args,
|
||||
struct ropkg_stream *stream,
|
||||
b_cstream *stream,
|
||||
struct ropkg_writer *pkg)
|
||||
{
|
||||
int ret;
|
||||
@@ -165,7 +177,7 @@ static int add_control_archive(
|
||||
struct ropkg_writer_file_info file = {0};
|
||||
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);
|
||||
|
||||
b_arglist_option_iterator it;
|
||||
@@ -188,16 +200,40 @@ static int add_control_archive(
|
||||
|
||||
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);
|
||||
|
||||
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(
|
||||
const b_arglist *args,
|
||||
struct ropkg_stream *stream,
|
||||
b_cstream *stream,
|
||||
struct ropkg_writer *pkg)
|
||||
{
|
||||
const char *manifest_path, *news_path;
|
||||
@@ -205,20 +241,26 @@ static int add_meta_archive(
|
||||
args,
|
||||
OPT_MANIFEST,
|
||||
OPT_MANIFEST_PATH,
|
||||
1,
|
||||
0,
|
||||
&manifest_path);
|
||||
if (!B_OK(bstatus)) {
|
||||
b_arglist_report_missing_option(args, OPT_MANIFEST);
|
||||
return -1;
|
||||
}
|
||||
|
||||
b_result result = validate_manifest(manifest_path);
|
||||
if (b_result_is_error(result)) {
|
||||
b_throw(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
struct ropkg_writer *meta;
|
||||
struct ropkg_writer_file_info file = {0};
|
||||
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);
|
||||
|
||||
bstatus = b_arglist_get_string(
|
||||
@@ -243,7 +285,7 @@ static int add_meta_archive(
|
||||
|
||||
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);
|
||||
|
||||
@@ -255,8 +297,8 @@ static int create(
|
||||
const b_arglist *opt,
|
||||
const b_array *args)
|
||||
{
|
||||
const struct ropkg_compression_function *zstd
|
||||
= ropkg_compression_function_for_type(ROPKG_COMPRESSION_ZSTD);
|
||||
const b_compression_function *zstd
|
||||
= b_compression_function_get_by_id(B_COMPRESSOR_FUNCTION_ZSTD);
|
||||
struct ropkg_writer *pkg, *subpkg;
|
||||
enum ropkg_status status;
|
||||
|
||||
@@ -265,7 +307,7 @@ static int create(
|
||||
opt,
|
||||
OPT_OUTPATH,
|
||||
OPT_OUTPATH_PATH,
|
||||
1,
|
||||
0,
|
||||
&out_path);
|
||||
if (!B_OK(bstatus)) {
|
||||
b_arglist_report_missing_option(opt, OPT_OUTPATH);
|
||||
@@ -273,37 +315,45 @@ static int create(
|
||||
}
|
||||
|
||||
FILE *fp = fopen(out_path, "wb");
|
||||
struct ropkg_stream *stream;
|
||||
status = ropkg_stream_open(fp, zstd, ROPKG_STREAM_WRITE, &stream);
|
||||
b_stream *fp_stream = b_stream_open_fp(fp);
|
||||
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;
|
||||
|
||||
ret = add_data_archive(opt, stream, pkg);
|
||||
ret = add_data_archive(opt, cstream, pkg);
|
||||
if (ret != 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = add_control_archive(opt, stream, pkg);
|
||||
ret = add_control_archive(opt, cstream, pkg);
|
||||
if (ret != 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = add_meta_archive(opt, stream, pkg);
|
||||
ret = add_meta_archive(opt, cstream, pkg);
|
||||
if (ret != 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
ropkg_writer_close(pkg);
|
||||
ropkg_stream_close(stream);
|
||||
|
||||
b_cstream_close(cstream);
|
||||
b_stream_close(fp_stream);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
B_COMMAND(CMD_CREATE, CMD_ROOT)
|
||||
B_COMMAND(CMD_PACKAGE_CREATE, CMD_PACKAGE)
|
||||
{
|
||||
B_COMMAND_NAME("create");
|
||||
B_COMMAND_SHORT_NAME('C');
|
||||
@@ -376,7 +426,8 @@ B_COMMAND(CMD_CREATE, CMD_ROOT)
|
||||
B_OPTION_SHORT_NAME('s');
|
||||
B_OPTION_LONG_NAME("script");
|
||||
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.");
|
||||
|
||||
B_OPTION_ARG(OPT_SCRIPT_NAME)
|
||||
@@ -402,10 +453,13 @@ B_COMMAND(CMD_CREATE, CMD_ROOT)
|
||||
B_OPTION_SHORT_NAME('p');
|
||||
B_OPTION_LONG_NAME("parameter");
|
||||
B_OPTION_DESC(
|
||||
"a parameter to use when creating the new file. "
|
||||
"if a parameter EXAMPLE is defined, any variable "
|
||||
"a parameter to use when creating the new "
|
||||
"file. "
|
||||
"if a parameter EXAMPLE is defined, any "
|
||||
"variable "
|
||||
"reference "
|
||||
"of the form ${EXAMPLE} in the package manifest will "
|
||||
"of the form ${EXAMPLE} in the package "
|
||||
"manifest will "
|
||||
"be "
|
||||
"replaced with the specified parameter value.");
|
||||
|
||||
@@ -426,8 +480,10 @@ B_COMMAND(CMD_CREATE, CMD_ROOT)
|
||||
{
|
||||
B_ARG_NAME("source-dir");
|
||||
B_ARG_DESC(
|
||||
"the directory to package. the specified directory "
|
||||
"will become the root of the newly created package.");
|
||||
"the directory to package. the specified "
|
||||
"directory "
|
||||
"will become the root of the newly created "
|
||||
"package.");
|
||||
B_ARG_NR_VALUES(1);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "commands.h"
|
||||
#include "../commands.h"
|
||||
|
||||
#include <blue/cmd.h>
|
||||
|
||||
@@ -17,12 +17,12 @@ static int extract(
|
||||
return 0;
|
||||
}
|
||||
|
||||
B_COMMAND(CMD_EXTRACT, CMD_ROOT)
|
||||
B_COMMAND(CMD_PACKAGE_EXTRACT, CMD_PACKAGE)
|
||||
{
|
||||
B_COMMAND_NAME("extract");
|
||||
B_COMMAND_SHORT_NAME('X');
|
||||
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_HELP_OPTION();
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "commands.h"
|
||||
#include "../commands.h"
|
||||
|
||||
#include <blue/cmd.h>
|
||||
|
||||
@@ -17,7 +17,7 @@ static int install(
|
||||
return 0;
|
||||
}
|
||||
|
||||
B_COMMAND(CMD_INSTALL, CMD_ROOT)
|
||||
B_COMMAND(CMD_PACKAGE_INSTALL, CMD_PACKAGE)
|
||||
{
|
||||
B_COMMAND_NAME("install");
|
||||
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 <blue/cmd.h>
|
||||
@@ -175,9 +175,10 @@ end:
|
||||
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_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||
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