Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
os:
- ubuntu-latest
- macOS-latest
- windows-latest
# - windows-latest
steps:
- name: setup rust
run: |
Expand Down
37 changes: 13 additions & 24 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,33 @@ jobs:
- name: Git Tag name
id: vars
run: |
# 後から参照するために、タグ名とアプリケーション名を出力しておく。
# タグ名は、ブランチ名から 'releases/v' を取り除いたもの。
# アプリケーション名は、リポジトリ名からオーナー名を取り除いたもの。
# $GITHUB_OUTPUT に出力することで、後続のジョブから参照できるようになる。
echo "tag=${GITHUB_HEAD_REF##*/v}" >> $GITHUB_OUTPUT
echo "appname=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT

- name: Set git identity
run: |
# git tag を push するので、git のユーザ名とメールアドレスを設定しておく。
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Create and Push tag
run: |
# タグを作成して、リモートに push する。
git tag v${{ steps.vars.outputs.tag }}
git push origin v${{ steps.vars.outputs.tag }}

- name: Create release
env:
GH_TOKEN: ${{ github.token }}
run: |
# gh コマンドを使って、リリースを作成する。
# draft として作成する。後続のジョブで、ドラフトを false にする。
gh release create v${{ steps.vars.outputs.tag }} --verify-tag --generate-notes --title "Release v${{ steps.vars.outputs.tag }}" --draft

# - name: Create release
# id: create_release
# uses: actions/create-release@v1.0.0
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# with:
# tag_name: v${{ steps.vars.outputs.tag }}
# release_name: Release v${{ steps.vars.outputs.tag }}
# draft: true
# prerelease: false

publish:
runs-on: ${{ matrix.os }}
needs: setup
Expand All @@ -76,18 +73,6 @@ jobs:
os_name: linux
artifact_name: ${{ needs.setup.outputs.appname }}
ext: ''
# - os: ubuntu-latest
# architecture: arm64
# os_name: windows
# target: aarch64-pc-windows-gnullvm
# artifact_name: ${{ needs.setup.outputs.appname }}-cli.exe
# ext: '.exe'
# - os: ubuntu-latest
# architecture: amd64
# os_name: windows
# target: x86_64-pc-windows-gnu
# artifact_name: ${{ needs.setup.outputs.appname }}-cli.exe
# ext: '.exe'
- os: macos-latest
target: aarch64-apple-darwin
architecture: arm64
Expand Down Expand Up @@ -117,10 +102,12 @@ jobs:
rustup update stable
rustup target add ${{ matrix.target }}
cargo install cargo-zigbuild
# zigbuild を使って、クロスコンパイルする。
cargo zigbuild --release --target ${{ matrix.target }}

- name: Create distribution files.
run: |
# 配布用のファイルを作成する。
ASSET_NAME=${{ needs.setup.outputs.appname }}-${{ needs.setup.outputs.tag}}_${{ matrix.architecture }}_${{ matrix.os_name }}
mkdir -p dist/$ASSET_NAME
cp target/${{ matrix.target }}/release/${{ needs.setup.outputs.appname }}${{ matrix.ext }} dist/$ASSET_NAME/
Expand All @@ -131,14 +118,15 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
# gh コマンドを使って、リリースにアセットをアップロードする。
ASSET_NAME=${{ needs.setup.outputs.appname }}-${{ needs.setup.outputs.tag}}_${{ matrix.architecture }}_${{ matrix.os_name }}
gh release upload v${{ needs.setup.outputs.tag }} dist/${ASSET_NAME}.tar.gz

finalize:
runs-on: ubuntu-latest
permissions:
contents: write
needs: publish
needs: publish # publish ジョブが完了した後に実行される。
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -150,4 +138,5 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
# gh コマンドを使って、ドラフトを false にする(release が immutable であれば、これ以降変更できない)。
gh release edit v${{ needs.publish.outputs.tag }} --draft=false
2 changes: 1 addition & 1 deletion .github/workflows/update-version.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
echo "tag=${GITHUB_REF##**/v}" >> $GITHUB_OUTPUT

- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ steps.vars.outputs.branch }}
fetch-depth: 0
Expand Down
19 changes: 19 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,22 @@ version = "0.0.10"
edition = "2024"

[dependencies]
clap = { version = "4.5", features = ["derive"] }
chrono = "0.4"
humansize = "2.1"
uzers = "0.12"
git2 = "0.19"
ignore = "0.4"
lscolors = "0.19"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"
csv = "1.3"
terminal_size = "0.4"
unicode-width = "0.2"
colored = "2.1"
nix = { version = "0.29", features = ["fs", "user"] }

