Skip to content

RyderFreeman4Logos/mvln

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mvln

Move files and create symlinks at their original locations.

mvln is a command-line utility that moves files or directories to a new location while preserving access at the original path through symbolic links. This is particularly useful when reorganizing files while maintaining compatibility with tools or scripts that expect files at their original locations.

Features

  • Transparent File Movement: Move files while preserving access through symlinks
  • Glob Pattern Support: Move multiple files matching patterns (e.g., *.txt)
  • Directory Handling: Move entire directories with the -w/--whole-dir flag
  • Flexible Symlink Modes: Create relative (default) or absolute symlinks
  • Force Overwrite: Replace existing destinations with -f/--force
  • Internationalization: Supports multiple languages based on system locale
  • Safe Operations: Type-checked operations prevent unsafe cross-type replacements
  • Verbose Mode: Detailed operation logging with -v/--verbose

Installation

cargo install --locked --git https://github.com/RyderFreeman4Logos/mvln

Usage

Basic Syntax

mvln [OPTIONS] <SOURCE>... <DESTINATION>

Examples

Move a Single File

# Move file.txt to /backup/, create symlink at original location
mvln file.txt /backup/

# Result:
# - /backup/file.txt (actual file)
# - file.txt -> ../backup/file.txt (symlink)

Move Multiple Files

# Move all .log files to archive/
mvln *.log archive/

# Each .log file is replaced with a symlink pointing to archive/

Move a Directory

# Move entire directory (requires -w flag)
mvln -w ./old_project /archive/

# Result:
# - /archive/old_project/ (moved directory)
# - ./old_project -> ../archive/old_project (symlink)

Use Absolute Symlinks

# Create absolute symlinks instead of relative
mvln -a config.toml /etc/myapp/

# Result:
# - /etc/myapp/config.toml (actual file)
# - config.toml -> /etc/myapp/config.toml (absolute symlink)

Force Overwrite

# Replace existing destination file (same type only)
mvln -f new_version.bin /usr/local/bin/tool.bin

# Replaces existing tool.bin with new_version.bin

Verbose Output

# Show detailed operation information
mvln -v data.db /mnt/storage/

# Output:
# mv data.db /mnt/storage/
# ln -s ../mnt/storage/data.db data.db
# Moving: data.db -> /mnt/storage/data.db
# Creating symlink: data.db -> ../mnt/storage/data.db
# Completed: 1 file(s) moved, 1 symlink(s) created

Command-Line Options

Option Short Description
--relative -r Create relative symlinks (default behavior)
--absolute -a Create absolute symlinks instead of relative
--whole-dir -w Move entire directory instead of contents
--verbose -v Enable verbose output
--force -f Overwrite existing destination (same type only)
--help -h Display help information
--version -V Display version information

Behavior Details

Symlink Path Resolution

Default (Relative Mode):

  • Symlinks use relative paths from the original location
  • Portable across different mount points
  • Example: file.txt -> ../backup/file.txt

Absolute Mode (-a):

  • Symlinks use absolute paths
  • More robust when moving symlinks themselves
  • Example: file.txt -> /home/user/backup/file.txt

Directory Handling

By default, mvln rejects directory sources to prevent accidental moves. Use the -w/--whole-dir flag to explicitly move directories:

# Without -w: Error
mvln my_dir /backup/
# Error: my_dir is a directory, use -w/--whole-dir flag

# With -w: Success
mvln -w my_dir /backup/
# my_dir is moved to /backup/my_dir, symlink created

Force Overwrite Rules

The -f/--force flag allows overwriting existing destinations with the following constraints:

  • File → File: Allowed (replaces destination file)
  • Directory → Directory: Allowed (merges into destination directory)
  • File → Directory: Moves file into directory (standard behavior)
  • Directory → File: Rejected (type mismatch)

Glob Pattern Expansion

mvln natively supports glob patterns:

# Move all .txt files
mvln *.txt archive/

# Move files matching pattern
mvln report_202*.pdf /backup/reports/

# Multiple patterns
mvln *.log *.txt /archive/

Error Recovery

If symlink creation fails after moving a file, mvln provides a recovery command:

Error: Failed to create symlink at file.txt

File was successfully moved to /backup/file.txt
To recover the original state, run:
  mv /backup/file.txt file.txt

Internationalization

mvln supports multiple languages based on your system locale:

  • English (en)
  • Chinese Simplified (zh-CN)
  • (More languages can be added via Fluent translation files)

Messages, error descriptions, and hints are automatically localized.

Platform Support

  • Unix/Linux: Full support
  • macOS: Full support
  • Windows: Limited (symbolic link creation may require administrator privileges)

Safety Guarantees

  • Type Safety: Prevents replacing files with directories and vice versa (unless moving into a directory)
  • No Unsafe Code: The codebase forbids unsafe blocks
  • Atomic Operations: File moves use filesystem primitives for atomicity
  • Symlink Validation: Verifies symlink creation and target resolution

Concurrency Warning

⚠️ Do not use mvln in highly concurrent modification environments.

For cross-filesystem moves, mvln uses a copy-then-remove strategy. There is an inherent TOCTOU (Time-of-Check Time-of-Use) race condition window between verifying the copy succeeded and removing the source. If another process modifies or deletes the destination during this window, data loss may occur.

For single-user, non-concurrent workflows (the typical CLI use case), this is not a concern. For automated pipelines with concurrent file access, consider using filesystem-level locking or atomic rename operations instead.

Use Cases

Reorganizing Large Codebases

# Move source files to organized directory structure
mvln -w src/ archive/2024-01-backup/
# src/ is now a symlink, builds still work

Log Rotation

# Move logs to archive while preserving access
mvln /var/log/app.log /archive/logs/
# /var/log/app.log -> /archive/logs/app.log

Configuration Management

# Move config to system location, keep local access
mvln -a config.toml /etc/myapp/
# config.toml -> /etc/myapp/config.toml (absolute)

Building from Source

Prerequisites

  • Rust 2021 edition or later
  • just command runner

Build Commands

# Debug build
just build

# Release build
just build-release

# Run all tests
just test

# Run linter (Clippy)
just clippy

# Run all pre-commit checks (format, clippy, test)
just pre-commit

# Install locally
just install

Development

Project Structure

mvln/
├── src/
│   ├── main.rs          # CLI entry point
│   ├── cli.rs           # Argument parsing
│   ├── lib.rs           # Library exports
│   ├── operation.rs     # Core move-and-link logic
│   ├── path_utils.rs    # Path computation utilities
│   ├── glob_expand.rs   # Glob pattern expansion
│   ├── error.rs         # Error types
│   └── i18n.rs          # Internationalization
├── tests/
│   ├── integration.rs   # Integration tests
│   └── safety.rs        # Safety tests
└── Cargo.toml

Running Tests

# All tests
just test

# Integration tests only
just test-integration

# With output
just test-verbose

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Run pre-commit checks (just pre-commit)
  4. Commit with clear messages (Conventional Commits format)
  5. Push to your fork and submit a pull request

License

This project is licensed under the MIT License. See LICENSE for details.

Acknowledgments

Links

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •