Commit Graph

205 Commits

Author SHA1 Message Date
Joshua Clayton
8828f65cb7
Make reading files safer 2016-06-27 05:55:11 -04:00
Joshua Clayton
87d773c126
ask -> asks 2016-06-27 05:54:47 -04:00
Joshua Clayton
fa0a947ca8
Update docs around installation/upgrading 2016-06-26 05:13:28 -04:00
Joshua Clayton
8f424ea0e3
Outline installation via Stack
This documents now to install via Stack, by updating the list of known
packages, ensuring at least lts-6.0, and then installing unused
directly.
2016-06-24 09:22:06 -04:00
Joshua Clayton
b852cff74c
Bump version to 0.5.0.2 2016-06-24 08:31:44 -04:00
Joshua Clayton
94bbd04f6a
Remove final -Werror setting 2016-06-24 08:31:14 -04:00
Joshua Clayton
f0c24682e4
Bump version to 0.5.0.1 2016-06-24 08:30:13 -04:00
Joshua Clayton
121775cbc6
Remove -O flag entirely for Hackage upload 2016-06-24 08:29:32 -04:00
Joshua Clayton
b0f8d7f620
Bump version to 0.5.0.0 2016-06-24 08:27:20 -04:00
Joshua Clayton
5d6ec8d611
Remove -Werror from compilation
To upload to hackage, -Wall -Werror cannot both be set. This can be
achieved by installing with stack's `--pedantic` flag.
2016-06-24 08:17:55 -04:00
Joshua Clayton
11ff583d3c
Convert from -O2 to -O 2016-06-24 08:15:57 -04:00
Joshua Clayton
240b5bbb19 Support digesting on Linux with md5sum
This introduces behavior searching for an available program to calculate
digests across directories. OS X ships with md5, but on *nix-based
systems, it's md5sum. The output is largely the same, apart from the
final digest calculation, which includes a "file path":

    da52a1a5d5a3c9672371746e4d32708a  -

This strips the trailing whitespace and dash:

    da52a1a5d5a3c9672371746e4d32708a

Closes #49
2016-06-23 23:11:32 -04:00
Joshua Clayton
1892f8c0ba Extract error headers 2016-06-23 22:44:23 -04:00
Joshua Clayton
b65de02efc Display recent git SHAs per token
This creates a new "list" output format that includes a certain number
of git SHAs per token. This allows for perusal of the most recent
changes for a given token to understand what changed.
2016-06-21 23:02:37 -04:00
Joshua Clayton
ce9b3b8a13 Store computed aliases on TermResults 2016-06-21 06:12:40 -04:00
Joshua Clayton
a6e926e4d2 Move thread management to app wrapper
Why?
====

With multiple calls to `parallel`, `stopGlobalPool` stops working
correctly.

This moves `stopGlobalPool` higher up, and executes it once, allowing
multiple calls to `parallel` to happen without causing issues.
2016-06-21 06:10:18 -04:00
Joshua Clayton
a5b8f31e4d Use internal CacheFileName newtype for referencing where the cache lives 2016-06-16 07:04:37 -04:00
Joshua Clayton
cfa194b936 Roll up App into a monad transformer stack
This introduces a monad transformer stack to cover our reader (options
from the CLI) and except (for handling failure cases, initially missing
tags or invalid config).

This ensures errors are bubbled up appropriately (and halt program
execution) and the Options are available in the correct locations within
the app.

This also separates options parsing (which remains in app/Main.) from
translating those options into the correctly executed runner and
generated output.
2016-06-16 06:12:29 -04:00
Joshua Clayton
9ddbd0949c Rename to AppError and Main.hs code reorganization 2016-06-12 04:44:51 -04:00
Joshua Clayton
07c0fb0d3f Move away from regexes for basic String matching
This leverages simpler tests to determine matches over regular
expressions
2016-06-11 06:58:28 -04:00
Joshua Clayton
9b58030110 Replace custom lift with liftIO 2016-06-11 06:10:57 -04:00
Joshua Clayton
f7421079f3 Fail inside the context of a monad instead of erroring 2016-06-11 06:08:51 -04:00
Joshua Clayton
9c4f411168 Remove reference to unsupported config matcher 2016-06-11 06:05:29 -04:00
Joshua Clayton
85b6914f11 Bump version to 0.4.0.0 2016-06-10 07:05:58 -04:00
Joshua Clayton
764b21b798 Update Cabal category to CLI 2016-06-10 07:04:14 -04:00
Joshua Clayton
58e219eb2e Allow developer-authored configurations
This enables per-user and per-project configs, located in:

