Updated 2019-07-31
Shells
Rez provides support for a number of shells on Windows, Linux and MacOS. Each of which operate almost identically, some having their own special powers.
Supported shells
PowerShell
On Windows, you'll likely want to use PowerShell.
Note that "Windows Powershell" is different from PowerShell 6 and above which is cross-platform but not yet supported by Rez.
- Aliases are created as
function ()
Resources
Process Management
PowerShell, like Python, works with objects rather than text like cmd
and bash
.
PS> $fx = get-process -name firefox PS> $fx.path # C:\Program Files\Mozilla Firefox\firefox.exe PS> $fx.workingset / 1mb # 414.23828125 PS> $fx.kill()
Aliases
PS> ls # # Directory: C:\Users\marcus\.ssh # # Mode LastWriteTime Length Name # ---- ------------- ------ ---- # -a---- 11/02/2018 15:52 1766 id_rsa # -a---- 18/02/2018 11:30 1486 id_rsa.ppk # -a---- 11/02/2018 15:52 392 id_rsa.pub # -a---- 18/03/2019 08:05 3514 known_hosts PS> get-alias clear # CommandType Name Version Source # ----------- ---- ------- ------ # Alias cls -> Clear-Host
Working with processes
Get-Member
is akin to Python's dir()
.
PS> $notepad = start-process notepad -passthru PS> $notepad | get-member # TypeName: System.Diagnostics.Process # # Name MemberType Definition # ---- ---------- ---------- # ... # Name AliasProperty Name = ProcessName # Company ScriptProperty System.Object Company # {get=$this.Mainmodule.FileVersionInfo.CompanyName;} # ... # Path ScriptProperty System.Object Path {get=$this.Mainmodule.FileName;} # WorkingSet Property int WorkingSet {get;} # Kill Method void Kill() # Refresh Method void Refresh() # Start Method bool Start() # ToString Method string ToString() # ... PS> $notepad.company # Microsoft Corporation
.bashrc on PowerShell
Also found out that PowerShell has a startup script like Bash does; that's amazing. It means you can store not just environment variables "globally" but also functions and aliases like with Bash.
PS> $profile # C:\Users\marcus\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 PS> echo 'set-alias -name eco -value echo' >> $profile
Run with double-click
Normally, .ps1
scripts, unlike .bat
, open with notepad. Here's how you can change that.
This time you do need to be admin, unless there's another variable for the local user?
PS> reg add "HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\Open\Command" /d "\`"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe\`" -noLogo -ExecutionPolicy unrestricted -file \`"%1\`"" # Value exists, overwrite(Yes/No)? yes # The operation completed successfully.
The interesting bit being ExecutionPolicy unrestricted
. Running PS scripts are not allowed per default on Windows. You can either allow it per invokation like this, or globally like this:
Set-ExecutionPolicy unrestricted -scope CurrentUser
Commands to variables
Like Bash, the result of a command can be passed to a variable.
PS> $cd = "$(pwd)"
This example is particularly important, as $(pwd)
in Bash returns a string (Bash doesn't have types) whereas in PS it returns an object. Wrapping it in "
is akin to str()
in that it converts the object to its string representation.
$ mkdir temp $ cd "$(pwd)\temp"
The cool thing about an object is that it's got properties and methods. :)
PS> $(pwd) | Get-Member # # TypeName: System.Management.Automation.PathInfo # # Name MemberType Definition # ---- ---------- ---------- # Equals Method bool Equals(System.Object obj) # GetHashCode Method int GetHashCode() # GetType Method type GetType() # ToString Method string ToString() # Drive Property System.Management.Automation.PSDriveInfo Drive {get;} # Path Property string Path {get;} # Provider Property System.Management.Automation.ProviderInfo Provider {get;} # ProviderPath Property string ProviderPath {get;}
Undo/Redo
Yes, ctrl+z/ctrl+y works on the command-line, similar to a text-editor.
Ctrl+Space
You can list commands from a partial entry with ctrl+space.
Send to Clipboard
PS> get-process | clip
And ctrl+v to paste.
Navigate registry and environment like files
Apparently, PS doesn't distinguish between what is a filesystem and what is an environment or registry, each referred to as a "drive".
PS> cd c: PS> cd hkcu: PS> cd env: PS> pwd Path ---- Env:\ PS> Get-PSDrive Name Used (GB) Free (GB) Provider Root ---- --------- --------- -------- ---- Alias Alias C 460.97 13.79 FileSystem C:\ Cert Certificate \ Env Environment Function Function HKCU Registry HKEY_CURRENT_USER HKLM Registry HKEY_LOCAL_MACHINE Variable Variable WSMan WSMan
Get startup environment from running process
PS> $maya = get-process -name maya PS> $si = $maya.startupinfo PS> $si.environment["PATH"] C:\Program Files\Docker\Docker\Resources\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\Git\cmd;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\WINDOWS\System32\OpenSSH\
cmd
Things to be aware of when using Rez with cmd
.
Long Environment Variables
cmd.exe
is both familiar and available on every Windows machine dating back to Windows 95. It does however suffer from one major limitation; environment variables are limited in length to 2,000 characters.
It isn't quite as simple as that, as there is a limit in the Windows API, another limit in conhost.exe
and yet another in cmd.exe
. When using Rez with cmd.exe
, it is this limit you must take into consideration, and it is the most limiting of them all.
Why does the cmd.exe
limit apply? It's because whenever you execute_shell
or enter into a context using rez env
, Rez is creating a .bat
script with a series of commands that look like this.
set PATH=c:\some\path;%PATH% set PATH=c:\some\other\path;%PATH% set PATH=c:\yet\another\path;%PATH% ...
With one line of set
for every call to env
from within your package.py:commands()
function. And this is where the problem lies, for you see launching cmd
with a environment containing values longer than 2,000 characters work fine.
import subprocess subprocess.Popen("cmd", env={"a": "really", "long": "environment"}) # Works
But cmd.exe
itself has issues handling anything longer than 2,000 characters which is why one of those lines of set
will eventually stop growing.
Command-line history
A normal Rez context generates a deep process hierarchy.
- Under normal circumstances, Rez is made available as
rez.exe
, generated bypip install
into a virtual environment. - This executable calls another executable
python.exe
from that same install - Which in turn calls the parent Python process from which your virtual environment was made, e.g.
c:\python37\python.exe
- From here, Rez instantiates your
REZ_DEFAULT_SHELL
, e.g.cmd
That's 4 layers of processes, one calling the next.
It just so happens that 4 is the default number of buffers the windows ConHost.exe is configured to keep track of, which means that when you launch a 5th layer you lose history.
To account for this, configure your shell to keep track of 5 or more buffers.
Alias
The use of alias()
in packages with cmd.exe
has a few quicks worth considering.
- Utilises
doskey
, which works similar toalias
on Linux - Does not work with
rez env -- arbitrary command
- Does not carry across shell, e.g.
start
- Does not respect cmd.exe scope, e.g.
cmd /Q /K doskey python=c:\python27\python.exe $*
affects parent too
bash
The default shell on Linux and MacOS.
- Aliases are created as
function()