fix merge conflict
This commit is contained in:
parent
dc0260c20c
commit
fadaa837fb
538 changed files with 6 additions and 20498 deletions
|
|
@ -1,2 +1,5 @@
|
|||
**/original_*
|
||||
.config/lazygit/state.yml
|
||||
|
||||
config/tmux/plugins/*
|
||||
!config/tmux/plugins/.gitkeep
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@
|
|||
"LuaSnip": { "branch": "master", "commit": "ce0a05ab4e2839e1c48d072c5236cce846a387bc" },
|
||||
"alpha-nvim": { "branch": "main", "commit": "41283fb402713fc8b327e60907f74e46166f4cfd" },
|
||||
"auto-session": { "branch": "main", "commit": "4b0728715e674ad9c18f1519127dcaed59f9981b" },
|
||||
"ccc.nvim": { "branch": "main", "commit": "4fb5abaef2f2e0540fe22d4d74a9841205fff9e4" },
|
||||
"chezmoi.nvim": { "branch": "main", "commit": "faf61465718424696269b2647077331b3e4605f1" },
|
||||
"chezmoi.vim": { "branch": "main", "commit": "10f2692791b5e512a2c1bb4dc560b42ca5bf71fd" },
|
||||
"cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" },
|
||||
"cmp-cmdline": { "branch": "main", "commit": "d250c63aa13ead745e3a40f61fdd3470efde3923" },
|
||||
"cmp-conventionalcommits": { "branch": "master", "commit": "a4dfacf0601130b7f8afa7c948d735c27802fb7f" },
|
||||
|
|
@ -14,14 +11,13 @@
|
|||
"cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" },
|
||||
"cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" },
|
||||
"comment-box.nvim": { "branch": "main", "commit": "06bb771690bc9df0763d14769b779062d8f12bc5" },
|
||||
"conform.nvim": { "branch": "master", "commit": "0ebe875d9c306f5fc829db38492ffff2a70d8e9d" },
|
||||
"conform.nvim": { "branch": "master", "commit": "cd75be867f2331b22905f47d28c0c270a69466aa" },
|
||||
"debugprint.nvim": { "branch": "main", "commit": "8f2a335fb0e6ebf0291a3551e0198363437e3a38" },
|
||||
"diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" },
|
||||
"dressing.nvim": { "branch": "master", "commit": "6741f1062d3dc6e4755367a7e9b347b553623f04" },
|
||||
"flash.nvim": { "branch": "main", "commit": "d0799ae43a581d9f190e182e2a1f389d2887c42a" },
|
||||
"friendly-snippets": { "branch": "main", "commit": "45a1b96e46efe5fce8af325d4bed45feb9d29d0f" },
|
||||
"gitsigns.nvim": { "branch": "main", "commit": "e9c4187c3774a46df2d086a66cf3a7e6bea4c432" },
|
||||
"gopher.nvim": { "branch": "main", "commit": "f55c15ada8e02398000c04a96ef44d986cd01051" },
|
||||
"grapple.nvim": { "branch": "main", "commit": "7aedc261b05a6c030397c4bc26416efbe746ebf1" },
|
||||
"hurl.nvim": { "branch": "main", "commit": "d708158dda9a175c0f83cd106ea232301f4317cb" },
|
||||
"indent-blankline.nvim": { "branch": "master", "commit": "65e20ab94a26d0e14acac5049b8641336819dfc7" },
|
||||
|
|
@ -65,13 +61,9 @@
|
|||
"trouble.nvim": { "branch": "main", "commit": "03c1fbf518bef683422a3be9643c3da190903488" },
|
||||
"ts-node-action": { "branch": "master", "commit": "6d3b60754fd87963d70eadaa2f77873b447eac26" },
|
||||
"twilight.nvim": { "branch": "main", "commit": "2b632c169a4b51b1eba5be90fde22a80c51c990e" },
|
||||
"typescript-tools.nvim": { "branch": "master", "commit": "5da4d695d66f676eb6ea766b946e86f93baaafe7" },
|
||||
"undotree": { "branch": "master", "commit": "56c684a805fe948936cda0d1b19505b84ad7e065" },
|
||||
"vim-dadbod": { "branch": "master", "commit": "7888cb7164d69783d3dce4e0283decd26b82538b" },
|
||||
"vim-dadbod-completion": { "branch": "master", "commit": "8c9051c1cfc73fcf5bfe9a84db7097e4f7c0180d" },
|
||||
"vim-dadbod-ui": { "branch": "master", "commit": "f74a31e8c6c5a9dccc63450a09d5cd64a9294330" },
|
||||
"vim-illuminate": { "branch": "master", "commit": "5eeb7951fc630682c322e88a9bbdae5c224ff0aa" },
|
||||
"vim-sleuth": { "branch": "master", "commit": "1cc4557420f215d02c4d2645a748a816c220e99b" },
|
||||
"zen-mode.nvim": { "branch": "main", "commit": "2694c5a2bc4dc26c7a9e74b9e2b812920c90a830" },
|
||||
"zk-nvim": { "branch": "main", "commit": "dbf4eeab55b08856c9d6b6722dbff39630bb35eb" }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
# extrakto help
|
||||
|
||||
You can give feedback or star extrakto at https://github.com/laktak/extrakto
|
||||
|
||||
Extrakto uses fzf. You only need to type a few keys to find your selection with a fuzzy match.
|
||||
|
||||
- Press *ctrl-f* to change to the next filter mode (*filter_key*)
|
||||
- *word*, the default filter allows you to select words (min length=5)
|
||||
- *all*, runs all filters and allows you select quotes, url, paths, etc. \
|
||||
You can define your own filters as well.
|
||||
- *line*, select full lines
|
||||
|
||||
- Press *ctrl-g* to change the grab are (see *grab_key* and configuration)
|
||||
- *full*, everything from the current pane
|
||||
- *window full*, everything from all panes in this window
|
||||
- *recent*, everything visible with a few lines from the history (current pane)
|
||||
- *window recent*, everything visible with a few lines from the history (window)
|
||||
|
||||
- Press *esc* or *ctrl-c* to cancel
|
||||
|
||||
- Use *shift-tab* to select multiple entries.
|
||||
|
||||
Actions that use the current selection:
|
||||
|
||||
- Press *tab* to insert the selection into the active tmux pane (*insert_key*).
|
||||
|
||||
- Press *enter* to copy the selection to the clipboard (*copy_key*).
|
||||
|
||||
- Press *ctrl-o* to pass the selection to the *open* command of your OS (*open_key*). \
|
||||
For example if you select a URL this will open the browser.
|
||||
|
||||
- Press *ctrl-e* to open the selection in your $EDITOR (*edit_key*). \
|
||||
This only makes sense if you select a path and if you are currently in a shell. \
|
||||
extrakto will send the command to launch the editor to your active pane.
|
||||
|
||||
You can change most keys, define your own filters and change other configuration options. Please see the GitHub readme for instructions.
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 Christian Zangl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
# extrakto for tmux
|
||||
|
||||

|
||||
|
||||
**Output completions** - you can complete commands that require you to retype text that is already on the screen. This works everywhere, even in remote ssh sessions.
|
||||
|
||||
You can **fuzzy find your text** instead of selecting it by hand:
|
||||
|
||||
- press tmux `prefix + tab` to start extrakto
|
||||
- fuzzy find the text/path/url/line
|
||||
- use custom filters (`ctrl + f`)
|
||||
- press
|
||||
- `tab` to insert it to the current pane,
|
||||
- `enter` to copy it to the clipboard,
|
||||
- see other features in [HELP](HELP.md) (press `ctrl-h` in extrakto)
|
||||
|
||||
Use it for paths, URLs, options from a man page, git hashes, docker container names, ...
|
||||
|
||||
## Requirements
|
||||
|
||||
- [tmux](https://github.com/tmux/tmux) - popups require 3.2, otherwise extrakto will open in a split window.
|
||||
- [fzf](https://github.com/junegunn/fzf)
|
||||
- Python 3.6+
|
||||
- Bash (tested with 5.0+, on macOS please `brew install bash` first)
|
||||
see the [Wiki for Bash 4 support](https://github.com/laktak/extrakto/wiki/Bash4)
|
||||
|
||||
Supported clipboards:
|
||||
|
||||
- Linux Xorg (xclip) and Wayland (wl-copy)
|
||||
- macOS (pbcopy)
|
||||
- WSL (aka "Bash on Windows")
|
||||
- *bring your own*, see the [Wiki](https://github.com/laktak/extrakto/wiki/) for examples (like termux)
|
||||
|
||||
## Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm)
|
||||
|
||||
Add the plugin to the list of TPM plugins in `.tmux.conf`:
|
||||
|
||||
set -g @plugin 'laktak/extrakto'
|
||||
|
||||
Hit `prefix + I` to fetch the plugin and source it.
|
||||
|
||||
You should now have all `extrakto` key bindings defined.
|
||||
|
||||
## Manual Installation
|
||||
|
||||
Clone the repo:
|
||||
|
||||
$ git clone https://github.com/laktak/extrakto ~/clone/path
|
||||
|
||||
Add this line to the bottom of `.tmux.conf`:
|
||||
|
||||
run-shell ~/clone/path/extrakto.tmux
|
||||
|
||||
Reload the tmux environment:
|
||||
|
||||
# type this in terminal
|
||||
$ tmux source-file ~/.tmux.conf
|
||||
|
||||
You should now have all `extrakto` key bindings defined.
|
||||
|
||||
## Wiki
|
||||
|
||||
Add or look for special tips in our [wiki](https://github.com/laktak/extrakto/wiki).
|
||||
|
||||
## Options
|
||||
|
||||
To set any of these options write on your `~/.tmux.conf` file:
|
||||
|
||||
```
|
||||
set -g <option> "<value>"
|
||||
```
|
||||
|
||||
Where `<option>` and `<value>` are one of the specified here below
|
||||
|
||||
### Common Options
|
||||
|
||||
| Option | Default | Description |
|
||||
| :--- | :---: | :--- |
|
||||
| `@extrakto_grab_area` | `window full` | Whether you want extrakto to grab data from the `recent` area, the `full` pane, all current window's (`window recent`) areas or all current window's (`window full`) panes. You can also set this option to any number you want (or number preceded by "window ", e.g. "window 500"), this allows you to grab a smaller amount of data from the pane(s) than the pane's limit. For instance, you may have a really big limit for tmux history but using the same limit may end up on having slow performance on Extrakto. |
|
||||
| `@extrakto_filter_order` | `word all line` | Filter modes order. The first listed mode will be the default when opening extrakto. You may use `word`, `line`, `path`, `url`, `quote`, `s-quote` or any of your own filters separated by a space. `all` applies all filters at the same time. |
|
||||
|
||||
### Keys
|
||||
|
||||
| Option | Default | Description |
|
||||
| :--- | :---: | :--- |
|
||||
| `@extrakto_key` | `tab` | The key binding to start. If you have any special requirements (like a custom key table) set this to 'none' and define a binding in your `.tmux.conf`. See `extrakto.tmux` for a sample. |
|
||||
| `@extrakto_copy_key` | `enter` | Key to copy selection to clipboard. |
|
||||
| `@extrakto_insert_key` | `tab` | Key to insert selection. |
|
||||
| `@extrakto_filter_key` | `ctrl-f` | Key to toggle filter mode. |
|
||||
| `@extrakto_grab_key` | `ctrl-g` | Key to toggle grab mode. |
|
||||
| `@extrakto_edit_key` | `ctrl-e` | Key to run the editor. |
|
||||
| `@extrakto_open_key` | `ctrl-o` | Key to run the open command. |
|
||||
|
||||
All but `@extrakto_key` are controlled by fzf and must follow its conventions.
|
||||
|
||||
### Advanced Options
|
||||
|
||||
| Option | Default | Description |
|
||||
| :--- | :---: | :--- |
|
||||
| `@extrakto_clip_tool_run` | `bg` | Set this to `tmux_osc52` to enable [remote clipboard support](https://github.com/laktak/extrakto/wiki/Remote-Copy-via-OSC52) or `fg`/`bg` to have your clipboard tool run in a foreground/background shell. |
|
||||
| `@extrakto_clip_tool` | `auto` | Set this to whatever clipboard tool you would like extrakto to use to copy data into your clipboard. `auto` will try to choose the correct clipboard for your platform. |
|
||||
| `@extrakto_editor` | | This defaults to `$EDITOR` if not set. |
|
||||
| `@extrakto_fzf_layout` |`default` | Control the fzf layout which is "bottom-up" by default. If you prefer "top-down" layout instead set this to `reverse`. In fact, this value is passed to the fzf `--layout` parameter. Possible values are: `default`, `reverse` and `reverse-list` |
|
||||
| `@extrakto_fzf_tool` | `fzf` | Set this to path of fzf if it can't be found in your `PATH`. |
|
||||
| `@extrakto_fzf_unset_default_opts` | `true` | Unsets custom FZF_DEFAULT_OPTS as it can potentially cause problems in extrakto operations |
|
||||
| `@extrakto_open_tool` | `auto` | Set this to path of your own tool or `auto` to use your platforms *open* implementation. |
|
||||
| `@extrakto_popup_position` | `C` | Set position of the tmux popup window. Possible values are in the `display-popup` entry in `man tmux`. Set this to `x,y` to set the x and y positions to `x` and `y` respectively. |
|
||||
| `@extrakto_popup_size` | `90%` | Set width and height of the tmux popup window. Set this to `w,h` to set the width to `w` and height to `h`. |
|
||||
| `@extrakto_split_direction` | `a` | Whether the tmux split will be `a`uto, `p`opup, `v`ertical or `h`orizontal |
|
||||
| `@extrakto_split_size` | `7` | The size of the tmux split (for vertical/horizontal) |
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
set -g @extrakto_split_size "15"
|
||||
set -g @extrakto_clip_tool "xsel --input --clipboard" # works better for nvim
|
||||
set -g @extrakto_copy_key "tab" # use tab to copy to clipboard
|
||||
set -g @extrakto_insert_key "enter" # use enter to insert selection
|
||||
set -g @extrakto_fzf_unset_default_opts "false" # keep our custom FZF_DEFAULT_OPTS
|
||||
```
|
||||
|
||||
## Custom Filters
|
||||
|
||||
You can define your own filters by creating a file in `~/.config/extrakto/extrakto.conf`:
|
||||
|
||||
```
|
||||
[quote]
|
||||
regex: ("[^"\n\r]+")
|
||||
```
|
||||
|
||||
To override an existing filter copy it to your file first.
|
||||
|
||||
If you want to remove one of the alternate filters you can set it to `None`:
|
||||
|
||||
```toml
|
||||
[quote]
|
||||
alt2: None
|
||||
```
|
||||
|
||||
See [extrakto.conf](extrakto.conf) for syntax and predefined filters.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# CLI
|
||||
|
||||
You can also use extrakto as a standalone tool to extract tokens from text.
|
||||
|
||||
## Installation
|
||||
|
||||
For now simply clone the repository and link to the tool somewhere in your path:
|
||||
|
||||
```
|
||||
git clone https://github.com/laktak/extrakto
|
||||
cd extrakto
|
||||
# assuming you `export PATH=$PATH:~/.local/bin` in your `.bashrc`:
|
||||
ln -s $PWD/extrakto.py ~/.local/bin/extrakto
|
||||
```
|
||||
|
||||
Requires Python 3.6+.
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```
|
||||
usage: extrakto.py [-h] [--name] [-w] [-l] [--all] [-a ADD] [-p] [-u] [--alt] [-r] [-m MIN_LENGTH] [--warn-empty]
|
||||
|
||||
Extracts tokens from plaintext.
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--name prefix filter name in the output
|
||||
-w, --words extract "word" tokens
|
||||
-l, --lines extract lines
|
||||
--all extract using all filters defined in extrakto.conf
|
||||
-a ADD, --add ADD add custom filter
|
||||
-p, --paths short for -a=path
|
||||
-u, --urls short for -a=url
|
||||
--alt return alternate variants for each match (e.g. https://example.com and example.com)
|
||||
-r, --reverse reverse output
|
||||
-m MIN_LENGTH, --min-length MIN_LENGTH
|
||||
minimum token length
|
||||
--warn-empty warn if result is empty
|
||||
```
|
||||
|
||||
# Contributions
|
||||
|
||||
Thanks go to all contributors for their ideas and PRs!
|
||||
|
||||
**If you make a PR, please keep it small so that it's easier to test and review. Try to create one PR per feature/bug.**
|
||||
|
||||
Please run `black` if you change any python code and run `shfmt` if you change any bash files.
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.sh]
|
||||
shell_variant=bash
|
||||
binary_next_line=true
|
||||
switch_case_indent=true
|
||||
space_redirects=true
|
||||
keep_padding=false
|
||||
function_next_line=false
|
||||
|
|
@ -1 +0,0 @@
|
|||
ref: refs/heads/master
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
[submodule]
|
||||
active = .
|
||||
[remote "origin"]
|
||||
url = https://git::@github.com/laktak/extrakto
|
||||
fetch = +refs/heads/master:refs/remotes/origin/master
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
|
|
@ -1 +0,0 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||
:
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use IPC::Open2;
|
||||
|
||||
# An example hook script to integrate Watchman
|
||||
# (https://facebook.github.io/watchman/) with git to speed up detecting
|
||||
# new and modified files.
|
||||
#
|
||||
# The hook is passed a version (currently 2) and last update token
|
||||
# formatted as a string and outputs to stdout a new update token and
|
||||
# all files that have been modified since the update token. Paths must
|
||||
# be relative to the root of the working tree and separated by a single NUL.
|
||||
#
|
||||
# To enable this hook, rename this file to "query-watchman" and set
|
||||
# 'git config core.fsmonitor .git/hooks/query-watchman'
|
||||
#
|
||||
my ($version, $last_update_token) = @ARGV;
|
||||
|
||||
# Uncomment for debugging
|
||||
# print STDERR "$0 $version $last_update_token\n";
|
||||
|
||||
# Check the hook interface version
|
||||
if ($version ne 2) {
|
||||
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
||||
"Falling back to scanning...\n";
|
||||
}
|
||||
|
||||
my $git_work_tree = get_working_dir();
|
||||
|
||||
my $retry = 1;
|
||||
|
||||
my $json_pkg;
|
||||
eval {
|
||||
require JSON::XS;
|
||||
$json_pkg = "JSON::XS";
|
||||
1;
|
||||
} or do {
|
||||
require JSON::PP;
|
||||
$json_pkg = "JSON::PP";
|
||||
};
|
||||
|
||||
launch_watchman();
|
||||
|
||||
sub launch_watchman {
|
||||
my $o = watchman_query();
|
||||
if (is_work_tree_watched($o)) {
|
||||
output_result($o->{clock}, @{$o->{files}});
|
||||
}
|
||||
}
|
||||
|
||||
sub output_result {
|
||||
my ($clockid, @files) = @_;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# binmode $fh, ":utf8";
|
||||
# print $fh "$clockid\n@files\n";
|
||||
# close $fh;
|
||||
|
||||
binmode STDOUT, ":utf8";
|
||||
print $clockid;
|
||||
print "\0";
|
||||
local $, = "\0";
|
||||
print @files;
|
||||
}
|
||||
|
||||
sub watchman_clock {
|
||||
my $response = qx/watchman clock "$git_work_tree"/;
|
||||
die "Failed to get clock id on '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub watchman_query {
|
||||
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
|
||||
or die "open2() failed: $!\n" .
|
||||
"Falling back to scanning...\n";
|
||||
|
||||
# In the query expression below we're asking for names of files that
|
||||
# changed since $last_update_token but not from the .git folder.
|
||||
#
|
||||
# To accomplish this, we're using the "since" generator to use the
|
||||
# recency index to select candidate nodes and "fields" to limit the
|
||||
# output to file names only. Then we're using the "expression" term to
|
||||
# further constrain the results.
|
||||
my $last_update_line = "";
|
||||
if (substr($last_update_token, 0, 1) eq "c") {
|
||||
$last_update_token = "\"$last_update_token\"";
|
||||
$last_update_line = qq[\n"since": $last_update_token,];
|
||||
}
|
||||
my $query = <<" END";
|
||||
["query", "$git_work_tree", {$last_update_line
|
||||
"fields": ["name"],
|
||||
"expression": ["not", ["dirname", ".git"]]
|
||||
}]
|
||||
END
|
||||
|
||||
# Uncomment for debugging the watchman query
|
||||
# open (my $fh, ">", ".git/watchman-query.json");
|
||||
# print $fh $query;
|
||||
# close $fh;
|
||||
|
||||
print CHLD_IN $query;
|
||||
close CHLD_IN;
|
||||
my $response = do {local $/; <CHLD_OUT>};
|
||||
|
||||
# Uncomment for debugging the watch response
|
||||
# open ($fh, ">", ".git/watchman-response.json");
|
||||
# print $fh $response;
|
||||
# close $fh;
|
||||
|
||||
die "Watchman: command returned no output.\n" .
|
||||
"Falling back to scanning...\n" if $response eq "";
|
||||
die "Watchman: command returned invalid output: $response\n" .
|
||||
"Falling back to scanning...\n" unless $response =~ /^\{/;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub is_work_tree_watched {
|
||||
my ($output) = @_;
|
||||
my $error = $output->{error};
|
||||
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
|
||||
$retry--;
|
||||
my $response = qx/watchman watch "$git_work_tree"/;
|
||||
die "Failed to make watchman watch '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
$output = $json_pkg->new->utf8->decode($response);
|
||||
$error = $output->{error};
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# close $fh;
|
||||
|
||||
# Watchman will always return all files on the first query so
|
||||
# return the fast "everything is dirty" flag to git and do the
|
||||
# Watchman query just to get it over with now so we won't pay
|
||||
# the cost in git to look up each individual file.
|
||||
my $o = watchman_clock();
|
||||
$error = $output->{error};
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
output_result($o->{clock}, ("/"));
|
||||
$last_update_token = $o->{clock};
|
||||
|
||||
eval { launch_watchman() };
|
||||
return 0;
|
||||
}
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub get_working_dir {
|
||||
my $working_dir;
|
||||
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
|
||||
$working_dir = Win32::GetCwd();
|
||||
$working_dir =~ tr/\\/\//;
|
||||
} else {
|
||||
require Cwd;
|
||||
$working_dir = Cwd::cwd();
|
||||
}
|
||||
|
||||
return $working_dir;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to prepare a packed repository for use over
|
||||
# dumb transports.
|
||||
#
|
||||
# To enable this hook, rename this file to "post-update".
|
||||
|
||||
exec git update-server-info
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||
:
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=$(git hash-object -t tree /dev/null)
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git merge" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message to
|
||||
# stderr if it wants to stop the merge commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-merge-commit".
|
||||
|
||||
. git-sh-setup
|
||||
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||
exec "$GIT_DIR/hooks/pre-commit"
|
||||
:
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
# An example hook script to verify what is about to be pushed. Called by "git
|
||||
# push" after it has checked the remote status, but before anything has been
|
||||
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# This hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- Name of the remote to which the push is being done
|
||||
# $2 -- URL to which the push is being done
|
||||
#
|
||||
# If pushing without using a named remote those arguments will be equal.
|
||||
#
|
||||
# Information about the commits which are being pushed is supplied as lines to
|
||||
# the standard input in the form:
|
||||
#
|
||||
# <local ref> <local oid> <remote ref> <remote oid>
|
||||
#
|
||||
# This sample shows how to prevent push of commits where the log message starts
|
||||
# with "WIP" (work in progress).
|
||||
|
||||
remote="$1"
|
||||
url="$2"
|
||||
|
||||
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||
|
||||
while read local_ref local_oid remote_ref remote_oid
|
||||
do
|
||||
if test "$local_oid" = "$zero"
|
||||
then
|
||||
# Handle delete
|
||||
:
|
||||
else
|
||||
if test "$remote_oid" = "$zero"
|
||||
then
|
||||
# New branch, examine all commits
|
||||
range="$local_oid"
|
||||
else
|
||||
# Update to existing branch, examine new commits
|
||||
range="$remote_oid..$local_oid"
|
||||
fi
|
||||
|
||||
# Check for WIP commit
|
||||
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||
if test -n "$commit"
|
||||
then
|
||||
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||
#
|
||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||
# its job, and can prevent the command from running by exiting with
|
||||
# non-zero status.
|
||||
#
|
||||
# The hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- the upstream the series was forked from.
|
||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||
#
|
||||
# This sample shows how to prevent topic branches that are already
|
||||
# merged to 'next' branch from getting rebased, because allowing it
|
||||
# would result in rebasing already published history.
|
||||
|
||||
publish=next
|
||||
basebranch="$1"
|
||||
if test "$#" = 2
|
||||
then
|
||||
topic="refs/heads/$2"
|
||||
else
|
||||
topic=`git symbolic-ref HEAD` ||
|
||||
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||
fi
|
||||
|
||||
case "$topic" in
|
||||
refs/heads/??/*)
|
||||
;;
|
||||
*)
|
||||
exit 0 ;# we do not interrupt others.
|
||||
;;
|
||||
esac
|
||||
|
||||
# Now we are dealing with a topic branch being rebased
|
||||
# on top of master. Is it OK to rebase it?
|
||||
|
||||
# Does the topic really exist?
|
||||
git show-ref -q "$topic" || {
|
||||
echo >&2 "No such branch $topic"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Is topic fully merged to master?
|
||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||
if test -z "$not_in_master"
|
||||
then
|
||||
echo >&2 "$topic is fully merged to master; better remove it."
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
fi
|
||||
|
||||
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||
if test "$only_next_1" = "$only_next_2"
|
||||
then
|
||||
not_in_topic=`git rev-list "^$topic" master`
|
||||
if test -z "$not_in_topic"
|
||||
then
|
||||
echo >&2 "$topic is already up to date with master"
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||
/usr/bin/perl -e '
|
||||
my $topic = $ARGV[0];
|
||||
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||
my (%not_in_next) = map {
|
||||
/^([0-9a-f]+) /;
|
||||
($1 => 1);
|
||||
} split(/\n/, $ARGV[1]);
|
||||
for my $elem (map {
|
||||
/^([0-9a-f]+) (.*)$/;
|
||||
[$1 => $2];
|
||||
} split(/\n/, $ARGV[2])) {
|
||||
if (!exists $not_in_next{$elem->[0]}) {
|
||||
if ($msg) {
|
||||
print STDERR $msg;
|
||||
undef $msg;
|
||||
}
|
||||
print STDERR " $elem->[1]\n";
|
||||
}
|
||||
}
|
||||
' "$topic" "$not_in_next" "$not_in_master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
<<\DOC_END
|
||||
|
||||
This sample hook safeguards topic branches that have been
|
||||
published from being rewound.
|
||||
|
||||
The workflow assumed here is:
|
||||
|
||||
* Once a topic branch forks from "master", "master" is never
|
||||
merged into it again (either directly or indirectly).
|
||||
|
||||
* Once a topic branch is fully cooked and merged into "master",
|
||||
it is deleted. If you need to build on top of it to correct
|
||||
earlier mistakes, a new topic branch is created by forking at
|
||||
the tip of the "master". This is not strictly necessary, but
|
||||
it makes it easier to keep your history simple.
|
||||
|
||||
* Whenever you need to test or publish your changes to topic
|
||||
branches, merge them into "next" branch.
|
||||
|
||||
The script, being an example, hardcodes the publish branch name
|
||||
to be "next", but it is trivial to make it configurable via
|
||||
$GIT_DIR/config mechanism.
|
||||
|
||||
With this workflow, you would want to know:
|
||||
|
||||
(1) ... if a topic branch has ever been merged to "next". Young
|
||||
topic branches can have stupid mistakes you would rather
|
||||
clean up before publishing, and things that have not been
|
||||
merged into other branches can be easily rebased without
|
||||
affecting other people. But once it is published, you would
|
||||
not want to rewind it.
|
||||
|
||||
(2) ... if a topic branch has been fully merged to "master".
|
||||
Then you can delete it. More importantly, you should not
|
||||
build on top of it -- other people may already want to
|
||||
change things related to the topic as patches against your
|
||||
"master", so if you need further changes, it is better to
|
||||
fork the topic (perhaps with the same name) afresh from the
|
||||
tip of "master".
|
||||
|
||||
Let's look at this example:
|
||||
|
||||
o---o---o---o---o---o---o---o---o---o "next"
|
||||
/ / / /
|
||||
/ a---a---b A / /
|
||||
/ / / /
|
||||
/ / c---c---c---c B /
|
||||
/ / / \ /
|
||||
/ / / b---b C \ /
|
||||
/ / / / \ /
|
||||
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||
|
||||
|
||||
A, B and C are topic branches.
|
||||
|
||||
* A has one fix since it was merged up to "next".
|
||||
|
||||
* B has finished. It has been fully merged up to "master" and "next",
|
||||
and is ready to be deleted.
|
||||
|
||||
* C has not merged to "next" at all.
|
||||
|
||||
We would want to allow C to be rebased, refuse A, and encourage
|
||||
B to be deleted.
|
||||
|
||||
To compute (1):
|
||||
|
||||
git rev-list ^master ^topic next
|
||||
git rev-list ^master next
|
||||
|
||||
if these match, topic has not merged in next at all.
|
||||
|
||||
To compute (2):
|
||||
|
||||
git rev-list master..topic
|
||||
|
||||
if this is empty, it is fully merged to "master".
|
||||
|
||||
DOC_END
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to make use of push options.
|
||||
# The example simply echoes all push options that start with 'echoback='
|
||||
# and rejects all pushes when the "reject" push option is used.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-receive".
|
||||
|
||||
if test -n "$GIT_PUSH_OPTION_COUNT"
|
||||
then
|
||||
i=0
|
||||
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
||||
do
|
||||
eval "value=\$GIT_PUSH_OPTION_$i"
|
||||
case "$value" in
|
||||
echoback=*)
|
||||
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
||||
;;
|
||||
reject)
|
||||
exit 1
|
||||
esac
|
||||
i=$((i + 1))
|
||||
done
|
||||
fi
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to prepare the commit log message.
|
||||
# Called by "git commit" with the name of the file that has the
|
||||
# commit message, followed by the description of the commit
|
||||
# message's source. The hook's purpose is to edit the commit
|
||||
# message file. If the hook fails with a non-zero status,
|
||||
# the commit is aborted.
|
||||
#
|
||||
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||
|
||||
# This hook includes three examples. The first one removes the
|
||||
# "# Please enter the commit message..." help message.
|
||||
#
|
||||
# The second includes the output of "git diff --name-status -r"
|
||||
# into the message, just before the "git status" output. It is
|
||||
# commented because it doesn't cope with --amend or with squashed
|
||||
# commits.
|
||||
#
|
||||
# The third example adds a Signed-off-by line to the message, that can
|
||||
# still be edited. This is rarely a good idea.
|
||||
|
||||
COMMIT_MSG_FILE=$1
|
||||
COMMIT_SOURCE=$2
|
||||
SHA1=$3
|
||||
|
||||
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
||||
|
||||
# case "$COMMIT_SOURCE,$SHA1" in
|
||||
# ,|template,)
|
||||
# /usr/bin/perl -i.bak -pe '
|
||||
# print "\n" . `git diff --cached --name-status -r`
|
||||
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
||||
# *) ;;
|
||||
# esac
|
||||
|
||||
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
||||
# if test -z "$COMMIT_SOURCE"
|
||||
# then
|
||||
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
||||
# fi
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
# An example hook script to update a checked-out tree on a git push.
|
||||
#
|
||||
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
||||
# push and updates reference(s) in its repository, and when the push
|
||||
# tries to update the branch that is currently checked out and the
|
||||
# receive.denyCurrentBranch configuration variable is set to
|
||||
# updateInstead.
|
||||
#
|
||||
# By default, such a push is refused if the working tree and the index
|
||||
# of the remote repository has any difference from the currently
|
||||
# checked out commit; when both the working tree and the index match
|
||||
# the current commit, they are updated to match the newly pushed tip
|
||||
# of the branch. This hook is to be used to override the default
|
||||
# behaviour; however the code below reimplements the default behaviour
|
||||
# as a starting point for convenient modification.
|
||||
#
|
||||
# The hook receives the commit with which the tip of the current
|
||||
# branch is going to be updated:
|
||||
commit=$1
|
||||
|
||||
# It can exit with a non-zero status to refuse the push (when it does
|
||||
# so, it must not modify the index or the working tree).
|
||||
die () {
|
||||
echo >&2 "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Or it can make any necessary changes to the working tree and to the
|
||||
# index to bring them to the desired state when the tip of the current
|
||||
# branch is updated to the new commit, and exit with a zero status.
|
||||
#
|
||||
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
||||
# in order to emulate git fetch that is run in the reverse direction
|
||||
# with git push, as the two-tree form of git read-tree -u -m is
|
||||
# essentially the same as git switch or git checkout that switches
|
||||
# branches while keeping the local changes in the working tree that do
|
||||
# not interfere with the difference between the branches.
|
||||
|
||||
# The below is a more-or-less exact translation to shell of the C code
|
||||
# for the default behaviour for git's push-to-checkout hook defined in
|
||||
# the push_to_deploy() function in builtin/receive-pack.c.
|
||||
#
|
||||
# Note that the hook will be executed from the repository directory,
|
||||
# not from the working tree, so if you want to perform operations on
|
||||
# the working tree, you will have to adapt your code accordingly, e.g.
|
||||
# by adding "cd .." or using relative paths.
|
||||
|
||||
if ! git update-index -q --ignore-submodules --refresh
|
||||
then
|
||||
die "Up-to-date check failed"
|
||||
fi
|
||||
|
||||
if ! git diff-files --quiet --ignore-submodules --
|
||||
then
|
||||
die "Working directory has unstaged changes"
|
||||
fi
|
||||
|
||||
# This is a rough translation of:
|
||||
#
|
||||
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
||||
if git cat-file -e HEAD 2>/dev/null
|
||||
then
|
||||
head=HEAD
|
||||
else
|
||||
head=$(git hash-object -t tree --stdin </dev/null)
|
||||
fi
|
||||
|
||||
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
||||
then
|
||||
die "Working directory has staged changes"
|
||||
fi
|
||||
|
||||
if ! git read-tree -u -m "$commit"
|
||||
then
|
||||
die "Could not update working tree to new HEAD"
|
||||
fi
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
# An example hook script to validate a patch (and/or patch series) before
|
||||
# sending it via email.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an appropriate
|
||||
# message if it wants to prevent the email(s) from being sent.
|
||||
#
|
||||
# To enable this hook, rename this file to "sendemail-validate".
|
||||
#
|
||||
# By default, it will only check that the patch(es) can be applied on top of
|
||||
# the default upstream branch without conflicts in a secondary worktree. After
|
||||
# validation (successful or not) of the last patch of a series, the worktree
|
||||
# will be deleted.
|
||||
#
|
||||
# The following config variables can be set to change the default remote and
|
||||
# remote ref that are used to apply the patches against:
|
||||
#
|
||||
# sendemail.validateRemote (default: origin)
|
||||
# sendemail.validateRemoteRef (default: HEAD)
|
||||
#
|
||||
# Replace the TODO placeholders with appropriate checks according to your
|
||||
# needs.
|
||||
|
||||
validate_cover_letter () {
|
||||
file="$1"
|
||||
# TODO: Replace with appropriate checks (e.g. spell checking).
|
||||
true
|
||||
}
|
||||
|
||||
validate_patch () {
|
||||
file="$1"
|
||||
# Ensure that the patch applies without conflicts.
|
||||
git am -3 "$file" || return
|
||||
# TODO: Replace with appropriate checks for this patch
|
||||
# (e.g. checkpatch.pl).
|
||||
true
|
||||
}
|
||||
|
||||
validate_series () {
|
||||
# TODO: Replace with appropriate checks for the whole series
|
||||
# (e.g. quick build, coding style checks, etc.).
|
||||
true
|
||||
}
|
||||
|
||||
# main -------------------------------------------------------------------------
|
||||
|
||||
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
|
||||
then
|
||||
remote=$(git config --default origin --get sendemail.validateRemote) &&
|
||||
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
|
||||
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
|
||||
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
|
||||
git config --replace-all sendemail.validateWorktree "$worktree"
|
||||
else
|
||||
worktree=$(git config --get sendemail.validateWorktree)
|
||||
fi || {
|
||||
echo "sendemail-validate: error: failed to prepare worktree" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
unset GIT_DIR GIT_WORK_TREE
|
||||
cd "$worktree" &&
|
||||
|
||||
if grep -q "^diff --git " "$1"
|
||||
then
|
||||
validate_patch "$1"
|
||||
else
|
||||
validate_cover_letter "$1"
|
||||
fi &&
|
||||
|
||||
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
|
||||
then
|
||||
git config --unset-all sendemail.validateWorktree &&
|
||||
trap 'git worktree remove -ff "$worktree"' EXIT &&
|
||||
validate_series
|
||||
fi
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to block unannotated tags from entering.
|
||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||
#
|
||||
# To enable this hook, rename this file to "update".
|
||||
#
|
||||
# Config
|
||||
# ------
|
||||
# hooks.allowunannotated
|
||||
# This boolean sets whether unannotated tags will be allowed into the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletetag
|
||||
# This boolean sets whether deleting tags will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowmodifytag
|
||||
# This boolean sets whether a tag may be modified after creation. By default
|
||||
# it won't be.
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.denycreatebranch
|
||||
# This boolean sets whether remotely creating branches will be denied
|
||||
# in the repository. By default this is allowed.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
refname="$1"
|
||||
oldrev="$2"
|
||||
newrev="$3"
|
||||
|
||||
# --- Safety check
|
||||
if [ -z "$GIT_DIR" ]; then
|
||||
echo "Don't run this script from the command line." >&2
|
||||
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Config
|
||||
allowunannotated=$(git config --type=bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
|
||||
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
|
||||
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
|
||||
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
|
||||
|
||||
# check for no description
|
||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||
case "$projectdesc" in
|
||||
"Unnamed repository"* | "")
|
||||
echo "*** Project description file hasn't been set" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||
if [ "$newrev" = "$zero" ]; then
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git cat-file -t $newrev)
|
||||
fi
|
||||
|
||||
case "$refname","$newrev_type" in
|
||||
refs/tags/*,commit)
|
||||
# un-annotated tag
|
||||
short_refname=${refname##refs/tags/}
|
||||
if [ "$allowunannotated" != "true" ]; then
|
||||
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,delete)
|
||||
# delete tag
|
||||
if [ "$allowdeletetag" != "true" ]; then
|
||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,tag)
|
||||
# annotated tag
|
||||
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||
then
|
||||
echo "*** Tag '$refname' already exists." >&2
|
||||
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/remotes/*,commit)
|
||||
# tracking branch
|
||||
;;
|
||||
refs/remotes/*,delete)
|
||||
# delete tracking branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Anything else (is there anything else?)
|
||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Finished
|
||||
exit 0
|
||||
Binary file not shown.
|
|
@ -1,6 +0,0 @@
|
|||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
||||
|
|
@ -1 +0,0 @@
|
|||
0000000000000000000000000000000000000000 8796a673d46f9d2de1f37174ace39a84521aaf4b aleidk <ale.navarro.parra@gmail.com> 1699105324 -0300 clone: from https://github.com/laktak/extrakto
|
||||
|
|
@ -1 +0,0 @@
|
|||
0000000000000000000000000000000000000000 8796a673d46f9d2de1f37174ace39a84521aaf4b aleidk <ale.navarro.parra@gmail.com> 1699105324 -0300 clone: from https://github.com/laktak/extrakto
|
||||
|
|
@ -1 +0,0 @@
|
|||
0000000000000000000000000000000000000000 8796a673d46f9d2de1f37174ace39a84521aaf4b aleidk <ale.navarro.parra@gmail.com> 1699105324 -0300 clone: from https://github.com/laktak/extrakto
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,2 +0,0 @@
|
|||
# pack-refs with: peeled fully-peeled sorted
|
||||
8796a673d46f9d2de1f37174ace39a84521aaf4b refs/remotes/origin/master
|
||||
|
|
@ -1 +0,0 @@
|
|||
8796a673d46f9d2de1f37174ace39a84521aaf4b
|
||||
|
|
@ -1 +0,0 @@
|
|||
ref: refs/remotes/origin/master
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
name: Check
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: psf/black@stable
|
||||
- name: shfmt
|
||||
run: |
|
||||
curl -LsS -o ~/shfmt https://github.com/mvdan/sh/releases/download/v3.1.2/shfmt_v3.1.2_linux_amd64
|
||||
chmod +x ~/shfmt
|
||||
~/shfmt -d scripts/ extrakto.tmux
|
||||
- name: tests
|
||||
run: |
|
||||
python3 -m unittest discover -s tests/
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from collections import OrderedDict
|
||||
from configparser import ConfigParser
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# "words" consist of anything but the following characters:
|
||||
# [](){}=$
|
||||
# unicode range 2500-27BF which includes:
|
||||
# - Box Drawing
|
||||
# - Block Elements
|
||||
# - Geometric Shapes
|
||||
# - Miscellaneous Symbols
|
||||
# - Dingbats
|
||||
# unicode range E000-F8FF (private use/Powerline)
|
||||
# and whitespace ( \t\n\r)
|
||||
RE_WORD = "[^][(){}=$\u2500-\u27BF\uE000-\uF8FF \\t\\n\\r]+"
|
||||
|
||||
|
||||
class Extrakto:
|
||||
def __init__(self, *, min_length=5, alt=False, prefix_name=False):
|
||||
conf = ConfigParser(interpolation=None)
|
||||
default_conf = os.path.join(SCRIPT_DIR, "extrakto.conf")
|
||||
user_conf = os.path.join(
|
||||
os.path.expanduser("~/.config"), "extrakto/extrakto.conf"
|
||||
)
|
||||
|
||||
conf.read([default_conf, user_conf])
|
||||
sections = conf.sections()
|
||||
|
||||
if not "path" in sections or not "url" in sections:
|
||||
raise Exception("extrakto.conf incomplete, path and url must exist")
|
||||
|
||||
self.min_length = min_length
|
||||
self.alt = alt
|
||||
self.prefix_name = prefix_name
|
||||
|
||||
self.in_all = []
|
||||
self.fdict = {}
|
||||
|
||||
for name in sections:
|
||||
sect = conf[name]
|
||||
alt = []
|
||||
for i in range(2, 10):
|
||||
key = f"alt{i}"
|
||||
|
||||
# if alt2, alt{n} exists as a value in a section, create a variant based on that regex
|
||||
if key in sect:
|
||||
alt.append(sect[key])
|
||||
|
||||
if sect.getboolean("in_all", fallback=True):
|
||||
self.in_all.append(name)
|
||||
|
||||
if sect.getboolean("enabled", fallback=True):
|
||||
self.fdict[name] = FilterDef(
|
||||
self,
|
||||
name,
|
||||
regex=sect.get("regex"),
|
||||
exclude=sect.get("exclude", ""),
|
||||
lstrip=sect.get("lstrip", ""),
|
||||
rstrip=sect.get("rstrip", ""),
|
||||
alt=alt,
|
||||
)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if not key in self.fdict:
|
||||
raise Exception(f"Unknown filter {key}")
|
||||
return self.fdict[key]
|
||||
|
||||
def all(self):
|
||||
return self.in_all
|
||||
|
||||
def keys(self):
|
||||
return list(self.fdict.keys())
|
||||
|
||||
|
||||
class FilterDef:
|
||||
def __init__(self, extrakto, name, *, regex, exclude, lstrip, rstrip, alt):
|
||||
self.extrakto = extrakto
|
||||
self.name = name
|
||||
self.regex = regex
|
||||
self.exclude = exclude
|
||||
self.lstrip = lstrip
|
||||
self.rstrip = rstrip
|
||||
self.alt = alt
|
||||
|
||||
def filter(self, text):
|
||||
res = list()
|
||||
if self.extrakto.prefix_name:
|
||||
add = lambda name, value: res.append(f"{name}: {value}")
|
||||
else:
|
||||
add = lambda name, value: res.append(value)
|
||||
|
||||
for m in re.finditer(self.regex, "\n" + text, flags=re.I):
|
||||
item = "".join(filter(None, m.groups()))
|
||||
|
||||
# strip invalid characters (like punctuation or markdown syntax)
|
||||
if self.lstrip:
|
||||
item = item.lstrip(self.lstrip)
|
||||
if self.rstrip:
|
||||
item = item.rstrip(self.rstrip)
|
||||
|
||||
if len(item) >= self.extrakto.min_length:
|
||||
if not self.exclude or not re.search(self.exclude, item, re.I):
|
||||
if self.extrakto.alt:
|
||||
for i, altre in enumerate(self.alt):
|
||||
m = re.search(altre, item)
|
||||
if m:
|
||||
add(f"{self.name}{i+2}", m[1])
|
||||
add(self.name, item)
|
||||
return res
|
||||
|
||||
|
||||
def get_lines(text, *, min_length=5, prefix_name=False):
|
||||
lines = []
|
||||
|
||||
for raw_line in text.splitlines():
|
||||
line = raw_line.strip()
|
||||
if len(line) >= min_length:
|
||||
if prefix_name:
|
||||
lines.append("line: " + line)
|
||||
else:
|
||||
lines.append(line)
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
def main(parser):
|
||||
args = parser.parse_args()
|
||||
|
||||
run_list = []
|
||||
if args.words:
|
||||
run_list.append("word")
|
||||
if args.paths:
|
||||
run_list.append("path")
|
||||
if args.urls:
|
||||
run_list.append("url")
|
||||
run_list += args.add
|
||||
|
||||
res = []
|
||||
# input from the terminal can cause UnicodeDecodeErrors in some instances, ignore for now
|
||||
text = sys.stdin.buffer.read().decode("utf-8", "ignore")
|
||||
|
||||
extrakto = Extrakto(min_length=args.min_length, alt=args.alt, prefix_name=args.name)
|
||||
if args.all:
|
||||
run_list = extrakto.all()
|
||||
|
||||
if args.lines:
|
||||
res += get_lines(text, min_length=args.min_length, prefix_name=args.name)
|
||||
|
||||
for name in run_list:
|
||||
res += extrakto[name].filter(text)
|
||||
|
||||
if res:
|
||||
if args.reverse:
|
||||
res.reverse()
|
||||
|
||||
# remove duplicates and print
|
||||
for item in OrderedDict.fromkeys(res):
|
||||
print(item)
|
||||
|
||||
elif args.warn_empty:
|
||||
print("NO MATCH - use a different filter")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = ArgumentParser(description="Extracts tokens from plaintext.")
|
||||
|
||||
parser.add_argument(
|
||||
"--name", action="store_true", help="prefix filter name in the output"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-w", "--words", action="store_true", help='extract "word" tokens'
|
||||
)
|
||||
|
||||
parser.add_argument("-l", "--lines", action="store_true", help="extract lines")
|
||||
|
||||
parser.add_argument(
|
||||
"--all",
|
||||
action="store_true",
|
||||
help="extract using all filters defined in extrakto.conf",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-a", "--add", action="append", default=[], help="add custom filter"
|
||||
)
|
||||
|
||||
parser.add_argument("-p", "--paths", action="store_true", help="short for -a=path")
|
||||
|
||||
parser.add_argument("-u", "--urls", action="store_true", help="short for -a=url")
|
||||
|
||||
parser.add_argument(
|
||||
"--alt",
|
||||
action="store_true",
|
||||
help="return alternate variants for each match (e.g. https://example.com and example.com)",
|
||||
)
|
||||
|
||||
parser.add_argument("-r", "--reverse", action="store_true", help="reverse output")
|
||||
|
||||
parser.add_argument(
|
||||
"-m", "--min-length", default=5, help="minimum token length", type=int
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--warn-empty", action="store_true", help="warn if result is empty"
|
||||
)
|
||||
|
||||
main(parser)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "$CURRENT_DIR/scripts/helpers.sh"
|
||||
extrakto_open="$CURRENT_DIR/scripts/open.sh"
|
||||
|
||||
extrakto_key=$(get_option "@extrakto_key")
|
||||
|
||||
if [[ $(echo $extrakto_key | tr [:upper:] [:lower:]) != none ]]; then
|
||||
tmux bind-key ${extrakto_key} run-shell "\"$extrakto_open\" \"#{pane_id}\""
|
||||
fi
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
# extrakto filter definitions
|
||||
|
||||
# Define your own filters in ~/.config/extrakto/extrakto.conf
|
||||
# To override an existing filter just specify the new values.
|
||||
# For example, if you prefer to split words on comma as well you can define:
|
||||
# [word]
|
||||
# regex: ([^][(){}=$─-➿-, \t\n\r]+)
|
||||
|
||||
# define a section per filter
|
||||
# each filter must have at least a regex containing one or more capture groups
|
||||
# regex: a python regex expression
|
||||
# enabled: is filter active (default True)
|
||||
# in_all: is included in --all (default True)
|
||||
# lstrip: characters to strip from left result
|
||||
# rstrip: characters to strip from right result
|
||||
# exclude: exclude result if matching
|
||||
# alt2-9: alternate result (see url)
|
||||
|
||||
[word]
|
||||
# "words" consist of anything but the following characters:
|
||||
# [](){}=$
|
||||
# unicode range 2500-27BF which includes:
|
||||
# - Box Drawing
|
||||
# - Block Elements
|
||||
# - Geometric Shapes
|
||||
# - Miscellaneous Symbols
|
||||
# - Dingbats
|
||||
# unicode range E000-F8FF (private use/Powerline)
|
||||
# common editor 'whitespace' characters: ⋅↴│
|
||||
# and whitespace ( \t\n\r)
|
||||
# regex: [^][(){}=$\u2500-\u27BF\uE000-\uF8FF \t\n\r]+
|
||||
regex: ([^][(){}=$─-➿-⋅↴│ \t\n\r]+)
|
||||
lstrip: ,:;()[]{}<>'"|
|
||||
rstrip: ,:;()[]{}<>'"|.
|
||||
in_all: False
|
||||
|
||||
[path]
|
||||
# separator: (?=[ \t\n]|"|\(|\[|<|\')?
|
||||
# optionally starts with: (~|/)?
|
||||
regex: (?:[ \t\n\"([<':]|^)(~|/)?([-~a-zA-Z0-9_+-,.]+/[^ \t\n\r|:"'$%&)>\]]*)
|
||||
# exclude transfer speeds like 5k/s or m/s, and page 1/2
|
||||
exclude: [kmgKMG]/s$|^\d+/\d+$
|
||||
# remove invalid end characters (like punctuation or markdown syntax)
|
||||
rstrip: ",):"
|
||||
|
||||
[url]
|
||||
regex: (https?://|git@|git://|ssh://|s*ftp://|file:///)([a-zA-Z0-9?=%/_.:,;~@!#$&()*+-]*)
|
||||
alt2: ://([^/? ]+)
|
||||
# remove invalid end characters (like punctuation or markdown syntax)
|
||||
rstrip: ",):"
|
||||
|
||||
[quote]
|
||||
regex: ("[^"\n\r]+")
|
||||
alt2: "([^"\n\r]+)"
|
||||
|
||||
[s-quote]
|
||||
regex: ('[^'\n\r]+')
|
||||
alt2: '([^'\n\r]+)'
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
platform="$(uname)"
|
||||
|
||||
# first check the version of bash
|
||||
if ! type mapfile &> /dev/null; then
|
||||
echo "error: extrakto needs a newer Bash"
|
||||
if [[ $platform == Darwin ]]; then
|
||||
echo "On macOS you need to install/update it with Homebrew."
|
||||
fi
|
||||
read # pause
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PRJ_URL=https://github.com/laktak/extrakto
|
||||
current_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
trigger_pane=$1
|
||||
launch_mode=$2
|
||||
source "$current_dir/helpers.sh"
|
||||
extrakto="$current_dir/../extrakto.py"
|
||||
|
||||
declare -Ar COLORS=(
|
||||
[RED]=$'\033[0;31m'
|
||||
[GREEN]=$'\033[0;32m'
|
||||
[BLUE]=$'\033[0;34m'
|
||||
[PURPLE]=$'\033[0;35m'
|
||||
[CYAN]=$'\033[0;36m'
|
||||
[WHITE]=$'\033[0;37m'
|
||||
[YELLOW]=$'\033[0;33m'
|
||||
[OFF]=$'\033[0m'
|
||||
[BOLD]=$'\033[1m'
|
||||
)
|
||||
|
||||
# options; note some of the values can be overwritten by capture()
|
||||
grab_area=$(get_option "@extrakto_grab_area")
|
||||
clip_tool=$(get_option "@extrakto_clip_tool")
|
||||
clip_tool_run=$(get_option "@extrakto_clip_tool_run")
|
||||
editor=$(get_option "@extrakto_editor")
|
||||
fzf_tool=$(get_option "@extrakto_fzf_tool")
|
||||
open_tool=$(get_option "@extrakto_open_tool")
|
||||
copy_key=$(get_option "@extrakto_copy_key")
|
||||
insert_key=$(get_option "@extrakto_insert_key")
|
||||
filter_key=$(get_option "@extrakto_filter_key")
|
||||
open_key=$(get_option "@extrakto_open_key")
|
||||
edit_key=$(get_option "@extrakto_edit_key")
|
||||
grab_key=$(get_option "@extrakto_grab_key")
|
||||
help_key=$(get_option "@extrakto_help_key")
|
||||
fzf_layout=$(get_option "@extrakto_fzf_layout")
|
||||
fzf_unset_default_opts=$(get_option "@extrakto_fzf_unset_default_opts")
|
||||
|
||||
capture_pane_start=$(get_capture_pane_start "$grab_area")
|
||||
original_grab_area=${grab_area} # keep this so we can cycle between alternatives on fzf
|
||||
|
||||
# avoid side effects from FZF_DEFAULT_OPTS
|
||||
if [[ $fzf_unset_default_opts == "true" ]]; then
|
||||
unset FZF_DEFAULT_OPTS
|
||||
fi
|
||||
|
||||
if [[ "$clip_tool" == "auto" ]]; then
|
||||
case "$platform" in
|
||||
'Linux')
|
||||
if [[ $(cat /proc/sys/kernel/osrelease) =~ Microsoft|microsoft ]]; then
|
||||
clip_tool='clip.exe'
|
||||
elif [[ $XDG_SESSION_TYPE == "wayland" ]]; then
|
||||
clip_tool='wl-copy'
|
||||
else
|
||||
clip_tool='xclip -i -selection clipboard >/dev/null'
|
||||
fi
|
||||
;;
|
||||
'Darwin') clip_tool='pbcopy' ;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [[ "$open_tool" == "auto" ]]; then
|
||||
case "$platform" in
|
||||
'Linux') open_tool='xdg-open >/dev/null' ;;
|
||||
'Darwin') open_tool='open' ;;
|
||||
*) open_tool='' ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [[ -z $editor ]]; then
|
||||
editor="${EDITOR:-vi}"
|
||||
fi
|
||||
|
||||
copy() {
|
||||
if [[ "$clip_tool_run" == "fg" ]]; then
|
||||
# run in foreground as OSC-52 copying won't work otherwise
|
||||
tmux set-buffer -- "$1"
|
||||
tmux run-shell "tmux show-buffer|$clip_tool"
|
||||
elif [[ "$clip_tool_run" == "tmux_osc52" ]]; then
|
||||
# use native tmux 3.2 OSC 52 functionality
|
||||
tmux set-buffer -w -- "$1"
|
||||
else
|
||||
# run in background as xclip won't work otherwise
|
||||
tmux set-buffer -- "$1"
|
||||
tmux run-shell -b "tmux show-buffer|$clip_tool"
|
||||
fi
|
||||
}
|
||||
|
||||
open() {
|
||||
if [[ -n "$open_tool" ]]; then
|
||||
tmux run-shell -b "cd -- $PWD; $open_tool $1"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
capture_panes() {
|
||||
local pane captured
|
||||
captured=""
|
||||
|
||||
if [[ $grab_area =~ ^window\ ]]; then
|
||||
for pane in $(tmux list-panes -F "#{pane_active}:#{pane_id}"); do
|
||||
# exclude the active (for split) and trigger panes
|
||||
# in popup mode the active and tigger panes are the same
|
||||
if [[ $pane =~ ^0: && ${pane:2} != "$trigger_pane" ]]; then
|
||||
captured+="$(tmux capture-pane -pJS ${capture_pane_start} -t ${pane:2})"
|
||||
captured+=$'\n'
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
captured+="$(tmux capture-pane -pJS ${capture_pane_start} -t $trigger_pane)"
|
||||
|
||||
echo "$captured"
|
||||
}
|
||||
|
||||
has_single_pane() {
|
||||
local num_panes
|
||||
num_panes=$(tmux list-panes | wc -l)
|
||||
if [[ $launch_mode == popup ]]; then
|
||||
[[ $num_panes == 1 ]]
|
||||
else
|
||||
[[ $num_panes == 2 ]]
|
||||
fi
|
||||
}
|
||||
|
||||
show_fzf_error() {
|
||||
echo "error: unable to extract - check/report errors above"
|
||||
echo "You can also set the fzf path in options (see readme)."
|
||||
read # pause
|
||||
}
|
||||
|
||||
capture() {
|
||||
local mode header_tmpl header out res key text query
|
||||
|
||||
mode=$(get_next_mode "initial")
|
||||
|
||||
header_tmpl="${COLORS[BOLD]}${insert_key}${COLORS[OFF]}=insert"
|
||||
header_tmpl+=", ${COLORS[BOLD]}${copy_key}${COLORS[OFF]}=copy"
|
||||
[[ -n "$open_tool" ]] && header_tmpl+=", ${COLORS[BOLD]}${open_key}${COLORS[OFF]}=open"
|
||||
header_tmpl+=", ${COLORS[BOLD]}${edit_key}${COLORS[OFF]}=edit"
|
||||
header_tmpl+=", ${COLORS[BOLD]}${filter_key}${COLORS[OFF]}=filter [${COLORS[YELLOW]}${COLORS[BOLD]}:filter:${COLORS[OFF]}]"
|
||||
header_tmpl+=", ${COLORS[BOLD]}${grab_key}${COLORS[OFF]}=grab [${COLORS[YELLOW]}${COLORS[BOLD]}:ga:${COLORS[OFF]}]"
|
||||
header_tmpl+=", ${COLORS[BOLD]}${help_key}${COLORS[OFF]}=help"
|
||||
|
||||
get_cap() {
|
||||
case "$mode" in
|
||||
"all")
|
||||
capture_panes | $extrakto --warn-empty --alt --all --name -r
|
||||
;;
|
||||
"line")
|
||||
capture_panes | $extrakto --warn-empty -r --lines
|
||||
;;
|
||||
"path")
|
||||
capture_panes | $extrakto --warn-empty -r --paths
|
||||
;;
|
||||
"url")
|
||||
capture_panes | $extrakto --warn-empty -r --urls
|
||||
;;
|
||||
"word")
|
||||
capture_panes | $extrakto --warn-empty -r --words
|
||||
;;
|
||||
*)
|
||||
# custom filters
|
||||
capture_panes | $extrakto --warn-empty -ra $mode
|
||||
;;
|
||||
|
||||
esac
|
||||
}
|
||||
|
||||
while true; do
|
||||
header=$header_tmpl
|
||||
header=${header/:ga:/$grab_area}
|
||||
header=${header/:filter:/$mode}
|
||||
header=${header//ctrl-/^}
|
||||
|
||||
# for troubleshooting add
|
||||
# tee /tmp/stageN | \
|
||||
# between the commands
|
||||
out="$(get_cap \
|
||||
| $fzf_tool \
|
||||
--multi \
|
||||
--print-query \
|
||||
--query="$query" \
|
||||
--header="$header" \
|
||||
--expect=${insert_key},${copy_key},${filter_key},${edit_key},${open_key},${grab_key},${help_key},ctrl-c,esc \
|
||||
--tiebreak=index \
|
||||
--layout="$fzf_layout" \
|
||||
--no-info)"
|
||||
res=$?
|
||||
{
|
||||
read query
|
||||
read key
|
||||
mapfile -t selection
|
||||
} <<< "$out"
|
||||
|
||||
if [[ $res -gt 0 && -z "$key" ]]; then
|
||||
show_fzf_error
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$mode" in
|
||||
all)
|
||||
text="${selection[@]#*: }"
|
||||
;;
|
||||
line)
|
||||
IFS=$'\n' text="${selection[*]}"
|
||||
;;
|
||||
*)
|
||||
text="${selection[@]}"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$key" in
|
||||
"${copy_key}")
|
||||
copy "$text"
|
||||
return 0
|
||||
;;
|
||||
|
||||
"${insert_key}")
|
||||
tmux set-buffer -- "$text"
|
||||
tmux paste-buffer -p -t $trigger_pane
|
||||
return 0
|
||||
;;
|
||||
|
||||
"${filter_key}")
|
||||
mode=$(get_next_mode $mode)
|
||||
;;
|
||||
|
||||
"${grab_key}")
|
||||
# cycle between options like this:
|
||||
# recent -> full -> window recent -> window full -> custom (if any) -> recent ...
|
||||
if [[ $grab_area == "recent" ]]; then
|
||||
if has_single_pane; then
|
||||
grab_area="full"
|
||||
else
|
||||
grab_area="window recent"
|
||||
fi
|
||||
elif [[ $grab_area == "window recent" ]]; then
|
||||
grab_area="full"
|
||||
elif [[ $grab_area == "full" ]]; then
|
||||
if has_single_pane; then
|
||||
grab_area="recent"
|
||||
|
||||
if [[ ! "$original_grab_area" =~ ^(window )?(recent|full)$ ]]; then
|
||||
grab_area="$original_grab_area"
|
||||
fi
|
||||
else
|
||||
grab_area="window full"
|
||||
fi
|
||||
elif [[ $grab_area == "window full" ]]; then
|
||||
grab_area="recent"
|
||||
|
||||
if [[ ! "$original_grab_area" =~ ^(window )?(recent|full)$ ]]; then
|
||||
grab_area="$original_grab_area"
|
||||
fi
|
||||
else
|
||||
grab_area="recent"
|
||||
fi
|
||||
|
||||
capture_pane_start=$(get_capture_pane_start "$grab_area")
|
||||
;;
|
||||
|
||||
"${open_key}")
|
||||
open "$text"
|
||||
return 0
|
||||
;;
|
||||
|
||||
"${edit_key}")
|
||||
tmux send-keys -t $trigger_pane "$editor -- $text" 'C-m'
|
||||
return 0
|
||||
;;
|
||||
|
||||
"${help_key}")
|
||||
clear
|
||||
less -+EF $(realpath "$current_dir/../HELP.md")
|
||||
|
||||
echo -e "\nSince the help page is not 'extrakt'-able:"
|
||||
read -p "Do you wish to [o]pen or [c]opy the GitHub page or [a]bort? [ocA]" -d'' -s -n1 confirm
|
||||
if [[ $confirm == o ]]; then
|
||||
open $PRJ_URL
|
||||
elif [[ $confirm == c ]]; then
|
||||
copy $PRJ_URL
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Entry
|
||||
|
||||
if [[ $launch_mode != popup ]]; then
|
||||
# check terminal size, zoom pane if too small
|
||||
lines=$(tput lines)
|
||||
if [[ $lines -lt 7 ]]; then
|
||||
tmux resize-pane -Z
|
||||
fi
|
||||
fi
|
||||
|
||||
capture
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
current_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "$current_dir/helpers.sh"
|
||||
extrakto="$current_dir/extrakto.sh"
|
||||
|
||||
pane_id=$1
|
||||
split_direction=$(get_option "@extrakto_split_direction")
|
||||
|
||||
if [[ $split_direction == a ]]; then
|
||||
if [[ -n $(tmux list-commands popup) ]]; then
|
||||
split_direction=p
|
||||
else
|
||||
split_direction=v
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $split_direction == p ]]; then
|
||||
IFS=, read popup_width popup_height <<< "$(get_option "@extrakto_popup_size")"
|
||||
IFS=, read popup_x popup_y <<< "$(get_option "@extrakto_popup_position")"
|
||||
rc=129
|
||||
while [ $rc -eq 129 ]; do
|
||||
tmux popup \
|
||||
-w ${popup_width} \
|
||||
-h ${popup_height:-$popup_width} \
|
||||
-x ${popup_x} \
|
||||
-y ${popup_y:-$popup_x} \
|
||||
-E "${extrakto} ${pane_id} popup"
|
||||
rc=$?
|
||||
done
|
||||
exit $rc
|
||||
else
|
||||
split_size=$(get_option "@extrakto_split_size")
|
||||
tmux split-window -${split_direction} -l ${split_size} "tmux setw remain-on-exit off; ${extrakto} ${pane_id} split"
|
||||
fi
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
get_tmux_option() {
|
||||
local option default_value option_value
|
||||
|
||||
option=$1
|
||||
default_value=$2
|
||||
option_value=$(tmux show-option -gqv "$option")
|
||||
|
||||
if [[ -z "$option_value" ]]; then
|
||||
echo "$default_value"
|
||||
else
|
||||
echo "$option_value"
|
||||
fi
|
||||
}
|
||||
|
||||
get_option() {
|
||||
local option=$1
|
||||
|
||||
case "$option" in
|
||||
"@extrakto_key")
|
||||
echo $(get_tmux_option $option "tab")
|
||||
;;
|
||||
|
||||
"@extrakto_split_direction")
|
||||
echo $(get_tmux_option $option "a")
|
||||
;;
|
||||
|
||||
"@extrakto_split_size")
|
||||
echo $(get_tmux_option $option "7")
|
||||
;;
|
||||
|
||||
"@extrakto_grab_area")
|
||||
echo $(get_tmux_option $option "window full")
|
||||
;;
|
||||
|
||||
"@extrakto_clip_tool")
|
||||
echo $(get_tmux_option $option "auto")
|
||||
;;
|
||||
|
||||
"@extrakto_fzf_tool")
|
||||
echo $(get_tmux_option $option "fzf")
|
||||
;;
|
||||
|
||||
"@extrakto_open_tool")
|
||||
echo $(get_tmux_option $option "auto")
|
||||
;;
|
||||
|
||||
"@extrakto_copy_key")
|
||||
echo $(get_tmux_option $option "enter")
|
||||
;;
|
||||
|
||||
"@extrakto_insert_key")
|
||||
echo $(get_tmux_option $option "tab")
|
||||
;;
|
||||
|
||||
"@extrakto_filter_key")
|
||||
echo $(get_tmux_option $option "ctrl-f")
|
||||
;;
|
||||
|
||||
"@extrakto_open_key")
|
||||
echo $(get_tmux_option $option "ctrl-o")
|
||||
;;
|
||||
|
||||
"@extrakto_edit_key")
|
||||
echo $(get_tmux_option $option "ctrl-e")
|
||||
;;
|
||||
|
||||
"@extrakto_grab_key")
|
||||
echo $(get_tmux_option $option "ctrl-g")
|
||||
;;
|
||||
|
||||
"@extrakto_help_key")
|
||||
echo $(get_tmux_option $option "ctrl-h")
|
||||
;;
|
||||
|
||||
"@extrakto_clip_tool_run")
|
||||
echo $(get_tmux_option $option "bg")
|
||||
;;
|
||||
|
||||
"@extrakto_popup_size")
|
||||
echo $(get_tmux_option $option "90%")
|
||||
;;
|
||||
|
||||
"@extrakto_popup_position")
|
||||
echo $(get_tmux_option $option "C")
|
||||
;;
|
||||
|
||||
"@extrakto_fzf_layout")
|
||||
echo $(get_tmux_option $option "default")
|
||||
;;
|
||||
|
||||
"@extrakto_filter_order")
|
||||
echo $(get_tmux_option $option "word all line")
|
||||
;;
|
||||
|
||||
"@extrakto_fzf_unset_default_opts")
|
||||
echo $(get_tmux_option $option "true")
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# This returns the start point parameter for `tmux capture-pane`.
|
||||
# The result will depend on how the user has set the grab area and grab size.
|
||||
get_capture_pane_start() {
|
||||
local grab_area capture_start history_limit
|
||||
|
||||
grab_area="$1"
|
||||
|
||||
if [[ "$grab_area" == "recent" || "$grab_area" == "window recent" ]]; then
|
||||
capture_start="-10"
|
||||
|
||||
elif [[ "$grab_area" == "full" || "$grab_area" == "window full" ]]; then
|
||||
# use the history limit, this is all the data on the pane
|
||||
# if not set just go with tmux's default
|
||||
history_limit=$(get_tmux_option "history-limit" "2000")
|
||||
capture_start="-${history_limit}"
|
||||
|
||||
elif [[ "$grab_area" =~ ^window\ ]]; then
|
||||
# use the user defined limit for how much to grab from every pane in the current window
|
||||
capture_start="-${grab_area:7}"
|
||||
|
||||
else
|
||||
# use the user defined limit for how much to grab from the current pane
|
||||
capture_start="-${grab_area}"
|
||||
fi
|
||||
|
||||
echo "$capture_start"
|
||||
}
|
||||
|
||||
# Implement ordered filters list as defined by @extrakto_filter_order
|
||||
declare -A next_mode
|
||||
declare -a modes_list
|
||||
|
||||
# If there is a bogus filter mode name in the list,
|
||||
# fall back to the default list of "word all line"
|
||||
sanitize_modes_list() {
|
||||
# in case of further "first class" filter modes implemented in the future
|
||||
# add their names to the following default list and valid_modes set
|
||||
local -a default=("word" "all" "line")
|
||||
local -A valid_modes=(["word"]=1
|
||||
["all"]=1
|
||||
["line"]=1
|
||||
["url"]=1
|
||||
["path"]=1
|
||||
["quote"]=1
|
||||
["s-quote"]=1)
|
||||
|
||||
local invalid=false
|
||||
for mode in ${modes_list[@]}; do
|
||||
if [[ ${valid_modes[$mode]} -ne 1 ]]; then
|
||||
invalid=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $invalid == true ]]; then
|
||||
# change $modes_list to $default
|
||||
for i in ${!default[@]}; do
|
||||
modes_list[$i]=${default[$i]}
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# transform the modes_list acquired from @extrakto_filter_order into
|
||||
# the more usable form of associative array
|
||||
mk_next_mode_map() {
|
||||
for i in ${!modes_list[@]}; do
|
||||
if [[ $i -eq $((${#modes_list[@]} - 1)) ]]; then
|
||||
next_mode+=([${modes_list[$i]}]=${modes_list[0]})
|
||||
else
|
||||
next_mode+=([${modes_list[$i]}]=${modes_list[$((i + 1))]})
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# initialize
|
||||
modes_list_init() {
|
||||
readarray -td ' ' modes_list <<< "$(get_option @extrakto_filter_order) "
|
||||
unset 'modes_list[-1]'
|
||||
sanitize_modes_list
|
||||
mk_next_mode_map
|
||||
}
|
||||
|
||||
# get next mode in order defined by @extrakto_filter_order
|
||||
get_next_mode() {
|
||||
if [[ ${#modes_list[@]} -eq 0 || ${#next_mode[@]} -le ${#modes_list[@]} ]]; then
|
||||
modes_list_init
|
||||
fi
|
||||
|
||||
local next=$1
|
||||
if [ $next == "initial" ]; then
|
||||
echo ${modes_list[0]}
|
||||
else
|
||||
echo ${next_mode[$next]}
|
||||
fi
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
|
||||
prefix [/path/in_brackets] suffix
|
||||
[/path/in_brackets]
|
||||
prefix [path/in_brackets] suffix
|
||||
[path/in_brackets]
|
||||
prefix (/path/in-parantheses) suffix
|
||||
(/path/in-parantheses)
|
||||
prefix (path/in-parantheses) suffix
|
||||
(path/in-parantheses)
|
||||
prefix "/path/in/quotes" suffix
|
||||
"/path/in/quotes"
|
||||
prefix "path/in/quotes" suffix
|
||||
"path/in/quotes"
|
||||
prefix '/path/in-single' suffix
|
||||
'/path/in-single'
|
||||
prefix 'path/in-single' suffix
|
||||
'path/in-single'
|
||||
prefix ~/home/path suffix
|
||||
~/home/path
|
||||
|
||||
prompt:~/dot$ git status
|
||||
modified: home/.tmux.conf
|
||||
deleted: home/tools/bin/hello
|
||||
new file: home/.laktakrc
|
||||
|
||||
non path: 100 k/s 50m/s 10k/s
|
||||
non path: page 1/2
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
/path/in_brackets
|
||||
path/in_brackets
|
||||
/path/in-parantheses
|
||||
path/in-parantheses
|
||||
/path/in/quotes
|
||||
path/in/quotes
|
||||
/path/in-single
|
||||
path/in-single
|
||||
~/home/path
|
||||
~/dot
|
||||
home/.tmux.conf
|
||||
home/tools/bin/hello
|
||||
home/.laktakrc
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
prefix
|
||||
/path/in_brackets
|
||||
suffix
|
||||
path/in_brackets
|
||||
/path/in-parantheses
|
||||
path/in-parantheses
|
||||
/path/in/quotes
|
||||
path/in/quotes
|
||||
/path/in-single
|
||||
path/in-single
|
||||
~/home/path
|
||||
prompt:~/dot
|
||||
status
|
||||
modified
|
||||
home/.tmux.conf
|
||||
deleted
|
||||
home/tools/bin/hello
|
||||
home/.laktakrc
|
||||
50m/s
|
||||
10k/s
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
foo "simple quote" bar
|
||||
foo "first quote" foobar "second quote" bar
|
||||
foo 'single quote' bar
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
simple quote
|
||||
"simple quote"
|
||||
first quote
|
||||
"first quote"
|
||||
second quote
|
||||
"second quote"
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
simple
|
||||
quote
|
||||
first
|
||||
foobar
|
||||
second
|
||||
single
|
||||
|
|
@ -1,706 +0,0 @@
|
|||
|
||||
Text from [teaching.idallen.com](http://teaching.idallen.com/cst8207/12f/notes/160_pathnames.html)
|
||||
|
||||
Unix/Linux File System and Pathnames (ROOT, absolute, relative, dot, dot dot)
|
||||
Ian! D. Allen – idallen@idallen.ca – www.idallen.com
|
||||
Fall 2012 - September to December 2012 - Updated 2017-02-25 06:30 EST
|
||||
|
||||
Course Home Page Course Outline All Weeks Plain Text
|
||||
|
||||
Updated: 2017-02-25 06:30 EST
|
||||
|
||||
1 The Unix/Linux File System Structure
|
||||
1.1 One file system ROOT
|
||||
1.2 No loops or cycles
|
||||
2 Name components can contain any character except slash
|
||||
3 Pathnames ("path of names") separated by slashes
|
||||
3.1 Destination object may be file, directory, or other
|
||||
3.2 Only one name doesn’t need any slashes as separators
|
||||
4 Slashes separate name components
|
||||
4.1 The ROOT directory precedes the leftmost slash
|
||||
5 The topmost ROOT directory / has no name
|
||||
5.1 By convention, we call the ROOT directory "slash" or /
|
||||
6 Only directories lead to other names
|
||||
6.1 Pathnames ending in directories followed by slashes (ok)
|
||||
6.2 Pathnames ending in files followed by slashes (wrong)
|
||||
7 Definition of basename
|
||||
8 Absolute and Relative pathnames
|
||||
8.1 Absolute pathnames start with a slash /
|
||||
8.1.1 Absolute pathnames always start at the system ROOT
|
||||
8.2 Relative pathnames do not start with a slash
|
||||
8.2.1 Relative pathnames start in the current working directory
|
||||
8.2.2 Using relative pathnames saves typing
|
||||
8.3 Differences between absolute and relative
|
||||
8.3.1 Examples of different relative pathnames
|
||||
8.3.2 Current Directory + Relative Pathname = Absolute Pathname
|
||||
8.4 Pathnames such as ~, ~user, and $HOME may become Absolute
|
||||
8.4.1 Leading tilde may mean absolute
|
||||
8.4.2 leading $HOME variable may mean absolute
|
||||
8.5 Rule for absolute pathnames in the shell
|
||||
9 Relative Pathnames Exercise
|
||||
9.1 Using absolute pathnames
|
||||
9.2 Six slashes means seven names
|
||||
9.3 Current directory /home/user/lab/foo/bar
|
||||
9.4 Current directory /home/user/lab/foo
|
||||
9.5 Current directory /home/user/lab
|
||||
9.6 Current directory /home/user
|
||||
9.7 Current directory /home
|
||||
9.8 Current directory / (ROOT)
|
||||
10 Dot and Dot Dot – . and ..
|
||||
10.1 Using ls -a to show hidden dot files
|
||||
10.2 Example: /tmp/. and /./tmp
|
||||
10.3 Example: /tmp/..
|
||||
10.4 Example: /home/idallen/bin/../..
|
||||
10.5 ROOT is its own parent directory
|
||||
10.5.1 Examples: /../tmp and /../../../../../tmp
|
||||
10.6 Using .. for shorter pathnames
|
||||
11 Redundant but useful ./ prefix
|
||||
11.1 Removing a file that looks like an option (e.g. -r)
|
||||
11.2 Don’t put ./ in front of relative pathnames
|
||||
12 Understanding Pathnames Exercises
|
||||
12.1 Relative pathnames exercise
|
||||
12.2 Absolute pathnames exercise
|
||||
12.3 Relative pathnames exercise with dir1
|
||||
12.4 Absolute pathnames exercise with dir1
|
||||
12.5 Pathnames exercises involving ROOT
|
||||
12.6 Copy exercise: two pathnames
|
||||
|
||||
1 The Unix/Linux File System Structure
|
||||
|
||||
Unix/Linux files are organized within a single-tree hierarchical file system structure made up of files containing data (e.g. documents, programs), and directories (folders) that may contain other sub-directories and files.
|
||||
1.1 One file system ROOT
|
||||
|
||||
Unlike Windows with separate multiple drive letters (A:, B:, C:, etc.) for each disk partition, the Unix/Linux file system hides the physical disk structure and has a single tree root, no matter how many disks or partitions are actually in use. There is no way to tell on what disk partition a Unix/Linux file resides by looking at its name.
|
||||
1.2 No loops or cycles
|
||||
|
||||
The directory structure in the file system is "acyclic" – following a path of directories down from the tree root into sub-directories will never lead you back toward the tree root into a "cycle" or loop.
|
||||
|
||||
Each file and directory has its own name.
|
||||
2 Name components can contain any character except slash
|
||||
|
||||
The name of some object in the file system may contain any characters except the NUL character and forward slashes (/). The name may contain spaces, newlines, unprintable control characters, and characters from non-English languages.
|
||||
|
||||
Yes, you can have a file or directory name that is entirely made of blanks or backspace characters!
|
||||
|
||||
A single Linux name component is typically limited to 255 characters. Older Unix systems may have smaller limits.
|
||||
3 Pathnames ("path of names") separated by slashes
|
||||
|
||||
A Unix/Linux pathname is a text string made up of one or more names separated by slashes. The pathname indicates how to find something in the hierarchical file system tree. Here are some examples of pathnames:
|
||||
|
||||
/home
|
||||
/etc/passwd
|
||||
/usr/bin/wc
|
||||
/var/log/ntpstats/loopstats
|
||||
/home/abcd0001/CST8207-16W/Assignments/assignment02
|
||||
|
||||
A pathname is literally a "path of names" through the hierarchy. A pathname specifies how to traverse (navigate) the hierarchical directory names in the file system to reach some destination object.
|
||||
|
||||
The pathname text string will contain, in order, the directories you need to go through to arrive at the destination. To do this, the pathname text string lists one or more name components separated by forward slashes, e.g. /etc/passwd, /usr/bin/wc. This is why individual file and directory names cannot themselves contain slashes – slashes are used to separate the names in pathname text strings.
|
||||
3.1 Destination object may be file, directory, or other
|
||||
|
||||
The destination object identified by the name at the far right end of a pathname text string might be a file, a directory, or some other thing such as system memory, a disk partition, or a terminal device. (Unix/Linux also uses the file system to name many things that are not ordinary files or directories.)
|
||||
3.2 Only one name doesn’t need any slashes as separators
|
||||
|
||||
A pathname with only one name component doesn’t need to have any slashes to separate it from other name components, e.g. resume, cal.txt, dir.exe.
|
||||
|
||||
Slashes are only used to separate name components in a pathname; an individual name component can never itself contain a slash. Slashes are never part of a name component; they separate the names in a pathname.
|
||||
|
||||
A Linux pathname text string has an overall limit of 4,096 characters including all the individual names and all the separating slashes. Older Unix systems have a smaller limit.
|
||||
|
||||
Unlike Windows, Unix/Linux file system name components are separated by forward slashes (/), not backslashes (\). You can blame Microsoft for this annoying difference: Unix came first and Microsoft deliberately chose a different separator character, likely to avoid being sued by AT&T for copying the Unix file system naming.
|
||||
|
||||
You will note that Internet World-Wide-Web URL pathnames use the Unix forward slash separator (e.g. http://teaching.idallen.com/, because the web was invented and grew up on Unix machines.
|
||||
|
||||
4 Slashes separate name components
|
||||
|
||||
Consider the following Unix/Linux pathname text string, composed of several individual name components separated by forward slashes:
|
||||
|
||||
/home/idallen/bin/file.txt
|
||||
|
||||
Since slashes always separate name components, a pathname with four slashes in it must contain and separate five name components. In this example above, those five name components are:
|
||||
|
||||
"" (the nameless "ROOT" directory, to the left of the leftmost slash)
|
||||
home
|
||||
idallen
|
||||
bin
|
||||
file.txt
|
||||
|
||||
4.1 The ROOT directory precedes the leftmost slash
|
||||
|
||||
Yes, there is actually an implied directory to the left of the leftmost slash in a pathname that starts with a slash! It is the nameless "ROOT" directory, the unique tree root of the whole hierarchical file system tree, where all pathnames originate.
|
||||
5 The topmost ROOT directory / has no name
|
||||
|
||||
Slashes always separate name components. If a pathname starts with a slash, e.g. /etc/passwd, the nameless "ROOT" directory is what begins the pathname at the far left end. This top-most ROOT directory itself has no name. It is the starting point or the tree root of the entire hierarchical Unix/Linux file system tree.
|
||||
|
||||
A pathname starting with a slash is called an absolute pathname. It always starts at the unique topmost file system ROOT directory.
|
||||
5.1 By convention, we call the ROOT directory "slash" or /
|
||||
|
||||
Because it is difficult to talk about a directory that has no name, we usually (incorrectly) use the name / (slash) for the ROOT directory. This is technically wrong, because name components of a pathname can’t contain slashes – the slashes separate the name components. So nothing can have an actual name of /. Still, we often call the topmost ROOT directory slash (/).
|
||||
|
||||
Understand that when we use the name slash (/) for ROOT, we really mean "the nameless topmost ROOT directory that is to the left of the separating slash", not the slash itself.
|
||||
|
||||
NOTE! Do not confuse the topmost file system ROOT directory, that has no name, with an actual directory named /root that is usually the HOME directory of the system account named root. In these notes we use upper-case ROOT to refer to the root of the file system, and just root to refer to a directory named root.
|
||||
|
||||
6 Only directories lead to other names
|
||||
|
||||
To be a valid pathname ("path of names") in the file system, every name component that is to the left of the rightmost slash in a pathname must either be a directory or be a symbolic link to a directory.
|
||||
|
||||
Only directories can have substructure that may lead to other names.
|
||||
|
||||
If the pathname /home/idallen/bin/file.txt is to be a valid path of names through the file system hierarchy, the first four name components (the ROOT, home, idallen, and bin) must name existing directories. Only directories can contain and lead to other names. The four name components to the left of the rightmost slash must be names for existing directories (or be symbolic links to existing directories).
|
||||
|
||||
In /home/idallen/bin/file.txt, the final component name file.txt (the name to the right of the rightmost slash) is the name of the file system object itself. It might be a file or directory or anything else, though the name file.txt suggests that it is a text file name.
|
||||
|
||||
The final named component in the pathname, after the rightmost slash, can name anything – a file, directory, symbolic link, or other special file.
|
||||
6.1 Pathnames ending in directories followed by slashes (ok)
|
||||
|
||||
If a pathname ends in a directory name followed by a slash at the right end, e.g. /usr/bin/ or dir/, the self-referential name . (dot, or period) is assumed after the ending slash. In a directory, . refers to the directory itself. For example, all these are equivalent:
|
||||
|
||||
$ ls /bin
|
||||
...many names print here...
|
||||
$ ls /bin/
|
||||
...same names print here...
|
||||
$ ls /bin/.
|
||||
...same names print here...
|
||||
|
||||
Putting one or more slashes at the right end of a directory pathname makes almost no difference – it usually refers to the same directory:
|
||||
|
||||
$ ls /bin
|
||||
...many names print here...
|
||||
$ ls /bin/
|
||||
...same names print here...
|
||||
$ ls /bin//
|
||||
...same names print here...
|
||||
$ ls /bin////////////////////////////////
|
||||
...same names print here...
|
||||
|
||||
In most pathnames ending in a directory name dir, all the names dir and dir/ and dir/. refer to the same dir directory. The trailing slash or slash-plus-dot don’t make any difference.
|
||||
|
||||
If the last name component in a pathname is a symbolic link to a directory, e.g. /dir/symlink, trailing slashes may result in different behaviour with some commands. More on symbolic links later.
|
||||
|
||||
By convention, multiple adjacent slashes are treated as one slash and do not create additional implied names. The pathnames /etc/passwd and ///etc///////passwd are equivalent.
|
||||
6.2 Pathnames ending in files followed by slashes (wrong)
|
||||
|
||||
A name component that names a file cannot be followed by a slash in a valid pathname. Only a directory name can have a slash to its right, because only directories can contain and lead to other names.
|
||||
|
||||
Putting a slash to the right of a non-directory (e.g. a file) results in an invalid pathname. Here is an example using the file pathname /etc/passwd:
|
||||
|
||||
$ wc /etc/passwd
|
||||
37 89 1802 /etc/passwd # expected command output
|
||||
$ wc /etc/passwd/
|
||||
wc: /etc/passwd/: Not a directory # error message!
|
||||
$ wc /etc/passwd/.
|
||||
wc: /etc/passwd/.: Not a directory # error message!
|
||||
$ wc /etc/passwd/..
|
||||
wc: /etc/passwd/..: Not a directory # error message!
|
||||
|
||||
In a directory named /tmp/dir, the pathname /tmp/dir/../dir is the same as /tmp/dir, but if /tmp/f is a file name, the pathname /tmp/f/../f is invalid: Not a directory.
|
||||
|
||||
You can’t put a slash after a file name component, because the file name component isn’t a directory that leads to other names. You can’t use a file name as if it were a directory. The error message tells you this.
|
||||
7 Definition of basename
|
||||
|
||||
Definition of basename: The basename of any pathname is its right-most name component, to the right of its right-most slash.
|
||||
|
||||
pathname /home/user/file has a basename of file
|
||||
pathname /usr/lib/file has a basename of file
|
||||
pathname /etc/file has a basename of file
|
||||
pathname /bin/grep has a basename of grep
|
||||
pathname bin/grep has a basename of grep
|
||||
pathname ./grep has a basename of grep
|
||||
pathname grep has a basename of grep
|
||||
pathname bin/. has a basename of .
|
||||
pathname /etc/.. has a basename of ..
|
||||
pathname lib/ has an empty basename
|
||||
|
||||
Several different files with the same basename can exist on a Unix/Linux system, in different directories (as in the example above of /home/user/file and /usr/lib/file that have the same basename but reside in different directories).
|
||||
8 Absolute and Relative pathnames
|
||||
|
||||
Pathnames come in two flavours: absolute and relative:
|
||||
|
||||
Absolute pathnames start with a slash on the left, e.g. /etc/passwd
|
||||
Relative pathnames do not start with a slash, e.g. etc/passwd
|
||||
|
||||
8.1 Absolute pathnames start with a slash /
|
||||
|
||||
A pathname that starts with a leading slash on the left is called an absolute pathname, e.g. /etc/passwd, /root/.bashrc, /bin, /, etc.
|
||||
|
||||
The leading slash on the left indicates that the pathname starts at the topmost nameless ROOT directory in the file system.
|
||||
8.1.1 Absolute pathnames always start at the system ROOT
|
||||
|
||||
An absolute pathname traverses the file system hierarchy tree from the very top, always starting at the topmost ROOT directory of the file system hierarchy. The topmost ROOT directory is signalled by the leading "slash" character (/) at the start of an absolute pathname.
|
||||
|
||||
Absolute pathnames always start with this topmost ROOT directory slash and descend through every directory name that leads down to the destination, e.g. /home/user/file or /usr/bin/grep or /bin/ls or /etc/passwd.
|
||||
|
||||
The slash must always be at the start (left) of an absolute pathname.
|
||||
8.2 Relative pathnames do not start with a slash
|
||||
|
||||
Pathnames with no leading slash on the left are called relative pathnames.
|
||||
|
||||
A relative pathname never starts with a slash on the left, but it may contain slashes anywhere else: /bar is not relative (it is an absolute pathname) but bar and bar/ and ./bar and ../bar and foo/bar are all relative pathnames.
|
||||
|
||||
A relative pathname is used along with the current working directory to avoid typing long pathnames.
|
||||
8.2.1 Relative pathnames start in the current working directory
|
||||
|
||||
To save typing long pathnames all the time, many operating systems (including Unix/Linux and DOS) have the concept of a saved current working directory, also called current directory or working directory.
|
||||
|
||||
Every process in Linux can save one absolute directory pathname to be its current working directory. This working directory can be set and changed in shells using the built-in cd (change directory) command, e.g. cd /home/idallen. The current working directory can be displayed in shells using the pwd (print working directory) command.
|
||||
|
||||
If a process refers to a pathname that is relative (does not start with a slash), the saved current directory is always automatically prefixed to ("inserted in front of") the beginning of the pathname.
|
||||
|
||||
For example, if the current working directory of a process is the absolute pathname /usr/bin then all relative pathnames used by the process have /usr/bin prefixed in front of them:
|
||||
|
||||
In /usr/bin relative pathname foo is the same as as: /usr/bin/foo
|
||||
In /usr/bin relative pathname ../etc is the same as as: /usr/bin/../etc
|
||||
In /usr/bin relative pathname ./hello is the same as as: /usr/bin/./hello
|
||||
In /usr/bin relative pathname . (dot) is the same as as: /usr/bin/.
|
||||
In /usr/bin absolute pathname /bin is unchanged, since it is not a relative pathname.
|
||||
|
||||
If you then change the current working directory of the process to be the absolute pathname /home then all relative pathnames used by the process now have /home prefixed in front of them instead:
|
||||
|
||||
In /home relative pathname foo is the same as: /home/foo
|
||||
In /home relative pathname ../etc is the same as: /home/../etc
|
||||
In /home relative pathname ./hello is the same as: /home/./hello
|
||||
In /home relative pathname . (dot) is the same as: /home/.
|
||||
In /home absolute pathname /bin is unchanged, since it is not a relative pathname.
|
||||
|
||||
The saved current directory of a process is only prefixed to relative pathname references – pathnames that do not start with a slash. Absolute pathnames (starting with a slash) are not affected.
|
||||
|
||||
Changing the saved current directory of a process changes the meaning of relative pathnames used by the process. You don’t know what relative path foo means until you know what saved current directory is going to be prefixed in front of it.
|
||||
|
||||
The saved current working directory of a process has no effect on an absolute pathname. An absolute pathname always starts at the ROOT and doesn’t depend on the saved current directory of a process. The current directory is not used when evaluating absolute pathnames. Absolute pathname /etc/passwd always always refers to the same file, no matter what the current directory of a process might be.
|
||||
|
||||
8.2.2 Using relative pathnames saves typing
|
||||
|
||||
Shells have change directory commands that let you change the saved current working directory of the shell, and of all the commands run by the shell, so that you can then type shorter relative pathnames, instead of always using long absolute pathnames. The shell change directory command is often named cd, e.g.: cd /usr/bin
|
||||
|
||||
Saving an appropriate current working directory prefix and using relative pathnames can make using pathnames in shell command lines much shorter to type. For example, to copy file /usr/bin/foo to /usr/bin/bar looks like this when using absolute pathnames in a shell command line:
|
||||
|
||||
$ cp /usr/bin/foo /usr/bin/bar # using two absolute pathnames
|
||||
|
||||
Setting an appropriate current working directory with cd and switching to using relative pathnames in the copy command makes the command much simpler to type:
|
||||
|
||||
$ cd /usr/bin
|
||||
$ cp foo bar # two relative pathnames each use current directory
|
||||
|
||||
The relative pathname foo automatically becomes /usr/bin/foo and the relative pathname bar automatically becomes /usr/bin/bar thanks to the saved current working directory /usr/bin being prefixed to each pathname.
|
||||
|
||||
The saved current working directory is only prefixed to relative pathnames. Absolute pathnames remain unchanged.
|
||||
8.3 Differences between absolute and relative
|
||||
|
||||
Absolute pathnames always refer to the same, unique destination, since absolute pathnames always start with the topmost ROOT slash and don’t depend on the current directory of a process. Every process using an absolute pathname refers to the same, unique file system object, no matter what the current directory of the process is. For example, the absolute pathname /etc/passwd (starting with the topmost ROOT slash) always means the same file anywhere it is used, ignoring the current directory. The current directory is ignored for absolute pathnames.
|
||||
|
||||
Relative pathnames always start in the saved current directory of a process, so the final destination changes depending on the current directory of the process. The same relative pathname may refer to different things in processes that have different current directories. Changing the current directory changes the final destination of the relative pathname.
|
||||
8.3.1 Examples of different relative pathnames
|
||||
|
||||
If the saved current working directory of a process is /home/user, and the absolute pathname of a file is /home/user/file, then a relative pathname to that file (using the saved current directory prefix) is simply file (no leading slash):
|
||||
|
||||
$ cd /home/user
|
||||
$ cat file # relative path is same as /home/user/file
|
||||
|
||||
If the saved current working directory is changed to /home, then a relative pathname to that same file (using the saved current directory prefix) must be user/file:
|
||||
|
||||
$ cd /home
|
||||
$ cat user/file # relative path is same as /home/user/file
|
||||
|
||||
If the current directory is changed to / (the topmost ROOT), then the relative pathname to that same file (using the saved current directory prefix) must be home/user/file:
|
||||
|
||||
$ cd /
|
||||
$ cat home/user/file # relative path is same as /home/user/file
|
||||
|
||||
If your saved current working directory is the topmost ROOT directory, then absolute and relative pathnames look almost the same. The only difference is the leading slash on the absolute pathname:
|
||||
|
||||
$ cd /
|
||||
$ cat home/user/file # relative path is same as /home/user/file
|
||||
$ cat /home/user/file # equivalent absolute pathname
|
||||
|
||||
8.3.2 Current Directory + Relative Pathname = Absolute Pathname
|
||||
|
||||
The saved current directory is prefixed to a relative pathname, resulting in an absolute pathname. A current directory of /home/user plus a relative pathname of bin/script equals an absolute pathname of /home/user/bin/script.
|
||||
|
||||
To take an absolute pathname and turn it into a shorter relative pathname, using the saved current directory, take the absolute pathname and remove the current directory from the start, leaving a relative pathname (no leading slash). A current directory of /home/user removed from the start of an absolute pathname /home/user/bin/script leaves a relative pathname of bin/script:
|
||||
|
||||
$ cat /home/user/bin/script # (too) long absolute pathname
|
||||
$ cd /home/user # set working directory
|
||||
$ cat bin/script # use shorter relative pathname!
|
||||
$ cd /home/user/bin # set better working directory
|
||||
$ cat script # use even shorter relative pathname!
|
||||
|
||||
One of the major reasons we use relative pathnames is because they are usually much shorter to type than absolute pathnames. Choose a good working directory to make your relative pathnames short.
|
||||
8.4 Pathnames such as ~, ~user, and $HOME may become Absolute
|
||||
|
||||
Most Unix/Linux shells have short-cuts that let you specify short versions of absolute pathnames but where the syntax of the short-cut doesn’t start with a slash and so the short-cut doesn’t appear to be an absolute path, even though it is.
|
||||
|
||||
Here are some examples:
|
||||
8.4.1 Leading tilde may mean absolute
|
||||
|
||||
Shells may expand a leading tilde (~) on a token (command argument) to be the absolute pathname to the user’s home directory:
|
||||
|
||||
$ echo ~
|
||||
/home/user
|
||||
$ echo ~/bar
|
||||
/home/user/bar
|
||||
$ cat ~/bar # same as cat /home/user/bar
|
||||
|
||||
If the tilde stands alone or is immediately followed by a slash, the home directory substituted is the home directory found in the shell variable $HOME, which is usually set to the home directory of the user who is logged in (but can be changed).
|
||||
|
||||
Try this command line to see how the shell expands the tilde pathnames:
|
||||
|
||||
$ whoami
|
||||
idallen
|
||||
$ echo ~ ~/bin
|
||||
/home/idallen /home/idallen/bin
|
||||
|
||||
If the tilde is followed by a valid account name, e.g. ~idallen, the shell replaces the tilde and account name with the absolute pathname of the home directory of that account, e.g. idallen may have home /home/idallen.
|
||||
|
||||
Try this command line to see how the shell expands the tilde pathnames for different account names:
|
||||
|
||||
$ echo ~mail ~uucp ~games ~root ~nosuch
|
||||
/var/mail /var/spool/uucp /usr/games /root ~nosuch
|
||||
|
||||
Thus, ls ~idallen/bin secretly expands to and uses an absolute pathname, because, ~idallen is actually expanded (by the shell) to be the absolute path /home/idallen. Be aware of this!
|
||||
8.4.2 leading $HOME variable may mean absolute
|
||||
|
||||
Absolute pathnames may also hide inside shell variables, e.g. $HOME/foo could be expanded by the shell to be /home/idallen/foo, an absolute pathname:
|
||||
|
||||
$ echo "$HOME" "$HOME/bin"
|
||||
/home/idallen /home/idallen/bin
|
||||
|
||||
Thus, ls "$HOME/bin" secretly expands to and uses an absolute pathname, because, $HOME is actually expanded (by the shell) to be the absolute path /home/idallen. Be aware of this!
|
||||
8.5 Rule for absolute pathnames in the shell
|
||||
|
||||
The shells modify your command line before they call the command to be executed. These modifications can turn what look like relative pathnames (e.g. ~/bin) into absolute pathnames (e.g. /home/idallen/bin):
|
||||
|
||||
A pathname is absolute if and only if it starts with a leading slash after all shell expansions are finished. If the expanded pathname starts with a slash, the nameless ROOT directory is always the first directory in the pathname. Otherwise, without a starting slash, the pathname is relative to the current working directory and the current working directory is prefixed to the pathname.
|
||||
|
||||
Watch for hidden leading slashes inserted by your shell when expanding short-cuts such as ~, ~userid, and $HOME.
|
||||
9 Relative Pathnames Exercise
|
||||
|
||||
Given this absolute pathname to the file file.txt:
|
||||
|
||||
/home/user/lab/foo/bar/file.txt
|
||||
|
||||
Show how to rename file.txt to be file2.txt in the same directory, using relative pathnames, using as a starting point (a current directory) every directory from the bar directory up the tree to the topmost ROOT directory (giving six different answers, one for each different current working directory).
|
||||
|
||||
Show how the relative pathnames change depending on each of the six different current working directories.
|
||||
9.1 Using absolute pathnames
|
||||
|
||||
If we were using absolute pathnames, the command to rename the file would be very long:
|
||||
|
||||
$ mv /home/user/lab/foo/bar/file.txt /home/user/lab/foo/bar/file2.txt
|
||||
|
||||
Below, we show how different saved current working directories make the pathname shorter.
|
||||
9.2 Six slashes means seven names
|
||||
|
||||
The absolute file pathname /home/user/lab/foo/bar/file.txt contains six slashes, so it must have seven name components. The six name components to the left of the rightmost slash must be existing directories. There are six directories to the left of the final slash: ROOT, home, user, lab, foo, and bar.
|
||||
|
||||
We will start our answer in the bar directory and work our way up to the ROOT directory, giving six different answers:
|
||||
9.3 Current directory /home/user/lab/foo/bar
|
||||
|
||||
If the current working directory is bar (actually /home/user/lab/foo/bar), then a relative path to file.txt from the bar directory is simply file.txt, e.g.
|
||||
|
||||
$ cd /home/user/lab/foo/bar
|
||||
$ mv file.txt file2.txt
|
||||
|
||||
The file.txt relative pathname, used with a current working directory of /home/user/lab/foo/bar, means /home/user/lab/foo/bar/file.txt.
|
||||
|
||||
The file2.txt relative pathname, used with a current working directory of /home/user/lab/foo/bar, means /home/user/lab/foo/bar/file2.txt.
|
||||
|
||||
Now, go up one directory, from bar to its parent directory foo:
|
||||
9.4 Current directory /home/user/lab/foo
|
||||
|
||||
If the current working directory is foo (actually /home/user/lab/foo), then a relative path to file.txt from the foo directory is bar/file.txt, e.g.
|
||||
|
||||
$ cd /home/user/lab/foo # or use the parent directory: cd ..
|
||||
$ mv bar/file.txt bar/file2.txt
|
||||
|
||||
The bar/file.txt relative pathname, used with a current working directory of /home/user/lab/foo, means /home/user/lab/foo/bar/file.txt.
|
||||
|
||||
The bar/file2.txt relative pathname, used with a current working directory of /home/user/lab/foo, means /home/user/lab/foo/bar/file2.txt.
|
||||
|
||||
Now, go up one directory, from foo to its parent directory lab:
|
||||
9.5 Current directory /home/user/lab
|
||||
|
||||
If the current directory is lab (actually /home/user/lab), then a relative path to file.txt from lab is foo/bar/file.txt, e.g.
|
||||
|
||||
$ cd /home/user/lab # or use the parent directory: cd ..
|
||||
$ mv foo/bar/file.txt foo/bar/file2.txt
|
||||
|
||||
The foo/bar/file.txt relative pathname, used with a current working directory of /home/user/lab, means /home/user/lab/foo/bar/file.txt. Similar for foo/bar/file2.txt.
|
||||
|
||||
Now, go up one directory, from lab to its parent directory user:
|
||||
9.6 Current directory /home/user
|
||||
|
||||
If the current directory is user, then a relative path to file.txt from user is lab/foo/bar/file.txt, e.g.
|
||||
|
||||
$ cd /home/user # or use the parent directory: cd ..
|
||||
$ mv lab/foo/bar/file.txt lab/foo/bar/file2.txt
|
||||
|
||||
As with the previous examples, to find out the full pathname, concatenate the relative path to the end of the current working directory.
|
||||
|
||||
Now, go up one directory, from user to its parent directory home:
|
||||
9.7 Current directory /home
|
||||
|
||||
If the current directory is home, then a relative path to file.txt from home is user/lab/foo/bar/file.txt, e.g.
|
||||
|
||||
$ cd /home # or use the parent directory: cd ..
|
||||
$ mv user/lab/foo/bar/file.txt user/lab/foo/bar/file2.txt
|
||||
|
||||
Now, go up one directory, from home to its parent directory the ROOT:
|
||||
9.8 Current directory / (ROOT)
|
||||
|
||||
If the current directory is the ROOT then a relative path to file.txt from the ROOT is home/user/lab/foo/bar/file.txt, e.g.
|
||||
|
||||
$ cd / # or use the parent directory: cd ..
|
||||
$ mv home/user/lab/foo/bar/file.txt home/user/lab/foo/bar/file2.txt
|
||||
|
||||
The home/user/lab/foo/bar/file.txt relative pathname, used with a current working directory of / (ROOT), means /home/user/lab/foo/bar/file.txt.
|
||||
|
||||
Note that in every case above, the saved current directory when prefixed to the beginning of the relative path, gives the absolute path, e.g. in #5 above, the current directory /home prefixed to the relative pathname user/foo/bar/file.txt gives the absolute path /home/user/lab/foo/bar/file.txt – this is how current directories let us write shorter relative pathnames.
|
||||
|
||||
Your current working directory is NOT prefixed to absolute pathnames (that start with a slash). Absolute pathnames always start at the ROOT and are always independent of your current working directory.
|
||||
|
||||
Your current working directory is ONLY prefixed to relative pathnames (names that do not start with a slash).
|
||||
10 Dot and Dot Dot – . and ..
|
||||
|
||||
Every Unix directory contains two special names that you can’t change and can’t remove:
|
||||
|
||||
Every Unix directory contains the name . (dot), which is a name that leads right back to the directory in which it is found.
|
||||
|
||||
Every directory contains the name .. (dot dot), which is a name that leads to the unique parent directory of the directory in which it is found.
|
||||
|
||||
10.1 Using ls -a to show hidden dot files
|
||||
|
||||
The two directory names . and .. are in every Unix/Linux directory, but are not normally shown by the ls command unless you use the -a (all) option to display names that begin with a leading dot (period):
|
||||
|
||||
$ ls
|
||||
|
||||
$ ls -a
|
||||
. ..
|
||||
|
||||
$ ls -a -l
|
||||
drwx------ 2 idallen idallen 40 Sep 12 01:32 .
|
||||
drwxr-xr-x 26 root root 1600 Sep 12 01:33 ..
|
||||
|
||||
The ls command does not normally display any names that begin with a leading dot (period). Use the -a option to show them.
|
||||
10.2 Example: /tmp/. and /./tmp
|
||||
|
||||
The directory pathname /tmp contains two directories: the leading topmost ROOT directory and tmp. The pathname /tmp/. contains three directories, ROOT, tmp, and .. The . is searched for in the tmp directory in which it is contained, and leads right back to tmp; so, /tmp and /tmp/. are equivalent.
|
||||
|
||||
The directory pathname /./tmp contains three directories: ROOT, ., and tmp. The . is searched for in the ROOT directory in which it is contained, and leads right back to ROOT; so, /./tmp and /tmp are equivalent.
|
||||
|
||||
The directory pathname /./tmp/. contains four directories: ROOT, ., tmp, and .. The first (leftmost) . is searched for in the ROOT directory; the last (rightmost) . is searched for in the tmp directory. Thus, /./tmp/. is equivalent to just: /tmp
|
||||
10.3 Example: /tmp/..
|
||||
|
||||
The directory pathname /tmp/.. contains three directories: ROOT, tmp, and ... The .. is searched for in the tmp directory in which it is contained, and leads to the parent of the tmp directory (which is always ROOT, unless tmp is a symbolic link); so, /tmp/.. and / (ROOT) are usually equivalent.
|
||||
|
||||
We won’t deal with symbolic links in this document. If /tmp is a symbolic link to a directory, not an actual directory, then /tmp/.. may not be the same as /. More on that later.
|
||||
|
||||
10.4 Example: /home/idallen/bin/../..
|
||||
|
||||
The directory pathname /home/idallen/bin/../.. contains six directories: ROOT, home, idallen, bin, .., and ... The first .. is searched for in the bin directory in which it is contained and leads to the parent of the bin directory, which is idallen. The second .. is therefore searched for in the idallen directory in which it is contained, and leads to the parent of the idallen directory, which is home. Thus, /home/idallen/bin/../.. is equivalent to /home (unless there are symbolic links involved).
|
||||
|
||||
Each .. in a pathname backs up one directory level.
|
||||
|
||||
If any of the pathname components are symbolic links to directories, not real directories, then the actions of . and .. are not so well behaved and the answers may differ from those given above. (We won’t cover symbolic links here.) The ROOT directory can never be a symbolic link; so, /. and /.. (and /./. and /../../.., etc.) are always the same as / all by itself.
|
||||
10.5 ROOT is its own parent directory
|
||||
|
||||
The topmost ROOT directory is the only directory that is its own parent: both . and .. are the same in the ROOT directory. If you go to the parent of the ROOT directory, you are still in the ROOT directory.
|
||||
10.5.1 Examples: /../tmp and /../../../../../tmp
|
||||
|
||||
The directory pathname /../tmp contains three directories: ROOT, .., and tmp. The .. is searched for in the ROOT directory in which it is contained, and leads to the parent of the ROOT directory, which is (special case) also ROOT. ROOT is the only directory that is its own parent. Thus, /../tmp is the same as /tmp. Similarly, the pathname /../../../../../tmp is also the same as /tmp.
|
||||
10.6 Using .. for shorter pathnames
|
||||
|
||||
You can use .. to make shorter pathnames when typing. Here are three examples using the cp (copy) command:
|
||||
|
||||
$ cp /usr/local/foo /usr/local/bin/ # 1. using absolute pathnames
|
||||
|
||||
$ cd /usr/local # 2. set current directory; use
|
||||
$ cp foo bin/ # short relative pathnames
|
||||
|
||||
$ cd /usr/local/bin # 3. set current directory; use
|
||||
$ cp ../foo . # short relative pathnames
|
||||
|
||||
From the current directory /usr/local/bin, the pathname ../foo is a relative path that goes up one level to /usr/local and then down to foo inside /usr/local giving /usr/local/foo. That file is copied into the current directory (/usr/local/bin) using the relative pathname . (/usr/local/bin/.).
|
||||
|
||||
Using .. and . can shorten your pathnames considerably if you choose your current directory carefully.
|
||||
11 Redundant but useful ./ prefix
|
||||
|
||||
Putting ./ in front of any relative pathname does not change what the pathname refers to; the pathname is still relative to the current directory and still refers to the same thing. Don’t do it.
|
||||
|
||||
Given directory dir1, these pathname arguments are all valid and all refer to the same directory dir1, so don’t add the ./ because it isn’t needed:
|
||||
|
||||
$ ls dir1 # use this
|
||||
$ ls ./dir1 # same, but unnecessary
|
||||
$ ls ././dir1 # same, but more unnecessary
|
||||
$ ls ./././dir1 # same, but even more unnecessary
|
||||
|
||||
Given file name file1, these pathname arguments are also valid and all refer to the same file file1, so don’t add the ./ because it isn’t needed:
|
||||
|
||||
$ ls file1 # use this
|
||||
$ ls ./file1 # same, but unnecessary
|
||||
$ ls ././file1 # same, but more unnecessary
|
||||
$ ls ./././file1 # same, but even more unnecessary
|
||||
|
||||
11.1 Removing a file that looks like an option (e.g. -r)
|
||||
|
||||
If you create a file (or directory) with a name starting with a dash, e.g. named -r, the file name cannot be removed without some trickery, because the name looks like an option to the rm (or rmdir) command:
|
||||
|
||||
$ ls # show the files in the current directory
|
||||
-r # a problem file named "-r" !
|
||||
|
||||
$ rm -r # WRONG: does not remove file named "-r"
|
||||
rm: missing operand
|
||||
Try 'rm --help' for more information.
|
||||
|
||||
$ rmdir -r # WRONG: does not remove directory named "-r"
|
||||
rmdir: invalid option -- 'r'
|
||||
Try 'rmdir --help' for more information.
|
||||
|
||||
The trick is: You can put the superfluous ./ in front of the relative pathname to make the name stop looking like an option letter:
|
||||
|
||||
$ rm ./ -r # this works to remove a file named -r
|
||||
-OR-
|
||||
$ rmdir ./ -r # this works to remove a directory named -r
|
||||
|
||||
Of course, you can also use the full absolute pathname that starts with a slash, since that doesn’t look like an option letter either.
|
||||
|
||||
$ rm /home/idallen/ -r # this works! but it's long!
|
||||
$ rmdir /home/idallen/ -r # this works! but it's long!
|
||||
|
||||
11.2 Don’t put ./ in front of relative pathnames
|
||||
|
||||
The above option hiding tricks are the only reason to add ./ in front of a relative pathname. Don’t use ./ in front of a relative pathname unless you need to. This is superfluous:
|
||||
|
||||
$ touch ./foo # WRONG: ./ is not needed
|
||||
$ touch foo # RIGHT
|
||||
|
||||
Relative pathnames do not start with a slash. Putting ./ in front of a pathname that does not start with a slash is unnecessary.
|
||||
12 Understanding Pathnames Exercises
|
||||
|
||||
Below are some pathname exercises given this current working directory:
|
||||
|
||||
$ pwd
|
||||
/tmp/idallen
|
||||
|
||||
and this sub-structure in the current directory:
|
||||
|
||||
$ ls -l
|
||||
drwxr-xr-x 2 idallen idallen 4096 Feb 3 20:33 dir1
|
||||
-rw-r--r-- 1 idallen idallen 0 Feb 3 20:33 file1
|
||||
|
||||
Note that I have created name dir1 as a directory and name file1 as a file for all the examples below, though I could have called them any names.
|
||||
|
||||
For the exercises below, assume none of the names are symbolic links (which could change the answers).
|
||||
|
||||
12.1 Relative pathnames exercise
|
||||
|
||||
All the relative pathnames below give the same output, because all these relative pathnames refer to the same (current) directory /tmp/idallen:
|
||||
|
||||
$ pwd
|
||||
/tmp/idallen
|
||||
$ ls # with no pathname arguments, ls lists the current directory
|
||||
$ ls .
|
||||
$ ls ./.
|
||||
$ ls ././././././.
|
||||
$ ls dir1/.. # the parent directory of dir1 is the current directory
|
||||
$ ls ./dir1/..
|
||||
$ ls dir1/../.
|
||||
$ ls dir1/../././././.
|
||||
$ ls ../idallen # go up to the parent, then back down into idallen
|
||||
$ ls ./../idallen/./././.
|
||||
$ ls ../../tmp/idallen
|
||||
$ ls ../idallen/dir1/..
|
||||
$ ls ../idallen/dir1/.././././.
|
||||
$ ls dir1/../../idallen
|
||||
$ ls ./dir1/../../idallen/.
|
||||
|
||||
12.2 Absolute pathnames exercise
|
||||
|
||||
All the absolute pathnames below also give the same output, because all these absolute pathnames refer to the same /tmp/idallen directory:
|
||||
|
||||
$ ls /tmp/idallen
|
||||
$ ls /tmp/idallen/././.
|
||||
$ ls /tmp/idallen/dir1/..
|
||||
$ ls /tmp/../tmp/idallen/../idallen/dir1/..
|
||||
$ ls /././tmp/./././../tmp/./././idallen/./././../././idallen/./dir1/./..
|
||||
|
||||
12.3 Relative pathnames exercise with dir1
|
||||
|
||||
All the relative pathnames below give the same output, because all these relative pathnames refer to the same sub-directory /tmp/idallen/dir1:
|
||||
|
||||
$ pwd
|
||||
/tmp/idallen
|
||||
$ ls dir1
|
||||
$ ls dir1/.
|
||||
$ ls ./dir1
|
||||
$ ls ./dir1/.
|
||||
$ ls ././././dir1/././././.
|
||||
$ ls ../idallen/dir1
|
||||
$ ls ../idallen/dir1/../dir1/.
|
||||
$ ls ../../tmp/idallen/dir1/../../idallen/dir1/.
|
||||
|
||||
12.4 Absolute pathnames exercise with dir1
|
||||
|
||||
All the absolute pathnames below give the same output, because all these absolute pathnames refer to the same sub-directory /tmp/idallen/dir1:
|
||||
|
||||
$ ls /tmp/idallen/dir1
|
||||
$ ls /tmp/../tmp/idallen/dir1
|
||||
$ ls /tmp/../tmp/idallen/../idallen/dir1
|
||||
$ ls /tmp/../tmp/idallen/../idallen/dir1/../dir1
|
||||
$ ls /././tmp/./././idallen/./././dir1/./.
|
||||
|
||||
12.5 Pathnames exercises involving ROOT
|
||||
|
||||
All the relative pathnames below give the same output, because all these relative pathnames refer to the ROOT directory (from /tmp/idallen):
|
||||
|
||||
$ pwd
|
||||
/tmp/idallen
|
||||
$ ls ../..
|
||||
$ ls ../../../../..
|
||||
$ ls dir1/../../..
|
||||
$ ls dir1/../dir1/../../..
|
||||
$ ls ../idallen/../..
|
||||
$ ls ../../tmp/..
|
||||
$ ls ../../tmp/idallen/../..
|
||||
$ ls ../../tmp/idallen/../../tmp/idallen/../../././././.
|
||||
|
||||
All the absolute pathnames below give the same output, because all these absolute pathnames below refer to the ROOT directory:
|
||||
|
||||
$ ls /
|
||||
$ ls /.
|
||||
$ ls /./././.
|
||||
$ ls /tmp/..
|
||||
$ ls /tmp/idallen/../..
|
||||
$ ls /tmp/../tmp/idallen/../..
|
||||
$ ls /tmp/idallen/dir1/../../..
|
||||
|
||||
12.6 Copy exercise: two pathnames
|
||||
|
||||
All these commands copy the file file1 into file2 in the same (current) directory of /tmp/idallen:
|
||||
|
||||
$ pwd
|
||||
/tmp/idallen
|
||||
$ cp file1 file2
|
||||
$ cp ./file1 ./file2
|
||||
$ cp ././././././file1 ././././././file2
|
||||
$ cp file1 ../idallen/file2
|
||||
$ cp ../idallen/file1 file2
|
||||
$ cp ../idallen/file1 ../idallen/file2
|
||||
$ cp ../../tmp/idallen/file1 file2
|
||||
$ cp file1 ../../tmp/idallen/file2
|
||||
$ cp ../../tmp/idallen/file1 ../../tmp/idallen/file2
|
||||
$ cp ./././././../../tmp/idallen/file1 ./././././../../tmp/idallen/file2
|
||||
$ cp /tmp/idallen/file1 /tmp/idallen/file2
|
||||
$ cp /tmp/../tmp/idallen/file1 /tmp/idallen/../idallen/file2
|
||||
$ cp file1 /tmp/idallen/../../tmp/idallen/file2
|
||||
|
||||
Author:
|
||||
| Ian! D. Allen, BA, MMath - idallen@idallen.ca - Ottawa, Ontario, Canada
|
||||
| Home Page: http://idallen.com/ Contact Improv: http://contactimprov.ca/
|
||||
| College professor (Free/Libre GNU+Linux) at: http://teaching.idallen.com/
|
||||
| Defend digital freedom: http://eff.org/ and have fun: http://fools.ca/
|
||||
|
||||
Plain Text - plain text version of this page in Pandoc Markdown format
|
||||
|
||||
Campaign for non-browser-specific HTML Valid XHTML 1.0 Transitional Valid CSS! Creative Commons by nc sa 3.0 Hacker Ideals Emblem Author Ian! D. Allen
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
path of names
|
||||
"path of names"
|
||||
slash
|
||||
"slash"
|
||||
acyclic
|
||||
"acyclic"
|
||||
cycle
|
||||
"cycle"
|
||||
(the nameless
|
||||
" (the nameless "
|
||||
ROOT
|
||||
"ROOT"
|
||||
the nameless topmost ROOT directory that is to the left of the separating slash
|
||||
"the nameless topmost ROOT directory that is to the left of the separating slash"
|
||||
inserted in front of
|
||||
"inserted in front of"
|
||||
$HOME
|
||||
"$HOME"
|
||||
$HOME/bin
|
||||
"$HOME/bin"
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
Unix/Linux
|
||||
/home/user/lab/foo/bar
|
||||
/home/user/lab/foo
|
||||
/home/user/lab
|
||||
/home/user
|
||||
/tmp/.
|
||||
/./tmp
|
||||
/tmp/..
|
||||
/home/idallen/bin/../..
|
||||
/../tmp
|
||||
/../../../../../tmp
|
||||
/etc/passwd
|
||||
/usr/bin/wc
|
||||
/var/log/ntpstats/loopstats
|
||||
/home/abcd0001/CST8207-16W/Assignments/assignment02
|
||||
/usr/bin/wc.
|
||||
/home/idallen/bin/file.txt
|
||||
/usr/bin/
|
||||
/bin/
|
||||
/bin/.
|
||||
/bin//
|
||||
/bin////////////////////////////////
|
||||
dir/.
|
||||
/dir/symlink
|
||||
/etc/passwd/
|
||||
/etc/passwd/.
|
||||
/etc/passwd/..
|
||||
/tmp/dir
|
||||
/tmp/dir/../dir
|
||||
/tmp/f
|
||||
/tmp/f/../f
|
||||
/home/user/file
|
||||
/usr/lib/file
|
||||
/etc/file
|
||||
/bin/grep
|
||||
bin/grep
|
||||
./grep
|
||||
bin/.
|
||||
/etc/..
|
||||
etc/passwd
|
||||
/root/.bashrc
|
||||
/usr/bin/grep
|
||||
/bin/ls
|
||||
/etc/passwd.
|
||||
./bar
|
||||
../bar
|
||||
foo/bar
|
||||
/home/idallen.
|
||||
/usr/bin
|
||||
/usr/bin/foo
|
||||
../etc
|
||||
/usr/bin/../etc
|
||||
./hello
|
||||
/usr/bin/./hello
|
||||
/usr/bin/.
|
||||
/home/foo
|
||||
/home/../etc
|
||||
/home/./hello
|
||||
/home/.
|
||||
/usr/bin/bar
|
||||
user/file
|
||||
home/user/file
|
||||
bin/script
|
||||
/home/user/bin/script.
|
||||
/home/user/bin/script
|
||||
/home/user/bin
|
||||
~/bar
|
||||
/home/user/bar
|
||||
~/bin
|
||||
/home/idallen
|
||||
/home/idallen/bin
|
||||
/var/mail
|
||||
/var/spool/uucp
|
||||
/usr/games
|
||||
~idallen/bin
|
||||
/home/idallen/foo
|
||||
/home/user/lab/foo/bar/file.txt
|
||||
/home/user/lab/foo/bar/file2.txt
|
||||
/home/user/lab/foo/bar/file.txt.
|
||||
/home/user/lab/foo/bar/file2.txt.
|
||||
bar/file.txt
|
||||
bar/file2.txt
|
||||
foo/bar/file.txt
|
||||
foo/bar/file2.txt
|
||||
foo/bar/file2.txt.
|
||||
lab/foo/bar/file.txt
|
||||
lab/foo/bar/file2.txt
|
||||
user/lab/foo/bar/file.txt
|
||||
user/lab/foo/bar/file2.txt
|
||||
home/user/lab/foo/bar/file.txt
|
||||
home/user/lab/foo/bar/file2.txt
|
||||
user/foo/bar/file.txt
|
||||
/./tmp/.
|
||||
/../../..
|
||||
/usr/local/foo
|
||||
/usr/local/bin/
|
||||
/usr/local
|
||||
/usr/local/bin
|
||||
../foo
|
||||
/usr/local/foo.
|
||||
/usr/local/bin/.
|
||||
./dir1
|
||||
././dir1
|
||||
./././dir1
|
||||
./file1
|
||||
././file1
|
||||
./././file1
|
||||
/home/idallen/
|
||||
./foo
|
||||
/tmp/idallen
|
||||
././././././.
|
||||
dir1/..
|
||||
./dir1/..
|
||||
dir1/../.
|
||||
dir1/../././././.
|
||||
../idallen
|
||||
./../idallen/./././.
|
||||
../../tmp/idallen
|
||||
../idallen/dir1/..
|
||||
../idallen/dir1/.././././.
|
||||
dir1/../../idallen
|
||||
./dir1/../../idallen/.
|
||||
/tmp/idallen/././.
|
||||
/tmp/idallen/dir1/..
|
||||
/tmp/../tmp/idallen/../idallen/dir1/..
|
||||
/././tmp/./././../tmp/./././idallen/./././../././idallen/./dir1/./..
|
||||
/tmp/idallen/dir1
|
||||
dir1/.
|
||||
./dir1/.
|
||||
././././dir1/././././.
|
||||
../idallen/dir1
|
||||
../idallen/dir1/../dir1/.
|
||||
../../tmp/idallen/dir1/../../idallen/dir1/.
|
||||
/tmp/../tmp/idallen/dir1
|
||||
/tmp/../tmp/idallen/../idallen/dir1
|
||||
/tmp/../tmp/idallen/../idallen/dir1/../dir1
|
||||
/././tmp/./././idallen/./././dir1/./.
|
||||
../..
|
||||
../../../../..
|
||||
dir1/../../..
|
||||
dir1/../dir1/../../..
|
||||
../idallen/../..
|
||||
../../tmp/..
|
||||
../../tmp/idallen/../..
|
||||
../../tmp/idallen/../../tmp/idallen/../../././././.
|
||||
/./././.
|
||||
/tmp/idallen/../..
|
||||
/tmp/../tmp/idallen/../..
|
||||
/tmp/idallen/dir1/../../..
|
||||
./file2
|
||||
././././././file1
|
||||
././././././file2
|
||||
../idallen/file2
|
||||
../idallen/file1
|
||||
../../tmp/idallen/file1
|
||||
../../tmp/idallen/file2
|
||||
./././././../../tmp/idallen/file1
|
||||
./././././../../tmp/idallen/file2
|
||||
/tmp/idallen/file1
|
||||
/tmp/idallen/file2
|
||||
/tmp/../tmp/idallen/file1
|
||||
/tmp/idallen/../idallen/file2
|
||||
/tmp/idallen/../../tmp/idallen/file2
|
||||
Free/Libre
|
||||
teaching.idallen.com
|
||||
http://teaching.idallen.com/cst8207/12f/notes/160_pathnames.html
|
||||
http://teaching.idallen.com/
|
||||
idallen.com
|
||||
http://idallen.com/
|
||||
contactimprov.ca
|
||||
http://contactimprov.ca/
|
||||
eff.org
|
||||
http://eff.org/
|
||||
fools.ca
|
||||
http://fools.ca/
|
||||
|
|
@ -1,675 +0,0 @@
|
|||
teaching.idallen.com
|
||||
http://teaching.idallen.com/cst8207/12f/notes/160_pathnames.html
|
||||
Unix/Linux
|
||||
System
|
||||
Pathnames
|
||||
absolute
|
||||
relative
|
||||
Allen
|
||||
idallen@idallen.ca
|
||||
www.idallen.com
|
||||
September
|
||||
December
|
||||
Updated
|
||||
2017-02-25
|
||||
06:30
|
||||
Course
|
||||
Outline
|
||||
Weeks
|
||||
Plain
|
||||
Structure
|
||||
system
|
||||
loops
|
||||
cycles
|
||||
components
|
||||
contain
|
||||
character
|
||||
except
|
||||
slash
|
||||
names
|
||||
separated
|
||||
slashes
|
||||
Destination
|
||||
object
|
||||
directory
|
||||
other
|
||||
doesn’t
|
||||
separators
|
||||
Slashes
|
||||
separate
|
||||
precedes
|
||||
leftmost
|
||||
topmost
|
||||
convention
|
||||
directories
|
||||
ending
|
||||
followed
|
||||
files
|
||||
wrong
|
||||
Definition
|
||||
basename
|
||||
Absolute
|
||||
Relative
|
||||
pathnames
|
||||
start
|
||||
8.1.1
|
||||
always
|
||||
8.2.1
|
||||
current
|
||||
working
|
||||
8.2.2
|
||||
Using
|
||||
saves
|
||||
typing
|
||||
Differences
|
||||
between
|
||||
8.3.1
|
||||
Examples
|
||||
different
|
||||
8.3.2
|
||||
Current
|
||||
Directory
|
||||
Pathname
|
||||
~user
|
||||
become
|
||||
8.4.1
|
||||
Leading
|
||||
tilde
|
||||
8.4.2
|
||||
leading
|
||||
variable
|
||||
shell
|
||||
Exercise
|
||||
means
|
||||
seven
|
||||
/home/user/lab/foo/bar
|
||||
/home/user/lab/foo
|
||||
/home/user/lab
|
||||
/home/user
|
||||
/home
|
||||
hidden
|
||||
Example
|
||||
/tmp/
|
||||
/./tmp
|
||||
/home/idallen/bin/../
|
||||
parent
|
||||
10.5.1
|
||||
/../tmp
|
||||
/../../../../../tmp
|
||||
shorter
|
||||
Redundant
|
||||
useful
|
||||
prefix
|
||||
Removing
|
||||
looks
|
||||
option
|
||||
Don’t
|
||||
front
|
||||
Understanding
|
||||
Exercises
|
||||
exercise
|
||||
exercises
|
||||
involving
|
||||
organized
|
||||
within
|
||||
single-tree
|
||||
hierarchical
|
||||
structure
|
||||
containing
|
||||
documents
|
||||
programs
|
||||
folders
|
||||
sub-directories
|
||||
Unlike
|
||||
Windows
|
||||
multiple
|
||||
drive
|
||||
letters
|
||||
partition
|
||||
hides
|
||||
physical
|
||||
single
|
||||
matter
|
||||
disks
|
||||
partitions
|
||||
actually
|
||||
There
|
||||
resides
|
||||
looking
|
||||
acyclic
|
||||
following
|
||||
never
|
||||
toward
|
||||
cycle
|
||||
characters
|
||||
forward
|
||||
spaces
|
||||
newlines
|
||||
unprintable
|
||||
control
|
||||
non-English
|
||||
languages
|
||||
entirely
|
||||
blanks
|
||||
backspace
|
||||
characters!
|
||||
Linux
|
||||
component
|
||||
typically
|
||||
limited
|
||||
Older
|
||||
systems
|
||||
smaller
|
||||
limits
|
||||
pathname
|
||||
string
|
||||
indicates
|
||||
something
|
||||
examples
|
||||
/etc/passwd
|
||||
/usr/bin/wc
|
||||
/var/log/ntpstats/loopstats
|
||||
/home/abcd0001/CST8207-16W/Assignments/assignment02
|
||||
literally
|
||||
through
|
||||
hierarchy
|
||||
specifies
|
||||
traverse
|
||||
navigate
|
||||
reach
|
||||
destination
|
||||
order
|
||||
arrive
|
||||
lists
|
||||
individual
|
||||
cannot
|
||||
themselves
|
||||
strings
|
||||
identified
|
||||
right
|
||||
might
|
||||
thing
|
||||
memory
|
||||
terminal
|
||||
device
|
||||
things
|
||||
ordinary
|
||||
resume
|
||||
cal.txt
|
||||
dir.exe
|
||||
itself
|
||||
overall
|
||||
limit
|
||||
4,096
|
||||
including
|
||||
separating
|
||||
backslashes
|
||||
blame
|
||||
Microsoft
|
||||
annoying
|
||||
difference
|
||||
first
|
||||
deliberately
|
||||
chose
|
||||
separator
|
||||
likely
|
||||
avoid
|
||||
being
|
||||
copying
|
||||
naming
|
||||
Internet
|
||||
World-Wide-Web
|
||||
http://teaching.idallen.com/
|
||||
because
|
||||
invented
|
||||
machines
|
||||
Consider
|
||||
composed
|
||||
several
|
||||
/home/idallen/bin/file.txt
|
||||
Since
|
||||
example
|
||||
above
|
||||
those
|
||||
nameless
|
||||
idallen
|
||||
file.txt
|
||||
there
|
||||
implied
|
||||
starts
|
||||
slash!
|
||||
unique
|
||||
whole
|
||||
where
|
||||
originate
|
||||
begins
|
||||
top-most
|
||||
starting
|
||||
point
|
||||
entire
|
||||
called
|
||||
Because
|
||||
difficult
|
||||
about
|
||||
usually
|
||||
incorrectly
|
||||
technically
|
||||
can’t
|
||||
nothing
|
||||
actual
|
||||
Still
|
||||
often
|
||||
Understand
|
||||
really
|
||||
NOTE!
|
||||
confuse
|
||||
named
|
||||
/root
|
||||
account
|
||||
these
|
||||
notes
|
||||
upper-case
|
||||
refer
|
||||
valid
|
||||
every
|
||||
rightmost
|
||||
either
|
||||
symbolic
|
||||
substructure
|
||||
existing
|
||||
links
|
||||
final
|
||||
anything
|
||||
though
|
||||
suggests
|
||||
after
|
||||
special
|
||||
/usr/bin/
|
||||
self-referential
|
||||
period
|
||||
assumed
|
||||
refers
|
||||
equivalent
|
||||
...many
|
||||
print
|
||||
/bin/
|
||||
...same
|
||||
Putting
|
||||
makes
|
||||
almost
|
||||
/bin//
|
||||
/bin////////////////////////////////
|
||||
trailing
|
||||
slash-plus-dot
|
||||
don’t
|
||||
/dir/symlink
|
||||
result
|
||||
behaviour
|
||||
commands
|
||||
later
|
||||
adjacent
|
||||
treated
|
||||
create
|
||||
additional
|
||||
///etc///////passwd
|
||||
non-directory
|
||||
results
|
||||
invalid
|
||||
using
|
||||
expected
|
||||
command
|
||||
output
|
||||
/etc/passwd/
|
||||
error
|
||||
message!
|
||||
/tmp/dir
|
||||
/tmp/dir/../dir
|
||||
/tmp/f
|
||||
/tmp/f/../f
|
||||
isn’t
|
||||
leads
|
||||
message
|
||||
tells
|
||||
right-most
|
||||
/home/user/file
|
||||
/usr/lib/file
|
||||
/etc/file
|
||||
/bin/grep
|
||||
bin/grep
|
||||
./grep
|
||||
/etc/
|
||||
empty
|
||||
Several
|
||||
exist
|
||||
reside
|
||||
flavours
|
||||
etc/passwd
|
||||
/root/.bashrc
|
||||
traverses
|
||||
signalled
|
||||
descend
|
||||
/usr/bin/grep
|
||||
/bin/ls
|
||||
anywhere
|
||||
./bar
|
||||
../bar
|
||||
foo/bar
|
||||
along
|
||||
operating
|
||||
concept
|
||||
saved
|
||||
Every
|
||||
process
|
||||
changed
|
||||
shells
|
||||
built-in
|
||||
change
|
||||
/home/idallen
|
||||
displayed
|
||||
automatically
|
||||
prefixed
|
||||
inserted
|
||||
beginning
|
||||
/usr/bin
|
||||
/usr/bin/foo
|
||||
../etc
|
||||
/usr/bin/../etc
|
||||
./hello
|
||||
/usr/bin/./hello
|
||||
unchanged
|
||||
since
|
||||
instead
|
||||
/home/foo
|
||||
/home/../etc
|
||||
/home/./hello
|
||||
/home/
|
||||
references
|
||||
affected
|
||||
Changing
|
||||
changes
|
||||
meaning
|
||||
until
|
||||
going
|
||||
effect
|
||||
depend
|
||||
evaluating
|
||||
Shells
|
||||
Saving
|
||||
appropriate
|
||||
lines
|
||||
/usr/bin/bar
|
||||
Setting
|
||||
switching
|
||||
simpler
|
||||
becomes
|
||||
thanks
|
||||
remain
|
||||
ignoring
|
||||
ignored
|
||||
depending
|
||||
processes
|
||||
simply
|
||||
user/file
|
||||
home/user/file
|
||||
resulting
|
||||
bin/script
|
||||
equals
|
||||
/home/user/bin/script
|
||||
remove
|
||||
leaving
|
||||
removed
|
||||
leaves
|
||||
pathname!
|
||||
/home/user/bin
|
||||
better
|
||||
script
|
||||
major
|
||||
reasons
|
||||
Choose
|
||||
short
|
||||
short-cuts
|
||||
specify
|
||||
versions
|
||||
syntax
|
||||
short-cut
|
||||
appear
|
||||
expand
|
||||
token
|
||||
argument
|
||||
user’s
|
||||
~/bar
|
||||
/home/user/bar
|
||||
stands
|
||||
alone
|
||||
immediately
|
||||
substituted
|
||||
found
|
||||
which
|
||||
logged
|
||||
expands
|
||||
whoami
|
||||
~/bin
|
||||
/home/idallen/bin
|
||||
~idallen
|
||||
replaces
|
||||
~mail
|
||||
~uucp
|
||||
~games
|
||||
~root
|
||||
~nosuch
|
||||
/var/mail
|
||||
/var/spool/uucp
|
||||
/usr/games
|
||||
~idallen/bin
|
||||
secretly
|
||||
expanded
|
||||
aware
|
||||
this!
|
||||
inside
|
||||
variables
|
||||
HOME/foo
|
||||
could
|
||||
/home/idallen/foo
|
||||
HOME/bin
|
||||
modify
|
||||
before
|
||||
executed
|
||||
These
|
||||
modifications
|
||||
expansions
|
||||
finished
|
||||
Otherwise
|
||||
without
|
||||
Watch
|
||||
expanding
|
||||
~userid
|
||||
Given
|
||||
/home/user/lab/foo/bar/file.txt
|
||||
rename
|
||||
file2.txt
|
||||
giving
|
||||
answers
|
||||
would
|
||||
/home/user/lab/foo/bar/file2.txt
|
||||
Below
|
||||
contains
|
||||
answer
|
||||
bar/file.txt
|
||||
bar/file2.txt
|
||||
foo/bar/file.txt
|
||||
foo/bar/file2.txt
|
||||
Similar
|
||||
lab/foo/bar/file.txt
|
||||
lab/foo/bar/file2.txt
|
||||
previous
|
||||
concatenate
|
||||
user/lab/foo/bar/file.txt
|
||||
user/lab/foo/bar/file2.txt
|
||||
home/user/lab/foo/bar/file.txt
|
||||
home/user/lab/foo/bar/file2.txt
|
||||
gives
|
||||
user/foo/bar/file.txt
|
||||
write
|
||||
independent
|
||||
normally
|
||||
shown
|
||||
unless
|
||||
display
|
||||
begin
|
||||
drwx------
|
||||
01:32
|
||||
drwxr-xr-x
|
||||
01:33
|
||||
three
|
||||
searched
|
||||
contained
|
||||
/./tmp/
|
||||
won’t
|
||||
document
|
||||
second
|
||||
therefore
|
||||
involved
|
||||
backs
|
||||
level
|
||||
actions
|
||||
behaved
|
||||
differ
|
||||
given
|
||||
cover
|
||||
/../../
|
||||
still
|
||||
Similarly
|
||||
/usr/local/foo
|
||||
/usr/local/bin/
|
||||
/usr/local
|
||||
/usr/local/bin
|
||||
../foo
|
||||
copied
|
||||
shorten
|
||||
considerably
|
||||
choose
|
||||
carefully
|
||||
arguments
|
||||
needed
|
||||
./dir1
|
||||
unnecessary
|
||||
././dir1
|
||||
./././dir1
|
||||
file1
|
||||
./file1
|
||||
././file1
|
||||
./././file1
|
||||
trickery
|
||||
rmdir
|
||||
problem
|
||||
WRONG
|
||||
missing
|
||||
operand
|
||||
--help
|
||||
information
|
||||
trick
|
||||
superfluous
|
||||
letter
|
||||
works
|
||||
course
|
||||
/home/idallen/
|
||||
works!
|
||||
long!
|
||||
hiding
|
||||
tricks
|
||||
reason
|
||||
touch
|
||||
./foo
|
||||
RIGHT
|
||||
/tmp/idallen
|
||||
sub-structure
|
||||
20:33
|
||||
-rw-r--r--
|
||||
created
|
||||
below
|
||||
assume
|
||||
././././././
|
||||
dir1/
|
||||
./dir1/
|
||||
dir1/../
|
||||
dir1/../././././
|
||||
../idallen
|
||||
./../idallen/./././
|
||||
../../tmp/idallen
|
||||
../idallen/dir1/
|
||||
../idallen/dir1/.././././
|
||||
dir1/../../idallen
|
||||
./dir1/../../idallen/
|
||||
/tmp/idallen/././
|
||||
/tmp/idallen/dir1/
|
||||
/tmp/../tmp/idallen/../idallen/dir1/
|
||||
/././tmp/./././../tmp/./././idallen/./././../././idallen/./dir1/./
|
||||
sub-directory
|
||||
/tmp/idallen/dir1
|
||||
././././dir1/././././
|
||||
../idallen/dir1
|
||||
../idallen/dir1/../dir1/
|
||||
../../tmp/idallen/dir1/../../idallen/dir1/
|
||||
/tmp/../tmp/idallen/dir1
|
||||
/tmp/../tmp/idallen/../idallen/dir1
|
||||
/tmp/../tmp/idallen/../idallen/dir1/../dir1
|
||||
/././tmp/./././idallen/./././dir1/./
|
||||
../../../../
|
||||
dir1/../../
|
||||
dir1/../dir1/../../
|
||||
../idallen/../
|
||||
../../tmp/
|
||||
../../tmp/idallen/../
|
||||
../../tmp/idallen/../../tmp/idallen/../../././././
|
||||
/./././
|
||||
/tmp/idallen/../
|
||||
/tmp/../tmp/idallen/../
|
||||
/tmp/idallen/dir1/../../
|
||||
file2
|
||||
./file2
|
||||
././././././file1
|
||||
././././././file2
|
||||
../idallen/file2
|
||||
../idallen/file1
|
||||
../../tmp/idallen/file1
|
||||
../../tmp/idallen/file2
|
||||
./././././../../tmp/idallen/file1
|
||||
./././././../../tmp/idallen/file2
|
||||
/tmp/idallen/file1
|
||||
/tmp/idallen/file2
|
||||
/tmp/../tmp/idallen/file1
|
||||
/tmp/idallen/../idallen/file2
|
||||
/tmp/idallen/../../tmp/idallen/file2
|
||||
Author
|
||||
MMath
|
||||
Ottawa
|
||||
Ontario
|
||||
Canada
|
||||
http://idallen.com/
|
||||
Contact
|
||||
Improv
|
||||
http://contactimprov.ca/
|
||||
College
|
||||
professor
|
||||
Free/Libre
|
||||
GNU+Linux
|
||||
Defend
|
||||
digital
|
||||
freedom
|
||||
http://eff.org/
|
||||
http://fools.ca/
|
||||
plain
|
||||
version
|
||||
Pandoc
|
||||
Markdown
|
||||
format
|
||||
Campaign
|
||||
non-browser-specific
|
||||
Valid
|
||||
XHTML
|
||||
Transitional
|
||||
Creative
|
||||
Commons
|
||||
Hacker
|
||||
Ideals
|
||||
Emblem
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
Some additional tests
|
||||
FOO_BAR=value
|
||||
BAR_FOO="longer value"
|
||||
echo $FOO_BAR $BAR_FOO
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
additional
|
||||
tests
|
||||
FOO_BAR
|
||||
value
|
||||
BAR_FOO
|
||||
longer
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
Unicode:
|
||||
|
||||
euro_€_
|
||||
infinity_∞_
|
||||
ruble_₽_
|
||||
|
||||
excluded:
|
||||
note_♫_
|
||||
block_drawing_│_
|
||||
some_whitespace_⋅↴│_
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
Unicode
|
||||
euro_€_
|
||||
infinity_∞_
|
||||
ruble_₽_
|
||||
excluded
|
||||
note_
|
||||
block_drawing_
|
||||
some_whitespace_
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import unittest
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def run_test(switch, name):
|
||||
subprocess.run(
|
||||
f"../extrakto.py {switch} --alt < assets/{name}.txt | cmp - ./assets/{name}_result{switch}.txt",
|
||||
shell=True,
|
||||
check=True,
|
||||
cwd=script_dir,
|
||||
)
|
||||
|
||||
|
||||
class TestAssets(unittest.TestCase):
|
||||
def test_all(self):
|
||||
for test in ["text1", "text2", "path", "unicode", "quotes"]:
|
||||
run_test("-w", test)
|
||||
|
||||
for test in ["text1", "path"]:
|
||||
run_test("-pu", test)
|
||||
|
||||
for test in ["text1", "quotes"]:
|
||||
run_test("-a=quote", test)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
|
||||
from extrakto import get_lines
|
||||
|
||||
|
||||
class TestGetLines(unittest.TestCase):
|
||||
def test_get_lines_of_min_length(self):
|
||||
text = """\
|
||||
first line
|
||||
second line with whitespace
|
||||
short"""
|
||||
words = [
|
||||
"first line",
|
||||
"second line with whitespace",
|
||||
]
|
||||
|
||||
result = get_lines(text, min_length=6)
|
||||
self.assertEqual(words, result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
|
||||
from extrakto import Extrakto
|
||||
|
||||
get_paths = Extrakto()["path"].filter
|
||||
|
||||
|
||||
class TestGetPaths(unittest.TestCase):
|
||||
def test_match_tilde_path(self):
|
||||
text = "hey, test ~/tmp/test.txt etc..."
|
||||
urls = ["~/tmp/test.txt"]
|
||||
|
||||
result = get_paths(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
def test_match_full_path(self):
|
||||
text = "hey, open this file /home/joe/test.txt etc..."
|
||||
urls = ["/home/joe/test.txt"]
|
||||
|
||||
result = get_paths(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
|
||||
from extrakto import Extrakto
|
||||
|
||||
get_urls = Extrakto()["url"].filter
|
||||
|
||||
|
||||
class TestGetURLs(unittest.TestCase):
|
||||
def test_match_http(self):
|
||||
text = "hey, open this url http://google.com etc..."
|
||||
urls = ["http://google.com"]
|
||||
|
||||
result = get_urls(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
def test_match_https(self):
|
||||
text = "hey, open this secure url https://google.com etc..."
|
||||
urls = ["https://google.com"]
|
||||
|
||||
result = get_urls(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
def test_match_ftp(self):
|
||||
text = "hey, connect to this server ftp://myserver.com etc..."
|
||||
urls = ["ftp://myserver.com"]
|
||||
|
||||
result = get_urls(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
def test_match_sftp(self):
|
||||
text = "hey, connect to this secure server sftp://myserver.com etc..."
|
||||
urls = ["sftp://myserver.com"]
|
||||
|
||||
result = get_urls(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
def test_match_home_path(self):
|
||||
text = "hey, open this file file:////home/joe etc..."
|
||||
urls = ["file:////home/joe"]
|
||||
|
||||
result = get_urls(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
def test_match_git(self):
|
||||
text = (
|
||||
"hey, check out this repo git@github.com:laktak/extrakto.git"
|
||||
", it's a great tmux plugin"
|
||||
)
|
||||
urls = ["git@github.com:laktak/extrakto.git"]
|
||||
|
||||
result = get_urls(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
def test_match_HTTP(self):
|
||||
text = "hey, open this url HTTP://GOOGLE.COM etc..."
|
||||
urls = ["HTTP://GOOGLE.COM"]
|
||||
|
||||
result = get_urls(text)
|
||||
self.assertEqual(urls, result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
|
||||
from extrakto import Extrakto
|
||||
|
||||
get_words = Extrakto(min_length=5)["word"].filter
|
||||
|
||||
|
||||
class TestGetWords(unittest.TestCase):
|
||||
def test_skip_dot_last_word_in_sentence(self):
|
||||
text = "Hello world. Extrakto is an awesome plugin."
|
||||
words = ["Hello", "world", "Extrakto", "awesome", "plugin"]
|
||||
|
||||
result = get_words(text)
|
||||
self.assertEqual(words, result)
|
||||
|
||||
def test_box_drawing(self):
|
||||
text = "other│something"
|
||||
words = ["other", "something"]
|
||||
|
||||
result = get_words(text)
|
||||
self.assertEqual(words, result)
|
||||
|
||||
def test_match_hidden_files(self):
|
||||
text = "one /home/user/.hidden.txt two .hidden.txt three ./.hidden.txt four ../.hidden.txt"
|
||||
words = [
|
||||
"/home/user/.hidden.txt",
|
||||
".hidden.txt",
|
||||
"three",
|
||||
"./.hidden.txt",
|
||||
"../.hidden.txt",
|
||||
]
|
||||
|
||||
result = get_words(text)
|
||||
self.assertEqual(words, result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
### master
|
||||
- bugfix: "auto restore" feature stopped working
|
||||
- bugfix: prevent race condition when auto-saving with locks (@v9v)
|
||||
- Multiple users on a system can now each run continuum on their own.
|
||||
|
||||
### v3.1.0, 2015-03-14
|
||||
- properly quote scripts
|
||||
- bugfix: "auto restore" feature does not work on tmux `1.9a`
|
||||
- bugfix: do not count `tmux source-file .tmux.conf` as a tmux process (when
|
||||
checking if other tmux server is running). Previously, this caused
|
||||
interpolation command not to be inserted into `status-right` because `tmux
|
||||
source-file` was falsely detected as another tmux server.
|
||||
- add `#{continuum_status}` status line interpolation
|
||||
|
||||
### v3.0.0, 2015-02-20
|
||||
- rename the plugin from `tmux-resurrect-auto` to `tmux-continuum`
|
||||
|
||||
### v2.2.0, 2015-02-20
|
||||
- document tmux multi-server behavior in the readme
|
||||
- do not auto-restore tmux environment if another tmux server is already running
|
||||
(we don't want to duplicate stuff)
|
||||
- bugfixes for 'tmux auto start' OS X Terminal.app and iTerm scripts
|
||||
- prevent saving for the first 15 minutes only when plugin is sourced the first
|
||||
time (not on subsequent sources or tmux.conf reloads)
|
||||
- do not start auto-saving if there's another tmux server running (we don't want
|
||||
for save files from various tmux environments to override each other)
|
||||
|
||||
### v2.1.0, 2015-02-18
|
||||
- enable "tmux auto start" for OS X
|
||||
- enable customizing "tmux auto start" for OS X
|
||||
- fix errors when creating a launchd plist file for auto-start on OS X
|
||||
|
||||
### v2.0.0, 2015-02-15
|
||||
- enable automatic environment restore when tmux is started
|
||||
|
||||
### v1.0.0, 2015-02-12
|
||||
- first working version
|
||||
- run the save script in the background
|
||||
- do not start saving right after tmux is started
|
||||
- add a check for tmux version to the initializer script
|
||||
- when interval is set to '0' autosave is disabled
|
||||
- bugfix: helper files not loaded
|
||||
- update readme with the instructions how to disable auto saving
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
### Contributing
|
||||
|
||||
Code contributions are welcome!
|
||||
|
||||
If you wanna contribute a bigger feature, please open a github issue so we can
|
||||
discuss it together first.
|
||||
|
||||
### Reporting a bug
|
||||
|
||||
If you find a bug please report it in the issues. When reporting a bug please
|
||||
attach:
|
||||
- a file symlinked to `~/.tmux/resurrect/last`.
|
||||
- your `.tmux.conf`
|
||||
- if you're getting an error paste it to a [gist](https://gist.github.com/) and
|
||||
link it in the issue
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
Copyright (C) Bruno Sutic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
# tmux-continuum
|
||||
|
||||
Features:
|
||||
|
||||
- continuous saving of tmux environment
|
||||
- automatic tmux start when computer/server is turned on
|
||||
- automatic restore when tmux is started
|
||||
|
||||
Together, these features enable uninterrupted tmux usage. No matter the computer
|
||||
or server restarts, if the machine is on, tmux will be there how you left it off
|
||||
the last time it was used.
|
||||
|
||||
Tested and working on Linux, OSX and Cygwin.
|
||||
|
||||
#### Continuous saving
|
||||
|
||||
Tmux environment will be saved at an interval of 15 minutes. All the saving
|
||||
happens in the background without impact to your workflow.
|
||||
|
||||
This action starts automatically when the plugin is installed. Note it requires
|
||||
the status line to be `on` to run (since it uses a hook in status-right to run).
|
||||
|
||||
#### Automatic tmux start
|
||||
|
||||
Tmux is automatically started after the computer/server is turned on.
|
||||
|
||||
See the [instructions](docs/automatic_start.md) on how to enable this for your
|
||||
system.
|
||||
|
||||
#### Automatic restore
|
||||
|
||||
Last saved environment is automatically restored when tmux is started.
|
||||
|
||||
Put `set -g @continuum-restore 'on'` in `.tmux.conf` to enable this.
|
||||
|
||||
Note: automatic restore happens **exclusively** on tmux server start. No other
|
||||
action (e.g. sourcing `.tmux.conf`) triggers this.
|
||||
|
||||
#### Dependencies
|
||||
|
||||
`tmux 1.9` or higher, `bash`,
|
||||
[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) plugin.
|
||||
|
||||
### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended)
|
||||
|
||||
Please make sure you have
|
||||
[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) installed.
|
||||
|
||||
Add plugin to the list of TPM plugins in `.tmux.conf`:
|
||||
|
||||
set -g @plugin 'tmux-plugins/tmux-resurrect'
|
||||
set -g @plugin 'tmux-plugins/tmux-continuum'
|
||||
|
||||
Hit `prefix + I` to fetch the plugin and source it. The plugin will
|
||||
automatically start "working" in the background, no action required.
|
||||
|
||||
### Manual Installation
|
||||
|
||||
Please make sure you have
|
||||
[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) installed.
|
||||
|
||||
Clone the repo:
|
||||
|
||||
$ git clone https://github.com/tmux-plugins/tmux-continuum ~/clone/path
|
||||
|
||||
Add this line to the bottom of `.tmux.conf`:
|
||||
|
||||
run-shell ~/clone/path/continuum.tmux
|
||||
|
||||
Reload TMUX environment with: `$ tmux source-file ~/.tmux.conf`
|
||||
|
||||
The plugin will automatically start "working" in the background, no action
|
||||
required.
|
||||
|
||||
### Docs
|
||||
|
||||
- [frequently asked questions](docs/faq.md)
|
||||
- [behavior when running multiple tmux servers](docs/multiple_tmux_servers.md) -
|
||||
this doc is safe to skip, but you might want to read it if you're using tmux
|
||||
with `-L` or `-S` flags
|
||||
- [automatically start tmux after the computer is turned on](docs/automatic_start.md)
|
||||
- [continuum status in tmux status line](docs/continuum_status.md)
|
||||
|
||||
### Other goodies
|
||||
|
||||
- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for
|
||||
regex searches in tmux and fast match selection
|
||||
- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying
|
||||
highlighted text to system clipboard
|
||||
- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly
|
||||
opening highlighted file or a url
|
||||
|
||||
### Known Issues
|
||||
|
||||
- In order to be executed periodically, the plugin updates the `status-right` tmux variable. In case some plugin (usually themes) overwrites the `status-right` variable, the autosave feature stops working. To fix this issue, place the plugin last in the TPM plugins list.
|
||||
|
||||
### Reporting bugs and contributing
|
||||
|
||||
Both contributing and bug reports are welcome. Please check out
|
||||
[contributing guidelines](CONTRIBUTING.md).
|
||||
|
||||
### License
|
||||
[MIT](LICENSE.md)
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
# Automatic Tmux start
|
||||
|
||||
Tmux is automatically started after the computer/server is turned on.
|
||||
|
||||
### OS X
|
||||
|
||||
To enable this feature:
|
||||
- put `set -g @continuum-boot 'on'` in `.tmux.conf`
|
||||
- reload tmux config with this shell command: `$ tmux source-file ~/.tmux.conf`
|
||||
|
||||
Next time the computer is started:
|
||||
- `Terminal.app` window will open and resize to maximum size
|
||||
- `tmux` command will be executed in the terminal window
|
||||
- if "auto restore" feature is enabled, tmux will start restoring previous env
|
||||
|
||||
Config options:
|
||||
- `set -g @continuum-boot-options 'fullscreen'` - terminal window
|
||||
will go fullscreen
|
||||
- `set -g @continuum-boot-options 'iterm'` - start [iTerm](https://www.iterm2.com) instead
|
||||
of `Terminal.app`
|
||||
- `set -g @continuum-boot-options 'iterm,fullscreen'` - start `iTerm`
|
||||
in fullscreen
|
||||
- `set -g @continuum-boot-options 'kitty'` - start [kitty](https://sw.kovidgoyal.net/kitty) instead
|
||||
of `Terminal.app`
|
||||
- `set -g @continuum-boot-options 'kitty,fullscreen'` - start `kitty`
|
||||
in fullscreen
|
||||
- `set -g @continuum-boot-options 'alacritty'` - start [alacritty](https://github.com/alacritty/alacritty) instead of `Terminal.app`
|
||||
- `set -g @continuum-boot-options 'alacritty,fullscreen'` - start `alacritty`
|
||||
in fullscreen
|
||||
|
||||
Note: The first time you reboot your machine and activate this feature you may be prompted about a script requiring
|
||||
access to a system program (i.e. - System Events). If this happens tmux will not start automatically and you will need
|
||||
to go to `System Preferences -> Security & Privacy -> Accessability` and add the script to the list of apps that are
|
||||
allowed to control your computer.
|
||||
|
||||
### Linux
|
||||
|
||||
Help with this would be greatly appreciated. Please get in touch.
|
||||
|
||||
#### Systemd
|
||||
|
||||
##### this will only start the tmux server, it will *not* start any terminal emulator
|
||||
|
||||
To enable automatic start with systemd:
|
||||
- Put `set -g @continuum-boot 'on'` in `.tmux.conf`
|
||||
- reload tmux config with this shell command: `$ tmux source-file ~/.tmux.conf`
|
||||
- see [systemd](/docs/systemd_details.md) for more details about how this is implemented
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
## Continuum status in tmux status line
|
||||
|
||||
There is an option to display current status of tmux continuum in tmux status
|
||||
line. This is done via `#{continuum_status}` interpolation and it works with
|
||||
both `status-right` and `status-left` tmux native options.
|
||||
|
||||
Example usage:
|
||||
|
||||
set -g status-right 'Continuum status: #{continuum_status}'
|
||||
|
||||
When running, `#{continuum_status}` will show continuum save interval:
|
||||
|
||||
Continuum status: 15
|
||||
|
||||
or if continuous saving is disabled:
|
||||
|
||||
Continuum status: off
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
### FAQ
|
||||
|
||||
> Will a previous save be overwritten immediately after I start tmux?
|
||||
|
||||
No, first automatic save starts 15 minutes after tmux is started. If automatic
|
||||
restore is not enabled, that gives you enough time to manually restore from a
|
||||
previous save.
|
||||
|
||||
> I want to make a restore to a previous point in time, but it seems that save
|
||||
is now overwritten?
|
||||
|
||||
Read how to [restore a previously saved environment](https://github.com/tmux-plugins/tmux-resurrect/blob/master/docs/restoring_previously_saved_environment.md)
|
||||
|
||||
> Will this plugin fill my hard disk?
|
||||
|
||||
Most likely no. A regular save file is in the range of 5Kb. And `tmux-resurrect` already has a `remove_old_backups()` routine that will ["remove resurrect files older than 30 days, but keep at least 5 copies of backup."](https://github.com/tmux-plugins/tmux-resurrect/blob/da1a7558024b8552f7262b39ed22e3d679304f99/scripts/save.sh#L271-L277)
|
||||
|
||||
> How do I change the save interval to i.e. 1 hour?
|
||||
|
||||
The interval is always measured in minutes. So setting the interval to `60`
|
||||
(minutes) will do the trick. Put this in `.tmux.conf`:
|
||||
|
||||
set -g @continuum-save-interval '60'
|
||||
|
||||
and then source `tmux.conf` by executing this command in the shell
|
||||
`$ tmux source-file ~/.tmux.conf`.
|
||||
|
||||
> How do I stop automatic saving?
|
||||
|
||||
Just set the save interval to `0`. Put this in `.tmux.conf`
|
||||
|
||||
set -g @continuum-save-interval '0'
|
||||
|
||||
and then source `tmux.conf` by executing this command in the shell
|
||||
`$ tmux source-file ~/.tmux.conf`.
|
||||
|
||||
> I had automatic restore turned on, how do I disable it now?
|
||||
|
||||
Just remove `set -g @continuum-restore 'on'` from `tmux.conf`.
|
||||
|
||||
To be absolutely sure automatic restore doesn't happen, create a
|
||||
`tmux_no_auto_restore` file in your home directory (command:
|
||||
`$ touch ~/tmux_no_auto_restore`). Automatic restore won't happen if this file
|
||||
exists.
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
### Behavior when running multiple tmux servers
|
||||
|
||||
(This is safe to skip if you're always running a single tmux server.)
|
||||
|
||||
If you're an advanced tmux user, you might be running multiple tmux servers at
|
||||
the same time. Maybe you start the first tmux server with `$ tmux` and then
|
||||
later another one with e.g. `$ tmux -S/tmp/foo`.
|
||||
|
||||
You probably don't want to "auto restore" the same environment in the second
|
||||
tmux that uses `/tmp/foo` socket. You also probably don't want two tmux
|
||||
environments both having "auto save" feature on (think about overwrites).
|
||||
|
||||
This plugin handles multi-server scenario by giving precedence to the tmux
|
||||
server that was first started.
|
||||
|
||||
In the above example, the server started with `$ tmux` will do "auto
|
||||
restore" (if enabled) and will start "auto saving".
|
||||
"Auto restore" or "auto saving" **will not** happen for the second server that
|
||||
was started later with the `$ tmux -S/tmp/foo` command. The plugin will
|
||||
detect the presence of another server (`$ tmux`) and give it precedence.
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Systemd automatic start for tmux
|
||||
|
||||
The first time tmux starts when `@continuum-boot` is set to 'on' tmux-continuum will generate a user level systemd unit file which it will save to `${HOME}/.config/systemd/user/tmux.service` and enable it. From then on when that user logs in, either through a GUI session or on the console or via ssh, Systemd will start the tmux server.
|
||||
|
||||
The command used to start the tmux server is determined via the `@continuum-systemd-start-cmd` option that can be set in .tmux.conf. (Remember to reload your configuration with `tmux source ~/.tmux.conf` afterwards.
|
||||
|
||||
The default command to use is `new-session -d`. If you want more control over what sessions get started then you should set up your sessions in tmux.conf and set `@continuum-systemd-start-cmd = 'start-server'`. As this will be executed as part of systemd's ExecStart statement there will be no shell parsing. See [Systemd manual](http://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines) for more details.
|
||||
|
||||
To control the tmux service you can use all the standard `systemctl` commands using the `--user` argument. eg to see if the tmux server has started:
|
||||
|
||||
systemctl --user status tmux.service
|
||||
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
ref: refs/heads/master
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
[submodule]
|
||||
active = .
|
||||
[remote "origin"]
|
||||
url = https://git::@github.com/tmux-plugins/tmux-continuum
|
||||
fetch = +refs/heads/master:refs/remotes/origin/master
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
|
|
@ -1 +0,0 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||
:
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use IPC::Open2;
|
||||
|
||||
# An example hook script to integrate Watchman
|
||||
# (https://facebook.github.io/watchman/) with git to speed up detecting
|
||||
# new and modified files.
|
||||
#
|
||||
# The hook is passed a version (currently 2) and last update token
|
||||
# formatted as a string and outputs to stdout a new update token and
|
||||
# all files that have been modified since the update token. Paths must
|
||||
# be relative to the root of the working tree and separated by a single NUL.
|
||||
#
|
||||
# To enable this hook, rename this file to "query-watchman" and set
|
||||
# 'git config core.fsmonitor .git/hooks/query-watchman'
|
||||
#
|
||||
my ($version, $last_update_token) = @ARGV;
|
||||
|
||||
# Uncomment for debugging
|
||||
# print STDERR "$0 $version $last_update_token\n";
|
||||
|
||||
# Check the hook interface version
|
||||
if ($version ne 2) {
|
||||
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
||||
"Falling back to scanning...\n";
|
||||
}
|
||||
|
||||
my $git_work_tree = get_working_dir();
|
||||
|
||||
my $retry = 1;
|
||||
|
||||
my $json_pkg;
|
||||
eval {
|
||||
require JSON::XS;
|
||||
$json_pkg = "JSON::XS";
|
||||
1;
|
||||
} or do {
|
||||
require JSON::PP;
|
||||
$json_pkg = "JSON::PP";
|
||||
};
|
||||
|
||||
launch_watchman();
|
||||
|
||||
sub launch_watchman {
|
||||
my $o = watchman_query();
|
||||
if (is_work_tree_watched($o)) {
|
||||
output_result($o->{clock}, @{$o->{files}});
|
||||
}
|
||||
}
|
||||
|
||||
sub output_result {
|
||||
my ($clockid, @files) = @_;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# binmode $fh, ":utf8";
|
||||
# print $fh "$clockid\n@files\n";
|
||||
# close $fh;
|
||||
|
||||
binmode STDOUT, ":utf8";
|
||||
print $clockid;
|
||||
print "\0";
|
||||
local $, = "\0";
|
||||
print @files;
|
||||
}
|
||||
|
||||
sub watchman_clock {
|
||||
my $response = qx/watchman clock "$git_work_tree"/;
|
||||
die "Failed to get clock id on '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub watchman_query {
|
||||
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
|
||||
or die "open2() failed: $!\n" .
|
||||
"Falling back to scanning...\n";
|
||||
|
||||
# In the query expression below we're asking for names of files that
|
||||
# changed since $last_update_token but not from the .git folder.
|
||||
#
|
||||
# To accomplish this, we're using the "since" generator to use the
|
||||
# recency index to select candidate nodes and "fields" to limit the
|
||||
# output to file names only. Then we're using the "expression" term to
|
||||
# further constrain the results.
|
||||
my $last_update_line = "";
|
||||
if (substr($last_update_token, 0, 1) eq "c") {
|
||||
$last_update_token = "\"$last_update_token\"";
|
||||
$last_update_line = qq[\n"since": $last_update_token,];
|
||||
}
|
||||
my $query = <<" END";
|
||||
["query", "$git_work_tree", {$last_update_line
|
||||
"fields": ["name"],
|
||||
"expression": ["not", ["dirname", ".git"]]
|
||||
}]
|
||||
END
|
||||
|
||||
# Uncomment for debugging the watchman query
|
||||
# open (my $fh, ">", ".git/watchman-query.json");
|
||||
# print $fh $query;
|
||||
# close $fh;
|
||||
|
||||
print CHLD_IN $query;
|
||||
close CHLD_IN;
|
||||
my $response = do {local $/; <CHLD_OUT>};
|
||||
|
||||
# Uncomment for debugging the watch response
|
||||
# open ($fh, ">", ".git/watchman-response.json");
|
||||
# print $fh $response;
|
||||
# close $fh;
|
||||
|
||||
die "Watchman: command returned no output.\n" .
|
||||
"Falling back to scanning...\n" if $response eq "";
|
||||
die "Watchman: command returned invalid output: $response\n" .
|
||||
"Falling back to scanning...\n" unless $response =~ /^\{/;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub is_work_tree_watched {
|
||||
my ($output) = @_;
|
||||
my $error = $output->{error};
|
||||
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
|
||||
$retry--;
|
||||
my $response = qx/watchman watch "$git_work_tree"/;
|
||||
die "Failed to make watchman watch '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
$output = $json_pkg->new->utf8->decode($response);
|
||||
$error = $output->{error};
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# close $fh;
|
||||
|
||||
# Watchman will always return all files on the first query so
|
||||
# return the fast "everything is dirty" flag to git and do the
|
||||
# Watchman query just to get it over with now so we won't pay
|
||||
# the cost in git to look up each individual file.
|
||||
my $o = watchman_clock();
|
||||
$error = $output->{error};
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
output_result($o->{clock}, ("/"));
|
||||
$last_update_token = $o->{clock};
|
||||
|
||||
eval { launch_watchman() };
|
||||
return 0;
|
||||
}
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub get_working_dir {
|
||||
my $working_dir;
|
||||
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
|
||||
$working_dir = Win32::GetCwd();
|
||||
$working_dir =~ tr/\\/\//;
|
||||
} else {
|
||||
require Cwd;
|
||||
$working_dir = Cwd::cwd();
|
||||
}
|
||||
|
||||
return $working_dir;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to prepare a packed repository for use over
|
||||
# dumb transports.
|
||||
#
|
||||
# To enable this hook, rename this file to "post-update".
|
||||
|
||||
exec git update-server-info
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||
:
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=$(git hash-object -t tree /dev/null)
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git merge" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message to
|
||||
# stderr if it wants to stop the merge commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-merge-commit".
|
||||
|
||||
. git-sh-setup
|
||||
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||
exec "$GIT_DIR/hooks/pre-commit"
|
||||
:
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
# An example hook script to verify what is about to be pushed. Called by "git
|
||||
# push" after it has checked the remote status, but before anything has been
|
||||
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# This hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- Name of the remote to which the push is being done
|
||||
# $2 -- URL to which the push is being done
|
||||
#
|
||||
# If pushing without using a named remote those arguments will be equal.
|
||||
#
|
||||
# Information about the commits which are being pushed is supplied as lines to
|
||||
# the standard input in the form:
|
||||
#
|
||||
# <local ref> <local oid> <remote ref> <remote oid>
|
||||
#
|
||||
# This sample shows how to prevent push of commits where the log message starts
|
||||
# with "WIP" (work in progress).
|
||||
|
||||
remote="$1"
|
||||
url="$2"
|
||||
|
||||
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||
|
||||
while read local_ref local_oid remote_ref remote_oid
|
||||
do
|
||||
if test "$local_oid" = "$zero"
|
||||
then
|
||||
# Handle delete
|
||||
:
|
||||
else
|
||||
if test "$remote_oid" = "$zero"
|
||||
then
|
||||
# New branch, examine all commits
|
||||
range="$local_oid"
|
||||
else
|
||||
# Update to existing branch, examine new commits
|
||||
range="$remote_oid..$local_oid"
|
||||
fi
|
||||
|
||||
# Check for WIP commit
|
||||
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||
if test -n "$commit"
|
||||
then
|
||||
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||
#
|
||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||
# its job, and can prevent the command from running by exiting with
|
||||
# non-zero status.
|
||||
#
|
||||
# The hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- the upstream the series was forked from.
|
||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||
#
|
||||
# This sample shows how to prevent topic branches that are already
|
||||
# merged to 'next' branch from getting rebased, because allowing it
|
||||
# would result in rebasing already published history.
|
||||
|
||||
publish=next
|
||||
basebranch="$1"
|
||||
if test "$#" = 2
|
||||
then
|
||||
topic="refs/heads/$2"
|
||||
else
|
||||
topic=`git symbolic-ref HEAD` ||
|
||||
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||
fi
|
||||
|
||||
case "$topic" in
|
||||
refs/heads/??/*)
|
||||
;;
|
||||
*)
|
||||
exit 0 ;# we do not interrupt others.
|
||||
;;
|
||||
esac
|
||||
|
||||
# Now we are dealing with a topic branch being rebased
|
||||
# on top of master. Is it OK to rebase it?
|
||||
|
||||
# Does the topic really exist?
|
||||
git show-ref -q "$topic" || {
|
||||
echo >&2 "No such branch $topic"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Is topic fully merged to master?
|
||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||
if test -z "$not_in_master"
|
||||
then
|
||||
echo >&2 "$topic is fully merged to master; better remove it."
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
fi
|
||||
|
||||
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||
if test "$only_next_1" = "$only_next_2"
|
||||
then
|
||||
not_in_topic=`git rev-list "^$topic" master`
|
||||
if test -z "$not_in_topic"
|
||||
then
|
||||
echo >&2 "$topic is already up to date with master"
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||
/usr/bin/perl -e '
|
||||
my $topic = $ARGV[0];
|
||||
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||
my (%not_in_next) = map {
|
||||
/^([0-9a-f]+) /;
|
||||
($1 => 1);
|
||||
} split(/\n/, $ARGV[1]);
|
||||
for my $elem (map {
|
||||
/^([0-9a-f]+) (.*)$/;
|
||||
[$1 => $2];
|
||||
} split(/\n/, $ARGV[2])) {
|
||||
if (!exists $not_in_next{$elem->[0]}) {
|
||||
if ($msg) {
|
||||
print STDERR $msg;
|
||||
undef $msg;
|
||||
}
|
||||
print STDERR " $elem->[1]\n";
|
||||
}
|
||||
}
|
||||
' "$topic" "$not_in_next" "$not_in_master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
<<\DOC_END
|
||||
|
||||
This sample hook safeguards topic branches that have been
|
||||
published from being rewound.
|
||||
|
||||
The workflow assumed here is:
|
||||
|
||||
* Once a topic branch forks from "master", "master" is never
|
||||
merged into it again (either directly or indirectly).
|
||||
|
||||
* Once a topic branch is fully cooked and merged into "master",
|
||||
it is deleted. If you need to build on top of it to correct
|
||||
earlier mistakes, a new topic branch is created by forking at
|
||||
the tip of the "master". This is not strictly necessary, but
|
||||
it makes it easier to keep your history simple.
|
||||
|
||||
* Whenever you need to test or publish your changes to topic
|
||||
branches, merge them into "next" branch.
|
||||
|
||||
The script, being an example, hardcodes the publish branch name
|
||||
to be "next", but it is trivial to make it configurable via
|
||||
$GIT_DIR/config mechanism.
|
||||
|
||||
With this workflow, you would want to know:
|
||||
|
||||
(1) ... if a topic branch has ever been merged to "next". Young
|
||||
topic branches can have stupid mistakes you would rather
|
||||
clean up before publishing, and things that have not been
|
||||
merged into other branches can be easily rebased without
|
||||
affecting other people. But once it is published, you would
|
||||
not want to rewind it.
|
||||
|
||||
(2) ... if a topic branch has been fully merged to "master".
|
||||
Then you can delete it. More importantly, you should not
|
||||
build on top of it -- other people may already want to
|
||||
change things related to the topic as patches against your
|
||||
"master", so if you need further changes, it is better to
|
||||
fork the topic (perhaps with the same name) afresh from the
|
||||
tip of "master".
|
||||
|
||||
Let's look at this example:
|
||||
|
||||
o---o---o---o---o---o---o---o---o---o "next"
|
||||
/ / / /
|
||||
/ a---a---b A / /
|
||||
/ / / /
|
||||
/ / c---c---c---c B /
|
||||
/ / / \ /
|
||||
/ / / b---b C \ /
|
||||
/ / / / \ /
|
||||
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||
|
||||
|
||||
A, B and C are topic branches.
|
||||
|
||||
* A has one fix since it was merged up to "next".
|
||||
|
||||
* B has finished. It has been fully merged up to "master" and "next",
|
||||
and is ready to be deleted.
|
||||
|
||||
* C has not merged to "next" at all.
|
||||
|
||||
We would want to allow C to be rebased, refuse A, and encourage
|
||||
B to be deleted.
|
||||
|
||||
To compute (1):
|
||||
|
||||
git rev-list ^master ^topic next
|
||||
git rev-list ^master next
|
||||
|
||||
if these match, topic has not merged in next at all.
|
||||
|
||||
To compute (2):
|
||||
|
||||
git rev-list master..topic
|
||||
|
||||
if this is empty, it is fully merged to "master".
|
||||
|
||||
DOC_END
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to make use of push options.
|
||||
# The example simply echoes all push options that start with 'echoback='
|
||||
# and rejects all pushes when the "reject" push option is used.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-receive".
|
||||
|
||||
if test -n "$GIT_PUSH_OPTION_COUNT"
|
||||
then
|
||||
i=0
|
||||
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
||||
do
|
||||
eval "value=\$GIT_PUSH_OPTION_$i"
|
||||
case "$value" in
|
||||
echoback=*)
|
||||
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
||||
;;
|
||||
reject)
|
||||
exit 1
|
||||
esac
|
||||
i=$((i + 1))
|
||||
done
|
||||
fi
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to prepare the commit log message.
|
||||
# Called by "git commit" with the name of the file that has the
|
||||
# commit message, followed by the description of the commit
|
||||
# message's source. The hook's purpose is to edit the commit
|
||||
# message file. If the hook fails with a non-zero status,
|
||||
# the commit is aborted.
|
||||
#
|
||||
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||
|
||||
# This hook includes three examples. The first one removes the
|
||||
# "# Please enter the commit message..." help message.
|
||||
#
|
||||
# The second includes the output of "git diff --name-status -r"
|
||||
# into the message, just before the "git status" output. It is
|
||||
# commented because it doesn't cope with --amend or with squashed
|
||||
# commits.
|
||||
#
|
||||
# The third example adds a Signed-off-by line to the message, that can
|
||||
# still be edited. This is rarely a good idea.
|
||||
|
||||
COMMIT_MSG_FILE=$1
|
||||
COMMIT_SOURCE=$2
|
||||
SHA1=$3
|
||||
|
||||
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
||||
|
||||
# case "$COMMIT_SOURCE,$SHA1" in
|
||||
# ,|template,)
|
||||
# /usr/bin/perl -i.bak -pe '
|
||||
# print "\n" . `git diff --cached --name-status -r`
|
||||
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
||||
# *) ;;
|
||||
# esac
|
||||
|
||||
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
||||
# if test -z "$COMMIT_SOURCE"
|
||||
# then
|
||||
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
||||
# fi
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
# An example hook script to update a checked-out tree on a git push.
|
||||
#
|
||||
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
||||
# push and updates reference(s) in its repository, and when the push
|
||||
# tries to update the branch that is currently checked out and the
|
||||
# receive.denyCurrentBranch configuration variable is set to
|
||||
# updateInstead.
|
||||
#
|
||||
# By default, such a push is refused if the working tree and the index
|
||||
# of the remote repository has any difference from the currently
|
||||
# checked out commit; when both the working tree and the index match
|
||||
# the current commit, they are updated to match the newly pushed tip
|
||||
# of the branch. This hook is to be used to override the default
|
||||
# behaviour; however the code below reimplements the default behaviour
|
||||
# as a starting point for convenient modification.
|
||||
#
|
||||
# The hook receives the commit with which the tip of the current
|
||||
# branch is going to be updated:
|
||||
commit=$1
|
||||
|
||||
# It can exit with a non-zero status to refuse the push (when it does
|
||||
# so, it must not modify the index or the working tree).
|
||||
die () {
|
||||
echo >&2 "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Or it can make any necessary changes to the working tree and to the
|
||||
# index to bring them to the desired state when the tip of the current
|
||||
# branch is updated to the new commit, and exit with a zero status.
|
||||
#
|
||||
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
||||
# in order to emulate git fetch that is run in the reverse direction
|
||||
# with git push, as the two-tree form of git read-tree -u -m is
|
||||
# essentially the same as git switch or git checkout that switches
|
||||
# branches while keeping the local changes in the working tree that do
|
||||
# not interfere with the difference between the branches.
|
||||
|
||||
# The below is a more-or-less exact translation to shell of the C code
|
||||
# for the default behaviour for git's push-to-checkout hook defined in
|
||||
# the push_to_deploy() function in builtin/receive-pack.c.
|
||||
#
|
||||
# Note that the hook will be executed from the repository directory,
|
||||
# not from the working tree, so if you want to perform operations on
|
||||
# the working tree, you will have to adapt your code accordingly, e.g.
|
||||
# by adding "cd .." or using relative paths.
|
||||
|
||||
if ! git update-index -q --ignore-submodules --refresh
|
||||
then
|
||||
die "Up-to-date check failed"
|
||||
fi
|
||||
|
||||
if ! git diff-files --quiet --ignore-submodules --
|
||||
then
|
||||
die "Working directory has unstaged changes"
|
||||
fi
|
||||
|
||||
# This is a rough translation of:
|
||||
#
|
||||
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
||||
if git cat-file -e HEAD 2>/dev/null
|
||||
then
|
||||
head=HEAD
|
||||
else
|
||||
head=$(git hash-object -t tree --stdin </dev/null)
|
||||
fi
|
||||
|
||||
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
||||
then
|
||||
die "Working directory has staged changes"
|
||||
fi
|
||||
|
||||
if ! git read-tree -u -m "$commit"
|
||||
then
|
||||
die "Could not update working tree to new HEAD"
|
||||
fi
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
# An example hook script to validate a patch (and/or patch series) before
|
||||
# sending it via email.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an appropriate
|
||||
# message if it wants to prevent the email(s) from being sent.
|
||||
#
|
||||
# To enable this hook, rename this file to "sendemail-validate".
|
||||
#
|
||||
# By default, it will only check that the patch(es) can be applied on top of
|
||||
# the default upstream branch without conflicts in a secondary worktree. After
|
||||
# validation (successful or not) of the last patch of a series, the worktree
|
||||
# will be deleted.
|
||||
#
|
||||
# The following config variables can be set to change the default remote and
|
||||
# remote ref that are used to apply the patches against:
|
||||
#
|
||||
# sendemail.validateRemote (default: origin)
|
||||
# sendemail.validateRemoteRef (default: HEAD)
|
||||
#
|
||||
# Replace the TODO placeholders with appropriate checks according to your
|
||||
# needs.
|
||||
|
||||
validate_cover_letter () {
|
||||
file="$1"
|
||||
# TODO: Replace with appropriate checks (e.g. spell checking).
|
||||
true
|
||||
}
|
||||
|
||||
validate_patch () {
|
||||
file="$1"
|
||||
# Ensure that the patch applies without conflicts.
|
||||
git am -3 "$file" || return
|
||||
# TODO: Replace with appropriate checks for this patch
|
||||
# (e.g. checkpatch.pl).
|
||||
true
|
||||
}
|
||||
|
||||
validate_series () {
|
||||
# TODO: Replace with appropriate checks for the whole series
|
||||
# (e.g. quick build, coding style checks, etc.).
|
||||
true
|
||||
}
|
||||
|
||||
# main -------------------------------------------------------------------------
|
||||
|
||||
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
|
||||
then
|
||||
remote=$(git config --default origin --get sendemail.validateRemote) &&
|
||||
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
|
||||
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
|
||||
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
|
||||
git config --replace-all sendemail.validateWorktree "$worktree"
|
||||
else
|
||||
worktree=$(git config --get sendemail.validateWorktree)
|
||||
fi || {
|
||||
echo "sendemail-validate: error: failed to prepare worktree" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
unset GIT_DIR GIT_WORK_TREE
|
||||
cd "$worktree" &&
|
||||
|
||||
if grep -q "^diff --git " "$1"
|
||||
then
|
||||
validate_patch "$1"
|
||||
else
|
||||
validate_cover_letter "$1"
|
||||
fi &&
|
||||
|
||||
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
|
||||
then
|
||||
git config --unset-all sendemail.validateWorktree &&
|
||||
trap 'git worktree remove -ff "$worktree"' EXIT &&
|
||||
validate_series
|
||||
fi
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
#!/usr/bin/sh
|
||||
#
|
||||
# An example hook script to block unannotated tags from entering.
|
||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||
#
|
||||
# To enable this hook, rename this file to "update".
|
||||
#
|
||||
# Config
|
||||
# ------
|
||||
# hooks.allowunannotated
|
||||
# This boolean sets whether unannotated tags will be allowed into the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletetag
|
||||
# This boolean sets whether deleting tags will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowmodifytag
|
||||
# This boolean sets whether a tag may be modified after creation. By default
|
||||
# it won't be.
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.denycreatebranch
|
||||
# This boolean sets whether remotely creating branches will be denied
|
||||
# in the repository. By default this is allowed.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
refname="$1"
|
||||
oldrev="$2"
|
||||
newrev="$3"
|
||||
|
||||
# --- Safety check
|
||||
if [ -z "$GIT_DIR" ]; then
|
||||
echo "Don't run this script from the command line." >&2
|
||||
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Config
|
||||
allowunannotated=$(git config --type=bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
|
||||
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
|
||||
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
|
||||
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
|
||||
|
||||
# check for no description
|
||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||
case "$projectdesc" in
|
||||
"Unnamed repository"* | "")
|
||||
echo "*** Project description file hasn't been set" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||
if [ "$newrev" = "$zero" ]; then
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git cat-file -t $newrev)
|
||||
fi
|
||||
|
||||
case "$refname","$newrev_type" in
|
||||
refs/tags/*,commit)
|
||||
# un-annotated tag
|
||||
short_refname=${refname##refs/tags/}
|
||||
if [ "$allowunannotated" != "true" ]; then
|
||||
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,delete)
|
||||
# delete tag
|
||||
if [ "$allowdeletetag" != "true" ]; then
|
||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,tag)
|
||||
# annotated tag
|
||||
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||
then
|
||||
echo "*** Tag '$refname' already exists." >&2
|
||||
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/remotes/*,commit)
|
||||
# tracking branch
|
||||
;;
|
||||
refs/remotes/*,delete)
|
||||
# delete tracking branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Anything else (is there anything else?)
|
||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Finished
|
||||
exit 0
|
||||
Binary file not shown.
|
|
@ -1,6 +0,0 @@
|
|||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
||||
|
|
@ -1 +0,0 @@
|
|||
0000000000000000000000000000000000000000 3e4bc35da41f956c873aea716c97555bf1afce5d aleidk <ale.navarro.parra@gmail.com> 1699105330 -0300 clone: from https://github.com/tmux-plugins/tmux-continuum
|
||||
|
|
@ -1 +0,0 @@
|
|||
0000000000000000000000000000000000000000 3e4bc35da41f956c873aea716c97555bf1afce5d aleidk <ale.navarro.parra@gmail.com> 1699105330 -0300 clone: from https://github.com/tmux-plugins/tmux-continuum
|
||||
|
|
@ -1 +0,0 @@
|
|||
0000000000000000000000000000000000000000 3e4bc35da41f956c873aea716c97555bf1afce5d aleidk <ale.navarro.parra@gmail.com> 1699105330 -0300 clone: from https://github.com/tmux-plugins/tmux-continuum
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue