Merge branch 'master' into mc-1.14.x

This commit is contained in:
SquidDev 2019-06-15 08:00:20 +01:00
commit 57318b022d
26 changed files with 446 additions and 41 deletions

View File

@ -3,10 +3,6 @@
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<!-- Has a public m_label field. We need to check if this is used in other projects before renaming it. -->
<suppress checks="MemberName" files=".*[\\/]TileComputerBase.java"
message="Name 'm_label' must match pattern .*" />
<!-- All the config options and method fields. -->
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraft.java" />
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraftAPI.java" />

View File

@ -48,7 +48,7 @@ protected ServerComputer createComputer( int instanceID, int id )
{
ComputerFamily family = getFamily();
ServerComputer computer = new ServerComputer(
getWorld(), id, m_label, instanceID, family,
getWorld(), id, label, instanceID, family,
ComputerCraft.terminalWidth_computer,
ComputerCraft.terminalHeight_computer
);

View File

@ -52,7 +52,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
private int m_instanceID = -1;
private int m_computerID = -1;
protected String m_label = null;
protected String label = null;
private boolean m_on = false;
boolean m_startOn = false;
private boolean m_fresh = false;
@ -160,7 +160,7 @@ public void tick()
m_fresh = false;
m_computerID = computer.getID();
m_label = computer.getLabel();
label = computer.getLabel();
m_on = computer.isOn();
if( computer.hasOutputChanged() ) updateOutput();
@ -181,7 +181,7 @@ public CompoundNBT write( CompoundNBT nbt )
{
// Save ID, label and power state
if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID );
if( m_label != null ) nbt.putString( NBT_LABEL, m_label );
if( label != null ) nbt.putString( NBT_LABEL, label );
nbt.putBoolean( NBT_ON, m_on );
return super.write( nbt );
@ -194,7 +194,7 @@ public void read( CompoundNBT nbt )
// Load ID, label and power state
m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
m_label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
m_on = m_startOn = nbt.getBoolean( NBT_ON );
}
@ -308,7 +308,7 @@ public final int getComputerID()
@Override
public final String getLabel()
{
return m_label;
return label;
}
@Override
@ -325,9 +325,9 @@ public final void setComputerID( int id )
@Override
public final void setLabel( String label )
{
if( getWorld().isRemote || Objects.equals( m_label, label ) ) return;
if( getWorld().isRemote || Objects.equals( this.label, label ) ) return;
m_label = label;
this.label = label;
ServerComputer computer = getServerComputer();
if( computer != null ) computer.setLabel( label );
markDirty();
@ -375,16 +375,15 @@ public ServerComputer getServerComputer()
protected void writeDescription( @Nonnull CompoundNBT nbt )
{
super.writeDescription( nbt );
if( label != null ) nbt.putString( NBT_LABEL, label );
if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID );
if( m_label != null ) nbt.putString( NBT_LABEL, m_label );
}
@Override
protected void readDescription( @Nonnull CompoundNBT nbt )
{
super.readDescription( nbt );
m_label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
}
@ -395,7 +394,7 @@ protected void transferStateFrom( TileComputerBase copy )
unload();
m_instanceID = copy.m_instanceID;
m_computerID = copy.m_computerID;
m_label = copy.m_label;
label = copy.label;
m_on = copy.m_on;
m_startOn = copy.m_startOn;
updateBlock();
@ -414,20 +413,20 @@ public IPeripheral getPeripheral( @Nonnull Direction side )
@Override
public ITextComponent getName()
{
return hasCustomName() ? new StringTextComponent( m_label ) : getBlockState().getBlock().getNameTextComponent();
return hasCustomName() ? new StringTextComponent( label ) : getBlockState().getBlock().getNameTextComponent();
}
@Override
public boolean hasCustomName()
{
return !Strings.isNullOrEmpty( m_label );
return !Strings.isNullOrEmpty( label );
}
@Nullable
@Override
public ITextComponent getCustomName()
{
return hasCustomName() ? new StringTextComponent( m_label ) : null;
return hasCustomName() ? new StringTextComponent( label ) : null;
}
@Nonnull

View File

@ -106,7 +106,7 @@ public boolean hasMoved()
protected ServerComputer createComputer( int instanceID, int id )
{
ServerComputer computer = new ServerComputer(
getWorld(), id, m_label, instanceID, getFamily(),
getWorld(), id, label, instanceID, getFamily(),
ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle
);
computer.setPosition( getPos() );

View File

@ -5,3 +5,4 @@ ex:
"wget http://pastebin.com/raw/CxaWmPrX test" will download the file from the URL http://pastebin.com/raw/CxaWmPrX, and save it as "test".
"wget http://example.org/test.lua/?foo=bar#qzu" will download the file from the URL http://example.org/test.lua/?foo=bar#qzu and save it as "test.lua"
"wget http://example.org/" will download the file from the URL http://example.org and save it as "example.org"
"wget run http://pastebin.com/raw/CxaWmPrX" will download the file from the URL http://pastebin.com/raw/CxaWmPrX and run it immediately.

View File

@ -8,6 +8,8 @@ Run "list" or "ls" to see all files in a directory.
You can delete files and directories with "delete" or "rm".
Use "pastebin put" to upload a program to pastebin.
Use "pastebin get" to download a program from pastebin.
Use "pastebin run" to run a program from pastebin without saving it.
Use "pastebin run" to run a program from pastebin.
Use the "edit" program to create and edit your programs.
You can copy files with "copy" or "cp".
You can use "wget run <url>" to run a program from the internet.
You can use "wget" to download a file from the internet.

View File

@ -15,6 +15,10 @@ if #tFiles > 0 then
elseif #tFiles == 1 then
if fs.exists( sDest ) then
printError( "Destination exists" )
elseif fs.isReadOnly( sDest ) then
printError( "Destination is read-only" )
elseif fs.getFreeSpace( sDest ) < fs.getSize( sFile ) then
printError( "Not enough space" )
else
fs.copy( sFile, sDest )
end

View File

@ -2,14 +2,24 @@
local function printUsage()
print( "Usage:" )
print( "wget <url> [filename]" )
print( "wget run <url>" )
end
local tArgs = { ... }
local run = false
if tArgs[1] == "run" then
table.remove( tArgs, 1 )
run = true
end
if #tArgs < 1 then
printUsage()
return
end
local url = table.remove( tArgs, 1 )
if not http then
printError( "wget requires http API" )
printError( "Set http_enable to true in ComputerCraft.cfg" )
@ -22,6 +32,13 @@ local function getFilename( sUrl )
end
local function get( sUrl )
-- Check if the URL is valid
local ok, err = http.checkURL( url )
if not ok then
printError( err or "Invalid URL." )
return
end
write( "Connecting to " .. sUrl .. "... " )
local response = http.get( sUrl , nil , true )
@ -37,29 +54,34 @@ local function get( sUrl )
return sResponse
end
-- Determine file to download
local sUrl = tArgs[1]
if run then
local res = get(url)
if not res then return end
--Check if the URL is valid
local ok, err = http.checkURL( sUrl )
if not ok then
printError( err or "Invalid URL." )
return
end
local func, err = load(res, getFilename(url), "t", _ENV)
if not func then
printError(err)
return
end
local sFile = tArgs[2] or getFilename( sUrl )
local sPath = shell.resolve( sFile )
if fs.exists( sPath ) then
print( "File already exists" )
return
end
local ok, err = pcall(func, table.unpack(tArgs))
if not ok then
printError( err )
end
else
local sFile = tArgs[1] or getFilename( url )
local sPath = shell.resolve( sFile )
if fs.exists( sPath ) then
print( "File already exists" )
return
end
local res = get(url)
if not res then return end
-- Do the get
local res = get( sUrl )
if res then
local file = fs.open( sPath, "wb" )
file.write( res )
file.close()
print( "Downloaded as "..sFile )
print( "Downloaded as " .. sFile )
end

View File

@ -7,8 +7,15 @@ end
local sSource = shell.resolve( tArgs[1] )
local sDest = shell.resolve( tArgs[2] )
if fs.exists( sDest ) then
if not fs.exists( sSource ) then
printError( "No matching files" )
return
elseif fs.exists( sDest ) then
printError( "Destination exists" )
return
elseif fs.isReadOnly( sDest ) then
printError( "Destination is read-only" )
return
end
fs.move( sSource, sDest )

View File

@ -183,6 +183,12 @@ local function completeExec( shell, nIndex, sText, tPreviousText )
return completeMultipleChoice( sText, tCommands, true )
end
end
local tWgetOptions = { "run" }
local function completeWget( shell, nIndex, sText, tPreviousText )
if nIndex == 1 then
return completeMultipleChoice( sText, tWgetOptions, true )
end
end
shell.setCompletionFunction( "rom/programs/alias.lua", completeAlias )
shell.setCompletionFunction( "rom/programs/cd.lua", completeDir )
shell.setCompletionFunction( "rom/programs/copy.lua", completeEitherEither )
@ -210,6 +216,7 @@ shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completeFile
shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completePastebin )
shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completeChat )
shell.setCompletionFunction( "rom/programs/command/exec.lua", completeExec )
shell.setCompletionFunction( "rom/programs/http/wget.lua", completeWget )
if turtle then
local tGoOptions = { "left", "right", "forward", "back", "down", "up" }

View File

@ -42,7 +42,7 @@ public void testList() throws IOException
files.sort( Comparator.naturalOrder() );
assertEquals(
Arrays.asList( "apis", "autorun", "help", "modules", "programs", "startup.lua" ),
Arrays.asList( "apis", "autorun", "help", "modules", "motd.txt", "programs", "startup.lua" ),
files
);
}

View File

@ -49,6 +49,8 @@ local function push_state()
term = term.current(),
input = io.input(),
output = io.output(),
dir = shell.dir(),
path = shell.path(),
stubs = stubs,
}
end
@ -65,6 +67,8 @@ local function pop_state(state)
term.redirect(state.term)
io.input(state.input)
io.output(state.output)
shell.setDir(state.dir)
shell.setPath(state.path)
end
local error_mt = { __tostring = function(self) return self.message end }

View File

@ -0,0 +1,20 @@
local capture = require "test_helpers".capture_program
describe("The cd program", function()
it("cd into a directory", function()
shell.run("cd /rom/programs")
expect(shell.dir()):eq("rom/programs")
end)
it("cd into a not existing directory", function()
expect(capture(stub, "cd /rom/nothing"))
:matches { ok = true, output = "Not a directory\n", error = "" }
end)
it("displays the usage with no arguments", function()
expect(capture(stub, "cd"))
:matches { ok = true, output = "Usage: cd <path>\n", error = "" }
end)
end)

View File

@ -0,0 +1,40 @@
local capture = require "test_helpers".capture_program
describe("The copy program", function()
local function touch(file)
io.open(file, "w"):close()
end
it("copies a file", function()
touch("/test-files/copy/a.txt")
shell.run("copy /test-files/copy/a.txt /test-files/copy/b.txt")
expect(fs.exists("/test-files/copy/a.txt")):eq(true)
expect(fs.exists("/test-files/copy/b.txt")):eq(true)
end)
it("fails when copying a non-existent file", function()
expect(capture(stub, "copy nothing destination"))
:matches { ok = true, output = "", error = "No matching files\n" }
end)
it("fails when overwriting an existing file", function()
touch("/test-files/copy/c.txt")
expect(capture(stub, "copy /test-files/copy/c.txt /test-files/copy/c.txt"))
:matches { ok = true, output = "", error = "Destination exists\n" }
end)
it("fails when copying into read-only locations", function()
touch("/test-files/copy/d.txt")
expect(capture(stub, "copy /test-files/copy/d.txt /rom/test.txt"))
:matches { ok = true, output = "", error = "Destination is read-only\n" }
end)
it("displays the usage when given no arguments", function()
expect(capture(stub, "copy"))
:matches { ok = true, output = "Usage: cp <source> <destination>\n", error = "" }
end)
end)

View File

@ -0,0 +1,11 @@
local capture = require "test_helpers".capture_program
describe("The edit program", function()
it("displays its usage when given no argument", function()
multishell = nil
expect(capture(stub, "edit"))
:matches { ok = true, output = "Usage: edit <path>\n", error = "" }
end)
end)

View File

