GithubHelp home page GithubHelp logo

atc0005 / elbow Goto Github PK

View Code? Open in Web Editor NEW
0.0 2.0 0.0 5 MB

Elbow, Elbow grease.

License: Apache License 2.0

Go 76.17% Makefile 15.83% Shell 6.66% Dockerfile 1.35%
golang go prune command-line file

elbow's Introduction

elbow

Elbow, Elbow grease.

Latest Release Go Reference go.mod Go version Lint and Build Project Analysis

Project home

See our GitHub repo for the latest code, to file an issue or submit improvements for review and potential inclusion into the project.

Purpose

Prune content matching specific patterns, either in a single directory or recursively through a directory tree. The primary goal is to use this application from a cron job to perform routine pruning of generated files that would otherwise completely clog a filesystem.

Gotchas

  • File extensions are case-sensitive
  • File name patterns are case-sensitive
  • File name patterns, much like shell globs, may match more than intended.
    • Test carefully and do not provide the --remove flag until you have tested and are ready to actually prune the content.

Features

  • Supports multiple (merged) sources for supplying configuration settings
    • Environment variables
    • TOML format configuration file
    • Command-line flags (with detailed help output)
    • Note: See the Precedence list for how multiple configuration sources are processed
  • Match on specified file patterns
  • Flat (single-level) or recursive search
  • Process one or many paths
  • Age-based threshold for matches (e.g., match files X days old or older)
  • Keep a specified number of older or newer matches
  • Limit search to specified list of file extensions
  • Toggle file removal (read-only by default)
  • Extensive, leveled-logging
    • (Optional) Syslog logging (not supported on Windows)
    • (Optional) Logging to a file (if enabled, mutes console output)
    • Text or JSON log formats
  • (Optional) Ignore errors encountered when removing files

Worth noting: This project uses Go modules (vs classic GOPATH setup)

Changelog

See the CHANGELOG.md file for the changes associated with each release of this application. Changes that have been merged to master, but not yet an official release may also be noted in the file under the Unreleased section. A helpful link to the Git commit history since the last official release is also provided for further review.

Requirements

The following is a loose guideline. Other combinations of Go and operating systems for building and running tools from this repo may work, but have not been tested.

Building source code

  • Go
    • see this project's go.mod file for preferred version
    • this project tests against officially supported Go releases
      • the most recent stable release (aka, "stable")
      • the prior, but still supported release (aka, "oldstable")
  • GCC
    • if building with custom options (as the provided Makefile does)
  • make
    • if using the provided Makefile

Running

  • Windows 10
  • Ubuntu Linux 18.04+
  • Red Hat Enterprise Linux 7+

Installation

From source

  1. Download Go
  2. Install Go
    • NOTE: Pay special attention to the remarks about $HOME/.profile
  3. Clone the repo
    1. cd /tmp
    2. git clone https://github.com/atc0005/elbow
    3. cd elbow
  4. Install dependencies (optional)
    • for Ubuntu Linux
      • sudo apt-get install make gcc
    • for CentOS Linux
      1. sudo yum install make gcc
  5. Build
    • for current operating system
      • go build -mod=vendor ./cmd/elbow/
        • forces build to use bundled dependencies in top-level vendor folder
    • for all supported platforms (where make is installed)
      • make all
    • for Windows
      • make windows
    • for Linux
      • make linux
  6. Copy the applicable binary to whatever systems needs to run it
    • if using Makefile: look in /tmp/release_assets/elbow/
    • if using go build: look in /tmp/elbow/

NOTE: Depending on which Makefile recipe you use the generated binary may be compressed and have an xz extension. If so, you should decompress the binary first before deploying it (e.g., xz -d elbow-linux-amd64.xz).

Using release binaries

  1. Download the latest release binaries
  2. Decompress binaries
    • e.g., xz -d elbow-linux-amd64.xz
  3. Deploy
    • Place elbow in a location of your choice
      • e.g., /usr/local/bin/

NOTE:

DEB and RPM packages are provided as an alternative to manually deploying binaries.

Setup test environment

  1. Launch container, VM or WSL instance
  2. Clone the repo
    1. cd /tmp
    2. git clone https://github.com/atc0005/elbow
    3. cd elbow
  3. Create test files
    • in subdirectories of /tmp/elbow
      • make testenv
    • in a custom location (e.g., in $HOME)
      • mkdir -vp $HOME/tmp/elbow
      • make testenv TESTENVBASEDIR="$HOME/tmp/elbow"

