How do I execute a Move script with the Aptos CLI? - move-lang

Let's say I have a Move script like this:
script {
use std::signer;
use aptos_framework::aptos_account;
use aptos_framework::aptos_coin;
use aptos_framework::coin;
fun main(src: &signer, dest: address, desired_balance: u64) {
let src_addr = signer::address_of(src);
let balance = coin::balance<aptos_coin::AptosCoin>(src_addr);
if (balance < desired_balance) {
aptos_account::transfer(src, dest, desired_balance - balance);
};
addr::my_module::do_nothing();
}
}
This is calling functions on the aptos_coin.move module, which is deployed on chain. What it does isn't so important for this question, but in short, it checks that the balance of the destination account is less than desired_balance, and if so, tops it up to desired_balance.
Notice also how it calls a function in a Move module I've defined:
module addr::my_module {
public entry fun do_nothing() { }
}
Where do I put these files? Do I need a Move.toml? How do I run my script with the CLI?

Let's run through how to execute a Move script with a step by step example, this should answer all your questions.
Make a new directory to work from:
mkdir testing
cd testing
Setup the Aptos CLI:
aptos init
The CLI will ask you which network you want to work with (e.g. devnet, testnet, mainnet). It will also ask you for your private key (which looks like this: 0xf1adc8d01c1a890f17efc6b08f92179e6008d43026dd56b71e7b0d9b453536be), or it can generate a new one for you, as part of setting up your account.
From here, initialize a new Move project:
aptos move init --name my_script
Now you need to make a file for your script. So, take the script you created above, and put it in sources/, e.g. like this:
testing/
Move.toml
sources/
top_up.move
In other words, top_up.move should contain the script you included in the question.
Now do the same thing with the Move module, leaving you with this:
testing/
Move.toml
sources/
top_up.move
my_module.move
Now you can compile the script:
$ aptos move compile --named-addresses addr=81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING my_script
{
"Result": []
}
Note how I use the --named-addresses argument. This is necessary because in your code, you refer to this named address called addr. The compiler needs to know what this refers to. Instead of using this CLI argument, you could put something like this in your Move.toml:
[addresses]
addr = "b078d693856a65401d492f99ca0d6a29a0c5c0e371bc2521570a86e40d95f823"
Finally you can run the compiled script:
$ aptos move run-script --compiled-script-path build/my_script/bytecode_scripts/main.mv --args address:b078d693856a65401d492f99ca0d6a29a0c5c0e371bc2521570a86e40d95f823 --args u64:5
Do you want to submit a transaction for a range of [17000 - 25500] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result": {
"transaction_hash": "0x655f839a45c5f14ba92590c321f97c3c3f9aba334b9152e994fb715d5648db4b",
"gas_used": 178,
"gas_unit_price": 100,
"sender": "81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e",
"sequence_number": 53,
"success": true,
"timestamp_us": 1669811892262502,
"version": 370133122,
"vm_status": "Executed successfully"
}
}
Note that the path of the compiled script is under build/my_script/, not build/top_up/. This is because it uses the name of the project contained in Move.toml, which is my_script from when we ran aptos move init --name my_script.
So to answer one of your questions, yes you need a Move.toml, you can't currently just execute a script file on its own with the CLI. The compiler needs this determine what Aptos framework to use for example.
See the code used in this answer here: https://github.com/banool/move-examples/tree/main/run_script.
See also how to do this with the Rust SDK instead of the CLI: How do I execute a Move script on Aptos using the Rust SDK?.
P.S. There is a more streamlined way to execute a script. Instead of running aptos move compile and then aptos move run-script --compiled-script-path separately, you can just do this:
$ aptos move run-script --script-path sources/my_script.move --args address:b078d693856a65401d492f99ca0d6a29a0c5c0e371bc2521570a86e40d95f823 --args u64:5
This will do both steps with a single CLI command. Note however that there are some major footguns with this approach, see https://github.com/aptos-labs/aptos-core/issues/5733. So I'd recommend using the previous two-step approach for now.

Related

Golang Cobra multiple flags with no value