@ -0,0 +1,77 @@
local capture = require "test_helpers".capture_program
describe("The pastebin program", function()
local function setup_request()
stub(_G, "http", {
checkURL = function()
return true
end,
get = function()
return {
readAll = function()
return [[print("Hello", ...)]]
end,
close = function()
end,
getResponseHeaders = function()
local tHeader = {}
tHeader["Content-Type"] = "text/plain; charset=utf-8"
return tHeader
end
}
end,
post = function()
return {
readAll = function()
return "https://pastebin.com/abcde"
end,
close = function()
end,
}
end
})
end
it("downloads one file", function()
setup_request()
capture(stub, "pastebin", "get", "abcde", "testdown")
expect(fs.exists("/testdown")):eq(true)
end)
it("runs a program from the internet", function()
setup_request()
expect(capture(stub, "pastebin", "run", "abcde", "a", "b", "c"))
:matches { ok = true, output = "Connecting to pastebin.com... Success.\nHello a b c\n", error = "" }
end)
it("upload a program to pastebin", function()
setup_request()
local file = fs.open( "testup", "w" )
file.close()
expect(capture(stub, "pastebin", "put", "testup" ))
:matches { ok = true, output = "Connecting to pastebin.com... Success.\nUploaded as https://pastebin.com/abcde\nRun \"pastebin get abcde\" to download anywhere\n", error = "" }
end)
it("upload a not existing program to pastebin", function()
setup_request()
expect(capture(stub, "pastebin", "put", "nothing" ))
:matches { ok = true, output = "No such file\n", error = "" }
end)
it("displays its usage when given no arguments", function()
setup_request()
expect(capture(stub, "pastebin"))
:matches { ok = true, output = "Usages:\npastebin put <filename>\npastebin get <code> <filename>\npastebin run <code> <arguments>\n", error = "" }
end)
it("can be completed", function()
local complete = shell.getCompletionInfo()["rom/programs/http/pastebin.lua"].fnComplete
expect(complete(shell, 1, "", {})):same { "put ", "get ", "run " }
end)
end)

View File

@ -0,0 +1,53 @@
local capture = require "test_helpers".capture_program
describe("The wget program", function()
local function setup_request()
stub(_G, "http", {
checkURL = function()
return true
end,
get = function()
return {
readAll = function()
return [[print("Hello", ...)]]
end,
close = function()
end,
}
end
})
end
it("downloads one file", function()
setup_request()
capture(stub, "wget", "https://example.com")
expect(fs.exists("/example.com")):eq(true)
end)
it("downloads one file with given filename", function()
setup_request()
capture(stub, "wget", "https://example.com /test-files/download")
expect(fs.exists("/test-files/download")):eq(true)
end)
it("runs a program from the internet", function()
setup_request()
expect(capture(stub, "wget", "run", "http://test.com", "a", "b", "c"))
:matches { ok = true, output = "Connecting to http://test.com... Success.\nHello a b c\n", error = "" }
end)
it("displays its usage when given no arguments", function()
setup_request()
expect(capture(stub, "wget"))
:matches { ok = true, output = "Usage:\nwget <url> [filename]\nwget run <url>\n", error = "" }
end)
it("can be completed", function()
local complete = shell.getCompletionInfo()["rom/programs/http/wget.lua"].fnComplete
expect(complete(shell, 1, "", {})):same { "run " }
end)
end)

View File

@ -0,0 +1,11 @@
local capture = require "test_helpers".capture_program
describe("The id program", function()
it("displays computer id", function()
local id = os.getComputerID()
expect(capture(stub, "id"))
:matches { ok = true, output = "This is computer #"..id.."\n", error = "" }
end)
end)

View File

@ -0,0 +1,14 @@
local capture = require "test_helpers".capture_program
describe("The motd program", function()
it("displays MODT", function()
local file = fs.open("/modt_check.txt","w")
file.write("Hello World!")
file.close()
settings.set("motd.path","/modt_check.txt")
expect(capture(stub, "motd"))
:matches { ok = true, output = "Hello World!\n", error = "" }
end)
end)

View File