See the Examples or the Configuration Options sections for examples of running elbow against these newly created test files.

Configuration Options

Precedence

Note: This behavior is subject to change based on feedback.

The priority order is (mostly):

  1. Command line flags (highest priority)
  2. Environment variables
  3. Environment variables loaded from .env files
    • Not supported yet
  4. Configuration file
  5. Default settings (lowest priority)

Configuration sources lower in the list are loaded first, with configuration sources above loaded sequentially (if enabled) after. Settings are merged, with settings specifically defined in sources with higher precedence overriding values set by configuration sources with lower precedence.

For example, if the configuration file defines /tmp/elbow/path1 as the path to process, an environment variable defines /tmp/elbow/path2 and the command-line flag for that setting specifies /tmp/elbow/path3, the command-line flag will win and /tmp/elbow/path3 will be used.

The intent of this behavior is to provide a feathered layering of configuration settings; if a configuration file provides all settings that you want other than one, you can use the configuration file for the other settings and specify the settings that you wish to override via environment variable or command-line flag.

Note: This behavior is subject to change based on feedback.

Command-line Arguments

Aside from the built-in -h, short flag names are currently not supported.

Long Required Default Repeat Possible Description
keep No 0 No 0+ Keep specified number of matching files.
paths Yes N/A No one or more valid directory paths List of comma or space-separated paths to process.
pattern No empty string No valid file name characters Substring pattern to compare filenames against. Wildcards are not supported.
extensions No empty list No valid file extensions Limit search to specified file extension. Specify as space separated list to match multiple required extensions. Comparisons are performed case-insensitively.
recurse No false No true, false Perform recursive search into subdirectories.
keep-old No false No true, false Keep oldest files instead of newer.
age No 0 No 0+ Limit search to files that are the specified number of days old or older.
remove Maybe false No true, false Remove matched files. The default behavior is to only note what matching files would be removed.
ignore-errors No false No true, false Ignore errors encountered during file removal.
log-format No text No text, json Log formatter used by logging package.
log-file No empty string No writable directory path Optional log file used to hold logged messages. If set, log messages are not displayed on the console.
console-output No stdout No stdout, stderr Specify how log messages are logged to the console.
log-level No info No emergency, alert, critical, panic, fatal, error, warn, info, notice, debug, trace Maximum log level at which messages will be logged. Log messages below this threshold will be discarded.
use-syslog No false No true, false Log messages to syslog in addition to other ouputs. Not supported on Windows.
config-file No empty string No valid path to config file Full path to optional TOML-formatted configuration file. See config.example.toml for a starter template.

Environment Variables

If set, environment variables override settings provided by a configuration file. If used, command-line arguments override the equivalent environment variables listed below. See the Command-line Arguments table for more information.

Flag Name Environment Variable Name Notes Example
keep ELBOW_KEEP ELBOW_KEEP=1
paths ELBOW_PATHS ELBOW_PATHS="/tmp/elbow/path1", ELBOW_PATHS="/tmp/elbow/path1,/tmp/elbow/path2"
pattern ELBOW_FILE_PATTERN ELBOW_FILE_PATTERN="reach-masterdev-"
extensions ELBOW_EXTENSIONS Comma-separated, no spaces ELBOW_EXTENSIONS=".war,.tmp"
recurse ELBOW_RECURSE ELBOW_RECURSE="true"
keep-old ELBOW_KEEP_OLD ELBOW_KEEP_OLD="true"
age ELBOW_FILE_AGE ELBOW_FILE_AGE=120
remove ELBOW_REMOVE ELBOW_REMOVE="false"
ignore-errors ELBOW_IGNORE_ERRORS ELBOW_IGNORE_ERRORS="true"
log-format ELBOW_LOG_FORMAT ELBOW_LOG_FORMAT="json"
log-file ELBOW_LOG_FILE ELBOW_LOG_FILE="/tmp/testing-masterqa-build-removals.txt"
console-output ELBOW_CONSOLE_OUTPUT ELBOW_CONSOLE_OUTPUT="stdout"
log-level ELBOW_LOG_LEVEL ELBOW_LOG_LEVEL="debug"
use-syslog ELBOW_USE_SYSLOG ELBOW_USE_SYSLOG="true"
config-file ELBOW_CONFIG_FILE ELBOW_CONFIG_FILE="/usr/local/elbow/config.toml"

Configuration File

Configuration file settings have the lowest priority and are overridden by settings specified in other configuration sources, except for default values. See the Command-line Arguments table for more information, including the available values for the listed configuration settings.

Flag Name Config file Setting Name Section Name Notes
pattern pattern filehandling
extensions file_extensions filehandling
age file_age filehandling
keep files_to_keep filehandling
keep-old keep_oldest filehandling
remove remove filehandling
ignore-errors ignore_errors filehandling
paths paths search Multi-line array
recurse recursive_search search
log-level log_level logging
log-format log_format logging
log-file log_file_path logging
console-output console_output logging
use-syslog use_syslog logging

See the config.example.toml file for an example of how to use these settings.

Examples

Overview

The following steps illustrate a rough, overall idea of what elbow is intended to do. The steps illustrate building and running the application from within an Ubuntu Linux Subsystem for Windows (WSL) instance. The t volume is present on the Windows host.

The file extension used in the examples below is for WAR files that are generated on a build system that our group used to maintain. The idea is that elbow could be run as a cron job to help ensure that only X copies (the most recent in our case) for each of three branches remain on the build box.

There are better approaches to managing build artifacts (e.g., containers); this tool seeks to solve in a simple, "low tech" way.

The particular repo that the build system processed has three branches:

Branch Name Type of build
master Production
masterqa Q/A
masterdev Development

We had little control over the name of these branches.

Log output

Text format

./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-master" --keep 1 --recurse --keep-old --ignore-errors --log-level info --use-syslog --log-format text
INFO[0000] Syslog logging requested, attempting to enable it  use_syslog=true
ERRO[0000] Failed to enable syslog logging: unable to connect to syslog socket: Unix syslog delivery error  use_syslog=true
WARN[0000] Proceeding without syslog logging             use_syslog=true
INFO[0000] Starting evaluation of paths list             extensions="[]" file_age=0 file_pattern=reach-master paths="[/tmp/elbow/path1 /tmp/elbow/path2]"
INFO[0000] Beginning processing of path "/tmp/elbow/path1" (1 of 2)  ignore_errors=true iteration=1 total_paths=2
INFO[0000] 183 files eligible for removal (910.0 MiB)    extensions="[]" file_age=0 file_pattern=reach-master iteration=1 path=/tmp/elbow/path1 total_file_size=954204160
INFO[0000] 1 files to keep as requested                  iteration=1 keep_oldest=true
INFO[0000] Ignoring file removal errors: true
INFO[0000] File removal not enabled, not removing files
INFO[0000] 0 files successfully removed (0 B)
INFO[0000] 0 files failed to remove (0 B)
INFO[0000] Ending processing of path "/tmp/elbow/path1" (1 of 2)  ignore_errors=true iteration=1 total_paths=2
INFO[0000] Beginning processing of path "/tmp/elbow/path2" (2 of 2)  ignore_errors=true iteration=2 total_paths=2
INFO[0000] 183 files eligible for removal (954.0 KiB)    extensions="[]" file_age=0 file_pattern=reach-master iteration=2 path=/tmp/elbow/path2 total_file_size=976896
INFO[0000] 1 files to keep as requested                  iteration=2 keep_oldest=true
INFO[0000] Ignoring file removal errors: true
INFO[0000] File removal not enabled, not removing files
INFO[0000] 0 files successfully removed (0 B)
INFO[0000] 0 files failed to remove (0 B)
INFO[0000] Ending processing of path "/tmp/elbow/path2" (2 of 2)  ignore_errors=true iteration=2 total_paths=2
INFO[0000] Elbow successfully completed.                 eligible_remove=366 eligible_size="910.9 MiB" failed_removed=0 failed_size="0 B" success_removed=0 success_size="0 B"

Where supported, the output is colored.

Screenshots
Original implementation

From just before the v0.2.0 milestone was completed and the v0.2.0 tag created:

Colored text output example screenshot

Multiple paths

While working on support for multiple paths per issue 32:

Colored text output example screenshot

JSON format

./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-master" --keep 1 --recurse --keep-old --ignore-errors --log-level info --use-syslog --log-format json
{"level":"info","msg":"Syslog logging requested, attempting to enable it","time":"2019-11-12T06:51:50-06:00","use_syslog":true}
{"level":"error","msg":"Failed to enable syslog logging: unable to connect to syslog socket: Unix syslog delivery error","time":"2019-11-12T06:51:50-06:00","use_syslog":true}
{"level":"warning","msg":"Proceeding without syslog logging","time":"2019-11-12T06:51:50-06:00","use_syslog":true}
{"extensions":null,"file_age":0,"file_pattern":"reach-master","level":"info","msg":"Starting evaluation of paths list","paths":["/tmp/elbow/path1","/tmp/elbow/path2"],"time":"2019-11-12T06:51:50-06:00"}
{"ignore_errors":true,"iteration":1,"level":"info","msg":"Beginning processing of path \"/tmp/elbow/path1\" (1 of 2)","time":"2019-11-12T06:51:50-06:00","total_paths":2}
{"extensions":null,"file_age":0,"file_pattern":"reach-master","iteration":1,"level":"info","msg":"183 files eligible for removal (910.0 MiB)","path":"/tmp/elbow/path1","time":"2019-11-12T06:51:50-06:00","total_file_size":954204160}
{"iteration":1,"keep_oldest":true,"level":"info","msg":"1 files to keep as requested","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"Ignoring file removal errors: true","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"File removal not enabled, not removing files","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"0 files successfully removed (0 B)","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"0 files failed to remove (0 B)","time":"2019-11-12T06:51:50-06:00"}
{"ignore_errors":true,"iteration":1,"level":"info","msg":"Ending processing of path \"/tmp/elbow/path1\" (1 of 2)","time":"2019-11-12T06:51:50-06:00","total_paths":2}
{"ignore_errors":true,"iteration":2,"level":"info","msg":"Beginning processing of path \"/tmp/elbow/path2\" (2 of 2)","time":"2019-11-12T06:51:50-06:00","total_paths":2}
{"extensions":null,"file_age":0,"file_pattern":"reach-master","iteration":2,"level":"info","msg":"183 files eligible for removal (954.0 KiB)","path":"/tmp/elbow/path2","time":"2019-11-12T06:51:50-06:00","total_file_size":976896}
{"iteration":2,"keep_oldest":true,"level":"info","msg":"1 files to keep as requested","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"Ignoring file removal errors: true","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"File removal not enabled, not removing files","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"0 files successfully removed (0 B)","time":"2019-11-12T06:51:50-06:00"}
{"level":"info","msg":"0 files failed to remove (0 B)","time":"2019-11-12T06:51:50-06:00"}
{"ignore_errors":true,"iteration":2,"level":"info","msg":"Ending processing of path \"/tmp/elbow/path2\" (2 of 2)","time":"2019-11-12T06:51:50-06:00","total_paths":2}
{"eligible_remove":366,"eligible_size":"910.9 MiB","failed_removed":0,"failed_size":"0 B","level":"info","msg":"Elbow successfully completed.","success_removed":0,"success_size":"0 B","time":"2019-11-12T06:51:50-06:00"}

Help Output

$ ./elbow --help
Elbow prunes content matching specific patterns, either in a single directory or recursively through a directory tree.

ELBOW x.y.z
https://github.com/atc0005/elbow

Usage: elbow [--pattern PATTERN] [--extensions EXTENSIONS] [--age AGE] [--keep KEEP] [--keep-old] [--remove] [--ignore-errors] [--log-level LOG-LEVEL] [--log-format LOG-FORMAT] [--log-file LOG-FILE] [--console-output CONSOLE-OUTPUT] [--use-syslog] [--paths PATHS] [--recurse] [--config-file CONFIG-FILE]

Options:
  --pattern PATTERN      Substring pattern to compare filenames against. Wildcards are not supported.
  --extensions EXTENSIONS
                         Limit search to specified file extensions. Specify as space separated list to match multiple required extensions. Comparisons are performed case-insensitively.
  --age AGE              Limit search to files that are the specified number of days old or older.
  --keep KEEP            Keep specified number of matching files per provided path. [default: -1]
  --keep-old             Keep oldest files instead of newer per provided path.
  --remove               Remove matched files per provided path.
  --ignore-errors        Ignore errors encountered during file removal.
  --log-level LOG-LEVEL
                         Maximum log level at which messages will be logged. Log messages below this threshold will be discarded. [default: info]
  --log-format LOG-FORMAT
                         Log formatter used by logging package. [default: text]
  --log-file LOG-FILE    Optional log file used to hold logged messages. If set, log messages are not displayed on the console.
  --console-output CONSOLE-OUTPUT
                         Specify how log messages are logged to the console. [default: stdout]
  --use-syslog           Log messages to syslog in addition to other outputs. Not supported on Windows.
  --paths PATHS          List of comma or space-separated paths to process.
  --recurse              Perform recursive search into subdirectories per provided path.
  --config-file CONFIG-FILE
                         Full path to optional TOML-formatted configuration file. See config.example.toml for a starter template.
  --help, -h             display this help and exit
  --version              display version and exit

Prune .war files from each branch recursively, keep newest 2

Note: Leave off --remove to display what would be removed.

./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --extensions ".war" --pattern "reach-master-" --keep 2 --recurse --remove
./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --extensions ".war" --pattern "reach-masterqa-" --keep 2 --recurse --remove
./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --extensions ".war" --pattern "reach-masterdev-" --keep 2 --recurse --remove

Keep oldest 1, debug logging, ignore errors, use syslog

Note: Leave off --remove to display what would be removed.

./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-master-" --keep 1 --recurse --keep-old --ignore-errors --log-level debug --use-syslog
./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-masterqa-" --keep 1 --recurse --keep-old --ignore-errors --log-level debug --use-syslog
./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-masterdev-" --keep 1 --recurse --keep-old --ignore-errors --log-level debug --use-syslog

Log to a file in JSON format

  • These examples attempt to create a log file in the current directory.
  • The default logging format is text unless overridden; here we specify json.
  • We attempt to enable syslog logging. This currently fails gracefully on Windows.
  • We ignore file removal errors and proceed to the next matching file.
./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-master-" --keep 1 --recurse --keep-old --ignore-errors --log-level debug --log-format json --use-syslog --log-file testing-master-build-removals.txt
./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-masterqa-" --keep 1 --recurse --keep-old --ignore-errors --log-level debug --use-syslog --log-format json --log-file testing-masterqa-build-removals.txt
./elbow --paths "/tmp/elbow/path1" "/tmp/elbow/path2" --pattern "reach-masterdev-" --keep 1 --recurse --keep-old --ignore-errors --log-level debug --use-syslog --log-format json --log-file testing-masterdev-build-removals.txt

License

Taken directly from the LICENSE and NOTICE.txt files:

Copyright 2019-Present Adam Chalkley

https://github.com/atc0005/elbow/blob/master/LICENSE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

References

Flag packages

The following list of packages were either used or seriously considered at some point during the development of this project.

Configuration object

Sorting files

Path/File Existence

Slice management

elbow's People

Contributors

atc0005 avatar dependabot[bot] avatar

Stargazers

 avatar

Watchers

 avatar  avatar

elbow's Issues

Add support for persistent processing of content

Whether through an application loop using one or more timers or a true service/daemon configuration, support having the application repeat its removal process.

Either before or as preparation for this, support could be added to process multiple paths in one invocation. As of v0.3.1, only one path is supported at a time.

Add support for command-line flags

Not yet sure which package, but this tool will need to be heavily command-line driven.

Standard library

Third-party

Implementation / Examples

Add default option settings directly to Config struct

Now that the alexflint/go-arg package supports it, update the Config struct to specify defaults settings. The assumption is that this will apply the default settings there which could potentially be used/respected by other configuration packages that reference a default struct tag.

The primary hope/goal is that this will better display default values to the user in the Help output.

Create initial prototype

The idea is to either use hard-coded settings or the standard library to support basic options via positional command-line arguments.

The core concept is an app that can be pointed at a target directory and allowed to recursively prune all files matching specific patterns.

Those patterns can be any of:

  • date (modified X days in the past)
  • filename (e.g., date/time naming scheme)
  • extension (e.g., .tmp)
  • ?

The idea is that this tool would be called by a cron job or as needed as a one-shot run to perform cleanup work.

Age option missing from README

While actually trying to use the app myself today, I went to match files based on age and decided I would use the existing README for guidance. I did not find the option listed, aside from further down the page in the "Help Output".

Oops?

refs #10, #27

Add CHANGELOG file

Probably worth going ahead and add it now before going much further with the project. I need to look up the templates site that I came across a few years back in order to get a good refresher on the format.

README | Typo in License text

Minor nit, but worth fixing.

-specific language governing permissions and limitations under the Licens
+specific language governing permissions and limitations under the License.

godoc doesn't render intro text

As of v0.5.0, godoc does not render any useful text to the reader, either via local godoc binary or godoc.org.

Evidently what I've done thus far isn't sufficient to even provide the overview text to the reader.

Support .env files via godotenv package

When implemented, the traditional precedence of .env files should be followed.

This would modify the load order to look something like this:

  1. Default values
  2. Existing environment variables
  3. gotdotenv import of .env files
  4. Configuration file
  5. Command-line flags

As of this writing we're using the alexflint/go-arg package for flags and environment variable support. My understanding is that by using the godotenv package to load .env files the alexflint/go-arg package will automatically "see" the environment variables and use them. This should make the existing configuration setup seamless.

Add NOTICE file

Based on light reading, it doesn't appear that I have to include a NOTICE file, but it appears to be good practice to do so. The intent seems to be to include a quick reference for various licenses attached to the product.

In this project's case, I assume this includes all libraries/packages that are pulled in. I'm not fluent enough with licensing to know whether it applies to any code present in the repo, or just the official releases. In other words, if I have a temporary feature branch that I'm using to test various packages, does the NOTICE file need to be updated for each package that I test or just when an official release is made?

I assume that a good checklist item for tagging releases or (perhaps) even merging a Pull Request is to make sure that licensing is covered?

Decide on a logging package

I've been using the standard library log package and while it works, it seems to be lacking the basic leveled logging features I've come to rely upon over the years (e.g., logger from shell scripts, Python's logging module, ...).

There are a lot of options available, but I'm going to focus first on trying those which are most actively supported and used by some of the bigger teams/projects.

Report size of files that are eligible for removal (based on provided criteria)

This can be done per file in the logged messages and as a cumulative number in the INFO level message which is most likely to be printed to the console.

This could be particularly useful for summarizing what would be removed if a particular set of options are applied (e.g., what is the size difference with keeping 120 days worth of a type of file vs 60 days).

Add Makefile to handle builds

At least one set of the build options should include optimized builds for size and speed (to test if nothing else).

Replace lightweight release tags with annotated tags

While working on #54 and going through the docs/notes for git describe I noticed that only the v0.1.0 tag showed in the git describe output unless I used the --tags option to display both annotated tags (default) as well as lightweight tags.

Current tags:

$ git for-each-ref refs/tags
665a70d2c1cd1b8ead54fea5ba7816a77a74f9eb tag    refs/tags/v0.1.0
1508ae84959b21a79aa09e25f166e6bc6d10a425 commit refs/tags/v0.2.0
1b191cd4ca728f7a40f300406e98e1687c56ecbd commit refs/tags/v0.3.0
91c177c29c196d33177b4f1c3a677297d27cf428 commit refs/tags/v0.3.1
64d55334d64bf11d9e432808e7c0456e2d4f828b commit refs/tags/v0.3.2

It seems that "cutting a release" and having GitHub handle tagging results in lightweight tags only.

Light research indicates that you can convert lightweight tags to annotated tags like so: git tag -a <tag_name> <SHA-1> -f

References:

Specify default empty string values on Config struct?

go-flags provides the default:"" struct tag for specifying default values if one is not provided for the specified flag. The current code sets an empty string (explicitly) and Go's default "zero" value for a string is already "", so I'm not sure we really need to spell it out on the struct tag also, but perhaps it could be useful for generation of the help text?

Add support for configuration file settings

While this tool will be heavily command-line driven, there are likely to be several good use cases for laying out all desired options via configuration file.

The specific format is yet to be determined.

Potential options:

  • YAML
  • JSON (not likely)
  • TOML (instead of INI)
  • flat, space-separated text file

Pick a license

Goal

This might be somewhat determined by what packages I decide to pull in, but if not, I'll need to pick something flexible enough that someone would want to use this as a base for their own projects (e.g., someone entirely new to Go like myself).

Packages I'm considering

Package License GitHub repo
integrii/flaggy The Unlicense https://github.com/integrii/flaggy
urfave/cli MIT License https://github.com/urfave/cli
peterbourgon/ff Apache License 2.0 https://github.com/peterbourgon/ff

Resources

Prep v0.3.2 release

CHANGELOG updates, new tag, publish release.

This would be another "pre-release" as the codebase is still not as stable or feature complete as I would like.

Remove use of UPX

Overview

Brief testing shows that running go against a UPX compressed binary to determine version information doesn't work well. Uncompressed, good results can be obtained via either of:

  • go version BINARY_NAME
  • go version -m -v BINRARY_NAME

Being able to determine that build information (particularly via automated means) is likely a bigger perk than reducing the initial file size.

Example output

Examining compressed binary

$ go version elbow
elbow: go version not found

$ go version -m -v elbow
elbow: go version not found

Decompress binary

$ upx -d elbow
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2017
UPX 3.94        Markus Oberhumer, Laszlo Molnar & John Reiser   May 12th 2017

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   2887680 <-    876564   30.36%   linux/amd64   elbow

Examine decompressed binary

$ go version elbow
elbow: go1.13.3

$ go version -m -v elbow
elbow: go1.13.3
        path    github.com/atc0005/elbow
        mod     github.com/atc0005/elbow        (devel)
        dep     github.com/alexflint/go-arg     v1.1.0  h1:92ADei0d3TP0mGBdJ/FNcF54X6uFY7BQfhqkrQt3CCE=
        dep     github.com/alexflint/go-scalar  v1.0.0  h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70=
        dep     github.com/sirupsen/logrus      v1.4.2  h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
        dep     golang.org/x/sys        v0.0.0-20190422165155-953cdadca894      h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=

Update to v1.2.0 of alexflint/go-arg package

The v1.2.0 release provides support for configuring defaults directly on the configuration struct. Presumably this also opens up the option for better Help output in order to better communicate those default values to the user.

Update go.mod to reflect Go 1.13

Based on some reading in https://github.com/golang/go/wiki/Modules, the behavior for go get -u changed to allow more conservative updates of dependencies. The new behavior sounds more natural and is less likely to surprise newcomers, so locking the base behavior to Go 1.13 sounds like a "Good Thing" to do here.

As part of this, I should touch the docs to list Go version 1.13 as the desired Go version. If I learn that this change doesn't impact older (still supported) Go versions, I can update the docs again to include the older version as the minimum required.

cleanPath() function fails to use full path to file

Instead of using a fully-qualified path to the file, the cleanPath() function attempts to remove the file using the bare or "short" name only. When the current working directory is not the same directory where the target file is present, this results in a failed file removal.

Setup CI for Pull Request checks

Lots of options to choose from. Since this is an Open Source project, funding doesn't appear to be an issue (presumably based on low usage).

golangci-lint check results against v0.5.0

$ golangci-lint run
matches.go:173:23: func `FileMatches.sortByModTimeDesc` is unused (unused)
func (fm FileMatches) sortByModTimeDesc() {
                      ^
config.go:42:26: SA5008: duplicate struct tag "arg" (staticcheck)
        NumFilesToKeep int      `arg:"--keep,env:ELBOW_KEEP" arg:"required" help:"Keep specified number of matching files per provided path."`
                                ^
config.go:51:27: SA5008: duplicate struct tag "arg" (staticcheck)
        Paths           []string `arg:"--paths,env:ELBOW_PATHS" arg:"required" help:"List of comma or space-separated paths to process."`
                                 ^

Need to take a closer look at the struct tags to make sure I've defined them properly.

Structured logging output for path evaluation missing extension(s)

Command that I ran:

ubuntu@TESTBOX:/tmp$ cd /mnt/t/github/elbow; go build && cp -vf elbow /tmp/; cd /tmp/; ./elbow --path /tmp --pattern "reach-masterdev" --keep 1 --recurse --keep-old
 --ignore-errors --age 7 --extension ".tmp" --extension ".war" --log-level info --log-format text

Output:

'elbow' -> '/tmp/elbow'
INFO[0000] Starting evaluation of path                   extensions="[.war]" file_age=7 file_pattern=reach-masterdev path=/tmp

I expected to see something like:

'elbow' -> '/tmp/elbow'
INFO[0000] Starting evaluation of path                   extensions="[.war .tmp]" file_age=7 file_pattern=reach-masterdev path=/tmp

Split package "main" into multiple sub-packages

This is inspired by #76, but also because I've known for a while that this might eventually be needed. I'm hoping to better isolate code from the main package in the hope/belief that this will make setting up future tests easier and more reliable.

Add dry-run option to generate a list of files that would be removed

This is already listed at DEBUG log level, so this option would be enabling reporting of eligible files in some sort of format that is easily read and shared (e.g., logged to a ticket of some kind).

Example/concept usage:

sudo ./elbow --paths /var/log/tomcat7/ --recurse --age 120 --generate-report

Regarding an output format, I'm not sure what would work best. Hopefully something concise for the screen and something else to be saved in a file for later review.

Add support for pruning based on file age

Right now we're keeping X number of files and relying on filename patterns to help limit the files that are removed. To make this tool more useful, it will need to support age-based matching as well. Other criteria can be added later (e.g., size), but this one seems to be the more useful additoin to include first.

Match age in minutes, hours, days, ... ?

Add usage details to top of main.go

This would be useful not only for those reviewing the source, but for GoDoc generated coverage.

Example:

https://github.com/assafmo/joincap/blob/master/main.go

Snippet from the beginning of the file:

// Merge multiple pcap files together, gracefully.
//
//  Usage:
//    joincap [OPTIONS] InFiles...
//
//  Application Options:
//    -v, --verbose  Explain when skipping packets or entire input files
//    -V, --version  Print the version and exit
//    -w=            Sets the output filename. If the name is '-', stdout will be used (default: -)
//
//  Help Options:
//    -h, --help     Show this help message
package main

import (

Add GoDoc badge to README

Per the Tools page:

[![GoDoc](https://godoc.org/github.com/atc0005/elbow?status.svg)](https://godoc.org/github.com/atc0005/elbow)

Reasoning: Should make it easier for future readers to quickly view GoDoc documentation for this project (which admittedly is nearly nonexistent at the moment).

Alter log level for "removing file" messages

Example output from a recent live run against a Tomcat 7 log directory:

INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-14.txt-20190615.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-15.txt-20190616.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-16.txt-20190617.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-17.txt-20190618.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-18.txt-20190619.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-19.txt-20190620.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-20.txt-20190621.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-21.txt-20190622.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-22.txt-20190623.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-23.txt-20190624.bz2 removal_enabled=true
INFO[0000] Removing file                                 file=/var/log/tomcat7/old/localhost_access_log.2019-06-24.txt-20190625.bz2 removal_enabled=true
INFO[0000] 1576 files successfully removed
INFO[0000] localhost_access_log.2015-04-23.txt-20160906.bz2  failed_removal=false
INFO[0000] localhost_access_log.2015-04-24.txt-20160906.bz2  failed_removal=false
INFO[0000] localhost_access_log.2015-04-25.txt-20160906.bz2  failed_removal=false
INFO[0000] localhost_access_log.2015-04-26.txt-20160906.bz2  failed_removal=false

I don't yet know the best way to handle listing/logging the latter items showing what did occur, but logging what was going to occur seems like duplicate information based on the default INFO log level.

A good first start here would be setting the former log messages to DEBUG level so that they're muted by default. The X files successfully removed message would explicitly remain INFO level and the latter messages better evaluated as part of the work on #72.

Update CHANGELOG and prep v0.5.1 release

Quite a number of small improvements since the v0.5.0 release. This is a good stopping point before beginning work to implement support for configuration files.

Add support for logging to multiple locations simultaneously

This is handled now via syslog + whatever output is chosen (log file, or one of stdout/stderr), but if using an io.MultiWriter the user could choose to log to ALL chosen outputs simultaneously.

Example:

package logging

import (
    "io"
    logging "log"
    "os"

    "github.com/Sirupsen/logrus"
)

var (
    log *logrus.Logger
)

func init() {
    f, err := os.OpenFile("logs/application.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)

    if err != nil {
        logging.Fatalf("error opening file: %v", err)
    }

    log = logrus.New()

    //log.Formatter = &logrus.JSONFormatter{}

    log.SetReportCaller(true)

    mw := io.MultiWriter(os.Stdout, f)
    log.SetOutput(mw)
}

// Info ...
func Info(format string, v ...interface{}) {
    log.Infof(format, v...)
}

// Warn ...
func Warn(format string, v ...interface{}) {
    log.Warnf(format, v...)
}

// Error ...
func Error(format string, v ...interface{}) {
    log.Errorf(format, v...)
}

var (

    // ConfigError ...
    ConfigError = "%v type=config.error"

    // HTTPError ...
    HTTPError = "%v type=http.error"

    // HTTPWarn ...
    HTTPWarn = "%v type=http.warn"

    // HTTPInfo ...
    HTTPInfo = "%v type=http.info"
)
package main

import (

    log "logging"
)

func main() {
    log.Error(log.ConfigError, "Testing the error")
}

Reference:

https://stackoverflow.com/a/55989885/903870

Update list of build dependencies

On a whim, I fired up a clean Ubuntu 18.04 LXD container and proceeded with my attempts to build this application using Go version 1.13.1.

  • ubuntu@ubuntu-1804-golang-testing:~/elbow$ GOOS=linux go build -o elbow
  • ubuntu@ubuntu-1804-golang-testing:~/elbow$ GOOS=linux go build -a -ldflags="-s -w

The first command works without issue. Using the second variant I get a complaint that gcc wasn't found.

Here are the (base) packages which I had to install to make this process work using the provided Makefile:

  • make
  • upx
  • gcc

From there all of the Makefile recipes worked as expected.

Provide rsyslog config snippet

Since syslog output is attempted, providing a template for catching and routing the log data could be useful. If providing this snippet, also providing a logrotate snippet would be a good idea.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.