9

Sto provando a trasferire alcuni vecchi AppleScript sulla nuova sintassi JavaScript.Elenco di tutti i file in una cartella utilizzando JavaScript per l'automazione su Yosemite

Qualcosa sembra essere piuttosto semplice così:

tell application "System Events" to keystroke "t" using command down 

diventa:

System = Application('System Events'); 
System.keystroke("t", {using: "command down"}) 

Tuttavia non posso per la vita di me capire come elencare i file in una posizione specifica. In AppleScript, per tornare me un elenco dei file nella directory /usr, si dovrebbe fare:

tell application "System Events" to set fileList to name of items in folder "/usr" 
-- > {"bin", "include", "lib", "libexec", "local", "sbin", "share", "standalone", "X11"} 

Tuttavia non posso per la vita di me capire come farlo in Javascript.

System = Application('System Events') 
myPath = Path("/usr") 

fileList = System.items(myPath) 
-- > message not understood 

fileList = System.folder(myPath) 
-- > message not understood 

fileList = System.diskItems(myPath) 
-- > [] 

fileList = System.diskItems({at:myPath) 
-- > [] 

Ho provato anche molte altre combinazioni, ma senza fortuna. Qualche idea?

risposta

13

Come 0.123.019,105128 millionsprima di esso, JXA interrompe intenzionalmente tutti i tipi di elementi che funzionano perfettamente in AppleScript. Ecco la traduzione del vostro comando originale AppleScript per la sintassi JXA:

//tell application "System Events" to name of items in folder "/usr" 
Application('System Events').folders.byName('/usr').items.name() 

La versione AS funziona perfettamente, ma il JXA equivalente getta solo una completamente priva di senso Error -1700: Can't convert types.

JXA sembra funzionare se si scrive diskItems invece di items:

Application('System Events').folders.byName('/usr').diskItems.name() 
// --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"] 

che suggerisce JXA indulge nello stesso "intelligenza" interna che provoca SB rompere in tante applicazioni. (Si noti che ho riscontrato numerosi difetti di progettazione in precedenti test, ma ho rinunciato a segnalarli una volta che era chiaro che gli sviluppatori AS si preoccupavano solo di imporre la propria ideologia personale e pregiudizi su tutti gli altri, le capacità paralizzate e la compatibilità interrotta essere dannati.)

per confronto, ecco la JavaScriptOSA (JOSA) prototype ho subito messo insieme per riferimento degli sviluppatori JXA qualche mese fa (hanno prontamente ignorato, natch):

app('System Events').folders.named('/usr').items.name() 
// -> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"] 

(Anche se non completamente finito o testati, JOSA funziona ancora un fico secco Vista migliore di JXA, è meglio documentata e include anche uno strumento di traduzione automatica per convertire i comandi AS in sintassi JS. Sfortunatamente, perché Apple ha le gassificato o deprecato le API AEM, CM, PM e OSA Carbon, non posso raccomandarlo per l'uso in produzione; è puramente lì per scopi di confronto.)

Allo stesso modo:

set myPath to POSIX file "/usr" 
tell application "System Events" to name of every disk item of folder named myPath 
--> {"bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"} 

myPath = Path('/usr') 
Application('System Events').folders.byName(myPath).diskItems.name() 
// Error -1728: Can't get object. 

var myPath = Path('/usr') 
app('System Events').folders.named(myPath).diskItems.name() 
// --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"] 

È possibile lavorare intorno a quel caso particolare convertendo l'oggetto Path in una stringa, e l'utilizzo che:

myPath = Path('/usr') 
Application('System Events').folders.byName(myPath.toString()).diskItems.name() 

Anche se questo soluzione non sarà necessariamente aiuterà a altre situazioni; per esempio. non riesce nel Finder perché Finder non capisce le stringhe di percorso in stile POSIX, e non c'è modo per avere una stringa di percorso in stile HFS (che Finder capisce) da un oggetto JXA Percorso:

set myPath to POSIX file "/usr" 
tell application "Finder" to name of every item of item myPath 
--> {"X11", "X11R6", "bin", "lib", "libexec", "local", "sbin", "share", "standalone"} 

myPath = Path('/usr') 
Application('Finder').folders.byName(myPath.toString()).items.name() 
// Error -1728: Can't get object. 

E così va. (Es Prova collaudo sostegno JXA per gamma, filtro, relativa, e l'inserimento reference forms: è particolarmente marcia.)

+0

Wow risposta incredibilmente completa. Immagino che non ci siano troppi problemi nell'apportare modifiche (elementi a diskItems) se rende le cose più facili da capire (probabilmente vero in questo caso) E su di esso c'era una documentazione decente e chiara. Questo non sembra essere il caso (beh almeno non ancora, è ancora una beta - ha detto speranzoso). Detto questo, se stai per fare cambiamenti semantici come questo allora sicuramente qualcosa come Application ('Finder'). DiskItems ({atPath: path, return: "nomi", includeSubDirectories: true, excludeInvisibles: true) etc farebbe molto più senso, almeno di testa. – dwkns

+0

JXA non sta apportando modifiche per rendere le cose più facili da capire; sta rompendo la compatibilità perché ai suoi sviluppatori non piace e/o capisce come funziona l'evento Apple IPC. Le applicazioni scriptable [i] definiscono già tutti i comportamenti [/ i]. Come [i] cliente [/ i] di quelle applicazioni, è responsabilità di JXA supportare tali comportamenti in modo completo e corretto, non gettare un attacco sibilante solo perché offende le convinzioni personali degli sviluppatori JXA. È patologico guidare il sedile posteriore, nient'altro. – foo

+0

OK. Quindi c'è un modo per capire quali metodi/proprietà effettivamente si applicano in un dato momento. La documentazione non è di grande aiuto in questo senso. Posso trovare nella documentazione Application ('System Events'). Folder ma nessun riferimento a byName(). E sembra che tu non sia in grado di costruire comandi un po 'alla volta. Applicazione ('Eventi di sistema'). Folders.byName ('/ usr') non restituisce nulla, quindi come fai a sapere di applicare .diskItems.name() ad esso? Devi solo conoscere questa roba? O come lo risolvi? – dwkns

2

posso ottenere in questo modo

foldersList = foldersList = System.folders.byName("usr").folders.name() 

-> [ "bin", "lib", "libexec", "sbin", "share", "stand-alone", "X11"]

E anche questo funziona:

foldersList = System.folders.byName("/Users/USERName/Documents/").folders.name() 

ma finora non può ottenere il comando Percorso di lavorare su qualche cosa ma 'aperto'

+0

@dwkns Ha fatto un leggero aggiornamento – markhunte

7

L'approccio "System Events" ha certamente il pregio della semplicità, ma si scopre che l'uso $.NSFileManager (ora direttamente disponibile per lo scripting) offre prestazioni notevolmente più veloci.

Sul mio sistema, a partire per il confronto con

var strPath = '/usr'; 

var appSys = Application('System Events'), 
lstHarvest = appSys.folders.byName(strPath).diskItems.name(); 

Un test rapido con poche migliaia di iterazioni suggerisce che possiamo costantemente accelerarlo di un modesto 40% con questo approccio un po 'barocco:

var strPath = '/usr'; 
var fm = $.NSFileManager.defaultManager, 
    oURL = $.NSURL.fileURLWithPathIsDirectory(strPath, true), 
    lstFiles = ObjC.unwrap(
     fm.contentsOfDirectoryAtURLIncludingPropertiesForKeysOptionsError(
      oURL, [], 1 << 2, null 
     ) 
    ), 
    lstHarvest = []; 

lstFiles.forEach(function (oItem) { 
    lstHarvest.push(
     ObjC.unwrap(oItem.path) 
    ); 
}); 

e da ben oltre il 300% con i piuttosto semplici:

var strPath = '/usr'; 
var fm = $.NSFileManager.defaultManager, 
    lstFiles = ObjC.unwrap(
     fm.contentsOfDirectoryAtPathError(strPath, null) 
    ), 
    lstHarvest = []; 

lstFiles.forEach(function (oItem) { 
    lstHarvest.push(
     ObjC.unwrap(oItem) 
    ); 
}); 
Problemi correlati