Adds the following edify functions: mount unmount format show_progress delete delete_recursive package_extract symlink set_perm set_perm_recursive This set is enough to extract and install the system part of a (full) OTA package. Adds the updater binary that extracts an edify script from the OTA package and then executes it. Minor changes to the edify core (adds a sleep() builtin for debugging, adds "." to the set of characters that can appear in an unquoted string).
		
			
				
	
	
		
			109 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			109 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| Update scripts (from donut onwards) are written in a new little
 | |
| scripting language ("edify") that is superficially somewhat similar to
 | |
| the old one ("amend").  This is a brief overview of the new language.
 | |
| 
 | |
| - The entire script is a single expression.
 | |
| 
 | |
| - All expressions are string-valued.
 | |
| 
 | |
| - String literals appear in double quotes.  \n, \t, \", and \\ are
 | |
|   understood, as are hexadecimal escapes like \x4a.
 | |
| 
 | |
| - String literals consisting of only letters, numbers, colons,
 | |
|   underscores, slashes, and periods don't need to be in double quotes.
 | |
| 
 | |
| - The following words are reserved:
 | |
| 
 | |
|        if    then    else   endif
 | |
| 
 | |
|   They have special meaning when unquoted.  (In quotes, they are just
 | |
|   string literals.)
 | |
| 
 | |
| - When used as a boolean, the empty string is "false" and all other
 | |
|   strings are "true".
 | |
| 
 | |
| - All functions are actually macros (in the Lisp sense); the body of
 | |
|   the function can control which (if any) of the arguments are
 | |
|   evaluated.  This means that functions can act as control
 | |
|   structures.
 | |
| 
 | |
| - Operators (like "&&" and "||") are just syntactic sugar for builtin
 | |
|   functions, so they can act as control structures as well.
 | |
| 
 | |
| - ";" is a binary operator; evaluating it just means to first evaluate
 | |
|   the left side, then the right.  It can also appear after any
 | |
|   expression.
 | |
| 
 | |
| - Comments start with "#" and run to the end of the line.
 | |
| 
 | |
| 
 | |
| 
 | |
| Some examples:
 | |
| 
 | |
| - There's no distinction between quoted and unquoted strings; the
 | |
|   quotes are only needed if you want characters like whitespace to
 | |
|   appear in the string.  The following expressions all evaluate to the
 | |
|   same string.
 | |
| 
 | |
|      "a b"
 | |
|      a + " " + b
 | |
|      "a" + " " + "b"
 | |
|      "a\x20b"
 | |
|      a + "\x20b"
 | |
|      concat(a, " ", "b")
 | |
|      "concat"(a, " ", "b")
 | |
| 
 | |
|   As shown in the last example, function names are just strings,
 | |
|   too.  They must be string *literals*, however.  This is not legal:
 | |
| 
 | |
|      ("con" + "cat")(a, " ", b)         # syntax error!
 | |
| 
 | |
| 
 | |
| - The ifelse() builtin takes three arguments:  it evaluates exactly
 | |
|   one of the second and third, depending on whether the first one is
 | |
|   true.  There is also some syntactic sugar to make expressions that
 | |
|   look like if/else statements:
 | |
| 
 | |
|      # these are all equivalent
 | |
|      ifelse(something(), "yes", "no")
 | |
|      if something() then yes else no endif
 | |
|      if something() then "yes" else "no" endif
 | |
| 
 | |
|   The else part is optional.
 | |
| 
 | |
|      if something() then "yes" endif    # if something() is false,
 | |
|                                         # evaluates to false
 | |
| 
 | |
|      ifelse(condition(), "", abort())   # abort() only called if
 | |
|                                         # condition() is false
 | |
| 
 | |
|   The last example is equivalent to:
 | |
| 
 | |
|      assert(condition())
 | |
| 
 | |
| 
 | |
| - The && and || operators can be used similarly; they evaluate their
 | |
|   second argument only if it's needed to determine the truth of the
 | |
|   expression.  Their value is the value of the last-evaluated
 | |
|   argument:
 | |
| 
 | |
|      file_exists("/data/system/bad") && delete("/data/system/bad")
 | |
| 
 | |
|      file_exists("/data/system/missing") || create("/data/system/missing")
 | |
| 
 | |
|      get_it() || "xxx"     # returns value of get_it() if that value is
 | |
|                            # true, otherwise returns "xxx"
 | |
| 
 | |
| 
 | |
| - The purpose of ";" is to simulate imperative statements, of course,
 | |
|   but the operator can be used anywhere.  Its value is the value of
 | |
|   its right side:
 | |
| 
 | |
|      concat(a;b;c, d, e;f)     # evaluates to "cdf"
 | |
| 
 | |
|   A more useful example might be something like:
 | |
| 
 | |
|      ifelse(condition(),
 | |
|             (first_step(); second_step();),   # second ; is optional
 | |
|             alternative_procedure())
 |