OAuth 2.0 inconsistent errors when using BigQuery commandline tool - c#

I'm using BigQuery's command-line tool to load data into BigQuery.
I'm running the bq tool through a C# program using the following method:
private void RunShellCmd(string cmd, string args)
{
ProcessStartInfo start = new ProcessStartInfo
{
FileName = cmd,
Arguments = args,
UseShellExecute = false,
RedirectStandardOutput = true
};
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
if (OnMessage != null)
{
OnMessage(result);
}
}
}
}
Where cmd is the path for the bq script tool and args are:
load --nosync --credential_file=_CRED_PATH_ --source_format=NEWLINE_DELIMITED_JSON --project_id=_PROJECT_ID_ _TABLE_URI_ _DATA_FILE_
When performing the exact command from shell, it works perfectly.
However, through the C# program, I'm getting the following output:
Welcome to BigQuery! This script will walk you through the process of initializing your .bigqueryrc configuration file.
First, we need to set up your credentials if they do not already exist.
******************************************************************
** No OAuth2 credentials found, beginning authorization process **
******************************************************************
Go to the following link in your browser:
https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fbigquery&redirect_uri=...
Enter verification code: You have encountered a bug in the BigQuery CLI. Google engineers monitor and answer questions on Stack Overflow, with the tag google-bigquery: http://stackoverflow.com/questions/ask?tags=google-bigquery Please include a brief description of the steps that led to this issue, as well as the following information:
========================================
== Platform == CPython:2.7.5:Windows-2008ServerR2-6.1.7601-SP1
== bq version == v2.0.16
== Command line == ['C:\\Python27\\Scripts\\bq-script.py', 'load', '--nosync', '--credential_file=C:\\Users\\Administrator\\.bigquery.v2.token', '--source_format=NEWLINE_DELIMITED_JSON', '--project_id=_PROJECT_ID_',
>'_TABLE_URI_', '_DATA_FILE_PATH_']
== UTC timestamp == 2013-10-20 05:52:59
== Error trace == File "build\bdist.win32\egg\bq.py", line 783, in RunSafely
return_value = self.RunWithArgs(*args, **kwds) File "build\bdist.win32\egg\bq.py", line 2082, in RunWithArgs
client = Client.Get() File "build\bdist.win32\egg\bq.py", line 604, in Get
cls.client = Client.Create() File "build\bdist.win32\egg\bq.py", line 584, in Create
credentials = _GetCredentialsFromFlags() File "build\bdist.win32\egg\bq.py", line 390, in _GetCredentialsFromFlags
credentials = credentials_getter(storage) File "build\bdist.win32\egg\bq.py", line 330, in
_GetCredentialsFromOAuthFlow
credentials = oauth2client.tools.run(flow, storage) File "build\bdist.win32\egg\oauth2client\util.py", line 132, in positional_wrapper
return wrapped(*args, **kwargs) File "build\bdist.win32\egg\oauth2client\old_run.py", line 149, in run
code = raw_input('Enter verification code: ').strip()
========================================
Unexpected exception in init operation: EOF when reading a line
Successfully started load _TABLE_URI_
The odd thing is that the command actually works and loads the data correctly (As also proven by the final output line).
But for some reason, it is preceded by an OAUTH 2.0 error.
Has anyone encountered something like this before?
Any idea what might cause it?
Thanks!

Why are you calling the bq.py tool from c# rather than using the C# client?
The c# client is available here:
https://developers.google.com/api-client-library/dotnet/apis/#BigQuery_API
and the ndocs are here:
https://developers.google.com/resources/api-libraries/documentation/bigquery/v2/csharp/latest/annotated.html
If you don't want to / can't use the C# client, my guess as to what is happening is that bq is having trouble writing out a credential file (or reading a credential file). Possibly this is due to a windows path issue ('/' vs '\') or possibly the path it tries to write to or read-from is inaccessible. (or possibly the path it writes to doesn't match the path it tries to read from the next time).

Related

C# git command line process

