first version of the util
This commit is contained in:
commit
0db8655af4
8 changed files with 358 additions and 0 deletions
8
.editorconfig
Normal file
8
.editorconfig
Normal file
|
@ -0,0 +1,8 @@
|
|||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.v]
|
||||
indent_style = tab
|
8
.gitattributes
vendored
Normal file
8
.gitattributes
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
* text=auto eol=lf
|
||||
*.bat eol=crlf
|
||||
|
||||
*.v linguist-language=V
|
||||
*.vv linguist-language=V
|
||||
*.vsh linguist-language=V
|
||||
v.mod linguist-language=V
|
||||
.vdocignore linguist-language=ignore
|
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Binaries for programs and plugins
|
||||
main
|
||||
setup-browser
|
||||
*.exe
|
||||
*.exe~
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Ignore binary output folders
|
||||
bin/
|
||||
|
||||
# Ignore common editor/system specific metadata
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/
|
||||
*.iml
|
||||
|
||||
# ENV
|
||||
.env
|
||||
|
||||
# vweb and database
|
||||
*.db
|
||||
*.js
|
||||
cache
|
36
src/cache.v
Normal file
36
src/cache.v
Normal file
|
@ -0,0 +1,36 @@
|
|||
module main
|
||||
|
||||
import log
|
||||
import os
|
||||
|
||||
@[noinit]
|
||||
struct Cache {
|
||||
base_path string
|
||||
}
|
||||
|
||||
fn Cache.new(base_path string) !Cache {
|
||||
log.info('using cache dir: ${base_path}')
|
||||
os.mkdir_all(base_path) or { return error('failed to create cache directory ${base_path}') }
|
||||
|
||||
return Cache{
|
||||
base_path: base_path
|
||||
}
|
||||
}
|
||||
|
||||
fn Cache.default() !Cache {
|
||||
base_path := os.getenv_opt('XDG_CACHE_HOME') or { os.getenv('HOME') + '.cache' }
|
||||
cache_dir := os.join_path(base_path, 'setup-browser')
|
||||
return Cache.new(cache_dir)
|
||||
}
|
||||
|
||||
fn (c Cache) path(name ...string) !string {
|
||||
dir := os.join_path(c.base_path, ...name)
|
||||
os.mkdir_all(dir) or { return error('failed to create directory ${dir}') }
|
||||
return dir
|
||||
}
|
||||
|
||||
fn (c Cache) file(name ...string) !string {
|
||||
file := os.join_path(c.base_path, ...name)
|
||||
os.mkdir_all(os.dir(file)) or { return error('failed to create directory ${os.dir(file)}') }
|
||||
return file
|
||||
}
|
90
src/install.v
Normal file
90
src/install.v
Normal file
|
@ -0,0 +1,90 @@
|
|||
module main
|
||||
|
||||
import cli
|
||||
import log
|
||||
import os
|
||||
|
||||
const install_command = cli.Command{
|
||||
name: 'install'
|
||||
description: 'Installs a browser'
|
||||
execute: execute_install
|
||||
required_args: 1
|
||||
flags: [
|
||||
cli.Flag{
|
||||
flag: .bool
|
||||
name: 'verbose'
|
||||
abbrev: 'v'
|
||||
description: 'Enable debug logging'
|
||||
},
|
||||
cli.Flag{
|
||||
flag: .string
|
||||
name: 'cache-path'
|
||||
abbrev: 'c'
|
||||
description: 'Path to cache directory'
|
||||
},
|
||||
cli.Flag{
|
||||
flag: .string
|
||||
name: 'install-to'
|
||||
abbrev: 'i'
|
||||
description: 'Path to which the binary is linked'
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn execute_install(cmd cli.Command) ! {
|
||||
if cmd.flags.get_bool('debug') or { false } {
|
||||
log.set_level(.debug)
|
||||
}
|
||||
|
||||
browser, version := parse_target(cmd.args[0]) or {
|
||||
return error('failed to parse target: ${err}')
|
||||
}
|
||||
|
||||
cache_path := cmd.flags.get_string('cache-path') or { '' }
|
||||
cache := match cache_path {
|
||||
'' { Cache.default() or { return error('failed to create default cache: ${err}') } }
|
||||
else { Cache.new(cache_path) or { return error('failed to create cache: ${err}') } }
|
||||
}
|
||||
|
||||
install_path := cmd.flags.get_string('install-to') or { '' }
|
||||
install_to := match install_path {
|
||||
'' {
|
||||
cache.file('bin', 'uchromium') or {
|
||||
return error('failed to create default install dir: ${err}')
|
||||
}
|
||||
}
|
||||
else {
|
||||
install_dir := os.dir(install_path)
|
||||
os.mkdir_all(install_dir) or {
|
||||
return error('failed to create install dir ${install_dir}: ${err}')
|
||||
}
|
||||
install_path
|
||||
}
|
||||
}
|
||||
|
||||
log.info('using install path: ${install_path}')
|
||||
|
||||
prov := Provider.for_browser(browser, cache) or {
|
||||
return error('failed to get provider: ${err}')
|
||||
}
|
||||
|
||||
return prov.install(version, install_to)
|
||||
}
|
||||
|
||||
enum BrowserType {
|
||||
uchromium
|
||||
}
|
||||
|
||||
fn parse_target(target string) !(BrowserType, string) {
|
||||
parts := target.split_n(':', 2)
|
||||
|
||||
name, version := match parts.len {
|
||||
1 { parts[0], 'latest' }
|
||||
2 { parts[0], parts[1] }
|
||||
else { return error('unexpected target ${target}') }
|
||||
}
|
||||
|
||||
browser := BrowserType.from(name) or { return error('unexpected browser name ${name}') }
|
||||
|
||||
return browser, version
|
||||
}
|
28
src/main.v
Normal file
28
src/main.v
Normal file
|
@ -0,0 +1,28 @@
|
|||
module main
|
||||
|
||||
import cli
|
||||
import os
|
||||
|
||||
fn main() {
|
||||
mut app := cli.Command{
|
||||
name: 'setup-browser'
|
||||
description: 'Set-up browsers from various sources'
|
||||
version: '0.0.1'
|
||||
defaults: struct {
|
||||
man: false
|
||||
help: true
|
||||
version: true
|
||||
}
|
||||
}
|
||||
|
||||
app.execute = fn [app] (cmd cli.Command) ! {
|
||||
println(app.help_message())
|
||||
// cli.print_help_for_command(cmd) or { eprintln('failed to print help for command') }
|
||||
return
|
||||
}
|
||||
|
||||
app.add_command(install_command)
|
||||
|
||||
app.setup()
|
||||
app.parse(os.args)
|
||||
}
|
156
src/uchromium.v
Normal file
156
src/uchromium.v
Normal file
|
@ -0,0 +1,156 @@
|
|||
module main
|
||||
|
||||
import net.http
|
||||
import log
|
||||
import os
|
||||
import math
|
||||
|
||||
interface Provider {
|
||||
install(version string, install_to string) !
|
||||
}
|
||||
|
||||
fn Provider.for_browser(browser_type BrowserType, cache Cache) !Provider {
|
||||
return match browser_type {
|
||||
.uchromium { Provider(UChromium.new(cache)!) }
|
||||
}
|
||||
}
|
||||
|
||||
const uchromium_repo = 'https://github.com/ungoogled-software/ungoogled-chromium-binaries.git'
|
||||
|
||||
struct UChromiumVersion {
|
||||
url string
|
||||
md5 string
|
||||
sha1 string
|
||||
sha256 string
|
||||
}
|
||||
|
||||
fn UChromiumVersion.from_file(file string) !UChromiumVersion {
|
||||
lines := os.read_lines(file) or { return error('failed to read file ${file}: ${err}') }
|
||||
mut data := map[string]string{}
|
||||
|
||||
for line in lines {
|
||||
parts := line.split_any(' =').filter(it != '')
|
||||
if parts.len != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
data[parts[0]] = parts[1] or { '' }
|
||||
}
|
||||
|
||||
log.debug('data: ${data}')
|
||||
|
||||
return UChromiumVersion{
|
||||
url: data['url']
|
||||
md5: data['md5']
|
||||
sha1: data['sha1']
|
||||
sha256: data['sha256']
|
||||
}
|
||||
}
|
||||
|
||||
@[noinit]
|
||||
struct UChromium {
|
||||
cache Cache
|
||||
}
|
||||
|
||||
fn UChromium.new(cache Cache) !UChromium {
|
||||
return UChromium{
|
||||
cache: cache
|
||||
}
|
||||
}
|
||||
|
||||
fn (u UChromium) repo_path() !string {
|
||||
return u.cache.path('uchromium-repo')
|
||||
}
|
||||
|
||||
fn (u UChromium) set_repo() ! {
|
||||
repo_path := u.repo_path()!
|
||||
cmd := match os.is_dir(repo_path) {
|
||||
false {
|
||||
log.info('cloning ${uchromium_repo} to ${repo_path}')
|
||||
'git clone ${uchromium_repo} ${repo_path}'
|
||||
}
|
||||
true {
|
||||
log.info('updating ${repo_path}')
|
||||
'git -C ${repo_path} pull'
|
||||
}
|
||||
}
|
||||
|
||||
os.execute_opt(cmd) or {
|
||||
return error('failed to sync ${uchromium_repo} to ${repo_path}: ${err}')
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fn (u UChromium) find_version(version string) !UChromiumVersion {
|
||||
base_dir := os.join_path(u.repo_path()!, 'config', 'platforms', 'appimage', '64bit')
|
||||
log.debug('base_dir: ${base_dir}')
|
||||
|
||||
mut versions := os.glob(base_dir + '/*.ini') or {
|
||||
return error('failed to list versions: ${err}')
|
||||
}
|
||||
log.debug('versions: ${versions}')
|
||||
|
||||
versions.sort_with_compare(fn (a &string, b &string) int {
|
||||
a_parts := a.split_any('.-/')
|
||||
b_parts := b.split_any('.-/')
|
||||
|
||||
for i in 0 .. math.min(a_parts.len, b_parts.len) {
|
||||
return if a_parts[i].int() < b_parts[i].int() {
|
||||
-1
|
||||
} else if a_parts[i].int() > b_parts[i].int() {
|
||||
1
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
})
|
||||
|
||||
log.debug('sorted versions: ${versions}')
|
||||
|
||||
version_file := match version {
|
||||
'latest' {
|
||||
versions.last()
|
||||
}
|
||||
else {
|
||||
cand := os.join_path(base_dir, '${version}.ini')
|
||||
if cand in versions {
|
||||
cand
|
||||
} else {
|
||||
return error('version not found: ${version}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UChromiumVersion.from_file(version_file)
|
||||
}
|
||||
|
||||
fn (u UChromium) download(version UChromiumVersion) !string {
|
||||
dest := u.cache.file('dl', os.base(version.url))!
|
||||
log.info('downloading ${version.url} to ${dest}')
|
||||
|
||||
if os.is_file(dest) {
|
||||
log.info('file already exists')
|
||||
return dest
|
||||
}
|
||||
|
||||
http.download_file(version.url, dest) or {
|
||||
return error('failed to download ${version.url}: ${err}')
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
fn (u UChromium) install(version string, install_to string) ! {
|
||||
u.set_repo()!
|
||||
v := u.find_version(version)!
|
||||
log.info('version ${version} found')
|
||||
dest := u.download(v)!
|
||||
os.chmod(dest, 0o777)!
|
||||
os.rm(install_to) or {}
|
||||
os.cp(dest, install_to)!
|
||||
|
||||
return
|
||||
}
|
7
v.mod
Normal file
7
v.mod
Normal file
|
@ -0,0 +1,7 @@
|
|||
Module {
|
||||
name: 'setup-browser'
|
||||
description: 'Utility to install browsers'
|
||||
version: '0.0.0'
|
||||
license: 'MIT'
|
||||
dependencies: []
|
||||
}
|
Loading…
Reference in a new issue