diff options
| author | ruki <[email protected]> | 2017-08-14 11:27:19 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2017-08-14 11:29:30 +0800 |
| commit | dba45d143d8aff047da82cbe1a881056e6e4bc00 (patch) | |
| tree | 7b80d5de264c17b538a7c9d0fbb234ded39ac683 | |
| parent | 34706ba053dda9dd86902cacf42a6c1878c85234 (diff) | |
merge repo and require codes
106 files changed, 8756 insertions, 231 deletions
diff --git a/core/src/demo/makefile b/core/src/demo/makefile index 3a474649f..084e525fe 100644 --- a/core/src/demo/makefile +++ b/core/src/demo/makefile @@ -15,9 +15,9 @@ demo_PKGS-$(TBOX) += tbox demo_PKGS-$(BASE) += base # others -demo_LIBS += xmake$(DTYPE) luajit$(DTYPE) -demo_INC_DIRS += ../ ../luajit/src -demo_LIB_DIRS += ../xmake ../luajit +demo_LIBS += xmake$(DTYPE) luajit$(DTYPE) sv$(DTYPE) +demo_INC_DIRS += ../ ../luajit/src ../sv/include +demo_LIB_DIRS += ../xmake ../luajit ../sv demo_CXFLAGS += -D__tb_prefix__=\"xmake\" # suffix diff --git a/core/src/demo/xmake.lua b/core/src/demo/xmake.lua index 40d089f7f..520241669 100644 --- a/core/src/demo/xmake.lua +++ b/core/src/demo/xmake.lua @@ -2,7 +2,7 @@ target("demo") -- add deps - add_deps("xmake") + add_deps("sv", "luajit", "xmake") -- make as a binary set_kind("binary") @@ -19,10 +19,6 @@ target("demo") -- add includes directory add_includedirs("$(projectdir)", "$(projectdir)/src", "$(buildir)/luajit") - -- add links and directory - add_links("xmake", "luajit") - add_linkdirs("$(buildir)") - -- link readline if not is_plat("windows") then add_links("readline") @@ -33,9 +29,14 @@ target("demo") -- add the common source files add_files("**.c") + + -- for macosx + if is_plat("macosx") then + add_ldflags("-all_load", "-pagezero_size 10000", "-image_base 100000000") + end -- add the resource files (it will be enabled after publishing new version) if is_plat("windows") then add_files("*.rc") end - + diff --git a/core/src/makefile b/core/src/makefile index 139d4ac64..6636d2ad6 100644 --- a/core/src/makefile +++ b/core/src/makefile @@ -3,7 +3,7 @@ include $(PRO_DIR)/prefix.mak # projects SUB_PROS += demo -DEP_PROS += luajit xmake +DEP_PROS += sv luajit xmake # suffix include $(PRO_DIR)/suffix.mak diff --git a/core/src/sv/.gitignore b/core/src/sv/.gitignore new file mode 100644 index 000000000..51272dc42 --- /dev/null +++ b/core/src/sv/.gitignore @@ -0,0 +1,149 @@ +# Created by .ignore support plugin (hsz.mobi) +### Autotools template +# http://www.gnu.org/software/automake + +Makefile.in +/ar-lib +/mdate-sh +/py-compile +/test-driver +/ylwrap + +# http://www.gnu.org/software/autoconf + +/autom4te.cache +/autoscan.log +/autoscan-*.log +/aclocal.m4 +/compile +/config.guess +/config.h.in +/config.sub +/configure +/configure.scan +/depcomp +/install-sh +/missing +/stamp-h1 + +# https://www.gnu.org/software/libtool/ + +/ltmain.sh + +# http://www.gnu.org/software/texinfo + +/texinfo.tex +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### C template +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +modules.order +Module.symvers +Mkfile.old +dkms.conf +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Clion +.idea/ +cmake-build-debug/ + +# xmake +.xmake/ +build/ diff --git a/core/src/sv/.travis.yml b/core/src/sv/.travis.yml new file mode 100644 index 000000000..505409db5 --- /dev/null +++ b/core/src/sv/.travis.yml @@ -0,0 +1,107 @@ +sudo: false +language: c + +before_install: + - bash <(curl -s https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh) + +install: + - xmake + - cd build + - cmake .. + - make all + +script: + - ctest --verbose + - cd .. && xmake check + +matrix: + include: + - os: linux + - os: linux + compiler: gcc-4.9 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.9 + - os: linux + compiler: gcc-5 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-5 + - os: linux + compiler: gcc-6 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-6 + - os: linux + compiler: clang-3.5 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + packages: + - clang-3.5 + - os: linux + compiler: clang-3.6 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + - os: linux + compiler: clang-3.7 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + - os: linux + compiler: clang-3.8 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + - os: linux + compiler: clang-3.9 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + packages: + - clang-3.9 + - os: linux + dist: trusty + compiler: clang-4.0 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-4.0 + packages: + - clang-4.0 + - os: osx + osx_image: xcode6.4 + compiler: clang + - os: osx + osx_image: xcode7.3 + compiler: clang + - os: osx + osx_image: xcode8.3 + compiler: clang diff --git a/core/src/sv/CMakeLists.txt b/core/src/sv/CMakeLists.txt new file mode 100644 index 000000000..9a08b2b1c --- /dev/null +++ b/core/src/sv/CMakeLists.txt @@ -0,0 +1,93 @@ +cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR) +project(sv) + +option(SHARED "Build as shared library" OFF) +option(COVERAGE "Turn on COVERAGE support" OFF) + +if (COVERAGE AND NOT MSVC) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} --coverage") +endif() + +if(CMAKE_VERSION VERSION_LESS "3.1") + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + set(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}") + endif() +else() + set(CMAKE_C_STANDARD 99) +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +if(MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") +else() + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g3 -DDEBUG") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") + endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Werror -fomit-frame-pointer") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-function") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-variable -Wno-unused-value -Wno-unused-result") +endif() + +set(sv_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include) +set(sv_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/src) +set(sv_TEST_DIR ${CMAKE_CURRENT_LIST_DIR}/test) + +file(GLOB sv_HEADERS ${sv_HEADERS} ${sv_INCLUDE_DIR}/*.h) +file(GLOB sv_SOURCES ${sv_SOURCES} ${sv_SOURCE_DIR}/*.c) + +include_directories(${sv_INCLUDE_DIR}) +if(SHARED) + if(MSVC) + set(CMAKE_FLAGS + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + ) + foreach(CMAKE_FLAG ${CMAKE_FLAGS}) + string(REPLACE "/MD" "/MT" ${CMAKE_FLAG} "${${CMAKE_FLAG}}") + string(REPLACE "/MDd" "/MTd" ${CMAKE_FLAG} "${${CMAKE_FLAG}}") + endforeach() + endif() + + add_library(${PROJECT_NAME} SHARED ${sv_SOURCES} ${sv_HEADERS}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSV_BUILD_DYNAMIC_LINK=1") +else() + add_library(${PROJECT_NAME} STATIC ${sv_SOURCES} ${sv_HEADERS}) +endif() +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSV_COMPILE=1") + +enable_testing() +add_subdirectory(${sv_TEST_DIR}) + +if(WIN32) + set(CPACK_GENERATOR "WIX") + set(CPACK_SOURCE_GENERATOR "ZIP") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(CPACK_GENERATOR "PackageMake") +else() + set(CPACK_GENERATOR "DEB;RPM") + set(CPACK_SOURCE_GENERATOR "TGZ") +endif() + +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Lucas Abel") + +set(CPACK_PACKAGE_VERSION "1.0.0") +set(CPACK_PACKAGE_VERSION_MAJOR "1") +set(CPACK_PACKAGE_VERSION_MINOR "0") +set(CPACK_PACKAGE_VERSION_PATCH "0") + +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/UNLICENSE") +set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md") +set(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/README.md") + +set(CPACK_SOURCE_IGNORE_FILES "${CMAKE_SOURCE_DIR}/build/;${CMAKE_SOURCE_DIR}/.git/") + +set(CPACK_SYSTEM_NAME "") + +include(CPack) diff --git a/core/src/sv/INSTALL b/core/src/sv/INSTALL new file mode 100644 index 000000000..64c69372e --- /dev/null +++ b/core/src/sv/INSTALL @@ -0,0 +1,364 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/core/src/sv/LICENSE b/core/src/sv/LICENSE new file mode 100644 index 000000000..cf1ab25da --- /dev/null +++ b/core/src/sv/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org> diff --git a/core/src/sv/Makefile.am b/core/src/sv/Makefile.am new file mode 100644 index 000000000..a53382d22 --- /dev/null +++ b/core/src/sv/Makefile.am @@ -0,0 +1,105 @@ +## Process this file with automake to produce Makefile.in + +ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = foreign +dist_doc_DATA = UNLICENSE README.md +AM_CFLAGS = -I$(srcdir)/src -I$(srcdir)/include -Wall $(AX_CFLAGS) + +## -------------------------------------------------------------------- + +EXTRA_DIST = scripts/libsv.pc.in +pkgconfigdir = $(libdir)/pkgconfig +nodist_pkgconfig_DATA = scripts/libsv.pc + +## -------------------------------------------------------------------- + +# Commented out because at present there is no Texinfo documentation +# included. It will come later. (Marco Maggi; May 17, 2017) +# +# AM_MAKEINFOFLAGS = --no-split +# info_TEXINFOS = doc/semver.texi +# doc_semver_TEXINFOS = doc/macros.texi + +#page +#### libraries + +libsv_CURRENT = @libsv_VERSION_INTERFACE_CURRENT@ +libsv_REVISION = @libsv_VERSION_INTERFACE_REVISION@ +libsv_AGE = @libsv_VERSION_INTERFACE_AGE@ + +include_HEADERS = include/semver.h + +lib_LTLIBRARIES = libsv.la +libsv_la_LDFLAGS = -version-info $(libsv_CURRENT):$(libsv_REVISION):$(libsv_AGE) +libsv_la_SOURCES = \ + src/comp.c \ + src/id.c \ + src/num.c \ + src/range.c \ + src/semvers.c \ + src/version.c \ + src/utils.c + +#page +#### test + +check_PROGRAMS = \ + test/version \ + test/comp \ + test/match \ + test/range \ + test/semvers \ + test/utils \ + test/usage + +TESTS = $(check_PROGRAMS) + +libsv_test_cppflags = -I$(srcdir)/src -I$(srcdir)/include +libsv_test_ldadd = libsv.la + +test_version_CPPFLAGS = $(libsv_test_cppflags) +test_version_LDADD = $(libsv_test_ldadd) + +test_comp_CPPFLAGS = $(libsv_test_cppflags) +test_comp_LDADD = $(libsv_test_ldadd) + +test_match_CPPFLAGS = $(libsv_test_cppflags) +test_match_LDADD = $(libsv_test_ldadd) + +test_range_CPPFLAGS = $(libsv_test_cppflags) +test_range_LDADD = $(libsv_test_ldadd) + +test_semvers_CPPFLAGS = $(libsv_test_cppflags) +test_semvers_LDADD = $(libsv_test_ldadd) + +test_utils_CPPFLAGS = $(libsv_test_cppflags) +test_utils_LDADD = $(libsv_test_ldadd) + +test_usage_CPPFLAGS = $(libsv_test_cppflags) +test_usage_LDADD = $(libsv_test_ldadd) + +installcheck-local: $(TEST) + @for f in $(TEST); do $(builddir)/$$f; done + +#page +#### Static analysis with Clang's Static Analyzer +# +# See the documentation for the command line tool at: +# +# <http://clang-analyzer.llvm.org/scan-build.html> +# +# To run the tool we must do: +# +# $ make clean +# $ make clang-static-analysis +# +# The program "scan-build" works by overriding the CC and CXX +# environment variables. +# + +.PHONY: clang-static-analysis + +clang-static-analysis: + scan-build make + +### end of file diff --git a/core/src/sv/README.md b/core/src/sv/README.md new file mode 100644 index 000000000..e55d9718d --- /dev/null +++ b/core/src/sv/README.md @@ -0,0 +1,330 @@ +# libsv +libsv - Public domain semantic versioning in c + +[](https://travis-ci.org/uael/sv) +[](https://ci.appveyor.com/project/uael/sv) +[](https://codecov.io/gh/uael/sv) +[](https://www.codacy.com/app/lucas.abel/sv?utm_source=github.com&utm_medium=referral&utm_content=uael/sv&utm_campaign=Badge_Grade) + +# Topics +- [Introduction](#introduction) +- [License](#license) +- [Install](#install) + - [xmake](#xmake) + - [cmake](#cmake) + - [autotools](#autotools) +- [Usage](#usage) +- [Credits](#credits) +- [Bugs, vulnerabilities and contributions](#bugs-vulnerabilities-and-contributions) +- [Resources](#resources) +- [Badges and static analysis](#badges-and-static-analysis) + - [Travis CI](#travis-ci) + - [Clang's Static Analyzer](#clangs-static-analyzer) + +## Introduction + +This is free and unencumbered software released into the public domain. +This package installs a C language library implementing semantic versioning for the C language. + +## License + +See the [UNLICENSE](https://github.com/uael/sv/blob/master/UNLICENSE) file. + +## Install + +### xmake + +[Install xmake build system (A make-like build utility based on Lua)](http://xmake.io) + +```bash +$ xmake +$ xmake check +$ xmake install +``` + +### cmake + +```bash +$ mkdir build && cd build +$ cmake .. +$ make +$ make test +$ make install +``` + +### autotools + +To install from a proper release tarball, do this: +```bash +$ cd libsv-3.1 +$ mkdir build +$ cd build +$ ../configure +$ make +$ make check +$ make install +``` +to inspect the available configuration options: +```bash +$ ../configure --help +``` +The Makefile is designed to allow parallel builds, so we can do: +```bash +$ make -j4 all && make -j4 check +``` +which, on a 4-core CPU, should speed up building and checking significantly. +The Makefile supports the DESTDIR environment variable to install files in a temporary location, example: to see what will happen: +```bash +$ make -n install DESTDIR=/tmp/libsv +``` +to really do it: +```bash +$ make install DESTDIR=/tmp/libsv +``` +After the installation it is possible to verify the installed library against the test suite with: +```bash +$ make installcheck +``` +From a repository checkout or snapshot (the ones from the Github site): we must install the GNU Autotools (GNU Automake, GNU Autoconf, GNU Libtool), then we must first run the script "autogen.sh" from the top source directory, to generate the needed files: +```bash +$ cd libsv +$ sh autogen.sh +``` +notice that "autogen.sh" will run the programs "autoreconf" and "libtoolize"; the latter is selected through the environment variable "LIBTOOLIZE", whose value can be customised; for example to run "glibtoolize" rather than "libtoolize" we do: +```bash +$ LIBTOOLIZE=glibtoolize sh autogen.sh +``` +After this the procedure is the same as the one for building from a proper release tarball, but we have to enable maintainer mode: +```bash +$ ../configure --enable-maintainer-mode [options] +$ make +$ make check +$ make install +``` + +## Usage + +```c +... +semver_t semver = {0}; + +semver(&semver, "v1.2.3-alpha.1"); + +assert(1 == semver.major); +assert(2 == semver.minor); +assert(3 == semver.patch); +assert(0 == memcmp("alpha", semver.prerelease.raw, sizeof("alpha")-1)); +assert(0 == memcmp("1", semver.prerelease.next->raw, sizeof("1")-1)); +assert(true == semver_rmatch(semver, "1.2.1 || >=1.2.3-alpha <1.2.5")); + +semver_dtor(&semver); +... +``` + +### Versions + +A "version" is described by the `v2.0.0` specification found at +<http://semver.org/>. + +A leading `"v"` character is stripped off and ignored. + +### Ranges + +A `version range` is a set of `comparators` which specify versions +that satisfy the range. + +A `comparator` is composed of an `operator` and a `version`. The set +of primitive `operators` is: + +* `<` Less than +* `<=` Less than or equal to +* `>` Greater than +* `>=` Greater than or equal to +* `=` Equal. If no operator is specified, then equality is assumed, + so this operator is optional, but MAY be included. + +For example, the comparator `>=1.2.7` would match the versions +`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6` +or `1.1.0`. + +Comparators can be joined by whitespace to form a `comparator set`, +which is satisfied by the **intersection** of all of the comparators +it includes. + +A range is composed of one or more comparator sets, joined by `||`. A +version matches a range if and only if every comparator in at least +one of the `||`-separated comparator sets is satisfied by the version. + +For example, the range `>=1.2.7 <1.3.0` would match the versions +`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`, +or `1.1.0`. + +The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`, +`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`. + +#### Prerelease Tags + +If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then +it will only be allowed to satisfy comparator sets if at least one +comparator with the same `[major, minor, patch]` tuple also has a +prerelease tag. + +For example, the range `>1.2.3-alpha.3` would be allowed to match the +version `1.2.3-alpha.7`, but it would *not* be satisfied by +`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater +than" `1.2.3-alpha.3` according to the SemVer sort rules. The version +range only accepts prerelease tags on the `1.2.3` version. The +version `3.4.5` *would* satisfy the range, because it does not have a +prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`. + +The purpose for this behavior is twofold. First, prerelease versions +frequently are updated very quickly, and contain many breaking changes +that are (by the author's design) not yet fit for public consumption. +Therefore, by default, they are excluded from range matching +semantics. + +Second, a user who has opted into using a prerelease version has +clearly indicated the intent to use *that specific* set of +alpha/beta/rc versions. By including a prerelease tag in the range, +the user is indicating that they are aware of the risk. However, it +is still not appropriate to assume that they have opted into taking a +similar risk on the *next* set of prerelease versions. + +#### Advanced Range Syntax + +Advanced range syntax desugars to primitive comparators in +deterministic ways. + +Advanced ranges may be combined in the same way as primitive +comparators using white space or `||`. + +##### Hyphen Ranges `X.Y.Z - A.B.C` + +Specifies an inclusive set. + +* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4` + +If a partial version is provided as the first version in the inclusive +range, then the missing pieces are replaced with zeroes. + +* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4` + +If a partial version is provided as the second version in the +inclusive range, then all versions that start with the supplied parts +of the tuple are accepted, but nothing that would be greater than the +provided tuple parts. + +* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0` +* `1.2.3 - 2` := `>=1.2.3 <3.0.0` + +##### X-Ranges `1.2.x` `1.X` `1.2.*` `*` + +Any of `X`, `x`, or `*` may be used to "stand in" for one of the +numeric values in the `[major, minor, patch]` tuple. + +* `*` := `>=0.0.0` (Any version satisfies) +* `1.x` := `>=1.0.0 <2.0.0` (Matching major version) +* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions) + +A partial version range is treated as an X-Range, so the special +character is in fact optional. + +* `""` (empty string) := `*` := `>=0.0.0` +* `1` := `1.x.x` := `>=1.0.0 <2.0.0` +* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0` + +##### Tilde Ranges `~1.2.3` `~1.2` `~1` + +Allows patch-level changes if a minor version is specified on the +comparator. Allows minor-level changes if not. + +* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0` +* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`) +* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`) +* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0` +* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`) +* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`) +* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in + the `1.2.3` version will be allowed, if they are greater than or + equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but + `1.2.4-beta.2` would not, because it is a prerelease of a + different `[major, minor, patch]` tuple. + +#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4` + +Allows changes that do not modify the left-most non-zero digit in the +`[major, minor, patch]` tuple. In other words, this allows patch and +minor updates for versions `1.0.0` and above, patch updates for +versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`. + +Many authors treat a `0.x` version as if the `x` were the major +"breaking-change" indicator. + +Caret ranges are ideal when an author may make breaking changes +between `0.2.4` and `0.3.0` releases, which is a common practice. +However, it presumes that there will *not* be breaking changes between +`0.2.4` and `0.2.5`. It allows for changes that are presumed to be +additive (but non-breaking), according to commonly observed practices. + +* `^1.2.3` := `>=1.2.3 <2.0.0` +* `^0.2.3` := `>=0.2.3 <0.3.0` +* `^0.0.3` := `>=0.0.3 <0.0.4` +* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in + the `1.2.3` version will be allowed, if they are greater than or + equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but + `1.2.4-beta.2` would not, because it is a prerelease of a + different `[major, minor, patch]` tuple. +* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4` Note that prereleases in the + `0.0.3` version *only* will be allowed, if they are greater than or + equal to `beta`. So, `0.0.3-pr.2` would be allowed. + +When parsing caret ranges, a missing `patch` value desugars to the +number `0`, but will allow flexibility within that value, even if the +major and minor versions are both `0`. + +* `^1.2.x` := `>=1.2.0 <2.0.0` +* `^0.0.x` := `>=0.0.0 <0.1.0` +* `^0.0` := `>=0.0.0 <0.1.0` + +A missing `minor` and `patch` values will desugar to zero, but also +allow flexibility within those values, even if the major version is +zero. + +* `^1.x` := `>=1.0.0 <2.0.0` +* `^0.x` := `>=0.0.0 <1.0.0` + +## Credits + +The stuff was written by Lucas Abel <https://github.com/uael> and contributors +- Marco Maggi <https://github.com/marcomaggi> + +## Bugs, vulnerabilities and contributions + +Bug and vulnerability reports are appreciated, all the vulnerability reports are public; register them using the Issue Tracker at the project's Github site. For contributions and patches please use the Pull Requests feature at the project's Github site. + +Reports about the original code must be registered at: +<https://github.com/uael/sv/issues> + +## Resources + +Development of the original projects takes place at: +<https://github.com/uael/sv/> + +the GNU Project software can be found here: +<https://www.gnu.org/> + +## Badges and static analysis + +### Travis CI + +Travis CI is a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub. We can find this project's dashboards at: +<https://travis-ci.org/uael/sv> + +Usage of this service is configured through the file ".travis.yml". + +### Clang's Static Analyzer + +The Clang Static Analyzer is a source code analysis tool that finds bugs in C, C++, and Objective-C programs. It is distributed along with Clang and we can find it at: +<http://clang-analyzer.llvm.org/> + +Usage of this service is implemented with make rules; see the relevant section in the file "Makefile.am". diff --git a/core/src/sv/UNLICENSE b/core/src/sv/UNLICENSE new file mode 100644 index 000000000..cf1ab25da --- /dev/null +++ b/core/src/sv/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org> diff --git a/core/src/sv/appveyor.yml b/core/src/sv/appveyor.yml new file mode 100644 index 000000000..fb1c88bd9 --- /dev/null +++ b/core/src/sv/appveyor.yml @@ -0,0 +1,40 @@ +version: "1.0.{build}" + +platform: + - Win32 + - x64 + +environment: + MSVC_DEFAULT_OPTIONS: ON + matrix: + - msvc: 'Visual Studio 12 2013' + - msvc: 'Visual Studio 14 2015' + +configuration: + - Debug + - Release + +init: + - cmd: cmake --version + - cmd: msbuild /version + +clone_folder: C:\projects\sv + +install: + - git submodule update --init --recursive + +before_build: + - cmd: cd C:\projects\sv + - cmd: md build + - cmd: cd build + - cmd: if "%platform%"=="Win32" set CMAKE_GENERATOR_NAME=%msvc% + - cmd: if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%msvc% Win64 + - cmd: cmake -G "%CMAKE_GENERATOR_NAME%" -DCMAKE_BUILD_TYPE=%configuration% .. + +build: + project: C:\projects\sv\build\sv.sln + verbosity: quiet + +test_script: + - ps: cd C:\projects\sv\build + - cmd: ctest -VV diff --git a/core/src/sv/autogen.sh b/core/src/sv/autogen.sh new file mode 100755 index 000000000..586ab6a35 --- /dev/null +++ b/core/src/sv/autogen.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# autogen.sh -- +# +# Run this in the top source directory to rebuild the infrastructure. + +LIBTOOLIZE=${LIBTOOLIZE:=libtoolize} + +set -xe +test -d m4 || mkdir -p m4 +test -f m4/libtool.m4 || "$LIBTOOLIZE" +autoreconf --warnings=all --install --verbose "$@" + +### end of file diff --git a/core/src/sv/codecov.yml b/core/src/sv/codecov.yml new file mode 100644 index 000000000..32f50be1c --- /dev/null +++ b/core/src/sv/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "test" # ignore test folder and all its contents diff --git a/core/src/sv/configure.ac b/core/src/sv/configure.ac new file mode 100644 index 000000000..c6cbb6f48 --- /dev/null +++ b/core/src/sv/configure.ac @@ -0,0 +1,77 @@ +dnl @configure_input@ +dnl + +AC_PREREQ([2.69]) +AC_INIT([libsv],[0.0.1],,[libsv],[http://github.com/uael/sv]) +AC_COPYRIGHT([This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any means. + +In jurisdictions that recognize copyright laws, the author or authors of +this software dedicate any and all copyright interest in the software to +the public domain. We make this dedication for the benefit of the public +at large and to the detriment of our heirs and successors. We intend +this dedication to be an overt act of relinquishment in perpetuity of +all present and future rights to this software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org> +]) +AC_CONFIG_SRCDIR([src]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([scripts]) +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_CANONICAL_TARGET +AM_INIT_AUTOMAKE([foreign dist-xz no-dist-gzip subdir-objects]) +AM_MAINTAINER_MODE + +AM_PROG_AR +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_MKDIR_P + +LT_PREREQ([2.4]) +LT_INIT + +dnl This is the version stored in the pkg-config data file. +AC_SUBST([LIBSV_PKG_CONFIG_VERSION],[0.0.1]) + +dnl page +#### libraries interface version + +MM_LIBTOOL_LIBRARY_VERSIONS([libsv],1,0,0) + +dnl page +#### basic system inspection + +AC_LANG([C]) +AM_PROG_AS +AC_PROG_CC_C99 +AM_PROG_CC_C_O +AC_HEADER_STDC + +AC_CACHE_SAVE + +dnl page +#### finish + +AC_CONFIG_FILES([Makefile] + [scripts/libsv.pc]) +AC_OUTPUT + +### end of file +# Local Variables: +# mode: autoconf +# page-delimiter: "^dnl page" +# End: diff --git a/core/src/sv/include/semver.h b/core/src/sv/include/semver.h new file mode 100644 index 000000000..bdc005702 --- /dev/null +++ b/core/src/sv/include/semver.h @@ -0,0 +1,228 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_H__ +# define SV_H__ + +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +#ifndef SV_COMPILE +# define SV_COMPILE (0) +#endif + +#ifndef SV_BUILD_DYNAMIC_LINK +# define SV_BUILD_DYNAMIC_LINK (0) +#endif + +#if SV_BUILD_DYNAMIC_LINK && defined(_MSC_VER) +# define SV_EXPORT_LINK __declspec(dllexport) +# define SV_IMPORT_LINK __declspec(dllimport) +#else +# define SV_EXPORT_LINK +# define SV_IMPORT_LINK +#endif +#if SV_COMPILE +# ifdef __cplusplus +# define SV_API extern "C" SV_EXPORT_LINK +# else +# define SV_API extern SV_EXPORT_LINK +# endif +#else +# ifdef __cplusplus +# define SV_API extern "C" SV_IMPORT_LINK +# else +# define SV_API extern SV_IMPORT_LINK +# endif +#endif + +#ifndef __cplusplus +# if defined(_MSC_VER) && _MSC_VER < 1900 +# define bool unsigned char +# define true 1 +# define false 0 +# define __bool_true_false_are_defined 1 +# else +# include <stdbool.h> +# endif +#endif + +#if defined(_MSC_VER) +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#ifdef _WIN64 +typedef __int64 intptr_t; +typedef unsigned __int64 uintptr_t; +#else +typedef __int32 intptr_t; +typedef unsigned __int32 uintptr_t; +#endif +#else +# include <stdint.h> +#endif + +#ifndef sv_malloc +# define sv_malloc malloc +#endif + +#ifndef sv_free +# define sv_free free +#endif + +#define SEMVER_NUM_X (-1) + +#define semver(self, str) semvern(self, str, strlen(str)) +#define semver_write(self, buffer, len) semver_pwrite(&(self), buffer, len) +#define semver_cmp(self, other) semver_pcmp(&(self), &(other)) +#define semver_comp(self, str) semver_compn(self, str, strlen(str)) +#define semver_comp_write(self, buffer, len) semver_comp_pwrite(&(self), buffer, len) +#define semver_comp_match(self, comp) semver_comp_pmatch(&(self), &(comp)) +#define semver_match(self, comp_str) semver_comp_matchn(&(self), comp_str, strlen(comp_str)) +#define semver_range(self, str) semver_rangen(self, str, strlen(str)) +#define semver_range_write(self, buffer, len) semver_range_pwrite(&(self), buffer, len) +#define semver_range_match(self, range) semver_range_pmatch(&(self), &(range)) +#define semver_rmatch(self, range_str) semver_range_matchn(&(self), range_str, strlen(range_str)) + +typedef struct semver semver_t; +typedef struct semver_id semver_id_t; +typedef struct semver_comp semver_comp_t; +typedef struct semver_range semver_range_t; +typedef struct semvers semvers_t; + +enum semver_op { + SEMVER_OP_EQ = 0, + SEMVER_OP_LT, + SEMVER_OP_LE, + SEMVER_OP_GT, + SEMVER_OP_GE, +}; + +struct semver_id { + bool numeric; + int num; + size_t len; + const char *raw; + struct semver_id *next; +}; + +struct semver { + int major, minor, patch; + semver_id_t prerelease, build; + size_t len; + const char *raw; +}; + +SV_API char semvern(semver_t *self, const char *str, size_t len); +SV_API char semver_tryn(semver_t *self, const char *str, size_t len); +SV_API void semver_dtor(semver_t *self); +SV_API int semver_pwrite(const semver_t *self, char *buffer, size_t len); +SV_API size_t semver_fwrite (const semver_t *self, FILE * stream); +SV_API char semver_pcmp(const semver_t *self, const semver_t *other); +SV_API bool semver_comp_pmatch(const semver_t *self, const semver_comp_t *comp); +SV_API bool semver_comp_matchn(const semver_t *self, const char *comp_str, size_t comp_len); +SV_API bool semver_range_pmatch(const semver_t *self, const semver_range_t *range); +SV_API bool semver_range_matchn(const semver_t *self, const char *range_str, size_t range_len); + +struct semver_comp { + struct semver_comp *next; + enum semver_op op; + semver_t version; +}; + +SV_API char semver_compn(semver_comp_t *self, const char *str, size_t len); +SV_API void semver_comp_dtor(semver_comp_t *self); +SV_API int semver_comp_pwrite(const semver_comp_t *self, char *buffer, size_t len); +SV_API size_t semver_comp_fwrite (const semver_comp_t *self, FILE *stream); +SV_API char semver_and(semver_comp_t *left, const char *str, size_t len); + +struct semver_range { + struct semver_range *next; + semver_comp_t comp; +}; + +SV_API char semver_rangen(semver_range_t *self, const char *str, size_t len); +SV_API void semver_range_dtor(semver_range_t *self); +SV_API int semver_range_pwrite(const semver_range_t *self, char *buffer, size_t len); +SV_API size_t semver_range_fwrite (const semver_range_t *rangep, FILE *stream); +SV_API char semver_or(semver_range_t *left, const char *str, size_t len); + +struct semvers { + uint32_t length, capacity; + semver_t *data; +}; + +SV_API uint32_t semvers_pgrowth(semvers_t *self, int32_t nmin); +SV_API semver_t semvers_perase(semvers_t *self, uint32_t i); +SV_API void semvers_psort(semvers_t *self); +SV_API void semvers_prsort(semvers_t *self); +SV_API void semvers_pdtor(semvers_t *self); +SV_API void semvers_pclear(semvers_t *self); + +#define semvers_dtor(s) \ + semvers_pdtor(&(s)) + +#define semvers_clear(s) \ + semvers_pclear(&(s)) + +#define semvers_growth(s, n) \ + semvers_pgrowth(&(s),n) + +#define semvers_grow(s, n) \ + semvers_pgrowth(&(s),(s).length+(n)) + +#define semvers_resize(s, n) \ + ((s).length=semvers_growth(s, n)) + +#define semvers_erase(s, i) \ + semvers_perase(&(s), i) + +#define semvers_push(s, x) \ + (semvers_grow(s,1),(s).data[(s).length++]=(x)) + +#define semvers_pop(s) \ + (s).data[--(s).length] + +#define semvers_unshift(s, x) \ + (semvers_grow(s,1),memmove((s).data+1,(s).data,(s).length++*sizeof(semver_t)),(s).data[0]=(x)) + +#define semvers_shift(s) \ + semvers_erase(s, 0) + +#define semvers_sort(s) \ + semvers_psort(&(s)) + +#define semvers_rsort(s) \ + semvers_prsort(&(s)) + +#endif /* SV_H__ */ diff --git a/core/src/sv/m4/mm-libtool-library-versions.m4 b/core/src/sv/m4/mm-libtool-library-versions.m4 new file mode 100644 index 000000000..26f4194b0 --- /dev/null +++ b/core/src/sv/m4/mm-libtool-library-versions.m4 @@ -0,0 +1,30 @@ +dnl mm-libtool-library-versions.m4 + +dnl Set version numbers for libraries built with GNU Libtool. +dnl +dnl MM_LIBTOOL_LIBRARY_VERSIONS(stem,current,revision,age) +dnl +AC_DEFUN([MM_LIBTOOL_LIBRARY_VERSIONS], + [$1_VERSION_INTERFACE_CURRENT=$2 + $1_VERSION_INTERFACE_REVISION=$3 + $1_VERSION_INTERFACE_AGE=$4 + AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE], + [$$1_VERSION_INTERFACE_CURRENT.$$1_VERSION_INTERFACE_REVISION.$$1_VERSION_INTERFACE_AGE], + [current interface number]) + AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_CURRENT], + [$$1_VERSION_INTERFACE_CURRENT], + [current interface number]) + AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_REVISION], + [$$1_VERSION_INTERFACE_REVISION], + [current interface implementation number]) + AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_AGE], + [$$1_VERSION_INTERFACE_AGE], + [current interface age number]) + AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_STRING], + ["$$1_VERSION_INTERFACE_CURRENT.$$1_VERSION_INTERFACE_REVISION"], + [library interface version]) + AC_SUBST([$1_VERSION_INTERFACE_CURRENT]) + AC_SUBST([$1_VERSION_INTERFACE_REVISION]) + AC_SUBST([$1_VERSION_INTERFACE_AGE])]) + +dnl end of file diff --git a/core/src/sv/makefile b/core/src/sv/makefile new file mode 100644 index 000000000..b7b8e543e --- /dev/null +++ b/core/src/sv/makefile @@ -0,0 +1,29 @@ +# prefix +include $(PRO_DIR)/prefix.mak + +# module name +NAMES = sv + +# module type +sv_TYPE = LIB + +# config +sv_CONFIG = n + +# core files +sv_C_FILES += \ + src/comp \ + src/id \ + src/num \ + src/range \ + src/semvers \ + src/utils \ + src/version + +# includes +sv_INC_DIRS += include + + +# suffix +include $(PRO_DIR)/suffix.mak + diff --git a/core/src/sv/scripts/libsv.pc.in b/core/src/sv/scripts/libsv.pc.in new file mode 100644 index 000000000..bce3e8982 --- /dev/null +++ b/core/src/sv/scripts/libsv.pc.in @@ -0,0 +1,30 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +bindir=@bindir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +docdir=${prefix}/doc +includedir=@includedir@ +infodir=@infodir@ +htmldir=${docdir} +libdir=@libdir@ +libexecdir=@libexecdir@ +localstatedir=@localstatedir@ +mandir=@mandir@ +sbindir=@sbindir@ +sharedstatedir=@sharedstatedir@ +sysconfdir=@sysconfdir@ + +## ------------------------------------------------------------ + +Name: @PACKAGE_NAME@ +Description: semantic versioning for the C language +Version: @LIBSV_PKG_CONFIG_VERSION@ +Libs: -L${libdir} -lsv +Cflags: -I${includedir} + +### end of file +# Local Variables: +# mode: script +# End: diff --git a/core/src/sv/src/comp.c b/core/src/sv/src/comp.c new file mode 100644 index 000000000..d02fe4dfc --- /dev/null +++ b/core/src/sv/src/comp.c @@ -0,0 +1,382 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "comp.h" +#include "num.h" +#include "id.h" +#include "utils.h" + +static void semver_xrevert(semver_t *semver) { + if (semver->major == SEMVER_NUM_X) { + semver->major = semver->minor = semver->patch = 0; + } else if (semver->minor == SEMVER_NUM_X) { + semver->minor = semver->patch = 0; + } else if (semver->patch == SEMVER_NUM_X) { + semver->patch = 0; + } +} + +static semver_comp_t *semver_xconvert(semver_comp_t *self) { + if (self->version.major == SEMVER_NUM_X) { + self->op = SEMVER_OP_GE; + semver_xrevert(&self->version); + return self; + } + if (self->version.minor == SEMVER_NUM_X) { + semver_xrevert(&self->version); + self->op = SEMVER_OP_GE; + self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); + if (self->next == NULL) { + return NULL; + } + semver_comp_ctor(self->next); + self->next->op = SEMVER_OP_LT; + self->next->version = self->version; + ++self->next->version.major; + return self->next; + } + if (self->version.patch == SEMVER_NUM_X) { + semver_xrevert(&self->version); + self->op = SEMVER_OP_GE; + self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); + if (self->next == NULL) { + return NULL; + } + semver_comp_ctor(self->next); + self->next->op = SEMVER_OP_LT; + self->next->version = self->version; + ++self->next->version.minor; + return self->next; + } + self->op = SEMVER_OP_EQ; + return self; +} + +static char parse_partial(semver_t *self, const char *str, size_t len, size_t *offset) { + semver_ctor(self); + self->major = self->minor = self->patch = SEMVER_NUM_X; + if (*offset < len) { + self->raw = str + *offset; + if (semver_num_read(&self->major, str, len, offset)) { + return 0; + } + if (*offset >= len || str[*offset] != '.') { + return 0; + } + ++*offset; + if (semver_num_read(&self->minor, str, len, offset)) { + return 1; + } + if (*offset >= len || str[*offset] != '.') { + return 0; + } + ++*offset; + if (semver_num_read(&self->patch, str, len, offset)) { + return 1; + } + if ((str[*offset] == '-' && semver_id_read(&self->prerelease, str, len, (++*offset, offset))) + || (str[*offset] == '+' && semver_id_read(&self->build, str, len, (++*offset, offset)))) { + return 1; + } + self->len = str + *offset - self->raw; + return 0; + } + return 0; +} + +static char parse_hiphen(semver_comp_t *self, const char *str, size_t len, size_t *offset) { + semver_t partial; + + if (parse_partial(&partial, str, len, offset)) { + return 1; + } + self->op = SEMVER_OP_GE; + semver_xrevert(&self->version); + self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); + if (self->next == NULL) { + return 1; + } + semver_comp_ctor(self->next); + self->next->op = SEMVER_OP_LT; + if (partial.minor == SEMVER_NUM_X) { + self->next->version.major = partial.major + 1; + } else if (partial.patch == SEMVER_NUM_X) { + self->next->version.major = partial.major; + self->next->version.minor = partial.minor + 1; + } else { + self->next->op = SEMVER_OP_LE; + self->next->version = partial; + } + + return 0; +} + +static char parse_tidle(semver_comp_t *self, const char *str, size_t len, size_t *offset) { + semver_t partial; + + if (parse_partial(&self->version, str, len, offset)) { + return 1; + } + semver_xrevert(&self->version); + self->op = SEMVER_OP_GE; + partial = self->version; + if (partial.major != 0) { + ++partial.major; + partial.minor = partial.patch = 0; + } else if (partial.minor != 0) { + ++partial.minor; + partial.patch = 0; + } else { + ++partial.patch; + } + self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); + if (self->next == NULL) { + return 1; + } + semver_comp_ctor(self->next); + self->next->op = SEMVER_OP_LT; + self->next->version = partial; + return 0; +} + +static char parse_caret(semver_comp_t *self, const char *str, size_t len, size_t *offset) { + semver_t partial; + + if (parse_partial(&self->version, str, len, offset)) { + return 1; + } + semver_xrevert(&self->version); + self->op = SEMVER_OP_GE; + partial = self->version; + if (partial.minor || partial.patch) { + ++partial.minor; + partial.patch = 0; + } else { + ++partial.major; + partial.minor = partial.patch = 0; + } + self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); + if (self->next == NULL) { + return 1; + } + semver_comp_ctor(self->next); + self->next->op = SEMVER_OP_LT; + self->next->version = partial; + return 0; +} + +void semver_comp_ctor(semver_comp_t *self) { +#ifndef _MSC_VER + *self = (semver_comp_t) {0}; +#else + self->next = NULL; + self->op = SEMVER_OP_EQ; + semver_ctor(&self->version); +#endif +} + +void semver_comp_dtor(semver_comp_t *self) { + if (self && self->next) { + semver_comp_dtor(self->next); + free(self->next); + self->next = NULL; + } +} + +char semver_compn(semver_comp_t *self, const char *str, size_t len) { + size_t offset = 0; + + if (len > SV_COMP_MAX_LEN) { + return 1; + } + if (semver_comp_read(self, str, len, &offset) || offset < len) { + semver_comp_dtor(self); + return 1; + } + return 0; +} + +char semver_comp_read(semver_comp_t *self, const char *str, size_t len, size_t *offset) { + semver_comp_ctor(self); + while (*offset < len) { + switch (str[*offset]) { + case '^': + ++*offset; + if (parse_tidle(self, str, len, offset)) { + return 1; + } + self = self->next; + goto next; + case '~': + ++*offset; + if (parse_caret(self, str, len, offset)) { + return 1; + } + self = self->next; + goto next; + case '>': + ++*offset; + if (*offset < len && str[*offset] == '=') { + ++*offset; + self->op = SEMVER_OP_GE; + } else { + self->op = SEMVER_OP_GT; + } + if (parse_partial(&self->version, str, len, offset)) { + return 1; + } + semver_xrevert(&self->version); + goto next; + case '<': + ++*offset; + if (*offset < len && str[*offset] == '=') { + ++*offset; + self->op = SEMVER_OP_LE; + } else { + self->op = SEMVER_OP_LT; + } + if (parse_partial(&self->version, str, len, offset)) { + return 1; + } + semver_xrevert(&self->version); + goto next; + case '=': + ++*offset; + self->op = SEMVER_OP_EQ; + if (parse_partial(&self->version, str, len, offset)) { + return 1; + } + semver_xrevert(&self->version); + goto next; + default: + goto range; + } + } + range: + if (parse_partial(&self->version, str, len, offset)) { + return 1; + } + if (*offset < len && str[*offset] == ' ' + && *offset + 1 < len && str[*offset + 1] == '-' + && *offset + 2 < len && str[*offset + 2] == ' ') { + *offset += 3; + if (parse_hiphen(self, str, len, offset)) { + return 1; + } + self = self->next; + } else { + self = semver_xconvert(self); + if (self == NULL) { + return 1; + } + } + next: + if (*offset < len && str[*offset] == ' ' + && *offset < len + 1 && str[*offset + 1] != ' ' && str[*offset + 1] != '|') { + ++*offset; + if (*offset < len) { + self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); + if (self->next == NULL) { + return 1; + } + return semver_comp_read(self->next, str, len, offset); + } + return 1; + } + return 0; +} + +char semver_and(semver_comp_t *left, const char *str, size_t len) { + semver_comp_t *comp, *tail; + + if (len > 0) { + comp = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); + if (NULL == comp) { + return 1; + } + if (semver_compn(comp, str, len)) { + sv_free(comp); + return 1; + } + if (NULL == left->next) { + left->next = comp; + } else { + tail = left->next; + while (tail->next) tail = tail->next; + tail->next = comp; + } + return 0; + } + return 1; +} + +bool semver_comp_pmatch(const semver_t *self, const semver_comp_t *comp) { + char result = semver_pcmp(self, &comp->version); + + if (result < 0 && comp->op != SEMVER_OP_LT && comp->op != SEMVER_OP_LE) { + return false; + } + if (result > 0 && comp->op != SEMVER_OP_GT && comp->op != SEMVER_OP_GE) { + return false; + } + if (result == 0 && comp->op != SEMVER_OP_EQ && comp->op != SEMVER_OP_LE && comp->op != SEMVER_OP_GE) { + return false; + } + if (comp->next) { + return semver_comp_pmatch(self, comp->next); + } + return true; +} + +bool semver_comp_matchn(const semver_t *self, const char *comp_str, size_t comp_len) { + semver_comp_t comp; + bool result; + + if (semver_compn(&comp, comp_str, comp_len)) { + return false; + } + result = semver_comp_pmatch(self, &comp); + semver_comp_dtor(&comp); + return result; +} + +int semver_comp_pwrite(const semver_comp_t *self, char *buffer, size_t len) { + char semver[SV_COMP_MAX_LEN]; + + semver_write(self->version, semver, SV_COMP_MAX_LEN); + if (self->next) { + char next[SV_COMP_MAX_LEN]; + return snprintf(buffer, len, "%s%s %.*s", + semver_op_string(self->op), semver, semver_comp_pwrite(self->next, next, SV_COMP_MAX_LEN), next + ); + } + return snprintf(buffer, len, "%s%s", semver_op_string(self->op), semver); +} diff --git a/core/src/sv/src/comp.h b/core/src/sv/src/comp.h new file mode 100644 index 000000000..9130ee987 --- /dev/null +++ b/core/src/sv/src/comp.h @@ -0,0 +1,38 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_COMP_H__ +# define SV_COMP_H__ + +#include "version.h" + +#define SV_COMP_MAX_LEN (512) + +void semver_comp_ctor(semver_comp_t *self); +char semver_comp_read(semver_comp_t *self, const char *str, size_t len, size_t *offset); + +#endif /* SV_COMP_H__ */ diff --git a/core/src/sv/src/id.c b/core/src/sv/src/id.c new file mode 100644 index 000000000..9341eb02c --- /dev/null +++ b/core/src/sv/src/id.c @@ -0,0 +1,141 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdio.h> + +#include "id.h" + +void semver_id_ctor(semver_id_t *self) { +#ifndef _MSC_VER + *self = (semver_id_t) {true}; +#else + self->next = NULL; + self->len = 0; + self->raw = NULL; + self->num = 0; + self->numeric = true; +#endif +} + +void semver_id_dtor(semver_id_t *self) { + if (self && self->next) { + semver_id_dtor(self->next); + sv_free(self->next); + self->next = NULL; + } +} + +char semver_id_read(semver_id_t *self, const char *str, size_t len, size_t *offset) { + size_t i = 0; + char is_zero = 0; + + semver_id_ctor(self); + while (*offset < len) { + if (isalnum(str[*offset]) || str[*offset] == '-') { + if (!isdigit(str[*offset])) { + is_zero = 0; + self->numeric = false; + } else { + if (i == 0) { + is_zero = str[*offset] == '0'; + } else if (is_zero) { + return 1; + } + } + ++i, ++*offset; + continue; + } + break; + } + if (!i) { + return 1; + } + self->raw = str + *offset - i; + self->len = i; + if (!is_zero && self->numeric) { + self->num = (int) strtol(self->raw, NULL, 0); + } + if (str[*offset] == '.') { + self->next = (semver_id_t *) sv_malloc(sizeof(semver_id_t)); + if (self->next == NULL) { + return 1; + } + ++*offset; + return semver_id_read(self->next, str, len, offset); + } + return 0; +} + +char semver_id_pcmp(const semver_id_t *self, const semver_id_t *other) { + char s; + + if (self->len && !other->len) { + return -1; + } + if (!self->len && other->len) { + return 1; + } + if (!self->len) { + return 0; + } + + if (self->numeric && other->numeric) { + if (self->num > other->num) { + return 1; + } + if (self->num < other->num) { + return -1; + } + } else if ((s = (char) memcmp(self->raw, other->raw, self->len > other->len ? self->len : other->len)) != 0) { + return s; + } + + if (!self->next && other->next) { + return -1; + } + if (self->next && !other->next) { + return 1; + } + if (!self->next) { + return 0; + } + + return semver_id_pcmp(self->next, other->next); +} + +int semver_id_pwrite(const semver_id_t *self, char *buffer, size_t len) { + if (self->next) { + char next[SV_MAX_LEN]; + return snprintf(buffer, len, "%.*s.%.*s", + (int) self->len, self->raw, semver_id_pwrite(self->next, next, SV_MAX_LEN), next + ); + } + return snprintf(buffer, len, "%.*s", (int) self->len, self->raw); +} diff --git a/core/src/sv/src/id.h b/core/src/sv/src/id.h new file mode 100644 index 000000000..914b4c237 --- /dev/null +++ b/core/src/sv/src/id.h @@ -0,0 +1,42 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_ID_H__ +# define SV_ID_H__ + +#include "version.h" + +void semver_id_ctor(semver_id_t *self); +void semver_id_dtor(semver_id_t *self); +char semver_id_read(semver_id_t *self, const char *str, size_t len, size_t *offset); +int semver_id_pwrite(const semver_id_t *self, char *buffer, size_t len); +char semver_id_pcmp(const semver_id_t *self, const semver_id_t *other); + +#define semver_id_write(self, buffer, len) semver_id_pwrite(&(self), buffer, len) +#define semver_id_comp(self, other) semver_id_pcmp(&(self), &(other)) + +#endif /* SV_ID_H__ */ diff --git a/core/src/sv/src/num.c b/core/src/sv/src/num.c new file mode 100644 index 000000000..34410cbfa --- /dev/null +++ b/core/src/sv/src/num.c @@ -0,0 +1,75 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <string.h> +#include <stdlib.h> +#include <ctype.h> + +#include "num.h" + +char semver_num_read(int *self, const char *str, size_t len, size_t *offset) { + char *endptr; + + *self = 0; + if (*offset >= len) { + return 1; + } + switch (str[*offset]) { + case 'x': + case 'X': + case '*': + *self = SEMVER_NUM_X; + ++*offset; + break; + case '0': + ++*offset; + if (*offset < len && isdigit(str[*offset])) { + return 1; + } + *self = 0; + break; + default: + if (isdigit(str[*offset])) { + *self = (int) strtol(str + *offset, &endptr, 0); + *offset += endptr - str - *offset; + } else { + return 1; + } + break; + } + return 0; +} + +char semver_num_cmp(int self, int other) { + if (self > other) { + return 1; + } + if (self < other) { + return -1; + } + return 0; +} diff --git a/core/src/sv/src/num.h b/core/src/sv/src/num.h new file mode 100644 index 000000000..12c4b694c --- /dev/null +++ b/core/src/sv/src/num.h @@ -0,0 +1,36 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_NUM_H__ +# define SV_NUM_H__ + +#include "version.h" + +char semver_num_read(int *self, const char *str, size_t len, size_t *offset); +char semver_num_cmp(int self, int other); + +#endif /* SV_NUM_H__ */ diff --git a/core/src/sv/src/range.c b/core/src/sv/src/range.c new file mode 100644 index 000000000..c23a9ae81 --- /dev/null +++ b/core/src/sv/src/range.c @@ -0,0 +1,135 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "range.h" +#include "comp.h" + +void semver_range_ctor(semver_range_t *self) { +#ifndef _MSC_VER + *self = (semver_range_t) {0}; +#else + self->next = NULL; + semver_comp_ctor(&self->comp); +#endif +} + +void semver_range_dtor(semver_range_t *self) { + if (self && self->next) { + semver_range_dtor(self->next); + sv_free(self->next); + self->next = NULL; + } +} + +char semver_rangen(semver_range_t *self, const char *str, size_t len) { + size_t offset = 0; + + if (len > SV_RANGE_MAX_LEN) { + return 1; + } + if (semver_range_read(self, str, len, &offset) || offset < len) { + semver_range_dtor(self); + return 1; + } + return 0; +} + +char semver_range_read(semver_range_t *self, const char *str, size_t len, size_t *offset) { + semver_range_ctor(self); + if (semver_comp_read(&self->comp, str, len, offset)) { + return 1; + } + while (*offset < len && str[*offset] == ' ') ++*offset; + if (*offset < len && str[*offset] == '|' + && *offset + 1 < len && str[*offset + 1] == '|') { + *offset += 2; + while (*offset < len && str[*offset] == ' ') ++*offset; + self->next = (semver_range_t *) sv_malloc(sizeof(semver_range_t)); + if (self->next == NULL) { + return 1; + } + return semver_range_read(self->next, str, len, offset); + } + return 0; +} + +char semver_or(semver_range_t *left, const char *str, size_t len) { + semver_range_t *range, *tail; + + if (len > 0) { + range = (semver_range_t *) sv_malloc(sizeof(semver_range_t)); + if (NULL == range) { + return 1; + } + if (semver_rangen(range, str, len)) { + sv_free(range); + return 1; + } + if (NULL == left->next) { + left->next = range; + } else { + tail = left->next; + while (tail->next) tail = tail->next; + tail->next = range; + } + return 0; + } + return 1; +} + +bool semver_range_pmatch(const semver_t *self, const semver_range_t *range) { + return semver_comp_pmatch(self, &range->comp) ? true : range->next ? semver_range_pmatch(self, range->next) : false; +} + +bool semver_range_matchn(const semver_t *self, const char *range_str, size_t range_len) { + semver_range_t range; + bool result; + + if (semver_rangen(&range, range_str, range_len)) { + return false; + } + result = semver_range_pmatch(self, &range); + semver_range_dtor(&range); + return result; +} + +int semver_range_pwrite(const semver_range_t *self, char *buffer, size_t len) { + char comp[SV_RANGE_MAX_LEN]; + + if (self->next) { + char next[SV_RANGE_MAX_LEN]; + return snprintf(buffer, len, "%.*s || %.*s", + semver_comp_write(self->comp, comp, SV_RANGE_MAX_LEN), comp, + semver_range_pwrite(self->next, next, SV_RANGE_MAX_LEN), next + ); + } + return snprintf(buffer, len, "%.*s", semver_comp_write(self->comp, comp, SV_RANGE_MAX_LEN), comp); +} diff --git a/core/src/sv/src/range.h b/core/src/sv/src/range.h new file mode 100644 index 000000000..2c8f0974e --- /dev/null +++ b/core/src/sv/src/range.h @@ -0,0 +1,38 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_RANGE_H__ +# define SV_RANGE_H__ + +#include "version.h" + +#define SV_RANGE_MAX_LEN (512) + +void semver_range_ctor(semver_range_t *self); +char semver_range_read(semver_range_t *self, const char *str, size_t len, size_t *offset); + +#endif /* SV_RANGE_H__ */ diff --git a/core/src/sv/src/semvers.c b/core/src/sv/src/semvers.c new file mode 100644 index 000000000..f8ce9ac9d --- /dev/null +++ b/core/src/sv/src/semvers.c @@ -0,0 +1,108 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "semvers.h" + +#define ISPOW2(n) (((n) & -(n)) == (n)) + +uint32_t semvers_pgrowth(semvers_t *self, const int32_t nmin) { + if (nmin > 0) { + uint32_t unmin = (uint32_t) nmin; + + if (self->capacity) { + if (self->capacity < unmin) { + if (ISPOW2(nmin)) { + self->capacity = unmin; + } else { + do self->capacity *= 2; while (self->capacity < unmin); + } + self->data = (semver_t *) realloc((char *) self->data, sizeof(semver_t) * self->capacity); + } + } else { + if (unmin == SEMVERS_MIN_CAP || (unmin > SEMVERS_MIN_CAP && ISPOW2(nmin))) { + self->capacity = unmin; + } else { + self->capacity = SEMVERS_MIN_CAP; + while (self->capacity < unmin) self->capacity *= 2; + } + self->data = (semver_t *) sv_malloc(sizeof(semver_t) * self->capacity); + } + return unmin; + } + return 0; +} + +semver_t semvers_perase(semvers_t *self, uint32_t i) { + semver_t x = self->data[i]; + + memmove(self->data + i, self->data + i + 1, --self->length * sizeof(semver_t)); + return x; +} + +static int semvers_qsort_fn(const void *a, const void *b) { + return semver_pcmp((semver_t *) a, (semver_t *) b); +} + +void semvers_psort(semvers_t *self) { + qsort((char *) self->data, self->length, sizeof(semver_t), semvers_qsort_fn); +} + +static int semvers_rqsort_fn(const void *a, const void *b) { + return semver_pcmp((semver_t *) b, (semver_t *) a); +} + +void semvers_prsort(semvers_t *self) { + qsort((char *) self->data, self->length, sizeof(semver_t), semvers_rqsort_fn); +} + +void semvers_pdtor(semvers_t *self) { + if (self->data) { + uint32_t i; + + for (i = 0; i < self->length; ++i) { + semver_dtor(self->data + i); + } + sv_free(self->data); + self->data = NULL; + } + self->length = self->capacity = 0; +} + +void semvers_pclear(semvers_t *self) { + if (self->data) { + uint32_t i; + + for (i = 0; i < self->length; ++i) { + semver_dtor(self->data + i); + } + memset((char *) self->data, 0, self->length * sizeof(semver_t)); + } + self->length = 0; +} diff --git a/core/src/sv/src/semvers.h b/core/src/sv/src/semvers.h new file mode 100644 index 000000000..6803380b4 --- /dev/null +++ b/core/src/sv/src/semvers.h @@ -0,0 +1,35 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_SEMVERS_H__ +# define SV_SEMVERS_H__ + +#include "semver.h" + +#define SEMVERS_MIN_CAP (4) + +#endif /* SV_SEMVERS_H__ */ diff --git a/core/src/sv/src/utils.c b/core/src/sv/src/utils.c new file mode 100644 index 000000000..166cbe83f --- /dev/null +++ b/core/src/sv/src/utils.c @@ -0,0 +1,96 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "utils.h" +#include "comp.h" +#include "range.h" + +/*!\brief Serialise the version to the STREAM. When successful: return the + * number of bytes written and set "errno" to zero. When unsuccessful: + * set "errno" to an error code. + */ +size_t semver_fwrite(const semver_t *self, FILE *stream) { + char buffer[SV_MAX_LEN]; + int cs; + + if ((cs = semver_pwrite(self, buffer, SV_MAX_LEN)) == 0) { + return 0; + } + errno = 0; + return fwrite(buffer, sizeof(char), (size_t) cs, stream); +} + +/*!\brief Serialise the comparator to the STREAM. When successful: return the + * number of bytes written and set "errno" to zero. When unsuccessful: + * set "errno" to an error code. + */ +size_t semver_comp_fwrite(const semver_comp_t *self, FILE *stream) { + char buffer[SV_COMP_MAX_LEN]; + int cs; + + if ((cs = semver_comp_pwrite(self, buffer, SV_COMP_MAX_LEN)) == 0) { + return 0; + } + errno = 0; + return fwrite(buffer, sizeof(char), (size_t) cs, stream); +} + +/*!\brief Serialise the range to the STREAM. When successful: return the + * number of bytes written and set "errno" to zero. When unsuccessful: + * set "errno" to an error code. + */ +size_t semver_range_fwrite(const semver_range_t *self, FILE *stream) { + char buffer[SV_RANGE_MAX_LEN]; + int cs; + + if ((cs = semver_range_pwrite(self, buffer, SV_RANGE_MAX_LEN)) == 0) { + return 0; + } + errno = 0; + return fwrite(buffer, sizeof(char), (size_t) cs, stream); +} + +const char *semver_op_string(enum semver_op op) { + switch (op) { + case SEMVER_OP_EQ: + return ""; + case SEMVER_OP_LT: + return "<"; + case SEMVER_OP_LE: + return "<="; + case SEMVER_OP_GT: + return ">"; + case SEMVER_OP_GE: + return ">="; + default: + return NULL; + } +} diff --git a/core/src/sv/src/utils.h b/core/src/sv/src/utils.h new file mode 100644 index 000000000..5f09529a6 --- /dev/null +++ b/core/src/sv/src/utils.h @@ -0,0 +1,35 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_UTILS_H__ +# define SV_UTILS_H__ + +#include "version.h" + +const char *semver_op_string(enum semver_op op); + +#endif /* SV_UTILS_H__ */ diff --git a/core/src/sv/src/version.c b/core/src/sv/src/version.c new file mode 100644 index 000000000..6670a4287 --- /dev/null +++ b/core/src/sv/src/version.c @@ -0,0 +1,175 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <string.h> +#include <stdio.h> + +#include "version.h" +#include "num.h" +#include "id.h" + +void semver_ctor(semver_t *self) { +#ifndef _MSC_VER + *self = (semver_t) {0}; +#else + self->len = 0; + self->raw = NULL; + self->major = 0; + self->minor = 0; + self->patch = 0; + semver_id_ctor(&self->prerelease); + semver_id_ctor(&self->build); +#endif +} + +void semver_dtor(semver_t *self) { + semver_id_dtor(&self->prerelease); + semver_id_dtor(&self->build); +} + +char semvern(semver_t *self, const char *str, size_t len) { + size_t offset = 0; + + if (len > SV_MAX_LEN) { + return 1; + } + if (semver_read(self, str, len, &offset) || offset < len) { + semver_dtor(self); + return 1; + } + return 0; +} + +char semver_tryn(semver_t *self, const char *str, size_t len) { + size_t offset = 0; + + if (len > SV_MAX_LEN) { + return 1; + } + if (semver_try_read(self, str, len, &offset) || offset < len) { + semver_dtor(self); + return 1; + } + return 0; +} + +char semver_read(semver_t *self, const char *str, size_t len, size_t *offset) { + if (*offset < len) { + semver_ctor(self); + self->raw = str + *offset; + if (str[*offset] == 'v') { + ++*offset; + } + if (semver_num_read(&self->major, str, len, offset) || self->major == SEMVER_NUM_X + || *offset >= len || str[*offset] != '.' + || semver_num_read(&self->minor, str, len, (++*offset, offset)) || self->minor == SEMVER_NUM_X + || *offset >= len || str[*offset] != '.' + || semver_num_read(&self->patch, str, len, (++*offset, offset)) || self->patch == SEMVER_NUM_X + || (str[*offset] == '-' && semver_id_read(&self->prerelease, str, len, (++*offset, offset))) + || (str[*offset] == '+' && semver_id_read(&self->build, str, len, (++*offset, offset)))) { + self->len = str + *offset - self->raw; + return 1; + } + self->len = str + *offset - self->raw; + return 0; + } + return 1; +} + +char semver_try_read(semver_t *self, const char *str, size_t len, size_t *offset) { + if (*offset < len) { + semver_ctor(self); + self->raw = str + *offset; + if (str[*offset] == 'v') { + ++*offset; + } + if (semver_num_read(&self->major, str, len, offset) || self->major == SEMVER_NUM_X) { + fail: + self->len = str + *offset - self->raw; + return 1; + } + if (*offset < len && str[*offset] == '.' + && (semver_num_read(&self->minor, str, len, (++*offset, offset)) || self->minor == SEMVER_NUM_X)) { + goto fail; + } + if (*offset < len && str[*offset] == '.' + && (semver_num_read(&self->patch, str, len, (++*offset, offset)) || self->patch == SEMVER_NUM_X)) { + goto fail; + } + if (*offset < len && str[*offset] == '-') { + ++*offset; + } + semver_id_read(&self->prerelease, str, len, offset); + if (*offset < len && str[*offset] == '+') { + ++*offset; + } + semver_id_read(&self->build, str, len, offset); + self->len = str + *offset - self->raw; + return 0; + } + return 1; +} + +char semver_pcmp(const semver_t *self, const semver_t *other) { + char result; + + if ((result = semver_num_cmp(self->major, other->major)) != 0) { + return result; + } + if ((result = semver_num_cmp(self->minor, other->minor)) != 0) { + return result; + } + if ((result = semver_num_cmp(self->patch, other->patch)) != 0) { + return result; + } + return semver_id_comp(self->prerelease, other->prerelease); +} + +int semver_pwrite(const semver_t *self, char *buffer, size_t len) { + char prerelease[SV_MAX_LEN], build[SV_MAX_LEN]; + + if (self->prerelease.len && self->build.len) { + return snprintf(buffer, len, "%d.%d.%d-%.*s+%.*s", + self->major, self->minor, self->patch, + semver_id_write(self->prerelease, prerelease, SV_MAX_LEN), prerelease, + semver_id_write(self->build, build, SV_MAX_LEN), build + ); + } + if (self->prerelease.len) { + return snprintf(buffer, len, "%d.%d.%d-%.*s", + self->major, self->minor, self->patch, + semver_id_write(self->prerelease, prerelease, SV_MAX_LEN), prerelease + ); + } + if (self->build.len) { + return snprintf(buffer, len, "%d.%d.%d+%.*s", + self->major, self->minor, self->patch, + semver_id_write(self->build, build, SV_MAX_LEN), build + ); + } + return snprintf(buffer, len, "%d.%d.%d", self->major, self->minor, self->patch); +} diff --git a/core/src/sv/src/version.h b/core/src/sv/src/version.h new file mode 100644 index 000000000..df1abe5c2 --- /dev/null +++ b/core/src/sv/src/version.h @@ -0,0 +1,43 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#ifndef SV_VERSION_H__ +# define SV_VERSION_H__ + +#include "semver.h" + +#ifdef _MSC_VER +# define snprintf(s, maxlen, fmt, ...) _snprintf_s(s, _TRUNCATE, maxlen, fmt, __VA_ARGS__) +#endif + +#define SV_MAX_LEN (256) + +void semver_ctor(semver_t *self); +char semver_read(semver_t *self, const char *str, size_t len, size_t *offset); +char semver_try_read(semver_t *self, const char *str, size_t len, size_t *offset); + +#endif /* SV_VERSION_H__ */ diff --git a/core/src/sv/test/CMakeLists.txt b/core/src/sv/test/CMakeLists.txt new file mode 100644 index 000000000..89d4a0eec --- /dev/null +++ b/core/src/sv/test/CMakeLists.txt @@ -0,0 +1,27 @@ +add_executable(version version.c) +target_link_libraries(version ${PROJECT_NAME}) +add_test(version version) + +add_executable(comp comp.c) +target_link_libraries(comp ${PROJECT_NAME}) +add_test(comp comp) + +add_executable(range range.c) +target_link_libraries(range ${PROJECT_NAME}) +add_test(range range) + +add_executable(match match.c) +target_link_libraries(match ${PROJECT_NAME}) +add_test(match match) + +add_executable(utils utils.c) +target_link_libraries(utils ${PROJECT_NAME}) +add_test(utils utils) + +add_executable(usage usage.c) +target_link_libraries(usage ${PROJECT_NAME}) +add_test(usage usage) + +add_executable(semvers semvers.c) +target_link_libraries(semvers ${PROJECT_NAME}) +add_test(semvers semvers) diff --git a/core/src/sv/test/comp.c b/core/src/sv/test/comp.c new file mode 100644 index 000000000..faa68a500 --- /dev/null +++ b/core/src/sv/test/comp.c @@ -0,0 +1,333 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "semver.h" + +#define STRNSIZE(s) (s), sizeof(s)-1 + +int test_read(const char *expected, const char *str, size_t len) { + unsigned slen; + char buffer[1024]; + semver_comp_t comp = {0}; + + printf("test: `%.*s`", (int) len, str); + if (semver_compn(&comp, str, len)) { + puts(" \tcouldn't parse"); + return 1; + } + slen = (unsigned) semver_comp_write(comp, buffer, 1024); + printf(" \t=> \t`%.*s`", slen, buffer); + if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { + printf(" != `%s`\n", expected); + semver_comp_dtor(&comp); + return 1; + } + printf(" == `%s`\n", expected); + semver_comp_dtor(&comp); + return 0; +} + +int test_and(const char *expected, const char *base_str, size_t base_len, const char *str, size_t len) { + unsigned slen; + char buffer[1024]; + semver_comp_t comp = {0}; + + printf("test and: `%.*s`", (int) base_len, base_str); + if (semver_compn(&comp, base_str, base_len)) { + puts(" \tcouldn't parse"); + return 1; + } + if (semver_and(&comp, str, len)) { + puts(" \tand failed"); + return 1; + } + slen = (unsigned) semver_comp_write(comp, buffer, 1024); + printf(" \t=> \t`%.*s`", slen, buffer); + if (memcmp(expected, buffer, (size_t) slen > base_len + len + 1 ? slen : base_len + len + 1) != 0) { + printf(" != `%s`\n", expected); + semver_comp_dtor(&comp); + return 1; + } + printf(" == `%s`\n", expected); + semver_comp_dtor(&comp); + return 0; +} + +int main(void) { + puts("failure:"); + if (test_read("", STRNSIZE("* ")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("* ")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("* |")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("* || *")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("abc")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE(">")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("<=")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("~")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("^")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("=")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE(">a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("<a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("~a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("^a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("=a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE(">1.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("<1.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("~1.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("^1.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("=1.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3 ")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3 -")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3 - ")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3 -a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3 - a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3 - 1.2.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("a.2.3")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.a.3")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3-")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3-alpha+")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("1.2.3+")) == 0) { + return EXIT_FAILURE; + } + if (test_read("1.2.3", STRNSIZE("1.2.3"))) { + return EXIT_FAILURE; + } + + puts("\nsome prerelease and build:"); + if (test_read(">=0.0.0 1.2.3-alpha", STRNSIZE("* 1.2.3-alpha"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 1.2.3-alpha.2", STRNSIZE("* 1.2.3-alpha.2"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 1.2.3+77", STRNSIZE("* 1.2.3+77"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 1.2.3+77.2", STRNSIZE("* 1.2.3+77.2"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 1.2.3-alpha.2+77", STRNSIZE("* 1.2.3-alpha.2+77"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 1.2.3-alpha.2+77.2", STRNSIZE("* 1.2.3-alpha.2+77.2"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 1.2.3-al-pha.2+77", STRNSIZE("* 1.2.3-al-pha.2+77"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 1.2.3-al-pha.2+77.2", STRNSIZE("* 1.2.3-al-pha.2+77.2"))) { + return EXIT_FAILURE; + } + + puts("\nx-range:"); + if (test_read(">=0.0.0", STRNSIZE("*"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.0.0 <2.0.0", STRNSIZE("1.x"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <1.3.0", STRNSIZE("1.2.x"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0", STRNSIZE(""))) { + return EXIT_FAILURE; + } + if (test_read(">=1.0.0 <2.0.0", STRNSIZE("1"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <1.3.0", STRNSIZE("1.2"))) { + return EXIT_FAILURE; + } + + puts("\nhyphen:"); + if (test_read(">=1.2.3 <=2.3.4", STRNSIZE("1.2.3 - 2.3.4"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <=2.3.4", STRNSIZE("1.2 - 2.3.4"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.3 <2.4.0", STRNSIZE("1.2.3 - 2.3"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.3 <3.0.0", STRNSIZE("1.2.3 - 2"))) { + return EXIT_FAILURE; + } + + puts("\ntidle:"); + if (test_read(">=1.2.3 <1.3.0", STRNSIZE("~1.2.3"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <1.3.0", STRNSIZE("~1.2"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.0.0 <2.0.0", STRNSIZE("~1"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.2.3 <0.3.0", STRNSIZE("~0.2.3"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.2.0 <0.3.0", STRNSIZE("~0.2"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 <1.0.0", STRNSIZE("~0"))) { + return EXIT_FAILURE; + } + + puts("\ncaret:"); + if (test_read(">=1.2.3 <2.0.0", STRNSIZE("^1.2.3"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.2.3 <0.3.0", STRNSIZE("^0.2.3"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.3 <0.0.4", STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + + puts("\nprimitive:"); + if (test_read(">=1.2.3 <2.0.0", STRNSIZE(">=1.2.3 <2.0"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.2.3 <0.3.0", STRNSIZE(">=0.2.3 <0.3"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.5.0 <0.0.4", STRNSIZE(">=0.5 <0.0.4"))) { + return EXIT_FAILURE; + } + if (test_read(">0.0.3", STRNSIZE(">0.0.3"))) { + return EXIT_FAILURE; + } + if (test_read("0.0.3", STRNSIZE("=0.0.3"))) { + return EXIT_FAILURE; + } + if (test_read("9.0.0", STRNSIZE("=9"))) { + return EXIT_FAILURE; + } + + puts("\nand:"); + if (test_and(">=0.0.0 >=0.0.3 <0.0.4", STRNSIZE("*"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_and(">=1.0.0 <2.0.0 >=0.0.3 <0.0.4", STRNSIZE("1.x"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_and(">=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2.x"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_and(">=1.2.0 <1.3.0 >=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2 1.2.x"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_and(">=1.0.0 <2.0.0 >=0.0.3 <0.0.4", STRNSIZE("1"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_and(">=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_and("", STRNSIZE("1.2"), STRNSIZE("")) == 0) { + return EXIT_FAILURE; + } + if (test_and("", STRNSIZE("1.2"), STRNSIZE("a")) == 0) { + return EXIT_FAILURE; + } + if (test_and("", STRNSIZE("1.2"), STRNSIZE("1.2.x abc")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " + "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" + "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) + == 0) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/sv/test/match.c b/core/src/sv/test/match.c new file mode 100644 index 000000000..d960bb7fc --- /dev/null +++ b/core/src/sv/test/match.c @@ -0,0 +1,357 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "semver.h" + +#define STRNSIZE(s) (s), sizeof(s)-1 + +int test_matchn(bool expected, const char *semver_str, size_t semver_len, const char *comp_str, size_t comp_len) { + bool result; + semver_t semver = {0}; + + printf("test: `%.*s` ^ `%.*s`", (int) semver_len, semver_str, (int) comp_len, comp_str); + if (semvern(&semver, semver_str, semver_len)) { + puts(" \tcouldn't parse semver"); + return 1; + } + result = semver_comp_matchn(&semver, comp_str, comp_len); + printf(" \t=> %d\t", result); + if (result != expected) { + printf(" != `%d`\n", expected); + semver_dtor(&semver); + return 1; + } + printf(" == `%d`\n", expected); + semver_dtor(&semver); + return 0; +} + +int test_rmatchn(bool expected, const char *semver_str, size_t semver_len, const char *range_str, size_t range_len) { + bool result; + semver_t semver = {0}; + + printf("test: `%.*s` ^ `%.*s`", (int) semver_len, semver_str, (int) range_len, range_str); + if (semvern(&semver, semver_str, semver_len)) { + puts(" \tcouldn't parse semver"); + return 1; + } + result = semver_range_matchn(&semver, range_str, range_len); + printf(" \t=> %d\t", result); + if (result != expected) { + printf(" != `%d`\n", expected); + semver_dtor(&semver); + return 1; + } + printf(" == `%d`\n", expected); + semver_dtor(&semver); + return 0; +} + +int main(void) { + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.2.3"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.2.x"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.x.x"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.x"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("*"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE(">1"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">2"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">=2"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<1"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<=1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE(">=1.2.3"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">1.2.3"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<1.2.3"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("<=1.2.3"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("2.x"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<0.0.1-99"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<=0.0.1-99"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<=0.0.1-98"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("=0.0.1-98"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">=0.0.1-98"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">=0.0.1-97"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">0.0.1-97"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha"), STRNSIZE("0.0.1-alpha"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<0.0.1-99"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<0.0.1-alpha.99"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.99"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.98"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("=0.0.1-alpha.98"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.98"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.97"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">0.0.1-alpha.97"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<=0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">=0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.2.3"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.2.x"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.x.x"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.x"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || *"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >2"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >=2"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <=1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >=1.2.3"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >1.2.3"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <1.2.3"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <=1.2.3"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 2.x"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <0.0.1-99"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <=0.0.1-99"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <=0.0.1-98"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || =0.0.1-98"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >=0.0.1-98"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >=0.0.1-97"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >0.0.1-97"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha"), STRNSIZE("9.x || 0.0.1-alpha"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <0.0.1-99"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <0.0.1-alpha.99"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.99"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.98"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || =0.0.1-alpha.98"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.98"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.97"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >0.0.1-alpha.97"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || =0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <=0.0.1-alpha.99.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || =0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >=0.0.1-alpha.98.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >=0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >0.0.1-alpha.97.1"))) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/sv/test/range.c b/core/src/sv/test/range.c new file mode 100644 index 000000000..17611ab25 --- /dev/null +++ b/core/src/sv/test/range.c @@ -0,0 +1,200 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "semver.h" + +#define STRNSIZE(s) (s), sizeof(s)-1 + +int test_read(const char *expected, const char *str, size_t len) { + unsigned slen; + char buffer[1024]; + semver_range_t range = {0}; + + printf("test: `%.*s`", (int) len, str); + if (semver_rangen(&range, str, len)) { + puts(" \tcouldn't parse"); + return 1; + } + slen = (unsigned) semver_range_write(range, buffer, 1024); + printf(" \t=> \t`%.*s`", slen, buffer); + if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { + printf(" != `%s`\n", expected); + semver_range_dtor(&range); + return 1; + } + printf(" == `%s`\n", expected); + semver_range_dtor(&range); + return 0; +} + +int test_or(const char *expected, const char *base_str, size_t base_len, const char *str, size_t len) { + unsigned slen; + char buffer[1024]; + semver_range_t range = {0}; + + printf("test and: `%.*s`", (int) base_len, base_str); + if (semver_rangen(&range, base_str, base_len)) { + puts(" \tcouldn't parse base"); + return 1; + } + if (semver_or(&range, str, len)) { + puts(" \tand failed"); + return 1; + } + slen = (unsigned) semver_range_write(range, buffer, 1024); + printf(" \t=> \t`%.*s`", slen, buffer); + if (memcmp(expected, buffer, (size_t) slen > base_len + len + 1 ? slen : base_len + len + 1) != 0) { + printf(" != `%s`\n", expected); + semver_range_dtor(&range); + return 1; + } + printf(" == `%s`\n", expected); + semver_range_dtor(&range); + return 0; +} + +int main(void) { + puts("failure:"); + if (test_read("", STRNSIZE("* |")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("* ||a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("* || a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("* || 1.a")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " + "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" + "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) + == 0) { + return EXIT_FAILURE; + } + + puts("\nx-range:"); + if (test_read(">=0.0.0 || 1.2.3", STRNSIZE("* || 1.2.3"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.0.0 <2.0.0 || >=2.0.0 <3.0.0", STRNSIZE("1.x || 2.x"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <1.3.0 || 3.0.0", STRNSIZE("1.2.x || 3.0.0"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0", STRNSIZE(""))) { + return EXIT_FAILURE; + } + if (test_read(">=1.0.0 <2.0.0 || >=2.0.0 <3.0.0 || >=3.0.0 <4.0.0", STRNSIZE("1 || 2 || 3"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <1.3.0 || >=5.0.0", STRNSIZE("1.2 || >=5"))) { + return EXIT_FAILURE; + } + + puts("\nhyphen:"); + if (test_read(">=1.2.3 <=2.3.4 || >=5.0.0", STRNSIZE("1.2.3 - 2.3.4 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <=2.3.4 || >=5.0.0", STRNSIZE("1.2 - 2.3.4 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.3 <2.4.0 || >=5.0.0", STRNSIZE("1.2.3 - 2.3 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.3 <3.0.0 || >=5.0.0", STRNSIZE("1.2.3 - 2 || >=5"))) { + return EXIT_FAILURE; + } + + puts("\ntidle:"); + if (test_read(">=1.2.3 <1.3.0 || >=5.0.0", STRNSIZE("~1.2.3 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.2.0 <1.3.0 || >=5.0.0", STRNSIZE("~1.2 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=1.0.0 <2.0.0 || >=5.0.0", STRNSIZE("~1 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.2.3 <0.3.0 || >=5.0.0", STRNSIZE("~0.2.3 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.2.0 <0.3.0 || >=5.0.0", STRNSIZE("~0.2 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.0 <1.0.0 || >=5.0.0", STRNSIZE("~0 || >=5"))) { + return EXIT_FAILURE; + } + + puts("\ncaret:"); + if (test_read(">=1.2.3 <2.0.0 || >=5.0.0", STRNSIZE("^1.2.3 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.2.3 <0.3.0 || >=5.0.0", STRNSIZE("^0.2.3 || >=5"))) { + return EXIT_FAILURE; + } + if (test_read(">=0.0.3 <0.0.4 || >=5.0.0", STRNSIZE("^0.0.3 || >=5"))) { + return EXIT_FAILURE; + } + + puts("\nand:"); + if (test_or(">=0.0.0 || >=0.0.3 <0.0.4", STRNSIZE("*"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_or(">=1.0.0 <2.0.0 || >=0.0.3 <0.0.4", STRNSIZE("1.x"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_or(">=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2.x"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_or(">=1.2.0 <1.3.0 || >=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2 || 1.2.x"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_or(">=1.0.0 <2.0.0 || >=0.0.3 <0.0.4", STRNSIZE("1"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_or(">=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2"), STRNSIZE("^0.0.3"))) { + return EXIT_FAILURE; + } + if (test_or("", STRNSIZE("1.2"), STRNSIZE("")) == 0) { + return EXIT_FAILURE; + } + if (test_or("", STRNSIZE("1.2"), STRNSIZE("a")) == 0) { + return EXIT_FAILURE; + } + if (test_or("", STRNSIZE("1.2"), STRNSIZE("1.2.x || abc")) == 0) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/sv/test/semver.c b/core/src/sv/test/semver.c new file mode 100644 index 000000000..762f4ce40 --- /dev/null +++ b/core/src/sv/test/semver.c @@ -0,0 +1,106 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <semver.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define STRNSIZE(s) (s), sizeof(s)-1 + +int test_semver(const char *expected, const char *str, size_t len) { + size_t offset = 0; + unsigned slen; + char buffer[1024]; + semver_t semver = {0}; + + printf("test: `%.*s`", (int) len, str); + if (semver_read(&semver, str, len, &offset)) { + puts(" \tcouldn't parse"); + return 1; + } + slen = (unsigned) semver_write(semver, buffer, 1024); + printf(" \t=> \t`%.*s`", slen, buffer); + if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { + printf(" != `%s`\n", expected); + semver_dtor(&semver); + return 1; + } + printf(" == `%s`\n", expected); + semver_dtor(&semver); + return 0; +} + +int main(void) { + if (test_semver("1.2.3", STRNSIZE("1.2.3"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3+77", STRNSIZE("v1.2.3+77"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) { + return EXIT_FAILURE; + } + if (test_semver("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) { + return EXIT_FAILURE; + } + if (test_semver("", STRNSIZE("")) == 0) { + return EXIT_FAILURE; + } + if (test_semver("", STRNSIZE("vv1.2.3")) == 0) { + return EXIT_FAILURE; + } + if (test_semver("", STRNSIZE("v1.2")) == 0) { + return EXIT_FAILURE; + } + if (test_semver("", STRNSIZE("v1.2.x")) == 0) { + return EXIT_FAILURE; + } + if (test_semver("", STRNSIZE("v1.2.3-")) == 0) { + return EXIT_FAILURE; + } + if (test_semver("", STRNSIZE("v1.2.3+")) == 0) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/sv/test/semvers.c b/core/src/sv/test/semvers.c new file mode 100644 index 000000000..fec6072bd --- /dev/null +++ b/core/src/sv/test/semvers.c @@ -0,0 +1,115 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdlib.h> +#include <assert.h> + +#include "semver.h" + +#define STRNSIZE(s) (s), sizeof(s)-1 + +int main(void) { + semver_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10; + semvers_t semvers = {0}; + + semver_tryn(&v0, STRNSIZE("2.0.0")); + semver_tryn(&v1, STRNSIZE("2.0.1")); + semver_tryn(&v2, STRNSIZE("2.0.2")); + semver_tryn(&v3, STRNSIZE("v2.0.0")); + semver_tryn(&v4, STRNSIZE("v2.0.1")); + semver_tryn(&v5, STRNSIZE("v2.0.2")); + semver_tryn(&v6, STRNSIZE("v2.0.3")); + semver_tryn(&v7, STRNSIZE("v2.1.0-beta1")); + semver_tryn(&v8, STRNSIZE("v2.1.0-beta2")); + semver_tryn(&v9, STRNSIZE("v2.0")); + semver_tryn(&v10, STRNSIZE("v2.1")); + + if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0); + if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1); + if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2); + if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3); + if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4); + if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5); + if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6); + if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7); + if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8); + if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9); + if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10); + if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0); + if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1); + if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2); + if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3); + if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4); + if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5); + if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6); + if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7); + if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8); + if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9); + if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10); + if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0); + if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1); + if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2); + if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3); + if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4); + if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5); + if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6); + if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7); + if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8); + if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9); + if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10); + + if (semvers.length != 18) { + return EXIT_FAILURE; + } + if (semvers.capacity != 32) { + return EXIT_FAILURE; + } + + semvers_sort(semvers); + + for (unsigned i = 0; i < semvers.length; ++i) { + semver_fwrite(semvers.data + i, stdout); + putc('\n', stdout); + } + + v0 = semvers_pop(semvers); + v1 = semvers_shift(semvers); + + assert(memcmp("v2.1", v0.raw, v0.len) == 0); + assert(memcmp("v2.0.2", v1.raw, v1.len) == 0 || memcmp("2.0.2", v1.raw, v1.len) == 0); + + semvers_rsort(semvers); + putc('\n', stdout); + for (unsigned i = 0; i < semvers.length; ++i) { + semver_fwrite(semvers.data + i, stdout); + putc('\n', stdout); + } + + semvers_dtor(semvers); + + return EXIT_SUCCESS; +} diff --git a/core/src/sv/test/usage.c b/core/src/sv/test/usage.c new file mode 100644 index 000000000..818608137 --- /dev/null +++ b/core/src/sv/test/usage.c @@ -0,0 +1,46 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdlib.h> +#include <assert.h> + +#include "semver.h" + +int main(void) { + semver_t semver = {0}; + + semver(&semver, "v1.2.3-alpha.1"); + + assert(1 == semver.major); + assert(2 == semver.minor); + assert(3 == semver.patch); + assert(0 == memcmp("alpha", semver.prerelease.raw, sizeof("alpha")-1)); + assert(0 == memcmp("1", semver.prerelease.next->raw, sizeof("1")-1)); + assert(true == semver_rmatch(semver, "1.2.1 || >=1.2.3-alpha <1.2.5")); + + semver_dtor(&semver); +} diff --git a/core/src/sv/test/utils.c b/core/src/sv/test/utils.c new file mode 100644 index 000000000..89ae4cd1b --- /dev/null +++ b/core/src/sv/test/utils.c @@ -0,0 +1,102 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "semver.h" + +int test_version_fwrite(void) { + static const char input_str[] = "1.2.3-alpha.1+x86-64"; + semver_t version; + int rv; + + rv = semver(&version, input_str); + if (0 == rv) { + printf("test_version_fwrite: "); + semver_fwrite(&version, stdout); + if (0 == errno) { + printf("\n"); + rv = 0; + } + } + semver_dtor(&version); + return rv; +} + +int test_comparator_fwrite(void) { + static const char input_str[] = "<=1.2.3"; + semver_comp_t comp; + int rv; + + rv = semver_comp(&comp, input_str); + if (0 == rv) { + printf("test_comparator_fwrite: "); + semver_comp_fwrite(&comp, stdout); + if (0 == errno) { + printf("\n"); + rv = 0; + } + } + semver_comp_dtor(&comp); + return rv; +} + +int test_range_fwrite(void) { + static const char input_str[] = ">=1.2.3 <4.0.0"; + semver_range_t range; + int rv; + + rv = semver_range(&range, input_str); + if (0 == rv) { + printf("test_range_fwrite: "); + semver_range_fwrite(&range, stdout); + if (0 == errno) { + printf("\n"); + rv = 0; + } + } + semver_range_dtor(&range); + return rv; +} + +int main(void) { + if (test_version_fwrite()) { + return EXIT_FAILURE; + } + + if (test_comparator_fwrite()) { + return EXIT_FAILURE; + } + + if (test_range_fwrite()) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/sv/test/version.c b/core/src/sv/test/version.c new file mode 100644 index 000000000..a10b6e645 --- /dev/null +++ b/core/src/sv/test/version.c @@ -0,0 +1,236 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to <http://unlicense.org> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "semver.h" + +#define STRNSIZE(s) (s), sizeof(s)-1 + +int test_read(const char *expected, const char *str, size_t len) { + unsigned slen; + char buffer[1024]; + semver_t semver = {0}; + + printf("test: `%.*s`", (int) len, str); + if (semvern(&semver, str, len)) { + puts(" \tcouldn't parse"); + return 1; + } + slen = (unsigned) semver_write(semver, buffer, 1024); + printf(" \t=> \t`%.*s`", slen, buffer); + if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { + printf(" != `%s`\n", expected); + semver_dtor(&semver); + return 1; + } + printf(" == `%s`\n", expected); + semver_dtor(&semver); + return 0; +} + +int test_try_read(const char *expected, const char *str, size_t len) { + unsigned slen; + char buffer[1024]; + semver_t semver = {0}; + + printf("test: `%.*s`", (int) len, str); + if (semver_tryn(&semver, str, len)) { + puts(" \tcouldn't parse"); + return 1; + } + slen = (unsigned) semver_write(semver, buffer, 1024); + printf(" \t=> \t`%.*s`", slen, buffer); + if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { + printf(" != `%s`\n", expected); + semver_dtor(&semver); + return 1; + } + printf(" == `%s`\n", expected); + semver_dtor(&semver); + return 0; +} + +int main(void) { + puts("normal:"); + if (test_read("0.2.3", STRNSIZE("0.2.3"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3", STRNSIZE("1.2.3"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3+77", STRNSIZE("v1.2.3+77"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3+0", STRNSIZE("v1.2.3+0"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) { + return EXIT_FAILURE; + } + if (test_read("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("vv1.2.3")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("v1.2")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("v1.2.x")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("v1.2.3-")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("v1.2.3+")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("v1.2.3+01")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("v0.01.3")) == 0) { + return EXIT_FAILURE; + } + if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " + "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" + "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) + == 0) { + return EXIT_FAILURE; + } + + puts("try:"); + if (test_try_read("0.2.3", STRNSIZE("0.2.3"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3", STRNSIZE("1.2.3"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3+77", STRNSIZE("v1.2.3+77"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3+0", STRNSIZE("v1.2.3+0"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("vv1.2.3")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("v1.2")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("v1.2.x")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("v1.2.3-")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("v1.2.3+")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("v1.2.3+01")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("v0.01.3")) == 0) { + return EXIT_FAILURE; + } + if (test_try_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " + "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" + "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) + == 0) { + return EXIT_FAILURE; + } + if (test_try_read("0.2.0", STRNSIZE("0.2"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.0.0", STRNSIZE("v1"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.0-alpha", STRNSIZE("v1.2alpha"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-alpha.2", STRNSIZE("1.2.3alpha.2"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.0.0+77", STRNSIZE("v1+77"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.0+0", STRNSIZE("v1.2+0"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.0.0+77.2", STRNSIZE("v1+77.2"))) { + return EXIT_FAILURE; + } + if (test_try_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3alpha.2+77"))) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/sv/test/xmake.lua b/core/src/sv/test/xmake.lua new file mode 100644 index 000000000..4169560e8 --- /dev/null +++ b/core/src/sv/test/xmake.lua @@ -0,0 +1,45 @@ +set_default(false) +set_languages("c99") +set_kind("binary") +add_deps("sv") +add_links("sv") +add_includedirs("../include") +add_linkdirs("$(buildir)") + +target("version_test") + add_files("version.c") + +target("comp_test") + add_files("comp.c") + +target("range_test") + add_files("range.c") + +target("match_test") + add_files("match.c") + +target("semvers_test") + add_files("semvers.c") + +target("utils_test") + add_files("utils.c") + +target("usage_test") + add_files("usage.c") + +task("check") + on_run(function () + import("core.project.task") + task.run("run", {target = "version_test"}) + task.run("run", {target = "comp_test"}) + task.run("run", {target = "range_test"}) + task.run("run", {target = "match_test"}) + task.run("run", {target = "semvers_test"}) + task.run("run", {target = "utils_test"}) + task.run("run", {target = "usage_test"}) + end) + set_menu { + usage = "xmake check" + , description = "Run tests !" + , options = {} + } diff --git a/core/src/sv/xmake.lua b/core/src/sv/xmake.lua new file mode 100644 index 000000000..490c8bf01 --- /dev/null +++ b/core/src/sv/xmake.lua @@ -0,0 +1,31 @@ +set_project("libsv") +set_version("0.0.1") + +set_warnings("all", "error") + +if is_os("macosx") or is_os("ios") then + add_cflags("-Wno-nullability-completeness") + add_cxxflags("-Wno-nullability-completeness") +end + +if is_mode("release") then + set_symbols("hidden") + set_optimize("fastest") + set_strip("all") +end + +if is_mode("debug") then + set_symbols("debug") + set_optimize("none") +end + +target("sv") + set_default(true) + set_languages("c99") + set_kind("$(kind)") + set_headerdir("$(buildir)/include") + add_headers("include/(*.h)") + add_includedirs("$(buildir)", "include") + add_files("src/*.c") + +add_subdirs("test") diff --git a/core/src/xmake/hash/prefix.h b/core/src/xmake/hash/prefix.h new file mode 100644 index 000000000..5df85a1d3 --- /dev/null +++ b/core/src/xmake/hash/prefix.h @@ -0,0 +1,36 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file prefix.h + * + */ +#ifndef XM_HASH_PREFIX_H +#define XM_HASH_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + + +#endif + + diff --git a/core/src/xmake/hash/sha256.c b/core/src/xmake/hash/sha256.c new file mode 100644 index 000000000..6a9b1f5df --- /dev/null +++ b/core/src/xmake/hash/sha256.c @@ -0,0 +1,110 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file sha256.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "sha256" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_hash_sha256(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get the filename + tb_char_t const* filename = luaL_checkstring(lua, 1); + tb_check_return_val(filename, 0); + + // load data from file + tb_bool_t ok = tb_false; + tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO); + if (stream) + { + // open stream + if (tb_stream_open(stream)) + { + // init sha256 + tb_sha_t sha; + tb_sha_init(&sha, TB_SHA_MODE_SHA2_256); + + // read data and update sha256 + tb_byte_t data[TB_STREAM_BLOCK_MAXN]; + while (!tb_stream_beof(stream)) + { + // read data + tb_long_t real = tb_stream_read(stream, data, sizeof(data)); + + // ok? + if (real > 0) tb_sha_spak(&sha, data, real); + // no data? continue it + else if (!real) + { + // wait + real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream)); + tb_check_break(real > 0); + + // has read? + tb_assert_and_check_break(real & TB_STREAM_WAIT_READ); + } + // failed or end? + else break; + } + + // exit sha256 + tb_byte_t buffer[32]; + tb_sha_exit(&sha, buffer, sizeof(buffer)); + + // make sha256 string + tb_size_t i = 0; + tb_size_t n = sha.digest_len << 2; + tb_char_t s[256] = {0}; + for (i = 0; i < n; ++i) tb_snprintf(s + (i << 1), 3, "%02x", buffer[i]); + + // save result + lua_pushstring(lua, s); + + // ok + ok = tb_true; + } + + // exit stream + tb_stream_exit(stream); + } + + // failed? return nil + if (!ok) lua_pushnil(lua); + + // ok + return 1; +} diff --git a/core/src/xmake/os/uuid.c b/core/src/xmake/hash/uuid.c index 044bbe83d..9dc8e0eb7 100644 --- a/core/src/xmake/os/uuid.c +++ b/core/src/xmake/hash/uuid.c @@ -37,7 +37,7 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ -tb_int_t xm_os_uuid(lua_State* lua) +tb_int_t xm_hash_uuid(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c index 7f1acfbd0..e1a080d3a 100644 --- a/core/src/xmake/machine.c +++ b/core/src/xmake/machine.c @@ -60,13 +60,13 @@ typedef struct __xm_machine_impl_t // the os functions tb_int_t xm_os_argv(lua_State* lua); tb_int_t xm_os_find(lua_State* lua); -tb_int_t xm_os_uuid(lua_State* lua); tb_int_t xm_os_isdir(lua_State* lua); tb_int_t xm_os_rmdir(lua_State* lua); tb_int_t xm_os_mkdir(lua_State* lua); tb_int_t xm_os_cpdir(lua_State* lua); tb_int_t xm_os_chdir(lua_State* lua); tb_int_t xm_os_mtime(lua_State* lua); +tb_int_t xm_os_sleep(lua_State* lua); tb_int_t xm_os_mclock(lua_State* lua); tb_int_t xm_os_curdir(lua_State* lua); tb_int_t xm_os_tmpdir(lua_State* lua); @@ -93,6 +93,10 @@ tb_int_t xm_path_absolute(lua_State* lua); tb_int_t xm_path_translate(lua_State* lua); tb_int_t xm_path_is_absolute(lua_State* lua); +// the hash functions +tb_int_t xm_hash_uuid(lua_State* lua); +tb_int_t xm_hash_sha256(lua_State* lua); + // the winreg functions #ifdef TB_CONFIG_OS_WINDOWS tb_int_t xm_winreg_query(lua_State* lua); @@ -120,6 +124,11 @@ tb_int_t xm_readline_add_history(lua_State* lua); tb_int_t xm_readline_clear_history(lua_State* lua); #endif +// the semver functions +tb_int_t xm_semver_parse(lua_State* lua); +tb_int_t xm_semver_satisfies(lua_State* lua); +tb_int_t xm_semver_select(lua_State* lua); + /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ @@ -129,13 +138,13 @@ static luaL_Reg const g_os_functions[] = { { "argv", xm_os_argv } , { "find", xm_os_find } -, { "uuid", xm_os_uuid } , { "isdir", xm_os_isdir } , { "rmdir", xm_os_rmdir } , { "mkdir", xm_os_mkdir } , { "cpdir", xm_os_cpdir } , { "chdir", xm_os_chdir } , { "mtime", xm_os_mtime } +, { "sleep", xm_os_sleep } , { "mclock", xm_os_mclock } , { "curdir", xm_os_curdir } , { "tmpdir", xm_os_tmpdir } @@ -168,6 +177,14 @@ static luaL_Reg const g_path_functions[] = , { tb_null, tb_null } }; +// the hash functions +static luaL_Reg const g_hash_functions[] = +{ + { "uuid", xm_hash_uuid } +, { "sha256", xm_hash_sha256 } +, { tb_null, tb_null } +}; + // the string functions static luaL_Reg const g_string_functions[] = { @@ -215,6 +232,15 @@ static luaL_Reg const g_readline_functions[] = }; #endif +// the semver functions +static luaL_Reg const g_semver_functions[] = +{ + { "parse", xm_semver_parse } +, { "satisfies", xm_semver_satisfies } +, { "select", xm_semver_select } +, { tb_null, tb_null } +}; + /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ @@ -422,6 +448,9 @@ xm_machine_ref_t xm_machine_init() // bind path functions luaL_register(impl->lua, "path", g_path_functions); + // bind hash functions + luaL_register(impl->lua, "hash", g_hash_functions); + // bind string functions luaL_register(impl->lua, "string", g_string_functions); @@ -441,6 +470,9 @@ xm_machine_ref_t xm_machine_init() luaL_register(impl->lua, "readline", g_readline_functions); #endif + // bind semver functions + luaL_register(impl->lua, "semver", g_semver_functions); + // init host #if defined(TB_CONFIG_OS_WINDOWS) lua_pushstring(impl->lua, "windows"); diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile index e9f5badce..aa003cc35 100644 --- a/core/src/xmake/makefile +++ b/core/src/xmake/makefile @@ -16,13 +16,13 @@ xmake_C_FILES += \ machine \ os/argv \ os/find \ - os/uuid \ os/isdir \ os/rmdir \ os/mkdir \ os/cpdir \ os/chdir \ os/mtime \ + os/sleep \ os/mclock \ os/curdir \ os/tmpdir \ @@ -44,6 +44,8 @@ xmake_C_FILES += \ path/absolute \ path/translate \ path/is_absolute \ + hash/uuid \ + hash/sha256 \ winreg/query \ string/endswith \ string/startswith \ @@ -53,6 +55,10 @@ xmake_C_FILES += \ process/waitlist \ process/close \ sandbox/interactive \ + semver/parse \ + semver/satisfies \ + semver/select \ + semver/semver \ readline/readline \ readline/history_list \ readline/add_history \ @@ -65,7 +71,8 @@ xmake_CXFLAGS += $(if $(findstring readline,$(base_LIBNAMES)),-DXM_CONFIG_API # includes xmake_INC_DIRS += \ - ../luajit/src + ../luajit/src \ + ../sv/include # suffix diff --git a/core/src/xmake/os/sleep.c b/core/src/xmake/os/sleep.c new file mode 100644 index 000000000..4615c274f --- /dev/null +++ b/core/src/xmake/os/sleep.c @@ -0,0 +1,53 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file sleep.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "sleep" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_os_sleep(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get the interval (ms) + tb_long_t interval = (tb_long_t)luaL_checklong(lua, 1); + + // sleep it + if (interval >= 0) tb_msleep(interval); + + // ok + return 0; +} diff --git a/core/src/xmake/semver/parse.c b/core/src/xmake/semver/parse.c new file mode 100644 index 000000000..976f198fb --- /dev/null +++ b/core/src/xmake/semver/parse.c @@ -0,0 +1,65 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author uael + * @file parse.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "parse" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +// parse wrapper +tb_int_t xm_semver_parse(lua_State* lua) +{ + semver_t semver = {0}; + + // check + tb_assert_and_check_return_val(lua, 0); + + // get the version string + tb_char_t const* str = luaL_checkstring(lua, 1); + tb_check_return_val(str, 0); + + if (semvern(&semver, str, tb_strlen(str))) { + lua_pushnil(lua); + lua_pushfstring(lua, "Unable to parse semver '%s'", str); + + return 2; + } + + lua_pushsemver(lua, semver); + semver_dtor(&semver); + + // ok + return 1; +} diff --git a/core/src/xmake/semver/prefix.h b/core/src/xmake/semver/prefix.h new file mode 100644 index 000000000..17c4e9f5a --- /dev/null +++ b/core/src/xmake/semver/prefix.h @@ -0,0 +1,37 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author uael + * @file prefix.h + * + */ +#ifndef XM_SEMVER_PREFIX_H +#define XM_SEMVER_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + +#include "semver.h" + +void lua_pushsemver(lua_State *lua, semver_t semver); + +#endif diff --git a/core/src/xmake/semver/satisfies.c b/core/src/xmake/semver/satisfies.c new file mode 100644 index 000000000..f3b34890f --- /dev/null +++ b/core/src/xmake/semver/satisfies.c @@ -0,0 +1,78 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author uael + * @file satisfies.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "satisfies" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +// satisfies wrapper +tb_int_t xm_semver_satisfies(lua_State* lua) +{ + semver_t semver = {0}; + semver_range_t range = {0}; + + // check + tb_assert_and_check_return_val(lua, 0); + + // get the version string + tb_char_t const* str = luaL_checkstring(lua, 1); + tb_char_t const* range_str = luaL_checkstring(lua, 2); + + tb_check_return_val(str, 0); + tb_check_return_val(range_str, 0); + + if (semvern(&semver, str, tb_strlen(str))) { + lua_pushnil(lua); + lua_pushfstring(lua, "Unable to parse semver '%s'", str); + + return 2; + } + + if (semver_rangen(&range, range_str, tb_strlen(range_str))) { + semver_dtor(&semver); + lua_pushnil(lua); + lua_pushfstring(lua, "Unable to parse semver range '%s'", range_str); + + return 2; + } + + lua_pushboolean(lua, semver_range_match(semver, range)); + semver_dtor(&semver); + semver_range_dtor(&range); + + // ok + return 1; +} diff --git a/core/src/xmake/semver/select.c b/core/src/xmake/semver/select.c new file mode 100644 index 000000000..6400de6a8 --- /dev/null +++ b/core/src/xmake/semver/select.c @@ -0,0 +1,160 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author uael + * @file select.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "select" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include <stdlib.h> +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +// satisfies wrapper +tb_int_t xm_semver_select(lua_State* lua) +{ + semver_t semver = {0}; + semvers_t matches = {0}; + semver_range_t range = {0}; + lua_Integer i; + size_t range_len = 0, source_len; + tb_char_t const* source_str; + tb_char_t const* source; + tb_bool_t is_range; + + lua_settop(lua, 4); + + // check + tb_assert_and_check_return_val(lua, 0); + + // get the version string + tb_char_t const* range_str = luaL_checkstring(lua, 1); + tb_check_return_val(range_str, 0); + range_len = tb_strlen(range_str); + + is_range = semver_rangen(&range, range_str, range_len) == 0; + if (is_range) { + source = "versions"; + luaL_checktype(lua, 2, LUA_TTABLE); + for (i = lua_objlen(lua, 2); i > 0; --i) { + lua_pushinteger(lua, i); + lua_gettable(lua, 2); + + source_str = luaL_checkstring(lua, -1); + tb_check_return_val(source_str, 0); + + if (semver_tryn(&semver, source_str, tb_strlen(source_str)) == 0) { + if (semver_range_match(semver, range)) { + semvers_push(matches, semver); + } else { + semver_dtor(&semver); + } + } + } + if (matches.length) { + goto match; + } + semvers_clear(matches); + source = "tags"; + luaL_checktype(lua, 3, LUA_TTABLE); + for (i = lua_objlen(lua, 3); i > 0; --i) { + lua_pushinteger(lua, i); + lua_gettable(lua, 3); + + source_str = luaL_checkstring(lua, -1); + tb_check_return_val(source_str, 0); + + if (semver_tryn(&semver, source_str, tb_strlen(source_str)) == 0) { + if (semver_range_match(semver, range)) { + semvers_push(matches, semver); + } else { + semver_dtor(&semver); + } + } + } + if (matches.length) { + goto match; + } + semvers_dtor(matches); + semver_range_dtor(&range); + } + + source = "branches"; + luaL_checktype(lua, 4, LUA_TTABLE); + for (i = lua_objlen(lua, 4); i > 0; --i) { + lua_pushinteger(lua, i); + lua_gettable(lua, 4); + + source_str = luaL_checkstring(lua, -1); + tb_check_return_val(source_str, 0); + source_len = tb_strlen(source_str); + + if (source_len == range_len && tb_memcmp(source_str, range_str, source_len) == 0) { + lua_createtable(lua, 0, 2); + + lua_pushlstring(lua, source_str, source_len); + lua_setfield(lua, -2, "version"); + + lua_pushstring(lua, source); + lua_setfield(lua, -2, "source"); + + return 1; + } + } + + if (!is_range) { + lua_pushnil(lua); + lua_pushfstring(lua, "Unable to parse semver range '%s'", range_str); + + return 2; + } + lua_pushnil(lua); + lua_pushfstring(lua, "Unable to select version for range '%s'", range_str); + + return 2; + match: + semvers_sort(matches); + semver = semvers_pop(matches); + lua_createtable(lua, 0, 2); + + lua_pushstring(lua, semver.raw); + lua_setfield(lua, -2, "version"); + + lua_pushstring(lua, source); + lua_setfield(lua, -2, "source"); + + semvers_dtor(matches); + semver_dtor(&semver); + semver_range_dtor(&range); + + return 1; +} diff --git a/core/src/xmake/semver/semver.c b/core/src/xmake/semver/semver.c new file mode 100644 index 000000000..27dfb3fb6 --- /dev/null +++ b/core/src/xmake/semver/semver.c @@ -0,0 +1,91 @@ +/*!The Make-like Build Utility based on Lua + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015 - 2017, TBOOX Open Source Group. + * + * @author uael + * @file semver.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "semver" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +void lua_pushsemver(lua_State *lua, const semver_t semver) +{ + semver_id_t const *id; + tb_uchar_t i = 0; + + lua_createtable(lua, 0, 7); + + lua_pushstring(lua, semver.raw); + lua_setfield(lua, -2, "raw"); + + lua_pushlstring(lua, semver.raw, semver.len); + lua_setfield(lua, -2, "version"); + + lua_pushinteger(lua, semver.major); + lua_setfield(lua, -2, "major"); + + lua_pushinteger(lua, semver.minor); + lua_setfield(lua, -2, "minor"); + + lua_pushinteger(lua, semver.patch); + lua_setfield(lua, -2, "patch"); + + lua_pushstring(lua, "prerelease"); + lua_newtable(lua); + id = &semver.prerelease; + while (id && id->len) { + if (id->numeric) { + lua_pushinteger(lua, id->num); + } else { + lua_pushlstring(lua, id->raw, id->len); + } + id = id->next; + lua_rawseti(lua, -2, ++i); + } + lua_settable(lua, -3); + + i = 0; + lua_pushstring(lua, "build"); + lua_newtable(lua); + id = &semver.build; + while (id && id->len) { + if (id->numeric) { + lua_pushinteger(lua, id->num); + } else { + lua_pushlstring(lua, id->raw, id->len); + } + id = id->next; + lua_rawseti(lua, -2, ++i); + } + lua_settable(lua, -3); +} diff --git a/core/src/xmake/xmake.lua b/core/src/xmake/xmake.lua index 484d94b98..acc71ed46 100644 --- a/core/src/xmake/xmake.lua +++ b/core/src/xmake/xmake.lua @@ -5,7 +5,7 @@ target("xmake") set_kind("static") -- add deps - add_deps("luajit") + add_deps("sv", "luajit") -- add defines add_defines("__tb_prefix__=\"xmake\"") diff --git a/core/xmake.lua b/core/xmake.lua index 581f91224..141b81c6b 100644 --- a/core/xmake.lua +++ b/core/xmake.lua @@ -5,7 +5,7 @@ set_project("xmake") set_version("2.1.5") -- set xmake min version -set_xmakever("2.1.2") +set_xmakever("2.1.5") -- set warning all as error set_warnings("all", "error") @@ -14,7 +14,7 @@ set_warnings("all", "error") set_languages("c99", "cxx11") -- disable some compiler errors -add_cxflags("-Wno-error=deprecated-declarations", "-fno-strict-aliasing") +add_cxflags("-Wno-error=deprecated-declarations", "-fno-strict-aliasing", "-Wno-error=nullability-completeness") -- add defines add_defines("_GNU_SOURCE=1", "_FILE_OFFSET_BITS=64", "_LARGEFILE_SOURCE") @@ -41,11 +41,6 @@ if is_plat("windows") then add_ldflags("-nodefaultlib:\"msvcrt.lib\"") end --- for macosx -if is_plat("macosx") then - add_ldflags("-all_load", "-pagezero_size 10000", "-image_base 100000000") -end - -- for mode coverage if is_mode("coverage") then add_ldflags("-coverage", "-fprofile-arcs", "-ftest-coverage") @@ -55,4 +50,4 @@ end add_packagedirs("pkg") -- add projects -add_subdirs("src/luajit", "src/xmake", "src/demo") +add_subdirs("src/sv","src/luajit", "src/xmake", "src/demo") diff --git a/docs/get.sh b/docs/get.sh deleted file mode 100755 index 6e417b98c..000000000 --- a/docs/get.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash - -# xmake getter -# usage: bash <(curl -s <my location>) [[mirror:]branch] [commit/__install_only__] - -set -o pipefail - -if [ 0 -ne "$(id -u)" ] -then - sudoprefix=sudo -else - sudoprefix= -fi - -tmpdir=/tmp/.xmake_getter$$ - -remote_get_content(){ - if curl --version >/dev/null 2>&1 - then - curl -fsSL "$1" - elif wget --version >/dev/null 2>&1 - then - wget -q "$1" -O - - fi -} - -if [ "$1" = "__uninstall__" ] -then - # uninstall - makefile=$(remote_get_content https://github.com/tboox/xmake/raw/master/makefile) - while which xmake >/dev/null 2>&1 - do - pre=$(which xmake | sed 's/\/bin\/xmake$//') - # don't care if make exists -- if there's no make, how xmake built and installed? - echo "$makefile" | make -f - uninstall prefix="$pre" 2>/dev/null || echo "$makefile" | $sudoprefix make -f - uninstall prefix="$pre" || exit $? - done - exit -fi - -# below is installation -# print a LOGO! -echo ' _ ' -echo ' __ ___ __ __ __ _| | ______ ' -echo ' \ \/ / | \/ |/ _ | |/ / __ \ ' -echo ' > < | \__/ | /_| | < ___/ ' -echo ' /_/\_\_|_| |_|\__ \|_|\_\____| getter ' -echo ' ' - -if [ 'x__local__' != "x$1" ] -then - brew --version >/dev/null 2>&1 && brew install --HEAD xmake && xmake --version && exit -fi - -my_exit(){ - rv=$? - if [ "x$1" != x ] - then - echo -ne '\x1b[41;37m' - echo "$1" - echo -ne '\x1b[0m' - fi - rm -rf $tmpdir 2>/dev/null - if [ "x$2" != x ] - then - if [ $rv -eq 0 ];then rv=$2;fi - fi - exit "$rv" -} -test_tools() -{ - prog='#include<stdio.h>\n#include<readline/readline.h>\nint main(){readline(0);return 0;}' - { - git --version && - make --version && - { - echo -e "$prog" | cc -xc - -o /dev/null -lreadline || - echo -e "$prog" | gcc -xc - -o /dev/null -lreadline || - echo -e "$prog" | clang -xc - -o /dev/null -lreadline - } - } >/dev/null 2>&1 -} -install_tools() -{ - { apt-get --version >/dev/null 2>&1 && $sudoprefix apt-get install -y git build-essential libreadline-dev ccache; } || - { yum --version >/dev/null 2>&1 && $sudoprefix yum install -y git readline-devel ccache && $sudoprefix yum groupinstall -y 'Development Tools'; } || - { zypper --version >/dev/null 2>&1 && $sudoprefix zypper --non-interactive install git readline-devel ccache && $sudoprefix zypper --non-interactive install -t pattern devel_C_C++; } || - { pacman -V >/dev/null 2>&1 && $sudoprefix pacman -S --noconfirm --needed git base-devel ccache; } -} -test_tools || { install_tools && test_tools; } || my_exit "$(echo -e 'Dependencies Installation Fail\nThe getter currently only support these package managers\n\t* apt\n\t* yum\n\t* zypper\n\t* pacman\nPlease install following dependencies manually:\n\t* git\n\t* build essential like `make`, `gcc`, etc\n\t* libreadline-dev (readline-devel)\n\t* ccache (optional)')" 1 -branch=master -mirror=tboox -IFS=':' -if [ x != "x$1" ] -then - brancharr=($1) - if [ ${#brancharr[@]} -eq 1 ] - then - branch=${brancharr[0]} - fi - if [ ${#brancharr[@]} -eq 2 ] - then - branch=${brancharr[1]} - mirror=${brancharr[0]} - fi - echo "Branch: $branch" -fi -if [ 'x__local__' != "x$branch" ] -then - git clone --depth=50 -b "$branch" "https://github.com/$mirror/xmake.git" $tmpdir || my_exit "$(echo -e 'Clone Fail\nCheck your network or branch name')" - if [ x != "x$2" ] - then - cd $tmpdir || my_exit 'Chdir Error' - git checkout -qf "$2" - cd - || my_exit 'Chdir Error' - fi -else - tmpdir=`pwd` -fi -if [ 'x__install_only__' != "x$2" ] -then - make -C $tmpdir --no-print-directory build - rv=$? - if [ $rv -ne 0 ] - then - make -C $tmpdir/core --no-print-directory error - my_exit "$(echo -e 'Build Fail\nDetail:\n' | cat - /tmp/xmake.out)" $rv - fi -fi - -if [ "$prefix" = "" ] -then - prefix=~/.local -fi - -if [ "x$prefix" != x ] -then - make -C $tmpdir --no-print-directory install prefix="$prefix"|| my_exit 'Install Fail' -else - $sudoprefix make -C $tmpdir --no-print-directory install || my_exit 'Install Fail' -fi -write_profile() -{ - grep -sq ".xmake/profile" $1 || echo "[[ -s \"\$HOME/.xmake/profile\" ]] && source \"\$HOME/.xmake/profile\" # load xmake profile" >> $1 -} -install_profile() -{ - if [ ! -d ~/.xmake ]; then mkdir ~/.xmake; fi - echo "export PATH=$prefix/bin:\$PATH" > ~/.xmake/profile - if [[ "$SHELL" = */zsh ]]; then write_profile ~/.zshrc - elif [[ "$SHELL" = */ksh ]]; then write_profile ~/.kshrc - elif [[ "$SHELL" = */bash ]]; then write_profile ~/.bashrc - fi - write_profile ~/.bash_profile -} -install_profile -if xmake --version >/dev/null 2>&1; then xmake --version; else - source ~/.xmake/profile - xmake --version - echo "Reload shell profile by running the following command now!" - echo -e "\x1b[1msource ~/.xmake/profile\x1b[0m" -fi diff --git a/tests/modules/semver/test.lua b/tests/modules/semver/test.lua new file mode 100755 index 000000000..884eaf82e --- /dev/null +++ b/tests/modules/semver/test.lua @@ -0,0 +1,119 @@ +-- imports +import("core.base.semver") + +-- select version +function _check_semver_select(results, required_ver, versions, tags, branches) + + -- select it + local version, source = semver.select(required_ver, versions or {}, tags or {}, branches or {}) + if (version.version or version) ~= results[1] or source ~= results[2] then + print("semver.select(\"%s\", {\"%s\"}, {\"%s\"}, {\"%s\"})" + , required_ver + , table.concat(versions or {}, "\", \"") + , table.concat(tags or {}, "\", \"") + , table.concat(branches or {}, "\", \"")) + raise("{\"%s\", \"%s\"} != {\"%s\", \"%s\"}", version.version or version, source or "", results[1] or "", results[2] or "") + end +end + +-- test select version +function _test_semver_select() + + _check_semver_select({"1.5.1", "versions"} + , ">=1.5.0 <1.6.0" + , {"1.4.0", "1.5.0", "1.5.1"}) + + _check_semver_select({"1.5.1", "versions"} + , "^1.5.0" + ,{"1.4.0", "1.5.0", "1.5.1"}) + + _check_semver_select({"master", "branches"} + , "master" + , {"1.4.0", "1.5.0", "1.5.1"} + , {"v1.2.0", "v1.6.0"} + , {"master", "dev"}) + + print("semver.select: ok!") +end + +-- select version +function _check_semver_satisfies(expected, version, range) + + -- select it + local result = semver.satisfies(version, range) + if expected ~= result then + print("semver.satisfies(\"%s\", \"%s\")" + , version + , range) + raise("\"%s\" != \"%s\"", expected, result) + end +end + +-- test satisfies version +function _test_semver_satisfies() + + _check_semver_satisfies(true, "1.5.1", ">=1.5.0 <1.6.0") + _check_semver_satisfies(true, "1.5.1", "^1.5.0") + + print("semver.satisfies: ok!") +end + +-- parse version +function _check_semver_parse(version_str, major, minor, patch, prerelease, build) + + -- create it + local version = semver.parse(version_str) + + if version.major ~= major then + raise("major: \"%s\" != \"%s\"", version.major or "", major or "") + end + + if version.minor ~= minor then + raise("minor: \"%s\" != \"%s\"", version.minor or "", minor or "") + end + + if version.patch ~= patch then + raise("patch: \"%s\" != \"%s\"", version.patch or "", patch or "") + end + + if table.concat(version.prerelease or {}, ".") ~= table.concat(prerelease or {}, ".") then + raise("prerelease: \"%s\" != \"%s\"" + , table.concat(version.prerelease or {}, ".") or "" + , table.concat(prerelease or {}, ".") or "") + end + + if table.concat(version.build or {}, ".") ~= table.concat(build or {}, ".") then + raise("build: \"%s\" != \"%s\"" + , table.concat(version.build or {}, ".") or "" + , table.concat(build or {}, ".") or "") + end +end + +-- test parse version +function _test_semver_parse() + + _check_semver_parse("1.2.3", 1, 2, 3) + _check_semver_parse("1.2.3-beta", 1, 2, 3, {"beta"}) + _check_semver_parse("1.2.3-beta+77", 1, 2, 3, {"beta"}, {"77"}) + _check_semver_parse("v1.2.3-alpha.1+77", 1, 2, 3, {"alpha", "1"}, {"77"}) + _check_semver_parse("v3.2.1-alpha.1+77.foo", 3, 2, 1, {"alpha", "1"}, {"77", "foo"}) + + print("semver.parse: ok!") +end + +-- +-- run tests: +-- +-- $ make test name=semver +-- +function main() + + -- test semver + _test_semver_parse() + + -- test semver satisfies + _test_semver_satisfies() + + -- test select version + _test_semver_select() +end diff --git a/tests/projects/requires/src/main.c b/tests/projects/requires/src/main.c new file mode 100755 index 000000000..9ae580511 --- /dev/null +++ b/tests/projects/requires/src/main.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int main(int argc, char** argv) +{ + printf("hello world!\n"); + return 0; +} diff --git a/tests/projects/requires/test.lua b/tests/projects/requires/test.lua new file mode 100644 index 000000000..eacf35408 --- /dev/null +++ b/tests/projects/requires/test.lua @@ -0,0 +1,10 @@ +-- imports +import("..build") + +-- main entry +function main() + + -- TODO + -- build project +-- build() +end diff --git a/tests/projects/requires/xmake.lua b/tests/projects/requires/xmake.lua new file mode 100644 index 000000000..f96866d10 --- /dev/null +++ b/tests/projects/requires/xmake.lua @@ -0,0 +1,48 @@ +-- define package +package("mbedtls") + set_urls("https://github.com/ARMmbed/mbedtls.git") + add_requires("https://github.com/glennrp/libpng.git@libpng >=1.6.28") +package_end() + +-- group packages +package("zlib-mbedtls") + add_requires("zlib >=1.2.11") + add_requires("mbedtls master optional") +package_end() + +-- requires +add_requires("zlib-mbedtls") +add_requires("[email protected] >=1.5.1 <1.6.1 optional") + +-- the debug mode +if is_mode("debug") then + + -- enable the debug symbols + set_symbols("debug") + + -- disable optimization + set_optimize("none") +end + +-- the release mode +if is_mode("release") then + + -- set the symbols visibility: hidden + set_symbols("hidden") + + -- enable fastest optimization + set_optimize("fastest") + + -- strip all symbols + set_strip("all") +end + +-- add target +target("console_c") + + -- set kind + set_kind("binary") + + -- add files + add_files("src/*.c") + diff --git a/xmake/actions/install/install_admin.lua b/xmake/actions/install/install_admin.lua index f641628ea..7028e5c09 100644 --- a/xmake/actions/install/install_admin.lua +++ b/xmake/actions/install/install_admin.lua @@ -41,9 +41,6 @@ function main(targetname, installdir) -- load platform platform.load(config.plat()) - -- laod project - project.load() - -- save the current option and push a new option context option.save() diff --git a/xmake/actions/require/action/build.lua b/xmake/actions/require/action/build.lua new file mode 100644 index 000000000..0ae19a44c --- /dev/null +++ b/xmake/actions/require/action/build.lua @@ -0,0 +1,193 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file build.lua +-- + +-- imports +import("core.base.option") +import("core.project.config") +import("core.sandbox.sandbox") + +-- build for xmake file +function _build_for_xmakefile(package, buildfile) + + -- configure it first + os.vrun("xmake f -p $(plat) -a $(arch) -m $(mode) -c") + + -- build it + os.vrun("xmake -r") + + -- ok + return true +end + +-- build for makefile +function _build_for_makefile(package, buildfile) + + -- build it + os.vrun("make") + + -- ok + return true +end + +-- build for configure +function _build_for_configure(package, buildfile) + + -- make prefix directory + os.mkdir(".prefix") + + -- configure it first + os.vrun("./configure --prefix=%s", path.absolute(".prefix")) + + -- build it + os.vrun("make") + + -- install to .prefix + os.vrun("make install") + + -- ok + return true +end + +-- build for cmakelist +function _build_for_cmakelists(package, buildfile) + + -- make makefile first + os.vrun("cmake -DCMAKE_INSTALL_PREFIX=%s .", path.absolute(".prefix")) + + -- build it + os.vrun("make") + + -- install to .prefix + os.vrun("make install") + + -- ok + return true +end + +-- build for *.sln +function _build_for_sln(package, buildfile) + + -- build it for windows + if config.plat() == "windows" then + os.vrun("msbuild %s -nologo -t:Rebuild -p:Configuration=Release", buildfile) + return true + end + return false +end + +-- on build the given package +function _on_build_package(package) + + -- TODO *.vcproj, premake.lua, scons, autogen.sh, Makefile.am, ... + -- init build scripts + local buildscripts = + { + {"xmake.lua", _build_for_xmakefile } + , {"*.sln", _build_for_sln } + , {"CMakeLists.txt", _build_for_cmakelists } + , {"configure", _build_for_configure } + , {"[mM]akefile", _build_for_makefile } + } + + -- attempt to build it + for _, buildscript in pairs(buildscripts) do + + -- save the current directory + local oldir = os.curdir() + + -- try building + local ok = try + { + function () + + -- attempt to build it if file exists + local files = os.files(buildscript[1]) + if #files > 0 then + return buildscript[2](package, files[1]) + end + end, + + catch + { + function (errors) + + -- trace verbose info + if errors then + vprint(errors) + end + end + } + } + + -- restore directory + os.cd(oldir) + + -- ok? + if ok then return end + end + + -- failed + raise("attempt to build package %s failed!", package:name()) +end + +-- run script +function _run_script(script, package) + + -- TODO + -- register filter handler before building +-- sandbox.filter_register(script, "package.build", function (var) +-- end) + + -- run it + script(package) + + -- cancel filter handler before building +-- sandbox.filter_register(script, "package.build", nil) +end + +-- build the given package +function main(package) + + -- the package scripts + local scripts = + { + package:script("build_before") + , package:script("build", _on_build_package) + , package:script("build_after") + } + + -- save the current directory + local oldir = os.curdir() + + -- build it + for i = 1, 3 do + local script = scripts[i] + if script ~= nil then + _run_script(script, package) + end + end + + -- restore the current directory + os.cd(oldir) +end diff --git a/xmake/actions/require/action/download.lua b/xmake/actions/require/action/download.lua new file mode 100644 index 000000000..cfc41706f --- /dev/null +++ b/xmake/actions/require/action/download.lua @@ -0,0 +1,201 @@ +--!The Make-like download Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file download.lua +-- + +-- imports +import("core.base.option") +import("net.http") +import("devel.git") +import("utils.archive") + +-- empty chars +function _emptychars() + return " " +end + +-- checkout codes from git +function _checkout(package, url, sourcedir) + + -- use previous source directory if exists + local packagedir = path.join(sourcedir, package:name()) + if os.isdir(packagedir) and not option.get("force") then + + -- clean the previous build files + git.clean({repodir = packagedir, force = true}) + return + end + + -- remove temporary directory + os.rm(sourcedir .. ".tmp") + + -- download package from branches? + packagedir = path.join(sourcedir .. ".tmp", package:name()) + if package:version_from("branches") then + + -- only shadow clone this branch + git.clone(url, {depth = 1, branch = package:version_str(), outputdir = packagedir}) + + -- download package from tags or versions? + else + + -- clone whole history and tags + git.clone(url, {outputdir = packagedir}) + + -- attempt to checkout the given version + git.checkout(package:version_str(), {repodir = packagedir}) + end + + -- move to source directory + os.rm(sourcedir) + os.mv(sourcedir .. ".tmp", sourcedir) + + -- trace + cprint("\r${yellow} => ${clear}clone %s %s .. ${green}ok%s", url, package:version_str(), _emptychars()) +end + +-- download codes from ftp/http/https +function _download(package, url, sourcedir) + + -- get package file + local packagefile = path.filename(url) + + -- the package file have been downloaded? + local sha256 = package:sha256() + if option.get("force") or not os.isfile(packagefile) or (sha256 and sha256 ~= hash.sha256(packagefile)) then + + -- attempt to remove package file first + os.rm(packagefile) + + -- download package file + http.download(url, packagefile) + + -- check hash + if sha256 and sha256 ~= hash.sha256(packagefile) then + raise("unmatched checksum!") + end + end + + -- extract package file + os.rm(sourcedir .. ".tmp") + archive.extract(packagefile, sourcedir .. ".tmp") + + -- move to source directory + os.rm(sourcedir) + os.mv(sourcedir .. ".tmp", sourcedir) + + -- trace + cprint("\r${yellow} => ${clear}download %s .. ${green}ok%s", url, _emptychars()) +end + +-- get sorted urls +function _urls(package) + + -- sort urls from the version source + local urls = {{}, {}} + for _, url in ipairs(package:urls()) do + if git.checkurl(url) then + table.insert(urls[1], url) + else + table.insert(urls[2], url) + end + end + if package:version_from("tags", "branches") then + return table.join(urls[1], urls[2]) + else + return table.join(urls[2], urls[1]) + end +end + +-- download the given package +function main(package) + + -- skip phony package without urls + if #package:urls() == 0 then + return + end + + -- get working directory of this package + local workdir = package:cachedir() + + -- ensure the working directory first + os.mkdir(workdir) + + -- enter the working directory + local oldir = os.cd(workdir) + + -- download package from urls + local urls = _urls(package) + for idx, url in ipairs(urls) do + + -- filter url + url = package:filter():handle(url) + + -- download url + local ok = try + { + function () + + -- download package + local sourcedir = "source" + if git.checkurl(url) then + _checkout(package, url, sourcedir) + else + _download(package, url, sourcedir) + end + + -- ok + return true + end, + catch + { + function (errors) + + -- verbose? + if option.get("verbose") and errors then + cprint("${bright red}error: ${clear}%s", errors) + end + + -- trace + if git.checkurl(url) then + cprint("\r${yellow} => ${clear}clone %s %s .. ${red}failed%s", url, package:version_str(), _emptychars()) + else + cprint("\r${yellow} => ${clear}download %s .. ${red}failed%s", url, _emptychars()) + end + + -- failed? break it + if idx == #urls then + raise("download failed!") + end + end + } + } + + -- ok? break it + if ok then break end + end + + -- leave working directory + os.cd(oldir) +end + + diff --git a/xmake/actions/require/action/install.lua b/xmake/actions/require/action/install.lua new file mode 100644 index 000000000..a5a3292cc --- /dev/null +++ b/xmake/actions/require/action/install.lua @@ -0,0 +1,260 @@ +--!The Make-like install Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file install.lua +-- + +-- imports +import("core.base.option") +import("core.project.target") +import("build") + +-- install for xmake file +function _install_for_xmakefile(package) + + -- package to install directory + os.vrun("xmake p -o %s", package:installdir()) + + -- ok + return true +end + +-- install for generic +function _install_for_generic(package) + + -- the package name + local name = package:name() + + -- the install directory + local installdir = path.join(package:installdir(), name .. ".pkg") + + -- the linkdir + local linkdir = path.join(installdir, "lib/$(mode)/$(plat)/$(arch)") + os.mkdir(linkdir) + + -- the includedir + local includedir = path.join(installdir, "inc") + os.mkdir(includedir) + + -- the prefix directory exists? + local prefixdir = "" + if os.isdir(".prefix") and not os.emptydir(".prefix") then + prefixdir = ".prefix" .. path.seperator() + end + + -- install the library files and ignore hidden files (.xxx) + if not os.trycp(prefixdir .. "**" .. target.filename("*", "static"), linkdir) and + not os.trycp(prefixdir .. "**" .. target.filename("*", "shared"), linkdir) then + raise("the library files not found in package %s", name) + end + + -- install the header files + for _, headerfile in ipairs(table.join((os.files(prefixdir .. "**.h")), (os.files(prefixdir .. "**.hpp")))) do + + -- the destinate header + local dstheaderfile = nil + if #prefixdir > 0 then + dstheaderfile = path.absolute(path.relative(headerfile, path.join(prefixdir, "include")), includedir) + else + dstheaderfile = path.join(includedir, path.filename(headerfile)) + end + + -- install header file + os.cp(headerfile, dstheaderfile) + end + + -- make xmake.lua + local file = io.open(path.join(installdir, "xmake.lua"), "w") + if file then + + -- the xmake.lua content + local content = [[ +-- the %s package +option("%s") + + -- show menu + set_showmenu(true) + + -- set category + set_category("package") + + -- set description + set_description("The %s package") + + -- add defines to config.h if checking ok + add_defines_h_if_ok("$(prefix)_PACKAGE_HAVE_%s") + + -- add links for checking + add_links("%s") + + -- add link directories + add_linkdirs("lib/$(mode)/$(plat)/$(arch)") + + -- add include directories + add_includedirs("inc") +]] + + -- save file + file:writef(content, name, name, name, name:upper(), name) + + -- exit file + file:close() + end + + -- ok + return true +end + +-- on install the given package +function _on_install_package(package) + + -- init install scripts + local installscripts = + { + {"xmake.lua", _install_for_xmakefile } + , {"*", _install_for_generic } + } + + -- attempt to install it + for _, installscript in pairs(installscripts) do + + -- save the current directory + local oldir = os.curdir() + + -- try installing + local ok = try + { + function () + + -- attempt to install it if file exists + local files = os.files(installscript[1]) + if #files > 0 then + return installscript[2](package) + end + end, + + catch + { + function (errors) + + -- trace verbose info + if errors then + vprint(errors) + end + end + } + } + + -- restore directory + os.cd(oldir) + + -- ok? + if ok then return end + end + + -- failed + raise("attempt to install package %s failed!", package:name()) +end + +-- install the given package +function main(package) + + -- skip phony package without urls + if #package:urls() == 0 then + return + end + + -- get working directory of this package + local workdir = package:cachedir() + + -- enter source files directory + local oldir = nil + for _, srcdir in ipairs(os.dirs(path.join(workdir, "source", "*"))) do + oldir = os.cd(srcdir) + break + end + + -- trace + cprintf("${yellow} => ${clear}installing %s-%s .. ", package:name(), package:version_str()) + if option.get("verbose") then + print("") + end + + -- install it + try + { + function () + + -- the package scripts + local scripts = + { + package:script("install_before") + , package:script("install", _on_install_package) + , package:script("install_after") + } + + -- create the install task + local installtask = function () + + -- build it + build(package) + + -- install it + for i = 1, 3 do + local script = scripts[i] + if script ~= nil then + script(package) + end + end + end + + -- install package + if option.get("verbose") then + installtask() + else + process.asyncrun(installtask) + end + + -- trace + cprint("${green}ok") + end, + + catch + { + function (errors) + + -- verbose? + if option.get("verbose") and errors then + cprint("${bright red}error: ${clear}%s", errors) + end + + -- trace + cprint("${red}failed") + + -- failed + raise("install failed!") + end + } + } + + -- leave source codes directory + os.cd(oldir) +end diff --git a/xmake/actions/require/clear.lua b/xmake/actions/require/clear.lua new file mode 100644 index 000000000..169723ef3 --- /dev/null +++ b/xmake/actions/require/clear.lua @@ -0,0 +1,40 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file clear.lua +-- + +-- imports +import("core.project.cache") +import("core.package.package") + +-- clear all installed package caches +function main() + + -- clear cache directory + os.rm(package.cachedir()) + + -- clear require cache + cache.enter("local.require") + cache.clear() + cache.flush() +end + diff --git a/xmake/actions/require/environment.lua b/xmake/actions/require/environment.lua new file mode 100644 index 000000000..937ede435 --- /dev/null +++ b/xmake/actions/require/environment.lua @@ -0,0 +1,218 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file environment.lua +-- + +-- imports +import("core.base.option") +import("core.platform.environment") +import("net.http") +import("net.fasturl") +import("utils.archive") + +-- enter linux environment +function _enter_linux() + + -- add $programdir to $path for running xmake + os.addenv("PATH", os.programdir()) +end + +-- enter macosx environment +function _enter_macosx() + + -- add $programdir to $path for running xmake + os.addenv("PATH", os.programdir()) +end + +-- enter windows environment (xmake/winenv/cmd) +-- +-- @note curl and tar has been placed in the xmake installation package +-- +function _enter_windows() + + -- init winenv directory + local winenv_dir = path.translate("~/.xmake/winenv") + + -- add $programdir/winenv/cmd to $path + os.addenv("PATH", path.join(os.programdir(), "winenv", "bin")) + + -- load winenv + for _, script_dir in ipairs(os.files(path.join(winenv_dir, "**", "winenv.lua")), path.directory) do + import("winenv", {rootdir = script_dir}).main(script_dir) + return + end + + -- trace + cprintf("installing winenv .. ") + if option.get("verbose") then + print("") + end + + -- init winenv.zip file path + local winenv_zip = os.tmpfile() .. ".zip" + local winenv_zip_tmp = winenv_zip .. ".tmp" + + -- init winenv.zip urls + local winenv_arch = ifelse(os.arch() == "x64", "win64", "win32") + local winenv_urls = + { + format("https://github.com/tboox/xmake-%senv/archive/master.zip", winenv_arch) + , format("https://coding.net/u/waruqi/p/xmake-%senv/git/archive/master", winenv_arch) + } + fasturl.add(winenv_urls) + + -- download winenv.zip file + for _, winenv_url in ipairs(fasturl.sort(winenv_urls)) do + local ok = try + { + function () + + -- no cached winenv.zip file? + if not os.isfile(winenv_zip) or option.get("force") then + + -- remove winenv.zip.tmp file first + os.rm(winenv_zip_tmp) + + -- create a download task + local task = function () + http.download(winenv_url, winenv_zip_tmp) + end + + -- download winenv.zip + if option.get("verbose") then + task() + else + process.asyncrun(task) + end + + -- attempt to remove previous winenv.zip first + os.rm(winenv_zip) + + -- rename winenv.zip.tmp to winenv.zip + os.mv(winenv_zip_tmp, winenv_zip) + end + + -- ok + return true + end, + + catch + { + function (errors) + + -- verbose? + if option.get("verbose") then + cprint("${bright red}error: ${clear}%s", errors) + end + end + } + } + + -- ok? + if ok then + + -- remove winenv directory first + os.rm(winenv_dir) + + -- extract winenv.zip file + archive.extract(winenv_zip, winenv_dir) + + -- load winenv + for _, script_dir in ipairs(os.files(path.join(winenv_dir, "**", "winenv.lua")), path.directory) do + import("winenv", {rootdir = script_dir}).main(script_dir) + break + end + + -- trace + cprint("${green}ok") + + -- ok + return + end + end + + -- failed + cprint("${red}failed") + raise() +end + +-- enter host environment +function _enter_host() + + -- save old $path environment + _g._PATH_ENV = os.getenv("PATH") + + -- init loaders + local loaders = + { + linux = _enter_linux + , macosx = _enter_macosx + , windows = _enter_windows + } + + -- enter host environment + local loader = loaders[os.host()] + if loader then + loader() + end +end + +-- leave host environment +function _leave_host() + + -- restore old $path environment + os.setenv("PATH", _g._PATH_ENV) +end + +-- enter environment +-- +-- ensure that we can find some basic tools: git, make/nmake/cmake, msbuild ... +-- +-- If these tools not exist, we will install it first. +-- +function enter() + + -- enter host environment + _enter_host() + + -- set search pathes of toolchains + environment.enter("toolchains") + + -- TODO set toolchains for CC, LD, .. + + -- TODO set flags of toolchains +end + +-- leave environment +function leave() + + -- restore search pathes of toolchains + environment.leave("toolchains") + + -- TODO restore toolchains for CC, LD + + -- TODO set flags of toolchains + + + -- leave host environment + _leave_host() +end diff --git a/xmake/actions/require/info.lua b/xmake/actions/require/info.lua new file mode 100644 index 000000000..1e5d95a80 --- /dev/null +++ b/xmake/actions/require/info.lua @@ -0,0 +1,29 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file info.lua +-- + +-- show the given package info +function main(packages) + -- TODO +end + diff --git a/xmake/actions/require/install.lua b/xmake/actions/require/install.lua new file mode 100644 index 000000000..421945d52 --- /dev/null +++ b/xmake/actions/require/install.lua @@ -0,0 +1,89 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file package.lua +-- + +-- imports +import("core.base.option") +import("core.project.project") +import("action") +import("package") +import("repository") +import("environment") + +-- install packages +function main(requires) + + -- enter environment + environment.enter() + + -- TODO need optimization + -- pull all repositories first + repository.pull() + + -- load packages + local packages = package.load_packages(requires or project.requires()) + + -- download packages + local waitindex = 0 + local waitchars = {'\\', '|', '/', '-'} + process.runjobs(function (index) + + local instance = packages[index] + if instance then + + -- download package + action.download(instance) + end + + end, #packages, ifelse(option.get("verbose"), 1, 4), 300, function (indices) + + -- do not print progress info if be verbose + if option.get("verbose") then + return + end + + -- update waitchar index + waitindex = ((waitindex + 1) % #waitchars) + + -- make downloading packages list + local downloading = {} + for _, index in ipairs(indices) do + local instance = packages[index] + if instance then + table.insert(downloading, instance:name()) + end + end + + -- trace + cprintf("\r${yellow} => ${clear}downloading %s .. %s", table.concat(downloading, ", "), waitchars[waitindex + 1]) + end) + + -- install all required packages from repositories + for _, instance in ipairs(packages) do + action.install(instance) + end + + -- leave environment + environment.leave() +end + diff --git a/xmake/actions/require/list.lua b/xmake/actions/require/list.lua new file mode 100644 index 000000000..056fdab16 --- /dev/null +++ b/xmake/actions/require/list.lua @@ -0,0 +1,38 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file list.lua +-- + +-- imports +import("core.project.project") +import("package") + +-- list packages +function main() + + -- list all requires + print("Tha package dependencies:") + for packagename, requireinfo in pairs(package.load_requires(project.requires())) do + print(" %s %s", packagename, requireinfo.version) + end +end + diff --git a/xmake/actions/require/main.lua b/xmake/actions/require/main.lua new file mode 100644 index 000000000..23fce2766 --- /dev/null +++ b/xmake/actions/require/main.lua @@ -0,0 +1,100 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file main.lua +-- + +-- imports +import("core.base.option") +import("core.base.task") +import("core.project.config") +import("core.project.project") +import("core.platform.platform") +import("list") +import("info") +import("clear") +import("search") +import("install") + +-- +-- the default repositories: +-- xmake-repo https://github.com/tboox/xmake-repo.git +-- +-- add other repositories: +-- xmake repo --add other-repo https://github.com/other/other-repo.git +-- or +-- add_repositories("other-repo https://github.com/other/other-repo.git") +-- +-- add requires: +-- +-- add_requires("tboox.tbox >=1.5.1", "zlib >=1.2.11") +-- add_requires("zlib master") +-- add_requires("[email protected] >=1.5.1") +-- add_requires("https://github.com/tboox/[email protected] >=1.5.1") +-- +-- add package dependencies: +-- +-- target("test") +-- add_packages("tboox.tbox", "zlib") +-- + +-- load project +function _load_project() + + -- config it first + task.run("config") + + -- enter project directory + os.cd(project.directory()) +end + +-- main +function main() + + -- load project first + _load_project() + + -- clear all installed packages cache + if option.get("clear") then + + clear(option.get("global")) + + -- search for the given packages from repositories + elseif option.get("search") then + + search(option.get("packages")) + + -- show the given package info + elseif option.get("info") then + + info(option.get("packages")) + + -- list all package dependencies + elseif option.get("list") then + + list() + + -- install and update all outdated package dependencies by default if no arguments + else + install(option.get("requires")) + end +end + diff --git a/xmake/actions/require/package.lua b/xmake/actions/require/package.lua new file mode 100644 index 000000000..6b401ab73 --- /dev/null +++ b/xmake/actions/require/package.lua @@ -0,0 +1,360 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file package.lua +-- + +-- imports +import("core.base.semver") +import("core.base.option") +import("core.base.global") +import("core.project.cache") +import("core.project.project") +import("core.package.package", {alias = "core_package"}) +import("devel.git") +import("net.fasturl") +import("repository") + +-- +-- parse require string +-- +-- add_requires("tboox.tbox >=1.5.1", "zlib >=1.2.11") +-- add_requires("zlib master") +-- add_requires("[email protected] >=1.5.1") +-- add_requires("https://github.com/tboox/[email protected] >=1.5.1") +-- add_requires("tboox.tbox >=1.5.1 <1.6.0 optional") +-- +function _parse_require(require_str) + + -- get it from cache first + local requires = _g._REQUIRES or {} + local required = requires[require_str] + if required then + return required.packagename, required.requireinfo + end + + -- split package and version info + local splitinfo = require_str:split('%s+') + assert(splitinfo and #splitinfo > 0, "require(\"%s\"): invalid!", require_str) + + -- get package info + local packageinfo = splitinfo[1] + + -- get mode at last position + -- + -- .e.g + -- + -- must + -- optional + -- + local mode = "must" + if #splitinfo > 1 then + + -- get mode + local modes = {must = true, optional = true} + local value = splitinfo[#splitinfo]:lower() + if modes[value] then + mode = value + table.remove(splitinfo) + end + end + + -- get version + -- + -- .e.g + -- + -- >=1.5.1 <1.6.0 + -- master || >1.4 + -- ~1.2.3 + -- ^1.1 + -- + local version = "master" + if #splitinfo > 1 then + version = table.concat(table.slice(splitinfo, 2), " ") + end + assert(version, "require(\"%s\"): unknown version!", require_str) + + -- get repository name, package name and package url + local reponame = nil + local packageurl = nil + local packagename = nil + local pos = packageinfo:find_last('@', true) + if pos then + + -- get package name + packagename = packageinfo:sub(pos + 1) + + -- get reponame or packageurl + local repo_or_pkgurl = packageinfo:sub(1, pos - 1) + + -- is package url? + if repo_or_pkgurl:find('[/\\]') then + packageurl = repo_or_pkgurl + else + reponame = repo_or_pkgurl + end + else + packagename = packageinfo + end + + -- check package name + assert(packagename, "require(\"%s\"): the package name not found!", require_str) + + -- init required item + local required = {} + required.packagename = packagename + required.requireinfo = {reponame = reponame, packageurl = packageurl, version = version, mode = mode} + + -- save this required item to cache + requires[require_str] = required + _g._REQUIRES = requires + + -- ok + return required.packagename, required.requireinfo +end + +-- load package instance from the given package url +function _load_package_from_url(packagename, packageurl) + + -- load it + return core_package.load_from_url(packagename, packageurl) +end + +-- load package instance from project +function _load_package_from_project(packagename) + + -- load it + return core_package.load_from_project(packagename) +end + +-- load package instance from repositories +function _load_package_from_repository(packagename, reponame) + + -- get package directory from the given package name + local packagedir, is_global = repository.packagedir(packagename, reponame) + if packagedir then + -- load it + return core_package.load_from_repository(packagename, is_global, packagedir) + end +end + +-- load required packages +function _load_package(packagename, requireinfo) + + -- attempt to get it from cache first + local packages = _g._PACKAGES or {} + local instance = packages[packagename] + if instance then + + -- satisfy required version? + if not semver.satisfies(instance:version(), requireinfo.version) then + raise("package(%s): version conflict, '%s' does not satisfy '%s'!", packagename, instance:version(), requireinfo.version) + end + + -- ok + return instance + end + + -- load package instance + instance = nil + if requireinfo.packageurl then + -- load package from the given package url + instance = _load_package_from_url(packagename, requireinfo.packageurl) + else + -- load package from project first + instance = _load_package_from_project(packagename) + if not instance then + -- load package from repositories + instance = _load_package_from_repository(packagename, requireinfo.reponame) + end + end + + -- check + assert(instance, "package(%s) not found!", packagename) + + -- save require info to package + instance:requireinfo_set(requireinfo) + + -- save this package instance to cache + packages[packagename] = instance + _g._PACKAGES = packages + + -- ok + return instance +end + +-- load all required packages +function _load_packages(requires) + + -- no requires? + if not requires or #requires == 0 then + return {} + end + + -- load packages + local packages = {} + for packagename, requireinfo in pairs(load_requires(requires)) do + + -- load package instance + local package = _load_package(packagename, requireinfo) + + -- load required packages and save them first of this package + requires = package:get("requires") + if requires then + table.join2(packages, _load_packages(requires)) + end + + -- save this package instance + table.insert(packages, package) + end + + -- ok? + return packages +end + +-- load all git refs from packages +function _load_packages_gitrefs(packages) + + -- enter cache scope + cache.enter("local.require") + + -- load cache + local gitrefs = nil + if option.get("force") then + gitrefs = {} + else + gitrefs = cache.get("gitrefs") or {} + end + + -- run tasks + local results = {} + process.runjobs(function (index) + local package = packages[index] + if package then + + -- attempt to get refs from cache first + local refs = gitrefs[package:name()] + if refs then + results[package:name()] = {tags = refs.tags, branches = refs.branches} + else + -- attempt to get refs from the git url + local tags = {} + local branches = {} + for _, url in ipairs(package:urls()) do + if git.checkurl(url) then + + -- fetch refs + tags, branches = git.refs(url) + + -- save result + results[package:name()] = {tags = tags, branches = branches} + + -- cache result + gitrefs[package:name()] = {tags = tags, branches = branches} + break + end + end + end + end + end, #packages) + + -- save cache + cache.set("gitrefs", gitrefs) + cache.flush() + + -- ok? + return results +end + +-- select package version +function _select_package_version(package, required_ver, gitrefs) + + -- get versions + local versions = package:get("versions") + + -- attempt to get tags and branches from the git url + local refs = {} + if gitrefs then + refs = gitrefs[package:name()] or {} + end + + -- select required version + return semver.select(required_ver, versions, refs.tags, refs.branches) +end + +-- the cache directory +function cachedir() + return path.join(global.directory(), "cache", "packages") +end + +-- load requires +function load_requires(requires) + + -- parse requires + local requireinfos = {} + for _, require_str in ipairs(requires) do + + -- parse require info + local packagename, requireinfo = _parse_require(require_str) + + -- save this required package + requireinfos[packagename] = requireinfo + end + + -- ok + return requireinfos +end + +-- load all required packages +function load_packages(requires) + + -- laod all required packages recursively + local packages = _load_packages(requires) + + -- add all urls to fasturl and prepare to sort them together + for _, package in ipairs(packages) do + fasturl.add(package:urls()) + end + + -- load git refs from packages + local gitrefs = _load_packages_gitrefs(packages) + + -- sort and update urls + for _, package in ipairs(packages) do + + -- sort package urls + package:urls_set(fasturl.sort(package:urls())) + + -- exists urls? otherwise be phony package (only as package group) + if #package:urls() > 0 then + + -- select package version + local version, source = _select_package_version(package, package:requireinfo().version, gitrefs) + + -- save version to package + package:version_set(version, source) + end + end + + -- ok + return packages +end + diff --git a/xmake/actions/require/repository.lua b/xmake/actions/require/repository.lua new file mode 100644 index 000000000..5576b4103 --- /dev/null +++ b/xmake/actions/require/repository.lua @@ -0,0 +1,152 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file repository.lua +-- + +-- imports +import("core.base.option") +import("core.package.repository") +import("devel.git") + +-- get all repositories +function repositories() + + -- get it from cache it + if _g._REPOSITORIES then + return _g._REPOSITORIES + end + + -- get all repositories (local first) + local repos = table.join(repository.repositories(false), repository.repositories(true)) + + -- save repositories + _g._REPOSITORIES = repos + + -- ok + return repos +end + +-- pull repositories +function pull(position) + + -- trace + printf("updating repositories .. ") + if option.get("verbose") then + print("") + end + + -- create a pull task + local task = function () + + -- pull all repositories + local pulled = {} + for _, repo in ipairs(repositories()) do + + -- the repository directory + local repodir = path.join(repository.directory(repo.global), repo.name) + + -- remove repeat and only pull the first repository + if not pulled[repodir] then + if os.isdir(repodir) then + + -- trace + vprint("pulling repository(%s): %s to %s ..", repo.name, repo.url, repodir) + + -- pull it + git.pull({verbose = option.get("verbose"), branch = "master", repodir = repodir}) + else + -- trace + vprint("cloning repository(%s): %s to %s ..", repo.name, repo.url, repodir) + + -- clone it + git.clone(repo.url, {verbose = option.get("verbose"), branch = "master", outputdir = repodir}) + end + + -- pull this repository ok + pulled[repodir] = true + end + end + end + + -- pull repositories + if option.get("verbose") then + task() + else + process.asyncrun(task) + end + + -- trace + cprint("${green}ok") +end + +-- get package directory from repositories +function packagedir(packagename, reponame) + + -- get it from cache it + local packagedirs = _g._PACKAGEDIRS or {} + local foundir = packagedirs[packagename] + if foundir then + return foundir[1], foundir[2] + end + + -- find the package directory from the given repository + if reponame then + for _, from in ipairs({"local", "global"}) do + local is_global = (from == "global") + for _, repodir in ipairs(repository.directory(is_global)) do + local dir = path.join(repodir, reponame, "packages", (packagename:gsub('%.', path.seperator()))) + if os.isdir(dir) then + foundir = {dir, is_global} + break + end + end + if foundir then + break + end + end + else + -- find the package directory from all repositories + for _, repo in ipairs(repositories()) do + + -- the package directory + local dir = path.join(repository.directory(repo.global), repo.name, "packages", (packagename:gsub('%.', path.seperator()))) + if os.isdir(dir) then + foundir = {dir, repo.global} + break + end + end + end + + -- found? + if foundir then + + -- save package directory + packagedirs[packagename] = foundir + + -- update cache + _g._PACKAGEDIRS = packagedirs + end + + -- ok + return foundir[1], foundir[2] +end + diff --git a/xmake/actions/require/search.lua b/xmake/actions/require/search.lua new file mode 100644 index 000000000..569f99115 --- /dev/null +++ b/xmake/actions/require/search.lua @@ -0,0 +1,29 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file search.lua +-- + +-- search for the given packages from repositories +function main(packages) + -- TODO +end + diff --git a/xmake/actions/require/xmake.lua b/xmake/actions/require/xmake.lua new file mode 100644 index 000000000..6c5b7cacd --- /dev/null +++ b/xmake/actions/require/xmake.lua @@ -0,0 +1,61 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file require.lua +-- + +-- define task +task("require") + + -- set category + set_category("action") + + -- on run + on_run("main") + + -- set menu + set_menu { + -- usage + usage = "xmake require [options] [packages]" + + -- description + , description = "Install and update required packages." + + -- xmake q + , shortname = 'q' + + -- options + , options = + { + {'c', "clear", "k", nil, "Clear all installed package caches." } + , {'f', "force", "k", nil, "Force to reinstall all package dependencies." } + , {'l', "list", "k", nil, "List all package dependencies." } + , { } + , {nil, "info", "k", nil, "Show the given package info." } + , {'s', "search", "k", nil, "Search for the given packages from repositories." } + , { } + , {nil, "requires", "vs", nil, "The package requires.", + ".e.g", + " $ xmake require zlib tboox.tbox", + " $ xmake require \"zlib >=1.2.11\" \"tboox.tbox master\"", + " $ xmake require \"[email protected]:tboox/[email protected] >=1.6.0 <1.6.1 || master\"" } + } + } diff --git a/xmake/actions/uninstall/uninstall_admin.lua b/xmake/actions/uninstall/uninstall_admin.lua index 891b4a857..a8ac07468 100644 --- a/xmake/actions/uninstall/uninstall_admin.lua +++ b/xmake/actions/uninstall/uninstall_admin.lua @@ -41,9 +41,6 @@ function main(targetname, installdir) -- load platform platform.load(config.plat()) - -- laod project - project.load() - -- save the current option and push a new option context option.save() diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index ad01c67f1..fbe208b9b 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -468,7 +468,7 @@ end function os.tmpfile() -- make it - return path.join(os.tmpdir(), "_" .. (os.uuid():gsub("-", ""))) + return path.join(os.tmpdir(), "_" .. (hash.uuid():gsub("-", ""))) end -- run command diff --git a/xmake/core/main.lua b/xmake/core/main.lua index ef0edd874..227d0e970 100644 --- a/xmake/core/main.lua +++ b/xmake/core/main.lua @@ -36,6 +36,7 @@ local privilege = require("base/privilege") local task = require("base/task") local project = require("project/project") local history = require("project/history") +local package = require("package/package") -- init the option menu local menu = @@ -51,7 +52,6 @@ local menu = } - -- show logo function main._show_logo() @@ -62,6 +62,7 @@ function main._show_logo() \ \/ / | \/ |/ _ | |/ / __ \ > < | \__/ | /_| | < ___/ /_/\_\_|_| |_|\__ \|_|\_\____| + by ruki, ${underline}tboox.org${clear} ${point_right} ${bright}Manual${clear}: ${underline}http://xmake.io/#/home${clear} @@ -162,6 +163,7 @@ function main._init() -- define task and package apis first before loading project's xmake.lua - calling option.init() project.define_apis(task.apis()) + project.define_apis(package.apis()) end -- the main function diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua new file mode 100644 index 000000000..e5ca87b84 --- /dev/null +++ b/xmake/core/package/package.lua @@ -0,0 +1,419 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific package governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file package.lua +-- + +-- define module +local package = package or {} +local _instance = _instance or {} + +-- load modules +local os = require("base/os") +local io = require("base/io") +local path = require("base/path") +local utils = require("base/utils") +local table = require("base/table") +local filter = require("base/filter") +local global = require("base/global") +local interpreter = require("base/interpreter") +local sandbox = require("sandbox/sandbox") +local config = require("project/config") +local project = require("project/project") +local platform = require("platform/platform") + +-- new an instance +function _instance.new(name, info, rootdir) + + -- new an instance + local instance = table.inherit(_instance) + + -- init instance + instance._NAME = name + instance._INFO = info + instance._ROOTDIR = rootdir + instance._FILTER = filter.new() + + -- register filter handler + instance._FILTER:register("package", function (variable) + + -- init maps + local maps = + { + version = instance:version_str() + } + + -- map it + return maps[variable] + end) + + -- ok + return instance +end + +-- get the package configure +function _instance:get(name) + + -- the info + local info = self._INFO + + -- get if from info first + local value = info[name] + if value ~= nil then + return value + end +end + +-- get the package name +function _instance:name() + return self._NAME +end + +-- get the package filter +function _instance:filter() + return self._FILTER +end + +-- get urls +function _instance:urls() + return self._URLS or table.wrap(self:get("urls")) +end + +-- get urls +function _instance:urls_set(urls) + self._URLS = urls +end + +-- get sha256 +function _instance:sha256() + + -- get it from cache first + if self._SHA256 then + return self._SHA256 + end + + -- find sha256 + local version = self:version() + local sha256s = table.wrap(self:get("sha256s")) + local versions = table.wrap(self:get("versions")) + if version then + for idx, ver in ipairs(versions) do + if ver == version then + self._SHA256 = sha256s[idx] + break + end + end + end + + -- get it + return self._SHA256 +end + +-- is global package? +function _instance:global() + return self._ISGLOBAL +end + +-- is optional package? +function _instance:optional() + + -- optional? + return self._REQUIREINFO.mode == "optional" +end + +-- get the cached directory of this package +function _instance:cachedir() + return path.join(package.cachedir(), self:name() .. "-" .. (self:version_str() or "group")) +end + +-- get the installed directory of this package +function _instance:installdir() + return path.join(package.installdir(self:global()), self:name() .. "-" .. (self:version_str() or "group")) +end + +-- get the version +function _instance:version() + + -- get it + return self._VERSION or {} +end + +-- get the version string +function _instance:version_str() + + -- get it + return self:version().raw or self:version().version +end + +-- the verson from tags, branches or versions? +function _instance:version_from(...) + + -- from source? + for _, source in ipairs({...}) do + return self:version().source == source + end +end + +-- set the version +function _instance:version_set(version, source) + + -- init package version + if type(version) == "string" then + version = {version = version, source = source} + else + version.source = source + end + + -- save version + self._VERSION = version +end + +-- get the require info +function _instance:requireinfo() + return self._REQUIREINFO +end + +-- set the require info +function _instance:requireinfo_set(requireinfo) + self._REQUIREINFO = requireinfo +end + +-- get xxx_script +function _instance:script(name, generic) + + -- get script + local script = self:get(name) + if type(script) == "function" then + return script + elseif type(script) == "table" then + + -- match script for special plat and arch + local plat = (config.get("plat") or "") + local pattern = plat .. '|' .. (config.get("arch") or "") + for _pattern, _script in pairs(script) do + if not _pattern:startswith("__") and pattern:find('^' .. _pattern .. '$') then + return _script + end + end + + -- match script for special plat + for _pattern, _script in pairs(script) do + if not _pattern:startswith("__") and plat:find('^' .. _pattern .. '$') then + return _script + end + end + + -- get generic script + return script["__generic__"] or generic + end + + -- only generic script + return generic +end + +-- the interpreter +function package._interpreter() + + -- the interpreter has been initialized? return it directly + if package._INTERPRETER then + return package._INTERPRETER + end + + -- init interpreter + local interp = interpreter.new() + assert(interp) + + -- define apis + interp:api_define(package.apis()) + + -- save interpreter + package._INTERPRETER = interp + + -- ok? + return interp +end + +-- get package apis +function package.apis() + + return + { + values = + { + -- package.set_xxx + "package.set_urls" + , "package.set_sha256s" + , "package.set_versions" + , "package.set_homepage" + , "package.set_description" + -- package.add_xxx + , "package.add_requires" + } + , script = + { + -- package.on_xxx + "package.on_build" + , "package.on_install" + , "package.on_test" + + -- package.before_xxx + , "package.before_build" + , "package.before_install" + , "package.before_test" + + -- package.before_xxx + , "package.after_build" + , "package.after_install" + , "package.after_test" + } + } +end + +-- get install directory +function package.installdir(is_global) + + -- get directory + if is_global then + return path.join(global.directory(), "packages") + else + return path.join(config.directory(), "packages") + end +end + +-- the cache directory +function package.cachedir() + return path.join(global.directory(), "cache", "packages") +end + +-- load the package from the package url +function package.load_from_url(packagename, packageurl) + + -- make a temporary package file + local packagefile = os.tmpfile() .. ".lua" + + -- make package description + local packagedata = string.format([[ + package("%s") + set_urls("%s") + ]], packagename, packageurl) + + -- write a temporary package description to file + local ok, errors = io.writefile(packagefile, packagedata) + if not ok then + return nil, errors + end + + -- load package instance + local instance, errors = package.load_from_repository(packagename, false, nil, packagefile) + + -- remove the package file + os.rm(packagefile) + + -- ok? + return instance, errors +end + +-- load the package from the project file +function package.load_from_project(packagename) + + -- get it directly from cache first + package._PACKAGES = package._PACKAGES or {} + if package._PACKAGES[packagename] then + return package._PACKAGES[packagename] + end + + -- load packages (with cache) + local packages, errors = project.packages() + if not packages then + return nil, errors + end + + -- get interpreter + local interp = errors or package._interpreter() + + -- not found? + if not packages[packagename] then + return + end + + -- new an instance + local instance, errors = _instance.new(packagename, packages[packagename], interp:rootdir()) + if not instance then + return nil, errors + end + + -- mark as loval package + instance._ISGLOBAL = false + + -- save instance to the cache + package._PACKAGES[packagename] = instance + + -- ok + return instance +end + +-- load the package from the package directory or package description file +function package.load_from_repository(packagename, is_global, packagedir, packagefile) + + -- get it directly from cache first + package._PACKAGES = package._PACKAGES or {} + if package._PACKAGES[packagename] then + return package._PACKAGES[packagename] + end + + -- find the package script path + local scriptpath = packagefile + if not packagefile and packagedir then + scriptpath = path.join(packagedir, "xmake.lua") + end + if not scriptpath or not os.isfile(scriptpath) then + return nil, string.format("the package %s not found!", packagename) + end + + -- load package and disable filter, we will process filter after a while + local results, errors = package._interpreter():load(scriptpath, "package", true, false) + if not results and os.isfile(scriptpath) then + return nil, errors + end + + -- check the package name + if not results[packagename] then + return nil, string.format("the package %s not found!", name) + end + + -- new an instance + local instance, errors = _instance.new(packagename, results[packagename], package._interpreter():rootdir()) + if not instance then + return nil, errors + end + + -- mark as global package? + instance._ISGLOBAL = is_global + + -- save instance to the cache + package._PACKAGES[packagename] = instance + + -- ok + return instance +end + +-- return module +return package diff --git a/xmake/core/package/repository.lua b/xmake/core/package/repository.lua new file mode 100644 index 000000000..6a4bcc9f0 --- /dev/null +++ b/xmake/core/package/repository.lua @@ -0,0 +1,134 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file repository.lua +-- + +-- define module +local repository = repository or {} + +-- load modules +local utils = require("base/utils") +local string = require("base/string") +local global = require("base/global") +local cache = require("project/cache") +local config = require("project/config") + +-- get cache +function repository._cache(is_global) + + -- get position + local position = utils.ifelse(is_global, "global", "local") + + -- get it from cache first if exists + if repository._CACHE and repository._CACHE[position] then + return repository._CACHE[position] + end + + -- init cache + repository._CACHE = repository._CACHE or {} + repository._CACHE[position] = cache(position .. ".repository") + + -- ok + return repository._CACHE[position] +end + +-- get the local or global package directory +function repository.directory(is_global) + + -- get directory + if is_global then + return path.join(global.directory(), "repositories") + else + return path.join(config.directory(), "repositories") + end +end + +-- get repository url from the given name +function repository.get(name, is_global) + + -- get it + local repositories = repository.repositories(is_global) + if repositories then + return repositories[name] + end +end + +-- add repository url to the given name +function repository.add(name, url, is_global) + + -- no name? + if not name then + return false, string.format("please set name to repository: %s", url) + end + + -- get repositories + local repositories = repository.repositories(is_global) or {} + + -- set it + repositories[name] = url + + -- save repositories + repository._cache(is_global):set("repositories", repositories) + + -- flush it + return repository._cache(is_global):flush() +end + +-- remove repository from gobal or local directory +function repository.remove(name, is_global) + + -- get repositories + local repositories = repository.repositories(is_global) or {} + if not repositories[name] then + return false, string.format("repository(%s): not found!", name) + end + + -- remove it + repositories[name] = nil + + -- save repositories + repository._cache(is_global):set("repositories", repositories) + + -- flush it + return repository._cache(is_global):flush() +end + +-- clear all repositories +function repository.clear(is_global) + + -- clear repositories + repository._cache(is_global):set("repositories", {}) + + -- flush it + return repository._cache(is_global):flush() +end + + +-- get all repositories from global or local directory +function repository.repositories(is_global) + + -- get repositories + return repository._cache(is_global):get("repositories") +end + +-- return module +return repository diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua index 6c844e4f0..d57721d76 100644 --- a/xmake/core/project/project.lua +++ b/xmake/core/project/project.lua @@ -209,6 +209,9 @@ function project.interpreter() "set_project" , "set_version" , "set_modes" + -- add_xxx + , "add_requires" + , "add_repositories" -- target.set_xxx , "target.set_kind" , "target.set_strip" @@ -235,8 +238,8 @@ function project.interpreter() -- option.add_xxx , "option.add_deps" , "option.add_vectorexts" - , "option.add_bindings" -- deprecated - , "option.add_rbindings" -- deprecated + , "option.add_bindings" -- deprecated + , "option.add_rbindings" -- deprecated } , pathes = { @@ -633,6 +636,36 @@ function project.tasks() return results, interp end +-- get packages +function project.packages() + + -- get it from cache first + if project._PACKAGES then + return project._PACKAGES, interp + end + + -- get interpreter + local interp = project.interpreter() + assert(interp) + + -- the project file is not found? + if not os.isfile(os.projectfile()) then + return {}, nil + end + + -- load the tasks from the the project file and disable filter, we will process filter after a while + local results, errors = interp:load(os.projectfile(), "package", true, false) + if not results then + return nil, errors + end + + -- save results to cache + project._PACKAGES = results + + -- ok? + return results, interp +end + -- get the mtimes function project.mtimes() return project.interpreter():mtimes() diff --git a/xmake/core/sandbox/modules/hash.lua b/xmake/core/sandbox/modules/hash.lua new file mode 100644 index 000000000..7143aa511 --- /dev/null +++ b/xmake/core/sandbox/modules/hash.lua @@ -0,0 +1,59 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file hash.lua +-- + +-- load modules +local raise = require("sandbox/modules/raise") + +-- define module +local sandbox_hash = sandbox_hash or {} + +-- make a new uuid +function sandbox_hash.uuid(name) + + -- make it + local uuid = hash.uuid(name) + if not uuid then + raise("cannot make uuid %s", name) + end + + -- ok? + return uuid +end + +-- make sha256 from the given file +function sandbox_hash.sha256(file) + + -- make it + local sha256 = hash.sha256(file) + if not sha256 then + raise("cannot make sha256 for %s", file) + end + + -- ok? + return sha256 +end + +-- return module +return sandbox_hash + diff --git a/xmake/core/sandbox/modules/import/core/base/semver.lua b/xmake/core/sandbox/modules/import/core/base/semver.lua new file mode 100644 index 000000000..ee4c6e685 --- /dev/null +++ b/xmake/core/sandbox/modules/import/core/base/semver.lua @@ -0,0 +1,86 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file semver.lua +-- + +-- define module +local sandbox_core_base_semver = sandbox_core_base_semver or {} + +-- load modules +local table = require("base/table") +local raise = require("sandbox/modules/raise") + +-- parse a version string into a props table containing all semver infos +-- +-- semver.parse('1.2.3') => { major = 1, minor = 2, patch = 3, ... } +-- semver.parse('a.b.c') => nil +-- +function sandbox_core_base_semver.parse(version) + + -- compare version + local result, errors = semver.parse(version) + if errors then + raise(errors) + end + + -- ok + return result +end + +-- this version satisfies in the given version range +-- +-- semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true +-- +function sandbox_core_base_semver.satisfies(version, range) + -- satisfies version + local result, errors = semver.satisfies(version, range) + if errors then + raise(errors) + end + + -- ok + return result +end + +-- select required version from versions, tags and branches +-- +-- .e.g +-- +-- local version, source = semver.select(">=1.5.0 <1.6", {"1.5.0", "1.5.1"}, {"v1.5.0", ..}, {"master", "dev"}) +-- +-- @version the selected version number +-- @source the version source, .e.g versions, tags, branchs +-- +function sandbox_core_base_semver.select(range, versions, tags, branches) + + -- select version + local verinfo, errors = semver.select(range, versions or {}, tags or {}, branches or {}) + if not verinfo then + raise(errors) + end + + -- ok + return verinfo.version, verinfo.source +end + +-- return module +return sandbox_core_base_semver diff --git a/xmake/core/sandbox/modules/import/core/package/package.lua b/xmake/core/sandbox/modules/import/core/package/package.lua new file mode 100644 index 000000000..10d62f493 --- /dev/null +++ b/xmake/core/sandbox/modules/import/core/package/package.lua @@ -0,0 +1,82 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file package.lua +-- + +-- define module +local sandbox_core_package_package = sandbox_core_package_package or {} + +-- load modules +local package = require("package/package") +local raise = require("sandbox/modules/raise") + +-- get cache directory +function sandbox_core_package_package.cachedir() + return package.cachedir() +end + +-- get install directory +function sandbox_core_package_package.installdir(is_global) + return package.installdir(is_global) +end + +-- load the package from the project file +function sandbox_core_package_package.load_from_project(packagename) + + -- load package instance + local instance, errors = package.load_from_project(packagename) + if errors then + raise(errors) + end + + -- ok + return instance +end + +-- load the package from repositories +function sandbox_core_package_package.load_from_repository(packagename, is_global, packagedir, packagefile) + + -- load package instance + local instance, errors = package.load_from_repository(packagename, is_global, packagedir, packagefile) + if not instance then + raise(errors) + end + + -- ok + return instance +end + +-- load the package from the package url +function sandbox_core_package_package.load_from_url(packagename, packageurl) + + -- load package instance + local instance, errors = package.load_from_url(packagename, packageurl) + if not instance then + raise(errors) + end + + -- ok + return instance +end + +-- return module +return sandbox_core_package_package diff --git a/xmake/core/sandbox/modules/import/core/package/repository.lua b/xmake/core/sandbox/modules/import/core/package/repository.lua new file mode 100644 index 000000000..3336ab4e1 --- /dev/null +++ b/xmake/core/sandbox/modules/import/core/package/repository.lua @@ -0,0 +1,119 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file repository.lua +-- + +-- define module +local sandbox_core_package_repository = sandbox_core_package_repository or {} + +-- load modules +local project = require("project/project") +local repository = require("package/repository") +local raise = require("sandbox/modules/raise") +local import = require("sandbox/modules/import") + +-- get repository directory +function sandbox_core_package_repository.directory(is_global) + return repository.directory(is_global) +end + +-- get repository url from the given name +function sandbox_core_package_repository.get(name, is_global) + + -- get it + return repository.get(name, is_global) +end + +-- add repository url to the given name +function sandbox_core_package_repository.add(name, url, is_global) + + -- add it + local ok, errors = repository.add(name, url, is_global) + if not ok then + raise(errors) + end +end + +-- remove repository from gobal or local directory +function sandbox_core_package_repository.remove(name, is_global) + + -- remove it + local ok, errors = repository.remove(name, is_global) + if not ok then + raise(errors) + end +end + +-- clear all repositories from global or local directory +function sandbox_core_package_repository.clear(is_global) + + -- clear all repositories + local ok, errors = repository.clear(is_global) + if not ok then + raise(errors) + end +end + +-- get all repositories from global or local directory +function sandbox_core_package_repository.repositories(is_global) + + -- add main global xmake repository + local repositories = {} + if is_global then + + -- import fasturl + import("net.fasturl") + + -- sort main urls + local mainurls = {"https://github.com/tboox/xmake-repo.git", "https://git.oschina.net/tboox/xmake-repo.git"} + fasturl.add(mainurls) + mainurls = fasturl.sort(mainurls) + + -- add main urls + for _, mainurl in ipairs(mainurls) do + table.insert(repositories, {name = "xmake-repo", url = mainurl, global = true}) + end + end + + -- load repositories from repository cache + for name, url in pairs(table.wrap(repository.repositories(is_global))) do + table.insert(repositories, {name = name, url = url, global = is_global}) + end + + -- load repositories from project file + if not is_global then + for _, repo in ipairs(table.wrap(project.get("repositories"))) do + local repoinfo = repo:split(' ') + if #repoinfo == 2 then + table.insert(repositories, {name = repoinfo[1], url = repoinfo[2], global = is_global}) + else + raise("invalid repository: %s", repo) + end + end + end + + -- get the repositories + return repositories +end + +-- return module +return sandbox_core_package_repository diff --git a/xmake/core/sandbox/modules/import/core/project/project.lua b/xmake/core/sandbox/modules/import/core/project/project.lua index 4a7beb3e0..bae02f7a0 100644 --- a/xmake/core/sandbox/modules/import/core/project/project.lua +++ b/xmake/core/sandbox/modules/import/core/project/project.lua @@ -34,6 +34,7 @@ local project = require("project/project") local sandbox = require("sandbox/sandbox") local raise = require("sandbox/modules/raise") local environment = require("platform/environment") +local package = require("package/package") -- load project function sandbox_core_project.load() @@ -161,5 +162,10 @@ function sandbox_core_project.modes() return project.get("modes") end +-- get the project requires +function sandbox_core_project.requires() + return project.get("requires") +end + -- return module return sandbox_core_project diff --git a/xmake/core/sandbox/modules/interpreter/os.lua b/xmake/core/sandbox/modules/interpreter/os.lua index b956726eb..ec650a212 100644 --- a/xmake/core/sandbox/modules/interpreter/os.lua +++ b/xmake/core/sandbox/modules/interpreter/os.lua @@ -44,7 +44,7 @@ sandbox_os.programdir = os.programdir sandbox_os.programfile = os.programfile sandbox_os.projectdir = os.projectdir sandbox_os.projectfile = os.projectfile -sandbox_os.uuid = os.uuid +sandbox_os.uuid = hash.uuid -- match files function sandbox_os.files(pattern, ...) diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 839d5cbba..65608327b 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -443,17 +443,6 @@ function sandbox_os.exists(file_or_dir) return os.exists(file_or_dir) end --- make a new uuid -function sandbox_os.uuid(name) - - -- make it - local uuid = os.uuid(name) - assert(uuid) - - -- ok? - return uuid -end - -- return module return sandbox_os diff --git a/xmake/core/sandbox/modules/utils.lua b/xmake/core/sandbox/modules/utils.lua index 40d2c6170..e282ef80e 100644 --- a/xmake/core/sandbox/modules/utils.lua +++ b/xmake/core/sandbox/modules/utils.lua @@ -26,6 +26,7 @@ local io = require("base/io") local utils = require("base/utils") local colors = require("base/colors") +local option = require("base/option") local try = require("sandbox/modules/try") local catch = require("sandbox/modules/catch") local vformat = require("sandbox/modules/vformat") @@ -72,7 +73,7 @@ function sandbox_utils.print(format, ...) { function () -- attempt to print format string first - utils._iowrite(vformat(format, unpack(args)) .. "\n") + utils._print(vformat(format, unpack(args))) end, catch { @@ -100,7 +101,7 @@ end function sandbox_utils.cprint(format, ...) -- done - utils._iowrite(colors(vformat(format, ...)) .. "\n") + utils._print(colors(vformat(format, ...))) end -- print format string, the builtin variables and colors without newline @@ -110,6 +111,20 @@ function sandbox_utils.cprintf(format, ...) utils._iowrite(colors(vformat(format, ...))) end +-- print() if enable verbose +function sandbox_utils.vprint(format, ...) + if option.get("verbose") then + sandbox_utils.print(format, ...) + end +end + +-- vprintf() if enable verbose +function sandbox_utils.vprintf(format, ...) + if option.get("verbose") then + sandbox_utils.printf(format, ...) + end +end + -- assert function sandbox_utils.assert(value, format, ...) @@ -126,7 +141,6 @@ function sandbox_utils.assert(value, format, ...) return value end - -- return module return sandbox_utils diff --git a/xmake/core/sandbox/modules/vprint.lua b/xmake/core/sandbox/modules/vprint.lua new file mode 100644 index 000000000..49064afae --- /dev/null +++ b/xmake/core/sandbox/modules/vprint.lua @@ -0,0 +1,27 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file vprint.lua +-- + +-- load module +return require("sandbox/modules/utils").vprint + diff --git a/xmake/core/sandbox/modules/vprintf.lua b/xmake/core/sandbox/modules/vprintf.lua new file mode 100644 index 000000000..58f211666 --- /dev/null +++ b/xmake/core/sandbox/modules/vprintf.lua @@ -0,0 +1,27 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file vprintf.lua +-- + +-- load module +return require("sandbox/modules/utils").vprintf + diff --git a/xmake/modules/detect/tools/find_ping.lua b/xmake/modules/detect/tools/find_ping.lua new file mode 100644 index 000000000..ae3d571bf --- /dev/null +++ b/xmake/modules/detect/tools/find_ping.lua @@ -0,0 +1,48 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file find_ping.lua +-- + +-- imports +import("lib.detect.find_program") + +-- find ping +-- +-- +-- @param opt the argument options +-- +-- @return program +-- +function main(opt) + + -- init options + opt = opt or {} + + -- find program + return find_program(opt.program or "ping", opt.pathes, opt.check or function (program) + if os.host() == "windows" then + os.run("%s -n 1 127.0.0.1", program) + else + os.run("%s -c 1 127.0.0.1", program) + end + end) +end diff --git a/xmake/modules/devel/git/checkurl.lua b/xmake/modules/devel/git/checkurl.lua new file mode 100644 index 000000000..225351458 --- /dev/null +++ b/xmake/modules/devel/git/checkurl.lua @@ -0,0 +1,35 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file checkurl.lua +-- + +-- check git url +-- +-- @param url is git url? +-- +-- @return true or false +-- +function main(url) + + -- check it + return url:endswith(".git") or os.isdir(url .. ".git") +end diff --git a/xmake/modules/devel/git/refs.lua b/xmake/modules/devel/git/refs.lua index 306b2fd26..7af98b854 100644 --- a/xmake/modules/devel/git/refs.lua +++ b/xmake/modules/devel/git/refs.lua @@ -30,13 +30,13 @@ import("ls_remote") -- -- @param url the remote url, optional -- --- @return the refs +-- @return the tags, branches -- -- @code -- -- import("devel.git") -- --- local refs = git.refs(url) +-- local tags, branches = git.refs(url) -- -- @endcode -- @@ -45,7 +45,7 @@ function main(url) -- get refs local refs = ls_remote("refs", url) if not refs or #refs == 0 then - return {} + return {}, {} end -- get tags and branches @@ -60,5 +60,5 @@ function main(url) end -- ok - return {tags = tags, branches = branches} + return tags, branches end diff --git a/xmake/modules/net/fasturl.lua b/xmake/modules/net/fasturl.lua new file mode 100644 index 000000000..8cc90f035 --- /dev/null +++ b/xmake/modules/net/fasturl.lua @@ -0,0 +1,92 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file fasturl.lua +-- + +-- imports +import("ping") + +-- parse host from url +function _parse_host(url) + + -- init host cache + _g._URLHOSTS = _g._URLHOSTS or {} + + -- http[s]://xxx.com/.. or [email protected]:xxx/xxx.git + local host = _g._URLHOSTS[url] or url:match("://(.-)/") or url:match("@(.-):") + + -- save to cache + _g._URLHOSTS[url] = host + + -- ok + return host +end + +-- add urls +function add(urls) + + -- get current ping info + local pinginfo = _g._PINGINFO or {} + + -- add ping hosts + _g._PINGHOSTS = _g._PINGHOSTS or {} + for _, url in ipairs(urls) do + + -- parse host + local host = _parse_host(url) + + -- this host has not been tested? + if host and not pinginfo[host] then + table.insert(_g._PINGHOSTS, host) + end + end +end + +-- sort urls +function sort(urls) + + -- ping hosts + local pinghosts = table.unique(_g._PINGHOSTS or {}) + if pinghosts and #pinghosts > 0 then + + -- ping them and test speed + local pinginfo = ping(unpack(pinghosts)) + + -- merge to ping info + _g._PINGINFO = table.join(_g._PINGINFO or {}, pinginfo) + end + + -- sort urls by the ping info + local pinginfo = _g._PINGINFO or {} + table.sort(urls, function(a, b) + a = pinginfo[_parse_host(a) or ""] or 65536 + b = pinginfo[_parse_host(b) or ""] or 65536 + return a < b + end) + + -- clear hosts + _g._PINGHOSTS = {} + + -- ok + return urls +end + diff --git a/xmake/modules/net/ping.lua b/xmake/modules/net/ping.lua new file mode 100644 index 000000000..9a2bd21f2 --- /dev/null +++ b/xmake/modules/net/ping.lua @@ -0,0 +1,73 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file ping.lua +-- + +-- imports +import("detect.tools.find_ping") + +-- send ping to hosts +-- +-- @param ... the hosts +-- +-- @return the time or -1 +-- +function main(...) + + -- find ping + local ping = find_ping() + if not ping then + return {} + end + + -- run tasks + local hosts = {...} + local results = {} + process.runjobs(function (index) + local host = hosts[index] + if host then + try + { + function () + + -- ping it + local data = nil + if os.host() == "windows" then + data = os.iorun("%s -n 1 %s", ping, host) + else + data = os.iorun("%s -c 1 %s", ping, host) + end + + -- find time + local time = data:match("time=(.-)ms", 1, true) + if time then + results[host] = tonumber(time:trim()) + end + end + } + end + end, #hosts) + + -- ok? + return results +end + diff --git a/xmake/plugins/doxygen/main.lua b/xmake/plugins/doxygen/main.lua index c13327959..fe9c0df4d 100644 --- a/xmake/plugins/doxygen/main.lua +++ b/xmake/plugins/doxygen/main.lua @@ -44,9 +44,6 @@ function main() -- load configure config.load() - -- load project - project.load() - -- enable recursive -- -- RECURSIVE = YES diff --git a/xmake/plugins/macro/macros/package.lua b/xmake/plugins/macro/macros/package.lua index 27f15969c..c9fef7977 100644 --- a/xmake/plugins/macro/macros/package.lua +++ b/xmake/plugins/macro/macros/package.lua @@ -73,9 +73,6 @@ function main(argv) -- load configure config.load() - -- load project - project.load() - -- enter the project directory os.cd(project.directory()) diff --git a/xmake/plugins/project/vstudio/impl/vs200x_solution.lua b/xmake/plugins/project/vstudio/impl/vs200x_solution.lua index b076d35bd..26117a557 100644 --- a/xmake/plugins/project/vstudio/impl/vs200x_solution.lua +++ b/xmake/plugins/project/vstudio/impl/vs200x_solution.lua @@ -43,12 +43,12 @@ function _make_projects(slnfile, vsinfo) if not target:isphony() then -- enter project - slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcproj\", \"{%s}\"", vctool, targetname, targetname, targetname, os.uuid(targetname)) + slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid(targetname)) -- add dependences for _, dep in ipairs(target:get("deps")) do slnfile:enter("ProjectSection(ProjectDependencies) = postProject") - slnfile:print("{%s} = {%s}", os.uuid(dep), os.uuid(dep)) + slnfile:print("{%s} = {%s}", hash.uuid(dep), hash.uuid(dep)) slnfile:leave("EndProjectSection") end @@ -73,8 +73,8 @@ function _make_global(slnfile, vsinfo) slnfile:enter("GlobalSection(ProjectConfigurationPlatforms) = postSolution") for targetname, target in pairs(project.targets()) do if not target:isphony() then - slnfile:print("{%s}.$(mode)|Win32.ActiveCfg = $(mode)|Win32", os.uuid(targetname)) - slnfile:print("{%s}.$(mode)|Win32.Build.0 = $(mode)|Win32", os.uuid(targetname)) + slnfile:print("{%s}.$(mode)|Win32.ActiveCfg = $(mode)|Win32", hash.uuid(targetname)) + slnfile:print("{%s}.$(mode)|Win32.Build.0 = $(mode)|Win32", hash.uuid(targetname)) end end slnfile:leave("EndGlobalSection") diff --git a/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua b/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua index 102ab8399..eb0706cf8 100644 --- a/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua +++ b/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua @@ -133,7 +133,7 @@ function _make_header(vcprojfile, vsinfo, target) vcprojfile:print("ProjectType=\"Visual C++\"") vcprojfile:print("Version=\"%s0\"", assert(versions["vs" .. vsinfo.vstudio_version])) vcprojfile:print("Name=\"%s\"", targetname) - vcprojfile:print("ProjectGUID=\"{%s}\"", os.uuid(targetname)) + vcprojfile:print("ProjectGUID=\"{%s}\"", hash.uuid(targetname)) vcprojfile:print("RootNamespace=\"%s\"", targetname) vcprojfile:print("TargetFrameworkVersion=\"196613\"") vcprojfile:print(">") diff --git a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua index 40ac3e0f5..73bc1655d 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua @@ -43,12 +43,12 @@ function _make_projects(slnfile, vsinfo) if not target:isphony() then -- enter project - slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, os.uuid(targetname)) + slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid(targetname)) -- add dependences for _, dep in ipairs(target:get("deps")) do slnfile:enter("ProjectSection(ProjectDependencies) = postProject") - slnfile:print("{%s} = {%s}", os.uuid(dep), os.uuid(dep)) + slnfile:print("{%s} = {%s}", hash.uuid(dep), hash.uuid(dep)) slnfile:leave("EndProjectSection") end @@ -79,8 +79,8 @@ function _make_global(slnfile, vsinfo) if not target:isphony() then for _, mode in ipairs(vsinfo.modes) do for _, arch in ipairs({"x86", "x64"}) do - slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", os.uuid(targetname), mode, arch, mode, arch) - slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", os.uuid(targetname), mode, arch, mode, arch) + slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", hash.uuid(targetname), mode, arch, mode, arch) + slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", hash.uuid(targetname), mode, arch, mode, arch) end end end diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua index 7abe20a54..fbff38a72 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua @@ -157,7 +157,7 @@ function _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir) -- make Globals vcxprojfile:enter("<PropertyGroup Label=\"Globals\">") - vcxprojfile:print("<ProjectGuid>{%s}</ProjectGuid>", os.uuid(targetname)) + vcxprojfile:print("<ProjectGuid>{%s}</ProjectGuid>", hash.uuid(targetname)) vcxprojfile:print("<RootNamespace>%s</RootNamespace>", targetname) if vsinfo.vstudio_version >= "2015" then vcxprojfile:print("<WindowsTargetPlatformVersion>%s</WindowsTargetPlatformVersion>", sdkver or sdk_versions["vs" .. vsinfo.vstudio_version]) diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua index f15fa9c5f..7361611e2 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua @@ -75,7 +75,7 @@ function _make_filters(filtersfile, vsinfo, target, vcxprojdir) while filter and filter ~= '.' do
if not exists[filter] then
filtersfile:enter("<Filter Include=\"%s\">", filter)
- filtersfile:print("<UniqueIdentifier>{%s}</UniqueIdentifier>", os.uuid(filter))
+ filtersfile:print("<UniqueIdentifier>{%s}</UniqueIdentifier>", hash.uuid(filter))
filtersfile:leave("</Filter>")
exists[filter] = true
end
diff --git a/xmake/plugins/repo/main.lua b/xmake/plugins/repo/main.lua new file mode 100644 index 000000000..58d9b2090 --- /dev/null +++ b/xmake/plugins/repo/main.lua @@ -0,0 +1,158 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file main.lua +-- + +-- imports +import("core.base.option") +import("core.project.config") +import("core.project.project") +import("core.platform.platform") +import("core.package.repository") +import("devel.git") + +-- add repository url +function _add(name, url, is_global) + + -- add url + repository.add(name, url, is_global) + + -- remove previous repository if exists + local repodir = path.join(repository.directory(is_global), name) + if os.isdir(repodir) then + os.rmdir(repodir) + end + + -- clone repository + git.clone(url, {verbose = option.get("verbose"), branch = "master", outputdir = repodir}) + + -- trace + cprint("${bright}add %s repository(%s): %s ok!", ifelse(is_global, "global", "local"), name, url) +end + +-- remove repository url +function _remove(name, is_global) + + -- remove url + repository.remove(name, is_global) + + -- remove repository + local repodir = path.join(repository.directory(is_global), name) + if os.isdir(repodir) then + os.rmdir(repodir) + end + + -- trace + cprint("${bright}remove %s repository(%s): %s ok!", ifelse(is_global, "global", "local"), name, url) +end + +-- clear all repositories +function _clear(is_global) + + -- clear all urls + repository.clear(is_global) + + -- remove all repositories + local repodir = repository.directory(is_global) + if os.isdir(repodir) then + os.rmdir(repodir) + end + + -- trace + cprint("${bright}clear %s repositories: ok!", ifelse(is_global, "global", "local")) +end + +-- list all repositories +function _list(is_global) + + -- list all repositories + local count = 0 + for _, position in ipairs({"local", "global"}) do + + -- trace + print("%s repositories:", position) + + -- list all + for _, repo in pairs(repository.repositories(position == "global")) do + + -- trace + print(" %s %s", repo.name, repo.url) + + -- update count + count = count + 1 + end + + -- trace + print("") + end + + -- trace + print("%d repositories were found!", count) +end + +-- load project +function _load_project() + + -- enter project directory + os.cd(project.directory()) + + -- load config + config.load() + + -- load platform + platform.load(config.plat()) +end + +-- main +function main() + + -- load project if operate local repositories + if not option.get("global") then + _load_project() + end + + -- add repository url + if option.get("add") then + + _add(option.get("name"), option.get("url"), option.get("global")) + + -- remove repository url + elseif option.get("remove") then + + _remove(option.get("name"), option.get("global")) + + -- clear all repositories + elseif option.get("clear") then + + _clear(option.get("global")) + + -- list all repositories + elseif option.get("list") then + + _list(option.get("global")) + + -- show help + else + option.show_help() + end +end + diff --git a/xmake/plugins/repo/xmake.lua b/xmake/plugins/repo/xmake.lua new file mode 100644 index 000000000..6f38fdc12 --- /dev/null +++ b/xmake/plugins/repo/xmake.lua @@ -0,0 +1,54 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file repo.lua +-- + +-- define task +task("repo") + + -- set category + set_category("plugin") + + -- on run + on_run("main") + + -- set menu + set_menu { + -- usage + usage = "xmake repo [options] [name] [url]" + + -- description + , description = "Manage package repositories." + + -- options + , options = + { + {'a', "add", "k", nil, "Add the given remote repository url." } + , {'r', "remove", "k", nil, "Remove the given remote repository url." } + , {'l', "list", "k", nil, "List all added repositories." } + , {'g', "global", "k", nil, "Save repository to global. (default: local)" } + , {'c', "clear", "k", nil, "Clear all added repositories." } + , { } + , {nil, "name", "v", nil, "The repository name." } + , {nil, "url", "v", nil, "The repository url" } + } + } |