@ -0,0 +1,26 @@
local capture = require "test_helpers".capture_program
describe("The move program", function()
local function touch(file)
io.open(file, "w"):close()
end
it("move a file", function()
touch("/test-files/move/a.txt")
shell.run("move /test-files/move/a.txt /test-files/move/b.txt")
expect(fs.exists("/test-files/move/a.txt")):eq(false)
expect(fs.exists("/test-files/move/b.txt")):eq(true)
end)
it("try to move a not existing file", function()
expect(capture(stub, "move nothing destination"))
:matches { ok = true, output = "", error = "No matching files\n" }
end)
it("displays the usage with no arguments", function()
expect(capture(stub, "move"))
:matches { ok = true, output = "Usage: mv <source> <destination>\n", error = "" }
end)
end)

View File

@ -0,0 +1,40 @@
local capture = require "test_helpers".capture_program
describe("The rename program", function()
local function touch(file)
io.open(file, "w"):close()
end
it("can rename a file", function()
touch("/test-files/rename/a.txt")
shell.run("rename /test-files/rename/a.txt /test-files/rename/b.txt")
expect(fs.exists("/test-files/rename/a.txt")):eq(false)
expect(fs.exists("/test-files/rename/b.txt")):eq(true)
end)
it("fails when renaming a file which doesn't exist", function()
expect(capture(stub, "rename nothing destination"))
:matches { ok = true, output = "", error = "No matching files\n" }
end)
it("fails when overwriting an existing file", function()
touch("/test-files/rename/c.txt")
expect(capture(stub, "rename /test-files/rename/c.txt /test-files/rename/c.txt"))
:matches { ok = true, output = "", error = "Destination exists\n" }
end)
it("fails when copying to read-only locations", function()
touch("/test-files/rename/d.txt")
expect(capture(stub, "rename /test-files/rename/d.txt /rom/test.txt"))
:matches { ok = true, output = "", error = "Destination is read-only\n" }
end)
it("displays the usage when given no arguments", function()
expect(capture(stub, "rename"))
:matches { ok = true, output = "Usage: rename <source> <destination>\n", error = "" }
end)
end)

View File

@ -0,0 +1,29 @@
local capture = require "test_helpers".capture_program
describe("The set program", function()
it("displays all settings", function()
settings.clear()
settings.set("Test","Hello World!")
settings.set("123",456)
expect(capture(stub, "set"))
:matches { ok = true, output = '"123" is 456\n"Test" is "Hello World!"\n', error = "" }
end)
it("displays a single settings", function()
settings.clear()
settings.set("Test","Hello World!")
settings.set("123",456)
expect(capture(stub, "set Test"))
:matches { ok = true, output = '"Test" is "Hello World!"\n', error = "" }
end)
it("set a setting", function()
expect(capture(stub, "set Test Hello"))
:matches { ok = true, output = '"Test" set to "Hello"\n', error = "" }
expect(settings.get("Test")):eq("Hello")
end)
end)

View File

@ -27,6 +27,10 @@ describe("The shell", function()
shell.setDir(shell.dir())
expect.error(shell.setDir, nil):eq("bad argument #1 (expected string, got nil)")
end)
it("not existing directory", function()
expect.error(shell.setDir, "/rom/nothing"):eq("Not a directory")
end)
end)
describe("shell.setPath", function()

View File

@ -0,0 +1,12 @@
local capture = require "test_helpers".capture_program
describe("The time program", function()
it("displays time", function()
local time = textutils.formatTime(os.time())
local day = os.day()
expect(capture(stub, "time"))
:matches { ok = true, output = "The time is "..time.." on Day "..day.."\n", error = "" }
end)
end)

View File

@ -0,0 +1,26 @@
local capture = require "test_helpers".capture_program
describe("The type program", function()
it("displays the usage with no arguments", function()
expect(capture(stub, "type"))
:matches { ok = true, output = "Usage: type <path>\n", error = "" }
end)
it("displays the output for a file", function()
expect(capture(stub, "type /rom/startup.lua"))
:matches { ok = true, output = "file\n", error = "" }
end)
it("displays the output for a directory", function()
expect(capture(stub, "type /rom"))
:matches { ok = true, output = "directory\n", error = "" }
end)
it("displays the output for a not existing path", function()
expect(capture(stub, "type /rom/nothing"))
:matches { ok = true, output = "No such path\n", error = "" }
end)
end)