How do i compile something with Pgocaml - ocaml

I'm trying to use Pgocaml for database interactions within my application.
This is the file I'm trying to compile:
let () =
let dbh = PGOCaml.connect () in
let insert name salary email =
PGSQL(dbh) "insert into employees (name, salary, email) values ($name, $salary, $?email)"
in
insert "Ann" 10_000_l None;
insert "Bob" 45_000_l None;
insert "Jim" 20_000_l None;
insert "Mary" 30_000_l (Some "mary#example.com");
let print_row (id, name, salary, email) =
let email = match email with Some email -> email | None -> " -"
in Printf.printf "%ld %S %ld %S\n" id name salary email in
let rows =
PGSQL(dbh) "select id, name, salary, email from employees"
in List.iter print_row rows;
PGOCaml.close dbh
This is how I am trying to compile it:
ocamlbuild -use-ocamlfind -pkg pgocaml pgex.native
and this is the error I am getting:
+ ocamlfind ocamldep -package pgocaml -modules pgex.ml > pgex.ml.depends
File "pgex.ml", line 4, characters 19-97:
Error: Syntax error
Command exited with code 2.
Why am I getting this error?
Thanks in advance!

PG'OCaml is a syntax extension, it is not a regular ocaml code, so you need to take extra steps to let it perform its magic. First, read the tutorial which also explains how to compile projects with pgocaml. Second, tell the build system that pgex.ml should be preprocessed with camlp4 - i.e. create _tags file with the contents <pgex.ml>: syntax(camlp4o).

Related

Rmarkdown addin for creating new post not working

Today I wanted to create a new post for my website (built using blogdown), but the New Post addin doesn't seem to work.
When I select "New Post" or run
blogdown:::new_post_addin()
I get an error:
Error in FUN(X[[i]], ...) : subscript out of bounds
In addition: Warning messages:
1: In value[[3L]](cond) :
Cannot parse the YAML metadata in 'content/photo.md': Scanner error: while scanning an alias at line 3, column 1 did not find expected alphabetic or numeric character at line 3, column 2
2: In value[[3L]](cond) :
Cannot parse the YAML metadata in 'content/research.md': Scanner error: while scanning an alias at line 4, column 1 did not find expected alphabetic or numeric character at line 4, column 2
I am not sure what the additional warnings are about, but I want to focus on the main error. Here are details returned by traceback():
> traceback()
10: lapply(meta, `[[`, i)
9: unlist(lapply(meta, `[[`, i))
8: blogdown:::collect_yaml()
7: eval(exprs[i], envir)
6: eval(exprs[i], envir)
5: sys.source(pkg_file("scripts", file), envir = new.env(parent = globalenv()),
keep.source = FALSE)
4: xfun::in_dir(site_root(), expr)
3: in_root(sys.source(pkg_file("scripts", file), envir = new.env(parent = globalenv()),
keep.source = FALSE))
2: source_addin("new_post.R")
1: blogdown:::new_post_addin()
Interestingly, when I run this command:
blogdown::new_post(title, ext = '.md')
it works fine and I can create a new post. I updated both blogdown and hugo but to no avail. Could someone help me understand what this error is about? Other addins (such as Insert Image) work fine.
As requested, the githup repo is https://github.com/msmielak/msmielak.github.io and the dput() output is below:
>dput(blogdown:::scan_yaml())
list(`content/about.md` = "<img align=\"right\" src=\"/./about_files/rsz_screenshot_2020-12-28_une_home.png\" alt=\"\" width=\"100px\"/>\n\n**2014-**\nPhD candidate at the School of Environmental and Rural Sciences University of New England in Armidale, Australia.",
`content/code.md` = NULL, `content/contact.md` = NULL, `content/photo.md` = NULL,
`content/post/2021-03-29-extracting-date-and-time-from-photo-using-ocr-engine-tesseract/index.md` = list(
title = "Extracting date and time from camera trap photos using R and tesseract",
author = "", date = "2021-03-29", slug = list(), categories = c("code",
"R"), tags = c("R", "code", "camera trap", "OCR"), description = "",
featured = "", featuredalt = "", featuredpath = "", linktitle = ""),
`content/research.md` = NULL, `content/technology.md` = NULL)
Warning messages:
1: In value[[3L]](cond) :
Cannot parse the YAML metadata in 'content/code.md': Parser error: did not find expected <document start> at line 3, column 67
2: In value[[3L]](cond) :
Cannot parse the YAML metadata in 'content/photo.md': Scanner error: while scanning an alias at line 3, column 1 did not find expected alphabetic or numeric character at line 3, column 2
3: In value[[3L]](cond) :
Cannot parse the YAML metadata in 'content/research.md': Scanner error: while scanning an alias at line 4, column 1 did not find expected alphabetic or numeric character at line 4, column 2
The YAML metadata of the file content/about.md seems to be invalid. Normally YAML metadata should be of the form:
---
tag1: value1
tag2: value2
---
Update: with the dev version of blogdown (>= v1.2.4), the error will no longer occur. What's more, blogdown::check_site() can detect this problem and suggest users fix the problematic YAML metadata.
remotes::install_github('rstudio/blogdown')

