Skip to content

Commit

Permalink
Utilities/semver: Add semver basic utility tool
Browse files Browse the repository at this point in the history
Currently it supports the crucial features like
	- filter semvers that satisfies the spec
	- bump all the versions with same bump type
	- if none of above is provided, sort them and print in asc order
  • Loading branch information
tbhaxor committed Jan 26, 2024
1 parent 327712e commit 68c982e
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
49 changes: 49 additions & 0 deletions Base/usr/share/man/man1/semver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## Name

semver - utility to compare

## Synopsis

```**sh
$ semver [--satisfies SPEC] [--separator SEPARATOR] [--bump BUMP_TYPE] <versions...>
```

## Description

Validate, compare, bump, or check if the versions satisfies the spec or not.

## Options

* `--help`: Display help message and exit
* `--version`: Display version
* `--satisfies`: Spec string to filter all the versions that satisfies it
* `-s`, `--separator`: Normal version part separator (default: `.`)
* `-b`, `--bump`: Part of the version to bump. You must choose from `major`, `minor`, `patch`, or `prerelease`

## Arguments

* `versions`: raw version strings to process

## Examples

```sh
# Try
$ mkdir serenity ; echo cool > serenity/cool.txt
$ rmdir serenity
rmdir: Directory not empty

# Remove empty directory
$ mkdir example
$ ls -a example
. ..
$ rmdir example
$ ls -a example
example: No such file or directory

# Removes foo/bar/baz/, foo/bar/ and foo/
$ rmdir -p foo/bar/baz/
```

## See also
* [`mkdir`(1)](help://man/1/mkdir)
* [`rm`(1)](help://man/1/rm)
1 change: 1 addition & 0 deletions Userland/Utilities/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ target_link_libraries(realpath PRIVATE LibFileSystem)
target_link_libraries(run-tests PRIVATE LibCoredump LibDebug LibFileSystem LibRegex)
target_link_libraries(rm PRIVATE LibFileSystem)
target_link_libraries(sed PRIVATE LibRegex LibFileSystem)
target_link_libraries(semver PRIVATE LibSemVer)
target_link_libraries(shot PRIVATE LibFileSystem LibGfx LibGUI LibIPC)
target_link_libraries(slugify PRIVATE LibUnicode)
target_link_libraries(sql PRIVATE LibFileSystem LibIPC LibLine LibSQL)
Expand Down
86 changes: 86 additions & 0 deletions Userland/Utilities/semver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2023, Gurkirat Singh <tbhaxor@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <AK/Find.h>
#include <AK/QuickSort.h>
#include <LibCore/ArgsParser.h>
#include <LibMain/Main.h>
#include <LibSemVer/SemVer.h>

ErrorOr<int> serenity_main(Main::Arguments arguments)
{
Vector<StringView> versions;
StringView spec_sv;
StringView bump_type_sv;
StringView normal_version_separator_sv = "."sv;

Core::ArgsParser parser;
parser.add_positional_argument(versions, "List of all the versions to process", "versions");
parser.add_option(spec_sv, "Spec string to filter all the versions that satisfies it", "satisfies", '\0', "SPEC");
parser.add_option(normal_version_separator_sv, "Normal version part separator (default: `.`)", "separator", 's', "SEPARATOR");
parser.add_option(bump_type_sv, "Part of the version to bump. You must choose from `major`, `minor`, `patch`, or `prerelease`", "bump", 'b', "BUMP_TYPE");

if (!parser.parse(arguments))
return Error::from_string_view("Unable to parse the arguments"sv);

if (normal_version_separator_sv.is_empty())
return Error::from_string_view("Omit the -s or --separator option to use the default instead"sv);
if (normal_version_separator_sv.length() > 1)
return Error::from_string_view("Normal version separator must be exactly 1 character long"sv);

auto const normal_version_separator = normal_version_separator_sv[0];
if (normal_version_separator != '.' && normal_version_separator != '-')
return Error::from_string_view("Only . or - are supported as normal version separator"sv);

Vector<SemVer::SemVer> parsed_semvers;
TRY(parsed_semvers.try_ensure_capacity(versions.size()));

for (auto const& version : versions)
parsed_semvers.unchecked_append(TRY(SemVer::from_string_view(version, normal_version_separator)));

if (!spec_sv.is_empty()) {
outln("Printing all the versions out of {} statisfies {} ---", parsed_semvers.size(), spec_sv);

for (auto const& parsed_semver : parsed_semvers) {
if (parsed_semver.satisfies(spec_sv))
outln("{}", parsed_semver);
}

return 0;
}

if (!bump_type_sv.is_empty()) {

SemVer::BumpType bump_type;
if (bump_type_sv == "major"sv)
bump_type = SemVer::BumpType::Major;
else if (bump_type_sv == "minor"sv)
bump_type = SemVer::BumpType::Minor;
else if (bump_type_sv == "patch"sv)
bump_type = SemVer::BumpType::Patch;
else if (bump_type_sv == "prerelease"sv)
bump_type = SemVer::BumpType::Prerelease;
else
return Error::from_string_view("Bump type is invalid. Choose from `major`, `minor`, `patch` or `prerelease`"sv);

outln("Bumping {} part of {} versions ---", bump_type_sv, parsed_semvers.size());

for (auto const& parsed_semver : parsed_semvers)
outln("{}", parsed_semver.bump(bump_type));

return 0;
}

outln("Sorting {} versions in ascending order ---", parsed_semvers.size());
quick_sort(parsed_semvers, [](SemVer::SemVer const& lhs, SemVer::SemVer const& rhs) {
return lhs < rhs;
});

for (auto const& parsed_semver : AK::ReverseWrapper::in_reverse(parsed_semvers))
outln("{}", parsed_semver);

return 0;
}

0 comments on commit 68c982e

Please sign in to comment.