I'm new to Golang, and i'm trying out my first CLI application, using the Cobra framework.
My plan is to have few commands, with many flags.
These flags, don't have to have a value attached to them, since they can simply be -r to restart the device.
Currently, i have the following working, but i keep thinking, that this cannot be the correct way to do it.
So any help is appreciated.
The logic is currently, that each command, get's a default value attached to it, and then i look for this, in the run command, and triggers my function, once it captures it.
My "working code" looks like below.
My init function, in the command contains the following.
chargerCmd.Flags().StringP("UpdateFirmware", "u", "", "Updeates the firmware of the charger")
chargerCmd.Flags().Lookup("UpdateFirmware").NoOptDefVal = "yes"
chargerCmd.Flags().StringP("reboot", "r", "", "Reboots the charger")
chargerCmd.Flags().Lookup("reboot").NoOptDefVal = "yes"
And the run section looks like this.
Run: func(cmd *cobra.Command, args []string) {
input, _ := cmd.Flags().GetString("UpdateFirmware")
if input == "yes" {
fmt.Println("Updating firmware")
UpdateFirmware(os.Getenv("Test"), os.Getenv("Test2"))
}
input, _ = cmd.Flags().GetString("reboot")
if input == "yes" {
fmt.Println("Rebooting Charger")
}
},
Maybe to make the usage a bit cleaner, as stated in the comment from Burak - you can better differentiate between commands and flags. With cobra you have the root command and sub-commands attached to the root command. Additionaly each command can accept flags.
In your case, charger is the root commands and you want two sub-commands: update_firmware and reboot.
So as an example to reboot the charger, you would execute the command:
$ charger reboot
In the code above, you are trying to define sub-commands as flags, which is possible, but likely not good practice.
Instead, the project should be set-up something like this: https://github.com/hesamchobanlou/stackoverflow/tree/main/74934087
You can then move the UpdateFirmware(...) operation within the respective command definition under cmd/update_firmware.go instead of trying to check each flag variation on the root chargerCmd.
If that does not help, provide some more details on why you think your approach might not be correct?

Grub throws "can't find command `['." when adding conditional to grub.cfg

It was my understanding that grub supports a small subset of bash. Their documentation doesn't go into super detail, other than it "supports conditionals", etc.
I am trying to run a simple if.
grub> if [ "${myvar}" = "fred" ]; then
> echo "test"
> fi
error: can't find command `['.
Anybody have an idea? I am using grub2-efi 2.00.
You are missing a grub2 module in order to run if tests.
I'm running Gentoo on a PowerPC system (PPC64 G5 machine) and doing a default grub-mkconfig then booting from it gives me the error in your question.
Since bash has that syntax support, I figured it was simply a grub module that needed to be added (I had been doing work with grub modules recently).
tl;dr: You need to load the appropriate grub module and then the error goes away.
The first step is to find out what modules you have. For me, it's whatever is available in my /boot/grub/powerpc-ieee1275/ folder.
There's also modules in /usr/lib/grub/powerpc-ieee1275/.
I wrote up a list of modules I thought I needed:
normal
eval
read
test
test_blockarg
trig
true
I then added them to my /etc/default/grub file:
GRUB_PRELOAD_MODULES="normal eval read test test_blockarg trig true"
I did not find an entry for GRUB_PRELOAD_MODULES in the config file, so I had to do some searching to find out how. I want these modules to be added every time I generate the grub config file, which means putting them in the 00_header portion of grub.
Then I recreated the configuration file:
grub-mkconfig -o /boot/grub/grub.cfg
The modules were in the header and things worked perfectly on reboot.
If I had to guess: you probably only need the test module to enable if statements.

What is the equivalent of an Ant taskdef in Gradle?

I've been struggling with this for a day and a half or so. I'm trying to replicate the following Ant concept in Gradle:
<target name="test">
...
<runexe name="<filename> params="<params>" />
...
</target>
where runexe is declared elsewhere as
<macrodef name="runexe" >
...
</macrodef>
and might also be a taskdef or a scriptdef i.e. I'd like to be able to call a reusable, pre-defined block of code and pass it the necessary parameters from within Gradle tasks. I've tried many things. I can create a task that runs the exe without any trouble:
task runexe(type: Exec){
commandLine 'cmd', '/c', 'dir', '/B'
}
task test(dependsOn: 'runexe') {
runexe {
commandLine 'cmd', '/c', 'dir', '/N', 'e:\\utilities\\'
}
}
test << {
println "Testing..."
// I want to call runexe here.
...
}
and use dependsOn to have it run. However this doesn't allow me to run runexe precisely when I need to. I've experimented extensively with executable, args and commandLine. I've played around with exec and tried several different variations found here and around the 'net. I've also been working with the free books available from the Gradle site.
What I need to do is read a list of files from a directory and pass each file to the application with some other arguments. The list of files won't be known until execution time i.e. until the script reads them, the list can vary and the call needs to be made repeatedly.
My best option currently appears to be what I found here, which may be fine, but it just seems that there should be a better way. I understand that tasks are meant to be called once and that you can't call a task from within another task or pass one parameters but I'd dearly like to know what the correct approach to this is in Gradle. I'm hoping that one of the Gradle designers might be kind enough to enlighten me as this is a question asked frequently all over the web and I'm yet to find a clear answer or a solution that I can make work.
If your task needs to read file names, then I suggest to use the provided API instead of executing commands. Also using exec will make it OS specific, therefore not necessarily portable on different OS.
Here's how to do it:
task hello {
doLast {
def tree = fileTree(dir: '/tmp/test/txt')
def array = []
tree.each {
array << it
print "${it.getName()} added to array!\n"
}
}
}
I ultimately went with this, mentioned above. I have exec {} working well in several places and it seems to be the best option for this use case.
To please an overzealous moderator, that means this:
def doMyThing(String target) {
exec {
executable "something.sh"
args "-t", target
}
}
as mentioned above. This provides the same ultimate functionality.