Our organization utilizes VisualStudioOnline, GitHub and BitBucket for various repositories. I've been trying to figure out a way in c# to automate the pull of changes from various git repositories on a regular schedule. I've tried starting a process like this and then redirecting the standard input/output.
var p = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\Program Files (x86)\Git\bin\sh.exe",
RedirectStandardInput = true,
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = "--login -i"
}
};
p.Start();
using (var so = p.StandardOutput)
{
using (var si = p.StandardInput)
{
if (si.BaseStream.CanWrite)
{
...
}
}
}
Inside of the block, I'm able to execute git commands like this:
si.WriteLine("cd \"P:/code/testapp\""); which navigates the git
shell to that directory
si.WriteLine("git rev-parse HEAD");
which will give me the latest hash of the repository at that location.
I can see the hash returned in the bash shell and can also read it in through the standard input like this var hash = so.ReadLine();
When I try to do si.WriteLint("git pull"); though, it asks for username and password, which I would expect, but that isn't done through the standard input/output. I can't us var prompt = so.ReadLine(); to get the prompt for username or password and I can't use si.WriteLine("username"); to input my password to the prompt.
I've tried a number of things to get this to work, but so far no luck.
WARNING: messy code ahead, just tried to quickly prototype something, not create a masterpiece
Attempt 1: used standard input/output redirects as shown above to try to write/read the prompts for username/password.
Attempt 2: attempt to get the ssh-agent process that is being utilized by the git bash and write to it
si.WriteLine("ssh-agent --help");
var sshAgentInfo = string.Empty;
var tmp = a.ReadLine();
while (a.Peek() != -1)
{
sshAgentInfo += tmp;
tmp = a.ReadLine();
}
var begPos = sshAgentInfo.IndexOf("SSH_AGENT_PID=", StringComparison.Ordinal);
begPos = begPos + "SSH_AGENT_PID=".Length;
var endPos = sshAgentInfo.IndexOf(";", begPos, StringComparison.Ordinal);
var processId = int.Parse(sshAgentInfo.Substring(begPos, endPos - begPos));
var sshProcess = Process.GetProcessById(processId);
sshProcess.StartInfo.RedirectStandardInput = true;
sshProcess.StartInfo.RedirectStandardInput = true;
using (var si1 = sshProcess.StandardInput) { ... }
Attempt 3: Utilize credential git config credential.helper wincred
This and four were very similar attempts. Again just trying to figure out how to set the password in either of these credential managers from the command line.
Attempt 4: Utilize Git-Credential-Manager-for-Windows
I've tried looking through the documentation here and it seems as though there is an enhancement request to do something along these lines.
Both of these seem to have similar problems to attempt one. The git shell seems to be invoking another process which handles the standard input and output separate from the git shell. The difference and hope I have for these last two though is, Is there a way to call into those credential managers directly to set username/passwords for different urls? In the .git directory, the config file has the credentials setting to tell it which manager to use and it stores the username and email in plain text.
If I invoke a git pull through the shell on the machine and enter my credentials once through that shell it seems to store them, but is there a way to allow users to enter their credentials through a website and then call into the manager through the command line to securely store that information for future automated use?
I also came across this. I haven't had a chance to try it yet, but is this a viable option for doing something like this?
Any help would be greatly appreciated.

Process.Start leaves streams empty

I have the code to run a console command/utility, monitor the live output using 'Debug.WriteLine' and write the final output to a log file when needed.
Edit: It does not work for Praatcon.exe an analysis command line utility. It can be downloaded from here . Just invoke praatcon.exe without argument, it should write on 'stdout' about the Usage. The code wont catch it.
The issue is, it works good for certain utilities and I can see the debug output as well as log in the file. But for certain utilities, I see empty commands, even though when I run those commands through a CMD window, I see the output. I am capturing both the streams Output and Error.
Can someone help me with this ?
Full code can be found here
Here is how I am trying to do it
Initialization of ProcessStartInfo
var info = new ProcessStartInfo(command, parameters)
{
WorkingDirectory = workingDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
Running the process and initializing the string builders for output and error streams.
var process = Process.Start(info);
var output = new StringBuilder();
var error = new StringBuilder();
Starting the tasks for Reading Streams
var errorTask = process.StandardError.ReadLineAsync();
var lineTask = process.StandardOutput.ReadLineAsync();
Here is my while loop to monitor the progress and write output to the Debug Output window when there is any available.
while (process.HasExited == false)
{
if (lineTask.IsCompleted)
{
output.AppendLine(lineTask.Result);
Debug.WriteLine(lineTask.Result);
lineTask = process.StandardOutput.ReadLineAsync();
}
if (errorTask.IsCompleted)
{
error.AppendLine(errorTask.Result);
Debug.WriteLine(errorTask.Result);
errorTask = process.StandardError.ReadLineAsync();
}
errorTask.Wait(TimeSpan.FromMilliseconds(100.0));
lineTask.Wait(TimeSpan.FromMilliseconds(100.0));
}
After this, I am reading the streams further to see if there is anything left in there.
I get empty strings in output and error for one command. The only thing I get correct is the 'ExitCode'.
Please tell me if there is anything I am doing the wrong way.
As discussed on IRC, there was a possibility that the program you're calling may have been writing to a stream other than standard out or standard error. There are also streams with numbers 3-9 on Windows.
This was not the case with the process you were calling. It was actually using the Win32 call 'WriteConsole', which seems to access the console directly.
It would be possible to move the output back to stderr by preloading a DLL (DLL injection) but this is hackish, so as the source of the program is available, it's perhaps better to 'fix' it or submit a patch to the authors.
Your question is borderline too broad, in that it's missing details, and "anything I am doing the wrong way" is fairly open-ended.
That said, you are doing the reading of the streams the wrong way, in the sense that you should not be polling. I don't see any specific reason that would cause the behavior you've (vaguely) described. But just in case, I offer this correct implementation of the reading:
async Task ConsumeStream(StreamReader reader, StringBuilder builder)
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
builder.AppendLine(line);
Debug.WriteLine(line);
}
}
Then call that method like this:
var errorTask = ConsumeStream(process.StandardError, error);
var lineTask = ConsumeStream(process.StandardOutput, output);
// Technically superfluous, since you'll also wait on the tasks,
// but won't hurt.
process.WaitForExit();
Task.WaitAll(errorTask, lineTask);
// error and output StringBuilders will be valid here
If that doesn't help, you'll need to post a better code example, which will allow others to reproduce the actual problem. See https://stackoverflow.com/help/mcve