Comment on lines +7 to +22
[[bin]]
name = "lis"
path = "cli/main.rs"
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,44 @@ It is not intended for production use.

## 🗣️ Overview

`lis` provides a library and a CLI tool for listing directory entries with advanced features like Git status, icons, and multiple output formats.

## 🚀 Features

- List entries in specified directories.
- Support for sorting (name, time, size, extension) and reverse order.
- Long format with detailed information, including **Git status**.
- Support for hidden files, respecting `.gitignore`.
- Display icons for each entry based on file type and extension.
- Multiple output formats: `plain`, `csv`, `json`, and `yaml`.
- Support for `LS_COLORS` environment variable.

## 📖 Library Usage

Add `lis` to your `Cargo.toml`. Then use it as follows:

```rust
use lis::Lis;
use std::path::PathBuf;

fn main() {
let entries = Lis::new(PathBuf::from("."))
.recursive(true)
.all(true)
.list();

for entry in entries {
println!("{:<10} {}", entry.mode, entry.name);
}
}
```

Check the [examples](examples/) directory for more details.

## 💻 CLI Usage

See [cli/README.md](cli/README.md) for more details.

## ℹ️ About

### 👨‍💼​ Developers 👩‍💼
Expand Down
52 changes: 52 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 💻 lis CLI Tool

`lis` is a command-line interface for listing directory entries with advanced features.

## 🛠️ Installation

```bash
cargo install --path .
```

## 🚀 Usage

```bash
lis [OPTIONS] [PATH]
```

### ⚙️ Options

- `-l`, `--long`: Display in long format with details.
- `--sort <SORT>`: Sort entries by `name` (default), `time`, `size`, or `extension`.
- `--reverse`: Reverse the sort order.
- `-a`, `--all`: List all entries, respecting `.gitignore`.
- `-A`, `--whole-all`: List all entries, ignoring `.gitignore`.
- `--icon`: Display icons for each entry.
- `--format <FORMAT>`: Specify output format: `plain` (default), `csv`, `json`, or `yaml`.
- `-R`, `--recursive`: List entries recursively.

### 🌟 Examples

- **List current directory in long format with icons:**
```bash
lis -l --icon
```

- **List current directory recursively in JSON format:**
```bash
lis -R --format json
```

- **List all entries (including hidden) sorted by size:**
```bash
lis -a --sort size
```

- **List hidden files ignoring `.gitignore`:**
```bash
lis -A
```

## 📖 Specifications

The detailed specification of `lis` can be found in [.github/assets/spec.md](../.github/assets/spec.md).
85 changes: 85 additions & 0 deletions cli/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use clap::{Parser, ValueEnum};
use lis::entry::SortBy;
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
/// Directory to list
#[arg(default_value = ".")]
pub path: PathBuf,

/// Sort by
#[arg(long, value_enum, default_value_t = SortBy::Name)]
pub sort: SortBy,

/// Reverse sort order
#[arg(short, long)]
pub reverse: bool,

/// Long format
#[arg(short, long)]
pub long: bool,

/// All entries, respecting .gitignore
#[arg(short, long)]
pub all: bool,

/// All entries, ignoring .gitignore
#[arg(short = 'A', long)]
pub whole_all: bool,

/// Display icons
#[arg(long)]
pub icon: bool,

/// Output format
#[arg(long, value_enum, default_value_t = Format::Plain)]
pub format: Format,

/// Recursive listing
#[arg(short = 'R', long)]
pub recursive: bool,
}

#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
pub enum Format {
Plain,
Csv,
Json,
Yaml,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_args_default() {
let args = Args::try_parse_from(["lis"]).unwrap();
assert_eq!(args.path, PathBuf::from("."));
assert_eq!(args.sort, SortBy::Name);
assert!(!args.reverse);
assert!(!args.long);
assert!(!args.all);
assert!(!args.whole_all);
assert_eq!(args.format, Format::Plain);
}

#[test]
fn test_args_custom() {
let args = Args::try_parse_from([
"lis", "src", "--sort", "size", "-r", "-l", "-a", "--icon", "--format", "json", "-R",
])
.unwrap();
assert_eq!(args.path, PathBuf::from("src"));
assert_eq!(args.sort, SortBy::Size);
assert!(args.reverse);
assert!(args.long);
assert!(args.all);
assert!(args.icon);
assert_eq!(args.format, Format::Json);
assert!(args.recursive);
}
}

Loading