Get autocompletion list in bash variable

I'm working with a big software project with many build targets. When typing make <tab> <tab> it shows over 1000 possible make targets.
What I want is a bash script that filters those targets by certain rules. Therefore I would like to have this list of make targets in a bash variable.
make_targets=$(???)
[do something with make_targets]
make $make_targets
It would be best if I wouldn't have to change anything with my project.
How can I get such a List?
#yuyichao created a function to get autocomplete output:
comp() {
COMP_LINE="$*"
COMP_WORDS=("$#")
COMP_CWORD=${#COMP_WORDS[#]}
((COMP_CWORD--))
COMP_POINT=${#COMP_LINE}
COMP_WORDBREAKS='"'"'><=;|&(:"
# Don't really thing any real autocompletion script will rely on
# the following 2 vars, but on principle they could ~~~ LOL.
COMP_TYPE=9
COMP_KEY=9
_command_offset 0
echo ${COMPREPLY[#]}
}
Just run comp make '' to get the results, and you can manipulate that. Example:
$ comp make ''
test foo clean
You would need to overwrite / modify the completion function for make. On Ubuntu it is located at:
/usr/share/bash-completion/completions/make
(Other distributions may store the file at /etc/bash_completion.d/make)
If you don't want to change the completion behavior for the whole system, you might write a small wrapper script like build-project, which calls make. Then write a completion function for that mapper which is derived from make's one.

Unable to figure out ruby method "directory" and what it does

I am very new to ruby and was trying to understand some code when I got stuck at this snippet:
directory "test_dir" do
action :create
recursive true
end
I tried googling directory class but was unsuccessful. I found a class Dir but its not the same. I see that intuitively this snippet should create a new directory and name it test_dir but I do not want to assume things and move forward.
EDIT
This was a part of a chef-recipe which is used to launch a particular task. For the purposes of launching, it needs to create a directory and download some jars to it. There is an execute method below which goes like this:
execute 'deploy' do
action :nothing
# ignore exit status of storm kill command
command <<-EOH
set -e
storm kill #{name} -w 1 || true
sleep 3
storm jar #{points to the jar}
EOH
end
Sorry I have to be a bit obfuscated as some of the things are not open sourced.
It is the Directory resource of the Chef framework. (DSL stands for domain-specific language. Ruby is well suited for them.)
It's the Chef internal DSL for Directory management. Read more here: http://wiki.opscode.com/display/chef/Resources#Resources-Directory
PS: The recursive true tells it to create the folder much like mkdir -p.
The snippet you pasted is not really enough information to go on (need context; where is the snippet from?)
That said directory looks more like a method than a class. First, it's lowercased and classes are CamelCased.
If it's a method, it's defined somewhere within the application. Have you tried something like this:
grep -r "def directory" ./ or
grep -r "directory" ./| grep "def"
If not in the application itself, it would be defined in one of the application's dependencies (grep -r "..." $GEM_HOME/gems instead)
directory is not a class, it is a method. I do not know what module it is a part of, but that snippet is about equivalent to this:
Kernel.directory.call("test_dir",lambda {action :create; recursive true})
That snippet uses some gem that adds a directory method to the Kernel object.
As others have mentioned, it is part of the directory management DSL Chef. A DSL is a set of methods integrated into the Kernel object; because of the very flexible method calling syntax of Ruby, method calls can look a lot like language keywords. That makes task specific commands (Domain Specific Languages: DSL) look very nice in Ruby; easy to use and flexible. Thus gems that add DSLs are very common.

Resources