Global CLI flag in OCaml Core.Command

I am currently creating a CLI application in OCaml and using Core.Command, the CLI parser included in core (v0.10), to parse the command line.
I want to have a global flag that can be used for any subcommand (like the --paginate or --git-dir flags in git for example).
For instance, I want a -debug flag so that the two following commands are valid
my-cli -debug hello world
my-cli -debug goodbye world
However, I could not find a way to do this with the Core.Command API.
Here is a simplified version what I currently have.
open Core
let initialize_logger debug =
Logs.set_reporter (Logs_fmt.reporter ());
let log_level = if debug then Logs.Debug else Logs.Info in
Logs.set_level (Some log_level)
let some_func_with_logging () =
Logs.debug (fun m -> m "the flag debug was passed!")
let hello name =
some_func_with_logging ();
Printf.printf "Hello %s!\n" name
let goodbye name =
some_func_with_logging ();
Printf.printf "Goodbye %s!\n" name
let hello_command =
let open Command.Let_syntax in
Command.basic
~summary:"says hello"
[%map_open
let name = anon ("name" %: string)
and debug = flag "debug" no_arg ~doc:"debug" in
fun () ->
initialize_logger debug;
hello name
]
let goodbye_command =
let open Command.Let_syntax in
Command.basic
~summary:"says goodbye"
[%map_open
let name = anon ("name" %: string)
and debug = flag "debug" no_arg ~doc:"debug" in
fun () ->
initialize_logger debug;
goodbye name
]
let main_command =
Command.group ~summary:"a cool CLI tool"
[ ("hello", hello_command);
("goodbye", goodbye_command);
]
let () = Command.run main_command
There are two main issues here:
the debug flag as well as the call to initialize_logger is duplicated in every subcommand
the debug flag needs to be passed after the subcommand when invoking the command: my-cli hello world -debug instead of my-cli -debug hello world
Is there a clean way to handle this with Core.Command API?

Awk - replace coumn 2 in table 1 from coumn 2 in table 2 based on matching data in column 1 (common between tables)

After my company purchased new servers I'm doing a top-down upgrade of the server room. since all the hardware is changing I'm not able to use bare-metal cloning tool to migrate. Using the newusers command from Debian I am able to create in bulk all the users from the old server. For the /etc/shadow file, you can copy the second column from your shadow.sync (from the old server) file into the second column of the associated account in the new system. This will transfer the passwords for your accounts to the new system. However I'm not sure how to do this programmatically using awk (or something else I can integrate into my shell script I already have setup).
shadow.sync contains the following (users & passwords changed for security reasons) This is the file to be copied INTO the current shadow file which looks almost identical except the data in the second column has the INCORECT values.
An in-depth explanation of the fields for the /etc/shadow file can be found here
user1:$6$HiwQEKYDgT$xYU9F3Wv0jFWHmZxN60nFMkTqWn87RRIOvx7Epp57rOmdHN9plJgjhC.jRVVNc1.HUaqSpX/ZcCEFSn6RmQQA0:17531::0:99999:7:::
user2:$6$oOuwJtrIKk$THLsfDppLI8QVw9xEOAaIoZ90Mcz3xGukVdyWGJJqygsavtXvtJ8X9ECc0CfuGzHp0pHNSAqdZY9TAzF5YKLc.:17531::0:99999:7:::
user3:$6$IEHAyRsokQ$e5K3RicE.PUAej8IxG9GnF/SUl1NQ57pqzUVuAzsP8.89SNhuaKE1W7kG5P4hbzV23Bb2zWHx353t.e9ERSVy.:17531::0:99999:7:::
user4:$6$lFOIUQvxdb$W5ITiH/Y021xw1vo8uw6ZtIOmfKjnNnC/SttQjN85MHtLbFeQ2Th5kfAIijXC81CRG4T0kJQ3rzRNRSyQHjyb1:17531::0:99999:7:::
user5:$6$RZbtYxWiwE$lnP8.tTbs0JbLZg5FsmPR8QvrJARbcRuJi2nYm1okwjfkWPkj212mBPjVF1BTo2hVCxLGSw64Cp6DgXheacSx.:17531::0:99999:7:::
Essentially i need to match column 1 (username) between the sync file and the shadow file and copy column 2 from the sync file over-top of the same column on the actual shadow file. Doing this by hand would be terrible as I have 90 servers that I'm migrating with over 900 users total.
Random shadow.sync file for demonstration was generated using:
#!/usr/bin/env python
import random, string, crypt, datetime
userList = ['user1','user2','user3','user4','user5']
dateNow = (datetime.datetime.utcnow() - datetime.datetime(1970,1,1)).days
for user in userList:
randomsalt = ''.join(random.sample(string.ascii_letters,10))
randompass = ''.join(random.sample(string.ascii_letters,10))
print("%s:%s:%s::0:99999:7:::" % (user, crypt.crypt(randompass, "$6$"+randomsalt), dateNow))
Please note this python script was ONLY for demonstration and not for actual production data. As users are added to the server the /etc/shadow file is generated with the password presented on the command line. The Original data (from shadow.sync) needs to be "Merged" with the data in /etc/shadow after the newusers command is run (which essentially sets every password to the letter x)
#!/usr/bin/env python
with open('/etc/shadow','rb') as file:
for line in file:
TargetLine = line.rstrip().split(":")
with open('shadow.sync','rb') as shadow:
for row in shadow:
SyncLine = row.rstrip().split(":")
if TargetLine[0] == SyncLine[0]:
TargetLine[1] = SyncLine[1]
break
print "NEW MODIFIED LINE: %s" % ":".join(TargetLine)
This will open the /etc/shadow file and loop through the lines. For each line on the /etc/shadow file we loop through the shadow.sync file once a match for the usernames TargetLine[0] == SyncLine[0] the password field is modified and the loop is broken.
If a match is NOT found (username in /etc/shadow but NOT in the shadow.sync file) the if block on the inner loop falls through and the line is left untouched the results are handled on the final print statement. As this answers the question I will leave the data output and file manipulation up to the user.
use Data::Dumper;
# we only need to process the sync file once -
# and store what we find in a hash (dictionary)
open $fh1, '<', 'shadow.sync.txt';
while (<$fh1>)
{
m/^([^:]+):(.*)$/;
$hash->{$1} = $2;
}
close $fh1;
# this shows us what we found & stored
print Dumper $hash;
# now we'll process the shadow file which needs updating -
# here we output a side-by-side comarison of what the passwords
# currently are & what they will be updated to (from the hash)
open $fh2, '<', 'shadow.txt';
open $fh3, '>', 'shadow.UPDATED.txt';
while (<$fh2>)
{
m/^([^:]+):(.*)$/;
printf ( "%s => %s\n", $1, $2 );
printf ( "%s => %s\n\n", $1, $hash->{$1} );
printf $fh3 ( "%s:%s\n", $1, $hash->{$1} );
}
close $fh3;
close $fh2;
Sample output:
$VAR1 = {
'user5' => '$6$RZbtYxWiwE$lnP8w64Cp6DgXheacSx.:17531::0:99999:7:::',
'user1' => '$6$HiwVVNc1.HUaqSpX/ZcCEFSn6RmQQA0:17531::0:99999:7:::',
'user4' => '$6$lFOIUQv1CRG4T0kJQ3rzRNRSyQHjyb1:17531::0:99999:7:::',
'user3' => '$6$P8.89SNhu23Bb2zWHx353t.e9ERSVy.:17531::0:99999:7:::',
'user2' => '$6$Cc0CfuGzHp0pHNSAqdZY9TAzF5YKLc.:17531::0:99999:7:::'
};
user1 => $6$RANDOM1RANDOM1RANDOM1RANDOM1:17531::0:99999:7:::
user1 => $6$HiwVVNc1.HUaqSpX/ZcCEFSn6RmQQA0:17531::0:99999:7:::
user2 => $6$RANDOM2RANDOM2RANDOM2RANDOM2:17531::0:99999:7:::
user2 => $6$Cc0CfuGzHp0pHNSAqdZY9TAzF5YKLc.:17531::0:99999:7:::
user3 => $6$RANDOM3RANDOM3RANDOM3RANDOM3:17531::0:99999:7:::
user3 => $6$P8.89SNhu23Bb2zWHx353t.e9ERSVy.:17531::0:99999:7:::
user4 => $6$RANDOM4RANDOM4RANDOM4RANDOM4:17531::0:99999:7:::
user4 => $6$lFOIUQv1CRG4T0kJQ3rzRNRSyQHjyb1:17531::0:99999:7:::
user5 => $6$RANDOM5RANDOM5RANDOM5RANDOM5:17531::0:99999:7:::
user5 => $6$RZbtYxWiwE$lnP8w64Cp6DgXheacSx.:17531::0:99999:7:::

