You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
556 lines
27 KiB
556 lines
27 KiB
# -*- tcl -*- |
|
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'deck 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::mix::commandset::module 0.1.0 |
|
# Meta platform tcl |
|
# Meta license BSD |
|
# @@ Meta End |
|
|
|
|
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
## Requirements |
|
##e.g package require frobz |
|
package require punk::repo |
|
# depends on punk,punk::mix::base,punk::mix::cli |
|
|
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
namespace eval punk::mix::commandset::module { |
|
namespace export * |
|
|
|
proc paths {} { |
|
#set roots [punk::repo::find_repos ""] |
|
#set project [lindex [dict get $roots project] 0] |
|
set project [punk::repo::find_project ""] |
|
|
|
if {$project ne ""} { |
|
set is_project 1 |
|
set searchbase $project |
|
} else { |
|
set is_project 0 |
|
set searchbase [pwd] |
|
} |
|
|
|
if {[catch { |
|
set source_module_folderlist [punk::mix::cli::lib::find_source_module_paths $searchbase] |
|
} errMsg]} { |
|
set source_module_folderlist [list] |
|
} |
|
|
|
set tm_folders [tcl::tm::list] |
|
package require overtype |
|
|
|
set result "" |
|
if {$is_project} { |
|
append result "Project module source paths:" \n |
|
foreach f $source_module_folderlist { |
|
append result "$f" \n |
|
} |
|
} |
|
append result \n |
|
append result "tcl::tm::list" \n |
|
foreach f $tm_folders { |
|
if {$is_project} { |
|
if {[punk::mix::cli::lib::path_a_aboveorat_b $project $f]} { |
|
set pinfo "(within project)" |
|
} else { |
|
set pinfo "" |
|
} |
|
} else { |
|
set pinfo "" |
|
} |
|
set warning "" |
|
if {![file isdirectory $f]} { |
|
set warning "(PATH NOT FOUND)" |
|
} |
|
append result "$f $pinfo $warning" \n |
|
} |
|
|
|
|
|
return $result |
|
} |
|
#require current dir when calling to be the projectdir, or |
|
proc templates {args} { |
|
set tdict_low_to_high [templates_dict {*}$args] |
|
#convert to screen order - with higher priority at the top |
|
set tdict [dict create] |
|
foreach k [lreverse [dict keys $tdict_low_to_high]] { |
|
dict set tdict $k [dict get $tdict_low_to_high $k] |
|
} |
|
|
|
package require overtype |
|
package require textblock |
|
#set pathinfolist [dict values $tdict] |
|
#set paths [lsearch -all -inline -index 1 -subindices $pathinfolist *] ;#relies on first key of templates_dict being path |
|
|
|
set names [dict keys $tdict] |
|
set paths [list] |
|
set pathtypes [list] |
|
dict for {nm tinfo} $tdict { |
|
lappend paths [dict get $tinfo path] |
|
lappend pathtypes [dict get $tinfo sourceinfo pathtype] |
|
} |
|
|
|
set title(path) "Path" |
|
set widest(path) [tcl::mathfunc::max {*}[lmap v [concat [list $title(path)] $paths] {punk::strlen $v}]] |
|
set col(path) [string repeat " " $widest(path)] |
|
|
|
set title(pathtype) "[a+ green]Path Type[a]" |
|
set widest(pathtype) [tcl::mathfunc::max {*}[lmap v [concat [list $title(pathtype)] $pathtypes] {string length $v}]] |
|
set col(pathtype) [string repeat " " $widest(pathtype)] |
|
|
|
set title(name) "Template Name" |
|
set widest(name) [tcl::mathfunc::max {*}[lmap v [concat [list $title(name)] $names] {string length $v}]] |
|
set col(name) [string repeat " " $widest(name)] |
|
|
|
set tablewidth [expr {$widest(name) + 1 + $widest(pathtype) + 1 + $widest(name)}] |
|
set table "" |
|
append table [string repeat - $tablewidth] \n |
|
append table "[textblock::join -- [overtype::left $col(name) $title(name)] " " [overtype::left $col(pathtype) $title(pathtype)] " " [overtype::left $col(path) $title(path)]]" \n |
|
append table [string repeat - $tablewidth] \n |
|
|
|
foreach n $names pt $pathtypes p $paths { |
|
append table "[overtype::left $col(name) $n] [overtype::left $col(pathtype) $pt] [overtype::left $col(path) $p]" \n |
|
} |
|
|
|
return $table |
|
} |
|
|
|
#return all module templates with repeated ones suffixed with #2 #3 etc |
|
punk::args::define { |
|
@id -id ::punk::mix::commandset::module::templates_dict |
|
@cmd -name templates_dict -help\ |
|
"Templates from module and project paths" |
|
-startdir -default "" -help\ |
|
"Project folder used in addition to module paths" |
|
-not -default "" -multiple 1 |
|
@values |
|
globsearches -default * -multiple 1 |
|
} |
|
proc templates_dict {args} { |
|
set argd [punk::args::get_by_id ::punk::mix::commandset::module::templates_dict $args] |
|
package require punk::cap |
|
if {[punk::cap::capability_has_handler punk.templates]} { |
|
set template_folder_dict [punk::cap::call_handler punk.templates get_itemdict_moduletemplates {*}$args] |
|
} else { |
|
put stderr "get_template_basefolders WARNING - no handler available for the 'punk.templates' capability - template providers will be unable to provide template locations" |
|
} |
|
} |
|
|
|
|
|
set moduletypes [punk::mix::cli::lib::module_types] |
|
punk::args::define [subst { |
|
@id -id ::punk::mix::commandset::module::new |
|
@cmd -name "punk::mix::commandset::module::new" -help\ |
|
"Create a new module file in the appropriate folder within src/modules. |
|
If the name given in the module argument is namespaced, |
|
the necessary subfolder(s) will be used or created." |
|
-project -optional 1 |
|
-version -default "0.1.0" -help\ |
|
"version to use if not specified as part of the module argument. |
|
If a version is specified in the module argument as well as in -version |
|
the higher version number will be used. |
|
" |
|
-license -default <unspecified> |
|
-author -default <unspecified> -multiple 1 |
|
-template -default punk.module |
|
-type -default "[lindex $moduletypes 0]" -choices {$moduletypes} |
|
-force -default 0 -type boolean -help\ |
|
"If set true, will OVERWRITE an existing .tm file if there is one. |
|
If false (default) an error will be raised if there is a conflict." |
|
-quiet -default 0 -type boolean -help\ |
|
"Suppress information messages on stdout" |
|
@values -min 1 -max 1 |
|
module -type string -help\ |
|
"Name of module, possibly including a namespace and/or version number |
|
e.g mynamespace::mymodule-1.0" |
|
}] |
|
proc new {args} { |
|
set year [clock format [clock seconds] -format %Y] |
|
# use \uFFFD because unicode replacement char should consistently render as 1 wide |
|
set argd [punk::args::get_by_id ::punk::mix::commandset::module::new $args] |
|
lassign [dict values $argd] leaders opts values received |
|
set module [dict get $values module] |
|
|
|
#set opts [dict merge $defaults $args] |
|
|
|
#todo - review compatibility between -template and -type |
|
#-type is the wrapping technology e.g 'plain' for none or tarjar or zip (modpod) etc (consider also snappy/snappy-tcl) |
|
#-template may be a folder - but only if the selected -type suports it |
|
|
|
|
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
# option -version |
|
# we need this value before looking at the named argument |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
set opt_version_supplied [dict get $opts -version] |
|
set opt_version $opt_version_supplied |
|
if {![util::is_valid_tm_version $opt_version]} { |
|
error "deck module.new error - supplied -version $opt_version doesn't appear to be a valid Tcl module version" |
|
} |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
#named argument |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
set mversion_supplied "" ;#version supplied directly in module argument |
|
if {[string first - $module]> 0} { |
|
#if it has a dash then version is required to be valid |
|
lassign [punk::mix::cli::lib::split_modulename_version $module] modulename mversion |
|
if {![util::is_valid_tm_version $mversion]} { |
|
error "deck module.new error - unable to determine modulename-version from supplied value '$module'" |
|
} |
|
set mversion_supplied $mversion ;#record as may need to compare to version from templatefile name |
|
set vcompare_is_mversion_bigger [package vcompare $mversion $opt_version] |
|
if {$vcompare_is_mversion_bigger > 0} { |
|
set opt_version $mversion; #module parameter has higher value than -version |
|
set vmsg "from module argument: $module" |
|
} else { |
|
set vmsg "from -version option: $opt_version_supplied" |
|
} |
|
if {"-version" in $received} { |
|
if {$vcompare_is_mversion_bigger != 0} { |
|
#is bigger or smaller |
|
puts stderr "module.new WARNING: version supplied in module argument as well as -version option. Using the higher version number $vmsg" |
|
} |
|
} |
|
} else { |
|
set modulename $module |
|
} |
|
punk::mix::cli::lib::validate_modulename $modulename -errorprefix "punk::mix::commandset::module::new" |
|
|
|
if {[regexp {[A-Z]} $module]} { |
|
set msg "module names containing uppercase are not recommended (see tip 590).\n" |
|
append msg "Please retype the module name '$module' to proceed.\n" |
|
append msg "If you type it exactly as it was you will be allowed to proceed with uppercase anyway\n" |
|
append msg "Retype it all in lowercase to use recommended naming" |
|
set answer [util::askuser $msg] |
|
if {[regexp {[A-Z]} $answer]} { |
|
if {$answer eq $module} { |
|
#ok - user insists |
|
} else { |
|
|
|
} |
|
} else { |
|
#user has resupplied modulename all as lowercase |
|
if {$answer eq [string tolower $module]} { |
|
set module $answer |
|
} else { |
|
#.. but it doesn't match original - require rerun |
|
} |
|
} |
|
} |
|
|
|
|
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
#options |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
set testdir [pwd] |
|
if {![string length [set projectdir [punk::repo::find_project $testdir]]]} { |
|
if {![string length [set projectdir [punk::repo::find_candidate $testdir]]]} { |
|
set msg [punk::repo::is_candidate_root_requirements_msg] |
|
error "module.new unable to create module in projectdir:$projectdir - directory doesn't appear to meet basic standards $msg" |
|
} |
|
} |
|
if {![dict exists $received -project]} { |
|
set projectname [file tail $projectdir] |
|
} else { |
|
set opt_project [dict get $opts -project] |
|
set projectname $opt_project |
|
if {$projectname ne [file tail $projectdir]} { |
|
error "module.new -project '$opt_project' doesn't match detected projectname '$projectname' at path: $projectdir" |
|
} |
|
} |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
set opt_license [dict get $opts -license] |
|
set opt_authors [dict get $opts -author] ;#-multiple true |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
set opt_template [dict get $opts -template] |
|
if {[regexp {.*[?*].*} $opt_template]} { |
|
error "module.new -template does not support glob chars. Use an exact full name including version (and optionally .tm) - or use just the name without version or .tm, and the latest version will be selected" |
|
} |
|
|
|
set templates_dict [templates_dict] ;#keys are possibly prefixed with <vendor>. and/or suffixed with #2 #3 etc if there are collisions - the remaining unsuffixed being the one with highest preference |
|
#todo - allow versionless name - pick latest which isn't suffixed with #2 etc |
|
#if the user wants to exactly match an unversioned template, in the presence of versioned ones - they may need to include the trailing .tm |
|
if {[dict exists $templates_dict $opt_template]} { |
|
#exact long name (possibly including version) |
|
#Note - an unversioned .tm template will be matched here - even though versioned templates of the same name may exist. |
|
set templatefile [dict get $templates_dict $opt_template path] |
|
set templatefile_info [dict get $templates_dict $opt_template sourceinfo] |
|
} else { |
|
#if it wasn't an exact match for opt_template - then opt_template now shouldn't contain a version (we have also ruled out glob chars * & ? above) |
|
#(if it does - then we just won't find anything - which is fine) |
|
#module file name could contain dots - but only one dash - if it is versioned |
|
|
|
set matches [lsearch -all -inline [dict keys $templates_dict] $opt_template-*] ;#the key is of form vendor.modulename-version(#suffix) (version optional, suffix if lower precedence with same name was found) |
|
#only .tm (or .TM .Tm .tM) files make it into the templates_dict - they are allowed to be unversioned though. |
|
set key_version_list [list] |
|
foreach m $matches { |
|
#vendorname could contain dashes or dots - so easiest way to split out is to examine the stored vendor value in sourceinfo |
|
set vendor [dict get $templates_dict $m sourceinfo vendor] |
|
if {$vendor ne "_project"} { |
|
#_project special case - not included in module names |
|
set module $m |
|
} else { |
|
set module [string range [string length $vendor.] end] |
|
} |
|
lassign [punk::mix::cli::lib::split_modulename_version $m] _tailmname mversion |
|
lappend key_version_list [list $m $mversion] |
|
} |
|
if {[llength $matches]} { |
|
set highest_m "" |
|
set highest_v "" |
|
foreach kv $key_version_list { |
|
if {$highest_v eq ""} { |
|
set highest_m [lindex $kv 0] |
|
set highest_v [lindex $kv 1] |
|
} else { |
|
if {[package vcompare $highest_v [lindex $kv 1]] == -1} { |
|
set highest_m [lindex $kv 0] |
|
set highest_v [lindex $kv 1] |
|
} |
|
} |
|
} |
|
set templatefile [dict get $templates_dict $highest_m path] |
|
set templatefile_info [dict get $templates_dict $highest_m sourceinfo] |
|
} else { |
|
error "module.new unable to find template '$opt_template'. [dict size $templates_dict] Known templates. Use deck module.templates to display" |
|
} |
|
} |
|
|
|
|
|
set tpldir [file dirname $templatefile] ;#use same folder for modulename_buildversion.txt, modulename_description.txt if they exist |
|
|
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
set opt_type [dict get $opts -type] |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
set opt_quiet [dict get $opts -quiet] |
|
set opt_force [dict get $opts -force] |
|
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
|
|
|
|
|
|
|
|
|
|
|
set subpath [punk::mix::cli::lib::module_subpath $modulename] ;#commonly empty string for simple modulename e.g "mymodule" but x::mymodule has subpath 'x' and x::y::mymodule has subpath 'x/y' |
|
if {![string length $subpath]} { |
|
set modulefolder $projectdir/src/modules |
|
} else { |
|
set modulefolder $projectdir/src/modules/$subpath |
|
} |
|
file mkdir $modulefolder |
|
|
|
set moduletail [namespace tail $modulename] |
|
set magicversion [punk::mix::util::magic_tm_version] ;#deliberately large so given load-preference when testing |
|
|
|
|
|
|
|
|
|
set template_tail [file tail $templatefile] ;#convert template_xxx-version.tm.x to {xxx version} |
|
set template_tail [string range $template_tail [string length template_] end] |
|
set ext [string tolower [file extension $template_tail]] |
|
if {$ext eq ".tm"} { |
|
set template_modulename_part [file rootname $template_tail] |
|
} elseif {[string is integer -strict [string range $ext 1 end]]} { |
|
#something like modulename-0.0.1.tm.2 |
|
#strip of last 2 dotted parts |
|
set shortened [file rootname $template_tail] |
|
if {![string equal -nocase [file extension $shortened] ".tm"]} { |
|
error "module.new error: Unable to interpret filename components of template file '$templatefile' (expected .tm as second-last or last component)" |
|
} |
|
set template_modulename_part [file rootname $shortened] |
|
} else { |
|
error "module.new error: Unable to interpret filename components of template file '$templatefile'" |
|
} |
|
lassign [punk::mix::cli::lib::split_modulename_version $template_modulename_part] t_mname t_version |
|
#t_version may be empty string if template is unversioned e.g template_whatever.tm |
|
|
|
set fd [open $templatefile r]; set template_filedata [read $fd]; close $fd |
|
if {[string match "*$magicversion*" $template_filedata]} { |
|
set use_magic 1 |
|
set build_version $opt_version |
|
set infile_version $magicversion |
|
} else { |
|
set use_magic 0 |
|
if {$opt_version_supplied ne "\uFFFF"} { |
|
set build_version $opt_version |
|
} else { |
|
# |
|
|
|
if {[util::is_valid_tm_version $t_version]} { |
|
if {$mversion_supplied eq ""} { |
|
set build_version $t_version |
|
} else { |
|
#we have a version from the named argument 'module' |
|
if {[package vcompare $mversion_supplied $t_version] > 0} { |
|
set build_version $mversion_supplied |
|
} else { |
|
set build_version $t_version |
|
} |
|
} |
|
} else { |
|
#probably an unversioned module template |
|
#use opt_version default from above |
|
set build_version $opt_version |
|
} |
|
} |
|
set infile_version $build_version |
|
} |
|
|
|
set moduletemplate [file join $projectname [punk::path::relative $projectdir $templatefile]] ;#if templatfile is on another volume - just $templatefile will be returned. |
|
#moduletemplate should usually be a relative path - but could be absolute, or contain info about the relative locations of projectdir vs templatefile if template comes from another project or a module outside the project |
|
#This path info may be undesired in the template output (%moduletemplate%) |
|
#it is nevertheless useful information - and not the only way developer-machine/build-machine paths can leak |
|
#for now the user has the option to override any templates and remove %moduletemplate% if it is a security/privacy concern |
|
|
|
#Don't put literal %x% in the code for the commandset::module itself - to stop them being seen by layout scanner as replacable tokens |
|
set tagnames [list moduletemplate $moduletemplate project $projectname pkg $modulename year $year license $opt_license authors $opt_authors version $infile_version] |
|
set strmap [list] |
|
foreach {tag val} $tagnames { |
|
lappend strmap %$tag% $val |
|
} |
|
set template_filedata [string map $strmap $template_filedata] |
|
|
|
set tmfile $modulefolder/${moduletail}-$infile_version.tm |
|
set podfile $modulefolder/#modpod-$moduletail-$infile_version/$moduletail-$infile_version.tm |
|
set has_tm [file exists $tmfile] |
|
set has_pod [file exists $podfile] |
|
if {$has_tm && $has_pod} { |
|
#invalid configuration - bomb out |
|
error "module.new error: Invalid target configuration found. module folder has both a .tm file $tmfile and a modpod file $podfile. Please delete one of them before trying again." |
|
} |
|
if {$opt_type eq "plain"} { |
|
set modulefile $tmfile |
|
} else { |
|
set modulefile $podfile |
|
} |
|
if {$has_tm || $has_pod} { |
|
if {!$opt_force} { |
|
if {$has_tm} { |
|
set errmsg "module.new error: module file $tmfile already exists - aborting" |
|
} else { |
|
set errmsg "module.new error: module file $podfile already exists - aborting" |
|
} |
|
if {[string match "*$magicversion*" $tmfile]} { |
|
append errmsg \n "If you are attempting to create a module file with a specific version in the source-file name - you will need to use a template that doesn't contain the string '$magicversion' e.g the provided template moduleexactversion-0.0.1.tm" |
|
} |
|
error $errmsg |
|
} else { |
|
#review - prompt here vs caller? |
|
#we are committed to overwriting/replacing if there was a pre-existing module of same version |
|
if {$has_pod} { |
|
file delete -force [file dirname $podfile] |
|
} elseif {$has_tm} { |
|
file delete -force $tmfile |
|
} |
|
} |
|
} |
|
|
|
|
|
if {[file exists $tpldir/modulename_buildversion.txt]} { |
|
set fd [open $tpldir/modulename_buildversion.txt r]; set buildversion_filedata [read $fd]; close $fd |
|
} else { |
|
#mix_templates_dir warns of deprecation - review |
|
set lib_tpldir [file join [punk::mix::cli::lib::mix_templates_dir] modules];#fallback for modulename_buildversion.txt, modulename_description.txt |
|
set fd [open $lib_tpldir/modulename_buildversion.txt r]; set buildversion_filedata [read $fd]; close $fd |
|
} |
|
set buildversionfile [file join $modulefolder ${moduletail}-buildversion.txt] |
|
set existing_build_version "" |
|
if {!$opt_force && [file exists $buildversionfile]} { |
|
set buildversiondata [punk::mix::util::fcat $buildversionfile] |
|
set lines [split $buildversiondata \n] |
|
set existing_build_version [string trim [lindex $lines 0]] |
|
if {[package vcompare $existing_build_version $build_version] >= 0} { |
|
#existing version in -buildversion.txt file is lower than the module version we are creating |
|
error "module.new error: there is an existing buildversion file $buildversionfile with version $existing_build_version equal to or higher than $build_version - unable to continue" |
|
} |
|
} |
|
|
|
set existing_tm_versions [glob -nocomplain -dir $modulefolder -tails ${moduletail}-*.tm] |
|
#it shouldn't be possible to overmatch with the glob - because '-' is not valid in a Tcl module name |
|
set existing_pod_versions [glob -nocomplain -dir $modulefolder -tails #modpod-$moduletail-*] |
|
set existing_versions [concat $existing_tm_versions $existing_pod_versions] |
|
|
|
if {[llength $existing_versions]} { |
|
set name_version_pairs [list] |
|
lappend name_version_pairs [list $moduletail $infile_version] |
|
foreach existing $existing_versions { |
|
lassign [punk::mix::cli::lib::split_modulename_version $existing] namepart version ;# .tm is stripped and ignored |
|
if {[string match #modpod-* $namepart]} { |
|
set namepart [string range $namepart 8 end] |
|
} |
|
lappend name_version_pairs [list $namepart $version] |
|
} |
|
set name_version_pairs [lsort -command {package vcompare} -index 1 $name_version_pairs] ;#while plain lsort will often work with versions - it can get order wrong with some - so use package vcompare |
|
if {[lindex $name_version_pairs end] ne [list $moduletail $infile_version]} { |
|
set thisposn [lsearch -index 1 $name_version_pairs $infile_version] |
|
set name_version_pairs [lreplace $name_version_pairs $thisposn $thisposn] |
|
set other_versions [lsearch -all -inline -index 1 -subindices $name_version_pairs *] |
|
set errmsg "module.new error: There are existing modules in the target folder with higher versions than $infile_version." |
|
append errmsg \n "Other versions found: $other_versions" |
|
if {$magicversion in $other_versions} { |
|
append errmsg \n "Existing build version for special source file name: '$magicversion' is: '$existing_build_version'" |
|
append errmsg \n "If '$magicversion' file doesn't represent the latest source it should be removed or the filename and contents adjusted to be a specific version" |
|
} |
|
error $errmsg |
|
} else { |
|
puts stderr "module.new WARNING: There are existing modules in the target folder with lower versions than $infile_version - manual review recommended" |
|
puts stderr "Other versions found: [lsearch -all -inline -index 1 -subindices [lrange $name_version_pairs 0 end-1] *]" |
|
} |
|
} |
|
|
|
if {!$opt_quiet} { |
|
puts stdout "Creating $modulefile from template $moduletemplate" |
|
} |
|
file mkdir [file dirname $modulefile] |
|
|
|
set fd [open $modulefile w] |
|
fconfigure $fd -translation binary |
|
puts -nonewline $fd $template_filedata |
|
close $fd |
|
|
|
|
|
set buildversion_filedata [string map [list %Major.Minor.Level% $build_version] $buildversion_filedata] |
|
set fd [open $buildversionfile w] |
|
fconfigure $fd -translation binary |
|
puts -nonewline $fd $buildversion_filedata |
|
close $fd |
|
|
|
return [list file $modulefile version $build_version] |
|
} |
|
|
|
namespace eval lib { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
## Ready |
|
package provide punk::mix::commandset::module [namespace eval punk::mix::commandset::module { |
|
variable version |
|
set version 0.1.0 |
|
}] |
|
return
|
|
|