Hidden flag default values - go

Go provides easy CLI switches aka flags.
var debug = flag.Bool("debug", false, "enable debugging")
var hostname = flag.String("hostname", "127.0.0.1", "hostname")
flag.Parse()
As expected this yields
> ./program -h
Usage:
-debug
enable debugging
-hostname string
hostname (default "127.0.0.1")
I would like to hide the (default "127.0.0.1") part of specific flags.
Searching on SO and around suggested use of flag.FlagSet.
var shown flag.FlagSet
var hidden flag.FlagSet
var debug = shown.Bool("debug", false, "enable debugging")
var hostname = hidden.String("hostname", "127.0.0.1", "hostname")
flag.Usage = func() {
shown.PrintDefaults()
}
flag.Parse()
//shown.Parse(os.Args[0:]) // tried to solve "flag provided but not defined"
Output part shows only "debug" flag, however this breaks actual flag usage.
> ./program -debug
flag provided but not defined: -debug
Usage of ./program:
-debug
enable debugging
And this is not ideal either, since I would like to see the available flag, just hide the default value.
Desired output:
> ./program -h
Usage:
-debug
enable debugging
-hostname string
hostname

Best solution so far is the one Eugene proposed. Thanks!
var debug = flag.Bool("debug", false, "enable debugging")
var hostname = flag.String("hostname", "", "hostname")
flag.Parse()
defaultHostname := "127.0.0.1"
if *hostname == "" {
*hostname = defaultHostname
}

You can just copy & paste the codes from the source and remove the print default part.
flag.Usage = func() {
f := flag.CommandLine
_, _ = fmt.Fprintf(f.Output(), "Usage of %s:\n", os.Args[0])
flag.VisitAll(func(flag_ *flag.Flag) {
if flag_.Usage == "" {
return
}
s := fmt.Sprintf(" -%s", flag_.Name) // Two spaces before -; see next two comments.
name, usage := flag.UnquoteUsage(flag_)
if len(name) > 0 {
s += " " + name
}
// Boolean flags of one ASCII letter are so common we
// treat them specially, putting their usage on the same line.
if len(s) <= 4 { // space, space, '-', 'x'.
s += "\t"
} else {
// Four spaces before the tab triggers good alignment
// for both 4- and 8-space tab stops.
s += "\n \t"
}
s += strings.ReplaceAll(usage, "\n", "\n \t")
_, _ = fmt.Fprint(f.Output(), s, "\n")
})
}
flag.Parse()

Related

Why `#f::true ? MsgBox true : Run notepad` does nothing?

I expect #f::true ? MsgBox true : Run notepad will open a message box with "true" when pressing #f, but it does nothing in practice, can anyone explain the mechanism behind this behavior?
Commands only work at the start of a line, you can't use them inline.
What you're doing, is concatenating two variables together. A variable named MsgBox and a variable named true (or Run and notepad).
You can only use expressions inline.
In AHK v1, you could, of course wrap the legacy commands in a function and then use that function inline:
#f::true ? MsgBoxFunc(true) : RunFunc("notepad")
MsgBoxFunc(Options := "", Title := "", Text := "", Timeout := "")
{
if (Options && (!Title && !Text && !Timeout))
MsgBox, % Options
else
MsgBox, % Options, % Title, % Text, % Timeout
}
RunFunc(Target, WorkingDir := "", Options := "", ByRef OutputVarPID := "")
{
Run, % Target, % WorkingDir, % Options, pid
OutputVarPID := pid
}
Or in AHK v2, this problem of course doesn't exist:
#f::true ? MsgBox(true) : Run("notepad")

std::process::Command cannot run hdiutil on macOS (mount failed - No such file or directory) but the command works fine when run in the terminal

