2 # Copyright 2015,2016,2017 Lucas Sköldqvist <frusen@dragora.org>
5 package require sqlite3
12 {frusen kelsoo mprodrigues tom mmpg
}
18 if {[file exists
$::env(HOME
)/.julrc
] == 1} {
19 source $::env(HOME
)/.julrc
20 } elseif
{[file exists
$::env(HOME
)/.jul
/config.tcl
] == 1} {
21 source $::env(HOME
)/.jul
/config.tcl
24 proc list_repo
{args
} {
28 # if there is no argument, search for all
29 if {[lindex $args 0] == {}} {
32 set query
"WHERE name LIKE '%$args%' and"
37 append query
" and arch = '$arch' and"
39 set query
"WHERE arch = '$arch' and"
44 foreach repo
[lreverse
[array names repolist
]] {
45 set db_file
$::env(HOME
)/.jul
/[get_db_file
$repo]
46 if {[catch {sqlite3 db
$db_file -create false
} fid
]} {
47 puts stderr
"jul: search: Unable to open database file."
51 foreach re
[lindex $repolist($repo) 0] {
52 db
eval "SELECT rowid,* FROM package $query repo='$re'" {
55 set pkg
(version
) $version
59 db
eval "SELECT desc FROM description \
60 JOIN package USING(name) \
61 WHERE lang = 'en' AND name='$name'" {
64 lappend result
[array get pkg
]
74 # Returns the file name of the repository 'name'.
75 proc get_db_file
{name
} {
77 return [lindex $repolist($name) 1]
83 set cmd
[lindex $args 0]
88 # receive a list of all the packages
89 set pkg_list
[list_repo
[lindex $args 1]]
91 if {[llength $pkg_list] == 0} {
92 puts "jul: $cmd: No packages found."
98 foreach key
$pkg_list {
100 lappend finds
$pkg(rowid
)
101 puts -nonewline " \[$i\] $pkg(repo) $pkg(name)-$pkg(version)"
102 puts "-$pkg(arch)-$pkg(build)"
110 puts "Select a package to $cmd or `q' to quit."
111 puts -nonewline "Pressing `enter' selects the top package: "
114 set z
[checkanswer
$c [llength $pkg_list]]
115 # If enter was pressed, select the first package.
116 if {$z == 2} {set c
"1"}
123 foreach repo
[lreverse
[array names repolist
]] {
124 set db_file
$::env(HOME
)/.jul
/[get_db_file
$repo]
125 if {[catch {sqlite3 db
$db_file -create false
} fid
]} {
126 puts stderr
"jul: $cmd: Unable to open database file."
130 db
eval "SELECT * FROM repository JOIN package \
131 ON repository.name = package.repo \
132 WHERE package.rowid=[lindex $finds $c]" {
134 set p
(version
) $version
138 lappend result
[array get p
]
144 foreach item
[getplist
] {
145 if {"$p(name)-$p(version)-$p(arch)-$p(build)" == $item} {
146 puts "jul: $cmd: Package already installed."
151 cd "$::env(HOME)/.jul/cache"
152 set fn
$p(name
)-$p(version
)-$p(arch
)-$p(build
).tlz
153 set pkg
$p(url
)$p(name
)/$fn
154 puts -nonewline "Downloading $p(name)... "
157 puts -nonewline "Downloading checksum... "
159 puts -nonewline "Verifying... "
161 if {[verify_file
$fn.sha1sum
] == -1} {
166 set pfile
$::env(HOME
)/.jul
/cache
/$fn
167 catch {exec su
-c "pkg $cmd $pfile"} results
options
171 # List the changes in 'repo'.
172 proc changes
{repo
} {
176 puts "jul: changes: You must specify a repository."
178 } elseif
{$repo == "-h"} {
182 if {[lsearch -exact [lreverse
[array names repolist
]] $repo] == -1} {
183 puts "jul: changes: `$repo' is not a valid repository."
187 if {[file exists
$::env(HOME
)/.jul
/repos
/$repo.changes
] == 1} {
188 set f
[open $::env(HOME
)/.jul
/repos
/$repo.changes
]
192 puts -nonewline "jul: changes: Can't list changes for `$repo'."
193 puts " Try synchronising."
197 # Check if 'value' is in 'range' and return 1 if that is the case. Exit if
199 proc checkanswer
{value range
} {
200 if {$value == "q"} {exit}
201 if {$value == ""} {return 2}
203 if {[string is integer
-strict $value] == 1} {
204 # $value < $range because we start to count from 0 and
205 # array size does not
206 if {[expr {$value >= 1}] && [expr {$value <= $range}]} {
214 # Remove '$HOME/.jul'.
216 if {$args == "-h"} {help clean
}
219 puts "You're about to delete `$::env(HOME)/.jul/' and all of its "
221 puts -nonewline "Proceed? (Y/n) "
225 if {$c == "n" ||
$c == "N"} {
228 file delete
-force $::env(HOME
)/.jul
232 file delete
-force $::env(HOME
)/.jul
233 puts "Deleted $::env(HOME)/.jul and all of its content."
238 if {[catch {exec curl
-sfO $url} results
options]} {
239 set details
[dict get
$options -errorcode]
242 puts -nonewline "Could not download file: "
244 if {[lindex $details 0] eq
"CHILDSTATUS"} {
245 set status
[lindex $details 2]
247 puts "HTTP error code > 400"
248 puts "The file was probably not found."
249 puts "Please report this!"
250 } elseif
{$status == 23} {
251 puts "Write error in $::env(PWD)"
253 } elseif
{[lindex $details 1] eq
"ENOENT"} {
254 puts "Could not find `curl'. Make sure it is installed."
256 puts "Unknown error. Please report this!"
263 proc verify_file
{fn
} {
264 if {[catch {exec sha1sum
-c $fn} results
options]} {
272 # Print the usage of the command passed as 'args' or the help screen if no
280 switch -exact $args {
282 puts "Usage: jul changes \[options\] repository"
283 puts "Shows the changelog of repository.\n"
284 puts "Changes command options:"
285 puts " -h display this help and exit"
288 puts "Usage: jul clean \[options\]"
289 puts "Removes ~/.jul and all of its content.\n"
290 puts "Clean command options:"
291 puts " -h display this help and exit"
292 puts " -y skip (y/N) prompt"
295 puts "jul: help: $args no such command."
302 # Lists the installed packages.
303 proc listpkgs
{pattern
} {
304 foreach item
[getplist
] {
305 if {$pattern != ""} {
306 if {[string match
"*$pattern*" $item] == 1} {
315 # Return a sorted list of all installed packages.
318 foreach file [glob -nocomplain -directory \
319 "/var/db/pkg" -tails -types f
*] {
325 proc printColumnarLines
{lines
} {
326 foreach fields
$lines {
328 foreach field
$fields {
329 set w
[string length
$field]
330 if {![info exist width
($col)] ||
$width($col) < $w} {
337 foreach fields
$lines {
339 foreach field
$fields {
340 puts -nonewline [format "%-*s " $width($col) $field]
347 # Search for packages.
349 # receive a list of all the packages
350 set pkg_list
[list_repo
[lindex $args 0]]
352 # if the number of elements in $pkg_list is 0, put an error and return
353 if {[llength $pkg_list] == 0} {
354 puts "jul: search: No packages found."
359 foreach key
$pkg_list {
361 lappend lines
[list $p(repo
) \
362 $p(name
)-$p(version
)-$p(arch
)-$p(build
) $p(desc
)]
365 printColumnarLines
$lines
369 # fill finds with all available packages
370 array set finds
[list_repo
[lindex "" 0]]
372 for {set x
0} {$x < [array size finds
]} {incr x
} {
373 set s
[split_pkg
[lindex $finds($x) 0]]
378 # Split the package string 'p' into a list and return it.
380 # remove the trailing '.tlz'
381 set p
[string trimright
$p ".tlz"]
383 # split 'p' at every '-' found
384 set psplit
[split $p -]
386 if {[llength $psplit] > 4} {
387 # number of dashes in the package name part
388 set dashes
[expr {[llength $psplit] - 4}]
390 # the new package name, with dashes
391 set newname
[join [lrange $psplit 0 $dashes] -]
393 # replace the elements for the 'package name' with 'newname'
394 set psplit
[lreplace $psplit 0 $dashes $newname]
404 # Get and verify files.
408 puts -nonewline "Downloading [get_db_file $repo]... "
409 getfile
[lindex $repolist($repo) 2][get_db_file
$repo]
410 puts -nonewline "Downloading checksum... "
411 getfile
[lindex $repolist($repo) 2][get_db_file
$repo].sha1sum
412 puts -nonewline "Verifying... "
413 if {[verify_file
$repo.db.sha1sum
] == -1} {
423 if {[file exists
$::env(HOME
)/.jul
/cache
] == 0} {
424 file mkdir
$::env(HOME
)/.jul
/cache
427 cd "$::env(HOME)/.jul"
429 # loop through all repositories
430 foreach repo
[lreverse
[array names repolist
]] {
431 set rpo
[get_db_file
$repo]
433 # synchronise if there is no database
434 if {[file isfile
$rpo] == 0} {
437 # read the local and remote version
438 # TODO: only reads first line
439 set f
[open $::env(HOME
)/.jul
/$rpo.sha1sum
]
443 set rver_file
[lindex $repolist($repo) 2]$rpo.sha1sum
444 if {[catch {set rver
[exec curl
-sf $rver_file]} results
options]} {
445 set details
[dict get
$options -errorcode]
447 puts "Trying to download $rver_file"
448 puts -nonewline "Could not download file: "
450 if {[lindex $details 0] eq
"CHILDSTATUS"} {
451 set status
[lindex $details 2]
453 puts "HTTP error code > 400"
454 puts "The file was probably not found."
455 puts "Please report this!"
456 } elseif
{$status == 23} {
457 puts "Write error in $::env(PWD)"
460 puts "Unknown error. Please report this!"
466 # if the local and remote versions are the same, verify
468 if {$lver == $rver} {
469 puts "$repo is up to date"
470 puts -nonewline "Verifying... "
472 # synchronise if the verification fails
473 if {[verify_file
$repo.db.sha1sum
] == -1} {
486 puts "Usage: jul <command> \[options] \[package|keyword|command]"
488 puts " changes lists recent changes in the repositories"
489 puts " clean removes ~/.jul and all of its content"
490 puts " help display information for a command or this screen"
491 puts " add/install fetch and install packages from repositories"
492 puts " list list installed or downloaded packages"
493 puts " search search repositories for packages"
494 puts " sync synchronise with repositories"
495 puts " upgrade fetch and upgrade packages from repositories"
496 puts " version show version of this program"
500 switch -exact [lindex $::argv 0] {
501 add
{add add
[lindex $::argv 1]}
502 changes
{changes
[lindex $::argv 1]}
503 clean
{clean
[lindex $::argv 1]}
504 help
{help
[lindex $::argv 1]}
505 install
{add add
[lindex $::argv 1]}
506 "list" {listpkgs
[lindex $::argv 1]}
507 search
{search
[lindex $::argv 1]}
510 upgrade
{add upgrade
[lindex $::argv 1]}
511 version
{puts "This is jul version $version"}
512 default {puts "jul: [lindex $::argv 0]: No such command."}