Compile in C using a Windows Forms Application

I'm creating a compiler App in C#, using Visual Studio 2010.
The goal of this program is to compile a code written in either C# or C at runtime and return the results of the compilation.
I have done the C# part, but the C part is the one I have problems. For this one, I've tried to use the Visual Studio Command Prompt. The way I'm coding this part is like this:
Create a .c file in C:\ using File.Create.
Using a Process, open the Visual Studio Command Prompt and execute the compilation.
Capture the output to return it as the compilation results.
However, it doesn't work. It throws and Win32 exception, but I don't really know why.
I've heard something about using gcc. But I thought about using the Visual Studio Command Prompt as a possible solution.
EDIT: I figured out the steps to do it (I think). But the Win32 exception appears when the program tries to do the process.Start() line. I guess this might be a permissions problem, but I don't really know.
A friend of mine worked on something similar, and helped me to solve this problem.
On steps 2 and 3, I was trying to write the input and read the output using simply the process standard input and output, and also, I was trying to use an .lnk to run the Command Prompt. All those things caused the error.
The solution was:
Create two batch files, one to start up the Command Prompt and the other to compile the .c file (those were created outside the program's code).
(On runtime) Create the .c file, using the code written. If file exists, delete it and create a new one.
Start the process with cmd.exe.
Run the batch files, using a Stream Writer to write them in the cmd.exe.
Retrieve the output using a Stream Reader.
Fortunately, this worked! Code ended like this:
string CompileC (string code)
{
string path = #"C:\sample.c";
string results = "";
try
{
if (File.Exists(path))
File.Delete(path);
using (FileStream fs = File.Create(path))
{
byte[] codeText = new UTF8Encoding(true).GetBytes(code);
fs.Write(codeText, 0, codeText.Length);
}
Process process = new Process();
process.StartInfo.FileName = #"C:\Windows\system32\cmd.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
using (StreamWriter sw = process.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
//This batch starts up the Visual Studio Command Prompt.
sw.WriteLine(#"C:\Startup.bat");
//This batch does the compilation, once the Command Prompt
//is running, using the 'cl' command.
sw.WriteLine(#"C:\Compile.bat");
}
}
using (StreamReader sr = process.StandardOutput)
{
if (sr.BaseStream.CanRead)
results = sr.ReadToEnd();
}
}
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
return results;
}

Microsoft Diagnostics Runtime crash.dmp analysis (C#)

I'm trying to read in a crash.dmp using the functionality in Microsoft.Diagnostics.Runtime .NET componenet (also known as ClrMD).
I have a crash.dmp in a known location (in a string called pathToFile) so that's not the issue. The rest of the code looks like this.
DataTarget dataTarget = DataTarget.LoadCrashDump(pathToFile);
ClrInfo clrInfo = dataTarget.ClrVersions[0];
string dacLocation = clrInfo.TryGetDacLocation();
When testing this code, I get the following error in the command window:
Error processing directory: System.ArgumentOutOfRangeException. Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index.
I'm assuming it's something to do with the ClrVersions[0] bit but can't for the life of me pin it down.
Any help would be appreciated.
Current Status
When running the following command (which fails)
ClrRuntime rt = dataTarget.CreateRuntime("path\to\mscordawks.dll");
I receive the following error in cmd
mismatched architecture between this process and the dac
Cheers
Anyone?
If the TryGetDacLocation succeeded then you should be able to do
ClrRuntime rt = dataTarget.CreateRuntime(dacLocation);
so you get the correct dacLocation.
Was the dump you are analysing generated on same machine where you are analysing it?
Also what are the bitnesses of the process the dump was generated from, the process in which the CLRMD code is running and the debugger utility used to generate the dump?
Generally you want to be matching the bitnesses all round (x86/x64).
Doug
I was having the same issue reading a dump file generated on the same computer. There were two problems, first bitness (should have been 64, was running in 32) and the second harder problem that the proper DLL could not be located. To fix the second problem I created a method that tries all of the properly named DLLs it can find:
private static ClrRuntime GetRuntime(DataTarget target)
{
ClrInfo version = target.ClrVersions[0];
string dacLocation = version.TryGetDacLocation();
// If we don't have the dac installed, we will use the long-name dac in the same folder.
if (!string.IsNullOrEmpty(dacLocation))
dacLocation = version.DacInfo.FileName;
try // try the one it should be
{
return target.CreateRuntime(dacLocation);
}
catch (Exception e)
{
}
// can't find the one it should be, try'em all
string fileName = "mscordacwks.dll";
string[] searchLocations = new[]
{
#"C:\Windows\Microsoft.NET\",
#"C:\Windows\winsxs\"
};
foreach (string searchLocation in searchLocations)
{
foreach (string file in Directory.GetFiles(searchLocation, fileName, SearchOption.AllDirectories))
{
try
{
return target.CreateRuntime(file);
}
catch (Exception e)
{
}
}
}
throw new Exception("No found valid runtimes");
}
I followed this artificial to get the mscordacwks.dll when dealing with platform differences between where the dmp file was taken and the machine doing the analysis.
http://chentiangemalc.wordpress.com/2014/04/16/obtaining-correct-mscordacwks-dll-for-net-windbging/#comment-3380
and followed the steps including renaming the file to include the architecture and version information.
After that I just http://chentiangemalc.wordpress.com/2014/04/16/obtaining-correct-mscordacwks-dll-for-net-windbging/#comment-3380ut the full path of the file as dacLocation in the script.
After that it worked!
I suspect that putting it on the path could be made to work.

Getting output from one executable in an other one

I'm currently trying to get the output of an executable console-app into an other one. To be exact, a little overview of what I'm trying to do:
I have one executable which I cannot edit and neither see it's code. It writes some (quite a bunch to be honest) lines into the console when executed.
Now I want to write another executable that starts the one above and reads the things it writes.
Seems simple to me, so I started coding but ended up with an error message saying that StandardOut has not been redirected or the process hasn't started yet.
I tried it using this kinda structure (C#):
Process MyApp = Process.Start(#"C:\some\dirs\foo.exe", "someargs");
MyApp.Start();
StreamReader _Out = MyApp.StandardOutput;
string _Line = "";
while ((_Line = _Out.ReadLine()) != null)
Console.WriteLine("Read: " + _Line);
MyApp.Close();
I can open the executable and it also does open the one inside, but as soon as it comes to reading the returned values, the app crashes.
What am I doing wrong?!
Take a look at the documentation for the Process.StandardOutput property. You will need to set a boolean indicating that you want the stream redirected as well as disabling shell execute.
Note from the documentation:
To use StandardOutput, you must set ProcessStartInfo..::.UseShellExecute to false, and you must set ProcessStartInfo..::.RedirectStandardOutput to true. Otherwise, reading from the StandardOutput stream throws an exception
You would need to change your code a little bit to adjust for the changes:
Process myApp = new Process(#"C:\some\dirs\foo.exe", "someargs");
myApp.StartInfo.UseShellExecute = false;
myApp.StartInfo.RedirectStandardOutput = false;
myApp.Start();
string output = myApp.StandardOutput.ReadToEnd();
p.WaitForExit();
you could try setting processStartInfo.RedirectStandardOutput = true;
As noted above, you can use RedirectStandardOutput as here.
Another, dirtier way is something like
using (Process child = Process.Start
("cmd", #"/c C:\some\dirs\foo.exe someargs > somefilename"))
{
exeProcess.WaitForExit();
}
And then read its output from somefilename

Categories