hdiutils, when fed a correct path to a valid file, returns error 2, no such file or directory. When I join the indices of the command array with " ", print them, copy them and run the exact string in a terminal, it works fine.
This is the function edited to contain only the relevant bits. In order to reproduce my error, you will need a disk image located at ~/Downloads/StarUML.dmg.
use std::env;
use std::fs;
use std::process::Command;
fn setup_downloads(download_name: &str) {
let downloads_path: String = {
if cfg!(unix) {
//these both yield options to unwrap
let path = env::home_dir().unwrap();
let mut downloads_path = path.to_str().unwrap().to_owned();
downloads_path += "/Downloads/";
downloads_path
} else {
"we currently only support Mac OS".to_string()
}
};
let files_in_downloads =
fs::read_dir(&downloads_path).expect("the read_dir that sets files_in_downloads broke");
let mut file_path: String = "None".to_string();
for file_name in files_in_downloads {
let file_name: String = file_name
.expect("the pre string result which sets file_name has broken")
.file_name()
.into_string()
.expect("the post string result which sets file_name has broken")
.to_owned();
if file_name.contains(&download_name) {
file_path = format!("'{}{}'", &downloads_path, &file_name);
}
}
let len = file_path.len();
if file_path[len - 4..len - 1] == "dmg".to_string() {
let mount_command = ["hdiutil", "mount"];
let output = Command::new(&mount_command[0])
.arg(&mount_command[1])
.arg(&file_path)
.output()
.expect("failed to execute mount cmd");
if output.status.success() {
println!(
"command successful, returns: {}",
String::from_utf8_lossy(&output.stderr).into_owned()
);
} else {
println!(
"command failed, returns: {}",
String::from_utf8_lossy(&output.stderr).into_owned()
);
}
}
}
fn main() {
setup_downloads(&"StarUML".to_string());
}
Split your Command into a variable and print it using the debugging formatter after you have specified the arguments:
let mut c = Command::new(&mount_command[0]);
c
.arg(&mount_command[1])
.arg(&file_path);
println!("{:?}", c);
This outputs
"hdiutil" "mount" "\'/Users/shep/Downloads/StarUML.dmg\'"
Note that Command automatically provides quoting for each argument, but you have added your own set of single quotes:
format!("'{}{}'", &downloads_path, &file_name);
// ^ ^
Remove these single quotes.

socketio ip: why is ipfix variable / username not changing

io.on('connection', function(socket){
var ip = socket.request.connection.remoteAddress;
var ipfix = ip; // made a copy of ip cause thought it may be a constant
for (var g = 0; g < ipfix.length; g++)
{
if (ipfix[g] == 'f' || ipfix[g] == ':')
{
ipfix[g] = '';
console.log("changed to nothing"); // logs to console
}
if (ipfix[g] == '.')
{
ipfix[g] = '0';
console.log("changed to zero"); // logs to console
}
}
var username = 'User#' + ipfix[9] + ipfix[8] + ipfix[11] + ipfix[13];
console.log(username); // Logs, no change to dots / f / :
}
The purpose of this is to remove dots, colons, and 'f' from ip
To me this seems perfectly reasonable, but everytime i've run it, it prints out username with no change to the values seen in IP, even though IP was copied into ipfix and iterated through.
I found a fix, unlike C, javascript strings are immutable - a solution is to use ipfix = ip.split(''); <-- turns into an array of characters.

golang flag hidden options from print defaults

this is my actual code :
package main
import (
"flag"
)
var loadList = ""
var threads = 50
var skip = 0
func main() {
//defaults variables
flag.StringVar(&loadList, "f", "", "load links list file (required)")
flag.IntVar(&threads,"t", 50, "run `N` attempts in parallel threads")
flag.IntVar(&skip, "l", 0, "skip first `n` lines of input")
flag.Parse()
flag.PrintDefaults()
}
and this is output :
-f string
load links list file (required)
-l n
skip first n lines of input
-t N
run N attempts in parallel threads (default 50)
i want hide from printdefaults -l and -t, how i can do this ?
There might be multiple ways of doing this. An easy one would be to use VisitAll:
func VisitAll(fn func(*Flag))
In the function you pass you can decide whether or not to output a flag based on any of the exported fields of Flag.
Example:
flag.VisitAll(func(f *flag.Flag) {
if f.Name == "l" || f.Name == "t" {
return
}
fmt.Println("Flag: ", f)
})
Run it at: https://play.golang.org/p/rsrKgWeAQf

Parsing file, ignoring comments and blank lines

As the title says, I am trying to parse a file but ignore comments (started with #) or blank lines. I have tried to make a system for this, yet it always seems to ignore that it should be ignoring comments and/or blank lines.
lines := strings.Split(d, "\n")
var output map[string]bool = make(map[string]bool)
for _, line := range lines {
if strings.HasPrefix(line, "#") != true {
output[line] = true
} else if len(line) > 0 {
output[line] = true
}
}
When run (this is part of a function), it outputs the following
This is the input ('d' variable):
Minecraft
Zerg Rush
Pokemon
# Hello
This is the output when printed ('output' variable):
map[Minecraft:true Zerg Rush:true Pokemon:true :true # Hello:true]
My issue here is that it still keeps the "" and "# Hello" values, meaning that something failed, something I haven't been able to figure out.
So, what am I doing wrong that this keeps the improper values?
len(line) > 0 will be true for the "# Hello" line, so it will get added to output.
Currently, you are adding lines that either don't start with a # or are not empty. You need to only add lines that satisfy both conditions:
if !strings.HasPrefix(line, "#") && len(line) > 0 {
output[line] = true
}

Resources