85 changed files with 4532 additions and 1677 deletions
@ -1,23 +0,0 @@ |
|||||||
[comment {--- punk::docgen generated from inline doctools comments ---}] |
|
||||||
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}] |
|
||||||
[comment {--- punk::docgen overwrites this file ---}] |
|
||||||
[manpage_begin punk::cap 0 0.1.0] |
|
||||||
[copyright "2023 JMNoble - BSD licensed"] |
|
||||||
[titledesc {Module API}] |
|
||||||
[moddesc {punk capabilities plugin system}] |
|
||||||
[require punk::cap] |
|
||||||
[description] |
|
||||||
[list_begin definitions] |
|
||||||
[call [class interface_caphandler.registry] [method pkg_register] [arg pkg] [arg capname] [arg capdict] [arg fullcapabilitylist]] |
|
||||||
handler may override and return 0 (indicating don't register)e.g if pkg capdict data wasn't valid |
|
||||||
overridden handler must be able to handle multiple calls for same pkg - but it may return 1 or 0 as it wishes. |
|
||||||
[call [class interface_caphandler.registry] [method pkg_unregister] [arg pkg]] |
|
||||||
[call [class interface_capprovider.registration] [method pkg_unregister] [arg pkg]] |
|
||||||
[call [class interface_capprovider.provider] [method register] [opt capabilityname_glob]] |
|
||||||
[call [class interface_capprovider.provider] [method capabilities]] |
|
||||||
[call [fun exists] [arg capname]] |
|
||||||
Return a boolean indicating if the named capability exists (0|1) |
|
||||||
[call [fun has_handler] [arg capname]] |
|
||||||
Return a boolean indicating if the named capability has a handler package installed (0|1) |
|
||||||
[list_end] |
|
||||||
[manpage_end] |
|
@ -1,11 +0,0 @@ |
|||||||
[comment {--- punk::docgen generated from inline doctools comments ---}] |
|
||||||
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}] |
|
||||||
[manpage_begin %pkg% 0 999999.0a1.0] |
|
||||||
[copyright "%year%"] |
|
||||||
[titledesc {Module API}] |
|
||||||
[moddesc {-}] |
|
||||||
[require %pkg%] |
|
||||||
[description] |
|
||||||
[list_begin definitions] |
|
||||||
[list_end] |
|
||||||
[manpage_end] |
|
@ -0,0 +1,84 @@ |
|||||||
|
[comment {--- punk::docgen generated from inline doctools comments ---}] |
||||||
|
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}] |
||||||
|
[comment {--- punk::docgen overwrites this file ---}] |
||||||
|
[manpage_begin punk::path 0 0.1.0] |
||||||
|
[copyright "2023"] |
||||||
|
[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}] |
||||||
|
[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}] |
||||||
|
[require punk::path] |
||||||
|
[description] |
||||||
|
[section Overview] |
||||||
|
[para] overview of punk::path |
||||||
|
[para] Filesystem path utility functions |
||||||
|
[subsection Concepts] |
||||||
|
[para] - |
||||||
|
[subsection dependencies] |
||||||
|
[para] packages used by punk::path |
||||||
|
[list_begin itemized] |
||||||
|
[item] [package {Tcl 8.6}] |
||||||
|
[list_end] |
||||||
|
[section API] |
||||||
|
[subsection {Namespace punk::path::class}] |
||||||
|
[para] class definitions |
||||||
|
[list_begin enumerated] |
||||||
|
[list_end] [comment {--- end class enumeration ---}] |
||||||
|
[subsection {Namespace punk::path}] |
||||||
|
[para] Core API functions for punk::path |
||||||
|
[list_begin definitions] |
||||||
|
[call [fun pathglob_as_re] [arg pathglob]] |
||||||
|
[para] Returns a regular expression for matching a path to a glob pattern which can contain glob chars *|? in any segment of the path structure |
||||||
|
[para] ** matches any number of subdirectories. |
||||||
|
[para] e.g /etc/**/*.txt will match any .txt files at any depth below /etc (except directly within /etc itself) |
||||||
|
[para] e.g /etc/**.txt will match any .txt files at any depth below /etc |
||||||
|
[para] any segment that does not contain ** must match exactly one segment in the path |
||||||
|
[para] e.g the glob /etc/*/*.doc - will match any .doc files that are exactly one tree level below /etc |
||||||
|
[para] The pathglob doesn't have to contain glob characters, in which case the returned regex will match the pathglob exactly as specified. |
||||||
|
[para] Regular expression syntax is deliberateley not supported within the pathglob string so that supplied regex characters will be treated as literals |
||||||
|
[call [fun globmatchpath] [arg pathglob] [arg path] [opt {option value...}]] |
||||||
|
[para] Return true if the pathglob matches the path |
||||||
|
[para] see [fun pathglob_as_re] for pathglob description |
||||||
|
[para] Caller must ensure that file separator is forward slash. (e.g use file normalize on windows) |
||||||
|
[para] |
||||||
|
[para] Known options: |
||||||
|
[para] -nocase 0|1 (default 0 - case sensitive) |
||||||
|
[para] If -nocase is not supplied - default to case sensitive *except for driveletter* |
||||||
|
[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah) |
||||||
|
[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter. |
||||||
|
[call [fun treefilenames] [arg basepath] [arg tailglob] [opt {option value...}]] |
||||||
|
basic (glob based) list of filenames matching tailglob - recursive |
||||||
|
no natsorting - so order is dependent on filesystem |
||||||
|
[call [fun relative] [arg reference] [arg location]] |
||||||
|
[para] Taking two directory paths, a reference and a location, computes the path |
||||||
|
of the location relative to the reference. |
||||||
|
[list_begin itemized] |
||||||
|
[item] |
||||||
|
[para] Arguments: |
||||||
|
[list_begin arguments] |
||||||
|
[arg_def string reference] The path from which the relative path to location is determined. |
||||||
|
[arg_def string location] The location path which may be above or below the reference path |
||||||
|
[list_end] |
||||||
|
[item] |
||||||
|
[para] Results: |
||||||
|
[para] The relative path of the location to the reference path. |
||||||
|
[para] Will return a single dot "." if the paths are the same |
||||||
|
[item] |
||||||
|
[para] Notes: |
||||||
|
[para] Both paths must be the same type - ie both absolute or both relative |
||||||
|
[para] Case sensitive. ie relative /etc /etC |
||||||
|
will return ../etC |
||||||
|
[para] On windows, the drive-letter component (only) is not case sensitive |
||||||
|
[para] ie relative c:/etc C:/etc returns . |
||||||
|
[para] but relative c:/etc C:/Etc returns ../Etc |
||||||
|
[para] On windows, if the paths are absolute and specifiy different volumes, only the location will be returned. |
||||||
|
ie relative c:/etc d:/etc/blah |
||||||
|
returns d:/etc/blah |
||||||
|
[list_end] |
||||||
|
[list_end] [comment {--- end definitions namespace punk::path ---}] |
||||||
|
[subsection {Namespace punk::path::lib}] |
||||||
|
[para] Secondary functions that are part of the API |
||||||
|
[list_begin definitions] |
||||||
|
[list_end] [comment {--- end definitions namespace punk::path::lib ---}] |
||||||
|
[section Internal] |
||||||
|
[subsection {Namespace punk::path::system}] |
||||||
|
[para] Internal functions that are not part of the API |
||||||
|
[manpage_end] |
@ -0,0 +1,48 @@ |
|||||||
|
[comment {--- punk::docgen generated from inline doctools comments ---}] |
||||||
|
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}] |
||||||
|
[comment {--- punk::docgen overwrites this file ---}] |
||||||
|
[manpage_begin punk::mix::commandset::project 0 0.1.0] |
||||||
|
[copyright "2023"] |
||||||
|
[titledesc {pmix commandset - project}] [comment {-- Name section and table of contents description --}] |
||||||
|
[moddesc {pmix CLI commandset - project}] [comment {-- Description at end of page heading --}] |
||||||
|
[require punk::mix::commandset::project] |
||||||
|
[description] |
||||||
|
[section Overview] |
||||||
|
[para] overview of punk::mix::commandset::project |
||||||
|
[para]Import into an ensemble namespace similarly to the way it is done with punk::mix::cli e.g |
||||||
|
[example { |
||||||
|
namespace eval myproject::cli { |
||||||
|
namespace export * |
||||||
|
namespace ensemble create |
||||||
|
package require punk::overlay |
||||||
|
|
||||||
|
package require punk::mix::commandset::project |
||||||
|
punk::overlay::import_commandset project . ::punk::mix::commandset::project |
||||||
|
punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection |
||||||
|
} |
||||||
|
}] |
||||||
|
[para] Where the . in the above example is the prefix/command separator |
||||||
|
[para]The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets. |
||||||
|
[para]The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new |
||||||
|
[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.<procname> |
||||||
|
[para] |
||||||
|
[subsection Concepts] |
||||||
|
[para] see punk::overlay |
||||||
|
[subsection dependencies] |
||||||
|
[para] packages used by punk::mix::commandset::project |
||||||
|
[list_begin itemized] |
||||||
|
[item] [package {Tcl 8.6}] |
||||||
|
[item] [package punk::ns] |
||||||
|
[item] [package sqlite3] (binary) |
||||||
|
[item] [package overtype] |
||||||
|
[item] [package textutil] (tcllib) |
||||||
|
[list_end] |
||||||
|
[section API] |
||||||
|
[subsection {Namespace punk::mix::commandset::project}] |
||||||
|
[para] core commandset functions for punk::mix::commandset::project |
||||||
|
[list_begin definitions] |
||||||
|
[call [fun new] [arg newprojectpath_or_name] [opt args]] |
||||||
|
new project structure - may be dedicated to one module, or contain many. |
||||||
|
create minimal folder structure only by specifying in args: -modules {} |
||||||
|
[list_end] [comment {--- end definitions namespace punk::mix::commandset::project ---}] |
||||||
|
[manpage_end] |
@ -1,6 +1,6 @@ |
|||||||
[toc_begin {Table Of Contents} doc] |
[toc_begin {Table Of Contents} doc] |
||||||
[item doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.md %pkg% {Module API}] |
[item doc/files/punk/_module_cap-0.1.0.tm.md punk::cap {capability provider and handler plugin system}] |
||||||
[item doc/files/_module_punk_cap-0.1.0.tm.md punk::cap {capability provider and handler plugin system}] |
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punk::mix::commandset::project {pmix commandset - project}] |
||||||
[item doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.md punk::cap {Module API}] |
[item doc/files/punk/_module_path-0.1.0.tm.md punk::path {Filesystem path utilities}] |
||||||
[item doc/files/main.md punkshell {punkshell - Core}] |
[item doc/files/main.md punkshell {punkshell - Core}] |
||||||
[toc_end] |
[toc_end] |
||||||
|
@ -1 +1 @@ |
|||||||
doc {doc/toc {{doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.md %pkg% {Module API}} {doc/files/_module_punk_cap-0.1.0.tm.md punk::cap {capability provider and handler plugin system}} {doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.md punk::cap {Module API}} {doc/files/main.md punkshell {punkshell - Core}}}} |
doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.md punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_path-0.1.0.tm.md punk::path {Filesystem path utilities}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punk::mix::commandset::project {pmix commandset - project}} {doc/files/main.md punkshell {punkshell - Core}}}} |
@ -1 +1 @@ |
|||||||
{capability provider and handler plugin system} doc/files/_module_punk_cap-0.1.0.tm.md repl {index.md repl} %pkg% doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.md kw,punk {index.md punk} %pkg%(0) doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.md punkshell(n) doc/files/main.md sa,punk::cap doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.md punkshell doc/files/main.md sa,punk::cap(0) doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.md {Module API} doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.md shell {index.md shell} kw,repl {index.md repl} sa,%pkg% doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.md {punkshell - Core} doc/files/main.md sa,%pkg%(0) doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.md sa,punkshell(n) doc/files/main.md punk::cap doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.md sa,punkshell doc/files/main.md kw,shell {index.md shell} punk {index.md punk} punk::cap(0) doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.md |
sa,punk::path(0) doc/files/punk/_module_path-0.1.0.tm.md {capability provider and handler plugin system} doc/files/punk/_module_cap-0.1.0.tm.md punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md repl {index.md repl} kw,punk {index.md punk} punkshell(n) doc/files/main.md sa,punk::cap doc/files/punk/_module_cap-0.1.0.tm.md {Filesystem path utilities} doc/files/punk/_module_path-0.1.0.tm.md punkshell doc/files/main.md sa,punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.md sa,punk::path doc/files/punk/_module_path-0.1.0.tm.md punk::path(0) doc/files/punk/_module_path-0.1.0.tm.md shell {index.md shell} kw,repl {index.md repl} sa,punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md sa,punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md {punkshell - Core} doc/files/main.md {pmix commandset - project} doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md sa,punkshell(n) doc/files/main.md punk::cap doc/files/punk/_module_cap-0.1.0.tm.md sa,punkshell doc/files/main.md kw,shell {index.md shell} punk {index.md punk} punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.md punk::path doc/files/punk/_module_path-0.1.0.tm.md |
@ -1,64 +0,0 @@ |
|||||||
|
|
||||||
[//000000001]: # (punk::cap \- punk capabilities plugin system) |
|
||||||
[//000000002]: # (Generated from file '\_module\_punk\_mix\_templates\_layouts\_project\_src\_bootsupport\_modules\_punk\_cap\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown') |
|
||||||
[//000000003]: # (Copyright © 2023 JMNoble \- BSD licensed) |
|
||||||
[//000000004]: # (punk::cap\(0\) 0\.1\.0 doc "punk capabilities plugin system") |
|
||||||
|
|
||||||
<hr> [ <a href="../../toc.md">Main Table Of Contents</a> | <a |
|
||||||
href="../toc.md">Table Of Contents</a> | <a |
|
||||||
href="../../index.md">Keyword Index</a> ] <hr> |
|
||||||
|
|
||||||
# NAME |
|
||||||
|
|
||||||
punk::cap \- Module API |
|
||||||
|
|
||||||
# <a name='toc'></a>Table Of Contents |
|
||||||
|
|
||||||
- [Table Of Contents](#toc) |
|
||||||
|
|
||||||
- [Synopsis](#synopsis) |
|
||||||
|
|
||||||
- [Description](#section1) |
|
||||||
|
|
||||||
- [Copyright](#copyright) |
|
||||||
|
|
||||||
# <a name='synopsis'></a>SYNOPSIS |
|
||||||
|
|
||||||
package require punk::cap |
|
||||||
|
|
||||||
[__interface\_caphandler\.registry__ __pkg\_register__ *pkg* *capname* *capdict* *fullcapabilitylist*](#1) |
|
||||||
[__interface\_caphandler\.registry__ __pkg\_unregister__ *pkg*](#2) |
|
||||||
[__interface\_capprovider\.registration__ __pkg\_unregister__ *pkg*](#3) |
|
||||||
[__interface\_capprovider\.provider__ __register__ ?capabilityname\_glob?](#4) |
|
||||||
[__interface\_capprovider\.provider__ __capabilities__](#5) |
|
||||||
[__exists__ *capname*](#6) |
|
||||||
[__has\_handler__ *capname*](#7) |
|
||||||
|
|
||||||
# <a name='description'></a>DESCRIPTION |
|
||||||
|
|
||||||
- <a name='1'></a>__interface\_caphandler\.registry__ __pkg\_register__ *pkg* *capname* *capdict* *fullcapabilitylist* |
|
||||||
|
|
||||||
handler may override and return 0 \(indicating don't register\)e\.g if pkg |
|
||||||
capdict data wasn't valid overridden handler must be able to handle multiple |
|
||||||
calls for same pkg \- but it may return 1 or 0 as it wishes\. |
|
||||||
|
|
||||||
- <a name='2'></a>__interface\_caphandler\.registry__ __pkg\_unregister__ *pkg* |
|
||||||
|
|
||||||
- <a name='3'></a>__interface\_capprovider\.registration__ __pkg\_unregister__ *pkg* |
|
||||||
|
|
||||||
- <a name='4'></a>__interface\_capprovider\.provider__ __register__ ?capabilityname\_glob? |
|
||||||
|
|
||||||
- <a name='5'></a>__interface\_capprovider\.provider__ __capabilities__ |
|
||||||
|
|
||||||
- <a name='6'></a>__exists__ *capname* |
|
||||||
|
|
||||||
Return a boolean indicating if the named capability exists \(0|1\) |
|
||||||
|
|
||||||
- <a name='7'></a>__has\_handler__ *capname* |
|
||||||
|
|
||||||
Return a boolean indicating if the named capability has a handler package |
|
||||||
installed \(0|1\) |
|
||||||
|
|
||||||
# <a name='copyright'></a>COPYRIGHT |
|
||||||
|
|
||||||
Copyright © 2023 JMNoble \- BSD licensed |
|
@ -1,33 +0,0 @@ |
|||||||
|
|
||||||
[//000000001]: # (%pkg% \- \-) |
|
||||||
[//000000002]: # (Generated from file '\_module\_punk\_mix\_templates\_modules\_template\_module\-0\.0\.1\.tm\.man' by tcllib/doctools with format 'markdown') |
|
||||||
[//000000003]: # (Copyright © %year%) |
|
||||||
[//000000004]: # (%pkg%\(0\) 999999\.0a1\.0 doc "\-") |
|
||||||
|
|
||||||
<hr> [ <a href="../../toc.md">Main Table Of Contents</a> | <a |
|
||||||
href="../toc.md">Table Of Contents</a> | <a |
|
||||||
href="../../index.md">Keyword Index</a> ] <hr> |
|
||||||
|
|
||||||
# NAME |
|
||||||
|
|
||||||
%pkg% \- Module API |
|
||||||
|
|
||||||
# <a name='toc'></a>Table Of Contents |
|
||||||
|
|
||||||
- [Table Of Contents](#toc) |
|
||||||
|
|
||||||
- [Synopsis](#synopsis) |
|
||||||
|
|
||||||
- [Description](#section1) |
|
||||||
|
|
||||||
- [Copyright](#copyright) |
|
||||||
|
|
||||||
# <a name='synopsis'></a>SYNOPSIS |
|
||||||
|
|
||||||
package require %pkg% |
|
||||||
|
|
||||||
# <a name='description'></a>DESCRIPTION |
|
||||||
|
|
||||||
# <a name='copyright'></a>COPYRIGHT |
|
||||||
|
|
||||||
Copyright © %year% |
|
@ -0,0 +1,176 @@ |
|||||||
|
|
||||||
|
[//000000001]: # (punk::path \- punk path filesystem utils) |
||||||
|
[//000000002]: # (Generated from file '\_module\_path\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown') |
||||||
|
[//000000003]: # (Copyright © 2023) |
||||||
|
[//000000004]: # (punk::path\(0\) 0\.1\.0 doc "punk path filesystem utils") |
||||||
|
|
||||||
|
<hr> [ <a href="../../../toc.md">Main Table Of Contents</a> | <a |
||||||
|
href="../../toc.md">Table Of Contents</a> | <a |
||||||
|
href="../../../index.md">Keyword Index</a> ] <hr> |
||||||
|
|
||||||
|
# NAME |
||||||
|
|
||||||
|
punk::path \- Filesystem path utilities |
||||||
|
|
||||||
|
# <a name='toc'></a>Table Of Contents |
||||||
|
|
||||||
|
- [Table Of Contents](#toc) |
||||||
|
|
||||||
|
- [Synopsis](#synopsis) |
||||||
|
|
||||||
|
- [Description](#section1) |
||||||
|
|
||||||
|
- [Overview](#section2) |
||||||
|
|
||||||
|
- [Concepts](#subsection1) |
||||||
|
|
||||||
|
- [dependencies](#subsection2) |
||||||
|
|
||||||
|
- [API](#section3) |
||||||
|
|
||||||
|
- [Namespace punk::path::class](#subsection3) |
||||||
|
|
||||||
|
- [Namespace punk::path](#subsection4) |
||||||
|
|
||||||
|
- [Namespace punk::path::lib](#subsection5) |
||||||
|
|
||||||
|
- [Internal](#section4) |
||||||
|
|
||||||
|
- [Namespace punk::path::system](#subsection6) |
||||||
|
|
||||||
|
- [Copyright](#copyright) |
||||||
|
|
||||||
|
# <a name='synopsis'></a>SYNOPSIS |
||||||
|
|
||||||
|
package require punk::path |
||||||
|
|
||||||
|
[__pathglob\_as\_re__ *pathglob*](#1) |
||||||
|
[__globmatchpath__ *pathglob* *path* ?option value\.\.\.?](#2) |
||||||
|
[__treefilenames__ *basepath* *tailglob* ?option value\.\.\.?](#3) |
||||||
|
[__relative__ *reference* *location*](#4) |
||||||
|
|
||||||
|
# <a name='description'></a>DESCRIPTION |
||||||
|
|
||||||
|
# <a name='section2'></a>Overview |
||||||
|
|
||||||
|
overview of punk::path |
||||||
|
|
||||||
|
Filesystem path utility functions |
||||||
|
|
||||||
|
## <a name='subsection1'></a>Concepts |
||||||
|
|
||||||
|
\- |
||||||
|
|
||||||
|
## <a name='subsection2'></a>dependencies |
||||||
|
|
||||||
|
packages used by punk::path |
||||||
|
|
||||||
|
- __Tcl 8\.6__ |
||||||
|
|
||||||
|
# <a name='section3'></a>API |
||||||
|
|
||||||
|
## <a name='subsection3'></a>Namespace punk::path::class |
||||||
|
|
||||||
|
class definitions |
||||||
|
|
||||||
|
## <a name='subsection4'></a>Namespace punk::path |
||||||
|
|
||||||
|
- <a name='1'></a>__pathglob\_as\_re__ *pathglob* |
||||||
|
|
||||||
|
Returns a regular expression for matching a path to a glob pattern which can |
||||||
|
contain glob chars \*|? in any segment of the path structure |
||||||
|
|
||||||
|
\*\* matches any number of subdirectories\. |
||||||
|
|
||||||
|
e\.g /etc/\*\*/\*\.txt will match any \.txt files at any depth below /etc \(except |
||||||
|
directly within /etc itself\) |
||||||
|
|
||||||
|
e\.g /etc/\*\*\.txt will match any \.txt files at any depth below /etc |
||||||
|
|
||||||
|
any segment that does not contain \*\* must match exactly one segment in the |
||||||
|
path |
||||||
|
|
||||||
|
e\.g the glob /etc/\*/\*\.doc \- will match any \.doc files that are exactly one |
||||||
|
tree level below /etc |
||||||
|
|
||||||
|
The pathglob doesn't have to contain glob characters, in which case the |
||||||
|
returned regex will match the pathglob exactly as specified\. |
||||||
|
|
||||||
|
Regular expression syntax is deliberateley not supported within the pathglob |
||||||
|
string so that supplied regex characters will be treated as literals |
||||||
|
|
||||||
|
- <a name='2'></a>__globmatchpath__ *pathglob* *path* ?option value\.\.\.? |
||||||
|
|
||||||
|
Return true if the pathglob matches the path |
||||||
|
|
||||||
|
see __pathglob\_as\_re__ for pathglob description |
||||||
|
|
||||||
|
Caller must ensure that file separator is forward slash\. \(e\.g use file |
||||||
|
normalize on windows\) |
||||||
|
|
||||||
|
Known options: |
||||||
|
|
||||||
|
\-nocase 0|1 \(default 0 \- case sensitive\) |
||||||
|
|
||||||
|
If \-nocase is not supplied \- default to case sensitive \*except for |
||||||
|
driveletter\* |
||||||
|
|
||||||
|
ie \- the driveletter alone in paths such as c:/etc will still be case |
||||||
|
insensitive\. \(ie c:/ETC/\* will match C:/ETC/blah but not C:/etc/blah\) |
||||||
|
|
||||||
|
Explicitly specifying \-nocase 0 will require the entire case to match |
||||||
|
including the driveletter\. |
||||||
|
|
||||||
|
- <a name='3'></a>__treefilenames__ *basepath* *tailglob* ?option value\.\.\.? |
||||||
|
|
||||||
|
basic \(glob based\) list of filenames matching tailglob \- recursive no |
||||||
|
natsorting \- so order is dependent on filesystem |
||||||
|
|
||||||
|
- <a name='4'></a>__relative__ *reference* *location* |
||||||
|
|
||||||
|
Taking two directory paths, a reference and a location, computes the path of |
||||||
|
the location relative to the reference\. |
||||||
|
|
||||||
|
* Arguments: |
||||||
|
|
||||||
|
+ string *reference* |
||||||
|
|
||||||
|
The path from which the relative path to location is determined\. |
||||||
|
|
||||||
|
+ string *location* |
||||||
|
|
||||||
|
The location path which may be above or below the reference path |
||||||
|
|
||||||
|
* Results: |
||||||
|
|
||||||
|
The relative path of the location to the reference path\. |
||||||
|
|
||||||
|
Will return a single dot "\." if the paths are the same |
||||||
|
|
||||||
|
* Notes: |
||||||
|
|
||||||
|
Both paths must be the same type \- ie both absolute or both relative |
||||||
|
|
||||||
|
Case sensitive\. ie relative /etc /etC will return \.\./etC |
||||||
|
|
||||||
|
On windows, the drive\-letter component \(only\) is not case sensitive |
||||||
|
|
||||||
|
ie relative c:/etc C:/etc returns \. |
||||||
|
|
||||||
|
but relative c:/etc C:/Etc returns \.\./Etc |
||||||
|
|
||||||
|
On windows, if the paths are absolute and specifiy different volumes, |
||||||
|
only the location will be returned\. ie relative c:/etc d:/etc/blah |
||||||
|
returns d:/etc/blah |
||||||
|
|
||||||
|
## <a name='subsection5'></a>Namespace punk::path::lib |
||||||
|
|
||||||
|
Secondary functions that are part of the API |
||||||
|
|
||||||
|
# <a name='section4'></a>Internal |
||||||
|
|
||||||
|
## <a name='subsection6'></a>Namespace punk::path::system |
||||||
|
|
||||||
|
# <a name='copyright'></a>COPYRIGHT |
||||||
|
|
||||||
|
Copyright © 2023 |
@ -0,0 +1,102 @@ |
|||||||
|
|
||||||
|
[//000000001]: # (punk::mix::commandset::project \- pmix CLI commandset \- project) |
||||||
|
[//000000002]: # (Generated from file '\_module\_project\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown') |
||||||
|
[//000000003]: # (Copyright © 2023) |
||||||
|
[//000000004]: # (punk::mix::commandset::project\(0\) 0\.1\.0 doc "pmix CLI commandset \- project") |
||||||
|
|
||||||
|
<hr> [ <a href="../../../../../toc.md">Main Table Of Contents</a> | |
||||||
|
<a href="../../../../toc.md">Table Of Contents</a> | <a |
||||||
|
href="../../../../../index.md">Keyword Index</a> ] <hr> |
||||||
|
|
||||||
|
# NAME |
||||||
|
|
||||||
|
punk::mix::commandset::project \- pmix commandset \- project |
||||||
|
|
||||||
|
# <a name='toc'></a>Table Of Contents |
||||||
|
|
||||||
|
- [Table Of Contents](#toc) |
||||||
|
|
||||||
|
- [Synopsis](#synopsis) |
||||||
|
|
||||||
|
- [Description](#section1) |
||||||
|
|
||||||
|
- [Overview](#section2) |
||||||
|
|
||||||
|
- [Concepts](#subsection1) |
||||||
|
|
||||||
|
- [dependencies](#subsection2) |
||||||
|
|
||||||
|
- [API](#section3) |
||||||
|
|
||||||
|
- [Namespace punk::mix::commandset::project](#subsection3) |
||||||
|
|
||||||
|
- [Copyright](#copyright) |
||||||
|
|
||||||
|
# <a name='synopsis'></a>SYNOPSIS |
||||||
|
|
||||||
|
package require punk::mix::commandset::project |
||||||
|
|
||||||
|
[__new__ *newprojectpath\_or\_name* ?args?](#1) |
||||||
|
|
||||||
|
# <a name='description'></a>DESCRIPTION |
||||||
|
|
||||||
|
# <a name='section2'></a>Overview |
||||||
|
|
||||||
|
overview of punk::mix::commandset::project |
||||||
|
|
||||||
|
Import into an ensemble namespace similarly to the way it is done with |
||||||
|
punk::mix::cli e\.g |
||||||
|
|
||||||
|
namespace eval myproject::cli { |
||||||
|
namespace export * |
||||||
|
namespace ensemble create |
||||||
|
package require punk::overlay |
||||||
|
|
||||||
|
package require punk::mix::commandset::project |
||||||
|
punk::overlay::import_commandset project . ::punk::mix::commandset::project |
||||||
|
punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection |
||||||
|
} |
||||||
|
|
||||||
|
Where the \. in the above example is the prefix/command separator |
||||||
|
|
||||||
|
The prefix \('project' in the above example\) can be any string desired to |
||||||
|
disambiguate commands imported from other commandsets\. |
||||||
|
|
||||||
|
The above results in the availability of the ensemble command: ::myproject::cli |
||||||
|
project\.new, which is implemented in ::punk::mix::commandset::project::new |
||||||
|
|
||||||
|
Similarly, procs under ::punk::mix::commandset::project::collection will be |
||||||
|
available as subcommands of the ensemble as projects\.<procname> |
||||||
|
|
||||||
|
## <a name='subsection1'></a>Concepts |
||||||
|
|
||||||
|
see punk::overlay |
||||||
|
|
||||||
|
## <a name='subsection2'></a>dependencies |
||||||
|
|
||||||
|
packages used by punk::mix::commandset::project |
||||||
|
|
||||||
|
- __Tcl 8\.6__ |
||||||
|
|
||||||
|
- __punk::ns__ |
||||||
|
|
||||||
|
- __sqlite3__ \(binary\) |
||||||
|
|
||||||
|
- __overtype__ |
||||||
|
|
||||||
|
- __textutil__ \(tcllib\) |
||||||
|
|
||||||
|
# <a name='section3'></a>API |
||||||
|
|
||||||
|
## <a name='subsection3'></a>Namespace punk::mix::commandset::project |
||||||
|
|
||||||
|
core commandset functions for punk::mix::commandset::project |
||||||
|
|
||||||
|
- <a name='1'></a>__new__ *newprojectpath\_or\_name* ?args? |
||||||
|
|
||||||
|
new project structure \- may be dedicated to one module, or contain many\. |
||||||
|
create minimal folder structure only by specifying in args: \-modules \{\} |
||||||
|
|
||||||
|
# <a name='copyright'></a>COPYRIGHT |
||||||
|
|
||||||
|
Copyright © 2023 |
@ -1,6 +1,6 @@ |
|||||||
[toc_begin {Table Of Contents} doc] |
[toc_begin {Table Of Contents} doc] |
||||||
[item doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.html %pkg% {Module API}] |
[item doc/files/punk/_module_cap-0.1.0.tm.html punk::cap {capability provider and handler plugin system}] |
||||||
[item doc/files/_module_punk_cap-0.1.0.tm.html punk::cap {capability provider and handler plugin system}] |
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punk::mix::commandset::project {pmix commandset - project}] |
||||||
[item doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.html punk::cap {Module API}] |
[item doc/files/punk/_module_path-0.1.0.tm.html punk::path {Filesystem path utilities}] |
||||||
[item doc/files/main.html punkshell {punkshell - Core}] |
[item doc/files/main.html punkshell {punkshell - Core}] |
||||||
[toc_end] |
[toc_end] |
||||||
|
@ -1 +1 @@ |
|||||||
doc {doc/toc {{doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.html %pkg% {Module API}} {doc/files/_module_punk_cap-0.1.0.tm.html punk::cap {capability provider and handler plugin system}} {doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.html punk::cap {Module API}} {doc/files/main.html punkshell {punkshell - Core}}}} |
doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.html punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_path-0.1.0.tm.html punk::path {Filesystem path utilities}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punk::mix::commandset::project {pmix commandset - project}} {doc/files/main.html punkshell {punkshell - Core}}}} |
@ -1 +1 @@ |
|||||||
{capability provider and handler plugin system} doc/files/_module_punk_cap-0.1.0.tm.html repl {index.html repl} %pkg% doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.html kw,punk {index.html punk} %pkg%(0) doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.html punkshell(n) doc/files/main.html sa,punk::cap doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.html punkshell doc/files/main.html sa,punk::cap(0) doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.html {Module API} doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.html shell {index.html shell} kw,repl {index.html repl} sa,%pkg% doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.html {punkshell - Core} doc/files/main.html sa,%pkg%(0) doc/files/_module_punk_mix_templates_modules_template_module-0.0.1.tm.html sa,punkshell(n) doc/files/main.html punk::cap doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.html sa,punkshell doc/files/main.html kw,shell {index.html shell} punk {index.html punk} punk::cap(0) doc/files/_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.html |
sa,punk::path(0) doc/files/punk/_module_path-0.1.0.tm.html {capability provider and handler plugin system} doc/files/punk/_module_cap-0.1.0.tm.html punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html repl {index.html repl} kw,punk {index.html punk} punkshell(n) doc/files/main.html sa,punk::cap doc/files/punk/_module_cap-0.1.0.tm.html {Filesystem path utilities} doc/files/punk/_module_path-0.1.0.tm.html punkshell doc/files/main.html sa,punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.html sa,punk::path doc/files/punk/_module_path-0.1.0.tm.html punk::path(0) doc/files/punk/_module_path-0.1.0.tm.html shell {index.html shell} kw,repl {index.html repl} sa,punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html sa,punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html {punkshell - Core} doc/files/main.html {pmix commandset - project} doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html sa,punkshell(n) doc/files/main.html punk::cap doc/files/punk/_module_cap-0.1.0.tm.html sa,punkshell doc/files/main.html kw,shell {index.html shell} punk {index.html punk} punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.html punk::path doc/files/punk/_module_path-0.1.0.tm.html |
@ -1,156 +0,0 @@ |
|||||||
<!DOCTYPE html><html><head> |
|
||||||
<title>punk::cap - punk capabilities plugin system</title> |
|
||||||
<style type="text/css"><!-- |
|
||||||
HTML { |
|
||||||
background: #FFFFFF; |
|
||||||
color: black; |
|
||||||
} |
|
||||||
BODY { |
|
||||||
background: #FFFFFF; |
|
||||||
color: black; |
|
||||||
} |
|
||||||
DIV.doctools { |
|
||||||
margin-left: 10%; |
|
||||||
margin-right: 10%; |
|
||||||
} |
|
||||||
DIV.doctools H1,DIV.doctools H2 { |
|
||||||
margin-left: -5%; |
|
||||||
} |
|
||||||
H1, H2, H3, H4 { |
|
||||||
margin-top: 1em; |
|
||||||
font-family: sans-serif; |
|
||||||
font-size: large; |
|
||||||
color: #005A9C; |
|
||||||
background: transparent; |
|
||||||
text-align: left; |
|
||||||
} |
|
||||||
H1.doctools_title { |
|
||||||
text-align: center; |
|
||||||
} |
|
||||||
UL,OL { |
|
||||||
margin-right: 0em; |
|
||||||
margin-top: 3pt; |
|
||||||
margin-bottom: 3pt; |
|
||||||
} |
|
||||||
UL LI { |
|
||||||
list-style: disc; |
|
||||||
} |
|
||||||
OL LI { |
|
||||||
list-style: decimal; |
|
||||||
} |
|
||||||
DT { |
|
||||||
padding-top: 1ex; |
|
||||||
} |
|
||||||
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { |
|
||||||
font: normal 12pt/14pt sans-serif; |
|
||||||
list-style: none; |
|
||||||
} |
|
||||||
LI.doctools_section, LI.doctools_subsection { |
|
||||||
list-style: none; |
|
||||||
margin-left: 0em; |
|
||||||
text-indent: 0em; |
|
||||||
padding: 0em; |
|
||||||
} |
|
||||||
PRE { |
|
||||||
display: block; |
|
||||||
font-family: monospace; |
|
||||||
white-space: pre; |
|
||||||
margin: 0%; |
|
||||||
padding-top: 0.5ex; |
|
||||||
padding-bottom: 0.5ex; |
|
||||||
padding-left: 1ex; |
|
||||||
padding-right: 1ex; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
PRE.doctools_example { |
|
||||||
color: black; |
|
||||||
background: #f5dcb3; |
|
||||||
border: 1px solid black; |
|
||||||
} |
|
||||||
UL.doctools_requirements LI, UL.doctools_syntax LI { |
|
||||||
list-style: none; |
|
||||||
margin-left: 0em; |
|
||||||
text-indent: 0em; |
|
||||||
padding: 0em; |
|
||||||
} |
|
||||||
DIV.doctools_synopsis { |
|
||||||
color: black; |
|
||||||
background: #80ffff; |
|
||||||
border: 1px solid black; |
|
||||||
font-family: serif; |
|
||||||
margin-top: 1em; |
|
||||||
margin-bottom: 1em; |
|
||||||
} |
|
||||||
UL.doctools_syntax { |
|
||||||
margin-top: 1em; |
|
||||||
border-top: 1px solid black; |
|
||||||
} |
|
||||||
UL.doctools_requirements { |
|
||||||
margin-bottom: 1em; |
|
||||||
border-bottom: 1px solid black; |
|
||||||
} |
|
||||||
--></style> |
|
||||||
</head> |
|
||||||
<!-- Generated from file '_module_punk_mix_templates_layouts_project_src_bootsupport_modules_punk_cap-0.1.0.tm.man' by tcllib/doctools with format 'html' |
|
||||||
--> |
|
||||||
<!-- Copyright &copy; 2023 JMNoble - BSD licensed |
|
||||||
--> |
|
||||||
<!-- punk::cap.0 |
|
||||||
--> |
|
||||||
<body><hr> [ |
|
||||||
<a href="../../toc.html">Main Table Of Contents</a> |
|
||||||
| <a href="../toc.html">Table Of Contents</a> |
|
||||||
| <a href="../../index.html">Keyword Index</a> |
|
||||||
] <hr> |
|
||||||
<div class="doctools"> |
|
||||||
<h1 class="doctools_title">punk::cap(0) 0.1.0 doc "punk capabilities plugin system"</h1> |
|
||||||
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> |
|
||||||
<p>punk::cap - Module API</p> |
|
||||||
</div> |
|
||||||
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> |
|
||||||
<ul class="doctools_toc"> |
|
||||||
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li> |
|
||||||
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li> |
|
||||||
<li class="doctools_section"><a href="#section1">Description</a></li> |
|
||||||
<li class="doctools_section"><a href="#copyright">Copyright</a></li> |
|
||||||
</ul> |
|
||||||
</div> |
|
||||||
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> |
|
||||||
<div class="doctools_synopsis"> |
|
||||||
<ul class="doctools_requirements"> |
|
||||||
<li>package require <b class="pkgname">punk::cap</b></li> |
|
||||||
</ul> |
|
||||||
<ul class="doctools_syntax"> |
|
||||||
<li><a href="#1"><b class="class">interface_caphandler.registry</b> <b class="method">pkg_register</b> <i class="arg">pkg</i> <i class="arg">capname</i> <i class="arg">capdict</i> <i class="arg">fullcapabilitylist</i></a></li> |
|
||||||
<li><a href="#2"><b class="class">interface_caphandler.registry</b> <b class="method">pkg_unregister</b> <i class="arg">pkg</i></a></li> |
|
||||||
<li><a href="#3"><b class="class">interface_capprovider.registration</b> <b class="method">pkg_unregister</b> <i class="arg">pkg</i></a></li> |
|
||||||
<li><a href="#4"><b class="class">interface_capprovider.provider</b> <b class="method">register</b> <span class="opt">?capabilityname_glob?</span></a></li> |
|
||||||
<li><a href="#5"><b class="class">interface_capprovider.provider</b> <b class="method">capabilities</b></a></li> |
|
||||||
<li><a href="#6"><b class="function">exists</b> <i class="arg">capname</i></a></li> |
|
||||||
<li><a href="#7"><b class="function">has_handler</b> <i class="arg">capname</i></a></li> |
|
||||||
</ul> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> |
|
||||||
<dl class="doctools_definitions"> |
|
||||||
<dt><a name="1"><b class="class">interface_caphandler.registry</b> <b class="method">pkg_register</b> <i class="arg">pkg</i> <i class="arg">capname</i> <i class="arg">capdict</i> <i class="arg">fullcapabilitylist</i></a></dt> |
|
||||||
<dd><p>handler may override and return 0 (indicating don't register)e.g if pkg capdict data wasn't valid |
|
||||||
overridden handler must be able to handle multiple calls for same pkg - but it may return 1 or 0 as it wishes.</p></dd> |
|
||||||
<dt><a name="2"><b class="class">interface_caphandler.registry</b> <b class="method">pkg_unregister</b> <i class="arg">pkg</i></a></dt> |
|
||||||
<dd></dd> |
|
||||||
<dt><a name="3"><b class="class">interface_capprovider.registration</b> <b class="method">pkg_unregister</b> <i class="arg">pkg</i></a></dt> |
|
||||||
<dd></dd> |
|
||||||
<dt><a name="4"><b class="class">interface_capprovider.provider</b> <b class="method">register</b> <span class="opt">?capabilityname_glob?</span></a></dt> |
|
||||||
<dd></dd> |
|
||||||
<dt><a name="5"><b class="class">interface_capprovider.provider</b> <b class="method">capabilities</b></a></dt> |
|
||||||
<dd></dd> |
|
||||||
<dt><a name="6"><b class="function">exists</b> <i class="arg">capname</i></a></dt> |
|
||||||
<dd><p>Return a boolean indicating if the named capability exists (0|1)</p></dd> |
|
||||||
<dt><a name="7"><b class="function">has_handler</b> <i class="arg">capname</i></a></dt> |
|
||||||
<dd><p>Return a boolean indicating if the named capability has a handler package installed (0|1)</p></dd> |
|
||||||
</dl> |
|
||||||
</div> |
|
||||||
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> |
|
||||||
<p>Copyright © 2023 JMNoble - BSD licensed</p> |
|
||||||
</div> |
|
||||||
</div></body></html> |
|
@ -1,132 +0,0 @@ |
|||||||
<!DOCTYPE html><html><head> |
|
||||||
<title>%pkg% - -</title> |
|
||||||
<style type="text/css"><!-- |
|
||||||
HTML { |
|
||||||
background: #FFFFFF; |
|
||||||
color: black; |
|
||||||
} |
|
||||||
BODY { |
|
||||||
background: #FFFFFF; |
|
||||||
color: black; |
|
||||||
} |
|
||||||
DIV.doctools { |
|
||||||
margin-left: 10%; |
|
||||||
margin-right: 10%; |
|
||||||
} |
|
||||||
DIV.doctools H1,DIV.doctools H2 { |
|
||||||
margin-left: -5%; |
|
||||||
} |
|
||||||
H1, H2, H3, H4 { |
|
||||||
margin-top: 1em; |
|
||||||
font-family: sans-serif; |
|
||||||
font-size: large; |
|
||||||
color: #005A9C; |
|
||||||
background: transparent; |
|
||||||
text-align: left; |
|
||||||
} |
|
||||||
H1.doctools_title { |
|
||||||
text-align: center; |
|
||||||
} |
|
||||||
UL,OL { |
|
||||||
margin-right: 0em; |
|
||||||
margin-top: 3pt; |
|
||||||
margin-bottom: 3pt; |
|
||||||
} |
|
||||||
UL LI { |
|
||||||
list-style: disc; |
|
||||||
} |
|
||||||
OL LI { |
|
||||||
list-style: decimal; |
|
||||||
} |
|
||||||
DT { |
|
||||||
padding-top: 1ex; |
|
||||||
} |
|
||||||
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { |
|
||||||
font: normal 12pt/14pt sans-serif; |
|
||||||
list-style: none; |
|
||||||
} |
|
||||||
LI.doctools_section, LI.doctools_subsection { |
|
||||||
list-style: none; |
|
||||||
margin-left: 0em; |
|
||||||
text-indent: 0em; |
|
||||||
padding: 0em; |
|
||||||
} |
|
||||||
PRE { |
|
||||||
display: block; |
|
||||||
font-family: monospace; |
|
||||||
white-space: pre; |
|
||||||
margin: 0%; |
|
||||||
padding-top: 0.5ex; |
|
||||||
padding-bottom: 0.5ex; |
|
||||||
padding-left: 1ex; |
|
||||||
padding-right: 1ex; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
PRE.doctools_example { |
|
||||||
color: black; |
|
||||||
background: #f5dcb3; |
|
||||||
border: 1px solid black; |
|
||||||
} |
|
||||||
UL.doctools_requirements LI, UL.doctools_syntax LI { |
|
||||||
list-style: none; |
|
||||||
margin-left: 0em; |
|
||||||
text-indent: 0em; |
|
||||||
padding: 0em; |
|
||||||
} |
|
||||||
DIV.doctools_synopsis { |
|
||||||
color: black; |
|
||||||
background: #80ffff; |
|
||||||
border: 1px solid black; |
|
||||||
font-family: serif; |
|
||||||
margin-top: 1em; |
|
||||||
margin-bottom: 1em; |
|
||||||
} |
|
||||||
UL.doctools_syntax { |
|
||||||
margin-top: 1em; |
|
||||||
border-top: 1px solid black; |
|
||||||
} |
|
||||||
UL.doctools_requirements { |
|
||||||
margin-bottom: 1em; |
|
||||||
border-bottom: 1px solid black; |
|
||||||
} |
|
||||||
--></style> |
|
||||||
</head> |
|
||||||
<!-- Generated from file '_module_punk_mix_templates_modules_template_module-0.0.1.tm.man' by tcllib/doctools with format 'html' |
|
||||||
--> |
|
||||||
<!-- Copyright &copy; %year% |
|
||||||
--> |
|
||||||
<!-- %pkg%.0 |
|
||||||
--> |
|
||||||
<body><hr> [ |
|
||||||
<a href="../../toc.html">Main Table Of Contents</a> |
|
||||||
| <a href="../toc.html">Table Of Contents</a> |
|
||||||
| <a href="../../index.html">Keyword Index</a> |
|
||||||
] <hr> |
|
||||||
<div class="doctools"> |
|
||||||
<h1 class="doctools_title">%pkg%(0) 999999.0a1.0 doc "-"</h1> |
|
||||||
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> |
|
||||||
<p>%pkg% - Module API</p> |
|
||||||
</div> |
|
||||||
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> |
|
||||||
<ul class="doctools_toc"> |
|
||||||
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li> |
|
||||||
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li> |
|
||||||
<li class="doctools_section"><a href="#section1">Description</a></li> |
|
||||||
<li class="doctools_section"><a href="#copyright">Copyright</a></li> |
|
||||||
</ul> |
|
||||||
</div> |
|
||||||
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> |
|
||||||
<div class="doctools_synopsis"> |
|
||||||
<ul class="doctools_requirements"> |
|
||||||
<li>package require <b class="pkgname">%pkg%</b></li> |
|
||||||
</ul> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> |
|
||||||
<dl class="doctools_definitions"> |
|
||||||
</dl> |
|
||||||
</div> |
|
||||||
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> |
|
||||||
<p>Copyright © %year%</p> |
|
||||||
</div> |
|
||||||
</div></body></html> |
|
@ -0,0 +1,237 @@ |
|||||||
|
<!DOCTYPE html><html><head> |
||||||
|
<title>punk::path - punk path filesystem utils</title> |
||||||
|
<style type="text/css"><!-- |
||||||
|
HTML { |
||||||
|
background: #FFFFFF; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
BODY { |
||||||
|
background: #FFFFFF; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
DIV.doctools { |
||||||
|
margin-left: 10%; |
||||||
|
margin-right: 10%; |
||||||
|
} |
||||||
|
DIV.doctools H1,DIV.doctools H2 { |
||||||
|
margin-left: -5%; |
||||||
|
} |
||||||
|
H1, H2, H3, H4 { |
||||||
|
margin-top: 1em; |
||||||
|
font-family: sans-serif; |
||||||
|
font-size: large; |
||||||
|
color: #005A9C; |
||||||
|
background: transparent; |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
H1.doctools_title { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
UL,OL { |
||||||
|
margin-right: 0em; |
||||||
|
margin-top: 3pt; |
||||||
|
margin-bottom: 3pt; |
||||||
|
} |
||||||
|
UL LI { |
||||||
|
list-style: disc; |
||||||
|
} |
||||||
|
OL LI { |
||||||
|
list-style: decimal; |
||||||
|
} |
||||||
|
DT { |
||||||
|
padding-top: 1ex; |
||||||
|
} |
||||||
|
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { |
||||||
|
font: normal 12pt/14pt sans-serif; |
||||||
|
list-style: none; |
||||||
|
} |
||||||
|
LI.doctools_section, LI.doctools_subsection { |
||||||
|
list-style: none; |
||||||
|
margin-left: 0em; |
||||||
|
text-indent: 0em; |
||||||
|
padding: 0em; |
||||||
|
} |
||||||
|
PRE { |
||||||
|
display: block; |
||||||
|
font-family: monospace; |
||||||
|
white-space: pre; |
||||||
|
margin: 0%; |
||||||
|
padding-top: 0.5ex; |
||||||
|
padding-bottom: 0.5ex; |
||||||
|
padding-left: 1ex; |
||||||
|
padding-right: 1ex; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
PRE.doctools_example { |
||||||
|
color: black; |
||||||
|
background: #f5dcb3; |
||||||
|
border: 1px solid black; |
||||||
|
} |
||||||
|
UL.doctools_requirements LI, UL.doctools_syntax LI { |
||||||
|
list-style: none; |
||||||
|
margin-left: 0em; |
||||||
|
text-indent: 0em; |
||||||
|
padding: 0em; |
||||||
|
} |
||||||
|
DIV.doctools_synopsis { |
||||||
|
color: black; |
||||||
|
background: #80ffff; |
||||||
|
border: 1px solid black; |
||||||
|
font-family: serif; |
||||||
|
margin-top: 1em; |
||||||
|
margin-bottom: 1em; |
||||||
|
} |
||||||
|
UL.doctools_syntax { |
||||||
|
margin-top: 1em; |
||||||
|
border-top: 1px solid black; |
||||||
|
} |
||||||
|
UL.doctools_requirements { |
||||||
|
margin-bottom: 1em; |
||||||
|
border-bottom: 1px solid black; |
||||||
|
} |
||||||
|
--></style> |
||||||
|
</head> |
||||||
|
<!-- Generated from file '_module_path-0.1.0.tm.man' by tcllib/doctools with format 'html' |
||||||
|
--> |
||||||
|
<!-- Copyright &copy; 2023 |
||||||
|
--> |
||||||
|
<!-- punk::path.0 |
||||||
|
--> |
||||||
|
<body><hr> [ |
||||||
|
<a href="../../../toc.html">Main Table Of Contents</a> |
||||||
|
| <a href="../../toc.html">Table Of Contents</a> |
||||||
|
| <a href="../../../index.html">Keyword Index</a> |
||||||
|
] <hr> |
||||||
|
<div class="doctools"> |
||||||
|
<h1 class="doctools_title">punk::path(0) 0.1.0 doc "punk path filesystem utils"</h1> |
||||||
|
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> |
||||||
|
<p>punk::path - Filesystem path utilities</p> |
||||||
|
</div> |
||||||
|
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> |
||||||
|
<ul class="doctools_toc"> |
||||||
|
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li> |
||||||
|
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li> |
||||||
|
<li class="doctools_section"><a href="#section1">Description</a></li> |
||||||
|
<li class="doctools_section"><a href="#section2">Overview</a> |
||||||
|
<ul> |
||||||
|
<li class="doctools_subsection"><a href="#subsection1">Concepts</a></li> |
||||||
|
<li class="doctools_subsection"><a href="#subsection2">dependencies</a></li> |
||||||
|
</ul> |
||||||
|
</li> |
||||||
|
<li class="doctools_section"><a href="#section3">API</a> |
||||||
|
<ul> |
||||||
|
<li class="doctools_subsection"><a href="#subsection3">Namespace punk::path::class</a></li> |
||||||
|
<li class="doctools_subsection"><a href="#subsection4">Namespace punk::path</a></li> |
||||||
|
<li class="doctools_subsection"><a href="#subsection5">Namespace punk::path::lib</a></li> |
||||||
|
</ul> |
||||||
|
</li> |
||||||
|
<li class="doctools_section"><a href="#section4">Internal</a> |
||||||
|
<ul> |
||||||
|
<li class="doctools_subsection"><a href="#subsection6">Namespace punk::path::system</a></li> |
||||||
|
</ul> |
||||||
|
</li> |
||||||
|
<li class="doctools_section"><a href="#copyright">Copyright</a></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> |
||||||
|
<div class="doctools_synopsis"> |
||||||
|
<ul class="doctools_requirements"> |
||||||
|
<li>package require <b class="pkgname">punk::path</b></li> |
||||||
|
</ul> |
||||||
|
<ul class="doctools_syntax"> |
||||||
|
<li><a href="#1"><b class="function">pathglob_as_re</b> <i class="arg">pathglob</i></a></li> |
||||||
|
<li><a href="#2"><b class="function">globmatchpath</b> <i class="arg">pathglob</i> <i class="arg">path</i> <span class="opt">?option value...?</span></a></li> |
||||||
|
<li><a href="#3"><b class="function">treefilenames</b> <i class="arg">basepath</i> <i class="arg">tailglob</i> <span class="opt">?option value...?</span></a></li> |
||||||
|
<li><a href="#4"><b class="function">relative</b> <i class="arg">reference</i> <i class="arg">location</i></a></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> |
||||||
|
</div> |
||||||
|
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2> |
||||||
|
<p>overview of punk::path</p> |
||||||
|
<p>Filesystem path utility functions</p> |
||||||
|
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3> |
||||||
|
<p>-</p> |
||||||
|
</div> |
||||||
|
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">dependencies</a></h3> |
||||||
|
<p>packages used by punk::path</p> |
||||||
|
<ul class="doctools_itemized"> |
||||||
|
<li><p><b class="package">Tcl 8.6</b></p></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div id="section3" class="doctools_section"><h2><a name="section3">API</a></h2> |
||||||
|
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Namespace punk::path::class</a></h3> |
||||||
|
<p>class definitions</p> |
||||||
|
<ol class="doctools_enumerated"> |
||||||
|
</ol> |
||||||
|
</div> |
||||||
|
<div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Namespace punk::path</a></h3> |
||||||
|
<p>Core API functions for punk::path</p> |
||||||
|
<dl class="doctools_definitions"> |
||||||
|
<dt><a name="1"><b class="function">pathglob_as_re</b> <i class="arg">pathglob</i></a></dt> |
||||||
|
<dd><p>Returns a regular expression for matching a path to a glob pattern which can contain glob chars *|? in any segment of the path structure</p> |
||||||
|
<p>** matches any number of subdirectories.</p> |
||||||
|
<p>e.g /etc/**/*.txt will match any .txt files at any depth below /etc (except directly within /etc itself)</p> |
||||||
|
<p>e.g /etc/**.txt will match any .txt files at any depth below /etc</p> |
||||||
|
<p>any segment that does not contain ** must match exactly one segment in the path</p> |
||||||
|
<p>e.g the glob /etc/*/*.doc - will match any .doc files that are exactly one tree level below /etc</p> |
||||||
|
<p>The pathglob doesn't have to contain glob characters, in which case the returned regex will match the pathglob exactly as specified.</p> |
||||||
|
<p>Regular expression syntax is deliberateley not supported within the pathglob string so that supplied regex characters will be treated as literals</p></dd> |
||||||
|
<dt><a name="2"><b class="function">globmatchpath</b> <i class="arg">pathglob</i> <i class="arg">path</i> <span class="opt">?option value...?</span></a></dt> |
||||||
|
<dd><p>Return true if the pathglob matches the path</p> |
||||||
|
<p>see <b class="function">pathglob_as_re</b> for pathglob description</p> |
||||||
|
<p>Caller must ensure that file separator is forward slash. (e.g use file normalize on windows)</p> |
||||||
|
<p>Known options:</p> |
||||||
|
<p>-nocase 0|1 (default 0 - case sensitive)</p> |
||||||
|
<p>If -nocase is not supplied - default to case sensitive *except for driveletter*</p> |
||||||
|
<p>ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah)</p> |
||||||
|
<p>Explicitly specifying -nocase 0 will require the entire case to match including the driveletter.</p></dd> |
||||||
|
<dt><a name="3"><b class="function">treefilenames</b> <i class="arg">basepath</i> <i class="arg">tailglob</i> <span class="opt">?option value...?</span></a></dt> |
||||||
|
<dd><p>basic (glob based) list of filenames matching tailglob - recursive |
||||||
|
no natsorting - so order is dependent on filesystem</p></dd> |
||||||
|
<dt><a name="4"><b class="function">relative</b> <i class="arg">reference</i> <i class="arg">location</i></a></dt> |
||||||
|
<dd><p>Taking two directory paths, a reference and a location, computes the path |
||||||
|
of the location relative to the reference.</p> |
||||||
|
<ul class="doctools_itemized"> |
||||||
|
<li><p>Arguments:</p> |
||||||
|
<dl class="doctools_arguments"> |
||||||
|
|
||||||
|
<dt>string <i class="arg">reference</i></dt> |
||||||
|
<dd><p>The path from which the relative path to location is determined.</p></dd> |
||||||
|
<dt>string <i class="arg">location</i></dt> |
||||||
|
<dd><p>The location path which may be above or below the reference path</p></dd> |
||||||
|
</dl> |
||||||
|
</li> |
||||||
|
<li><p>Results:</p> |
||||||
|
<p>The relative path of the location to the reference path.</p> |
||||||
|
<p>Will return a single dot "." if the paths are the same</p></li> |
||||||
|
<li><p>Notes:</p> |
||||||
|
<p>Both paths must be the same type - ie both absolute or both relative</p> |
||||||
|
<p>Case sensitive. ie relative /etc /etC |
||||||
|
will return ../etC</p> |
||||||
|
<p>On windows, the drive-letter component (only) is not case sensitive</p> |
||||||
|
<p>ie relative c:/etc C:/etc returns .</p> |
||||||
|
<p>but relative c:/etc C:/Etc returns ../Etc</p> |
||||||
|
<p>On windows, if the paths are absolute and specifiy different volumes, only the location will be returned. |
||||||
|
ie relative c:/etc d:/etc/blah |
||||||
|
returns d:/etc/blah</p></li> |
||||||
|
</ul></dd> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
<div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::path::lib</a></h3> |
||||||
|
<p>Secondary functions that are part of the API</p> |
||||||
|
<dl class="doctools_definitions"> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div id="section4" class="doctools_section"><h2><a name="section4">Internal</a></h2> |
||||||
|
<div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Namespace punk::path::system</a></h3> |
||||||
|
<p>Internal functions that are not part of the API</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> |
||||||
|
<p>Copyright © 2023</p> |
||||||
|
</div> |
||||||
|
</div></body></html> |
@ -0,0 +1,186 @@ |
|||||||
|
<!DOCTYPE html><html><head> |
||||||
|
<title>punk::mix::commandset::project - pmix CLI commandset - project</title> |
||||||
|
<style type="text/css"><!-- |
||||||
|
HTML { |
||||||
|
background: #FFFFFF; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
BODY { |
||||||
|
background: #FFFFFF; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
DIV.doctools { |
||||||
|
margin-left: 10%; |
||||||
|
margin-right: 10%; |
||||||
|
} |
||||||
|
DIV.doctools H1,DIV.doctools H2 { |
||||||
|
margin-left: -5%; |
||||||
|
} |
||||||
|
H1, H2, H3, H4 { |
||||||
|
margin-top: 1em; |
||||||
|
font-family: sans-serif; |
||||||
|
font-size: large; |
||||||
|
color: #005A9C; |
||||||
|
background: transparent; |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
H1.doctools_title { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
UL,OL { |
||||||
|
margin-right: 0em; |
||||||
|
margin-top: 3pt; |
||||||
|
margin-bottom: 3pt; |
||||||
|
} |
||||||
|
UL LI { |
||||||
|
list-style: disc; |
||||||
|
} |
||||||
|
OL LI { |
||||||
|
list-style: decimal; |
||||||
|
} |
||||||
|
DT { |
||||||
|
padding-top: 1ex; |
||||||
|
} |
||||||
|
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { |
||||||
|
font: normal 12pt/14pt sans-serif; |
||||||
|
list-style: none; |
||||||
|
} |
||||||
|
LI.doctools_section, LI.doctools_subsection { |
||||||
|
list-style: none; |
||||||
|
margin-left: 0em; |
||||||
|
text-indent: 0em; |
||||||
|
padding: 0em; |
||||||
|
} |
||||||
|
PRE { |
||||||
|
display: block; |
||||||
|
font-family: monospace; |
||||||
|
white-space: pre; |
||||||
|
margin: 0%; |
||||||
|
padding-top: 0.5ex; |
||||||
|
padding-bottom: 0.5ex; |
||||||
|
padding-left: 1ex; |
||||||
|
padding-right: 1ex; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
PRE.doctools_example { |
||||||
|
color: black; |
||||||
|
background: #f5dcb3; |
||||||
|
border: 1px solid black; |
||||||
|
} |
||||||
|
UL.doctools_requirements LI, UL.doctools_syntax LI { |
||||||
|
list-style: none; |
||||||
|
margin-left: 0em; |
||||||
|
text-indent: 0em; |
||||||
|
padding: 0em; |
||||||
|
} |
||||||
|
DIV.doctools_synopsis { |
||||||
|
color: black; |
||||||
|
background: #80ffff; |
||||||
|
border: 1px solid black; |
||||||
|
font-family: serif; |
||||||
|
margin-top: 1em; |
||||||
|
margin-bottom: 1em; |
||||||
|
} |
||||||
|
UL.doctools_syntax { |
||||||
|
margin-top: 1em; |
||||||
|
border-top: 1px solid black; |
||||||
|
} |
||||||
|
UL.doctools_requirements { |
||||||
|
margin-bottom: 1em; |
||||||
|
border-bottom: 1px solid black; |
||||||
|
} |
||||||
|
--></style> |
||||||
|
</head> |
||||||
|
<!-- Generated from file '_module_project-0.1.0.tm.man' by tcllib/doctools with format 'html' |
||||||
|
--> |
||||||
|
<!-- Copyright &copy; 2023 |
||||||
|
--> |
||||||
|
<!-- punk::mix::commandset::project.0 |
||||||
|
--> |
||||||
|
<body><hr> [ |
||||||
|
<a href="../../../../../toc.html">Main Table Of Contents</a> |
||||||
|
| <a href="../../../../toc.html">Table Of Contents</a> |
||||||
|
| <a href="../../../../../index.html">Keyword Index</a> |
||||||
|
] <hr> |
||||||
|
<div class="doctools"> |
||||||
|
<h1 class="doctools_title">punk::mix::commandset::project(0) 0.1.0 doc "pmix CLI commandset - project"</h1> |
||||||
|
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> |
||||||
|
<p>punk::mix::commandset::project - pmix commandset - project</p> |
||||||
|
</div> |
||||||
|
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> |
||||||
|
<ul class="doctools_toc"> |
||||||
|
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li> |
||||||
|
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li> |
||||||
|
<li class="doctools_section"><a href="#section1">Description</a></li> |
||||||
|
<li class="doctools_section"><a href="#section2">Overview</a> |
||||||
|
<ul> |
||||||
|
<li class="doctools_subsection"><a href="#subsection1">Concepts</a></li> |
||||||
|
<li class="doctools_subsection"><a href="#subsection2">dependencies</a></li> |
||||||
|
</ul> |
||||||
|
</li> |
||||||
|
<li class="doctools_section"><a href="#section3">API</a> |
||||||
|
<ul> |
||||||
|
<li class="doctools_subsection"><a href="#subsection3">Namespace punk::mix::commandset::project</a></li> |
||||||
|
</ul> |
||||||
|
</li> |
||||||
|
<li class="doctools_section"><a href="#copyright">Copyright</a></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> |
||||||
|
<div class="doctools_synopsis"> |
||||||
|
<ul class="doctools_requirements"> |
||||||
|
<li>package require <b class="pkgname">punk::mix::commandset::project</b></li> |
||||||
|
</ul> |
||||||
|
<ul class="doctools_syntax"> |
||||||
|
<li><a href="#1"><b class="function">new</b> <i class="arg">newprojectpath_or_name</i> <span class="opt">?args?</span></a></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> |
||||||
|
</div> |
||||||
|
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2> |
||||||
|
<p>overview of punk::mix::commandset::project</p> |
||||||
|
<p>Import into an ensemble namespace similarly to the way it is done with punk::mix::cli e.g</p> |
||||||
|
<pre class="doctools_example"> |
||||||
|
namespace eval myproject::cli { |
||||||
|
namespace export * |
||||||
|
namespace ensemble create |
||||||
|
package require punk::overlay |
||||||
|
package require punk::mix::commandset::project |
||||||
|
punk::overlay::import_commandset project . ::punk::mix::commandset::project |
||||||
|
punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection |
||||||
|
} |
||||||
|
</pre> |
||||||
|
<p>Where the . in the above example is the prefix/command separator</p> |
||||||
|
<p>The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets.</p> |
||||||
|
<p>The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new</p> |
||||||
|
<p>Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.<procname></p> |
||||||
|
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3> |
||||||
|
<p>see punk::overlay</p> |
||||||
|
</div> |
||||||
|
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">dependencies</a></h3> |
||||||
|
<p>packages used by punk::mix::commandset::project</p> |
||||||
|
<ul class="doctools_itemized"> |
||||||
|
<li><p><b class="package">Tcl 8.6</b></p></li> |
||||||
|
<li><p><b class="package">punk::ns</b></p></li> |
||||||
|
<li><p><b class="package">sqlite3</b> (binary)</p></li> |
||||||
|
<li><p><b class="package">overtype</b></p></li> |
||||||
|
<li><p><b class="package">textutil</b> (tcllib)</p></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div id="section3" class="doctools_section"><h2><a name="section3">API</a></h2> |
||||||
|
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Namespace punk::mix::commandset::project</a></h3> |
||||||
|
<p>core commandset functions for punk::mix::commandset::project</p> |
||||||
|
<dl class="doctools_definitions"> |
||||||
|
|
||||||
|
<dt><a name="1"><b class="function">new</b> <i class="arg">newprojectpath_or_name</i> <span class="opt">?args?</span></a></dt> |
||||||
|
<dd><p>new project structure - may be dedicated to one module, or contain many. |
||||||
|
create minimal folder structure only by specifying in args: -modules {}</p></dd> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> |
||||||
|
<p>Copyright © 2023</p> |
||||||
|
</div> |
||||||
|
</div></body></html> |
@ -0,0 +1,396 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt |
||||||
|
# |
||||||
|
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. |
||||||
|
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository. |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
# (C) 2023 |
||||||
|
# |
||||||
|
# @@ Meta Begin |
||||||
|
# Application punk::path 999999.0a1.0 |
||||||
|
# Meta platform tcl |
||||||
|
# Meta license <unspecified> |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
# doctools header |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
#*** !doctools |
||||||
|
#[manpage_begin punk::path 0 999999.0a1.0] |
||||||
|
#[copyright "2023"] |
||||||
|
#[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}] |
||||||
|
#[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}] |
||||||
|
#[require punk::path] |
||||||
|
#[description] |
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[section Overview] |
||||||
|
#[para] overview of punk::path |
||||||
|
#[para] Filesystem path utility functions |
||||||
|
#[subsection Concepts] |
||||||
|
#[para] - |
||||||
|
|
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
## Requirements |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[subsection dependencies] |
||||||
|
#[para] packages used by punk::path |
||||||
|
#[list_begin itemized] |
||||||
|
|
||||||
|
package require Tcl 8.6 |
||||||
|
#*** !doctools |
||||||
|
#[item] [package {Tcl 8.6}] |
||||||
|
|
||||||
|
# #package require frobz |
||||||
|
# #*** !doctools |
||||||
|
# #[item] [package {frobz}] |
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[list_end] |
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[section API] |
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
# oo::class namespace |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
namespace eval punk::path::class { |
||||||
|
#*** !doctools |
||||||
|
#[subsection {Namespace punk::path::class}] |
||||||
|
#[para] class definitions |
||||||
|
if {[info commands [namespace current]::interface_sample1] eq ""} { |
||||||
|
#*** !doctools |
||||||
|
#[list_begin enumerated] |
||||||
|
|
||||||
|
# oo::class create interface_sample1 { |
||||||
|
# #*** !doctools |
||||||
|
# #[enum] CLASS [class interface_sample1] |
||||||
|
# #[list_begin definitions] |
||||||
|
|
||||||
|
# method test {arg1} { |
||||||
|
# #*** !doctools |
||||||
|
# #[call class::interface_sample1 [method test] [arg arg1]] |
||||||
|
# #[para] test method |
||||||
|
# puts "test: $arg1" |
||||||
|
# } |
||||||
|
|
||||||
|
# #*** !doctools |
||||||
|
# #[list_end] [comment {-- end definitions interface_sample1}] |
||||||
|
# } |
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[list_end] [comment {--- end class enumeration ---}] |
||||||
|
} |
||||||
|
} |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
# Base namespace |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
namespace eval punk::path { |
||||||
|
namespace export * |
||||||
|
#variable xyz |
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[subsection {Namespace punk::path}] |
||||||
|
#[para] Core API functions for punk::path |
||||||
|
#[list_begin definitions] |
||||||
|
|
||||||
|
|
||||||
|
proc pathglob_as_re {pathglob} { |
||||||
|
#*** !doctools |
||||||
|
#[call [fun pathglob_as_re] [arg pathglob]] |
||||||
|
#[para] Returns a regular expression for matching a path to a glob pattern which can contain glob chars *|? in any segment of the path structure |
||||||
|
#[para] ** matches any number of subdirectories. |
||||||
|
#[para] e.g /etc/**/*.txt will match any .txt files at any depth below /etc (except directly within /etc itself) |
||||||
|
#[para] e.g /etc/**.txt will match any .txt files at any depth below /etc |
||||||
|
#[para] any segment that does not contain ** must match exactly one segment in the path |
||||||
|
#[para] e.g the glob /etc/*/*.doc - will match any .doc files that are exactly one tree level below /etc |
||||||
|
#[para] The pathglob doesn't have to contain glob characters, in which case the returned regex will match the pathglob exactly as specified. |
||||||
|
#[para] Regular expression syntax is deliberateley not supported within the pathglob string so that supplied regex characters will be treated as literals |
||||||
|
|
||||||
|
|
||||||
|
#todo - consider whether a way to escape the glob chars ? * is practical - to allow literals ? * |
||||||
|
# - would require counting immediately-preceding backslashes |
||||||
|
set pats [list] |
||||||
|
foreach seg [file split $pathglob] { |
||||||
|
if {[string range $seg end end] eq "/"} { |
||||||
|
set seg [string range $seg 0 end-1] ;# e.g c:/ -> c: / -> "" so that join at end doesn't double up |
||||||
|
} |
||||||
|
if {$seg eq "*"} { |
||||||
|
lappend pats {[^/]*} |
||||||
|
} elseif {$seg eq "**"} { |
||||||
|
lappend pats {.*} |
||||||
|
} else { |
||||||
|
set seg [string map [list {^ {\^} $ {\$} [} {\[} ( {\(} \{ \\\{ \\ {\\}] $seg] ;#treat regex characters in the input as literals |
||||||
|
set seg [string map [list . {[.]}] $seg] |
||||||
|
if {[regexp {[*?]} $seg]} { |
||||||
|
set pat [string map [list ** {.*} * {[^/]*} ? {[^/]}] $seg] |
||||||
|
lappend pats "$pat" |
||||||
|
} else { |
||||||
|
lappend pats "$seg" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return "^[join $pats /]\$" |
||||||
|
} |
||||||
|
proc globmatchpath {pathglob path args} { |
||||||
|
#*** !doctools |
||||||
|
#[call [fun globmatchpath] [arg pathglob] [arg path] [opt {option value...}]] |
||||||
|
#[para] Return true if the pathglob matches the path |
||||||
|
#[para] see [fun pathglob_as_re] for pathglob description |
||||||
|
#[para] Caller must ensure that file separator is forward slash. (e.g use file normalize on windows) |
||||||
|
#[para] |
||||||
|
#[para] Known options: |
||||||
|
#[para] -nocase 0|1 (default 0 - case sensitive) |
||||||
|
#[para] If -nocase is not supplied - default to case sensitive *except for driveletter* |
||||||
|
#[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah) |
||||||
|
#[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter. |
||||||
|
|
||||||
|
set defaults [dict create\ |
||||||
|
-nocase \uFFFF\ |
||||||
|
] |
||||||
|
set known_opts [dict keys $defaults] |
||||||
|
set opts [dict merge $defaults $args] |
||||||
|
dict for {k v} $args { |
||||||
|
if {$k ni $known_opts} { |
||||||
|
error "Unrecognised options $k - known options: $known_opts" |
||||||
|
} |
||||||
|
} |
||||||
|
# -- --- --- --- --- --- |
||||||
|
set opt_nocase [dict get $opts -nocase] |
||||||
|
set explicit_nocase 1 ;#default to disprove |
||||||
|
if {$opt_nocase eq "\uFFFF"} { |
||||||
|
set opt_nocase 0 |
||||||
|
set explicit_nocase 0 |
||||||
|
} |
||||||
|
# -- --- --- --- --- --- |
||||||
|
if {$opt_nocase} { |
||||||
|
return [regexp -nocase [pathglob_as_re $pathglob] $path] |
||||||
|
} else { |
||||||
|
set re [pathglob_as_re $pathglob] |
||||||
|
if {$explicit_nocase} { |
||||||
|
set ismatch [regexp $re $path] ;#explicit -nocase 0 - require exact match of path literals including driveletter |
||||||
|
} else { |
||||||
|
#caller is using default for -nocase - which indicates case sensitivity - but we have an exception for the driveletter. |
||||||
|
set re_segments [file split $re] ;#Note that file split c:/etc gives {c:/ etc} but file split ^c:/etc gives {^c: etc} |
||||||
|
set first_seg [lindex $re_segments 0] |
||||||
|
if {[regexp {^\^(.{1}):$} $first_seg _match driveletter]} { |
||||||
|
#first part of re is like "^c:" i.e a drive letter |
||||||
|
set chars [string tolower $driveletter][string toupper $driveletter] |
||||||
|
set re [join [concat "^\[$chars\]:" [lrange $re_segments 1 end]] /] ;#rebuild re with case insensitive driveletter only - use join - not file join. file join will misinterpret leading re segment. |
||||||
|
} |
||||||
|
#puts stderr "-->re: $re" |
||||||
|
set ismatch [regexp $re $path] |
||||||
|
} |
||||||
|
} |
||||||
|
return $ismatch |
||||||
|
} |
||||||
|
|
||||||
|
#todo - implement treefiles which acts like dirfiles but allows path globbing in the same way as punk::ns::ns/ |
||||||
|
#then review if treefiles can replace dirfiles or if both should exist (dirfiles can have literal glob chars in path segments - but that is a rare usecase) |
||||||
|
proc treefilenames {basepath tailglob args} { |
||||||
|
#*** !doctools |
||||||
|
#[call [fun treefilenames] [arg basepath] [arg tailglob] [opt {option value...}]] |
||||||
|
#basic (glob based) list of filenames matching tailglob - recursive |
||||||
|
#no natsorting - so order is dependent on filesystem |
||||||
|
set defaults [dict create\ |
||||||
|
-call-depth-internal 0\ |
||||||
|
-antiglob_paths {}\ |
||||||
|
] |
||||||
|
set opts [dict merge $defaults $args] |
||||||
|
set opt_antiglob_paths [dict get $opts -antiglob_paths] |
||||||
|
set CALLDEPTH [dict get $opts -call-depth-internal] |
||||||
|
|
||||||
|
set files [list] |
||||||
|
if {$CALLDEPTH == 0} { |
||||||
|
if {![file isdirectory $basepath]} { |
||||||
|
return [list] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
set skip 0 |
||||||
|
foreach anti $opt_antiglob_paths { |
||||||
|
if {[globmatchpath $anti $basepath]} { |
||||||
|
set skip 1 |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
if {$skip} { |
||||||
|
return [list] |
||||||
|
} |
||||||
|
|
||||||
|
#todo - account for vfs where matched path could appear to be a directory but is mounted so could be a desired match? |
||||||
|
set dirfiles [glob -nocomplain -dir $basepath -type f $tailglob] |
||||||
|
lappend files {*}$dirfiles |
||||||
|
set dirdirs [glob -nocomplain -dir $basepath -type d *] |
||||||
|
foreach dir $dirdirs { |
||||||
|
set skip 0 |
||||||
|
foreach anti $opt_antiglob_paths { |
||||||
|
if {[globmatchpath $anti $dir]} { |
||||||
|
set skip 1 |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
if {$skip} { |
||||||
|
continue |
||||||
|
} |
||||||
|
set nextargs [dict merge $args [list -call-depth-internal [incr CALLDEPTH]]] |
||||||
|
lappend files {*}[treefilenames $dir $tailglob {*}$nextargs] |
||||||
|
} |
||||||
|
return $files |
||||||
|
} |
||||||
|
|
||||||
|
#maint warning - also in punkcheck |
||||||
|
proc relative {reference location} { |
||||||
|
#*** !doctools |
||||||
|
#[call [fun relative] [arg reference] [arg location]] |
||||||
|
#[para] Taking two directory paths, a reference and a location, computes the path |
||||||
|
# of the location relative to the reference. |
||||||
|
#[list_begin itemized] |
||||||
|
#[item] |
||||||
|
#[para] Arguments: |
||||||
|
# [list_begin arguments] |
||||||
|
# [arg_def string reference] The path from which the relative path to location is determined. |
||||||
|
# [arg_def string location] The location path which may be above or below the reference path |
||||||
|
# [list_end] |
||||||
|
#[item] |
||||||
|
#[para] Results: |
||||||
|
#[para] The relative path of the location to the reference path. |
||||||
|
#[para] Will return a single dot "." if the paths are the same |
||||||
|
#[item] |
||||||
|
#[para] Notes: |
||||||
|
#[para] Both paths must be the same type - ie both absolute or both relative |
||||||
|
#[para] Case sensitive. ie relative /etc /etC |
||||||
|
# will return ../etC |
||||||
|
#[para] On windows, the drive-letter component (only) is not case sensitive |
||||||
|
#[para] ie relative c:/etc C:/etc returns . |
||||||
|
#[para] but relative c:/etc C:/Etc returns ../Etc |
||||||
|
#[para] On windows, if the paths are absolute and specifiy different volumes, only the location will be returned. |
||||||
|
# ie relative c:/etc d:/etc/blah |
||||||
|
# returns d:/etc/blah |
||||||
|
#[list_end] |
||||||
|
|
||||||
|
#see also kettle |
||||||
|
# Modified copy of ::fileutil::relative (tcllib) |
||||||
|
# Adapted to 8.5 ({*}). |
||||||
|
|
||||||
|
#review - check volume info on windows.. UNC paths? |
||||||
|
if {[file pathtype $reference] ne [file pathtype $location]} { |
||||||
|
return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $reference] vs. [file pathtype $location], ($reference vs. $location)" |
||||||
|
} |
||||||
|
|
||||||
|
#avoid normalizing if possible (file normalize *very* expensive on windows) |
||||||
|
set do_normalize 0 |
||||||
|
if {[file pathtype $reference] eq "relative"} { |
||||||
|
#if reference is relative so is location |
||||||
|
if {[regexp {[.]{2}} [list $reference $location]]} { |
||||||
|
set do_normalize 1 |
||||||
|
} |
||||||
|
if {[regexp {[.]/} [list $reference $location]]} { |
||||||
|
set do_normalize 1 |
||||||
|
} |
||||||
|
} else { |
||||||
|
set do_normalize 1 |
||||||
|
} |
||||||
|
if {$do_normalize} { |
||||||
|
set reference [file normalize $reference] |
||||||
|
set location [file normalize $location] |
||||||
|
} |
||||||
|
|
||||||
|
set save $location |
||||||
|
set reference [file split $reference] |
||||||
|
set location [file split $location] |
||||||
|
|
||||||
|
while {[lindex $location 0] eq [lindex $reference 0]} { |
||||||
|
set location [lrange $location 1 end] |
||||||
|
set reference [lrange $reference 1 end] |
||||||
|
if {![llength $location]} {break} |
||||||
|
} |
||||||
|
|
||||||
|
set location_len [llength $location] |
||||||
|
set reference_len [llength $reference] |
||||||
|
|
||||||
|
if {($location_len == 0) && ($reference_len == 0)} { |
||||||
|
# Cases: |
||||||
|
# (a) reference == location |
||||||
|
|
||||||
|
set location . |
||||||
|
} else { |
||||||
|
# Cases: |
||||||
|
# (b) ref is: ref/sub = sub |
||||||
|
# loc is: ref = {} |
||||||
|
|
||||||
|
# (c) ref is: ref = {} |
||||||
|
# loc is: ref/sub = sub |
||||||
|
|
||||||
|
while {$reference_len > 0} { |
||||||
|
set location [linsert $location 0 ..] |
||||||
|
incr reference_len -1 |
||||||
|
} |
||||||
|
set location [file join {*}$location] |
||||||
|
} |
||||||
|
return $location |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[list_end] [comment {--- end definitions namespace punk::path ---}] |
||||||
|
} |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
|
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
# Secondary API namespace |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
namespace eval punk::path::lib { |
||||||
|
namespace export * |
||||||
|
namespace path [namespace parent] |
||||||
|
#*** !doctools |
||||||
|
#[subsection {Namespace punk::path::lib}] |
||||||
|
#[para] Secondary functions that are part of the API |
||||||
|
#[list_begin definitions] |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[list_end] [comment {--- end definitions namespace punk::path::lib ---}] |
||||||
|
} |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
#*** !doctools |
||||||
|
#[section Internal] |
||||||
|
namespace eval punk::path::system { |
||||||
|
#*** !doctools |
||||||
|
#[subsection {Namespace punk::path::system}] |
||||||
|
#[para] Internal functions that are not part of the API |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||||
|
## Ready |
||||||
|
package provide punk::path [namespace eval punk::path { |
||||||
|
variable pkg punk::path |
||||||
|
variable version |
||||||
|
set version 999999.0a1.0 |
||||||
|
}] |
||||||
|
return |
||||||
|
|
||||||
|
#*** !doctools |
||||||
|
#[manpage_end] |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
0.1.0 |
||||||
|
#First line must be a semantic version number |
||||||
|
#all other lines are ignored. |
@ -0,0 +1,186 @@ |
|||||||
|
2013-11-22 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.man: Reviewed the work on the pyk-tar branch. Brought |
||||||
|
* tar.tcl: new testsuite up to spec. Reviewed the skip fix, |
||||||
|
* tar.test: modified it to reinstate the skip limit per round |
||||||
|
* test-support.tcl: without getting the bug back. Bumped version |
||||||
|
to 0.9. Thanks to PoorYorick for the initial work on the bug, |
||||||
|
fix, and testsuite. This also fixes ticket [6b7aa0aecc]. |
||||||
|
|
||||||
|
2013-08-12 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.man (tar::untar, contents, stat, get): Extended the |
||||||
|
* tar.tcl: procedures to detect and properly handle @LongName |
||||||
|
* pkgIndex.tcl: header entries as generated by GNU tar. These |
||||||
|
entries contain the file name for the next header entry as file |
||||||
|
data, for files whose name is longer than the 100-char field of |
||||||
|
the regular header. Version bumped to 0.8. This is a new |
||||||
|
feature. |
||||||
|
|
||||||
|
2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.15 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2012-09-11 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.tcl (seekorskip): Fixed seekorskip which prevented its use |
||||||
|
* pkgIndex.tcl: from a non-seekable channel, like stdin. The issue |
||||||
|
was that the original attempt to seek before skipping not just |
||||||
|
failed, but apparently still moved the read pointer in some way |
||||||
|
which skipped over irreplacable input, breaking the next call of |
||||||
|
readHeader. Using [tell] to check seekability does not break in |
||||||
|
this manner. Bumped version to 0.7.1. |
||||||
|
|
||||||
|
2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.14 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.13 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2011-01-20 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.tcl: [Bug 3162548]: Applied patch by Alexandre Ferrieux, |
||||||
|
* tar.man: extending various tar commands to be able to use |
||||||
|
* pkgIndex.tcl: the -chan option, and channels instead of files. |
||||||
|
Version bumped to 0.7 |
||||||
|
|
||||||
|
2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.12 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2009-12-03 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.man: [Patch 2840147]. Applied. New options -prefix and |
||||||
|
* tar.tcl: -quick for tar::add. -prefix allows specifying a |
||||||
|
* tar.pcx: prefix for filenames in the archive, and -quick 1 |
||||||
|
* pkgIndex.tcl: changes back to the seek-from-end algorithm for |
||||||
|
finding the place where to add the new files. The new default |
||||||
|
scans from start (robust). Bumped version to 0.6. |
||||||
|
|
||||||
|
2009-05-12 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.tcl: add support for reading pre-posix archives. |
||||||
|
if a file isnt writable when extracting, try deleting |
||||||
|
before giving up. |
||||||
|
|
||||||
|
2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.11.1 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2008-11-26 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.man: add and clarify documentation |
||||||
|
|
||||||
|
2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.11 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2008-06-14 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.pcx: New file. Syntax definitions for the public commands of |
||||||
|
the tar package. |
||||||
|
|
||||||
|
2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.10 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2007-03-21 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.man: Fixed all warnings due to use of now deprecated |
||||||
|
commands. Added a section about how to give feedback. |
||||||
|
|
||||||
|
2007-02-08 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.tcl: bug fix in recursion algorithm that missed |
||||||
|
some files in deep subdirs. incremented version |
||||||
|
|
||||||
|
2007-01-08 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.tcl: Bumped version to 0.3, for the bugfix described |
||||||
|
* tar.man: by the last entry. |
||||||
|
* pkgIndex.tcl: |
||||||
|
|
||||||
|
2006-12-20 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.tcl: fix in parseOpts which affected -file and -glob |
||||||
|
arguments to tar::untar |
||||||
|
* tar.man: clarifications to add, create, and untar |
||||||
|
|
||||||
|
2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.9 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2006-29-06 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.tcl: fixed bug in parseOpts |
||||||
|
|
||||||
|
2005-11-08 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* pkgIndex.tcl: Corrected buggy commit, synchronized version |
||||||
|
* tar.man: numbers across all relevant files. |
||||||
|
|
||||||
|
2005-11-08 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.tcl: bumped version to 0.2 because of new feature |
||||||
|
* tar.man: tar::remove |
||||||
|
|
||||||
|
2005-11-07 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.man: Fixed error, incorrect placement of [call] markup |
||||||
|
outside of list. |
||||||
|
|
||||||
|
2005-11-04 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.man: added tar::remove command and documentation for it |
||||||
|
* tar.tcl: |
||||||
|
|
||||||
|
2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.8 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2005-09-30 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.tcl: qualified all [open] calls with :: to ensure usag of |
||||||
|
the builtin. Apparently mitigates conflict between this package |
||||||
|
and the vfs::tar module. |
||||||
|
|
||||||
|
2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.7 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2004-10-02 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.man: Added keywords and title/module description to the |
||||||
|
documentation. |
||||||
|
|
||||||
|
2004-09-10 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
|
||||||
|
* tar.tcl: Fixed typo bug in ::tar::add |
||||||
|
* tar.man: Added info for ::tar::stat |
||||||
|
|
||||||
|
2004-08-23 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* tar.man: Fixed problems in the documentation. |
||||||
|
|
@ -0,0 +1,5 @@ |
|||||||
|
if {![package vsatisfies [package provide Tcl] 8.5 9]} { |
||||||
|
# PRAGMA: returnok |
||||||
|
return |
||||||
|
} |
||||||
|
package ifneeded tar 0.12 [list source [file join $dir tar.tcl]] |
@ -0,0 +1,202 @@ |
|||||||
|
[comment {-*- mode: tcl ; fill-column: 80 -*- doctools manpage}] |
||||||
|
[vset PACKAGE_VERSION 0.12] |
||||||
|
[manpage_begin tar n [vset PACKAGE_VERSION]] |
||||||
|
[keywords archive] |
||||||
|
[keywords {tape archive}] |
||||||
|
[keywords tar] |
||||||
|
[moddesc {Tar file handling}] |
||||||
|
[titledesc {Tar file creation, extraction & manipulation}] |
||||||
|
[category {File formats}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require tar [opt [vset PACKAGE_VERSION]]] |
||||||
|
[description] |
||||||
|
|
||||||
|
[para] [strong Note]: Starting with version 0.8 the tar reader commands |
||||||
|
(contents, stats, get, untar) support the GNU LongName extension (header type |
||||||
|
'L') for large paths. |
||||||
|
|
||||||
|
[para] |
||||||
|
|
||||||
|
[section BEWARE] |
||||||
|
|
||||||
|
For all commands, when using [option -chan] ... |
||||||
|
|
||||||
|
[list_begin enumerated] |
||||||
|
|
||||||
|
[enum] It is assumed that the channel was opened for reading, and configured for |
||||||
|
binary input. |
||||||
|
|
||||||
|
[enum] It is assumed that the channel position is at the beginning of a legal |
||||||
|
tar file. |
||||||
|
|
||||||
|
[enum] The commands will [emph modify] the channel position as they perform their |
||||||
|
task. |
||||||
|
|
||||||
|
[enum] The commands will [emph not] close the channel. |
||||||
|
|
||||||
|
[enum] In other words, the commands leave the channel in a state very likely |
||||||
|
unsuitable for use by further [cmd tar] commands. Still doing so will |
||||||
|
very likely results in errors, bad data, etc. pp. |
||||||
|
|
||||||
|
[enum] It is the responsibility of the user to seek the channel back to a |
||||||
|
suitable position. |
||||||
|
|
||||||
|
[enum] When using a channel transformation which is not generally seekable, for |
||||||
|
example [cmd gunzip], then it is the responsibility of the user to (a) |
||||||
|
unstack the transformation before seeking the channel back to a suitable |
||||||
|
position, and (b) for restacking it after. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[section COMMANDS] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tar::contents] [arg tarball] [opt [option -chan]]] |
||||||
|
|
||||||
|
Returns a list of the files contained in [arg tarball]. The order is not sorted and depends on the order |
||||||
|
files were stored in the archive. |
||||||
|
[para] |
||||||
|
|
||||||
|
If the option [option -chan] is present [arg tarball] is interpreted as an open channel. |
||||||
|
It is assumed that the channel was opened for reading, and configured for binary input. |
||||||
|
The command will [emph not] close the channel. |
||||||
|
|
||||||
|
[call [cmd ::tar::stat] [arg tarball] [opt file] [opt [option -chan]]] |
||||||
|
|
||||||
|
Returns a nested dict containing information on the named [opt file] in [arg tarball], |
||||||
|
or all files if none is specified. The top level are pairs of filename and info. The info is a dict with the keys |
||||||
|
"[const mode] [const uid] [const gid] [const size] [const mtime] [const type] [const linkname] [const uname] [const gname] |
||||||
|
[const devmajor] [const devminor]" |
||||||
|
|
||||||
|
[example { |
||||||
|
% ::tar::stat tarball.tar |
||||||
|
foo.jpg {mode 0644 uid 1000 gid 0 size 7580 mtime 811903867 type file linkname {} uname user gname wheel devmajor 0 devminor 0} |
||||||
|
}] |
||||||
|
|
||||||
|
[para] |
||||||
|
If the option [option -chan] is present [arg tarball] is interpreted as an open channel. |
||||||
|
It is assumed that the channel was opened for reading, and configured for binary input. |
||||||
|
The command will [emph not] close the channel. |
||||||
|
|
||||||
|
[call [cmd ::tar::untar] [arg tarball] [arg args]] |
||||||
|
|
||||||
|
Extracts [arg tarball]. [arg -file] and [arg -glob] limit the extraction |
||||||
|
to files which exactly match or pattern match the given argument. No error is |
||||||
|
thrown if no files match. Returns a list of filenames extracted and the file |
||||||
|
size. The size will be null for non regular files. Leading path seperators are |
||||||
|
stripped so paths will always be relative. |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -dir dirName] |
||||||
|
Directory to extract to. Uses [cmd pwd] if none is specified |
||||||
|
[opt_def -file fileName] |
||||||
|
Only extract the file with this name. The name is matched against the complete path |
||||||
|
stored in the archive including directories. |
||||||
|
[opt_def -glob pattern] |
||||||
|
Only extract files patching this glob style pattern. The pattern is matched against the complete path |
||||||
|
stored in the archive. |
||||||
|
[opt_def -nooverwrite] |
||||||
|
Dont overwrite files that already exist |
||||||
|
[opt_def -nomtime] |
||||||
|
Leave the file modification time as the current time instead of setting it to the value in the archive. |
||||||
|
[opt_def -noperms] |
||||||
|
In Unix, leave the file permissions as the current umask instead of setting them to the values in the archive. |
||||||
|
|
||||||
|
[opt_def -chan] |
||||||
|
If this option is present [arg tarball] is interpreted as an open channel. |
||||||
|
It is assumed that the channel was opened for reading, and configured for binary input. |
||||||
|
The command will [emph not] close the channel. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
[para] |
||||||
|
|
||||||
|
[example { |
||||||
|
% foreach {file size} [::tar::untar tarball.tar -glob *.jpg] { |
||||||
|
puts "Extracted $file ($size bytes)" |
||||||
|
} |
||||||
|
}] |
||||||
|
|
||||||
|
[call [cmd ::tar::get] [arg tarball] [arg fileName] [opt [option -chan]]] |
||||||
|
|
||||||
|
Returns the contents of [arg fileName] from the [arg tarball]. |
||||||
|
|
||||||
|
[para][example { |
||||||
|
% set readme [::tar::get tarball.tar doc/README] { |
||||||
|
% puts $readme |
||||||
|
} |
||||||
|
}] |
||||||
|
|
||||||
|
[para] If the option [option -chan] is present [arg tarball] is |
||||||
|
interpreted as an open channel. It is assumed that the channel was |
||||||
|
opened for reading, and configured for binary input. The command will |
||||||
|
[emph not] close the channel. |
||||||
|
|
||||||
|
[para] An error is thrown when [arg fileName] is not found in the tar |
||||||
|
archive. |
||||||
|
|
||||||
|
[call [cmd ::tar::create] [arg tarball] [arg files] [arg args]] |
||||||
|
|
||||||
|
Creates a new tar file containing the [arg files]. [arg files] must be specified |
||||||
|
as a single argument which is a proper list of filenames. |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -dereference] |
||||||
|
Normally [cmd create] will store links as an actual link pointing at a file that may |
||||||
|
or may not exist in the archive. Specifying this option will cause the actual file point to |
||||||
|
by the link to be stored instead. |
||||||
|
|
||||||
|
[opt_def -chan] |
||||||
|
If this option is present [arg tarball] is interpreted as an open channel. |
||||||
|
It is assumed that the channel was opened for writing, and configured for binary output. |
||||||
|
The command will [emph not] close the channel. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
[para] |
||||||
|
|
||||||
|
[example { |
||||||
|
% ::tar::create new.tar [glob -nocomplain file*] |
||||||
|
% ::tar::contents new.tar |
||||||
|
file1 file2 file3 |
||||||
|
}] |
||||||
|
|
||||||
|
[call [cmd ::tar::add] [arg tarball] [arg files] [arg args]] |
||||||
|
|
||||||
|
Appends [arg files] to the end of the existing [arg tarball]. [arg files] must be specified |
||||||
|
as a single argument which is a proper list of filenames. |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -dereference] |
||||||
|
Normally [cmd add] will store links as an actual link pointing at a file that may |
||||||
|
or may not exist in the archive. Specifying this option will cause the actual file point to |
||||||
|
by the link to be stored instead. |
||||||
|
[opt_def -prefix string] |
||||||
|
Normally [cmd add] will store files under exactly the name specified as |
||||||
|
argument. Specifying a [opt -prefix] causes the [arg string] to be |
||||||
|
prepended to every name. |
||||||
|
[opt_def -quick] |
||||||
|
The only sure way to find the position in the [arg tarball] where new |
||||||
|
files can be added is to read it from start, but if [arg tarball] was |
||||||
|
written with a "blocksize" of 1 (as this package does) then one can |
||||||
|
alternatively find this position by seeking from the end. The |
||||||
|
[opt -quick] option tells [cmd add] to do the latter. |
||||||
|
[list_end] |
||||||
|
[para] |
||||||
|
|
||||||
|
[call [cmd ::tar::remove] [arg tarball] [arg files]] |
||||||
|
|
||||||
|
Removes [arg files] from the [arg tarball]. No error will result if the file does not exist in the |
||||||
|
tarball. Directory write permission and free disk space equivalent to at least the size of the tarball |
||||||
|
will be needed. |
||||||
|
|
||||||
|
[example { |
||||||
|
% ::tar::remove new.tar {file2 file3} |
||||||
|
% ::tar::contents new.tar |
||||||
|
file3 |
||||||
|
}] |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY tar] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,83 @@ |
|||||||
|
# -*- tcl -*- tar.pcx |
||||||
|
# Syntax of the commands provided by package tar. |
||||||
|
# |
||||||
|
# For use by TclDevKit's static syntax checker (v4.1+). |
||||||
|
# See http://www.activestate.com/solutions/tcl/ |
||||||
|
# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api |
||||||
|
# for the specification of the format of the code in this file. |
||||||
|
# |
||||||
|
|
||||||
|
package require pcx |
||||||
|
pcx::register tar |
||||||
|
pcx::tcldep 0.4 needs tcl 8.2 |
||||||
|
pcx::tcldep 0.5 needs tcl 8.2 |
||||||
|
pcx::tcldep 0.6 needs tcl 8.2 |
||||||
|
|
||||||
|
namespace eval ::tar {} |
||||||
|
|
||||||
|
#pcx::message FOO {... text ...} type |
||||||
|
#pcx::scan <VERSION> <NAME> <RULE> |
||||||
|
|
||||||
|
pcx::check 0.4 std ::tar::add \ |
||||||
|
{checkSimpleArgs 2 -1 { |
||||||
|
checkFileName |
||||||
|
{checkListValues 1 -1 checkFileName} |
||||||
|
{checkSwitches 1 { |
||||||
|
{-dereference checkBoolean} |
||||||
|
} {}} |
||||||
|
}} |
||||||
|
pcx::check 0.6 std ::tar::add \ |
||||||
|
{checkSimpleArgs 2 -1 { |
||||||
|
checkFileName |
||||||
|
{checkListValues 1 -1 checkFileName} |
||||||
|
{checkSwitches 1 { |
||||||
|
{-dereference checkBoolean} |
||||||
|
{-quick checkBoolean} |
||||||
|
{-prefix checkWord} |
||||||
|
} {}} |
||||||
|
}} |
||||||
|
pcx::check 0.4 std ::tar::contents \ |
||||||
|
{checkSimpleArgs 1 1 { |
||||||
|
checkFileName |
||||||
|
}} |
||||||
|
pcx::check 0.4 std ::tar::create \ |
||||||
|
{checkSimpleArgs 2 -1 { |
||||||
|
checkFileName |
||||||
|
{checkListValues 1 -1 checkFileName} |
||||||
|
{checkSwitches 1 { |
||||||
|
{-chan checkChannelID} |
||||||
|
{-dereference checkBoolean} |
||||||
|
} {}} |
||||||
|
}} |
||||||
|
pcx::check 0.4 std ::tar::get \ |
||||||
|
{checkSimpleArgs 2 2 { |
||||||
|
checkFileName |
||||||
|
checkFileName |
||||||
|
}} |
||||||
|
pcx::check 0.4 std ::tar::remove \ |
||||||
|
{checkSimpleArgs 2 2 { |
||||||
|
checkFileName |
||||||
|
{checkListValues 1 -1 checkFileName} |
||||||
|
}} |
||||||
|
pcx::check 0.4 std ::tar::stat \ |
||||||
|
{checkSimpleArgs 1 2 { |
||||||
|
checkFileName |
||||||
|
checkFileName |
||||||
|
}} |
||||||
|
pcx::check 0.4 std ::tar::untar \ |
||||||
|
{checkSimpleArgs 1 -1 { |
||||||
|
checkFileName |
||||||
|
{checkSwitches 1 { |
||||||
|
{-chan checkChannelID} |
||||||
|
{-dir checkFileName} |
||||||
|
{-file checkFileName} |
||||||
|
{-glob checkPattern} |
||||||
|
{-nomtime checkBoolean} |
||||||
|
{-nooverwrite checkBoolean} |
||||||
|
{-noperms checkBoolean} |
||||||
|
} {}} |
||||||
|
}} |
||||||
|
|
||||||
|
# Initialization via pcx::init. |
||||||
|
# Use a ::tar::init procedure for non-standard initialization. |
||||||
|
pcx::complete |
@ -0,0 +1,550 @@ |
|||||||
|
# tar.tcl -- |
||||||
|
# |
||||||
|
# Creating, extracting, and listing posix tar archives |
||||||
|
# |
||||||
|
# Copyright (c) 2004 Aaron Faupell <afaupell@users.sourceforge.net> |
||||||
|
# Copyright (c) 2013 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
# (GNU tar @LongLink support). |
||||||
|
# |
||||||
|
# See the file "license.terms" for information on usage and redistribution |
||||||
|
# of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
||||||
|
# |
||||||
|
# RCS: @(#) $Id: tar.tcl,v 1.17 2012/09/11 17:22:24 andreas_kupries Exp $ |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package provide tar 0.12 |
||||||
|
|
||||||
|
namespace eval ::tar {} |
||||||
|
|
||||||
|
proc ::tar::parseOpts {acc opts} { |
||||||
|
array set flags $acc |
||||||
|
foreach {x y} $acc {upvar $x $x} |
||||||
|
|
||||||
|
set len [llength $opts] |
||||||
|
set i 0 |
||||||
|
while {$i < $len} { |
||||||
|
set name [string trimleft [lindex $opts $i] -] |
||||||
|
if {![info exists flags($name)]} { |
||||||
|
return -errorcode {TAR INVALID OPTION} \ |
||||||
|
-code error "unknown option \"$name\"" |
||||||
|
} |
||||||
|
if {$flags($name) == 1} { |
||||||
|
set $name [lindex $opts [expr {$i + 1}]] |
||||||
|
incr i $flags($name) |
||||||
|
} elseif {$flags($name) > 1} { |
||||||
|
set $name [lrange $opts [expr {$i + 1}] [expr {$i + $flags($name)}]] |
||||||
|
incr i $flags($name) |
||||||
|
} else { |
||||||
|
set $name 1 |
||||||
|
} |
||||||
|
incr i |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::pad {size} { |
||||||
|
set pad [expr {512 - ($size % 512)}] |
||||||
|
if {$pad == 512} {return 0} |
||||||
|
return $pad |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::seekorskip {ch off wh} { |
||||||
|
if {[tell $ch] < 0} { |
||||||
|
if {$wh!="current"} { |
||||||
|
return -code error -errorcode [list TAR INVALID WHENCE $wh] \ |
||||||
|
"WHENCE=$wh not supported on non-seekable channel $ch" |
||||||
|
} |
||||||
|
skip $ch $off |
||||||
|
return |
||||||
|
} |
||||||
|
seek $ch $off $wh |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::skip {ch skipover} { |
||||||
|
while {$skipover > 0} { |
||||||
|
set requested $skipover |
||||||
|
|
||||||
|
# Limit individual skips to 64K, as a compromise between speed |
||||||
|
# of skipping (Number of read requests), and memory usage |
||||||
|
# (Note how skipped block is read into memory!). While the |
||||||
|
# read data is immediately discarded it still generates memory |
||||||
|
# allocation traffic, gets copied, etc. Trying to skip the |
||||||
|
# block in one go without the limit may cause us to run out of |
||||||
|
# (virtual) memory, or just induce swapping, for nothing. |
||||||
|
|
||||||
|
if {$requested > 65536} { |
||||||
|
set requested 65536 |
||||||
|
} |
||||||
|
|
||||||
|
set skipped [string length [read $ch $requested]] |
||||||
|
|
||||||
|
# Stop in short read into the end of the file. |
||||||
|
if {!$skipped && [eof $ch]} break |
||||||
|
|
||||||
|
# Keep track of how much is (not) skipped yet. |
||||||
|
incr skipover -$skipped |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::readHeader {data} { |
||||||
|
binary scan $data a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155 \ |
||||||
|
name mode uid gid size mtime cksum type \ |
||||||
|
linkname magic version uname gname devmajor devminor prefix |
||||||
|
|
||||||
|
foreach x {name type linkname} { |
||||||
|
set $x [string trim [set $x] "\x00"] |
||||||
|
} |
||||||
|
foreach x {uid gid size mtime cksum} { |
||||||
|
set $x [format %d 0[string trim [set $x] " \x00"]] |
||||||
|
} |
||||||
|
set mode [string trim $mode " \x00"] |
||||||
|
|
||||||
|
if {$magic == "ustar "} { |
||||||
|
# gnu tar |
||||||
|
# not fully supported |
||||||
|
foreach x {uname gname prefix} { |
||||||
|
set $x [string trim [set $x] "\x00"] |
||||||
|
} |
||||||
|
foreach x {devmajor devminor} { |
||||||
|
set $x [format %d 0[string trim [set $x] " \x00"]] |
||||||
|
} |
||||||
|
} elseif {$magic == "ustar\x00"} { |
||||||
|
# posix tar |
||||||
|
foreach x {uname gname prefix} { |
||||||
|
set $x [string trim [set $x] "\x00"] |
||||||
|
} |
||||||
|
foreach x {devmajor devminor} { |
||||||
|
set $x [format %d 0[string trim [set $x] " \x00"]] |
||||||
|
} |
||||||
|
} else { |
||||||
|
# old style tar |
||||||
|
foreach x {uname gname devmajor devminor prefix} { set $x {} } |
||||||
|
if {$type == ""} { |
||||||
|
if {[string match */ $name]} { |
||||||
|
set type 5 |
||||||
|
} else { |
||||||
|
set type 0 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return [list name $name mode $mode uid $uid gid $gid size $size mtime $mtime \ |
||||||
|
cksum $cksum type $type linkname $linkname magic $magic \ |
||||||
|
version $version uname $uname gname $gname devmajor $devmajor \ |
||||||
|
devminor $devminor prefix $prefix] |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::contents {file args} { |
||||||
|
set chan 0 |
||||||
|
parseOpts {chan 0} $args |
||||||
|
if {$chan} { |
||||||
|
set fh $file |
||||||
|
} else { |
||||||
|
set fh [::open $file] |
||||||
|
fconfigure $fh -encoding binary -translation lf -eofchar {} |
||||||
|
} |
||||||
|
set ret {} |
||||||
|
while {![eof $fh]} { |
||||||
|
array set header [readHeader [read $fh 512]] |
||||||
|
HandleLongLink $fh header |
||||||
|
if {$header(name) == ""} break |
||||||
|
if {$header(prefix) != ""} {append header(prefix) /} |
||||||
|
lappend ret $header(prefix)$header(name) |
||||||
|
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current |
||||||
|
} |
||||||
|
if {!$chan} { |
||||||
|
close $fh |
||||||
|
} |
||||||
|
return $ret |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::stat {tar {file {}} args} { |
||||||
|
set chan 0 |
||||||
|
parseOpts {chan 0} $args |
||||||
|
if {$chan} { |
||||||
|
set fh $tar |
||||||
|
} else { |
||||||
|
set fh [::open $tar] |
||||||
|
fconfigure $fh -encoding binary -translation lf -eofchar {} |
||||||
|
} |
||||||
|
set ret {} |
||||||
|
while {![eof $fh]} { |
||||||
|
array set header [readHeader [read $fh 512]] |
||||||
|
HandleLongLink $fh header |
||||||
|
if {$header(name) == ""} break |
||||||
|
if {$header(prefix) != ""} {append header(prefix) /} |
||||||
|
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current |
||||||
|
if {$file != "" && "$header(prefix)$header(name)" != $file} {continue} |
||||||
|
set header(type) [string map {0 file 5 directory 3 characterSpecial 4 blockSpecial 6 fifo 2 link} $header(type)] |
||||||
|
set header(mode) [string range $header(mode) 2 end] |
||||||
|
lappend ret $header(prefix)$header(name) [list mode $header(mode) uid $header(uid) gid $header(gid) \ |
||||||
|
size $header(size) mtime $header(mtime) type $header(type) linkname $header(linkname) \ |
||||||
|
uname $header(uname) gname $header(gname) devmajor $header(devmajor) devminor $header(devminor)] |
||||||
|
} |
||||||
|
if {!$chan} { |
||||||
|
close $fh |
||||||
|
} |
||||||
|
return $ret |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::get {tar file args} { |
||||||
|
set chan 0 |
||||||
|
parseOpts {chan 0} $args |
||||||
|
if {$chan} { |
||||||
|
set fh $tar |
||||||
|
} else { |
||||||
|
set fh [::open $tar] |
||||||
|
fconfigure $fh -encoding binary -translation lf -eofchar {} |
||||||
|
} |
||||||
|
while {![eof $fh]} { |
||||||
|
set data [read $fh 512] |
||||||
|
array set header [readHeader $data] |
||||||
|
HandleLongLink $fh header |
||||||
|
if {$header(name) eq ""} break |
||||||
|
if {$header(prefix) ne ""} {append header(prefix) /} |
||||||
|
set name [string trimleft $header(prefix)$header(name) /] |
||||||
|
if {$name eq $file} { |
||||||
|
set file [read $fh $header(size)] |
||||||
|
if {!$chan} { |
||||||
|
close $fh |
||||||
|
} |
||||||
|
return $file |
||||||
|
} |
||||||
|
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current |
||||||
|
} |
||||||
|
if {!$chan} { |
||||||
|
close $fh |
||||||
|
} |
||||||
|
return -code error -errorcode {TAR MISSING FILE} \ |
||||||
|
"Tar \"$tar\": File \"$file\" not found" |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::untar {tar args} { |
||||||
|
set nooverwrite 0 |
||||||
|
set data 0 |
||||||
|
set nomtime 0 |
||||||
|
set noperms 0 |
||||||
|
set chan 0 |
||||||
|
parseOpts {dir 1 file 1 glob 1 nooverwrite 0 nomtime 0 noperms 0 chan 0} $args |
||||||
|
if {![info exists dir]} {set dir [pwd]} |
||||||
|
set pattern * |
||||||
|
if {[info exists file]} { |
||||||
|
set pattern [string map {* \\* ? \\? \\ \\\\ \[ \\\[ \] \\\]} $file] |
||||||
|
} elseif {[info exists glob]} { |
||||||
|
set pattern $glob |
||||||
|
} |
||||||
|
|
||||||
|
set ret {} |
||||||
|
if {$chan} { |
||||||
|
set fh $tar |
||||||
|
} else { |
||||||
|
set fh [::open $tar] |
||||||
|
fconfigure $fh -encoding binary -translation lf -eofchar {} |
||||||
|
} |
||||||
|
while {![eof $fh]} { |
||||||
|
array set header [readHeader [read $fh 512]] |
||||||
|
HandleLongLink $fh header |
||||||
|
if {$header(name) == ""} break |
||||||
|
if {$header(prefix) != ""} {append header(prefix) /} |
||||||
|
set name [string trimleft $header(prefix)$header(name) /] |
||||||
|
if {![string match $pattern $name] || ($nooverwrite && [file exists $name])} { |
||||||
|
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
set name [file join $dir $name] |
||||||
|
if {![file isdirectory [file dirname $name]]} { |
||||||
|
file mkdir [file dirname $name] |
||||||
|
lappend ret [file dirname $name] {} |
||||||
|
} |
||||||
|
if {[string match {[0346]} $header(type)]} { |
||||||
|
if {[catch {::open $name w+} new]} { |
||||||
|
# sometimes if we dont have write permission we can still delete |
||||||
|
catch {file delete -force $name} |
||||||
|
set new [::open $name w+] |
||||||
|
} |
||||||
|
fconfigure $new -encoding binary -translation lf -eofchar {} |
||||||
|
fcopy $fh $new -size $header(size) |
||||||
|
close $new |
||||||
|
lappend ret $name $header(size) |
||||||
|
} elseif {$header(type) == 5} { |
||||||
|
file mkdir $name |
||||||
|
lappend ret $name {} |
||||||
|
} elseif {[string match {[12]} $header(type)] && $::tcl_platform(platform) == "unix"} { |
||||||
|
catch {file delete $name} |
||||||
|
if {![catch {file link [string map {1 -hard 2 -symbolic} $header(type)] $name $header(linkname)}]} { |
||||||
|
lappend ret $name {} |
||||||
|
} |
||||||
|
} |
||||||
|
seekorskip $fh [pad $header(size)] current |
||||||
|
if {![file exists $name]} continue |
||||||
|
|
||||||
|
if {$::tcl_platform(platform) == "unix"} { |
||||||
|
if {!$noperms} { |
||||||
|
catch {file attributes $name -permissions 0o[string range $header(mode) 2 end]} |
||||||
|
} |
||||||
|
catch {file attributes $name -owner $header(uid) -group $header(gid)} |
||||||
|
catch {file attributes $name -owner $header(uname) -group $header(gname)} |
||||||
|
} |
||||||
|
if {!$nomtime} { |
||||||
|
file mtime $name $header(mtime) |
||||||
|
} |
||||||
|
} |
||||||
|
if {!$chan} { |
||||||
|
close $fh |
||||||
|
} |
||||||
|
return $ret |
||||||
|
} |
||||||
|
|
||||||
|
## |
||||||
|
# ::tar::statFile |
||||||
|
# |
||||||
|
# Returns stat info about a filesystem object, in the form of an info |
||||||
|
# dictionary like that returned by ::tar::readHeader. |
||||||
|
# |
||||||
|
# The mode, uid, gid, mtime, and type entries are always present. |
||||||
|
# The size and linkname entries are present if relevant for this type |
||||||
|
# of object. The uname and gname entries are present if the OS supports |
||||||
|
# them. No devmajor or devminor entry is present. |
||||||
|
## |
||||||
|
|
||||||
|
proc ::tar::statFile {name followlinks} { |
||||||
|
if {$followlinks} { |
||||||
|
file stat $name stat |
||||||
|
} else { |
||||||
|
file lstat $name stat |
||||||
|
} |
||||||
|
|
||||||
|
set ret {} |
||||||
|
|
||||||
|
if {$::tcl_platform(platform) == "unix"} { |
||||||
|
# Tcl 9 returns the permission as 0o octal number. Since this |
||||||
|
# is written to the tar file and the file format expects "00" |
||||||
|
# we have to rewrite. |
||||||
|
lappend ret mode 1[string map {o 0} [file attributes $name -permissions]] |
||||||
|
lappend ret uname [file attributes $name -owner] |
||||||
|
lappend ret gname [file attributes $name -group] |
||||||
|
if {$stat(type) == "link"} { |
||||||
|
lappend ret linkname [file link $name] |
||||||
|
} |
||||||
|
} else { |
||||||
|
lappend ret mode [lindex {100644 100755} [expr {$stat(type) == "directory"}]] |
||||||
|
} |
||||||
|
|
||||||
|
lappend ret uid $stat(uid) gid $stat(gid) mtime $stat(mtime) \ |
||||||
|
type $stat(type) |
||||||
|
|
||||||
|
if {$stat(type) == "file"} {lappend ret size $stat(size)} |
||||||
|
|
||||||
|
return $ret |
||||||
|
} |
||||||
|
|
||||||
|
## |
||||||
|
# ::tar::formatHeader |
||||||
|
# |
||||||
|
# Opposite operation to ::tar::readHeader; takes a file name and info |
||||||
|
# dictionary as arguments, returns a corresponding (POSIX-tar) header. |
||||||
|
# |
||||||
|
# The following dictionary entries must be present: |
||||||
|
# mode |
||||||
|
# type |
||||||
|
# |
||||||
|
# The following dictionary entries are used if present, otherwise |
||||||
|
# the indicated default is used: |
||||||
|
# uid 0 |
||||||
|
# gid 0 |
||||||
|
# size 0 |
||||||
|
# mtime [clock seconds] |
||||||
|
# linkname {} |
||||||
|
# uname {} |
||||||
|
# gname {} |
||||||
|
# |
||||||
|
# All other dictionary entries, including devmajor and devminor, are |
||||||
|
# presently ignored. |
||||||
|
## |
||||||
|
|
||||||
|
proc ::tar::formatHeader {name info} { |
||||||
|
array set A { |
||||||
|
linkname "" |
||||||
|
uname "" |
||||||
|
gname "" |
||||||
|
size 0 |
||||||
|
gid 0 |
||||||
|
uid 0 |
||||||
|
} |
||||||
|
set A(mtime) [clock seconds] |
||||||
|
array set A $info |
||||||
|
array set A {devmajor "" devminor ""} |
||||||
|
|
||||||
|
set type [string map {file 0 directory 5 characterSpecial 3 \ |
||||||
|
blockSpecial 4 fifo 6 link 2 socket A} $A(type)] |
||||||
|
|
||||||
|
set osize [format %o $A(size)] |
||||||
|
set ogid [format %o $A(gid)] |
||||||
|
set ouid [format %o $A(uid)] |
||||||
|
set omtime [format %o $A(mtime)] |
||||||
|
|
||||||
|
set name [string trimleft $name /] |
||||||
|
if {[string length $name] > 255} { |
||||||
|
return -code error -errorcode {TAR BAD PATH LENGTH} \ |
||||||
|
"path name over 255 chars" |
||||||
|
} elseif {[string length $name] > 100} { |
||||||
|
set common [string range $name end-99 154] |
||||||
|
if {[set splitpoint [string first / $common]] == -1} { |
||||||
|
return -code error -errorcode {TAR BAD PATH UNSPLITTABLE} \ |
||||||
|
"path name cannot be split into prefix and name" |
||||||
|
} |
||||||
|
set prefix [string range $name 0 end-100][string range $common 0 $splitpoint-1] |
||||||
|
set name [string range $common $splitpoint+1 end][string range $name 155 end] |
||||||
|
} else { |
||||||
|
set prefix "" |
||||||
|
} |
||||||
|
|
||||||
|
set header [binary format a100A8A8A8A12A12A8a1a100A6a2a32a32a8a8a155a12 \ |
||||||
|
$name $A(mode)\x00 $ouid\x00 $ogid\x00\ |
||||||
|
$osize\x00 $omtime\x00 {} $type \ |
||||||
|
$A(linkname) ustar\x00 00 $A(uname) $A(gname)\ |
||||||
|
$A(devmajor) $A(devminor) $prefix {}] |
||||||
|
|
||||||
|
binary scan $header c* tmp |
||||||
|
set cksum 0 |
||||||
|
foreach x $tmp {incr cksum $x} |
||||||
|
|
||||||
|
return [string replace $header 148 155 [binary format A8 [format %o $cksum]\x00]] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
proc ::tar::recurseDirs {files followlinks} { |
||||||
|
foreach x $files { |
||||||
|
if {[file isdirectory $x] && ([file type $x] != "link" || $followlinks)} { |
||||||
|
if {[set more [glob -dir $x -nocomplain *]] != ""} { |
||||||
|
eval lappend files [recurseDirs $more $followlinks] |
||||||
|
} else { |
||||||
|
lappend files $x |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return $files |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::writefile {in out followlinks name} { |
||||||
|
puts -nonewline $out [formatHeader $name [statFile $in $followlinks]] |
||||||
|
set size 0 |
||||||
|
if {[file type $in] == "file" || ($followlinks && [file type $in] == "link")} { |
||||||
|
set in [::open $in] |
||||||
|
fconfigure $in -encoding binary -translation lf -eofchar {} |
||||||
|
set size [fcopy $in $out] |
||||||
|
close $in |
||||||
|
} |
||||||
|
puts -nonewline $out [string repeat \x00 [pad $size]] |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::create {tar files args} { |
||||||
|
set dereference 0 |
||||||
|
set chan 0 |
||||||
|
parseOpts {dereference 0 chan 0} $args |
||||||
|
|
||||||
|
if {$chan} { |
||||||
|
set fh $tar |
||||||
|
} else { |
||||||
|
set fh [::open $tar w+] |
||||||
|
fconfigure $fh -encoding binary -translation lf -eofchar {} |
||||||
|
} |
||||||
|
foreach x [recurseDirs $files $dereference] { |
||||||
|
writefile $x $fh $dereference $x |
||||||
|
} |
||||||
|
puts -nonewline $fh [string repeat \x00 1024] |
||||||
|
|
||||||
|
if {!$chan} { |
||||||
|
close $fh |
||||||
|
} |
||||||
|
return $tar |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::add {tar files args} { |
||||||
|
set dereference 0 |
||||||
|
set prefix "" |
||||||
|
set quick 0 |
||||||
|
parseOpts {dereference 0 prefix 1 quick 0} $args |
||||||
|
|
||||||
|
set fh [::open $tar r+] |
||||||
|
fconfigure $fh -encoding binary -translation lf -eofchar {} |
||||||
|
|
||||||
|
if {$quick} then { |
||||||
|
seek $fh -1024 end |
||||||
|
} else { |
||||||
|
set data [read $fh 512] |
||||||
|
while {[regexp {[^\0]} $data]} { |
||||||
|
array set header [readHeader $data] |
||||||
|
seek $fh [expr {$header(size) + [pad $header(size)]}] current |
||||||
|
set data [read $fh 512] |
||||||
|
} |
||||||
|
seek $fh -512 current |
||||||
|
} |
||||||
|
|
||||||
|
foreach x [recurseDirs $files $dereference] { |
||||||
|
writefile $x $fh $dereference $prefix$x |
||||||
|
} |
||||||
|
puts -nonewline $fh [string repeat \x00 1024] |
||||||
|
|
||||||
|
close $fh |
||||||
|
return $tar |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::remove {tar files} { |
||||||
|
set n 0 |
||||||
|
while {[file exists $tar$n.tmp]} {incr n} |
||||||
|
set tfh [::open $tar$n.tmp w] |
||||||
|
set fh [::open $tar r] |
||||||
|
|
||||||
|
fconfigure $fh -encoding binary -translation lf -eofchar {} |
||||||
|
fconfigure $tfh -encoding binary -translation lf -eofchar {} |
||||||
|
|
||||||
|
while {![eof $fh]} { |
||||||
|
array set header [readHeader [read $fh 512]] |
||||||
|
if {$header(name) == ""} { |
||||||
|
puts -nonewline $tfh [string repeat \x00 1024] |
||||||
|
break |
||||||
|
} |
||||||
|
if {$header(prefix) != ""} {append header(prefix) /} |
||||||
|
set name $header(prefix)$header(name) |
||||||
|
set len [expr {$header(size) + [pad $header(size)]}] |
||||||
|
if {[lsearch $files $name] > -1} { |
||||||
|
seek $fh $len current |
||||||
|
} else { |
||||||
|
seek $fh -512 current |
||||||
|
fcopy $fh $tfh -size [expr {$len + 512}] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
close $fh |
||||||
|
close $tfh |
||||||
|
|
||||||
|
file rename -force $tar$n.tmp $tar |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tar::HandleLongLink {fh hv} { |
||||||
|
upvar 1 $hv header thelongname thelongname |
||||||
|
|
||||||
|
# @LongName Part I. |
||||||
|
if {$header(type) == "L"} { |
||||||
|
# Size == Length of name. Read it, and pad to full 512 |
||||||
|
# size. After that is a regular header for the actual |
||||||
|
# file, where we have to insert the name. This is handled |
||||||
|
# by the next iteration and the part II below. |
||||||
|
set thelongname [string trimright [read $fh $header(size)] \000] |
||||||
|
seekorskip $fh [pad $header(size)] current |
||||||
|
return -code continue |
||||||
|
} |
||||||
|
# Not supported yet: type 'K' for LongLink (long symbolic links). |
||||||
|
|
||||||
|
# @LongName, part II, get data from previous entry, if defined. |
||||||
|
if {[info exists thelongname]} { |
||||||
|
set header(name) $thelongname |
||||||
|
# Prevent leakage to further entries. |
||||||
|
unset thelongname |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# These tests are in the public domain |
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
source [file join \ |
||||||
|
[file dirname [file dirname [file normalize [info script]]]] \ |
||||||
|
devtools testutilities.tcl] |
||||||
|
|
||||||
|
testsNeedTcl 8.5 ; # Virt channel support! |
||||||
|
testsNeedTcltest 1.0 |
||||||
|
|
||||||
|
# Check if we have TclOO available. |
||||||
|
tcltest::testConstraint tcloo [expr {![catch {package require TclOO}]}] |
||||||
|
|
||||||
|
support { |
||||||
|
if {[tcltest::testConstraint tcloo]} { |
||||||
|
use virtchannel_base/memchan.tcl tcl::chan::memchan |
||||||
|
} |
||||||
|
useLocalFile tests/support.tcl |
||||||
|
} |
||||||
|
testing { |
||||||
|
useLocal tar.tcl tar |
||||||
|
} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tar-stream {stream} -constraints tcloo -setup { |
||||||
|
setup1 |
||||||
|
} -body { |
||||||
|
string length [read $chan1] |
||||||
|
} -cleanup { |
||||||
|
cleanup1 |
||||||
|
} -result 128000 |
||||||
|
|
||||||
|
test tar-pad {pad} -body { |
||||||
|
tar::pad 230 |
||||||
|
} -result {282} |
||||||
|
|
||||||
|
test tar-skip {skip} -constraints tcloo -setup { |
||||||
|
setup1 |
||||||
|
} -body { |
||||||
|
tar::skip $chan1 10 |
||||||
|
lappend res [read $chan1 10] |
||||||
|
tar::skip $chan1 72313 |
||||||
|
lappend res [read $chan1 10] |
||||||
|
} -cleanup { |
||||||
|
cleanup1 |
||||||
|
} -result {{6 7 8 9 10} {07 13908 1}} |
||||||
|
|
||||||
|
test tar-seekorskip-backwards {seekorskip} -constraints tcl8.6plus -setup setup1 -body { |
||||||
|
# The zlib push stuff is Tcl 8.6+. Properly restrict the test. |
||||||
|
zlib push gzip $chan1 |
||||||
|
catch {tar::seekorskip $chan1 -10 start} cres |
||||||
|
lappend res $cres |
||||||
|
catch {tar::seekorskip $chan1 10 start} cres |
||||||
|
lappend res $cres |
||||||
|
catch {tar::seekorskip $chan1 -10 end} cres |
||||||
|
lappend res $cres |
||||||
|
catch {tar::seekorskip $chan1 10 end} cres |
||||||
|
lappend res $cres |
||||||
|
lappend res [read $chan1 10] |
||||||
|
} -cleanup cleanup1 -match glob \ |
||||||
|
-result [list \ |
||||||
|
{WHENCE=start not supported*} \ |
||||||
|
{WHENCE=start not supported*} \ |
||||||
|
{WHENCE=end not supported*} \ |
||||||
|
{WHENCE=end not supported*} \ |
||||||
|
{1 2 3 4 5 } \ |
||||||
|
] |
||||||
|
|
||||||
|
test tar-header {header} -body { |
||||||
|
set file1 [dict get $filesys Dir1 File1] |
||||||
|
dict set file1 path /Dir1/File1 |
||||||
|
set header [header_posix $file1] |
||||||
|
set parsed [string trim [tar::readHeader $header]] |
||||||
|
set golden "name /Dir1/File1 mode 755 uid 13103 gid 18103 size 100 mtime 5706756101 cksum 3676 type 0 linkname {} magic ustar\0 version 00 uname {} gname {} devmajor 0 devminor 0 prefix {}" |
||||||
|
set len [string length $parsed] |
||||||
|
foreach {key value} $golden { |
||||||
|
if {[set value1 [dict get $parsed $key]] ne $value } { |
||||||
|
lappend res [list $key $value $value1] |
||||||
|
} |
||||||
|
} |
||||||
|
} -result {} |
||||||
|
|
||||||
|
test tar-add {add} -constraints tcloo -setup { |
||||||
|
setup1 |
||||||
|
} -body { |
||||||
|
tar::create $chan1 [list $tmpdir/one/a $tmpdir/one/two/a $tmpdir/one/three/a] -chan |
||||||
|
seek $chan1 0 |
||||||
|
lappend res {*}[tar::contents $chan1 -chan] |
||||||
|
seek $chan1 0 |
||||||
|
lappend res [string trim [tar::get $chan1 $tmpdir/one/two/a -chan]] |
||||||
|
} -cleanup { |
||||||
|
cleanup1 |
||||||
|
} -result {tartest/one/a tartest/one/two/a tartest/one/three/a hello2} |
||||||
|
|
||||||
|
|
||||||
|
test tar-bug-2840180 {Ticket 2840180} -setup { |
||||||
|
setup2 |
||||||
|
} -body { |
||||||
|
tar::create $chan1 [list $tmpdir/[large-path]/a] -chan |
||||||
|
seek $chan1 0 |
||||||
|
|
||||||
|
# What the package sees. |
||||||
|
lappend res {*}[tar::contents $chan1 -chan] |
||||||
|
close $chan1 |
||||||
|
|
||||||
|
# What a regular tar package sees. |
||||||
|
lappend res [exec 2> $tmpfile.err tar tvf $tmpfile] |
||||||
|
join $res \n |
||||||
|
} -cleanup { |
||||||
|
cleanup2 |
||||||
|
} -match glob -result [join [list \ |
||||||
|
tartest/[large-path]/a \ |
||||||
|
"* tartest/[large-path]/a" \ |
||||||
|
] \n] |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tar-tkt-9f4c0e3e95-1.0 {Ticket 9f4c0e3e95, A} -setup { |
||||||
|
set tarfile [setup-tkt-9f4c0e3e95] |
||||||
|
} -body { |
||||||
|
string trim [tar::get $tarfile 02] |
||||||
|
} -cleanup { |
||||||
|
cleanup-tkt-9f4c0e3e95 |
||||||
|
unset tarfile |
||||||
|
} -result {zero-two} |
||||||
|
|
||||||
|
test tar-tkt-9f4c0e3e95-1.1 {Ticket 9f4c0e3e95, B, } -setup { |
||||||
|
set tarfile [setup-tkt-9f4c0e3e95] |
||||||
|
} -body { |
||||||
|
tar::get $tarfile 0b10 |
||||||
|
} -cleanup { |
||||||
|
cleanup-tkt-9f4c0e3e95 |
||||||
|
unset tarfile |
||||||
|
} -returnCodes error -result {Tar "tartest/t.tar": File "0b10" not found} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
testsuiteCleanup |
@ -0,0 +1,149 @@ |
|||||||
|
|
||||||
|
proc stream {{size 128000}} { |
||||||
|
set chan [tcl::chan::memchan] |
||||||
|
set line {} |
||||||
|
while 1 { |
||||||
|
incr i |
||||||
|
set istring $i |
||||||
|
set ilen [string length $istring] |
||||||
|
if {$line ne {}} { |
||||||
|
append line { } |
||||||
|
incr size -1 |
||||||
|
} |
||||||
|
append line $istring |
||||||
|
incr size -$ilen |
||||||
|
if {$size < 1} { |
||||||
|
set line [string range $line 0 end-[expr {abs(1-$size)}]] |
||||||
|
puts $chan $line |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
if {$i % 10 == 0} { |
||||||
|
puts $chan $line |
||||||
|
incr size -1 ;# for the [puts] newline |
||||||
|
set line {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
seek $chan 0 |
||||||
|
return $chan |
||||||
|
} |
||||||
|
|
||||||
|
proc header_posix {tarball} { |
||||||
|
dict with tarball {} |
||||||
|
tar::formatHeader $path \ |
||||||
|
[dict create \ |
||||||
|
mode $mode \ |
||||||
|
type $type \ |
||||||
|
uid $uid \ |
||||||
|
gid $gid \ |
||||||
|
size $size \ |
||||||
|
mtime $mtime] |
||||||
|
} |
||||||
|
|
||||||
|
proc setup1 {} { |
||||||
|
variable chan1 |
||||||
|
variable res {} |
||||||
|
variable tmpdir tartest |
||||||
|
|
||||||
|
tcltest::makeDirectory $tmpdir |
||||||
|
|
||||||
|
foreach directory { |
||||||
|
one |
||||||
|
one/two |
||||||
|
one/three |
||||||
|
} { |
||||||
|
tcltest::makeDirectory $tmpdir/$directory |
||||||
|
set chan [open $tmpdir/$directory/a w] |
||||||
|
puts $chan hello[incr i] |
||||||
|
close $chan |
||||||
|
} |
||||||
|
set chan1 [stream] |
||||||
|
} |
||||||
|
|
||||||
|
proc large-path {} { |
||||||
|
return aaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbtcllib/modules/tar |
||||||
|
} |
||||||
|
|
||||||
|
proc setup2 {} { |
||||||
|
variable chan1 |
||||||
|
variable res {} |
||||||
|
variable tmpdir tartest |
||||||
|
variable tmpfile tarX |
||||||
|
|
||||||
|
tcltest::makeDirectory $tmpdir |
||||||
|
tcltest::makeFile {} $tmpfile |
||||||
|
|
||||||
|
foreach directory [list [large-path]] { |
||||||
|
tcltest::makeDirectory $tmpdir/$directory |
||||||
|
set chan [open $tmpdir/$directory/a w] |
||||||
|
puts $chan hello[incr i] |
||||||
|
close $chan |
||||||
|
} |
||||||
|
set chan1 [open $tmpfile w+] |
||||||
|
} |
||||||
|
|
||||||
|
proc cleanup1 {} { |
||||||
|
variable chan1 |
||||||
|
close $chan1 |
||||||
|
tcltest::removeDirectory tartest |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
proc cleanup2 {} { |
||||||
|
variable chan1 |
||||||
|
variable tmpdir |
||||||
|
variable tmpfile |
||||||
|
catch { close $chan1 } |
||||||
|
tcltest::removeDirectory $tmpdir |
||||||
|
tcltest::removeFile $tmpfile |
||||||
|
tcltest::removeFile $tmpfile.err |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
variable filesys { |
||||||
|
Dir1 { |
||||||
|
File1 { |
||||||
|
type 0 |
||||||
|
mode 755 |
||||||
|
uid 13103 |
||||||
|
gid 18103 |
||||||
|
size 100 |
||||||
|
mtime 5706756101 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Dir2 { |
||||||
|
File1 { |
||||||
|
type 0 |
||||||
|
mode 644 |
||||||
|
uid 15103 |
||||||
|
gid 19103 |
||||||
|
size 100 |
||||||
|
mtime 5706776103 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
proc setup-tkt-9f4c0e3e95 {} { |
||||||
|
variable tmpdir tartest |
||||||
|
|
||||||
|
tcltest::makeDirectory $tmpdir |
||||||
|
tcltest::makeFile {zero-two} $tmpdir/02 |
||||||
|
tcltest::makeFile {number two} $tmpdir/2 |
||||||
|
|
||||||
|
set here [pwd] |
||||||
|
cd $tmpdir |
||||||
|
tar::create t.tar {2 02} |
||||||
|
cd $here |
||||||
|
|
||||||
|
return $tmpdir/t.tar |
||||||
|
} |
||||||
|
|
||||||
|
proc cleanup-tkt-9f4c0e3e95 {} { |
||||||
|
variable tmpdir |
||||||
|
tcltest::removeFile $tmpdir/2 |
||||||
|
tcltest::removeFile $tmpdir/02 |
||||||
|
tcltest::removeDirectory $tmpdir |
||||||
|
return |
||||||
|
} |
Loading…
Reference in new issue