mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-03-25 13:30:52 +00:00
Compare commits
31 Commits
Release_4.
...
push-pvunn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cd4944fd8 | ||
|
|
fdd972bbd2 | ||
|
|
76f595e1fe | ||
|
|
1e1e5443e3 | ||
|
|
15d1f1fd80 | ||
|
|
8df2cbe22f | ||
|
|
58d685926b | ||
|
|
e9f24426df | ||
|
|
2f7be10b5d | ||
|
|
43125f9f5e | ||
|
|
c23368e929 | ||
|
|
6cb5a81685 | ||
|
|
94b0887069 | ||
|
|
c188580aac | ||
|
|
1e1f575d1c | ||
|
|
40769bf827 | ||
|
|
74e6fcaf83 | ||
|
|
30ec8b1b63 | ||
|
|
cdc72c5346 | ||
|
|
82a9972be7 | ||
|
|
ff6e515b2a | ||
|
|
cd0c525f50 | ||
|
|
abe935aa18 | ||
|
|
8dd32dc1bf | ||
|
|
6ee8750635 | ||
|
|
8c318c480e | ||
|
|
09fbc217d3 | ||
|
|
3d2e205722 | ||
|
|
623116ab13 | ||
|
|
1e4509cb63 | ||
|
|
b33d7705a8 |
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@@ -62,6 +62,12 @@ jobs:
|
|||||||
TAG=${GITHUB_REF#refs/tags/Release_}
|
TAG=${GITHUB_REF#refs/tags/Release_}
|
||||||
echo "version=$TAG" >> $GITHUB_OUTPUT
|
echo "version=$TAG" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Install build tools (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -q
|
||||||
|
sudo apt-get install -y musl-tools zlib1g-dev
|
||||||
|
|
||||||
- name: Install build tools (macOS)
|
- name: Install build tools (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
@@ -74,8 +80,14 @@ jobs:
|
|||||||
GOOS: ${{ matrix.goos }}
|
GOOS: ${{ matrix.goos }}
|
||||||
GOARCH: ${{ matrix.goarch }}
|
GOARCH: ${{ matrix.goarch }}
|
||||||
VERSION: ${{ steps.get_version.outputs.version }}
|
VERSION: ${{ steps.get_version.outputs.version }}
|
||||||
|
CC: ${{ matrix.goos == 'linux' && 'musl-gcc' || '' }}
|
||||||
|
CGO_CFLAGS: ${{ matrix.goos == 'linux' && '-I/usr/include' || '' }}
|
||||||
run: |
|
run: |
|
||||||
make obitools
|
if [ "$GOOS" = "linux" ]; then
|
||||||
|
make LDFLAGS='-linkmode=external -extldflags=-static' obitools
|
||||||
|
else
|
||||||
|
make obitools
|
||||||
|
fi
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
# Create a single tar.gz with all binaries for this platform
|
# Create a single tar.gz with all binaries for this platform
|
||||||
tar -czf artifacts/obitools4_${VERSION}_${{ matrix.output_name }}.tar.gz -C build .
|
tar -czf artifacts/obitools4_${VERSION}_${{ matrix.output_name }}.tar.gz -C build .
|
||||||
|
|||||||
118
Makefile
118
Makefile
@@ -2,9 +2,17 @@
|
|||||||
#export GOBIN=$(GOPATH)/bin
|
#export GOBIN=$(GOPATH)/bin
|
||||||
#export PATH=$(GOBIN):$(shell echo $${PATH})
|
#export PATH=$(GOBIN):$(shell echo $${PATH})
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := all
|
||||||
|
|
||||||
|
GREEN := \033[0;32m
|
||||||
|
YELLOW := \033[0;33m
|
||||||
|
BLUE := \033[0;34m
|
||||||
|
NC := \033[0m
|
||||||
|
|
||||||
GOFLAGS=
|
GOFLAGS=
|
||||||
|
LDFLAGS=
|
||||||
GOCMD=go
|
GOCMD=go
|
||||||
GOBUILD=$(GOCMD) build $(GOFLAGS)
|
GOBUILD=$(GOCMD) build $(GOFLAGS) $(if $(LDFLAGS),-ldflags="$(LDFLAGS)")
|
||||||
GOGENERATE=$(GOCMD) generate
|
GOGENERATE=$(GOCMD) generate
|
||||||
GOCLEAN=$(GOCMD) clean
|
GOCLEAN=$(GOCMD) clean
|
||||||
GOTEST=$(GOCMD) test
|
GOTEST=$(GOCMD) test
|
||||||
@@ -43,7 +51,7 @@ $(OBITOOLS_PREFIX)$(notdir $(1)): $(BUILD_DIR) $(1) pkg/obioptions/version.go
|
|||||||
@echo -n - Building obitool $(notdir $(1))...
|
@echo -n - Building obitool $(notdir $(1))...
|
||||||
@$(GOBUILD) -o $(BUILD_DIR)/$(OBITOOLS_PREFIX)$(notdir $(1)) ./$(1) \
|
@$(GOBUILD) -o $(BUILD_DIR)/$(OBITOOLS_PREFIX)$(notdir $(1)) ./$(1) \
|
||||||
2> $(OBITOOLS_PREFIX)$(notdir $(1)).log \
|
2> $(OBITOOLS_PREFIX)$(notdir $(1)).log \
|
||||||
|| cat $(OBITOOLS_PREFIX)$(notdir $(1)).log
|
|| { cat $(OBITOOLS_PREFIX)$(notdir $(1)).log; rm -f $(OBITOOLS_PREFIX)$(notdir $(1)).log; exit 1; }
|
||||||
@rm -f $(OBITOOLS_PREFIX)$(notdir $(1)).log
|
@rm -f $(OBITOOLS_PREFIX)$(notdir $(1)).log
|
||||||
@echo Done.
|
@echo Done.
|
||||||
endef
|
endef
|
||||||
@@ -60,6 +68,28 @@ endif
|
|||||||
|
|
||||||
OUTPUT:=$(shell mktemp)
|
OUTPUT:=$(shell mktemp)
|
||||||
|
|
||||||
|
help:
|
||||||
|
@printf "$(GREEN)OBITools4 Makefile$(NC)\n\n"
|
||||||
|
@printf "$(BLUE)Main targets:$(NC)\n"
|
||||||
|
@printf " %-20s %s\n" "all" "Build all obitools (default)"
|
||||||
|
@printf " %-20s %s\n" "obitools" "Build all obitools binaries to build/"
|
||||||
|
@printf " %-20s %s\n" "test" "Run Go unit tests"
|
||||||
|
@printf " %-20s %s\n" "obitests" "Run integration tests (obitests/)"
|
||||||
|
@printf " %-20s %s\n" "bump-version" "Increment patch version (or set with VERSION=x.y.z)"
|
||||||
|
@printf " %-20s %s\n" "update-deps" "Update all Go dependencies"
|
||||||
|
@printf "\n$(BLUE)Jujutsu workflow:$(NC)\n"
|
||||||
|
@printf " %-20s %s\n" "jjnew" "Document current commit and start a new one"
|
||||||
|
@printf " %-20s %s\n" "jjpush" "Release: describe, bump, generate notes, push PR, tag (VERSION=x.y.z optional)"
|
||||||
|
@printf " %-20s %s\n" "jjfetch" "Fetch latest commits from origin"
|
||||||
|
@printf "\n$(BLUE)Required tools:$(NC)\n"
|
||||||
|
@printf " %-20s " "go"; command -v go >/dev/null 2>&1 && printf "$(GREEN)✓$(NC) %s\n" "$$(go version)" || printf "$(YELLOW)✗ not found$(NC)\n"
|
||||||
|
@printf " %-20s " "git"; command -v git >/dev/null 2>&1 && printf "$(GREEN)✓$(NC) %s\n" "$$(git --version)" || printf "$(YELLOW)✗ not found$(NC)\n"
|
||||||
|
@printf " %-20s " "jj"; command -v jj >/dev/null 2>&1 && printf "$(GREEN)✓$(NC) %s\n" "$$(jj --version)" || printf "$(YELLOW)✗ not found$(NC)\n"
|
||||||
|
@printf " %-20s " "gh"; command -v gh >/dev/null 2>&1 && printf "$(GREEN)✓$(NC) %s\n" "$$(gh --version | head -1)" || printf "$(YELLOW)✗ not found$(NC) (brew install gh)\n"
|
||||||
|
@printf "\n$(BLUE)Optional tools (release notes generation):$(NC)\n"
|
||||||
|
@printf " %-20s " "aichat"; command -v aichat >/dev/null 2>&1 && printf "$(GREEN)✓$(NC) %s\n" "$$(aichat --version)" || printf "$(YELLOW)✗ not found$(NC) (https://github.com/sigoden/aichat)\n"
|
||||||
|
@printf " %-20s " "jq"; command -v jq >/dev/null 2>&1 && printf "$(GREEN)✓$(NC) %s\n" "$$(jq --version)" || printf "$(YELLOW)✗ not found$(NC) (brew install jq)\n"
|
||||||
|
|
||||||
all: install-githook obitools
|
all: install-githook obitools
|
||||||
|
|
||||||
obitools: $(patsubst %,$(OBITOOLS_PREFIX)%,$(OBITOOLS))
|
obitools: $(patsubst %,$(OBITOOLS_PREFIX)%,$(OBITOOLS))
|
||||||
@@ -106,15 +136,20 @@ pkg/obioptions/version.go: version.txt .FORCE
|
|||||||
@rm -f $(OUTPUT)
|
@rm -f $(OUTPUT)
|
||||||
|
|
||||||
bump-version:
|
bump-version:
|
||||||
@echo "Incrementing version..."
|
|
||||||
@current=$$(cat version.txt); \
|
@current=$$(cat version.txt); \
|
||||||
echo " Current version: $$current"; \
|
if [ -n "$(VERSION)" ]; then \
|
||||||
major=$$(echo $$current | cut -d. -f1); \
|
new_version="$(VERSION)"; \
|
||||||
minor=$$(echo $$current | cut -d. -f2); \
|
echo "Setting version to $$new_version (was $$current)"; \
|
||||||
patch=$$(echo $$current | cut -d. -f3); \
|
else \
|
||||||
new_patch=$$((patch + 1)); \
|
echo "Incrementing version..."; \
|
||||||
new_version="$$major.$$minor.$$new_patch"; \
|
echo " Current version: $$current"; \
|
||||||
echo " New version: $$new_version"; \
|
major=$$(echo $$current | cut -d. -f1); \
|
||||||
|
minor=$$(echo $$current | cut -d. -f2); \
|
||||||
|
patch=$$(echo $$current | cut -d. -f3); \
|
||||||
|
new_patch=$$((patch + 1)); \
|
||||||
|
new_version="$$major.$$minor.$$new_patch"; \
|
||||||
|
echo " New version: $$new_version"; \
|
||||||
|
fi; \
|
||||||
echo "$$new_version" > version.txt
|
echo "$$new_version" > version.txt
|
||||||
@echo "✓ Version updated in version.txt"
|
@echo "✓ Version updated in version.txt"
|
||||||
@$(MAKE) pkg/obioptions/version.go
|
@$(MAKE) pkg/obioptions/version.go
|
||||||
@@ -130,6 +165,7 @@ jjnew:
|
|||||||
jjpush:
|
jjpush:
|
||||||
@$(MAKE) jjpush-describe
|
@$(MAKE) jjpush-describe
|
||||||
@$(MAKE) jjpush-bump
|
@$(MAKE) jjpush-bump
|
||||||
|
@$(MAKE) jjpush-notes
|
||||||
@$(MAKE) jjpush-push
|
@$(MAKE) jjpush-push
|
||||||
@$(MAKE) jjpush-tag
|
@$(MAKE) jjpush-tag
|
||||||
@echo "$(GREEN)✓ Release complete$(NC)"
|
@echo "$(GREEN)✓ Release complete$(NC)"
|
||||||
@@ -142,44 +178,62 @@ jjpush-bump:
|
|||||||
@echo "$(BLUE)→ Creating new commit for version bump...$(NC)"
|
@echo "$(BLUE)→ Creating new commit for version bump...$(NC)"
|
||||||
@jj new
|
@jj new
|
||||||
@$(MAKE) bump-version
|
@$(MAKE) bump-version
|
||||||
@echo "$(BLUE)→ Documenting version bump commit...$(NC)"
|
|
||||||
@jj auto-describe
|
|
||||||
|
|
||||||
jjpush-push:
|
jjpush-notes:
|
||||||
@echo "$(BLUE)→ Pushing commits...$(NC)"
|
|
||||||
@jj git push --change @
|
|
||||||
|
|
||||||
jjpush-tag:
|
|
||||||
@version=$$(cat version.txt); \
|
@version=$$(cat version.txt); \
|
||||||
tag_name="Release_$$version"; \
|
echo "$(BLUE)→ Generating release notes for version $$version...$(NC)"; \
|
||||||
echo "$(BLUE)→ Generating release notes for $$tag_name...$(NC)"; \
|
release_title="Release $$version"; \
|
||||||
release_message="Release $$version"; \
|
release_body=""; \
|
||||||
if command -v orla >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then \
|
if command -v aichat >/dev/null 2>&1; then \
|
||||||
previous_tag=$$(git describe --tags --abbrev=0 --match 'Release_*' HEAD^ 2>/dev/null); \
|
previous_tag=$$(git describe --tags --abbrev=0 --match 'Release_*' 2>/dev/null); \
|
||||||
if [ -z "$$previous_tag" ]; then \
|
if [ -z "$$previous_tag" ]; then \
|
||||||
echo "$(YELLOW)⚠ No previous Release tag found, skipping release notes$(NC)"; \
|
echo "$(YELLOW)⚠ No previous Release tag found, skipping release notes$(NC)"; \
|
||||||
else \
|
else \
|
||||||
raw_output=$$(git log --format="%h %B" "$$previous_tag..HEAD" | \
|
raw_output=$$(git log --format="%h %B" "$$previous_tag..HEAD" | \
|
||||||
ORLA_MAX_TOOL_CALLS=50 orla agent -m ollama:qwen3-coder-next:latest \
|
aichat \
|
||||||
"Summarize the following commits into a GitHub release note for version $$version. Ignore commits related to version bumps, .gitignore changes, or any internal housekeeping that is irrelevant to end users. Describe each user-facing change precisely without exposing code. Eliminate redundancy. Output strictly valid JSON with no surrounding text, using this exact schema: {\"title\": \"<short release title>\", \"body\": \"<detailed markdown release notes>\"}" 2>/dev/null) || true; \
|
"Summarize the following commits into a GitHub release note for version $$version. Ignore commits related to version bumps, .gitignore changes, or any internal housekeeping that is irrelevant to end users. Describe each user-facing change precisely without exposing code. Eliminate redundancy. Output strictly valid JSON with no surrounding text, using this exact schema: {\"title\": \"<short release title>\", \"body\": \"<detailed markdown release notes>\"}" 2>/dev/null) || true; \
|
||||||
if [ -n "$$raw_output" ]; then \
|
if [ -n "$$raw_output" ]; then \
|
||||||
sanitized=$$(echo "$$raw_output" | sed -n '/^{/,/^}/p' | tr -d '\000-\011\013-\014\016-\037'); \
|
notes=$$(printf '%s\n' "$$raw_output" | python3 tools/json2md.py 2>/dev/null); \
|
||||||
release_title=$$(echo "$$sanitized" | jq -r '.title // empty' 2>/dev/null) ; \
|
if [ -n "$$notes" ]; then \
|
||||||
release_body=$$(echo "$$sanitized" | jq -r '.body // empty' 2>/dev/null) ; \
|
release_title=$$(echo "$$notes" | head -1); \
|
||||||
if [ -n "$$release_title" ] && [ -n "$$release_body" ]; then \
|
release_body=$$(echo "$$notes" | tail -n +3); \
|
||||||
release_message="$$release_title"$$'\n\n'"$$release_body"; \
|
|
||||||
else \
|
else \
|
||||||
echo "$(YELLOW)⚠ JSON parsing failed, using default release message$(NC)"; \
|
echo "$(YELLOW)⚠ JSON parsing failed, using default release message$(NC)"; \
|
||||||
fi; \
|
fi; \
|
||||||
fi; \
|
fi; \
|
||||||
fi; \
|
fi; \
|
||||||
fi; \
|
fi; \
|
||||||
|
printf '%s' "$$release_title" > /tmp/obitools4-release-title.txt; \
|
||||||
|
printf '%s' "$$release_body" > /tmp/obitools4-release-body.txt; \
|
||||||
|
echo "$(BLUE)→ Setting release notes as commit description...$(NC)"; \
|
||||||
|
jj desc -m "$$release_title"$$'\n\n'"$$release_body"
|
||||||
|
|
||||||
|
jjpush-push:
|
||||||
|
@echo "$(BLUE)→ Pushing commits...$(NC)"
|
||||||
|
@jj git push --change @
|
||||||
|
@echo "$(BLUE)→ Creating/updating PR...$(NC)"
|
||||||
|
@release_title=$$(cat /tmp/obitools4-release-title.txt 2>/dev/null || echo "Release $$(cat version.txt)"); \
|
||||||
|
release_body=$$(cat /tmp/obitools4-release-body.txt 2>/dev/null || echo ""); \
|
||||||
|
branch=$$(jj log -r @ --no-graph -T 'bookmarks.map(|b| b.name()).join("\n")' 2>/dev/null | head -1); \
|
||||||
|
if [ -n "$$branch" ] && command -v gh >/dev/null 2>&1; then \
|
||||||
|
gh pr create --title "$$release_title" --body "$$release_body" --base master --head "$$branch" 2>/dev/null \
|
||||||
|
|| gh pr edit "$$branch" --title "$$release_title" --body "$$release_body" 2>/dev/null \
|
||||||
|
|| echo "$(YELLOW)⚠ Could not create/update PR$(NC)"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
jjpush-tag:
|
||||||
|
@version=$$(cat version.txt); \
|
||||||
|
tag_name="Release_$$version"; \
|
||||||
|
release_title=$$(cat /tmp/obitools4-release-title.txt 2>/dev/null || echo "Release $$version"); \
|
||||||
|
release_body=$$(cat /tmp/obitools4-release-body.txt 2>/dev/null || echo ""); \
|
||||||
install_section=$$'\n## Installation\n\n### Pre-built binaries\n\nDownload the appropriate archive for your system from the\n[release assets](https://github.com/metabarcoding/obitools4/releases/tag/Release_'"$$version"')\nand extract it:\n\n#### Linux (AMD64)\n```bash\ntar -xzf obitools4_'"$$version"'_linux_amd64.tar.gz\n```\n\n#### Linux (ARM64)\n```bash\ntar -xzf obitools4_'"$$version"'_linux_arm64.tar.gz\n```\n\n#### macOS (Intel)\n```bash\ntar -xzf obitools4_'"$$version"'_darwin_amd64.tar.gz\n```\n\n#### macOS (Apple Silicon)\n```bash\ntar -xzf obitools4_'"$$version"'_darwin_arm64.tar.gz\n```\n\nAll OBITools4 binaries are included in each archive.\n\n### From source\n\nYou can also compile and install OBITools4 directly from source using the\ninstallation script:\n\n```bash\ncurl -L https://raw.githubusercontent.com/metabarcoding/obitools4/master/install_obitools.sh | bash -s -- --version '"$$version"'\n```\n\nBy default binaries are installed in `/usr/local/bin`. Use `--install-dir` to\nchange the destination and `--obitools-prefix` to add a prefix to command names:\n\n```bash\ncurl -L https://raw.githubusercontent.com/metabarcoding/obitools4/master/install_obitools.sh | \\\n bash -s -- --version '"$$version"' --install-dir ~/local --obitools-prefix k\n```\n'; \
|
install_section=$$'\n## Installation\n\n### Pre-built binaries\n\nDownload the appropriate archive for your system from the\n[release assets](https://github.com/metabarcoding/obitools4/releases/tag/Release_'"$$version"')\nand extract it:\n\n#### Linux (AMD64)\n```bash\ntar -xzf obitools4_'"$$version"'_linux_amd64.tar.gz\n```\n\n#### Linux (ARM64)\n```bash\ntar -xzf obitools4_'"$$version"'_linux_arm64.tar.gz\n```\n\n#### macOS (Intel)\n```bash\ntar -xzf obitools4_'"$$version"'_darwin_amd64.tar.gz\n```\n\n#### macOS (Apple Silicon)\n```bash\ntar -xzf obitools4_'"$$version"'_darwin_arm64.tar.gz\n```\n\nAll OBITools4 binaries are included in each archive.\n\n### From source\n\nYou can also compile and install OBITools4 directly from source using the\ninstallation script:\n\n```bash\ncurl -L https://raw.githubusercontent.com/metabarcoding/obitools4/master/install_obitools.sh | bash -s -- --version '"$$version"'\n```\n\nBy default binaries are installed in `/usr/local/bin`. Use `--install-dir` to\nchange the destination and `--obitools-prefix` to add a prefix to command names:\n\n```bash\ncurl -L https://raw.githubusercontent.com/metabarcoding/obitools4/master/install_obitools.sh | \\\n bash -s -- --version '"$$version"' --install-dir ~/local --obitools-prefix k\n```\n'; \
|
||||||
release_message="$$release_message$$install_section"; \
|
release_message="$$release_title"$$'\n\n'"$$release_body$$install_section"; \
|
||||||
echo "$(BLUE)→ Creating tag $$tag_name...$(NC)"; \
|
echo "$(BLUE)→ Creating tag $$tag_name...$(NC)"; \
|
||||||
git tag -a "$$tag_name" -m "$$release_message" 2>/dev/null || echo "$(YELLOW)⚠ Tag $$tag_name already exists$(NC)"; \
|
commit_hash=$$(jj log -r @ --no-graph -T 'commit_id' 2>/dev/null); \
|
||||||
|
git tag -a "$$tag_name" $${commit_hash:+"$$commit_hash"} -m "$$release_message" 2>/dev/null || echo "$(YELLOW)⚠ Tag $$tag_name already exists$(NC)"; \
|
||||||
echo "$(BLUE)→ Pushing tag $$tag_name...$(NC)"; \
|
echo "$(BLUE)→ Pushing tag $$tag_name...$(NC)"; \
|
||||||
git push origin "$$tag_name" 2>/dev/null || echo "$(YELLOW)⚠ Tag push failed or already pushed$(NC)"
|
git push origin "$$tag_name" 2>/dev/null || echo "$(YELLOW)⚠ Tag push failed or already pushed$(NC)"; \
|
||||||
|
rm -f /tmp/obitools4-release-title.txt /tmp/obitools4-release-body.txt
|
||||||
|
|
||||||
jjfetch:
|
jjfetch:
|
||||||
@echo "$(YELLOW)→ Pulling latest commits...$(NC)"
|
@echo "$(YELLOW)→ Pulling latest commits...$(NC)"
|
||||||
@@ -187,5 +241,5 @@ jjfetch:
|
|||||||
@jj new master@origin
|
@jj new master@origin
|
||||||
@echo "$(GREEN)✓ Latest commits pulled$(NC)"
|
@echo "$(GREEN)✓ Latest commits pulled$(NC)"
|
||||||
|
|
||||||
.PHONY: all obitools update-deps obitests githubtests jjnew jjpush jjpush-describe jjpush-bump jjpush-push jjpush-tag jjfetch bump-version .FORCE
|
.PHONY: all obitools update-deps obitests githubtests help jjnew jjpush jjpush-describe jjpush-bump jjpush-notes jjpush-push jjpush-tag jjfetch bump-version .FORCE
|
||||||
.FORCE:
|
.FORCE:
|
||||||
|
|||||||
@@ -32,8 +32,12 @@ The installation script offers several options:
|
|||||||
>
|
>
|
||||||
> -p, --obitools-prefix Prefix added to the obitools command names if you
|
> -p, --obitools-prefix Prefix added to the obitools command names if you
|
||||||
> want to have several versions of obitools at the
|
> want to have several versions of obitools at the
|
||||||
> same time on your system (as example `-p g` will produce
|
> same time on your system (as example `-p g` will produce
|
||||||
> `gobigrep` command instead of `obigrep`).
|
> `gobigrep` command instead of `obigrep`).
|
||||||
|
>
|
||||||
|
> -j, --jobs Number of parallel jobs used for compilation
|
||||||
|
> (default: 1). Increase this value to speed up
|
||||||
|
> compilation on multi-core systems (e.g., `-j 4`).
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
|||||||
41
go.mod
41
go.mod
@@ -1,35 +1,33 @@
|
|||||||
module git.metabarcoding.org/obitools/obitools4/obitools4
|
module git.metabarcoding.org/obitools/obitools4/obitools4
|
||||||
|
|
||||||
go 1.23.4
|
go 1.26.1
|
||||||
|
|
||||||
toolchain go1.24.2
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/DavidGamba/go-getoptions v0.28.0
|
github.com/DavidGamba/go-getoptions v0.33.0
|
||||||
github.com/PaesslerAG/gval v1.2.2
|
github.com/PaesslerAG/gval v1.2.4
|
||||||
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df
|
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df
|
||||||
github.com/buger/jsonparser v1.1.1
|
github.com/buger/jsonparser v1.1.1
|
||||||
github.com/chen3feng/stl4go v0.1.1
|
github.com/chen3feng/stl4go v0.1.1
|
||||||
github.com/dlclark/regexp2 v1.11.4
|
github.com/dlclark/regexp2 v1.11.5
|
||||||
github.com/goccy/go-json v0.10.3
|
github.com/goccy/go-json v0.10.6
|
||||||
github.com/klauspost/pgzip v1.2.6
|
github.com/klauspost/pgzip v1.2.6
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4
|
github.com/pelletier/go-toml/v2 v2.2.4
|
||||||
github.com/rrethy/ahocorasick v1.0.0
|
github.com/rrethy/ahocorasick v1.0.0
|
||||||
github.com/schollz/progressbar/v3 v3.13.1
|
github.com/schollz/progressbar/v3 v3.19.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.4
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/tevino/abool/v2 v2.1.0
|
github.com/tevino/abool/v2 v2.1.0
|
||||||
github.com/yuin/gopher-lua v1.1.1
|
github.com/yuin/gopher-lua v1.1.1
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90
|
||||||
gonum.org/v1/gonum v0.14.0
|
gonum.org/v1/gonum v0.17.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
scientificgo.org/special v0.0.0
|
scientificgo.org/special v0.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/goombaio/orderedmap v0.0.0-20180924084748-ba921b7e2419 // indirect
|
github.com/goombaio/orderedmap v0.0.0-20180925151256-3da0e2f905f9 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
@@ -38,16 +36,15 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dsnet/compress v0.0.1
|
github.com/dsnet/compress v0.0.1
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3
|
github.com/gabriel-vasile/mimetype v1.4.13
|
||||||
github.com/goombaio/orderedset v0.0.0-20180925151225-8e67b20a9b77
|
github.com/goombaio/orderedset v0.0.0-20180925151225-8e67b20a9b77
|
||||||
github.com/klauspost/compress v1.17.2
|
github.com/klauspost/compress v1.18.4
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.21 // indirect
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/ulikunitz/xz v0.5.11
|
github.com/ulikunitz/xz v0.5.15
|
||||||
golang.org/x/net v0.35.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/sys v0.30.0 // indirect
|
golang.org/x/term v0.41.0 // indirect
|
||||||
golang.org/x/term v0.29.0 // indirect
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||||
)
|
)
|
||||||
|
|||||||
91
go.sum
91
go.sum
@@ -1,7 +1,7 @@
|
|||||||
github.com/DavidGamba/go-getoptions v0.28.0 h1:18wgEvfZdrlfIhVDGEBO3Dl0fkOyXqXLa0tLMCKxM1c=
|
github.com/DavidGamba/go-getoptions v0.33.0 h1:8xCPH87Yy5avYenygyHVlqqm8RpymH0YFe4a7IWlarE=
|
||||||
github.com/DavidGamba/go-getoptions v0.28.0/go.mod h1:zE97E3PR9P3BI/HKyNYgdMlYxodcuiC6W68KIgeYT84=
|
github.com/DavidGamba/go-getoptions v0.33.0/go.mod h1:zE97E3PR9P3BI/HKyNYgdMlYxodcuiC6W68KIgeYT84=
|
||||||
github.com/PaesslerAG/gval v1.2.2 h1:Y7iBzhgE09IGTt5QgGQ2IdaYYYOU134YGHBThD+wm9E=
|
github.com/PaesslerAG/gval v1.2.4 h1:rhX7MpjJlcxYwL2eTTYIOBUyEKZ+A96T9vQySWkVUiU=
|
||||||
github.com/PaesslerAG/gval v1.2.2/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac=
|
github.com/PaesslerAG/gval v1.2.4/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac=
|
||||||
github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI=
|
github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI=
|
||||||
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
|
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
|
||||||
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0=
|
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0=
|
||||||
@@ -10,27 +10,32 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU
|
|||||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
github.com/chen3feng/stl4go v0.1.1 h1:0L1+mDw7pomftKDruM23f1mA7miavOj6C6MZeadzN2Q=
|
github.com/chen3feng/stl4go v0.1.1 h1:0L1+mDw7pomftKDruM23f1mA7miavOj6C6MZeadzN2Q=
|
||||||
github.com/chen3feng/stl4go v0.1.1/go.mod h1:5ml3psLgETJjRJnMbPE+JiHLrCpt+Ajc2weeTECXzWU=
|
github.com/chen3feng/stl4go v0.1.1/go.mod h1:5ml3psLgETJjRJnMbPE+JiHLrCpt+Ajc2weeTECXzWU=
|
||||||
|
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
||||||
|
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
||||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/goombaio/orderedmap v0.0.0-20180924084748-ba921b7e2419 h1:SajEQ6tktpF9SRIuzbiPOX9AEZZ53Bvw0k9Mzrts8Lg=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/goombaio/orderedmap v0.0.0-20180924084748-ba921b7e2419/go.mod h1:YKu81H3RSd1cFh0d7NhvUoTtUC9IY/vBX0WUQb1/o4Y=
|
github.com/goombaio/orderedmap v0.0.0-20180924084748-ba921b7e2419/go.mod h1:YKu81H3RSd1cFh0d7NhvUoTtUC9IY/vBX0WUQb1/o4Y=
|
||||||
|
github.com/goombaio/orderedmap v0.0.0-20180925151256-3da0e2f905f9 h1:vFjPvFavIiDY71bQ9HIxPQBANvNl1SmFC4fgg5xRkho=
|
||||||
|
github.com/goombaio/orderedmap v0.0.0-20180925151256-3da0e2f905f9/go.mod h1:YKu81H3RSd1cFh0d7NhvUoTtUC9IY/vBX0WUQb1/o4Y=
|
||||||
github.com/goombaio/orderedset v0.0.0-20180925151225-8e67b20a9b77 h1:4dvq1tGHn1Y9KSRY0OZ24Khki4+4U+ZrA//YYsdUlJU=
|
github.com/goombaio/orderedset v0.0.0-20180925151225-8e67b20a9b77 h1:4dvq1tGHn1Y9KSRY0OZ24Khki4+4U+ZrA//YYsdUlJU=
|
||||||
github.com/goombaio/orderedset v0.0.0-20180925151225-8e67b20a9b77/go.mod h1:HPelMYpOyy0XvglpBbmZ3krZpwaHmszj/vQNlnETPTM=
|
github.com/goombaio/orderedset v0.0.0-20180925151225-8e67b20a9b77/go.mod h1:HPelMYpOyy0XvglpBbmZ3krZpwaHmszj/vQNlnETPTM=
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
@@ -41,10 +46,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
|
||||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||||
@@ -54,50 +57,40 @@ github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8
|
|||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/rrethy/ahocorasick v1.0.0 h1:YKkCB+E5PXc0xmLfMrWbfNht8vG9Re97IHSWZk/Lk8E=
|
github.com/rrethy/ahocorasick v1.0.0 h1:YKkCB+E5PXc0xmLfMrWbfNht8vG9Re97IHSWZk/Lk8E=
|
||||||
github.com/rrethy/ahocorasick v1.0.0/go.mod h1:nq8oScE7Vy1rOppoQxpQiiDmPHuKCuk9rXrNcxUV3R0=
|
github.com/rrethy/ahocorasick v1.0.0/go.mod h1:nq8oScE7Vy1rOppoQxpQiiDmPHuKCuk9rXrNcxUV3R0=
|
||||||
github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
|
github.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc=
|
||||||
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
|
github.com/schollz/progressbar/v3 v3.19.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
|
||||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/tevino/abool/v2 v2.1.0 h1:7w+Vf9f/5gmKT4m4qkayb33/92M+Um45F2BkHOR+L/c=
|
github.com/tevino/abool/v2 v2.1.0 h1:7w+Vf9f/5gmKT4m4qkayb33/92M+Um45F2BkHOR+L/c=
|
||||||
github.com/tevino/abool/v2 v2.1.0/go.mod h1:+Lmlqk6bHDWHqN1cbxqhwEAwMPXgc8I1SDEamtseuXY=
|
github.com/tevino/abool/v2 v2.1.0/go.mod h1:+Lmlqk6bHDWHqN1cbxqhwEAwMPXgc8I1SDEamtseuXY=
|
||||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
||||||
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
|
||||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
|
||||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
|
||||||
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
|
|
||||||
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
scientificgo.org/special v0.0.0 h1:P6WJkECo6tgtvZAEfNXl+KEB9ReAatjKAeX8U07mjSc=
|
scientificgo.org/special v0.0.0 h1:P6WJkECo6tgtvZAEfNXl+KEB9ReAatjKAeX8U07mjSc=
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0=
|
|||||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
|
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ INSTALL_DIR="/usr/local"
|
|||||||
OBITOOLS_PREFIX=""
|
OBITOOLS_PREFIX=""
|
||||||
VERSION=""
|
VERSION=""
|
||||||
LIST_VERSIONS=false
|
LIST_VERSIONS=false
|
||||||
|
JOBS=1
|
||||||
|
|
||||||
# Help message
|
# Help message
|
||||||
function display_help {
|
function display_help {
|
||||||
@@ -21,6 +22,7 @@ function display_help {
|
|||||||
echo " gobigrep command instead of obigrep)."
|
echo " gobigrep command instead of obigrep)."
|
||||||
echo " -v, --version Install a specific version (e.g., 4.4.8)."
|
echo " -v, --version Install a specific version (e.g., 4.4.8)."
|
||||||
echo " If not specified, installs the latest version."
|
echo " If not specified, installs the latest version."
|
||||||
|
echo " -j, --jobs Number of parallel jobs for compilation (default: 1)."
|
||||||
echo " -l, --list List all available versions and exit."
|
echo " -l, --list List all available versions and exit."
|
||||||
echo " -h, --help Display this help message."
|
echo " -h, --help Display this help message."
|
||||||
echo ""
|
echo ""
|
||||||
@@ -65,6 +67,10 @@ while [ "$#" -gt 0 ]; do
|
|||||||
VERSION="$2"
|
VERSION="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
-j|--jobs)
|
||||||
|
JOBS="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-l|--list)
|
-l|--list)
|
||||||
LIST_VERSIONS=true
|
LIST_VERSIONS=true
|
||||||
shift
|
shift
|
||||||
@@ -122,9 +128,15 @@ mkdir -p "${WORK_DIR}/cache" \
|
|||||||
exit 1)
|
exit 1)
|
||||||
|
|
||||||
# Create installation directory
|
# Create installation directory
|
||||||
mkdir -p "${INSTALL_DIR}/bin" 2> /dev/null \
|
if ! mkdir -p "${INSTALL_DIR}/bin" 2>/dev/null; then
|
||||||
|| (echo "Please enter your password for installing obitools in ${INSTALL_DIR}" 1>&2
|
if [ ! -w "$(dirname "${INSTALL_DIR}")" ] && [ ! -w "${INSTALL_DIR}" ]; then
|
||||||
sudo mkdir -p "${INSTALL_DIR}/bin")
|
echo "Please enter your password for installing obitools in ${INSTALL_DIR}" 1>&2
|
||||||
|
sudo mkdir -p "${INSTALL_DIR}/bin"
|
||||||
|
else
|
||||||
|
echo "Error: Could not create ${INSTALL_DIR}/bin (check path or disk space)" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ ! -d "${INSTALL_DIR}/bin" ]]; then
|
if [[ ! -d "${INSTALL_DIR}/bin" ]]; then
|
||||||
echo "Could not create ${INSTALL_DIR}/bin directory for installing obitools" 1>&2
|
echo "Could not create ${INSTALL_DIR}/bin directory for installing obitools" 1>&2
|
||||||
@@ -171,22 +183,24 @@ GOURL=$(curl -s "${URL}${GOFILE}" \
|
|||||||
|
|
||||||
echo "Installing Go from: $GOURL" 1>&2
|
echo "Installing Go from: $GOURL" 1>&2
|
||||||
|
|
||||||
curl -s "$GOURL" | tar zxf -
|
curl --progress-bar "$GOURL" | tar zxf -
|
||||||
|
|
||||||
PATH="$(pwd)/go/bin:$PATH"
|
export GOROOT="$(pwd)/go"
|
||||||
|
PATH="${GOROOT}/bin:$PATH"
|
||||||
export PATH
|
export PATH
|
||||||
GOPATH="$(pwd)/go"
|
export GOPATH="$(pwd)/gopath"
|
||||||
export GOPATH
|
|
||||||
export GOCACHE="$(pwd)/cache"
|
export GOCACHE="$(pwd)/cache"
|
||||||
|
export GOTOOLCHAIN=local
|
||||||
|
|
||||||
|
echo "GOROOT=$GOROOT" 1>&2
|
||||||
echo "GOCACHE=$GOCACHE" 1>&2
|
echo "GOCACHE=$GOCACHE" 1>&2
|
||||||
mkdir -p "$GOCACHE"
|
mkdir -p "$GOPATH" "$GOCACHE"
|
||||||
|
|
||||||
# Download OBITools4 source
|
# Download OBITools4 source
|
||||||
echo "Downloading OBITools4 v${VERSION}..." 1>&2
|
echo "Downloading OBITools4 v${VERSION}..." 1>&2
|
||||||
echo "Source URL: $OBIURL4" 1>&2
|
echo "Source URL: $OBIURL4" 1>&2
|
||||||
|
|
||||||
if ! curl -sL "$OBIURL4" > obitools4.zip; then
|
if ! curl --progress-bar -L "$OBIURL4" > obitools4.zip; then
|
||||||
echo "Error: Could not download OBITools4 version ${VERSION}" 1>&2
|
echo "Error: Could not download OBITools4 version ${VERSION}" 1>&2
|
||||||
echo "Please check that this version exists with: $0 --list" 1>&2
|
echo "Please check that this version exists with: $0 --list" 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -208,16 +222,29 @@ mkdir -p vendor
|
|||||||
|
|
||||||
# Build with or without prefix
|
# Build with or without prefix
|
||||||
if [[ -z "$OBITOOLS_PREFIX" ]] ; then
|
if [[ -z "$OBITOOLS_PREFIX" ]] ; then
|
||||||
make GOFLAGS="-buildvcs=false"
|
make -j"${JOBS}" obitools GOFLAGS="-buildvcs=false"
|
||||||
else
|
else
|
||||||
make GOFLAGS="-buildvcs=false" OBITOOLS_PREFIX="${OBITOOLS_PREFIX}"
|
make -j"${JOBS}" obitools GOFLAGS="-buildvcs=false" OBITOOLS_PREFIX="${OBITOOLS_PREFIX}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install binaries
|
# Install binaries
|
||||||
echo "Installing binaries to ${INSTALL_DIR}/bin..." 1>&2
|
echo "Installing binaries to ${INSTALL_DIR}/bin..." 1>&2
|
||||||
(cp build/* "${INSTALL_DIR}/bin" 2> /dev/null) \
|
if ! cp build/* "${INSTALL_DIR}/bin" 2>/dev/null; then
|
||||||
|| (echo "Please enter your password for installing obitools in ${INSTALL_DIR}" 1>&2
|
if [ ! -w "${INSTALL_DIR}/bin" ]; then
|
||||||
sudo cp build/* "${INSTALL_DIR}/bin")
|
echo "Please enter your password for installing obitools in ${INSTALL_DIR}" 1>&2
|
||||||
|
sudo cp build/* "${INSTALL_DIR}/bin"
|
||||||
|
else
|
||||||
|
echo "Error: Could not copy binaries to ${INSTALL_DIR}/bin" 1>&2
|
||||||
|
echo " Source files: $(ls build/ 2>/dev/null || echo 'none found')" 1>&2
|
||||||
|
echo "" 1>&2
|
||||||
|
echo "The build directory has been preserved for manual recovery:" 1>&2
|
||||||
|
echo " $(pwd)/build/" 1>&2
|
||||||
|
echo "You can install manually with:" 1>&2
|
||||||
|
echo " cp $(pwd)/build/* ${INSTALL_DIR}/bin/" 1>&2
|
||||||
|
popd > /dev/null || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
popd > /dev/null || exit
|
popd > /dev/null || exit
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
package obidefault
|
package obidefault
|
||||||
|
|
||||||
var _BatchSize = 2000
|
// _BatchSize is the minimum number of sequences per batch (floor).
|
||||||
|
// Used as the minSeqs argument to RebatchBySize.
|
||||||
|
var _BatchSize = 1
|
||||||
|
|
||||||
|
// _BatchSizeMax is the maximum number of sequences per batch (ceiling).
|
||||||
|
// A batch is flushed when this count is reached regardless of memory usage.
|
||||||
|
var _BatchSizeMax = 2000
|
||||||
|
|
||||||
// SetBatchSize sets the size of the sequence batches.
|
// SetBatchSize sets the size of the sequence batches.
|
||||||
//
|
//
|
||||||
@@ -24,3 +30,42 @@ func BatchSize() int {
|
|||||||
func BatchSizePtr() *int {
|
func BatchSizePtr() *int {
|
||||||
return &_BatchSize
|
return &_BatchSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BatchSizeMax returns the maximum number of sequences per batch.
|
||||||
|
func BatchSizeMax() int {
|
||||||
|
return _BatchSizeMax
|
||||||
|
}
|
||||||
|
|
||||||
|
func BatchSizeMaxPtr() *int {
|
||||||
|
return &_BatchSizeMax
|
||||||
|
}
|
||||||
|
|
||||||
|
// _BatchMem holds the maximum cumulative memory (in bytes) per batch when
|
||||||
|
// memory-based batching is requested. A value of 0 disables memory-based
|
||||||
|
// batching and falls back to count-based batching.
|
||||||
|
var _BatchMem = 128 * 1024 * 1024 // 128 MB default; set to 0 to disable
|
||||||
|
var _BatchMemStr = ""
|
||||||
|
|
||||||
|
// SetBatchMem sets the memory budget per batch in bytes.
|
||||||
|
func SetBatchMem(n int) {
|
||||||
|
_BatchMem = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchMem returns the current memory budget per batch in bytes.
|
||||||
|
// A value of 0 means memory-based batching is disabled.
|
||||||
|
func BatchMem() int {
|
||||||
|
return _BatchMem
|
||||||
|
}
|
||||||
|
|
||||||
|
func BatchMemPtr() *int {
|
||||||
|
return &_BatchMem
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchMemStr returns the raw --batch-mem string value as provided on the CLI.
|
||||||
|
func BatchMemStr() string {
|
||||||
|
return _BatchMemStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func BatchMemStrPtr() *string {
|
||||||
|
return &_BatchMemStr
|
||||||
|
}
|
||||||
|
|||||||
@@ -161,6 +161,149 @@ func EmblChunkParser(withFeatureTable, UtoT bool) func(string, io.Reader) (obise
|
|||||||
return parser
|
return parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractEmblSeq scans the sequence section of an EMBL record directly on the
|
||||||
|
// rope. EMBL sequence lines start with 5 spaces followed by bases in groups of
|
||||||
|
// 10, separated by spaces, with a position number at the end. The section ends
|
||||||
|
// with "//".
|
||||||
|
func (s *ropeScanner) extractEmblSeq(dest []byte, UtoT bool) []byte {
|
||||||
|
// We use ReadLine and scan each line for bases (skip digits, spaces, newlines).
|
||||||
|
for {
|
||||||
|
line := s.ReadLine()
|
||||||
|
if line == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(line) >= 2 && line[0] == '/' && line[1] == '/' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Lines start with 5 spaces; bases follow separated by single spaces.
|
||||||
|
// Digits at the end are the position counter — skip them.
|
||||||
|
// Simplest: take every byte that is a letter.
|
||||||
|
for _, b := range line {
|
||||||
|
if b >= 'A' && b <= 'Z' {
|
||||||
|
b += 'a' - 'A'
|
||||||
|
}
|
||||||
|
if UtoT && b == 'u' {
|
||||||
|
b = 't'
|
||||||
|
}
|
||||||
|
if b >= 'a' && b <= 'z' {
|
||||||
|
dest = append(dest, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmblChunkParserRope parses an EMBL chunk directly from a rope without Pack().
|
||||||
|
func EmblChunkParserRope(source string, rope *PieceOfChunk, withFeatureTable, UtoT bool) (obiseq.BioSequenceSlice, error) {
|
||||||
|
scanner := newRopeScanner(rope)
|
||||||
|
sequences := obiseq.MakeBioSequenceSlice(100)[:0]
|
||||||
|
|
||||||
|
var id string
|
||||||
|
var scientificName string
|
||||||
|
defBytes := make([]byte, 0, 256)
|
||||||
|
featBytes := make([]byte, 0, 1024)
|
||||||
|
var taxid int
|
||||||
|
inSeq := false
|
||||||
|
|
||||||
|
for {
|
||||||
|
line := scanner.ReadLine()
|
||||||
|
if line == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if inSeq {
|
||||||
|
// Should not happen — extractEmblSeq consumed up to "//"
|
||||||
|
inSeq = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case bytes.HasPrefix(line, []byte("ID ")):
|
||||||
|
id = string(bytes.SplitN(line[5:], []byte(";"), 2)[0])
|
||||||
|
case bytes.HasPrefix(line, []byte("OS ")):
|
||||||
|
scientificName = string(bytes.TrimSpace(line[5:]))
|
||||||
|
case bytes.HasPrefix(line, []byte("DE ")):
|
||||||
|
if len(defBytes) > 0 {
|
||||||
|
defBytes = append(defBytes, ' ')
|
||||||
|
}
|
||||||
|
defBytes = append(defBytes, bytes.TrimSpace(line[5:])...)
|
||||||
|
case withFeatureTable && bytes.HasPrefix(line, []byte("FH ")):
|
||||||
|
featBytes = append(featBytes, line...)
|
||||||
|
case withFeatureTable && bytes.Equal(line, []byte("FH")):
|
||||||
|
featBytes = append(featBytes, '\n')
|
||||||
|
featBytes = append(featBytes, line...)
|
||||||
|
case bytes.HasPrefix(line, []byte("FT ")):
|
||||||
|
if withFeatureTable {
|
||||||
|
featBytes = append(featBytes, '\n')
|
||||||
|
featBytes = append(featBytes, line...)
|
||||||
|
}
|
||||||
|
if bytes.HasPrefix(line, []byte(`FT /db_xref="taxon:`)) {
|
||||||
|
rest := line[37:]
|
||||||
|
end := bytes.IndexByte(rest, '"')
|
||||||
|
if end > 0 {
|
||||||
|
taxid, _ = strconv.Atoi(string(rest[:end]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case bytes.HasPrefix(line, []byte(" ")):
|
||||||
|
// First sequence line: extract all bases via extractEmblSeq,
|
||||||
|
// which also consumes this line's remaining content.
|
||||||
|
// But ReadLine already consumed this line — we need to process it
|
||||||
|
// plus subsequent lines. Process this line inline then call helper.
|
||||||
|
seqDest := make([]byte, 0, 4096)
|
||||||
|
for _, b := range line {
|
||||||
|
if b >= 'A' && b <= 'Z' {
|
||||||
|
b += 'a' - 'A'
|
||||||
|
}
|
||||||
|
if UtoT && b == 'u' {
|
||||||
|
b = 't'
|
||||||
|
}
|
||||||
|
if b >= 'a' && b <= 'z' {
|
||||||
|
seqDest = append(seqDest, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seqDest = scanner.extractEmblSeq(seqDest, UtoT)
|
||||||
|
|
||||||
|
seq := obiseq.NewBioSequenceOwning(id, seqDest, string(defBytes))
|
||||||
|
seq.SetSource(source)
|
||||||
|
if withFeatureTable {
|
||||||
|
seq.SetFeatures(featBytes)
|
||||||
|
}
|
||||||
|
annot := seq.Annotations()
|
||||||
|
annot["scientific_name"] = scientificName
|
||||||
|
annot["taxid"] = taxid
|
||||||
|
sequences = append(sequences, seq)
|
||||||
|
|
||||||
|
// Reset state
|
||||||
|
id = ""
|
||||||
|
scientificName = ""
|
||||||
|
defBytes = defBytes[:0]
|
||||||
|
featBytes = featBytes[:0]
|
||||||
|
taxid = 1
|
||||||
|
|
||||||
|
case bytes.Equal(line, []byte("//")):
|
||||||
|
// record ended without SQ/sequence section (e.g. WGS entries)
|
||||||
|
if id != "" {
|
||||||
|
seq := obiseq.NewBioSequenceOwning(id, []byte{}, string(defBytes))
|
||||||
|
seq.SetSource(source)
|
||||||
|
if withFeatureTable {
|
||||||
|
seq.SetFeatures(featBytes)
|
||||||
|
}
|
||||||
|
annot := seq.Annotations()
|
||||||
|
annot["scientific_name"] = scientificName
|
||||||
|
annot["taxid"] = taxid
|
||||||
|
sequences = append(sequences, seq)
|
||||||
|
}
|
||||||
|
id = ""
|
||||||
|
scientificName = ""
|
||||||
|
defBytes = defBytes[:0]
|
||||||
|
featBytes = featBytes[:0]
|
||||||
|
taxid = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequences, nil
|
||||||
|
}
|
||||||
|
|
||||||
func _ParseEmblFile(
|
func _ParseEmblFile(
|
||||||
input ChannelFileChunk,
|
input ChannelFileChunk,
|
||||||
out obiiter.IBioSequence,
|
out obiiter.IBioSequence,
|
||||||
@@ -171,7 +314,14 @@ func _ParseEmblFile(
|
|||||||
|
|
||||||
for chunks := range input {
|
for chunks := range input {
|
||||||
order := chunks.Order
|
order := chunks.Order
|
||||||
sequences, err := parser(chunks.Source, chunks.Raw)
|
var sequences obiseq.BioSequenceSlice
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if chunks.Rope != nil {
|
||||||
|
sequences, err = EmblChunkParserRope(chunks.Source, chunks.Rope, withFeatureTable, UtoT)
|
||||||
|
} else {
|
||||||
|
sequences, err = parser(chunks.Source, chunks.Raw)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("%s : Cannot parse the embl file : %v", chunks.Source, err)
|
log.Fatalf("%s : Cannot parse the embl file : %v", chunks.Source, err)
|
||||||
@@ -196,7 +346,7 @@ func ReadEMBL(reader io.Reader, options ...WithOption) (obiiter.IBioSequence, er
|
|||||||
1024*1024*128,
|
1024*1024*128,
|
||||||
EndOfLastFlatFileEntry,
|
EndOfLastFlatFileEntry,
|
||||||
"\nID ",
|
"\nID ",
|
||||||
true,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
newIter := obiiter.MakeIBioSequence()
|
newIter := obiiter.MakeIBioSequence()
|
||||||
|
|||||||
@@ -209,28 +209,121 @@ func FastaChunkParser(UtoT bool) func(string, io.Reader) (obiseq.BioSequenceSlic
|
|||||||
return parser
|
return parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractFastaSeq scans sequence bytes from the rope directly into dest,
|
||||||
|
// appending valid nucleotide characters and skipping whitespace.
|
||||||
|
// Stops when '>' is found at the start of a line (next record) or at EOF.
|
||||||
|
// Returns (dest with appended bases, hasMore).
|
||||||
|
// hasMore=true means scanner is now positioned at '>' of the next record.
|
||||||
|
func (s *ropeScanner) extractFastaSeq(dest []byte, UtoT bool) ([]byte, bool) {
|
||||||
|
lineStart := true
|
||||||
|
|
||||||
|
for s.current != nil {
|
||||||
|
data := s.current.data[s.pos:]
|
||||||
|
for i, b := range data {
|
||||||
|
if lineStart && b == '>' {
|
||||||
|
s.pos += i
|
||||||
|
if s.pos >= len(s.current.data) {
|
||||||
|
s.current = s.current.Next()
|
||||||
|
s.pos = 0
|
||||||
|
}
|
||||||
|
return dest, true
|
||||||
|
}
|
||||||
|
if b == '\n' || b == '\r' {
|
||||||
|
lineStart = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lineStart = false
|
||||||
|
if b == ' ' || b == '\t' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b >= 'A' && b <= 'Z' {
|
||||||
|
b += 'a' - 'A'
|
||||||
|
}
|
||||||
|
if UtoT && b == 'u' {
|
||||||
|
b = 't'
|
||||||
|
}
|
||||||
|
dest = append(dest, b)
|
||||||
|
}
|
||||||
|
s.current = s.current.Next()
|
||||||
|
s.pos = 0
|
||||||
|
}
|
||||||
|
return dest, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastaChunkParserRope parses a FASTA chunk directly from the rope without Pack().
|
||||||
|
func FastaChunkParserRope(source string, rope *PieceOfChunk, UtoT bool) (obiseq.BioSequenceSlice, error) {
|
||||||
|
scanner := newRopeScanner(rope)
|
||||||
|
sequences := obiseq.MakeBioSequenceSlice(100)[:0]
|
||||||
|
|
||||||
|
for {
|
||||||
|
bline := scanner.ReadLine()
|
||||||
|
if bline == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(bline) == 0 || bline[0] != '>' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse header: ">id definition"
|
||||||
|
header := bline[1:]
|
||||||
|
var id string
|
||||||
|
var definition string
|
||||||
|
sp := bytes.IndexByte(header, ' ')
|
||||||
|
if sp < 0 {
|
||||||
|
sp = bytes.IndexByte(header, '\t')
|
||||||
|
}
|
||||||
|
if sp < 0 {
|
||||||
|
id = string(header)
|
||||||
|
} else {
|
||||||
|
id = string(header[:sp])
|
||||||
|
definition = string(bytes.TrimSpace(header[sp+1:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
seqDest := make([]byte, 0, 4096)
|
||||||
|
var hasMore bool
|
||||||
|
seqDest, hasMore = scanner.extractFastaSeq(seqDest, UtoT)
|
||||||
|
|
||||||
|
if len(seqDest) == 0 {
|
||||||
|
log.Fatalf("%s [%s]: sequence is empty", source, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
seq := obiseq.NewBioSequenceOwning(id, seqDest, definition)
|
||||||
|
seq.SetSource(source)
|
||||||
|
sequences = append(sequences, seq)
|
||||||
|
|
||||||
|
if !hasMore {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequences, nil
|
||||||
|
}
|
||||||
|
|
||||||
func _ParseFastaFile(
|
func _ParseFastaFile(
|
||||||
input ChannelFileChunk,
|
input ChannelFileChunk,
|
||||||
out obiiter.IBioSequence,
|
out obiiter.IBioSequence,
|
||||||
UtoT bool,
|
UtoT bool,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
parser := FastaChunkParser(UtoT)
|
parser := FastaChunkParser(UtoT)
|
||||||
|
|
||||||
for chunks := range input {
|
for chunks := range input {
|
||||||
sequences, err := parser(chunks.Source, chunks.Raw)
|
var sequences obiseq.BioSequenceSlice
|
||||||
// obilog.Warnf("Chunck(%d:%d) -%d- ", chunks.Order, l, sequences.Len())
|
var err error
|
||||||
|
|
||||||
|
if chunks.Rope != nil {
|
||||||
|
sequences, err = FastaChunkParserRope(chunks.Source, chunks.Rope, UtoT)
|
||||||
|
} else {
|
||||||
|
sequences, err = parser(chunks.Source, chunks.Raw)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("File %s : Cannot parse the fasta file : %v", chunks.Source, err)
|
log.Fatalf("File %s : Cannot parse the fasta file : %v", chunks.Source, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Push(obiiter.MakeBioSequenceBatch(chunks.Source, chunks.Order, sequences))
|
out.Push(obiiter.MakeBioSequenceBatch(chunks.Source, chunks.Order, sequences))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Done()
|
out.Done()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadFasta(reader io.Reader, options ...WithOption) (obiiter.IBioSequence, error) {
|
func ReadFasta(reader io.Reader, options ...WithOption) (obiiter.IBioSequence, error) {
|
||||||
@@ -245,7 +338,7 @@ func ReadFasta(reader io.Reader, options ...WithOption) (obiiter.IBioSequence, e
|
|||||||
1024*1024,
|
1024*1024,
|
||||||
EndOfLastFastaEntry,
|
EndOfLastFastaEntry,
|
||||||
"\n>",
|
"\n>",
|
||||||
true,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
for i := 0; i < nworker; i++ {
|
for i := 0; i < nworker; i++ {
|
||||||
|
|||||||
@@ -303,6 +303,80 @@ func FastqChunkParser(quality_shift byte, with_quality bool, UtoT bool) func(str
|
|||||||
return parser
|
return parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FastqChunkParserRope parses a FASTQ chunk directly from a rope without Pack().
|
||||||
|
func FastqChunkParserRope(source string, rope *PieceOfChunk, quality_shift byte, with_quality, UtoT bool) (obiseq.BioSequenceSlice, error) {
|
||||||
|
scanner := newRopeScanner(rope)
|
||||||
|
sequences := obiseq.MakeBioSequenceSlice(100)[:0]
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Line 1: @id [definition]
|
||||||
|
hline := scanner.ReadLine()
|
||||||
|
if hline == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(hline) == 0 || hline[0] != '@' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
header := hline[1:]
|
||||||
|
var id string
|
||||||
|
var definition string
|
||||||
|
sp := bytes.IndexByte(header, ' ')
|
||||||
|
if sp < 0 {
|
||||||
|
sp = bytes.IndexByte(header, '\t')
|
||||||
|
}
|
||||||
|
if sp < 0 {
|
||||||
|
id = string(header)
|
||||||
|
} else {
|
||||||
|
id = string(header[:sp])
|
||||||
|
definition = string(bytes.TrimSpace(header[sp+1:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line 2: sequence
|
||||||
|
sline := scanner.ReadLine()
|
||||||
|
if sline == nil {
|
||||||
|
log.Fatalf("@%s[%s]: unexpected EOF after header", id, source)
|
||||||
|
}
|
||||||
|
seqDest := make([]byte, len(sline))
|
||||||
|
w := 0
|
||||||
|
for _, b := range sline {
|
||||||
|
if b >= 'A' && b <= 'Z' {
|
||||||
|
b += 'a' - 'A'
|
||||||
|
}
|
||||||
|
if UtoT && b == 'u' {
|
||||||
|
b = 't'
|
||||||
|
}
|
||||||
|
seqDest[w] = b
|
||||||
|
w++
|
||||||
|
}
|
||||||
|
seqDest = seqDest[:w]
|
||||||
|
if len(seqDest) == 0 {
|
||||||
|
log.Fatalf("@%s[%s]: sequence is empty", id, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line 3: + (skip)
|
||||||
|
scanner.ReadLine()
|
||||||
|
|
||||||
|
// Line 4: quality
|
||||||
|
qline := scanner.ReadLine()
|
||||||
|
|
||||||
|
seq := obiseq.NewBioSequenceOwning(id, seqDest, definition)
|
||||||
|
seq.SetSource(source)
|
||||||
|
|
||||||
|
if with_quality && qline != nil {
|
||||||
|
qDest := make([]byte, len(qline))
|
||||||
|
copy(qDest, qline)
|
||||||
|
for i := range qDest {
|
||||||
|
qDest[i] -= quality_shift
|
||||||
|
}
|
||||||
|
seq.TakeQualities(qDest)
|
||||||
|
}
|
||||||
|
|
||||||
|
sequences = append(sequences, seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequences, nil
|
||||||
|
}
|
||||||
|
|
||||||
func _ParseFastqFile(
|
func _ParseFastqFile(
|
||||||
input ChannelFileChunk,
|
input ChannelFileChunk,
|
||||||
out obiiter.IBioSequence,
|
out obiiter.IBioSequence,
|
||||||
@@ -313,7 +387,14 @@ func _ParseFastqFile(
|
|||||||
parser := FastqChunkParser(quality_shift, with_quality, UtoT)
|
parser := FastqChunkParser(quality_shift, with_quality, UtoT)
|
||||||
|
|
||||||
for chunks := range input {
|
for chunks := range input {
|
||||||
sequences, err := parser(chunks.Source, chunks.Raw)
|
var sequences obiseq.BioSequenceSlice
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if chunks.Rope != nil {
|
||||||
|
sequences, err = FastqChunkParserRope(chunks.Source, chunks.Rope, quality_shift, with_quality, UtoT)
|
||||||
|
} else {
|
||||||
|
sequences, err = parser(chunks.Source, chunks.Raw)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("File %s : Cannot parse the fastq file : %v", chunks.Source, err)
|
log.Fatalf("File %s : Cannot parse the fastq file : %v", chunks.Source, err)
|
||||||
@@ -339,7 +420,7 @@ func ReadFastq(reader io.Reader, options ...WithOption) (obiiter.IBioSequence, e
|
|||||||
1024*1024,
|
1024*1024,
|
||||||
EndOfLastFastqEntry,
|
EndOfLastFastqEntry,
|
||||||
"\n@",
|
"\n@",
|
||||||
true,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
for i := 0; i < nworker; i++ {
|
for i := 0; i < nworker; i++ {
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ func _parse_json_header_(header string, sequence *obiseq.BioSequence) string {
|
|||||||
|
|
||||||
case strings.HasSuffix(skey, "_taxid"):
|
case strings.HasSuffix(skey, "_taxid"):
|
||||||
if dataType == jsonparser.Number || dataType == jsonparser.String {
|
if dataType == jsonparser.Number || dataType == jsonparser.String {
|
||||||
rank, _ := obiutils.SplitInTwo(skey, '_')
|
rank := skey[:len(skey)-len("_taxid")]
|
||||||
|
|
||||||
taxid := string(value)
|
taxid := string(value)
|
||||||
sequence.SetTaxid(taxid, rank)
|
sequence.SetTaxid(taxid, rank)
|
||||||
|
|||||||
@@ -29,70 +29,11 @@ const (
|
|||||||
|
|
||||||
var _seqlenght_rx = regexp.MustCompile(" +([0-9]+) bp")
|
var _seqlenght_rx = regexp.MustCompile(" +([0-9]+) bp")
|
||||||
|
|
||||||
// gbRopeScanner reads lines from a PieceOfChunk rope without heap allocation.
|
|
||||||
// The carry buffer (stack) handles lines that span two rope nodes.
|
|
||||||
type gbRopeScanner struct {
|
|
||||||
current *PieceOfChunk
|
|
||||||
pos int
|
|
||||||
carry [256]byte // max GenBank line = 80 chars; 256 gives ample margin
|
|
||||||
carryN int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGbRopeScanner(rope *PieceOfChunk) *gbRopeScanner {
|
|
||||||
return &gbRopeScanner{current: rope}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadLine returns the next line without the trailing \n (or \r\n).
|
|
||||||
// Returns nil at end of rope. The returned slice aliases carry[] or the node
|
|
||||||
// data and is valid only until the next ReadLine call.
|
|
||||||
func (s *gbRopeScanner) ReadLine() []byte {
|
|
||||||
for {
|
|
||||||
if s.current == nil {
|
|
||||||
if s.carryN > 0 {
|
|
||||||
n := s.carryN
|
|
||||||
s.carryN = 0
|
|
||||||
return s.carry[:n]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
data := s.current.data[s.pos:]
|
|
||||||
idx := bytes.IndexByte(data, '\n')
|
|
||||||
|
|
||||||
if idx >= 0 {
|
|
||||||
var line []byte
|
|
||||||
if s.carryN == 0 {
|
|
||||||
line = data[:idx]
|
|
||||||
} else {
|
|
||||||
n := copy(s.carry[s.carryN:], data[:idx])
|
|
||||||
s.carryN += n
|
|
||||||
line = s.carry[:s.carryN]
|
|
||||||
s.carryN = 0
|
|
||||||
}
|
|
||||||
s.pos += idx + 1
|
|
||||||
if s.pos >= len(s.current.data) {
|
|
||||||
s.current = s.current.Next()
|
|
||||||
s.pos = 0
|
|
||||||
}
|
|
||||||
if len(line) > 0 && line[len(line)-1] == '\r' {
|
|
||||||
line = line[:len(line)-1]
|
|
||||||
}
|
|
||||||
return line
|
|
||||||
}
|
|
||||||
|
|
||||||
// No \n in this node: accumulate into carry and advance
|
|
||||||
n := copy(s.carry[s.carryN:], data)
|
|
||||||
s.carryN += n
|
|
||||||
s.current = s.current.Next()
|
|
||||||
s.pos = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractSequence scans the ORIGIN section byte-by-byte directly on the rope,
|
// extractSequence scans the ORIGIN section byte-by-byte directly on the rope,
|
||||||
// appending compacted bases to dest. Returns the extended slice.
|
// appending compacted bases to dest. Returns the extended slice.
|
||||||
// Stops and returns when "//" is found at the start of a line.
|
// Stops and returns when "//" is found at the start of a line.
|
||||||
// The scanner is left positioned after the "//" line.
|
// The scanner is left positioned after the "//" line.
|
||||||
func (s *gbRopeScanner) extractSequence(dest []byte, UtoT bool) []byte {
|
func (s *ropeScanner) extractSequence(dest []byte, UtoT bool) []byte {
|
||||||
lineStart := true
|
lineStart := true
|
||||||
skipDigits := true
|
skipDigits := true
|
||||||
|
|
||||||
@@ -139,24 +80,6 @@ func (s *gbRopeScanner) extractSequence(dest []byte, UtoT bool) []byte {
|
|||||||
return dest
|
return dest
|
||||||
}
|
}
|
||||||
|
|
||||||
// skipToNewline advances the scanner past the next '\n'.
|
|
||||||
func (s *gbRopeScanner) skipToNewline() {
|
|
||||||
for s.current != nil {
|
|
||||||
data := s.current.data[s.pos:]
|
|
||||||
idx := bytes.IndexByte(data, '\n')
|
|
||||||
if idx >= 0 {
|
|
||||||
s.pos += idx + 1
|
|
||||||
if s.pos >= len(s.current.data) {
|
|
||||||
s.current = s.current.Next()
|
|
||||||
s.pos = 0
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.current = s.current.Next()
|
|
||||||
s.pos = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseLseqFromLocus extracts the declared sequence length from a LOCUS line.
|
// parseLseqFromLocus extracts the declared sequence length from a LOCUS line.
|
||||||
// Format: "LOCUS <id> <length> bp ..."
|
// Format: "LOCUS <id> <length> bp ..."
|
||||||
// Returns -1 if not found or parse error.
|
// Returns -1 if not found or parse error.
|
||||||
@@ -205,7 +128,7 @@ func GenbankChunkParserRope(source string, rope *PieceOfChunk,
|
|||||||
withFeatureTable, UtoT bool) (obiseq.BioSequenceSlice, error) {
|
withFeatureTable, UtoT bool) (obiseq.BioSequenceSlice, error) {
|
||||||
|
|
||||||
state := inHeader
|
state := inHeader
|
||||||
scanner := newGbRopeScanner(rope)
|
scanner := newRopeScanner(rope)
|
||||||
sequences := obiseq.MakeBioSequenceSlice(100)[:0]
|
sequences := obiseq.MakeBioSequenceSlice(100)[:0]
|
||||||
|
|
||||||
id := ""
|
id := ""
|
||||||
|
|||||||
77
pkg/obiformats/rope_scanner.go
Normal file
77
pkg/obiformats/rope_scanner.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package obiformats
|
||||||
|
|
||||||
|
import "bytes"
|
||||||
|
|
||||||
|
// ropeScanner reads lines from a PieceOfChunk rope.
|
||||||
|
// The carry buffer handles lines that span two rope nodes; it grows as needed.
|
||||||
|
type ropeScanner struct {
|
||||||
|
current *PieceOfChunk
|
||||||
|
pos int
|
||||||
|
carry []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRopeScanner(rope *PieceOfChunk) *ropeScanner {
|
||||||
|
return &ropeScanner{current: rope}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadLine returns the next line without the trailing \n (or \r\n).
|
||||||
|
// Returns nil at end of rope. The returned slice aliases carry[] or the node
|
||||||
|
// data and is valid only until the next ReadLine call.
|
||||||
|
func (s *ropeScanner) ReadLine() []byte {
|
||||||
|
for {
|
||||||
|
if s.current == nil {
|
||||||
|
if len(s.carry) > 0 {
|
||||||
|
line := s.carry
|
||||||
|
s.carry = s.carry[:0]
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data := s.current.data[s.pos:]
|
||||||
|
idx := bytes.IndexByte(data, '\n')
|
||||||
|
|
||||||
|
if idx >= 0 {
|
||||||
|
var line []byte
|
||||||
|
if len(s.carry) == 0 {
|
||||||
|
line = data[:idx]
|
||||||
|
} else {
|
||||||
|
s.carry = append(s.carry, data[:idx]...)
|
||||||
|
line = s.carry
|
||||||
|
s.carry = s.carry[:0]
|
||||||
|
}
|
||||||
|
s.pos += idx + 1
|
||||||
|
if s.pos >= len(s.current.data) {
|
||||||
|
s.current = s.current.Next()
|
||||||
|
s.pos = 0
|
||||||
|
}
|
||||||
|
if len(line) > 0 && line[len(line)-1] == '\r' {
|
||||||
|
line = line[:len(line)-1]
|
||||||
|
}
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
// No \n in this node: accumulate into carry and advance
|
||||||
|
s.carry = append(s.carry, data...)
|
||||||
|
s.current = s.current.Next()
|
||||||
|
s.pos = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skipToNewline advances the scanner past the next '\n'.
|
||||||
|
func (s *ropeScanner) skipToNewline() {
|
||||||
|
for s.current != nil {
|
||||||
|
data := s.current.data[s.pos:]
|
||||||
|
idx := bytes.IndexByte(data, '\n')
|
||||||
|
if idx >= 0 {
|
||||||
|
s.pos += idx + 1
|
||||||
|
if s.pos >= len(s.current.data) {
|
||||||
|
s.current = s.current.Next()
|
||||||
|
s.pos = 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.current = s.current.Next()
|
||||||
|
s.pos = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -444,6 +444,67 @@ func (iterator IBioSequence) Rebatch(size int) IBioSequence {
|
|||||||
return newIter
|
return newIter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RebatchBySize reorganises the stream into batches bounded by two independent
|
||||||
|
// upper limits: maxCount (max number of sequences) and maxBytes (max cumulative
|
||||||
|
// estimated memory). A batch is flushed as soon as either limit would be
|
||||||
|
// exceeded. A single sequence larger than maxBytes is always emitted alone.
|
||||||
|
// Passing 0 for a limit disables that constraint; if both are 0 it falls back
|
||||||
|
// to Rebatch(obidefault.BatchSizeMax()).
|
||||||
|
func (iterator IBioSequence) RebatchBySize(maxBytes int, maxCount int) IBioSequence {
|
||||||
|
if maxBytes <= 0 && maxCount <= 0 {
|
||||||
|
return iterator.Rebatch(obidefault.BatchSizeMax())
|
||||||
|
}
|
||||||
|
|
||||||
|
newIter := MakeIBioSequence()
|
||||||
|
|
||||||
|
newIter.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
newIter.WaitAndClose()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
order := 0
|
||||||
|
iterator = iterator.SortBatches()
|
||||||
|
buffer := obiseq.MakeBioSequenceSlice()
|
||||||
|
bufBytes := 0
|
||||||
|
source := ""
|
||||||
|
|
||||||
|
flush := func() {
|
||||||
|
if len(buffer) > 0 {
|
||||||
|
newIter.Push(MakeBioSequenceBatch(source, order, buffer))
|
||||||
|
order++
|
||||||
|
buffer = obiseq.MakeBioSequenceSlice()
|
||||||
|
bufBytes = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for iterator.Next() {
|
||||||
|
seqs := iterator.Get()
|
||||||
|
source = seqs.Source()
|
||||||
|
for _, s := range seqs.Slice() {
|
||||||
|
sz := s.MemorySize()
|
||||||
|
countFull := maxCount > 0 && len(buffer) >= maxCount
|
||||||
|
memFull := maxBytes > 0 && bufBytes+sz > maxBytes && len(buffer) > 0
|
||||||
|
if countFull || memFull {
|
||||||
|
flush()
|
||||||
|
}
|
||||||
|
buffer = append(buffer, s)
|
||||||
|
bufBytes += sz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flush()
|
||||||
|
|
||||||
|
newIter.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if iterator.IsPaired() {
|
||||||
|
newIter.MarkAsPaired()
|
||||||
|
}
|
||||||
|
|
||||||
|
return newIter
|
||||||
|
}
|
||||||
|
|
||||||
func (iterator IBioSequence) FilterEmpty() IBioSequence {
|
func (iterator IBioSequence) FilterEmpty() IBioSequence {
|
||||||
|
|
||||||
newIter := MakeIBioSequence()
|
newIter := MakeIBioSequence()
|
||||||
@@ -638,7 +699,7 @@ func (iterator IBioSequence) FilterOn(predicate obiseq.SequencePredicate,
|
|||||||
trueIter.MarkAsPaired()
|
trueIter.MarkAsPaired()
|
||||||
}
|
}
|
||||||
|
|
||||||
return trueIter.Rebatch(size)
|
return trueIter.RebatchBySize(obidefault.BatchMem(), obidefault.BatchSizeMax())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iterator IBioSequence) FilterAnd(predicate obiseq.SequencePredicate,
|
func (iterator IBioSequence) FilterAnd(predicate obiseq.SequencePredicate,
|
||||||
@@ -694,7 +755,7 @@ func (iterator IBioSequence) FilterAnd(predicate obiseq.SequencePredicate,
|
|||||||
trueIter.MarkAsPaired()
|
trueIter.MarkAsPaired()
|
||||||
}
|
}
|
||||||
|
|
||||||
return trueIter.Rebatch(size)
|
return trueIter.RebatchBySize(obidefault.BatchMem(), obidefault.BatchSizeMax())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all sequences availables from an IBioSequenceBatch iterator into
|
// Load all sequences availables from an IBioSequenceBatch iterator into
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package obiiter
|
|||||||
import (
|
import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obidefault"
|
||||||
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiseq"
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiseq"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ func IFragments(minsize, length, overlap, size, nworkers int) Pipeable {
|
|||||||
}
|
}
|
||||||
go f(iterator)
|
go f(iterator)
|
||||||
|
|
||||||
return newiter.SortBatches().Rebatch(size)
|
return newiter.SortBatches().RebatchBySize(obidefault.BatchMem(), obidefault.BatchSizeMax())
|
||||||
}
|
}
|
||||||
|
|
||||||
return ifrg
|
return ifrg
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obidefault"
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obidefault"
|
||||||
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiformats"
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiformats"
|
||||||
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/DavidGamba/go-getoptions"
|
"github.com/DavidGamba/go-getoptions"
|
||||||
@@ -55,7 +56,15 @@ func RegisterGlobalOptions(options *getoptions.GetOpt) {
|
|||||||
|
|
||||||
options.IntVar(obidefault.BatchSizePtr(), "batch-size", obidefault.BatchSize(),
|
options.IntVar(obidefault.BatchSizePtr(), "batch-size", obidefault.BatchSize(),
|
||||||
options.GetEnv("OBIBATCHSIZE"),
|
options.GetEnv("OBIBATCHSIZE"),
|
||||||
options.Description("Number of sequence per batch for paralelle processing"))
|
options.Description("Minimum number of sequences per batch (floor, default 1)"))
|
||||||
|
|
||||||
|
options.IntVar(obidefault.BatchSizeMaxPtr(), "batch-size-max", obidefault.BatchSizeMax(),
|
||||||
|
options.GetEnv("OBIBATCHSIZEMAX"),
|
||||||
|
options.Description("Maximum number of sequences per batch (ceiling, default 2000)"))
|
||||||
|
|
||||||
|
options.StringVar(obidefault.BatchMemStrPtr(), "batch-mem", "",
|
||||||
|
options.GetEnv("OBIBATCHMEM"),
|
||||||
|
options.Description("Maximum memory per batch (e.g. 128K, 64M, 1G; default: 128M). Set to 0 to disable."))
|
||||||
|
|
||||||
options.Bool("solexa", false,
|
options.Bool("solexa", false,
|
||||||
options.GetEnv("OBISOLEXA"),
|
options.GetEnv("OBISOLEXA"),
|
||||||
@@ -157,6 +166,15 @@ func ProcessParsedOptions(options *getoptions.GetOpt, parseErr error) {
|
|||||||
if options.Called("solexa") {
|
if options.Called("solexa") {
|
||||||
obidefault.SetReadQualitiesShift(64)
|
obidefault.SetReadQualitiesShift(64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.Called("batch-mem") {
|
||||||
|
n, err := obiutils.ParseMemSize(obidefault.BatchMemStr())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Invalid --batch-mem value %q: %v", obidefault.BatchMemStr(), err)
|
||||||
|
}
|
||||||
|
obidefault.SetBatchMem(n)
|
||||||
|
log.Printf("Memory-based batching enabled: %s per batch", obidefault.BatchMemStr())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateOptionParser(program string,
|
func GenerateOptionParser(program string,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package obioptions
|
|||||||
// Version is automatically updated by the Makefile from version.txt
|
// Version is automatically updated by the Makefile from version.txt
|
||||||
// The patch number (third digit) is incremented on each push to the repository
|
// The patch number (third digit) is incremented on each push to the repository
|
||||||
|
|
||||||
var _Version = "Release 4.4.18"
|
var _Version = "Release 4.4.25"
|
||||||
|
|
||||||
// Version returns the version of the obitools package.
|
// Version returns the version of the obitools package.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -273,6 +273,28 @@ func (s *BioSequence) Len() int {
|
|||||||
return len(s.sequence)
|
return len(s.sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MemorySize returns an estimate of the memory footprint of the BioSequence
|
||||||
|
// in bytes. It accounts for the sequence, quality scores, feature data,
|
||||||
|
// annotations, and fixed struct overhead. The estimate is conservative
|
||||||
|
// (cap rather than len for byte slices) so it is suitable for memory-based
|
||||||
|
// batching decisions.
|
||||||
|
func (s *BioSequence) MemorySize() int {
|
||||||
|
if s == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// fixed struct overhead (strings, pointers, mutex pointer)
|
||||||
|
const overhead = 128
|
||||||
|
n := overhead
|
||||||
|
n += cap(s.sequence)
|
||||||
|
n += cap(s.qualities)
|
||||||
|
n += cap(s.feature)
|
||||||
|
n += len(s.id)
|
||||||
|
n += len(s.source)
|
||||||
|
// rough annotation estimate: each key+value pair ~64 bytes on average
|
||||||
|
n += len(s.annotations) * 64
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
// HasQualities checks if the BioSequence has sequence qualitiy scores.
|
// HasQualities checks if the BioSequence has sequence qualitiy scores.
|
||||||
//
|
//
|
||||||
// This function does not have any parameters.
|
// This function does not have any parameters.
|
||||||
@@ -480,6 +502,15 @@ func (s *BioSequence) SetQualities(qualities Quality) {
|
|||||||
s.qualities = CopySlice(qualities)
|
s.qualities = CopySlice(qualities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TakeQualities stores the slice directly without copying.
|
||||||
|
// The caller must not use the slice after this call.
|
||||||
|
func (s *BioSequence) TakeQualities(qualities Quality) {
|
||||||
|
if s.qualities != nil {
|
||||||
|
RecycleSlice(&s.qualities)
|
||||||
|
}
|
||||||
|
s.qualities = qualities
|
||||||
|
}
|
||||||
|
|
||||||
// A method that appends a byte slice to the qualities of the BioSequence.
|
// A method that appends a byte slice to the qualities of the BioSequence.
|
||||||
func (s *BioSequence) WriteQualities(data []byte) (int, error) {
|
func (s *BioSequence) WriteQualities(data []byte) (int, error) {
|
||||||
s.qualities = append(s.qualities, data...)
|
s.qualities = append(s.qualities, data...)
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ func (s *BioSequenceSlice) ExtractTaxonomy(taxonomy *obitax.Taxonomy, seqAsTaxa
|
|||||||
return nil, fmt.Errorf("sequence %v has no path", s.Id())
|
return nil, fmt.Errorf("sequence %v has no path", s.Id())
|
||||||
}
|
}
|
||||||
last := path[len(path)-1]
|
last := path[len(path)-1]
|
||||||
taxname, _ := obiutils.SplitInTwo(last, ':')
|
taxname, _ := obiutils.LeftSplitInTwo(last, ':')
|
||||||
if idx, ok := s.GetIntAttribute("seq_number"); !ok {
|
if idx, ok := s.GetIntAttribute("seq_number"); !ok {
|
||||||
return nil, errors.New("sequences are not numbered")
|
return nil, errors.New("sequences are not numbered")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
package obiseq
|
package obiseq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils"
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const _LargeSliceThreshold = 100 * 1024 // 100 kb — below: leave to GC, above: trigger explicit GC
|
||||||
|
const _GCBytesBudget = int64(256 * 1024 * 1024) // trigger GC every 256 MB of large discards
|
||||||
|
|
||||||
|
var _largeSliceDiscardedBytes = atomic.Int64{}
|
||||||
|
|
||||||
var _BioSequenceByteSlicePool = sync.Pool{
|
var _BioSequenceByteSlicePool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
bs := make([]byte, 0, 300)
|
bs := make([]byte, 0, 300)
|
||||||
@@ -34,6 +41,13 @@ func RecycleSlice(s *[]byte) {
|
|||||||
}
|
}
|
||||||
if cap(*s) <= 1024 {
|
if cap(*s) <= 1024 {
|
||||||
_BioSequenceByteSlicePool.Put(s)
|
_BioSequenceByteSlicePool.Put(s)
|
||||||
|
} else if cap(*s) >= _LargeSliceThreshold {
|
||||||
|
n := int64(cap(*s))
|
||||||
|
*s = nil
|
||||||
|
prev := _largeSliceDiscardedBytes.Load()
|
||||||
|
if _largeSliceDiscardedBytes.Add(n)/_GCBytesBudget > prev/_GCBytesBudget {
|
||||||
|
runtime.GC()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func NewTaxidFactory(code string, alphabet obiutils.AsciiSet) *TaxidFactory {
|
|||||||
// It extracts the relevant part of the string after the first colon (':') if present.
|
// It extracts the relevant part of the string after the first colon (':') if present.
|
||||||
func (f *TaxidFactory) FromString(taxid string) (Taxid, error) {
|
func (f *TaxidFactory) FromString(taxid string) (Taxid, error) {
|
||||||
taxid = obiutils.AsciiSpaceSet.TrimLeft(taxid)
|
taxid = obiutils.AsciiSpaceSet.TrimLeft(taxid)
|
||||||
part1, part2 := obiutils.SplitInTwo(taxid, ':')
|
part1, part2 := obiutils.LeftSplitInTwo(taxid, ':')
|
||||||
if len(part2) == 0 {
|
if len(part2) == 0 {
|
||||||
taxid = part1
|
taxid = part1
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func EmpiricalDistCsv(filename string, data [][]Ratio, compressed bool) {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
destfile, err := obiutils.CompressStream(file, true, true)
|
destfile, err := obiutils.CompressStream(file, compressed, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,6 +214,8 @@ func CLIReadBioSequences(filenames ...string) (obiiter.IBioSequence, error) {
|
|||||||
|
|
||||||
iterator = iterator.Speed("Reading sequences")
|
iterator = iterator.Speed("Reading sequences")
|
||||||
|
|
||||||
|
iterator = iterator.RebatchBySize(obidefault.BatchMem(), obidefault.BatchSizeMax())
|
||||||
|
|
||||||
return iterator, nil
|
return iterator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -291,5 +291,5 @@ func IndexReferenceDB(iterator obiiter.IBioSequence) obiiter.IBioSequence {
|
|||||||
go f()
|
go f()
|
||||||
}
|
}
|
||||||
|
|
||||||
return indexed.Rebatch(obidefault.BatchSize())
|
return indexed.RebatchBySize(obidefault.BatchMem(), obidefault.BatchSizeMax())
|
||||||
}
|
}
|
||||||
|
|||||||
85
pkg/obiutils/memsize.go
Normal file
85
pkg/obiutils/memsize.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package obiutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseMemSize parses a human-readable memory size string and returns the
|
||||||
|
// equivalent number of bytes. The value is a number optionally followed by a
|
||||||
|
// unit suffix (case-insensitive):
|
||||||
|
//
|
||||||
|
// B or (no suffix) — bytes
|
||||||
|
// K or KB — kibibytes (1 024)
|
||||||
|
// M or MB — mebibytes (1 048 576)
|
||||||
|
// G or GB — gibibytes (1 073 741 824)
|
||||||
|
// T or TB — tebibytes (1 099 511 627 776)
|
||||||
|
//
|
||||||
|
// Examples: "512", "128K", "128k", "64M", "1G", "2GB"
|
||||||
|
func ParseMemSize(s string) (int, error) {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
if s == "" {
|
||||||
|
return 0, fmt.Errorf("empty memory size string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// split numeric prefix from unit suffix
|
||||||
|
i := 0
|
||||||
|
for i < len(s) && (unicode.IsDigit(rune(s[i])) || s[i] == '.') {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
numStr := s[:i]
|
||||||
|
unit := strings.ToUpper(strings.TrimSpace(s[i:]))
|
||||||
|
// strip trailing 'B' from two-letter units (KB→K, MB→M …)
|
||||||
|
if len(unit) == 2 && unit[1] == 'B' {
|
||||||
|
unit = unit[:1]
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := strconv.ParseFloat(numStr, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("invalid memory size %q: %w", s, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var multiplier float64
|
||||||
|
switch unit {
|
||||||
|
case "", "B":
|
||||||
|
multiplier = 1
|
||||||
|
case "K":
|
||||||
|
multiplier = 1024
|
||||||
|
case "M":
|
||||||
|
multiplier = 1024 * 1024
|
||||||
|
case "G":
|
||||||
|
multiplier = 1024 * 1024 * 1024
|
||||||
|
case "T":
|
||||||
|
multiplier = 1024 * 1024 * 1024 * 1024
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("unknown memory unit %q in %q", unit, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(val * multiplier), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatMemSize formats a byte count as a human-readable string with the
|
||||||
|
// largest unit that produces a value ≥ 1 (e.g. 1536 → "1.5K").
|
||||||
|
func FormatMemSize(n int) string {
|
||||||
|
units := []struct {
|
||||||
|
suffix string
|
||||||
|
size int
|
||||||
|
}{
|
||||||
|
{"T", 1024 * 1024 * 1024 * 1024},
|
||||||
|
{"G", 1024 * 1024 * 1024},
|
||||||
|
{"M", 1024 * 1024},
|
||||||
|
{"K", 1024},
|
||||||
|
}
|
||||||
|
for _, u := range units {
|
||||||
|
if n >= u.size {
|
||||||
|
v := float64(n) / float64(u.size)
|
||||||
|
if v == float64(int(v)) {
|
||||||
|
return fmt.Sprintf("%d%s", int(v), u.suffix)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%.1f%s", v, u.suffix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%dB", n)
|
||||||
|
}
|
||||||
@@ -144,7 +144,7 @@ func (r *AsciiSet) TrimLeft(s string) string {
|
|||||||
return s[i:]
|
return s[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func SplitInTwo(s string, sep byte) (string, string) {
|
func LeftSplitInTwo(s string, sep byte) (string, string) {
|
||||||
i := 0
|
i := 0
|
||||||
for ; i < len(s); i++ {
|
for ; i < len(s); i++ {
|
||||||
c := s[i]
|
c := s[i]
|
||||||
@@ -157,3 +157,17 @@ func SplitInTwo(s string, sep byte) (string, string) {
|
|||||||
}
|
}
|
||||||
return s[:i], s[i+1:]
|
return s[:i], s[i+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RightSplitInTwo(s string, sep byte) (string, string) {
|
||||||
|
i := len(s) - 1
|
||||||
|
for ; i >= 0; i-- {
|
||||||
|
c := s[i]
|
||||||
|
if c == sep {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == len(s) {
|
||||||
|
return s, ""
|
||||||
|
}
|
||||||
|
return s[:i], s[i+1:]
|
||||||
|
}
|
||||||
|
|||||||
36
tools/json2md.py
Executable file
36
tools/json2md.py
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Read potentially malformed JSON from stdin (aichat output), extract title and
|
||||||
|
body, and print them as plain text: title on first line, blank line, then body.
|
||||||
|
Exits with 1 on failure (no output).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
text = sys.stdin.read()
|
||||||
|
|
||||||
|
m = re.search(r'\{.*\}', text, re.DOTALL)
|
||||||
|
if not m:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
s = m.group()
|
||||||
|
obj = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
obj = json.loads(s)
|
||||||
|
except Exception:
|
||||||
|
s2 = re.sub(r'(?<!\\)\n', r'\\n', s)
|
||||||
|
try:
|
||||||
|
obj = json.loads(s2)
|
||||||
|
except Exception:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
title = obj.get('title', '').strip()
|
||||||
|
body = obj.get('body', '').strip()
|
||||||
|
|
||||||
|
if not title or not body:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"{title}\n\n{body}")
|
||||||
@@ -1 +1 @@
|
|||||||
4.4.18
|
4.4.25
|
||||||
|
|||||||
Reference in New Issue
Block a user