* ~/.unused.yml
* APP_ROOT/.unused.yml

Configurations stack upon each other, not replace; unused provides a
very base config, but additional configurations can be defined.

Per-user configs are best used to suit common types of projects at a
generic level. For example, a developer commonly working in Rails
applications might have a config at ~/.unused.yml for patterns like
Policy objects from Pundit, ActiveModel::Serializers, etc.

Per-project config would be less-generic patterns, ones where re-use
isn't likely or applicable.

See unused's global config:
https://github.com/joshuaclayton/unused/blob/master/data/config.yml

The structure is as follows:

    - name: Rails
      autoLowLikelihood:
        - name: Pundit
          pathStartsWith: app/policies
          pathEndsWith: .rb
          termEndsWith: Policy
          classOrModule: true
        - name: Pundit Helpers
          pathStartsWith: app/policies
          allowedTerms:
            - Scope
            - index?
            - new?
            - create?
            - show?
            - edit?
            - destroy?
            - resolve
    - name: Other Language
      autoLowLikelihood:
        - name: Thing
          pathEndsWith: .ex
          classOrModule: true

Name each item, and include an autoLowLikelihood key with multiple named
matchers. Each matcher can look for various formatting aspects,
including termStartsWith, termEndsWith, pathStartsWith, pathEndsWith,
classOrModule, and allowedTerms.
2016-06-10 06:16:41 -04:00
Joshua Clayton
5590f5fc4c Update cabalfile to reflect correct version
Version 0.3.0.0 was released in
9cc640aef747b9179e35104610bb869398df31ac; however, unused.cabal wasn't
updated.
2016-06-10 05:33:52 -04:00
Joshua Clayton
f8e020b831 Be more modular about exporting ResultsClassifier functions 2016-06-09 09:01:07 -04:00
Joshua Clayton
ad9308a672 Encapsulate runtime config into a withRuntime wrapper 2016-06-09 06:44:18 -04:00
Joshua Clayton
09231cdccd Cover case within autoLowLikelihood where no matches are present
Why?
====

In cases where no matchers are present, a language config should not
auto-classify every match as low-likelihood; instead, it should return
False so subsequent checks can operate on the match itself.

This is related to 9bf9499e67f52bcde2420bfe3945f73cfdaa06d7; both are
handling cases where less configuration data than ideal is present and
the program still needs to operate correctly.
2016-06-07 05:19:40 -04:00
Joshua Clayton
8a294a6acc Don't cache an empty list of matches
Why?
====

If a list of matches is empty, there's no reason to cache it.
2016-06-05 08:09:52 -04:00
Joshua Clayton
9bf9499e67 Ensure results work when no config can be loaded
Why?
====

If no config can be loaded correctly, unused should still function
correctly, albeit with likely more false positives.
2016-06-05 08:09:02 -04:00
Joshua Clayton
54e55c46a2 Add missing spec name to unused.cabal 2016-06-05 07:42:18 -04:00
Joshua Clayton
5c4e0c1ccd Allow allowedTerms and autoLowLikelihood to be optional configs 2016-06-04 08:11:47 -04:00
Joshua Clayton
9cc640aef7 Bump to 0.3.0.0 2016-06-04 06:53:53 -04:00
Joshua Clayton
7c26ae8e72 Move withoutCursor to wrap run
Why?
====

If parsing options fails, the program will exit; if
withoutCursor has been called prior to execParser, the program may exit
without any way to re-enable the cursor. This can cause confusion and
frustration for users.
2016-06-04 06:52:01 -04:00
Joshua Clayton
0505b4bff3 Re-enable cache by default
Why?

With SHA fingerprinting speeds improved drastically by
f618d8a796, we can now re-enable
caching by default.

This introduces a -C flag to disable the cache for a run.