BioPerl: extract CDS error

I am trying to extract CDS and corresponding amino acid sequences from GenBank file using BioPerl. The script is shown below:
while (my $seq_object = $in->next_seq){
for my $feat_object ($seq_object->get_SeqFeatures) {
if ($feat_object ->primary_tag eq "CDS") {
# warn("all tags are ", join ("," , $feat_object->get_all_tags),"\n");
if ($feat_object->has_tag ("protein_id")){
my ($protein_id) = $feat_object->get_tag_values('protein_id');
my ($pseq) = $feat_object->get_tag_values('translation') ;
my ($pepseq) = Bio::Seq->new(-id => $protein_id , -description => $seq_object -> accession_number,
-seq => $pseq);
$out->write_seq($pepseq);
}
}
}
}
I am getting error message as:
Filehandle GEN1 opened only for input at /Library/Perl/5.12/Bio/Root/IO.pm line 533, line 148.
Kindly help me to solve this issue.
Thanks in advance
I'll add this as an answer since it is likely the source of the error. When creating a Bio::SeqIO object for output, you must follow the normal Perl rules for open and specify the file is for output. So, try the following:
my $out = Bio::SeqIO->new( -file => ">Oct_test.fasta", -format => 'fasta');
This is a really easy thing to forget and the error message could be a bit more descriptive.

Redirect standard output OCaml

How can you redirect the standard output in OCaml ?
I tried Format.set_formatter_out_channel but it doesn't seem to work. When I use printf afterwards, the text is still printed on the screen, and the file I created remains empty.
The reason your experiment failed is that Printf.printf doesn't use the output channel of the Format module. The Format module is for pretty-printing, a fairly elaborate task. The Printf.printf function writes formatted data to the standard output (a C-style printf).
Do you really want to redirect standard output, or do you just want to write to a specific channel? To write to a channel oc you can just use
Printf.fprintf oc ...
rather than
Printf.printf ...
Doing redirection is a different thing. You can do it with Unix.dup2. Here's an example session that shows how to do it:
$ cat redirected
cat: redirected: No such file or directory
$ cat redir.ml
let main () =
let newstdout = open_out "redirected" in
Unix.dup2 (Unix.descr_of_out_channel newstdout) Unix.stdout;
Printf.printf "line of text\n";
Printf.printf "second line of text\n"
let () = main ()
$ ocamlopt -o redir unix.cmxa redir.ml
$ ./redir
$ cat redirected
line of text
second line of text
Since this is changing low-level file descriptors behind the back of the OCaml I/O system, I'd be a little careful. As a quick hack it's fantastic--I've done it many times.
Update
Here's a version of the above code that redirects standard output temporarily, then puts it back where it was before.
$ cat redirected
cat: redirected: No such file or directory
$
$ cat redir.ml
let main () =
let oldstdout = Unix.dup Unix.stdout in
let newstdout = open_out "redirected" in
Unix.dup2 (Unix.descr_of_out_channel newstdout) Unix.stdout;
Printf.printf "line of text\n";
Printf.printf "second line of text\n";
flush stdout;
Unix.dup2 oldstdout Unix.stdout;
Printf.printf "third line of text\n";
Printf.printf "fourth line of text\n"
let () = main ()
$
$ ocamlopt -o redir unix.cmxa redir.ml
$ ./redir
third line of text
fourth line of text
$
$ cat redirected
line of text
second line of text