-- This is the lua p4 api -- It wraps shell calls to the p4 command line client and parses it returns -- Module setup local Private, Public = {}, {} p4 = Public -- executes a p4 command and returns the output as a large string function Private.p4Execute(params) local cmd assert(params) if type(params) == "table" then assert(params.Command) cmd = params.Command else cmd = params end -- tmpdatei ermitteln local tmpfile = tmpname() -- befehl ausführen execute('p4 ' .. cmd .. ' > ' .. tmpfile) -- tmpdatei auslesen local retval = readfile(tmpfile) -- tmpdatei löschen remove(tmpfile) return retval end -- FUNCTION: -- CounterGet -- PURPOSE: -- Read a perforce counter and returns its value -- INPUT TABLE LAYOUT: -- Name: Name of the counter to read -- OUTPUT TABLE LAYOUT: -- Message: Perforce return string unfiltered -- Name: Name of the counter requested -- Value: Value of the counter function Public.CounterGet(params) assert(params ~= nil) assert(params.Name ~= nil) local cmd = 'counter ' .. params.Name local result = %Private.p4Execute(cmd) local retval = {} retval.Name = params.Name retval.Value = tonumber(result) retval.Message = result return retval end -- FUNCTION: -- CounterSet -- PURPOSE: -- Sets a perforce counter to a specific value -- INPUT TABLE LAYOUT: -- Name: Name of the counter to set -- Value: New value of the counter -- OUTPUT TABLE LAYOUT: -- Message: Perforce return string unfiltered -- Name: Name of the counter to set -- Value: Value of the counter set function Public.CounterSet(params) assert(params ~= nil) assert(params.Name ~= nil) assert(params.Value ~= nil) local cmd = 'counter ' .. params.Name .. ' ' .. params.Value local result = %Private.p4Execute(cmd) local retval = {} retval.Name = params.Name retval.Value = params.Value retval.Message = result return retval end -- FUNCTION: -- Sync -- PURPOSE: -- Syncs the depot or part of it -- INPUT TABLE LAYOUT: -- Filespec: Files to sync (file part and revisions allowed) -- OUTPUT TABLE LAYOUT: -- Message: Perforce return string unfiltered -- Filespec: Filespec from input table function Public.Sync(params) assert(params ~= nil) assert(params.Filespec ~= nil) local cmd = 'sync ' .. params.Filespec local result = %Private.p4Execute(cmd) local retval = {} retval.Filespec = params.Filespec retval.Message = result -- %$ TODO: ergebnis des syncs als retval liefern return retval end -- FUNCTION: -- Changes -- PURPOSE: -- Lists the changes in the depot -- INPUT TABLE LAYOUT: -- Filespec(optional): Part of the depot to filter for changes -- Flags(optional): Additional command flags (described in "p4 help changes") -- OUTPUT TABLE LAYOUT: -- Message: Perforce return string unfiltered -- Filespec: Filespec requested -- Changes: Table with changes returned. Each entry has the following fields: -- Change: # of the changelist -- Date: Date of the change as string -- User: User who submitted this change -- Client: Client from which this change was submitted -- Decription: Checkin text for this change -- Status: Pending or nil function Public.Changes(params) assert(params ~= nil) local filespec = params.Filespec or "" local flags = params.Flags or "" local cmd = 'changes ' .. flags .. " " .. filespec local result = %Private.p4Execute(cmd) -- retval zusammenbauen -- zuerst header local retval = {} retval.Filespec = params.Filespec retval.Message = result retval.Changes = {} -- und jetzt die changes zeilenweise durchgehen changes = strsplit("\n", result) foreachi(changes, function(_i, _v) assert(_v ~= nil) assert(type(_v) == "string") if _v ~= "" then local c = {} local hit hit,_,c.Change,c.Date,c.User,c.Client,c.Status, c.Description = strfind(_v, "Change (%d+) on (%d+/%d+/%d+) by ([%w_]+)@([%w_]+) %*(pending)%* '(.*)'") if not hit then hit,_,c.Change,c.Date,c.User,c.Client,c.Description = strfind(_v, "Change (%d+) on (%d+/%d+/%d+) by ([%w_]+)@([%w_]+) '(.*)'") end assert(hit) tinsert(%retval.Changes, c) end end) return retval end -- FUNCTION: -- Where -- PURPOSE: -- Translated between depot path, client path and systempath -- INPUT TABLE LAYOUT: -- Filespec: Filespec to translate -- OUTPUT TABLE LAYOUT: -- Message: Perforce return string unfiltered -- Filespec: Filespec from params -- Where: Table of path infos from where command. Layout of each table entry: -- DepotPath: Path of this entry in depot syntax (eg. //depot/main/foo.c) -- ClientPath: Path of this entry in client syntax (eg. //dirk/main/foo.c) -- SystemPath: Filesystempath for this entry (eg. c:\project\main\foo.c) function Public.Where(params) assert(params ~= nil) assert(params.Filespec ~= nil) local cmd = 'where ' .. params.Filespec local result = %Private.p4Execute(cmd) -- retval zusammenbauen -- zuerst header local retval = {} retval.Filespec = params.Filespec retval.Message = result retval.Where = {} -- und jetzt die changes zeilenweise durchgehen changes = strsplit("\n", result) foreachi(changes, function(_i, _v) assert(_v ~= nil) assert(type(_v) == "string") if _v ~= "" then local c = {} _,_,c.DepotPath,c.ClientPath,c.SystemPath = strfind(_v, "([%w_/ %.]+) ([%w_/ %.]+) ([%w_/:\\ %.]+)") tinsert(%retval.Where, c) end end) return retval end -- FUNCTION: -- Opened -- PURPOSE: -- Gets a set of opened files -- INPUT TABLE LAYOUT: -- Filespec: Filespec to search for opened files -- Flags: Additional command flags (see "p4 help opened") -- OUTPUT TABLE LAYOUT: -- Message: Perforce return string unfiltered -- Filespec: Filespec from input params -- Flags: Flags from input -- Opened: Table with input about each opened file. Entry layout: -- File: Name of the file -- Revision: Revision at which the file is opened -- Action: Action used to open (edit, integrate, add, delete,...) -- Filetype: Filetype of this file -- Changelist: Changelist under which this file is opened ("default" or number of the change) function Public.Opened(params) local p = params or {} local flags = p.Flags or "" local filespec = p.Filespec or "//..." local cmd = 'opened ' .. flags .. " " .. filespec local result = %Private.p4Execute(cmd) -- retval zusammenbauen -- zuerst header local retval = {} retval.Filespec = filespec retval.Flags = flags retval.Message = result retval.Opened = {} -- und jetzt die changes zeilenweise durchgehen changes = strsplit("\n", result) foreachi(changes, function(_i, _v) assert(_v ~= nil) assert(type(_v) == "string") if _v ~= "" then local c = {} local hit hit,_,c.File,c.Revision,c.Action, c.Filetype = strfind(_v, "([%w\._/ ]+)#(%d+) %- (%w+) default change %(([%w%+]+)%)") if hit then c.Changelist = "default" else hit,_,c.File,c.Revision,c.Action, c.Changelist, c.Filetype = strfind(_v, "([%w\._/ ]+)#(%d+) %- (%w+) change (%d+) %(([%w%+]+)%)") c.Changelist = tonumber(c.Changelist) end assert(hit) tinsert(%retval.Opened, c) end end) return retval end -- FUNCTION: -- Add -- PURPOSE: -- Opens a file for add -- INPUT TABLE LAYOUT: -- Filespec: Files to add to the depot function Public.Add(params) assert(params) assert(type(params) == "table") assert(params.Filespec) local cmd = 'add ' .. params.Filespec local result = %Private.p4Execute(cmd) end -- FUNCTION: -- Edit -- PURPOSE: -- Opens files for edit -- INPUT TABLE LAYOUT: -- Filespec: Files to edit function Public.Edit(params) assert(params) assert(type(params) == "table") assert(params.Filespec) local cmd = 'edit ' .. params.Filespec local result = %Private.p4Execute(cmd) end -- FUNCTION: -- Submit -- PURPOSE: -- Submits a changelist to the depot -- INPUT TABLE LAYOUT: -- Description: Description for this checkin -- Changelist: Changelist to submit ("default" or number) -- Files: Stringtable with files to submit function Public.Submit(params) assert(params) assert(type(params) == "table") assert(params.Description) assert(params.Changelist) assert(params.Files) assert(type(params.Files) == "table") local tmp = tmpname() -- kommandozeile zusammenfreckeln local cmd = 'submit -i' if params.Changelist ~= "default" then assert(type(params.Changelist) == "number") cmd = cmd .. ' -c ' .. params.Changelist end cmd = cmd .. " < " .. tmp -- parameterdatei zusammenfreckeln local desc = {[1] = "Change: \n\tnew\n\nDescription:\n\t" .. params.Description .. "\n\nFiles:\n" } foreachi(params.Files, function(_i,_f) assert(type(_f) == "string") %desc[1] = %desc[1] .. "\t" .. _f .. "\n" end) writefile(tmp, desc[1]) local result = %Private.p4Execute(cmd) remove(tmp) end -- FUNCTION: -- Revert -- PURPOSE: -- Reverts files -- INPUT TABLE LAYOUT: -- Filespec: Which files to revert -- Flags: Additional flags (most used "-a" for unchanged files) function Public.Revert(params) assert(params) assert(type(params) == "table") local files = params.Filespec or "" local flags = params.Flags or "" local cmd = 'revert ' .. flags .. ' ' .. files local result = %Private.p4Execute(cmd) end -- FUNCTION: -- Describe -- PURPOSE: -- Gets infos about a change -- INPUT TABLE LAYOUT: -- Changelist: Number of the changelist to query -- OUTPUT TABLE LAYOUT: -- Message: Perforce result unfiltered -- Changelist: Changelistnumber -- User: User who owns/submitted this change -- Client: Client used -- Date: Date of change as string -- Time: Time of change as string -- Status: "pending" or nil -- Description: Description of the change -- Filelist: List of files in this change. Each file is a table with the following entries: -- File: Name of file -- Revision: Revision -- Action: Action function Public.Describe(params) assert(params) assert(params.Changelist) local flags = params.Flags or "" local cmd = "describe " .. flags .. " " .. params.Changelist local result = %Private.p4Execute(cmd) local retval = {} retval.Message = result -- erste infozeile parsen local hit hit,_,retval.Changelist,retval.User,retval.Client,retval.Date,retval.Time,retval.Status = strfind(result, "Change (%d+) by ([%w_]+)@([%w_]+) on (%d+/%d+/%d+) (%d+%:%d+%:%d+) %*(pending)%*\n") if not hit then hit,_,retval.Changelist,retval.User,retval.Client,retval.Date,retval.Time,retval.Status = strfind(result, "Change (%d+) by ([%w_]+)@([%w_]+) on (%d+/%d+/%d+) (%d+%:%d+%:%d+)\n") end assert(hit) -- description parsen local hit = nil hit,_,retval.Description = strfind(result, "[^\n]*\n[^\n]*\n(.*)\n\nAffected files") if not hit then hit,_,retval.Description = strfind(result, "[^\n]*\n[^\n]*\n(.*)\n\n") end assert(hit) -- file list local hit = nil local filelist hit,_,filelist = strfind(result, "[^\n]*\n[^\n]*\n.*\n\nAffected files ...\n\n(.*)\nDifferences ...") if not hit then hit,_,filelist = strfind(result, "[^\n]*\n[^\n]*\n.*\n\nAffected files ...\n\n(.*)") end -- yep, tatsächlich files gefunden if filelist then retval.Filelist = {} filelist = strsplit("\n", filelist) foreachi(filelist, function(_i, _file) assert(_file) local f = {} _,_,f.File,f.Revision,f.Action = strfind(_file, "... ([%w\._/ ]+)#(%d+) (%w+)") tinsert(%retval.Filelist, f) end) end return retval end -- FUNCTION: -- Change -- PURPOSE: -- Creates or deletes changelists -- INPUT TABLE LAYOUT: -- Changelist: Number of the changelist -- Flags: Additional flags (see "p4 help change") function Public.Change(params) assert(params) assert(params.Changelist) local flags = params.Flags or "" local cmd = "change " .. flags .. " " .. params.Changelist local result = %Private.p4Execute(cmd) end