Note that the cache is always invalidated when files are modified.
2016-06-04 06:44:41 -04:00
Joshua Clayton
792d0dca05 Minor reorganization within Main.hs 2016-06-02 08:22:53 -04:00
Joshua Clayton
6ffb098b20 Initial support of aliases based on wildcard matching
Why?
====

Dynamic languages, and Rails in particular, support some fun method
creation. One common pattern is, within RSpec, to create matchers
dynamically based on predicate methods. Two common examples are:

* `#admin?` gets converted to the matcher `#be_admin`
* `#has_active_todos?` gets converted to the matcher `#have_active_todos`

This especially comes into play when writing page objects with predicate
methods.

This change introduces the concept of aliases, a way to describe the
before/after for these transformations. This introduces a direct swap
with a wildcard value (%s), although this may change in the future to
support other transformations for pluralization, camel-casing, etc.

Externally, aliases are not grouped together by term; however, the
underlying counts are summed together, increasing the total occurrences
and likely pushing the individual method out of "high" likelihood into
"medium" or "low" likelihood.

Closes #19.
2016-06-01 22:16:44 -04:00
Joshua Clayton
0dcb06fe70 Incorporate hlint suggestions 2016-06-01 05:36:32 -04:00
Joshua Clayton
95836e536b Use isPrefixOf and isSuffixOf for simple start/end matches over regex 2016-05-29 16:33:05 -04:00
Joshua Clayton
ef0fb49841 Classify Phoenix controller actions as always low-likelihood 2016-05-27 15:01:33 -04:00
Joshua Clayton
965cc0a178 Move allowedTerms into auto low-likelihood classification
Why?
====

This ensures no method/function bleed between languages, which may cause
confusing miscalculation when methods/functions are reused across
different types of projects (e.g. index from Rails migrations and index
action from Phoenix controllers).
2016-05-27 15:01:33 -04:00
Joshua Clayton
6eb2e38882 Use ReaderT for ColumnFormatter
Why?
====

When printing results, the column formatter has to be configured at the
topmost level (where it has all result data) to calculate widths
appropriately; however, it's only used layers deep, when rendering the
columns themselves.

This moves the formatter into a ReaderT so the configuration can be
passed around appropriately.
2016-05-27 11:17:48 -04:00
Joshua Clayton
4dfd788318 Extract views to a Views module
Why?
====

View logic was scattered all over the place; this introduces a views
module to encapsulate any corresponding view work into one spot.
2016-05-27 06:11:52 -04:00
Joshua Clayton
1b945eba18 Update image to demonstrate usage 2016-05-27 06:10:50 -04:00
Joshua Clayton
2a74a807ac Bump to LTS 6.0 2016-05-26 22:24:28 -04:00
Joshua Clayton
0d2470815d Simplify parsing and caching of results
Why?
====

Parsec is overkill when all that's really needed is splitting on
semicolons and converting a string to a non-negative Int.

One side-effect of this is to convert the caching mechanism from flat
text to CSV, with cassava handling (de-)serialization.

Additional
==========

Introduce ReaderT to calculate sha once per cache interaction

Previously, we were calculating the fingerprint (SHA) for match results
potentially twice, once when reading from the cache, and a second time
if no cache was found. This introduces a ReaderT to manage cache
interaction with a single fingerprint calculation.

This also abstracts what's being cached to only care about the fact that
the data can be converted to/from csv.
2016-05-26 21:37:11 -04:00
Joshua Clayton
f618d8a796 Use .gitignore to determine files for fingerprinting a project
Why?
====

Because a .gitignore file captures a fair number of project-specific
directories and files to ignore, we can use this list to reduce the
number of files to look at when determining a fingerprint for a project.

Because the fingerprint should be based on files we care about changing,
the project-specific .gitignore is a great place to start.

This drastically reduces fingerprint timing - for larger projects, or
projects with a massive number of files (e.g. anything doing anything
significant with NPM and a front-end framework), this will help make
caching usable. For normal projects, this cuts fingerprint
calculation to 10%-20% of what it was previously.

Closes #38
2016-05-26 17:19:35 -04:00
Joshua Clayton
279cdfa494 Be more flexible with progress indicator types 2016-05-26 05:56:24 -04:00